diff options
Diffstat (limited to 'drivers/net/sfc/tenxpress.c')
-rw-r--r-- | drivers/net/sfc/tenxpress.c | 434 |
1 files changed, 434 insertions, 0 deletions
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c new file mode 100644 index 000000000000..a2e9f79e47b1 --- /dev/null +++ b/drivers/net/sfc/tenxpress.c | |||
@@ -0,0 +1,434 @@ | |||
1 | /**************************************************************************** | ||
2 | * Driver for Solarflare 802.3an compliant PHY | ||
3 | * Copyright 2007 Solarflare Communications Inc. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published | ||
7 | * by the Free Software Foundation, incorporated herein by reference. | ||
8 | */ | ||
9 | |||
10 | #include <linux/delay.h> | ||
11 | #include <linux/seq_file.h> | ||
12 | #include "efx.h" | ||
13 | #include "gmii.h" | ||
14 | #include "mdio_10g.h" | ||
15 | #include "falcon.h" | ||
16 | #include "phy.h" | ||
17 | #include "falcon_hwdefs.h" | ||
18 | #include "boards.h" | ||
19 | #include "mac.h" | ||
20 | |||
21 | /* We expect these MMDs to be in the package */ | ||
22 | /* AN not here as mdio_check_mmds() requires STAT2 support */ | ||
23 | #define TENXPRESS_REQUIRED_DEVS (MDIO_MMDREG_DEVS0_PMAPMD | \ | ||
24 | MDIO_MMDREG_DEVS0_PCS | \ | ||
25 | MDIO_MMDREG_DEVS0_PHYXS) | ||
26 | |||
27 | /* We complain if we fail to see the link partner as 10G capable this many | ||
28 | * times in a row (must be > 1 as sampling the autoneg. registers is racy) | ||
29 | */ | ||
30 | #define MAX_BAD_LP_TRIES (5) | ||
31 | |||
32 | /* Extended control register */ | ||
33 | #define PMA_PMD_XCONTROL_REG 0xc000 | ||
34 | #define PMA_PMD_LNPGA_POWERDOWN_LBN 8 | ||
35 | #define PMA_PMD_LNPGA_POWERDOWN_WIDTH 1 | ||
36 | |||
37 | /* extended status register */ | ||
38 | #define PMA_PMD_XSTATUS_REG 0xc001 | ||
39 | #define PMA_PMD_XSTAT_FLP_LBN (12) | ||
40 | |||
41 | /* LED control register */ | ||
42 | #define PMA_PMD_LED_CTRL_REG (0xc007) | ||
43 | #define PMA_PMA_LED_ACTIVITY_LBN (3) | ||
44 | |||
45 | /* LED function override register */ | ||
46 | #define PMA_PMD_LED_OVERR_REG (0xc009) | ||
47 | /* Bit positions for different LEDs (there are more but not wired on SFE4001)*/ | ||
48 | #define PMA_PMD_LED_LINK_LBN (0) | ||
49 | #define PMA_PMD_LED_SPEED_LBN (2) | ||
50 | #define PMA_PMD_LED_TX_LBN (4) | ||
51 | #define PMA_PMD_LED_RX_LBN (6) | ||
52 | /* Override settings */ | ||
53 | #define PMA_PMD_LED_AUTO (0) /* H/W control */ | ||
54 | #define PMA_PMD_LED_ON (1) | ||
55 | #define PMA_PMD_LED_OFF (2) | ||
56 | #define PMA_PMD_LED_FLASH (3) | ||
57 | /* All LEDs under hardware control */ | ||
58 | #define PMA_PMD_LED_FULL_AUTO (0) | ||
59 | /* Green and Amber under hardware control, Red off */ | ||
60 | #define PMA_PMD_LED_DEFAULT (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN) | ||
61 | |||
62 | |||
63 | /* Self test (BIST) control register */ | ||
64 | #define PMA_PMD_BIST_CTRL_REG (0xc014) | ||
65 | #define PMA_PMD_BIST_BER_LBN (2) /* Run BER test */ | ||
66 | #define PMA_PMD_BIST_CONT_LBN (1) /* Run continuous BIST until cleared */ | ||
67 | #define PMA_PMD_BIST_SINGLE_LBN (0) /* Run 1 BIST iteration (self clears) */ | ||
68 | /* Self test status register */ | ||
69 | #define PMA_PMD_BIST_STAT_REG (0xc015) | ||
70 | #define PMA_PMD_BIST_ENX_LBN (3) | ||
71 | #define PMA_PMD_BIST_PMA_LBN (2) | ||
72 | #define PMA_PMD_BIST_RXD_LBN (1) | ||
73 | #define PMA_PMD_BIST_AFE_LBN (0) | ||
74 | |||
75 | #define BIST_MAX_DELAY (1000) | ||
76 | #define BIST_POLL_DELAY (10) | ||
77 | |||
78 | /* Misc register defines */ | ||
79 | #define PCS_CLOCK_CTRL_REG 0xd801 | ||
80 | #define PLL312_RST_N_LBN 2 | ||
81 | |||
82 | #define PCS_SOFT_RST2_REG 0xd806 | ||
83 | #define SERDES_RST_N_LBN 13 | ||
84 | #define XGXS_RST_N_LBN 12 | ||
85 | |||
86 | #define PCS_TEST_SELECT_REG 0xd807 /* PRM 10.5.8 */ | ||
87 | #define CLK312_EN_LBN 3 | ||
88 | |||
89 | /* Boot status register */ | ||
90 | #define PCS_BOOT_STATUS_REG (0xd000) | ||
91 | #define PCS_BOOT_FATAL_ERR_LBN (0) | ||
92 | #define PCS_BOOT_PROGRESS_LBN (1) | ||
93 | #define PCS_BOOT_PROGRESS_WIDTH (2) | ||
94 | #define PCS_BOOT_COMPLETE_LBN (3) | ||
95 | #define PCS_BOOT_MAX_DELAY (100) | ||
96 | #define PCS_BOOT_POLL_DELAY (10) | ||
97 | |||
98 | /* Time to wait between powering down the LNPGA and turning off the power | ||
99 | * rails */ | ||
100 | #define LNPGA_PDOWN_WAIT (HZ / 5) | ||
101 | |||
102 | static int crc_error_reset_threshold = 100; | ||
103 | module_param(crc_error_reset_threshold, int, 0644); | ||
104 | MODULE_PARM_DESC(crc_error_reset_threshold, | ||
105 | "Max number of CRC errors before XAUI reset"); | ||
106 | |||
107 | struct tenxpress_phy_data { | ||
108 | enum tenxpress_state state; | ||
109 | atomic_t bad_crc_count; | ||
110 | int bad_lp_tries; | ||
111 | }; | ||
112 | |||
113 | static int tenxpress_state_is(struct efx_nic *efx, int state) | ||
114 | { | ||
115 | struct tenxpress_phy_data *phy_data = efx->phy_data; | ||
116 | return (phy_data != NULL) && (state == phy_data->state); | ||
117 | } | ||
118 | |||
119 | void tenxpress_set_state(struct efx_nic *efx, | ||
120 | enum tenxpress_state state) | ||
121 | { | ||
122 | struct tenxpress_phy_data *phy_data = efx->phy_data; | ||
123 | if (phy_data != NULL) | ||
124 | phy_data->state = state; | ||
125 | } | ||
126 | |||
127 | void tenxpress_crc_err(struct efx_nic *efx) | ||
128 | { | ||
129 | struct tenxpress_phy_data *phy_data = efx->phy_data; | ||
130 | if (phy_data != NULL) | ||
131 | atomic_inc(&phy_data->bad_crc_count); | ||
132 | } | ||
133 | |||
134 | /* Check that the C166 has booted successfully */ | ||
135 | static int tenxpress_phy_check(struct efx_nic *efx) | ||
136 | { | ||
137 | int phy_id = efx->mii.phy_id; | ||
138 | int count = PCS_BOOT_MAX_DELAY / PCS_BOOT_POLL_DELAY; | ||
139 | int boot_stat; | ||
140 | |||
141 | /* Wait for the boot to complete (or not) */ | ||
142 | while (count) { | ||
143 | boot_stat = mdio_clause45_read(efx, phy_id, | ||
144 | MDIO_MMD_PCS, | ||
145 | PCS_BOOT_STATUS_REG); | ||
146 | if (boot_stat & (1 << PCS_BOOT_COMPLETE_LBN)) | ||
147 | break; | ||
148 | count--; | ||
149 | udelay(PCS_BOOT_POLL_DELAY); | ||
150 | } | ||
151 | |||
152 | if (!count) { | ||
153 | EFX_ERR(efx, "%s: PHY boot timed out. Last status " | ||
154 | "%x\n", __func__, | ||
155 | (boot_stat >> PCS_BOOT_PROGRESS_LBN) & | ||
156 | ((1 << PCS_BOOT_PROGRESS_WIDTH) - 1)); | ||
157 | return -ETIMEDOUT; | ||
158 | } | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | static void tenxpress_reset_xaui(struct efx_nic *efx); | ||
164 | |||
165 | static int tenxpress_init(struct efx_nic *efx) | ||
166 | { | ||
167 | int rc, reg; | ||
168 | |||
169 | /* Turn on the clock */ | ||
170 | reg = (1 << CLK312_EN_LBN); | ||
171 | mdio_clause45_write(efx, efx->mii.phy_id, | ||
172 | MDIO_MMD_PCS, PCS_TEST_SELECT_REG, reg); | ||
173 | |||
174 | rc = tenxpress_phy_check(efx); | ||
175 | if (rc < 0) | ||
176 | return rc; | ||
177 | |||
178 | /* Set the LEDs up as: Green = Link, Amber = Link/Act, Red = Off */ | ||
179 | reg = mdio_clause45_read(efx, efx->mii.phy_id, | ||
180 | MDIO_MMD_PMAPMD, PMA_PMD_LED_CTRL_REG); | ||
181 | reg |= (1 << PMA_PMA_LED_ACTIVITY_LBN); | ||
182 | mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, | ||
183 | PMA_PMD_LED_CTRL_REG, reg); | ||
184 | |||
185 | reg = PMA_PMD_LED_DEFAULT; | ||
186 | mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, | ||
187 | PMA_PMD_LED_OVERR_REG, reg); | ||
188 | |||
189 | return rc; | ||
190 | } | ||
191 | |||
192 | static int tenxpress_phy_init(struct efx_nic *efx) | ||
193 | { | ||
194 | struct tenxpress_phy_data *phy_data; | ||
195 | int rc = 0; | ||
196 | |||
197 | phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL); | ||
198 | efx->phy_data = phy_data; | ||
199 | |||
200 | tenxpress_set_state(efx, TENXPRESS_STATUS_NORMAL); | ||
201 | |||
202 | rc = mdio_clause45_wait_reset_mmds(efx, | ||
203 | TENXPRESS_REQUIRED_DEVS); | ||
204 | if (rc < 0) | ||
205 | goto fail; | ||
206 | |||
207 | rc = mdio_clause45_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0); | ||
208 | if (rc < 0) | ||
209 | goto fail; | ||
210 | |||
211 | rc = tenxpress_init(efx); | ||
212 | if (rc < 0) | ||
213 | goto fail; | ||
214 | |||
215 | schedule_timeout_uninterruptible(HZ / 5); /* 200ms */ | ||
216 | |||
217 | /* Let XGXS and SerDes out of reset and resets 10XPress */ | ||
218 | falcon_reset_xaui(efx); | ||
219 | |||
220 | return 0; | ||
221 | |||
222 | fail: | ||
223 | kfree(efx->phy_data); | ||
224 | efx->phy_data = NULL; | ||
225 | return rc; | ||
226 | } | ||
227 | |||
228 | static void tenxpress_set_bad_lp(struct efx_nic *efx, int bad_lp) | ||
229 | { | ||
230 | struct tenxpress_phy_data *pd = efx->phy_data; | ||
231 | int reg; | ||
232 | |||
233 | /* Nothing to do if all is well and was previously so. */ | ||
234 | if (!(bad_lp || pd->bad_lp_tries)) | ||
235 | return; | ||
236 | |||
237 | reg = mdio_clause45_read(efx, efx->mii.phy_id, | ||
238 | MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG); | ||
239 | |||
240 | if (bad_lp) | ||
241 | pd->bad_lp_tries++; | ||
242 | else | ||
243 | pd->bad_lp_tries = 0; | ||
244 | |||
245 | if (pd->bad_lp_tries == MAX_BAD_LP_TRIES) { | ||
246 | pd->bad_lp_tries = 0; /* Restart count */ | ||
247 | reg &= ~(PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN); | ||
248 | reg |= (PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN); | ||
249 | EFX_ERR(efx, "This NIC appears to be plugged into" | ||
250 | " a port that is not 10GBASE-T capable.\n" | ||
251 | " This PHY is 10GBASE-T ONLY, so no link can" | ||
252 | " be established.\n"); | ||
253 | } else { | ||
254 | reg |= (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN); | ||
255 | } | ||
256 | mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, | ||
257 | PMA_PMD_LED_OVERR_REG, reg); | ||
258 | } | ||
259 | |||
260 | /* Check link status and return a boolean OK value. If the link is NOT | ||
261 | * OK we have a quick rummage round to see if we appear to be plugged | ||
262 | * into a non-10GBT port and if so warn the user that they won't get | ||
263 | * link any time soon as we are 10GBT only, unless caller specified | ||
264 | * not to do this check (it isn't useful in loopback) */ | ||
265 | static int tenxpress_link_ok(struct efx_nic *efx, int check_lp) | ||
266 | { | ||
267 | int ok = mdio_clause45_links_ok(efx, TENXPRESS_REQUIRED_DEVS); | ||
268 | |||
269 | if (ok) { | ||
270 | tenxpress_set_bad_lp(efx, 0); | ||
271 | } else if (check_lp) { | ||
272 | /* Are we plugged into the wrong sort of link? */ | ||
273 | int bad_lp = 0; | ||
274 | int phy_id = efx->mii.phy_id; | ||
275 | int an_stat = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, | ||
276 | MDIO_AN_STATUS); | ||
277 | int xphy_stat = mdio_clause45_read(efx, phy_id, | ||
278 | MDIO_MMD_PMAPMD, | ||
279 | PMA_PMD_XSTATUS_REG); | ||
280 | /* Are we plugged into anything that sends FLPs? If | ||
281 | * not we can't distinguish between not being plugged | ||
282 | * in and being plugged into a non-AN antique. The FLP | ||
283 | * bit has the advantage of not clearing when autoneg | ||
284 | * restarts. */ | ||
285 | if (!(xphy_stat & (1 << PMA_PMD_XSTAT_FLP_LBN))) { | ||
286 | tenxpress_set_bad_lp(efx, 0); | ||
287 | return ok; | ||
288 | } | ||
289 | |||
290 | /* If it can do 10GBT it must be XNP capable */ | ||
291 | bad_lp = !(an_stat & (1 << MDIO_AN_STATUS_XNP_LBN)); | ||
292 | if (!bad_lp && (an_stat & (1 << MDIO_AN_STATUS_PAGE_LBN))) { | ||
293 | bad_lp = !(mdio_clause45_read(efx, phy_id, | ||
294 | MDIO_MMD_AN, MDIO_AN_10GBT_STATUS) & | ||
295 | (1 << MDIO_AN_10GBT_STATUS_LP_10G_LBN)); | ||
296 | } | ||
297 | tenxpress_set_bad_lp(efx, bad_lp); | ||
298 | } | ||
299 | return ok; | ||
300 | } | ||
301 | |||
302 | static void tenxpress_phy_reconfigure(struct efx_nic *efx) | ||
303 | { | ||
304 | if (!tenxpress_state_is(efx, TENXPRESS_STATUS_NORMAL)) | ||
305 | return; | ||
306 | |||
307 | efx->link_up = tenxpress_link_ok(efx, 0); | ||
308 | efx->link_options = GM_LPA_10000FULL; | ||
309 | } | ||
310 | |||
311 | static void tenxpress_phy_clear_interrupt(struct efx_nic *efx) | ||
312 | { | ||
313 | /* Nothing done here - LASI interrupts aren't reliable so poll */ | ||
314 | } | ||
315 | |||
316 | |||
317 | /* Poll PHY for interrupt */ | ||
318 | static int tenxpress_phy_check_hw(struct efx_nic *efx) | ||
319 | { | ||
320 | struct tenxpress_phy_data *phy_data = efx->phy_data; | ||
321 | int phy_up = tenxpress_state_is(efx, TENXPRESS_STATUS_NORMAL); | ||
322 | int link_ok; | ||
323 | |||
324 | link_ok = phy_up && tenxpress_link_ok(efx, 1); | ||
325 | |||
326 | if (link_ok != efx->link_up) | ||
327 | falcon_xmac_sim_phy_event(efx); | ||
328 | |||
329 | /* Nothing to check if we've already shut down the PHY */ | ||
330 | if (!phy_up) | ||
331 | return 0; | ||
332 | |||
333 | if (atomic_read(&phy_data->bad_crc_count) > crc_error_reset_threshold) { | ||
334 | EFX_ERR(efx, "Resetting XAUI due to too many CRC errors\n"); | ||
335 | falcon_reset_xaui(efx); | ||
336 | atomic_set(&phy_data->bad_crc_count, 0); | ||
337 | } | ||
338 | |||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | static void tenxpress_phy_fini(struct efx_nic *efx) | ||
343 | { | ||
344 | int reg; | ||
345 | |||
346 | /* Power down the LNPGA */ | ||
347 | reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN); | ||
348 | mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, | ||
349 | PMA_PMD_XCONTROL_REG, reg); | ||
350 | |||
351 | /* Waiting here ensures that the board fini, which can turn off the | ||
352 | * power to the PHY, won't get run until the LNPGA powerdown has been | ||
353 | * given long enough to complete. */ | ||
354 | schedule_timeout_uninterruptible(LNPGA_PDOWN_WAIT); /* 200 ms */ | ||
355 | |||
356 | kfree(efx->phy_data); | ||
357 | efx->phy_data = NULL; | ||
358 | } | ||
359 | |||
360 | |||
361 | /* Set the RX and TX LEDs and Link LED flashing. The other LEDs | ||
362 | * (which probably aren't wired anyway) are left in AUTO mode */ | ||
363 | void tenxpress_phy_blink(struct efx_nic *efx, int blink) | ||
364 | { | ||
365 | int reg; | ||
366 | |||
367 | if (blink) | ||
368 | reg = (PMA_PMD_LED_FLASH << PMA_PMD_LED_TX_LBN) | | ||
369 | (PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN) | | ||
370 | (PMA_PMD_LED_FLASH << PMA_PMD_LED_LINK_LBN); | ||
371 | else | ||
372 | reg = PMA_PMD_LED_DEFAULT; | ||
373 | |||
374 | mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, | ||
375 | PMA_PMD_LED_OVERR_REG, reg); | ||
376 | } | ||
377 | |||
378 | static void tenxpress_reset_xaui(struct efx_nic *efx) | ||
379 | { | ||
380 | int phy = efx->mii.phy_id; | ||
381 | int clk_ctrl, test_select, soft_rst2; | ||
382 | |||
383 | /* Real work is done on clock_ctrl other resets are thought to be | ||
384 | * optional but make the reset more reliable | ||
385 | */ | ||
386 | |||
387 | /* Read */ | ||
388 | clk_ctrl = mdio_clause45_read(efx, phy, MDIO_MMD_PCS, | ||
389 | PCS_CLOCK_CTRL_REG); | ||
390 | test_select = mdio_clause45_read(efx, phy, MDIO_MMD_PCS, | ||
391 | PCS_TEST_SELECT_REG); | ||
392 | soft_rst2 = mdio_clause45_read(efx, phy, MDIO_MMD_PCS, | ||
393 | PCS_SOFT_RST2_REG); | ||
394 | |||
395 | /* Put in reset */ | ||
396 | test_select &= ~(1 << CLK312_EN_LBN); | ||
397 | mdio_clause45_write(efx, phy, MDIO_MMD_PCS, | ||
398 | PCS_TEST_SELECT_REG, test_select); | ||
399 | |||
400 | soft_rst2 &= ~((1 << XGXS_RST_N_LBN) | (1 << SERDES_RST_N_LBN)); | ||
401 | mdio_clause45_write(efx, phy, MDIO_MMD_PCS, | ||
402 | PCS_SOFT_RST2_REG, soft_rst2); | ||
403 | |||
404 | clk_ctrl &= ~(1 << PLL312_RST_N_LBN); | ||
405 | mdio_clause45_write(efx, phy, MDIO_MMD_PCS, | ||
406 | PCS_CLOCK_CTRL_REG, clk_ctrl); | ||
407 | udelay(10); | ||
408 | |||
409 | /* Remove reset */ | ||
410 | clk_ctrl |= (1 << PLL312_RST_N_LBN); | ||
411 | mdio_clause45_write(efx, phy, MDIO_MMD_PCS, | ||
412 | PCS_CLOCK_CTRL_REG, clk_ctrl); | ||
413 | udelay(10); | ||
414 | |||
415 | soft_rst2 |= ((1 << XGXS_RST_N_LBN) | (1 << SERDES_RST_N_LBN)); | ||
416 | mdio_clause45_write(efx, phy, MDIO_MMD_PCS, | ||
417 | PCS_SOFT_RST2_REG, soft_rst2); | ||
418 | udelay(10); | ||
419 | |||
420 | test_select |= (1 << CLK312_EN_LBN); | ||
421 | mdio_clause45_write(efx, phy, MDIO_MMD_PCS, | ||
422 | PCS_TEST_SELECT_REG, test_select); | ||
423 | udelay(10); | ||
424 | } | ||
425 | |||
426 | struct efx_phy_operations falcon_tenxpress_phy_ops = { | ||
427 | .init = tenxpress_phy_init, | ||
428 | .reconfigure = tenxpress_phy_reconfigure, | ||
429 | .check_hw = tenxpress_phy_check_hw, | ||
430 | .fini = tenxpress_phy_fini, | ||
431 | .clear_interrupt = tenxpress_phy_clear_interrupt, | ||
432 | .reset_xaui = tenxpress_reset_xaui, | ||
433 | .mmds = TENXPRESS_REQUIRED_DEVS, | ||
434 | }; | ||