From patchwork Mon Mar 23 01:45:21 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Vasut X-Patchwork-Id: 244122 List-Id: U-Boot discussion From: marex at denx.de (Marek Vasut) Date: Mon, 23 Mar 2020 02:45:21 +0100 Subject: [PATCH 1/6] net: dwc_eth_qos: Fully rewrite RX descriptor field 3 Message-ID: <20200323014526.3340884-1-marex@denx.de> The RX descriptor field 3 should contain only OWN and BUF1V bits before being used for receiving data by the DMA engine. However, right now, if the descriptor was already used for receiving data and is being cleared, the field 3 is only modified and the aforementioned two bits are ORRed into the field. This could lead to a residual dirty bits being left in the field 3 from previous transfer, and it generally does. Fully set the field 3 instead to clear those residual dirty bits. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Patrice Chotard Cc: Patrick Delaunay Cc: Ramon Fried Cc: Stephen Warren Reviewed-by: Ramon Fried Tested-by: Stephen Warren --- drivers/net/dwc_eth_qos.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 0564bebf76..4bce6d4290 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -1242,7 +1242,7 @@ static int eqos_start(struct udevice *dev) struct eqos_desc *rx_desc = &(eqos->rx_descs[i]); rx_desc->des0 = (u32)(ulong)(eqos->rx_dma_buf + (i * EQOS_MAX_PACKET_SIZE)); - rx_desc->des3 |= EQOS_DESC3_OWN | EQOS_DESC3_BUF1V; + rx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_BUF1V; } eqos->config->ops->eqos_flush_desc(eqos->descs); @@ -1436,7 +1436,7 @@ static int eqos_free_pkt(struct udevice *dev, uchar *packet, int length) * writes to the rest of the descriptor too. */ mb(); - rx_desc->des3 |= EQOS_DESC3_OWN | EQOS_DESC3_BUF1V; + rx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_BUF1V; eqos->config->ops->eqos_flush_desc(rx_desc); writel((ulong)rx_desc, &eqos->dma_regs->ch0_rxdesc_tail_pointer); From patchwork Mon Mar 23 01:45:22 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Vasut X-Patchwork-Id: 244123 List-Id: U-Boot discussion From: marex at denx.de (Marek Vasut) Date: Mon, 23 Mar 2020 02:45:22 +0100 Subject: [PATCH 2/6] net: dwc_eth_qos: Correctly wrap around TX descriptor tail pointer In-Reply-To: <20200323014526.3340884-1-marex@denx.de> References: <20200323014526.3340884-1-marex@denx.de> Message-ID: <20200323014526.3340884-2-marex@denx.de> This code programs the next descriptor in the TX descriptor ring into the hardware as the last valid TX descriptor. The problem is that if the currenty descriptor is the last one in the array, the code will not wrap around correctly and use TX descriptor 0 again, but instead will use TX descriptor at address right past the TX descriptor ring, which is the first descriptor in the RX ring. Fix this by adding the necessary wrap-around. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Patrice Chotard Cc: Patrick Delaunay Cc: Ramon Fried Cc: Stephen Warren Reviewed-by: Ramon Fried --- drivers/net/dwc_eth_qos.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 4bce6d4290..c4f665bda9 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -1373,7 +1373,8 @@ static int eqos_send(struct udevice *dev, void *packet, int length) tx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_FD | EQOS_DESC3_LD | length; eqos->config->ops->eqos_flush_desc(tx_desc); - writel((ulong)(tx_desc + 1), &eqos->dma_regs->ch0_txdesc_tail_pointer); + writel((ulong)(&(eqos->tx_descs[eqos->tx_desc_idx])), + &eqos->dma_regs->ch0_txdesc_tail_pointer); for (i = 0; i < 1000000; i++) { eqos->config->ops->eqos_inval_desc(tx_desc); From patchwork Mon Mar 23 01:45:23 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Vasut X-Patchwork-Id: 244126 List-Id: U-Boot discussion From: marex at denx.de (Marek Vasut) Date: Mon, 23 Mar 2020 02:45:23 +0100 Subject: [PATCH 3/6] net: dwc_eth_qos: Flush the RX descriptors on init In-Reply-To: <20200323014526.3340884-1-marex@denx.de> References: <20200323014526.3340884-1-marex@denx.de> Message-ID: <20200323014526.3340884-3-marex@denx.de> Currently the code only flushes the first RX descriptor, not every entry in the RX descriptor ring. Fix this, to make sure the DMA engine can pick the RX descriptors correctly. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Patrice Chotard Cc: Patrick Delaunay Cc: Ramon Fried Cc: Stephen Warren Reviewed-by: Ramon Fried --- drivers/net/dwc_eth_qos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index c4f665bda9..66cc301c8c 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -1243,8 +1243,8 @@ static int eqos_start(struct udevice *dev) rx_desc->des0 = (u32)(ulong)(eqos->rx_dma_buf + (i * EQOS_MAX_PACKET_SIZE)); rx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_BUF1V; + eqos->config->ops->eqos_flush_desc(rx_desc); } - eqos->config->ops->eqos_flush_desc(eqos->descs); writel(0, &eqos->dma_regs->ch0_txdesc_list_haddress); writel((ulong)eqos->tx_descs, &eqos->dma_regs->ch0_txdesc_list_address); From patchwork Mon Mar 23 01:45:24 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Vasut X-Patchwork-Id: 244124 List-Id: U-Boot discussion From: marex at denx.de (Marek Vasut) Date: Mon, 23 Mar 2020 02:45:24 +0100 Subject: [PATCH 4/6] net: dwc_eth_qos: Invalidate RX descriptor before reading In-Reply-To: <20200323014526.3340884-1-marex@denx.de> References: <20200323014526.3340884-1-marex@denx.de> Message-ID: <20200323014526.3340884-4-marex@denx.de> The current code polls the RX desciptor ring for new packets by reading the RX descriptor status. This works by accident, as the RX descriptors are often in non-cacheable memory. However, the driver does support use of RX descriptors in cacheable memory. This patch adds a missing RX descriptor invalidation, which assures the CPU will read a fresh copy of the RX descriptor instead of a cached one. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Patrice Chotard Cc: Patrick Delaunay Cc: Ramon Fried Cc: Stephen Warren Reviewed-by: Ramon Fried --- drivers/net/dwc_eth_qos.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 66cc301c8c..e40c461278 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -1397,6 +1397,7 @@ static int eqos_recv(struct udevice *dev, int flags, uchar **packetp) debug("%s(dev=%p, flags=%x):\n", __func__, dev, flags); rx_desc = &(eqos->rx_descs[eqos->rx_desc_idx]); + eqos->config->ops->eqos_inval_desc(rx_desc); if (rx_desc->des3 & EQOS_DESC3_OWN) { debug("%s: RX packet not available\n", __func__); return -EAGAIN; From patchwork Mon Mar 23 01:45:25 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Vasut X-Patchwork-Id: 244125 List-Id: U-Boot discussion From: marex at denx.de (Marek Vasut) Date: Mon, 23 Mar 2020 02:45:25 +0100 Subject: [PATCH 5/6] net: dwc_eth_qos: Invalidate RX packet DMA buffer In-Reply-To: <20200323014526.3340884-1-marex@denx.de> References: <20200323014526.3340884-1-marex@denx.de> Message-ID: <20200323014526.3340884-5-marex@denx.de> This patch prevents an issue where the RX packet might have been accessed by the CPU, which now has cached data from the packet in the caches and possibly various write buffers, and these data may be evicted from the caches into the DRAM while the buffer is also written by the DMA. By invalidating the buffer after the CPU accessed it and before the DMA populates the buffer, it is assured that the buffer will not be corrupted. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Patrice Chotard Cc: Patrick Delaunay Cc: Ramon Fried Cc: Stephen Warren Reviewed-by: Ramon Fried --- drivers/net/dwc_eth_qos.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index e40c461278..7dadb10fe7 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -1430,6 +1430,9 @@ static int eqos_free_pkt(struct udevice *dev, uchar *packet, int length) } rx_desc = &(eqos->rx_descs[eqos->rx_desc_idx]); + + eqos->config->ops->eqos_inval_buffer(packet, length); + rx_desc->des0 = (u32)(ulong)packet; rx_desc->des1 = 0; rx_desc->des2 = 0; @@ -1492,6 +1495,9 @@ static int eqos_probe_resources_core(struct udevice *dev) } debug("%s: rx_pkt=%p\n", __func__, eqos->rx_pkt); + eqos->config->ops->eqos_inval_buffer(eqos->rx_dma_buf, + EQOS_MAX_PACKET_SIZE * EQOS_DESCRIPTORS_RX); + debug("%s: OK\n", __func__); return 0; From patchwork Mon Mar 23 01:45:26 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Vasut X-Patchwork-Id: 244127 List-Id: U-Boot discussion From: marex at denx.de (Marek Vasut) Date: Mon, 23 Mar 2020 02:45:26 +0100 Subject: [PATCH 6/6] net: dwc_eth_qos: Prevent DMA from writing updated RX DMA descriptor In-Reply-To: <20200323014526.3340884-1-marex@denx.de> References: <20200323014526.3340884-1-marex@denx.de> Message-ID: <20200323014526.3340884-6-marex@denx.de> The DMA may attempt to write a DMA descriptor in the ring while it is being updated. By writing the DMA descriptor buffer address to 0, it is assured the DMA will not use such a buffer and the buffer can be updated without any interference. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Patrice Chotard Cc: Patrick Delaunay Cc: Ramon Fried Cc: Stephen Warren Reviewed-by: Ramon Fried --- drivers/net/dwc_eth_qos.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 7dadb10fe7..c86b9d59a5 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -1431,8 +1431,10 @@ static int eqos_free_pkt(struct udevice *dev, uchar *packet, int length) rx_desc = &(eqos->rx_descs[eqos->rx_desc_idx]); + rx_desc->des0 = 0; + mb(); + eqos->config->ops->eqos_flush_desc(rx_desc); eqos->config->ops->eqos_inval_buffer(packet, length); - rx_desc->des0 = (u32)(ulong)packet; rx_desc->des1 = 0; rx_desc->des2 = 0;