From e8ca976eff4fe2ea9ac433ae615e4384b155b783 Mon Sep 17 00:00:00 2001 From: krava Date: Mon, 13 Jul 2026 19:13:59 +0000 Subject: [PATCH] qualcommbe: fix PPE EDMA RX DMA mappings EDMA maps RX fill buffers with DMA_TO_DEVICE but unmaps them with DMA_FROM_DEVICE. Use DMA_FROM_DEVICE consistently, release mappings left on RX rings during teardown, and flush ring-disable writes before descriptor cleanup. Signed-off-by: krava Link: https://github.com/openwrt/openwrt/pull/24218 Signed-off-by: Robert Marko --- ...omm-ppe-fix-rx-dma-mapping-direction.patch | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 target/linux/qualcommbe/patches-6.18/0362-net-ethernet-qualcomm-ppe-fix-rx-dma-mapping-direction.patch diff --git a/target/linux/qualcommbe/patches-6.18/0362-net-ethernet-qualcomm-ppe-fix-rx-dma-mapping-direction.patch b/target/linux/qualcommbe/patches-6.18/0362-net-ethernet-qualcomm-ppe-fix-rx-dma-mapping-direction.patch new file mode 100644 index 00000000000..13e151b8eb8 --- /dev/null +++ b/target/linux/qualcommbe/patches-6.18/0362-net-ethernet-qualcomm-ppe-fix-rx-dma-mapping-direction.patch @@ -0,0 +1,135 @@ +From 67edad5e196f088098d25e1c843ffbf798627860 Mon Sep 17 00:00:00 2001 +From: Igor Kravchenko +Date: Mon, 13 Jul 2026 19:13:59 +0000 +Subject: [PATCH] net: ethernet: qualcomm: ppe: fix RX DMA mappings + +EDMA writes received frames into buffers supplied by the RxFill ring. +Map them with DMA_FROM_DEVICE and use the same direction when unmapping. + +The driver currently maps those buffers with DMA_TO_DEVICE but unmaps +them with DMA_FROM_DEVICE. Besides violating the DMA API direction +pairing requirement, this can skip CPU cache invalidation on +non-coherent systems and expose stale RX data. + +Also unmap buffers still attached to RxFill and RxDesc descriptors +during ring cleanup. Freeing an skb alone does not release its streaming +DMA mapping, leaving mappings behind on error handling and teardown. + +Read back the ring enable registers after disabling them, ensuring the +disable writes reach the hardware before cleanup touches descriptors and +buffers. + +Signed-off-by: Igor Kravchenko +--- + drivers/net/ethernet/qualcomm/ppe/edma_cfg_rx.c | 26 ++++++++++++++++++++++++++ + drivers/net/ethernet/qualcomm/ppe/edma_rx.c | 4 ++-- + drivers/net/ethernet/qualcomm/ppe/edma_rx.h | 2 ++ + +--- a/drivers/net/ethernet/qualcomm/ppe/edma_rx.c ++++ b/drivers/net/ethernet/qualcomm/ppe/edma_rx.c +@@ -58,7 +58,7 @@ static int edma_rx_alloc_buffer_list(str + skb_reserve(skb, EDMA_RX_SKB_HEADROOM + NET_IP_ALIGN); + + if (likely(!page_mode)) { +- buff_addr = dma_map_single(dev, skb->data, dma_map_size, DMA_TO_DEVICE); ++ buff_addr = dma_map_single(dev, skb->data, dma_map_size, DMA_FROM_DEVICE); + if (dma_mapping_error(dev, buff_addr)) { + dev_dbg(dev, "edma_context:%pK Unable to dma for non page mode", + edma_ctx); +@@ -77,7 +77,7 @@ static int edma_rx_alloc_buffer_list(str + break; + } + +- buff_addr = dma_map_page(dev, pg, 0, PAGE_SIZE, DMA_TO_DEVICE); ++ buff_addr = dma_map_page(dev, pg, 0, PAGE_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(dev, buff_addr)) { + dev_dbg(dev, "edma_context:%pK Mapping error for page mode", + edma_ctx); +--- a/drivers/net/ethernet/qualcomm/ppe/edma_cfg_rx.c ++++ b/drivers/net/ethernet/qualcomm/ppe/edma_cfg_rx.c +@@ -43,6 +43,22 @@ static u32 edma_rx_ring_queue_map[][EDMA + { 6, 14, 22, 30 }, + { 7, 15, 23, 31 }}; + ++static void edma_cfg_rx_unmap_buffer(struct device *dev, ++ struct edma_rxfill_ring *rxfill_ring, ++ dma_addr_t dma_addr) ++{ ++ u32 dma_map_size; ++ ++ if (rxfill_ring->page_mode) { ++ dma_unmap_page(dev, dma_addr, PAGE_SIZE, DMA_FROM_DEVICE); ++ return; ++ } ++ ++ dma_map_size = rxfill_ring->alloc_size - ++ EDMA_RX_SKB_HEADROOM - NET_IP_ALIGN; ++ dma_unmap_single(dev, dma_addr, dma_map_size, DMA_FROM_DEVICE); ++} ++ + u32 edma_cfg_rx_rps_bitmap_cores = EDMA_RX_DEFAULT_BITMAP; + + static int edma_cfg_rx_desc_rings_reset_queue_mapping(void) +@@ -376,6 +392,8 @@ void edma_cfg_rx_rings_disable(void) + regmap_read(regmap, reg, &data); + data &= ~EDMA_RXDESC_RX_EN; + regmap_write(regmap, reg, data); ++ /* Flush the disable write before ring cleanup. */ ++ regmap_read(regmap, reg, &data); + } + + /* Disable RxFill Rings */ +@@ -388,6 +406,8 @@ void edma_cfg_rx_rings_disable(void) + regmap_read(regmap, reg, &data); + data &= ~EDMA_RXFILL_RING_EN; + regmap_write(regmap, reg, data); ++ /* Flush the disable write before ring cleanup. */ ++ regmap_read(regmap, reg, &data); + } + } + +@@ -420,6 +440,7 @@ static void edma_cfg_rx_fill_ring_cleanu + + while (curr_idx != cons_idx) { + struct edma_rxfill_desc *rxfill_desc; ++ dma_addr_t dma_addr; + struct sk_buff *skb; + + /* Get RxFill descriptor */ +@@ -435,6 +456,8 @@ static void edma_cfg_rx_fill_ring_cleanu + continue; + } + ++ dma_addr = EDMA_RXFILL_BUFFER_ADDR_GET(rxfill_desc); ++ edma_cfg_rx_unmap_buffer(dev, rxfill_ring, dma_addr); + dev_kfree_skb_any(skb); + } + +@@ -506,6 +529,7 @@ static void edma_cfg_rx_desc_ring_cleanu + while (cons_idx != prod_idx) { + struct edma_rxdesc_pri *rxdesc_pri = + EDMA_RXDESC_PRI_DESC(rxdesc_ring, cons_idx); ++ dma_addr_t dma_addr; + struct sk_buff *skb; + + /* Update consumer index */ +@@ -519,6 +543,8 @@ static void edma_cfg_rx_desc_ring_cleanu + continue; + } + ++ dma_addr = EDMA_RXDESC_BUFFER_ADDR_GET(rxdesc_pri); ++ edma_cfg_rx_unmap_buffer(dev, rxdesc_ring->rxfill, dma_addr); + dev_kfree_skb_any(skb); + } + +--- a/drivers/net/ethernet/qualcomm/ppe/edma_rx.h ++++ b/drivers/net/ethernet/qualcomm/ppe/edma_rx.h +@@ -124,6 +124,8 @@ + } + + #define EDMA_RXFILL_BUFFER_ADDR_SET(desc, addr) (((desc)->word0) = (u32)(addr)) ++#define EDMA_RXFILL_BUFFER_ADDR_GET(desc) \ ++ ((u32)(le32_to_cpu((__force __le32)((desc)->word0)))) + + /* Opaque values are set in word2 and word3, they are not accessed by the EDMA HW, + * so endianness conversion is not needed.