net: dc2114x: allow users to decide how to tx packets according to IP core
Some IP cores of dc2114x or its variants do not comply so well with
the behaviors described by the official document. Originally this
driver uses only one tx descriptor and organizes it as a ring buffer,
which would lead to a problem that one packet would be sent twice.
This commit adds support to prevent this bug if you are using IP
cores with this issue, by using multiple tx descriptors and
organizing them as a real well-defined ring buffer.
Signed-off-by: Hanyuan Zhao <zhaohy22@mails.tsinghua.edu.cn>
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 804f4b0..6fd037b 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -781,6 +781,19 @@
of this IP core do not detect this error anymore. Say Y to this could
disable handling of this error.
+config TULIP_MULTIPLE_TX_DESC
+ bool "Use multiple tx descriptors"
+ depends on TULIP
+ default n
+ help
+ Some IP cores of dc2114x or its variants do not comply so well with
+ the behaviors described by the official document. Originally this
+ driver uses only one tx descriptor and organizes it as a ring buffer,
+ which would lead to a problem that one packet would be sent twice.
+ Say Y to this could prevent this bug if you are using IP cores with
+ this issue, by using multiple tx descriptors and organizing them as
+ a real well-defined ring buffer.
+
config XILINX_AXIEMAC
select PHYLIB
select MII
diff --git a/drivers/net/dc2114x.c b/drivers/net/dc2114x.c
index dc28712..11dea9b 100644
--- a/drivers/net/dc2114x.c
+++ b/drivers/net/dc2114x.c
@@ -78,10 +78,15 @@
#else
#define phys_to_bus(dev, a) dm_pci_phys_to_mem((dev), (a))
#endif
+
+/* Number of TX descriptors */
+#if CONFIG_IS_ENABLED(TULIP_MULTIPLE_TX_DESC)
+#define NUM_TX_DESC 4
+#else
+#define NUM_TX_DESC 1
#endif
#define NUM_RX_DESC PKTBUFSRX
-#define NUM_TX_DESC 1 /* Number of TX descriptors */
#define RX_BUFF_SZ PKTSIZE_ALIGN
#define TOUT_LOOP 1000000
@@ -312,7 +317,12 @@
priv->tx_ring[priv->tx_new].buf = cpu_to_le32(phys_to_bus(priv->devno,
(phys_addr_t)&setup_frame[0]));
+#if CONFIG_IS_ENABLED(TULIP_MULTIPLE_TX_DESC)
+ priv->tx_ring[priv->tx_new].des1 = cpu_to_le32(TD_SET | SETUP_FRAME_LEN);
+ priv->tx_ring[priv->tx_ring_size - 1].des1 |= cpu_to_le32(TD_TER);
+#else
priv->tx_ring[priv->tx_new].des1 = cpu_to_le32(TD_TER | TD_SET | SETUP_FRAME_LEN);
+#endif
priv->tx_ring[priv->tx_new].status = cpu_to_le32(T_OWN);
dc2114x_outl(priv, POLL_DEMAND, DE4X5_TPD);
@@ -356,7 +366,12 @@
priv->tx_ring[priv->tx_new].buf = cpu_to_le32(phys_to_bus(priv->devno,
(phys_addr_t)packet));
+#if CONFIG_IS_ENABLED(TULIP_MULTIPLE_TX_DESC)
+ priv->tx_ring[priv->tx_new].des1 = cpu_to_le32(TD_LS | TD_FS | length);
+ priv->tx_ring[priv->tx_ring_size - 1].des1 |= cpu_to_le32(TD_TER);
+#else
priv->tx_ring[priv->tx_new].des1 = cpu_to_le32(TD_TER | TD_LS | TD_FS | length);
+#endif
priv->tx_ring[priv->tx_new].status = cpu_to_le32(T_OWN);
dc2114x_outl(priv, POLL_DEMAND, DE4X5_TPD);