aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorTomasz Lemiech <szpajder@staszic.waw.pl>2009-03-13 18:43:38 -0400
committerDavid S. Miller <davem@davemloft.net>2009-03-13 18:43:38 -0400
commit1f8ae0a21d83f43006d7f6d2862e921dbf2eeddd (patch)
tree36f744e3dda465f67d4bf5e2faab45ab14b791f4 /drivers
parenta390d1f379cf821248b735f43d2e1147ebb8241d (diff)
tulip: Fix for MTU problems with 802.1q tagged frames
The original patch was submitted last year but wasn't discussed or applied because of missing maintainer's CCs. I only fixed some formatting errors, but as I saw tulip is very badly formatted and needs further work. Original description: This patch fixes MTU problem, which occurs when using 802.1q VLANs. We should allow receiving frames of up to 1518 bytes in length, instead of 1514. Based on patch written by Ben McKeegan for 2.4.x kernels. It is archived at http://www.candelatech.com/~greear/vlan/howto.html#tulip I've adjusted a few things to make it apply on 2.6.x kernels. Tested on D-Link DFE-570TX quad-fastethernet card. Signed-off-by: Tomasz Lemiech <szpajder@staszic.waw.pl> Signed-off-by: Ivan Vecera <ivecera@redhat.com> Signed-off-by: Ben McKeegan <ben@netservers.co.uk> Acked-by: Grant Grundler <grundler@parisc-linux.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/tulip/interrupt.c84
-rw-r--r--drivers/net/tulip/tulip.h32
2 files changed, 86 insertions, 30 deletions
diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c
index 9f946d421088..c8d220cf2cce 100644
--- a/drivers/net/tulip/interrupt.c
+++ b/drivers/net/tulip/interrupt.c
@@ -140,6 +140,7 @@ int tulip_poll(struct napi_struct *napi, int budget)
140 /* If we own the next entry, it is a new packet. Send it up. */ 140 /* If we own the next entry, it is a new packet. Send it up. */
141 while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { 141 while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) {
142 s32 status = le32_to_cpu(tp->rx_ring[entry].status); 142 s32 status = le32_to_cpu(tp->rx_ring[entry].status);
143 short pkt_len;
143 144
144 if (tp->dirty_rx + RX_RING_SIZE == tp->cur_rx) 145 if (tp->dirty_rx + RX_RING_SIZE == tp->cur_rx)
145 break; 146 break;
@@ -151,8 +152,28 @@ int tulip_poll(struct napi_struct *napi, int budget)
151 if (++work_done >= budget) 152 if (++work_done >= budget)
152 goto not_done; 153 goto not_done;
153 154
154 if ((status & 0x38008300) != 0x0300) { 155 /*
155 if ((status & 0x38000300) != 0x0300) { 156 * Omit the four octet CRC from the length.
157 * (May not be considered valid until we have
158 * checked status for RxLengthOver2047 bits)
159 */
160 pkt_len = ((status >> 16) & 0x7ff) - 4;
161
162 /*
163 * Maximum pkt_len is 1518 (1514 + vlan header)
164 * Anything higher than this is always invalid
165 * regardless of RxLengthOver2047 bits
166 */
167
168 if ((status & (RxLengthOver2047 |
169 RxDescCRCError |
170 RxDescCollisionSeen |
171 RxDescRunt |
172 RxDescDescErr |
173 RxWholePkt)) != RxWholePkt
174 || pkt_len > 1518) {
175 if ((status & (RxLengthOver2047 |
176 RxWholePkt)) != RxWholePkt) {
156 /* Ingore earlier buffers. */ 177 /* Ingore earlier buffers. */
157 if ((status & 0xffff) != 0x7fff) { 178 if ((status & 0xffff) != 0x7fff) {
158 if (tulip_debug > 1) 179 if (tulip_debug > 1)
@@ -161,30 +182,23 @@ int tulip_poll(struct napi_struct *napi, int budget)
161 dev->name, status); 182 dev->name, status);
162 tp->stats.rx_length_errors++; 183 tp->stats.rx_length_errors++;
163 } 184 }
164 } else if (status & RxDescFatalErr) { 185 } else {
165 /* There was a fatal error. */ 186 /* There was a fatal error. */
166 if (tulip_debug > 2) 187 if (tulip_debug > 2)
167 printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n", 188 printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
168 dev->name, status); 189 dev->name, status);
169 tp->stats.rx_errors++; /* end of a packet.*/ 190 tp->stats.rx_errors++; /* end of a packet.*/
170 if (status & 0x0890) tp->stats.rx_length_errors++; 191 if (pkt_len > 1518 ||
192 (status & RxDescRunt))
193 tp->stats.rx_length_errors++;
194
171 if (status & 0x0004) tp->stats.rx_frame_errors++; 195 if (status & 0x0004) tp->stats.rx_frame_errors++;
172 if (status & 0x0002) tp->stats.rx_crc_errors++; 196 if (status & 0x0002) tp->stats.rx_crc_errors++;
173 if (status & 0x0001) tp->stats.rx_fifo_errors++; 197 if (status & 0x0001) tp->stats.rx_fifo_errors++;
174 } 198 }
175 } else { 199 } else {
176 /* Omit the four octet CRC from the length. */
177 short pkt_len = ((status >> 16) & 0x7ff) - 4;
178 struct sk_buff *skb; 200 struct sk_buff *skb;
179 201
180#ifndef final_version
181 if (pkt_len > 1518) {
182 printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n",
183 dev->name, pkt_len, pkt_len);
184 pkt_len = 1518;
185 tp->stats.rx_length_errors++;
186 }
187#endif
188 /* Check if the packet is long enough to accept without copying 202 /* Check if the packet is long enough to accept without copying
189 to a minimally-sized skbuff. */ 203 to a minimally-sized skbuff. */
190 if (pkt_len < tulip_rx_copybreak 204 if (pkt_len < tulip_rx_copybreak
@@ -356,14 +370,35 @@ static int tulip_rx(struct net_device *dev)
356 /* If we own the next entry, it is a new packet. Send it up. */ 370 /* If we own the next entry, it is a new packet. Send it up. */
357 while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { 371 while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) {
358 s32 status = le32_to_cpu(tp->rx_ring[entry].status); 372 s32 status = le32_to_cpu(tp->rx_ring[entry].status);
373 short pkt_len;
359 374
360 if (tulip_debug > 5) 375 if (tulip_debug > 5)
361 printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n", 376 printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n",
362 dev->name, entry, status); 377 dev->name, entry, status);
363 if (--rx_work_limit < 0) 378 if (--rx_work_limit < 0)
364 break; 379 break;
365 if ((status & 0x38008300) != 0x0300) { 380
366 if ((status & 0x38000300) != 0x0300) { 381 /*
382 Omit the four octet CRC from the length.
383 (May not be considered valid until we have
384 checked status for RxLengthOver2047 bits)
385 */
386 pkt_len = ((status >> 16) & 0x7ff) - 4;
387 /*
388 Maximum pkt_len is 1518 (1514 + vlan header)
389 Anything higher than this is always invalid
390 regardless of RxLengthOver2047 bits
391 */
392
393 if ((status & (RxLengthOver2047 |
394 RxDescCRCError |
395 RxDescCollisionSeen |
396 RxDescRunt |
397 RxDescDescErr |
398 RxWholePkt)) != RxWholePkt
399 || pkt_len > 1518) {
400 if ((status & (RxLengthOver2047 |
401 RxWholePkt)) != RxWholePkt) {
367 /* Ingore earlier buffers. */ 402 /* Ingore earlier buffers. */
368 if ((status & 0xffff) != 0x7fff) { 403 if ((status & 0xffff) != 0x7fff) {
369 if (tulip_debug > 1) 404 if (tulip_debug > 1)
@@ -372,31 +407,22 @@ static int tulip_rx(struct net_device *dev)
372 dev->name, status); 407 dev->name, status);
373 tp->stats.rx_length_errors++; 408 tp->stats.rx_length_errors++;
374 } 409 }
375 } else if (status & RxDescFatalErr) { 410 } else {
376 /* There was a fatal error. */ 411 /* There was a fatal error. */
377 if (tulip_debug > 2) 412 if (tulip_debug > 2)
378 printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n", 413 printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
379 dev->name, status); 414 dev->name, status);
380 tp->stats.rx_errors++; /* end of a packet.*/ 415 tp->stats.rx_errors++; /* end of a packet.*/
381 if (status & 0x0890) tp->stats.rx_length_errors++; 416 if (pkt_len > 1518 ||
417 (status & RxDescRunt))
418 tp->stats.rx_length_errors++;
382 if (status & 0x0004) tp->stats.rx_frame_errors++; 419 if (status & 0x0004) tp->stats.rx_frame_errors++;
383 if (status & 0x0002) tp->stats.rx_crc_errors++; 420 if (status & 0x0002) tp->stats.rx_crc_errors++;
384 if (status & 0x0001) tp->stats.rx_fifo_errors++; 421 if (status & 0x0001) tp->stats.rx_fifo_errors++;
385 } 422 }
386 } else { 423 } else {
387 /* Omit the four octet CRC from the length. */
388 short pkt_len = ((status >> 16) & 0x7ff) - 4;
389 struct sk_buff *skb; 424 struct sk_buff *skb;
390 425
391#ifndef final_version
392 if (pkt_len > 1518) {
393 printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n",
394 dev->name, pkt_len, pkt_len);
395 pkt_len = 1518;
396 tp->stats.rx_length_errors++;
397 }
398#endif
399
400 /* Check if the packet is long enough to accept without copying 426 /* Check if the packet is long enough to accept without copying
401 to a minimally-sized skbuff. */ 427 to a minimally-sized skbuff. */
402 if (pkt_len < tulip_rx_copybreak 428 if (pkt_len < tulip_rx_copybreak
diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h
index 19abbc36b60a..0afa2d4f9472 100644
--- a/drivers/net/tulip/tulip.h
+++ b/drivers/net/tulip/tulip.h
@@ -201,8 +201,38 @@ enum desc_status_bits {
201 DescStartPkt = 0x20000000, 201 DescStartPkt = 0x20000000,
202 DescEndRing = 0x02000000, 202 DescEndRing = 0x02000000,
203 DescUseLink = 0x01000000, 203 DescUseLink = 0x01000000,
204 RxDescFatalErr = 0x008000, 204
205 /*
206 * Error summary flag is logical or of 'CRC Error', 'Collision Seen',
207 * 'Frame Too Long', 'Runt' and 'Descriptor Error' flags generated
208 * within tulip chip.
209 */
210 RxDescErrorSummary = 0x8000,
211 RxDescCRCError = 0x0002,
212 RxDescCollisionSeen = 0x0040,
213
214 /*
215 * 'Frame Too Long' flag is set if packet length including CRC exceeds
216 * 1518. However, a full sized VLAN tagged frame is 1522 bytes
217 * including CRC.
218 *
219 * The tulip chip does not block oversized frames, and if this flag is
220 * set on a receive descriptor it does not indicate the frame has been
221 * truncated. The receive descriptor also includes the actual length.
222 * Therefore we can safety ignore this flag and check the length
223 * ourselves.
224 */
225 RxDescFrameTooLong = 0x0080,
226 RxDescRunt = 0x0800,
227 RxDescDescErr = 0x4000,
205 RxWholePkt = 0x00000300, 228 RxWholePkt = 0x00000300,
229 /*
230 * Top three bits of 14 bit frame length (status bits 27-29) should
231 * never be set as that would make frame over 2047 bytes. The Receive
232 * Watchdog flag (bit 4) may indicate the length is over 2048 and the
233 * length field is invalid.
234 */
235 RxLengthOver2047 = 0x38000010
206}; 236};
207 237
208 238