.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /**************************************************************************** |
---|
2 | 3 | * Driver for Solarflare network controllers and boards |
---|
3 | 4 | * Copyright 2009-2013 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 | 5 | */ |
---|
9 | 6 | |
---|
10 | 7 | /* |
---|
.. | .. |
---|
13 | 10 | |
---|
14 | 11 | #include <linux/slab.h> |
---|
15 | 12 | #include "efx.h" |
---|
| 13 | +#include "mcdi_port.h" |
---|
16 | 14 | #include "mcdi.h" |
---|
17 | 15 | #include "mcdi_pcol.h" |
---|
18 | 16 | #include "nic.h" |
---|
19 | 17 | #include "selftest.h" |
---|
20 | | - |
---|
21 | | -struct efx_mcdi_phy_data { |
---|
22 | | - u32 flags; |
---|
23 | | - u32 type; |
---|
24 | | - u32 supported_cap; |
---|
25 | | - u32 channel; |
---|
26 | | - u32 port; |
---|
27 | | - u32 stats_mask; |
---|
28 | | - u8 name[20]; |
---|
29 | | - u32 media; |
---|
30 | | - u32 mmd_mask; |
---|
31 | | - u8 revision[20]; |
---|
32 | | - u32 forced_cap; |
---|
33 | | -}; |
---|
34 | | - |
---|
35 | | -static int |
---|
36 | | -efx_mcdi_get_phy_cfg(struct efx_nic *efx, struct efx_mcdi_phy_data *cfg) |
---|
37 | | -{ |
---|
38 | | - MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_PHY_CFG_OUT_LEN); |
---|
39 | | - size_t outlen; |
---|
40 | | - int rc; |
---|
41 | | - |
---|
42 | | - BUILD_BUG_ON(MC_CMD_GET_PHY_CFG_IN_LEN != 0); |
---|
43 | | - BUILD_BUG_ON(MC_CMD_GET_PHY_CFG_OUT_NAME_LEN != sizeof(cfg->name)); |
---|
44 | | - |
---|
45 | | - rc = efx_mcdi_rpc(efx, MC_CMD_GET_PHY_CFG, NULL, 0, |
---|
46 | | - outbuf, sizeof(outbuf), &outlen); |
---|
47 | | - if (rc) |
---|
48 | | - goto fail; |
---|
49 | | - |
---|
50 | | - if (outlen < MC_CMD_GET_PHY_CFG_OUT_LEN) { |
---|
51 | | - rc = -EIO; |
---|
52 | | - goto fail; |
---|
53 | | - } |
---|
54 | | - |
---|
55 | | - cfg->flags = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_FLAGS); |
---|
56 | | - cfg->type = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_TYPE); |
---|
57 | | - cfg->supported_cap = |
---|
58 | | - MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_SUPPORTED_CAP); |
---|
59 | | - cfg->channel = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_CHANNEL); |
---|
60 | | - cfg->port = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_PRT); |
---|
61 | | - cfg->stats_mask = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_STATS_MASK); |
---|
62 | | - memcpy(cfg->name, MCDI_PTR(outbuf, GET_PHY_CFG_OUT_NAME), |
---|
63 | | - sizeof(cfg->name)); |
---|
64 | | - cfg->media = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_MEDIA_TYPE); |
---|
65 | | - cfg->mmd_mask = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_MMD_MASK); |
---|
66 | | - memcpy(cfg->revision, MCDI_PTR(outbuf, GET_PHY_CFG_OUT_REVISION), |
---|
67 | | - sizeof(cfg->revision)); |
---|
68 | | - |
---|
69 | | - return 0; |
---|
70 | | - |
---|
71 | | -fail: |
---|
72 | | - netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); |
---|
73 | | - return rc; |
---|
74 | | -} |
---|
75 | | - |
---|
76 | | -static int efx_mcdi_set_link(struct efx_nic *efx, u32 capabilities, |
---|
77 | | - u32 flags, u32 loopback_mode, |
---|
78 | | - u32 loopback_speed) |
---|
79 | | -{ |
---|
80 | | - MCDI_DECLARE_BUF(inbuf, MC_CMD_SET_LINK_IN_LEN); |
---|
81 | | - int rc; |
---|
82 | | - |
---|
83 | | - BUILD_BUG_ON(MC_CMD_SET_LINK_OUT_LEN != 0); |
---|
84 | | - |
---|
85 | | - MCDI_SET_DWORD(inbuf, SET_LINK_IN_CAP, capabilities); |
---|
86 | | - MCDI_SET_DWORD(inbuf, SET_LINK_IN_FLAGS, flags); |
---|
87 | | - MCDI_SET_DWORD(inbuf, SET_LINK_IN_LOOPBACK_MODE, loopback_mode); |
---|
88 | | - MCDI_SET_DWORD(inbuf, SET_LINK_IN_LOOPBACK_SPEED, loopback_speed); |
---|
89 | | - |
---|
90 | | - rc = efx_mcdi_rpc(efx, MC_CMD_SET_LINK, inbuf, sizeof(inbuf), |
---|
91 | | - NULL, 0, NULL); |
---|
92 | | - return rc; |
---|
93 | | -} |
---|
94 | | - |
---|
95 | | -static int efx_mcdi_loopback_modes(struct efx_nic *efx, u64 *loopback_modes) |
---|
96 | | -{ |
---|
97 | | - MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_LOOPBACK_MODES_OUT_LEN); |
---|
98 | | - size_t outlen; |
---|
99 | | - int rc; |
---|
100 | | - |
---|
101 | | - rc = efx_mcdi_rpc(efx, MC_CMD_GET_LOOPBACK_MODES, NULL, 0, |
---|
102 | | - outbuf, sizeof(outbuf), &outlen); |
---|
103 | | - if (rc) |
---|
104 | | - goto fail; |
---|
105 | | - |
---|
106 | | - if (outlen < (MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_OFST + |
---|
107 | | - MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_LEN)) { |
---|
108 | | - rc = -EIO; |
---|
109 | | - goto fail; |
---|
110 | | - } |
---|
111 | | - |
---|
112 | | - *loopback_modes = MCDI_QWORD(outbuf, GET_LOOPBACK_MODES_OUT_SUGGESTED); |
---|
113 | | - |
---|
114 | | - return 0; |
---|
115 | | - |
---|
116 | | -fail: |
---|
117 | | - netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); |
---|
118 | | - return rc; |
---|
119 | | -} |
---|
| 18 | +#include "mcdi_port_common.h" |
---|
120 | 19 | |
---|
121 | 20 | static int efx_mcdi_mdio_read(struct net_device *net_dev, |
---|
122 | 21 | int prtad, int devad, u16 addr) |
---|
.. | .. |
---|
171 | 70 | return 0; |
---|
172 | 71 | } |
---|
173 | 72 | |
---|
174 | | -static void mcdi_to_ethtool_linkset(u32 media, u32 cap, unsigned long *linkset) |
---|
175 | | -{ |
---|
176 | | - #define SET_BIT(name) __set_bit(ETHTOOL_LINK_MODE_ ## name ## _BIT, \ |
---|
177 | | - linkset) |
---|
178 | | - |
---|
179 | | - bitmap_zero(linkset, __ETHTOOL_LINK_MODE_MASK_NBITS); |
---|
180 | | - switch (media) { |
---|
181 | | - case MC_CMD_MEDIA_KX4: |
---|
182 | | - SET_BIT(Backplane); |
---|
183 | | - if (cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN)) |
---|
184 | | - SET_BIT(1000baseKX_Full); |
---|
185 | | - if (cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN)) |
---|
186 | | - SET_BIT(10000baseKX4_Full); |
---|
187 | | - if (cap & (1 << MC_CMD_PHY_CAP_40000FDX_LBN)) |
---|
188 | | - SET_BIT(40000baseKR4_Full); |
---|
189 | | - break; |
---|
190 | | - |
---|
191 | | - case MC_CMD_MEDIA_XFP: |
---|
192 | | - case MC_CMD_MEDIA_SFP_PLUS: |
---|
193 | | - case MC_CMD_MEDIA_QSFP_PLUS: |
---|
194 | | - SET_BIT(FIBRE); |
---|
195 | | - if (cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN)) |
---|
196 | | - SET_BIT(1000baseT_Full); |
---|
197 | | - if (cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN)) |
---|
198 | | - SET_BIT(10000baseT_Full); |
---|
199 | | - if (cap & (1 << MC_CMD_PHY_CAP_40000FDX_LBN)) |
---|
200 | | - SET_BIT(40000baseCR4_Full); |
---|
201 | | - if (cap & (1 << MC_CMD_PHY_CAP_100000FDX_LBN)) |
---|
202 | | - SET_BIT(100000baseCR4_Full); |
---|
203 | | - if (cap & (1 << MC_CMD_PHY_CAP_25000FDX_LBN)) |
---|
204 | | - SET_BIT(25000baseCR_Full); |
---|
205 | | - if (cap & (1 << MC_CMD_PHY_CAP_50000FDX_LBN)) |
---|
206 | | - SET_BIT(50000baseCR2_Full); |
---|
207 | | - break; |
---|
208 | | - |
---|
209 | | - case MC_CMD_MEDIA_BASE_T: |
---|
210 | | - SET_BIT(TP); |
---|
211 | | - if (cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN)) |
---|
212 | | - SET_BIT(10baseT_Half); |
---|
213 | | - if (cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN)) |
---|
214 | | - SET_BIT(10baseT_Full); |
---|
215 | | - if (cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN)) |
---|
216 | | - SET_BIT(100baseT_Half); |
---|
217 | | - if (cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN)) |
---|
218 | | - SET_BIT(100baseT_Full); |
---|
219 | | - if (cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN)) |
---|
220 | | - SET_BIT(1000baseT_Half); |
---|
221 | | - if (cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN)) |
---|
222 | | - SET_BIT(1000baseT_Full); |
---|
223 | | - if (cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN)) |
---|
224 | | - SET_BIT(10000baseT_Full); |
---|
225 | | - break; |
---|
226 | | - } |
---|
227 | | - |
---|
228 | | - if (cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN)) |
---|
229 | | - SET_BIT(Pause); |
---|
230 | | - if (cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN)) |
---|
231 | | - SET_BIT(Asym_Pause); |
---|
232 | | - if (cap & (1 << MC_CMD_PHY_CAP_AN_LBN)) |
---|
233 | | - SET_BIT(Autoneg); |
---|
234 | | - |
---|
235 | | - #undef SET_BIT |
---|
236 | | -} |
---|
237 | | - |
---|
238 | | -static u32 ethtool_linkset_to_mcdi_cap(const unsigned long *linkset) |
---|
239 | | -{ |
---|
240 | | - u32 result = 0; |
---|
241 | | - |
---|
242 | | - #define TEST_BIT(name) test_bit(ETHTOOL_LINK_MODE_ ## name ## _BIT, \ |
---|
243 | | - linkset) |
---|
244 | | - |
---|
245 | | - if (TEST_BIT(10baseT_Half)) |
---|
246 | | - result |= (1 << MC_CMD_PHY_CAP_10HDX_LBN); |
---|
247 | | - if (TEST_BIT(10baseT_Full)) |
---|
248 | | - result |= (1 << MC_CMD_PHY_CAP_10FDX_LBN); |
---|
249 | | - if (TEST_BIT(100baseT_Half)) |
---|
250 | | - result |= (1 << MC_CMD_PHY_CAP_100HDX_LBN); |
---|
251 | | - if (TEST_BIT(100baseT_Full)) |
---|
252 | | - result |= (1 << MC_CMD_PHY_CAP_100FDX_LBN); |
---|
253 | | - if (TEST_BIT(1000baseT_Half)) |
---|
254 | | - result |= (1 << MC_CMD_PHY_CAP_1000HDX_LBN); |
---|
255 | | - if (TEST_BIT(1000baseT_Full) || TEST_BIT(1000baseKX_Full)) |
---|
256 | | - result |= (1 << MC_CMD_PHY_CAP_1000FDX_LBN); |
---|
257 | | - if (TEST_BIT(10000baseT_Full) || TEST_BIT(10000baseKX4_Full)) |
---|
258 | | - result |= (1 << MC_CMD_PHY_CAP_10000FDX_LBN); |
---|
259 | | - if (TEST_BIT(40000baseCR4_Full) || TEST_BIT(40000baseKR4_Full)) |
---|
260 | | - result |= (1 << MC_CMD_PHY_CAP_40000FDX_LBN); |
---|
261 | | - if (TEST_BIT(100000baseCR4_Full)) |
---|
262 | | - result |= (1 << MC_CMD_PHY_CAP_100000FDX_LBN); |
---|
263 | | - if (TEST_BIT(25000baseCR_Full)) |
---|
264 | | - result |= (1 << MC_CMD_PHY_CAP_25000FDX_LBN); |
---|
265 | | - if (TEST_BIT(50000baseCR2_Full)) |
---|
266 | | - result |= (1 << MC_CMD_PHY_CAP_50000FDX_LBN); |
---|
267 | | - if (TEST_BIT(Pause)) |
---|
268 | | - result |= (1 << MC_CMD_PHY_CAP_PAUSE_LBN); |
---|
269 | | - if (TEST_BIT(Asym_Pause)) |
---|
270 | | - result |= (1 << MC_CMD_PHY_CAP_ASYM_LBN); |
---|
271 | | - if (TEST_BIT(Autoneg)) |
---|
272 | | - result |= (1 << MC_CMD_PHY_CAP_AN_LBN); |
---|
273 | | - |
---|
274 | | - #undef TEST_BIT |
---|
275 | | - |
---|
276 | | - return result; |
---|
277 | | -} |
---|
278 | | - |
---|
279 | | -static u32 efx_get_mcdi_phy_flags(struct efx_nic *efx) |
---|
280 | | -{ |
---|
281 | | - struct efx_mcdi_phy_data *phy_cfg = efx->phy_data; |
---|
282 | | - enum efx_phy_mode mode, supported; |
---|
283 | | - u32 flags; |
---|
284 | | - |
---|
285 | | - /* TODO: Advertise the capabilities supported by this PHY */ |
---|
286 | | - supported = 0; |
---|
287 | | - if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_OUT_TXDIS_LBN)) |
---|
288 | | - supported |= PHY_MODE_TX_DISABLED; |
---|
289 | | - if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_OUT_LOWPOWER_LBN)) |
---|
290 | | - supported |= PHY_MODE_LOW_POWER; |
---|
291 | | - if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_OUT_POWEROFF_LBN)) |
---|
292 | | - supported |= PHY_MODE_OFF; |
---|
293 | | - |
---|
294 | | - mode = efx->phy_mode & supported; |
---|
295 | | - |
---|
296 | | - flags = 0; |
---|
297 | | - if (mode & PHY_MODE_TX_DISABLED) |
---|
298 | | - flags |= (1 << MC_CMD_SET_LINK_IN_TXDIS_LBN); |
---|
299 | | - if (mode & PHY_MODE_LOW_POWER) |
---|
300 | | - flags |= (1 << MC_CMD_SET_LINK_IN_LOWPOWER_LBN); |
---|
301 | | - if (mode & PHY_MODE_OFF) |
---|
302 | | - flags |= (1 << MC_CMD_SET_LINK_IN_POWEROFF_LBN); |
---|
303 | | - |
---|
304 | | - return flags; |
---|
305 | | -} |
---|
306 | | - |
---|
307 | | -static u8 mcdi_to_ethtool_media(u32 media) |
---|
308 | | -{ |
---|
309 | | - switch (media) { |
---|
310 | | - case MC_CMD_MEDIA_XAUI: |
---|
311 | | - case MC_CMD_MEDIA_CX4: |
---|
312 | | - case MC_CMD_MEDIA_KX4: |
---|
313 | | - return PORT_OTHER; |
---|
314 | | - |
---|
315 | | - case MC_CMD_MEDIA_XFP: |
---|
316 | | - case MC_CMD_MEDIA_SFP_PLUS: |
---|
317 | | - case MC_CMD_MEDIA_QSFP_PLUS: |
---|
318 | | - return PORT_FIBRE; |
---|
319 | | - |
---|
320 | | - case MC_CMD_MEDIA_BASE_T: |
---|
321 | | - return PORT_TP; |
---|
322 | | - |
---|
323 | | - default: |
---|
324 | | - return PORT_OTHER; |
---|
325 | | - } |
---|
326 | | -} |
---|
327 | | - |
---|
328 | | -static void efx_mcdi_phy_decode_link(struct efx_nic *efx, |
---|
329 | | - struct efx_link_state *link_state, |
---|
330 | | - u32 speed, u32 flags, u32 fcntl) |
---|
331 | | -{ |
---|
332 | | - switch (fcntl) { |
---|
333 | | - case MC_CMD_FCNTL_AUTO: |
---|
334 | | - WARN_ON(1); /* This is not a link mode */ |
---|
335 | | - link_state->fc = EFX_FC_AUTO | EFX_FC_TX | EFX_FC_RX; |
---|
336 | | - break; |
---|
337 | | - case MC_CMD_FCNTL_BIDIR: |
---|
338 | | - link_state->fc = EFX_FC_TX | EFX_FC_RX; |
---|
339 | | - break; |
---|
340 | | - case MC_CMD_FCNTL_RESPOND: |
---|
341 | | - link_state->fc = EFX_FC_RX; |
---|
342 | | - break; |
---|
343 | | - default: |
---|
344 | | - WARN_ON(1); |
---|
345 | | - case MC_CMD_FCNTL_OFF: |
---|
346 | | - link_state->fc = 0; |
---|
347 | | - break; |
---|
348 | | - } |
---|
349 | | - |
---|
350 | | - link_state->up = !!(flags & (1 << MC_CMD_GET_LINK_OUT_LINK_UP_LBN)); |
---|
351 | | - link_state->fd = !!(flags & (1 << MC_CMD_GET_LINK_OUT_FULL_DUPLEX_LBN)); |
---|
352 | | - link_state->speed = speed; |
---|
353 | | -} |
---|
354 | | - |
---|
355 | | -/* The semantics of the ethtool FEC mode bitmask are not well defined, |
---|
356 | | - * particularly the meaning of combinations of bits. Which means we get to |
---|
357 | | - * define our own semantics, as follows: |
---|
358 | | - * OFF overrides any other bits, and means "disable all FEC" (with the |
---|
359 | | - * exception of 25G KR4/CR4, where it is not possible to reject it if AN |
---|
360 | | - * partner requests it). |
---|
361 | | - * AUTO on its own means use cable requirements and link partner autoneg with |
---|
362 | | - * fw-default preferences for the cable type. |
---|
363 | | - * AUTO and either RS or BASER means use the specified FEC type if cable and |
---|
364 | | - * link partner support it, otherwise autoneg/fw-default. |
---|
365 | | - * RS or BASER alone means use the specified FEC type if cable and link partner |
---|
366 | | - * support it and either requests it, otherwise no FEC. |
---|
367 | | - * Both RS and BASER (whether AUTO or not) means use FEC if cable and link |
---|
368 | | - * partner support it, preferring RS to BASER. |
---|
369 | | - */ |
---|
370 | | -static u32 ethtool_fec_caps_to_mcdi(u32 ethtool_cap) |
---|
371 | | -{ |
---|
372 | | - u32 ret = 0; |
---|
373 | | - |
---|
374 | | - if (ethtool_cap & ETHTOOL_FEC_OFF) |
---|
375 | | - return 0; |
---|
376 | | - |
---|
377 | | - if (ethtool_cap & ETHTOOL_FEC_AUTO) |
---|
378 | | - ret |= (1 << MC_CMD_PHY_CAP_BASER_FEC_LBN) | |
---|
379 | | - (1 << MC_CMD_PHY_CAP_25G_BASER_FEC_LBN) | |
---|
380 | | - (1 << MC_CMD_PHY_CAP_RS_FEC_LBN); |
---|
381 | | - if (ethtool_cap & ETHTOOL_FEC_RS) |
---|
382 | | - ret |= (1 << MC_CMD_PHY_CAP_RS_FEC_LBN) | |
---|
383 | | - (1 << MC_CMD_PHY_CAP_RS_FEC_REQUESTED_LBN); |
---|
384 | | - if (ethtool_cap & ETHTOOL_FEC_BASER) |
---|
385 | | - ret |= (1 << MC_CMD_PHY_CAP_BASER_FEC_LBN) | |
---|
386 | | - (1 << MC_CMD_PHY_CAP_25G_BASER_FEC_LBN) | |
---|
387 | | - (1 << MC_CMD_PHY_CAP_BASER_FEC_REQUESTED_LBN) | |
---|
388 | | - (1 << MC_CMD_PHY_CAP_25G_BASER_FEC_REQUESTED_LBN); |
---|
389 | | - return ret; |
---|
390 | | -} |
---|
391 | | - |
---|
392 | | -/* Invert ethtool_fec_caps_to_mcdi. There are two combinations that function |
---|
393 | | - * can never produce, (baser xor rs) and neither req; the implementation below |
---|
394 | | - * maps both of those to AUTO. This should never matter, and it's not clear |
---|
395 | | - * what a better mapping would be anyway. |
---|
396 | | - */ |
---|
397 | | -static u32 mcdi_fec_caps_to_ethtool(u32 caps, bool is_25g) |
---|
398 | | -{ |
---|
399 | | - bool rs = caps & (1 << MC_CMD_PHY_CAP_RS_FEC_LBN), |
---|
400 | | - rs_req = caps & (1 << MC_CMD_PHY_CAP_RS_FEC_REQUESTED_LBN), |
---|
401 | | - baser = is_25g ? caps & (1 << MC_CMD_PHY_CAP_25G_BASER_FEC_LBN) |
---|
402 | | - : caps & (1 << MC_CMD_PHY_CAP_BASER_FEC_LBN), |
---|
403 | | - baser_req = is_25g ? caps & (1 << MC_CMD_PHY_CAP_25G_BASER_FEC_REQUESTED_LBN) |
---|
404 | | - : caps & (1 << MC_CMD_PHY_CAP_BASER_FEC_REQUESTED_LBN); |
---|
405 | | - |
---|
406 | | - if (!baser && !rs) |
---|
407 | | - return ETHTOOL_FEC_OFF; |
---|
408 | | - return (rs_req ? ETHTOOL_FEC_RS : 0) | |
---|
409 | | - (baser_req ? ETHTOOL_FEC_BASER : 0) | |
---|
410 | | - (baser == baser_req && rs == rs_req ? 0 : ETHTOOL_FEC_AUTO); |
---|
411 | | -} |
---|
412 | | - |
---|
413 | | -static int efx_mcdi_phy_probe(struct efx_nic *efx) |
---|
414 | | -{ |
---|
415 | | - struct efx_mcdi_phy_data *phy_data; |
---|
416 | | - MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_LINK_OUT_LEN); |
---|
417 | | - u32 caps; |
---|
418 | | - int rc; |
---|
419 | | - |
---|
420 | | - /* Initialise and populate phy_data */ |
---|
421 | | - phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL); |
---|
422 | | - if (phy_data == NULL) |
---|
423 | | - return -ENOMEM; |
---|
424 | | - |
---|
425 | | - rc = efx_mcdi_get_phy_cfg(efx, phy_data); |
---|
426 | | - if (rc != 0) |
---|
427 | | - goto fail; |
---|
428 | | - |
---|
429 | | - /* Read initial link advertisement */ |
---|
430 | | - BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); |
---|
431 | | - rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, |
---|
432 | | - outbuf, sizeof(outbuf), NULL); |
---|
433 | | - if (rc) |
---|
434 | | - goto fail; |
---|
435 | | - |
---|
436 | | - /* Fill out nic state */ |
---|
437 | | - efx->phy_data = phy_data; |
---|
438 | | - efx->phy_type = phy_data->type; |
---|
439 | | - |
---|
440 | | - efx->mdio_bus = phy_data->channel; |
---|
441 | | - efx->mdio.prtad = phy_data->port; |
---|
442 | | - efx->mdio.mmds = phy_data->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22); |
---|
443 | | - efx->mdio.mode_support = 0; |
---|
444 | | - if (phy_data->mmd_mask & (1 << MC_CMD_MMD_CLAUSE22)) |
---|
445 | | - efx->mdio.mode_support |= MDIO_SUPPORTS_C22; |
---|
446 | | - if (phy_data->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22)) |
---|
447 | | - efx->mdio.mode_support |= MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; |
---|
448 | | - |
---|
449 | | - caps = MCDI_DWORD(outbuf, GET_LINK_OUT_CAP); |
---|
450 | | - if (caps & (1 << MC_CMD_PHY_CAP_AN_LBN)) |
---|
451 | | - mcdi_to_ethtool_linkset(phy_data->media, caps, |
---|
452 | | - efx->link_advertising); |
---|
453 | | - else |
---|
454 | | - phy_data->forced_cap = caps; |
---|
455 | | - |
---|
456 | | - /* Assert that we can map efx -> mcdi loopback modes */ |
---|
457 | | - BUILD_BUG_ON(LOOPBACK_NONE != MC_CMD_LOOPBACK_NONE); |
---|
458 | | - BUILD_BUG_ON(LOOPBACK_DATA != MC_CMD_LOOPBACK_DATA); |
---|
459 | | - BUILD_BUG_ON(LOOPBACK_GMAC != MC_CMD_LOOPBACK_GMAC); |
---|
460 | | - BUILD_BUG_ON(LOOPBACK_XGMII != MC_CMD_LOOPBACK_XGMII); |
---|
461 | | - BUILD_BUG_ON(LOOPBACK_XGXS != MC_CMD_LOOPBACK_XGXS); |
---|
462 | | - BUILD_BUG_ON(LOOPBACK_XAUI != MC_CMD_LOOPBACK_XAUI); |
---|
463 | | - BUILD_BUG_ON(LOOPBACK_GMII != MC_CMD_LOOPBACK_GMII); |
---|
464 | | - BUILD_BUG_ON(LOOPBACK_SGMII != MC_CMD_LOOPBACK_SGMII); |
---|
465 | | - BUILD_BUG_ON(LOOPBACK_XGBR != MC_CMD_LOOPBACK_XGBR); |
---|
466 | | - BUILD_BUG_ON(LOOPBACK_XFI != MC_CMD_LOOPBACK_XFI); |
---|
467 | | - BUILD_BUG_ON(LOOPBACK_XAUI_FAR != MC_CMD_LOOPBACK_XAUI_FAR); |
---|
468 | | - BUILD_BUG_ON(LOOPBACK_GMII_FAR != MC_CMD_LOOPBACK_GMII_FAR); |
---|
469 | | - BUILD_BUG_ON(LOOPBACK_SGMII_FAR != MC_CMD_LOOPBACK_SGMII_FAR); |
---|
470 | | - BUILD_BUG_ON(LOOPBACK_XFI_FAR != MC_CMD_LOOPBACK_XFI_FAR); |
---|
471 | | - BUILD_BUG_ON(LOOPBACK_GPHY != MC_CMD_LOOPBACK_GPHY); |
---|
472 | | - BUILD_BUG_ON(LOOPBACK_PHYXS != MC_CMD_LOOPBACK_PHYXS); |
---|
473 | | - BUILD_BUG_ON(LOOPBACK_PCS != MC_CMD_LOOPBACK_PCS); |
---|
474 | | - BUILD_BUG_ON(LOOPBACK_PMAPMD != MC_CMD_LOOPBACK_PMAPMD); |
---|
475 | | - BUILD_BUG_ON(LOOPBACK_XPORT != MC_CMD_LOOPBACK_XPORT); |
---|
476 | | - BUILD_BUG_ON(LOOPBACK_XGMII_WS != MC_CMD_LOOPBACK_XGMII_WS); |
---|
477 | | - BUILD_BUG_ON(LOOPBACK_XAUI_WS != MC_CMD_LOOPBACK_XAUI_WS); |
---|
478 | | - BUILD_BUG_ON(LOOPBACK_XAUI_WS_FAR != MC_CMD_LOOPBACK_XAUI_WS_FAR); |
---|
479 | | - BUILD_BUG_ON(LOOPBACK_XAUI_WS_NEAR != MC_CMD_LOOPBACK_XAUI_WS_NEAR); |
---|
480 | | - BUILD_BUG_ON(LOOPBACK_GMII_WS != MC_CMD_LOOPBACK_GMII_WS); |
---|
481 | | - BUILD_BUG_ON(LOOPBACK_XFI_WS != MC_CMD_LOOPBACK_XFI_WS); |
---|
482 | | - BUILD_BUG_ON(LOOPBACK_XFI_WS_FAR != MC_CMD_LOOPBACK_XFI_WS_FAR); |
---|
483 | | - BUILD_BUG_ON(LOOPBACK_PHYXS_WS != MC_CMD_LOOPBACK_PHYXS_WS); |
---|
484 | | - |
---|
485 | | - rc = efx_mcdi_loopback_modes(efx, &efx->loopback_modes); |
---|
486 | | - if (rc != 0) |
---|
487 | | - goto fail; |
---|
488 | | - /* The MC indicates that LOOPBACK_NONE is a valid loopback mode, |
---|
489 | | - * but by convention we don't */ |
---|
490 | | - efx->loopback_modes &= ~(1 << LOOPBACK_NONE); |
---|
491 | | - |
---|
492 | | - /* Set the initial link mode */ |
---|
493 | | - efx_mcdi_phy_decode_link( |
---|
494 | | - efx, &efx->link_state, |
---|
495 | | - MCDI_DWORD(outbuf, GET_LINK_OUT_LINK_SPEED), |
---|
496 | | - MCDI_DWORD(outbuf, GET_LINK_OUT_FLAGS), |
---|
497 | | - MCDI_DWORD(outbuf, GET_LINK_OUT_FCNTL)); |
---|
498 | | - |
---|
499 | | - /* Record the initial FEC configuration (or nearest approximation |
---|
500 | | - * representable in the ethtool configuration space) |
---|
501 | | - */ |
---|
502 | | - efx->fec_config = mcdi_fec_caps_to_ethtool(caps, |
---|
503 | | - efx->link_state.speed == 25000 || |
---|
504 | | - efx->link_state.speed == 50000); |
---|
505 | | - |
---|
506 | | - /* Default to Autonegotiated flow control if the PHY supports it */ |
---|
507 | | - efx->wanted_fc = EFX_FC_RX | EFX_FC_TX; |
---|
508 | | - if (phy_data->supported_cap & (1 << MC_CMD_PHY_CAP_AN_LBN)) |
---|
509 | | - efx->wanted_fc |= EFX_FC_AUTO; |
---|
510 | | - efx_link_set_wanted_fc(efx, efx->wanted_fc); |
---|
511 | | - |
---|
512 | | - return 0; |
---|
513 | | - |
---|
514 | | -fail: |
---|
515 | | - kfree(phy_data); |
---|
516 | | - return rc; |
---|
517 | | -} |
---|
518 | | - |
---|
519 | | -int efx_mcdi_port_reconfigure(struct efx_nic *efx) |
---|
520 | | -{ |
---|
521 | | - struct efx_mcdi_phy_data *phy_cfg = efx->phy_data; |
---|
522 | | - u32 caps = (efx->link_advertising[0] ? |
---|
523 | | - ethtool_linkset_to_mcdi_cap(efx->link_advertising) : |
---|
524 | | - phy_cfg->forced_cap); |
---|
525 | | - |
---|
526 | | - caps |= ethtool_fec_caps_to_mcdi(efx->fec_config); |
---|
527 | | - |
---|
528 | | - return efx_mcdi_set_link(efx, caps, efx_get_mcdi_phy_flags(efx), |
---|
529 | | - efx->loopback_mode, 0); |
---|
530 | | -} |
---|
531 | | - |
---|
532 | | -/* Verify that the forced flow control settings (!EFX_FC_AUTO) are |
---|
533 | | - * supported by the link partner. Warn the user if this isn't the case |
---|
534 | | - */ |
---|
535 | | -static void efx_mcdi_phy_check_fcntl(struct efx_nic *efx, u32 lpa) |
---|
536 | | -{ |
---|
537 | | - struct efx_mcdi_phy_data *phy_cfg = efx->phy_data; |
---|
538 | | - u32 rmtadv; |
---|
539 | | - |
---|
540 | | - /* The link partner capabilities are only relevant if the |
---|
541 | | - * link supports flow control autonegotiation */ |
---|
542 | | - if (~phy_cfg->supported_cap & (1 << MC_CMD_PHY_CAP_AN_LBN)) |
---|
543 | | - return; |
---|
544 | | - |
---|
545 | | - /* If flow control autoneg is supported and enabled, then fine */ |
---|
546 | | - if (efx->wanted_fc & EFX_FC_AUTO) |
---|
547 | | - return; |
---|
548 | | - |
---|
549 | | - rmtadv = 0; |
---|
550 | | - if (lpa & (1 << MC_CMD_PHY_CAP_PAUSE_LBN)) |
---|
551 | | - rmtadv |= ADVERTISED_Pause; |
---|
552 | | - if (lpa & (1 << MC_CMD_PHY_CAP_ASYM_LBN)) |
---|
553 | | - rmtadv |= ADVERTISED_Asym_Pause; |
---|
554 | | - |
---|
555 | | - if ((efx->wanted_fc & EFX_FC_TX) && rmtadv == ADVERTISED_Asym_Pause) |
---|
556 | | - netif_err(efx, link, efx->net_dev, |
---|
557 | | - "warning: link partner doesn't support pause frames"); |
---|
558 | | -} |
---|
559 | | - |
---|
560 | | -static bool efx_mcdi_phy_poll(struct efx_nic *efx) |
---|
561 | | -{ |
---|
562 | | - struct efx_link_state old_state = efx->link_state; |
---|
563 | | - MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_LINK_OUT_LEN); |
---|
564 | | - int rc; |
---|
565 | | - |
---|
566 | | - WARN_ON(!mutex_is_locked(&efx->mac_lock)); |
---|
567 | | - |
---|
568 | | - BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); |
---|
569 | | - |
---|
570 | | - rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, |
---|
571 | | - outbuf, sizeof(outbuf), NULL); |
---|
572 | | - if (rc) |
---|
573 | | - efx->link_state.up = false; |
---|
574 | | - else |
---|
575 | | - efx_mcdi_phy_decode_link( |
---|
576 | | - efx, &efx->link_state, |
---|
577 | | - MCDI_DWORD(outbuf, GET_LINK_OUT_LINK_SPEED), |
---|
578 | | - MCDI_DWORD(outbuf, GET_LINK_OUT_FLAGS), |
---|
579 | | - MCDI_DWORD(outbuf, GET_LINK_OUT_FCNTL)); |
---|
580 | | - |
---|
581 | | - return !efx_link_state_equal(&efx->link_state, &old_state); |
---|
582 | | -} |
---|
583 | | - |
---|
584 | | -static void efx_mcdi_phy_remove(struct efx_nic *efx) |
---|
585 | | -{ |
---|
586 | | - struct efx_mcdi_phy_data *phy_data = efx->phy_data; |
---|
587 | | - |
---|
588 | | - efx->phy_data = NULL; |
---|
589 | | - kfree(phy_data); |
---|
590 | | -} |
---|
591 | | - |
---|
592 | | -static void efx_mcdi_phy_get_link_ksettings(struct efx_nic *efx, |
---|
593 | | - struct ethtool_link_ksettings *cmd) |
---|
594 | | -{ |
---|
595 | | - struct efx_mcdi_phy_data *phy_cfg = efx->phy_data; |
---|
596 | | - MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_LINK_OUT_LEN); |
---|
597 | | - int rc; |
---|
598 | | - |
---|
599 | | - cmd->base.speed = efx->link_state.speed; |
---|
600 | | - cmd->base.duplex = efx->link_state.fd; |
---|
601 | | - cmd->base.port = mcdi_to_ethtool_media(phy_cfg->media); |
---|
602 | | - cmd->base.phy_address = phy_cfg->port; |
---|
603 | | - cmd->base.autoneg = !!(efx->link_advertising[0] & ADVERTISED_Autoneg); |
---|
604 | | - cmd->base.mdio_support = (efx->mdio.mode_support & |
---|
605 | | - (MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22)); |
---|
606 | | - |
---|
607 | | - mcdi_to_ethtool_linkset(phy_cfg->media, phy_cfg->supported_cap, |
---|
608 | | - cmd->link_modes.supported); |
---|
609 | | - memcpy(cmd->link_modes.advertising, efx->link_advertising, |
---|
610 | | - sizeof(__ETHTOOL_DECLARE_LINK_MODE_MASK())); |
---|
611 | | - |
---|
612 | | - BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); |
---|
613 | | - rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, |
---|
614 | | - outbuf, sizeof(outbuf), NULL); |
---|
615 | | - if (rc) |
---|
616 | | - return; |
---|
617 | | - mcdi_to_ethtool_linkset(phy_cfg->media, |
---|
618 | | - MCDI_DWORD(outbuf, GET_LINK_OUT_LP_CAP), |
---|
619 | | - cmd->link_modes.lp_advertising); |
---|
620 | | -} |
---|
621 | | - |
---|
622 | | -static int |
---|
623 | | -efx_mcdi_phy_set_link_ksettings(struct efx_nic *efx, |
---|
624 | | - const struct ethtool_link_ksettings *cmd) |
---|
625 | | -{ |
---|
626 | | - struct efx_mcdi_phy_data *phy_cfg = efx->phy_data; |
---|
627 | | - u32 caps; |
---|
628 | | - int rc; |
---|
629 | | - |
---|
630 | | - if (cmd->base.autoneg) { |
---|
631 | | - caps = (ethtool_linkset_to_mcdi_cap(cmd->link_modes.advertising) | |
---|
632 | | - 1 << MC_CMD_PHY_CAP_AN_LBN); |
---|
633 | | - } else if (cmd->base.duplex) { |
---|
634 | | - switch (cmd->base.speed) { |
---|
635 | | - case 10: caps = 1 << MC_CMD_PHY_CAP_10FDX_LBN; break; |
---|
636 | | - case 100: caps = 1 << MC_CMD_PHY_CAP_100FDX_LBN; break; |
---|
637 | | - case 1000: caps = 1 << MC_CMD_PHY_CAP_1000FDX_LBN; break; |
---|
638 | | - case 10000: caps = 1 << MC_CMD_PHY_CAP_10000FDX_LBN; break; |
---|
639 | | - case 40000: caps = 1 << MC_CMD_PHY_CAP_40000FDX_LBN; break; |
---|
640 | | - case 100000: caps = 1 << MC_CMD_PHY_CAP_100000FDX_LBN; break; |
---|
641 | | - case 25000: caps = 1 << MC_CMD_PHY_CAP_25000FDX_LBN; break; |
---|
642 | | - case 50000: caps = 1 << MC_CMD_PHY_CAP_50000FDX_LBN; break; |
---|
643 | | - default: return -EINVAL; |
---|
644 | | - } |
---|
645 | | - } else { |
---|
646 | | - switch (cmd->base.speed) { |
---|
647 | | - case 10: caps = 1 << MC_CMD_PHY_CAP_10HDX_LBN; break; |
---|
648 | | - case 100: caps = 1 << MC_CMD_PHY_CAP_100HDX_LBN; break; |
---|
649 | | - case 1000: caps = 1 << MC_CMD_PHY_CAP_1000HDX_LBN; break; |
---|
650 | | - default: return -EINVAL; |
---|
651 | | - } |
---|
652 | | - } |
---|
653 | | - |
---|
654 | | - caps |= ethtool_fec_caps_to_mcdi(efx->fec_config); |
---|
655 | | - |
---|
656 | | - rc = efx_mcdi_set_link(efx, caps, efx_get_mcdi_phy_flags(efx), |
---|
657 | | - efx->loopback_mode, 0); |
---|
658 | | - if (rc) |
---|
659 | | - return rc; |
---|
660 | | - |
---|
661 | | - if (cmd->base.autoneg) { |
---|
662 | | - efx_link_set_advertising(efx, cmd->link_modes.advertising); |
---|
663 | | - phy_cfg->forced_cap = 0; |
---|
664 | | - } else { |
---|
665 | | - efx_link_clear_advertising(efx); |
---|
666 | | - phy_cfg->forced_cap = caps; |
---|
667 | | - } |
---|
668 | | - return 0; |
---|
669 | | -} |
---|
670 | | - |
---|
671 | | -static int efx_mcdi_phy_get_fecparam(struct efx_nic *efx, |
---|
672 | | - struct ethtool_fecparam *fec) |
---|
673 | | -{ |
---|
674 | | - MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_LINK_OUT_V2_LEN); |
---|
675 | | - u32 caps, active, speed; /* MCDI format */ |
---|
676 | | - bool is_25g = false; |
---|
677 | | - size_t outlen; |
---|
678 | | - int rc; |
---|
679 | | - |
---|
680 | | - BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); |
---|
681 | | - rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, |
---|
682 | | - outbuf, sizeof(outbuf), &outlen); |
---|
683 | | - if (rc) |
---|
684 | | - return rc; |
---|
685 | | - if (outlen < MC_CMD_GET_LINK_OUT_V2_LEN) |
---|
686 | | - return -EOPNOTSUPP; |
---|
687 | | - |
---|
688 | | - /* behaviour for 25G/50G links depends on 25G BASER bit */ |
---|
689 | | - speed = MCDI_DWORD(outbuf, GET_LINK_OUT_V2_LINK_SPEED); |
---|
690 | | - is_25g = speed == 25000 || speed == 50000; |
---|
691 | | - |
---|
692 | | - caps = MCDI_DWORD(outbuf, GET_LINK_OUT_V2_CAP); |
---|
693 | | - fec->fec = mcdi_fec_caps_to_ethtool(caps, is_25g); |
---|
694 | | - /* BASER is never supported on 100G */ |
---|
695 | | - if (speed == 100000) |
---|
696 | | - fec->fec &= ~ETHTOOL_FEC_BASER; |
---|
697 | | - |
---|
698 | | - active = MCDI_DWORD(outbuf, GET_LINK_OUT_V2_FEC_TYPE); |
---|
699 | | - switch (active) { |
---|
700 | | - case MC_CMD_FEC_NONE: |
---|
701 | | - fec->active_fec = ETHTOOL_FEC_OFF; |
---|
702 | | - break; |
---|
703 | | - case MC_CMD_FEC_BASER: |
---|
704 | | - fec->active_fec = ETHTOOL_FEC_BASER; |
---|
705 | | - break; |
---|
706 | | - case MC_CMD_FEC_RS: |
---|
707 | | - fec->active_fec = ETHTOOL_FEC_RS; |
---|
708 | | - break; |
---|
709 | | - default: |
---|
710 | | - netif_warn(efx, hw, efx->net_dev, |
---|
711 | | - "Firmware reports unrecognised FEC_TYPE %u\n", |
---|
712 | | - active); |
---|
713 | | - /* We don't know what firmware has picked. AUTO is as good a |
---|
714 | | - * "can't happen" value as any other. |
---|
715 | | - */ |
---|
716 | | - fec->active_fec = ETHTOOL_FEC_AUTO; |
---|
717 | | - break; |
---|
718 | | - } |
---|
719 | | - |
---|
720 | | - return 0; |
---|
721 | | -} |
---|
722 | | - |
---|
723 | | -static int efx_mcdi_phy_set_fecparam(struct efx_nic *efx, |
---|
724 | | - const struct ethtool_fecparam *fec) |
---|
725 | | -{ |
---|
726 | | - struct efx_mcdi_phy_data *phy_cfg = efx->phy_data; |
---|
727 | | - u32 caps; |
---|
728 | | - int rc; |
---|
729 | | - |
---|
730 | | - /* Work out what efx_mcdi_phy_set_link_ksettings() would produce from |
---|
731 | | - * saved advertising bits |
---|
732 | | - */ |
---|
733 | | - if (test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, efx->link_advertising)) |
---|
734 | | - caps = (ethtool_linkset_to_mcdi_cap(efx->link_advertising) | |
---|
735 | | - 1 << MC_CMD_PHY_CAP_AN_LBN); |
---|
736 | | - else |
---|
737 | | - caps = phy_cfg->forced_cap; |
---|
738 | | - |
---|
739 | | - caps |= ethtool_fec_caps_to_mcdi(fec->fec); |
---|
740 | | - rc = efx_mcdi_set_link(efx, caps, efx_get_mcdi_phy_flags(efx), |
---|
741 | | - efx->loopback_mode, 0); |
---|
742 | | - if (rc) |
---|
743 | | - return rc; |
---|
744 | | - |
---|
745 | | - /* Record the new FEC setting for subsequent set_link calls */ |
---|
746 | | - efx->fec_config = fec->fec; |
---|
747 | | - return 0; |
---|
748 | | -} |
---|
749 | | - |
---|
750 | | -static int efx_mcdi_phy_test_alive(struct efx_nic *efx) |
---|
751 | | -{ |
---|
752 | | - MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_PHY_STATE_OUT_LEN); |
---|
753 | | - size_t outlen; |
---|
754 | | - int rc; |
---|
755 | | - |
---|
756 | | - BUILD_BUG_ON(MC_CMD_GET_PHY_STATE_IN_LEN != 0); |
---|
757 | | - |
---|
758 | | - rc = efx_mcdi_rpc(efx, MC_CMD_GET_PHY_STATE, NULL, 0, |
---|
759 | | - outbuf, sizeof(outbuf), &outlen); |
---|
760 | | - if (rc) |
---|
761 | | - return rc; |
---|
762 | | - |
---|
763 | | - if (outlen < MC_CMD_GET_PHY_STATE_OUT_LEN) |
---|
764 | | - return -EIO; |
---|
765 | | - if (MCDI_DWORD(outbuf, GET_PHY_STATE_OUT_STATE) != MC_CMD_PHY_STATE_OK) |
---|
766 | | - return -EINVAL; |
---|
767 | | - |
---|
768 | | - return 0; |
---|
769 | | -} |
---|
770 | | - |
---|
771 | | -static const char *const mcdi_sft9001_cable_diag_names[] = { |
---|
772 | | - "cable.pairA.length", |
---|
773 | | - "cable.pairB.length", |
---|
774 | | - "cable.pairC.length", |
---|
775 | | - "cable.pairD.length", |
---|
776 | | - "cable.pairA.status", |
---|
777 | | - "cable.pairB.status", |
---|
778 | | - "cable.pairC.status", |
---|
779 | | - "cable.pairD.status", |
---|
780 | | -}; |
---|
781 | | - |
---|
782 | | -static int efx_mcdi_bist(struct efx_nic *efx, unsigned int bist_mode, |
---|
783 | | - int *results) |
---|
784 | | -{ |
---|
785 | | - unsigned int retry, i, count = 0; |
---|
786 | | - size_t outlen; |
---|
787 | | - u32 status; |
---|
788 | | - MCDI_DECLARE_BUF(inbuf, MC_CMD_START_BIST_IN_LEN); |
---|
789 | | - MCDI_DECLARE_BUF(outbuf, MC_CMD_POLL_BIST_OUT_SFT9001_LEN); |
---|
790 | | - u8 *ptr; |
---|
791 | | - int rc; |
---|
792 | | - |
---|
793 | | - BUILD_BUG_ON(MC_CMD_START_BIST_OUT_LEN != 0); |
---|
794 | | - MCDI_SET_DWORD(inbuf, START_BIST_IN_TYPE, bist_mode); |
---|
795 | | - rc = efx_mcdi_rpc(efx, MC_CMD_START_BIST, |
---|
796 | | - inbuf, MC_CMD_START_BIST_IN_LEN, NULL, 0, NULL); |
---|
797 | | - if (rc) |
---|
798 | | - goto out; |
---|
799 | | - |
---|
800 | | - /* Wait up to 10s for BIST to finish */ |
---|
801 | | - for (retry = 0; retry < 100; ++retry) { |
---|
802 | | - BUILD_BUG_ON(MC_CMD_POLL_BIST_IN_LEN != 0); |
---|
803 | | - rc = efx_mcdi_rpc(efx, MC_CMD_POLL_BIST, NULL, 0, |
---|
804 | | - outbuf, sizeof(outbuf), &outlen); |
---|
805 | | - if (rc) |
---|
806 | | - goto out; |
---|
807 | | - |
---|
808 | | - status = MCDI_DWORD(outbuf, POLL_BIST_OUT_RESULT); |
---|
809 | | - if (status != MC_CMD_POLL_BIST_RUNNING) |
---|
810 | | - goto finished; |
---|
811 | | - |
---|
812 | | - msleep(100); |
---|
813 | | - } |
---|
814 | | - |
---|
815 | | - rc = -ETIMEDOUT; |
---|
816 | | - goto out; |
---|
817 | | - |
---|
818 | | -finished: |
---|
819 | | - results[count++] = (status == MC_CMD_POLL_BIST_PASSED) ? 1 : -1; |
---|
820 | | - |
---|
821 | | - /* SFT9001 specific cable diagnostics output */ |
---|
822 | | - if (efx->phy_type == PHY_TYPE_SFT9001B && |
---|
823 | | - (bist_mode == MC_CMD_PHY_BIST_CABLE_SHORT || |
---|
824 | | - bist_mode == MC_CMD_PHY_BIST_CABLE_LONG)) { |
---|
825 | | - ptr = MCDI_PTR(outbuf, POLL_BIST_OUT_SFT9001_CABLE_LENGTH_A); |
---|
826 | | - if (status == MC_CMD_POLL_BIST_PASSED && |
---|
827 | | - outlen >= MC_CMD_POLL_BIST_OUT_SFT9001_LEN) { |
---|
828 | | - for (i = 0; i < 8; i++) { |
---|
829 | | - results[count + i] = |
---|
830 | | - EFX_DWORD_FIELD(((efx_dword_t *)ptr)[i], |
---|
831 | | - EFX_DWORD_0); |
---|
832 | | - } |
---|
833 | | - } |
---|
834 | | - count += 8; |
---|
835 | | - } |
---|
836 | | - rc = count; |
---|
837 | | - |
---|
838 | | -out: |
---|
839 | | - return rc; |
---|
840 | | -} |
---|
841 | | - |
---|
842 | | -static int efx_mcdi_phy_run_tests(struct efx_nic *efx, int *results, |
---|
843 | | - unsigned flags) |
---|
844 | | -{ |
---|
845 | | - struct efx_mcdi_phy_data *phy_cfg = efx->phy_data; |
---|
846 | | - u32 mode; |
---|
847 | | - int rc; |
---|
848 | | - |
---|
849 | | - if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_OUT_BIST_LBN)) { |
---|
850 | | - rc = efx_mcdi_bist(efx, MC_CMD_PHY_BIST, results); |
---|
851 | | - if (rc < 0) |
---|
852 | | - return rc; |
---|
853 | | - |
---|
854 | | - results += rc; |
---|
855 | | - } |
---|
856 | | - |
---|
857 | | - /* If we support both LONG and SHORT, then run each in response to |
---|
858 | | - * break or not. Otherwise, run the one we support */ |
---|
859 | | - mode = 0; |
---|
860 | | - if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_OUT_BIST_CABLE_SHORT_LBN)) { |
---|
861 | | - if ((flags & ETH_TEST_FL_OFFLINE) && |
---|
862 | | - (phy_cfg->flags & |
---|
863 | | - (1 << MC_CMD_GET_PHY_CFG_OUT_BIST_CABLE_LONG_LBN))) |
---|
864 | | - mode = MC_CMD_PHY_BIST_CABLE_LONG; |
---|
865 | | - else |
---|
866 | | - mode = MC_CMD_PHY_BIST_CABLE_SHORT; |
---|
867 | | - } else if (phy_cfg->flags & |
---|
868 | | - (1 << MC_CMD_GET_PHY_CFG_OUT_BIST_CABLE_LONG_LBN)) |
---|
869 | | - mode = MC_CMD_PHY_BIST_CABLE_LONG; |
---|
870 | | - |
---|
871 | | - if (mode != 0) { |
---|
872 | | - rc = efx_mcdi_bist(efx, mode, results); |
---|
873 | | - if (rc < 0) |
---|
874 | | - return rc; |
---|
875 | | - results += rc; |
---|
876 | | - } |
---|
877 | | - |
---|
878 | | - return 0; |
---|
879 | | -} |
---|
880 | | - |
---|
881 | | -static const char *efx_mcdi_phy_test_name(struct efx_nic *efx, |
---|
882 | | - unsigned int index) |
---|
883 | | -{ |
---|
884 | | - struct efx_mcdi_phy_data *phy_cfg = efx->phy_data; |
---|
885 | | - |
---|
886 | | - if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_OUT_BIST_LBN)) { |
---|
887 | | - if (index == 0) |
---|
888 | | - return "bist"; |
---|
889 | | - --index; |
---|
890 | | - } |
---|
891 | | - |
---|
892 | | - if (phy_cfg->flags & ((1 << MC_CMD_GET_PHY_CFG_OUT_BIST_CABLE_SHORT_LBN) | |
---|
893 | | - (1 << MC_CMD_GET_PHY_CFG_OUT_BIST_CABLE_LONG_LBN))) { |
---|
894 | | - if (index == 0) |
---|
895 | | - return "cable"; |
---|
896 | | - --index; |
---|
897 | | - |
---|
898 | | - if (efx->phy_type == PHY_TYPE_SFT9001B) { |
---|
899 | | - if (index < ARRAY_SIZE(mcdi_sft9001_cable_diag_names)) |
---|
900 | | - return mcdi_sft9001_cable_diag_names[index]; |
---|
901 | | - index -= ARRAY_SIZE(mcdi_sft9001_cable_diag_names); |
---|
902 | | - } |
---|
903 | | - } |
---|
904 | | - |
---|
905 | | - return NULL; |
---|
906 | | -} |
---|
907 | | - |
---|
908 | | -#define SFP_PAGE_SIZE 128 |
---|
909 | | -#define SFF_DIAG_TYPE_OFFSET 92 |
---|
910 | | -#define SFF_DIAG_ADDR_CHANGE BIT(2) |
---|
911 | | -#define SFF_8079_NUM_PAGES 2 |
---|
912 | | -#define SFF_8472_NUM_PAGES 4 |
---|
913 | | -#define SFF_8436_NUM_PAGES 5 |
---|
914 | | -#define SFF_DMT_LEVEL_OFFSET 94 |
---|
915 | | - |
---|
916 | | -/** efx_mcdi_phy_get_module_eeprom_page() - Get a single page of module eeprom |
---|
917 | | - * @efx: NIC context |
---|
918 | | - * @page: EEPROM page number |
---|
919 | | - * @data: Destination data pointer |
---|
920 | | - * @offset: Offset in page to copy from in to data |
---|
921 | | - * @space: Space available in data |
---|
922 | | - * |
---|
923 | | - * Return: |
---|
924 | | - * >=0 - amount of data copied |
---|
925 | | - * <0 - error |
---|
926 | | - */ |
---|
927 | | -static int efx_mcdi_phy_get_module_eeprom_page(struct efx_nic *efx, |
---|
928 | | - unsigned int page, |
---|
929 | | - u8 *data, ssize_t offset, |
---|
930 | | - ssize_t space) |
---|
931 | | -{ |
---|
932 | | - MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_PHY_MEDIA_INFO_OUT_LENMAX); |
---|
933 | | - MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN); |
---|
934 | | - size_t outlen; |
---|
935 | | - unsigned int payload_len; |
---|
936 | | - unsigned int to_copy; |
---|
937 | | - int rc; |
---|
938 | | - |
---|
939 | | - if (offset > SFP_PAGE_SIZE) |
---|
940 | | - return -EINVAL; |
---|
941 | | - |
---|
942 | | - to_copy = min(space, SFP_PAGE_SIZE - offset); |
---|
943 | | - |
---|
944 | | - MCDI_SET_DWORD(inbuf, GET_PHY_MEDIA_INFO_IN_PAGE, page); |
---|
945 | | - rc = efx_mcdi_rpc_quiet(efx, MC_CMD_GET_PHY_MEDIA_INFO, |
---|
946 | | - inbuf, sizeof(inbuf), |
---|
947 | | - outbuf, sizeof(outbuf), |
---|
948 | | - &outlen); |
---|
949 | | - |
---|
950 | | - if (rc) |
---|
951 | | - return rc; |
---|
952 | | - |
---|
953 | | - if (outlen < (MC_CMD_GET_PHY_MEDIA_INFO_OUT_DATA_OFST + |
---|
954 | | - SFP_PAGE_SIZE)) |
---|
955 | | - return -EIO; |
---|
956 | | - |
---|
957 | | - payload_len = MCDI_DWORD(outbuf, GET_PHY_MEDIA_INFO_OUT_DATALEN); |
---|
958 | | - if (payload_len != SFP_PAGE_SIZE) |
---|
959 | | - return -EIO; |
---|
960 | | - |
---|
961 | | - memcpy(data, MCDI_PTR(outbuf, GET_PHY_MEDIA_INFO_OUT_DATA) + offset, |
---|
962 | | - to_copy); |
---|
963 | | - |
---|
964 | | - return to_copy; |
---|
965 | | -} |
---|
966 | | - |
---|
967 | | -static int efx_mcdi_phy_get_module_eeprom_byte(struct efx_nic *efx, |
---|
968 | | - unsigned int page, |
---|
969 | | - u8 byte) |
---|
970 | | -{ |
---|
971 | | - int rc; |
---|
972 | | - u8 data; |
---|
973 | | - |
---|
974 | | - rc = efx_mcdi_phy_get_module_eeprom_page(efx, page, &data, byte, 1); |
---|
975 | | - if (rc == 1) |
---|
976 | | - return data; |
---|
977 | | - |
---|
978 | | - return rc; |
---|
979 | | -} |
---|
980 | | - |
---|
981 | | -static int efx_mcdi_phy_diag_type(struct efx_nic *efx) |
---|
982 | | -{ |
---|
983 | | - /* Page zero of the EEPROM includes the diagnostic type at byte 92. */ |
---|
984 | | - return efx_mcdi_phy_get_module_eeprom_byte(efx, 0, |
---|
985 | | - SFF_DIAG_TYPE_OFFSET); |
---|
986 | | -} |
---|
987 | | - |
---|
988 | | -static int efx_mcdi_phy_sff_8472_level(struct efx_nic *efx) |
---|
989 | | -{ |
---|
990 | | - /* Page zero of the EEPROM includes the DMT level at byte 94. */ |
---|
991 | | - return efx_mcdi_phy_get_module_eeprom_byte(efx, 0, |
---|
992 | | - SFF_DMT_LEVEL_OFFSET); |
---|
993 | | -} |
---|
994 | | - |
---|
995 | | -static u32 efx_mcdi_phy_module_type(struct efx_nic *efx) |
---|
996 | | -{ |
---|
997 | | - struct efx_mcdi_phy_data *phy_data = efx->phy_data; |
---|
998 | | - |
---|
999 | | - if (phy_data->media != MC_CMD_MEDIA_QSFP_PLUS) |
---|
1000 | | - return phy_data->media; |
---|
1001 | | - |
---|
1002 | | - /* A QSFP+ NIC may actually have an SFP+ module attached. |
---|
1003 | | - * The ID is page 0, byte 0. |
---|
1004 | | - */ |
---|
1005 | | - switch (efx_mcdi_phy_get_module_eeprom_byte(efx, 0, 0)) { |
---|
1006 | | - case 0x3: |
---|
1007 | | - return MC_CMD_MEDIA_SFP_PLUS; |
---|
1008 | | - case 0xc: |
---|
1009 | | - case 0xd: |
---|
1010 | | - return MC_CMD_MEDIA_QSFP_PLUS; |
---|
1011 | | - default: |
---|
1012 | | - return 0; |
---|
1013 | | - } |
---|
1014 | | -} |
---|
1015 | | - |
---|
1016 | | -static int efx_mcdi_phy_get_module_eeprom(struct efx_nic *efx, |
---|
1017 | | - struct ethtool_eeprom *ee, u8 *data) |
---|
1018 | | -{ |
---|
1019 | | - int rc; |
---|
1020 | | - ssize_t space_remaining = ee->len; |
---|
1021 | | - unsigned int page_off; |
---|
1022 | | - bool ignore_missing; |
---|
1023 | | - int num_pages; |
---|
1024 | | - int page; |
---|
1025 | | - |
---|
1026 | | - switch (efx_mcdi_phy_module_type(efx)) { |
---|
1027 | | - case MC_CMD_MEDIA_SFP_PLUS: |
---|
1028 | | - num_pages = efx_mcdi_phy_sff_8472_level(efx) > 0 ? |
---|
1029 | | - SFF_8472_NUM_PAGES : SFF_8079_NUM_PAGES; |
---|
1030 | | - page = 0; |
---|
1031 | | - ignore_missing = false; |
---|
1032 | | - break; |
---|
1033 | | - case MC_CMD_MEDIA_QSFP_PLUS: |
---|
1034 | | - num_pages = SFF_8436_NUM_PAGES; |
---|
1035 | | - page = -1; /* We obtain the lower page by asking for -1. */ |
---|
1036 | | - ignore_missing = true; /* Ignore missing pages after page 0. */ |
---|
1037 | | - break; |
---|
1038 | | - default: |
---|
1039 | | - return -EOPNOTSUPP; |
---|
1040 | | - } |
---|
1041 | | - |
---|
1042 | | - page_off = ee->offset % SFP_PAGE_SIZE; |
---|
1043 | | - page += ee->offset / SFP_PAGE_SIZE; |
---|
1044 | | - |
---|
1045 | | - while (space_remaining && (page < num_pages)) { |
---|
1046 | | - rc = efx_mcdi_phy_get_module_eeprom_page(efx, page, |
---|
1047 | | - data, page_off, |
---|
1048 | | - space_remaining); |
---|
1049 | | - |
---|
1050 | | - if (rc > 0) { |
---|
1051 | | - space_remaining -= rc; |
---|
1052 | | - data += rc; |
---|
1053 | | - page_off = 0; |
---|
1054 | | - page++; |
---|
1055 | | - } else if (rc == 0) { |
---|
1056 | | - space_remaining = 0; |
---|
1057 | | - } else if (ignore_missing && (page > 0)) { |
---|
1058 | | - int intended_size = SFP_PAGE_SIZE - page_off; |
---|
1059 | | - |
---|
1060 | | - space_remaining -= intended_size; |
---|
1061 | | - if (space_remaining < 0) { |
---|
1062 | | - space_remaining = 0; |
---|
1063 | | - } else { |
---|
1064 | | - memset(data, 0, intended_size); |
---|
1065 | | - data += intended_size; |
---|
1066 | | - page_off = 0; |
---|
1067 | | - page++; |
---|
1068 | | - rc = 0; |
---|
1069 | | - } |
---|
1070 | | - } else { |
---|
1071 | | - return rc; |
---|
1072 | | - } |
---|
1073 | | - } |
---|
1074 | | - |
---|
1075 | | - return 0; |
---|
1076 | | -} |
---|
1077 | | - |
---|
1078 | | -static int efx_mcdi_phy_get_module_info(struct efx_nic *efx, |
---|
1079 | | - struct ethtool_modinfo *modinfo) |
---|
1080 | | -{ |
---|
1081 | | - int sff_8472_level; |
---|
1082 | | - int diag_type; |
---|
1083 | | - |
---|
1084 | | - switch (efx_mcdi_phy_module_type(efx)) { |
---|
1085 | | - case MC_CMD_MEDIA_SFP_PLUS: |
---|
1086 | | - sff_8472_level = efx_mcdi_phy_sff_8472_level(efx); |
---|
1087 | | - |
---|
1088 | | - /* If we can't read the diagnostics level we have none. */ |
---|
1089 | | - if (sff_8472_level < 0) |
---|
1090 | | - return -EOPNOTSUPP; |
---|
1091 | | - |
---|
1092 | | - /* Check if this module requires the (unsupported) address |
---|
1093 | | - * change operation. |
---|
1094 | | - */ |
---|
1095 | | - diag_type = efx_mcdi_phy_diag_type(efx); |
---|
1096 | | - |
---|
1097 | | - if ((sff_8472_level == 0) || |
---|
1098 | | - (diag_type & SFF_DIAG_ADDR_CHANGE)) { |
---|
1099 | | - modinfo->type = ETH_MODULE_SFF_8079; |
---|
1100 | | - modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN; |
---|
1101 | | - } else { |
---|
1102 | | - modinfo->type = ETH_MODULE_SFF_8472; |
---|
1103 | | - modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; |
---|
1104 | | - } |
---|
1105 | | - break; |
---|
1106 | | - |
---|
1107 | | - case MC_CMD_MEDIA_QSFP_PLUS: |
---|
1108 | | - modinfo->type = ETH_MODULE_SFF_8436; |
---|
1109 | | - modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; |
---|
1110 | | - break; |
---|
1111 | | - |
---|
1112 | | - default: |
---|
1113 | | - return -EOPNOTSUPP; |
---|
1114 | | - } |
---|
1115 | | - |
---|
1116 | | - return 0; |
---|
1117 | | -} |
---|
1118 | | - |
---|
1119 | | -static const struct efx_phy_operations efx_mcdi_phy_ops = { |
---|
1120 | | - .probe = efx_mcdi_phy_probe, |
---|
1121 | | - .init = efx_port_dummy_op_int, |
---|
1122 | | - .reconfigure = efx_mcdi_port_reconfigure, |
---|
1123 | | - .poll = efx_mcdi_phy_poll, |
---|
1124 | | - .fini = efx_port_dummy_op_void, |
---|
1125 | | - .remove = efx_mcdi_phy_remove, |
---|
1126 | | - .get_link_ksettings = efx_mcdi_phy_get_link_ksettings, |
---|
1127 | | - .set_link_ksettings = efx_mcdi_phy_set_link_ksettings, |
---|
1128 | | - .get_fecparam = efx_mcdi_phy_get_fecparam, |
---|
1129 | | - .set_fecparam = efx_mcdi_phy_set_fecparam, |
---|
1130 | | - .test_alive = efx_mcdi_phy_test_alive, |
---|
1131 | | - .run_tests = efx_mcdi_phy_run_tests, |
---|
1132 | | - .test_name = efx_mcdi_phy_test_name, |
---|
1133 | | - .get_module_eeprom = efx_mcdi_phy_get_module_eeprom, |
---|
1134 | | - .get_module_info = efx_mcdi_phy_get_module_info, |
---|
1135 | | -}; |
---|
1136 | | - |
---|
1137 | 73 | u32 efx_mcdi_phy_get_caps(struct efx_nic *efx) |
---|
1138 | 74 | { |
---|
1139 | 75 | struct efx_mcdi_phy_data *phy_data = efx->phy_data; |
---|
1140 | 76 | |
---|
1141 | 77 | return phy_data->supported_cap; |
---|
1142 | | -} |
---|
1143 | | - |
---|
1144 | | -static unsigned int efx_mcdi_event_link_speed[] = { |
---|
1145 | | - [MCDI_EVENT_LINKCHANGE_SPEED_100M] = 100, |
---|
1146 | | - [MCDI_EVENT_LINKCHANGE_SPEED_1G] = 1000, |
---|
1147 | | - [MCDI_EVENT_LINKCHANGE_SPEED_10G] = 10000, |
---|
1148 | | - [MCDI_EVENT_LINKCHANGE_SPEED_40G] = 40000, |
---|
1149 | | - [MCDI_EVENT_LINKCHANGE_SPEED_25G] = 25000, |
---|
1150 | | - [MCDI_EVENT_LINKCHANGE_SPEED_50G] = 50000, |
---|
1151 | | - [MCDI_EVENT_LINKCHANGE_SPEED_100G] = 100000, |
---|
1152 | | -}; |
---|
1153 | | - |
---|
1154 | | -void efx_mcdi_process_link_change(struct efx_nic *efx, efx_qword_t *ev) |
---|
1155 | | -{ |
---|
1156 | | - u32 flags, fcntl, speed, lpa; |
---|
1157 | | - |
---|
1158 | | - speed = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_SPEED); |
---|
1159 | | - EFX_WARN_ON_PARANOID(speed >= ARRAY_SIZE(efx_mcdi_event_link_speed)); |
---|
1160 | | - speed = efx_mcdi_event_link_speed[speed]; |
---|
1161 | | - |
---|
1162 | | - flags = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_LINK_FLAGS); |
---|
1163 | | - fcntl = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_FCNTL); |
---|
1164 | | - lpa = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_LP_CAP); |
---|
1165 | | - |
---|
1166 | | - /* efx->link_state is only modified by efx_mcdi_phy_get_link(), |
---|
1167 | | - * which is only run after flushing the event queues. Therefore, it |
---|
1168 | | - * is safe to modify the link state outside of the mac_lock here. |
---|
1169 | | - */ |
---|
1170 | | - efx_mcdi_phy_decode_link(efx, &efx->link_state, speed, flags, fcntl); |
---|
1171 | | - |
---|
1172 | | - efx_mcdi_phy_check_fcntl(efx, lpa); |
---|
1173 | | - |
---|
1174 | | - efx_link_status_changed(efx); |
---|
1175 | | -} |
---|
1176 | | - |
---|
1177 | | -int efx_mcdi_set_mac(struct efx_nic *efx) |
---|
1178 | | -{ |
---|
1179 | | - u32 fcntl; |
---|
1180 | | - MCDI_DECLARE_BUF(cmdbytes, MC_CMD_SET_MAC_IN_LEN); |
---|
1181 | | - |
---|
1182 | | - BUILD_BUG_ON(MC_CMD_SET_MAC_OUT_LEN != 0); |
---|
1183 | | - |
---|
1184 | | - /* This has no effect on EF10 */ |
---|
1185 | | - ether_addr_copy(MCDI_PTR(cmdbytes, SET_MAC_IN_ADDR), |
---|
1186 | | - efx->net_dev->dev_addr); |
---|
1187 | | - |
---|
1188 | | - MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_MTU, |
---|
1189 | | - EFX_MAX_FRAME_LEN(efx->net_dev->mtu)); |
---|
1190 | | - MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_DRAIN, 0); |
---|
1191 | | - |
---|
1192 | | - /* Set simple MAC filter for Siena */ |
---|
1193 | | - MCDI_POPULATE_DWORD_1(cmdbytes, SET_MAC_IN_REJECT, |
---|
1194 | | - SET_MAC_IN_REJECT_UNCST, efx->unicast_filter); |
---|
1195 | | - |
---|
1196 | | - MCDI_POPULATE_DWORD_1(cmdbytes, SET_MAC_IN_FLAGS, |
---|
1197 | | - SET_MAC_IN_FLAG_INCLUDE_FCS, |
---|
1198 | | - !!(efx->net_dev->features & NETIF_F_RXFCS)); |
---|
1199 | | - |
---|
1200 | | - switch (efx->wanted_fc) { |
---|
1201 | | - case EFX_FC_RX | EFX_FC_TX: |
---|
1202 | | - fcntl = MC_CMD_FCNTL_BIDIR; |
---|
1203 | | - break; |
---|
1204 | | - case EFX_FC_RX: |
---|
1205 | | - fcntl = MC_CMD_FCNTL_RESPOND; |
---|
1206 | | - break; |
---|
1207 | | - default: |
---|
1208 | | - fcntl = MC_CMD_FCNTL_OFF; |
---|
1209 | | - break; |
---|
1210 | | - } |
---|
1211 | | - if (efx->wanted_fc & EFX_FC_AUTO) |
---|
1212 | | - fcntl = MC_CMD_FCNTL_AUTO; |
---|
1213 | | - if (efx->fc_disable) |
---|
1214 | | - fcntl = MC_CMD_FCNTL_OFF; |
---|
1215 | | - |
---|
1216 | | - MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_FCNTL, fcntl); |
---|
1217 | | - |
---|
1218 | | - return efx_mcdi_rpc(efx, MC_CMD_SET_MAC, cmdbytes, sizeof(cmdbytes), |
---|
1219 | | - NULL, 0, NULL); |
---|
1220 | 78 | } |
---|
1221 | 79 | |
---|
1222 | 80 | bool efx_mcdi_mac_check_fault(struct efx_nic *efx) |
---|
.. | .. |
---|
1235 | 93 | return MCDI_DWORD(outbuf, GET_LINK_OUT_MAC_FAULT) != 0; |
---|
1236 | 94 | } |
---|
1237 | 95 | |
---|
1238 | | -enum efx_stats_action { |
---|
1239 | | - EFX_STATS_ENABLE, |
---|
1240 | | - EFX_STATS_DISABLE, |
---|
1241 | | - EFX_STATS_PULL, |
---|
1242 | | -}; |
---|
1243 | | - |
---|
1244 | | -static int efx_mcdi_mac_stats(struct efx_nic *efx, |
---|
1245 | | - enum efx_stats_action action, int clear) |
---|
1246 | | -{ |
---|
1247 | | - MCDI_DECLARE_BUF(inbuf, MC_CMD_MAC_STATS_IN_LEN); |
---|
1248 | | - int rc; |
---|
1249 | | - int change = action == EFX_STATS_PULL ? 0 : 1; |
---|
1250 | | - int enable = action == EFX_STATS_ENABLE ? 1 : 0; |
---|
1251 | | - int period = action == EFX_STATS_ENABLE ? 1000 : 0; |
---|
1252 | | - dma_addr_t dma_addr = efx->stats_buffer.dma_addr; |
---|
1253 | | - u32 dma_len = action != EFX_STATS_DISABLE ? |
---|
1254 | | - efx->num_mac_stats * sizeof(u64) : 0; |
---|
1255 | | - |
---|
1256 | | - BUILD_BUG_ON(MC_CMD_MAC_STATS_OUT_DMA_LEN != 0); |
---|
1257 | | - |
---|
1258 | | - MCDI_SET_QWORD(inbuf, MAC_STATS_IN_DMA_ADDR, dma_addr); |
---|
1259 | | - MCDI_POPULATE_DWORD_7(inbuf, MAC_STATS_IN_CMD, |
---|
1260 | | - MAC_STATS_IN_DMA, !!enable, |
---|
1261 | | - MAC_STATS_IN_CLEAR, clear, |
---|
1262 | | - MAC_STATS_IN_PERIODIC_CHANGE, change, |
---|
1263 | | - MAC_STATS_IN_PERIODIC_ENABLE, enable, |
---|
1264 | | - MAC_STATS_IN_PERIODIC_CLEAR, 0, |
---|
1265 | | - MAC_STATS_IN_PERIODIC_NOEVENT, 1, |
---|
1266 | | - MAC_STATS_IN_PERIOD_MS, period); |
---|
1267 | | - MCDI_SET_DWORD(inbuf, MAC_STATS_IN_DMA_LEN, dma_len); |
---|
1268 | | - |
---|
1269 | | - if (efx_nic_rev(efx) >= EFX_REV_HUNT_A0) { |
---|
1270 | | - struct efx_ef10_nic_data *nic_data = efx->nic_data; |
---|
1271 | | - |
---|
1272 | | - MCDI_SET_DWORD(inbuf, MAC_STATS_IN_PORT_ID, nic_data->vport_id); |
---|
1273 | | - } |
---|
1274 | | - |
---|
1275 | | - rc = efx_mcdi_rpc_quiet(efx, MC_CMD_MAC_STATS, inbuf, sizeof(inbuf), |
---|
1276 | | - NULL, 0, NULL); |
---|
1277 | | - /* Expect ENOENT if DMA queues have not been set up */ |
---|
1278 | | - if (rc && (rc != -ENOENT || atomic_read(&efx->active_queues))) |
---|
1279 | | - efx_mcdi_display_error(efx, MC_CMD_MAC_STATS, sizeof(inbuf), |
---|
1280 | | - NULL, 0, rc); |
---|
1281 | | - return rc; |
---|
1282 | | -} |
---|
1283 | | - |
---|
1284 | | -void efx_mcdi_mac_start_stats(struct efx_nic *efx) |
---|
1285 | | -{ |
---|
1286 | | - __le64 *dma_stats = efx->stats_buffer.addr; |
---|
1287 | | - |
---|
1288 | | - dma_stats[efx->num_mac_stats - 1] = EFX_MC_STATS_GENERATION_INVALID; |
---|
1289 | | - |
---|
1290 | | - efx_mcdi_mac_stats(efx, EFX_STATS_ENABLE, 0); |
---|
1291 | | -} |
---|
1292 | | - |
---|
1293 | | -void efx_mcdi_mac_stop_stats(struct efx_nic *efx) |
---|
1294 | | -{ |
---|
1295 | | - efx_mcdi_mac_stats(efx, EFX_STATS_DISABLE, 0); |
---|
1296 | | -} |
---|
1297 | | - |
---|
1298 | | -#define EFX_MAC_STATS_WAIT_US 100 |
---|
1299 | | -#define EFX_MAC_STATS_WAIT_ATTEMPTS 10 |
---|
1300 | | - |
---|
1301 | | -void efx_mcdi_mac_pull_stats(struct efx_nic *efx) |
---|
1302 | | -{ |
---|
1303 | | - __le64 *dma_stats = efx->stats_buffer.addr; |
---|
1304 | | - int attempts = EFX_MAC_STATS_WAIT_ATTEMPTS; |
---|
1305 | | - |
---|
1306 | | - dma_stats[efx->num_mac_stats - 1] = EFX_MC_STATS_GENERATION_INVALID; |
---|
1307 | | - efx_mcdi_mac_stats(efx, EFX_STATS_PULL, 0); |
---|
1308 | | - |
---|
1309 | | - while (dma_stats[efx->num_mac_stats - 1] == |
---|
1310 | | - EFX_MC_STATS_GENERATION_INVALID && |
---|
1311 | | - attempts-- != 0) |
---|
1312 | | - udelay(EFX_MAC_STATS_WAIT_US); |
---|
1313 | | -} |
---|
1314 | | - |
---|
1315 | 96 | int efx_mcdi_port_probe(struct efx_nic *efx) |
---|
1316 | 97 | { |
---|
1317 | 98 | int rc; |
---|
1318 | | - |
---|
1319 | | - /* Hook in PHY operations table */ |
---|
1320 | | - efx->phy_op = &efx_mcdi_phy_ops; |
---|
1321 | 99 | |
---|
1322 | 100 | /* Set up MDIO structure for PHY */ |
---|
1323 | 101 | efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; |
---|
.. | .. |
---|
1325 | 103 | efx->mdio.mdio_write = efx_mcdi_mdio_write; |
---|
1326 | 104 | |
---|
1327 | 105 | /* Fill out MDIO structure, loopback modes, and initial link state */ |
---|
1328 | | - rc = efx->phy_op->probe(efx); |
---|
| 106 | + rc = efx_mcdi_phy_probe(efx); |
---|
1329 | 107 | if (rc != 0) |
---|
1330 | 108 | return rc; |
---|
1331 | 109 | |
---|
1332 | | - /* Allocate buffer for stats */ |
---|
1333 | | - rc = efx_nic_alloc_buffer(efx, &efx->stats_buffer, |
---|
1334 | | - efx->num_mac_stats * sizeof(u64), GFP_KERNEL); |
---|
1335 | | - if (rc) |
---|
1336 | | - return rc; |
---|
1337 | | - netif_dbg(efx, probe, efx->net_dev, |
---|
1338 | | - "stats buffer at %llx (virt %p phys %llx)\n", |
---|
1339 | | - (u64)efx->stats_buffer.dma_addr, |
---|
1340 | | - efx->stats_buffer.addr, |
---|
1341 | | - (u64)virt_to_phys(efx->stats_buffer.addr)); |
---|
1342 | | - |
---|
1343 | | - efx_mcdi_mac_stats(efx, EFX_STATS_DISABLE, 1); |
---|
1344 | | - |
---|
1345 | | - return 0; |
---|
| 110 | + return efx_mcdi_mac_init_stats(efx); |
---|
1346 | 111 | } |
---|
1347 | 112 | |
---|
1348 | 113 | void efx_mcdi_port_remove(struct efx_nic *efx) |
---|
1349 | 114 | { |
---|
1350 | | - efx->phy_op->remove(efx); |
---|
1351 | | - efx_nic_free_buffer(efx, &efx->stats_buffer); |
---|
1352 | | -} |
---|
1353 | | - |
---|
1354 | | -/* Get physical port number (EF10 only; on Siena it is same as PF number) */ |
---|
1355 | | -int efx_mcdi_port_get_number(struct efx_nic *efx) |
---|
1356 | | -{ |
---|
1357 | | - MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN); |
---|
1358 | | - int rc; |
---|
1359 | | - |
---|
1360 | | - rc = efx_mcdi_rpc(efx, MC_CMD_GET_PORT_ASSIGNMENT, NULL, 0, |
---|
1361 | | - outbuf, sizeof(outbuf), NULL); |
---|
1362 | | - if (rc) |
---|
1363 | | - return rc; |
---|
1364 | | - |
---|
1365 | | - return MCDI_DWORD(outbuf, GET_PORT_ASSIGNMENT_OUT_PORT); |
---|
| 115 | + efx_mcdi_phy_remove(efx); |
---|
| 116 | + efx_mcdi_mac_fini_stats(efx); |
---|
1366 | 117 | } |
---|