From 6bbfece5a4fbb4436eed124f4768473fff6e90e4 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Thu, 27 Feb 2020 18:08:09 +0100 Subject: s390/qeth: remove dead code in qeth_l3_iqd_read_initial_mac() card->info.unique_id is always 0 for IQD devices, so don't bother with copying it into the 0-initialized cmd. Signed-off-by: Julian Wiedmann Reviewed-by: Alexandra Winter Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l3_main.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 317d56647a4a..1c953981f73f 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -930,7 +930,6 @@ static int qeth_l3_iqd_read_initial_mac(struct qeth_card *card) { int rc = 0; struct qeth_cmd_buffer *iob; - struct qeth_ipa_cmd *cmd; QETH_CARD_TEXT(card, 2, "hsrmac"); @@ -938,9 +937,6 @@ static int qeth_l3_iqd_read_initial_mac(struct qeth_card *card) IPA_DATA_SIZEOF(create_destroy_addr)); if (!iob) return -ENOMEM; - cmd = __ipa_cmd(iob); - *((__u16 *) &cmd->data.create_destroy_addr.unique_id[6]) = - card->info.unique_id; rc = qeth_send_ipa_cmd(card, iob, qeth_l3_iqd_read_initial_mac_cb, NULL); -- cgit v1.2.3 From 9c6dc7af853382f119714889ba3de37b44a9fc0d Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Thu, 27 Feb 2020 18:08:10 +0100 Subject: s390/qeth: clean up CREATE_ADDR cmd code Properly define the cmd's struct to get rid of some casts and accesses at magic offsets. Signed-off-by: Julian Wiedmann Reviewed-by: Alexandra Winter Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_mpc.h | 5 +++-- drivers/s390/net/qeth_l3_main.c | 10 +++------- 2 files changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h index 3865f7258449..3a3cebdaf948 100644 --- a/drivers/s390/net/qeth_core_mpc.h +++ b/drivers/s390/net/qeth_core_mpc.h @@ -550,8 +550,9 @@ struct qeth_ipacmd_setadpparms { /* CREATE_ADDR IPA Command: ***********************************************/ struct qeth_create_destroy_address { - __u8 unique_id[8]; -} __attribute__ ((packed)); + u8 mac_addr[ETH_ALEN]; + u16 uid; +}; /* SET DIAGNOSTIC ASSIST IPA Command: *************************************/ diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 1c953981f73f..667a10d6495d 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -922,7 +922,7 @@ static int qeth_l3_iqd_read_initial_mac_cb(struct qeth_card *card, return -EIO; ether_addr_copy(card->dev->dev_addr, - cmd->data.create_destroy_addr.unique_id); + cmd->data.create_destroy_addr.mac_addr); return 0; } @@ -949,8 +949,7 @@ static int qeth_l3_get_unique_id_cb(struct qeth_card *card, struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data; if (cmd->hdr.return_code == 0) { - card->info.unique_id = *((__u16 *) - &cmd->data.create_destroy_addr.unique_id[6]); + card->info.unique_id = cmd->data.create_destroy_addr.uid; return 0; } @@ -964,7 +963,6 @@ static int qeth_l3_get_unique_id(struct qeth_card *card) { int rc = 0; struct qeth_cmd_buffer *iob; - struct qeth_ipa_cmd *cmd; QETH_CARD_TEXT(card, 2, "guniqeid"); @@ -978,10 +976,8 @@ static int qeth_l3_get_unique_id(struct qeth_card *card) IPA_DATA_SIZEOF(create_destroy_addr)); if (!iob) return -ENOMEM; - cmd = __ipa_cmd(iob); - *((__u16 *) &cmd->data.create_destroy_addr.unique_id[6]) = - card->info.unique_id; + __ipa_cmd(iob)->data.create_destroy_addr.uid = card->info.unique_id; rc = qeth_send_ipa_cmd(card, iob, qeth_l3_get_unique_id_cb, NULL); return rc; } -- cgit v1.2.3 From 13bf829581c7d7dadb5b531caa4de681ab03cbc1 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Thu, 27 Feb 2020 18:08:11 +0100 Subject: s390/qeth: validate device-provided MAC address It's good practice to not blindly trust what the HW offers. Signed-off-by: Julian Wiedmann Reviewed-by: Alexandra Winter Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l3_main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 667a10d6495d..1000e18c1090 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -920,6 +920,8 @@ static int qeth_l3_iqd_read_initial_mac_cb(struct qeth_card *card, if (cmd->hdr.return_code) return -EIO; + if (!is_valid_ether_addr(cmd->data.create_destroy_addr.mac_addr)) + return -EADDRNOTAVAIL; ether_addr_copy(card->dev->dev_addr, cmd->data.create_destroy_addr.mac_addr); -- cgit v1.2.3 From d74e5e84f25c825fe6ac78d6e7ca2139fc3f1cf6 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Thu, 27 Feb 2020 18:08:12 +0100 Subject: s390/qeth: remove unused cmd definitions Looks like these were never used, ever since the driver was initially added. Signed-off-by: Julian Wiedmann Reviewed-by: Alexandra Winter Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_mpc.h | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h index 3a3cebdaf948..6f304fdbb073 100644 --- a/drivers/s390/net/qeth_core_mpc.h +++ b/drivers/s390/net/qeth_core_mpc.h @@ -93,10 +93,6 @@ enum qeth_link_types { QETH_LINK_TYPE_LANE = 0x88, }; -/* - * Routing stuff - */ -#define RESET_ROUTING_FLAG 0x10 /* indicate that routing type shall be set */ enum qeth_routing_types { /* TODO: set to bit flag used in IPA Command */ NO_ROUTER = 0, @@ -427,7 +423,6 @@ struct qeth_ipacmd_setassparms { struct qeth_arp_cache_entry arp_entry; struct qeth_arp_query_data query_arp; struct qeth_tso_start_data tso; - __u8 ip[16]; } data; } __attribute__ ((packed)); -- cgit v1.2.3 From 7f23d55f4958d11577f6cf54d5d3baced25ecaea Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Thu, 27 Feb 2020 18:08:13 +0100 Subject: s390/qeth: reset seqnos on connection startup This let's us start every new IDX connection with clean seqnos. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 5efcaa43615b..ba1e50ed50ec 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -1624,17 +1624,16 @@ static void qeth_set_blkt_defaults(struct qeth_card *card) } } -static void qeth_init_tokens(struct qeth_card *card) +static void qeth_idx_init(struct qeth_card *card) { + memset(&card->seqno, 0, sizeof(card->seqno)); + card->token.issuer_rm_w = 0x00010103UL; card->token.cm_filter_w = 0x00010108UL; card->token.cm_connection_w = 0x0001010aUL; card->token.ulp_filter_w = 0x0001010bUL; card->token.ulp_connection_w = 0x0001010dUL; -} -static void qeth_init_func_level(struct qeth_card *card) -{ switch (card->info.type) { case QETH_CARD_TYPE_IQD: card->info.func_level = QETH_IDX_FUNC_LEVEL_IQD; @@ -4952,9 +4951,9 @@ retriable: else goto retry; } + qeth_determine_capabilities(card); - qeth_init_tokens(card); - qeth_init_func_level(card); + qeth_idx_init(card); rc = qeth_idx_activate_read_channel(card); if (rc == -EINTR) { -- cgit v1.2.3 From 3a5bad64db30a07459eb2f15ce6a4b995474350d Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Thu, 27 Feb 2020 18:08:14 +0100 Subject: s390/qeth: don't re-start read cmd when IDX has terminated Once the IDX connection is down, there's no point in trying to issue more IOs. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index ba1e50ed50ec..626da9698177 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -742,7 +742,7 @@ static void qeth_issue_next_read_cb(struct qeth_card *card, /* fall through */ default: qeth_clear_ipacmd_list(card); - goto out; + goto err_idx; } cmd = __ipa_reply(iob); @@ -795,8 +795,9 @@ out: memcpy(&card->seqno.pdu_hdr_ack, QETH_PDU_HEADER_SEQ_NO(iob->data), QETH_SEQ_NO_LENGTH); - qeth_put_cmd(iob); __qeth_issue_next_read(card); +err_idx: + qeth_put_cmd(iob); } static int qeth_set_thread_start_bit(struct qeth_card *card, -- cgit v1.2.3 From 3d35dbe6224e60a249dd492b0f757828db559c52 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Thu, 27 Feb 2020 18:08:15 +0100 Subject: s390/qeth: don't check for IFF_UP when scheduling napi Trust the napi_disable() in qeth_stop() to handle this. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 626da9698177..cbd2b4c46ea4 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -3405,8 +3405,7 @@ static void qeth_qdio_start_poll(struct ccw_device *ccwdev, int queue, { struct qeth_card *card = (struct qeth_card *)card_ptr; - if (card->dev->flags & IFF_UP) - napi_schedule_irqoff(&card->napi); + napi_schedule_irqoff(&card->napi); } int qeth_configure_cq(struct qeth_card *card, enum qeth_cq cq) -- cgit v1.2.3 From 562cf7736363c0b8a98f482cc7f6a19177d8fcea Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Thu, 27 Feb 2020 18:08:16 +0100 Subject: s390/qeth: support configurable RX copybreak Implement the ethtool hooks for the ETHTOOL_RX_COPYBREAK tunable. The copybreak is stored into netdev_priv, so that we automatically go back to the default value if the netdev is re-allocated. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 10 ++++++---- drivers/s390/net/qeth_core_main.c | 17 +++++++++++------ drivers/s390/net/qeth_ethtool.c | 31 +++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 10 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 9575a627a1e1..b7d64690ea38 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -189,6 +189,8 @@ struct qeth_vnicc_info { #define QETH_IQD_MIN_TXQ 2 /* One for ucast, one for mcast. */ #define QETH_IQD_MCAST_TXQ 0 #define QETH_IQD_MIN_UCAST_TXQ 1 + +#define QETH_RX_COPYBREAK (PAGE_SIZE >> 1) #define QETH_IN_BUF_SIZE_DEFAULT 65536 #define QETH_IN_BUF_COUNT_DEFAULT 64 #define QETH_IN_BUF_COUNT_HSDEFAULT 128 @@ -219,9 +221,6 @@ struct qeth_vnicc_info { #define QETH_HIGH_WATERMARK_PACK 5 #define QETH_WATERMARK_PACK_FUZZ 1 -/* large receive scatter gather copy break */ -#define QETH_RX_SG_CB (PAGE_SIZE >> 1) - struct qeth_hdr_layer3 { __u8 id; __u8 flags; @@ -711,7 +710,6 @@ struct qeth_card_options { struct qeth_vnicc_info vnicc; /* VNICC options */ int fake_broadcast; enum qeth_discipline_id layer; - int rx_sg_cb; enum qeth_ipa_isolation_modes isolation; enum qeth_ipa_isolation_modes prev_isolation; int sniffer; @@ -770,6 +768,10 @@ struct qeth_switch_info { __u32 settings; }; +struct qeth_priv { + unsigned int rx_copybreak; +}; + #define QETH_NAPI_WEIGHT NAPI_POLL_WEIGHT struct qeth_card { diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index cbd2b4c46ea4..1bcac50bb395 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -1257,7 +1257,6 @@ static void qeth_set_initial_options(struct qeth_card *card) { card->options.route4.type = NO_ROUTER; card->options.route6.type = NO_ROUTER; - card->options.rx_sg_cb = QETH_RX_SG_CB; card->options.isolation = ISOLATION_MODE_NONE; card->options.cq = QETH_CQ_DISABLED; card->options.layer = QETH_DISCIPLINE_UNDETERMINED; @@ -5268,6 +5267,7 @@ static int qeth_extract_skb(struct qeth_card *card, int *__offset) { struct qdio_buffer_element *element = *__element; + struct qeth_priv *priv = netdev_priv(card->dev); struct qdio_buffer *buffer = qethbuffer->buffer; struct napi_struct *napi = &card->napi; unsigned int linear_len = 0; @@ -5343,7 +5343,7 @@ next_packet: } use_rx_sg = (card->options.cq == QETH_CQ_ENABLED) || - (skb_len > card->options.rx_sg_cb && + (skb_len > READ_ONCE(priv->rx_copybreak) && !atomic_read(&card->force_alloc_skb) && !IS_OSN(card)); @@ -5892,25 +5892,30 @@ static void qeth_clear_dbf_list(void) static struct net_device *qeth_alloc_netdev(struct qeth_card *card) { struct net_device *dev; + struct qeth_priv *priv; switch (card->info.type) { case QETH_CARD_TYPE_IQD: - dev = alloc_netdev_mqs(0, "hsi%d", NET_NAME_UNKNOWN, + dev = alloc_netdev_mqs(sizeof(*priv), "hsi%d", NET_NAME_UNKNOWN, ether_setup, QETH_MAX_QUEUES, 1); break; case QETH_CARD_TYPE_OSM: - dev = alloc_etherdev(0); + dev = alloc_etherdev(sizeof(*priv)); break; case QETH_CARD_TYPE_OSN: - dev = alloc_netdev(0, "osn%d", NET_NAME_UNKNOWN, ether_setup); + dev = alloc_netdev(sizeof(*priv), "osn%d", NET_NAME_UNKNOWN, + ether_setup); break; default: - dev = alloc_etherdev_mqs(0, QETH_MAX_QUEUES, 1); + dev = alloc_etherdev_mqs(sizeof(*priv), QETH_MAX_QUEUES, 1); } if (!dev) return NULL; + priv = netdev_priv(dev); + priv->rx_copybreak = QETH_RX_COPYBREAK; + dev->ml_priv = card; dev->watchdog_timeo = QETH_TX_TIMEOUT; dev->min_mtu = IS_OSN(card) ? 64 : 576; diff --git a/drivers/s390/net/qeth_ethtool.c b/drivers/s390/net/qeth_ethtool.c index ab59bc975719..9052c72d5b8f 100644 --- a/drivers/s390/net/qeth_ethtool.c +++ b/drivers/s390/net/qeth_ethtool.c @@ -175,6 +175,35 @@ static void qeth_get_channels(struct net_device *dev, channels->combined_count = 0; } +static int qeth_get_tunable(struct net_device *dev, + const struct ethtool_tunable *tuna, void *data) +{ + struct qeth_priv *priv = netdev_priv(dev); + + switch (tuna->id) { + case ETHTOOL_RX_COPYBREAK: + *(u32 *)data = priv->rx_copybreak; + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int qeth_set_tunable(struct net_device *dev, + const struct ethtool_tunable *tuna, + const void *data) +{ + struct qeth_priv *priv = netdev_priv(dev); + + switch (tuna->id) { + case ETHTOOL_RX_COPYBREAK: + WRITE_ONCE(priv->rx_copybreak, *(u32 *)data); + return 0; + default: + return -EOPNOTSUPP; + } +} + /* Helper function to fill 'advertising' and 'supported' which are the same. */ /* Autoneg and full-duplex are supported and advertised unconditionally. */ /* Always advertise and support all speeds up to specified, and only one */ @@ -381,6 +410,8 @@ const struct ethtool_ops qeth_ethtool_ops = { .get_sset_count = qeth_get_sset_count, .get_drvinfo = qeth_get_drvinfo, .get_channels = qeth_get_channels, + .get_tunable = qeth_get_tunable, + .set_tunable = qeth_set_tunable, .get_link_ksettings = qeth_get_link_ksettings, }; -- cgit v1.2.3 From 13099824145a599c282dd9193d10577250f18382 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Fri, 6 Mar 2020 09:13:10 +0100 Subject: s390/qdio: add tighter controls for IRQ polling Once the call to qdio_establish() has completed, qdio is free to deliver data IRQs to the device driver's IRQ poll handler. For qeth (the only qdio driver that currently uses IRQ polling) this is problematic, since the IRQs can arrive before its NAPI instance is even registered. Calling napi_schedule() from qeth_qdio_start_poll() then crashes in various nasty ways. Until recently qeth checked for IFF_UP to drop such early interrupts, but that's fragile as well since it doesn't enforce any ordering. Fix this properly by bringing up the qdio device in IRQS_DISABLED mode, and have the driver explicitly opt-in to receive data IRQs. qeth does so from qeth_open(), which kick-starts a NAPI poll and then calls qdio_start_irq() from qeth_poll(). Also add a matching qdio_stop_irq() in qeth_stop() to switch the qdio dataplane back into a disabled state. Fixes: 3d35dbe6224e ("s390/qeth: don't check for IFF_UP when scheduling napi") CC: Qian Cai Reported-by: Qian Cai Signed-off-by: Julian Wiedmann Acked-by: Vasily Gorbik Signed-off-by: David S. Miller --- drivers/s390/cio/qdio_setup.c | 11 +++++++++-- drivers/s390/net/qeth_core_main.c | 5 ++--- 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index e115623b86b2..66e4bdca9d89 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -224,8 +224,15 @@ static void setup_queues(struct qdio_irq *irq_ptr, setup_queues_misc(q, irq_ptr, qdio_init->input_handler, i); q->is_input_q = 1; - q->u.in.queue_start_poll = qdio_init->queue_start_poll_array ? - qdio_init->queue_start_poll_array[i] : NULL; + if (qdio_init->queue_start_poll_array && + qdio_init->queue_start_poll_array[i]) { + q->u.in.queue_start_poll = + qdio_init->queue_start_poll_array[i]; + set_bit(QDIO_QUEUE_IRQS_DISABLED, + &q->u.in.queue_irq_state); + } else { + q->u.in.queue_start_poll = NULL; + } setup_storage_lists(q, irq_ptr, input_sbal_array, i); input_sbal_array += QDIO_MAX_BUFFERS_PER_Q; diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index fdc50543ce9a..37c17ad8ee25 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -6582,9 +6582,6 @@ int qeth_open(struct net_device *dev) QETH_CARD_TEXT(card, 4, "qethopen"); - if (qdio_stop_irq(CARD_DDEV(card), 0) < 0) - return -EIO; - card->data.state = CH_STATE_UP; netif_tx_start_all_queues(dev); @@ -6634,6 +6631,8 @@ int qeth_stop(struct net_device *dev) } napi_disable(&card->napi); + qdio_stop_irq(CARD_DDEV(card), 0); + return 0; } EXPORT_SYMBOL_GPL(qeth_stop); -- cgit v1.2.3 From 49f42f5d619486d876c71830fb3857d71105aa8e Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Fri, 6 Mar 2020 09:13:11 +0100 Subject: s390/qeth: remove VNICC callback parameter struct After recent cleanups this is just a complicated wrapper around an u32*. Signed-off-by: Julian Wiedmann Reviewed-by: Alexandra Winter Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l2_main.c | 29 ++++------------------------- 1 file changed, 4 insertions(+), 25 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 9972d96820f3..0bf5e7133229 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -1567,23 +1567,11 @@ static int qeth_l2_vnicc_makerc(struct qeth_card *card, u16 ipa_rc) return rc; } -/* generic VNICC request call back control */ -struct _qeth_l2_vnicc_request_cbctl { - struct { - union{ - u32 *sup_cmds; - u32 *timeout; - }; - } result; -}; - /* generic VNICC request call back */ static int qeth_l2_vnicc_request_cb(struct qeth_card *card, struct qeth_reply *reply, unsigned long data) { - struct _qeth_l2_vnicc_request_cbctl *cbctl = - (struct _qeth_l2_vnicc_request_cbctl *) reply->param; struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data; struct qeth_ipacmd_vnicc *rep = &cmd->data.vnicc; u32 sub_cmd = cmd->data.vnicc.hdr.sub_command; @@ -1596,9 +1584,9 @@ static int qeth_l2_vnicc_request_cb(struct qeth_card *card, card->options.vnicc.cur_chars = rep->vnicc_cmds.enabled; if (sub_cmd == IPA_VNICC_QUERY_CMDS) - *cbctl->result.sup_cmds = rep->data.query_cmds.sup_cmds; + *(u32 *)reply->param = rep->data.query_cmds.sup_cmds; else if (sub_cmd == IPA_VNICC_GET_TIMEOUT) - *cbctl->result.timeout = rep->data.getset_timeout.timeout; + *(u32 *)reply->param = rep->data.getset_timeout.timeout; return 0; } @@ -1639,7 +1627,6 @@ static int qeth_l2_vnicc_query_chars(struct qeth_card *card) static int qeth_l2_vnicc_query_cmds(struct qeth_card *card, u32 vnic_char, u32 *sup_cmds) { - struct _qeth_l2_vnicc_request_cbctl cbctl; struct qeth_cmd_buffer *iob; QETH_CARD_TEXT(card, 2, "vniccqcm"); @@ -1650,10 +1637,7 @@ static int qeth_l2_vnicc_query_cmds(struct qeth_card *card, u32 vnic_char, __ipa_cmd(iob)->data.vnicc.data.query_cmds.vnic_char = vnic_char; - /* prepare callback control */ - cbctl.result.sup_cmds = sup_cmds; - - return qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, &cbctl); + return qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, sup_cmds); } /* VNICC enable/disable characteristic request */ @@ -1677,7 +1661,6 @@ static int qeth_l2_vnicc_getset_timeout(struct qeth_card *card, u32 vnicc, u32 cmd, u32 *timeout) { struct qeth_vnicc_getset_timeout *getset_timeout; - struct _qeth_l2_vnicc_request_cbctl cbctl; struct qeth_cmd_buffer *iob; QETH_CARD_TEXT(card, 2, "vniccgst"); @@ -1692,11 +1675,7 @@ static int qeth_l2_vnicc_getset_timeout(struct qeth_card *card, u32 vnicc, if (cmd == IPA_VNICC_SET_TIMEOUT) getset_timeout->timeout = *timeout; - /* prepare callback control */ - if (cmd == IPA_VNICC_GET_TIMEOUT) - cbctl.result.timeout = timeout; - - return qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, &cbctl); + return qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, timeout); } /* set current VNICC flag state; called from sysfs store function */ -- cgit v1.2.3 From 714c9108851743bb718fbc1bfb81290f12a53854 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 18 Mar 2020 13:54:45 +0100 Subject: s390/qeth: use memory reserves to back RX buffers Use dev_alloc_page() for backing the RX buffers with pages. This way we pick up __GFP_MEMALLOC. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 6caa78d51bd1..be3f6295309b 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -244,7 +244,7 @@ static struct qeth_buffer_pool_entry *qeth_alloc_pool_entry(unsigned int pages) return NULL; for (i = 0; i < pages; i++) { - entry->elements[i] = alloc_page(GFP_KERNEL); + entry->elements[i] = __dev_alloc_page(GFP_KERNEL); if (!entry->elements[i]) { qeth_free_pool_entry(entry); @@ -2654,7 +2654,7 @@ static struct qeth_buffer_pool_entry *qeth_find_free_buffer_pool_entry( struct qeth_buffer_pool_entry, list); for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) { if (page_count(entry->elements[i]) > 1) { - struct page *page = alloc_page(GFP_ATOMIC); + struct page *page = dev_alloc_page(); if (!page) return NULL; -- cgit v1.2.3 From b413ff8a18d17b6ea3e4ca36d531257e12e9dd0f Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 18 Mar 2020 13:54:46 +0100 Subject: s390/qeth: use memory reserves in TX slow path When falling back to an allocation from the HW header cache, check if the skb is eligible for using memory reserves. This only makes a difference if the cache is empty and needs to be refilled. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 6 ++++-- drivers/s390/net/qeth_l2_main.c | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index be3f6295309b..767cef04c9d8 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -3705,6 +3705,7 @@ static int qeth_add_hw_header(struct qeth_qdio_out_q *queue, unsigned int hdr_len, unsigned int proto_len, unsigned int *elements) { + gfp_t gfp = GFP_ATOMIC | (skb_pfmemalloc(skb) ? __GFP_MEMALLOC : 0); const unsigned int contiguous = proto_len ? proto_len : 1; const unsigned int max_elements = queue->max_elements; unsigned int __elements; @@ -3760,10 +3761,11 @@ check_layout: *hdr = skb_push(skb, hdr_len); return hdr_len; } - /* fall back */ + + /* Fall back to cache element with known-good alignment: */ if (hdr_len + proto_len > QETH_HDR_CACHE_OBJ_SIZE) return -E2BIG; - *hdr = kmem_cache_alloc(qeth_core_header_cache, GFP_ATOMIC); + *hdr = kmem_cache_alloc(qeth_core_header_cache, gfp); if (!*hdr) return -ENOMEM; /* Copy protocol headers behind HW header: */ diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 4c8e93132e08..8ba4ac2a5b47 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -499,6 +499,7 @@ static void qeth_l2_rx_mode_work(struct work_struct *work) static int qeth_l2_xmit_osn(struct qeth_card *card, struct sk_buff *skb, struct qeth_qdio_out_q *queue) { + gfp_t gfp = GFP_ATOMIC | (skb_pfmemalloc(skb) ? __GFP_MEMALLOC : 0); struct qeth_hdr *hdr = (struct qeth_hdr *)skb->data; addr_t end = (addr_t)(skb->data + sizeof(*hdr)); addr_t start = (addr_t)skb->data; @@ -511,7 +512,7 @@ static int qeth_l2_xmit_osn(struct qeth_card *card, struct sk_buff *skb, if (qeth_get_elements_for_range(start, end) > 1) { /* Misaligned HW header, move it to its own buffer element. */ - hdr = kmem_cache_alloc(qeth_core_header_cache, GFP_ATOMIC); + hdr = kmem_cache_alloc(qeth_core_header_cache, gfp); if (!hdr) return -ENOMEM; hd_len = sizeof(*hdr); -- cgit v1.2.3 From 1c103cf819da7af23c96d968d3172b4358970502 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 18 Mar 2020 13:54:47 +0100 Subject: s390/qeth: remove prio-queueing support for z/VM NICs z/VM NICs don't offer HW QoS for TX rings. So just use netdev_pick_tx() to distribute the connections equally over all enabled TX queues. We start with just 1 enabled TX queue (this matches the typical configuration without prio-queueing). A follow-on patch will allow users to enable additional TX queues. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 1 + drivers/s390/net/qeth_core_main.c | 56 ++++++++++++++++++++++++--------------- drivers/s390/net/qeth_core_sys.c | 2 +- drivers/s390/net/qeth_l2_main.c | 8 +++++- drivers/s390/net/qeth_l3_main.c | 7 ++++- 5 files changed, 49 insertions(+), 25 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 962be94ed3ca..94cd39631eee 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -1053,6 +1053,7 @@ int qeth_configure_cq(struct qeth_card *, enum qeth_cq); 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_setup_netdev(struct qeth_card *card); int qeth_set_features(struct net_device *, netdev_features_t); void qeth_enable_hw_features(struct net_device *dev); netdev_features_t qeth_fix_features(struct net_device *, netdev_features_t); diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 767cef04c9d8..f13495d9209b 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -1244,9 +1244,12 @@ EXPORT_SYMBOL_GPL(qeth_drain_output_queues); static int qeth_osa_set_output_queues(struct qeth_card *card, bool single) { - unsigned int count = single ? 1 : card->dev->num_tx_queues; + unsigned int max = single ? 1 : card->dev->num_tx_queues; + unsigned int count; int rc; + count = IS_VM_NIC(card) ? min(max, card->dev->real_num_tx_queues) : max; + rtnl_lock(); rc = netif_set_real_num_tx_queues(card->dev, count); rtnl_unlock(); @@ -1254,16 +1257,16 @@ static int qeth_osa_set_output_queues(struct qeth_card *card, bool single) if (rc) return rc; - if (card->qdio.no_out_queues == count) + if (card->qdio.no_out_queues == max) return 0; if (atomic_read(&card->qdio.state) != QETH_QDIO_UNINITIALIZED) qeth_free_qdio_queues(card); - if (count == 1) + if (max == 1 && card->qdio.do_prio_queueing != QETH_PRIOQ_DEFAULT) dev_info(&card->gdev->dev, "Priority Queueing not supported\n"); - card->qdio.no_out_queues = count; + card->qdio.no_out_queues = max; return 0; } @@ -5987,22 +5990,8 @@ static struct net_device *qeth_alloc_netdev(struct qeth_card *card) SET_NETDEV_DEV(dev, &card->gdev->dev); netif_carrier_off(dev); - if (IS_OSN(card)) { - dev->ethtool_ops = &qeth_osn_ethtool_ops; - } else { - dev->ethtool_ops = &qeth_ethtool_ops; - dev->priv_flags &= ~IFF_TX_SKB_SHARING; - dev->hw_features |= NETIF_F_SG; - dev->vlan_features |= NETIF_F_SG; - if (IS_IQD(card)) { - dev->features |= NETIF_F_SG; - if (netif_set_real_num_tx_queues(dev, - QETH_IQD_MIN_TXQ)) { - free_netdev(dev); - return NULL; - } - } - } + dev->ethtool_ops = IS_OSN(card) ? &qeth_osn_ethtool_ops : + &qeth_ethtool_ops; return dev; } @@ -6018,6 +6007,28 @@ struct net_device *qeth_clone_netdev(struct net_device *orig) return clone; } +int qeth_setup_netdev(struct qeth_card *card) +{ + struct net_device *dev = card->dev; + unsigned int num_tx_queues; + + dev->priv_flags &= ~IFF_TX_SKB_SHARING; + dev->hw_features |= NETIF_F_SG; + dev->vlan_features |= NETIF_F_SG; + + if (IS_IQD(card)) { + dev->features |= NETIF_F_SG; + num_tx_queues = QETH_IQD_MIN_TXQ; + } else if (IS_VM_NIC(card)) { + num_tx_queues = 1; + } else { + num_tx_queues = dev->real_num_tx_queues; + } + + return netif_set_real_num_tx_queues(dev, num_tx_queues); +} +EXPORT_SYMBOL_GPL(qeth_setup_netdev); + static int qeth_core_probe_device(struct ccwgroup_device *gdev) { struct qeth_card *card; @@ -6057,12 +6068,13 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) goto err_card; } + qeth_determine_capabilities(card); + qeth_set_blkt_defaults(card); + card->qdio.no_out_queues = card->dev->num_tx_queues; rc = qeth_update_from_chp_desc(card); if (rc) goto err_chp_desc; - qeth_determine_capabilities(card); - qeth_set_blkt_defaults(card); enforced_disc = qeth_enforce_discipline(card); switch (enforced_disc) { diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index 78cae61bc924..533a7f26dbe1 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c @@ -176,7 +176,7 @@ static ssize_t qeth_dev_prioqing_store(struct device *dev, struct qeth_card *card = dev_get_drvdata(dev); int rc = 0; - if (IS_IQD(card)) + if (IS_IQD(card) || IS_VM_NIC(card)) return -EOPNOTSUPP; mutex_lock(&card->conf_mutex); diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 8ba4ac2a5b47..71eb2d9bfbb7 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -571,7 +571,9 @@ static u16 qeth_l2_select_queue(struct net_device *dev, struct sk_buff *skb, return qeth_iqd_select_queue(dev, skb, qeth_get_ether_cast_type(skb), sb_dev); - return qeth_get_priority_queue(card, skb); + + return IS_VM_NIC(card) ? netdev_pick_tx(dev, skb, sb_dev) : + qeth_get_priority_queue(card, skb); } static const struct device_type qeth_l2_devtype = { @@ -659,6 +661,10 @@ static int qeth_l2_setup_netdev(struct qeth_card *card, bool carrier_ok) goto add_napi; } + rc = qeth_setup_netdev(card); + if (rc) + return rc; + card->dev->needed_headroom = sizeof(struct qeth_hdr); card->dev->netdev_ops = &qeth_l2_netdev_ops; card->dev->priv_flags |= IFF_UNICAST_FLT; diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 8a803d6c9357..81ec0d2b7ea5 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -1880,7 +1880,8 @@ static u16 qeth_l3_osa_select_queue(struct net_device *dev, struct sk_buff *skb, { struct qeth_card *card = dev->ml_priv; - return qeth_get_priority_queue(card, skb); + return IS_VM_NIC(card) ? netdev_pick_tx(dev, skb, sb_dev) : + qeth_get_priority_queue(card, skb); } static const struct net_device_ops qeth_l3_netdev_ops = { @@ -1922,6 +1923,10 @@ static int qeth_l3_setup_netdev(struct qeth_card *card, bool carrier_ok) unsigned int headroom; int rc; + rc = qeth_setup_netdev(card); + if (rc) + return rc; + if (IS_OSD(card) || IS_OSX(card)) { if ((card->info.link_type == QETH_LINK_TYPE_LANE_TR) || (card->info.link_type == QETH_LINK_TYPE_HSTR)) { -- cgit v1.2.3 From fcc2df8b8777c960c8125bc157423c76415a5419 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 18 Mar 2020 13:54:48 +0100 Subject: s390/qeth: allow configuration of TX queues for z/VM NICs Add support for ETHTOOL_SCHANNELS to change the count of active TX queues. Since all TX queue structs are pre-allocated and -registered, we just need to trivially adjust dev->real_num_tx_queues. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_ethtool.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_ethtool.c b/drivers/s390/net/qeth_ethtool.c index 9052c72d5b8f..19b9c8302d36 100644 --- a/drivers/s390/net/qeth_ethtool.c +++ b/drivers/s390/net/qeth_ethtool.c @@ -175,6 +175,22 @@ static void qeth_get_channels(struct net_device *dev, channels->combined_count = 0; } +static int qeth_set_channels(struct net_device *dev, + struct ethtool_channels *channels) +{ + struct qeth_card *card = dev->ml_priv; + + if (IS_IQD(card) || !IS_VM_NIC(card)) + return -EOPNOTSUPP; + + if (channels->rx_count == 0 || channels->tx_count == 0) + return -EINVAL; + if (channels->tx_count > card->qdio.no_out_queues) + return -EINVAL; + + return netif_set_real_num_tx_queues(dev, channels->tx_count); +} + static int qeth_get_tunable(struct net_device *dev, const struct ethtool_tunable *tuna, void *data) { @@ -410,6 +426,7 @@ const struct ethtool_ops qeth_ethtool_ops = { .get_sset_count = qeth_get_sset_count, .get_drvinfo = qeth_get_drvinfo, .get_channels = qeth_get_channels, + .set_channels = qeth_set_channels, .get_tunable = qeth_get_tunable, .set_tunable = qeth_set_tunable, .get_link_ksettings = qeth_get_link_ksettings, -- cgit v1.2.3 From 66cddf101901a6cfcd21c840f0535e8f1c8c5186 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 18 Mar 2020 13:54:49 +0100 Subject: s390/qeth: allow configuration of TX queues for IQD devices Similar to the support for z/VM NICs, but we need to take extra care about the dedicated mcast queue: 1. netdev_pick_tx() is unaware of this limitation and might select the mcast txq. Catch this. 2. require at least _two_ TX queues - one for ucast, one for mcast. 3. when reducing the number of TX queues, there's a potential race where netdev_cap_txqueue() over-rules the selected txq index and falls back to index 0. This would place ucast traffic on the mcast queue, and result in TX errors. So for IQD, reject a reduction while the interface is running. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 6 +++++- drivers/s390/net/qeth_ethtool.c | 19 ++++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index f13495d9209b..aa493edc0082 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -6644,9 +6644,13 @@ EXPORT_SYMBOL_GPL(qeth_get_stats64); u16 qeth_iqd_select_queue(struct net_device *dev, struct sk_buff *skb, u8 cast_type, struct net_device *sb_dev) { + u16 txq; + if (cast_type != RTN_UNICAST) return QETH_IQD_MCAST_TXQ; - return QETH_IQD_MIN_UCAST_TXQ; + + txq = netdev_pick_tx(dev, skb, sb_dev); + return (txq == QETH_IQD_MCAST_TXQ) ? QETH_IQD_MIN_UCAST_TXQ : txq; } EXPORT_SYMBOL_GPL(qeth_iqd_select_queue); diff --git a/drivers/s390/net/qeth_ethtool.c b/drivers/s390/net/qeth_ethtool.c index 19b9c8302d36..715ee0015847 100644 --- a/drivers/s390/net/qeth_ethtool.c +++ b/drivers/s390/net/qeth_ethtool.c @@ -180,14 +180,27 @@ static int qeth_set_channels(struct net_device *dev, { struct qeth_card *card = dev->ml_priv; - if (IS_IQD(card) || !IS_VM_NIC(card)) - return -EOPNOTSUPP; - if (channels->rx_count == 0 || channels->tx_count == 0) return -EINVAL; if (channels->tx_count > card->qdio.no_out_queues) return -EINVAL; + if (IS_IQD(card)) { + if (channels->tx_count < QETH_IQD_MIN_TXQ) + return -EINVAL; + + /* Reject downgrade while running. It could push displaced + * ucast flows onto txq0, which is reserved for mcast. + */ + if (netif_running(dev) && + channels->tx_count < dev->real_num_tx_queues) + return -EPERM; + } else { + /* OSA still uses the legacy prio-queue mechanism: */ + if (!IS_VM_NIC(card)) + return -EOPNOTSUPP; + } + return netif_set_real_num_tx_queues(dev, channels->tx_count); } -- cgit v1.2.3 From 5d8ce41c6a878afac157a61299a9f810bf80995e Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 18 Mar 2020 13:54:50 +0100 Subject: s390/qeth: balance the TX queue selection for IQD devices For ucast traffic, qeth_iqd_select_queue() falls back to netdev_pick_tx(). This will potentially use skb_tx_hash() to distribute the flow over all active TX queues - so txq 0 is a valid selection, and qeth_iqd_select_queue() needs to check for this and put it on some other queue. As a result, the distribution for ucast flows is unbalanced and hits QETH_IQD_MIN_UCAST_TXQ heavier than the other queues. Open-coding a custom variant of skb_tx_hash() isn't an option, since netdev_pick_tx() also gives us eg. access to XPS. But we can pull a little trick: add a single TC class that excludes the mcast txq, and thus encourage skb_tx_hash() to not pick the mcast txq. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 1 + drivers/s390/net/qeth_core_main.c | 45 ++++++++++++++++++++++++++++++++++++++- drivers/s390/net/qeth_ethtool.c | 2 +- 3 files changed, 46 insertions(+), 2 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 94cd39631eee..b8b356aca674 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -1061,6 +1061,7 @@ netdev_features_t qeth_features_check(struct sk_buff *skb, struct net_device *dev, netdev_features_t features); void qeth_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats); +int qeth_set_real_num_tx_queues(struct qeth_card *card, unsigned int count); u16 qeth_iqd_select_queue(struct net_device *dev, struct sk_buff *skb, u8 cast_type, struct net_device *sb_dev); int qeth_open(struct net_device *dev); diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index aa493edc0082..e1d984c29e1f 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -6025,7 +6025,7 @@ int qeth_setup_netdev(struct qeth_card *card) num_tx_queues = dev->real_num_tx_queues; } - return netif_set_real_num_tx_queues(dev, num_tx_queues); + return qeth_set_real_num_tx_queues(card, num_tx_queues); } EXPORT_SYMBOL_GPL(qeth_setup_netdev); @@ -6641,6 +6641,47 @@ void qeth_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) } EXPORT_SYMBOL_GPL(qeth_get_stats64); +#define TC_IQD_UCAST 0 +static void qeth_iqd_set_prio_tc_map(struct net_device *dev, + unsigned int ucast_txqs) +{ + unsigned int prio; + + /* IQD requires mcast traffic to be placed on a dedicated queue, and + * qeth_iqd_select_queue() deals with this. + * For unicast traffic, we defer the queue selection to the stack. + * By installing a trivial prio map that spans over only the unicast + * queues, we can encourage the stack to spread the ucast traffic evenly + * without selecting the mcast queue. + */ + + /* One traffic class, spanning over all active ucast queues: */ + netdev_set_num_tc(dev, 1); + netdev_set_tc_queue(dev, TC_IQD_UCAST, ucast_txqs, + QETH_IQD_MIN_UCAST_TXQ); + + /* Map all priorities to this traffic class: */ + for (prio = 0; prio <= TC_BITMASK; prio++) + netdev_set_prio_tc_map(dev, prio, TC_IQD_UCAST); +} + +int qeth_set_real_num_tx_queues(struct qeth_card *card, unsigned int count) +{ + struct net_device *dev = card->dev; + int rc; + + /* Per netif_setup_tc(), adjust the mapping first: */ + if (IS_IQD(card)) + qeth_iqd_set_prio_tc_map(dev, count - 1); + + rc = netif_set_real_num_tx_queues(dev, count); + + if (rc && IS_IQD(card)) + qeth_iqd_set_prio_tc_map(dev, dev->real_num_tx_queues - 1); + + return rc; +} + u16 qeth_iqd_select_queue(struct net_device *dev, struct sk_buff *skb, u8 cast_type, struct net_device *sb_dev) { @@ -6648,6 +6689,8 @@ u16 qeth_iqd_select_queue(struct net_device *dev, struct sk_buff *skb, if (cast_type != RTN_UNICAST) return QETH_IQD_MCAST_TXQ; + if (dev->real_num_tx_queues == QETH_IQD_MIN_TXQ) + return QETH_IQD_MIN_UCAST_TXQ; txq = netdev_pick_tx(dev, skb, sb_dev); return (txq == QETH_IQD_MCAST_TXQ) ? QETH_IQD_MIN_UCAST_TXQ : txq; diff --git a/drivers/s390/net/qeth_ethtool.c b/drivers/s390/net/qeth_ethtool.c index 715ee0015847..079b695032ef 100644 --- a/drivers/s390/net/qeth_ethtool.c +++ b/drivers/s390/net/qeth_ethtool.c @@ -201,7 +201,7 @@ static int qeth_set_channels(struct net_device *dev, return -EOPNOTSUPP; } - return netif_set_real_num_tx_queues(dev, channels->tx_count); + return qeth_set_real_num_tx_queues(card, channels->tx_count); } static int qeth_get_tunable(struct net_device *dev, -- cgit v1.2.3 From 8d145da294a9371c050994bbe6fef98c91e3c072 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 18 Mar 2020 13:54:51 +0100 Subject: s390/qeth: add SW timestamping support for IQD devices This adds support for SOF_TIMESTAMPING_TX_SOFTWARE. No support for non-IQD devices, since they orphan the skb in their xmit path. To play nice with TX bulking, set the timestamp when the buffer that contains the skb(s) is actually flushed out to HW. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 6 +++++- drivers/s390/net/qeth_ethtool.c | 12 ++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index e1d984c29e1f..33796fe80a63 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -3355,6 +3355,7 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, for (i = index; i < index + count; ++i) { unsigned int bidx = QDIO_BUFNR(i); + struct sk_buff *skb; buf = queue->bufs[bidx]; buf->buffer->element[buf->next_element_to_fill - 1].eflags |= @@ -3363,8 +3364,11 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, if (queue->bufstates) queue->bufstates[bidx].user = buf; - if (IS_IQD(queue->card)) + if (IS_IQD(card)) { + skb_queue_walk(&buf->skb_list, skb) + skb_tx_timestamp(skb); continue; + } if (!queue->do_pack) { if ((atomic_read(&queue->used_buffers) >= diff --git a/drivers/s390/net/qeth_ethtool.c b/drivers/s390/net/qeth_ethtool.c index 079b695032ef..5cfa371b7426 100644 --- a/drivers/s390/net/qeth_ethtool.c +++ b/drivers/s390/net/qeth_ethtool.c @@ -204,6 +204,17 @@ static int qeth_set_channels(struct net_device *dev, return qeth_set_real_num_tx_queues(card, channels->tx_count); } +static int qeth_get_ts_info(struct net_device *dev, + struct ethtool_ts_info *info) +{ + struct qeth_card *card = dev->ml_priv; + + if (!IS_IQD(card)) + return -EOPNOTSUPP; + + return ethtool_op_get_ts_info(dev, info); +} + static int qeth_get_tunable(struct net_device *dev, const struct ethtool_tunable *tuna, void *data) { @@ -440,6 +451,7 @@ const struct ethtool_ops qeth_ethtool_ops = { .get_drvinfo = qeth_get_drvinfo, .get_channels = qeth_get_channels, .set_channels = qeth_set_channels, + .get_ts_info = qeth_get_ts_info, .get_tunable = qeth_get_tunable, .set_tunable = qeth_set_tunable, .get_link_ksettings = qeth_get_link_ksettings, -- cgit v1.2.3 From 54e73b9c0a88f71ce041a69471b7c4ef9a6a4407 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 18 Mar 2020 13:54:52 +0100 Subject: s390/qeth: don't report hard-coded driver version Versions are meaningless for an in-kernel driver. Instead use the UTS_RELEASE that is set by ethtool_get_drvinfo(). Cc: Leon Romanovsky Signed-off-by: Julian Wiedmann Reviewed-by: Leon Romanovsky Signed-off-by: David S. Miller --- drivers/s390/net/qeth_ethtool.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_ethtool.c b/drivers/s390/net/qeth_ethtool.c index 5cfa371b7426..31e019085fc3 100644 --- a/drivers/s390/net/qeth_ethtool.c +++ b/drivers/s390/net/qeth_ethtool.c @@ -153,7 +153,6 @@ static void qeth_get_drvinfo(struct net_device *dev, strlcpy(info->driver, IS_LAYER2(card) ? "qeth_l2" : "qeth_l3", sizeof(info->driver)); - strlcpy(info->version, "1.0", sizeof(info->version)); strlcpy(info->fw_version, card->info.mcl_level, sizeof(info->fw_version)); snprintf(info->bus_info, sizeof(info->bus_info), "%s/%s/%s", -- cgit v1.2.3 From 86e7a4e4afd5bb3b852f37fc8cb61bac2a1f19ce Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 18 Mar 2020 13:54:53 +0100 Subject: s390/qeth: add phys_to_virt() translation for AOB Data addresses in the AOB are absolute, and need to be translated before being fed into kmem_cache_free(). Currently this phys_to_virt() is a no-op. Also see commit 2db01da8d25f ("s390/qdio: fill SBALEs with absolute addresses"). Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 33796fe80a63..3f0b13ff580e 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -538,9 +538,10 @@ static void qeth_qdio_handle_aob(struct qeth_card *card, for (i = 0; i < aob->sb_count && i < QETH_MAX_BUFFER_ELEMENTS(card); i++) { - if (aob->sba[i] && buffer->is_header[i]) - kmem_cache_free(qeth_core_header_cache, - (void *) aob->sba[i]); + void *data = phys_to_virt(aob->sba[i]); + + if (data && buffer->is_header[i]) + kmem_cache_free(qeth_core_header_cache, data); } atomic_set(&buffer->state, QETH_QDIO_BUF_HANDLED_DELAYED); -- cgit v1.2.3 From 5bcd8ad9768391b59768f249c40a5ba34e5e43c6 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 18 Mar 2020 13:54:54 +0100 Subject: s390/qeth: remove gratuitous NULL checks qeth_do_ioctl() is only reached through our own net_device_ops, so we can trust that dev->ml_priv still contains what we put there earlier. qeth_bridgeport_an_set() is an internal function that doesn't require such sanity checks. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 3 --- drivers/s390/net/qeth_l2_main.c | 2 -- 2 files changed, 5 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 3f0b13ff580e..bd3adbb6ad50 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -6264,9 +6264,6 @@ int qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) struct mii_ioctl_data *mii_data; int rc = 0; - if (!card) - return -ENODEV; - switch (cmd) { case SIOC_QETH_ADP_SET_SNMP_CONTROL: rc = qeth_snmp_command(card, rq->ifr_ifru.ifru_data); diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 71eb2d9bfbb7..2aaf5e3779ce 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -1519,8 +1519,6 @@ int qeth_bridgeport_an_set(struct qeth_card *card, int enable) struct ccw_device *ddev; struct subchannel_id schid; - if (!card) - return -EINVAL; if (!card->options.sbp.supported_funcs) return -EOPNOTSUPP; ddev = CARD_DDEV(card); -- cgit v1.2.3 From cd652be52cd9d3cac816b27a518812eff7ef79eb Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 18 Mar 2020 13:54:55 +0100 Subject: s390/qeth: use dev->reg_state To check whether a netdevice has already been registered, look at NETREG_REGISTERED to replace some hacks I added a while ago. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 5 ----- drivers/s390/net/qeth_l2_main.c | 19 ++++++++----------- drivers/s390/net/qeth_l3_main.c | 22 +++++++++------------- 3 files changed, 17 insertions(+), 29 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index b8b356aca674..6eb431c194bd 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -847,11 +847,6 @@ struct qeth_trap_id { /*some helper functions*/ #define QETH_CARD_IFNAME(card) (((card)->dev)? (card)->dev->name : "") -static inline bool qeth_netdev_is_registered(struct net_device *dev) -{ - return dev->netdev_ops != NULL; -} - static inline u16 qeth_iqd_translate_txq(struct net_device *dev, u16 txq) { if (txq == QETH_IQD_MCAST_TXQ) diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 2aaf5e3779ce..73cb363b1fab 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -613,7 +613,7 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev) qeth_set_offline(card, false); cancel_work_sync(&card->close_dev_work); - if (qeth_netdev_is_registered(card->dev)) + if (card->dev->reg_state == NETREG_REGISTERED) unregister_netdev(card->dev); } @@ -651,7 +651,7 @@ static const struct net_device_ops qeth_osn_netdev_ops = { .ndo_tx_timeout = qeth_tx_timeout, }; -static int qeth_l2_setup_netdev(struct qeth_card *card, bool carrier_ok) +static int qeth_l2_setup_netdev(struct qeth_card *card) { int rc; @@ -711,13 +711,7 @@ static int qeth_l2_setup_netdev(struct qeth_card *card, bool carrier_ok) add_napi: netif_napi_add(card->dev, &card->napi, qeth_poll, QETH_NAPI_WEIGHT); - rc = register_netdev(card->dev); - if (!rc && carrier_ok) - netif_carrier_on(card->dev); - - if (rc) - card->dev->netdev_ops = NULL; - return rc; + return register_netdev(card->dev); } static void qeth_l2_trace_features(struct qeth_card *card) @@ -790,10 +784,13 @@ static int qeth_l2_set_online(struct qeth_card *card) qeth_set_allowed_threads(card, 0xffffffff, 0); - if (!qeth_netdev_is_registered(dev)) { - rc = qeth_l2_setup_netdev(card, carrier_ok); + 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) diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 81ec0d2b7ea5..83ae75cf1389 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -1918,7 +1918,7 @@ static const struct net_device_ops qeth_l3_osa_netdev_ops = { .ndo_neigh_setup = qeth_l3_neigh_setup, }; -static int qeth_l3_setup_netdev(struct qeth_card *card, bool carrier_ok) +static int qeth_l3_setup_netdev(struct qeth_card *card) { unsigned int headroom; int rc; @@ -1972,7 +1972,7 @@ static int qeth_l3_setup_netdev(struct qeth_card *card, bool carrier_ok) rc = qeth_l3_iqd_read_initial_mac(card); if (rc) - goto out; + return rc; } else return -ENODEV; @@ -1987,14 +1987,7 @@ static int qeth_l3_setup_netdev(struct qeth_card *card, bool carrier_ok) PAGE_SIZE * (QETH_MAX_BUFFER_ELEMENTS(card) - 1)); netif_napi_add(card->dev, &card->napi, qeth_poll, QETH_NAPI_WEIGHT); - rc = register_netdev(card->dev); - if (!rc && carrier_ok) - netif_carrier_on(card->dev); - -out: - if (rc) - card->dev->netdev_ops = NULL; - return rc; + return register_netdev(card->dev); } static const struct device_type qeth_l3_devtype = { @@ -2041,7 +2034,7 @@ static void qeth_l3_remove_device(struct ccwgroup_device *cgdev) qeth_set_offline(card, false); cancel_work_sync(&card->close_dev_work); - if (qeth_netdev_is_registered(card->dev)) + if (card->dev->reg_state == NETREG_REGISTERED) unregister_netdev(card->dev); flush_workqueue(card->cmd_wq); @@ -2088,10 +2081,13 @@ static int qeth_l3_set_online(struct qeth_card *card) qeth_set_allowed_threads(card, 0xffffffff, 0); qeth_l3_recover_ip(card); - if (!qeth_netdev_is_registered(dev)) { - rc = qeth_l3_setup_netdev(card, carrier_ok); + if (dev->reg_state != NETREG_REGISTERED) { + rc = qeth_l3_setup_netdev(card); if (rc) goto out_remove; + + if (carrier_ok) + netif_carrier_on(dev); } else { rtnl_lock(); if (carrier_ok) -- cgit v1.2.3 From ed13615dd32690ca2a9d1f730a596f950eafd905 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 25 Mar 2020 10:34:57 +0100 Subject: s390/qeth: simplify RX buffer tracking Since RX buffers may contain multiple packets, qeth's NAPI poll code can exhaust its budget in the middle of an RX buffer. Thus we keep track of our current position within the active RX buffer, so we can resume processing here in the next NAPI poll period. Clean up that code by tracking the index of the active buffer element, instead of a pointer to it. Also simplify the code that advances to the next RX buffer when the current buffer has been fully processed. v2: - remove QDIO_ELEMENT_NO() macro (davem) Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 2 +- drivers/s390/net/qeth_core_main.c | 30 ++++++++++++------------------ 2 files changed, 13 insertions(+), 19 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 6eb431c194bd..9840d4fab010 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -752,7 +752,7 @@ enum qeth_addr_disposition { struct qeth_rx { int b_count; int b_index; - struct qdio_buffer_element *b_element; + u8 buf_element; int e_offset; int qdio_err; }; diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index bd3adbb6ad50..4f33e4ee49d7 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -5332,14 +5332,13 @@ static inline int qeth_is_last_sbale(struct qdio_buffer_element *sbale) } static int qeth_extract_skb(struct qeth_card *card, - struct qeth_qdio_buffer *qethbuffer, - struct qdio_buffer_element **__element, + struct qeth_qdio_buffer *qethbuffer, u8 *element_no, int *__offset) { - struct qdio_buffer_element *element = *__element; struct qeth_priv *priv = netdev_priv(card->dev); struct qdio_buffer *buffer = qethbuffer->buffer; struct napi_struct *napi = &card->napi; + struct qdio_buffer_element *element; unsigned int linear_len = 0; bool uses_frags = false; int offset = *__offset; @@ -5349,6 +5348,8 @@ static int qeth_extract_skb(struct qeth_card *card, struct sk_buff *skb; int skb_len = 0; + element = &buffer->element[*element_no]; + next_packet: /* qeth_hdr must not cross element boundaries */ while (element->length < offset + sizeof(struct qeth_hdr)) { @@ -5504,7 +5505,7 @@ walk_packet: if (!skb) goto next_packet; - *__element = element; + *element_no = element - &buffer->element[0]; *__offset = offset; qeth_receive_skb(card, skb, hdr, uses_frags); @@ -5519,7 +5520,7 @@ static int qeth_extract_skbs(struct qeth_card *card, int budget, *done = false; while (budget) { - if (qeth_extract_skb(card, buf, &card->rx.b_element, + if (qeth_extract_skb(card, buf, &card->rx.buf_element, &card->rx.e_offset)) { *done = true; break; @@ -5550,10 +5551,6 @@ int qeth_poll(struct napi_struct *napi, int budget) card->rx.b_count = 0; break; } - card->rx.b_element = - &card->qdio.in_q->bufs[card->rx.b_index] - .buffer->element[0]; - card->rx.e_offset = 0; } while (card->rx.b_count) { @@ -5572,15 +5569,12 @@ int qeth_poll(struct napi_struct *napi, int budget) buffer->pool_entry); qeth_queue_input_buffer(card, card->rx.b_index); card->rx.b_count--; - if (card->rx.b_count) { - card->rx.b_index = - QDIO_BUFNR(card->rx.b_index + 1); - card->rx.b_element = - &card->qdio.in_q - ->bufs[card->rx.b_index] - .buffer->element[0]; - card->rx.e_offset = 0; - } + + /* Step forward to next buffer: */ + card->rx.b_index = + QDIO_BUFNR(card->rx.b_index + 1); + card->rx.buf_element = 0; + card->rx.e_offset = 0; } if (work_done >= budget) -- cgit v1.2.3 From 781b9a1820a1533135811bf281fefe0fc6920006 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 25 Mar 2020 10:34:58 +0100 Subject: s390/qeth: split out RX poll code The main NAPI poll routine should eventually handle more types of work, beyond just the RX ring. Split off the RX poll logic into a separate function, and simplify the nested while-loop. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 54 ++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 21 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 4f33e4ee49d7..7c98bc9e2c9a 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -5512,12 +5512,10 @@ walk_packet: return 0; } -static int qeth_extract_skbs(struct qeth_card *card, int budget, - struct qeth_qdio_buffer *buf, bool *done) +static unsigned int qeth_extract_skbs(struct qeth_card *card, int budget, + struct qeth_qdio_buffer *buf, bool *done) { - int work_done = 0; - - *done = false; + unsigned int work_done = 0; while (budget) { if (qeth_extract_skb(card, buf, &card->rx.buf_element, @@ -5533,15 +5531,12 @@ static int qeth_extract_skbs(struct qeth_card *card, int budget, return work_done; } -int qeth_poll(struct napi_struct *napi, int budget) +static unsigned int qeth_rx_poll(struct qeth_card *card, int budget) { - struct qeth_card *card = container_of(napi, struct qeth_card, napi); - int work_done = 0; - struct qeth_qdio_buffer *buffer; - int new_budget = budget; - bool done; + unsigned int work_done = 0; - while (1) { + while (budget > 0) { + /* Fetch completed RX buffers: */ if (!card->rx.b_count) { card->rx.qdio_err = 0; card->rx.b_count = qdio_get_next_buffers( @@ -5553,16 +5548,24 @@ int qeth_poll(struct napi_struct *napi, int budget) } } - while (card->rx.b_count) { + /* Process one completed RX buffer: */ + if (card->rx.b_count) { + struct qeth_qdio_buffer *buffer; + unsigned int skbs_done = 0; + bool done = false; + buffer = &card->qdio.in_q->bufs[card->rx.b_index]; if (!(card->rx.qdio_err && qeth_check_qdio_errors(card, buffer->buffer, card->rx.qdio_err, "qinerr"))) - work_done += qeth_extract_skbs(card, new_budget, - buffer, &done); + skbs_done = qeth_extract_skbs(card, budget, + buffer, &done); else done = true; + work_done += skbs_done; + budget -= skbs_done; + if (done) { QETH_CARD_STAT_INC(card, rx_bufs); qeth_put_buffer_pool_entry(card, @@ -5576,18 +5579,27 @@ int qeth_poll(struct napi_struct *napi, int budget) card->rx.buf_element = 0; card->rx.e_offset = 0; } - - if (work_done >= budget) - goto out; - else - new_budget = budget - work_done; } } + return work_done; +} + +int qeth_poll(struct napi_struct *napi, int budget) +{ + struct qeth_card *card = container_of(napi, struct qeth_card, napi); + unsigned int work_done; + + work_done = qeth_rx_poll(card, budget); + + /* Exhausted the RX budget. Keep IRQ disabled, we get called again. */ + if (budget && work_done >= budget) + return work_done; + if (napi_complete_done(napi, work_done) && qdio_start_irq(CARD_DDEV(card), 0)) napi_schedule(napi); -out: + return work_done; } EXPORT_SYMBOL_GPL(qeth_poll); -- cgit v1.2.3 From b439044b70e4b7992f82974eb77d92c95da5960f Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 25 Mar 2020 10:34:59 +0100 Subject: s390/qeth: remove redundant if-clause in RX poll code Whenever all completed RX buffers have been processed (ie. rx->b_count == 0), we call down to the HW layer to scan for additional buffers. If no further buffers are available, the code breaks out of the while-loop. So we never reach the 'process an RX buffer' step with rx->b_count == 0, eliminate that check and one level of indentation. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 56 ++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 30 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 7c98bc9e2c9a..13facf2d602b 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -5536,6 +5536,10 @@ static unsigned int qeth_rx_poll(struct qeth_card *card, int budget) unsigned int work_done = 0; while (budget > 0) { + struct qeth_qdio_buffer *buffer; + unsigned int skbs_done = 0; + bool done = false; + /* Fetch completed RX buffers: */ if (!card->rx.b_count) { card->rx.qdio_err = 0; @@ -5549,36 +5553,28 @@ static unsigned int qeth_rx_poll(struct qeth_card *card, int budget) } /* Process one completed RX buffer: */ - if (card->rx.b_count) { - struct qeth_qdio_buffer *buffer; - unsigned int skbs_done = 0; - bool done = false; - - buffer = &card->qdio.in_q->bufs[card->rx.b_index]; - if (!(card->rx.qdio_err && - qeth_check_qdio_errors(card, buffer->buffer, - card->rx.qdio_err, "qinerr"))) - skbs_done = qeth_extract_skbs(card, budget, - buffer, &done); - else - done = true; - - work_done += skbs_done; - budget -= skbs_done; - - if (done) { - QETH_CARD_STAT_INC(card, rx_bufs); - qeth_put_buffer_pool_entry(card, - buffer->pool_entry); - qeth_queue_input_buffer(card, card->rx.b_index); - card->rx.b_count--; - - /* Step forward to next buffer: */ - card->rx.b_index = - QDIO_BUFNR(card->rx.b_index + 1); - card->rx.buf_element = 0; - card->rx.e_offset = 0; - } + buffer = &card->qdio.in_q->bufs[card->rx.b_index]; + if (!(card->rx.qdio_err && + qeth_check_qdio_errors(card, buffer->buffer, + card->rx.qdio_err, "qinerr"))) + skbs_done = qeth_extract_skbs(card, budget, buffer, + &done); + else + done = true; + + work_done += skbs_done; + budget -= skbs_done; + + if (done) { + QETH_CARD_STAT_INC(card, rx_bufs); + qeth_put_buffer_pool_entry(card, buffer->pool_entry); + qeth_queue_input_buffer(card, card->rx.b_index); + card->rx.b_count--; + + /* Step forward to next buffer: */ + card->rx.b_index = QDIO_BUFNR(card->rx.b_index + 1); + card->rx.buf_element = 0; + card->rx.e_offset = 0; } } -- cgit v1.2.3 From 0a6e634535f1b47b00501c0b563a827eb1f8ec8c Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 25 Mar 2020 10:35:00 +0100 Subject: s390/qdio: extend polling support to multiple queues When the support for polling drivers was initially added, it only considered Input Queue 0. But as QDIO interrupts are actually for the full device and not a single queue, this doesn't really fit for configurations where multiple Input Queues are used. Rework the qdio code so that interrupts for a polling driver are not split up into actions for each queue. Instead deliver the interrupt as a single event, and let the driver decide which queue needs what action. When re-enabling the QDIO interrupt via qdio_start_irq(), this means that the qdio code needs to (1) put _all_ eligible queues back into a state where they raise IRQs, (2) and afterwards check _all_ eligible queues for new work to bridge the race window. On the qeth side of things (as the only qdio polling driver), we can now add CQ polling support to the main NAPI poll routine. It doesn't consume NAPI budget, and to avoid hogging the CPU we yield control after completing one full queue worth of buffers. The subsequent qdio_start_irq() will check for any additional work, and have us re-schedule the NAPI instance accordingly. Signed-off-by: Julian Wiedmann Acked-by: Heiko Carstens Signed-off-by: David S. Miller --- arch/s390/include/asm/qdio.h | 9 +++--- drivers/s390/cio/qdio.h | 11 +++---- drivers/s390/cio/qdio_debug.c | 4 +-- drivers/s390/cio/qdio_main.c | 50 +++++++++++++--------------- drivers/s390/cio/qdio_setup.c | 16 ++++----- drivers/s390/cio/qdio_thinint.c | 38 ++++++++++------------ drivers/s390/net/qeth_core_main.c | 68 +++++++++++++++++---------------------- 7 files changed, 87 insertions(+), 109 deletions(-) (limited to 'drivers/s390') diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h index 1e3517b0518b..e577f8533009 100644 --- a/arch/s390/include/asm/qdio.h +++ b/arch/s390/include/asm/qdio.h @@ -338,7 +338,7 @@ typedef void qdio_handler_t(struct ccw_device *, unsigned int, int, * @no_output_qs: number of output queues * @input_handler: handler to be called for input queues * @output_handler: handler to be called for output queues - * @queue_start_poll_array: polling handlers (one per input queue or NULL) + * @irq_poll: Data IRQ polling handler (NULL when not supported) * @scan_threshold: # of in-use buffers that triggers scan on output queue * @int_parm: interruption parameter * @input_sbal_addr_array: address of no_input_qs * 128 pointers @@ -359,8 +359,7 @@ struct qdio_initialize { unsigned int no_output_qs; qdio_handler_t *input_handler; qdio_handler_t *output_handler; - void (**queue_start_poll_array) (struct ccw_device *, int, - unsigned long); + void (*irq_poll)(struct ccw_device *cdev, unsigned long data); unsigned int scan_threshold; unsigned long int_parm; struct qdio_buffer **input_sbal_addr_array; @@ -415,8 +414,8 @@ extern int qdio_activate(struct ccw_device *); extern void qdio_release_aob(struct qaob *); extern int do_QDIO(struct ccw_device *, unsigned int, int, unsigned int, unsigned int); -extern int qdio_start_irq(struct ccw_device *, int); -extern int qdio_stop_irq(struct ccw_device *, int); +extern int qdio_start_irq(struct ccw_device *cdev); +extern int qdio_stop_irq(struct ccw_device *cdev); extern int qdio_get_next_buffers(struct ccw_device *, int, int *, int *); extern int qdio_inspect_queue(struct ccw_device *cdev, unsigned int nr, bool is_input, unsigned int *bufnr, diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index ff74eb5fce50..f72f961cc78f 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -177,8 +177,8 @@ struct qdio_queue_perf_stat { unsigned int nr_sbal_total; }; -enum qdio_queue_irq_states { - QDIO_QUEUE_IRQS_DISABLED, +enum qdio_irq_poll_states { + QDIO_IRQ_DISABLED, }; struct qdio_input_q { @@ -188,10 +188,6 @@ struct qdio_input_q { int ack_count; /* last time of noticing incoming data */ u64 timestamp; - /* upper-layer polling flag */ - unsigned long queue_irq_state; - /* callback to start upper-layer polling */ - void (*queue_start_poll) (struct ccw_device *, int, unsigned long); }; struct qdio_output_q { @@ -299,6 +295,9 @@ struct qdio_irq { struct qdio_q *input_qs[QDIO_MAX_QUEUES_PER_IRQ]; struct qdio_q *output_qs[QDIO_MAX_QUEUES_PER_IRQ]; + void (*irq_poll)(struct ccw_device *cdev, unsigned long data); + unsigned long poll_state; + debug_info_t *debug_area; struct mutex setup_mutex; struct qdio_dev_perf_stat perf_stat; diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c index 9c0370b27426..00244607c8c0 100644 --- a/drivers/s390/cio/qdio_debug.c +++ b/drivers/s390/cio/qdio_debug.c @@ -128,8 +128,8 @@ static int qstat_show(struct seq_file *m, void *v) q->u.in.ack_start, q->u.in.ack_count); seq_printf(m, "DSCI: %x IRQs disabled: %u\n", *(u8 *)q->irq_ptr->dsci, - test_bit(QDIO_QUEUE_IRQS_DISABLED, - &q->u.in.queue_irq_state)); + test_bit(QDIO_IRQ_DISABLED, + &q->irq_ptr->poll_state)); } seq_printf(m, "SBAL states:\n"); seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n"); diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 3475317c42e5..02ced5949287 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -950,19 +950,14 @@ static void qdio_int_handler_pci(struct qdio_irq *irq_ptr) if (unlikely(irq_ptr->state != QDIO_IRQ_STATE_ACTIVE)) return; - for_each_input_queue(irq_ptr, q, i) { - if (q->u.in.queue_start_poll) { - /* skip if polling is enabled or already in work */ - if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED, - &q->u.in.queue_irq_state)) { - QDIO_PERF_STAT_INC(irq_ptr, int_discarded); - continue; - } - q->u.in.queue_start_poll(q->irq_ptr->cdev, q->nr, - q->irq_ptr->int_parm); - } else { + if (irq_ptr->irq_poll) { + if (!test_and_set_bit(QDIO_IRQ_DISABLED, &irq_ptr->poll_state)) + irq_ptr->irq_poll(irq_ptr->cdev, irq_ptr->int_parm); + else + QDIO_PERF_STAT_INC(irq_ptr, int_discarded); + } else { + for_each_input_queue(irq_ptr, q, i) tasklet_schedule(&q->tasklet); - } } if (!pci_out_supported(irq_ptr) || !irq_ptr->scan_threshold) @@ -1610,24 +1605,26 @@ EXPORT_SYMBOL_GPL(do_QDIO); /** * qdio_start_irq - process input buffers * @cdev: associated ccw_device for the qdio subchannel - * @nr: input queue number * * Return codes * 0 - success * 1 - irqs not started since new data is available */ -int qdio_start_irq(struct ccw_device *cdev, int nr) +int qdio_start_irq(struct ccw_device *cdev) { struct qdio_q *q; struct qdio_irq *irq_ptr = cdev->private->qdio_data; + unsigned int i; if (!irq_ptr) return -ENODEV; - q = irq_ptr->input_qs[nr]; clear_nonshared_ind(irq_ptr); - qdio_stop_polling(q); - clear_bit(QDIO_QUEUE_IRQS_DISABLED, &q->u.in.queue_irq_state); + + for_each_input_queue(irq_ptr, q, i) + qdio_stop_polling(q); + + clear_bit(QDIO_IRQ_DISABLED, &irq_ptr->poll_state); /* * We need to check again to not lose initiative after @@ -1635,13 +1632,16 @@ int qdio_start_irq(struct ccw_device *cdev, int nr) */ if (test_nonshared_ind(irq_ptr)) goto rescan; - if (!qdio_inbound_q_done(q, q->first_to_check)) - goto rescan; + + for_each_input_queue(irq_ptr, q, i) { + if (!qdio_inbound_q_done(q, q->first_to_check)) + goto rescan; + } + return 0; rescan: - if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED, - &q->u.in.queue_irq_state)) + if (test_and_set_bit(QDIO_IRQ_DISABLED, &irq_ptr->poll_state)) return 0; else return 1; @@ -1729,23 +1729,19 @@ EXPORT_SYMBOL(qdio_get_next_buffers); /** * qdio_stop_irq - disable interrupt processing for the device * @cdev: associated ccw_device for the qdio subchannel - * @nr: input queue number * * Return codes * 0 - interrupts were already disabled * 1 - interrupts successfully disabled */ -int qdio_stop_irq(struct ccw_device *cdev, int nr) +int qdio_stop_irq(struct ccw_device *cdev) { - struct qdio_q *q; struct qdio_irq *irq_ptr = cdev->private->qdio_data; if (!irq_ptr) return -ENODEV; - q = irq_ptr->input_qs[nr]; - if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED, - &q->u.in.queue_irq_state)) + if (test_and_set_bit(QDIO_IRQ_DISABLED, &irq_ptr->poll_state)) return 0; else return 1; diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index 66e4bdca9d89..7b831bb4e229 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -224,15 +224,6 @@ static void setup_queues(struct qdio_irq *irq_ptr, setup_queues_misc(q, irq_ptr, qdio_init->input_handler, i); q->is_input_q = 1; - if (qdio_init->queue_start_poll_array && - qdio_init->queue_start_poll_array[i]) { - q->u.in.queue_start_poll = - qdio_init->queue_start_poll_array[i]; - set_bit(QDIO_QUEUE_IRQS_DISABLED, - &q->u.in.queue_irq_state); - } else { - q->u.in.queue_start_poll = NULL; - } setup_storage_lists(q, irq_ptr, input_sbal_array, i); input_sbal_array += QDIO_MAX_BUFFERS_PER_Q; @@ -483,6 +474,13 @@ int qdio_setup_irq(struct qdio_initialize *init_data) ccw_device_get_schid(irq_ptr->cdev, &irq_ptr->schid); setup_queues(irq_ptr, init_data); + if (init_data->irq_poll) { + irq_ptr->irq_poll = init_data->irq_poll; + set_bit(QDIO_IRQ_DISABLED, &irq_ptr->poll_state); + } else { + irq_ptr->irq_poll = NULL; + } + setup_qib(irq_ptr, init_data); qdio_setup_thinint(irq_ptr); set_impl_params(irq_ptr, init_data->qib_param_field_format, diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index 7c4e4ec08a12..8f315c53de23 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c @@ -135,28 +135,24 @@ static inline void tiqdio_call_inq_handlers(struct qdio_irq *irq) has_multiple_inq_on_dsci(irq)) xchg(irq->dsci, 0); + if (irq->irq_poll) { + if (!test_and_set_bit(QDIO_IRQ_DISABLED, &irq->poll_state)) + irq->irq_poll(irq->cdev, irq->int_parm); + else + QDIO_PERF_STAT_INC(irq, int_discarded); + + return; + } + for_each_input_queue(irq, q, i) { - if (q->u.in.queue_start_poll) { - /* skip if polling is enabled or already in work */ - if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED, - &q->u.in.queue_irq_state)) { - QDIO_PERF_STAT_INC(irq, int_discarded); - continue; - } - - /* avoid dsci clear here, done after processing */ - q->u.in.queue_start_poll(irq->cdev, q->nr, - irq->int_parm); - } else { - if (!shared_ind(irq)) - xchg(irq->dsci, 0); - - /* - * Call inbound processing but not directly - * since that could starve other thinint queues. - */ - tasklet_schedule(&q->tasklet); - } + if (!shared_ind(irq)) + xchg(irq->dsci, 0); + + /* + * Call inbound processing but not directly + * since that could starve other thinint queues. + */ + tasklet_schedule(&q->tasklet); } } diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 13facf2d602b..68bba8d057d1 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -548,14 +548,6 @@ static void qeth_qdio_handle_aob(struct qeth_card *card, qdio_release_aob(aob); } -static inline int qeth_is_cq(struct qeth_card *card, unsigned int queue) -{ - return card->options.cq == QETH_CQ_ENABLED && - card->qdio.c_q != NULL && - queue != 0 && - queue == card->qdio.no_in_queues - 1; -} - static void qeth_setup_ccw(struct ccw1 *ccw, u8 cmd_code, u8 flags, u32 len, void *data) { @@ -3469,8 +3461,7 @@ static void qeth_check_outbound_queue(struct qeth_qdio_out_q *queue) } } -static void qeth_qdio_start_poll(struct ccw_device *ccwdev, int queue, - unsigned long card_ptr) +static void qeth_qdio_poll(struct ccw_device *cdev, unsigned long card_ptr) { struct qeth_card *card = (struct qeth_card *)card_ptr; @@ -3508,9 +3499,6 @@ static void qeth_qdio_cq_handler(struct qeth_card *card, unsigned int qdio_err, int i; int rc; - if (!qeth_is_cq(card, queue)) - return; - QETH_CARD_TEXT_(card, 5, "qcqhe%d", first_element); QETH_CARD_TEXT_(card, 5, "qcqhc%d", count); QETH_CARD_TEXT_(card, 5, "qcqherr%d", qdio_err); @@ -3556,9 +3544,7 @@ static void qeth_qdio_input_handler(struct ccw_device *ccwdev, QETH_CARD_TEXT_(card, 2, "qihq%d", queue); QETH_CARD_TEXT_(card, 2, "qiec%d", qdio_err); - if (qeth_is_cq(card, queue)) - qeth_qdio_cq_handler(card, qdio_err, queue, first_elem, count); - else if (qdio_err) + if (qdio_err) qeth_schedule_recovery(card); } @@ -4805,10 +4791,7 @@ out: } static void qeth_qdio_establish_cq(struct qeth_card *card, - struct qdio_buffer **in_sbal_ptrs, - void (**queue_start_poll) - (struct ccw_device *, int, - unsigned long)) + struct qdio_buffer **in_sbal_ptrs) { int i; @@ -4819,8 +4802,6 @@ static void qeth_qdio_establish_cq(struct qeth_card *card, for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) in_sbal_ptrs[offset + i] = card->qdio.c_q->bufs[i].buffer; - - queue_start_poll[card->qdio.no_in_queues - 1] = NULL; } } @@ -4829,7 +4810,6 @@ static int qeth_qdio_establish(struct qeth_card *card) struct qdio_initialize init_data; char *qib_param_field; struct qdio_buffer **in_sbal_ptrs; - void (**queue_start_poll) (struct ccw_device *, int, unsigned long); struct qdio_buffer **out_sbal_ptrs; int i, j, k; int rc = 0; @@ -4856,16 +4836,7 @@ static int qeth_qdio_establish(struct qeth_card *card) for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) in_sbal_ptrs[i] = card->qdio.in_q->bufs[i].buffer; - queue_start_poll = kcalloc(card->qdio.no_in_queues, sizeof(void *), - GFP_KERNEL); - if (!queue_start_poll) { - rc = -ENOMEM; - goto out_free_in_sbals; - } - for (i = 0; i < card->qdio.no_in_queues; ++i) - queue_start_poll[i] = qeth_qdio_start_poll; - - qeth_qdio_establish_cq(card, in_sbal_ptrs, queue_start_poll); + qeth_qdio_establish_cq(card, in_sbal_ptrs); out_sbal_ptrs = kcalloc(card->qdio.no_out_queues * QDIO_MAX_BUFFERS_PER_Q, @@ -4873,7 +4844,7 @@ static int qeth_qdio_establish(struct qeth_card *card) GFP_KERNEL); if (!out_sbal_ptrs) { rc = -ENOMEM; - goto out_free_queue_start_poll; + goto out_free_in_sbals; } for (i = 0, k = 0; i < card->qdio.no_out_queues; ++i) @@ -4891,7 +4862,7 @@ static int qeth_qdio_establish(struct qeth_card *card) init_data.no_output_qs = card->qdio.no_out_queues; init_data.input_handler = qeth_qdio_input_handler; init_data.output_handler = qeth_qdio_output_handler; - init_data.queue_start_poll_array = queue_start_poll; + init_data.irq_poll = qeth_qdio_poll; init_data.int_parm = (unsigned long) card; init_data.input_sbal_addr_array = in_sbal_ptrs; init_data.output_sbal_addr_array = out_sbal_ptrs; @@ -4924,8 +4895,6 @@ static int qeth_qdio_establish(struct qeth_card *card) } out: kfree(out_sbal_ptrs); -out_free_queue_start_poll: - kfree(queue_start_poll); out_free_in_sbals: kfree(in_sbal_ptrs); out_free_qib_param: @@ -5581,6 +5550,24 @@ static unsigned int qeth_rx_poll(struct qeth_card *card, int budget) return work_done; } +static void qeth_cq_poll(struct qeth_card *card) +{ + unsigned int work_done = 0; + + while (work_done < QDIO_MAX_BUFFERS_PER_Q) { + unsigned int start, error; + int completed; + + completed = qdio_inspect_queue(CARD_DDEV(card), 1, true, &start, + &error); + if (completed <= 0) + return; + + qeth_qdio_cq_handler(card, error, 1, start, completed); + work_done += completed; + } +} + int qeth_poll(struct napi_struct *napi, int budget) { struct qeth_card *card = container_of(napi, struct qeth_card, napi); @@ -5588,12 +5575,15 @@ int qeth_poll(struct napi_struct *napi, int budget) work_done = qeth_rx_poll(card, budget); + if (card->options.cq == QETH_CQ_ENABLED) + qeth_cq_poll(card); + /* Exhausted the RX budget. Keep IRQ disabled, we get called again. */ if (budget && work_done >= budget) return work_done; if (napi_complete_done(napi, work_done) && - qdio_start_irq(CARD_DDEV(card), 0)) + qdio_start_irq(CARD_DDEV(card))) napi_schedule(napi); return work_done; @@ -6756,7 +6746,7 @@ int qeth_stop(struct net_device *dev) } napi_disable(&card->napi); - qdio_stop_irq(CARD_DDEV(card), 0); + qdio_stop_irq(CARD_DDEV(card)); return 0; } -- cgit v1.2.3 From 8ec1e247a23bd36eec94a9297fc051dd75d5e3f9 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 25 Mar 2020 10:35:01 +0100 Subject: s390/qeth: simplify L3 dev_id logic The logic that deals with errors from qeth_l3_get_unique_id() is quite complex: it sets card->unique_id to 0xfffe, additionally flags it as UNIQUE_ID_NOT_BY_CARD and later takes this flag as cue to not propagate card->unique_id to dev->dev_id. With dev->dev_id thus holding 0, addrconf_ifid_eui48() applies its default behaviour. Get rid of all the special bit masks, and just return the old uid in case of an error. For the vast majority of cases this will be 0 (and so we still get the desired default behaviour) - with the rare exception where qeth_l3_get_unique_id() might have been called earlier but the initialization then failed at a later point. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 5 ----- drivers/s390/net/qeth_l3_main.c | 30 +++++++++++++----------------- 2 files changed, 13 insertions(+), 22 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 9840d4fab010..257b7f3c5558 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -178,10 +178,6 @@ struct qeth_vnicc_info { #define QETH_RECLAIM_WORK_TIME HZ #define QETH_MAX_PORTNO 15 -/*IPv6 address autoconfiguration stuff*/ -#define UNIQUE_ID_IF_CREATE_ADDR_FAILED 0xfffe -#define UNIQUE_ID_NOT_BY_CARD 0x10000 - /*****************************************************************************/ /* QDIO queue and buffer handling */ /*****************************************************************************/ @@ -687,7 +683,6 @@ struct qeth_card_info { enum qeth_card_types type; enum qeth_link_types link_type; int broadcast_capable; - int unique_id; bool layer_enforced; struct qeth_card_blkt blkt; __u32 diagass_support; diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 83ae75cf1389..b48cd0df3e31 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -949,39 +949,36 @@ static int qeth_l3_get_unique_id_cb(struct qeth_card *card, struct qeth_reply *reply, unsigned long data) { struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data; + u16 *uid = reply->param; if (cmd->hdr.return_code == 0) { - card->info.unique_id = cmd->data.create_destroy_addr.uid; + *uid = cmd->data.create_destroy_addr.uid; return 0; } - card->info.unique_id = UNIQUE_ID_IF_CREATE_ADDR_FAILED | - UNIQUE_ID_NOT_BY_CARD; dev_warn(&card->gdev->dev, "The network adapter failed to generate a unique ID\n"); return -EIO; } -static int qeth_l3_get_unique_id(struct qeth_card *card) +static u16 qeth_l3_get_unique_id(struct qeth_card *card, u16 uid) { - int rc = 0; struct qeth_cmd_buffer *iob; QETH_CARD_TEXT(card, 2, "guniqeid"); - if (!qeth_is_supported(card, IPA_IPV6)) { - card->info.unique_id = UNIQUE_ID_IF_CREATE_ADDR_FAILED | - UNIQUE_ID_NOT_BY_CARD; - return 0; - } + if (!qeth_is_supported(card, IPA_IPV6)) + goto out; iob = qeth_ipa_alloc_cmd(card, IPA_CMD_CREATE_ADDR, QETH_PROT_IPV6, IPA_DATA_SIZEOF(create_destroy_addr)); if (!iob) - return -ENOMEM; + goto out; - __ipa_cmd(iob)->data.create_destroy_addr.uid = card->info.unique_id; - rc = qeth_send_ipa_cmd(card, iob, qeth_l3_get_unique_id_cb, NULL); - return rc; + __ipa_cmd(iob)->data.create_destroy_addr.uid = uid; + qeth_send_ipa_cmd(card, iob, qeth_l3_get_unique_id_cb, &uid); + +out: + return uid; } static int @@ -1920,6 +1917,7 @@ static const struct net_device_ops qeth_l3_osa_netdev_ops = { static int qeth_l3_setup_netdev(struct qeth_card *card) { + struct net_device *dev = card->dev; unsigned int headroom; int rc; @@ -1937,9 +1935,7 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) card->dev->netdev_ops = &qeth_l3_osa_netdev_ops; /*IPv6 address autoconfiguration stuff*/ - qeth_l3_get_unique_id(card); - if (!(card->info.unique_id & UNIQUE_ID_NOT_BY_CARD)) - card->dev->dev_id = card->info.unique_id & 0xffff; + dev->dev_id = qeth_l3_get_unique_id(card, dev->dev_id); if (!IS_VM_NIC(card)) { card->dev->features |= NETIF_F_SG; -- cgit v1.2.3 From 9de15117f1c5f2cda689cf6dcd9e8779cc8480b8 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 25 Mar 2020 10:35:02 +0100 Subject: s390/qeth: clean up the mac_bits We're down to a single bit flag for MAC-address related status, reflect that in the info struct. Also set up the flag during initialization instead of clearing it during shutdown - one more little step towards unifying the shutdown code. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 3 +-- drivers/s390/net/qeth_l2_main.c | 13 +++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 257b7f3c5558..911dcef6adc6 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -668,18 +668,17 @@ struct qeth_card_blkt { #define QETH_BROADCAST_WITH_ECHO 0x01 #define QETH_BROADCAST_WITHOUT_ECHO 0x02 -#define QETH_LAYER2_MAC_REGISTERED 0x02 struct qeth_card_info { unsigned short unit_addr2; unsigned short cula; u8 chpid; __u16 func_level; char mcl_level[QETH_MCL_LENGTH + 1]; + u8 dev_addr_is_registered:1; u8 open_when_online:1; u8 promisc_mode:1; u8 use_v1_blkt:1; u8 is_vm_nic:1; - int mac_bits; enum qeth_card_types type; enum qeth_link_types link_type; int broadcast_capable; diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 73cb363b1fab..249b00d91d46 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -291,7 +291,6 @@ static void qeth_l2_stop_card(struct qeth_card *card) qeth_qdio_clear_card(card, 0); qeth_clear_working_pool_list(card); flush_workqueue(card->event_wq); - card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED; card->info.promisc_mode = 0; } @@ -337,14 +336,16 @@ static void qeth_l2_register_dev_addr(struct qeth_card *card) qeth_l2_request_initial_mac(card); if (!IS_OSN(card) && !qeth_l2_send_setmac(card, card->dev->dev_addr)) - card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED; + card->info.dev_addr_is_registered = 1; + else + card->info.dev_addr_is_registered = 0; } static int qeth_l2_validate_addr(struct net_device *dev) { struct qeth_card *card = dev->ml_priv; - if (card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED) + if (card->info.dev_addr_is_registered) return eth_validate_addr(dev); QETH_CARD_TEXT(card, 4, "nomacadr"); @@ -370,7 +371,7 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p) /* don't register the same address twice */ if (ether_addr_equal_64bits(dev->dev_addr, addr->sa_data) && - (card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED)) + card->info.dev_addr_is_registered) return 0; /* add the new address, switch over, drop the old */ @@ -380,9 +381,9 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p) ether_addr_copy(old_addr, dev->dev_addr); ether_addr_copy(dev->dev_addr, addr->sa_data); - if (card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED) + if (card->info.dev_addr_is_registered) qeth_l2_remove_mac(card, old_addr); - card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED; + card->info.dev_addr_is_registered = 1; return 0; } -- cgit v1.2.3 From 1ab2f8c699d8e91c97f64c9871bcc89c107cdeef Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 25 Mar 2020 10:35:03 +0100 Subject: s390/qeth: collect more TX statistics Count the number of TX doorbells we issue to the qdio layer. Also count the number of actual frames in a TX buffer, and then use this data along with the byte count during TX completion. We'll make additional use of the frame count in a subsequent patch. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 2 ++ drivers/s390/net/qeth_core_main.c | 20 ++++++++++++++------ drivers/s390/net/qeth_ethtool.c | 1 + 3 files changed, 17 insertions(+), 6 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 911dcef6adc6..f56670bfcd0a 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -402,6 +402,7 @@ struct qeth_qdio_out_buffer { struct qdio_buffer *buffer; atomic_t state; int next_element_to_fill; + unsigned int frames; unsigned int bytes; struct sk_buff_head skb_list; int is_header[QDIO_MAX_ELEMENTS_PER_BUFFER]; @@ -457,6 +458,7 @@ struct qeth_out_q_stats { u64 tso_bytes; u64 packing_mode_switch; u64 stopped; + u64 doorbell; u64 completion_yield; u64 completion_timer; diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 68bba8d057d1..108dd9a34f30 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -1155,17 +1155,20 @@ static void qeth_tx_complete_buf(struct qeth_qdio_out_buffer *buf, bool error, QETH_TXQ_STAT_INC(queue, bufs); QETH_TXQ_STAT_ADD(queue, buf_elements, buf->next_element_to_fill); + if (error) { + QETH_TXQ_STAT_ADD(queue, tx_errors, buf->frames); + } else { + QETH_TXQ_STAT_ADD(queue, tx_packets, buf->frames); + QETH_TXQ_STAT_ADD(queue, tx_bytes, buf->bytes); + } + while ((skb = __skb_dequeue(&buf->skb_list)) != NULL) { unsigned int bytes = qdisc_pkt_len(skb); bool is_tso = skb_is_gso(skb); unsigned int packets; packets = is_tso ? skb_shinfo(skb)->gso_segs : 1; - if (error) { - QETH_TXQ_STAT_ADD(queue, tx_errors, packets); - } else { - QETH_TXQ_STAT_ADD(queue, tx_packets, packets); - QETH_TXQ_STAT_ADD(queue, tx_bytes, bytes); + if (!error) { if (skb->ip_summed == CHECKSUM_PARTIAL) QETH_TXQ_STAT_ADD(queue, skbs_csum, packets); if (skb_is_nonlinear(skb)) @@ -1202,6 +1205,7 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, qeth_scrub_qdio_buffer(buf->buffer, queue->max_elements); buf->next_element_to_fill = 0; + buf->frames = 0; buf->bytes = 0; atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY); } @@ -3389,6 +3393,7 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, } } + QETH_TXQ_STAT_INC(queue, doorbell); qdio_flags = QDIO_FLAG_SYNC_OUTPUT; if (atomic_read(&queue->set_pci_flags_count)) qdio_flags |= QDIO_FLAG_PCI_OUT; @@ -3942,6 +3947,7 @@ static int __qeth_xmit(struct qeth_card *card, struct qeth_qdio_out_q *queue, next_element = qeth_fill_buffer(buffer, skb, hdr, offset, hd_len); buffer->bytes += bytes; + buffer->frames += skb_is_gso(skb) ? skb_shinfo(skb)->gso_segs : 1; queue->prev_hdr = hdr; flush = __netdev_tx_sent_queue(txq, bytes, @@ -4032,6 +4038,8 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, } next_element = qeth_fill_buffer(buffer, skb, hdr, offset, hd_len); + buffer->bytes += qdisc_pkt_len(skb); + buffer->frames += skb_is_gso(skb) ? skb_shinfo(skb)->gso_segs : 1; if (queue->do_pack) QETH_TXQ_STAT_INC(queue, skbs_pack); @@ -5668,7 +5676,7 @@ static int qeth_tx_poll(struct napi_struct *napi, int budget) unsigned int bidx = QDIO_BUFNR(i); buffer = queue->bufs[bidx]; - packets += skb_queue_len(&buffer->skb_list); + packets += buffer->frames; bytes += buffer->bytes; qeth_handle_send_error(card, buffer, error); diff --git a/drivers/s390/net/qeth_ethtool.c b/drivers/s390/net/qeth_ethtool.c index 31e019085fc3..6f0cc6fcc759 100644 --- a/drivers/s390/net/qeth_ethtool.c +++ b/drivers/s390/net/qeth_ethtool.c @@ -39,6 +39,7 @@ static const struct qeth_stats txq_stats[] = { QETH_TXQ_STAT("TSO bytes", tso_bytes), QETH_TXQ_STAT("Packing mode switches", packing_mode_switch), QETH_TXQ_STAT("Queue stopped", stopped), + QETH_TXQ_STAT("Doorbell", doorbell), QETH_TXQ_STAT("Completion yield", completion_yield), QETH_TXQ_STAT("Completion timer", completion_timer), }; -- cgit v1.2.3 From ee1e52d1e4bb91826a2bf5c0586d5b15eb619898 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 25 Mar 2020 10:35:04 +0100 Subject: s390/qeth: add TX IRQ coalescing support for IQD devices Since IQD devices complete (most of) their transmissions synchronously, they don't offer TX completion IRQs and have no HW coalescing controls. But we can fake the easy parts in SW, and give the user some control wrt to how often the TX NAPI code should be triggered to process the TX completions. Having per-queue controls can in particular help the dedicated mcast queue, as it likely benefits from different fine-tuning than what the ucast queues need. CC: Jakub Kicinski Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 15 +++++--- drivers/s390/net/qeth_core_main.c | 20 +++++++++-- drivers/s390/net/qeth_ethtool.c | 75 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+), 8 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index f56670bfcd0a..a6553e78af08 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -459,6 +459,7 @@ struct qeth_out_q_stats { u64 packing_mode_switch; u64 stopped; u64 doorbell; + u64 coal_frames; u64 completion_yield; u64 completion_timer; @@ -469,6 +470,8 @@ struct qeth_out_q_stats { u64 tx_dropped; }; +#define QETH_TX_MAX_COALESCED_FRAMES 1 +#define QETH_TX_COALESCE_USECS 25 #define QETH_TX_TIMER_USECS 500 struct qeth_qdio_out_q { @@ -492,9 +495,13 @@ struct qeth_qdio_out_q { struct napi_struct napi; struct timer_list timer; struct qeth_hdr *prev_hdr; + unsigned int coalesced_frames; u8 bulk_start; u8 bulk_count; u8 bulk_max; + + unsigned int coalesce_usecs; + unsigned int max_coalesced_frames; }; #define qeth_for_each_output_queue(card, q, i) \ @@ -503,12 +510,10 @@ struct qeth_qdio_out_q { #define qeth_napi_to_out_queue(n) container_of(n, struct qeth_qdio_out_q, napi) -static inline void qeth_tx_arm_timer(struct qeth_qdio_out_q *queue) +static inline void qeth_tx_arm_timer(struct qeth_qdio_out_q *queue, + unsigned long usecs) { - if (timer_pending(&queue->timer)) - return; - mod_timer(&queue->timer, usecs_to_jiffies(QETH_TX_TIMER_USECS) + - jiffies); + timer_reduce(&queue->timer, usecs_to_jiffies(usecs) + jiffies); } static inline bool qeth_out_queue_is_full(struct qeth_qdio_out_q *queue) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 108dd9a34f30..0c9f1464a778 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -2404,6 +2404,8 @@ static int qeth_alloc_qdio_queues(struct qeth_card *card) queue->card = card; queue->queue_no = i; timer_setup(&queue->timer, qeth_tx_completion_timer, 0); + queue->coalesce_usecs = QETH_TX_COALESCE_USECS; + queue->max_coalesced_frames = QETH_TX_MAX_COALESCED_FRAMES; /* give outbound qeth_qdio_buffers their qdio_buffers */ for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) { @@ -2762,6 +2764,7 @@ static int qeth_init_qdio_queues(struct qeth_card *card) queue->next_buf_to_fill = 0; queue->do_pack = 0; queue->prev_hdr = NULL; + queue->coalesced_frames = 0; queue->bulk_start = 0; queue->bulk_count = 0; queue->bulk_max = qeth_tx_select_bulk_max(card, queue); @@ -3357,6 +3360,7 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, buf = queue->bufs[bidx]; buf->buffer->element[buf->next_element_to_fill - 1].eflags |= SBAL_EFLAGS_LAST_ENTRY; + queue->coalesced_frames += buf->frames; if (queue->bufstates) queue->bufstates[bidx].user = buf; @@ -3401,8 +3405,18 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, queue->queue_no, index, count); /* Fake the TX completion interrupt: */ - if (IS_IQD(card)) - napi_schedule(&queue->napi); + if (IS_IQD(card)) { + unsigned int frames = READ_ONCE(queue->max_coalesced_frames); + unsigned int usecs = READ_ONCE(queue->coalesce_usecs); + + if (frames && queue->coalesced_frames >= frames) { + napi_schedule(&queue->napi); + queue->coalesced_frames = 0; + QETH_TXQ_STAT_INC(queue, coal_frames); + } else if (usecs) { + qeth_tx_arm_timer(queue, usecs); + } + } if (rc) { /* ignore temporary SIGA errors without busy condition */ @@ -5667,7 +5681,7 @@ static int qeth_tx_poll(struct napi_struct *napi, int budget) if (completed <= 0) { /* Ensure we see TX completion for pending work: */ if (napi_complete_done(napi, 0)) - qeth_tx_arm_timer(queue); + qeth_tx_arm_timer(queue, QETH_TX_TIMER_USECS); return 0; } diff --git a/drivers/s390/net/qeth_ethtool.c b/drivers/s390/net/qeth_ethtool.c index 6f0cc6fcc759..ebdc03210608 100644 --- a/drivers/s390/net/qeth_ethtool.c +++ b/drivers/s390/net/qeth_ethtool.c @@ -40,6 +40,7 @@ static const struct qeth_stats txq_stats[] = { QETH_TXQ_STAT("Packing mode switches", packing_mode_switch), QETH_TXQ_STAT("Queue stopped", stopped), QETH_TXQ_STAT("Doorbell", doorbell), + QETH_TXQ_STAT("IRQ for frames", coal_frames), QETH_TXQ_STAT("Completion yield", completion_yield), QETH_TXQ_STAT("Completion timer", completion_timer), }; @@ -109,6 +110,38 @@ static void qeth_get_ethtool_stats(struct net_device *dev, txq_stats, TXQ_STATS_LEN); } +static void __qeth_set_coalesce(struct net_device *dev, + struct qeth_qdio_out_q *queue, + struct ethtool_coalesce *coal) +{ + WRITE_ONCE(queue->coalesce_usecs, coal->tx_coalesce_usecs); + WRITE_ONCE(queue->max_coalesced_frames, coal->tx_max_coalesced_frames); + + if (coal->tx_coalesce_usecs && + netif_running(dev) && + !qeth_out_queue_is_empty(queue)) + qeth_tx_arm_timer(queue, coal->tx_coalesce_usecs); +} + +static int qeth_set_coalesce(struct net_device *dev, + struct ethtool_coalesce *coal) +{ + struct qeth_card *card = dev->ml_priv; + struct qeth_qdio_out_q *queue; + unsigned int i; + + if (!IS_IQD(card)) + return -EOPNOTSUPP; + + if (!coal->tx_coalesce_usecs && !coal->tx_max_coalesced_frames) + return -EINVAL; + + qeth_for_each_output_queue(card, queue, i) + __qeth_set_coalesce(dev, queue, coal); + + return 0; +} + static void qeth_get_ringparam(struct net_device *dev, struct ethtool_ringparam *param) { @@ -244,6 +277,43 @@ static int qeth_set_tunable(struct net_device *dev, } } +static int qeth_get_per_queue_coalesce(struct net_device *dev, u32 __queue, + struct ethtool_coalesce *coal) +{ + struct qeth_card *card = dev->ml_priv; + struct qeth_qdio_out_q *queue; + + if (!IS_IQD(card)) + return -EOPNOTSUPP; + + if (__queue >= card->qdio.no_out_queues) + return -EINVAL; + + queue = card->qdio.out_qs[__queue]; + + coal->tx_coalesce_usecs = queue->coalesce_usecs; + coal->tx_max_coalesced_frames = queue->max_coalesced_frames; + return 0; +} + +static int qeth_set_per_queue_coalesce(struct net_device *dev, u32 queue, + struct ethtool_coalesce *coal) +{ + struct qeth_card *card = dev->ml_priv; + + if (!IS_IQD(card)) + return -EOPNOTSUPP; + + if (queue >= card->qdio.no_out_queues) + return -EINVAL; + + if (!coal->tx_coalesce_usecs && !coal->tx_max_coalesced_frames) + return -EINVAL; + + __qeth_set_coalesce(dev, card->qdio.out_qs[queue], coal); + return 0; +} + /* Helper function to fill 'advertising' and 'supported' which are the same. */ /* Autoneg and full-duplex are supported and advertised unconditionally. */ /* Always advertise and support all speeds up to specified, and only one */ @@ -443,7 +513,10 @@ static int qeth_get_link_ksettings(struct net_device *netdev, } const struct ethtool_ops qeth_ethtool_ops = { + .supported_coalesce_params = ETHTOOL_COALESCE_TX_USECS | + ETHTOOL_COALESCE_TX_MAX_FRAMES, .get_link = ethtool_op_get_link, + .set_coalesce = qeth_set_coalesce, .get_ringparam = qeth_get_ringparam, .get_strings = qeth_get_strings, .get_ethtool_stats = qeth_get_ethtool_stats, @@ -454,6 +527,8 @@ const struct ethtool_ops qeth_ethtool_ops = { .get_ts_info = qeth_get_ts_info, .get_tunable = qeth_get_tunable, .set_tunable = qeth_set_tunable, + .get_per_queue_coalesce = qeth_get_per_queue_coalesce, + .set_per_queue_coalesce = qeth_set_per_queue_coalesce, .get_link_ksettings = qeth_get_link_ksettings, }; -- cgit v1.2.3 From bdb0cc128bbf76fac7b4c6731cb72e7c474e55ef Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 25 Mar 2020 10:35:05 +0100 Subject: s390/qeth: fine-tune MAC Address-related errnos Return the correct errnos when .ndo_set_mac_address fails to set a new MAC address. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l2_main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 249b00d91d46..766ea0d07a24 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -52,11 +52,11 @@ static int qeth_l2_setdelmac_makerc(struct qeth_card *card, u16 retcode) break; case IPA_RC_L2_DUP_MAC: case IPA_RC_L2_DUP_LAYER3_MAC: - rc = -EEXIST; + rc = -EADDRINUSE; break; case IPA_RC_L2_MAC_NOT_AUTH_BY_HYP: case IPA_RC_L2_MAC_NOT_AUTH_BY_ADP: - rc = -EPERM; + rc = -EADDRNOTAVAIL; break; case IPA_RC_L2_MAC_NOT_FOUND: rc = -ENOENT; @@ -105,11 +105,11 @@ static int qeth_l2_send_setmac(struct qeth_card *card, __u8 *mac) "MAC address %pM successfully registered\n", mac); } else { switch (rc) { - case -EEXIST: + case -EADDRINUSE: dev_warn(&card->gdev->dev, "MAC address %pM already exists\n", mac); break; - case -EPERM: + case -EADDRNOTAVAIL: dev_warn(&card->gdev->dev, "MAC address %pM is not authorized\n", mac); break; @@ -126,7 +126,7 @@ static int qeth_l2_write_mac(struct qeth_card *card, u8 *mac) QETH_CARD_TEXT(card, 2, "L2Wmac"); rc = qeth_l2_send_setdelmac(card, mac, cmd); - if (rc == -EEXIST) + if (rc == -EADDRINUSE) QETH_DBF_MESSAGE(2, "MAC already registered on device %x\n", CARD_DEVID(card)); else if (rc) -- cgit v1.2.3 From c91a1fb7a4f2ba93eade1611c67b78c40c87e291 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 25 Mar 2020 10:35:06 +0100 Subject: s390/qeth: keep track of fixed prio-queue configuration When a device is configured in prio-queue mode to pin all traffic onto a specific HW queue, treat this as a distinct variant of prio-queueing instead of QETH_NO_PRIO_QUEUEING. This corrects an error message from qeth_osa_set_output_queues() for devices configured in such a mode. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 1 + drivers/s390/net/qeth_core_main.c | 2 ++ drivers/s390/net/qeth_core_sys.c | 8 ++++---- 3 files changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index a6553e78af08..5f85617bdce3 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -211,6 +211,7 @@ struct qeth_vnicc_info { #define QETH_PRIO_Q_ING_TOS 2 #define QETH_PRIO_Q_ING_SKB 3 #define QETH_PRIO_Q_ING_VLAN 4 +#define QETH_PRIO_Q_ING_FIXED 5 /* Packing */ #define QETH_LOW_WATERMARK_PACK 2 diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 0c9f1464a778..8713f1b821c1 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -3646,6 +3646,8 @@ int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb) return ~ntohs(veth->h_vlan_TCI) >> (VLAN_PRIO_SHIFT + 1) & 3; break; + case QETH_PRIO_Q_ING_FIXED: + return card->qdio.default_out_queue; default: break; } diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index 533a7f26dbe1..d7e429f6631e 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c @@ -211,16 +211,16 @@ static ssize_t qeth_dev_prioqing_store(struct device *dev, card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_VLAN; card->qdio.default_out_queue = QETH_DEFAULT_QUEUE; } else if (sysfs_streq(buf, "no_prio_queueing:0")) { - card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING; + card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_FIXED; card->qdio.default_out_queue = 0; } else if (sysfs_streq(buf, "no_prio_queueing:1")) { - card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING; + card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_FIXED; card->qdio.default_out_queue = 1; } else if (sysfs_streq(buf, "no_prio_queueing:2")) { - card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING; + card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_FIXED; card->qdio.default_out_queue = 2; } else if (sysfs_streq(buf, "no_prio_queueing:3")) { - card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING; + card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_FIXED; card->qdio.default_out_queue = 3; } else if (sysfs_streq(buf, "no_prio_queueing")) { card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING; -- cgit v1.2.3 From bb59c8a89a72fa8e4f165847eabf9fd7c1de1ffc Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 25 Mar 2020 10:35:07 +0100 Subject: s390/qeth: modernize two list helpers Replace list_for_each() with list_for_each_entry(), and list_entry(head.next) with list_first_entry(). Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core_main.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 8713f1b821c1..d06d9f847388 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -2629,15 +2629,13 @@ static void qeth_initialize_working_pool_list(struct qeth_card *card) static struct qeth_buffer_pool_entry *qeth_find_free_buffer_pool_entry( struct qeth_card *card) { - struct list_head *plh; struct qeth_buffer_pool_entry *entry; int i, free; if (list_empty(&card->qdio.in_buf_pool.entry_list)) return NULL; - list_for_each(plh, &card->qdio.in_buf_pool.entry_list) { - entry = list_entry(plh, struct qeth_buffer_pool_entry, list); + list_for_each_entry(entry, &card->qdio.in_buf_pool.entry_list, list) { free = 1; for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) { if (page_count(entry->elements[i]) > 1) { @@ -2652,8 +2650,8 @@ static struct qeth_buffer_pool_entry *qeth_find_free_buffer_pool_entry( } /* no free buffer in pool so take first one and swap pages */ - entry = list_entry(card->qdio.in_buf_pool.entry_list.next, - struct qeth_buffer_pool_entry, list); + entry = list_first_entry(&card->qdio.in_buf_pool.entry_list, + struct qeth_buffer_pool_entry, list); for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) { if (page_count(entry->elements[i]) > 1) { struct page *page = dev_alloc_page(); -- cgit v1.2.3 From 5f4019a808399431636aa2adcb3aed611dbd2cd7 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Fri, 27 Mar 2020 11:19:32 +0100 Subject: s390/qeth: remove fake_broadcast attribute Ever since commit 4a71df50047f ("qeth: new qeth device driver") introduced this attribute, it can be read & written but has no actual effect. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_core.h | 1 - drivers/s390/net/qeth_l3_sys.c | 35 ----------------------------------- 2 files changed, 36 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 5f85617bdce3..acda230323d5 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -710,7 +710,6 @@ struct qeth_card_options { struct qeth_ipa_caps adp; /* Adapter parameters */ struct qeth_sbp_info sbp; /* SETBRIDGEPORT options */ struct qeth_vnicc_info vnicc; /* VNICC options */ - int fake_broadcast; enum qeth_discipline_id layer; enum qeth_ipa_isolation_modes isolation; enum qeth_ipa_isolation_modes prev_isolation; diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c index a3d1c3bdfadb..dd0b39082534 100644 --- a/drivers/s390/net/qeth_l3_sys.c +++ b/drivers/s390/net/qeth_l3_sys.c @@ -133,40 +133,6 @@ static ssize_t qeth_l3_dev_route6_store(struct device *dev, static DEVICE_ATTR(route6, 0644, qeth_l3_dev_route6_show, qeth_l3_dev_route6_store); -static ssize_t qeth_l3_dev_fake_broadcast_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct qeth_card *card = dev_get_drvdata(dev); - - return sprintf(buf, "%i\n", card->options.fake_broadcast? 1:0); -} - -static ssize_t qeth_l3_dev_fake_broadcast_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct qeth_card *card = dev_get_drvdata(dev); - char *tmp; - int i, rc = 0; - - mutex_lock(&card->conf_mutex); - if (card->state != CARD_STATE_DOWN) { - rc = -EPERM; - goto out; - } - - i = simple_strtoul(buf, &tmp, 16); - if ((i == 0) || (i == 1)) - card->options.fake_broadcast = i; - else - rc = -EINVAL; -out: - mutex_unlock(&card->conf_mutex); - return rc ? rc : count; -} - -static DEVICE_ATTR(fake_broadcast, 0644, qeth_l3_dev_fake_broadcast_show, - qeth_l3_dev_fake_broadcast_store); - static ssize_t qeth_l3_dev_sniffer_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -305,7 +271,6 @@ static DEVICE_ATTR(hsuid, 0644, qeth_l3_dev_hsuid_show, static struct attribute *qeth_l3_device_attrs[] = { &dev_attr_route4.attr, &dev_attr_route6.attr, - &dev_attr_fake_broadcast.attr, &dev_attr_sniffer.attr, &dev_attr_hsuid.attr, NULL, -- cgit v1.2.3 From 4e2b5aa5676bf969b6e9fe936852caf2d583d47f Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Fri, 27 Mar 2020 11:19:33 +0100 Subject: s390/qeth: make OSN / OSX support configurable The last machine generation that supports OSN is z13, and OSX is only supported up to z14. Allow users and distros to decide whether they still need support for these device types. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/Kconfig | 16 ++++++++++++++++ drivers/s390/net/qeth_core_main.c | 4 ++++ drivers/s390/net/qeth_core_mpc.h | 11 +++++++++++ drivers/s390/net/qeth_l2_main.c | 2 ++ 4 files changed, 33 insertions(+) (limited to 'drivers/s390') diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig index ced896d1534a..36633387b952 100644 --- a/drivers/s390/net/Kconfig +++ b/drivers/s390/net/Kconfig @@ -91,6 +91,22 @@ config QETH_L3 To compile as a module choose M. The module name is qeth_l3. If unsure, choose Y. +config QETH_OSN + def_bool !HAVE_MARCH_Z14_FEATURES + prompt "qeth OSN device support" + depends on QETH + help + This enables the qeth driver to support devices in OSN mode. + If unsure, choose N. + +config QETH_OSX + def_bool !HAVE_MARCH_Z15_FEATURES + prompt "qeth OSX device support" + depends on QETH + help + This enables the qeth driver to support devices in OSX mode. + If unsure, choose N. + config CCWGROUP tristate default (LCS || CTCM || QETH) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index d06d9f847388..24fd17b347fe 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -4951,12 +4951,16 @@ static struct ccw_device_id qeth_ids[] = { .driver_info = QETH_CARD_TYPE_OSD}, {CCW_DEVICE_DEVTYPE(0x1731, 0x05, 0x1732, 0x05), .driver_info = QETH_CARD_TYPE_IQD}, +#ifdef CONFIG_QETH_OSN {CCW_DEVICE_DEVTYPE(0x1731, 0x06, 0x1732, 0x06), .driver_info = QETH_CARD_TYPE_OSN}, +#endif {CCW_DEVICE_DEVTYPE(0x1731, 0x02, 0x1732, 0x03), .driver_info = QETH_CARD_TYPE_OSM}, +#ifdef CONFIG_QETH_OSX {CCW_DEVICE_DEVTYPE(0x1731, 0x02, 0x1732, 0x02), .driver_info = QETH_CARD_TYPE_OSX}, +#endif {}, }; MODULE_DEVICE_TABLE(ccw, qeth_ids); diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h index 6f304fdbb073..d89a04bfd8b0 100644 --- a/drivers/s390/net/qeth_core_mpc.h +++ b/drivers/s390/net/qeth_core_mpc.h @@ -74,8 +74,19 @@ enum qeth_card_types { #define IS_IQD(card) ((card)->info.type == QETH_CARD_TYPE_IQD) #define IS_OSD(card) ((card)->info.type == QETH_CARD_TYPE_OSD) #define IS_OSM(card) ((card)->info.type == QETH_CARD_TYPE_OSM) + +#ifdef CONFIG_QETH_OSN #define IS_OSN(card) ((card)->info.type == QETH_CARD_TYPE_OSN) +#else +#define IS_OSN(card) false +#endif + +#ifdef CONFIG_QETH_OSX #define IS_OSX(card) ((card)->info.type == QETH_CARD_TYPE_OSX) +#else +#define IS_OSX(card) false +#endif + #define IS_VM_NIC(card) ((card)->info.is_vm_nic) #define QETH_MPC_DIFINFO_LEN_INDICATES_LINK_TYPE 0x18 diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 766ea0d07a24..974b4596b78d 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -869,6 +869,7 @@ struct qeth_discipline qeth_l2_discipline = { }; EXPORT_SYMBOL_GPL(qeth_l2_discipline); +#ifdef CONFIG_QETH_OSN static void qeth_osn_assist_cb(struct qeth_card *card, struct qeth_cmd_buffer *iob, unsigned int data_length) @@ -945,6 +946,7 @@ void qeth_osn_deregister(struct net_device *dev) return; } EXPORT_SYMBOL(qeth_osn_deregister); +#endif /* SETBRIDGEPORT support, async notifications */ -- cgit v1.2.3 From fb64de1bc36c7fdeb3b4279d0fe52496ce34c45a Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Fri, 27 Mar 2020 11:19:34 +0100 Subject: s390/qeth: phase out OSN support OSN devices currently spend an awful long time in qeth_l2_set_online() until various unsupported HW cmds time out. This has been broken for over two years, ever since commit d22ffb5a712f ("s390/qeth: fix IPA command submission race") triggered a FW bug in cmd processing. Prior to commit 782e4a792147 ("s390/qeth: don't poll for cmd IO completion"), this wait for timeout would have even been spent busy-polling. The offending patch was picked up by stable and all relevant distros, and yet noone noticed. OSN setups only ever worked in combination with an out-of-tree blob, and the last machine that even offered HW with OSN support was released back in 2015. Rather than attempting to work-around this FW issue for no actual gain, add a deprecation warning so anyone who still wants to maintain this part of the code can speak up. Else rip it all out in 2021. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/Kconfig | 1 + drivers/s390/net/qeth_l2_main.c | 3 +++ 2 files changed, 4 insertions(+) (limited to 'drivers/s390') diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig index 36633387b952..3850a0f5f0bc 100644 --- a/drivers/s390/net/Kconfig +++ b/drivers/s390/net/Kconfig @@ -97,6 +97,7 @@ config QETH_OSN depends on QETH help This enables the qeth driver to support devices in OSN mode. + This feature will be removed in 2021. If unsure, choose N. config QETH_OSX diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 974b4596b78d..0bd5b09e7a22 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -587,6 +587,9 @@ 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); -- cgit v1.2.3 From b8f14878e6ae210cad4025bfc97dca877b4df721 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Fri, 27 Mar 2020 12:00:42 +0100 Subject: s390/qeth: support net namespaces for L3 devices Enable the L3 driver's IPv4 address notifier to watch for events on qeth devices that have been moved into a net namespace. We need to program those IPs into the HW just as usual, otherwise inbound traffic won't flow. Fixes: 6133fb1aa137 ("[NETNS]: Disable inetaddr notifiers in namespaces other than initial.") Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller --- drivers/s390/net/qeth_l3_main.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index b48cd0df3e31..0742a749d26e 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2195,9 +2195,6 @@ static int qeth_l3_ip_event(struct notifier_block *this, struct qeth_ipaddr addr; struct qeth_card *card; - if (dev_net(dev) != &init_net) - return NOTIFY_DONE; - card = qeth_l3_get_card_from_dev(dev); if (!card) return NOTIFY_DONE; -- cgit v1.2.3