iwlwifi: pcie: avoid restocks inside rx loop if not emergency
authorGregory Greenman <gregory.greenman@intel.com>
Mon, 29 Feb 2016 13:34:25 +0000 (15:34 +0200)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Wed, 9 Mar 2016 19:05:16 +0000 (21:05 +0200)
When trying to reach high Rx throughput of more than 500Mbps on
a device with a relatively weak CPU (Atom x5-Z8500), CPU utilization
may become a bottleneck. Analysis showed that we are looping in
iwl_pcie_rx_handle for very long periods which led to starvation
of other threads (iwl_pcie_rx_handle runs with _bh disabled).
We were handling Rx and allocating new buffers and the new buffers
were ready quickly enough to be available before we had finished
handling all the buffers available in the hardware. As a
consequence, we called iwl_pcie_rxq_restock to refill the hardware
with the new buffers, and start again handling new buffers without
exiting the function. Since we read the hardware pointer again when
we goto restart, new buffers were handled immediately instead of
exiting the function.

This patch avoids refilling RBs inside rx handling loop, unless an
emergency situation is reached. It also doesn't read the hardware
pointer again unless we are in an emergency (unlikely) case.
This significantly reduce the maximal time we spend in
iwl_pcie_rx_handle with _bh disabled.

Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
drivers/net/wireless/intel/iwlwifi/pcie/rx.c

index 98524a006f7a89c1bd7f1bba9d3b89dbb7793186..4be3c35afd1928913c31b7b4fccb45f5776b5721 100644 (file)
@@ -231,6 +231,9 @@ static void iwl_pcie_rxq_check_wrptr(struct iwl_trans *trans)
        }
 }
 
+/*
+ * iwl_pcie_rxq_mq_restock - restock implementation for multi-queue rx
+ */
 static void iwl_pcie_rxq_mq_restock(struct iwl_trans *trans,
                                    struct iwl_rxq *rxq)
 {
@@ -277,17 +280,10 @@ static void iwl_pcie_rxq_mq_restock(struct iwl_trans *trans,
 }
 
 /*
- * iwl_pcie_rxq_restock - refill RX queue from pre-allocated pool
- *
- * If there are slots in the RX queue that need to be restocked,
- * and we have free pre-allocated buffers, fill the ranks as much
- * as we can, pulling from rx_free.
- *
- * This moves the 'write' index forward to catch up with 'processed', and
- * also updates the memory address in the firmware to reference the new
- * target buffer.
+ * iwl_pcie_rxq_sq_restock - restock implementation for single queue rx
  */
-static void iwl_pcie_rxq_restock(struct iwl_trans *trans, struct iwl_rxq *rxq)
+static void iwl_pcie_rxq_sq_restock(struct iwl_trans *trans,
+                                   struct iwl_rxq *rxq)
 {
        struct iwl_rx_mem_buffer *rxb;
 
@@ -331,6 +327,26 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans, struct iwl_rxq *rxq)
        }
 }
 
+/*
+ * iwl_pcie_rxq_restock - refill RX queue from pre-allocated pool
+ *
+ * If there are slots in the RX queue that need to be restocked,
+ * and we have free pre-allocated buffers, fill the ranks as much
+ * as we can, pulling from rx_free.
+ *
+ * This moves the 'write' index forward to catch up with 'processed', and
+ * also updates the memory address in the firmware to reference the new
+ * target buffer.
+ */
+static
+void iwl_pcie_rxq_restock(struct iwl_trans *trans, struct iwl_rxq *rxq)
+{
+       if (trans->cfg->mq_rx_supported)
+               iwl_pcie_rxq_mq_restock(trans, rxq);
+       else
+               iwl_pcie_rxq_sq_restock(trans, rxq);
+}
+
 /*
  * iwl_pcie_rx_alloc_page - allocates and returns a page.
  *
@@ -907,7 +923,7 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
        if (trans->cfg->mq_rx_supported) {
                iwl_pcie_rx_mq_hw_init(trans);
        } else {
-               iwl_pcie_rxq_restock(trans, def_rxq);
+               iwl_pcie_rxq_sq_restock(trans, def_rxq);
                iwl_pcie_rx_hw_init(trans, def_rxq);
        }
 
@@ -1222,24 +1238,13 @@ restart:
                                count = 0;
                                if (rxq->used_count < rxq->queue_size / 3)
                                        emergency = false;
+
+                               rxq->read = i;
                                spin_unlock(&rxq->lock);
                                iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC, rxq);
-                               spin_lock(&rxq->lock);
-                       }
-               }
-               /* handle restock for three cases, can be all of them at once:
-               * - we just pulled buffers from the allocator
-               * - we have 8+ unstolen pages accumulated
-               * - we are in emergency and allocated buffers
-                */
-               if (rxq->free_count >=  RX_CLAIM_REQ_ALLOC) {
-                       rxq->read = i;
-                       spin_unlock(&rxq->lock);
-                       if (trans->cfg->mq_rx_supported)
-                               iwl_pcie_rxq_mq_restock(trans, rxq);
-                       else
                                iwl_pcie_rxq_restock(trans, rxq);
-                       goto restart;
+                               goto restart;
+                       }
                }
        }
 out:
@@ -1264,6 +1269,8 @@ out:
 
        if (rxq->napi.poll)
                napi_gro_flush(&rxq->napi, false);
+
+       iwl_pcie_rxq_restock(trans, rxq);
 }
 
 static struct iwl_trans_pcie *iwl_pcie_get_trans_pcie(struct msix_entry *entry)
This page took 0.029836 seconds and 5 git commands to generate.