Skip to content

Commit a44d4ee

Browse files
author
Ye Li
committed
LFU-613 net: fsl_enetc: Fix NETC RX BD and buffer issue
The driver exists two issues: 1. For RX buffer, current driver release the buffer too early, should wait until free_pkt callback is called. Otherwise, the released buffer will put into rx bd ring again and may be used by enetc when uboot is processing the packet. 2. The RX BD size is only 16 bytes, but cache line is 64 bytes on iMX95, so when flush a free RX BD to submit it ring, the flush may write adjacent BDs which locate in same cache line into memory. It has the possibility that netc has used (filled) this adjacent BD before uboot processes it. So the BD content is overwritten. It will cause polling Ready bit of this BD always failed. We already observed such issue in 1000Mbps network. The patch added the free_pkt call back implementation for issue #1. And for issue #2, it adjusts to submit BDs in cache line size to ring. For example, on iMX95, we submit 4 RX BDs which are in one cache line. The cache operations are also re-fined in the patch with clean codes. Signed-off-by: Ye Li <[email protected]> Reviewed-by: Peng Fan <[email protected]> Acked-by: Wei Fang <[email protected]>
1 parent deb8c6d commit a44d4ee

File tree

3 files changed

+115
-46
lines changed

3 files changed

+115
-46
lines changed

drivers/net/fsl_enetc.c

+113-46
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,56 @@
2727
#include "fsl_enetc.h"
2828
#endif
2929

30+
#ifdef CONFIG_ARCH_IMX9
31+
#define ENETC_DRV_DCACHE_OPS_EN 1
32+
#endif
33+
3034
#define ENETC_DRIVER_NAME "enetc_eth"
3135

36+
static void enetc_inval_bd(void *desc, bool tx)
37+
{
38+
#ifdef ENETC_DRV_DCACHE_OPS_EN
39+
unsigned long start = (unsigned long)desc & ~(ARCH_DMA_MINALIGN - 1);
40+
unsigned long size = tx? sizeof(struct enetc_tx_bd) : sizeof(union enetc_rx_bd);
41+
unsigned long end = ALIGN(start + size, ARCH_DMA_MINALIGN);
42+
43+
invalidate_dcache_range(start, end);
44+
#endif
45+
}
46+
47+
static void enetc_flush_bd(void *desc, bool tx)
48+
{
49+
#ifdef ENETC_DRV_DCACHE_OPS_EN
50+
unsigned long start = (unsigned long)desc & ~(ARCH_DMA_MINALIGN - 1);
51+
unsigned long size = tx? sizeof(struct enetc_tx_bd) : sizeof(union enetc_rx_bd);
52+
unsigned long end = ALIGN(start + size, ARCH_DMA_MINALIGN);
53+
54+
flush_dcache_range(start, end);
55+
#endif
56+
}
57+
58+
static void enetc_inval_buffer(void *buf, size_t size)
59+
{
60+
#ifdef ENETC_DRV_DCACHE_OPS_EN
61+
unsigned long start = rounddown((unsigned long)buf, ARCH_DMA_MINALIGN);
62+
unsigned long end = roundup((unsigned long)buf + size,
63+
ARCH_DMA_MINALIGN);
64+
65+
invalidate_dcache_range(start, end);
66+
#endif
67+
}
68+
69+
static void enetc_flush_buffer(void *buf, size_t size)
70+
{
71+
#ifdef ENETC_DRV_DCACHE_OPS_EN
72+
unsigned long start = rounddown((unsigned long)buf, ARCH_DMA_MINALIGN);
73+
unsigned long end = roundup((unsigned long)buf + size,
74+
ARCH_DMA_MINALIGN);
75+
76+
flush_dcache_range(start, end);
77+
#endif
78+
}
79+
3280
static int enetc_remove(struct udevice *dev);
3381

3482
/*
@@ -384,11 +432,30 @@ static int enetc_probe(struct udevice *dev)
384432
return -ENODEV;
385433
}
386434

435+
#ifdef ENETC_DRV_DCACHE_OPS_EN
436+
if (ARCH_DMA_MINALIGN % sizeof(struct enetc_tx_bd) ||
437+
ARCH_DMA_MINALIGN % sizeof(union enetc_rx_bd)) {
438+
printf("Error: Cacheline size is not integral multiples of BD size\n");
439+
return -EINVAL;
440+
}
441+
442+
/* Only rx bdr uses the bd_num_in_cl */
443+
priv->tx_bdr.bd_num_in_cl = ARCH_DMA_MINALIGN / sizeof(struct enetc_tx_bd);
444+
priv->rx_bdr.bd_num_in_cl = ARCH_DMA_MINALIGN / sizeof(union enetc_rx_bd);
445+
446+
if (ENETC_BD_CNT % priv->rx_bdr.bd_num_in_cl) {
447+
printf("Error: BD CNT is not integral multiples of bd_num_in_cl\n");
448+
return -EINVAL;
449+
}
450+
#else
451+
priv->tx_bdr.bd_num_in_cl = 1;
452+
priv->rx_bdr.bd_num_in_cl = 1;
453+
#endif
454+
387455
priv->enetc_txbd = memalign(ENETC_BD_ALIGN,
388456
sizeof(struct enetc_tx_bd) * ENETC_BD_CNT);
389457
priv->enetc_rxbd = memalign(ENETC_BD_ALIGN,
390458
sizeof(union enetc_rx_bd) * ENETC_BD_CNT);
391-
392459
if (!priv->enetc_txbd || !priv->enetc_rxbd) {
393460
/* free should be able to handle NULL, just free all pointers */
394461
free(priv->enetc_txbd);
@@ -618,10 +685,8 @@ static void enetc_setup_rx_bdr(struct udevice *dev)
618685
priv->enetc_rxbd[i].w.addr = enetc_rxb_address(dev, i);
619686
/* each RX buffer must be aligned to 64B */
620687
WARN_ON(priv->enetc_rxbd[i].w.addr & (ARCH_DMA_MINALIGN - 1));
621-
#ifdef CONFIG_ARCH_IMX9
622-
flush_dcache_range((ulong)&priv->enetc_rxbd[i],
623-
(ulong)&priv->enetc_rxbd[i] + sizeof(union enetc_rx_bd));
624-
#endif
688+
689+
enetc_flush_bd((void *)&priv->enetc_rxbd[i], false);
625690
}
626691

627692
/* reset producer (ENETC owned) and consumer (SW owned) index */
@@ -705,27 +770,19 @@ static int enetc_send(struct udevice *dev, void *packet, int length)
705770
enetc_dbg(dev, "TxBD[%d]send: pkt_len=%d, buff @0x%x%08x\n", pi, length,
706771
upper_32_bits((u64)nv_packet), lower_32_bits((u64)nv_packet));
707772

708-
#ifdef CONFIG_ARCH_IMX9
709-
ulong start;
710-
ulong stop;
773+
enetc_flush_buffer(packet, length);
711774

712-
start = (ulong)packet;
713-
start &= ~(ARCH_DMA_MINALIGN - 1);
714-
stop = roundup(start + length, ARCH_DMA_MINALIGN);
715-
flush_dcache_range(start, stop);
716-
#endif
717775
/* prepare Tx BD */
718776
memset(&priv->enetc_txbd[pi], 0x0, sizeof(struct enetc_tx_bd));
719777
priv->enetc_txbd[pi].addr =
720778
cpu_to_le64(dm_pci_virt_to_mem(dev, nv_packet));
721779
priv->enetc_txbd[pi].buf_len = cpu_to_le16(length);
722780
priv->enetc_txbd[pi].frm_len = cpu_to_le16(length);
723781
priv->enetc_txbd[pi].flags = cpu_to_le16(ENETC_TXBD_FLAGS_F);
724-
#ifdef CONFIG_ARCH_IMX9
725-
flush_dcache_range((ulong)&priv->enetc_txbd[pi],
726-
(ulong)&priv->enetc_txbd[pi] + sizeof(struct enetc_tx_bd));
727-
#endif
782+
728783
dmb();
784+
enetc_flush_bd((void *)&priv->enetc_txbd[pi], true);
785+
729786
/* send frame: increment producer index */
730787
pi = (pi + 1) % txr->bd_count;
731788
txr->next_prod_idx = pi;
@@ -749,22 +806,13 @@ static int enetc_recv(struct udevice *dev, int flags, uchar **packetp)
749806
struct bd_ring *rxr = &priv->rx_bdr;
750807
int tries = ENETC_POLL_TRIES;
751808
int pi = rxr->next_prod_idx;
752-
int ci = rxr->next_cons_idx;
753809
u32 status;
754810
int len;
755811
u8 rdy;
756812

757813
do {
758814
dmb();
759-
#ifdef CONFIG_ARCH_IMX9
760-
ulong start;
761-
ulong stop;
762-
763-
start = (ulong)&priv->enetc_rxbd[pi];
764-
start &= ~(ARCH_DMA_MINALIGN - 1);
765-
stop = roundup(start + sizeof(union enetc_rx_bd), ARCH_DMA_MINALIGN);
766-
invalidate_dcache_range(start, stop);
767-
#endif
815+
enetc_inval_bd((void *)&priv->enetc_rxbd[pi], false);
768816
status = le32_to_cpu(priv->enetc_rxbd[pi].r.lstatus);
769817
/* check if current BD is ready to be consumed */
770818
rdy = ENETC_RXBD_STATUS_R(status);
@@ -775,35 +823,53 @@ static int enetc_recv(struct udevice *dev, int flags, uchar **packetp)
775823

776824
dmb();
777825
len = le16_to_cpu(priv->enetc_rxbd[pi].r.buf_len);
778-
#ifdef CONFIG_ARCH_IMX9
779-
ulong begin;
780-
ulong end;
781-
782-
begin = (ulong)enetc_rxb_address(dev, pi);
783-
begin &= ~(ARCH_DMA_MINALIGN - 1);
784-
end = roundup(begin + len, ARCH_DMA_MINALIGN);
785-
invalidate_dcache_range(begin, end);
786-
#endif
787826
*packetp = (uchar *)enetc_rxb_address(dev, pi);
827+
enetc_inval_buffer(*packetp, len);
788828
enetc_dbg(dev, "RxBD[%d]: len=%d err=%d pkt=0x%x%08x\n", pi, len,
789829
ENETC_RXBD_STATUS_ERRORS(status),
790830
upper_32_bits((u64)*packetp), lower_32_bits((u64)*packetp));
791831

792-
/* BD clean up and advance to next in ring */
793-
memset(&priv->enetc_rxbd[pi], 0, sizeof(union enetc_rx_bd));
794-
priv->enetc_rxbd[pi].w.addr = enetc_rxb_address(dev, pi);
795-
#ifdef CONFIG_ARCH_IMX9
796-
flush_dcache_range((ulong)&priv->enetc_rxbd[pi],
797-
(ulong)&priv->enetc_rxbd[pi] + sizeof(union enetc_rx_bd));
798-
#endif
832+
return len;
833+
}
834+
835+
static int enetc_free_pkt(struct udevice *dev, uchar *packet, int length)
836+
{
837+
struct enetc_priv *priv = dev_get_priv(dev);
838+
struct bd_ring *rxr = &priv->rx_bdr;
839+
int pi = rxr->next_prod_idx;
840+
int ci = rxr->next_cons_idx;
841+
uchar *packet_expected;
842+
int i;
843+
844+
packet_expected = (uchar *)enetc_rxb_address(dev, pi);
845+
if (packet != packet_expected) {
846+
printf("%s: Unexpected packet (expected %p)\n", __func__,
847+
packet_expected);
848+
return -EINVAL;
849+
}
850+
799851
rxr->next_prod_idx = (pi + 1) % rxr->bd_count;
800852
ci = (ci + 1) % rxr->bd_count;
801853
rxr->next_cons_idx = ci;
802854
dmb();
803-
/* free up the slot in the ring for HW */
804-
enetc_write_reg(rxr->cons_idx, ci);
805855

806-
return len;
856+
if ((pi + 1) % rxr->bd_num_in_cl == 0) {
857+
858+
/* BD clean up and advance to next in ring */
859+
for (i = 0; i < rxr->bd_num_in_cl; i++) {
860+
memset(&priv->enetc_rxbd[pi - i], 0, sizeof(union enetc_rx_bd));
861+
priv->enetc_rxbd[pi - i].w.addr = enetc_rxb_address(dev, pi - i);
862+
}
863+
864+
/* Will flush all bds in one cacheline */
865+
enetc_flush_bd((void *)&priv->enetc_rxbd[pi - rxr->bd_num_in_cl + 1], false);
866+
867+
/* free up the slot in the ring for HW */
868+
enetc_write_reg(rxr->cons_idx, ci);
869+
870+
}
871+
872+
return 0;
807873
}
808874

809875
#ifdef CONFIG_ARCH_IMX9
@@ -838,6 +904,7 @@ static const struct eth_ops enetc_ops = {
838904
.send = enetc_send,
839905
.recv = enetc_recv,
840906
.stop = enetc_stop,
907+
.free_pkt = enetc_free_pkt,
841908
.write_hwaddr = enetc_write_hwaddr,
842909
#ifdef CONFIG_ARCH_IMX9
843910
.read_rom_hwaddr = enetc_read_rom_hwaddr,

drivers/net/fsl_enetc.h

+1
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ struct bd_ring {
144144
int next_prod_idx;
145145
int next_cons_idx;
146146
int bd_count;
147+
int bd_num_in_cl; /* bd number in one cache line */
147148
};
148149

149150
/* ENETC private structure */

drivers/net/fsl_enetc4.h

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ struct bd_ring {
5454
int next_prod_idx;
5555
int next_cons_idx;
5656
int bd_count;
57+
int bd_num_in_cl; /* bd number in one cache line */
5758
};
5859

5960
struct enetc_priv {

0 commit comments

Comments
 (0)