net: mana: remove double CQ cleanup in mana_create_rxq error path
PATCH 1/2 net: mana: remove double CQ cleanup in mana_create_rxq error path
From: Dipayaan Roy <[email protected]>
[ Upstream commit 3985c9a56da49af8b2e45cb1fa55c03c89b1d471 ]
In mana_create_rxq(), the error cleanup path calls mana_destroy_rxq() followed by mana_deinit_cq(). This is incorrect for two reasons:
1. mana_destroy_rxq() already calls mana_deinit_cq() internally, so the CQ's GDMA queue is destroyed twice.
2. mana_destroy_rxq() frees the rxq via kfree(rxq) before returning. The subsequent mana_deinit_cq(apc, cq) then operates on freed memory since cq points to &rxq->rx_cq, which is embedded in the already-freed rxq structure — a use-after-free.
Remove the redundant mana_deinit_cq() call from the error path since mana_destroy_rxq() already handles CQ cleanup. mana_deinit_cq() is itself safe for an uninitialized CQ as it checks for a NULL gdma_cq before proceeding.
--- drivers/net/ethernet/microsoft/mana/mana_en.c | 3 --- 1 file changed, 3 deletions(-)
drivers/net/ethernet/microsoft/mana/mana_en.c +0 -3
@@ -3025,9 +3025,6 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc,mana_destroy_rxq (apc, rxq, false); -if (cq) -mana_deinit_cq (apc, cq); -return NULL ; }
Signature · 1 line
2.56.0
PATCH 2/2 net: mana: Sync page pool RX frags for CPU
From: Dexuan Cui <[email protected]>
[ Upstream commit c72a0f09c57f92113df69f9b902d11c9e4b132f5 ]
MANA allocates RX buffers from page pool fragments when frag_count is greater than 1. In that case the buffers remain DMA mapped by page pool and the RX completion path does not call dma_unmap_single(). As a result, the implicit sync-for-CPU normally performed by dma_unmap_single() is missing before the packet data is passed to the networking stack.
This breaks RX on configurations which require explicit DMA syncing, for example when booted with swiotlb=force.
Fix this by recording the page pool page and DMA sync offset when the RX buffer is allocated, and syncing the received packet range for CPU access before handing the RX buffer to the stack.
[ hmahfooz: resolve conflict with the earlier backport of 55d20f50a221
by passing pktlen to mana_refill_rx_oob() from mana_process_one_rx_pkt() ]
--- drivers/net/ethernet/microsoft/mana/mana_en.c | 40 +++++++++++++++---- include/net/mana/mana.h | 8 ++++ 2 files changed, 41 insertions(+), 7 deletions(-)
drivers/net/ethernet/microsoft/mana/mana_en.c +33 -7
@@ -2072,12 +2072,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.
@@ -2115,31 +2119,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_one_rx_pkt(struct device *dev, struct mana_rxq *rxq,
@@ -2165,7 +2185,8 @@ static void mana_process_one_rx_pkt(struct device *dev, struct mana_rxq *rxq,/* Reuse the RX buffer since rxbuf_oob is unchanged. */ }else { -mana_refill_rx_oob (dev, rxq, rxbuf_oob, &old_buf, &old_fp); +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.
@@ -2777,6 +2798,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;
@@ -2784,13 +2807,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;
include/net/mana/mana.h +8 -0
@@ -348,6 +348,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;
Signature · 1 line
2.56.0
Greg Kroah-Hartman
maintainerRe: [PATCH 6.18.y 2/2] net: mana: Sync page pool RX frags for CPU
Quoted 153 lines · Hamza Mahfooz
From: Dexuan Cui <[email protected]>
[ Upstream commit
c72a0f09c57f92113df69f9b902d11c9e4b132f5]MANA allocates RX buffers from page pool fragments when
frag_countis greater than 1. In that case the buffers remain DMA mapped by page pool and the RX completion path does not calldma_unmap_single(). As a result, the implicit sync-for-CPU normally performed bydma_unmap_single()is missing before the packet data is passed to the networking stack.This breaks RX on configurations which require explicit DMA syncing, for example when booted with swiotlb=force.
Fix this by recording the page pool page and DMA sync offset when the RX buffer is allocated, and syncing the received packet range for CPU access before handing the RX buffer to the stack.
Fixes 730ff06d3f5c ("net: mana: Use page pool fragments for RX buffers instead of full pages to improve memory efficiency.")Reviewed-by Haiyang Zhang <[email protected]>Signed-off-by Dexuan Cui <[email protected]>Signed-off-by Paolo Abeni <[email protected]>[ hmahfooz: resolve conflict with the earlier backport of
55d20f50a221
by passing pktlen tomana_refill_rx_oob()frommana_process_one_rx_pkt()]Signed-off-by Hamza Mahfooz <[email protected]>--- drivers/net/ethernet/microsoft/mana/mana_en.c | 40 +++++++++++++++---- include/net/mana/mana.h | 8 ++++ 2 files changed, 41 insertions(+), 7 deletions(-)drivers/net/ethernet/microsoft/mana/mana_en.c +33
-7@@ -2072,12 +2072,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. @@ -2115,31 +2119,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_one_rx_pkt(struct device *dev, struct mana_rxq *rxq,@@ -2165,7 +2185,8 @@ static void mana_process_one_rx_pkt(struct device *dev, struct mana_rxq *rxq,/* Reuse the RX buffer since rxbuf_oob is unchanged. */ }else { -mana_refill_rx_oob (dev, rxq, rxbuf_oob, &old_buf, &old_fp); +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. @@ -2777,6 +2798,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;@@ -2784,13 +2807,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;include/net/mana/mana.h +1
-0@@ -348,6 +348,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
include/net/mana/mana.h struct mana_recv_buf_oob { · line 361
Quoted 10 lines
include/net/mana/mana.h +7
-0+* 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;
Does not apply to the tree :(
Re: [PATCH 6.18.y 2/2] net: mana: Sync page pool RX frags for CPU
In reply to Hamza MahfoozQuoted 3 lines
[ hmahfooz: resolve conflict with the earlier backport of
55d20f50a221
by passing pktlen tomana_refill_rx_oob()frommana_process_one_rx_pkt()]
Queued for 6.18, thanks.
Passed pktlen to mana_refill_rx_oob() from mana_process_rx_cqe().
Signature · 2 lines
Thanks, Sasha
Quoted 2 lines
In
mana_create_rxq(), the error cleanup path callsmana_destroy_rxq()followed bymana_deinit_cq(). This is incorrect for two reasons:
Queued for 6.18, thanks.
Signature · 2 lines
Thanks, Sasha