From 7f3c6e6b905018d07228fe0f43f0ef1359e7196d Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Fri, 21 Apr 2017 15:38:40 -0400 Subject: [PATCH 1/7] ibmvnic: Set real number of rx queues Along with 5 TX queues, 5 RX queues are allocated at the beginning of device probe. However, only the real number of TX queues is set. Configure the real number of RX queues as well. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index e8c72abfd7ac..7f4cecbb4b5a 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -560,6 +560,24 @@ static void release_resources(struct ibmvnic_adapter *adapter) release_error_buffers(adapter); } +static int set_real_num_queues(struct net_device *netdev) +{ + struct ibmvnic_adapter *adapter = netdev_priv(netdev); + int rc; + + rc = netif_set_real_num_tx_queues(netdev, adapter->req_tx_queues); + if (rc) { + netdev_err(netdev, "failed to set the number of tx queues\n"); + return rc; + } + + rc = netif_set_real_num_rx_queues(netdev, adapter->req_rx_queues); + if (rc) + netdev_err(netdev, "failed to set the number of rx queues\n"); + + return rc; +} + static int ibmvnic_open(struct net_device *netdev) { struct ibmvnic_adapter *adapter = netdev_priv(netdev); @@ -578,11 +596,9 @@ static int ibmvnic_open(struct net_device *netdev) if (rc) return rc; - rc = netif_set_real_num_tx_queues(netdev, adapter->req_tx_queues); - if (rc) { - dev_err(dev, "failed to set the number of tx queues\n"); - return -1; - } + rc = set_real_num_queues(netdev); + if (rc) + return rc; rc = init_sub_crq_irqs(adapter); if (rc) { From 6052d5e2a1961b59dd942b52d3bf2b395d023644 Mon Sep 17 00:00:00 2001 From: Murilo Fossa Vicentini Date: Fri, 21 Apr 2017 15:38:46 -0400 Subject: [PATCH 2/7] ibmvnic: Insert header on VLAN tagged received frame This patch addresses a modification in the PAPR+ specification which now defines a previously reserved value for vNIC capabilities. It indicates whether the system firmware performs a VLAN header stripping on all VLAN tagged received frames, in case it does, the behavior expected is for the ibmvnic driver to be responsible for inserting the VLAN header. Reported-by: Manvanthara B. Puttashankar Signed-off-by: Murilo Fossa Vicentini Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 21 ++++++++++++++++++++- drivers/net/ethernet/ibm/ibmvnic.h | 2 ++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 7f4cecbb4b5a..0f3595439293 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -74,6 +74,7 @@ #include #include #include +#include #include "ibmvnic.h" @@ -1105,7 +1106,15 @@ static int ibmvnic_poll(struct napi_struct *napi, int budget) skb = rx_buff->skb; skb_copy_to_linear_data(skb, rx_buff->data + offset, length); - skb->vlan_tci = be16_to_cpu(next->rx_comp.vlan_tci); + + /* VLAN Header has been stripped by the system firmware and + * needs to be inserted by the driver + */ + if (adapter->rx_vlan_header_insertion && + (flags & IBMVNIC_VLAN_STRIPPED)) + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), + ntohs(next->rx_comp.vlan_tci)); + /* free the entry */ next->rx_comp.first = 0; remove_buff_from_pool(adapter, rx_buff); @@ -2170,6 +2179,10 @@ static void send_cap_queries(struct ibmvnic_adapter *adapter) atomic_inc(&adapter->running_cap_crqs); ibmvnic_send_crq(adapter, &crq); + crq.query_capability.capability = cpu_to_be16(RX_VLAN_HEADER_INSERTION); + atomic_inc(&adapter->running_cap_crqs); + ibmvnic_send_crq(adapter, &crq); + crq.query_capability.capability = cpu_to_be16(MAX_TX_SG_ENTRIES); atomic_inc(&adapter->running_cap_crqs); ibmvnic_send_crq(adapter, &crq); @@ -2719,6 +2732,12 @@ static void handle_query_cap_rsp(union ibmvnic_crq *crq, netdev_dbg(netdev, "vlan_header_insertion = %lld\n", adapter->vlan_header_insertion); break; + case RX_VLAN_HEADER_INSERTION: + adapter->rx_vlan_header_insertion = + be64_to_cpu(crq->query_capability.number); + netdev_dbg(netdev, "rx_vlan_header_insertion = %lld\n", + adapter->rx_vlan_header_insertion); + break; case MAX_TX_SG_ENTRIES: adapter->max_tx_sg_entries = be64_to_cpu(crq->query_capability.number); diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h index 355225cf6d30..387c84303b7f 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.h +++ b/drivers/net/ethernet/ibm/ibmvnic.h @@ -733,6 +733,7 @@ enum ibmvnic_capabilities { REQ_MTU = 21, MAX_MULTICAST_FILTERS = 22, VLAN_HEADER_INSERTION = 23, + RX_VLAN_HEADER_INSERTION = 24, MAX_TX_SG_ENTRIES = 25, RX_SG_SUPPORTED = 26, RX_SG_REQUESTED = 27, @@ -993,6 +994,7 @@ struct ibmvnic_adapter { u64 req_mtu; u64 max_multicast_filters; u64 vlan_header_insertion; + u64 rx_vlan_header_insertion; u64 max_tx_sg_entries; u64 rx_sg_supported; u64 rx_sg_requested; From 2f9de9bac625ae08e9ea132e8dc08cfbe9fb67d2 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Fri, 21 Apr 2017 15:38:52 -0400 Subject: [PATCH 3/7] ibmvnic: Only retrieve error info if present When handling a fatal error in the driver, there can be additional error information provided by the vios. This information is not always present, so only retrieve the additional error information when present. Signed-off-by: Nathan Fontenot Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 71 +++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 0f3595439293..cc34bf9be405 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -2361,25 +2361,22 @@ static void handle_error_info_rsp(union ibmvnic_crq *crq, kfree(error_buff); } -static void handle_error_indication(union ibmvnic_crq *crq, - struct ibmvnic_adapter *adapter) +static void request_error_information(struct ibmvnic_adapter *adapter, + union ibmvnic_crq *err_crq) { - int detail_len = be32_to_cpu(crq->error_indication.detail_error_sz); struct device *dev = &adapter->vdev->dev; + struct net_device *netdev = adapter->netdev; struct ibmvnic_error_buff *error_buff; - union ibmvnic_crq new_crq; + unsigned long timeout = msecs_to_jiffies(30000); + union ibmvnic_crq crq; unsigned long flags; - - dev_err(dev, "Firmware reports %serror id %x, cause %d\n", - crq->error_indication. - flags & IBMVNIC_FATAL_ERROR ? "FATAL " : "", - be32_to_cpu(crq->error_indication.error_id), - be16_to_cpu(crq->error_indication.error_cause)); + int rc, detail_len; error_buff = kmalloc(sizeof(*error_buff), GFP_ATOMIC); if (!error_buff) return; + detail_len = be32_to_cpu(err_crq->error_indication.detail_error_sz); error_buff->buff = kmalloc(detail_len, GFP_ATOMIC); if (!error_buff->buff) { kfree(error_buff); @@ -2389,27 +2386,61 @@ static void handle_error_indication(union ibmvnic_crq *crq, error_buff->dma = dma_map_single(dev, error_buff->buff, detail_len, DMA_FROM_DEVICE); if (dma_mapping_error(dev, error_buff->dma)) { - if (!firmware_has_feature(FW_FEATURE_CMO)) - dev_err(dev, "Couldn't map error buffer\n"); + netdev_err(netdev, "Couldn't map error buffer\n"); kfree(error_buff->buff); kfree(error_buff); return; } error_buff->len = detail_len; - error_buff->error_id = crq->error_indication.error_id; + error_buff->error_id = err_crq->error_indication.error_id; spin_lock_irqsave(&adapter->error_list_lock, flags); list_add_tail(&error_buff->list, &adapter->errors); spin_unlock_irqrestore(&adapter->error_list_lock, flags); - memset(&new_crq, 0, sizeof(new_crq)); - new_crq.request_error_info.first = IBMVNIC_CRQ_CMD; - new_crq.request_error_info.cmd = REQUEST_ERROR_INFO; - new_crq.request_error_info.ioba = cpu_to_be32(error_buff->dma); - new_crq.request_error_info.len = cpu_to_be32(detail_len); - new_crq.request_error_info.error_id = crq->error_indication.error_id; - ibmvnic_send_crq(adapter, &new_crq); + memset(&crq, 0, sizeof(crq)); + crq.request_error_info.first = IBMVNIC_CRQ_CMD; + crq.request_error_info.cmd = REQUEST_ERROR_INFO; + crq.request_error_info.ioba = cpu_to_be32(error_buff->dma); + crq.request_error_info.len = cpu_to_be32(detail_len); + crq.request_error_info.error_id = err_crq->error_indication.error_id; + + rc = ibmvnic_send_crq(adapter, &crq); + if (rc) { + netdev_err(netdev, "failed to request error information\n"); + goto err_info_fail; + } + + if (!wait_for_completion_timeout(&adapter->init_done, timeout)) { + netdev_err(netdev, "timeout waiting for error information\n"); + goto err_info_fail; + } + + return; + +err_info_fail: + spin_lock_irqsave(&adapter->error_list_lock, flags); + list_del(&error_buff->list); + spin_unlock_irqrestore(&adapter->error_list_lock, flags); + + kfree(error_buff->buff); + kfree(error_buff); +} + +static void handle_error_indication(union ibmvnic_crq *crq, + struct ibmvnic_adapter *adapter) +{ + struct device *dev = &adapter->vdev->dev; + + dev_err(dev, "Firmware reports %serror id %x, cause %d\n", + crq->error_indication.flags + & IBMVNIC_FATAL_ERROR ? "FATAL " : "", + be32_to_cpu(crq->error_indication.error_id), + be16_to_cpu(crq->error_indication.error_cause)); + + if (be32_to_cpu(crq->error_indication.error_id)) + request_error_information(adapter, crq); } static void handle_change_mac_rsp(union ibmvnic_crq *crq, From 5d5e84eb7276d30a21257515a83b34d1ef77f99b Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Fri, 21 Apr 2017 15:38:58 -0400 Subject: [PATCH 4/7] ibmvnic: Move initialization of the stats token to ibmvnic_open We should be initializing the stats token in the same place we initialize the other resources for the driver. Signed-off-by: Nathan Fontenot Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index cc34bf9be405..199cccbb577a 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -607,6 +607,10 @@ static int ibmvnic_open(struct net_device *netdev) return -1; } + rc = init_stats_token(adapter); + if (rc) + return rc; + adapter->map_id = 1; adapter->napi = kcalloc(adapter->req_rx_queues, sizeof(struct napi_struct), GFP_KERNEL); @@ -3241,12 +3245,6 @@ static int ibmvnic_init(struct ibmvnic_adapter *adapter) return rc; } - rc = init_stats_token(adapter); - if (rc) { - release_crq_queue(adapter); - return rc; - } - init_completion(&adapter->init_done); ibmvnic_send_crq_init(adapter); if (!wait_for_completion_timeout(&adapter->init_done, timeout)) { From 53da09e92910f675ebb93921007428a3c2a024fb Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Fri, 21 Apr 2017 15:39:04 -0400 Subject: [PATCH 5/7] ibmvnic: Add set_link_state routine for setting adapter link state Create a common routine for setting the link state for the vnic adapter. This update moves the sending of the crq and waiting for the link state response to a common place. The new routine also adds handling of resending the crq in cases of getting a partial success response. Signed-off-by: Nathan Fontenot Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 71 ++++++++++++++++++++++++------ drivers/net/ethernet/ibm/ibmvnic.h | 1 + 2 files changed, 58 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 199cccbb577a..115f21694994 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -561,6 +561,51 @@ static void release_resources(struct ibmvnic_adapter *adapter) release_error_buffers(adapter); } +static int set_link_state(struct ibmvnic_adapter *adapter, u8 link_state) +{ + struct net_device *netdev = adapter->netdev; + unsigned long timeout = msecs_to_jiffies(30000); + union ibmvnic_crq crq; + bool resend; + int rc; + + if (adapter->logical_link_state == link_state) { + netdev_dbg(netdev, "Link state already %d\n", link_state); + return 0; + } + + netdev_err(netdev, "setting link state %d\n", link_state); + memset(&crq, 0, sizeof(crq)); + crq.logical_link_state.first = IBMVNIC_CRQ_CMD; + crq.logical_link_state.cmd = LOGICAL_LINK_STATE; + crq.logical_link_state.link_state = link_state; + + do { + resend = false; + + reinit_completion(&adapter->init_done); + rc = ibmvnic_send_crq(adapter, &crq); + if (rc) { + netdev_err(netdev, "Failed to set link state\n"); + return rc; + } + + if (!wait_for_completion_timeout(&adapter->init_done, + timeout)) { + netdev_err(netdev, "timeout setting link state\n"); + return -1; + } + + if (adapter->init_done_rc == 1) { + /* Partuial success, delay and re-send */ + mdelay(1000); + resend = true; + } + } while (resend); + + return 0; +} + static int set_real_num_queues(struct net_device *netdev) { struct ibmvnic_adapter *adapter = netdev_priv(netdev); @@ -583,7 +628,6 @@ static int ibmvnic_open(struct net_device *netdev) { struct ibmvnic_adapter *adapter = netdev_priv(netdev); struct device *dev = &adapter->vdev->dev; - union ibmvnic_crq crq; int rc = 0; int i; @@ -643,11 +687,9 @@ static int ibmvnic_open(struct net_device *netdev) for (i = 0; i < adapter->req_tx_queues; i++) enable_scrq_irq(adapter, adapter->tx_scrq[i]); - memset(&crq, 0, sizeof(crq)); - crq.logical_link_state.first = IBMVNIC_CRQ_CMD; - crq.logical_link_state.cmd = LOGICAL_LINK_STATE; - crq.logical_link_state.link_state = IBMVNIC_LOGICAL_LNK_UP; - ibmvnic_send_crq(adapter, &crq); + rc = set_link_state(adapter, IBMVNIC_LOGICAL_LNK_UP); + if (rc) + goto ibmvnic_open_fail; netif_tx_start_all_queues(netdev); adapter->is_closed = false; @@ -681,7 +723,7 @@ static void disable_sub_crqs(struct ibmvnic_adapter *adapter) static int ibmvnic_close(struct net_device *netdev) { struct ibmvnic_adapter *adapter = netdev_priv(netdev); - union ibmvnic_crq crq; + int rc = 0; int i; adapter->closing = true; @@ -693,17 +735,13 @@ static int ibmvnic_close(struct net_device *netdev) if (!adapter->failover) netif_tx_stop_all_queues(netdev); - memset(&crq, 0, sizeof(crq)); - crq.logical_link_state.first = IBMVNIC_CRQ_CMD; - crq.logical_link_state.cmd = LOGICAL_LINK_STATE; - crq.logical_link_state.link_state = IBMVNIC_LOGICAL_LNK_DN; - ibmvnic_send_crq(adapter, &crq); + rc = set_link_state(adapter, IBMVNIC_LOGICAL_LNK_DN); release_resources(adapter); adapter->is_closed = true; adapter->closing = false; - return 0; + return rc; } /** @@ -2945,9 +2983,14 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq, handle_login_rsp(crq, adapter); break; case LOGICAL_LINK_STATE_RSP: - netdev_dbg(netdev, "Got Logical Link State Response\n"); + netdev_dbg(netdev, + "Got Logical Link State Response, state: %d rc: %d\n", + crq->logical_link_state_rsp.link_state, + crq->logical_link_state_rsp.rc.code); adapter->logical_link_state = crq->logical_link_state_rsp.link_state; + adapter->init_done_rc = crq->logical_link_state_rsp.rc.code; + complete(&adapter->init_done); break; case LINK_STATE_INDICATION: netdev_dbg(netdev, "Got Logical Link State Indication\n"); diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h index 387c84303b7f..a69979f6f19d 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.h +++ b/drivers/net/ethernet/ibm/ibmvnic.h @@ -964,6 +964,7 @@ struct ibmvnic_adapter { struct ibmvnic_tx_pool *tx_pool; bool closing; struct completion init_done; + int init_done_rc; struct list_head errors; spinlock_t error_list_lock; From 3ca1993264503957f81f3846598b16601b1e9457 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Fri, 21 Apr 2017 15:39:10 -0400 Subject: [PATCH 6/7] ibmvnic: Validate napi exist before disabling them Validate that the napi structs exist before trying to disable them at driver close. Signed-off-by: Nathan Fontenot Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 115f21694994..5a916a2f91be 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -729,8 +729,10 @@ static int ibmvnic_close(struct net_device *netdev) adapter->closing = true; disable_sub_crqs(adapter); - for (i = 0; i < adapter->req_rx_queues; i++) - napi_disable(&adapter->napi[i]); + if (adapter->napi) { + for (i = 0; i < adapter->req_rx_queues; i++) + napi_disable(&adapter->napi[i]); + } if (!adapter->failover) netif_tx_stop_all_queues(netdev); From 7f5b030830fecc4a2a235804a15b395720b48a24 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Fri, 21 Apr 2017 15:39:16 -0400 Subject: [PATCH 7/7] ibmvnic: Free skb's in cases of failure in transmit When an error is encountered during transmit we need to free the skb instead of returning TX_BUSY. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 5a916a2f91be..51bf337bea7a 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -908,9 +908,13 @@ static int ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev) be32_to_cpu(adapter->login_rsp_buf-> off_txsubm_subcrqs)); if (adapter->migrated) { + if (!netif_subqueue_stopped(netdev, skb)) + netif_stop_subqueue(netdev, queue_num); + dev_kfree_skb_any(skb); + tx_send_failed++; tx_dropped++; - ret = NETDEV_TX_BUSY; + ret = NETDEV_TX_OK; goto out; } @@ -976,11 +980,13 @@ static int ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev) sizeof(tx_buff->indir_arr), DMA_TO_DEVICE); if (dma_mapping_error(dev, tx_buff->indir_dma)) { + dev_kfree_skb_any(skb); + tx_buff->skb = NULL; if (!firmware_has_feature(FW_FEATURE_CMO)) dev_err(dev, "tx: unable to map descriptor array\n"); tx_map_failed++; tx_dropped++; - ret = NETDEV_TX_BUSY; + ret = NETDEV_TX_OK; goto out; } lpar_rc = send_subcrq_indirect(adapter, handle_array[queue_num], @@ -999,9 +1005,15 @@ static int ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev) else tx_pool->consumer_index--; + dev_kfree_skb_any(skb); + tx_buff->skb = NULL; + + if (lpar_rc == H_CLOSED) + netif_stop_subqueue(netdev, queue_num); + tx_send_failed++; tx_dropped++; - ret = NETDEV_TX_BUSY; + ret = NETDEV_TX_OK; goto out; }