mirror of
https://github.com/openwrt/openwrt.git
synced 2026-10-12 06:57:57 +04:00
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 <igor.kravchenko05@gmail.com> Link: https://github.com/openwrt/openwrt/pull/24218 Signed-off-by: Robert Marko <robimarko@gmail.com>
This commit is contained in:
1 parent
da141cba5c
commit
e8ca976eff
1 file changed
+135
+135
@@ -0,0 +1,135 @@
|
||||
From 67edad5e196f088098d25e1c843ffbf798627860 Mon Sep 17 00:00:00 2001
|
||||
From: Igor Kravchenko <igor.kravchenko05@gmail.com>
|
||||
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 <igor.kravchenko05@gmail.com>
|
||||
---
|
||||
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.
|
||||
Reference in new issue
Block a user