diff options
author | Toshiharu Okada <toshiharu-linux@dsn.okisemi.com> | 2011-02-08 17:15:59 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-02-14 00:50:19 -0500 |
commit | ac09664248e300342e92b937c9894a8149ddf189 (patch) | |
tree | fccdb0361ff3bb153ffc16d889229ecf872fcd4d /drivers/net/pch_gbe/pch_gbe_main.c | |
parent | 539c9aa5ba7c5f71794ef0948c6dd29552f033e4 (diff) |
pch_gbe: Fix the issue that the receiving data is not normal.
This PCH_GBE driver had an issue that the receiving data is not normal.
This driver had not removed correctly the padding data
which the DMA include in receiving data.
This patch fixed this issue.
Signed-off-by: Toshiharu Okada <toshiharu-linux@dsn.okisemi.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/pch_gbe/pch_gbe_main.c')
-rw-r--r-- | drivers/net/pch_gbe/pch_gbe_main.c | 97 |
1 files changed, 55 insertions, 42 deletions
diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c index 4c9a7d4f3fca..f52d852569fb 100644 --- a/drivers/net/pch_gbe/pch_gbe_main.c +++ b/drivers/net/pch_gbe/pch_gbe_main.c | |||
@@ -29,6 +29,7 @@ const char pch_driver_version[] = DRV_VERSION; | |||
29 | #define PCH_GBE_SHORT_PKT 64 | 29 | #define PCH_GBE_SHORT_PKT 64 |
30 | #define DSC_INIT16 0xC000 | 30 | #define DSC_INIT16 0xC000 |
31 | #define PCH_GBE_DMA_ALIGN 0 | 31 | #define PCH_GBE_DMA_ALIGN 0 |
32 | #define PCH_GBE_DMA_PADDING 2 | ||
32 | #define PCH_GBE_WATCHDOG_PERIOD (1 * HZ) /* watchdog time */ | 33 | #define PCH_GBE_WATCHDOG_PERIOD (1 * HZ) /* watchdog time */ |
33 | #define PCH_GBE_COPYBREAK_DEFAULT 256 | 34 | #define PCH_GBE_COPYBREAK_DEFAULT 256 |
34 | #define PCH_GBE_PCI_BAR 1 | 35 | #define PCH_GBE_PCI_BAR 1 |
@@ -1365,16 +1366,13 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter, | |||
1365 | struct pch_gbe_buffer *buffer_info; | 1366 | struct pch_gbe_buffer *buffer_info; |
1366 | struct pch_gbe_rx_desc *rx_desc; | 1367 | struct pch_gbe_rx_desc *rx_desc; |
1367 | u32 length; | 1368 | u32 length; |
1368 | unsigned char tmp_packet[ETH_HLEN]; | ||
1369 | unsigned int i; | 1369 | unsigned int i; |
1370 | unsigned int cleaned_count = 0; | 1370 | unsigned int cleaned_count = 0; |
1371 | bool cleaned = false; | 1371 | bool cleaned = false; |
1372 | struct sk_buff *skb; | 1372 | struct sk_buff *skb, *new_skb; |
1373 | u8 dma_status; | 1373 | u8 dma_status; |
1374 | u16 gbec_status; | 1374 | u16 gbec_status; |
1375 | u32 tcp_ip_status; | 1375 | u32 tcp_ip_status; |
1376 | u8 skb_copy_flag = 0; | ||
1377 | u8 skb_padding_flag = 0; | ||
1378 | 1376 | ||
1379 | i = rx_ring->next_to_clean; | 1377 | i = rx_ring->next_to_clean; |
1380 | 1378 | ||
@@ -1418,55 +1416,70 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter, | |||
1418 | pr_err("Receive CRC Error\n"); | 1416 | pr_err("Receive CRC Error\n"); |
1419 | } else { | 1417 | } else { |
1420 | /* get receive length */ | 1418 | /* get receive length */ |
1421 | /* length convert[-3], padding[-2] */ | 1419 | /* length convert[-3] */ |
1422 | length = (rx_desc->rx_words_eob) - 3 - 2; | 1420 | length = (rx_desc->rx_words_eob) - 3; |
1423 | 1421 | ||
1424 | /* Decide the data conversion method */ | 1422 | /* Decide the data conversion method */ |
1425 | if (!adapter->rx_csum) { | 1423 | if (!adapter->rx_csum) { |
1426 | /* [Header:14][payload] */ | 1424 | /* [Header:14][payload] */ |
1427 | skb_padding_flag = 0; | 1425 | if (NET_IP_ALIGN) { |
1428 | skb_copy_flag = 1; | 1426 | /* Because alignment differs, |
1427 | * the new_skb is newly allocated, | ||
1428 | * and data is copied to new_skb.*/ | ||
1429 | new_skb = netdev_alloc_skb(netdev, | ||
1430 | length + NET_IP_ALIGN); | ||
1431 | if (!new_skb) { | ||
1432 | /* dorrop error */ | ||
1433 | pr_err("New skb allocation " | ||
1434 | "Error\n"); | ||
1435 | goto dorrop; | ||
1436 | } | ||
1437 | skb_reserve(new_skb, NET_IP_ALIGN); | ||
1438 | memcpy(new_skb->data, skb->data, | ||
1439 | length); | ||
1440 | skb = new_skb; | ||
1441 | } else { | ||
1442 | /* DMA buffer is used as SKB as it is.*/ | ||
1443 | buffer_info->skb = NULL; | ||
1444 | } | ||
1429 | } else { | 1445 | } else { |
1430 | /* [Header:14][padding:2][payload] */ | 1446 | /* [Header:14][padding:2][payload] */ |
1431 | skb_padding_flag = 1; | 1447 | /* The length includes padding length */ |
1432 | if (length < copybreak) | 1448 | length = length - PCH_GBE_DMA_PADDING; |
1433 | skb_copy_flag = 1; | 1449 | if ((length < copybreak) || |
1434 | else | 1450 | (NET_IP_ALIGN != PCH_GBE_DMA_PADDING)) { |
1435 | skb_copy_flag = 0; | 1451 | /* Because alignment differs, |
1436 | } | 1452 | * the new_skb is newly allocated, |
1437 | 1453 | * and data is copied to new_skb. | |
1438 | /* Data conversion */ | 1454 | * Padding data is deleted |
1439 | if (skb_copy_flag) { /* recycle skb */ | 1455 | * at the time of a copy.*/ |
1440 | struct sk_buff *new_skb; | 1456 | new_skb = netdev_alloc_skb(netdev, |
1441 | new_skb = | 1457 | length + NET_IP_ALIGN); |
1442 | netdev_alloc_skb(netdev, | 1458 | if (!new_skb) { |
1443 | length + NET_IP_ALIGN); | 1459 | /* dorrop error */ |
1444 | if (new_skb) { | 1460 | pr_err("New skb allocation " |
1445 | if (!skb_padding_flag) { | 1461 | "Error\n"); |
1446 | skb_reserve(new_skb, | 1462 | goto dorrop; |
1447 | NET_IP_ALIGN); | ||
1448 | } | 1463 | } |
1464 | skb_reserve(new_skb, NET_IP_ALIGN); | ||
1449 | memcpy(new_skb->data, skb->data, | 1465 | memcpy(new_skb->data, skb->data, |
1450 | length); | 1466 | ETH_HLEN); |
1451 | /* save the skb | 1467 | memcpy(&new_skb->data[ETH_HLEN], |
1452 | * in buffer_info as good */ | 1468 | &skb->data[ETH_HLEN + |
1469 | PCH_GBE_DMA_PADDING], | ||
1470 | length - ETH_HLEN); | ||
1453 | skb = new_skb; | 1471 | skb = new_skb; |
1454 | } else if (!skb_padding_flag) { | 1472 | } else { |
1455 | /* dorrop error */ | 1473 | /* Padding data is deleted |
1456 | pr_err("New skb allocation Error\n"); | 1474 | * by moving header data.*/ |
1457 | goto dorrop; | 1475 | memmove(&skb->data[PCH_GBE_DMA_PADDING], |
1476 | &skb->data[0], ETH_HLEN); | ||
1477 | skb_reserve(skb, NET_IP_ALIGN); | ||
1478 | buffer_info->skb = NULL; | ||
1458 | } | 1479 | } |
1459 | } else { | ||
1460 | buffer_info->skb = NULL; | ||
1461 | } | 1480 | } |
1462 | if (skb_padding_flag) { | 1481 | /* The length includes FCS length */ |
1463 | memcpy(&tmp_packet[0], &skb->data[0], ETH_HLEN); | 1482 | length = length - ETH_FCS_LEN; |
1464 | memcpy(&skb->data[NET_IP_ALIGN], &tmp_packet[0], | ||
1465 | ETH_HLEN); | ||
1466 | skb_reserve(skb, NET_IP_ALIGN); | ||
1467 | |||
1468 | } | ||
1469 | |||
1470 | /* update status of driver */ | 1483 | /* update status of driver */ |
1471 | adapter->stats.rx_bytes += length; | 1484 | adapter->stats.rx_bytes += length; |
1472 | adapter->stats.rx_packets++; | 1485 | adapter->stats.rx_packets++; |