From 8d9a453c4714e474dbfdd929ea1db85bdfc1b209 Mon Sep 17 00:00:00 2001 From: Sham Muthayyan Date: Tue, 13 Mar 2018 13:19:17 +0530 Subject: [PATCH] ipq807x: Add uncahed alloc support for edma driver TX and RX descriptors are 16 bytes. This causes problems with the cache maintenance on CPUs where the cache-line size exceeds the size of these descriptors. What will happen is that when the driver receives a packet it will be immediately requeued for the hardware to reuse. The CPU will therefore need to flush the cache-line containing the descriptor, which will cause all other descriptors in the same cache-line to be flushed along with it. If one of those descriptors had been written to by the device those changes (and the associated packet) will be lost. To work around this, we make use of non-cached memory if available. If descriptors are mapped uncached there's no need to manually flush them or invalidate them. Change-Id: I7b8a9a55226dfdcbab49a93bcdf43af4d70c108a Signed-off-by: Sham Muthayyan --- drivers/net/ipq807x/ipq807x_edma.c | 157 ++++++++++------------------- include/configs/ipq807x.h | 2 + 2 files changed, 57 insertions(+), 102 deletions(-) diff --git a/drivers/net/ipq807x/ipq807x_edma.c b/drivers/net/ipq807x/ipq807x_edma.c index 0923809e70..50d1e0f4ff 100644 --- a/drivers/net/ipq807x/ipq807x_edma.c +++ b/drivers/net/ipq807x/ipq807x_edma.c @@ -111,7 +111,6 @@ void ipq807x_edma_reg_write(uint32_t reg_off, uint32_t val) int ipq807x_edma_alloc_rx_buffer(struct ipq807x_edma_hw *ehw, struct ipq807x_edma_rxfill_ring *rxfill_ring) { - u32 skb; uint16_t num_alloc = 0; uint16_t cons, next, counter; struct ipq807x_edma_rxfill_desc *rxfill_desc; @@ -149,11 +148,6 @@ int ipq807x_edma_alloc_rx_buffer(struct ipq807x_edma_hw *ehw, __func__, counter); break; } - /* - * Allocate buffer - */ - skb = virt_to_phys(net_rx_packets[next]); - /* * Get RXFILL descriptor */ @@ -162,12 +156,12 @@ int ipq807x_edma_alloc_rx_buffer(struct ipq807x_edma_hw *ehw, /* * Make room for Rx preheader */ - rxph = (struct ipq807x_edma_rx_preheader *)skb; + rxph = (struct ipq807x_edma_rx_preheader *)rxfill_desc->buffer_addr; /* * Fill the opaque value */ - rxph->opaque = cpu_to_le32(skb); + rxph->opaque = next; /* * Save buffer size in RXFILL descriptor @@ -175,18 +169,6 @@ int ipq807x_edma_alloc_rx_buffer(struct ipq807x_edma_hw *ehw, rxfill_desc->word1 = cpu_to_le32(IPQ807X_EDMA_RX_BUFF_SIZE & IPQ807X_EDMA_RXFILL_BUF_SIZE_MASK); - /* - * Map Rx buffer for DMA - */ - rxfill_desc->buffer_addr = cpu_to_le32(skb); - - flush_dcache_range((unsigned long)rxfill_desc, - (unsigned long)rxfill_desc + - sizeof(struct ipq807x_edma_rxfill_desc)); - flush_dcache_range((unsigned long)(rxfill_desc->buffer_addr), - (unsigned long)(rxfill_desc->buffer_addr) + - PKTSIZE_ALIGN); - num_alloc++; next = counter; } @@ -310,11 +292,6 @@ uint32_t ipq807x_edma_clean_rx(struct ipq807x_edma_common_info *c_info, rxdesc_desc = IPQ807X_EDMA_RXDESC_DESC(rxdesc_ring, cons_idx); - invalidate_dcache_range( - (unsigned long)(rxdesc_desc->buffer_addr), - (unsigned long)((rxdesc_desc->buffer_addr) + - PKTSIZE_ALIGN)); - skb = (void *)rxdesc_desc->buffer_addr; /* @@ -568,14 +545,6 @@ static int ipq807x_eth_snd(struct eth_device *dev, void *packet, int length) txdesc->word1 |= ((length & IPQ807X_EDMA_TXDESC_DATA_LENGTH_MASK) << IPQ807X_EDMA_TXDESC_DATA_LENGTH_SHIFT); - flush_dcache_range((unsigned long)txdesc, - (unsigned long)txdesc + - sizeof(struct ipq807x_edma_txdesc_desc)); - - flush_dcache_range((unsigned long)(txdesc->buffer_addr), - (unsigned long)(txdesc->buffer_addr) + - PKTSIZE_ALIGN); - /* * Update producer index */ @@ -611,11 +580,6 @@ static int ipq807x_eth_recv(struct eth_device *dev) for (i = 0; i < ehw->rxdesc_rings; i++) { rxdesc_ring = &ehw->rxdesc_ring[i]; - invalidate_dcache_range((unsigned long)(&rxdesc_ring->desc[0]), - (unsigned long)(&rxdesc_ring->desc[0] + - (IPQ807X_EDMA_RXDESC_RING_SIZE * - sizeof(struct ipq807x_edma_rxdesc_desc)))); - reg_data = ipq807x_edma_reg_read( IPQ807X_EDMA_REG_RXDESC_INT_STAT( rxdesc_ring->id)); @@ -646,8 +610,10 @@ static int ipq807x_edma_setup_ring_resources(struct ipq807x_edma_hw *ehw) struct ipq807x_edma_rxfill_ring *rxfill_ring; struct ipq807x_edma_rxdesc_ring *rxdesc_ring; struct ipq807x_edma_txdesc_desc *tx_desc; + struct ipq807x_edma_rxfill_desc *rxfill_desc; int i, j, index; void *tx_buf; + void *rx_buf; /* * Allocate Rx fill ring descriptors @@ -656,15 +622,31 @@ static int ipq807x_edma_setup_ring_resources(struct ipq807x_edma_hw *ehw) rxfill_ring = &ehw->rxfill_ring[i]; rxfill_ring->count = IPQ807X_EDMA_RXFILL_RING_SIZE; rxfill_ring->id = ehw->rxfill_ring_start + i; - rxfill_ring->desc = ipq807x_alloc_memalign( + rxfill_ring->desc = (void *)noncached_alloc( sizeof(struct ipq807x_edma_rxfill_desc) * - rxfill_ring->count); + rxfill_ring->count, + CONFIG_SYS_CACHELINE_SIZE); if (rxfill_ring->desc == NULL) { pr_info("%s: rxfill_ring->desc alloc error\n", __func__); - goto rxfill_ring_fail; + return -ENOMEM; } rxfill_ring->dma = virt_to_phys(rxfill_ring->desc); + rx_buf = (void *)noncached_alloc(PKTSIZE_ALIGN * + rxfill_ring->count, + CONFIG_SYS_CACHELINE_SIZE); + + if (rx_buf == NULL) { + pr_info("%s: rxfill_ring->desc buffer alloc error\n", + __func__); + return -ENOMEM; + } + + for (j = 0; j < rxfill_ring->count; j++) { + rxfill_desc = IPQ807X_EDMA_RXFILL_DESC(rxfill_ring, j); + rxfill_desc->buffer_addr = virt_to_phys(rx_buf); + rx_buf += PKTSIZE_ALIGN; + } } /* @@ -686,13 +668,14 @@ static int ipq807x_edma_setup_ring_resources(struct ipq807x_edma_hw *ehw) &ehw->rxfill_ring[index - ehw->rxfill_ring_start]; rxdesc_ring->rxfill = ehw->rxfill_ring; - rxdesc_ring->desc = ipq807x_alloc_memalign( + rxdesc_ring->desc = (void *)noncached_alloc( sizeof(struct ipq807x_edma_rxdesc_desc) * - rxdesc_ring->count); + rxdesc_ring->count, + CONFIG_SYS_CACHELINE_SIZE); if (rxdesc_ring->desc == NULL) { pr_info("%s: rxdesc_ring->desc alloc error\n", __func__); - goto rxdesc_ring_fail; + return -ENOMEM; } rxdesc_ring->dma = virt_to_phys(rxdesc_ring->desc); } @@ -704,13 +687,14 @@ static int ipq807x_edma_setup_ring_resources(struct ipq807x_edma_hw *ehw) txcmpl_ring = &ehw->txcmpl_ring[i]; txcmpl_ring->count = IPQ807X_EDMA_TXCMPL_RING_SIZE; txcmpl_ring->id = ehw->txcmpl_ring_start + i; - txcmpl_ring->desc = ipq807x_alloc_memalign( + txcmpl_ring->desc = (void *)noncached_alloc( sizeof(struct ipq807x_edma_txcmpl_desc) * - txcmpl_ring->count); + txcmpl_ring->count, + CONFIG_SYS_CACHELINE_SIZE); if (txcmpl_ring->desc == NULL) { pr_info("%s: txcmpl_ring->desc alloc error\n", __func__); - goto txcmpl_ring_fail; + return -ENOMEM; } txcmpl_ring->dma = virt_to_phys(txcmpl_ring->desc); } @@ -723,23 +707,25 @@ static int ipq807x_edma_setup_ring_resources(struct ipq807x_edma_hw *ehw) txdesc_ring = &ehw->txdesc_ring[i]; txdesc_ring->count = IPQ807X_EDMA_TXDESC_RING_SIZE; txdesc_ring->id = ehw->txdesc_ring_start + i; - txdesc_ring->desc = ipq807x_alloc_memalign( + txdesc_ring->desc = (void *)noncached_alloc( sizeof(struct ipq807x_edma_txdesc_desc) * - txdesc_ring->count); + txdesc_ring->count, + CONFIG_SYS_CACHELINE_SIZE); if (txdesc_ring->desc == NULL) { pr_info("%s: txdesc_ring->desc alloc error\n", __func__); - goto txdesc_ring_desc_fail; + return -ENOMEM; } txdesc_ring->dma = virt_to_phys(txdesc_ring->desc); - tx_buf = ipq807x_alloc_mem(IPQ807X_EDMA_TX_BUF_SIZE * - txdesc_ring->count); + tx_buf = (void *)noncached_alloc(IPQ807X_EDMA_TX_BUF_SIZE * + txdesc_ring->count, + CONFIG_SYS_CACHELINE_SIZE); if (tx_buf == NULL) { pr_info("%s: txdesc_ring->desc buffer alloc error\n", __func__); - goto txdesc_ring_desc_fail; + return -ENOMEM; } for (j = 0; j < txdesc_ring->count; j++) { @@ -753,36 +739,6 @@ static int ipq807x_edma_setup_ring_resources(struct ipq807x_edma_hw *ehw) return 0; -txdesc_ring_desc_fail: - for (i = 0; i < ehw->txdesc_rings; i++) { - txdesc_ring = &ehw->txdesc_ring[i]; - if (txdesc_ring->desc) { - tx_desc = IPQ807X_EDMA_TXDESC_DESC(txdesc_ring, 0); - if (tx_desc->buffer_addr) - ipq807x_free_mem((void *)tx_desc->buffer_addr); - ipq807x_free_mem(txdesc_ring->desc); - } - } -txcmpl_ring_fail: - for (i = 0; i < ehw->txcmpl_rings; i++) { - txcmpl_ring = &ehw->txcmpl_ring[i]; - if (txcmpl_ring->desc) { - ipq807x_free_mem(txcmpl_ring->desc); - } - } -rxdesc_ring_fail: - for (i = 0; i < ehw->rxdesc_rings; i++) { - rxdesc_ring = &ehw->rxdesc_ring[i]; - if (rxdesc_ring->desc) - ipq807x_free_mem(rxdesc_ring->desc); - } -rxfill_ring_fail: - for (i = 0; i < ehw->rxfill_rings; i++) { - rxfill_ring = &ehw->rxfill_ring[i]; - if (rxfill_ring->desc) - ipq807x_free_mem(rxfill_ring->desc); - } - return -ENOMEM; } /* @@ -1182,52 +1138,49 @@ static void ipq807x_edma_set_ring_values(struct ipq807x_edma_hw *edma_hw) */ static int ipq807x_edma_alloc_rings(struct ipq807x_edma_hw *ehw) { - ehw->rxfill_ring = ipq807x_alloc_memalign((sizeof( + ehw->rxfill_ring = (void *)noncached_alloc((sizeof( struct ipq807x_edma_rxfill_ring) * - ehw->rxfill_rings)); + ehw->rxfill_rings), + CONFIG_SYS_CACHELINE_SIZE); if (!ehw->rxfill_ring) { pr_info("%s: rxfill_ring alloc error\n", __func__); - return -1; + return -ENOMEM; } - ehw->rxdesc_ring = ipq807x_alloc_memalign((sizeof( + ehw->rxdesc_ring = (void *)noncached_alloc((sizeof( struct ipq807x_edma_rxdesc_ring) * - ehw->rxdesc_rings)); + ehw->rxdesc_rings), + CONFIG_SYS_CACHELINE_SIZE); if (!ehw->rxdesc_ring) { pr_info("%s: rxdesc_ring alloc error\n", __func__); - goto rxdesc_ring_alloc_fail; + return -ENOMEM; } - ehw->txdesc_ring = ipq807x_alloc_memalign((sizeof( + ehw->txdesc_ring = (void *)noncached_alloc((sizeof( struct ipq807x_edma_txdesc_ring) * - ehw->txdesc_rings)); + ehw->txdesc_rings), + CONFIG_SYS_CACHELINE_SIZE); if (!ehw->txdesc_ring) { pr_info("%s: txdesc_ring alloc error\n", __func__); - goto txdesc_ring_alloc_fail; + return -ENOMEM; } - ehw->txcmpl_ring = ipq807x_alloc_memalign((sizeof( + ehw->txcmpl_ring = (void *)noncached_alloc((sizeof( struct ipq807x_edma_txcmpl_ring) * - ehw->txcmpl_rings)); + ehw->txcmpl_rings), + CONFIG_SYS_CACHELINE_SIZE); if (!ehw->txcmpl_ring) { pr_info("%s: txcmpl_ring alloc error\n", __func__); - goto txcmpl_ring_alloc_fail; + return -ENOMEM; } pr_info("%s: successfull\n", __func__); return 0; -txcmpl_ring_alloc_fail: - ipq807x_free_mem(ehw->txdesc_ring); -txdesc_ring_alloc_fail: - ipq807x_free_mem(ehw->rxdesc_ring); -rxdesc_ring_alloc_fail: - ipq807x_free_mem(ehw->rxfill_ring); - return -ENOMEM; } diff --git a/include/configs/ipq807x.h b/include/configs/ipq807x.h index 2e510f7cd3..877eb25cda 100644 --- a/include/configs/ipq807x.h +++ b/include/configs/ipq807x.h @@ -34,6 +34,8 @@ #define CONFIG_SYS_CACHELINE_SIZE 64 #define CONFIG_SYS_VSNPRINTF +#define CONFIG_SYS_NONCACHED_MEMORY (1 << 20) + #define CONFIG_IPQ807X_UART #define CONFIG_NR_DRAM_BANKS 1 #define CONFIG_SKIP_LOWLEVEL_INIT