staticconstchar ice_gstrings_test[][ETH_GSTRING_LEN] = { "Register test (offline)", "EEPROM test (offline)", "Interrupt test (offline)", "Loopback test (offline)", "Link test (on/offline)",
};
/* Display NVM version (from which the firmware version can be *determined)whichcontainsmorepertinentinformation.
*/
snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), "%x.%02x 0x%x %d.%d.%d", nvm->major, nvm->minor,
nvm->eetrack, orom->major, orom->build, orom->patch);
status = ice_vsi_stop_lan_tx_rings(vsi, ICE_NO_RESET, 0); if (status)
netdev_err(vsi->netdev, "Failed to stop Tx rings, VSI %d error %d\n",
vsi->vsi_num, status);
status = ice_vsi_stop_all_rx_rings(vsi); if (status)
netdev_err(vsi->netdev, "Failed to stop Rx rings, VSI %d error %d\n",
vsi->vsi_num, status);
data = kzalloc(size, GFP_KERNEL); if (!data) return -ENOMEM;
/* Since the ethernet test frame should always be at least *64byteslong,fillsomeoctetsinthepayloadwithtestdata.
*/
memset(data, 0xFF, size);
data[32] = 0xDE;
data[42] = 0xAD;
data[44] = 0xBE;
data[46] = 0xEF;
if (ice_lbtest_prepare_rings(test_vsi)) {
ret = 2; goto lbtest_vsi_close;
}
if (ice_alloc_rx_bufs(rx_ring, rx_ring->count)) {
ret = 3; goto lbtest_rings_dis;
}
/* Enable MAC loopback in firmware */ if (ice_aq_set_mac_loopback(&pf->hw, true, NULL)) {
ret = 4; goto lbtest_mac_dis;
}
/* Test VSI needs to receive broadcast packets */
eth_broadcast_addr(broadcast); if (ice_fltr_add_mac(test_vsi, broadcast, ICE_FWD_TO_VSI)) {
ret = 5; goto lbtest_mac_dis;
}
if (ice_lbtest_create_frame(pf, &tx_frame, ICE_LB_FRAME_SIZE)) {
ret = 7; goto remove_mac_filters;
}
num_frames = min_t(int, tx_ring->count, 32); for (i = 0; i < num_frames; i++) { if (ice_diag_send(tx_ring, tx_frame, ICE_LB_FRAME_SIZE)) {
ret = 8; goto remove_mac_filters;
}
}
valid_frames = ice_lbtest_receive_frames(rx_ring); if (!valid_frames)
ret = 9; elseif (valid_frames != num_frames)
ret = 10;
remove_mac_filters: if (ice_fltr_remove_mac(test_vsi, broadcast, ICE_FWD_TO_VSI))
netdev_err(netdev, "Could not remove MAC filter for the test VSI\n");
lbtest_mac_dis: /* Disable MAC loopback after the test is completed. */ if (ice_aq_set_mac_loopback(&pf->hw, false, NULL))
netdev_err(netdev, "Could not disable MAC loopback\n");
lbtest_rings_dis: if (ice_lbtest_disable_rings(test_vsi))
netdev_err(netdev, "Could not disable test rings\n");
lbtest_vsi_close:
test_vsi->netdev = NULL; if (ice_vsi_release(test_vsi))
netdev_err(netdev, "Failed to remove the test VSI\n");
if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
netdev_info(netdev, "offline testing starting\n");
set_bit(ICE_TESTING, pf->state);
if (ice_active_vfs(pf)) {
dev_warn(dev, "Please take active VFs and Netqueues offline and restart the adapter before running NIC diagnostics\n");
data[ICE_ETH_TEST_REG] = 1;
data[ICE_ETH_TEST_EEPROM] = 1;
data[ICE_ETH_TEST_INTR] = 1;
data[ICE_ETH_TEST_LOOP] = 1;
data[ICE_ETH_TEST_LINK] = 1;
eth_test->flags |= ETH_TEST_FL_FAILED;
clear_bit(ICE_TESTING, pf->state); goto skip_ol_tests;
} /* If the device is online then take it offline */ if (if_running) /* indicate we're in test mode */
ice_stop(netdev);
if (status) {
dev_err(dev, "Could not open device %s, err %d\n",
pf->int_name, status);
}
}
} else { /* Online tests */
netdev_info(netdev, "online testing starting\n");
data[ICE_ETH_TEST_LINK] = ice_link_test(netdev); if (data[ICE_ETH_TEST_LINK])
eth_test->flags |= ETH_TEST_FL_FAILED;
/* Offline only tests, not run in online; pass by default */
data[ICE_ETH_TEST_REG] = 0;
data[ICE_ETH_TEST_EEPROM] = 0;
data[ICE_ETH_TEST_INTR] = 0;
data[ICE_ETH_TEST_LOOP] = 0;
}
/* Changing the FEC parameters is not supported if not the PF VSI */ if (vsi->type != ICE_VSI_PF) {
netdev_info(netdev, "Changing FEC parameters only supported for PF VSI\n"); return -EOPNOTSUPP;
}
/* Proceed only if requesting different FEC mode */ if (pi->phy.curr_user_fec_req == req_fec) return0;
/* Copy the current user PHY configuration. The current user PHY *configurationisinitializedduringprobefromPHYcapabilities *softwaremode,andupdatedonsetPHYconfiguration.
*/
memcpy(&config, &pi->phy.curr_user_phy_cfg, sizeof(config));
if (!pi) return -EOPNOTSUPP;
link_info = &pi->phy.link_info;
/* Set FEC mode based on negotiated link info */ switch (link_info->fec_info) { case ICE_AQ_LINK_25G_KR_FEC_EN:
fecparam->active_fec = ETHTOOL_FEC_BASER; break; case ICE_AQ_LINK_25G_RS_528_FEC_EN: case ICE_AQ_LINK_25G_RS_544_FEC_EN:
fecparam->active_fec = ETHTOOL_FEC_RS; break; default:
fecparam->active_fec = ETHTOOL_FEC_OFF; break;
}
caps = kzalloc(sizeof(*caps), GFP_KERNEL); if (!caps) return -ENOMEM;
/* If VSI state is up, then restart autoneg with link up */ if (!test_bit(ICE_DOWN, vsi->back->state))
err = ice_set_link(vsi, true); else
err = ice_set_link(vsi, false);
/* Do not allow change to link-down-on-close when Total Port Shutdown *isenabled.
*/ if (test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, change_flags) &&
test_bit(ICE_FLAG_TOTAL_PORT_SHUTDOWN_ENA, pf->flags)) {
dev_err(dev, "Setting link-down-on-close not supported on this port\n");
set_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, pf->flags);
ret = -EINVAL; goto ethtool_exit;
}
if (test_bit(ICE_FLAG_FW_LLDP_AGENT, change_flags)) { if (!test_bit(ICE_FLAG_FW_LLDP_AGENT, pf->flags)) { int status;
/* Disable FW LLDP engine */
status = ice_cfg_lldp_mib_change(&pf->hw, false);
/* If unregistering for LLDP events fails, this is *notanerrorstate,asthereshouldn'tbeany *eventstorespondto.
*/ if (status)
dev_info(dev, "Failed to unreg for LLDP events\n");
/* The AQ call to stop the FW LLDP agent will generate *anerroriftheagentisalreadystopped.
*/
status = ice_aq_stop_lldp(&pf->hw, true, true, NULL); if (status)
dev_warn(dev, "Fail to stop LLDP agent\n"); /* Use case for having the FW LLDP agent stopped *willlikelynotneedDCB,sofailuretoinitis *notaconcernofethtool
*/
status = ice_init_pf_dcb(pf, true); if (status)
dev_warn(dev, "Fail to init DCB\n");
if (ice_get_pfc_mode(pf) == ICE_QOS_MODE_DSCP) {
clear_bit(ICE_FLAG_FW_LLDP_AGENT, pf->flags);
dev_err(dev, "QoS in L3 DSCP mode, FW Agent not allowed to start\n");
ret = -EOPNOTSUPP; goto ethtool_exit;
}
/* Remove rule to direct LLDP packets to default VSI. *TheFWLLDPenginewillnowbeconsumingthem.
*/
ice_cfg_sw_rx_lldp(vsi->back, false);
/* AQ command to start FW LLDP agent will return an *erroriftheagentisalreadystarted
*/
status = ice_aq_start_lldp(&pf->hw, true, NULL); if (status)
dev_warn(dev, "Fail to start LLDP Agent\n");
/* AQ command to start FW DCBX agent will fail if *theagentisalreadystarted
*/
status = ice_aq_start_stop_dcbx(&pf->hw, true,
&dcbx_agent_status,
NULL); if (status)
dev_dbg(dev, "Failed to start FW DCBX\n");
/* Failure to configure MIB change or init DCB is not *relevanttoethtool.Printnotificationthat *registration/initfailedbutdonotreturnerror *statetoethtool
*/
status = ice_init_pf_dcb(pf, true); if (status)
dev_dbg(dev, "Fail to init DCB\n");
/* Register for MIB change events */
status = ice_cfg_lldp_mib_change(&pf->hw, true); if (status)
dev_dbg(dev, "Fail to enable MIB change events\n");
ice_nway_reset(netdev);
}
} if (test_bit(ICE_FLAG_LEGACY_RX, change_flags)) { /* down and up VSI so that changes of Rx cfg are reflected. */
ice_down_up(vsi);
} /* don't allow modification of this flag when a single VF is in *promiscuousmodebecauseit'snotsupported
*/ if (test_bit(ICE_FLAG_VF_TRUE_PROMISC_ENA, change_flags) &&
ice_is_any_vf_in_unicast_promisc(pf)) {
dev_err(dev, "Changing vf-true-promisc-support flag while VF(s) are in promiscuous mode not supported\n"); /* toggle bit back to previous state */
change_bit(ICE_FLAG_VF_TRUE_PROMISC_ENA, pf->flags);
ret = -EAGAIN;
}
if (test_bit(ICE_FLAG_VF_VLAN_PRUNING, change_flags) &&
ice_has_vfs(pf)) {
dev_err(dev, "vf-vlan-pruning: VLAN pruning cannot be changed while VFs are active.\n"); /* toggle bit back to previous state */
change_bit(ICE_FLAG_VF_VLAN_PRUNING, pf->flags);
ret = -EOPNOTSUPP;
}
ethtool_exit:
clear_bit(ICE_FLAG_ETHTOOL_CTXT, pf->flags); return ret;
}
staticint ice_get_sset_count(struct net_device *netdev, int sset)
{ switch (sset) { case ETH_SS_STATS: /* The number (and order) of strings reported *must* remain *constantforagivennetdevice.Thisfunctionmustnot *reportadifferentnumberbasedonruntimeparameters *(suchasthenumberofqueuesinuse,orthesettingof *aprivateethtoolflag).Thisisduetothenatureofthe *ethtoolstatsAPI. * *Userspaceprogramssuchasethtoolmustmake3separate *ioctlrequests,oneforsize,oneforthestrings,and *finallyoneforthestats.Sincethesecrossinto *userspace,changestothenumberorsizecouldresultin *undefinedmemoryaccessorincorrectstring<->value *correlationsforstatistics. * *Evenifitappearstobesafe,changestothesizeor *orderofstringswillsufferfromraceconditionsandare *notsafe.
*/ return ICE_ALL_STATS_LEN(netdev); case ETH_SS_TEST: return ICE_TEST_LEN; case ETH_SS_PRIV_FLAGS: return ICE_PRIV_FLAG_ARRAY_SIZE; default: return -EOPNOTSUPP;
}
}
/* Check if lenient mode is supported and enabled, or in strict mode. * *InlenientmodetheSupportedlinkmodesarethePHYtypeswithout *media.TheAdvertisinglinkmodeiseither1.theuserrequested *speed,2.theoverridePHYmask,or3.thePHYtypeswithmedia. * *InstrictmodeSupportedlinkmodearethePHYtypewithmedia, *andAdvertisinglinkmodesarethemediaPHYtypeorthespeed *requestedbyuser.
*/ if (test_bit(ICE_FLAG_LINK_LENIENT_MODE_ENA, pf->flags)) {
phy_types_low = le64_to_cpu(pf->nvm_phy_type_lo);
phy_types_high = le64_to_cpu(pf->nvm_phy_type_hi);
ice_mask_min_supported_speeds(&pf->hw, phy_types_high,
&phy_types_low); /* determine advertised modes based on link override only *ifit'ssupportedandiftheFWdoesn'tabstractthe *driverfromhavingtoaccountforlinkoverrides
*/ if (ice_fw_supports_link_override(&pf->hw) &&
!ice_fw_supports_report_dflt_cfg(&pf->hw)) { struct ice_link_default_override_tlv *ldo;
/* If Advertising link mode PHY type is not using override PHY type, *thenusePHYtypewithmedia.
*/ if (!advert_phy_type_lo && !advert_phy_type_hi) {
advert_phy_type_lo = vsi->port_info->phy.phy_type_low;
advert_phy_type_hi = vsi->port_info->phy.phy_type_high;
}
for (i = 0; i < ARRAY_SIZE(phy_type_low_lkup); i++) { if (phy_types_low & BIT_ULL(i))
ice_linkmode_set_bit(&phy_type_low_lkup[i], ks,
req_speeds, advert_phy_type_lo,
i);
}
for (i = 0; i < ARRAY_SIZE(phy_type_high_lkup); i++) { if (phy_types_high & BIT_ULL(i))
ice_linkmode_set_bit(&phy_type_high_lkup[i], ks,
req_speeds, advert_phy_type_hi,
i);
}
}
/* Get supported and advertised settings from PHY ability with media */
ice_phy_type_to_ethtool(netdev, ks);
switch (link_info->link_speed) { case ICE_AQ_LINK_SPEED_200GB:
ks->base.speed = SPEED_200000; break; case ICE_AQ_LINK_SPEED_100GB:
ks->base.speed = SPEED_100000; break; case ICE_AQ_LINK_SPEED_50GB:
ks->base.speed = SPEED_50000; break; case ICE_AQ_LINK_SPEED_40GB:
ks->base.speed = SPEED_40000; break; case ICE_AQ_LINK_SPEED_25GB:
ks->base.speed = SPEED_25000; break; case ICE_AQ_LINK_SPEED_20GB:
ks->base.speed = SPEED_20000; break; case ICE_AQ_LINK_SPEED_10GB:
ks->base.speed = SPEED_10000; break; case ICE_AQ_LINK_SPEED_5GB:
ks->base.speed = SPEED_5000; break; case ICE_AQ_LINK_SPEED_2500MB:
ks->base.speed = SPEED_2500; break; case ICE_AQ_LINK_SPEED_1000MB:
ks->base.speed = SPEED_1000; break; case ICE_AQ_LINK_SPEED_100MB:
ks->base.speed = SPEED_100; break; default:
netdev_info(netdev, "WARNING: Unrecognized link_speed (0x%x).\n",
link_info->link_speed); break;
}
ks->base.duplex = DUPLEX_FULL;
if (link_info->an_info & ICE_AQ_AN_COMPLETED)
ethtool_link_ksettings_add_link_mode(ks, lp_advertising,
Autoneg);
/* Set flow control negotiated Rx/Tx pause */ switch (pi->fc.current_mode) { case ICE_FC_FULL:
ethtool_link_ksettings_add_link_mode(ks, lp_advertising, Pause); break; case ICE_FC_TX_PAUSE:
ethtool_link_ksettings_add_link_mode(ks, lp_advertising, Pause);
ethtool_link_ksettings_add_link_mode(ks, lp_advertising,
Asym_Pause); break; case ICE_FC_RX_PAUSE:
ethtool_link_ksettings_add_link_mode(ks, lp_advertising,
Asym_Pause); break; case ICE_FC_PFC: default:
ethtool_link_ksettings_del_link_mode(ks, lp_advertising, Pause);
ethtool_link_ksettings_del_link_mode(ks, lp_advertising,
Asym_Pause); break;
}
}
/** *ice_get_settings_link_down-GettheLinksettingswhenlinkisdown *@ks:ethtoolksettingstofillin *@netdev:networkinterfacedevicestructure * *Reportslinksettingsthatcanbedeterminedwhenlinkisdown
*/ staticvoid
ice_get_settings_link_down(struct ethtool_link_ksettings *ks, struct net_device *netdev)
{ /* link is down and the driver needs to fall back on *supportedPHYtypestofigureoutwhatinfotodisplay
*/
ice_phy_type_to_ethtool(netdev, ks);
/* With no link, speed and duplex are unknown */
ks->base.speed = SPEED_UNKNOWN;
ks->base.duplex = DUPLEX_UNKNOWN;
}
/* set speed and duplex */ if (hw_link_info->link_info & ICE_AQ_LINK_UP)
ice_get_settings_link_up(ks, netdev); else
ice_get_settings_link_down(ks, netdev);
/* Check autoneg */ if (autoneg_enabled == AUTONEG_ENABLE) { /* If autoneg was not already enabled */ if (!(p->phy.link_info.an_info & ICE_AQ_AN_COMPLETED)) { /* If autoneg is not supported, return error */ if (!ethtool_link_ksettings_test_link_mode(ks,
supported,
Autoneg)) {
netdev_info(netdev, "Autoneg not supported on this phy.\n");
err = -EINVAL;
} else { /* Autoneg is allowed to change */
config->caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
*autoneg_changed = 1;
}
}
} else { /* If autoneg is currently enabled */ if (p->phy.link_info.an_info & ICE_AQ_AN_COMPLETED) { /* If autoneg is supported 10GBASE_T is the only PHY *thatcandisableit,sootherwisereturnerror
*/ if (ethtool_link_ksettings_test_link_mode(ks,
supported,
Autoneg)) {
netdev_info(netdev, "Autoneg cannot be disabled on this phy\n");
err = -EINVAL;
} else { /* Autoneg is allowed to change */
config->caps &= ~ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
*autoneg_changed = 1;
}
}
}
return err;
}
/** *ice_set_phy_type_from_speed-setphy_typesbasedonspeeds *andadvertisedmodes *@ks:ethtoollinkksettingsstruct *@phy_type_low:pointertothelowerpartofphy_type *@phy_type_high:pointertothehigherpartofphy_type *@adv_link_speed:targetedlinkspeedsbitmap
*/ staticvoid
ice_set_phy_type_from_speed(conststruct ethtool_link_ksettings *ks,
u64 *phy_type_low, u64 *phy_type_high,
u16 adv_link_speed)
{ /* Handle 1000M speed in a special way because ice_update_phy_type *enablesalllinkmodes,buthavingmixedcopperandoptical *standardsisnotsupported.
*/
adv_link_speed &= ~ICE_AQ_LINK_SPEED_1000MB;
if (ethtool_link_ksettings_test_link_mode(ks, advertising, 1000baseT_Full))
*phy_type_low |= ICE_PHY_TYPE_LOW_1000BASE_T |
ICE_PHY_TYPE_LOW_1G_SGMII;
if (ethtool_link_ksettings_test_link_mode(ks, advertising, 1000baseKX_Full))
*phy_type_low |= ICE_PHY_TYPE_LOW_1000BASE_KX;
if (ethtool_link_ksettings_test_link_mode(ks, advertising, 1000baseX_Full))
*phy_type_low |= ICE_PHY_TYPE_LOW_1000BASE_SX |
ICE_PHY_TYPE_LOW_1000BASE_LX;
phy_caps = kzalloc(sizeof(*phy_caps), GFP_KERNEL); if (!phy_caps) return -ENOMEM;
/* Get the PHY capabilities based on media */ if (ice_fw_supports_report_dflt_cfg(pi->hw))
err = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_DFLT_CFG,
phy_caps, NULL); else
err = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_TOPO_CAP_MEDIA,
phy_caps, NULL); if (err) goto done;
/* save autoneg out of ksettings */
autoneg = copy_ks.base.autoneg;
/* Get link modes supported by hardware.*/
ice_phy_type_to_ethtool(netdev, &safe_ks);
/* and check against modes requested by user. *Returnanerrorifunsupportedmodewasset.
*/ if (!bitmap_subset(copy_ks.link_modes.advertising,
safe_ks.link_modes.supported,
__ETHTOOL_LINK_MODE_MASK_NBITS)) { if (!test_bit(ICE_FLAG_LINK_LENIENT_MODE_ENA, pf->flags))
netdev_info(netdev, "The selected speed is not supported by the current media. Please select a link speed that is supported by the current media.\n");
err = -EOPNOTSUPP; goto done;
}
/* get our own copy of the bits to check against */
memset(&safe_ks, 0, sizeof(safe_ks));
safe_ks.base.cmd = copy_ks.base.cmd;
safe_ks.base.link_mode_masks_nwords =
copy_ks.base.link_mode_masks_nwords;
ice_get_link_ksettings(netdev, &safe_ks);
/* set autoneg back to what it currently is */
copy_ks.base.autoneg = safe_ks.base.autoneg; /* we don't compare the speed */
copy_ks.base.speed = safe_ks.base.speed;
while (test_and_set_bit(ICE_CFG_BUSY, pf->state)) {
timeout--; if (!timeout) {
err = -EBUSY; goto done;
}
usleep_range(TEST_SET_BITS_SLEEP_MIN, TEST_SET_BITS_SLEEP_MAX);
}
/* Copy the current user PHY configuration. The current user PHY *configurationisinitializedduringprobefromPHYcapabilities *softwaremode,andupdatedonsetPHYconfiguration.
*/
config = pi->phy.curr_user_phy_cfg;
/* If speed didn't get set, set it to what it currently is. *Thisisneededbecauseifadvertiseis0(asitiswhenautoneg *isdisabled)thenspeedwon'tgetset.
*/ if (!adv_link_speed)
adv_link_speed = curr_link_speed;
/* Convert the advertise link speeds to their corresponded PHY_TYPE */
ice_set_phy_type_from_speed(ks, &phy_type_low, &phy_type_high,
adv_link_speed);
if (!autoneg_changed && adv_link_speed == curr_link_speed) {
netdev_info(netdev, "Nothing changed, exiting without setting anything.\n"); goto done;
}
/* save the requested speeds */
pi->phy.link_info.req_speeds = adv_link_speed;
/* set link and auto negotiation so changes take effect */
config.caps |= ICE_AQ_PHY_ENA_LINK;
/* check if there is a PHY type for the requested advertised speed */ if (!(phy_type_low || phy_type_high)) {
netdev_info(netdev, "The selected speed is not supported by the current media. Please select a link speed that is supported by the current media.\n");
err = -EOPNOTSUPP; goto done;
}
if (!(config.phy_type_high || config.phy_type_low)) { /* If there is no intersection and lenient mode is enabled, then *intersecttherequestedadvertisedspeedwithNVMmediatype *PHYtypes.
*/ if (test_bit(ICE_FLAG_LINK_LENIENT_MODE_ENA, pf->flags)) {
config.phy_type_high = cpu_to_le64(phy_type_high) &
pf->nvm_phy_type_hi;
config.phy_type_low = cpu_to_le64(phy_type_low) &
pf->nvm_phy_type_lo;
} else {
netdev_info(netdev, "The selected speed is not supported by the current media. Please select a link speed that is supported by the current media.\n");
err = -EOPNOTSUPP; goto done;
}
}
/* If link is up put link down */ if (pi->phy.link_info.link_info & ICE_AQ_LINK_UP) { /* Tell the OS link is going down, the link will go *backupwhenfwsaysitisreadyasynchronously
*/
ice_print_link_msg(np->vsi, false);
netif_carrier_off(netdev);
netif_tx_stop_all_queues(netdev);
}
/* make the aq call */
err = ice_aq_set_phy_cfg(&pf->hw, pi, &config, NULL); if (err) {
netdev_info(netdev, "Set phy config failed,\n"); goto done;
}
if (nfc->data & RXH_IP_SRC || nfc->data & RXH_IP_DST) { switch (nfc->flow_type) { case TCP_V4_FLOW: case UDP_V4_FLOW: case SCTP_V4_FLOW: case GTPU_V4_FLOW: case GTPC_V4_FLOW: case GTPC_TEID_V4_FLOW: case GTPU_EH_V4_FLOW: case GTPU_UL_V4_FLOW: case GTPU_DL_V4_FLOW: if (nfc->data & RXH_IP_SRC)
hfld |= ICE_FLOW_HASH_FLD_IPV4_SA; if (nfc->data & RXH_IP_DST)
hfld |= ICE_FLOW_HASH_FLD_IPV4_DA; break; case TCP_V6_FLOW: case UDP_V6_FLOW: case SCTP_V6_FLOW: case GTPU_V6_FLOW: case GTPC_V6_FLOW: case GTPC_TEID_V6_FLOW: case GTPU_EH_V6_FLOW: case GTPU_UL_V6_FLOW: case GTPU_DL_V6_FLOW: if (nfc->data & RXH_IP_SRC)
hfld |= ICE_FLOW_HASH_FLD_IPV6_SA; if (nfc->data & RXH_IP_DST)
hfld |= ICE_FLOW_HASH_FLD_IPV6_DA; break; default: break;
}
}
if (nfc->data & RXH_L4_B_0_1 || nfc->data & RXH_L4_B_2_3) { switch (nfc->flow_type) { case TCP_V4_FLOW: case TCP_V6_FLOW: if (nfc->data & RXH_L4_B_0_1)
hfld |= ICE_FLOW_HASH_FLD_TCP_SRC_PORT; if (nfc->data & RXH_L4_B_2_3)
hfld |= ICE_FLOW_HASH_FLD_TCP_DST_PORT; break; case UDP_V4_FLOW: case UDP_V6_FLOW: if (nfc->data & RXH_L4_B_0_1)
hfld |= ICE_FLOW_HASH_FLD_UDP_SRC_PORT; if (nfc->data & RXH_L4_B_2_3)
hfld |= ICE_FLOW_HASH_FLD_UDP_DST_PORT; break; case SCTP_V4_FLOW: case SCTP_V6_FLOW: if (nfc->data & RXH_L4_B_0_1)
hfld |= ICE_FLOW_HASH_FLD_SCTP_SRC_PORT; if (nfc->data & RXH_L4_B_2_3)
hfld |= ICE_FLOW_HASH_FLD_SCTP_DST_PORT; break; default: break;
}
}
if (nfc->data & RXH_GTP_TEID) { switch (nfc->flow_type) { case GTPC_TEID_V4_FLOW: case GTPC_TEID_V6_FLOW:
hfld |= ICE_FLOW_HASH_FLD_GTPC_TEID; break; case GTPU_V4_FLOW: case GTPU_V6_FLOW:
hfld |= ICE_FLOW_HASH_FLD_GTPU_IP_TEID; break; case GTPU_EH_V4_FLOW: case GTPU_EH_V6_FLOW:
hfld |= ICE_FLOW_HASH_FLD_GTPU_EH_TEID; break; case GTPU_UL_V4_FLOW: case GTPU_UL_V6_FLOW:
hfld |= ICE_FLOW_HASH_FLD_GTPU_UP_TEID; break; case GTPU_DL_V4_FLOW: case GTPU_DL_V6_FLOW:
hfld |= ICE_FLOW_HASH_FLD_GTPU_DWN_TEID; break; default: break;
}
}
dev = ice_pf_to_dev(pf); if (ice_is_safe_mode(pf)) {
dev_dbg(dev, "Advanced RSS disabled. Package download failed, vsi num = %d\n",
vsi->vsi_num); return -EINVAL;
}
symm = !!(vsi->rss_hfunc == ICE_AQ_VSI_Q_OPT_RSS_HASH_SYM_TPLZ);
hashed_flds = ice_parse_hash_flds(nfc, symm); if (hashed_flds == ICE_HASH_INVALID) {
dev_dbg(dev, "Invalid hash fields, vsi num = %d\n",
vsi->vsi_num); return -EINVAL;
}
hdrs = ice_parse_hdrs(nfc); if (hdrs == ICE_FLOW_SEG_HDR_NONE) {
dev_dbg(dev, "Header type is not valid, vsi num = %d\n",
vsi->vsi_num); return -EINVAL;
}
nfc->data = 0; if (ice_is_safe_mode(pf)) {
dev_dbg(dev, "Advanced RSS disabled. Package download failed, vsi num = %d\n",
vsi->vsi_num); return0;
}
hdrs = ice_parse_hdrs(nfc); if (hdrs == ICE_FLOW_SEG_HDR_NONE) {
dev_dbg(dev, "Header type is not valid, vsi num = %d\n",
vsi->vsi_num); return0;
}
hash_flds = ice_get_rss_cfg(&pf->hw, vsi->idx, hdrs, &symm); if (hash_flds == ICE_HASH_INVALID) {
dev_dbg(dev, "No hash fields found for the given header type, vsi num = %d\n",
vsi->vsi_num); return0;
}
if (ring->tx_pending > ICE_MAX_NUM_DESC ||
ring->tx_pending < ICE_MIN_NUM_DESC ||
ring->rx_pending > ICE_MAX_NUM_DESC ||
ring->rx_pending < ICE_MIN_NUM_DESC) {
netdev_err(netdev, "Descriptors requested (Tx: %d / Rx: %d) out of range [%d-%d] (increment %d)\n",
ring->tx_pending, ring->rx_pending,
ICE_MIN_NUM_DESC, ICE_MAX_NUM_DESC,
ICE_REQ_DESC_MULTIPLE); return -EINVAL;
}
/* Return if there is no rings (device is reloading) */ if (!vsi->tx_rings || !vsi->rx_rings) return -EBUSY;
new_tx_cnt = ALIGN(ring->tx_pending, ICE_REQ_DESC_MULTIPLE); if (new_tx_cnt != ring->tx_pending)
netdev_info(netdev, "Requested Tx descriptor count rounded up to %d\n",
new_tx_cnt);
new_rx_cnt = ALIGN(ring->rx_pending, ICE_REQ_DESC_MULTIPLE); if (new_rx_cnt != ring->rx_pending)
netdev_info(netdev, "Requested Rx descriptor count rounded up to %d\n",
new_rx_cnt);
/* if nothing to do return success */ if (new_tx_cnt == vsi->tx_rings[0]->count &&
new_rx_cnt == vsi->rx_rings[0]->count) {
netdev_dbg(netdev, "Nothing to change, descriptor count is same as requested\n"); return0;
}
/* If there is a AF_XDP UMEM attached to any of Rx rings, *disallowchangingthenumberofdescriptors--regardless *ifthenetdevisrunningornot.
*/ if (ice_xsk_any_rx_ring_ena(vsi)) return -EBUSY;
while (test_and_set_bit(ICE_CFG_BUSY, pf->state)) {
timeout--; if (!timeout) return -EBUSY;
usleep_range(1000, 2000);
}
/* set for the next time the netdev is started */ if (!netif_running(vsi->netdev)) {
ice_for_each_alloc_txq(vsi, i)
vsi->tx_rings[i]->count = new_tx_cnt;
ice_for_each_alloc_rxq(vsi, i)
vsi->rx_rings[i]->count = new_rx_cnt; if (ice_is_xdp_ena_vsi(vsi))
ice_for_each_xdp_txq(vsi, i)
vsi->xdp_rings[i]->count = new_tx_cnt;
vsi->num_tx_desc = (u16)new_tx_cnt;
vsi->num_rx_desc = (u16)new_rx_cnt;
netdev_dbg(netdev, "Link is down, descriptor count change happens when link is brought up\n"); goto done;
}
if (new_tx_cnt == vsi->tx_rings[0]->count) goto process_rx;
/* alloc updated Tx resources */
netdev_info(netdev, "Changing Tx descriptor count from %d to %d\n",
vsi->tx_rings[0]->count, new_tx_cnt);
ice_for_each_rxq(vsi, i) { /* clone ring and setup updated count */
rx_rings[i] = *vsi->rx_rings[i];
rx_rings[i].count = new_rx_cnt;
rx_rings[i].cached_phctime = pf->ptp.cached_phc_time;
rx_rings[i].desc = NULL;
rx_rings[i].rx_buf = NULL; /* this is to allow wr32 to have something to write to *duringearlyallocationofRxbuffers
*/
rx_rings[i].tail = vsi->back->hw.hw_addr + PRTGEN_STATUS;
err = ice_setup_rx_ring(&rx_rings[i]); if (err) goto rx_unwind;
process_link: /* Bring interface down, copy in the new ring info, then restore the *interface.ifVSIisup,bringitdownandthenbackup
*/ if (!test_and_set_bit(ICE_VSI_DOWN, vsi->state)) {
ice_down(vsi);
/* Changing the port's flow control is not supported if this isn't the *PFVSI
*/ if (vsi->type != ICE_VSI_PF) {
netdev_info(netdev, "Changing flow control parameters only supported for PF VSI\n"); return -EOPNOTSUPP;
}
/* Get pause param reports configured and negotiated flow control pause *whenETHTOOL_GLINKSETTINGSisdefined.SinceETHTOOL_GLINKSETTINGSis *definedgetpauseparampause->autonegreportsSWconfiguredsetting, *socomparepause->autonegwithSWconfiguredtopreventtheuserfrom *usingsetpauseparamtochanceautoneg.
*/
pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL); if (!pcaps) return -ENOMEM;
/* Get current PHY config */
err = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_ACTIVE_CFG, pcaps,
NULL); if (err) {
kfree(pcaps); return err;
}
/* If we have link and don't have autoneg */ if (!test_bit(ICE_DOWN, pf->state) &&
!(hw_link_info->an_info & ICE_AQ_AN_COMPLETED)) { /* Send message that it might not necessarily work*/
netdev_info(netdev, "Autoneg did not complete so changing settings may not result in an actual change.\n");
}
if (dcbx_cfg->pfc.pfcena) {
netdev_info(netdev, "Priority flow control enabled. Cannot set link flow control.\n"); return -EOPNOTSUPP;
} if (pause->rx_pause && pause->tx_pause)
pi->fc.req_mode = ICE_FC_FULL; elseif (pause->rx_pause && !pause->tx_pause)
pi->fc.req_mode = ICE_FC_RX_PAUSE; elseif (!pause->rx_pause && pause->tx_pause)
pi->fc.req_mode = ICE_FC_TX_PAUSE; elseif (!pause->rx_pause && !pause->tx_pause)
pi->fc.req_mode = ICE_FC_NONE; else return -EINVAL;
/* Set the FC mode and only restart AN if link is up */
err = ice_set_fc(pi, &aq_failures, link_up);
if (aq_failures & ICE_SET_FC_AQ_FAIL_GET) {
netdev_info(netdev, "Set fc failed on the get_phy_capabilities call with err %d aq_err %s\n",
err, libie_aq_str(hw->adminq.sq_last_status));
err = -EAGAIN;
} elseif (aq_failures & ICE_SET_FC_AQ_FAIL_SET) {
netdev_info(netdev, "Set fc failed on the set_phy_config call with err %d aq_err %s\n",
err, libie_aq_str(hw->adminq.sq_last_status));
err = -EAGAIN;
} elseif (aq_failures & ICE_SET_FC_AQ_FAIL_UPDATE) {
netdev_info(netdev, "Set fc failed on the get_link_info call with err %d aq_err %s\n",
err, libie_aq_str(hw->adminq.sq_last_status));
err = -EAGAIN;
}
dev = ice_pf_to_dev(pf); if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
rxfh->hfunc != ETH_RSS_HASH_TOP) return -EOPNOTSUPP;
if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) { /* RSS not supported return error here */
netdev_warn(netdev, "RSS is not configured on this VSI!\n"); return -EIO;
}
if (ice_is_adq_active(pf)) {
netdev_err(netdev, "Cannot change RSS params with ADQ configured.\n"); return -EOPNOTSUPP;
}
/* Update the VSI's hash function */ if (rxfh->input_xfrm & RXH_XFRM_SYM_XOR)
hfunc = ICE_AQ_VSI_Q_OPT_RSS_HASH_SYM_TPLZ;
err = ice_set_rss_hfunc(vsi, hfunc); if (err) return err;
if (rxfh->key) { if (!vsi->rss_hkey_user) {
vsi->rss_hkey_user =
devm_kzalloc(dev, ICE_VSIQF_HKEY_ARRAY_SIZE,
GFP_KERNEL); if (!vsi->rss_hkey_user) return -ENOMEM;
}
memcpy(vsi->rss_hkey_user, rxfh->key,
ICE_VSIQF_HKEY_ARRAY_SIZE);
err = ice_set_rss_key(vsi, vsi->rss_hkey_user); if (err) return err;
}
if (!vsi->rss_lut_user) {
vsi->rss_lut_user = devm_kzalloc(dev, vsi->rss_table_size,
GFP_KERNEL); if (!vsi->rss_lut_user) return -ENOMEM;
}
/* Each 32 bits pointed by 'indir' is stored with a lut entry */ if (rxfh->indir) { int i;
for (i = 0; i < vsi->rss_table_size; i++)
vsi->rss_lut_user[i] = (u8)(rxfh->indir[i]);
} else {
ice_fill_rss_lut(vsi->rss_lut_user, vsi->rss_table_size,
vsi->rss_size);
}
err = ice_set_rss_lut(vsi, vsi->rss_lut_user, vsi->rss_table_size); if (err) return err;
/* do not support changing channels in Safe Mode */ if (ice_is_safe_mode(pf)) {
netdev_err(dev, "Changing channel in Safe Mode is not supported\n"); return -EOPNOTSUPP;
} /* do not support changing other_count */ if (ch->other_count != (test_bit(ICE_FLAG_FD_ENA, pf->flags) ? 1U : 0U)) return -EINVAL;
if (ice_is_adq_active(pf)) {
netdev_err(dev, "Cannot set channels with ADQ configured.\n"); return -EOPNOTSUPP;
}
if (test_bit(ICE_FLAG_FD_ENA, pf->flags) && pf->hw.fdir_active_fltr) {
netdev_err(dev, "Cannot set channels when Flow Director filters are active\n"); return -EOPNOTSUPP;
}
if (ch->rx_count && ch->tx_count) {
netdev_err(dev, "Dedicated RX or TX channels cannot be used simultaneously\n"); return -EINVAL;
}
if (new_rx < vsi->tc_cfg.numtc) {
netdev_err(dev, "Cannot set less Rx channels, than Traffic Classes you have (%u)\n",
vsi->tc_cfg.numtc); return -EINVAL;
} if (new_tx < vsi->tc_cfg.numtc) {
netdev_err(dev, "Cannot set less Tx channels, than Traffic Classes you have (%u)\n",
vsi->tc_cfg.numtc); return -EINVAL;
} if (new_rx > ice_get_max_rxq(pf)) {
netdev_err(dev, "Maximum allowed Rx channels is %d\n",
ice_get_max_rxq(pf)); return -EINVAL;
} if (new_tx > ice_get_max_txq(pf)) {
netdev_err(dev, "Maximum allowed Tx channels is %d\n",
ice_get_max_txq(pf)); return -EINVAL;
}
if (pf->cdev_info && pf->cdev_info->adev) {
mutex_lock(&pf->adev_mutex);
device_lock(&pf->cdev_info->adev->dev);
locked = true; if (pf->cdev_info->adev->dev.driver) {
netdev_err(dev, "Cannot change channels when RDMA is active\n");
ret = -EBUSY; goto adev_unlock;
}
}
ice_vsi_recfg_qs(vsi, new_rx, new_tx, locked);
if (!netif_is_rxfh_configured(dev)) {
ret = ice_vsi_set_dflt_rss_lut(vsi, new_rx); goto adev_unlock;
}
/* Update rss_size due to change in Rx queues */
vsi->rss_size = ice_get_valid_rss_size(&pf->hw, new_rx);
adev_unlock: if (locked) {
device_unlock(&pf->cdev_info->adev->dev);
mutex_unlock(&pf->adev_mutex);
} return ret;
}
if (vsi->type != ICE_VSI_PF || !ice_is_wol_supported(&pf->hw)) return -EOPNOTSUPP;
/* only magic packet is supported */ if (wol->wolopts && wol->wolopts != WAKE_MAGIC) return -EOPNOTSUPP;
/* Set WoL only if there is a new value */ if (pf->wol_ena != !!wol->wolopts) {
pf->wol_ena = !!wol->wolopts;
device_set_wakeup_enable(ice_pf_to_dev(pf), pf->wol_ena);
netdev_dbg(netdev, "WoL magic packet %sabled\n",
pf->wol_ena ? "en" : "dis");
}
itr_setting = rc->itr_setting; if (coalesce_usecs != itr_setting && use_adaptive_coalesce) {
netdev_info(vsi->netdev, "%s interrupt throttling cannot be changed if adaptive-%s is enabled\n",
c_type_str, c_type_str); return -EINVAL;
}
if (coalesce_usecs > ICE_ITR_MAX) {
netdev_info(vsi->netdev, "Invalid value, %s-usecs range is 0-%d\n",
c_type_str, ICE_ITR_MAX); return -EINVAL;
}
if (use_adaptive_coalesce) {
rc->itr_mode = ITR_DYNAMIC;
} else {
rc->itr_mode = ITR_STATIC; /* store user facing value how it was set */
rc->itr_setting = coalesce_usecs; /* write the change to the register */
ice_write_itr(rc, coalesce_usecs); /* force writes to take effect immediately, the flush shouldn't *bedoneinthefunctionsabovebecausetheintentisfor *themtodolazywrites.
*/
ice_flush(&pf->hw);
}
if (itr_setting != coalesce_usecs && (coalesce_usecs % 2))
netdev_info(netdev, "User set %s-usecs to %d, device only supports even values. Rounding down and attempting to set %s-usecs to %d\n",
c_type_str, coalesce_usecs, c_type_str,
ITR_REG_ALIGN(coalesce_usecs));
}
ice_for_each_q_vector(vsi, v_idx) { /* In some cases if DCB is configured the num_[rx|tx]q *canbelessthanvsi->num_q_vectors.Thischeck *accountsforthatsowedon'treportafalsefailure
*/ if (v_idx >= vsi->num_rxq && v_idx >= vsi->num_txq) goto set_complete;
if (ice_set_q_coalesce(vsi, ec, v_idx)) return -EINVAL;
status = ice_aq_sff_eeprom(hw, 0, addr, offset, page, 0, value, 1, 0,
NULL); if (status) return status;
if (value[0] == ICE_MODULE_TYPE_SFP)
is_sfp = true;
memset(data, 0, ee->len); for (i = 0; i < ee->len; i += SFF_READ_BLOCK_SIZE) {
offset = i + ee->offset;
page = 0;
/* Check if we need to access the other memory page */ if (is_sfp) { if (offset >= ETH_MODULE_SFF_8079_LEN) {
offset -= ETH_MODULE_SFF_8079_LEN;
addr = ICE_I2C_EEPROM_DEV_ADDR2;
}
} else { while (offset >= ETH_MODULE_SFF_8436_LEN) { /* Compute memory page number and offset. */
offset -= ETH_MODULE_SFF_8436_LEN / 2;
page++;
}
}
/* Bit 2 of EEPROM address 0x02 declares upper *pagesaredisabledonQSFPmodules. *SFPmodulesonlyeverusepage0.
*/ if (page == 0 || !(data[0x2] & 0x4)) {
u32 copy_len;
/* If i2c bus is busy due to slow page change or *linkmanagementaccess,callcanfail.Thisisnormal. *Soweretrythisafewtimes.
*/ for (j = 0; j < 4; j++) {
status = ice_aq_sff_eeprom(hw, 0, addr, offset, page,
!is_sfp, value,
SFF_READ_BLOCK_SIZE, 0, NULL);
netdev_dbg(netdev, "SFF %02X %02X %02X %X = %02X%02X%02X%02X.%02X%02X%02X%02X (%X)\n",
addr, offset, page, is_sfp,
value[0], value[1], value[2], value[3],
value[4], value[5], value[6], value[7],
status); if (status) {
usleep_range(1500, 2500);
memset(value, 0, SFF_READ_BLOCK_SIZE); continue;
} break;
}
/* Make sure we have enough room for the new block */
copy_len = min_t(u32, SFF_READ_BLOCK_SIZE, ee->len - i);
memcpy(data + i, value, copy_len);
}
} return0;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.