Skip to content

Commit d3de85a

Browse files
committed
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>
2 parents 288ac52 + 057a0c5 commit d3de85a

File tree

7 files changed

+59
-37
lines changed

7 files changed

+59
-37
lines changed

drivers/net/ethernet/stmicro/stmmac/descs_com.h

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,13 @@
2929
/* Specific functions used for Ring mode */
3030

3131
/* Enhanced descriptors */
32-
static inline void ehn_desc_rx_set_on_ring(struct dma_desc *p, int end)
32+
static inline void ehn_desc_rx_set_on_ring(struct dma_desc *p, int end,
33+
int bfsize)
3334
{
34-
p->des1 |= cpu_to_le32((BUF_SIZE_8KiB
35-
<< ERDES1_BUFFER2_SIZE_SHIFT)
36-
& ERDES1_BUFFER2_SIZE_MASK);
35+
if (bfsize == BUF_SIZE_16KiB)
36+
p->des1 |= cpu_to_le32((BUF_SIZE_8KiB
37+
<< ERDES1_BUFFER2_SIZE_SHIFT)
38+
& ERDES1_BUFFER2_SIZE_MASK);
3739

3840
if (end)
3941
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)
5961
}
6062

6163
/* Normal descriptors */
62-
static inline void ndesc_rx_set_on_ring(struct dma_desc *p, int end)
64+
static inline void ndesc_rx_set_on_ring(struct dma_desc *p, int end, int bfsize)
6365
{
64-
p->des1 |= cpu_to_le32(((BUF_SIZE_2KiB - 1)
65-
<< RDES1_BUFFER2_SIZE_SHIFT)
66-
& RDES1_BUFFER2_SIZE_MASK);
66+
if (bfsize >= BUF_SIZE_2KiB) {
67+
int bfsize2;
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+
}
6773

6874
if (end)
6975
p->des1 |= cpu_to_le32(RDES1_END_RING);

drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ static int dwmac4_wrback_get_rx_timestamp_status(void *desc, void *next_desc,
296296
}
297297

298298
static 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)
300300
{
301301
dwmac4_set_rx_owner(p, disable_rx_ic);
302302
}

drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ static int dwxgmac2_get_rx_timestamp_status(void *desc, void *next_desc,
123123
}
124124

125125
static 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)
127127
{
128128
dwxgmac2_set_rx_owner(p, disable_rx_ic);
129129
}

drivers/net/ethernet/stmicro/stmmac/enh_desc.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,11 @@ static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
201201
if (unlikely(rdes0 & RDES0_OWN))
202202
return dma_own;
203203

204+
if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) {
205+
stats->rx_length_errors++;
206+
return discard_frame;
207+
}
208+
204209
if (unlikely(rdes0 & RDES0_ERROR_SUMMARY)) {
205210
if (unlikely(rdes0 & RDES0_DESCRIPTOR_ERROR)) {
206211
x->rx_desc++;
@@ -231,9 +236,10 @@ static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
231236
* It doesn't match with the information reported into the databook.
232237
* At any rate, we need to understand if the CSUM hw computation is ok
233238
* and report this info to the upper layers. */
234-
ret = enh_desc_coe_rdes0(!!(rdes0 & RDES0_IPC_CSUM_ERROR),
235-
!!(rdes0 & RDES0_FRAME_TYPE),
236-
!!(rdes0 & ERDES0_RX_MAC_ADDR));
239+
if (likely(ret == good_frame))
240+
ret = enh_desc_coe_rdes0(!!(rdes0 & RDES0_IPC_CSUM_ERROR),
241+
!!(rdes0 & RDES0_FRAME_TYPE),
242+
!!(rdes0 & ERDES0_RX_MAC_ADDR));
237243

238244
if (unlikely(rdes0 & RDES0_DRIBBLING))
239245
x->dribbling_bit++;
@@ -259,15 +265,19 @@ static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
259265
}
260266

261267
static 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)
263269
{
270+
int bfsize1;
271+
264272
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);
266276

267277
if (mode == STMMAC_CHAIN_MODE)
268278
ehn_desc_rx_set_on_chain(p);
269279
else
270-
ehn_desc_rx_set_on_ring(p, end);
280+
ehn_desc_rx_set_on_ring(p, end, bfsize);
271281

272282
if (disable_rx_ic)
273283
p->des1 |= cpu_to_le32(ERDES1_DISABLE_IC);

drivers/net/ethernet/stmicro/stmmac/hwif.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ struct dma_extended_desc;
3333
struct stmmac_desc_ops {
3434
/* DMA RX descriptor ring initialization */
3535
void (*init_rx_desc)(struct dma_desc *p, int disable_rx_ic, int mode,
36-
int end);
36+
int end, int bfsize);
3737
/* DMA TX descriptor ring initialization */
3838
void (*init_tx_desc)(struct dma_desc *p, int mode, int end);
3939
/* Invoked by the xmit function to prepare the tx descriptor */

drivers/net/ethernet/stmicro/stmmac/norm_desc.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,6 @@ static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x,
9191
return dma_own;
9292

9393
if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) {
94-
pr_warn("%s: Oversized frame spanned multiple buffers\n",
95-
__func__);
9694
stats->rx_length_errors++;
9795
return discard_frame;
9896
}
@@ -135,15 +133,19 @@ static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x,
135133
}
136134

137135
static void ndesc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, int mode,
138-
int end)
136+
int end, int bfsize)
139137
{
138+
int bfsize1;
139+
140140
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);
142144

143145
if (mode == STMMAC_CHAIN_MODE)
144146
ndesc_rx_set_on_chain(p, end);
145147
else
146-
ndesc_rx_set_on_ring(p, end);
148+
ndesc_rx_set_on_ring(p, end, bfsize);
147149

148150
if (disable_rx_ic)
149151
p->des1 |= cpu_to_le32(RDES1_DISABLE_IC);

drivers/net/ethernet/stmicro/stmmac/stmmac_main.c

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,11 +1136,13 @@ static void stmmac_clear_rx_descriptors(struct stmmac_priv *priv, u32 queue)
11361136
if (priv->extend_desc)
11371137
stmmac_init_rx_desc(priv, &rx_q->dma_erx[i].basic,
11381138
priv->use_riwt, priv->mode,
1139-
(i == DMA_RX_SIZE - 1));
1139+
(i == DMA_RX_SIZE - 1),
1140+
priv->dma_buf_sz);
11401141
else
11411142
stmmac_init_rx_desc(priv, &rx_q->dma_rx[i],
11421143
priv->use_riwt, priv->mode,
1143-
(i == DMA_RX_SIZE - 1));
1144+
(i == DMA_RX_SIZE - 1),
1145+
priv->dma_buf_sz);
11441146
}
11451147

11461148
/**
@@ -3352,9 +3354,8 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
33523354
{
33533355
struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];
33543356
struct stmmac_channel *ch = &priv->channel[queue];
3355-
unsigned int entry = rx_q->cur_rx;
3357+
unsigned int next_entry = rx_q->cur_rx;
33563358
int coe = priv->hw->rx_csum;
3357-
unsigned int next_entry;
33583359
unsigned int count = 0;
33593360
bool xmac;
33603361

@@ -3372,10 +3373,12 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
33723373
stmmac_display_ring(priv, rx_head, DMA_RX_SIZE, true);
33733374
}
33743375
while (count < limit) {
3375-
int status;
3376+
int entry, status;
33763377
struct dma_desc *p;
33773378
struct dma_desc *np;
33783379

3380+
entry = next_entry;
3381+
33793382
if (priv->extend_desc)
33803383
p = (struct dma_desc *)(rx_q->dma_erx + entry);
33813384
else
@@ -3431,11 +3434,12 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
34313434
* ignored
34323435
*/
34333436
if (frame_len > priv->dma_buf_sz) {
3434-
netdev_err(priv->dev,
3435-
"len %d larger than size (%d)\n",
3436-
frame_len, priv->dma_buf_sz);
3437+
if (net_ratelimit())
3438+
netdev_err(priv->dev,
3439+
"len %d larger than size (%d)\n",
3440+
frame_len, priv->dma_buf_sz);
34373441
priv->dev->stats.rx_length_errors++;
3438-
break;
3442+
continue;
34393443
}
34403444

34413445
/* 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)
34703474
dev_warn(priv->device,
34713475
"packet dropped\n");
34723476
priv->dev->stats.rx_dropped++;
3473-
break;
3477+
continue;
34743478
}
34753479

34763480
dma_sync_single_for_cpu(priv->device,
@@ -3490,11 +3494,12 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
34903494
} else {
34913495
skb = rx_q->rx_skbuff[entry];
34923496
if (unlikely(!skb)) {
3493-
netdev_err(priv->dev,
3494-
"%s: Inconsistent Rx chain\n",
3495-
priv->dev->name);
3497+
if (net_ratelimit())
3498+
netdev_err(priv->dev,
3499+
"%s: Inconsistent Rx chain\n",
3500+
priv->dev->name);
34963501
priv->dev->stats.rx_dropped++;
3497-
break;
3502+
continue;
34983503
}
34993504
prefetch(skb->data - NET_IP_ALIGN);
35003505
rx_q->rx_skbuff[entry] = NULL;
@@ -3529,7 +3534,6 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
35293534
priv->dev->stats.rx_packets++;
35303535
priv->dev->stats.rx_bytes += frame_len;
35313536
}
3532-
entry = next_entry;
35333537
}
35343538

35353539
stmmac_rx_refill(priv, queue);

0 commit comments

Comments
 (0)