From 3b12e0141f7a97c3b84731b5f935ed738bb6f960 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 26 Sep 2007 17:58:47 -0700 Subject: sky2: sky2 FE+ receive status workaround The Yukon FE+ chip appears to have a hardware glitch that causes bogus receive status values to be posted. The data in the packet is good, but the status value is random garbage. As a temporary workaround until the problem is better understood, implement the workaround the vendor driver used of ignoring the status value on this chip. Since this means trusting dodgy hardware values; add additional checking of the receive packet length. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 0792031a5cf9..a3de0b6127eb 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2148,6 +2148,18 @@ static struct sk_buff *sky2_receive(struct net_device *dev, sky2->rx_next = (sky2->rx_next + 1) % sky2->rx_pending; prefetch(sky2->rx_ring + sky2->rx_next); + if (length < ETH_ZLEN || length > sky2->rx_data_size) + goto len_error; + + /* This chip has hardware problems that generates bogus status. + * So do only marginal checking and expect higher level protocols + * to handle crap frames. + */ + if (sky2->hw->chip_id == CHIP_ID_YUKON_FE_P && + sky2->hw->chip_rev == CHIP_REV_YU_FE2_A0 && + length != count) + goto okay; + if (status & GMR_FS_ANY_ERR) goto error; @@ -2156,8 +2168,9 @@ static struct sk_buff *sky2_receive(struct net_device *dev, /* if length reported by DMA does not match PHY, packet was truncated */ if (length != count) - goto len_mismatch; + goto len_error; +okay: if (length < copybreak) skb = receive_copy(sky2, re, length); else @@ -2167,13 +2180,13 @@ resubmit: return skb; -len_mismatch: +len_error: /* Truncation of overlength packets causes PHY length to not match MAC length */ ++sky2->net_stats.rx_length_errors; if (netif_msg_rx_err(sky2) && net_ratelimit()) - pr_info(PFX "%s: rx length mismatch: length %d status %#x\n", - dev->name, length, status); + pr_info(PFX "%s: rx length error: status %#x length %d\n", + dev->name, status, length); goto resubmit; error: @@ -3934,13 +3947,6 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, sky2->hw = hw; sky2->msg_enable = netif_msg_init(debug, default_msg); - /* This chip has hardware problems that generates - * bogus PHY receive status so by default shut up the message. - */ - if (hw->chip_id == CHIP_ID_YUKON_FE_P && - hw->chip_rev == CHIP_REV_YU_FE2_A0) - sky2->msg_enable &= ~NETIF_MSG_RX_ERR; - /* Auto speed and flow control */ sky2->autoneg = AUTONEG_ENABLE; sky2->flow_mode = FC_BOTH; -- cgit v1.2.3-59-g8ed1b From d6c9bc1ed4301cbc3df4565ff5348b64bf2a767c Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 27 Sep 2007 12:32:44 -0700 Subject: sky2: FE+ vlan workaround The FE+ workaround means the driver can no longer trust the status register to indicate VLAN tagged frames. The fix for this is to just disable VLAN acceleration for that chip version. Tested and works fine. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index a3de0b6127eb..3bfc9d3e3c6e 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3970,8 +3970,12 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, dev->features |= NETIF_F_HIGHDMA; #ifdef SKY2_VLAN_TAG_USED - dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - dev->vlan_rx_register = sky2_vlan_rx_register; + /* The workaround for FE+ status conflicts with VLAN tag detection. */ + if (!(sky2->hw->chip_id == CHIP_ID_YUKON_FE_P && + sky2->hw->chip_rev == CHIP_REV_YU_FE2_A0)) { + dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + dev->vlan_rx_register = sky2_vlan_rx_register; + } #endif /* read the mac address */ -- cgit v1.2.3-59-g8ed1b From 88f5f0cad396be594d6d55cb2d0cd69e8df9ab16 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 27 Sep 2007 12:38:12 -0700 Subject: sky2: fix transmit state on resume This should fix http://bugzilla.kernel.org/show_bug.cgi?id=8667 After resume, driver has reset the chip so the current state of transmit checksum offload state machine and DMA state machine will be undefined. The fix is to set the state so that first Tx will set MSS and offset values. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 3bfc9d3e3c6e..162489b9f599 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -910,6 +910,20 @@ static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2) return le; } +static void tx_init(struct sky2_port *sky2) +{ + struct sky2_tx_le *le; + + sky2->tx_prod = sky2->tx_cons = 0; + sky2->tx_tcpsum = 0; + sky2->tx_last_mss = 0; + + le = get_tx_le(sky2); + le->addr = 0; + le->opcode = OP_ADDR64 | HW_OWNER; + sky2->tx_addr64 = 0; +} + static inline struct tx_ring_info *tx_le_re(struct sky2_port *sky2, struct sky2_tx_le *le) { @@ -1320,7 +1334,8 @@ static int sky2_up(struct net_device *dev) GFP_KERNEL); if (!sky2->tx_ring) goto err_out; - sky2->tx_prod = sky2->tx_cons = 0; + + tx_init(sky2); sky2->rx_le = pci_alloc_consistent(hw->pdev, RX_LE_BYTES, &sky2->rx_le_map); -- cgit v1.2.3-59-g8ed1b From f4ec7f98714c2c0b7afa422c0cba6fb5c875c2c2 Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Thu, 30 Aug 2007 11:23:58 -0700 Subject: e1000: Add device IDs of blade version of the 82571 quad port This blade-specific board form factor is identical to the 82571EB board. Signed-off-by: Auke Kok Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_ethtool.c | 1 + drivers/net/e1000/e1000_hw.c | 1 + drivers/net/e1000/e1000_hw.h | 1 + drivers/net/e1000/e1000_main.c | 2 ++ 4 files changed, 5 insertions(+) diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 4c3785c9d4b8..9ecc3adcf6c1 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -1726,6 +1726,7 @@ static int e1000_wol_exclusion(struct e1000_adapter *adapter, struct ethtool_wol case E1000_DEV_ID_82571EB_QUAD_COPPER: case E1000_DEV_ID_82571EB_QUAD_FIBER: case E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE: + case E1000_DEV_ID_82571PT_QUAD_COPPER: case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3: /* quad port adapters only support WoL on port A */ if (!adapter->quad_port_a) { diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index ba120f7fb0be..8604adbe351c 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -387,6 +387,7 @@ e1000_set_mac_type(struct e1000_hw *hw) case E1000_DEV_ID_82571EB_SERDES_DUAL: case E1000_DEV_ID_82571EB_SERDES_QUAD: case E1000_DEV_ID_82571EB_QUAD_COPPER: + case E1000_DEV_ID_82571PT_QUAD_COPPER: case E1000_DEV_ID_82571EB_QUAD_FIBER: case E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE: hw->mac_type = e1000_82571; diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index fe8714655c90..07f0ea73676e 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -475,6 +475,7 @@ int32_t e1000_check_phy_reset_block(struct e1000_hw *hw); #define E1000_DEV_ID_82571EB_FIBER 0x105F #define E1000_DEV_ID_82571EB_SERDES 0x1060 #define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4 +#define E1000_DEV_ID_82571PT_QUAD_COPPER 0x10D5 #define E1000_DEV_ID_82571EB_QUAD_FIBER 0x10A5 #define E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE 0x10BC #define E1000_DEV_ID_82571EB_SERDES_DUAL 0x10D9 diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 4a225950fb43..e7c8951f47fa 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -108,6 +108,7 @@ static struct pci_device_id e1000_pci_tbl[] = { INTEL_E1000_ETHERNET_DEVICE(0x10BC), INTEL_E1000_ETHERNET_DEVICE(0x10C4), INTEL_E1000_ETHERNET_DEVICE(0x10C5), + INTEL_E1000_ETHERNET_DEVICE(0x10D5), INTEL_E1000_ETHERNET_DEVICE(0x10D9), INTEL_E1000_ETHERNET_DEVICE(0x10DA), /* required last entry */ @@ -1101,6 +1102,7 @@ e1000_probe(struct pci_dev *pdev, case E1000_DEV_ID_82571EB_QUAD_COPPER: case E1000_DEV_ID_82571EB_QUAD_FIBER: case E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE: + case E1000_DEV_ID_82571PT_QUAD_COPPER: /* if quad port adapter, disable WoL on all but port A */ if (global_quad_port_a != 0) adapter->eeprom_wol = 0; -- cgit v1.2.3-59-g8ed1b