Commit 40fe2e0d authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 's390-qeth-next'



Julian Wiedmann says:

====================
s390/qeth: updates 2020-09-23

please apply the following patch series for qeth to netdev's net-next tree.

This brings all sorts of cleanups. Highlights are more code sharing in
the init/teardown paths, and more fine-grained rollback on errors during
initialization (instead of a full-blown teardown).
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 46237bf3 58fa3575
Loading
Loading
Loading
Loading
+8 −14
Original line number Original line Diff line number Diff line
@@ -195,8 +195,8 @@ struct qeth_vnicc_info {
#define QETH_IN_BUF_SIZE_DEFAULT 65536
#define QETH_IN_BUF_SIZE_DEFAULT 65536
#define QETH_IN_BUF_COUNT_DEFAULT 64
#define QETH_IN_BUF_COUNT_DEFAULT 64
#define QETH_IN_BUF_COUNT_HSDEFAULT 128
#define QETH_IN_BUF_COUNT_HSDEFAULT 128
#define QETH_IN_BUF_COUNT_MIN 8
#define QETH_IN_BUF_COUNT_MIN	8U
#define QETH_IN_BUF_COUNT_MAX 128
#define QETH_IN_BUF_COUNT_MAX	128U
#define QETH_MAX_BUFFER_ELEMENTS(card) ((card)->qdio.in_buf_size >> 12)
#define QETH_MAX_BUFFER_ELEMENTS(card) ((card)->qdio.in_buf_size >> 12)
#define QETH_IN_BUF_REQUEUE_THRESHOLD(card) \
#define QETH_IN_BUF_REQUEUE_THRESHOLD(card) \
		 ((card)->qdio.in_buf_pool.buf_count / 2)
		 ((card)->qdio.in_buf_pool.buf_count / 2)
@@ -753,7 +753,7 @@ struct qeth_discipline {
	const struct device_type *devtype;
	const struct device_type *devtype;
	int (*setup) (struct ccwgroup_device *);
	int (*setup) (struct ccwgroup_device *);
	void (*remove) (struct ccwgroup_device *);
	void (*remove) (struct ccwgroup_device *);
	int (*set_online)(struct qeth_card *card);
	int (*set_online)(struct qeth_card *card, bool carrier_ok);
	void (*set_offline)(struct qeth_card *card);
	void (*set_offline)(struct qeth_card *card);
	int (*do_ioctl)(struct net_device *dev, struct ifreq *rq, int cmd);
	int (*do_ioctl)(struct net_device *dev, struct ifreq *rq, int cmd);
	int (*control_event_handler)(struct qeth_card *card,
	int (*control_event_handler)(struct qeth_card *card,
@@ -814,12 +814,16 @@ struct qeth_card {
	struct workqueue_struct *event_wq;
	struct workqueue_struct *event_wq;
	struct workqueue_struct *cmd_wq;
	struct workqueue_struct *cmd_wq;
	wait_queue_head_t wait_q;
	wait_queue_head_t wait_q;

	struct mutex ip_lock;
	/* protected by ip_lock: */
	DECLARE_HASHTABLE(ip_htable, 4);
	DECLARE_HASHTABLE(ip_htable, 4);
	struct qeth_ipato ipato;

	DECLARE_HASHTABLE(local_addrs4, 4);
	DECLARE_HASHTABLE(local_addrs4, 4);
	DECLARE_HASHTABLE(local_addrs6, 4);
	DECLARE_HASHTABLE(local_addrs6, 4);
	spinlock_t local_addrs4_lock;
	spinlock_t local_addrs4_lock;
	spinlock_t local_addrs6_lock;
	spinlock_t local_addrs6_lock;
	struct mutex ip_lock;
	DECLARE_HASHTABLE(rx_mode_addrs, 4);
	DECLARE_HASHTABLE(rx_mode_addrs, 4);
	struct work_struct rx_mode_work;
	struct work_struct rx_mode_work;
	struct work_struct kernel_thread_starter;
	struct work_struct kernel_thread_starter;
@@ -827,7 +831,6 @@ struct qeth_card {
	unsigned long thread_start_mask;
	unsigned long thread_start_mask;
	unsigned long thread_allowed_mask;
	unsigned long thread_allowed_mask;
	unsigned long thread_running_mask;
	unsigned long thread_running_mask;
	struct qeth_ipato ipato;
	struct list_head cmd_waiter_list;
	struct list_head cmd_waiter_list;
	/* QDIO buffer handling */
	/* QDIO buffer handling */
	struct qeth_qdio_info qdio;
	struct qeth_qdio_info qdio;
@@ -1034,11 +1037,8 @@ struct net_device *qeth_clone_netdev(struct net_device *orig);
struct qeth_card *qeth_get_card_by_busid(char *bus_id);
struct qeth_card *qeth_get_card_by_busid(char *bus_id);
void qeth_set_allowed_threads(struct qeth_card *, unsigned long , int);
void qeth_set_allowed_threads(struct qeth_card *, unsigned long , int);
int qeth_threads_running(struct qeth_card *, unsigned long);
int qeth_threads_running(struct qeth_card *, unsigned long);
int qeth_core_hardsetup_card(struct qeth_card *card, bool *carrier_ok);
int qeth_stop_channel(struct qeth_channel *channel);
int qeth_set_offline(struct qeth_card *card, bool resetting);
int qeth_set_offline(struct qeth_card *card, bool resetting);


void qeth_print_status_message(struct qeth_card *);
int qeth_send_ipa_cmd(struct qeth_card *, struct qeth_cmd_buffer *,
int qeth_send_ipa_cmd(struct qeth_card *, struct qeth_cmd_buffer *,
		  int (*reply_cb)
		  int (*reply_cb)
		  (struct qeth_card *, struct qeth_reply *, unsigned long),
		  (struct qeth_card *, struct qeth_reply *, unsigned long),
@@ -1062,12 +1062,7 @@ void qeth_notify_cmd(struct qeth_cmd_buffer *iob, int reason);
void qeth_put_cmd(struct qeth_cmd_buffer *iob);
void qeth_put_cmd(struct qeth_cmd_buffer *iob);


int qeth_schedule_recovery(struct qeth_card *card);
int qeth_schedule_recovery(struct qeth_card *card);
void qeth_flush_local_addrs(struct qeth_card *card);
int qeth_poll(struct napi_struct *napi, int budget);
int qeth_poll(struct napi_struct *napi, int budget);
void qeth_clear_ipacmd_list(struct qeth_card *);
int qeth_qdio_clear_card(struct qeth_card *, int);
void qeth_clear_working_pool_list(struct qeth_card *);
void qeth_drain_output_queues(struct qeth_card *card);
void qeth_setadp_promisc_mode(struct qeth_card *card, bool enable);
void qeth_setadp_promisc_mode(struct qeth_card *card, bool enable);
int qeth_setadpparms_change_macaddr(struct qeth_card *);
int qeth_setadpparms_change_macaddr(struct qeth_card *);
void qeth_tx_timeout(struct net_device *, unsigned int txqueue);
void qeth_tx_timeout(struct net_device *, unsigned int txqueue);
@@ -1091,7 +1086,6 @@ int qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
void qeth_dbf_longtext(debug_info_t *id, int level, char *text, ...);
void qeth_dbf_longtext(debug_info_t *id, int level, char *text, ...);
int qeth_configure_cq(struct qeth_card *, enum qeth_cq);
int qeth_configure_cq(struct qeth_card *, enum qeth_cq);
int qeth_hw_trap(struct qeth_card *, enum qeth_diags_trap_action);
int qeth_hw_trap(struct qeth_card *, enum qeth_diags_trap_action);
void qeth_trace_features(struct qeth_card *);
int qeth_setassparms_cb(struct qeth_card *, struct qeth_reply *, unsigned long);
int qeth_setassparms_cb(struct qeth_card *, struct qeth_reply *, unsigned long);
int qeth_setup_netdev(struct qeth_card *card);
int qeth_setup_netdev(struct qeth_card *card);
int qeth_set_features(struct net_device *, netdev_features_t);
int qeth_set_features(struct net_device *, netdev_features_t);
+52 −19
Original line number Original line Diff line number Diff line
@@ -201,7 +201,7 @@ int qeth_threads_running(struct qeth_card *card, unsigned long threads)
}
}
EXPORT_SYMBOL_GPL(qeth_threads_running);
EXPORT_SYMBOL_GPL(qeth_threads_running);


void qeth_clear_working_pool_list(struct qeth_card *card)
static void qeth_clear_working_pool_list(struct qeth_card *card)
{
{
	struct qeth_buffer_pool_entry *pool_entry, *tmp;
	struct qeth_buffer_pool_entry *pool_entry, *tmp;
	struct qeth_qdio_q *queue = card->qdio.in_q;
	struct qeth_qdio_q *queue = card->qdio.in_q;
@@ -216,7 +216,6 @@ void qeth_clear_working_pool_list(struct qeth_card *card)
	for (i = 0; i < ARRAY_SIZE(queue->bufs); i++)
	for (i = 0; i < ARRAY_SIZE(queue->bufs); i++)
		queue->bufs[i].pool_entry = NULL;
		queue->bufs[i].pool_entry = NULL;
}
}
EXPORT_SYMBOL_GPL(qeth_clear_working_pool_list);


static void qeth_free_pool_entry(struct qeth_buffer_pool_entry *entry)
static void qeth_free_pool_entry(struct qeth_buffer_pool_entry *entry)
{
{
@@ -658,12 +657,11 @@ static void qeth_flush_local_addrs6(struct qeth_card *card)
	spin_unlock_irq(&card->local_addrs6_lock);
	spin_unlock_irq(&card->local_addrs6_lock);
}
}


void qeth_flush_local_addrs(struct qeth_card *card)
static void qeth_flush_local_addrs(struct qeth_card *card)
{
{
	qeth_flush_local_addrs4(card);
	qeth_flush_local_addrs4(card);
	qeth_flush_local_addrs6(card);
	qeth_flush_local_addrs6(card);
}
}
EXPORT_SYMBOL_GPL(qeth_flush_local_addrs);


static void qeth_add_local_addrs4(struct qeth_card *card,
static void qeth_add_local_addrs4(struct qeth_card *card,
				  struct qeth_ipacmd_local_addrs4 *cmd)
				  struct qeth_ipacmd_local_addrs4 *cmd)
@@ -965,7 +963,7 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card,
	}
	}
}
}


void qeth_clear_ipacmd_list(struct qeth_card *card)
static void qeth_clear_ipacmd_list(struct qeth_card *card)
{
{
	struct qeth_cmd_buffer *iob;
	struct qeth_cmd_buffer *iob;
	unsigned long flags;
	unsigned long flags;
@@ -977,7 +975,6 @@ void qeth_clear_ipacmd_list(struct qeth_card *card)
		qeth_notify_cmd(iob, -ECANCELED);
		qeth_notify_cmd(iob, -ECANCELED);
	spin_unlock_irqrestore(&card->lock, flags);
	spin_unlock_irqrestore(&card->lock, flags);
}
}
EXPORT_SYMBOL_GPL(qeth_clear_ipacmd_list);


static int qeth_check_idx_response(struct qeth_card *card,
static int qeth_check_idx_response(struct qeth_card *card,
	unsigned char *buffer)
	unsigned char *buffer)
@@ -1502,7 +1499,7 @@ static void qeth_drain_output_queue(struct qeth_qdio_out_q *q, bool free)
	}
	}
}
}


void qeth_drain_output_queues(struct qeth_card *card)
static void qeth_drain_output_queues(struct qeth_card *card)
{
{
	int i;
	int i;


@@ -1513,7 +1510,6 @@ void qeth_drain_output_queues(struct qeth_card *card)
			qeth_drain_output_queue(card->qdio.out_qs[i], false);
			qeth_drain_output_queue(card->qdio.out_qs[i], false);
	}
	}
}
}
EXPORT_SYMBOL_GPL(qeth_drain_output_queues);


static int qeth_osa_set_output_queues(struct qeth_card *card, bool single)
static int qeth_osa_set_output_queues(struct qeth_card *card, bool single)
{
{
@@ -1754,7 +1750,7 @@ static int qeth_halt_channel(struct qeth_card *card,
	return 0;
	return 0;
}
}


int qeth_stop_channel(struct qeth_channel *channel)
static int qeth_stop_channel(struct qeth_channel *channel)
{
{
	struct ccw_device *cdev = channel->ccwdev;
	struct ccw_device *cdev = channel->ccwdev;
	int rc;
	int rc;
@@ -1772,7 +1768,6 @@ int qeth_stop_channel(struct qeth_channel *channel)


	return rc;
	return rc;
}
}
EXPORT_SYMBOL_GPL(qeth_stop_channel);


static int qeth_start_channel(struct qeth_channel *channel)
static int qeth_start_channel(struct qeth_channel *channel)
{
{
@@ -1842,7 +1837,7 @@ static int qeth_clear_halt_card(struct qeth_card *card, int halt)
	return qeth_clear_channels(card);
	return qeth_clear_channels(card);
}
}


int qeth_qdio_clear_card(struct qeth_card *card, int use_halt)
static int qeth_qdio_clear_card(struct qeth_card *card, int use_halt)
{
{
	int rc = 0;
	int rc = 0;


@@ -1870,7 +1865,6 @@ int qeth_qdio_clear_card(struct qeth_card *card, int use_halt)
		QETH_CARD_TEXT_(card, 3, "2err%d", rc);
		QETH_CARD_TEXT_(card, 3, "2err%d", rc);
	return rc;
	return rc;
}
}
EXPORT_SYMBOL_GPL(qeth_qdio_clear_card);


static enum qeth_discipline_id qeth_vm_detect_layer(struct qeth_card *card)
static enum qeth_discipline_id qeth_vm_detect_layer(struct qeth_card *card)
{
{
@@ -2867,7 +2861,7 @@ static int qeth_mpc_initialize(struct qeth_card *card)
	return 0;
	return 0;
}
}


void qeth_print_status_message(struct qeth_card *card)
static void qeth_print_status_message(struct qeth_card *card)
{
{
	switch (card->info.type) {
	switch (card->info.type) {
	case QETH_CARD_TYPE_OSD:
	case QETH_CARD_TYPE_OSD:
@@ -2908,7 +2902,6 @@ void qeth_print_status_message(struct qeth_card *card)
		 (card->info.mcl_level[0]) ? ")" : "",
		 (card->info.mcl_level[0]) ? ")" : "",
		 qeth_get_cardname_short(card));
		 qeth_get_cardname_short(card));
}
}
EXPORT_SYMBOL_GPL(qeth_print_status_message);


static void qeth_initialize_working_pool_list(struct qeth_card *card)
static void qeth_initialize_working_pool_list(struct qeth_card *card)
{
{
@@ -5124,7 +5117,7 @@ static void qeth_core_free_card(struct qeth_card *card)
	kfree(card);
	kfree(card);
}
}


void qeth_trace_features(struct qeth_card *card)
static void qeth_trace_features(struct qeth_card *card)
{
{
	QETH_CARD_TEXT(card, 2, "features");
	QETH_CARD_TEXT(card, 2, "features");
	QETH_CARD_HEX(card, 2, &card->options.ipa4, sizeof(card->options.ipa4));
	QETH_CARD_HEX(card, 2, &card->options.ipa4, sizeof(card->options.ipa4));
@@ -5133,7 +5126,6 @@ void qeth_trace_features(struct qeth_card *card)
	QETH_CARD_HEX(card, 2, &card->info.diagass_support,
	QETH_CARD_HEX(card, 2, &card->info.diagass_support,
		      sizeof(card->info.diagass_support));
		      sizeof(card->info.diagass_support));
}
}
EXPORT_SYMBOL_GPL(qeth_trace_features);


static struct ccw_device_id qeth_ids[] = {
static struct ccw_device_id qeth_ids[] = {
	{CCW_DEVICE_DEVTYPE(0x1731, 0x01, 0x1732, 0x01),
	{CCW_DEVICE_DEVTYPE(0x1731, 0x01, 0x1732, 0x01),
@@ -5164,7 +5156,7 @@ static struct ccw_driver qeth_ccw_driver = {
	.remove = ccwgroup_remove_ccwdev,
	.remove = ccwgroup_remove_ccwdev,
};
};


int qeth_core_hardsetup_card(struct qeth_card *card, bool *carrier_ok)
static int qeth_hardsetup_card(struct qeth_card *card, bool *carrier_ok)
{
{
	int retries = 3;
	int retries = 3;
	int rc;
	int rc;
@@ -5278,6 +5270,8 @@ int qeth_core_hardsetup_card(struct qeth_card *card, bool *carrier_ok)
			QETH_CARD_TEXT_(card, 2, "8err%d", rc);
			QETH_CARD_TEXT_(card, 2, "8err%d", rc);
	}
	}


	qeth_trace_features(card);

	if (!qeth_is_diagass_supported(card, QETH_DIAGS_CMD_TRAP) ||
	if (!qeth_is_diagass_supported(card, QETH_DIAGS_CMD_TRAP) ||
	    (card->info.hwtrap && qeth_hw_trap(card, QETH_DIAGS_TRAP_ARM)))
	    (card->info.hwtrap && qeth_hw_trap(card, QETH_DIAGS_TRAP_ARM)))
		card->info.hwtrap = 0;
		card->info.hwtrap = 0;
@@ -5303,21 +5297,49 @@ int qeth_core_hardsetup_card(struct qeth_card *card, bool *carrier_ok)
			 CARD_DEVID(card), rc);
			 CARD_DEVID(card), rc);
	return rc;
	return rc;
}
}
EXPORT_SYMBOL_GPL(qeth_core_hardsetup_card);


static int qeth_set_online(struct qeth_card *card)
static int qeth_set_online(struct qeth_card *card)
{
{
	bool carrier_ok;
	int rc;
	int rc;


	mutex_lock(&card->discipline_mutex);
	mutex_lock(&card->discipline_mutex);
	mutex_lock(&card->conf_mutex);
	mutex_lock(&card->conf_mutex);
	QETH_CARD_TEXT(card, 2, "setonlin");
	QETH_CARD_TEXT(card, 2, "setonlin");


	rc = card->discipline->set_online(card);
	rc = qeth_hardsetup_card(card, &carrier_ok);
	if (rc) {
		QETH_CARD_TEXT_(card, 2, "2err%04x", rc);
		rc = -ENODEV;
		goto err_hardsetup;
	}

	qeth_print_status_message(card);

	rc = card->discipline->set_online(card, carrier_ok);
	if (rc)
		goto err_online;

	/* let user_space know that device is online */
	kobject_uevent(&card->gdev->dev.kobj, KOBJ_CHANGE);


	mutex_unlock(&card->conf_mutex);
	mutex_unlock(&card->conf_mutex);
	mutex_unlock(&card->discipline_mutex);
	mutex_unlock(&card->discipline_mutex);
	return 0;

err_online:
err_hardsetup:
	qeth_qdio_clear_card(card, 0);
	qeth_clear_working_pool_list(card);
	qeth_flush_local_addrs(card);

	qeth_stop_channel(&card->data);
	qeth_stop_channel(&card->write);
	qeth_stop_channel(&card->read);
	qdio_free(CARD_DDEV(card));


	mutex_unlock(&card->conf_mutex);
	mutex_unlock(&card->discipline_mutex);
	return rc;
	return rc;
}
}


@@ -5334,6 +5356,9 @@ int qeth_set_offline(struct qeth_card *card, bool resetting)
		card->info.hwtrap = 1;
		card->info.hwtrap = 1;
	}
	}


	/* cancel any stalled cmd that might block the rtnl: */
	qeth_clear_ipacmd_list(card);

	rtnl_lock();
	rtnl_lock();
	card->info.open_when_online = card->dev->flags & IFF_UP;
	card->info.open_when_online = card->dev->flags & IFF_UP;
	dev_close(card->dev);
	dev_close(card->dev);
@@ -5341,8 +5366,16 @@ int qeth_set_offline(struct qeth_card *card, bool resetting)
	netif_carrier_off(card->dev);
	netif_carrier_off(card->dev);
	rtnl_unlock();
	rtnl_unlock();


	cancel_work_sync(&card->rx_mode_work);

	card->discipline->set_offline(card);
	card->discipline->set_offline(card);


	qeth_qdio_clear_card(card, 0);
	qeth_drain_output_queues(card);
	qeth_clear_working_pool_list(card);
	qeth_flush_local_addrs(card);
	card->info.promisc_mode = 0;

	rc  = qeth_stop_channel(&card->data);
	rc  = qeth_stop_channel(&card->data);
	rc2 = qeth_stop_channel(&card->write);
	rc2 = qeth_stop_channel(&card->write);
	rc3 = qeth_stop_channel(&card->read);
	rc3 = qeth_stop_channel(&card->read);
+34 −31
Original line number Original line Diff line number Diff line
@@ -103,21 +103,21 @@ static ssize_t qeth_dev_portno_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
		struct device_attribute *attr, const char *buf, size_t count)
{
{
	struct qeth_card *card = dev_get_drvdata(dev);
	struct qeth_card *card = dev_get_drvdata(dev);
	char *tmp;
	unsigned int portno, limit;
	unsigned int portno, limit;
	int rc = 0;
	int rc = 0;


	rc = kstrtouint(buf, 16, &portno);
	if (rc)
		return rc;
	if (portno > QETH_MAX_PORTNO)
		return -EINVAL;

	mutex_lock(&card->conf_mutex);
	mutex_lock(&card->conf_mutex);
	if (card->state != CARD_STATE_DOWN) {
	if (card->state != CARD_STATE_DOWN) {
		rc = -EPERM;
		rc = -EPERM;
		goto out;
		goto out;
	}
	}


	portno = simple_strtoul(buf, &tmp, 16);
	if (portno > QETH_MAX_PORTNO) {
		rc = -EINVAL;
		goto out;
	}
	limit = (card->ssqd.pcnt ? card->ssqd.pcnt - 1 : card->ssqd.pcnt);
	limit = (card->ssqd.pcnt ? card->ssqd.pcnt - 1 : card->ssqd.pcnt);
	if (portno > limit) {
	if (portno > limit) {
		rc = -EINVAL;
		rc = -EINVAL;
@@ -248,19 +248,19 @@ static ssize_t qeth_dev_bufcnt_store(struct device *dev,
{
{
	struct qeth_card *card = dev_get_drvdata(dev);
	struct qeth_card *card = dev_get_drvdata(dev);
	unsigned int cnt;
	unsigned int cnt;
	char *tmp;
	int rc = 0;
	int rc = 0;


	rc = kstrtouint(buf, 10, &cnt);
	if (rc)
		return rc;

	mutex_lock(&card->conf_mutex);
	mutex_lock(&card->conf_mutex);
	if (card->state != CARD_STATE_DOWN) {
	if (card->state != CARD_STATE_DOWN) {
		rc = -EPERM;
		rc = -EPERM;
		goto out;
		goto out;
	}
	}


	cnt = simple_strtoul(buf, &tmp, 10);
	cnt = clamp(cnt, QETH_IN_BUF_COUNT_MIN, QETH_IN_BUF_COUNT_MAX);
	cnt = (cnt < QETH_IN_BUF_COUNT_MIN) ? QETH_IN_BUF_COUNT_MIN :
		((cnt > QETH_IN_BUF_COUNT_MAX) ? QETH_IN_BUF_COUNT_MAX : cnt);

	rc = qeth_resize_buffer_pool(card, cnt);
	rc = qeth_resize_buffer_pool(card, cnt);


out:
out:
@@ -341,18 +341,15 @@ static ssize_t qeth_dev_layer2_store(struct device *dev,
{
{
	struct qeth_card *card = dev_get_drvdata(dev);
	struct qeth_card *card = dev_get_drvdata(dev);
	struct net_device *ndev;
	struct net_device *ndev;
	char *tmp;
	int i, rc = 0;
	enum qeth_discipline_id newdis;
	enum qeth_discipline_id newdis;
	unsigned int input;
	int rc;


	mutex_lock(&card->discipline_mutex);
	rc = kstrtouint(buf, 16, &input);
	if (card->state != CARD_STATE_DOWN) {
	if (rc)
		rc = -EPERM;
		return rc;
		goto out;
	}


	i = simple_strtoul(buf, &tmp, 16);
	switch (input) {
	switch (i) {
	case 0:
	case 0:
		newdis = QETH_DISCIPLINE_LAYER3;
		newdis = QETH_DISCIPLINE_LAYER3;
		break;
		break;
@@ -360,7 +357,12 @@ static ssize_t qeth_dev_layer2_store(struct device *dev,
		newdis = QETH_DISCIPLINE_LAYER2;
		newdis = QETH_DISCIPLINE_LAYER2;
		break;
		break;
	default:
	default:
		rc = -EINVAL;
		return -EINVAL;
	}

	mutex_lock(&card->discipline_mutex);
	if (card->state != CARD_STATE_DOWN) {
		rc = -EPERM;
		goto out;
		goto out;
	}
	}


@@ -551,20 +553,21 @@ static DEVICE_ATTR(hw_trap, 0644, qeth_hw_trap_show,
static ssize_t qeth_dev_blkt_store(struct qeth_card *card,
static ssize_t qeth_dev_blkt_store(struct qeth_card *card,
		const char *buf, size_t count, int *value, int max_value)
		const char *buf, size_t count, int *value, int max_value)
{
{
	char *tmp;
	unsigned int input;
	int i, rc = 0;
	int rc;

	rc = kstrtouint(buf, 10, &input);
	if (rc)
		return rc;

	if (input > max_value)
		return -EINVAL;


	mutex_lock(&card->conf_mutex);
	mutex_lock(&card->conf_mutex);
	if (card->state != CARD_STATE_DOWN) {
	if (card->state != CARD_STATE_DOWN)
		rc = -EPERM;
		rc = -EPERM;
		goto out;
	}
	i = simple_strtoul(buf, &tmp, 10);
	if (i <= max_value)
		*value = i;
	else
	else
		rc = -EINVAL;
		*value = input;
out:
	mutex_unlock(&card->conf_mutex);
	mutex_unlock(&card->conf_mutex);
	return rc ? rc : count;
	return rc ? rc : count;
}
}
+7 −0
Original line number Original line Diff line number Diff line
@@ -31,4 +31,11 @@ struct qeth_mac {
	struct hlist_node hnode;
	struct hlist_node hnode;
};
};


static inline bool qeth_bridgeport_is_in_use(struct qeth_card *card)
{
	return card->options.sbp.role ||
	       card->options.sbp.reflect_promisc ||
	       card->options.sbp.hostnotification;
}

#endif /* __QETH_L2_H__ */
#endif /* __QETH_L2_H__ */
+181 −231
Original line number Original line Diff line number Diff line
@@ -28,17 +28,6 @@
#include "qeth_core.h"
#include "qeth_core.h"
#include "qeth_l2.h"
#include "qeth_l2.h"


static void qeth_bridgeport_query_support(struct qeth_card *card);
static void qeth_bridge_state_change(struct qeth_card *card,
					struct qeth_ipa_cmd *cmd);
static void qeth_addr_change_event(struct qeth_card *card,
				   struct qeth_ipa_cmd *cmd);
static bool qeth_bridgeport_is_in_use(struct qeth_card *card);
static void qeth_l2_vnicc_set_defaults(struct qeth_card *card);
static void qeth_l2_vnicc_init(struct qeth_card *card);
static bool qeth_l2_vnicc_recover_timeout(struct qeth_card *card, u32 vnicc,
					  u32 *timeout);

static int qeth_l2_setdelmac_makerc(struct qeth_card *card, u16 retcode)
static int qeth_l2_setdelmac_makerc(struct qeth_card *card, u16 retcode)
{
{
	int rc;
	int rc;
@@ -304,36 +293,6 @@ static void qeth_l2_dev2br_fdb_flush(struct qeth_card *card)
				 card->dev, &info.info, NULL);
				 card->dev, &info.info, NULL);
}
}


static void qeth_l2_stop_card(struct qeth_card *card)
{
	struct qeth_priv *priv = netdev_priv(card->dev);

	QETH_CARD_TEXT(card, 2, "stopcard");

	qeth_set_allowed_threads(card, 0, 1);

	cancel_work_sync(&card->rx_mode_work);
	qeth_l2_drain_rx_mode_cache(card);

	if (card->state == CARD_STATE_SOFTSETUP) {
		qeth_clear_ipacmd_list(card);
		card->state = CARD_STATE_DOWN;
	}

	qeth_qdio_clear_card(card, 0);
	qeth_drain_output_queues(card);
	qeth_clear_working_pool_list(card);
	qeth_l2_set_pnso_mode(card, QETH_PNSO_NONE);
	qeth_flush_local_addrs(card);
	card->info.promisc_mode = 0;

	if (priv->brport_features & BR_LEARNING_SYNC) {
		rtnl_lock();
		qeth_l2_dev2br_fdb_flush(card);
		rtnl_unlock();
	}
}

static int qeth_l2_request_initial_mac(struct qeth_card *card)
static int qeth_l2_request_initial_mac(struct qeth_card *card)
{
{
	int rc = 0;
	int rc = 0;
@@ -617,49 +576,6 @@ static u16 qeth_l2_select_queue(struct net_device *dev, struct sk_buff *skb,
				 qeth_get_priority_queue(card, skb);
				 qeth_get_priority_queue(card, skb);
}
}


static const struct device_type qeth_l2_devtype = {
	.name = "qeth_layer2",
	.groups = qeth_l2_attr_groups,
};

static int qeth_l2_probe_device(struct ccwgroup_device *gdev)
{
	struct qeth_card *card = dev_get_drvdata(&gdev->dev);
	int rc;

	if (IS_OSN(card))
		dev_notice(&gdev->dev, "OSN support will be dropped in 2021\n");

	qeth_l2_vnicc_set_defaults(card);
	mutex_init(&card->sbp_lock);

	if (gdev->dev.type == &qeth_generic_devtype) {
		rc = qeth_l2_create_device_attributes(&gdev->dev);
		if (rc)
			return rc;
	}

	INIT_WORK(&card->rx_mode_work, qeth_l2_rx_mode_work);
	return 0;
}

static void qeth_l2_remove_device(struct ccwgroup_device *cgdev)
{
	struct qeth_card *card = dev_get_drvdata(&cgdev->dev);

	if (cgdev->dev.type == &qeth_generic_devtype)
		qeth_l2_remove_device_attributes(&cgdev->dev);
	qeth_set_allowed_threads(card, 0, 1);
	wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);

	if (cgdev->state == CCWGROUP_ONLINE)
		qeth_set_offline(card, false);

	cancel_work_sync(&card->close_dev_work);
	if (card->dev->reg_state == NETREG_REGISTERED)
		unregister_netdev(card->dev);
}

static void qeth_l2_set_rx_mode(struct net_device *dev)
static void qeth_l2_set_rx_mode(struct net_device *dev)
{
{
	struct qeth_card *card = dev->ml_priv;
	struct qeth_card *card = dev->ml_priv;
@@ -1140,134 +1056,6 @@ static void qeth_l2_enable_brport_features(struct qeth_card *card)
	}
	}
}
}


static int qeth_l2_set_online(struct qeth_card *card)
{
	struct ccwgroup_device *gdev = card->gdev;
	struct net_device *dev = card->dev;
	int rc = 0;
	bool carrier_ok;

	rc = qeth_core_hardsetup_card(card, &carrier_ok);
	if (rc) {
		QETH_CARD_TEXT_(card, 2, "2err%04x", rc);
		rc = -ENODEV;
		goto out_remove;
	}

	/* query before bridgeport_notification may be enabled */
	qeth_l2_detect_dev2br_support(card);

	mutex_lock(&card->sbp_lock);
	qeth_bridgeport_query_support(card);
	if (card->options.sbp.supported_funcs) {
		qeth_l2_setup_bridgeport_attrs(card);
		dev_info(&card->gdev->dev,
			 "The device represents a Bridge Capable Port\n");
	}
	mutex_unlock(&card->sbp_lock);

	qeth_l2_register_dev_addr(card);

	/* for the rx_bcast characteristic, init VNICC after setmac */
	qeth_l2_vnicc_init(card);

	qeth_trace_features(card);
	qeth_l2_trace_features(card);

	qeth_print_status_message(card);

	/* softsetup */
	QETH_CARD_TEXT(card, 2, "softsetp");

	card->state = CARD_STATE_SOFTSETUP;

	qeth_set_allowed_threads(card, 0xffffffff, 0);

	if (dev->reg_state != NETREG_REGISTERED) {
		rc = qeth_l2_setup_netdev(card);
		if (rc)
			goto out_remove;

		if (carrier_ok)
			netif_carrier_on(dev);
	} else {
		rtnl_lock();
		if (carrier_ok)
			netif_carrier_on(dev);
		else
			netif_carrier_off(dev);

		netif_device_attach(dev);
		qeth_enable_hw_features(dev);
		qeth_l2_enable_brport_features(card);

		if (card->info.open_when_online) {
			card->info.open_when_online = 0;
			dev_open(dev, NULL);
		}
		rtnl_unlock();
	}
	/* let user_space know that device is online */
	kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE);
	return 0;

out_remove:
	qeth_l2_stop_card(card);
	qeth_stop_channel(&card->data);
	qeth_stop_channel(&card->write);
	qeth_stop_channel(&card->read);
	qdio_free(CARD_DDEV(card));
	return rc;
}

static void qeth_l2_set_offline(struct qeth_card *card)
{
	qeth_l2_stop_card(card);
}

static int __init qeth_l2_init(void)
{
	pr_info("register layer 2 discipline\n");
	return 0;
}

static void __exit qeth_l2_exit(void)
{
	pr_info("unregister layer 2 discipline\n");
}

/* Returns zero if the command is successfully "consumed" */
static int qeth_l2_control_event(struct qeth_card *card,
					struct qeth_ipa_cmd *cmd)
{
	switch (cmd->hdr.command) {
	case IPA_CMD_SETBRIDGEPORT_OSA:
	case IPA_CMD_SETBRIDGEPORT_IQD:
		if (cmd->data.sbp.hdr.command_code ==
				IPA_SBP_BRIDGE_PORT_STATE_CHANGE) {
			qeth_bridge_state_change(card, cmd);
			return 0;
		} else
			return 1;
	case IPA_CMD_ADDRESS_CHANGE_NOTIF:
		qeth_addr_change_event(card, cmd);
		return 0;
	default:
		return 1;
	}
}

struct qeth_discipline qeth_l2_discipline = {
	.devtype = &qeth_l2_devtype,
	.setup = qeth_l2_probe_device,
	.remove = qeth_l2_remove_device,
	.set_online = qeth_l2_set_online,
	.set_offline = qeth_l2_set_offline,
	.do_ioctl = NULL,
	.control_event_handler = qeth_l2_control_event,
};
EXPORT_SYMBOL_GPL(qeth_l2_discipline);

#ifdef CONFIG_QETH_OSN
#ifdef CONFIG_QETH_OSN
static void qeth_osn_assist_cb(struct qeth_card *card,
static void qeth_osn_assist_cb(struct qeth_card *card,
			       struct qeth_cmd_buffer *iob,
			       struct qeth_cmd_buffer *iob,
@@ -1987,12 +1775,6 @@ int qeth_bridgeport_an_set(struct qeth_card *card, int enable)
	return rc;
	return rc;
}
}


static bool qeth_bridgeport_is_in_use(struct qeth_card *card)
{
	return (card->options.sbp.role || card->options.sbp.reflect_promisc ||
		card->options.sbp.hostnotification);
}

/* VNIC Characteristics support */
/* VNIC Characteristics support */


/* handle VNICC IPA command return codes; convert to error codes */
/* handle VNICC IPA command return codes; convert to error codes */
@@ -2138,6 +1920,19 @@ static int qeth_l2_vnicc_getset_timeout(struct qeth_card *card, u32 vnicc,
	return qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, timeout);
	return qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, timeout);
}
}


/* recover user timeout setting */
static bool qeth_l2_vnicc_recover_timeout(struct qeth_card *card, u32 vnicc,
					  u32 *timeout)
{
	if (card->options.vnicc.sup_chars & vnicc &&
	    card->options.vnicc.getset_timeout_sup & vnicc &&
	    !qeth_l2_vnicc_getset_timeout(card, vnicc, IPA_VNICC_SET_TIMEOUT,
					  timeout))
		return false;
	*timeout = QETH_VNICC_DEFAULT_TIMEOUT;
	return true;
}

/* set current VNICC flag state; called from sysfs store function */
/* set current VNICC flag state; called from sysfs store function */
int qeth_l2_vnicc_set_state(struct qeth_card *card, u32 vnicc, bool state)
int qeth_l2_vnicc_set_state(struct qeth_card *card, u32 vnicc, bool state)
{
{
@@ -2308,19 +2103,6 @@ bool qeth_bridgeport_allowed(struct qeth_card *card)
		!(priv->brport_features & BR_LEARNING_SYNC));
		!(priv->brport_features & BR_LEARNING_SYNC));
}
}


/* recover user timeout setting */
static bool qeth_l2_vnicc_recover_timeout(struct qeth_card *card, u32 vnicc,
					  u32 *timeout)
{
	if (card->options.vnicc.sup_chars & vnicc &&
	    card->options.vnicc.getset_timeout_sup & vnicc &&
	    !qeth_l2_vnicc_getset_timeout(card, vnicc, IPA_VNICC_SET_TIMEOUT,
					  timeout))
		return false;
	*timeout = QETH_VNICC_DEFAULT_TIMEOUT;
	return true;
}

/* recover user characteristic setting */
/* recover user characteristic setting */
static bool qeth_l2_vnicc_recover_char(struct qeth_card *card, u32 vnicc,
static bool qeth_l2_vnicc_recover_char(struct qeth_card *card, u32 vnicc,
				       bool enable)
				       bool enable)
@@ -2409,6 +2191,174 @@ static void qeth_l2_vnicc_set_defaults(struct qeth_card *card)
	card->options.vnicc.wanted_chars = QETH_VNICC_DEFAULT;
	card->options.vnicc.wanted_chars = QETH_VNICC_DEFAULT;
}
}


static const struct device_type qeth_l2_devtype = {
	.name = "qeth_layer2",
	.groups = qeth_l2_attr_groups,
};

static int qeth_l2_probe_device(struct ccwgroup_device *gdev)
{
	struct qeth_card *card = dev_get_drvdata(&gdev->dev);
	int rc;

	if (IS_OSN(card))
		dev_notice(&gdev->dev, "OSN support will be dropped in 2021\n");

	qeth_l2_vnicc_set_defaults(card);
	mutex_init(&card->sbp_lock);

	if (gdev->dev.type == &qeth_generic_devtype) {
		rc = qeth_l2_create_device_attributes(&gdev->dev);
		if (rc)
			return rc;
	}

	INIT_WORK(&card->rx_mode_work, qeth_l2_rx_mode_work);
	return 0;
}

static void qeth_l2_remove_device(struct ccwgroup_device *gdev)
{
	struct qeth_card *card = dev_get_drvdata(&gdev->dev);

	if (gdev->dev.type == &qeth_generic_devtype)
		qeth_l2_remove_device_attributes(&gdev->dev);
	qeth_set_allowed_threads(card, 0, 1);
	wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);

	if (gdev->state == CCWGROUP_ONLINE)
		qeth_set_offline(card, false);

	cancel_work_sync(&card->close_dev_work);
	if (card->dev->reg_state == NETREG_REGISTERED)
		unregister_netdev(card->dev);
}

static int qeth_l2_set_online(struct qeth_card *card, bool carrier_ok)
{
	struct net_device *dev = card->dev;
	int rc = 0;

	/* query before bridgeport_notification may be enabled */
	qeth_l2_detect_dev2br_support(card);

	mutex_lock(&card->sbp_lock);
	qeth_bridgeport_query_support(card);
	if (card->options.sbp.supported_funcs) {
		qeth_l2_setup_bridgeport_attrs(card);
		dev_info(&card->gdev->dev,
			 "The device represents a Bridge Capable Port\n");
	}
	mutex_unlock(&card->sbp_lock);

	qeth_l2_register_dev_addr(card);

	/* for the rx_bcast characteristic, init VNICC after setmac */
	qeth_l2_vnicc_init(card);

	qeth_l2_trace_features(card);

	/* softsetup */
	QETH_CARD_TEXT(card, 2, "softsetp");

	card->state = CARD_STATE_SOFTSETUP;

	qeth_set_allowed_threads(card, 0xffffffff, 0);

	if (dev->reg_state != NETREG_REGISTERED) {
		rc = qeth_l2_setup_netdev(card);
		if (rc)
			goto err_setup;

		if (carrier_ok)
			netif_carrier_on(dev);
	} else {
		rtnl_lock();
		if (carrier_ok)
			netif_carrier_on(dev);
		else
			netif_carrier_off(dev);

		netif_device_attach(dev);
		qeth_enable_hw_features(dev);
		qeth_l2_enable_brport_features(card);

		if (card->info.open_when_online) {
			card->info.open_when_online = 0;
			dev_open(dev, NULL);
		}
		rtnl_unlock();
	}
	return 0;

err_setup:
	qeth_set_allowed_threads(card, 0, 1);
	card->state = CARD_STATE_DOWN;
	return rc;
}

static void qeth_l2_set_offline(struct qeth_card *card)
{
	struct qeth_priv *priv = netdev_priv(card->dev);

	qeth_set_allowed_threads(card, 0, 1);
	qeth_l2_drain_rx_mode_cache(card);

	if (card->state == CARD_STATE_SOFTSETUP)
		card->state = CARD_STATE_DOWN;

	qeth_l2_set_pnso_mode(card, QETH_PNSO_NONE);
	if (priv->brport_features & BR_LEARNING_SYNC) {
		rtnl_lock();
		qeth_l2_dev2br_fdb_flush(card);
		rtnl_unlock();
	}
}

/* Returns zero if the command is successfully "consumed" */
static int qeth_l2_control_event(struct qeth_card *card,
				 struct qeth_ipa_cmd *cmd)
{
	switch (cmd->hdr.command) {
	case IPA_CMD_SETBRIDGEPORT_OSA:
	case IPA_CMD_SETBRIDGEPORT_IQD:
		if (cmd->data.sbp.hdr.command_code ==
		    IPA_SBP_BRIDGE_PORT_STATE_CHANGE) {
			qeth_bridge_state_change(card, cmd);
			return 0;
		}

		return 1;
	case IPA_CMD_ADDRESS_CHANGE_NOTIF:
		qeth_addr_change_event(card, cmd);
		return 0;
	default:
		return 1;
	}
}

struct qeth_discipline qeth_l2_discipline = {
	.devtype = &qeth_l2_devtype,
	.setup = qeth_l2_probe_device,
	.remove = qeth_l2_remove_device,
	.set_online = qeth_l2_set_online,
	.set_offline = qeth_l2_set_offline,
	.do_ioctl = NULL,
	.control_event_handler = qeth_l2_control_event,
};
EXPORT_SYMBOL_GPL(qeth_l2_discipline);

static int __init qeth_l2_init(void)
{
	pr_info("register layer 2 discipline\n");
	return 0;
}

static void __exit qeth_l2_exit(void)
{
	pr_info("unregister layer 2 discipline\n");
}

module_init(qeth_l2_init);
module_init(qeth_l2_init);
module_exit(qeth_l2_exit);
module_exit(qeth_l2_exit);
MODULE_AUTHOR("Frank Blaschka <frank.blaschka@de.ibm.com>");
MODULE_AUTHOR("Frank Blaschka <frank.blaschka@de.ibm.com>");
Loading