OSDN Git Service

ibmvnic: Reuse LTB when possible
authorSukadev Bhattiprolu <sukadev@linux.ibm.com>
Wed, 15 Sep 2021 03:52:57 +0000 (20:52 -0700)
committerDavid S. Miller <davem@davemloft.net>
Wed, 15 Sep 2021 10:12:24 +0000 (11:12 +0100)
Reuse the long term buffer during a reset as long as its size has
not changed. If the size has changed, free it and allocate a new
one of the appropriate size.

When we do this, alloc_long_term_buff() and reset_long_term_buff()
become identical. Drop reset_long_term_buff().

Reviewed-by: Rick Lindsley <ricklind@linux.vnet.ibm.com>
Reviewed-by: Dany Madden <drt@linux.ibm.com>
Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/ibm/ibmvnic.c

index 4603597..dafb366 100644 (file)
@@ -108,6 +108,8 @@ static int init_crq_queue(struct ibmvnic_adapter *adapter);
 static int send_query_phys_parms(struct ibmvnic_adapter *adapter);
 static void ibmvnic_tx_scrq_clean_buffer(struct ibmvnic_adapter *adapter,
                                         struct ibmvnic_sub_crq_queue *tx_scrq);
+static void free_long_term_buff(struct ibmvnic_adapter *adapter,
+                               struct ibmvnic_long_term_buff *ltb);
 
 struct ibmvnic_stat {
        char name[ETH_GSTRING_LEN];
@@ -214,23 +216,77 @@ static int ibmvnic_wait_for_completion(struct ibmvnic_adapter *adapter,
        return -ETIMEDOUT;
 }
 
+/**
+ * reuse_ltb() - Check if a long term buffer can be reused
+ * @ltb:  The long term buffer to be checked
+ * @size: The size of the long term buffer.
+ *
+ * An LTB can be reused unless its size has changed.
+ *
+ * Return: Return true if the LTB can be reused, false otherwise.
+ */
+static bool reuse_ltb(struct ibmvnic_long_term_buff *ltb, int size)
+{
+       return (ltb->buff && ltb->size == size);
+}
+
+/**
+ * alloc_long_term_buff() - Allocate a long term buffer (LTB)
+ *
+ * @adapter: ibmvnic adapter associated to the LTB
+ * @ltb:     container object for the LTB
+ * @size:    size of the LTB
+ *
+ * Allocate an LTB of the specified size and notify VIOS.
+ *
+ * If the given @ltb already has the correct size, reuse it. Otherwise if
+ * its non-NULL, free it. Then allocate a new one of the correct size.
+ * Notify the VIOS either way since we may now be working with a new VIOS.
+ *
+ * Allocating larger chunks of memory during resets, specially LPM or under
+ * low memory situations can cause resets to fail/timeout and for LPAR to
+ * lose connectivity. So hold onto the LTB even if we fail to communicate
+ * with the VIOS and reuse it on next open. Free LTB when adapter is closed.
+ *
+ * Return: 0 if we were able to allocate the LTB and notify the VIOS and
+ *        a negative value otherwise.
+ */
 static int alloc_long_term_buff(struct ibmvnic_adapter *adapter,
                                struct ibmvnic_long_term_buff *ltb, int size)
 {
        struct device *dev = &adapter->vdev->dev;
        int rc;
 
-       ltb->size = size;
-       ltb->buff = dma_alloc_coherent(dev, ltb->size, &ltb->addr,
-                                      GFP_KERNEL);
+       if (!reuse_ltb(ltb, size)) {
+               dev_dbg(dev,
+                       "LTB size changed from 0x%llx to 0x%x, reallocating\n",
+                        ltb->size, size);
+               free_long_term_buff(adapter, ltb);
+       }
 
-       if (!ltb->buff) {
-               dev_err(dev, "Couldn't alloc long term buffer\n");
-               return -ENOMEM;
+       if (ltb->buff) {
+               dev_dbg(dev, "Reusing LTB [map %d, size 0x%llx]\n",
+                       ltb->map_id, ltb->size);
+       } else {
+               ltb->buff = dma_alloc_coherent(dev, size, &ltb->addr,
+                                              GFP_KERNEL);
+               if (!ltb->buff) {
+                       dev_err(dev, "Couldn't alloc long term buffer\n");
+                       return -ENOMEM;
+               }
+               ltb->size = size;
+
+               ltb->map_id = find_first_zero_bit(adapter->map_ids,
+                                                 MAX_MAP_ID);
+               bitmap_set(adapter->map_ids, ltb->map_id, 1);
+
+               dev_dbg(dev,
+                       "Allocated new LTB [map %d, size 0x%llx]\n",
+                        ltb->map_id, ltb->size);
        }
-       ltb->map_id = find_first_zero_bit(adapter->map_ids,
-                                         MAX_MAP_ID);
-       bitmap_set(adapter->map_ids, ltb->map_id, 1);
+
+       /* Ensure ltb is zeroed - specially when reusing it. */
+       memset(ltb->buff, 0, ltb->size);
 
        mutex_lock(&adapter->fw_lock);
        adapter->fw_done_rc = 0;
@@ -257,10 +313,7 @@ static int alloc_long_term_buff(struct ibmvnic_adapter *adapter,
        }
        rc = 0;
 out:
-       if (rc) {
-               dma_free_coherent(dev, ltb->size, ltb->buff, ltb->addr);
-               ltb->buff = NULL;
-       }
+       /* don't free LTB on communication error - see function header */
        mutex_unlock(&adapter->fw_lock);
        return rc;
 }
@@ -290,43 +343,6 @@ static void free_long_term_buff(struct ibmvnic_adapter *adapter,
        ltb->map_id = 0;
 }
 
-static int reset_long_term_buff(struct ibmvnic_adapter *adapter,
-                               struct ibmvnic_long_term_buff *ltb)
-{
-       struct device *dev = &adapter->vdev->dev;
-       int rc;
-
-       memset(ltb->buff, 0, ltb->size);
-
-       mutex_lock(&adapter->fw_lock);
-       adapter->fw_done_rc = 0;
-
-       reinit_completion(&adapter->fw_done);
-       rc = send_request_map(adapter, ltb->addr, ltb->size, ltb->map_id);
-       if (rc) {
-               mutex_unlock(&adapter->fw_lock);
-               return rc;
-       }
-
-       rc = ibmvnic_wait_for_completion(adapter, &adapter->fw_done, 10000);
-       if (rc) {
-               dev_info(dev,
-                        "Reset failed, long term map request timed out or aborted\n");
-               mutex_unlock(&adapter->fw_lock);
-               return rc;
-       }
-
-       if (adapter->fw_done_rc) {
-               dev_info(dev,
-                        "Reset failed, attempting to free and reallocate buffer\n");
-               free_long_term_buff(adapter, ltb);
-               mutex_unlock(&adapter->fw_lock);
-               return alloc_long_term_buff(adapter, ltb, ltb->size);
-       }
-       mutex_unlock(&adapter->fw_lock);
-       return 0;
-}
-
 static void deactivate_rx_pools(struct ibmvnic_adapter *adapter)
 {
        int i;
@@ -548,18 +564,10 @@ static int reset_rx_pools(struct ibmvnic_adapter *adapter)
 
                netdev_dbg(adapter->netdev, "Re-setting rx_pool[%d]\n", i);
 
-               if (rx_pool->buff_size != buff_size) {
-                       free_long_term_buff(adapter, &rx_pool->long_term_buff);
-                       rx_pool->buff_size = ALIGN(buff_size, L1_CACHE_BYTES);
-                       rc = alloc_long_term_buff(adapter,
-                                                 &rx_pool->long_term_buff,
-                                                 rx_pool->size *
-                                                 rx_pool->buff_size);
-               } else {
-                       rc = reset_long_term_buff(adapter,
-                                                 &rx_pool->long_term_buff);
-               }
-
+               rx_pool->buff_size = ALIGN(buff_size, L1_CACHE_BYTES);
+               rc = alloc_long_term_buff(adapter,
+                                         &rx_pool->long_term_buff,
+                                         rx_pool->size * rx_pool->buff_size);
                if (rc)
                        return rc;
 
@@ -694,9 +702,12 @@ static int init_rx_pools(struct net_device *netdev)
 static int reset_one_tx_pool(struct ibmvnic_adapter *adapter,
                             struct ibmvnic_tx_pool *tx_pool)
 {
+       struct ibmvnic_long_term_buff *ltb;
        int rc, i;
 
-       rc = reset_long_term_buff(adapter, &tx_pool->long_term_buff);
+       ltb = &tx_pool->long_term_buff;
+
+       rc = alloc_long_term_buff(adapter, ltb, ltb->size);
        if (rc)
                return rc;