]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From 23a2d1b233f535fc74f8dca66e488980b4db041b Mon Sep 17 00:00:00 2001 |
2 | From: Dave Graham <david.graham@intel.com> | |
3 | Date: Mon, 8 Jun 2009 14:28:17 +0000 | |
4 | Subject: [PATCH] e1000e: Fixes possible phy corrupton on 82571 designs. | |
5 | References: bnc#495259 | |
6 | ||
7 | Phy corruption has been observed on 2-port 82571 adapters, and is root-caused | |
8 | to lack of synchronization between the 2 driver instances, which conflict | |
9 | when attempting to access the phy via the single MDIC register. | |
10 | A semaphore exists for this purpose, and is now used on these designs. Because | |
11 | PXE &/or EFI boot code (which we cannot expect to be built with this fix) may | |
12 | leave the inter-instance semaphore in an invalid initial state when the driver | |
13 | first loads, this fix also includes a one-time (per driver load) fix-up of the | |
14 | semaphore initial state. | |
15 | ||
16 | Signed-off-by: dave graham <david.graham@intel.com> | |
17 | Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> | |
18 | Signed-off-by: David S. Miller <davem@davemloft.net> | |
19 | Acked-by: Brandon Philips <bphilips@suse.de> | |
20 | --- | |
21 | drivers/net/e1000e/82571.c | 86 +++++++++++++++++++++++++++++++++++++++---- | |
22 | drivers/net/e1000e/defines.h | 2 + | |
23 | drivers/net/e1000e/hw.h | 2 + | |
24 | 3 files changed, 83 insertions(+), 7 deletions(-) | |
25 | ||
26 | Index: linux-2.6.27-SLE11_BRANCH/drivers/net/e1000e/82571.c | |
27 | =================================================================== | |
28 | --- linux-2.6.27-SLE11_BRANCH.orig/drivers/net/e1000e/82571.c | |
29 | +++ linux-2.6.27-SLE11_BRANCH/drivers/net/e1000e/82571.c | |
30 | @@ -68,6 +68,7 @@ static s32 e1000_setup_link_82571(struct | |
31 | static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw); | |
32 | static bool e1000_check_mng_mode_82574(struct e1000_hw *hw); | |
33 | static s32 e1000_led_on_82574(struct e1000_hw *hw); | |
34 | +static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw); | |
35 | ||
36 | /** | |
37 | * e1000_init_phy_params_82571 - Init PHY func ptrs. | |
38 | @@ -206,6 +207,9 @@ static s32 e1000_init_mac_params_82571(s | |
39 | struct e1000_hw *hw = &adapter->hw; | |
40 | struct e1000_mac_info *mac = &hw->mac; | |
41 | struct e1000_mac_operations *func = &mac->ops; | |
42 | + u32 swsm = 0; | |
43 | + u32 swsm2 = 0; | |
44 | + bool force_clear_smbi = false; | |
45 | ||
46 | /* Set media type */ | |
47 | switch (adapter->pdev->device) { | |
48 | @@ -269,6 +273,50 @@ static s32 e1000_init_mac_params_82571(s | |
49 | break; | |
50 | } | |
51 | ||
52 | + /* | |
53 | + * Ensure that the inter-port SWSM.SMBI lock bit is clear before | |
54 | + * first NVM or PHY acess. This should be done for single-port | |
55 | + * devices, and for one port only on dual-port devices so that | |
56 | + * for those devices we can still use the SMBI lock to synchronize | |
57 | + * inter-port accesses to the PHY & NVM. | |
58 | + */ | |
59 | + switch (hw->mac.type) { | |
60 | + case e1000_82571: | |
61 | + case e1000_82572: | |
62 | + swsm2 = er32(SWSM2); | |
63 | + | |
64 | + if (!(swsm2 & E1000_SWSM2_LOCK)) { | |
65 | + /* Only do this for the first interface on this card */ | |
66 | + ew32(SWSM2, | |
67 | + swsm2 | E1000_SWSM2_LOCK); | |
68 | + force_clear_smbi = true; | |
69 | + } else | |
70 | + force_clear_smbi = false; | |
71 | + break; | |
72 | + default: | |
73 | + force_clear_smbi = true; | |
74 | + break; | |
75 | + } | |
76 | + | |
77 | + if (force_clear_smbi) { | |
78 | + /* Make sure SWSM.SMBI is clear */ | |
79 | + swsm = er32(SWSM); | |
80 | + if (swsm & E1000_SWSM_SMBI) { | |
81 | + /* This bit should not be set on a first interface, and | |
82 | + * indicates that the bootagent or EFI code has | |
83 | + * improperly left this bit enabled | |
84 | + */ | |
85 | + hw_dbg(hw, "Please update your 82571 Bootagent\n"); | |
86 | + } | |
87 | + ew32(SWSM, swsm & ~E1000_SWSM_SMBI); | |
88 | + } | |
89 | + | |
90 | + /* | |
91 | + * Initialze device specific counter of SMBI acquisition | |
92 | + * timeouts. | |
93 | + */ | |
94 | + hw->dev_spec.e82571.smb_counter = 0; | |
95 | + | |
96 | return 0; | |
97 | } | |
98 | ||
99 | @@ -402,11 +450,37 @@ static s32 e1000_get_phy_id_82571(struct | |
100 | static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw) | |
101 | { | |
102 | u32 swsm; | |
103 | - s32 timeout = hw->nvm.word_size + 1; | |
104 | + s32 sw_timeout = hw->nvm.word_size + 1; | |
105 | + s32 fw_timeout = hw->nvm.word_size + 1; | |
106 | s32 i = 0; | |
107 | ||
108 | + /* | |
109 | + * If we have timedout 3 times on trying to acquire | |
110 | + * the inter-port SMBI semaphore, there is old code | |
111 | + * operating on the other port, and it is not | |
112 | + * releasing SMBI. Modify the number of times that | |
113 | + * we try for the semaphore to interwork with this | |
114 | + * older code. | |
115 | + */ | |
116 | + if (hw->dev_spec.e82571.smb_counter > 2) | |
117 | + sw_timeout = 1; | |
118 | + | |
119 | + /* Get the SW semaphore */ | |
120 | + while (i < sw_timeout) { | |
121 | + swsm = er32(SWSM); | |
122 | + if (!(swsm & E1000_SWSM_SMBI)) | |
123 | + break; | |
124 | + | |
125 | + udelay(50); | |
126 | + i++; | |
127 | + } | |
128 | + | |
129 | + if (i == sw_timeout) { | |
130 | + hw_dbg(hw, "Driver can't access device - SMBI bit is set.\n"); | |
131 | + hw->dev_spec.e82571.smb_counter++; | |
132 | + } | |
133 | /* Get the FW semaphore. */ | |
134 | - for (i = 0; i < timeout; i++) { | |
135 | + for (i = 0; i < fw_timeout; i++) { | |
136 | swsm = er32(SWSM); | |
137 | ew32(SWSM, swsm | E1000_SWSM_SWESMBI); | |
138 | ||
139 | @@ -417,9 +491,9 @@ static s32 e1000_get_hw_semaphore_82571( | |
140 | udelay(50); | |
141 | } | |
142 | ||
143 | - if (i == timeout) { | |
144 | + if (i == fw_timeout) { | |
145 | /* Release semaphores */ | |
146 | - e1000e_put_hw_semaphore(hw); | |
147 | + e1000_put_hw_semaphore_82571(hw); | |
148 | hw_dbg(hw, "Driver can't access the NVM\n"); | |
149 | return -E1000_ERR_NVM; | |
150 | } | |
151 | @@ -438,9 +512,7 @@ static void e1000_put_hw_semaphore_82571 | |
152 | u32 swsm; | |
153 | ||
154 | swsm = er32(SWSM); | |
155 | - | |
156 | - swsm &= ~E1000_SWSM_SWESMBI; | |
157 | - | |
158 | + swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); | |
159 | ew32(SWSM, swsm); | |
160 | } | |
161 | ||
162 | Index: linux-2.6.27-SLE11_BRANCH/drivers/net/e1000e/defines.h | |
163 | =================================================================== | |
164 | --- linux-2.6.27-SLE11_BRANCH.orig/drivers/net/e1000e/defines.h | |
165 | +++ linux-2.6.27-SLE11_BRANCH/drivers/net/e1000e/defines.h | |
166 | @@ -359,6 +359,8 @@ | |
167 | #define E1000_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ | |
168 | #define E1000_SWSM_DRV_LOAD 0x00000008 /* Driver Loaded Bit */ | |
169 | ||
170 | +#define E1000_SWSM2_LOCK 0x00000002 /* Secondary driver semaphore bit */ | |
171 | + | |
172 | /* Interrupt Cause Read */ | |
173 | #define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */ | |
174 | #define E1000_ICR_LSC 0x00000004 /* Link Status Change */ | |
175 | Index: linux-2.6.27-SLE11_BRANCH/drivers/net/e1000e/hw.h | |
176 | =================================================================== | |
177 | --- linux-2.6.27-SLE11_BRANCH.orig/drivers/net/e1000e/hw.h | |
178 | +++ linux-2.6.27-SLE11_BRANCH/drivers/net/e1000e/hw.h | |
179 | @@ -209,6 +209,7 @@ enum e1e_registers { | |
180 | E1000_FACTPS = 0x05B30, /* Function Active and Power State to MNG */ | |
181 | E1000_SWSM = 0x05B50, /* SW Semaphore */ | |
182 | E1000_FWSM = 0x05B54, /* FW Semaphore */ | |
183 | + E1000_SWSM2 = 0x05B58, /* Driver-only SW semaphore */ | |
184 | E1000_HICR = 0x08F00, /* Host Interface Control */ | |
185 | }; | |
186 | ||
187 | @@ -856,6 +857,7 @@ struct e1000_fc_info { | |
188 | struct e1000_dev_spec_82571 { | |
189 | bool laa_is_present; | |
190 | bool alt_mac_addr_is_present; | |
191 | + u32 smb_counter; | |
192 | }; | |
193 | ||
194 | struct e1000_shadow_ram { |