Commit e0e168dc authored by Gregory Greenman's avatar Gregory Greenman Committed by Emmanuel Grumbach

iwlwifi: pcie: avoid restocks inside rx loop if not emergency

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: default avatarGregory Greenman <gregory.greenman@intel.com>
Signed-off-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
parent b358993b
...@@ -231,6 +231,9 @@ static void iwl_pcie_rxq_check_wrptr(struct iwl_trans *trans) ...@@ -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, static void iwl_pcie_rxq_mq_restock(struct iwl_trans *trans,
struct iwl_rxq *rxq) struct iwl_rxq *rxq)
{ {
...@@ -277,17 +280,10 @@ static void iwl_pcie_rxq_mq_restock(struct iwl_trans *trans, ...@@ -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 * iwl_pcie_rxq_sq_restock - restock implementation for single queue rx
*
* 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) static void iwl_pcie_rxq_sq_restock(struct iwl_trans *trans,
struct iwl_rxq *rxq)
{ {
struct iwl_rx_mem_buffer *rxb; struct iwl_rx_mem_buffer *rxb;
...@@ -331,6 +327,26 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans, struct iwl_rxq *rxq) ...@@ -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. * iwl_pcie_rx_alloc_page - allocates and returns a page.
* *
...@@ -907,7 +923,7 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) ...@@ -907,7 +923,7 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
if (trans->cfg->mq_rx_supported) { if (trans->cfg->mq_rx_supported) {
iwl_pcie_rx_mq_hw_init(trans); iwl_pcie_rx_mq_hw_init(trans);
} else { } else {
iwl_pcie_rxq_restock(trans, def_rxq); iwl_pcie_rxq_sq_restock(trans, def_rxq);
iwl_pcie_rx_hw_init(trans, def_rxq); iwl_pcie_rx_hw_init(trans, def_rxq);
} }
...@@ -1222,24 +1238,13 @@ static void iwl_pcie_rx_handle(struct iwl_trans *trans, int queue) ...@@ -1222,24 +1238,13 @@ static void iwl_pcie_rx_handle(struct iwl_trans *trans, int queue)
count = 0; count = 0;
if (rxq->used_count < rxq->queue_size / 3) if (rxq->used_count < rxq->queue_size / 3)
emergency = false; emergency = false;
rxq->read = i;
spin_unlock(&rxq->lock); spin_unlock(&rxq->lock);
iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC, rxq); 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); iwl_pcie_rxq_restock(trans, rxq);
goto restart; goto restart;
}
} }
} }
out: out:
...@@ -1264,6 +1269,8 @@ static void iwl_pcie_rx_handle(struct iwl_trans *trans, int queue) ...@@ -1264,6 +1269,8 @@ static void iwl_pcie_rx_handle(struct iwl_trans *trans, int queue)
if (rxq->napi.poll) if (rxq->napi.poll)
napi_gro_flush(&rxq->napi, false); 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) static struct iwl_trans_pcie *iwl_pcie_get_trans_pcie(struct msix_entry *entry)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment