mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
Merge branch 'fix-mana-rx-with-bounce-buffering'
Dexuan Cui says:
====================
Fix MANA RX with bounce buffering
With swiotlb=force, the MANA NIC fails to work properly due to commit
730ff06d3f ("net: mana: Use page pool fragments for RX buffers instead
of full pages to improve memory efficiency.").
This happens because, with the standard MTU=1500, the aforementioned
commit uses page pool frags with PP_FLAG_DMA_MAP, but fails to call
page_pool_dma_sync_for_cpu() to sync the received packet for CPU acces
before handing the RX buffer to the stack.
Here patch #2 adds the required page_pool_dma_sync_for_cpu().
Patch #1 validates the packet length reported by the NIC. With patch #2,
page_pool_dma_sync_for_cpu() uses the packet length, so we don't want
to blindly trust the packet length, just in case.
There is no change between v2 and v3.
v3 just swaps the order of the 2 patches in v2, as suggested by Simon [3].
References:
[1] v1: https://lore.kernel.org/netdev/20260618035029.249361-1-decui@microsoft.com/
[2] v2: https://lore.kernel.org/netdev/20260624222605.1794719-1-decui@microsoft.com/
[3] https://lore.kernel.org/netdev/20260626145048.GB1310988@horms.kernel.org/
====================
Link: https://patch.msgid.link/20260702041237.617719-1-decui@microsoft.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
commit
c26c33e632
|
|
@ -2120,12 +2120,16 @@ static void mana_rx_skb(void *buf_va, bool from_pool,
|
|||
}
|
||||
|
||||
static void *mana_get_rxfrag(struct mana_rxq *rxq, struct device *dev,
|
||||
dma_addr_t *da, bool *from_pool)
|
||||
dma_addr_t *da, bool *from_pool,
|
||||
struct page **pp_page, u32 *dma_sync_offset)
|
||||
{
|
||||
struct page *page;
|
||||
u32 offset;
|
||||
void *va;
|
||||
|
||||
*from_pool = false;
|
||||
*pp_page = NULL;
|
||||
*dma_sync_offset = 0;
|
||||
|
||||
/* Don't use fragments for jumbo frames or XDP where it's 1 fragment
|
||||
* per page.
|
||||
|
|
@ -2163,31 +2167,47 @@ static void *mana_get_rxfrag(struct mana_rxq *rxq, struct device *dev,
|
|||
va = page_to_virt(page) + offset;
|
||||
*da = page_pool_get_dma_addr(page) + offset + rxq->headroom;
|
||||
*from_pool = true;
|
||||
*pp_page = page;
|
||||
*dma_sync_offset = offset + rxq->headroom;
|
||||
|
||||
return va;
|
||||
}
|
||||
|
||||
/* Allocate frag for rx buffer, and save the old buf */
|
||||
static void mana_refill_rx_oob(struct device *dev, struct mana_rxq *rxq,
|
||||
struct mana_recv_buf_oob *rxoob, void **old_buf,
|
||||
bool *old_fp)
|
||||
struct mana_recv_buf_oob *rxoob, u32 pktlen,
|
||||
void **old_buf, bool *old_fp)
|
||||
{
|
||||
struct page *pp_page;
|
||||
u32 dma_sync_offset;
|
||||
bool from_pool;
|
||||
dma_addr_t da;
|
||||
void *va;
|
||||
|
||||
va = mana_get_rxfrag(rxq, dev, &da, &from_pool);
|
||||
va = mana_get_rxfrag(rxq, dev, &da, &from_pool, &pp_page,
|
||||
&dma_sync_offset);
|
||||
if (!va)
|
||||
return;
|
||||
if (!rxoob->from_pool || rxq->frag_count == 1)
|
||||
if (!rxoob->from_pool || rxq->frag_count == 1) {
|
||||
dma_unmap_single(dev, rxoob->sgl[0].address, rxq->datasize,
|
||||
DMA_FROM_DEVICE);
|
||||
} else {
|
||||
/* The page pool maps the whole page and only syncs for device
|
||||
* automatically (PP_FLAG_DMA_SYNC_DEV). Sync the received bytes
|
||||
* for the CPU before they are read: this is required if DMA
|
||||
* is incoherent or bounce buffers are used.
|
||||
*/
|
||||
page_pool_dma_sync_for_cpu(rxq->page_pool, rxoob->pp_page,
|
||||
rxoob->dma_sync_offset, pktlen);
|
||||
}
|
||||
*old_buf = rxoob->buf_va;
|
||||
*old_fp = rxoob->from_pool;
|
||||
|
||||
rxoob->buf_va = va;
|
||||
rxoob->sgl[0].address = da;
|
||||
rxoob->from_pool = from_pool;
|
||||
rxoob->pp_page = pp_page;
|
||||
rxoob->dma_sync_offset = dma_sync_offset;
|
||||
}
|
||||
|
||||
static void mana_process_rx_cqe(struct mana_rxq *rxq, struct mana_cq *cq,
|
||||
|
|
@ -2246,12 +2266,26 @@ static void mana_process_rx_cqe(struct mana_rxq *rxq, struct mana_cq *cq,
|
|||
rxbuf_oob = &rxq->rx_oobs[curr];
|
||||
WARN_ON_ONCE(rxbuf_oob->wqe_inf.wqe_size_in_bu != 1);
|
||||
|
||||
mana_refill_rx_oob(dev, rxq, rxbuf_oob, &old_buf, &old_fp);
|
||||
if (unlikely(pktlen > rxq->datasize)) {
|
||||
/* Increase it even if mana_rx_skb() isn't called. */
|
||||
rxq->rx_cq.work_done++;
|
||||
|
||||
/* Unsuccessful refill will have old_buf == NULL.
|
||||
* In this case, mana_rx_skb() will drop the packet.
|
||||
*/
|
||||
mana_rx_skb(old_buf, old_fp, oob, rxq, i);
|
||||
++ndev->stats.rx_dropped;
|
||||
netdev_warn_once(ndev,
|
||||
"Dropped oversized RX packet: len=%u, datasize=%u\n",
|
||||
pktlen, rxq->datasize);
|
||||
|
||||
/* Reuse the RX buffer since rxbuf_oob is unchanged. */
|
||||
} else {
|
||||
|
||||
mana_refill_rx_oob(dev, rxq, rxbuf_oob, pktlen,
|
||||
&old_buf, &old_fp);
|
||||
|
||||
/* Unsuccessful refill will have old_buf == NULL.
|
||||
* In this case, mana_rx_skb() will drop the packet.
|
||||
*/
|
||||
mana_rx_skb(old_buf, old_fp, oob, rxq, i);
|
||||
}
|
||||
|
||||
mana_move_wq_tail(rxq->gdma_rq,
|
||||
rxbuf_oob->wqe_inf.wqe_size_in_bu);
|
||||
|
|
@ -2655,6 +2689,8 @@ static int mana_fill_rx_oob(struct mana_recv_buf_oob *rx_oob, u32 mem_key,
|
|||
struct mana_rxq *rxq, struct device *dev)
|
||||
{
|
||||
struct mana_port_context *mpc = netdev_priv(rxq->ndev);
|
||||
struct page *pp_page = NULL;
|
||||
u32 dma_sync_offset = 0;
|
||||
bool from_pool = false;
|
||||
dma_addr_t da;
|
||||
void *va;
|
||||
|
|
@ -2662,13 +2698,16 @@ static int mana_fill_rx_oob(struct mana_recv_buf_oob *rx_oob, u32 mem_key,
|
|||
if (mpc->rxbufs_pre)
|
||||
va = mana_get_rxbuf_pre(rxq, &da);
|
||||
else
|
||||
va = mana_get_rxfrag(rxq, dev, &da, &from_pool);
|
||||
va = mana_get_rxfrag(rxq, dev, &da, &from_pool, &pp_page,
|
||||
&dma_sync_offset);
|
||||
|
||||
if (!va)
|
||||
return -ENOMEM;
|
||||
|
||||
rx_oob->buf_va = va;
|
||||
rx_oob->from_pool = from_pool;
|
||||
rx_oob->pp_page = pp_page;
|
||||
rx_oob->dma_sync_offset = dma_sync_offset;
|
||||
|
||||
rx_oob->sgl[0].address = da;
|
||||
rx_oob->sgl[0].size = rxq->datasize;
|
||||
|
|
|
|||
|
|
@ -305,6 +305,14 @@ struct mana_recv_buf_oob {
|
|||
|
||||
void *buf_va;
|
||||
bool from_pool; /* allocated from a page pool */
|
||||
/* head page of the page_pool fragment; valid only when
|
||||
* from_pool && frag_count > 1.
|
||||
*/
|
||||
struct page *pp_page;
|
||||
/* Fragment offset plus rxq->headroom, passed to
|
||||
* page_pool_dma_sync_for_cpu().
|
||||
*/
|
||||
u32 dma_sync_offset;
|
||||
|
||||
/* SGL of the buffer going to be sent as part of the work request. */
|
||||
u32 num_sge;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user