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