aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2019-03-31 17:00:59 -0400
committerDavid S. Miller <davem@davemloft.net>2019-03-31 17:00:59 -0400
commitd3de85a51a4b4eaeb62541dfdbf5159f3b210260 (patch)
tree21df898b0676583247063786206b24d7d00f7d11
parent288ac524cf70a8e7ed851a61ed2a9744039dae8d (diff)
parent057a0c5642a2ff2db7c421cdcde34294a23bf37b (diff)
Merge branch 'net-stmmac-fix-handling-of-oversized-frames'
Aaro Koskinen says: ==================== net: stmmac: fix handling of oversized frames I accidentally had MTU size mismatch (9000 vs. 1500) in my network, and I noticed I could kill a system using stmmac & 1500 MTU simply by pinging it with "ping -s 2000 ...". While testing a fix I encountered also some other issues that need fixing. I have tested these only with enhanced descriptors, so the normal descriptor changes need a careful review. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/descs_com.h22
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/enh_desc.c22
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/hwif.h2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/norm_desc.c12
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c34
7 files changed, 59 insertions, 37 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/descs_com.h b/drivers/net/ethernet/stmicro/stmmac/descs_com.h
index 40d6356a7e73..3dfb07a78952 100644
--- a/drivers/net/ethernet/stmicro/stmmac/descs_com.h
+++ b/drivers/net/ethernet/stmicro/stmmac/descs_com.h
@@ -29,11 +29,13 @@
29/* Specific functions used for Ring mode */ 29/* Specific functions used for Ring mode */
30 30
31/* Enhanced descriptors */ 31/* Enhanced descriptors */
32static inline void ehn_desc_rx_set_on_ring(struct dma_desc *p, int end) 32static inline void ehn_desc_rx_set_on_ring(struct dma_desc *p, int end,
33 int bfsize)
33{ 34{
34 p->des1 |= cpu_to_le32((BUF_SIZE_8KiB 35 if (bfsize == BUF_SIZE_16KiB)
35 << ERDES1_BUFFER2_SIZE_SHIFT) 36 p->des1 |= cpu_to_le32((BUF_SIZE_8KiB
36 & ERDES1_BUFFER2_SIZE_MASK); 37 << ERDES1_BUFFER2_SIZE_SHIFT)
38 & ERDES1_BUFFER2_SIZE_MASK);
37 39
38 if (end) 40 if (end)
39 p->des1 |= cpu_to_le32(ERDES1_END_RING); 41 p->des1 |= cpu_to_le32(ERDES1_END_RING);
@@ -59,11 +61,15 @@ static inline void enh_set_tx_desc_len_on_ring(struct dma_desc *p, int len)
59} 61}
60 62
61/* Normal descriptors */ 63/* Normal descriptors */
62static inline void ndesc_rx_set_on_ring(struct dma_desc *p, int end) 64static inline void ndesc_rx_set_on_ring(struct dma_desc *p, int end, int bfsize)
63{ 65{
64 p->des1 |= cpu_to_le32(((BUF_SIZE_2KiB - 1) 66 if (bfsize >= BUF_SIZE_2KiB) {
65 << RDES1_BUFFER2_SIZE_SHIFT) 67 int bfsize2;
66 & RDES1_BUFFER2_SIZE_MASK); 68
69 bfsize2 = min(bfsize - BUF_SIZE_2KiB + 1, BUF_SIZE_2KiB - 1);
70 p->des1 |= cpu_to_le32((bfsize2 << RDES1_BUFFER2_SIZE_SHIFT)
71 & RDES1_BUFFER2_SIZE_MASK);
72 }
67 73
68 if (end) 74 if (end)
69 p->des1 |= cpu_to_le32(RDES1_END_RING); 75 p->des1 |= cpu_to_le32(RDES1_END_RING);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
index 7fbb6a4dbf51..e061e9f5fad7 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
@@ -296,7 +296,7 @@ exit:
296} 296}
297 297
298static void dwmac4_rd_init_rx_desc(struct dma_desc *p, int disable_rx_ic, 298static void dwmac4_rd_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
299 int mode, int end) 299 int mode, int end, int bfsize)
300{ 300{
301 dwmac4_set_rx_owner(p, disable_rx_ic); 301 dwmac4_set_rx_owner(p, disable_rx_ic);
302} 302}
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c
index 1d858fdec997..98fa471da7c0 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c
@@ -123,7 +123,7 @@ static int dwxgmac2_get_rx_timestamp_status(void *desc, void *next_desc,
123} 123}
124 124
125static void dwxgmac2_init_rx_desc(struct dma_desc *p, int disable_rx_ic, 125static void dwxgmac2_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
126 int mode, int end) 126 int mode, int end, int bfsize)
127{ 127{
128 dwxgmac2_set_rx_owner(p, disable_rx_ic); 128 dwxgmac2_set_rx_owner(p, disable_rx_ic);
129} 129}
diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
index 5ef91a790f9d..5202d6ad7919 100644
--- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
@@ -201,6 +201,11 @@ static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
201 if (unlikely(rdes0 & RDES0_OWN)) 201 if (unlikely(rdes0 & RDES0_OWN))
202 return dma_own; 202 return dma_own;
203 203
204 if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) {
205 stats->rx_length_errors++;
206 return discard_frame;
207 }
208
204 if (unlikely(rdes0 & RDES0_ERROR_SUMMARY)) { 209 if (unlikely(rdes0 & RDES0_ERROR_SUMMARY)) {
205 if (unlikely(rdes0 & RDES0_DESCRIPTOR_ERROR)) { 210 if (unlikely(rdes0 & RDES0_DESCRIPTOR_ERROR)) {
206 x->rx_desc++; 211 x->rx_desc++;
@@ -231,9 +236,10 @@ static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
231 * It doesn't match with the information reported into the databook. 236 * It doesn't match with the information reported into the databook.
232 * At any rate, we need to understand if the CSUM hw computation is ok 237 * At any rate, we need to understand if the CSUM hw computation is ok
233 * and report this info to the upper layers. */ 238 * and report this info to the upper layers. */
234 ret = enh_desc_coe_rdes0(!!(rdes0 & RDES0_IPC_CSUM_ERROR), 239 if (likely(ret == good_frame))
235 !!(rdes0 & RDES0_FRAME_TYPE), 240 ret = enh_desc_coe_rdes0(!!(rdes0 & RDES0_IPC_CSUM_ERROR),
236 !!(rdes0 & ERDES0_RX_MAC_ADDR)); 241 !!(rdes0 & RDES0_FRAME_TYPE),
242 !!(rdes0 & ERDES0_RX_MAC_ADDR));
237 243
238 if (unlikely(rdes0 & RDES0_DRIBBLING)) 244 if (unlikely(rdes0 & RDES0_DRIBBLING))
239 x->dribbling_bit++; 245 x->dribbling_bit++;
@@ -259,15 +265,19 @@ static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
259} 265}
260 266
261static void enh_desc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, 267static void enh_desc_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
262 int mode, int end) 268 int mode, int end, int bfsize)
263{ 269{
270 int bfsize1;
271
264 p->des0 |= cpu_to_le32(RDES0_OWN); 272 p->des0 |= cpu_to_le32(RDES0_OWN);
265 p->des1 |= cpu_to_le32(BUF_SIZE_8KiB & ERDES1_BUFFER1_SIZE_MASK); 273
274 bfsize1 = min(bfsize, BUF_SIZE_8KiB);
275 p->des1 |= cpu_to_le32(bfsize1 & ERDES1_BUFFER1_SIZE_MASK);
266 276
267 if (mode == STMMAC_CHAIN_MODE) 277 if (mode == STMMAC_CHAIN_MODE)
268 ehn_desc_rx_set_on_chain(p); 278 ehn_desc_rx_set_on_chain(p);
269 else 279 else
270 ehn_desc_rx_set_on_ring(p, end); 280 ehn_desc_rx_set_on_ring(p, end, bfsize);
271 281
272 if (disable_rx_ic) 282 if (disable_rx_ic)
273 p->des1 |= cpu_to_le32(ERDES1_DISABLE_IC); 283 p->des1 |= cpu_to_le32(ERDES1_DISABLE_IC);
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h
index 92b8944f26e3..5bb00234d961 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@ -33,7 +33,7 @@ struct dma_extended_desc;
33struct stmmac_desc_ops { 33struct stmmac_desc_ops {
34 /* DMA RX descriptor ring initialization */ 34 /* DMA RX descriptor ring initialization */
35 void (*init_rx_desc)(struct dma_desc *p, int disable_rx_ic, int mode, 35 void (*init_rx_desc)(struct dma_desc *p, int disable_rx_ic, int mode,
36 int end); 36 int end, int bfsize);
37 /* DMA TX descriptor ring initialization */ 37 /* DMA TX descriptor ring initialization */
38 void (*init_tx_desc)(struct dma_desc *p, int mode, int end); 38 void (*init_tx_desc)(struct dma_desc *p, int mode, int end);
39 /* Invoked by the xmit function to prepare the tx descriptor */ 39 /* Invoked by the xmit function to prepare the tx descriptor */
diff --git a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
index de65bb29feba..b7dd4e3c760d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
@@ -91,8 +91,6 @@ static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x,
91 return dma_own; 91 return dma_own;
92 92
93 if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) { 93 if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) {
94 pr_warn("%s: Oversized frame spanned multiple buffers\n",
95 __func__);
96 stats->rx_length_errors++; 94 stats->rx_length_errors++;
97 return discard_frame; 95 return discard_frame;
98 } 96 }
@@ -135,15 +133,19 @@ static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x,
135} 133}
136 134
137static void ndesc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, int mode, 135static void ndesc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, int mode,
138 int end) 136 int end, int bfsize)
139{ 137{
138 int bfsize1;
139
140 p->des0 |= cpu_to_le32(RDES0_OWN); 140 p->des0 |= cpu_to_le32(RDES0_OWN);
141 p->des1 |= cpu_to_le32((BUF_SIZE_2KiB - 1) & RDES1_BUFFER1_SIZE_MASK); 141
142 bfsize1 = min(bfsize, BUF_SIZE_2KiB - 1);
143 p->des1 |= cpu_to_le32(bfsize & RDES1_BUFFER1_SIZE_MASK);
142 144
143 if (mode == STMMAC_CHAIN_MODE) 145 if (mode == STMMAC_CHAIN_MODE)
144 ndesc_rx_set_on_chain(p, end); 146 ndesc_rx_set_on_chain(p, end);
145 else 147 else
146 ndesc_rx_set_on_ring(p, end); 148 ndesc_rx_set_on_ring(p, end, bfsize);
147 149
148 if (disable_rx_ic) 150 if (disable_rx_ic)
149 p->des1 |= cpu_to_le32(RDES1_DISABLE_IC); 151 p->des1 |= cpu_to_le32(RDES1_DISABLE_IC);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 6a2e1031a62a..a26e36dbb5df 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -1136,11 +1136,13 @@ static void stmmac_clear_rx_descriptors(struct stmmac_priv *priv, u32 queue)
1136 if (priv->extend_desc) 1136 if (priv->extend_desc)
1137 stmmac_init_rx_desc(priv, &rx_q->dma_erx[i].basic, 1137 stmmac_init_rx_desc(priv, &rx_q->dma_erx[i].basic,
1138 priv->use_riwt, priv->mode, 1138 priv->use_riwt, priv->mode,
1139 (i == DMA_RX_SIZE - 1)); 1139 (i == DMA_RX_SIZE - 1),
1140 priv->dma_buf_sz);
1140 else 1141 else
1141 stmmac_init_rx_desc(priv, &rx_q->dma_rx[i], 1142 stmmac_init_rx_desc(priv, &rx_q->dma_rx[i],
1142 priv->use_riwt, priv->mode, 1143 priv->use_riwt, priv->mode,
1143 (i == DMA_RX_SIZE - 1)); 1144 (i == DMA_RX_SIZE - 1),
1145 priv->dma_buf_sz);
1144} 1146}
1145 1147
1146/** 1148/**
@@ -3352,9 +3354,8 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
3352{ 3354{
3353 struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; 3355 struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
3354 struct stmmac_channel *ch = &priv->channel[queue]; 3356 struct stmmac_channel *ch = &priv->channel[queue];
3355 unsigned int entry = rx_q->cur_rx; 3357 unsigned int next_entry = rx_q->cur_rx;
3356 int coe = priv->hw->rx_csum; 3358 int coe = priv->hw->rx_csum;
3357 unsigned int next_entry;
3358 unsigned int count = 0; 3359 unsigned int count = 0;
3359 bool xmac; 3360 bool xmac;
3360 3361
@@ -3372,10 +3373,12 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
3372 stmmac_display_ring(priv, rx_head, DMA_RX_SIZE, true); 3373 stmmac_display_ring(priv, rx_head, DMA_RX_SIZE, true);
3373 } 3374 }
3374 while (count < limit) { 3375 while (count < limit) {
3375 int status; 3376 int entry, status;
3376 struct dma_desc *p; 3377 struct dma_desc *p;
3377 struct dma_desc *np; 3378 struct dma_desc *np;
3378 3379
3380 entry = next_entry;
3381
3379 if (priv->extend_desc) 3382 if (priv->extend_desc)
3380 p = (struct dma_desc *)(rx_q->dma_erx + entry); 3383 p = (struct dma_desc *)(rx_q->dma_erx + entry);
3381 else 3384 else
@@ -3431,11 +3434,12 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
3431 * ignored 3434 * ignored
3432 */ 3435 */
3433 if (frame_len > priv->dma_buf_sz) { 3436 if (frame_len > priv->dma_buf_sz) {
3434 netdev_err(priv->dev, 3437 if (net_ratelimit())
3435 "len %d larger than size (%d)\n", 3438 netdev_err(priv->dev,
3436 frame_len, priv->dma_buf_sz); 3439 "len %d larger than size (%d)\n",
3440 frame_len, priv->dma_buf_sz);
3437 priv->dev->stats.rx_length_errors++; 3441 priv->dev->stats.rx_length_errors++;
3438 break; 3442 continue;
3439 } 3443 }
3440 3444
3441 /* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3 3445 /* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3
@@ -3470,7 +3474,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
3470 dev_warn(priv->device, 3474 dev_warn(priv->device,
3471 "packet dropped\n"); 3475 "packet dropped\n");
3472 priv->dev->stats.rx_dropped++; 3476 priv->dev->stats.rx_dropped++;
3473 break; 3477 continue;
3474 } 3478 }
3475 3479
3476 dma_sync_single_for_cpu(priv->device, 3480 dma_sync_single_for_cpu(priv->device,
@@ -3490,11 +3494,12 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
3490 } else { 3494 } else {
3491 skb = rx_q->rx_skbuff[entry]; 3495 skb = rx_q->rx_skbuff[entry];
3492 if (unlikely(!skb)) { 3496 if (unlikely(!skb)) {
3493 netdev_err(priv->dev, 3497 if (net_ratelimit())
3494 "%s: Inconsistent Rx chain\n", 3498 netdev_err(priv->dev,
3495 priv->dev->name); 3499 "%s: Inconsistent Rx chain\n",
3500 priv->dev->name);
3496 priv->dev->stats.rx_dropped++; 3501 priv->dev->stats.rx_dropped++;
3497 break; 3502 continue;
3498 } 3503 }
3499 prefetch(skb->data - NET_IP_ALIGN); 3504 prefetch(skb->data - NET_IP_ALIGN);
3500 rx_q->rx_skbuff[entry] = NULL; 3505 rx_q->rx_skbuff[entry] = NULL;
@@ -3529,7 +3534,6 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
3529 priv->dev->stats.rx_packets++; 3534 priv->dev->stats.rx_packets++;
3530 priv->dev->stats.rx_bytes += frame_len; 3535 priv->dev->stats.rx_bytes += frame_len;
3531 } 3536 }
3532 entry = next_entry;
3533 } 3537 }
3534 3538
3535 stmmac_rx_refill(priv, queue); 3539 stmmac_rx_refill(priv, queue);