From 22ece0e2e23c5cc5a23a5b8aff3dc75c9832e82f Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 20 Sep 2013 16:03:42 +0200 Subject: [PATCH] net: rtl8169: Improve cache maintenance Instead of directly calling the low-level invalidate_dcache_range() and flush_cache() functions, provide thin wrappers that take into account alignment requirements. While at it, fix a case where the cache was flushed but should have been invalidated, two cases where the buffer data was flushed instead of the descriptor and a missing cache invalidation before reading the packet data that the NIC just wrote to memory. Signed-off-by: Thierry Reding Patch: 276474 --- drivers/net/rtl8169.c | 61 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 8 deletions(-) diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c index 290c988..c47485a 100644 --- a/drivers/net/rtl8169.c +++ b/drivers/net/rtl8169.c @@ -395,6 +395,50 @@ match: return 0; } +/* + * Cache maintenance functions. These are simple wrappers around the more + * general purpose flush_cache() and invalidate_dcache_range() functions. + */ + +static void rtl_inval_rx_desc(struct RxDesc *desc) +{ + unsigned long start = (unsigned long)desc & ~(ARCH_DMA_MINALIGN - 1); + unsigned long end = ALIGN(start + sizeof(*desc), ARCH_DMA_MINALIGN); + + invalidate_dcache_range(start, end); +} + +static void rtl_flush_rx_desc(struct RxDesc *desc) +{ + flush_cache((unsigned long)desc, sizeof(*desc)); +} + +static void rtl_inval_tx_desc(struct TxDesc *desc) +{ + unsigned long start = (unsigned long)desc & ~(ARCH_DMA_MINALIGN - 1); + unsigned long end = ALIGN(start + sizeof(*desc), ARCH_DMA_MINALIGN); + + invalidate_dcache_range(start, end); +} + +static void rtl_flush_tx_desc(struct TxDesc *desc) +{ + flush_cache((unsigned long)desc, sizeof(*desc)); +} + +static void rtl_inval_buffer(void *buf, size_t size) +{ + unsigned long start = (unsigned long)buf & ~(ARCH_DMA_MINALIGN - 1); + unsigned long end = ALIGN(start + size, ARCH_DMA_MINALIGN); + + invalidate_dcache_range(start, end); +} + +static void rtl_flush_buffer(void *buf, size_t size) +{ + flush_cache((unsigned long)buf, size); +} + /************************************************************************** RECV - Receive a frame ***************************************************************************/ @@ -412,14 +456,16 @@ static int rtl_recv(struct eth_device *dev) ioaddr = dev->iobase; cur_rx = tpc->cur_rx; - flush_cache((unsigned long)&tpc->RxDescArray[cur_rx], - sizeof(struct RxDesc)); + + rtl_inval_rx_desc(&tpc->RxDescArray[cur_rx]); + if ((le32_to_cpu(tpc->RxDescArray[cur_rx].status) & OWNbit) == 0) { if (!(le32_to_cpu(tpc->RxDescArray[cur_rx].status) & RxRES)) { unsigned char rxdata[RX_BUF_LEN]; length = (int) (le32_to_cpu(tpc->RxDescArray[cur_rx]. status) & 0x00001FFF) - 4; + rtl_inval_buffer(tpc->RxBufferRing[cur_rx], length); memcpy(rxdata, tpc->RxBufferRing[cur_rx], length); NetReceive(rxdata, length); @@ -431,8 +477,7 @@ static int rtl_recv(struct eth_device *dev) cpu_to_le32(OWNbit + RX_BUF_SIZE); tpc->RxDescArray[cur_rx].buf_addr = cpu_to_le32(bus_to_phys(tpc->RxBufferRing[cur_rx])); - flush_cache((unsigned long)tpc->RxBufferRing[cur_rx], - RX_BUF_SIZE); + rtl_flush_rx_desc(&tpc->RxDescArray[cur_rx]); } else { puts("Error Rx"); } @@ -474,7 +519,7 @@ static int rtl_send(struct eth_device *dev, void *packet, int length) /* point to the current txb incase multiple tx_rings are used */ ptxb = tpc->Tx_skbuff[entry * MAX_ETH_FRAME_SIZE]; memcpy(ptxb, (char *)packet, (int)length); - flush_cache((unsigned long)ptxb, length); + rtl_flush_buffer(ptxb, length); while (len < ETH_ZLEN) ptxb[len++] = '\0'; @@ -490,13 +535,13 @@ static int rtl_send(struct eth_device *dev, void *packet, int length) cpu_to_le32((OWNbit | EORbit | FSbit | LSbit) | ((len > ETH_ZLEN) ? len : ETH_ZLEN)); } + rtl_flush_tx_desc(&tpc->TxDescArray[entry]); RTL_W8(TxPoll, 0x40); /* set polling bit */ tpc->cur_tx++; to = currticks() + TX_TIMEOUT; do { - flush_cache((unsigned long)&tpc->TxDescArray[entry], - sizeof(struct TxDesc)); + rtl_inval_tx_desc(&tpc->TxDescArray[entry]); } while ((le32_to_cpu(tpc->TxDescArray[entry].status) & OWNbit) && (currticks() < to)); /* wait */ @@ -639,7 +684,7 @@ static void rtl8169_init_ring(struct eth_device *dev) tpc->RxBufferRing[i] = &rxb[i * RX_BUF_SIZE]; tpc->RxDescArray[i].buf_addr = cpu_to_le32(bus_to_phys(tpc->RxBufferRing[i])); - flush_cache((unsigned long)tpc->RxBufferRing[i], RX_BUF_SIZE); + rtl_flush_rx_desc(&tpc->RxDescArray[i]); } #ifdef DEBUG_RTL8169