mirror of
https://github.com/openwrt/openwrt.git
synced 2026-10-13 00:17:02 +04:00
qualcommax: qca_edma: free a completed frame with the budget of its caller
edma_clean_tx() passes its loop bound to napi_consume_skb() as the NAPI
budget. A non-zero budget tells that helper it is running inside a poll and
frees the frame into the per-CPU NAPI cache, which is only safe from
softirq context. edma_rings_drain() calls the same routine from process
context with INT_MAX - on an MTU change that alters the receive page order,
and on the probe error and remove paths - so a transmit completion on the
same CPU can interleave with the cache update.
The budget the poll was given becomes an argument of its own, zero on the
drain, which routes those frees through dev_consume_skb_any() instead.
Fixes: bdb0b722b7 ("qualcommax: add EDMA driver")
Assisted-by: Claude:claude-opus-5
Signed-off-by: Julius Bairaktaris <julius@bairaktaris.de>
Link: https://github.com/openwrt/openwrt/pull/25084
Signed-off-by: Robert Marko <robimarko@gmail.com>
This commit is contained in:
1 parent
a9adfbf98f
commit
e3c00e95ca
1 file changed
+8
-4
@@ -310,8 +310,12 @@ static bool edma_rx_page_take(struct edma_priv *priv, struct page *page,
|
||||
return false;
|
||||
}
|
||||
|
||||
/* @napi_budget is the NAPI budget the poll was given, or zero when the caller
|
||||
* is not a poll: the skb cache napi_consume_skb() recycles into is per-CPU and
|
||||
* is only safe to touch from softirq context.
|
||||
*/
|
||||
static u32 edma_clean_tx(struct edma_priv *priv, struct edma_ring *txcmpl_ring,
|
||||
int budget)
|
||||
int budget, int napi_budget)
|
||||
{
|
||||
const struct edma_soc_data *soc = priv->soc;
|
||||
struct platform_device *pdev = priv->pdev;
|
||||
@@ -356,7 +360,7 @@ static u32 edma_clean_tx(struct edma_priv *priv, struct edma_ring *txcmpl_ring,
|
||||
le32_to_cpu(txdesc->buffer_addr),
|
||||
len, DMA_TO_DEVICE);
|
||||
bytes += len - EDMA_TX_PREHDR_SIZE;
|
||||
napi_consume_skb(skb, budget);
|
||||
napi_consume_skb(skb, napi_budget);
|
||||
|
||||
next:
|
||||
if (++cons == txcmpl_ring->count)
|
||||
@@ -477,7 +481,7 @@ next:
|
||||
static int edma_tx_napi(struct napi_struct *napi, int budget)
|
||||
{
|
||||
struct edma_priv *priv = container_of(napi, struct edma_priv, tx_napi);
|
||||
int work = edma_clean_tx(priv, &priv->txcmpl_ring, budget);
|
||||
int work = edma_clean_tx(priv, &priv->txcmpl_ring, budget, budget);
|
||||
const struct edma_soc_data *soc = priv->soc;
|
||||
u32 val;
|
||||
|
||||
@@ -756,7 +760,7 @@ err_txcmpl:
|
||||
static void edma_rings_drain(struct edma_priv *priv)
|
||||
{
|
||||
edma_txdesc_drain(priv, &priv->txdesc_ring);
|
||||
edma_clean_tx(priv, &priv->txcmpl_ring, INT_MAX);
|
||||
edma_clean_tx(priv, &priv->txcmpl_ring, INT_MAX, 0);
|
||||
|
||||
edma_tx_ring_free(priv, &priv->txdesc_ring, sizeof(struct edma_txdesc));
|
||||
edma_ring_free(priv, &priv->txcmpl_ring, sizeof(struct edma_txcmpl));
|
||||
|
||||
Reference in new issue
Block a user