Commit | Line | Data |
---|---|---|
8ceee660 BH |
1 | /**************************************************************************** |
2 | * Driver for Solarflare Solarstorm network controllers and boards | |
3 | * Copyright 2006-2008 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 | * Useful functions for working with MDIO clause 45 PHYs | |
11 | */ | |
12 | #include <linux/types.h> | |
13 | #include <linux/ethtool.h> | |
14 | #include <linux/delay.h> | |
15 | #include "net_driver.h" | |
16 | #include "mdio_10g.h" | |
17 | #include "boards.h" | |
8b9dc8dd | 18 | #include "workarounds.h" |
8ceee660 BH |
19 | |
20 | int mdio_clause45_reset_mmd(struct efx_nic *port, int mmd, | |
21 | int spins, int spintime) | |
22 | { | |
23 | u32 ctrl; | |
24 | int phy_id = port->mii.phy_id; | |
25 | ||
26 | /* Catch callers passing values in the wrong units (or just silly) */ | |
27 | EFX_BUG_ON_PARANOID(spins * spintime >= 5000); | |
28 | ||
29 | mdio_clause45_write(port, phy_id, mmd, MDIO_MMDREG_CTRL1, | |
30 | (1 << MDIO_MMDREG_CTRL1_RESET_LBN)); | |
31 | /* Wait for the reset bit to clear. */ | |
32 | do { | |
33 | msleep(spintime); | |
34 | ctrl = mdio_clause45_read(port, phy_id, mmd, MDIO_MMDREG_CTRL1); | |
35 | spins--; | |
36 | ||
37 | } while (spins && (ctrl & (1 << MDIO_MMDREG_CTRL1_RESET_LBN))); | |
38 | ||
39 | return spins ? spins : -ETIMEDOUT; | |
40 | } | |
41 | ||
42 | static int mdio_clause45_check_mmd(struct efx_nic *efx, int mmd, | |
43 | int fault_fatal) | |
44 | { | |
45 | int status; | |
46 | int phy_id = efx->mii.phy_id; | |
47 | ||
3273c2e8 BH |
48 | if (LOOPBACK_INTERNAL(efx)) |
49 | return 0; | |
50 | ||
04cc8cac BH |
51 | if (mmd != MDIO_MMD_AN) { |
52 | /* Read MMD STATUS2 to check it is responding. */ | |
53 | status = mdio_clause45_read(efx, phy_id, mmd, | |
54 | MDIO_MMDREG_STAT2); | |
55 | if (((status >> MDIO_MMDREG_STAT2_PRESENT_LBN) & | |
56 | ((1 << MDIO_MMDREG_STAT2_PRESENT_WIDTH) - 1)) != | |
57 | MDIO_MMDREG_STAT2_PRESENT_VAL) { | |
58 | EFX_ERR(efx, "PHY MMD %d not responding.\n", mmd); | |
59 | return -EIO; | |
60 | } | |
8ceee660 BH |
61 | } |
62 | ||
63 | /* Read MMD STATUS 1 to check for fault. */ | |
64 | status = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_STAT1); | |
65 | if ((status & (1 << MDIO_MMDREG_STAT1_FAULT_LBN)) != 0) { | |
66 | if (fault_fatal) { | |
67 | EFX_ERR(efx, "PHY MMD %d reporting fatal" | |
68 | " fault: status %x\n", mmd, status); | |
69 | return -EIO; | |
70 | } else { | |
71 | EFX_LOG(efx, "PHY MMD %d reporting status" | |
72 | " %x (expected)\n", mmd, status); | |
73 | } | |
74 | } | |
75 | return 0; | |
76 | } | |
77 | ||
78 | /* This ought to be ridiculous overkill. We expect it to fail rarely */ | |
79 | #define MDIO45_RESET_TIME 1000 /* ms */ | |
80 | #define MDIO45_RESET_ITERS 100 | |
81 | ||
82 | int mdio_clause45_wait_reset_mmds(struct efx_nic *efx, | |
83 | unsigned int mmd_mask) | |
84 | { | |
85 | const int spintime = MDIO45_RESET_TIME / MDIO45_RESET_ITERS; | |
86 | int tries = MDIO45_RESET_ITERS; | |
87 | int rc = 0; | |
88 | int in_reset; | |
89 | ||
90 | while (tries) { | |
91 | int mask = mmd_mask; | |
92 | int mmd = 0; | |
93 | int stat; | |
94 | in_reset = 0; | |
95 | while (mask) { | |
96 | if (mask & 1) { | |
97 | stat = mdio_clause45_read(efx, | |
98 | efx->mii.phy_id, | |
99 | mmd, | |
100 | MDIO_MMDREG_CTRL1); | |
101 | if (stat < 0) { | |
102 | EFX_ERR(efx, "failed to read status of" | |
103 | " MMD %d\n", mmd); | |
104 | return -EIO; | |
105 | } | |
106 | if (stat & (1 << MDIO_MMDREG_CTRL1_RESET_LBN)) | |
107 | in_reset |= (1 << mmd); | |
108 | } | |
109 | mask = mask >> 1; | |
110 | mmd++; | |
111 | } | |
112 | if (!in_reset) | |
113 | break; | |
114 | tries--; | |
115 | msleep(spintime); | |
116 | } | |
117 | if (in_reset != 0) { | |
118 | EFX_ERR(efx, "not all MMDs came out of reset in time." | |
119 | " MMDs still in reset: %x\n", in_reset); | |
120 | rc = -ETIMEDOUT; | |
121 | } | |
122 | return rc; | |
123 | } | |
124 | ||
125 | int mdio_clause45_check_mmds(struct efx_nic *efx, | |
126 | unsigned int mmd_mask, unsigned int fatal_mask) | |
127 | { | |
27dd2cac BH |
128 | u32 devices; |
129 | int mmd = 0, probe_mmd; | |
8ceee660 BH |
130 | |
131 | /* Historically we have probed the PHYXS to find out what devices are | |
132 | * present,but that doesn't work so well if the PHYXS isn't expected | |
133 | * to exist, if so just find the first item in the list supplied. */ | |
27dd2cac | 134 | probe_mmd = (mmd_mask & MDIO_MMDREG_DEVS_PHYXS) ? MDIO_MMD_PHYXS : |
8ceee660 | 135 | __ffs(mmd_mask); |
27dd2cac BH |
136 | devices = (mdio_clause45_read(efx, efx->mii.phy_id, |
137 | probe_mmd, MDIO_MMDREG_DEVS0) | | |
138 | mdio_clause45_read(efx, efx->mii.phy_id, | |
139 | probe_mmd, MDIO_MMDREG_DEVS1) << 16); | |
8ceee660 BH |
140 | |
141 | /* Check all the expected MMDs are present */ | |
142 | if (devices < 0) { | |
143 | EFX_ERR(efx, "failed to read devices present\n"); | |
144 | return -EIO; | |
145 | } | |
146 | if ((devices & mmd_mask) != mmd_mask) { | |
147 | EFX_ERR(efx, "required MMDs not present: got %x, " | |
148 | "wanted %x\n", devices, mmd_mask); | |
149 | return -ENODEV; | |
150 | } | |
151 | EFX_TRACE(efx, "Devices present: %x\n", devices); | |
152 | ||
153 | /* Check all required MMDs are responding and happy. */ | |
154 | while (mmd_mask) { | |
155 | if (mmd_mask & 1) { | |
156 | int fault_fatal = fatal_mask & 1; | |
157 | if (mdio_clause45_check_mmd(efx, mmd, fault_fatal)) | |
158 | return -EIO; | |
159 | } | |
160 | mmd_mask = mmd_mask >> 1; | |
161 | fatal_mask = fatal_mask >> 1; | |
162 | mmd++; | |
163 | } | |
164 | ||
165 | return 0; | |
166 | } | |
167 | ||
dc8cfa55 | 168 | bool mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask) |
8ceee660 BH |
169 | { |
170 | int phy_id = efx->mii.phy_id; | |
caa8d8bb | 171 | u32 reg; |
dc8cfa55 | 172 | bool ok = true; |
8ceee660 | 173 | int mmd = 0; |
8ceee660 | 174 | |
3273c2e8 BH |
175 | /* If the port is in loopback, then we should only consider a subset |
176 | * of mmd's */ | |
177 | if (LOOPBACK_INTERNAL(efx)) | |
dc8cfa55 | 178 | return true; |
3273c2e8 | 179 | else if (efx->loopback_mode == LOOPBACK_NETWORK) |
dc8cfa55 | 180 | return false; |
f8b87c17 BH |
181 | else if (efx_phy_mode_disabled(efx->phy_mode)) |
182 | return false; | |
67797763 | 183 | else if (efx->loopback_mode == LOOPBACK_PHYXS) |
27dd2cac BH |
184 | mmd_mask &= ~(MDIO_MMDREG_DEVS_PHYXS | |
185 | MDIO_MMDREG_DEVS_PCS | | |
04cc8cac BH |
186 | MDIO_MMDREG_DEVS_PMAPMD | |
187 | MDIO_MMDREG_DEVS_AN); | |
67797763 | 188 | else if (efx->loopback_mode == LOOPBACK_PCS) |
27dd2cac | 189 | mmd_mask &= ~(MDIO_MMDREG_DEVS_PCS | |
04cc8cac BH |
190 | MDIO_MMDREG_DEVS_PMAPMD | |
191 | MDIO_MMDREG_DEVS_AN); | |
3273c2e8 | 192 | else if (efx->loopback_mode == LOOPBACK_PMAPMD) |
04cc8cac BH |
193 | mmd_mask &= ~(MDIO_MMDREG_DEVS_PMAPMD | |
194 | MDIO_MMDREG_DEVS_AN); | |
3273c2e8 | 195 | |
67797763 SH |
196 | if (!mmd_mask) { |
197 | /* Use presence of XGMII faults in leui of link state */ | |
198 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PHYXS, | |
199 | MDIO_PHYXS_STATUS2); | |
200 | return !(reg & (1 << MDIO_PHYXS_STATUS2_RX_FAULT_LBN)); | |
201 | } | |
202 | ||
8ceee660 BH |
203 | while (mmd_mask) { |
204 | if (mmd_mask & 1) { | |
205 | /* Double reads because link state is latched, and a | |
206 | * read moves the current state into the register */ | |
caa8d8bb BH |
207 | reg = mdio_clause45_read(efx, phy_id, |
208 | mmd, MDIO_MMDREG_STAT1); | |
209 | reg = mdio_clause45_read(efx, phy_id, | |
210 | mmd, MDIO_MMDREG_STAT1); | |
211 | ok = ok && (reg & (1 << MDIO_MMDREG_STAT1_LINK_LBN)); | |
8ceee660 BH |
212 | } |
213 | mmd_mask = (mmd_mask >> 1); | |
214 | mmd++; | |
215 | } | |
216 | return ok; | |
217 | } | |
218 | ||
3273c2e8 BH |
219 | void mdio_clause45_transmit_disable(struct efx_nic *efx) |
220 | { | |
356eebb2 BH |
221 | mdio_clause45_set_flag(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, |
222 | MDIO_MMDREG_TXDIS, MDIO_MMDREG_TXDIS_GLOBAL_LBN, | |
223 | efx->phy_mode & PHY_MODE_TX_DISABLED); | |
3273c2e8 BH |
224 | } |
225 | ||
226 | void mdio_clause45_phy_reconfigure(struct efx_nic *efx) | |
227 | { | |
228 | int phy_id = efx->mii.phy_id; | |
3273c2e8 | 229 | |
356eebb2 BH |
230 | mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PMAPMD, |
231 | MDIO_MMDREG_CTRL1, MDIO_PMAPMD_CTRL1_LBACK_LBN, | |
232 | efx->loopback_mode == LOOPBACK_PMAPMD); | |
233 | mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PCS, | |
234 | MDIO_MMDREG_CTRL1, MDIO_MMDREG_CTRL1_LBACK_LBN, | |
235 | efx->loopback_mode == LOOPBACK_PCS); | |
236 | mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PHYXS, | |
237 | MDIO_MMDREG_CTRL1, MDIO_MMDREG_CTRL1_LBACK_LBN, | |
238 | efx->loopback_mode == LOOPBACK_NETWORK); | |
3273c2e8 BH |
239 | } |
240 | ||
3e133c44 BH |
241 | static void mdio_clause45_set_mmd_lpower(struct efx_nic *efx, |
242 | int lpower, int mmd) | |
243 | { | |
244 | int phy = efx->mii.phy_id; | |
245 | int stat = mdio_clause45_read(efx, phy, mmd, MDIO_MMDREG_STAT1); | |
3e133c44 BH |
246 | |
247 | EFX_TRACE(efx, "Setting low power mode for MMD %d to %d\n", | |
248 | mmd, lpower); | |
249 | ||
250 | if (stat & (1 << MDIO_MMDREG_STAT1_LPABLE_LBN)) { | |
356eebb2 BH |
251 | mdio_clause45_set_flag(efx, phy, mmd, MDIO_MMDREG_CTRL1, |
252 | MDIO_MMDREG_CTRL1_LPOWER_LBN, lpower); | |
3e133c44 BH |
253 | } |
254 | } | |
255 | ||
256 | void mdio_clause45_set_mmds_lpower(struct efx_nic *efx, | |
257 | int low_power, unsigned int mmd_mask) | |
258 | { | |
259 | int mmd = 0; | |
04cc8cac | 260 | mmd_mask &= ~MDIO_MMDREG_DEVS_AN; |
3e133c44 BH |
261 | while (mmd_mask) { |
262 | if (mmd_mask & 1) | |
263 | mdio_clause45_set_mmd_lpower(efx, low_power, mmd); | |
264 | mmd_mask = (mmd_mask >> 1); | |
265 | mmd++; | |
266 | } | |
267 | } | |
268 | ||
04cc8cac BH |
269 | static u32 mdio_clause45_get_an(struct efx_nic *efx, u16 addr, u32 xnp) |
270 | { | |
271 | int phy_id = efx->mii.phy_id; | |
272 | u32 result = 0; | |
273 | int reg; | |
274 | ||
275 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, addr); | |
276 | if (reg & ADVERTISE_10HALF) | |
277 | result |= ADVERTISED_10baseT_Half; | |
278 | if (reg & ADVERTISE_10FULL) | |
279 | result |= ADVERTISED_10baseT_Full; | |
280 | if (reg & ADVERTISE_100HALF) | |
281 | result |= ADVERTISED_100baseT_Half; | |
282 | if (reg & ADVERTISE_100FULL) | |
283 | result |= ADVERTISED_100baseT_Full; | |
284 | if (reg & LPA_RESV) | |
285 | result |= xnp; | |
286 | ||
287 | return result; | |
288 | } | |
289 | ||
8ceee660 BH |
290 | /** |
291 | * mdio_clause45_get_settings - Read (some of) the PHY settings over MDIO. | |
292 | * @efx: Efx NIC | |
293 | * @ecmd: Buffer for settings | |
294 | * | |
295 | * On return the 'port', 'speed', 'supported' and 'advertising' fields of | |
04cc8cac | 296 | * ecmd have been filled out. |
8ceee660 BH |
297 | */ |
298 | void mdio_clause45_get_settings(struct efx_nic *efx, | |
299 | struct ethtool_cmd *ecmd) | |
300 | { | |
04cc8cac BH |
301 | mdio_clause45_get_settings_ext(efx, ecmd, 0, 0); |
302 | } | |
8ceee660 | 303 | |
04cc8cac BH |
304 | /** |
305 | * mdio_clause45_get_settings_ext - Read (some of) the PHY settings over MDIO. | |
306 | * @efx: Efx NIC | |
307 | * @ecmd: Buffer for settings | |
308 | * @xnp: Advertised Extended Next Page state | |
309 | * @xnp_lpa: Link Partner's advertised XNP state | |
310 | * | |
311 | * On return the 'port', 'speed', 'supported' and 'advertising' fields of | |
312 | * ecmd have been filled out. | |
313 | */ | |
314 | void mdio_clause45_get_settings_ext(struct efx_nic *efx, | |
315 | struct ethtool_cmd *ecmd, | |
316 | u32 xnp, u32 xnp_lpa) | |
317 | { | |
318 | int phy_id = efx->mii.phy_id; | |
319 | int reg; | |
8ceee660 | 320 | |
04cc8cac BH |
321 | ecmd->transceiver = XCVR_INTERNAL; |
322 | ecmd->phy_address = phy_id; | |
8ceee660 | 323 | |
04cc8cac BH |
324 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, |
325 | MDIO_MMDREG_CTRL2); | |
326 | switch (reg & MDIO_PMAPMD_CTRL2_TYPE_MASK) { | |
8ceee660 | 327 | case MDIO_PMAPMD_CTRL2_10G_BT: |
8ceee660 | 328 | case MDIO_PMAPMD_CTRL2_1G_BT: |
8ceee660 | 329 | case MDIO_PMAPMD_CTRL2_100_BT: |
8ceee660 | 330 | case MDIO_PMAPMD_CTRL2_10_BT: |
8ceee660 | 331 | ecmd->port = PORT_TP; |
04cc8cac BH |
332 | ecmd->supported = SUPPORTED_TP; |
333 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, | |
334 | MDIO_MMDREG_SPEED); | |
335 | if (reg & (1 << MDIO_MMDREG_SPEED_10G_LBN)) | |
336 | ecmd->supported |= SUPPORTED_10000baseT_Full; | |
337 | if (reg & (1 << MDIO_MMDREG_SPEED_1000M_LBN)) | |
338 | ecmd->supported |= (SUPPORTED_1000baseT_Full | | |
339 | SUPPORTED_1000baseT_Half); | |
340 | if (reg & (1 << MDIO_MMDREG_SPEED_100M_LBN)) | |
341 | ecmd->supported |= (SUPPORTED_100baseT_Full | | |
342 | SUPPORTED_100baseT_Half); | |
343 | if (reg & (1 << MDIO_MMDREG_SPEED_10M_LBN)) | |
344 | ecmd->supported |= (SUPPORTED_10baseT_Full | | |
345 | SUPPORTED_10baseT_Half); | |
346 | ecmd->advertising = ADVERTISED_TP; | |
8ceee660 | 347 | break; |
04cc8cac BH |
348 | |
349 | /* We represent CX4 as fibre in the absence of anything better */ | |
350 | case MDIO_PMAPMD_CTRL2_10G_CX4: | |
351 | /* All the other defined modes are flavours of optical */ | |
8ceee660 | 352 | default: |
8ceee660 BH |
353 | ecmd->port = PORT_FIBRE; |
354 | ecmd->supported = SUPPORTED_FIBRE; | |
355 | ecmd->advertising = ADVERTISED_FIBRE; | |
356 | break; | |
357 | } | |
04cc8cac BH |
358 | |
359 | if (efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) { | |
360 | ecmd->supported |= SUPPORTED_Autoneg; | |
361 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, | |
362 | MDIO_MMDREG_CTRL1); | |
363 | if (reg & BMCR_ANENABLE) { | |
364 | ecmd->autoneg = AUTONEG_ENABLE; | |
365 | ecmd->advertising |= | |
366 | ADVERTISED_Autoneg | | |
367 | mdio_clause45_get_an(efx, | |
368 | MDIO_AN_ADVERTISE, xnp); | |
369 | } else | |
370 | ecmd->autoneg = AUTONEG_DISABLE; | |
371 | } else | |
372 | ecmd->autoneg = AUTONEG_DISABLE; | |
373 | ||
84381345 BH |
374 | if (ecmd->autoneg) { |
375 | /* If AN is complete, report best common mode, | |
376 | * otherwise report best advertised mode. */ | |
377 | u32 common = ecmd->advertising; | |
378 | if (mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, | |
379 | MDIO_MMDREG_STAT1) & | |
380 | (1 << MDIO_AN_STATUS_AN_DONE_LBN)) { | |
381 | common &= mdio_clause45_get_an(efx, MDIO_AN_LPA, | |
382 | xnp_lpa); | |
383 | } | |
04cc8cac BH |
384 | if (common & ADVERTISED_10000baseT_Full) { |
385 | ecmd->speed = SPEED_10000; | |
386 | ecmd->duplex = DUPLEX_FULL; | |
387 | } else if (common & (ADVERTISED_1000baseT_Full | | |
388 | ADVERTISED_1000baseT_Half)) { | |
389 | ecmd->speed = SPEED_1000; | |
390 | ecmd->duplex = !!(common & ADVERTISED_1000baseT_Full); | |
391 | } else if (common & (ADVERTISED_100baseT_Full | | |
392 | ADVERTISED_100baseT_Half)) { | |
393 | ecmd->speed = SPEED_100; | |
394 | ecmd->duplex = !!(common & ADVERTISED_100baseT_Full); | |
395 | } else { | |
396 | ecmd->speed = SPEED_10; | |
397 | ecmd->duplex = !!(common & ADVERTISED_10baseT_Full); | |
398 | } | |
399 | } else { | |
400 | /* Report forced settings */ | |
401 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, | |
402 | MDIO_MMDREG_CTRL1); | |
403 | ecmd->speed = (((reg & BMCR_SPEED1000) ? 100 : 1) * | |
404 | ((reg & BMCR_SPEED100) ? 100 : 10)); | |
405 | ecmd->duplex = (reg & BMCR_FULLDPLX || | |
406 | ecmd->speed == SPEED_10000); | |
407 | } | |
8ceee660 BH |
408 | } |
409 | ||
410 | /** | |
411 | * mdio_clause45_set_settings - Set (some of) the PHY settings over MDIO. | |
412 | * @efx: Efx NIC | |
413 | * @ecmd: New settings | |
8ceee660 BH |
414 | */ |
415 | int mdio_clause45_set_settings(struct efx_nic *efx, | |
416 | struct ethtool_cmd *ecmd) | |
417 | { | |
04cc8cac BH |
418 | int phy_id = efx->mii.phy_id; |
419 | struct ethtool_cmd prev; | |
420 | u32 required; | |
421 | int ctrl1_bits, reg; | |
422 | ||
423 | efx->phy_op->get_settings(efx, &prev); | |
424 | ||
425 | if (ecmd->advertising == prev.advertising && | |
426 | ecmd->speed == prev.speed && | |
427 | ecmd->duplex == prev.duplex && | |
428 | ecmd->port == prev.port && | |
429 | ecmd->autoneg == prev.autoneg) | |
8ceee660 | 430 | return 0; |
04cc8cac BH |
431 | |
432 | /* We can only change these settings for -T PHYs */ | |
433 | if (prev.port != PORT_TP || ecmd->port != PORT_TP) | |
434 | return -EINVAL; | |
435 | ||
436 | /* Check that PHY supports these settings and work out the | |
437 | * basic control bits */ | |
438 | if (ecmd->duplex) { | |
439 | switch (ecmd->speed) { | |
440 | case SPEED_10: | |
441 | ctrl1_bits = BMCR_FULLDPLX; | |
442 | required = SUPPORTED_10baseT_Full; | |
443 | break; | |
444 | case SPEED_100: | |
445 | ctrl1_bits = BMCR_SPEED100 | BMCR_FULLDPLX; | |
446 | required = SUPPORTED_100baseT_Full; | |
447 | break; | |
448 | case SPEED_1000: | |
449 | ctrl1_bits = BMCR_SPEED1000 | BMCR_FULLDPLX; | |
450 | required = SUPPORTED_1000baseT_Full; | |
451 | break; | |
452 | case SPEED_10000: | |
453 | ctrl1_bits = (BMCR_SPEED1000 | BMCR_SPEED100 | | |
454 | BMCR_FULLDPLX); | |
455 | required = SUPPORTED_10000baseT_Full; | |
456 | break; | |
457 | default: | |
458 | return -EINVAL; | |
459 | } | |
460 | } else { | |
461 | switch (ecmd->speed) { | |
462 | case SPEED_10: | |
463 | ctrl1_bits = 0; | |
464 | required = SUPPORTED_10baseT_Half; | |
465 | break; | |
466 | case SPEED_100: | |
467 | ctrl1_bits = BMCR_SPEED100; | |
468 | required = SUPPORTED_100baseT_Half; | |
469 | break; | |
470 | case SPEED_1000: | |
471 | ctrl1_bits = BMCR_SPEED1000; | |
472 | required = SUPPORTED_1000baseT_Half; | |
473 | break; | |
474 | default: | |
475 | return -EINVAL; | |
476 | } | |
477 | } | |
478 | if (ecmd->autoneg) | |
479 | required |= SUPPORTED_Autoneg; | |
480 | required |= ecmd->advertising; | |
481 | if (required & ~prev.supported) | |
482 | return -EINVAL; | |
483 | ||
484 | /* Set the basic control bits */ | |
485 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, | |
486 | MDIO_MMDREG_CTRL1); | |
487 | reg &= ~(BMCR_SPEED1000 | BMCR_SPEED100 | BMCR_FULLDPLX | 0x003c); | |
488 | reg |= ctrl1_bits; | |
489 | mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, MDIO_MMDREG_CTRL1, | |
490 | reg); | |
491 | ||
492 | /* Set the AN registers */ | |
493 | if (ecmd->autoneg != prev.autoneg || | |
494 | ecmd->advertising != prev.advertising) { | |
495 | bool xnp = false; | |
496 | ||
497 | if (efx->phy_op->set_xnp_advertise) | |
498 | xnp = efx->phy_op->set_xnp_advertise(efx, | |
499 | ecmd->advertising); | |
500 | ||
501 | if (ecmd->autoneg) { | |
502 | reg = 0; | |
503 | if (ecmd->advertising & ADVERTISED_10baseT_Half) | |
504 | reg |= ADVERTISE_10HALF; | |
505 | if (ecmd->advertising & ADVERTISED_10baseT_Full) | |
506 | reg |= ADVERTISE_10FULL; | |
507 | if (ecmd->advertising & ADVERTISED_100baseT_Half) | |
508 | reg |= ADVERTISE_100HALF; | |
509 | if (ecmd->advertising & ADVERTISED_100baseT_Full) | |
510 | reg |= ADVERTISE_100FULL; | |
511 | if (xnp) | |
512 | reg |= ADVERTISE_RESV; | |
513 | mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, | |
514 | MDIO_AN_ADVERTISE, reg); | |
515 | } | |
516 | ||
517 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, | |
518 | MDIO_MMDREG_CTRL1); | |
519 | if (ecmd->autoneg) | |
520 | reg |= BMCR_ANENABLE | BMCR_ANRESTART; | |
521 | else | |
522 | reg &= ~BMCR_ANENABLE; | |
8b9dc8dd SH |
523 | if (EFX_WORKAROUND_15195(efx) |
524 | && LOOPBACK_MASK(efx) & efx->phy_op->loopbacks) | |
525 | reg &= ~BMCR_ANRESTART; | |
04cc8cac BH |
526 | if (xnp) |
527 | reg |= 1 << MDIO_AN_CTRL_XNP_LBN; | |
528 | else | |
529 | reg &= ~(1 << MDIO_AN_CTRL_XNP_LBN); | |
530 | mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, | |
531 | MDIO_MMDREG_CTRL1, reg); | |
532 | } | |
533 | ||
534 | return 0; | |
535 | } | |
536 | ||
537 | void mdio_clause45_set_pause(struct efx_nic *efx) | |
538 | { | |
539 | int phy_id = efx->mii.phy_id; | |
540 | int reg; | |
541 | ||
542 | if (efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) { | |
543 | /* Set pause capability advertising */ | |
544 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, | |
545 | MDIO_AN_ADVERTISE); | |
546 | reg &= ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); | |
547 | reg |= efx_fc_advertise(efx->wanted_fc); | |
548 | mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, | |
549 | MDIO_AN_ADVERTISE, reg); | |
550 | ||
551 | /* Restart auto-negotiation */ | |
552 | reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, | |
553 | MDIO_MMDREG_CTRL1); | |
554 | if (reg & BMCR_ANENABLE) { | |
555 | reg |= BMCR_ANRESTART; | |
556 | mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, | |
557 | MDIO_MMDREG_CTRL1, reg); | |
558 | } | |
559 | } | |
560 | } | |
561 | ||
562 | enum efx_fc_type mdio_clause45_get_pause(struct efx_nic *efx) | |
563 | { | |
564 | int phy_id = efx->mii.phy_id; | |
565 | int lpa; | |
566 | ||
567 | if (!(efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN))) | |
568 | return efx->wanted_fc; | |
569 | lpa = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, MDIO_AN_LPA); | |
570 | return efx_fc_resolve(efx->wanted_fc, lpa); | |
8ceee660 | 571 | } |
356eebb2 BH |
572 | |
573 | void mdio_clause45_set_flag(struct efx_nic *efx, u8 prt, u8 dev, | |
574 | u16 addr, int bit, bool sense) | |
575 | { | |
576 | int old_val = mdio_clause45_read(efx, prt, dev, addr); | |
577 | int new_val; | |
578 | ||
579 | if (sense) | |
580 | new_val = old_val | (1 << bit); | |
581 | else | |
582 | new_val = old_val & ~(1 << bit); | |
583 | if (old_val != new_val) | |
584 | mdio_clause45_write(efx, prt, dev, addr, new_val); | |
585 | } |