From f992887c34a15d40a257c73fe59800826bcaf1a4 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Thu, 30 Mar 2017 02:48:54 -0400 Subject: [PATCH 1/7] ibmvnic: Update main crq initialization and release Update the initialization and release routines for the crq queue so that we validate the crq queue. Additionally this updates the naming of the init and release routines for the crq queue to drop the ibmvnic prefix. This matches the naming for similar routines in the driver Signed-off-by: Nathan Fontenot Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 1e8ba784ec92..01ab60f4a92a 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -113,7 +113,7 @@ static void send_login(struct ibmvnic_adapter *adapter); static void send_cap_queries(struct ibmvnic_adapter *adapter); static int init_sub_crq_irqs(struct ibmvnic_adapter *adapter); static int ibmvnic_init(struct ibmvnic_adapter *); -static void ibmvnic_release_crq_queue(struct ibmvnic_adapter *); +static void release_crq_queue(struct ibmvnic_adapter *); struct ibmvnic_stat { char name[ETH_GSTRING_LEN]; @@ -612,7 +612,7 @@ static void ibmvnic_release_resources(struct ibmvnic_adapter *adapter) adapter->rx_pool = NULL; release_sub_crqs(adapter); - ibmvnic_release_crq_queue(adapter); + release_crq_queue(adapter); if (adapter->stats_token) dma_unmap_single(dev, adapter->stats_token, @@ -3069,12 +3069,15 @@ static int ibmvnic_reset_crq(struct ibmvnic_adapter *adapter) return rc; } -static void ibmvnic_release_crq_queue(struct ibmvnic_adapter *adapter) +static void release_crq_queue(struct ibmvnic_adapter *adapter) { struct ibmvnic_crq_queue *crq = &adapter->crq; struct vio_dev *vdev = adapter->vdev; long rc; + if (!crq->msgs) + return; + netdev_dbg(adapter->netdev, "Releasing CRQ\n"); free_irq(vdev->irq, adapter); tasklet_kill(&adapter->tasklet); @@ -3085,15 +3088,19 @@ static void ibmvnic_release_crq_queue(struct ibmvnic_adapter *adapter) dma_unmap_single(&vdev->dev, crq->msg_token, PAGE_SIZE, DMA_BIDIRECTIONAL); free_page((unsigned long)crq->msgs); + crq->msgs = NULL; } -static int ibmvnic_init_crq_queue(struct ibmvnic_adapter *adapter) +static int init_crq_queue(struct ibmvnic_adapter *adapter) { struct ibmvnic_crq_queue *crq = &adapter->crq; struct device *dev = &adapter->vdev->dev; struct vio_dev *vdev = adapter->vdev; int rc, retrc = -ENOMEM; + if (crq->msgs) + return 0; + crq->msgs = (union ibmvnic_crq *)get_zeroed_page(GFP_KERNEL); /* Should we allocate more than one page? */ @@ -3155,6 +3162,7 @@ reg_crq_failed: dma_unmap_single(dev, crq->msg_token, PAGE_SIZE, DMA_BIDIRECTIONAL); map_failed: free_page((unsigned long)crq->msgs); + crq->msgs = NULL; return retrc; } @@ -3222,7 +3230,7 @@ static int ibmvnic_init(struct ibmvnic_adapter *adapter) unsigned long timeout = msecs_to_jiffies(30000); int rc; - rc = ibmvnic_init_crq_queue(adapter); + rc = init_crq_queue(adapter); if (rc) { dev_err(dev, "Couldn't initialize crq. rc=%d\n", rc); return rc; @@ -3232,7 +3240,7 @@ static int ibmvnic_init(struct ibmvnic_adapter *adapter) sizeof(struct ibmvnic_statistics), DMA_FROM_DEVICE); if (dma_mapping_error(dev, adapter->stats_token)) { - ibmvnic_release_crq_queue(adapter); + release_crq_queue(adapter); dev_err(dev, "Couldn't map stats buffer\n"); return -ENOMEM; } @@ -3241,7 +3249,7 @@ static int ibmvnic_init(struct ibmvnic_adapter *adapter) ibmvnic_send_crq_init(adapter); if (!wait_for_completion_timeout(&adapter->init_done, timeout)) { dev_err(dev, "Initialization sequence timed out\n"); - ibmvnic_release_crq_queue(adapter); + release_crq_queue(adapter); return -1; } From f0b8c96cbcc5fbd4f66abcbf4bc442a1066d8899 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Thu, 30 Mar 2017 02:49:00 -0400 Subject: [PATCH 2/7] ibmvnic: Create init and release routines for the bounce buffer Move the handling of initialization and releasing the bounce buffer to their own init and release routines. Signed-off-by: Nathan Fontenot Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 77 +++++++++++++++++++----------- 1 file changed, 50 insertions(+), 27 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 01ab60f4a92a..c3e5305604c8 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -372,6 +372,50 @@ static void free_rx_pool(struct ibmvnic_adapter *adapter, pool->rx_buff = NULL; } +static void release_bounce_buffer(struct ibmvnic_adapter *adapter) +{ + struct device *dev = &adapter->vdev->dev; + + if (!adapter->bounce_buffer) + return; + + if (!dma_mapping_error(dev, adapter->bounce_buffer_dma)) { + dma_unmap_single(dev, adapter->bounce_buffer_dma, + adapter->bounce_buffer_size, + DMA_BIDIRECTIONAL); + adapter->bounce_buffer_dma = DMA_ERROR_CODE; + } + + kfree(adapter->bounce_buffer); + adapter->bounce_buffer = NULL; +} + +static int init_bounce_buffer(struct net_device *netdev) +{ + struct ibmvnic_adapter *adapter = netdev_priv(netdev); + struct device *dev = &adapter->vdev->dev; + char *buf; + int buf_sz; + dma_addr_t map_addr; + + buf_sz = (netdev->mtu + ETH_HLEN - 1) / PAGE_SIZE + 1; + buf = kmalloc(adapter->bounce_buffer_size, GFP_KERNEL); + if (!buf) + return -1; + + map_addr = dma_map_single(dev, buf, buf_sz, DMA_TO_DEVICE); + if (dma_mapping_error(dev, map_addr)) { + dev_err(dev, "Couldn't map bounce buffer\n"); + kfree(buf); + return -1; + } + + adapter->bounce_buffer = buf; + adapter->bounce_buffer_size = buf_sz; + adapter->bounce_buffer_dma = map_addr; + return 0; +} + static int ibmvnic_login(struct net_device *netdev) { struct ibmvnic_adapter *adapter = netdev_priv(netdev); @@ -500,20 +544,11 @@ static int ibmvnic_open(struct net_device *netdev) tx_pool->consumer_index = 0; tx_pool->producer_index = 0; } - adapter->bounce_buffer_size = - (netdev->mtu + ETH_HLEN - 1) / PAGE_SIZE + 1; - adapter->bounce_buffer = kmalloc(adapter->bounce_buffer_size, - GFP_KERNEL); - if (!adapter->bounce_buffer) - goto bounce_alloc_failed; - adapter->bounce_buffer_dma = dma_map_single(dev, adapter->bounce_buffer, - adapter->bounce_buffer_size, - DMA_TO_DEVICE); - if (dma_mapping_error(dev, adapter->bounce_buffer_dma)) { - dev_err(dev, "Couldn't map tx bounce buffer\n"); - goto bounce_map_failed; - } + rc = init_bounce_buffer(netdev); + if (rc) + goto bounce_init_failed; + replenish_pools(adapter); /* We're ready to receive frames, enable the sub-crq interrupts and @@ -536,9 +571,7 @@ static int ibmvnic_open(struct net_device *netdev) return 0; -bounce_map_failed: - kfree(adapter->bounce_buffer); -bounce_alloc_failed: +bounce_init_failed: i = tx_subcrqs - 1; kfree(adapter->tx_pool[i].free_map); tx_fm_alloc_failed: @@ -578,17 +611,7 @@ static void ibmvnic_release_resources(struct ibmvnic_adapter *adapter) int tx_scrqs, rx_scrqs; int i; - if (adapter->bounce_buffer) { - if (!dma_mapping_error(dev, adapter->bounce_buffer_dma)) { - dma_unmap_single(&adapter->vdev->dev, - adapter->bounce_buffer_dma, - adapter->bounce_buffer_size, - DMA_BIDIRECTIONAL); - adapter->bounce_buffer_dma = DMA_ERROR_CODE; - } - kfree(adapter->bounce_buffer); - adapter->bounce_buffer = NULL; - } + release_bounce_buffer(adapter); tx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_txsubm_subcrqs); for (i = 0; i < tx_scrqs; i++) { From c657e32cd0555e97ae8903f8a5a9d7c2f3579650 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Thu, 30 Mar 2017 02:49:06 -0400 Subject: [PATCH 3/7] ibmvnic: Create init and release routines for the tx pool Move the initialization and the release of the tx pool to their own routines, and update them to do validation. This also adds validation to the release of the long term buffer. Signed-off-by: Nathan Fontenot Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 134 +++++++++++++++++------------ 1 file changed, 78 insertions(+), 56 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index c3e5305604c8..a9399e96e942 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -206,6 +206,9 @@ static void free_long_term_buff(struct ibmvnic_adapter *adapter, { struct device *dev = &adapter->vdev->dev; + if (!ltb->buff) + return; + dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr); if (!adapter->failover) send_request_unmap(adapter, ltb->map_id); @@ -372,6 +375,75 @@ static void free_rx_pool(struct ibmvnic_adapter *adapter, pool->rx_buff = NULL; } +static void release_tx_pools(struct ibmvnic_adapter *adapter) +{ + struct ibmvnic_tx_pool *tx_pool; + int i, tx_scrqs; + + if (!adapter->tx_pool) + return; + + tx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_txsubm_subcrqs); + for (i = 0; i < tx_scrqs; i++) { + tx_pool = &adapter->tx_pool[i]; + kfree(tx_pool->tx_buff); + free_long_term_buff(adapter, &tx_pool->long_term_buff); + kfree(tx_pool->free_map); + } + + kfree(adapter->tx_pool); + adapter->tx_pool = NULL; +} + +static int init_tx_pools(struct net_device *netdev) +{ + struct ibmvnic_adapter *adapter = netdev_priv(netdev); + struct device *dev = &adapter->vdev->dev; + struct ibmvnic_tx_pool *tx_pool; + int tx_subcrqs; + int i, j; + + tx_subcrqs = be32_to_cpu(adapter->login_rsp_buf->num_txsubm_subcrqs); + adapter->tx_pool = kcalloc(tx_subcrqs, + sizeof(struct ibmvnic_tx_pool), GFP_KERNEL); + if (!adapter->tx_pool) + return -1; + + for (i = 0; i < tx_subcrqs; i++) { + tx_pool = &adapter->tx_pool[i]; + tx_pool->tx_buff = kcalloc(adapter->req_tx_entries_per_subcrq, + sizeof(struct ibmvnic_tx_buff), + GFP_KERNEL); + if (!tx_pool->tx_buff) { + dev_err(dev, "tx pool buffer allocation failed\n"); + release_tx_pools(adapter); + return -1; + } + + if (alloc_long_term_buff(adapter, &tx_pool->long_term_buff, + adapter->req_tx_entries_per_subcrq * + adapter->req_mtu)) { + release_tx_pools(adapter); + return -1; + } + + tx_pool->free_map = kcalloc(adapter->req_tx_entries_per_subcrq, + sizeof(int), GFP_KERNEL); + if (!tx_pool->free_map) { + release_tx_pools(adapter); + return -1; + } + + for (j = 0; j < adapter->req_tx_entries_per_subcrq; j++) + tx_pool->free_map[j] = j; + + tx_pool->consumer_index = 0; + tx_pool->producer_index = 0; + } + + return 0; +} + static void release_bounce_buffer(struct ibmvnic_adapter *adapter) { struct device *dev = &adapter->vdev->dev; @@ -452,7 +524,6 @@ static int ibmvnic_open(struct net_device *netdev) { struct ibmvnic_adapter *adapter = netdev_priv(netdev); struct device *dev = &adapter->vdev->dev; - struct ibmvnic_tx_pool *tx_pool; union ibmvnic_crq crq; int rxadd_subcrqs; u64 *size_array; @@ -514,36 +585,10 @@ static int ibmvnic_open(struct net_device *netdev) goto rx_pool_alloc_failed; } } - adapter->tx_pool = - kcalloc(tx_subcrqs, sizeof(struct ibmvnic_tx_pool), GFP_KERNEL); - if (!adapter->tx_pool) - goto tx_pool_arr_alloc_failed; - for (i = 0; i < tx_subcrqs; i++) { - tx_pool = &adapter->tx_pool[i]; - tx_pool->tx_buff = - kcalloc(adapter->req_tx_entries_per_subcrq, - sizeof(struct ibmvnic_tx_buff), GFP_KERNEL); - if (!tx_pool->tx_buff) - goto tx_pool_alloc_failed; - - if (alloc_long_term_buff(adapter, &tx_pool->long_term_buff, - adapter->req_tx_entries_per_subcrq * - adapter->req_mtu)) - goto tx_ltb_alloc_failed; - - tx_pool->free_map = - kcalloc(adapter->req_tx_entries_per_subcrq, - sizeof(int), GFP_KERNEL); - if (!tx_pool->free_map) - goto tx_fm_alloc_failed; - - for (j = 0; j < adapter->req_tx_entries_per_subcrq; j++) - tx_pool->free_map[j] = j; - - tx_pool->consumer_index = 0; - tx_pool->producer_index = 0; - } + rc = init_tx_pools(netdev); + if (rc) + goto tx_pool_failed; rc = init_bounce_buffer(netdev); if (rc) @@ -574,20 +619,7 @@ static int ibmvnic_open(struct net_device *netdev) bounce_init_failed: i = tx_subcrqs - 1; kfree(adapter->tx_pool[i].free_map); -tx_fm_alloc_failed: - free_long_term_buff(adapter, &adapter->tx_pool[i].long_term_buff); -tx_ltb_alloc_failed: - kfree(adapter->tx_pool[i].tx_buff); -tx_pool_alloc_failed: - for (j = 0; j < i; j++) { - kfree(adapter->tx_pool[j].tx_buff); - free_long_term_buff(adapter, - &adapter->tx_pool[j].long_term_buff); - kfree(adapter->tx_pool[j].free_map); - } - kfree(adapter->tx_pool); - adapter->tx_pool = NULL; -tx_pool_arr_alloc_failed: +tx_pool_failed: i = rxadd_subcrqs; rx_pool_alloc_failed: for (j = 0; j < i; j++) { @@ -608,21 +640,11 @@ alloc_napi_failed: static void ibmvnic_release_resources(struct ibmvnic_adapter *adapter) { struct device *dev = &adapter->vdev->dev; - int tx_scrqs, rx_scrqs; + int rx_scrqs; int i; release_bounce_buffer(adapter); - - tx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_txsubm_subcrqs); - for (i = 0; i < tx_scrqs; i++) { - struct ibmvnic_tx_pool *tx_pool = &adapter->tx_pool[i]; - - kfree(tx_pool->tx_buff); - free_long_term_buff(adapter, &tx_pool->long_term_buff); - kfree(tx_pool->free_map); - } - kfree(adapter->tx_pool); - adapter->tx_pool = NULL; + release_tx_pools(adapter); rx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs); for (i = 0; i < rx_scrqs; i++) { From 0ffe2cb7903b20e74a9f42c53016e61e187ee345 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Thu, 30 Mar 2017 02:49:12 -0400 Subject: [PATCH 4/7] ibmvnic: Create init and release routines for the rx pool Move the initialization and the release of the rx pool to their own routines, and update them to do validation. Signed-off-by: Nathan Fontenot Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 204 ++++++++++++++--------------- 1 file changed, 101 insertions(+), 103 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index a9399e96e942..6774b3cbc5f9 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -163,21 +163,6 @@ static long h_reg_sub_crq(unsigned long unit_address, unsigned long token, return rc; } -/* net_device_ops functions */ - -static void init_rx_pool(struct ibmvnic_adapter *adapter, - struct ibmvnic_rx_pool *rx_pool, int num, int index, - int buff_size, int active) -{ - netdev_dbg(adapter->netdev, - "Initializing rx_pool %d, %d buffs, %d bytes each\n", - index, num, buff_size); - rx_pool->size = num; - rx_pool->index = index; - rx_pool->buff_size = buff_size; - rx_pool->active = active; -} - static int alloc_long_term_buff(struct ibmvnic_adapter *adapter, struct ibmvnic_long_term_buff *ltb, int size) { @@ -214,42 +199,6 @@ static void free_long_term_buff(struct ibmvnic_adapter *adapter, send_request_unmap(adapter, ltb->map_id); } -static int alloc_rx_pool(struct ibmvnic_adapter *adapter, - struct ibmvnic_rx_pool *pool) -{ - struct device *dev = &adapter->vdev->dev; - int i; - - pool->free_map = kcalloc(pool->size, sizeof(int), GFP_KERNEL); - if (!pool->free_map) - return -ENOMEM; - - pool->rx_buff = kcalloc(pool->size, sizeof(struct ibmvnic_rx_buff), - GFP_KERNEL); - - if (!pool->rx_buff) { - dev_err(dev, "Couldn't alloc rx buffers\n"); - kfree(pool->free_map); - return -ENOMEM; - } - - if (alloc_long_term_buff(adapter, &pool->long_term_buff, - pool->size * pool->buff_size)) { - kfree(pool->free_map); - kfree(pool->rx_buff); - return -ENOMEM; - } - - for (i = 0; i < pool->size; ++i) - pool->free_map[i] = i; - - atomic_set(&pool->available, 0); - pool->next_alloc = 0; - pool->next_free = 0; - - return 0; -} - static void replenish_rx_pool(struct ibmvnic_adapter *adapter, struct ibmvnic_rx_pool *pool) { @@ -354,25 +303,105 @@ static void replenish_pools(struct ibmvnic_adapter *adapter) } } -static void free_rx_pool(struct ibmvnic_adapter *adapter, - struct ibmvnic_rx_pool *pool) +static void release_rx_pools(struct ibmvnic_adapter *adapter) { - int i; + struct ibmvnic_rx_pool *rx_pool; + int rx_scrqs; + int i, j; - kfree(pool->free_map); - pool->free_map = NULL; - - if (!pool->rx_buff) + if (!adapter->rx_pool) return; - for (i = 0; i < pool->size; i++) { - if (pool->rx_buff[i].skb) { - dev_kfree_skb_any(pool->rx_buff[i].skb); - pool->rx_buff[i].skb = NULL; + rx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs); + for (i = 0; i < rx_scrqs; i++) { + rx_pool = &adapter->rx_pool[i]; + + kfree(rx_pool->free_map); + free_long_term_buff(adapter, &rx_pool->long_term_buff); + + if (!rx_pool->rx_buff) + continue; + + for (j = 0; j < rx_pool->size; j++) { + if (rx_pool->rx_buff[j].skb) { + dev_kfree_skb_any(rx_pool->rx_buff[i].skb); + rx_pool->rx_buff[i].skb = NULL; + } } + + kfree(rx_pool->rx_buff); } - kfree(pool->rx_buff); - pool->rx_buff = NULL; + + kfree(adapter->rx_pool); + adapter->rx_pool = NULL; +} + +static int init_rx_pools(struct net_device *netdev) +{ + struct ibmvnic_adapter *adapter = netdev_priv(netdev); + struct device *dev = &adapter->vdev->dev; + struct ibmvnic_rx_pool *rx_pool; + int rxadd_subcrqs; + u64 *size_array; + int i, j; + + rxadd_subcrqs = + be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs); + size_array = (u64 *)((u8 *)(adapter->login_rsp_buf) + + be32_to_cpu(adapter->login_rsp_buf->off_rxadd_buff_size)); + + adapter->rx_pool = kcalloc(rxadd_subcrqs, + sizeof(struct ibmvnic_rx_pool), + GFP_KERNEL); + if (!adapter->rx_pool) { + dev_err(dev, "Failed to allocate rx pools\n"); + return -1; + } + + for (i = 0; i < rxadd_subcrqs; i++) { + rx_pool = &adapter->rx_pool[i]; + + netdev_dbg(adapter->netdev, + "Initializing rx_pool %d, %lld buffs, %lld bytes each\n", + i, adapter->req_rx_add_entries_per_subcrq, + be64_to_cpu(size_array[i])); + + rx_pool->size = adapter->req_rx_add_entries_per_subcrq; + rx_pool->index = i; + rx_pool->buff_size = be64_to_cpu(size_array[i]); + rx_pool->active = 1; + + rx_pool->free_map = kcalloc(rx_pool->size, sizeof(int), + GFP_KERNEL); + if (!rx_pool->free_map) { + release_rx_pools(adapter); + return -1; + } + + rx_pool->rx_buff = kcalloc(rx_pool->size, + sizeof(struct ibmvnic_rx_buff), + GFP_KERNEL); + if (!rx_pool->rx_buff) { + dev_err(dev, "Couldn't alloc rx buffers\n"); + release_rx_pools(adapter); + return -1; + } + + if (alloc_long_term_buff(adapter, &rx_pool->long_term_buff, + rx_pool->size * rx_pool->buff_size)) { + release_rx_pools(adapter); + return -1; + } + + for (j = 0; j < rx_pool->size; ++j) + rx_pool->free_map[j] = j; + + atomic_set(&rx_pool->available, 0); + rx_pool->next_alloc = 0; + rx_pool->next_free = 0; + } + + return 0; } static void release_tx_pools(struct ibmvnic_adapter *adapter) @@ -526,10 +555,9 @@ static int ibmvnic_open(struct net_device *netdev) struct device *dev = &adapter->vdev->dev; union ibmvnic_crq crq; int rxadd_subcrqs; - u64 *size_array; int tx_subcrqs; int rc = 0; - int i, j; + int i; if (adapter->is_closed) { rc = ibmvnic_init(adapter); @@ -557,9 +585,7 @@ static int ibmvnic_open(struct net_device *netdev) be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs); tx_subcrqs = be32_to_cpu(adapter->login_rsp_buf->num_txsubm_subcrqs); - size_array = (u64 *)((u8 *)(adapter->login_rsp_buf) + - be32_to_cpu(adapter->login_rsp_buf-> - off_rxadd_buff_size)); + adapter->map_id = 1; adapter->napi = kcalloc(adapter->req_rx_queues, sizeof(struct napi_struct), GFP_KERNEL); @@ -570,21 +596,12 @@ static int ibmvnic_open(struct net_device *netdev) NAPI_POLL_WEIGHT); napi_enable(&adapter->napi[i]); } - adapter->rx_pool = - kcalloc(rxadd_subcrqs, sizeof(struct ibmvnic_rx_pool), GFP_KERNEL); - if (!adapter->rx_pool) - goto rx_pool_arr_alloc_failed; send_map_query(adapter); - for (i = 0; i < rxadd_subcrqs; i++) { - init_rx_pool(adapter, &adapter->rx_pool[i], - adapter->req_rx_add_entries_per_subcrq, i, - be64_to_cpu(size_array[i]), 1); - if (alloc_rx_pool(adapter, &adapter->rx_pool[i])) { - dev_err(dev, "Couldn't alloc rx pool\n"); - goto rx_pool_alloc_failed; - } - } + + rc = init_rx_pools(netdev); + if (rc) + goto rx_pool_failed; rc = init_tx_pools(netdev); if (rc) @@ -621,15 +638,7 @@ bounce_init_failed: kfree(adapter->tx_pool[i].free_map); tx_pool_failed: i = rxadd_subcrqs; -rx_pool_alloc_failed: - for (j = 0; j < i; j++) { - free_rx_pool(adapter, &adapter->rx_pool[j]); - free_long_term_buff(adapter, - &adapter->rx_pool[j].long_term_buff); - } - kfree(adapter->rx_pool); - adapter->rx_pool = NULL; -rx_pool_arr_alloc_failed: +rx_pool_failed: for (i = 0; i < adapter->req_rx_queues; i++) napi_disable(&adapter->napi[i]); alloc_napi_failed: @@ -640,21 +649,10 @@ alloc_napi_failed: static void ibmvnic_release_resources(struct ibmvnic_adapter *adapter) { struct device *dev = &adapter->vdev->dev; - int rx_scrqs; - int i; release_bounce_buffer(adapter); release_tx_pools(adapter); - - rx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs); - for (i = 0; i < rx_scrqs; i++) { - struct ibmvnic_rx_pool *rx_pool = &adapter->rx_pool[i]; - - free_rx_pool(adapter, rx_pool); - free_long_term_buff(adapter, &rx_pool->long_term_buff); - } - kfree(adapter->rx_pool); - adapter->rx_pool = NULL; + release_rx_pools(adapter); release_sub_crqs(adapter); release_crq_queue(adapter); From b510888f9639588d30d48eaaa32502cdb1c9e9e0 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Thu, 30 Mar 2017 02:49:18 -0400 Subject: [PATCH 5/7] ibmvnic: Merge the two release_sub_crq_queue routines Keeping two routines for releasing sub crqs, one for when irqs are not initialized and one for when they are, is a bit of overkill. Merge the two routines to a common release routine that will check for an irq and release it if needed. Signed-off-by: Nathan Fontenot Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 56 ++++++++++++------------------ 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 6774b3cbc5f9..f2d2f1f1ce1c 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -88,7 +88,6 @@ MODULE_VERSION(IBMVNIC_DRIVER_VERSION); static int ibmvnic_version = IBMVNIC_INITIAL_VERSION; static int ibmvnic_remove(struct vio_dev *); static void release_sub_crqs(struct ibmvnic_adapter *); -static void release_sub_crqs_no_irqs(struct ibmvnic_adapter *); static int ibmvnic_reset_crq(struct ibmvnic_adapter *); static int ibmvnic_send_crq_init(struct ibmvnic_adapter *); static int ibmvnic_reenable_crq_queue(struct ibmvnic_adapter *); @@ -526,7 +525,7 @@ static int ibmvnic_login(struct net_device *netdev) do { if (adapter->renegotiate) { adapter->renegotiate = false; - release_sub_crqs_no_irqs(adapter); + release_sub_crqs(adapter); reinit_completion(&adapter->init_done); send_cap_queries(adapter); @@ -1371,53 +1370,44 @@ static void release_sub_crqs(struct ibmvnic_adapter *adapter) int i; if (adapter->tx_scrq) { - for (i = 0; i < adapter->req_tx_queues; i++) - if (adapter->tx_scrq[i]) { + for (i = 0; i < adapter->req_tx_queues; i++) { + if (!adapter->tx_scrq[i]) + continue; + + if (adapter->tx_scrq[i]->irq) { free_irq(adapter->tx_scrq[i]->irq, adapter->tx_scrq[i]); irq_dispose_mapping(adapter->tx_scrq[i]->irq); - release_sub_crq_queue(adapter, - adapter->tx_scrq[i]); + adapter->tx_scrq[i]->irq = 0; } + + release_sub_crq_queue(adapter, adapter->tx_scrq[i]); + } + kfree(adapter->tx_scrq); adapter->tx_scrq = NULL; } if (adapter->rx_scrq) { - for (i = 0; i < adapter->req_rx_queues; i++) - if (adapter->rx_scrq[i]) { + for (i = 0; i < adapter->req_rx_queues; i++) { + if (!adapter->rx_scrq[i]) + continue; + + if (adapter->rx_scrq[i]->irq) { free_irq(adapter->rx_scrq[i]->irq, adapter->rx_scrq[i]); irq_dispose_mapping(adapter->rx_scrq[i]->irq); - release_sub_crq_queue(adapter, - adapter->rx_scrq[i]); + adapter->rx_scrq[i]->irq = 0; } + + release_sub_crq_queue(adapter, adapter->rx_scrq[i]); + } + kfree(adapter->rx_scrq); adapter->rx_scrq = NULL; } } -static void release_sub_crqs_no_irqs(struct ibmvnic_adapter *adapter) -{ - int i; - - if (adapter->tx_scrq) { - for (i = 0; i < adapter->req_tx_queues; i++) - if (adapter->tx_scrq[i]) - release_sub_crq_queue(adapter, - adapter->tx_scrq[i]); - adapter->tx_scrq = NULL; - } - - if (adapter->rx_scrq) { - for (i = 0; i < adapter->req_rx_queues; i++) - if (adapter->rx_scrq[i]) - release_sub_crq_queue(adapter, - adapter->rx_scrq[i]); - adapter->rx_scrq = NULL; - } -} - static int disable_scrq_irq(struct ibmvnic_adapter *adapter, struct ibmvnic_sub_crq_queue *scrq) { @@ -1609,7 +1599,7 @@ req_tx_irq_failed: free_irq(adapter->tx_scrq[j]->irq, adapter->tx_scrq[j]); irq_dispose_mapping(adapter->rx_scrq[j]->irq); } - release_sub_crqs_no_irqs(adapter); + release_sub_crqs(adapter); return rc; } @@ -2499,7 +2489,7 @@ static void handle_request_cap_rsp(union ibmvnic_crq *crq, *req_value, (long int)be64_to_cpu(crq->request_capability_rsp. number), name); - release_sub_crqs_no_irqs(adapter); + release_sub_crqs(adapter); *req_value = be64_to_cpu(crq->request_capability_rsp.number); init_sub_crqs(adapter, 1); return; From 7bbc27a4961a7d5f8e4294929ce64d6c6e81e90c Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Thu, 30 Mar 2017 02:49:23 -0400 Subject: [PATCH 6/7] ibmvnic: Create init/release routines for stats token Create an initialization and a release routine for the stats token used by the ibmvnic driver. Signed-off-by: Nathan Fontenot Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 46 ++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index f2d2f1f1ce1c..a2f972d72e34 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -302,6 +302,36 @@ static void replenish_pools(struct ibmvnic_adapter *adapter) } } +static void release_stats_token(struct ibmvnic_adapter *adapter) +{ + struct device *dev = &adapter->vdev->dev; + + if (!adapter->stats_token) + return; + + dma_unmap_single(dev, adapter->stats_token, + sizeof(struct ibmvnic_statistics), + DMA_FROM_DEVICE); + adapter->stats_token = 0; +} + +static int init_stats_token(struct ibmvnic_adapter *adapter) +{ + struct device *dev = &adapter->vdev->dev; + dma_addr_t stok; + + stok = dma_map_single(dev, &adapter->stats, + sizeof(struct ibmvnic_statistics), + DMA_FROM_DEVICE); + if (dma_mapping_error(dev, stok)) { + dev_err(dev, "Couldn't map stats buffer\n"); + return -1; + } + + adapter->stats_token = stok; + return 0; +} + static void release_rx_pools(struct ibmvnic_adapter *adapter) { struct ibmvnic_rx_pool *rx_pool; @@ -647,8 +677,6 @@ alloc_napi_failed: static void ibmvnic_release_resources(struct ibmvnic_adapter *adapter) { - struct device *dev = &adapter->vdev->dev; - release_bounce_buffer(adapter); release_tx_pools(adapter); release_rx_pools(adapter); @@ -656,10 +684,7 @@ static void ibmvnic_release_resources(struct ibmvnic_adapter *adapter) release_sub_crqs(adapter); release_crq_queue(adapter); - if (adapter->stats_token) - dma_unmap_single(dev, adapter->stats_token, - sizeof(struct ibmvnic_statistics), - DMA_FROM_DEVICE); + release_stats_token(adapter); } static int ibmvnic_close(struct net_device *netdev) @@ -3269,13 +3294,10 @@ static int ibmvnic_init(struct ibmvnic_adapter *adapter) return rc; } - adapter->stats_token = dma_map_single(dev, &adapter->stats, - sizeof(struct ibmvnic_statistics), - DMA_FROM_DEVICE); - if (dma_mapping_error(dev, adapter->stats_token)) { + rc = init_stats_token(adapter); + if (rc) { release_crq_queue(adapter); - dev_err(dev, "Couldn't map stats buffer\n"); - return -ENOMEM; + return rc; } init_completion(&adapter->init_done); From 1b8955ee5f6c1575c09b44c8253883394c78bef7 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Thu, 30 Mar 2017 02:49:29 -0400 Subject: [PATCH 7/7] ibmvnic: Cleanup failure path in ibmvnic_open Now that ibmvnic_release_resources will clean up all of our resources properly, even if they were not allocated, we can just call this for failues in ibmvnic_open. This patch also moves the ibmvnic_release_resources() routine up in the file to avoid creating a forward declaration ad re-names it to drop the ibmvnic prefix. Signed-off-by: Nathan Fontenot Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmvnic.c | 51 +++++++++++------------------- 1 file changed, 19 insertions(+), 32 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index a2f972d72e34..7ba43cfadf3a 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -578,13 +578,23 @@ static int ibmvnic_login(struct net_device *netdev) return 0; } +static void release_resources(struct ibmvnic_adapter *adapter) +{ + release_bounce_buffer(adapter); + release_tx_pools(adapter); + release_rx_pools(adapter); + + release_sub_crqs(adapter); + release_crq_queue(adapter); + + release_stats_token(adapter); +} + 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 rxadd_subcrqs; - int tx_subcrqs; int rc = 0; int i; @@ -610,16 +620,11 @@ static int ibmvnic_open(struct net_device *netdev) return -1; } - rxadd_subcrqs = - be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs); - tx_subcrqs = - be32_to_cpu(adapter->login_rsp_buf->num_txsubm_subcrqs); - adapter->map_id = 1; adapter->napi = kcalloc(adapter->req_rx_queues, sizeof(struct napi_struct), GFP_KERNEL); if (!adapter->napi) - goto alloc_napi_failed; + goto ibmvnic_open_fail; for (i = 0; i < adapter->req_rx_queues; i++) { netif_napi_add(netdev, &adapter->napi[i], ibmvnic_poll, NAPI_POLL_WEIGHT); @@ -630,15 +635,15 @@ static int ibmvnic_open(struct net_device *netdev) rc = init_rx_pools(netdev); if (rc) - goto rx_pool_failed; + goto ibmvnic_open_fail; rc = init_tx_pools(netdev); if (rc) - goto tx_pool_failed; + goto ibmvnic_open_fail; rc = init_bounce_buffer(netdev); if (rc) - goto bounce_init_failed; + goto ibmvnic_open_fail; replenish_pools(adapter); @@ -662,31 +667,13 @@ static int ibmvnic_open(struct net_device *netdev) return 0; -bounce_init_failed: - i = tx_subcrqs - 1; - kfree(adapter->tx_pool[i].free_map); -tx_pool_failed: - i = rxadd_subcrqs; -rx_pool_failed: +ibmvnic_open_fail: for (i = 0; i < adapter->req_rx_queues; i++) napi_disable(&adapter->napi[i]); -alloc_napi_failed: - release_sub_crqs(adapter); + release_resources(adapter); return -ENOMEM; } -static void ibmvnic_release_resources(struct ibmvnic_adapter *adapter) -{ - release_bounce_buffer(adapter); - release_tx_pools(adapter); - release_rx_pools(adapter); - - release_sub_crqs(adapter); - release_crq_queue(adapter); - - release_stats_token(adapter); -} - static int ibmvnic_close(struct net_device *netdev) { struct ibmvnic_adapter *adapter = netdev_priv(netdev); @@ -707,7 +694,7 @@ static int ibmvnic_close(struct net_device *netdev) crq.logical_link_state.link_state = IBMVNIC_LOGICAL_LNK_DN; ibmvnic_send_crq(adapter, &crq); - ibmvnic_release_resources(adapter); + release_resources(adapter); adapter->is_closed = true; adapter->closing = false;