diff options
author | Andy Cress <andycress@gmail.com> | 2012-07-26 02:00:11 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-07-26 17:30:23 -0400 |
commit | f2c31662762b9e82b9891d6b385b17f9e5ef0ed2 (patch) | |
tree | 143048e8a3d4e8da0ede50187bcb761522afeb72 /drivers/net/ethernet/oki-semi | |
parent | 913f53e4c8a464c46a70898c88f2291ade28c196 (diff) |
pch_gbe: add extra clean tx
This adds extra cleaning to the pch_gbe_clean_tx routine to avoid
transmit timeouts on some BCM PHYs that have different timing.
Also update the DRV_VERSION to 1.01, and show it.
Signed-off-by: Andy Cress <andy.cress@us.kontron.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/oki-semi')
-rw-r--r-- | drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c | 57 |
1 files changed, 44 insertions, 13 deletions
diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c index 99bba29e0553..1bb4cd14b149 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c +++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c | |||
@@ -26,7 +26,7 @@ | |||
26 | #include <linux/ptp_classify.h> | 26 | #include <linux/ptp_classify.h> |
27 | #endif | 27 | #endif |
28 | 28 | ||
29 | #define DRV_VERSION "1.00" | 29 | #define DRV_VERSION "1.01" |
30 | const char pch_driver_version[] = DRV_VERSION; | 30 | const char pch_driver_version[] = DRV_VERSION; |
31 | 31 | ||
32 | #define PCI_DEVICE_ID_INTEL_IOH1_GBE 0x8802 /* Pci device ID */ | 32 | #define PCI_DEVICE_ID_INTEL_IOH1_GBE 0x8802 /* Pci device ID */ |
@@ -1579,7 +1579,8 @@ pch_gbe_clean_tx(struct pch_gbe_adapter *adapter, | |||
1579 | struct sk_buff *skb; | 1579 | struct sk_buff *skb; |
1580 | unsigned int i; | 1580 | unsigned int i; |
1581 | unsigned int cleaned_count = 0; | 1581 | unsigned int cleaned_count = 0; |
1582 | bool cleaned = true; | 1582 | bool cleaned = false; |
1583 | int unused, thresh; | ||
1583 | 1584 | ||
1584 | pr_debug("next_to_clean : %d\n", tx_ring->next_to_clean); | 1585 | pr_debug("next_to_clean : %d\n", tx_ring->next_to_clean); |
1585 | 1586 | ||
@@ -1588,10 +1589,36 @@ pch_gbe_clean_tx(struct pch_gbe_adapter *adapter, | |||
1588 | pr_debug("gbec_status:0x%04x dma_status:0x%04x\n", | 1589 | pr_debug("gbec_status:0x%04x dma_status:0x%04x\n", |
1589 | tx_desc->gbec_status, tx_desc->dma_status); | 1590 | tx_desc->gbec_status, tx_desc->dma_status); |
1590 | 1591 | ||
1592 | unused = PCH_GBE_DESC_UNUSED(tx_ring); | ||
1593 | thresh = tx_ring->count - PCH_GBE_TX_WEIGHT; | ||
1594 | if ((tx_desc->gbec_status == DSC_INIT16) && (unused < thresh)) | ||
1595 | { /* current marked clean, tx queue filling up, do extra clean */ | ||
1596 | int j, k; | ||
1597 | if (unused < 8) { /* tx queue nearly full */ | ||
1598 | pr_debug("clean_tx: transmit queue warning (%x,%x) unused=%d\n", | ||
1599 | tx_ring->next_to_clean,tx_ring->next_to_use,unused); | ||
1600 | } | ||
1601 | |||
1602 | /* current marked clean, scan for more that need cleaning. */ | ||
1603 | k = i; | ||
1604 | for (j = 0; j < PCH_GBE_TX_WEIGHT; j++) | ||
1605 | { | ||
1606 | tx_desc = PCH_GBE_TX_DESC(*tx_ring, k); | ||
1607 | if (tx_desc->gbec_status != DSC_INIT16) break; /*found*/ | ||
1608 | if (++k >= tx_ring->count) k = 0; /*increment, wrap*/ | ||
1609 | } | ||
1610 | if (j < PCH_GBE_TX_WEIGHT) { | ||
1611 | pr_debug("clean_tx: unused=%d loops=%d found tx_desc[%x,%x:%x].gbec_status=%04x\n", | ||
1612 | unused,j, i,k, tx_ring->next_to_use, tx_desc->gbec_status); | ||
1613 | i = k; /*found one to clean, usu gbec_status==2000.*/ | ||
1614 | } | ||
1615 | } | ||
1616 | |||
1591 | while ((tx_desc->gbec_status & DSC_INIT16) == 0x0000) { | 1617 | while ((tx_desc->gbec_status & DSC_INIT16) == 0x0000) { |
1592 | pr_debug("gbec_status:0x%04x\n", tx_desc->gbec_status); | 1618 | pr_debug("gbec_status:0x%04x\n", tx_desc->gbec_status); |
1593 | buffer_info = &tx_ring->buffer_info[i]; | 1619 | buffer_info = &tx_ring->buffer_info[i]; |
1594 | skb = buffer_info->skb; | 1620 | skb = buffer_info->skb; |
1621 | cleaned = true; | ||
1595 | 1622 | ||
1596 | if ((tx_desc->gbec_status & PCH_GBE_TXD_GMAC_STAT_ABT)) { | 1623 | if ((tx_desc->gbec_status & PCH_GBE_TXD_GMAC_STAT_ABT)) { |
1597 | adapter->stats.tx_aborted_errors++; | 1624 | adapter->stats.tx_aborted_errors++; |
@@ -1639,18 +1666,21 @@ pch_gbe_clean_tx(struct pch_gbe_adapter *adapter, | |||
1639 | } | 1666 | } |
1640 | pr_debug("called pch_gbe_unmap_and_free_tx_resource() %d count\n", | 1667 | pr_debug("called pch_gbe_unmap_and_free_tx_resource() %d count\n", |
1641 | cleaned_count); | 1668 | cleaned_count); |
1642 | /* Recover from running out of Tx resources in xmit_frame */ | 1669 | if (cleaned_count > 0) { /*skip this if nothing cleaned*/ |
1643 | spin_lock(&tx_ring->tx_lock); | 1670 | /* Recover from running out of Tx resources in xmit_frame */ |
1644 | if (unlikely(cleaned && (netif_queue_stopped(adapter->netdev)))) { | 1671 | spin_lock(&tx_ring->tx_lock); |
1645 | netif_wake_queue(adapter->netdev); | 1672 | if (unlikely(cleaned && (netif_queue_stopped(adapter->netdev)))) |
1646 | adapter->stats.tx_restart_count++; | 1673 | { |
1647 | pr_debug("Tx wake queue\n"); | 1674 | netif_wake_queue(adapter->netdev); |
1648 | } | 1675 | adapter->stats.tx_restart_count++; |
1676 | pr_debug("Tx wake queue\n"); | ||
1677 | } | ||
1649 | 1678 | ||
1650 | tx_ring->next_to_clean = i; | 1679 | tx_ring->next_to_clean = i; |
1651 | 1680 | ||
1652 | pr_debug("next_to_clean : %d\n", tx_ring->next_to_clean); | 1681 | pr_debug("next_to_clean : %d\n", tx_ring->next_to_clean); |
1653 | spin_unlock(&tx_ring->tx_lock); | 1682 | spin_unlock(&tx_ring->tx_lock); |
1683 | } | ||
1654 | return cleaned; | 1684 | return cleaned; |
1655 | } | 1685 | } |
1656 | 1686 | ||
@@ -2389,7 +2419,7 @@ static int pch_gbe_napi_poll(struct napi_struct *napi, int budget) | |||
2389 | pch_gbe_clean_rx(adapter, adapter->rx_ring, &work_done, budget); | 2419 | pch_gbe_clean_rx(adapter, adapter->rx_ring, &work_done, budget); |
2390 | cleaned = pch_gbe_clean_tx(adapter, adapter->tx_ring); | 2420 | cleaned = pch_gbe_clean_tx(adapter, adapter->tx_ring); |
2391 | 2421 | ||
2392 | if (!cleaned) | 2422 | if (cleaned) |
2393 | work_done = budget; | 2423 | work_done = budget; |
2394 | /* If no Tx and not enough Rx work done, | 2424 | /* If no Tx and not enough Rx work done, |
2395 | * exit the polling mode | 2425 | * exit the polling mode |
@@ -2795,6 +2825,7 @@ static int __init pch_gbe_init_module(void) | |||
2795 | { | 2825 | { |
2796 | int ret; | 2826 | int ret; |
2797 | 2827 | ||
2828 | pr_info("EG20T PCH Gigabit Ethernet Driver - version %s\n",DRV_VERSION); | ||
2798 | ret = pci_register_driver(&pch_gbe_driver); | 2829 | ret = pci_register_driver(&pch_gbe_driver); |
2799 | if (copybreak != PCH_GBE_COPYBREAK_DEFAULT) { | 2830 | if (copybreak != PCH_GBE_COPYBREAK_DEFAULT) { |
2800 | if (copybreak == 0) { | 2831 | if (copybreak == 0) { |