If promisc mode is enabled (which is enabled for DSA switches by default) a LLDP frame received by barebox will trigger following panic: DABT (current EL) exception (ESR 0x9600014b) at 0x0000000000000000 elr: 00000000bfd967d8 lr : 00000000bfd963e0 x0 : 0000000000000000 x1 : 00000000000000e9 x2 : 0000000000000040 x3 : 000000000000003f x4 : 0000000000000000 x5 : 00000000000001a0 x6 : 0000000000000005 x7 : 0000000030200000 x8 : 000000007feda6a8 x9 : 0000000000000000 x10: 0000000000000000 x11: 00000000fffffffa x12: 00000000fffffffa x13: 0000000000000020 x14: 0000000000000000 x15: 0000000000000001 x16: 00000000bfff74c8 x17: 0000000000000001 x18: 00000000bfff7a60 x19: 000000007fee20c0 x20: 0000000000000000 x21: 000000007fee0dc8 x22: 000000007fee0dc8 x23: 00000000000000ea x24: 0000000000000080 x25: 0000000000000000 x26: 00000000000000ea x27: 000000007fee2040 x28: 0000000000000000 x29: 00000000bfff7a60 Call trace: [<bfd967d8>] (v8_inv_dcache_range+0x1c/0x34) from [<bfd953fc>] (arch_sync_dma_for_cpu+0x14/0x20) [<bfd953fc>] (arch_sync_dma_for_cpu+0x14/0x20) from [<bfd25a64>] (eqos_recv+0x78/0x104) [<bfd25a64>] (eqos_recv+0x78/0x104) from [<bfd80724>] (eth_rx+0xd0/0x160) [<bfd80724>] (eth_rx+0xd0/0x160) from [<bfd80b84>] (net_poll+0x24/0x34) [<bfd80b84>] (net_poll+0x24/0x34) from [<bfd80bbc>] (__net_poll+0x28/0x3c) [<bfd80bbc>] (__net_poll+0x28/0x3c) from [<bfd0ec7c>] (poller_call+0x58/0x68) [<bfd0ec7c>] (poller_call+0x58/0x68) from [<bfd0ea98>] (resched+0x38/0x48) [<bfd0ea98>] (resched+0x38/0x48) from [<bfd77be0>] (readline+0xb4/0x89c) [<bfd77be0>] (readline+0xb4/0x89c) from [<bfd0f17c>] (file_get+0x94/0x1d8) [<bfd0f17c>] (file_get+0x94/0x1d8) from [<bfd0f92c>] (parse_stream.constprop.0+0x40/0x534) [<bfd0f92c>] (parse_stream.constprop.0+0x40/0x534) from [<bfd0ff10>] (parse_stream_outer+0xf0/0x1ec) [<bfd0ff10>] (parse_stream_outer+0xf0/0x1ec) from [<bfd10e0c>] (run_shell+0x60/0x98) [<bfd10e0c>] (run_shell+0x60/0x98) from [<bfd01854>] (run_init+0x170/0x2b0) [<bfd01854>] (run_init+0x170/0x2b0) from [<bfd019e4>] (start_barebox+0x50/0x8c) [<bfd019e4>] (start_barebox+0x50/0x8c) from [<bfd95794>] (barebox_non_pbl_start+0x11c/0x150) [<bfd95794>] (barebox_non_pbl_start+0x11c/0x150) from [<bfd0000c>] (__bare_init_start+0x0/0x4) [<bfd0000c>] (__bare_init_start+0x0/0x4) from [<402041fc>] (0x402041fc) [<402041fc>] (0x402041fc) from [<40203bac>] (0x40203bac) panic: unhandled exception This issue can be reproduced by using following command and link partner: mausezahn enp1s0f1 01:80:c2:00:00:0e:08:60:6e:1f:a3:9c:88:cc The problem caused this issue is wrong or may be different (depending on the HW) interpretation of DMA RX buffers. The DMA descriptors have distinct formats depending on their direction: Read Format for CPU-to-DMA and Write-Back Format for DMA-to-CPU. Previously, the driver did not distinguish between these, leading to misinterpretations of the descriptor fields. For example the driver expected a DMA buffer pointer in the Write-Back desc0 which is actually a VLAN tag descriptor and contains artifacts of DMA buffer pointer only by accident. To fix it we should store DMA buffer pointers in a separate array and use them. To prevent more of misunderstandings, i renamed variables to make it visible what format of DMA buffer we actually using. Signed-off-by: Oleksij Rempel <o.rempel@xxxxxxxxxxxxxx> --- drivers/net/designware_eqos.c | 55 ++++++++++++++++++++++------------- drivers/net/designware_eqos.h | 4 +++ 2 files changed, 39 insertions(+), 20 deletions(-) diff --git a/drivers/net/designware_eqos.c b/drivers/net/designware_eqos.c index 4489725e87..825c8e0140 100644 --- a/drivers/net/designware_eqos.c +++ b/drivers/net/designware_eqos.c @@ -172,8 +172,6 @@ struct eqos_dma_regs { #define EQOS_DESCRIPTOR_SIZE (EQOS_DESCRIPTOR_WORDS * 4) /* We assume ARCH_DMA_MINALIGN >= 16; 16 is the EQOS HW minimum */ #define EQOS_DESCRIPTOR_ALIGN 64 -#define EQOS_DESCRIPTORS_TX 4 -#define EQOS_DESCRIPTORS_RX 64 #define EQOS_DESCRIPTORS_NUM (EQOS_DESCRIPTORS_TX + EQOS_DESCRIPTORS_RX) #define EQOS_DESCRIPTORS_SIZE ALIGN(EQOS_DESCRIPTORS_NUM * \ EQOS_DESCRIPTOR_SIZE, EQOS_DESCRIPTOR_ALIGN) @@ -416,7 +414,7 @@ static int eqos_start(struct eth_device *edev) { struct eqos *eqos = edev->priv; u32 val, tx_fifo_sz, rx_fifo_sz, tqs, rqs, pbl; - unsigned long last_rx_desc; + unsigned long last_rx_rf_desc; unsigned long rate; u32 mode_set; int ret; @@ -626,9 +624,9 @@ static int eqos_start(struct eth_device *edev) eqos->tx_currdescnum = eqos->rx_currdescnum = 0; for (i = 0; i < EQOS_DESCRIPTORS_RX; i++) { - struct eqos_desc *rx_desc = &eqos->rx_descs[i]; + struct eqos_desc *rx_rf_desc = &eqos->rx_descs[i]; - writel(EQOS_DESC3_BUF1V | EQOS_DESC3_OWN, &rx_desc->des3); + writel(EQOS_DESC3_BUF1V | EQOS_DESC3_OWN, &rx_rf_desc->des3); } writel(0, &eqos->dma_regs->ch0_txdesc_list_haddress); @@ -658,8 +656,8 @@ static int eqos_start(struct eth_device *edev) * that's not distinguishable from none of the descriptors being * available. */ - last_rx_desc = (ulong)&eqos->rx_descs[(EQOS_DESCRIPTORS_RX - 1)]; - writel(last_rx_desc, &eqos->dma_regs->ch0_rxdesc_tail_pointer); + last_rx_rf_desc = (ulong)&eqos->rx_descs[(EQOS_DESCRIPTORS_RX - 1)]; + writel(last_rx_rf_desc, &eqos->dma_regs->ch0_rxdesc_tail_pointer); return 0; } @@ -746,16 +744,30 @@ static int eqos_send(struct eth_device *edev, void *packet, int length) static int eqos_recv(struct eth_device *edev) { struct eqos *eqos = edev->priv; - struct eqos_desc *rx_desc; + struct eqos_desc *rx_wbf_desc, *rx_rf_desc; + dma_addr_t dma; void *frame; int length; - rx_desc = &eqos->rx_descs[eqos->rx_currdescnum]; - if (readl(&rx_desc->des3) & EQOS_DESC3_OWN) + /* We have two types of RX descriptors at some pointer: Read and + * Write-Back: + * All RX descriptors are prepared by the software and given to the + * DMA as "Normal" Descriptors with the content as shown in Receive + * Normal Descriptor (Read Format). The DMA reads this descriptor and + * after transferring a received packet (or part of) to the buffers + * indicated by the descriptor, the Rx DMA will close the descriptor + * with the corresponding packet status. The format of this status is + * given in the "Receive Normal Descriptor (Write-Back Format)" + */ + + /* Write-Back Format RX descriptor */ + rx_wbf_desc = &eqos->rx_descs[eqos->rx_currdescnum]; + if (readl(&rx_wbf_desc->des3) & EQOS_DESC3_OWN) return 0; - frame = phys_to_virt(rx_desc->des0); - length = rx_desc->des3 & 0x7fff; + dma = eqos->dma_rx_buf[eqos->rx_currdescnum]; + frame = phys_to_virt(dma); + length = rx_wbf_desc->des3 & 0x7fff; dma_sync_single_for_cpu(edev->parent, (unsigned long)frame, length, DMA_FROM_DEVICE); @@ -763,18 +775,20 @@ static int eqos_recv(struct eth_device *edev) dma_sync_single_for_device(edev->parent, (unsigned long)frame, length, DMA_FROM_DEVICE); - rx_desc->des0 = (unsigned long)frame; - rx_desc->des1 = 0; - rx_desc->des2 = 0; + /* Read Format RX descriptor */ + rx_rf_desc = &eqos->rx_descs[eqos->rx_currdescnum]; + rx_rf_desc->des0 = dma; + rx_rf_desc->des1 = 0; + rx_rf_desc->des2 = 0; /* * Make sure that if HW sees the _OWN write below, it will see all the * writes to the rest of the descriptor too. */ - rx_desc->des3 |= EQOS_DESC3_BUF1V; - rx_desc->des3 |= EQOS_DESC3_OWN; + rx_rf_desc->des3 |= EQOS_DESC3_BUF1V; + rx_rf_desc->des3 |= EQOS_DESC3_OWN; barrier(); - writel((ulong)rx_desc, &eqos->dma_regs->ch0_rxdesc_tail_pointer); + writel((ulong)rx_rf_desc, &eqos->dma_regs->ch0_rxdesc_tail_pointer); eqos->rx_currdescnum++; eqos->rx_currdescnum %= EQOS_DESCRIPTORS_RX; @@ -802,7 +816,7 @@ static int eqos_init_resources(struct eqos *eqos) goto err_free_desc; for (i = 0; i < EQOS_DESCRIPTORS_RX; i++) { - struct eqos_desc *rx_desc = &eqos->rx_descs[i]; + struct eqos_desc *rx_rf_desc = &eqos->rx_descs[i]; dma_addr_t dma; dma = dma_map_single(edev->parent, p, EQOS_MAX_PACKET_SIZE, DMA_FROM_DEVICE); @@ -811,7 +825,8 @@ static int eqos_init_resources(struct eqos *eqos) goto err_free_rx_bufs; } - rx_desc->des0 = dma; + rx_rf_desc->des0 = dma; + eqos->dma_rx_buf[i] = dma; p += EQOS_MAX_PACKET_SIZE; } diff --git a/drivers/net/designware_eqos.h b/drivers/net/designware_eqos.h index 58ba912cd0..951565e8f9 100644 --- a/drivers/net/designware_eqos.h +++ b/drivers/net/designware_eqos.h @@ -40,6 +40,9 @@ struct eqos_dma_regs; struct eqos_mac_regs; struct eqos_mtl_regs; +#define EQOS_DESCRIPTORS_TX 4 +#define EQOS_DESCRIPTORS_RX 64 + struct eqos { struct eth_device netdev; struct mii_bus miibus; @@ -49,6 +52,7 @@ struct eqos { u32 tx_currdescnum, rx_currdescnum; struct eqos_desc *tx_descs, *rx_descs; + dma_addr_t dma_rx_buf[EQOS_DESCRIPTORS_RX]; void __iomem *regs; struct eqos_mac_regs __iomem *mac_regs; -- 2.39.2