diff options
author | Matt Carlson <mcarlson@broadcom.com> | 2008-11-21 20:18:16 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-11-21 20:18:16 -0500 |
commit | 5e7dfd0fb94abed04f59481d1ce0cc06a892048a (patch) | |
tree | 9aa0223d967bfe42076887879596b4e778ac05c3 /drivers/net | |
parent | 52f4490c3b6dcb1e8dec7ff9f1c35f09bd7c136f (diff) |
tg3: Prevent corruption at 10 / 100Mbps w CLKREQ
This patch disables CLKREQ at 10Mbps and 100Mbps to workaround a TX BD
corruption issue. This problem only affects the 5784 and 5761 (and
57780 AX) ASIC revisions.
Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/tg3.c | 77 | ||||
-rw-r--r-- | drivers/net/tg3.h | 4 |
2 files changed, 67 insertions, 14 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 821e3812c085..659fb9978195 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c | |||
@@ -2154,6 +2154,20 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) | |||
2154 | tp->dev->name, state); | 2154 | tp->dev->name, state); |
2155 | return -EINVAL; | 2155 | return -EINVAL; |
2156 | } | 2156 | } |
2157 | |||
2158 | /* Restore the CLKREQ setting. */ | ||
2159 | if (tp->tg3_flags3 & TG3_FLG3_CLKREQ_BUG) { | ||
2160 | u16 lnkctl; | ||
2161 | |||
2162 | pci_read_config_word(tp->pdev, | ||
2163 | tp->pcie_cap + PCI_EXP_LNKCTL, | ||
2164 | &lnkctl); | ||
2165 | lnkctl |= PCI_EXP_LNKCTL_CLKREQ_EN; | ||
2166 | pci_write_config_word(tp->pdev, | ||
2167 | tp->pcie_cap + PCI_EXP_LNKCTL, | ||
2168 | lnkctl); | ||
2169 | } | ||
2170 | |||
2157 | misc_host_ctrl = tr32(TG3PCI_MISC_HOST_CTRL); | 2171 | misc_host_ctrl = tr32(TG3PCI_MISC_HOST_CTRL); |
2158 | tw32(TG3PCI_MISC_HOST_CTRL, | 2172 | tw32(TG3PCI_MISC_HOST_CTRL, |
2159 | misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT); | 2173 | misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT); |
@@ -2923,6 +2937,24 @@ relink: | |||
2923 | NIC_SRAM_FIRMWARE_MBOX_MAGIC2); | 2937 | NIC_SRAM_FIRMWARE_MBOX_MAGIC2); |
2924 | } | 2938 | } |
2925 | 2939 | ||
2940 | /* Prevent send BD corruption. */ | ||
2941 | if (tp->tg3_flags3 & TG3_FLG3_CLKREQ_BUG) { | ||
2942 | u16 oldlnkctl, newlnkctl; | ||
2943 | |||
2944 | pci_read_config_word(tp->pdev, | ||
2945 | tp->pcie_cap + PCI_EXP_LNKCTL, | ||
2946 | &oldlnkctl); | ||
2947 | if (tp->link_config.active_speed == SPEED_100 || | ||
2948 | tp->link_config.active_speed == SPEED_10) | ||
2949 | newlnkctl = oldlnkctl & ~PCI_EXP_LNKCTL_CLKREQ_EN; | ||
2950 | else | ||
2951 | newlnkctl = oldlnkctl | PCI_EXP_LNKCTL_CLKREQ_EN; | ||
2952 | if (newlnkctl != oldlnkctl) | ||
2953 | pci_write_config_word(tp->pdev, | ||
2954 | tp->pcie_cap + PCI_EXP_LNKCTL, | ||
2955 | newlnkctl); | ||
2956 | } | ||
2957 | |||
2926 | if (current_link_up != netif_carrier_ok(tp->dev)) { | 2958 | if (current_link_up != netif_carrier_ok(tp->dev)) { |
2927 | if (current_link_up) | 2959 | if (current_link_up) |
2928 | netif_carrier_on(tp->dev); | 2960 | netif_carrier_on(tp->dev); |
@@ -6016,7 +6048,7 @@ static int tg3_chip_reset(struct tg3 *tp) | |||
6016 | 6048 | ||
6017 | udelay(120); | 6049 | udelay(120); |
6018 | 6050 | ||
6019 | if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) { | 6051 | if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) && tp->pcie_cap) { |
6020 | if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A0) { | 6052 | if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A0) { |
6021 | int i; | 6053 | int i; |
6022 | u32 cfg_val; | 6054 | u32 cfg_val; |
@@ -6029,9 +6061,23 @@ static int tg3_chip_reset(struct tg3 *tp) | |||
6029 | pci_write_config_dword(tp->pdev, 0xc4, | 6061 | pci_write_config_dword(tp->pdev, 0xc4, |
6030 | cfg_val | (1 << 15)); | 6062 | cfg_val | (1 << 15)); |
6031 | } | 6063 | } |
6032 | if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) | 6064 | |
6033 | /* Set PCIE max payload size and clear error status. */ | 6065 | /* Set PCIE max payload size to 128 bytes and |
6034 | pci_write_config_dword(tp->pdev, 0xd8, 0xf5000); | 6066 | * clear the "no snoop" and "relaxed ordering" bits. |
6067 | */ | ||
6068 | pci_write_config_word(tp->pdev, | ||
6069 | tp->pcie_cap + PCI_EXP_DEVCTL, | ||
6070 | 0); | ||
6071 | |||
6072 | pcie_set_readrq(tp->pdev, 4096); | ||
6073 | |||
6074 | /* Clear error status */ | ||
6075 | pci_write_config_word(tp->pdev, | ||
6076 | tp->pcie_cap + PCI_EXP_DEVSTA, | ||
6077 | PCI_EXP_DEVSTA_CED | | ||
6078 | PCI_EXP_DEVSTA_NFED | | ||
6079 | PCI_EXP_DEVSTA_FED | | ||
6080 | PCI_EXP_DEVSTA_URD); | ||
6035 | } | 6081 | } |
6036 | 6082 | ||
6037 | tg3_restore_pci_state(tp); | 6083 | tg3_restore_pci_state(tp); |
@@ -11967,7 +12013,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) | |||
11967 | u32 pci_state_reg, grc_misc_cfg; | 12013 | u32 pci_state_reg, grc_misc_cfg; |
11968 | u32 val; | 12014 | u32 val; |
11969 | u16 pci_cmd; | 12015 | u16 pci_cmd; |
11970 | int err, pcie_cap; | 12016 | int err; |
11971 | 12017 | ||
11972 | /* Force memory write invalidate off. If we leave it on, | 12018 | /* Force memory write invalidate off. If we leave it on, |
11973 | * then on 5700_BX chips we have to enable a workaround. | 12019 | * then on 5700_BX chips we have to enable a workaround. |
@@ -12193,20 +12239,23 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) | |||
12193 | pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE, | 12239 | pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE, |
12194 | &pci_state_reg); | 12240 | &pci_state_reg); |
12195 | 12241 | ||
12196 | pcie_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_EXP); | 12242 | tp->pcie_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_EXP); |
12197 | if (pcie_cap != 0) { | 12243 | if (tp->pcie_cap != 0) { |
12244 | u16 lnkctl; | ||
12245 | |||
12198 | tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS; | 12246 | tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS; |
12199 | 12247 | ||
12200 | pcie_set_readrq(tp->pdev, 4096); | 12248 | pcie_set_readrq(tp->pdev, 4096); |
12201 | 12249 | ||
12202 | if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { | 12250 | pci_read_config_word(tp->pdev, |
12203 | u16 lnkctl; | 12251 | tp->pcie_cap + PCI_EXP_LNKCTL, |
12204 | 12252 | &lnkctl); | |
12205 | pci_read_config_word(tp->pdev, | 12253 | if (lnkctl & PCI_EXP_LNKCTL_CLKREQ_EN) { |
12206 | pcie_cap + PCI_EXP_LNKCTL, | 12254 | if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) |
12207 | &lnkctl); | ||
12208 | if (lnkctl & PCI_EXP_LNKCTL_CLKREQ_EN) | ||
12209 | tp->tg3_flags2 &= ~TG3_FLG2_HW_TSO_2; | 12255 | tp->tg3_flags2 &= ~TG3_FLG2_HW_TSO_2; |
12256 | if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || | ||
12257 | GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) | ||
12258 | tp->tg3_flags3 |= TG3_FLG3_CLKREQ_BUG; | ||
12210 | } | 12259 | } |
12211 | } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) { | 12260 | } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) { |
12212 | tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS; | 12261 | tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS; |
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 599e490cf62c..53684b9b83f9 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h | |||
@@ -2618,6 +2618,7 @@ struct tg3 { | |||
2618 | #define TG3_FLG3_RGMII_STD_IBND_DISABLE 0x00000100 | 2618 | #define TG3_FLG3_RGMII_STD_IBND_DISABLE 0x00000100 |
2619 | #define TG3_FLG3_RGMII_EXT_IBND_RX_EN 0x00000200 | 2619 | #define TG3_FLG3_RGMII_EXT_IBND_RX_EN 0x00000200 |
2620 | #define TG3_FLG3_RGMII_EXT_IBND_TX_EN 0x00000400 | 2620 | #define TG3_FLG3_RGMII_EXT_IBND_TX_EN 0x00000400 |
2621 | #define TG3_FLG3_CLKREQ_BUG 0x00000800 | ||
2621 | 2622 | ||
2622 | struct timer_list timer; | 2623 | struct timer_list timer; |
2623 | u16 timer_counter; | 2624 | u16 timer_counter; |
@@ -2656,7 +2657,10 @@ struct tg3 { | |||
2656 | 2657 | ||
2657 | int pm_cap; | 2658 | int pm_cap; |
2658 | int msi_cap; | 2659 | int msi_cap; |
2660 | union { | ||
2659 | int pcix_cap; | 2661 | int pcix_cap; |
2662 | int pcie_cap; | ||
2663 | }; | ||
2660 | 2664 | ||
2661 | struct mii_bus *mdio_bus; | 2665 | struct mii_bus *mdio_bus; |
2662 | int mdio_irq[PHY_MAX_ADDR]; | 2666 | int mdio_irq[PHY_MAX_ADDR]; |