1283 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/****************************************************************************3 * Driver for Solarflare network controllers and boards4 * Copyright 2018 Solarflare Communications Inc.5 *6 * This program is free software; you can redistribute it and/or modify it7 * under the terms of the GNU General Public License version 2 as published8 * by the Free Software Foundation, incorporated herein by reference.9 */10 11#include "mcdi_port_common.h"12#include "efx_common.h"13#include "nic.h"14 15static int efx_mcdi_get_phy_cfg(struct efx_nic *efx,16 struct efx_mcdi_phy_data *cfg)17{18 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_PHY_CFG_OUT_LEN);19 size_t outlen;20 int rc;21 22 BUILD_BUG_ON(MC_CMD_GET_PHY_CFG_IN_LEN != 0);23 BUILD_BUG_ON(MC_CMD_GET_PHY_CFG_OUT_NAME_LEN != sizeof(cfg->name));24 25 rc = efx_siena_mcdi_rpc(efx, MC_CMD_GET_PHY_CFG, NULL, 0,26 outbuf, sizeof(outbuf), &outlen);27 if (rc)28 goto fail;29 30 if (outlen < MC_CMD_GET_PHY_CFG_OUT_LEN) {31 rc = -EIO;32 goto fail;33 }34 35 cfg->flags = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_FLAGS);36 cfg->type = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_TYPE);37 cfg->supported_cap =38 MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_SUPPORTED_CAP);39 cfg->channel = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_CHANNEL);40 cfg->port = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_PRT);41 cfg->stats_mask = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_STATS_MASK);42 memcpy(cfg->name, MCDI_PTR(outbuf, GET_PHY_CFG_OUT_NAME),43 sizeof(cfg->name));44 cfg->media = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_MEDIA_TYPE);45 cfg->mmd_mask = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_MMD_MASK);46 memcpy(cfg->revision, MCDI_PTR(outbuf, GET_PHY_CFG_OUT_REVISION),47 sizeof(cfg->revision));48 49 return 0;50 51fail:52 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);53 return rc;54}55 56void efx_siena_link_set_advertising(struct efx_nic *efx,57 const unsigned long *advertising)58{59 memcpy(efx->link_advertising, advertising,60 sizeof(__ETHTOOL_DECLARE_LINK_MODE_MASK()));61 62 efx->link_advertising[0] |= ADVERTISED_Autoneg;63 if (advertising[0] & ADVERTISED_Pause)64 efx->wanted_fc |= (EFX_FC_TX | EFX_FC_RX);65 else66 efx->wanted_fc &= ~(EFX_FC_TX | EFX_FC_RX);67 if (advertising[0] & ADVERTISED_Asym_Pause)68 efx->wanted_fc ^= EFX_FC_TX;69}70 71static int efx_mcdi_set_link(struct efx_nic *efx, u32 capabilities,72 u32 flags, u32 loopback_mode, u32 loopback_speed)73{74 MCDI_DECLARE_BUF(inbuf, MC_CMD_SET_LINK_IN_LEN);75 76 BUILD_BUG_ON(MC_CMD_SET_LINK_OUT_LEN != 0);77 78 MCDI_SET_DWORD(inbuf, SET_LINK_IN_CAP, capabilities);79 MCDI_SET_DWORD(inbuf, SET_LINK_IN_FLAGS, flags);80 MCDI_SET_DWORD(inbuf, SET_LINK_IN_LOOPBACK_MODE, loopback_mode);81 MCDI_SET_DWORD(inbuf, SET_LINK_IN_LOOPBACK_SPEED, loopback_speed);82 83 return efx_siena_mcdi_rpc(efx, MC_CMD_SET_LINK, inbuf, sizeof(inbuf),84 NULL, 0, NULL);85}86 87static int efx_mcdi_loopback_modes(struct efx_nic *efx, u64 *loopback_modes)88{89 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_LOOPBACK_MODES_OUT_LEN);90 size_t outlen;91 int rc;92 93 rc = efx_siena_mcdi_rpc(efx, MC_CMD_GET_LOOPBACK_MODES, NULL, 0,94 outbuf, sizeof(outbuf), &outlen);95 if (rc)96 goto fail;97 98 if (outlen < (MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_OFST +99 MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_LEN)) {100 rc = -EIO;101 goto fail;102 }103 104 *loopback_modes = MCDI_QWORD(outbuf, GET_LOOPBACK_MODES_OUT_SUGGESTED);105 106 return 0;107 108fail:109 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);110 return rc;111}112 113static void mcdi_to_ethtool_linkset(u32 media, u32 cap, unsigned long *linkset)114{115 #define SET_BIT(name) __set_bit(ETHTOOL_LINK_MODE_ ## name ## _BIT, \116 linkset)117 118 bitmap_zero(linkset, __ETHTOOL_LINK_MODE_MASK_NBITS);119 switch (media) {120 case MC_CMD_MEDIA_KX4:121 SET_BIT(Backplane);122 if (cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN))123 SET_BIT(1000baseKX_Full);124 if (cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN))125 SET_BIT(10000baseKX4_Full);126 if (cap & (1 << MC_CMD_PHY_CAP_40000FDX_LBN))127 SET_BIT(40000baseKR4_Full);128 break;129 130 case MC_CMD_MEDIA_XFP:131 case MC_CMD_MEDIA_SFP_PLUS:132 case MC_CMD_MEDIA_QSFP_PLUS:133 SET_BIT(FIBRE);134 if (cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN)) {135 SET_BIT(1000baseT_Full);136 SET_BIT(1000baseX_Full);137 }138 if (cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN)) {139 SET_BIT(10000baseCR_Full);140 SET_BIT(10000baseLR_Full);141 SET_BIT(10000baseSR_Full);142 }143 if (cap & (1 << MC_CMD_PHY_CAP_40000FDX_LBN)) {144 SET_BIT(40000baseCR4_Full);145 SET_BIT(40000baseSR4_Full);146 }147 if (cap & (1 << MC_CMD_PHY_CAP_100000FDX_LBN)) {148 SET_BIT(100000baseCR4_Full);149 SET_BIT(100000baseSR4_Full);150 }151 if (cap & (1 << MC_CMD_PHY_CAP_25000FDX_LBN)) {152 SET_BIT(25000baseCR_Full);153 SET_BIT(25000baseSR_Full);154 }155 if (cap & (1 << MC_CMD_PHY_CAP_50000FDX_LBN))156 SET_BIT(50000baseCR2_Full);157 break;158 159 case MC_CMD_MEDIA_BASE_T:160 SET_BIT(TP);161 if (cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN))162 SET_BIT(10baseT_Half);163 if (cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN))164 SET_BIT(10baseT_Full);165 if (cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN))166 SET_BIT(100baseT_Half);167 if (cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN))168 SET_BIT(100baseT_Full);169 if (cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN))170 SET_BIT(1000baseT_Half);171 if (cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN))172 SET_BIT(1000baseT_Full);173 if (cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN))174 SET_BIT(10000baseT_Full);175 break;176 }177 178 if (cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN))179 SET_BIT(Pause);180 if (cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN))181 SET_BIT(Asym_Pause);182 if (cap & (1 << MC_CMD_PHY_CAP_AN_LBN))183 SET_BIT(Autoneg);184 185 #undef SET_BIT186}187 188static u32 ethtool_linkset_to_mcdi_cap(const unsigned long *linkset)189{190 u32 result = 0;191 192 #define TEST_BIT(name) test_bit(ETHTOOL_LINK_MODE_ ## name ## _BIT, \193 linkset)194 195 if (TEST_BIT(10baseT_Half))196 result |= (1 << MC_CMD_PHY_CAP_10HDX_LBN);197 if (TEST_BIT(10baseT_Full))198 result |= (1 << MC_CMD_PHY_CAP_10FDX_LBN);199 if (TEST_BIT(100baseT_Half))200 result |= (1 << MC_CMD_PHY_CAP_100HDX_LBN);201 if (TEST_BIT(100baseT_Full))202 result |= (1 << MC_CMD_PHY_CAP_100FDX_LBN);203 if (TEST_BIT(1000baseT_Half))204 result |= (1 << MC_CMD_PHY_CAP_1000HDX_LBN);205 if (TEST_BIT(1000baseT_Full) || TEST_BIT(1000baseKX_Full) ||206 TEST_BIT(1000baseX_Full))207 result |= (1 << MC_CMD_PHY_CAP_1000FDX_LBN);208 if (TEST_BIT(10000baseT_Full) || TEST_BIT(10000baseKX4_Full) ||209 TEST_BIT(10000baseCR_Full) || TEST_BIT(10000baseLR_Full) ||210 TEST_BIT(10000baseSR_Full))211 result |= (1 << MC_CMD_PHY_CAP_10000FDX_LBN);212 if (TEST_BIT(40000baseCR4_Full) || TEST_BIT(40000baseKR4_Full) ||213 TEST_BIT(40000baseSR4_Full))214 result |= (1 << MC_CMD_PHY_CAP_40000FDX_LBN);215 if (TEST_BIT(100000baseCR4_Full) || TEST_BIT(100000baseSR4_Full))216 result |= (1 << MC_CMD_PHY_CAP_100000FDX_LBN);217 if (TEST_BIT(25000baseCR_Full) || TEST_BIT(25000baseSR_Full))218 result |= (1 << MC_CMD_PHY_CAP_25000FDX_LBN);219 if (TEST_BIT(50000baseCR2_Full))220 result |= (1 << MC_CMD_PHY_CAP_50000FDX_LBN);221 if (TEST_BIT(Pause))222 result |= (1 << MC_CMD_PHY_CAP_PAUSE_LBN);223 if (TEST_BIT(Asym_Pause))224 result |= (1 << MC_CMD_PHY_CAP_ASYM_LBN);225 if (TEST_BIT(Autoneg))226 result |= (1 << MC_CMD_PHY_CAP_AN_LBN);227 228 #undef TEST_BIT229 230 return result;231}232 233static u32 efx_get_mcdi_phy_flags(struct efx_nic *efx)234{235 struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;236 enum efx_phy_mode mode, supported;237 u32 flags;238 239 /* TODO: Advertise the capabilities supported by this PHY */240 supported = 0;241 if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_OUT_TXDIS_LBN))242 supported |= PHY_MODE_TX_DISABLED;243 if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_OUT_LOWPOWER_LBN))244 supported |= PHY_MODE_LOW_POWER;245 if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_OUT_POWEROFF_LBN))246 supported |= PHY_MODE_OFF;247 248 mode = efx->phy_mode & supported;249 250 flags = 0;251 if (mode & PHY_MODE_TX_DISABLED)252 flags |= (1 << MC_CMD_SET_LINK_IN_TXDIS_LBN);253 if (mode & PHY_MODE_LOW_POWER)254 flags |= (1 << MC_CMD_SET_LINK_IN_LOWPOWER_LBN);255 if (mode & PHY_MODE_OFF)256 flags |= (1 << MC_CMD_SET_LINK_IN_POWEROFF_LBN);257 258 return flags;259}260 261static u8 mcdi_to_ethtool_media(u32 media)262{263 switch (media) {264 case MC_CMD_MEDIA_XAUI:265 case MC_CMD_MEDIA_CX4:266 case MC_CMD_MEDIA_KX4:267 return PORT_OTHER;268 269 case MC_CMD_MEDIA_XFP:270 case MC_CMD_MEDIA_SFP_PLUS:271 case MC_CMD_MEDIA_QSFP_PLUS:272 return PORT_FIBRE;273 274 case MC_CMD_MEDIA_BASE_T:275 return PORT_TP;276 277 default:278 return PORT_OTHER;279 }280}281 282static void efx_mcdi_phy_decode_link(struct efx_nic *efx,283 struct efx_link_state *link_state,284 u32 speed, u32 flags, u32 fcntl)285{286 switch (fcntl) {287 case MC_CMD_FCNTL_AUTO:288 WARN_ON(1); /* This is not a link mode */289 link_state->fc = EFX_FC_AUTO | EFX_FC_TX | EFX_FC_RX;290 break;291 case MC_CMD_FCNTL_BIDIR:292 link_state->fc = EFX_FC_TX | EFX_FC_RX;293 break;294 case MC_CMD_FCNTL_RESPOND:295 link_state->fc = EFX_FC_RX;296 break;297 default:298 WARN_ON(1);299 fallthrough;300 case MC_CMD_FCNTL_OFF:301 link_state->fc = 0;302 break;303 }304 305 link_state->up = !!(flags & (1 << MC_CMD_GET_LINK_OUT_LINK_UP_LBN));306 link_state->fd = !!(flags & (1 << MC_CMD_GET_LINK_OUT_FULL_DUPLEX_LBN));307 link_state->speed = speed;308}309 310/* The semantics of the ethtool FEC mode bitmask are not well defined,311 * particularly the meaning of combinations of bits. Which means we get to312 * define our own semantics, as follows:313 * OFF overrides any other bits, and means "disable all FEC" (with the314 * exception of 25G KR4/CR4, where it is not possible to reject it if AN315 * partner requests it).316 * AUTO on its own means use cable requirements and link partner autoneg with317 * fw-default preferences for the cable type.318 * AUTO and either RS or BASER means use the specified FEC type if cable and319 * link partner support it, otherwise autoneg/fw-default.320 * RS or BASER alone means use the specified FEC type if cable and link partner321 * support it and either requests it, otherwise no FEC.322 * Both RS and BASER (whether AUTO or not) means use FEC if cable and link323 * partner support it, preferring RS to BASER.324 */325static u32 ethtool_fec_caps_to_mcdi(u32 supported_cap, u32 ethtool_cap)326{327 u32 ret = 0;328 329 if (ethtool_cap & ETHTOOL_FEC_OFF)330 return 0;331 332 if (ethtool_cap & ETHTOOL_FEC_AUTO)333 ret |= ((1 << MC_CMD_PHY_CAP_BASER_FEC_LBN) |334 (1 << MC_CMD_PHY_CAP_25G_BASER_FEC_LBN) |335 (1 << MC_CMD_PHY_CAP_RS_FEC_LBN)) & supported_cap;336 if (ethtool_cap & ETHTOOL_FEC_RS &&337 supported_cap & (1 << MC_CMD_PHY_CAP_RS_FEC_LBN))338 ret |= (1 << MC_CMD_PHY_CAP_RS_FEC_LBN) |339 (1 << MC_CMD_PHY_CAP_RS_FEC_REQUESTED_LBN);340 if (ethtool_cap & ETHTOOL_FEC_BASER) {341 if (supported_cap & (1 << MC_CMD_PHY_CAP_BASER_FEC_LBN))342 ret |= (1 << MC_CMD_PHY_CAP_BASER_FEC_LBN) |343 (1 << MC_CMD_PHY_CAP_BASER_FEC_REQUESTED_LBN);344 if (supported_cap & (1 << MC_CMD_PHY_CAP_25G_BASER_FEC_LBN))345 ret |= (1 << MC_CMD_PHY_CAP_25G_BASER_FEC_LBN) |346 (1 << MC_CMD_PHY_CAP_25G_BASER_FEC_REQUESTED_LBN);347 }348 return ret;349}350 351/* Invert ethtool_fec_caps_to_mcdi. There are two combinations that function352 * can never produce, (baser xor rs) and neither req; the implementation below353 * maps both of those to AUTO. This should never matter, and it's not clear354 * what a better mapping would be anyway.355 */356static u32 mcdi_fec_caps_to_ethtool(u32 caps, bool is_25g)357{358 bool rs = caps & (1 << MC_CMD_PHY_CAP_RS_FEC_LBN),359 rs_req = caps & (1 << MC_CMD_PHY_CAP_RS_FEC_REQUESTED_LBN),360 baser = is_25g ? caps & (1 << MC_CMD_PHY_CAP_25G_BASER_FEC_LBN)361 : caps & (1 << MC_CMD_PHY_CAP_BASER_FEC_LBN),362 baser_req = is_25g ? caps & (1 << MC_CMD_PHY_CAP_25G_BASER_FEC_REQUESTED_LBN)363 : caps & (1 << MC_CMD_PHY_CAP_BASER_FEC_REQUESTED_LBN);364 365 if (!baser && !rs)366 return ETHTOOL_FEC_OFF;367 return (rs_req ? ETHTOOL_FEC_RS : 0) |368 (baser_req ? ETHTOOL_FEC_BASER : 0) |369 (baser == baser_req && rs == rs_req ? 0 : ETHTOOL_FEC_AUTO);370}371 372/* Verify that the forced flow control settings (!EFX_FC_AUTO) are373 * supported by the link partner. Warn the user if this isn't the case374 */375static void efx_mcdi_phy_check_fcntl(struct efx_nic *efx, u32 lpa)376{377 struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;378 u32 rmtadv;379 380 /* The link partner capabilities are only relevant if the381 * link supports flow control autonegotiation382 */383 if (~phy_cfg->supported_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))384 return;385 386 /* If flow control autoneg is supported and enabled, then fine */387 if (efx->wanted_fc & EFX_FC_AUTO)388 return;389 390 rmtadv = 0;391 if (lpa & (1 << MC_CMD_PHY_CAP_PAUSE_LBN))392 rmtadv |= ADVERTISED_Pause;393 if (lpa & (1 << MC_CMD_PHY_CAP_ASYM_LBN))394 rmtadv |= ADVERTISED_Asym_Pause;395 396 if ((efx->wanted_fc & EFX_FC_TX) && rmtadv == ADVERTISED_Asym_Pause)397 netif_err(efx, link, efx->net_dev,398 "warning: link partner doesn't support pause frames");399}400 401bool efx_siena_mcdi_phy_poll(struct efx_nic *efx)402{403 struct efx_link_state old_state = efx->link_state;404 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_LINK_OUT_LEN);405 int rc;406 407 WARN_ON(!mutex_is_locked(&efx->mac_lock));408 409 BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0);410 411 rc = efx_siena_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,412 outbuf, sizeof(outbuf), NULL);413 if (rc)414 efx->link_state.up = false;415 else416 efx_mcdi_phy_decode_link(417 efx, &efx->link_state,418 MCDI_DWORD(outbuf, GET_LINK_OUT_LINK_SPEED),419 MCDI_DWORD(outbuf, GET_LINK_OUT_FLAGS),420 MCDI_DWORD(outbuf, GET_LINK_OUT_FCNTL));421 422 return !efx_link_state_equal(&efx->link_state, &old_state);423}424 425int efx_siena_mcdi_phy_probe(struct efx_nic *efx)426{427 struct efx_mcdi_phy_data *phy_data;428 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_LINK_OUT_LEN);429 u32 caps;430 int rc;431 432 /* Initialise and populate phy_data */433 phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL);434 if (phy_data == NULL)435 return -ENOMEM;436 437 rc = efx_mcdi_get_phy_cfg(efx, phy_data);438 if (rc != 0)439 goto fail;440 441 /* Read initial link advertisement */442 BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0);443 rc = efx_siena_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,444 outbuf, sizeof(outbuf), NULL);445 if (rc)446 goto fail;447 448 /* Fill out nic state */449 efx->phy_data = phy_data;450 efx->phy_type = phy_data->type;451 452 efx->mdio_bus = phy_data->channel;453 efx->mdio.prtad = phy_data->port;454 efx->mdio.mmds = phy_data->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22);455 efx->mdio.mode_support = 0;456 if (phy_data->mmd_mask & (1 << MC_CMD_MMD_CLAUSE22))457 efx->mdio.mode_support |= MDIO_SUPPORTS_C22;458 if (phy_data->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22))459 efx->mdio.mode_support |= MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22;460 461 caps = MCDI_DWORD(outbuf, GET_LINK_OUT_CAP);462 if (caps & (1 << MC_CMD_PHY_CAP_AN_LBN))463 mcdi_to_ethtool_linkset(phy_data->media, caps,464 efx->link_advertising);465 else466 phy_data->forced_cap = caps;467 468 /* Assert that we can map efx -> mcdi loopback modes */469 BUILD_BUG_ON(LOOPBACK_NONE != MC_CMD_LOOPBACK_NONE);470 BUILD_BUG_ON(LOOPBACK_DATA != MC_CMD_LOOPBACK_DATA);471 BUILD_BUG_ON(LOOPBACK_GMAC != MC_CMD_LOOPBACK_GMAC);472 BUILD_BUG_ON(LOOPBACK_XGMII != MC_CMD_LOOPBACK_XGMII);473 BUILD_BUG_ON(LOOPBACK_XGXS != MC_CMD_LOOPBACK_XGXS);474 BUILD_BUG_ON(LOOPBACK_XAUI != MC_CMD_LOOPBACK_XAUI);475 BUILD_BUG_ON(LOOPBACK_GMII != MC_CMD_LOOPBACK_GMII);476 BUILD_BUG_ON(LOOPBACK_SGMII != MC_CMD_LOOPBACK_SGMII);477 BUILD_BUG_ON(LOOPBACK_XGBR != MC_CMD_LOOPBACK_XGBR);478 BUILD_BUG_ON(LOOPBACK_XFI != MC_CMD_LOOPBACK_XFI);479 BUILD_BUG_ON(LOOPBACK_XAUI_FAR != MC_CMD_LOOPBACK_XAUI_FAR);480 BUILD_BUG_ON(LOOPBACK_GMII_FAR != MC_CMD_LOOPBACK_GMII_FAR);481 BUILD_BUG_ON(LOOPBACK_SGMII_FAR != MC_CMD_LOOPBACK_SGMII_FAR);482 BUILD_BUG_ON(LOOPBACK_XFI_FAR != MC_CMD_LOOPBACK_XFI_FAR);483 BUILD_BUG_ON(LOOPBACK_GPHY != MC_CMD_LOOPBACK_GPHY);484 BUILD_BUG_ON(LOOPBACK_PHYXS != MC_CMD_LOOPBACK_PHYXS);485 BUILD_BUG_ON(LOOPBACK_PCS != MC_CMD_LOOPBACK_PCS);486 BUILD_BUG_ON(LOOPBACK_PMAPMD != MC_CMD_LOOPBACK_PMAPMD);487 BUILD_BUG_ON(LOOPBACK_XPORT != MC_CMD_LOOPBACK_XPORT);488 BUILD_BUG_ON(LOOPBACK_XGMII_WS != MC_CMD_LOOPBACK_XGMII_WS);489 BUILD_BUG_ON(LOOPBACK_XAUI_WS != MC_CMD_LOOPBACK_XAUI_WS);490 BUILD_BUG_ON(LOOPBACK_XAUI_WS_FAR != MC_CMD_LOOPBACK_XAUI_WS_FAR);491 BUILD_BUG_ON(LOOPBACK_XAUI_WS_NEAR != MC_CMD_LOOPBACK_XAUI_WS_NEAR);492 BUILD_BUG_ON(LOOPBACK_GMII_WS != MC_CMD_LOOPBACK_GMII_WS);493 BUILD_BUG_ON(LOOPBACK_XFI_WS != MC_CMD_LOOPBACK_XFI_WS);494 BUILD_BUG_ON(LOOPBACK_XFI_WS_FAR != MC_CMD_LOOPBACK_XFI_WS_FAR);495 BUILD_BUG_ON(LOOPBACK_PHYXS_WS != MC_CMD_LOOPBACK_PHYXS_WS);496 497 rc = efx_mcdi_loopback_modes(efx, &efx->loopback_modes);498 if (rc != 0)499 goto fail;500 /* The MC indicates that LOOPBACK_NONE is a valid loopback mode,501 * but by convention we don't502 */503 efx->loopback_modes &= ~(1 << LOOPBACK_NONE);504 505 /* Set the initial link mode */506 efx_mcdi_phy_decode_link(efx, &efx->link_state,507 MCDI_DWORD(outbuf, GET_LINK_OUT_LINK_SPEED),508 MCDI_DWORD(outbuf, GET_LINK_OUT_FLAGS),509 MCDI_DWORD(outbuf, GET_LINK_OUT_FCNTL));510 511 /* Record the initial FEC configuration (or nearest approximation512 * representable in the ethtool configuration space)513 */514 efx->fec_config = mcdi_fec_caps_to_ethtool(caps,515 efx->link_state.speed == 25000 ||516 efx->link_state.speed == 50000);517 518 /* Default to Autonegotiated flow control if the PHY supports it */519 efx->wanted_fc = EFX_FC_RX | EFX_FC_TX;520 if (phy_data->supported_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))521 efx->wanted_fc |= EFX_FC_AUTO;522 efx_siena_link_set_wanted_fc(efx, efx->wanted_fc);523 524 return 0;525 526fail:527 kfree(phy_data);528 return rc;529}530 531void efx_siena_mcdi_phy_remove(struct efx_nic *efx)532{533 struct efx_mcdi_phy_data *phy_data = efx->phy_data;534 535 efx->phy_data = NULL;536 kfree(phy_data);537}538 539void efx_siena_mcdi_phy_get_link_ksettings(struct efx_nic *efx,540 struct ethtool_link_ksettings *cmd)541{542 struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;543 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_LINK_OUT_LEN);544 int rc;545 546 cmd->base.speed = efx->link_state.speed;547 cmd->base.duplex = efx->link_state.fd;548 cmd->base.port = mcdi_to_ethtool_media(phy_cfg->media);549 cmd->base.phy_address = phy_cfg->port;550 cmd->base.autoneg = !!(efx->link_advertising[0] & ADVERTISED_Autoneg);551 cmd->base.mdio_support = (efx->mdio.mode_support &552 (MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22));553 554 mcdi_to_ethtool_linkset(phy_cfg->media, phy_cfg->supported_cap,555 cmd->link_modes.supported);556 memcpy(cmd->link_modes.advertising, efx->link_advertising,557 sizeof(__ETHTOOL_DECLARE_LINK_MODE_MASK()));558 559 BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0);560 rc = efx_siena_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,561 outbuf, sizeof(outbuf), NULL);562 if (rc)563 return;564 mcdi_to_ethtool_linkset(phy_cfg->media,565 MCDI_DWORD(outbuf, GET_LINK_OUT_LP_CAP),566 cmd->link_modes.lp_advertising);567}568 569int570efx_siena_mcdi_phy_set_link_ksettings(struct efx_nic *efx,571 const struct ethtool_link_ksettings *cmd)572{573 struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;574 u32 caps;575 int rc;576 577 if (cmd->base.autoneg) {578 caps = (ethtool_linkset_to_mcdi_cap(cmd->link_modes.advertising) |579 1 << MC_CMD_PHY_CAP_AN_LBN);580 } else if (cmd->base.duplex) {581 switch (cmd->base.speed) {582 case 10: caps = 1 << MC_CMD_PHY_CAP_10FDX_LBN; break;583 case 100: caps = 1 << MC_CMD_PHY_CAP_100FDX_LBN; break;584 case 1000: caps = 1 << MC_CMD_PHY_CAP_1000FDX_LBN; break;585 case 10000: caps = 1 << MC_CMD_PHY_CAP_10000FDX_LBN; break;586 case 40000: caps = 1 << MC_CMD_PHY_CAP_40000FDX_LBN; break;587 case 100000: caps = 1 << MC_CMD_PHY_CAP_100000FDX_LBN; break;588 case 25000: caps = 1 << MC_CMD_PHY_CAP_25000FDX_LBN; break;589 case 50000: caps = 1 << MC_CMD_PHY_CAP_50000FDX_LBN; break;590 default: return -EINVAL;591 }592 } else {593 switch (cmd->base.speed) {594 case 10: caps = 1 << MC_CMD_PHY_CAP_10HDX_LBN; break;595 case 100: caps = 1 << MC_CMD_PHY_CAP_100HDX_LBN; break;596 case 1000: caps = 1 << MC_CMD_PHY_CAP_1000HDX_LBN; break;597 default: return -EINVAL;598 }599 }600 601 caps |= ethtool_fec_caps_to_mcdi(phy_cfg->supported_cap, efx->fec_config);602 603 rc = efx_mcdi_set_link(efx, caps, efx_get_mcdi_phy_flags(efx),604 efx->loopback_mode, 0);605 if (rc)606 return rc;607 608 if (cmd->base.autoneg) {609 efx_siena_link_set_advertising(efx, cmd->link_modes.advertising);610 phy_cfg->forced_cap = 0;611 } else {612 efx_siena_link_clear_advertising(efx);613 phy_cfg->forced_cap = caps;614 }615 return 0;616}617 618int efx_siena_mcdi_phy_get_fecparam(struct efx_nic *efx,619 struct ethtool_fecparam *fec)620{621 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_LINK_OUT_V2_LEN);622 u32 caps, active, speed; /* MCDI format */623 bool is_25g = false;624 size_t outlen;625 int rc;626 627 BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0);628 rc = efx_siena_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,629 outbuf, sizeof(outbuf), &outlen);630 if (rc)631 return rc;632 if (outlen < MC_CMD_GET_LINK_OUT_V2_LEN)633 return -EOPNOTSUPP;634 635 /* behaviour for 25G/50G links depends on 25G BASER bit */636 speed = MCDI_DWORD(outbuf, GET_LINK_OUT_V2_LINK_SPEED);637 is_25g = speed == 25000 || speed == 50000;638 639 caps = MCDI_DWORD(outbuf, GET_LINK_OUT_V2_CAP);640 fec->fec = mcdi_fec_caps_to_ethtool(caps, is_25g);641 /* BASER is never supported on 100G */642 if (speed == 100000)643 fec->fec &= ~ETHTOOL_FEC_BASER;644 645 active = MCDI_DWORD(outbuf, GET_LINK_OUT_V2_FEC_TYPE);646 switch (active) {647 case MC_CMD_FEC_NONE:648 fec->active_fec = ETHTOOL_FEC_OFF;649 break;650 case MC_CMD_FEC_BASER:651 fec->active_fec = ETHTOOL_FEC_BASER;652 break;653 case MC_CMD_FEC_RS:654 fec->active_fec = ETHTOOL_FEC_RS;655 break;656 default:657 netif_warn(efx, hw, efx->net_dev,658 "Firmware reports unrecognised FEC_TYPE %u\n",659 active);660 /* We don't know what firmware has picked. AUTO is as good a661 * "can't happen" value as any other.662 */663 fec->active_fec = ETHTOOL_FEC_AUTO;664 break;665 }666 667 return 0;668}669 670/* Basic validation to ensure that the caps we are going to attempt to set are671 * in fact supported by the adapter. Note that 'no FEC' is always supported.672 */673static int ethtool_fec_supported(u32 supported_cap, u32 ethtool_cap)674{675 if (ethtool_cap & ETHTOOL_FEC_OFF)676 return 0;677 678 if (ethtool_cap &&679 !ethtool_fec_caps_to_mcdi(supported_cap, ethtool_cap))680 return -EINVAL;681 return 0;682}683 684int efx_siena_mcdi_phy_set_fecparam(struct efx_nic *efx,685 const struct ethtool_fecparam *fec)686{687 struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;688 u32 caps;689 int rc;690 691 rc = ethtool_fec_supported(phy_cfg->supported_cap, fec->fec);692 if (rc)693 return rc;694 695 /* Work out what efx_siena_mcdi_phy_set_link_ksettings() would produce from696 * saved advertising bits697 */698 if (test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, efx->link_advertising))699 caps = (ethtool_linkset_to_mcdi_cap(efx->link_advertising) |700 1 << MC_CMD_PHY_CAP_AN_LBN);701 else702 caps = phy_cfg->forced_cap;703 704 caps |= ethtool_fec_caps_to_mcdi(phy_cfg->supported_cap, fec->fec);705 rc = efx_mcdi_set_link(efx, caps, efx_get_mcdi_phy_flags(efx),706 efx->loopback_mode, 0);707 if (rc)708 return rc;709 710 /* Record the new FEC setting for subsequent set_link calls */711 efx->fec_config = fec->fec;712 return 0;713}714 715int efx_siena_mcdi_phy_test_alive(struct efx_nic *efx)716{717 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_PHY_STATE_OUT_LEN);718 size_t outlen;719 int rc;720 721 BUILD_BUG_ON(MC_CMD_GET_PHY_STATE_IN_LEN != 0);722 723 rc = efx_siena_mcdi_rpc(efx, MC_CMD_GET_PHY_STATE, NULL, 0,724 outbuf, sizeof(outbuf), &outlen);725 if (rc)726 return rc;727 728 if (outlen < MC_CMD_GET_PHY_STATE_OUT_LEN)729 return -EIO;730 if (MCDI_DWORD(outbuf, GET_PHY_STATE_OUT_STATE) != MC_CMD_PHY_STATE_OK)731 return -EINVAL;732 733 return 0;734}735 736int efx_siena_mcdi_port_reconfigure(struct efx_nic *efx)737{738 struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;739 u32 caps = (efx->link_advertising[0] ?740 ethtool_linkset_to_mcdi_cap(efx->link_advertising) :741 phy_cfg->forced_cap);742 743 caps |= ethtool_fec_caps_to_mcdi(phy_cfg->supported_cap, efx->fec_config);744 745 return efx_mcdi_set_link(efx, caps, efx_get_mcdi_phy_flags(efx),746 efx->loopback_mode, 0);747}748 749static const char *const mcdi_sft9001_cable_diag_names[] = {750 "cable.pairA.length",751 "cable.pairB.length",752 "cable.pairC.length",753 "cable.pairD.length",754 "cable.pairA.status",755 "cable.pairB.status",756 "cable.pairC.status",757 "cable.pairD.status",758};759 760static int efx_mcdi_bist(struct efx_nic *efx, unsigned int bist_mode,761 int *results)762{763 unsigned int retry, i, count = 0;764 size_t outlen;765 u32 status;766 MCDI_DECLARE_BUF(inbuf, MC_CMD_START_BIST_IN_LEN);767 MCDI_DECLARE_BUF(outbuf, MC_CMD_POLL_BIST_OUT_SFT9001_LEN);768 u8 *ptr;769 int rc;770 771 BUILD_BUG_ON(MC_CMD_START_BIST_OUT_LEN != 0);772 MCDI_SET_DWORD(inbuf, START_BIST_IN_TYPE, bist_mode);773 rc = efx_siena_mcdi_rpc(efx, MC_CMD_START_BIST, inbuf,774 MC_CMD_START_BIST_IN_LEN, NULL, 0, NULL);775 if (rc)776 goto out;777 778 /* Wait up to 10s for BIST to finish */779 for (retry = 0; retry < 100; ++retry) {780 BUILD_BUG_ON(MC_CMD_POLL_BIST_IN_LEN != 0);781 rc = efx_siena_mcdi_rpc(efx, MC_CMD_POLL_BIST, NULL, 0,782 outbuf, sizeof(outbuf), &outlen);783 if (rc)784 goto out;785 786 status = MCDI_DWORD(outbuf, POLL_BIST_OUT_RESULT);787 if (status != MC_CMD_POLL_BIST_RUNNING)788 goto finished;789 790 msleep(100);791 }792 793 rc = -ETIMEDOUT;794 goto out;795 796finished:797 results[count++] = (status == MC_CMD_POLL_BIST_PASSED) ? 1 : -1;798 799 /* SFT9001 specific cable diagnostics output */800 if (efx->phy_type == PHY_TYPE_SFT9001B &&801 (bist_mode == MC_CMD_PHY_BIST_CABLE_SHORT ||802 bist_mode == MC_CMD_PHY_BIST_CABLE_LONG)) {803 ptr = MCDI_PTR(outbuf, POLL_BIST_OUT_SFT9001_CABLE_LENGTH_A);804 if (status == MC_CMD_POLL_BIST_PASSED &&805 outlen >= MC_CMD_POLL_BIST_OUT_SFT9001_LEN) {806 for (i = 0; i < 8; i++) {807 results[count + i] =808 EFX_DWORD_FIELD(((efx_dword_t *)ptr)[i],809 EFX_DWORD_0);810 }811 }812 count += 8;813 }814 rc = count;815 816out:817 return rc;818}819 820int efx_siena_mcdi_phy_run_tests(struct efx_nic *efx, int *results,821 unsigned int flags)822{823 struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;824 u32 mode;825 int rc;826 827 if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_OUT_BIST_LBN)) {828 rc = efx_mcdi_bist(efx, MC_CMD_PHY_BIST, results);829 if (rc < 0)830 return rc;831 832 results += rc;833 }834 835 /* If we support both LONG and SHORT, then run each in response to836 * break or not. Otherwise, run the one we support837 */838 mode = 0;839 if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_OUT_BIST_CABLE_SHORT_LBN)) {840 if ((flags & ETH_TEST_FL_OFFLINE) &&841 (phy_cfg->flags &842 (1 << MC_CMD_GET_PHY_CFG_OUT_BIST_CABLE_LONG_LBN)))843 mode = MC_CMD_PHY_BIST_CABLE_LONG;844 else845 mode = MC_CMD_PHY_BIST_CABLE_SHORT;846 } else if (phy_cfg->flags &847 (1 << MC_CMD_GET_PHY_CFG_OUT_BIST_CABLE_LONG_LBN))848 mode = MC_CMD_PHY_BIST_CABLE_LONG;849 850 if (mode != 0) {851 rc = efx_mcdi_bist(efx, mode, results);852 if (rc < 0)853 return rc;854 results += rc;855 }856 857 return 0;858}859 860const char *efx_siena_mcdi_phy_test_name(struct efx_nic *efx,861 unsigned int index)862{863 struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;864 865 if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_OUT_BIST_LBN)) {866 if (index == 0)867 return "bist";868 --index;869 }870 871 if (phy_cfg->flags & ((1 << MC_CMD_GET_PHY_CFG_OUT_BIST_CABLE_SHORT_LBN) |872 (1 << MC_CMD_GET_PHY_CFG_OUT_BIST_CABLE_LONG_LBN))) {873 if (index == 0)874 return "cable";875 --index;876 877 if (efx->phy_type == PHY_TYPE_SFT9001B) {878 if (index < ARRAY_SIZE(mcdi_sft9001_cable_diag_names))879 return mcdi_sft9001_cable_diag_names[index];880 index -= ARRAY_SIZE(mcdi_sft9001_cable_diag_names);881 }882 }883 884 return NULL;885}886 887#define SFP_PAGE_SIZE 128888#define SFF_DIAG_TYPE_OFFSET 92889#define SFF_DIAG_ADDR_CHANGE BIT(2)890#define SFF_8079_NUM_PAGES 2891#define SFF_8472_NUM_PAGES 4892#define SFF_8436_NUM_PAGES 5893#define SFF_DMT_LEVEL_OFFSET 94894 895/** efx_mcdi_phy_get_module_eeprom_page() - Get a single page of module eeprom896 * @efx: NIC context897 * @page: EEPROM page number898 * @data: Destination data pointer899 * @offset: Offset in page to copy from in to data900 * @space: Space available in data901 *902 * Return:903 * >=0 - amount of data copied904 * <0 - error905 */906static int efx_mcdi_phy_get_module_eeprom_page(struct efx_nic *efx,907 unsigned int page,908 u8 *data, ssize_t offset,909 ssize_t space)910{911 MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_PHY_MEDIA_INFO_OUT_LENMAX);912 MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN);913 unsigned int payload_len;914 unsigned int to_copy;915 size_t outlen;916 int rc;917 918 if (offset > SFP_PAGE_SIZE)919 return -EINVAL;920 921 to_copy = min(space, SFP_PAGE_SIZE - offset);922 923 MCDI_SET_DWORD(inbuf, GET_PHY_MEDIA_INFO_IN_PAGE, page);924 rc = efx_siena_mcdi_rpc_quiet(efx, MC_CMD_GET_PHY_MEDIA_INFO,925 inbuf, sizeof(inbuf),926 outbuf, sizeof(outbuf),927 &outlen);928 929 if (rc)930 return rc;931 932 if (outlen < (MC_CMD_GET_PHY_MEDIA_INFO_OUT_DATA_OFST +933 SFP_PAGE_SIZE))934 return -EIO;935 936 payload_len = MCDI_DWORD(outbuf, GET_PHY_MEDIA_INFO_OUT_DATALEN);937 if (payload_len != SFP_PAGE_SIZE)938 return -EIO;939 940 memcpy(data, MCDI_PTR(outbuf, GET_PHY_MEDIA_INFO_OUT_DATA) + offset,941 to_copy);942 943 return to_copy;944}945 946static int efx_mcdi_phy_get_module_eeprom_byte(struct efx_nic *efx,947 unsigned int page,948 u8 byte)949{950 u8 data;951 int rc;952 953 rc = efx_mcdi_phy_get_module_eeprom_page(efx, page, &data, byte, 1);954 if (rc == 1)955 return data;956 957 return rc;958}959 960static int efx_mcdi_phy_diag_type(struct efx_nic *efx)961{962 /* Page zero of the EEPROM includes the diagnostic type at byte 92. */963 return efx_mcdi_phy_get_module_eeprom_byte(efx, 0,964 SFF_DIAG_TYPE_OFFSET);965}966 967static int efx_mcdi_phy_sff_8472_level(struct efx_nic *efx)968{969 /* Page zero of the EEPROM includes the DMT level at byte 94. */970 return efx_mcdi_phy_get_module_eeprom_byte(efx, 0,971 SFF_DMT_LEVEL_OFFSET);972}973 974static u32 efx_mcdi_phy_module_type(struct efx_nic *efx)975{976 struct efx_mcdi_phy_data *phy_data = efx->phy_data;977 978 if (phy_data->media != MC_CMD_MEDIA_QSFP_PLUS)979 return phy_data->media;980 981 /* A QSFP+ NIC may actually have an SFP+ module attached.982 * The ID is page 0, byte 0.983 */984 switch (efx_mcdi_phy_get_module_eeprom_byte(efx, 0, 0)) {985 case 0x3:986 return MC_CMD_MEDIA_SFP_PLUS;987 case 0xc:988 case 0xd:989 return MC_CMD_MEDIA_QSFP_PLUS;990 default:991 return 0;992 }993}994 995int efx_siena_mcdi_phy_get_module_eeprom(struct efx_nic *efx,996 struct ethtool_eeprom *ee, u8 *data)997{998 int rc;999 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; /* We obtain the lower page by asking for -1. */1015 ignore_missing = true; /* Ignore missing pages after page 0. */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 1057int 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 /* If we can't read the diagnostics level we have none. */1067 if (sff_8472_level < 0)1068 return -EOPNOTSUPP;1069 1070 /* Check if this module requires the (unsupported) address1071 * change operation.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 1097static unsigned int efx_calc_mac_mtu(struct efx_nic *efx)1098{1099 return EFX_MAX_FRAME_LEN(efx->net_dev->mtu);1100}1101 1102int 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 /* This has no effect on EF10 */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 /* Set simple MAC filter for Siena */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 1146enum efx_stats_action {1147 EFX_STATS_ENABLE,1148 EFX_STATS_DISABLE,1149 EFX_STATS_PULL,1150};1151 1152static 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 /* Expect ENOENT if DMA queues have not been set up */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 1189void 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 1198void 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 1001204#define EFX_MAC_STATS_WAIT_ATTEMPTS 101205 1206void 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 1220int 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 /* Allocate buffer for stats */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 1246void efx_siena_mcdi_mac_fini_stats(struct efx_nic *efx)1247{1248 efx_siena_free_buffer(efx, &efx->stats_buffer);1249}1250 1251static 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 1261void 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 /* efx->link_state is only modified by efx_mcdi_phy_get_link(),1274 * which is only run after flushing the event queues. Therefore, it1275 * is safe to modify the link state outside of the mac_lock here.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}1283