0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include "mcdi_port_common.h"
0012 #include "efx_common.h"
0013 #include "nic.h"
0014
0015 int efx_mcdi_get_phy_cfg(struct efx_nic *efx, struct efx_mcdi_phy_data *cfg)
0016 {
0017 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_PHY_CFG_OUT_LEN);
0018 size_t outlen;
0019 int rc;
0020
0021 BUILD_BUG_ON(MC_CMD_GET_PHY_CFG_IN_LEN != 0);
0022 BUILD_BUG_ON(MC_CMD_GET_PHY_CFG_OUT_NAME_LEN != sizeof(cfg->name));
0023
0024 rc = efx_mcdi_rpc(efx, MC_CMD_GET_PHY_CFG, NULL, 0,
0025 outbuf, sizeof(outbuf), &outlen);
0026 if (rc)
0027 goto fail;
0028
0029 if (outlen < MC_CMD_GET_PHY_CFG_OUT_LEN) {
0030 rc = -EIO;
0031 goto fail;
0032 }
0033
0034 cfg->flags = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_FLAGS);
0035 cfg->type = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_TYPE);
0036 cfg->supported_cap =
0037 MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_SUPPORTED_CAP);
0038 cfg->channel = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_CHANNEL);
0039 cfg->port = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_PRT);
0040 cfg->stats_mask = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_STATS_MASK);
0041 memcpy(cfg->name, MCDI_PTR(outbuf, GET_PHY_CFG_OUT_NAME),
0042 sizeof(cfg->name));
0043 cfg->media = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_MEDIA_TYPE);
0044 cfg->mmd_mask = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_MMD_MASK);
0045 memcpy(cfg->revision, MCDI_PTR(outbuf, GET_PHY_CFG_OUT_REVISION),
0046 sizeof(cfg->revision));
0047
0048 return 0;
0049
0050 fail:
0051 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
0052 return rc;
0053 }
0054
0055 void efx_link_set_advertising(struct efx_nic *efx,
0056 const unsigned long *advertising)
0057 {
0058 memcpy(efx->link_advertising, advertising,
0059 sizeof(__ETHTOOL_DECLARE_LINK_MODE_MASK()));
0060
0061 efx->link_advertising[0] |= ADVERTISED_Autoneg;
0062 if (advertising[0] & ADVERTISED_Pause)
0063 efx->wanted_fc |= (EFX_FC_TX | EFX_FC_RX);
0064 else
0065 efx->wanted_fc &= ~(EFX_FC_TX | EFX_FC_RX);
0066 if (advertising[0] & ADVERTISED_Asym_Pause)
0067 efx->wanted_fc ^= EFX_FC_TX;
0068 }
0069
0070 int efx_mcdi_set_link(struct efx_nic *efx, u32 capabilities,
0071 u32 flags, u32 loopback_mode, u32 loopback_speed)
0072 {
0073 MCDI_DECLARE_BUF(inbuf, MC_CMD_SET_LINK_IN_LEN);
0074
0075 BUILD_BUG_ON(MC_CMD_SET_LINK_OUT_LEN != 0);
0076
0077 MCDI_SET_DWORD(inbuf, SET_LINK_IN_CAP, capabilities);
0078 MCDI_SET_DWORD(inbuf, SET_LINK_IN_FLAGS, flags);
0079 MCDI_SET_DWORD(inbuf, SET_LINK_IN_LOOPBACK_MODE, loopback_mode);
0080 MCDI_SET_DWORD(inbuf, SET_LINK_IN_LOOPBACK_SPEED, loopback_speed);
0081
0082 return efx_mcdi_rpc(efx, MC_CMD_SET_LINK, inbuf, sizeof(inbuf),
0083 NULL, 0, NULL);
0084 }
0085
0086 int efx_mcdi_loopback_modes(struct efx_nic *efx, u64 *loopback_modes)
0087 {
0088 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_LOOPBACK_MODES_OUT_LEN);
0089 size_t outlen;
0090 int rc;
0091
0092 rc = efx_mcdi_rpc(efx, MC_CMD_GET_LOOPBACK_MODES, NULL, 0,
0093 outbuf, sizeof(outbuf), &outlen);
0094 if (rc)
0095 goto fail;
0096
0097 if (outlen < (MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_OFST +
0098 MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_LEN)) {
0099 rc = -EIO;
0100 goto fail;
0101 }
0102
0103 *loopback_modes = MCDI_QWORD(outbuf, GET_LOOPBACK_MODES_OUT_SUGGESTED);
0104
0105 return 0;
0106
0107 fail:
0108 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
0109 return rc;
0110 }
0111
0112 void mcdi_to_ethtool_linkset(u32 media, u32 cap, unsigned long *linkset)
0113 {
0114 #define SET_BIT(name) __set_bit(ETHTOOL_LINK_MODE_ ## name ## _BIT, \
0115 linkset)
0116
0117 bitmap_zero(linkset, __ETHTOOL_LINK_MODE_MASK_NBITS);
0118 switch (media) {
0119 case MC_CMD_MEDIA_KX4:
0120 SET_BIT(Backplane);
0121 if (cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN))
0122 SET_BIT(1000baseKX_Full);
0123 if (cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN))
0124 SET_BIT(10000baseKX4_Full);
0125 if (cap & (1 << MC_CMD_PHY_CAP_40000FDX_LBN))
0126 SET_BIT(40000baseKR4_Full);
0127 break;
0128
0129 case MC_CMD_MEDIA_XFP:
0130 case MC_CMD_MEDIA_SFP_PLUS:
0131 case MC_CMD_MEDIA_QSFP_PLUS:
0132 SET_BIT(FIBRE);
0133 if (cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN)) {
0134 SET_BIT(1000baseT_Full);
0135 SET_BIT(1000baseX_Full);
0136 }
0137 if (cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN)) {
0138 SET_BIT(10000baseCR_Full);
0139 SET_BIT(10000baseLR_Full);
0140 SET_BIT(10000baseSR_Full);
0141 }
0142 if (cap & (1 << MC_CMD_PHY_CAP_40000FDX_LBN)) {
0143 SET_BIT(40000baseCR4_Full);
0144 SET_BIT(40000baseSR4_Full);
0145 }
0146 if (cap & (1 << MC_CMD_PHY_CAP_100000FDX_LBN)) {
0147 SET_BIT(100000baseCR4_Full);
0148 SET_BIT(100000baseSR4_Full);
0149 }
0150 if (cap & (1 << MC_CMD_PHY_CAP_25000FDX_LBN)) {
0151 SET_BIT(25000baseCR_Full);
0152 SET_BIT(25000baseSR_Full);
0153 }
0154 if (cap & (1 << MC_CMD_PHY_CAP_50000FDX_LBN))
0155 SET_BIT(50000baseCR2_Full);
0156 break;
0157
0158 case MC_CMD_MEDIA_BASE_T:
0159 SET_BIT(TP);
0160 if (cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN))
0161 SET_BIT(10baseT_Half);
0162 if (cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN))
0163 SET_BIT(10baseT_Full);
0164 if (cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN))
0165 SET_BIT(100baseT_Half);
0166 if (cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN))
0167 SET_BIT(100baseT_Full);
0168 if (cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN))
0169 SET_BIT(1000baseT_Half);
0170 if (cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN))
0171 SET_BIT(1000baseT_Full);
0172 if (cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN))
0173 SET_BIT(10000baseT_Full);
0174 break;
0175 }
0176
0177 if (cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN))
0178 SET_BIT(Pause);
0179 if (cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN))
0180 SET_BIT(Asym_Pause);
0181 if (cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
0182 SET_BIT(Autoneg);
0183
0184 #undef SET_BIT
0185 }
0186
0187 u32 ethtool_linkset_to_mcdi_cap(const unsigned long *linkset)
0188 {
0189 u32 result = 0;
0190
0191 #define TEST_BIT(name) test_bit(ETHTOOL_LINK_MODE_ ## name ## _BIT, \
0192 linkset)
0193
0194 if (TEST_BIT(10baseT_Half))
0195 result |= (1 << MC_CMD_PHY_CAP_10HDX_LBN);
0196 if (TEST_BIT(10baseT_Full))
0197 result |= (1 << MC_CMD_PHY_CAP_10FDX_LBN);
0198 if (TEST_BIT(100baseT_Half))
0199 result |= (1 << MC_CMD_PHY_CAP_100HDX_LBN);
0200 if (TEST_BIT(100baseT_Full))
0201 result |= (1 << MC_CMD_PHY_CAP_100FDX_LBN);
0202 if (TEST_BIT(1000baseT_Half))
0203 result |= (1 << MC_CMD_PHY_CAP_1000HDX_LBN);
0204 if (TEST_BIT(1000baseT_Full) || TEST_BIT(1000baseKX_Full) ||
0205 TEST_BIT(1000baseX_Full))
0206 result |= (1 << MC_CMD_PHY_CAP_1000FDX_LBN);
0207 if (TEST_BIT(10000baseT_Full) || TEST_BIT(10000baseKX4_Full) ||
0208 TEST_BIT(10000baseCR_Full) || TEST_BIT(10000baseLR_Full) ||
0209 TEST_BIT(10000baseSR_Full))
0210 result |= (1 << MC_CMD_PHY_CAP_10000FDX_LBN);
0211 if (TEST_BIT(40000baseCR4_Full) || TEST_BIT(40000baseKR4_Full) ||
0212 TEST_BIT(40000baseSR4_Full))
0213 result |= (1 << MC_CMD_PHY_CAP_40000FDX_LBN);
0214 if (TEST_BIT(100000baseCR4_Full) || TEST_BIT(100000baseSR4_Full))
0215 result |= (1 << MC_CMD_PHY_CAP_100000FDX_LBN);
0216 if (TEST_BIT(25000baseCR_Full) || TEST_BIT(25000baseSR_Full))
0217 result |= (1 << MC_CMD_PHY_CAP_25000FDX_LBN);
0218 if (TEST_BIT(50000baseCR2_Full))
0219 result |= (1 << MC_CMD_PHY_CAP_50000FDX_LBN);
0220 if (TEST_BIT(Pause))
0221 result |= (1 << MC_CMD_PHY_CAP_PAUSE_LBN);
0222 if (TEST_BIT(Asym_Pause))
0223 result |= (1 << MC_CMD_PHY_CAP_ASYM_LBN);
0224 if (TEST_BIT(Autoneg))
0225 result |= (1 << MC_CMD_PHY_CAP_AN_LBN);
0226
0227 #undef TEST_BIT
0228
0229 return result;
0230 }
0231
0232 u32 efx_get_mcdi_phy_flags(struct efx_nic *efx)
0233 {
0234 struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
0235 enum efx_phy_mode mode, supported;
0236 u32 flags;
0237
0238
0239 supported = 0;
0240 if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_OUT_TXDIS_LBN))
0241 supported |= PHY_MODE_TX_DISABLED;
0242 if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_OUT_LOWPOWER_LBN))
0243 supported |= PHY_MODE_LOW_POWER;
0244 if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_OUT_POWEROFF_LBN))
0245 supported |= PHY_MODE_OFF;
0246
0247 mode = efx->phy_mode & supported;
0248
0249 flags = 0;
0250 if (mode & PHY_MODE_TX_DISABLED)
0251 flags |= (1 << MC_CMD_SET_LINK_IN_TXDIS_LBN);
0252 if (mode & PHY_MODE_LOW_POWER)
0253 flags |= (1 << MC_CMD_SET_LINK_IN_LOWPOWER_LBN);
0254 if (mode & PHY_MODE_OFF)
0255 flags |= (1 << MC_CMD_SET_LINK_IN_POWEROFF_LBN);
0256
0257 return flags;
0258 }
0259
0260 u8 mcdi_to_ethtool_media(u32 media)
0261 {
0262 switch (media) {
0263 case MC_CMD_MEDIA_XAUI:
0264 case MC_CMD_MEDIA_CX4:
0265 case MC_CMD_MEDIA_KX4:
0266 return PORT_OTHER;
0267
0268 case MC_CMD_MEDIA_XFP:
0269 case MC_CMD_MEDIA_SFP_PLUS:
0270 case MC_CMD_MEDIA_QSFP_PLUS:
0271 return PORT_FIBRE;
0272
0273 case MC_CMD_MEDIA_BASE_T:
0274 return PORT_TP;
0275
0276 default:
0277 return PORT_OTHER;
0278 }
0279 }
0280
0281 void efx_mcdi_phy_decode_link(struct efx_nic *efx,
0282 struct efx_link_state *link_state,
0283 u32 speed, u32 flags, u32 fcntl)
0284 {
0285 switch (fcntl) {
0286 case MC_CMD_FCNTL_AUTO:
0287 WARN_ON(1);
0288 link_state->fc = EFX_FC_AUTO | EFX_FC_TX | EFX_FC_RX;
0289 break;
0290 case MC_CMD_FCNTL_BIDIR:
0291 link_state->fc = EFX_FC_TX | EFX_FC_RX;
0292 break;
0293 case MC_CMD_FCNTL_RESPOND:
0294 link_state->fc = EFX_FC_RX;
0295 break;
0296 default:
0297 WARN_ON(1);
0298 fallthrough;
0299 case MC_CMD_FCNTL_OFF:
0300 link_state->fc = 0;
0301 break;
0302 }
0303
0304 link_state->up = !!(flags & (1 << MC_CMD_GET_LINK_OUT_LINK_UP_LBN));
0305 link_state->fd = !!(flags & (1 << MC_CMD_GET_LINK_OUT_FULL_DUPLEX_LBN));
0306 link_state->speed = speed;
0307 }
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324 u32 ethtool_fec_caps_to_mcdi(u32 supported_cap, u32 ethtool_cap)
0325 {
0326 u32 ret = 0;
0327
0328 if (ethtool_cap & ETHTOOL_FEC_OFF)
0329 return 0;
0330
0331 if (ethtool_cap & ETHTOOL_FEC_AUTO)
0332 ret |= ((1 << MC_CMD_PHY_CAP_BASER_FEC_LBN) |
0333 (1 << MC_CMD_PHY_CAP_25G_BASER_FEC_LBN) |
0334 (1 << MC_CMD_PHY_CAP_RS_FEC_LBN)) & supported_cap;
0335 if (ethtool_cap & ETHTOOL_FEC_RS &&
0336 supported_cap & (1 << MC_CMD_PHY_CAP_RS_FEC_LBN))
0337 ret |= (1 << MC_CMD_PHY_CAP_RS_FEC_LBN) |
0338 (1 << MC_CMD_PHY_CAP_RS_FEC_REQUESTED_LBN);
0339 if (ethtool_cap & ETHTOOL_FEC_BASER) {
0340 if (supported_cap & (1 << MC_CMD_PHY_CAP_BASER_FEC_LBN))
0341 ret |= (1 << MC_CMD_PHY_CAP_BASER_FEC_LBN) |
0342 (1 << MC_CMD_PHY_CAP_BASER_FEC_REQUESTED_LBN);
0343 if (supported_cap & (1 << MC_CMD_PHY_CAP_25G_BASER_FEC_LBN))
0344 ret |= (1 << MC_CMD_PHY_CAP_25G_BASER_FEC_LBN) |
0345 (1 << MC_CMD_PHY_CAP_25G_BASER_FEC_REQUESTED_LBN);
0346 }
0347 return ret;
0348 }
0349
0350
0351
0352
0353
0354
0355 u32 mcdi_fec_caps_to_ethtool(u32 caps, bool is_25g)
0356 {
0357 bool rs = caps & (1 << MC_CMD_PHY_CAP_RS_FEC_LBN),
0358 rs_req = caps & (1 << MC_CMD_PHY_CAP_RS_FEC_REQUESTED_LBN),
0359 baser = is_25g ? caps & (1 << MC_CMD_PHY_CAP_25G_BASER_FEC_LBN)
0360 : caps & (1 << MC_CMD_PHY_CAP_BASER_FEC_LBN),
0361 baser_req = is_25g ? caps & (1 << MC_CMD_PHY_CAP_25G_BASER_FEC_REQUESTED_LBN)
0362 : caps & (1 << MC_CMD_PHY_CAP_BASER_FEC_REQUESTED_LBN);
0363
0364 if (!baser && !rs)
0365 return ETHTOOL_FEC_OFF;
0366 return (rs_req ? ETHTOOL_FEC_RS : 0) |
0367 (baser_req ? ETHTOOL_FEC_BASER : 0) |
0368 (baser == baser_req && rs == rs_req ? 0 : ETHTOOL_FEC_AUTO);
0369 }
0370
0371
0372
0373
0374 void efx_mcdi_phy_check_fcntl(struct efx_nic *efx, u32 lpa)
0375 {
0376 struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
0377 u32 rmtadv;
0378
0379
0380
0381
0382 if (~phy_cfg->supported_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
0383 return;
0384
0385
0386 if (efx->wanted_fc & EFX_FC_AUTO)
0387 return;
0388
0389 rmtadv = 0;
0390 if (lpa & (1 << MC_CMD_PHY_CAP_PAUSE_LBN))
0391 rmtadv |= ADVERTISED_Pause;
0392 if (lpa & (1 << MC_CMD_PHY_CAP_ASYM_LBN))
0393 rmtadv |= ADVERTISED_Asym_Pause;
0394
0395 if ((efx->wanted_fc & EFX_FC_TX) && rmtadv == ADVERTISED_Asym_Pause)
0396 netif_err(efx, link, efx->net_dev,
0397 "warning: link partner doesn't support pause frames");
0398 }
0399
0400 bool efx_mcdi_phy_poll(struct efx_nic *efx)
0401 {
0402 struct efx_link_state old_state = efx->link_state;
0403 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_LINK_OUT_LEN);
0404 int rc;
0405
0406 WARN_ON(!mutex_is_locked(&efx->mac_lock));
0407
0408 BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0);
0409
0410 rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,
0411 outbuf, sizeof(outbuf), NULL);
0412 if (rc)
0413 efx->link_state.up = false;
0414 else
0415 efx_mcdi_phy_decode_link(
0416 efx, &efx->link_state,
0417 MCDI_DWORD(outbuf, GET_LINK_OUT_LINK_SPEED),
0418 MCDI_DWORD(outbuf, GET_LINK_OUT_FLAGS),
0419 MCDI_DWORD(outbuf, GET_LINK_OUT_FCNTL));
0420
0421 return !efx_link_state_equal(&efx->link_state, &old_state);
0422 }
0423
0424 int efx_mcdi_phy_probe(struct efx_nic *efx)
0425 {
0426 struct efx_mcdi_phy_data *phy_data;
0427 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_LINK_OUT_LEN);
0428 u32 caps;
0429 int rc;
0430
0431
0432 phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL);
0433 if (phy_data == NULL)
0434 return -ENOMEM;
0435
0436 rc = efx_mcdi_get_phy_cfg(efx, phy_data);
0437 if (rc != 0)
0438 goto fail;
0439
0440
0441 BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0);
0442 rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,
0443 outbuf, sizeof(outbuf), NULL);
0444 if (rc)
0445 goto fail;
0446
0447
0448 efx->phy_data = phy_data;
0449 efx->phy_type = phy_data->type;
0450
0451 efx->mdio_bus = phy_data->channel;
0452 efx->mdio.prtad = phy_data->port;
0453 efx->mdio.mmds = phy_data->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22);
0454 efx->mdio.mode_support = 0;
0455 if (phy_data->mmd_mask & (1 << MC_CMD_MMD_CLAUSE22))
0456 efx->mdio.mode_support |= MDIO_SUPPORTS_C22;
0457 if (phy_data->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22))
0458 efx->mdio.mode_support |= MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;
0459
0460 caps = MCDI_DWORD(outbuf, GET_LINK_OUT_CAP);
0461 if (caps & (1 << MC_CMD_PHY_CAP_AN_LBN))
0462 mcdi_to_ethtool_linkset(phy_data->media, caps,
0463 efx->link_advertising);
0464 else
0465 phy_data->forced_cap = caps;
0466
0467
0468 BUILD_BUG_ON(LOOPBACK_NONE != MC_CMD_LOOPBACK_NONE);
0469 BUILD_BUG_ON(LOOPBACK_DATA != MC_CMD_LOOPBACK_DATA);
0470 BUILD_BUG_ON(LOOPBACK_GMAC != MC_CMD_LOOPBACK_GMAC);
0471 BUILD_BUG_ON(LOOPBACK_XGMII != MC_CMD_LOOPBACK_XGMII);
0472 BUILD_BUG_ON(LOOPBACK_XGXS != MC_CMD_LOOPBACK_XGXS);
0473 BUILD_BUG_ON(LOOPBACK_XAUI != MC_CMD_LOOPBACK_XAUI);
0474 BUILD_BUG_ON(LOOPBACK_GMII != MC_CMD_LOOPBACK_GMII);
0475 BUILD_BUG_ON(LOOPBACK_SGMII != MC_CMD_LOOPBACK_SGMII);
0476 BUILD_BUG_ON(LOOPBACK_XGBR != MC_CMD_LOOPBACK_XGBR);
0477 BUILD_BUG_ON(LOOPBACK_XFI != MC_CMD_LOOPBACK_XFI);
0478 BUILD_BUG_ON(LOOPBACK_XAUI_FAR != MC_CMD_LOOPBACK_XAUI_FAR);
0479 BUILD_BUG_ON(LOOPBACK_GMII_FAR != MC_CMD_LOOPBACK_GMII_FAR);
0480 BUILD_BUG_ON(LOOPBACK_SGMII_FAR != MC_CMD_LOOPBACK_SGMII_FAR);
0481 BUILD_BUG_ON(LOOPBACK_XFI_FAR != MC_CMD_LOOPBACK_XFI_FAR);
0482 BUILD_BUG_ON(LOOPBACK_GPHY != MC_CMD_LOOPBACK_GPHY);
0483 BUILD_BUG_ON(LOOPBACK_PHYXS != MC_CMD_LOOPBACK_PHYXS);
0484 BUILD_BUG_ON(LOOPBACK_PCS != MC_CMD_LOOPBACK_PCS);
0485 BUILD_BUG_ON(LOOPBACK_PMAPMD != MC_CMD_LOOPBACK_PMAPMD);
0486 BUILD_BUG_ON(LOOPBACK_XPORT != MC_CMD_LOOPBACK_XPORT);
0487 BUILD_BUG_ON(LOOPBACK_XGMII_WS != MC_CMD_LOOPBACK_XGMII_WS);
0488 BUILD_BUG_ON(LOOPBACK_XAUI_WS != MC_CMD_LOOPBACK_XAUI_WS);
0489 BUILD_BUG_ON(LOOPBACK_XAUI_WS_FAR != MC_CMD_LOOPBACK_XAUI_WS_FAR);
0490 BUILD_BUG_ON(LOOPBACK_XAUI_WS_NEAR != MC_CMD_LOOPBACK_XAUI_WS_NEAR);
0491 BUILD_BUG_ON(LOOPBACK_GMII_WS != MC_CMD_LOOPBACK_GMII_WS);
0492 BUILD_BUG_ON(LOOPBACK_XFI_WS != MC_CMD_LOOPBACK_XFI_WS);
0493 BUILD_BUG_ON(LOOPBACK_XFI_WS_FAR != MC_CMD_LOOPBACK_XFI_WS_FAR);
0494 BUILD_BUG_ON(LOOPBACK_PHYXS_WS != MC_CMD_LOOPBACK_PHYXS_WS);
0495
0496 rc = efx_mcdi_loopback_modes(efx, &efx->loopback_modes);
0497 if (rc != 0)
0498 goto fail;
0499
0500
0501
0502 efx->loopback_modes &= ~(1 << LOOPBACK_NONE);
0503
0504
0505 efx_mcdi_phy_decode_link(efx, &efx->link_state,
0506 MCDI_DWORD(outbuf, GET_LINK_OUT_LINK_SPEED),
0507 MCDI_DWORD(outbuf, GET_LINK_OUT_FLAGS),
0508 MCDI_DWORD(outbuf, GET_LINK_OUT_FCNTL));
0509
0510
0511
0512
0513 efx->fec_config = mcdi_fec_caps_to_ethtool(caps,
0514 efx->link_state.speed == 25000 ||
0515 efx->link_state.speed == 50000);
0516
0517
0518 efx->wanted_fc = EFX_FC_RX | EFX_FC_TX;
0519 if (phy_data->supported_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
0520 efx->wanted_fc |= EFX_FC_AUTO;
0521 efx_link_set_wanted_fc(efx, efx->wanted_fc);
0522
0523 return 0;
0524
0525 fail:
0526 kfree(phy_data);
0527 return rc;
0528 }
0529
0530 void efx_mcdi_phy_remove(struct efx_nic *efx)
0531 {
0532 struct efx_mcdi_phy_data *phy_data = efx->phy_data;
0533
0534 efx->phy_data = NULL;
0535 kfree(phy_data);
0536 }
0537
0538 void efx_mcdi_phy_get_link_ksettings(struct efx_nic *efx, struct ethtool_link_ksettings *cmd)
0539 {
0540 struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
0541 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_LINK_OUT_LEN);
0542 int rc;
0543
0544 cmd->base.speed = efx->link_state.speed;
0545 cmd->base.duplex = efx->link_state.fd;
0546 cmd->base.port = mcdi_to_ethtool_media(phy_cfg->media);
0547 cmd->base.phy_address = phy_cfg->port;
0548 cmd->base.autoneg = !!(efx->link_advertising[0] & ADVERTISED_Autoneg);
0549 cmd->base.mdio_support = (efx->mdio.mode_support &
0550 (MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22));
0551
0552 mcdi_to_ethtool_linkset(phy_cfg->media, phy_cfg->supported_cap,
0553 cmd->link_modes.supported);
0554 memcpy(cmd->link_modes.advertising, efx->link_advertising,
0555 sizeof(__ETHTOOL_DECLARE_LINK_MODE_MASK()));
0556
0557 BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0);
0558 rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,
0559 outbuf, sizeof(outbuf), NULL);
0560 if (rc)
0561 return;
0562 mcdi_to_ethtool_linkset(phy_cfg->media,
0563 MCDI_DWORD(outbuf, GET_LINK_OUT_LP_CAP),
0564 cmd->link_modes.lp_advertising);
0565 }
0566
0567 int efx_mcdi_phy_set_link_ksettings(struct efx_nic *efx, const struct ethtool_link_ksettings *cmd)
0568 {
0569 struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
0570 u32 caps;
0571 int rc;
0572
0573 if (cmd->base.autoneg) {
0574 caps = (ethtool_linkset_to_mcdi_cap(cmd->link_modes.advertising) |
0575 1 << MC_CMD_PHY_CAP_AN_LBN);
0576 } else if (cmd->base.duplex) {
0577 switch (cmd->base.speed) {
0578 case 10: caps = 1 << MC_CMD_PHY_CAP_10FDX_LBN; break;
0579 case 100: caps = 1 << MC_CMD_PHY_CAP_100FDX_LBN; break;
0580 case 1000: caps = 1 << MC_CMD_PHY_CAP_1000FDX_LBN; break;
0581 case 10000: caps = 1 << MC_CMD_PHY_CAP_10000FDX_LBN; break;
0582 case 40000: caps = 1 << MC_CMD_PHY_CAP_40000FDX_LBN; break;
0583 case 100000: caps = 1 << MC_CMD_PHY_CAP_100000FDX_LBN; break;
0584 case 25000: caps = 1 << MC_CMD_PHY_CAP_25000FDX_LBN; break;
0585 case 50000: caps = 1 << MC_CMD_PHY_CAP_50000FDX_LBN; break;
0586 default: return -EINVAL;
0587 }
0588 } else {
0589 switch (cmd->base.speed) {
0590 case 10: caps = 1 << MC_CMD_PHY_CAP_10HDX_LBN; break;
0591 case 100: caps = 1 << MC_CMD_PHY_CAP_100HDX_LBN; break;
0592 case 1000: caps = 1 << MC_CMD_PHY_CAP_1000HDX_LBN; break;
0593 default: return -EINVAL;
0594 }
0595 }
0596
0597 caps |= ethtool_fec_caps_to_mcdi(phy_cfg->supported_cap, efx->fec_config);
0598
0599 rc = efx_mcdi_set_link(efx, caps, efx_get_mcdi_phy_flags(efx),
0600 efx->loopback_mode, 0);
0601 if (rc)
0602 return rc;
0603
0604 if (cmd->base.autoneg) {
0605 efx_link_set_advertising(efx, cmd->link_modes.advertising);
0606 phy_cfg->forced_cap = 0;
0607 } else {
0608 efx_link_clear_advertising(efx);
0609 phy_cfg->forced_cap = caps;
0610 }
0611 return 0;
0612 }
0613
0614 int efx_mcdi_phy_get_fecparam(struct efx_nic *efx, struct ethtool_fecparam *fec)
0615 {
0616 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_LINK_OUT_V2_LEN);
0617 u32 caps, active, speed;
0618 bool is_25g = false;
0619 size_t outlen;
0620 int rc;
0621
0622 BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0);
0623 rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,
0624 outbuf, sizeof(outbuf), &outlen);
0625 if (rc)
0626 return rc;
0627 if (outlen < MC_CMD_GET_LINK_OUT_V2_LEN)
0628 return -EOPNOTSUPP;
0629
0630
0631 speed = MCDI_DWORD(outbuf, GET_LINK_OUT_V2_LINK_SPEED);
0632 is_25g = speed == 25000 || speed == 50000;
0633
0634 caps = MCDI_DWORD(outbuf, GET_LINK_OUT_V2_CAP);
0635 fec->fec = mcdi_fec_caps_to_ethtool(caps, is_25g);
0636
0637 if (speed == 100000)
0638 fec->fec &= ~ETHTOOL_FEC_BASER;
0639
0640 active = MCDI_DWORD(outbuf, GET_LINK_OUT_V2_FEC_TYPE);
0641 switch (active) {
0642 case MC_CMD_FEC_NONE:
0643 fec->active_fec = ETHTOOL_FEC_OFF;
0644 break;
0645 case MC_CMD_FEC_BASER:
0646 fec->active_fec = ETHTOOL_FEC_BASER;
0647 break;
0648 case MC_CMD_FEC_RS:
0649 fec->active_fec = ETHTOOL_FEC_RS;
0650 break;
0651 default:
0652 netif_warn(efx, hw, efx->net_dev,
0653 "Firmware reports unrecognised FEC_TYPE %u\n",
0654 active);
0655
0656
0657
0658 fec->active_fec = ETHTOOL_FEC_AUTO;
0659 break;
0660 }
0661
0662 return 0;
0663 }
0664
0665
0666
0667
0668 static int ethtool_fec_supported(u32 supported_cap, u32 ethtool_cap)
0669 {
0670 if (ethtool_cap & ETHTOOL_FEC_OFF)
0671 return 0;
0672
0673 if (ethtool_cap &&
0674 !ethtool_fec_caps_to_mcdi(supported_cap, ethtool_cap))
0675 return -EINVAL;
0676 return 0;
0677 }
0678
0679 int efx_mcdi_phy_set_fecparam(struct efx_nic *efx, const struct ethtool_fecparam *fec)
0680 {
0681 struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
0682 u32 caps;
0683 int rc;
0684
0685 rc = ethtool_fec_supported(phy_cfg->supported_cap, fec->fec);
0686 if (rc)
0687 return rc;
0688
0689
0690
0691
0692 if (test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, efx->link_advertising))
0693 caps = (ethtool_linkset_to_mcdi_cap(efx->link_advertising) |
0694 1 << MC_CMD_PHY_CAP_AN_LBN);
0695 else
0696 caps = phy_cfg->forced_cap;
0697
0698 caps |= ethtool_fec_caps_to_mcdi(phy_cfg->supported_cap, fec->fec);
0699 rc = efx_mcdi_set_link(efx, caps, efx_get_mcdi_phy_flags(efx),
0700 efx->loopback_mode, 0);
0701 if (rc)
0702 return rc;
0703
0704
0705 efx->fec_config = fec->fec;
0706 return 0;
0707 }
0708
0709 int efx_mcdi_phy_test_alive(struct efx_nic *efx)
0710 {
0711 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_PHY_STATE_OUT_LEN);
0712 size_t outlen;
0713 int rc;
0714
0715 BUILD_BUG_ON(MC_CMD_GET_PHY_STATE_IN_LEN != 0);
0716
0717 rc = efx_mcdi_rpc(efx, MC_CMD_GET_PHY_STATE, NULL, 0,
0718 outbuf, sizeof(outbuf), &outlen);
0719 if (rc)
0720 return rc;
0721
0722 if (outlen < MC_CMD_GET_PHY_STATE_OUT_LEN)
0723 return -EIO;
0724 if (MCDI_DWORD(outbuf, GET_PHY_STATE_OUT_STATE) != MC_CMD_PHY_STATE_OK)
0725 return -EINVAL;
0726
0727 return 0;
0728 }
0729
0730 int efx_mcdi_port_reconfigure(struct efx_nic *efx)
0731 {
0732 struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
0733 u32 caps = (efx->link_advertising[0] ?
0734 ethtool_linkset_to_mcdi_cap(efx->link_advertising) :
0735 phy_cfg->forced_cap);
0736
0737 caps |= ethtool_fec_caps_to_mcdi(phy_cfg->supported_cap, efx->fec_config);
0738
0739 return efx_mcdi_set_link(efx, caps, efx_get_mcdi_phy_flags(efx),
0740 efx->loopback_mode, 0);
0741 }
0742
0743 static const char *const mcdi_sft9001_cable_diag_names[] = {
0744 "cable.pairA.length",
0745 "cable.pairB.length",
0746 "cable.pairC.length",
0747 "cable.pairD.length",
0748 "cable.pairA.status",
0749 "cable.pairB.status",
0750 "cable.pairC.status",
0751 "cable.pairD.status",
0752 };
0753
0754 static int efx_mcdi_bist(struct efx_nic *efx, unsigned int bist_mode,
0755 int *results)
0756 {
0757 unsigned int retry, i, count = 0;
0758 size_t outlen;
0759 u32 status;
0760 MCDI_DECLARE_BUF(inbuf, MC_CMD_START_BIST_IN_LEN);
0761 MCDI_DECLARE_BUF(outbuf, MC_CMD_POLL_BIST_OUT_SFT9001_LEN);
0762 u8 *ptr;
0763 int rc;
0764
0765 BUILD_BUG_ON(MC_CMD_START_BIST_OUT_LEN != 0);
0766 MCDI_SET_DWORD(inbuf, START_BIST_IN_TYPE, bist_mode);
0767 rc = efx_mcdi_rpc(efx, MC_CMD_START_BIST,
0768 inbuf, MC_CMD_START_BIST_IN_LEN, NULL, 0, NULL);
0769 if (rc)
0770 goto out;
0771
0772
0773 for (retry = 0; retry < 100; ++retry) {
0774 BUILD_BUG_ON(MC_CMD_POLL_BIST_IN_LEN != 0);
0775 rc = efx_mcdi_rpc(efx, MC_CMD_POLL_BIST, NULL, 0,
0776 outbuf, sizeof(outbuf), &outlen);
0777 if (rc)
0778 goto out;
0779
0780 status = MCDI_DWORD(outbuf, POLL_BIST_OUT_RESULT);
0781 if (status != MC_CMD_POLL_BIST_RUNNING)
0782 goto finished;
0783
0784 msleep(100);
0785 }
0786
0787 rc = -ETIMEDOUT;
0788 goto out;
0789
0790 finished:
0791 results[count++] = (status == MC_CMD_POLL_BIST_PASSED) ? 1 : -1;
0792
0793
0794 if (efx->phy_type == PHY_TYPE_SFT9001B &&
0795 (bist_mode == MC_CMD_PHY_BIST_CABLE_SHORT ||
0796 bist_mode == MC_CMD_PHY_BIST_CABLE_LONG)) {
0797 ptr = MCDI_PTR(outbuf, POLL_BIST_OUT_SFT9001_CABLE_LENGTH_A);
0798 if (status == MC_CMD_POLL_BIST_PASSED &&
0799 outlen >= MC_CMD_POLL_BIST_OUT_SFT9001_LEN) {
0800 for (i = 0; i < 8; i++) {
0801 results[count + i] =
0802 EFX_DWORD_FIELD(((efx_dword_t *)ptr)[i],
0803 EFX_DWORD_0);
0804 }
0805 }
0806 count += 8;
0807 }
0808 rc = count;
0809
0810 out:
0811 return rc;
0812 }
0813
0814 int efx_mcdi_phy_run_tests(struct efx_nic *efx, int *results, unsigned int flags)
0815 {
0816 struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
0817 u32 mode;
0818 int rc;
0819
0820 if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_OUT_BIST_LBN)) {
0821 rc = efx_mcdi_bist(efx, MC_CMD_PHY_BIST, results);
0822 if (rc < 0)
0823 return rc;
0824
0825 results += rc;
0826 }
0827
0828
0829
0830
0831 mode = 0;
0832 if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_OUT_BIST_CABLE_SHORT_LBN)) {
0833 if ((flags & ETH_TEST_FL_OFFLINE) &&
0834 (phy_cfg->flags &
0835 (1 << MC_CMD_GET_PHY_CFG_OUT_BIST_CABLE_LONG_LBN)))
0836 mode = MC_CMD_PHY_BIST_CABLE_LONG;
0837 else
0838 mode = MC_CMD_PHY_BIST_CABLE_SHORT;
0839 } else if (phy_cfg->flags &
0840 (1 << MC_CMD_GET_PHY_CFG_OUT_BIST_CABLE_LONG_LBN))
0841 mode = MC_CMD_PHY_BIST_CABLE_LONG;
0842
0843 if (mode != 0) {
0844 rc = efx_mcdi_bist(efx, mode, results);
0845 if (rc < 0)
0846 return rc;
0847 results += rc;
0848 }
0849
0850 return 0;
0851 }
0852
0853 const char *efx_mcdi_phy_test_name(struct efx_nic *efx, unsigned int index)
0854 {
0855 struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
0856
0857 if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_OUT_BIST_LBN)) {
0858 if (index == 0)
0859 return "bist";
0860 --index;
0861 }
0862
0863 if (phy_cfg->flags & ((1 << MC_CMD_GET_PHY_CFG_OUT_BIST_CABLE_SHORT_LBN) |
0864 (1 << MC_CMD_GET_PHY_CFG_OUT_BIST_CABLE_LONG_LBN))) {
0865 if (index == 0)
0866 return "cable";
0867 --index;
0868
0869 if (efx->phy_type == PHY_TYPE_SFT9001B) {
0870 if (index < ARRAY_SIZE(mcdi_sft9001_cable_diag_names))
0871 return mcdi_sft9001_cable_diag_names[index];
0872 index -= ARRAY_SIZE(mcdi_sft9001_cable_diag_names);
0873 }
0874 }
0875
0876 return NULL;
0877 }
0878
0879 #define SFP_PAGE_SIZE 128
0880 #define SFF_DIAG_TYPE_OFFSET 92
0881 #define SFF_DIAG_ADDR_CHANGE BIT(2)
0882 #define SFF_8079_NUM_PAGES 2
0883 #define SFF_8472_NUM_PAGES 4
0884 #define SFF_8436_NUM_PAGES 5
0885 #define SFF_DMT_LEVEL_OFFSET 94
0886
0887
0888
0889
0890
0891
0892
0893
0894
0895
0896
0897
0898 static int efx_mcdi_phy_get_module_eeprom_page(struct efx_nic *efx,
0899 unsigned int page,
0900 u8 *data, ssize_t offset,
0901 ssize_t space)
0902 {
0903 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_PHY_MEDIA_INFO_OUT_LENMAX);
0904 MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN);
0905 unsigned int payload_len;
0906 unsigned int to_copy;
0907 size_t outlen;
0908 int rc;
0909
0910 if (offset > SFP_PAGE_SIZE)
0911 return -EINVAL;
0912
0913 to_copy = min(space, SFP_PAGE_SIZE - offset);
0914
0915 MCDI_SET_DWORD(inbuf, GET_PHY_MEDIA_INFO_IN_PAGE, page);
0916 rc = efx_mcdi_rpc_quiet(efx, MC_CMD_GET_PHY_MEDIA_INFO,
0917 inbuf, sizeof(inbuf),
0918 outbuf, sizeof(outbuf),
0919 &outlen);
0920
0921 if (rc)
0922 return rc;
0923
0924 if (outlen < (MC_CMD_GET_PHY_MEDIA_INFO_OUT_DATA_OFST +
0925 SFP_PAGE_SIZE))
0926 return -EIO;
0927
0928 payload_len = MCDI_DWORD(outbuf, GET_PHY_MEDIA_INFO_OUT_DATALEN);
0929 if (payload_len != SFP_PAGE_SIZE)
0930 return -EIO;
0931
0932 memcpy(data, MCDI_PTR(outbuf, GET_PHY_MEDIA_INFO_OUT_DATA) + offset,
0933 to_copy);
0934
0935 return to_copy;
0936 }
0937
0938 static int efx_mcdi_phy_get_module_eeprom_byte(struct efx_nic *efx,
0939 unsigned int page,
0940 u8 byte)
0941 {
0942 u8 data;
0943 int rc;
0944
0945 rc = efx_mcdi_phy_get_module_eeprom_page(efx, page, &data, byte, 1);
0946 if (rc == 1)
0947 return data;
0948
0949 return rc;
0950 }
0951
0952 static int efx_mcdi_phy_diag_type(struct efx_nic *efx)
0953 {
0954
0955 return efx_mcdi_phy_get_module_eeprom_byte(efx, 0,
0956 SFF_DIAG_TYPE_OFFSET);
0957 }
0958
0959 static int efx_mcdi_phy_sff_8472_level(struct efx_nic *efx)
0960 {
0961
0962 return efx_mcdi_phy_get_module_eeprom_byte(efx, 0,
0963 SFF_DMT_LEVEL_OFFSET);
0964 }
0965
0966 static u32 efx_mcdi_phy_module_type(struct efx_nic *efx)
0967 {
0968 struct efx_mcdi_phy_data *phy_data = efx->phy_data;
0969
0970 if (phy_data->media != MC_CMD_MEDIA_QSFP_PLUS)
0971 return phy_data->media;
0972
0973
0974
0975
0976 switch (efx_mcdi_phy_get_module_eeprom_byte(efx, 0, 0)) {
0977 case 0x3:
0978 return MC_CMD_MEDIA_SFP_PLUS;
0979 case 0xc:
0980 case 0xd:
0981 return MC_CMD_MEDIA_QSFP_PLUS;
0982 default:
0983 return 0;
0984 }
0985 }
0986
0987 int efx_mcdi_phy_get_module_eeprom(struct efx_nic *efx, struct ethtool_eeprom *ee, u8 *data)
0988 {
0989 int rc;
0990 ssize_t space_remaining = ee->len;
0991 unsigned int page_off;
0992 bool ignore_missing;
0993 int num_pages;
0994 int page;
0995
0996 switch (efx_mcdi_phy_module_type(efx)) {
0997 case MC_CMD_MEDIA_SFP_PLUS:
0998 num_pages = efx_mcdi_phy_sff_8472_level(efx) > 0 ?
0999 SFF_8472_NUM_PAGES : SFF_8079_NUM_PAGES;
1000 page = 0;
1001 ignore_missing = false;
1002 break;
1003 case MC_CMD_MEDIA_QSFP_PLUS:
1004 num_pages = SFF_8436_NUM_PAGES;
1005 page = -1;
1006 ignore_missing = true;
1007 break;
1008 default:
1009 return -EOPNOTSUPP;
1010 }
1011
1012 page_off = ee->offset % SFP_PAGE_SIZE;
1013 page += ee->offset / SFP_PAGE_SIZE;
1014
1015 while (space_remaining && (page < num_pages)) {
1016 rc = efx_mcdi_phy_get_module_eeprom_page(efx, page,
1017 data, page_off,
1018 space_remaining);
1019
1020 if (rc > 0) {
1021 space_remaining -= rc;
1022 data += rc;
1023 page_off = 0;
1024 page++;
1025 } else if (rc == 0) {
1026 space_remaining = 0;
1027 } else if (ignore_missing && (page > 0)) {
1028 int intended_size = SFP_PAGE_SIZE - page_off;
1029
1030 space_remaining -= intended_size;
1031 if (space_remaining < 0) {
1032 space_remaining = 0;
1033 } else {
1034 memset(data, 0, intended_size);
1035 data += intended_size;
1036 page_off = 0;
1037 page++;
1038 rc = 0;
1039 }
1040 } else {
1041 return rc;
1042 }
1043 }
1044
1045 return 0;
1046 }
1047
1048 int efx_mcdi_phy_get_module_info(struct efx_nic *efx, struct ethtool_modinfo *modinfo)
1049 {
1050 int sff_8472_level;
1051 int diag_type;
1052
1053 switch (efx_mcdi_phy_module_type(efx)) {
1054 case MC_CMD_MEDIA_SFP_PLUS:
1055 sff_8472_level = efx_mcdi_phy_sff_8472_level(efx);
1056
1057
1058 if (sff_8472_level < 0)
1059 return -EOPNOTSUPP;
1060
1061
1062
1063
1064 diag_type = efx_mcdi_phy_diag_type(efx);
1065
1066 if (sff_8472_level == 0 ||
1067 (diag_type & SFF_DIAG_ADDR_CHANGE)) {
1068 modinfo->type = ETH_MODULE_SFF_8079;
1069 modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
1070 } else {
1071 modinfo->type = ETH_MODULE_SFF_8472;
1072 modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
1073 }
1074 break;
1075
1076 case MC_CMD_MEDIA_QSFP_PLUS:
1077 modinfo->type = ETH_MODULE_SFF_8436;
1078 modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN;
1079 break;
1080
1081 default:
1082 return -EOPNOTSUPP;
1083 }
1084
1085 return 0;
1086 }
1087
1088 static unsigned int efx_calc_mac_mtu(struct efx_nic *efx)
1089 {
1090 return EFX_MAX_FRAME_LEN(efx->net_dev->mtu);
1091 }
1092
1093 int efx_mcdi_set_mac(struct efx_nic *efx)
1094 {
1095 u32 fcntl;
1096 MCDI_DECLARE_BUF(cmdbytes, MC_CMD_SET_MAC_IN_LEN);
1097
1098 BUILD_BUG_ON(MC_CMD_SET_MAC_OUT_LEN != 0);
1099
1100
1101 ether_addr_copy(MCDI_PTR(cmdbytes, SET_MAC_IN_ADDR),
1102 efx->net_dev->dev_addr);
1103
1104 MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_MTU, efx_calc_mac_mtu(efx));
1105 MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_DRAIN, 0);
1106
1107
1108 MCDI_POPULATE_DWORD_1(cmdbytes, SET_MAC_IN_REJECT,
1109 SET_MAC_IN_REJECT_UNCST, efx->unicast_filter);
1110
1111 MCDI_POPULATE_DWORD_1(cmdbytes, SET_MAC_IN_FLAGS,
1112 SET_MAC_IN_FLAG_INCLUDE_FCS,
1113 !!(efx->net_dev->features & NETIF_F_RXFCS));
1114
1115 switch (efx->wanted_fc) {
1116 case EFX_FC_RX | EFX_FC_TX:
1117 fcntl = MC_CMD_FCNTL_BIDIR;
1118 break;
1119 case EFX_FC_RX:
1120 fcntl = MC_CMD_FCNTL_RESPOND;
1121 break;
1122 default:
1123 fcntl = MC_CMD_FCNTL_OFF;
1124 break;
1125 }
1126 if (efx->wanted_fc & EFX_FC_AUTO)
1127 fcntl = MC_CMD_FCNTL_AUTO;
1128 if (efx->fc_disable)
1129 fcntl = MC_CMD_FCNTL_OFF;
1130
1131 MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_FCNTL, fcntl);
1132
1133 return efx_mcdi_rpc(efx, MC_CMD_SET_MAC, cmdbytes, sizeof(cmdbytes),
1134 NULL, 0, NULL);
1135 }
1136
1137 int efx_mcdi_set_mtu(struct efx_nic *efx)
1138 {
1139 MCDI_DECLARE_BUF(inbuf, MC_CMD_SET_MAC_EXT_IN_LEN);
1140
1141 BUILD_BUG_ON(MC_CMD_SET_MAC_OUT_LEN != 0);
1142
1143 MCDI_SET_DWORD(inbuf, SET_MAC_EXT_IN_MTU, efx_calc_mac_mtu(efx));
1144
1145 MCDI_POPULATE_DWORD_1(inbuf, SET_MAC_EXT_IN_CONTROL,
1146 SET_MAC_EXT_IN_CFG_MTU, 1);
1147
1148 return efx_mcdi_rpc(efx, MC_CMD_SET_MAC, inbuf, sizeof(inbuf),
1149 NULL, 0, NULL);
1150 }
1151
1152 enum efx_stats_action {
1153 EFX_STATS_ENABLE,
1154 EFX_STATS_DISABLE,
1155 EFX_STATS_PULL,
1156 };
1157
1158 static int efx_mcdi_mac_stats(struct efx_nic *efx,
1159 enum efx_stats_action action, int clear)
1160 {
1161 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAC_STATS_IN_LEN);
1162 int rc;
1163 int change = action == EFX_STATS_PULL ? 0 : 1;
1164 int enable = action == EFX_STATS_ENABLE ? 1 : 0;
1165 int period = action == EFX_STATS_ENABLE ? 1000 : 0;
1166 dma_addr_t dma_addr = efx->stats_buffer.dma_addr;
1167 u32 dma_len = action != EFX_STATS_DISABLE ?
1168 efx->num_mac_stats * sizeof(u64) : 0;
1169
1170 BUILD_BUG_ON(MC_CMD_MAC_STATS_OUT_DMA_LEN != 0);
1171
1172 MCDI_SET_QWORD(inbuf, MAC_STATS_IN_DMA_ADDR, dma_addr);
1173 MCDI_POPULATE_DWORD_7(inbuf, MAC_STATS_IN_CMD,
1174 MAC_STATS_IN_DMA, !!enable,
1175 MAC_STATS_IN_CLEAR, clear,
1176 MAC_STATS_IN_PERIODIC_CHANGE, change,
1177 MAC_STATS_IN_PERIODIC_ENABLE, enable,
1178 MAC_STATS_IN_PERIODIC_CLEAR, 0,
1179 MAC_STATS_IN_PERIODIC_NOEVENT, 1,
1180 MAC_STATS_IN_PERIOD_MS, period);
1181 MCDI_SET_DWORD(inbuf, MAC_STATS_IN_DMA_LEN, dma_len);
1182
1183 if (efx_nic_rev(efx) >= EFX_REV_HUNT_A0)
1184 MCDI_SET_DWORD(inbuf, MAC_STATS_IN_PORT_ID, efx->vport_id);
1185
1186 rc = efx_mcdi_rpc_quiet(efx, MC_CMD_MAC_STATS, inbuf, sizeof(inbuf),
1187 NULL, 0, NULL);
1188
1189 if (rc && (rc != -ENOENT || atomic_read(&efx->active_queues)))
1190 efx_mcdi_display_error(efx, MC_CMD_MAC_STATS, sizeof(inbuf),
1191 NULL, 0, rc);
1192 return rc;
1193 }
1194
1195 void efx_mcdi_mac_start_stats(struct efx_nic *efx)
1196 {
1197 __le64 *dma_stats = efx->stats_buffer.addr;
1198
1199 dma_stats[efx->num_mac_stats - 1] = EFX_MC_STATS_GENERATION_INVALID;
1200
1201 efx_mcdi_mac_stats(efx, EFX_STATS_ENABLE, 0);
1202 }
1203
1204 void efx_mcdi_mac_stop_stats(struct efx_nic *efx)
1205 {
1206 efx_mcdi_mac_stats(efx, EFX_STATS_DISABLE, 0);
1207 }
1208
1209 #define EFX_MAC_STATS_WAIT_US 100
1210 #define EFX_MAC_STATS_WAIT_ATTEMPTS 10
1211
1212 void efx_mcdi_mac_pull_stats(struct efx_nic *efx)
1213 {
1214 __le64 *dma_stats = efx->stats_buffer.addr;
1215 int attempts = EFX_MAC_STATS_WAIT_ATTEMPTS;
1216
1217 dma_stats[efx->num_mac_stats - 1] = EFX_MC_STATS_GENERATION_INVALID;
1218 efx_mcdi_mac_stats(efx, EFX_STATS_PULL, 0);
1219
1220 while (dma_stats[efx->num_mac_stats - 1] ==
1221 EFX_MC_STATS_GENERATION_INVALID &&
1222 attempts-- != 0)
1223 udelay(EFX_MAC_STATS_WAIT_US);
1224 }
1225
1226 int efx_mcdi_mac_init_stats(struct efx_nic *efx)
1227 {
1228 int rc;
1229
1230 if (!efx->num_mac_stats)
1231 return 0;
1232
1233
1234 rc = efx_nic_alloc_buffer(efx, &efx->stats_buffer,
1235 efx->num_mac_stats * sizeof(u64), GFP_KERNEL);
1236 if (rc) {
1237 netif_warn(efx, probe, efx->net_dev,
1238 "failed to allocate DMA buffer: %d\n", rc);
1239 return rc;
1240 }
1241
1242 netif_dbg(efx, probe, efx->net_dev,
1243 "stats buffer at %llx (virt %p phys %llx)\n",
1244 (u64) efx->stats_buffer.dma_addr,
1245 efx->stats_buffer.addr,
1246 (u64) virt_to_phys(efx->stats_buffer.addr));
1247
1248 return 0;
1249 }
1250
1251 void efx_mcdi_mac_fini_stats(struct efx_nic *efx)
1252 {
1253 efx_nic_free_buffer(efx, &efx->stats_buffer);
1254 }
1255
1256
1257 int efx_mcdi_port_get_number(struct efx_nic *efx)
1258 {
1259 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN);
1260 int rc;
1261
1262 rc = efx_mcdi_rpc(efx, MC_CMD_GET_PORT_ASSIGNMENT, NULL, 0,
1263 outbuf, sizeof(outbuf), NULL);
1264 if (rc)
1265 return rc;
1266
1267 return MCDI_DWORD(outbuf, GET_PORT_ASSIGNMENT_OUT_PORT);
1268 }
1269
1270 static unsigned int efx_mcdi_event_link_speed[] = {
1271 [MCDI_EVENT_LINKCHANGE_SPEED_100M] = 100,
1272 [MCDI_EVENT_LINKCHANGE_SPEED_1G] = 1000,
1273 [MCDI_EVENT_LINKCHANGE_SPEED_10G] = 10000,
1274 [MCDI_EVENT_LINKCHANGE_SPEED_40G] = 40000,
1275 [MCDI_EVENT_LINKCHANGE_SPEED_25G] = 25000,
1276 [MCDI_EVENT_LINKCHANGE_SPEED_50G] = 50000,
1277 [MCDI_EVENT_LINKCHANGE_SPEED_100G] = 100000,
1278 };
1279
1280 void efx_mcdi_process_link_change(struct efx_nic *efx, efx_qword_t *ev)
1281 {
1282 u32 flags, fcntl, speed, lpa;
1283
1284 speed = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_SPEED);
1285 EFX_WARN_ON_PARANOID(speed >= ARRAY_SIZE(efx_mcdi_event_link_speed));
1286 speed = efx_mcdi_event_link_speed[speed];
1287
1288 flags = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_LINK_FLAGS);
1289 fcntl = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_FCNTL);
1290 lpa = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_LP_CAP);
1291
1292
1293
1294
1295
1296 efx_mcdi_phy_decode_link(efx, &efx->link_state, speed, flags, fcntl);
1297
1298 efx_mcdi_phy_check_fcntl(efx, lpa);
1299
1300 efx_link_status_changed(efx);
1301 }