]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From: John Ronciak <john.ronciak@intel.com> |
2 | Subject: ixgbe driver update to add Longcove (SFP+) NIC support for FCoE needs | |
3 | Acked-by: Karsten Keil <kkeil@novell.com> | |
4 | Reference: bnc#442411 | |
5 | ||
6 | ||
7 | The patch that will be attached is to update the ixgbe driver to add SFP+ NIC | |
8 | support to SLES11 beta4 version of the ixgbe driver. NIC have been sent to | |
9 | Nurnberg for testing purposes. We have already been testing the patch with | |
10 | both our test lab and in our FCoE testing. | |
11 | ||
12 | ||
13 | --- | |
14 | drivers/net/ixgbe/ixgbe.h | 5 | |
15 | drivers/net/ixgbe/ixgbe_82598.c | 161 ++++++++++++++++++++++++ | |
16 | drivers/net/ixgbe/ixgbe_main.c | 92 +++++++++++++- | |
17 | drivers/net/ixgbe/ixgbe_phy.c | 258 ++++++++++++++++++++++++++++++++++++++++ | |
18 | drivers/net/ixgbe/ixgbe_phy.h | 18 ++ | |
19 | drivers/net/ixgbe/ixgbe_type.h | 19 ++ | |
20 | 6 files changed, 546 insertions(+), 7 deletions(-) | |
21 | ||
22 | --- a/drivers/net/ixgbe/ixgbe_82598.c | |
23 | +++ b/drivers/net/ixgbe/ixgbe_82598.c | |
24 | @@ -46,6 +46,8 @@ static s32 ixgbe_setup_copper_link_speed | |
25 | ixgbe_link_speed speed, | |
26 | bool autoneg, | |
27 | bool autoneg_wait_to_complete); | |
28 | +static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, | |
29 | + u8 *eeprom_data); | |
30 | ||
31 | /** | |
32 | */ | |
33 | @@ -53,12 +55,35 @@ static s32 ixgbe_get_invariants_82598(st | |
34 | { | |
35 | struct ixgbe_mac_info *mac = &hw->mac; | |
36 | struct ixgbe_phy_info *phy = &hw->phy; | |
37 | + s32 ret_val = 0; | |
38 | + u16 list_offset, data_offset; | |
39 | ||
40 | /* Call PHY identify routine to get the phy type */ | |
41 | ixgbe_identify_phy_generic(hw); | |
42 | ||
43 | /* PHY Init */ | |
44 | switch (phy->type) { | |
45 | + case ixgbe_phy_nl: | |
46 | + phy->ops.reset = &ixgbe_reset_phy_nl; | |
47 | + | |
48 | + /* Call SFP+ identify routine to get the SFP+ module type */ | |
49 | + ret_val = phy->ops.identify_sfp(hw); | |
50 | + if (ret_val != 0) | |
51 | + goto out; | |
52 | + else if (hw->phy.sfp_type == ixgbe_sfp_type_unknown) { | |
53 | + ret_val = IXGBE_ERR_SFP_NOT_SUPPORTED; | |
54 | + goto out; | |
55 | + } | |
56 | + | |
57 | + /* Check to see if SFP+ module is supported */ | |
58 | + ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, | |
59 | + &list_offset, | |
60 | + &data_offset); | |
61 | + if (ret_val != 0) { | |
62 | + ret_val = IXGBE_ERR_SFP_NOT_SUPPORTED; | |
63 | + goto out; | |
64 | + } | |
65 | + break; | |
66 | case ixgbe_phy_tn: | |
67 | phy->ops.check_link = &ixgbe_check_phy_link_tnx; | |
68 | phy->ops.get_firmware_version = | |
69 | @@ -82,7 +107,8 @@ static s32 ixgbe_get_invariants_82598(st | |
70 | mac->max_rx_queues = IXGBE_82598_MAX_RX_QUEUES; | |
71 | mac->max_tx_queues = IXGBE_82598_MAX_TX_QUEUES; | |
72 | ||
73 | - return 0; | |
74 | +out: | |
75 | + return ret_val; | |
76 | } | |
77 | ||
78 | /** | |
79 | @@ -191,7 +217,10 @@ static enum ixgbe_media_type ixgbe_get_m | |
80 | case IXGBE_DEV_ID_82598AF_SINGLE_PORT: | |
81 | case IXGBE_DEV_ID_82598EB_CX4: | |
82 | case IXGBE_DEV_ID_82598_CX4_DUAL_PORT: | |
83 | + case IXGBE_DEV_ID_82598_DA_DUAL_PORT: | |
84 | + case IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM: | |
85 | case IXGBE_DEV_ID_82598EB_XF_LR: | |
86 | + case IXGBE_DEV_ID_82598EB_SFP_LOM: | |
87 | media_type = ixgbe_media_type_fiber; | |
88 | break; | |
89 | case IXGBE_DEV_ID_82598AT: | |
90 | @@ -399,6 +428,47 @@ static s32 ixgbe_check_mac_link_82598(st | |
91 | { | |
92 | u32 links_reg; | |
93 | u32 i; | |
94 | + u16 link_reg, adapt_comp_reg; | |
95 | + | |
96 | + /* | |
97 | + * SERDES PHY requires us to read link status from register 0xC79F. | |
98 | + * Bit 0 set indicates link is up/ready; clear indicates link down. | |
99 | + * OxC00C is read to check that the XAUI lanes are active. Bit 0 | |
100 | + * clear indicates active; set indicates inactive. | |
101 | + */ | |
102 | + if (hw->phy.type == ixgbe_phy_nl) { | |
103 | + hw->phy.ops.read_reg(hw, 0xC79F, IXGBE_TWINAX_DEV, &link_reg); | |
104 | + hw->phy.ops.read_reg(hw, 0xC79F, IXGBE_TWINAX_DEV, &link_reg); | |
105 | + hw->phy.ops.read_reg(hw, 0xC00C, IXGBE_TWINAX_DEV, | |
106 | + &adapt_comp_reg); | |
107 | + if (link_up_wait_to_complete) { | |
108 | + for (i = 0; i < IXGBE_LINK_UP_TIME; i++) { | |
109 | + if ((link_reg & 1) && | |
110 | + ((adapt_comp_reg & 1) == 0)) { | |
111 | + *link_up = true; | |
112 | + break; | |
113 | + } else { | |
114 | + *link_up = false; | |
115 | + } | |
116 | + msleep(100); | |
117 | + hw->phy.ops.read_reg(hw, 0xC79F, | |
118 | + IXGBE_TWINAX_DEV, | |
119 | + &link_reg); | |
120 | + hw->phy.ops.read_reg(hw, 0xC00C, | |
121 | + IXGBE_TWINAX_DEV, | |
122 | + &adapt_comp_reg); | |
123 | + } | |
124 | + } else { | |
125 | + if ((link_reg & 1) && | |
126 | + ((adapt_comp_reg & 1) == 0)) | |
127 | + *link_up = true; | |
128 | + else | |
129 | + *link_up = false; | |
130 | + } | |
131 | + | |
132 | + if (*link_up == false) | |
133 | + goto out; | |
134 | + } | |
135 | ||
136 | links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS); | |
137 | if (link_up_wait_to_complete) { | |
138 | @@ -424,6 +494,7 @@ static s32 ixgbe_check_mac_link_82598(st | |
139 | else | |
140 | *speed = IXGBE_LINK_SPEED_1GB_FULL; | |
141 | ||
142 | +out: | |
143 | return 0; | |
144 | } | |
145 | ||
146 | @@ -859,6 +930,69 @@ s32 ixgbe_write_analog_reg8_82598(struct | |
147 | } | |
148 | ||
149 | /** | |
150 | + * ixgbe_read_i2c_eeprom_82598 - Reads 8 bit EEPROM word of an SFP+ module | |
151 | + * over I2C interface through an intermediate phy. | |
152 | + * @hw: pointer to hardware structure | |
153 | + * @byte_offset: EEPROM byte offset to read | |
154 | + * @eeprom_data: value read | |
155 | + * | |
156 | + * Performs byte read operation to SFP module's EEPROM over I2C interface. | |
157 | + **/ | |
158 | +s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, | |
159 | + u8 *eeprom_data) | |
160 | +{ | |
161 | + s32 status = 0; | |
162 | + u16 sfp_addr = 0; | |
163 | + u16 sfp_data = 0; | |
164 | + u16 sfp_stat = 0; | |
165 | + u32 i; | |
166 | + | |
167 | + if (hw->phy.type == ixgbe_phy_nl) { | |
168 | + /* | |
169 | + * phy SDA/SCL registers are at addresses 0xC30A to | |
170 | + * 0xC30D. These registers are used to talk to the SFP+ | |
171 | + * module's EEPROM through the SDA/SCL (I2C) interface. | |
172 | + */ | |
173 | + sfp_addr = (IXGBE_I2C_EEPROM_DEV_ADDR << 8) + byte_offset; | |
174 | + sfp_addr = (sfp_addr | IXGBE_I2C_EEPROM_READ_MASK); | |
175 | + hw->phy.ops.write_reg(hw, | |
176 | + IXGBE_MDIO_PMA_PMD_SDA_SCL_ADDR, | |
177 | + IXGBE_MDIO_PMA_PMD_DEV_TYPE, | |
178 | + sfp_addr); | |
179 | + | |
180 | + /* Poll status */ | |
181 | + for (i = 0; i < 100; i++) { | |
182 | + hw->phy.ops.read_reg(hw, | |
183 | + IXGBE_MDIO_PMA_PMD_SDA_SCL_STAT, | |
184 | + IXGBE_MDIO_PMA_PMD_DEV_TYPE, | |
185 | + &sfp_stat); | |
186 | + sfp_stat = sfp_stat & IXGBE_I2C_EEPROM_STATUS_MASK; | |
187 | + if (sfp_stat != IXGBE_I2C_EEPROM_STATUS_IN_PROGRESS) | |
188 | + break; | |
189 | + msleep(10); | |
190 | + } | |
191 | + | |
192 | + if (sfp_stat != IXGBE_I2C_EEPROM_STATUS_PASS) { | |
193 | + hw_dbg(hw, "EEPROM read did not pass.\n"); | |
194 | + status = IXGBE_ERR_SFP_NOT_PRESENT; | |
195 | + goto out; | |
196 | + } | |
197 | + | |
198 | + /* Read data */ | |
199 | + hw->phy.ops.read_reg(hw, IXGBE_MDIO_PMA_PMD_SDA_SCL_DATA, | |
200 | + IXGBE_MDIO_PMA_PMD_DEV_TYPE, &sfp_data); | |
201 | + | |
202 | + *eeprom_data = (u8)(sfp_data >> 8); | |
203 | + } else { | |
204 | + status = IXGBE_ERR_PHY; | |
205 | + goto out; | |
206 | + } | |
207 | + | |
208 | +out: | |
209 | + return status; | |
210 | +} | |
211 | + | |
212 | +/** | |
213 | * ixgbe_get_supported_physical_layer_82598 - Returns physical layer type | |
214 | * @hw: pointer to hardware structure | |
215 | * | |
216 | @@ -873,13 +1007,35 @@ s32 ixgbe_get_supported_physical_layer_8 | |
217 | case IXGBE_DEV_ID_82598_CX4_DUAL_PORT: | |
218 | physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_CX4; | |
219 | break; | |
220 | + case IXGBE_DEV_ID_82598_DA_DUAL_PORT: | |
221 | + physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU; | |
222 | + break; | |
223 | case IXGBE_DEV_ID_82598AF_DUAL_PORT: | |
224 | case IXGBE_DEV_ID_82598AF_SINGLE_PORT: | |
225 | + case IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM: | |
226 | physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR; | |
227 | break; | |
228 | case IXGBE_DEV_ID_82598EB_XF_LR: | |
229 | physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR; | |
230 | break; | |
231 | + case IXGBE_DEV_ID_82598EB_SFP_LOM: | |
232 | + hw->phy.ops.identify_sfp(hw); | |
233 | + | |
234 | + switch (hw->phy.sfp_type) { | |
235 | + case ixgbe_sfp_type_da_cu: | |
236 | + physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU; | |
237 | + break; | |
238 | + case ixgbe_sfp_type_sr: | |
239 | + physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR; | |
240 | + break; | |
241 | + case ixgbe_sfp_type_lr: | |
242 | + physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR; | |
243 | + break; | |
244 | + default: | |
245 | + physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; | |
246 | + break; | |
247 | + } | |
248 | + break; | |
249 | case IXGBE_DEV_ID_82598AT: | |
250 | physical_layer = (IXGBE_PHYSICAL_LAYER_10GBASE_T | | |
251 | IXGBE_PHYSICAL_LAYER_1000BASE_T); | |
252 | @@ -935,12 +1091,13 @@ static struct ixgbe_eeprom_operations ee | |
253 | ||
254 | static struct ixgbe_phy_operations phy_ops_82598 = { | |
255 | .identify = &ixgbe_identify_phy_generic, | |
256 | - /* .identify_sfp = &ixgbe_identify_sfp_module_generic, */ | |
257 | + .identify_sfp = &ixgbe_identify_sfp_module_generic, | |
258 | .reset = &ixgbe_reset_phy_generic, | |
259 | .read_reg = &ixgbe_read_phy_reg_generic, | |
260 | .write_reg = &ixgbe_write_phy_reg_generic, | |
261 | .setup_link = &ixgbe_setup_phy_link_generic, | |
262 | .setup_link_speed = &ixgbe_setup_phy_link_speed_generic, | |
263 | + .read_i2c_eeprom = &ixgbe_read_i2c_eeprom_82598, | |
264 | }; | |
265 | ||
266 | struct ixgbe_info ixgbe_82598_info = { | |
267 | --- a/drivers/net/ixgbe/ixgbe.h | |
268 | +++ b/drivers/net/ixgbe/ixgbe.h | |
269 | @@ -318,12 +318,15 @@ struct ixgbe_adapter { | |
270 | unsigned long link_check_timeout; | |
271 | ||
272 | struct work_struct watchdog_task; | |
273 | + struct work_struct sfp_task; | |
274 | + struct timer_list sfp_timer; | |
275 | }; | |
276 | ||
277 | enum ixbge_state_t { | |
278 | __IXGBE_TESTING, | |
279 | __IXGBE_RESETTING, | |
280 | - __IXGBE_DOWN | |
281 | + __IXGBE_DOWN, | |
282 | + __IXGBE_SFP_MODULE_NOT_FOUND | |
283 | }; | |
284 | ||
285 | enum ixgbe_boards { | |
286 | --- a/drivers/net/ixgbe/ixgbe_main.c | |
287 | +++ b/drivers/net/ixgbe/ixgbe_main.c | |
288 | @@ -74,8 +74,14 @@ static struct pci_device_id ixgbe_pci_tb | |
289 | board_82598 }, | |
290 | {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_CX4_DUAL_PORT), | |
291 | board_82598 }, | |
292 | + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_DA_DUAL_PORT), | |
293 | + board_82598 }, | |
294 | + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM), | |
295 | + board_82598 }, | |
296 | {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_XF_LR), | |
297 | board_82598 }, | |
298 | + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_SFP_LOM), | |
299 | + board_82598 }, | |
300 | ||
301 | /* required last entry */ | |
302 | {0, } | |
303 | @@ -2678,6 +2684,56 @@ err_alloc_queues: | |
304 | } | |
305 | ||
306 | /** | |
307 | + * ixgbe_sfp_timer - worker thread to find a missing module | |
308 | + * @data: pointer to our adapter struct | |
309 | + **/ | |
310 | +static void ixgbe_sfp_timer(unsigned long data) | |
311 | +{ | |
312 | + struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data; | |
313 | + | |
314 | + /* Do the sfp_timer outside of interrupt context due to the | |
315 | + * delays that sfp+ detection requires */ | |
316 | + schedule_work(&adapter->sfp_task); | |
317 | +} | |
318 | + | |
319 | +/** | |
320 | + * ixgbe_sfp_task - worker thread to find a missing module | |
321 | + * @work: pointer to work_struct containing our data | |
322 | + **/ | |
323 | +static void ixgbe_sfp_task(struct work_struct *work) | |
324 | +{ | |
325 | + struct ixgbe_adapter *adapter = container_of(work, | |
326 | + struct ixgbe_adapter, | |
327 | + sfp_task); | |
328 | + struct ixgbe_hw *hw = &adapter->hw; | |
329 | + | |
330 | + if ((hw->phy.type == ixgbe_phy_nl) && | |
331 | + (hw->phy.sfp_type == ixgbe_sfp_type_not_present)) { | |
332 | + s32 ret = hw->phy.ops.identify_sfp(hw); | |
333 | + if (ret) | |
334 | + goto reschedule; | |
335 | + ret = hw->phy.ops.reset(hw); | |
336 | + if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) { | |
337 | + DPRINTK(PROBE, ERR, "failed to initialize because an " | |
338 | + "unsupported SFP+ module type was detected.\n" | |
339 | + "Reload the driver after installing a " | |
340 | + "supported module.\n"); | |
341 | + unregister_netdev(adapter->netdev); | |
342 | + } else { | |
343 | + DPRINTK(PROBE, INFO, "detected SFP+: %d\n", | |
344 | + hw->phy.sfp_type); | |
345 | + } | |
346 | + /* don't need this routine any more */ | |
347 | + clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); | |
348 | + } | |
349 | + return; | |
350 | +reschedule: | |
351 | + if (test_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state)) | |
352 | + mod_timer(&adapter->sfp_timer, | |
353 | + round_jiffies(jiffies + (2 * HZ))); | |
354 | +} | |
355 | + | |
356 | +/** | |
357 | * ixgbe_sw_init - Initialize general software structures (struct ixgbe_adapter) | |
358 | * @adapter: board private structure to initialize | |
359 | * | |
360 | @@ -4002,11 +4058,30 @@ static int __devinit ixgbe_probe(struct | |
361 | ||
362 | /* PHY */ | |
363 | memcpy(&hw->phy.ops, ii->phy_ops, sizeof(hw->phy.ops)); | |
364 | - /* phy->sfp_type = ixgbe_sfp_type_unknown; */ | |
365 | + hw->phy.sfp_type = ixgbe_sfp_type_unknown; | |
366 | + | |
367 | + /* set up this timer and work struct before calling get_invariants | |
368 | + * which might start the timer */ | |
369 | + init_timer(&adapter->sfp_timer); | |
370 | + adapter->sfp_timer.function = &ixgbe_sfp_timer; | |
371 | + adapter->sfp_timer.data = (unsigned long) adapter; | |
372 | + | |
373 | + INIT_WORK(&adapter->sfp_task, ixgbe_sfp_task); | |
374 | ||
375 | err = ii->get_invariants(hw); | |
376 | - if (err) | |
377 | + if (err == IXGBE_ERR_SFP_NOT_PRESENT) { | |
378 | + /* start a kernel thread to watch for a module to arrive */ | |
379 | + set_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); | |
380 | + mod_timer(&adapter->sfp_timer, | |
381 | + round_jiffies(jiffies + (2 * HZ))); | |
382 | + err = 0; | |
383 | + } else if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { | |
384 | + DPRINTK(PROBE, ERR, "failed to load because an " | |
385 | + "unsupported SFP+ module type was detected.\n"); | |
386 | + goto err_hw_init; | |
387 | + } else if (err) { | |
388 | goto err_hw_init; | |
389 | + } | |
390 | ||
391 | /* setup the private structure */ | |
392 | err = ixgbe_sw_init(adapter); | |
393 | @@ -4144,6 +4219,9 @@ err_hw_init: | |
394 | err_sw_init: | |
395 | ixgbe_reset_interrupt_capability(adapter); | |
396 | err_eeprom: | |
397 | + clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); | |
398 | + del_timer_sync(&adapter->sfp_timer); | |
399 | + cancel_work_sync(&adapter->sfp_task); | |
400 | iounmap(hw->hw_addr); | |
401 | err_ioremap: | |
402 | free_netdev(netdev); | |
403 | @@ -4170,8 +4248,13 @@ static void __devexit ixgbe_remove(struc | |
404 | struct ixgbe_adapter *adapter = netdev_priv(netdev); | |
405 | ||
406 | set_bit(__IXGBE_DOWN, &adapter->state); | |
407 | + /* clear the module not found bit to make sure the worker won't | |
408 | + * reschedule */ | |
409 | + clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); | |
410 | del_timer_sync(&adapter->watchdog_timer); | |
411 | - | |
412 | + del_timer_sync(&adapter->sfp_timer); | |
413 | + cancel_work_sync(&adapter->watchdog_task); | |
414 | + cancel_work_sync(&adapter->sfp_task); | |
415 | flush_scheduled_work(); | |
416 | ||
417 | #if defined(CONFIG_DCA) || defined(CONFIG_DCA_MODULE) | |
418 | @@ -4182,7 +4265,8 @@ static void __devexit ixgbe_remove(struc | |
419 | } | |
420 | ||
421 | #endif | |
422 | - unregister_netdev(netdev); | |
423 | + if (netdev->reg_state == NETREG_REGISTERED) | |
424 | + unregister_netdev(netdev); | |
425 | ||
426 | ixgbe_reset_interrupt_capability(adapter); | |
427 | ||
428 | --- a/drivers/net/ixgbe/ixgbe_phy.c | |
429 | +++ b/drivers/net/ixgbe/ixgbe_phy.c | |
430 | @@ -127,6 +127,9 @@ static enum ixgbe_phy_type ixgbe_get_phy | |
431 | case QT2022_PHY_ID: | |
432 | phy_type = ixgbe_phy_qt; | |
433 | break; | |
434 | + case ATH_PHY_ID: | |
435 | + phy_type = ixgbe_phy_nl; | |
436 | + break; | |
437 | default: | |
438 | phy_type = ixgbe_phy_unknown; | |
439 | break; | |
440 | @@ -430,6 +433,261 @@ s32 ixgbe_setup_phy_link_speed_generic(s | |
441 | } | |
442 | ||
443 | /** | |
444 | + * ixgbe_reset_phy_nl - Performs a PHY reset | |
445 | + * @hw: pointer to hardware structure | |
446 | + **/ | |
447 | +s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw) | |
448 | +{ | |
449 | + u16 phy_offset, control, eword, edata, block_crc; | |
450 | + bool end_data = false; | |
451 | + u16 list_offset, data_offset; | |
452 | + u16 phy_data = 0; | |
453 | + s32 ret_val = 0; | |
454 | + u32 i; | |
455 | + | |
456 | + hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, | |
457 | + IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data); | |
458 | + | |
459 | + /* reset the PHY and poll for completion */ | |
460 | + hw->phy.ops.write_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, | |
461 | + IXGBE_MDIO_PHY_XS_DEV_TYPE, | |
462 | + (phy_data | IXGBE_MDIO_PHY_XS_RESET)); | |
463 | + | |
464 | + for (i = 0; i < 100; i++) { | |
465 | + hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, | |
466 | + IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data); | |
467 | + if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) == 0) | |
468 | + break; | |
469 | + msleep(10); | |
470 | + } | |
471 | + | |
472 | + if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) != 0) { | |
473 | + hw_dbg(hw, "PHY reset did not complete.\n"); | |
474 | + ret_val = IXGBE_ERR_PHY; | |
475 | + goto out; | |
476 | + } | |
477 | + | |
478 | + /* Get init offsets */ | |
479 | + ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, &list_offset, | |
480 | + &data_offset); | |
481 | + if (ret_val != 0) | |
482 | + goto out; | |
483 | + | |
484 | + ret_val = hw->eeprom.ops.read(hw, data_offset, &block_crc); | |
485 | + data_offset++; | |
486 | + while (!end_data) { | |
487 | + /* | |
488 | + * Read control word from PHY init contents offset | |
489 | + */ | |
490 | + ret_val = hw->eeprom.ops.read(hw, data_offset, &eword); | |
491 | + control = (eword & IXGBE_CONTROL_MASK_NL) >> | |
492 | + IXGBE_CONTROL_SHIFT_NL; | |
493 | + edata = eword & IXGBE_DATA_MASK_NL; | |
494 | + switch (control) { | |
495 | + case IXGBE_DELAY_NL: | |
496 | + data_offset++; | |
497 | + hw_dbg(hw, "DELAY: %d MS\n", edata); | |
498 | + msleep(edata); | |
499 | + break; | |
500 | + case IXGBE_DATA_NL: | |
501 | + hw_dbg(hw, "DATA: \n"); | |
502 | + data_offset++; | |
503 | + hw->eeprom.ops.read(hw, data_offset++, | |
504 | + &phy_offset); | |
505 | + for (i = 0; i < edata; i++) { | |
506 | + hw->eeprom.ops.read(hw, data_offset, &eword); | |
507 | + hw->phy.ops.write_reg(hw, phy_offset, | |
508 | + IXGBE_TWINAX_DEV, eword); | |
509 | + hw_dbg(hw, "Wrote %4.4x to %4.4x\n", eword, | |
510 | + phy_offset); | |
511 | + data_offset++; | |
512 | + phy_offset++; | |
513 | + } | |
514 | + break; | |
515 | + case IXGBE_CONTROL_NL: | |
516 | + data_offset++; | |
517 | + hw_dbg(hw, "CONTROL: \n"); | |
518 | + if (edata == IXGBE_CONTROL_EOL_NL) { | |
519 | + hw_dbg(hw, "EOL\n"); | |
520 | + end_data = true; | |
521 | + } else if (edata == IXGBE_CONTROL_SOL_NL) { | |
522 | + hw_dbg(hw, "SOL\n"); | |
523 | + } else { | |
524 | + hw_dbg(hw, "Bad control value\n"); | |
525 | + ret_val = IXGBE_ERR_PHY; | |
526 | + goto out; | |
527 | + } | |
528 | + break; | |
529 | + default: | |
530 | + hw_dbg(hw, "Bad control type\n"); | |
531 | + ret_val = IXGBE_ERR_PHY; | |
532 | + goto out; | |
533 | + } | |
534 | + } | |
535 | + | |
536 | +out: | |
537 | + return ret_val; | |
538 | +} | |
539 | + | |
540 | +/** | |
541 | + * ixgbe_identify_sfp_module_generic - Identifies SFP module and assigns | |
542 | + * the PHY type. | |
543 | + * @hw: pointer to hardware structure | |
544 | + * | |
545 | + * Searches for and identifies the SFP module. Assigns appropriate PHY type. | |
546 | + **/ | |
547 | +s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) | |
548 | +{ | |
549 | + s32 status = IXGBE_ERR_PHY_ADDR_INVALID; | |
550 | + u32 vendor_oui = 0; | |
551 | + u8 identifier = 0; | |
552 | + u8 comp_codes_1g = 0; | |
553 | + u8 comp_codes_10g = 0; | |
554 | + u8 oui_bytes[4] = {0, 0, 0, 0}; | |
555 | + u8 transmission_media = 0; | |
556 | + | |
557 | + status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_IDENTIFIER, | |
558 | + &identifier); | |
559 | + | |
560 | + if (status == IXGBE_ERR_SFP_NOT_PRESENT) { | |
561 | + hw->phy.sfp_type = ixgbe_sfp_type_not_present; | |
562 | + goto out; | |
563 | + } | |
564 | + | |
565 | + if (identifier == IXGBE_SFF_IDENTIFIER_SFP) { | |
566 | + hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_1GBE_COMP_CODES, | |
567 | + &comp_codes_1g); | |
568 | + hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_10GBE_COMP_CODES, | |
569 | + &comp_codes_10g); | |
570 | + hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_TRANSMISSION_MEDIA, | |
571 | + &transmission_media); | |
572 | + | |
573 | + /* ID Module | |
574 | + * ============ | |
575 | + * 0 SFP_DA_CU | |
576 | + * 1 SFP_SR | |
577 | + * 2 SFP_LR | |
578 | + */ | |
579 | + if (transmission_media & IXGBE_SFF_TWIN_AX_CAPABLE) | |
580 | + hw->phy.sfp_type = ixgbe_sfp_type_da_cu; | |
581 | + else if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE) | |
582 | + hw->phy.sfp_type = ixgbe_sfp_type_sr; | |
583 | + else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE) | |
584 | + hw->phy.sfp_type = ixgbe_sfp_type_lr; | |
585 | + else | |
586 | + hw->phy.sfp_type = ixgbe_sfp_type_unknown; | |
587 | + | |
588 | + /* Determine PHY vendor */ | |
589 | + if (hw->phy.type == ixgbe_phy_unknown) { | |
590 | + hw->phy.id = identifier; | |
591 | + hw->phy.ops.read_i2c_eeprom(hw, | |
592 | + IXGBE_SFF_VENDOR_OUI_BYTE0, | |
593 | + &oui_bytes[0]); | |
594 | + hw->phy.ops.read_i2c_eeprom(hw, | |
595 | + IXGBE_SFF_VENDOR_OUI_BYTE1, | |
596 | + &oui_bytes[1]); | |
597 | + hw->phy.ops.read_i2c_eeprom(hw, | |
598 | + IXGBE_SFF_VENDOR_OUI_BYTE2, | |
599 | + &oui_bytes[2]); | |
600 | + | |
601 | + vendor_oui = | |
602 | + ((oui_bytes[0] << IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT) | | |
603 | + (oui_bytes[1] << IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT) | | |
604 | + (oui_bytes[2] << IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT)); | |
605 | + | |
606 | + switch (vendor_oui) { | |
607 | + case IXGBE_SFF_VENDOR_OUI_TYCO: | |
608 | + if (transmission_media & | |
609 | + IXGBE_SFF_TWIN_AX_CAPABLE) | |
610 | + hw->phy.type = ixgbe_phy_tw_tyco; | |
611 | + break; | |
612 | + case IXGBE_SFF_VENDOR_OUI_FTL: | |
613 | + hw->phy.type = ixgbe_phy_sfp_ftl; | |
614 | + break; | |
615 | + case IXGBE_SFF_VENDOR_OUI_AVAGO: | |
616 | + hw->phy.type = ixgbe_phy_sfp_avago; | |
617 | + break; | |
618 | + default: | |
619 | + if (transmission_media & | |
620 | + IXGBE_SFF_TWIN_AX_CAPABLE) | |
621 | + hw->phy.type = ixgbe_phy_tw_unknown; | |
622 | + else | |
623 | + hw->phy.type = ixgbe_phy_sfp_unknown; | |
624 | + break; | |
625 | + } | |
626 | + } | |
627 | + status = 0; | |
628 | + } | |
629 | + | |
630 | +out: | |
631 | + return status; | |
632 | +} | |
633 | + | |
634 | +/** | |
635 | + * ixgbe_get_sfp_init_sequence_offsets - Checks the MAC's EEPROM to see | |
636 | + * if it supports a given SFP+ module type, if so it returns the offsets to the | |
637 | + * phy init sequence block. | |
638 | + * @hw: pointer to hardware structure | |
639 | + * @list_offset: offset to the SFP ID list | |
640 | + * @data_offset: offset to the SFP data block | |
641 | + **/ | |
642 | +s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw, | |
643 | + u16 *list_offset, | |
644 | + u16 *data_offset) | |
645 | +{ | |
646 | + u16 sfp_id; | |
647 | + | |
648 | + if (hw->phy.sfp_type == ixgbe_sfp_type_unknown) | |
649 | + return IXGBE_ERR_SFP_NOT_SUPPORTED; | |
650 | + | |
651 | + if (hw->phy.sfp_type == ixgbe_sfp_type_not_present) | |
652 | + return IXGBE_ERR_SFP_NOT_PRESENT; | |
653 | + | |
654 | + if ((hw->device_id == IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM) && | |
655 | + (hw->phy.sfp_type == ixgbe_sfp_type_da_cu)) | |
656 | + return IXGBE_ERR_SFP_NOT_SUPPORTED; | |
657 | + | |
658 | + /* Read offset to PHY init contents */ | |
659 | + hw->eeprom.ops.read(hw, IXGBE_PHY_INIT_OFFSET_NL, list_offset); | |
660 | + | |
661 | + if ((!*list_offset) || (*list_offset == 0xFFFF)) | |
662 | + return IXGBE_ERR_PHY; | |
663 | + | |
664 | + /* Shift offset to first ID word */ | |
665 | + (*list_offset)++; | |
666 | + | |
667 | + /* | |
668 | + * Find the matching SFP ID in the EEPROM | |
669 | + * and program the init sequence | |
670 | + */ | |
671 | + hw->eeprom.ops.read(hw, *list_offset, &sfp_id); | |
672 | + | |
673 | + while (sfp_id != IXGBE_PHY_INIT_END_NL) { | |
674 | + if (sfp_id == hw->phy.sfp_type) { | |
675 | + (*list_offset)++; | |
676 | + hw->eeprom.ops.read(hw, *list_offset, data_offset); | |
677 | + if ((!*data_offset) || (*data_offset == 0xFFFF)) { | |
678 | + hw_dbg(hw, "SFP+ module not supported\n"); | |
679 | + return IXGBE_ERR_SFP_NOT_SUPPORTED; | |
680 | + } else { | |
681 | + break; | |
682 | + } | |
683 | + } else { | |
684 | + (*list_offset) += 2; | |
685 | + if (hw->eeprom.ops.read(hw, *list_offset, &sfp_id)) | |
686 | + return IXGBE_ERR_PHY; | |
687 | + } | |
688 | + } | |
689 | + | |
690 | + if (sfp_id == IXGBE_PHY_INIT_END_NL) { | |
691 | + hw_dbg(hw, "No matching SFP+ module found\n"); | |
692 | + return IXGBE_ERR_SFP_NOT_SUPPORTED; | |
693 | + } | |
694 | + | |
695 | + return 0; | |
696 | +} | |
697 | + | |
698 | +/** | |
699 | * ixgbe_check_phy_link_tnx - Determine link and speed status | |
700 | * @hw: pointer to hardware structure | |
701 | * | |
702 | --- a/drivers/net/ixgbe/ixgbe_phy.h | |
703 | +++ b/drivers/net/ixgbe/ixgbe_phy.h | |
704 | @@ -63,6 +63,18 @@ | |
705 | #define IXGBE_SFF_VENDOR_OUI_FTL 0x00906500 | |
706 | #define IXGBE_SFF_VENDOR_OUI_AVAGO 0x00176A00 | |
707 | ||
708 | +/* I2C SDA and SCL timing parameters for standard mode */ | |
709 | +#define IXGBE_I2C_T_HD_STA 4 | |
710 | +#define IXGBE_I2C_T_LOW 5 | |
711 | +#define IXGBE_I2C_T_HIGH 4 | |
712 | +#define IXGBE_I2C_T_SU_STA 5 | |
713 | +#define IXGBE_I2C_T_HD_DATA 5 | |
714 | +#define IXGBE_I2C_T_SU_DATA 1 | |
715 | +#define IXGBE_I2C_T_RISE 1 | |
716 | +#define IXGBE_I2C_T_FALL 1 | |
717 | +#define IXGBE_I2C_T_SU_STO 4 | |
718 | +#define IXGBE_I2C_T_BUF 5 | |
719 | + | |
720 | ||
721 | s32 ixgbe_init_phy_ops_generic(struct ixgbe_hw *hw); | |
722 | s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw); | |
723 | @@ -84,4 +96,10 @@ s32 ixgbe_check_phy_link_tnx(struct ixgb | |
724 | s32 ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw, | |
725 | u16 *firmware_version); | |
726 | ||
727 | +/* PHY specific */ | |
728 | +s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw); | |
729 | +s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw); | |
730 | +s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw, | |
731 | + u16 *list_offset, | |
732 | + u16 *data_offset); | |
733 | #endif /* _IXGBE_PHY_H_ */ | |
734 | --- a/drivers/net/ixgbe/ixgbe_type.h | |
735 | +++ b/drivers/net/ixgbe/ixgbe_type.h | |
736 | @@ -36,9 +36,12 @@ | |
737 | /* Device IDs */ | |
738 | #define IXGBE_DEV_ID_82598AF_DUAL_PORT 0x10C6 | |
739 | #define IXGBE_DEV_ID_82598AF_SINGLE_PORT 0x10C7 | |
740 | +#define IXGBE_DEV_ID_82598EB_SFP_LOM 0x10DB | |
741 | #define IXGBE_DEV_ID_82598AT 0x10C8 | |
742 | #define IXGBE_DEV_ID_82598EB_CX4 0x10DD | |
743 | #define IXGBE_DEV_ID_82598_CX4_DUAL_PORT 0x10EC | |
744 | +#define IXGBE_DEV_ID_82598_DA_DUAL_PORT 0x10F1 | |
745 | +#define IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM 0x10E1 | |
746 | #define IXGBE_DEV_ID_82598EB_XF_LR 0x10F4 | |
747 | ||
748 | /* General Registers */ | |
749 | @@ -453,6 +456,7 @@ | |
750 | #define IXGBE_MDIO_PHY_XS_DEV_TYPE 0x4 | |
751 | #define IXGBE_MDIO_AUTO_NEG_DEV_TYPE 0x7 | |
752 | #define IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE 0x1E /* Device 30 */ | |
753 | +#define IXGBE_TWINAX_DEV 1 | |
754 | ||
755 | #define IXGBE_MDIO_COMMAND_TIMEOUT 100 /* PHY Timeout for 1 GB mode */ | |
756 | ||
757 | @@ -492,9 +496,21 @@ | |
758 | #define TN1010_PHY_ID 0x00A19410 | |
759 | #define TNX_FW_REV 0xB | |
760 | #define QT2022_PHY_ID 0x0043A400 | |
761 | +#define ATH_PHY_ID 0x03429050 | |
762 | ||
763 | /* PHY Types */ | |
764 | #define IXGBE_M88E1145_E_PHY_ID 0x01410CD0 | |
765 | +/* Special PHY Init Routine */ | |
766 | +#define IXGBE_PHY_INIT_OFFSET_NL 0x002B | |
767 | +#define IXGBE_PHY_INIT_END_NL 0xFFFF | |
768 | +#define IXGBE_CONTROL_MASK_NL 0xF000 | |
769 | +#define IXGBE_DATA_MASK_NL 0x0FFF | |
770 | +#define IXGBE_CONTROL_SHIFT_NL 12 | |
771 | +#define IXGBE_DELAY_NL 0 | |
772 | +#define IXGBE_DATA_NL 1 | |
773 | +#define IXGBE_CONTROL_NL 0x000F | |
774 | +#define IXGBE_CONTROL_EOL_NL 0x0FFF | |
775 | +#define IXGBE_CONTROL_SOL_NL 0x0000 | |
776 | ||
777 | /* General purpose Interrupt Enable */ | |
778 | #define IXGBE_SDP0_GPIEN 0x00000001 /* SDP0 */ | |
779 | @@ -1208,6 +1224,7 @@ enum ixgbe_phy_type { | |
780 | ixgbe_phy_tn, | |
781 | ixgbe_phy_qt, | |
782 | ixgbe_phy_xaui, | |
783 | + ixgbe_phy_nl, | |
784 | ixgbe_phy_tw_tyco, | |
785 | ixgbe_phy_tw_unknown, | |
786 | ixgbe_phy_sfp_avago, | |
787 | @@ -1229,6 +1246,7 @@ enum ixgbe_sfp_type { | |
788 | ixgbe_sfp_type_da_cu = 0, | |
789 | ixgbe_sfp_type_sr = 1, | |
790 | ixgbe_sfp_type_lr = 2, | |
791 | + ixgbe_sfp_type_not_present = 0xFFFE, | |
792 | ixgbe_sfp_type_unknown = 0xFFFF | |
793 | }; | |
794 | ||
795 | @@ -1492,6 +1510,7 @@ struct ixgbe_info { | |
796 | #define IXGBE_ERR_PHY_ADDR_INVALID -17 | |
797 | #define IXGBE_ERR_I2C -18 | |
798 | #define IXGBE_ERR_SFP_NOT_SUPPORTED -19 | |
799 | +#define IXGBE_ERR_SFP_NOT_PRESENT -20 | |
800 | #define IXGBE_NOT_IMPLEMENTED 0x7FFFFFFF | |
801 | ||
802 | #endif /* _IXGBE_TYPE_H_ */ |