| .. | .. |
|---|
| 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 | } |
|---|