summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSerge Semin <fancer.lancer@gmail.com>2025-08-15 23:36:14 +0300
committerSerge Semin <fancer.lancer@gmail.com>2026-08-13 20:31:13 +0300
commitc0a6524f98d39f6313d912130e4ebcd444f29d4a (patch)
treef7fb50f627a309ac9ee74aa1b0c5cf31ea90db9d
parent2a2b01159b6610a1bf7137f8700921ec46efd846 (diff)
downloadlinux-c0a6524f98d39f6313d912130e4ebcd444f29d4a.tar.gz
linux-c0a6524f98d39f6313d912130e4ebcd444f29d4a.zip
net: stmmac: Add RXALL feature support
All except the ancient DW MAC100 controllers support permitting the erroneous frames to be delivered to the system memory instead of discarding them. The only that needs to be done is to fix the Rx DMA-descriptor status getters to return the error status and to enable the controller' DMA to stop dropping such the frames. It's done by setting up the flags DMA_CONTROL.DT (disable dropping the TCP/UDP/IP frames with incorrect csum), DMA_CONTROL.FEF (forward frames with CRC error, collision error, GMII_ER, giant frame, watchdog timeouted, or cut off due to the FIFO overflow), DMA_CONTROL.FUF (forward undesized good frames). Of course the NETIF_F_RXALL feature will be disabled by default and will be enabled upon the user request by the setting up the denoted flags in the net_device::ndo_set_features() callback. Signed-off-by: Serge Semin <fancer.lancer@gmail.com> --- The DMA_CONTROL.DGF (drop giant frames) flag setup will be added later. Until then the Giant frames won't dropped in anyway unless they exceed the critical size causing the WDT-based truncation.
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/common.h5
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/descs_com.h6
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac1000.h4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c9
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4.h2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c39
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c11
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h3
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c10
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c9
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/enh_desc.c48
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/hwif.h5
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/norm_desc.c46
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c62
14 files changed, 186 insertions, 73 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index 02df8523111a..82ae61ccfd78 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -362,6 +362,11 @@ enum rx_frame_status {
llc_snap = 0x4,
dma_own = 0x8,
rx_not_ls = 0x10,
+ len_err = 0x20, /* Under/Oversized frames */
+ csum_err = 0x40, /* Control sums check failure */
+ proto_err = 0x80, /* L1 protocol failures */
+ cutoff_err = 0x100, /* Frame' cut off due to HW failures */
+ rx_err = len_err | csum_err | proto_err | cutoff_err,
};
/* Tx status */
diff --git a/drivers/net/ethernet/stmicro/stmmac/descs_com.h b/drivers/net/ethernet/stmicro/stmmac/descs_com.h
index 7cb8c20fbe6f..d5c647184046 100644
--- a/drivers/net/ethernet/stmicro/stmmac/descs_com.h
+++ b/drivers/net/ethernet/stmicro/stmmac/descs_com.h
@@ -154,11 +154,11 @@ static inline int com_desc_rx_coe_rdes0(int ipc_err, int type, int payload_err)
case 0x4:
return good_frame;
case 0x5:
- return discard_frame;
+ return csum_err;
case 0x6:
- return discard_frame;
+ return csum_err;
case 0x7:
- return discard_frame;
+ return csum_err;
default:
return csum_none;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
index 9fe639fb06bb..2a51768cf64f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
@@ -172,7 +172,7 @@ enum rx_tx_priority_ratio {
/* DMA CRS Control and Status Register Mapping */
/* DMA operation mode defines (start/stop tx/rx are placed in common header)*/
-/* Disable Drop TCP/IP csum error */
+#define DMA_CONTROL_DT 0x04000000 /* Disable Drop TCP/IP csum error */
#define DMA_CONTROL_RSF 0x02000000 /* Receive Store and Forward */
#define DMA_CONTROL_DFF 0x01000000 /* Disaable flushing */
/* Threshold for Activating the FC */
@@ -204,6 +204,8 @@ enum ttc_control {
#define DMA_CONTROL_TC_TX_MASK 0xfffe3fff
#define DMA_CONTROL_EFC 0x00000100
+#define DMA_CONTROL_FEF 0x00000080
+#define DMA_CONTROL_FUF 0x00000040
/* Receive flow control activation field
* RFA field in DMA control register, bits 23,10:9
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
index a4b5b1a51f0a..a3052e29c8a2 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
@@ -125,7 +125,8 @@ static u32 dwmac1000_configure_fc(u32 csr6, int rxfifosz)
static void dwmac1000_dma_operation_mode_rx(struct stmmac_priv *priv,
void __iomem *ioaddr, int mode,
- u32 channel, int fifosz, u8 qmode)
+ u32 channel, int fifosz, u8 qmode,
+ bool rxall)
{
u32 csr6 = readl(ioaddr + DMA_CHAN_CONTROL(channel));
@@ -146,6 +147,12 @@ static void dwmac1000_dma_operation_mode_rx(struct stmmac_priv *priv,
csr6 |= DMA_CONTROL_RTC_128;
}
+ /* Permit errorneous frames (IP/TCP/UDP csum, overflow, giant, etc) */
+ if (rxall)
+ csr6 |= DMA_CONTROL_DT | DMA_CONTROL_FEF | DMA_CONTROL_FUF;
+ else
+ csr6 &= ~(DMA_CONTROL_DT | DMA_CONTROL_FEF | DMA_CONTROL_FUF);
+
/* Configure flow control based on rx fifo size */
csr6 = dwmac1000_configure_fc(csr6, fifosz);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
index 25572ac6a3f2..5c611dbc5abc 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
@@ -325,6 +325,8 @@ static inline u32 mtl_chanx_base_addr(const struct dwmac4_addrs *addrs,
#define MTL_OP_MODE_EHFC BIT(7)
#define MTL_OP_MODE_DIS_TCP_EF BIT(6)
+#define MTL_OP_MODE_FEP BIT(4)
+#define MTL_OP_MODE_FUP BIT(3)
#define MTL_OP_MODE_RTC_MASK GENMASK(1, 0)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
index 2c741bdae6fa..1b72fa907610 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
@@ -82,35 +82,46 @@ static int dwmac4_wrback_get_rx_status(struct stmmac_extra_stats *x,
return rx_not_ls;
if (unlikely(rdes3 & RDES3_ERROR_SUMMARY)) {
- if (unlikely(rdes3 & RDES3_GIANT_PACKET))
+ if (unlikely(rdes3 & RDES3_GIANT_PACKET)) {
x->rx_length++;
- if (unlikely(rdes3 & RDES3_OVERFLOW_ERROR))
+ ret |= len_err;
+ }
+
+ if (unlikely(rdes3 & RDES3_OVERFLOW_ERROR)) {
x->rx_gmac_overflow++;
+ ret |= cutoff_err;
+ }
- if (unlikely(rdes3 & RDES3_RECEIVE_WATCHDOG))
+ if (unlikely(rdes3 & RDES3_RECEIVE_WATCHDOG)) {
x->rx_watchdog++;
+ ret |= cutoff_err;
+ }
- if (unlikely(rdes3 & RDES3_RECEIVE_ERROR))
+ if (unlikely(rdes3 & RDES3_RECEIVE_ERROR)) {
x->rx_mii++;
+ ret |= proto_err;
+ }
- if (unlikely(rdes3 & RDES3_CRC_ERROR))
+ if (unlikely(rdes3 & RDES3_CRC_ERROR)) {
x->rx_crc_errors++;
+ ret |= csum_err;
+ }
- if (unlikely(rdes3 & RDES3_DRIBBLE_ERROR))
+ if (unlikely(rdes3 & RDES3_DRIBBLE_ERROR)) {
x->dribbling_bit++;
-
- ret = discard_frame;
+ ret |= proto_err;
+ }
}
message_type = FIELD_GET(RDES1_PTP_MSG_TYPE_MASK, rdes1);
if (rdes1 & RDES1_IP_HDR_ERROR) {
x->ip_hdr_err++;
- ret = discard_frame;
+ ret |= csum_err;
}
if (rdes1 & RDES1_IP_PAYLOAD_ERROR) {
x->ip_payload_err++;
- ret = discard_frame;
+ ret |= csum_err;
}
if (rdes1 & RDES1_IP_CSUM_BYPASSED) {
x->ip_csum_bypassed++;
@@ -153,14 +164,10 @@ static int dwmac4_wrback_get_rx_status(struct stmmac_extra_stats *x,
if (rdes1 & RDES1_TIMESTAMP_DROPPED)
x->timestamp_dropped++;
- if (unlikely(rdes2 & RDES2_SA_FILTER_FAIL)) {
+ if (unlikely(rdes2 & RDES2_SA_FILTER_FAIL))
x->sa_rx_filter_fail++;
- ret = discard_frame;
- }
- if (unlikely(rdes2 & RDES2_DA_FILTER_FAIL)) {
+ if (unlikely(rdes2 & RDES2_DA_FILTER_FAIL))
x->da_rx_filter_fail++;
- ret = discard_frame;
- }
if (rdes2 & RDES2_L3_FILTER_MATCH)
x->l3_filter_match++;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
index 00a8abd11bf2..93e9c636d86c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
@@ -264,7 +264,8 @@ static void dwmac4_rx_watchdog(struct stmmac_priv *priv, void __iomem *ioaddr,
static void dwmac4_dma_rx_chan_op_mode(struct stmmac_priv *priv,
void __iomem *ioaddr, int mode,
- u32 channel, int fifosz, u8 qmode)
+ u32 channel, int fifosz, u8 qmode,
+ bool rxall)
{
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
unsigned int rqs = fifosz / 256 - 1;
@@ -272,8 +273,6 @@ static void dwmac4_dma_rx_chan_op_mode(struct stmmac_priv *priv,
mtl_rx_op = readl(ioaddr + MTL_CHAN_RX_OP_MODE(dwmac4_addrs, channel));
- mtl_rx_op |= MTL_OP_MODE_DIS_TCP_EF;
-
if (mode == SF_DMA_MODE) {
pr_debug("GMAC: enable RX store and forward mode\n");
mtl_rx_op |= MTL_OP_MODE_RSF;
@@ -291,6 +290,12 @@ static void dwmac4_dma_rx_chan_op_mode(struct stmmac_priv *priv,
mtl_rx_op |= MTL_OP_MODE_RTC_128;
}
+ /* Permit errorneous frames (IP/TCP/UDP csum, overflow, giant, etc) */
+ if (rxall)
+ mtl_rx_op |= MTL_OP_MODE_DIS_TCP_EF | MTL_OP_MODE_FEP | MTL_OP_MODE_FUP;
+ else
+ mtl_rx_op &= ~(MTL_OP_MODE_DIS_TCP_EF | MTL_OP_MODE_FEP | MTL_OP_MODE_FUP);
+
mtl_rx_op &= ~MTL_OP_MODE_RQS_MASK;
mtl_rx_op |= FIELD_PREP(MTL_OP_MODE_RQS_MASK, rqs);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
index 3e9d0cf88422..6391e3d46c8d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
@@ -323,7 +323,10 @@
#define XGMAC_MTL_RXQ_OPMODE(x) (0x00001140 + (0x80 * (x)))
#define XGMAC_RQS GENMASK(25, 16)
#define XGMAC_EHFC BIT(7)
+#define XGMAC_DIS_TCP_EF BIT(6)
#define XGMAC_RSF BIT(5)
+#define XGMAC_FEF BIT(4)
+#define XGMAC_FUP BIT(3)
#define XGMAC_RTC GENMASK(1, 0)
#define XGMAC_MTL_RXQ_MISSED_PKT_CTR(x) (0x00001144 + (0x80 * (x)))
#define XGMAC_MISCNTOVF BIT(31)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c
index 8109421a0b78..e6f48dd7a5b1 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c
@@ -55,31 +55,37 @@ static int dwxgmac2_get_rx_status(struct stmmac_extra_stats *x,
switch (et) {
case XGMAC_ET_RECEIVE_WATCHDOG:
x->rx_watchdog++;
+ ret |= cutoff_err;
break;
case XGMAC_ET_XGMII_ERROR:
x->rx_mii++;
+ ret |= proto_err;
break;
case XGMAC_ET_CRC_ERROR:
x->rx_crc_errors++;
+ ret |= csum_err;
break;
case XGMAC_ET_GIANT_PACKET:
x->rx_length++;
+ ret |= len_err;
break;
case XGMAC_ET_IP_HDR_ERROR:
x->ip_hdr_err++;
+ ret |= csum_err;
break;
case XGMAC_ET_IP_PAYLOAD_ERROR:
x->ip_payload_err++;
+ ret |= csum_err;
break;
case XGMAC_ET_OVERFLOW_ERROR:
x->rx_gmac_overflow++;
+ ret |= cutoff_err;
break;
case XGMAC_ET_DESC_ERROR:
x->rx_desc++;
+ ret |= cutoff_err;
break;
}
-
- ret = discard_frame;
}
l34t = FIELD_GET(XGMAC_RDES3_L34T, rdes3);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
index c5888055c4e6..6b2362910285 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
@@ -142,7 +142,8 @@ static void dwxgmac2_dma_dump_regs(struct stmmac_priv *priv,
}
static void dwxgmac2_dma_rx_mode(struct stmmac_priv *priv, void __iomem *ioaddr,
- int mode, u32 channel, int fifosz, u8 qmode)
+ int mode, u32 channel, int fifosz, u8 qmode,
+ bool rxall)
{
u32 value = readl(ioaddr + XGMAC_MTL_RXQ_OPMODE(channel));
unsigned int rqs = fifosz / 256 - 1;
@@ -163,6 +164,12 @@ static void dwxgmac2_dma_rx_mode(struct stmmac_priv *priv, void __iomem *ioaddr,
value = u32_replace_bits(value, rtc, XGMAC_RTC);
}
+ /* Permit errorneous frames (IP/TCP/UDP csum, overflow, giant, etc) */
+ if (rxall)
+ value |= XGMAC_DIS_TCP_EF | XGMAC_FEF | XGMAC_FUP;
+ else
+ value &= ~(XGMAC_DIS_TCP_EF | XGMAC_FEF | XGMAC_FUP);
+
value = u32_replace_bits(value, rqs, XGMAC_RQS);
if ((fifosz >= 4096) && (qmode != MTL_QUEUE_AVB)) {
diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
index 5e0ef3558a5e..34cfe2fd26d2 100644
--- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
@@ -83,12 +83,12 @@ static int enh_desc_rx_ext_status(unsigned int rdes4,
if (rdes4 & ERDES4_IP_HDR_ERR) {
x->ip_hdr_err++;
- ret = discard_frame;
+ ret = csum_err;
}
if (rdes4 & ERDES4_IP_PAYLOAD_ERR) {
x->ip_payload_err++;
- ret = discard_frame;
+ ret = csum_err;
}
if (rdes4 & ERDES4_IP_CSUM_BYPASSED) {
@@ -179,44 +179,52 @@ static int enh_desc_get_rx_basic_status(unsigned int rdes0,
if (unlikely(rdes0 & RDES0_ERROR_SUMMARY)) {
if (unlikely(rdes0 & RDES0_DESCRIPTOR_ERROR)) {
x->rx_desc++;
- x->rx_length++;
+ ret |= cutoff_err;
}
- if (unlikely(rdes0 & RDES0_OVERFLOW_ERROR))
- x->rx_gmac_overflow++;
- if (unlikely(rdes0 & RDES0_COLLISION))
- x->rx_collision++;
+ if (unlikely(rdes0 & RDES0_OVERFLOW_ERROR)) {
+ x->rx_gmac_overflow++;
+ ret |= cutoff_err;
+ }
- if (unlikely(rdes0 & RDES0_GIANT_FRAME_ERROR))
+ if (unlikely(rdes0 & RDES0_GIANT_FRAME_ERROR)) {
x->rx_length++;
+ ret |= len_err;
+ }
+
+ if (unlikely(rdes0 & RDES0_COLLISION)) {
+ x->rx_collision++;
+ ret |= proto_err;
+ }
- if (unlikely(rdes0 & RDES0_RECEIVE_WATCHDOG))
+ if (unlikely(rdes0 & RDES0_RECEIVE_WATCHDOG)) {
x->rx_watchdog++;
+ ret |= cutoff_err;
+ }
- if (unlikely(rdes0 & RDES0_MII_ERROR)) /* GMII */
+ if (unlikely(rdes0 & RDES0_MII_ERROR)) {
x->rx_mii++;
+ ret |= proto_err;
+ }
if (unlikely(rdes0 & RDES0_CRC_ERROR)) {
x->rx_crc_errors++;
+ ret |= csum_err;
}
- ret = discard_frame;
}
if (unlikely(rdes0 & RDES0_DRIBBLING))
x->dribbling_bit++;
- if (unlikely(rdes0 & RDES0_SA_FILTER_FAIL)) {
+ if (unlikely(rdes0 & RDES0_SA_FILTER_FAIL))
x->sa_rx_filter_fail++;
- ret = discard_frame;
- }
- if (unlikely(rdes0 & RDES0_DA_FILTER_FAIL)) {
+
+ if (unlikely(rdes0 & RDES0_DA_FILTER_FAIL))
x->da_rx_filter_fail++;
- ret = discard_frame;
- }
- if (unlikely(rdes0 & RDES0_LENGTH_ERROR)) {
+
+ if (unlikely(rdes0 & RDES0_LENGTH_ERROR))
x->rx_length++;
- ret = discard_frame;
- }
+
#ifdef STMMAC_VLAN_TAG_USED
if (rdes0 & RDES0_VLAN_TAG)
x->rx_vlan++;
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h
index bf8138d75a13..e0495ee19a62 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@ -187,9 +187,10 @@ struct stmmac_dma_ops {
/* Dump DMA registers */
void (*dump_regs)(struct stmmac_priv *priv, void __iomem *ioaddr,
u32 *reg_space);
+ /* Setup DMA Rx/Tx channels */
void (*dma_rx_mode)(struct stmmac_priv *priv, void __iomem *ioaddr,
- int mode, u32 channel,
- int fifosz, u8 qmode);
+ int mode, u32 channel, int fifosz, u8 qmode,
+ bool rxall);
void (*dma_tx_mode)(struct stmmac_priv *priv, void __iomem *ioaddr,
int mode, u32 channel, int fifosz, u8 qmode);
/* To track extra statistic (if supported) */
diff --git a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
index fa95a1eeff5e..4e0b552aba3b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
@@ -78,33 +78,53 @@ static int ndesc_get_rx_basic_status(unsigned int rdes0,
}
if (unlikely(rdes0 & RDES0_ERROR_SUMMARY)) {
- if (unlikely(rdes0 & RDES0_DESCRIPTOR_ERROR))
+ if (unlikely(rdes0 & RDES0_DESCRIPTOR_ERROR)) {
x->rx_desc++;
- if (unlikely(rdes0 & RDES0_SA_FILTER_FAIL))
- x->sa_filter_fail++;
- if (unlikely(rdes0 & RDES0_OVERFLOW_ERROR))
+ ret |= cutoff_err;
+ }
+
+ if (unlikely(rdes0 & RDES0_OVERFLOW_ERROR)) {
x->overflow_error++;
- if (unlikely(rdes0 & RDES0_GIANT_FRAME_ERROR))
+ ret |= cutoff_err;
+ }
+
+ if (unlikely(rdes0 & RDES0_GIANT_FRAME_ERROR)) {
x->rx_length++;
+ ret |= len_err;
+ }
+
if (unlikely(rdes0 & RDES0_COLLISION)) {
x->rx_collision++;
+ ret |= proto_err;
+ }
+
+ if (unlikely(rdes0 & RDES0_RECEIVE_WATCHDOG)) {
+ x->rx_watchdog++;
+ ret |= cutoff_err;
}
+
+ if (unlikely(rdes0 & RDES0_MII_ERROR)) {
+ x->rx_mii++;
+ ret |= proto_err;
+ }
+
if (unlikely(rdes0 & RDES0_CRC_ERROR)) {
x->rx_crc_errors++;
+ ret |= csum_err;
}
- ret = discard_frame;
}
if (unlikely(rdes0 & RDES0_DRIBBLING))
x->dribbling_bit++;
- if (unlikely(rdes0 & RDES0_LENGTH_ERROR)) {
+ if (unlikely(rdes0 & RDES0_SA_FILTER_FAIL))
+ x->sa_filter_fail++;
+
+ if (unlikely(rdes0 & RDES0_DA_FILTER_FAIL))
+ x->da_rx_filter_fail++;
+
+ if (unlikely(rdes0 & RDES0_LENGTH_ERROR))
x->rx_length++;
- ret = discard_frame;
- }
- if (unlikely(rdes0 & RDES0_MII_ERROR)) {
- x->rx_mii++;
- ret = discard_frame;
- }
+
#ifdef STMMAC_VLAN_TAG_USED
if (rdes0 & RDES0_VLAN_TAG)
x->vlan_tag++;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index f0d395b86319..fc585c562eba 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -2707,8 +2707,8 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
qmode = priv->plat->rx_queues_cfg[chan].mode_to_use;
rx_q->rtc = rxmode;
- stmmac_dma_rx_mode(priv, priv->ioaddr, rxmode, chan,
- rxfifosz, qmode);
+ stmmac_dma_rx_mode(priv, priv->ioaddr, rxmode, chan, rxfifosz,
+ qmode, priv->dev->features & NETIF_F_RXALL);
if (rx_q->xsk_pool) {
buf_size = xsk_pool_get_rx_frame_size(rx_q->xsk_pool);
@@ -5021,6 +5021,28 @@ flush_ring:
return ret;
}
+/**
+ * stmmac_get_rx_status - Retrieve Rx DMA-descriptor status
+ * @priv: driver private structure
+ * @p : descriptor pointer
+ * Description :
+ * This function will parse the Rx DMA-descriptor status to get the generic
+ * status utilized by the Rx packets methods. It shall submit the descriptor
+ * for dropping if an error detected with no rx-all feature activated.
+ * Return: Rx DMA-descriptor status (rx_frame_status)
+ */
+static int stmmac_get_rx_status(struct stmmac_priv *priv, struct dma_desc *p)
+{
+ bool rxall = priv->dev->features & NETIF_F_RXALL;
+ int ret;
+
+ ret = stmmac_rx_status(priv, &priv->xstats, p);
+ if (likely(!(ret & rx_err) || rxall))
+ return ret;
+
+ return ret | discard_frame;
+}
+
static void stmmac_rx_vlan(struct net_device *dev, struct sk_buff *skb)
{
struct vlan_ethhdr *veth = skb_vlan_eth_hdr(skb);
@@ -5617,9 +5639,7 @@ read_again:
else
p = rx_q->dma_rx + entry;
- /* read the status of the incoming frame */
- status = stmmac_rx_status(priv, &priv->xstats, p);
- /* check if managed by the DMA otherwise go ahead */
+ status = stmmac_get_rx_status(priv, p);
if (unlikely(status & dma_own))
break;
@@ -5642,7 +5662,7 @@ read_again:
if (unlikely(status & discard_frame)) {
dirty++;
error = 1;
- if (!priv->hwts_rx_en)
+ if (status & rx_err)
rx_errors++;
}
@@ -5804,9 +5824,7 @@ read_again:
else
p = rx_q->dma_rx + entry;
- /* read the status of the incoming frame */
- status = stmmac_rx_status(priv, &priv->xstats, p);
- /* check if managed by the DMA otherwise go ahead */
+ status = stmmac_get_rx_status(priv, p);
if (unlikely(status & dma_own))
break;
@@ -5823,7 +5841,7 @@ read_again:
if (unlikely(status & discard_frame)) {
error = 1;
- if (!priv->hwts_rx_en)
+ if (status & rx_err)
rx_errors++;
}
@@ -6259,6 +6277,21 @@ static int stmmac_set_features(struct net_device *netdev,
stmmac_rx_ipc(priv, priv->hw, features & NETIF_F_RXCSUM);
+ for (chan = 0; chan < priv->plat->rx_queues_to_use; chan++) {
+ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan];
+ u8 rxqmode = priv->plat->rx_queues_cfg[chan].mode_to_use;
+ int rxfifosz = priv->plat->rx_fifo_size;
+
+ if (rxfifosz == 0)
+ rxfifosz = priv->dma_cap.rx_fifo_size;
+
+ if (dwmac_is_xmac(priv->plat->core_type))
+ rxfifosz /= priv->plat->rx_queues_to_use;
+
+ stmmac_dma_rx_mode(priv, priv->ioaddr, rx_q->rtc, chan,
+ rxfifosz, rxqmode, features & NETIF_F_RXALL);
+ }
+
for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) {
struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan];
bool tso_en = !(tx_q->tbs & STMMAC_TBS_AVAIL) &&
@@ -7621,7 +7654,8 @@ static void stmmac_drop_rtc_subtask(struct stmmac_priv *priv, u32 queue)
rxqmode = priv->plat->rx_queues_cfg[queue].mode_to_use;
- stmmac_dma_rx_mode(priv, priv->ioaddr, rx_q->rtc, queue, rxfifosz, rxqmode);
+ stmmac_dma_rx_mode(priv, priv->ioaddr, rx_q->rtc, queue, rxfifosz,
+ rxqmode, priv->dev->features & NETIF_F_RXALL);
}
/**
@@ -8385,6 +8419,12 @@ static int __stmmac_dvr_probe(struct device *device,
ndev->hw_features |= NETIF_F_RXHASH;
ndev->features |= ndev->hw_features | NETIF_F_SG | NETIF_F_HIGHDMA;
+
+ /* Old DW MAC doesn't seem to provide the pass-error-frames setting */
+ if (priv->plat->core_type == DWMAC_CORE_GMAC ||
+ dwmac_is_xmac(priv->plat->core_type))
+ ndev->hw_features |= NETIF_F_RXALL;
+
ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
#ifdef STMMAC_VLAN_TAG_USED
/* Both mac100 and gmac support receive VLAN tag detection */