162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright(c) 2017 - 2019 Pensando Systems, Inc */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/module.h> 562306a36Sopenharmony_ci#include <linux/netdevice.h> 662306a36Sopenharmony_ci#include <linux/sfp.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "ionic.h" 962306a36Sopenharmony_ci#include "ionic_bus.h" 1062306a36Sopenharmony_ci#include "ionic_lif.h" 1162306a36Sopenharmony_ci#include "ionic_ethtool.h" 1262306a36Sopenharmony_ci#include "ionic_stats.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic void ionic_get_stats_strings(struct ionic_lif *lif, u8 *buf) 1562306a36Sopenharmony_ci{ 1662306a36Sopenharmony_ci u32 i; 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci for (i = 0; i < ionic_num_stats_grps; i++) 1962306a36Sopenharmony_ci ionic_stats_groups[i].get_strings(lif, &buf); 2062306a36Sopenharmony_ci} 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic void ionic_get_stats(struct net_device *netdev, 2362306a36Sopenharmony_ci struct ethtool_stats *stats, u64 *buf) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci struct ionic_lif *lif = netdev_priv(netdev); 2662306a36Sopenharmony_ci u32 i; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci if (test_bit(IONIC_LIF_F_FW_RESET, lif->state)) 2962306a36Sopenharmony_ci return; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci memset(buf, 0, stats->n_stats * sizeof(*buf)); 3262306a36Sopenharmony_ci for (i = 0; i < ionic_num_stats_grps; i++) 3362306a36Sopenharmony_ci ionic_stats_groups[i].get_values(lif, &buf); 3462306a36Sopenharmony_ci} 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic int ionic_get_stats_count(struct ionic_lif *lif) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci int i, num_stats = 0; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci for (i = 0; i < ionic_num_stats_grps; i++) 4162306a36Sopenharmony_ci num_stats += ionic_stats_groups[i].get_count(lif); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci return num_stats; 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic int ionic_get_sset_count(struct net_device *netdev, int sset) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci struct ionic_lif *lif = netdev_priv(netdev); 4962306a36Sopenharmony_ci int count = 0; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci switch (sset) { 5262306a36Sopenharmony_ci case ETH_SS_STATS: 5362306a36Sopenharmony_ci count = ionic_get_stats_count(lif); 5462306a36Sopenharmony_ci break; 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci return count; 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic void ionic_get_strings(struct net_device *netdev, 6062306a36Sopenharmony_ci u32 sset, u8 *buf) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci struct ionic_lif *lif = netdev_priv(netdev); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci switch (sset) { 6562306a36Sopenharmony_ci case ETH_SS_STATS: 6662306a36Sopenharmony_ci ionic_get_stats_strings(lif, buf); 6762306a36Sopenharmony_ci break; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic void ionic_get_drvinfo(struct net_device *netdev, 7262306a36Sopenharmony_ci struct ethtool_drvinfo *drvinfo) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci struct ionic_lif *lif = netdev_priv(netdev); 7562306a36Sopenharmony_ci struct ionic *ionic = lif->ionic; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci strscpy(drvinfo->driver, IONIC_DRV_NAME, sizeof(drvinfo->driver)); 7862306a36Sopenharmony_ci strscpy(drvinfo->fw_version, ionic->idev.dev_info.fw_version, 7962306a36Sopenharmony_ci sizeof(drvinfo->fw_version)); 8062306a36Sopenharmony_ci strscpy(drvinfo->bus_info, ionic_bus_info(ionic), 8162306a36Sopenharmony_ci sizeof(drvinfo->bus_info)); 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic int ionic_get_regs_len(struct net_device *netdev) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci return (IONIC_DEV_INFO_REG_COUNT + IONIC_DEV_CMD_REG_COUNT) * sizeof(u32); 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic void ionic_get_regs(struct net_device *netdev, struct ethtool_regs *regs, 9062306a36Sopenharmony_ci void *p) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci struct ionic_lif *lif = netdev_priv(netdev); 9362306a36Sopenharmony_ci unsigned int offset; 9462306a36Sopenharmony_ci unsigned int size; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci regs->version = IONIC_DEV_CMD_REG_VERSION; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci offset = 0; 9962306a36Sopenharmony_ci size = IONIC_DEV_INFO_REG_COUNT * sizeof(u32); 10062306a36Sopenharmony_ci memcpy_fromio(p + offset, lif->ionic->idev.dev_info_regs->words, size); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci offset += size; 10362306a36Sopenharmony_ci size = IONIC_DEV_CMD_REG_COUNT * sizeof(u32); 10462306a36Sopenharmony_ci memcpy_fromio(p + offset, lif->ionic->idev.dev_cmd_regs->words, size); 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic void ionic_get_link_ext_stats(struct net_device *netdev, 10862306a36Sopenharmony_ci struct ethtool_link_ext_stats *stats) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci struct ionic_lif *lif = netdev_priv(netdev); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci if (lif->ionic->pdev->is_physfn) 11362306a36Sopenharmony_ci stats->link_down_events = lif->link_down_count; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic int ionic_get_link_ksettings(struct net_device *netdev, 11762306a36Sopenharmony_ci struct ethtool_link_ksettings *ks) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct ionic_lif *lif = netdev_priv(netdev); 12062306a36Sopenharmony_ci struct ionic_dev *idev = &lif->ionic->idev; 12162306a36Sopenharmony_ci int copper_seen = 0; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(ks, supported); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (!idev->port_info) { 12662306a36Sopenharmony_ci netdev_err(netdev, "port_info not initialized\n"); 12762306a36Sopenharmony_ci return -EOPNOTSUPP; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* The port_info data is found in a DMA space that the NIC keeps 13162306a36Sopenharmony_ci * up-to-date, so there's no need to request the data from the 13262306a36Sopenharmony_ci * NIC, we already have it in our memory space. 13362306a36Sopenharmony_ci */ 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci switch (le16_to_cpu(idev->port_info->status.xcvr.pid)) { 13662306a36Sopenharmony_ci /* Copper */ 13762306a36Sopenharmony_ci case IONIC_XCVR_PID_QSFP_100G_CR4: 13862306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 13962306a36Sopenharmony_ci 100000baseCR4_Full); 14062306a36Sopenharmony_ci copper_seen++; 14162306a36Sopenharmony_ci break; 14262306a36Sopenharmony_ci case IONIC_XCVR_PID_QSFP_40GBASE_CR4: 14362306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 14462306a36Sopenharmony_ci 40000baseCR4_Full); 14562306a36Sopenharmony_ci copper_seen++; 14662306a36Sopenharmony_ci break; 14762306a36Sopenharmony_ci case IONIC_XCVR_PID_SFP_25GBASE_CR_S: 14862306a36Sopenharmony_ci case IONIC_XCVR_PID_SFP_25GBASE_CR_L: 14962306a36Sopenharmony_ci case IONIC_XCVR_PID_SFP_25GBASE_CR_N: 15062306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 15162306a36Sopenharmony_ci 25000baseCR_Full); 15262306a36Sopenharmony_ci copper_seen++; 15362306a36Sopenharmony_ci break; 15462306a36Sopenharmony_ci case IONIC_XCVR_PID_SFP_10GBASE_AOC: 15562306a36Sopenharmony_ci case IONIC_XCVR_PID_SFP_10GBASE_CU: 15662306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 15762306a36Sopenharmony_ci 10000baseCR_Full); 15862306a36Sopenharmony_ci copper_seen++; 15962306a36Sopenharmony_ci break; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci /* Fibre */ 16262306a36Sopenharmony_ci case IONIC_XCVR_PID_QSFP_100G_SR4: 16362306a36Sopenharmony_ci case IONIC_XCVR_PID_QSFP_100G_AOC: 16462306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 16562306a36Sopenharmony_ci 100000baseSR4_Full); 16662306a36Sopenharmony_ci break; 16762306a36Sopenharmony_ci case IONIC_XCVR_PID_QSFP_100G_CWDM4: 16862306a36Sopenharmony_ci case IONIC_XCVR_PID_QSFP_100G_PSM4: 16962306a36Sopenharmony_ci case IONIC_XCVR_PID_QSFP_100G_LR4: 17062306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 17162306a36Sopenharmony_ci 100000baseLR4_ER4_Full); 17262306a36Sopenharmony_ci break; 17362306a36Sopenharmony_ci case IONIC_XCVR_PID_QSFP_100G_ER4: 17462306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 17562306a36Sopenharmony_ci 100000baseLR4_ER4_Full); 17662306a36Sopenharmony_ci break; 17762306a36Sopenharmony_ci case IONIC_XCVR_PID_QSFP_40GBASE_SR4: 17862306a36Sopenharmony_ci case IONIC_XCVR_PID_QSFP_40GBASE_AOC: 17962306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 18062306a36Sopenharmony_ci 40000baseSR4_Full); 18162306a36Sopenharmony_ci break; 18262306a36Sopenharmony_ci case IONIC_XCVR_PID_QSFP_40GBASE_LR4: 18362306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 18462306a36Sopenharmony_ci 40000baseLR4_Full); 18562306a36Sopenharmony_ci break; 18662306a36Sopenharmony_ci case IONIC_XCVR_PID_SFP_25GBASE_SR: 18762306a36Sopenharmony_ci case IONIC_XCVR_PID_SFP_25GBASE_AOC: 18862306a36Sopenharmony_ci case IONIC_XCVR_PID_SFP_25GBASE_ACC: 18962306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 19062306a36Sopenharmony_ci 25000baseSR_Full); 19162306a36Sopenharmony_ci break; 19262306a36Sopenharmony_ci case IONIC_XCVR_PID_SFP_10GBASE_SR: 19362306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 19462306a36Sopenharmony_ci 10000baseSR_Full); 19562306a36Sopenharmony_ci break; 19662306a36Sopenharmony_ci case IONIC_XCVR_PID_SFP_10GBASE_LR: 19762306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 19862306a36Sopenharmony_ci 10000baseLR_Full); 19962306a36Sopenharmony_ci break; 20062306a36Sopenharmony_ci case IONIC_XCVR_PID_SFP_10GBASE_LRM: 20162306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 20262306a36Sopenharmony_ci 10000baseLRM_Full); 20362306a36Sopenharmony_ci break; 20462306a36Sopenharmony_ci case IONIC_XCVR_PID_SFP_10GBASE_ER: 20562306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 20662306a36Sopenharmony_ci 10000baseER_Full); 20762306a36Sopenharmony_ci break; 20862306a36Sopenharmony_ci case IONIC_XCVR_PID_SFP_10GBASE_T: 20962306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 21062306a36Sopenharmony_ci 10000baseT_Full); 21162306a36Sopenharmony_ci break; 21262306a36Sopenharmony_ci case IONIC_XCVR_PID_SFP_1000BASE_T: 21362306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, 21462306a36Sopenharmony_ci 1000baseT_Full); 21562306a36Sopenharmony_ci break; 21662306a36Sopenharmony_ci case IONIC_XCVR_PID_UNKNOWN: 21762306a36Sopenharmony_ci /* This means there's no module plugged in */ 21862306a36Sopenharmony_ci break; 21962306a36Sopenharmony_ci default: 22062306a36Sopenharmony_ci dev_info(lif->ionic->dev, "unknown xcvr type pid=%d / 0x%x\n", 22162306a36Sopenharmony_ci idev->port_info->status.xcvr.pid, 22262306a36Sopenharmony_ci idev->port_info->status.xcvr.pid); 22362306a36Sopenharmony_ci break; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci linkmode_copy(ks->link_modes.advertising, ks->link_modes.supported); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, FEC_BASER); 22962306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, FEC_RS); 23062306a36Sopenharmony_ci if (idev->port_info->config.fec_type == IONIC_PORT_FEC_TYPE_FC) 23162306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_BASER); 23262306a36Sopenharmony_ci else if (idev->port_info->config.fec_type == IONIC_PORT_FEC_TYPE_RS) 23362306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_RS); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, FIBRE); 23662306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, Pause); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci if (idev->port_info->status.xcvr.phy == IONIC_PHY_TYPE_COPPER || 23962306a36Sopenharmony_ci copper_seen) 24062306a36Sopenharmony_ci ks->base.port = PORT_DA; 24162306a36Sopenharmony_ci else if (idev->port_info->status.xcvr.phy == IONIC_PHY_TYPE_FIBER) 24262306a36Sopenharmony_ci ks->base.port = PORT_FIBRE; 24362306a36Sopenharmony_ci else 24462306a36Sopenharmony_ci ks->base.port = PORT_NONE; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci if (ks->base.port != PORT_NONE) { 24762306a36Sopenharmony_ci ks->base.speed = le32_to_cpu(lif->info->status.link_speed); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci if (le16_to_cpu(lif->info->status.link_status)) 25062306a36Sopenharmony_ci ks->base.duplex = DUPLEX_FULL; 25162306a36Sopenharmony_ci else 25262306a36Sopenharmony_ci ks->base.duplex = DUPLEX_UNKNOWN; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, supported, Autoneg); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (idev->port_info->config.an_enable) { 25762306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(ks, advertising, 25862306a36Sopenharmony_ci Autoneg); 25962306a36Sopenharmony_ci ks->base.autoneg = AUTONEG_ENABLE; 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci return 0; 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic int ionic_set_link_ksettings(struct net_device *netdev, 26762306a36Sopenharmony_ci const struct ethtool_link_ksettings *ks) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci struct ionic_lif *lif = netdev_priv(netdev); 27062306a36Sopenharmony_ci struct ionic_dev *idev = &lif->ionic->idev; 27162306a36Sopenharmony_ci struct ionic *ionic = lif->ionic; 27262306a36Sopenharmony_ci int err = 0; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci if (test_bit(IONIC_LIF_F_FW_RESET, lif->state)) 27562306a36Sopenharmony_ci return -EBUSY; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci /* set autoneg */ 27862306a36Sopenharmony_ci if (ks->base.autoneg != idev->port_info->config.an_enable) { 27962306a36Sopenharmony_ci mutex_lock(&ionic->dev_cmd_lock); 28062306a36Sopenharmony_ci ionic_dev_cmd_port_autoneg(idev, ks->base.autoneg); 28162306a36Sopenharmony_ci err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT); 28262306a36Sopenharmony_ci mutex_unlock(&ionic->dev_cmd_lock); 28362306a36Sopenharmony_ci if (err) 28462306a36Sopenharmony_ci return err; 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci /* set speed */ 28862306a36Sopenharmony_ci if (ks->base.speed != le32_to_cpu(idev->port_info->config.speed)) { 28962306a36Sopenharmony_ci mutex_lock(&ionic->dev_cmd_lock); 29062306a36Sopenharmony_ci ionic_dev_cmd_port_speed(idev, ks->base.speed); 29162306a36Sopenharmony_ci err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT); 29262306a36Sopenharmony_ci mutex_unlock(&ionic->dev_cmd_lock); 29362306a36Sopenharmony_ci if (err) 29462306a36Sopenharmony_ci return err; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci return 0; 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic void ionic_get_pauseparam(struct net_device *netdev, 30162306a36Sopenharmony_ci struct ethtool_pauseparam *pause) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci struct ionic_lif *lif = netdev_priv(netdev); 30462306a36Sopenharmony_ci u8 pause_type; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci pause->autoneg = 0; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci pause_type = lif->ionic->idev.port_info->config.pause_type; 30962306a36Sopenharmony_ci if (pause_type) { 31062306a36Sopenharmony_ci pause->rx_pause = (pause_type & IONIC_PAUSE_F_RX) ? 1 : 0; 31162306a36Sopenharmony_ci pause->tx_pause = (pause_type & IONIC_PAUSE_F_TX) ? 1 : 0; 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic int ionic_set_pauseparam(struct net_device *netdev, 31662306a36Sopenharmony_ci struct ethtool_pauseparam *pause) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci struct ionic_lif *lif = netdev_priv(netdev); 31962306a36Sopenharmony_ci struct ionic *ionic = lif->ionic; 32062306a36Sopenharmony_ci u32 requested_pause; 32162306a36Sopenharmony_ci int err; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci if (test_bit(IONIC_LIF_F_FW_RESET, lif->state)) 32462306a36Sopenharmony_ci return -EBUSY; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (pause->autoneg) 32762306a36Sopenharmony_ci return -EOPNOTSUPP; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci /* change both at the same time */ 33062306a36Sopenharmony_ci requested_pause = IONIC_PORT_PAUSE_TYPE_LINK; 33162306a36Sopenharmony_ci if (pause->rx_pause) 33262306a36Sopenharmony_ci requested_pause |= IONIC_PAUSE_F_RX; 33362306a36Sopenharmony_ci if (pause->tx_pause) 33462306a36Sopenharmony_ci requested_pause |= IONIC_PAUSE_F_TX; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if (requested_pause == lif->ionic->idev.port_info->config.pause_type) 33762306a36Sopenharmony_ci return 0; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci mutex_lock(&ionic->dev_cmd_lock); 34062306a36Sopenharmony_ci ionic_dev_cmd_port_pause(&lif->ionic->idev, requested_pause); 34162306a36Sopenharmony_ci err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT); 34262306a36Sopenharmony_ci mutex_unlock(&ionic->dev_cmd_lock); 34362306a36Sopenharmony_ci if (err) 34462306a36Sopenharmony_ci return err; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci return 0; 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic int ionic_get_fecparam(struct net_device *netdev, 35062306a36Sopenharmony_ci struct ethtool_fecparam *fec) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci struct ionic_lif *lif = netdev_priv(netdev); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci switch (lif->ionic->idev.port_info->config.fec_type) { 35562306a36Sopenharmony_ci case IONIC_PORT_FEC_TYPE_NONE: 35662306a36Sopenharmony_ci fec->active_fec = ETHTOOL_FEC_OFF; 35762306a36Sopenharmony_ci break; 35862306a36Sopenharmony_ci case IONIC_PORT_FEC_TYPE_RS: 35962306a36Sopenharmony_ci fec->active_fec = ETHTOOL_FEC_RS; 36062306a36Sopenharmony_ci break; 36162306a36Sopenharmony_ci case IONIC_PORT_FEC_TYPE_FC: 36262306a36Sopenharmony_ci fec->active_fec = ETHTOOL_FEC_BASER; 36362306a36Sopenharmony_ci break; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci fec->fec = ETHTOOL_FEC_OFF | ETHTOOL_FEC_RS | ETHTOOL_FEC_BASER; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci return 0; 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic int ionic_set_fecparam(struct net_device *netdev, 37262306a36Sopenharmony_ci struct ethtool_fecparam *fec) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci struct ionic_lif *lif = netdev_priv(netdev); 37562306a36Sopenharmony_ci u8 fec_type; 37662306a36Sopenharmony_ci int ret = 0; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci if (test_bit(IONIC_LIF_F_FW_RESET, lif->state)) 37962306a36Sopenharmony_ci return -EBUSY; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci if (lif->ionic->idev.port_info->config.an_enable) { 38262306a36Sopenharmony_ci netdev_err(netdev, "FEC request not allowed while autoneg is enabled\n"); 38362306a36Sopenharmony_ci return -EINVAL; 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci switch (fec->fec) { 38762306a36Sopenharmony_ci case ETHTOOL_FEC_NONE: 38862306a36Sopenharmony_ci fec_type = IONIC_PORT_FEC_TYPE_NONE; 38962306a36Sopenharmony_ci break; 39062306a36Sopenharmony_ci case ETHTOOL_FEC_OFF: 39162306a36Sopenharmony_ci fec_type = IONIC_PORT_FEC_TYPE_NONE; 39262306a36Sopenharmony_ci break; 39362306a36Sopenharmony_ci case ETHTOOL_FEC_RS: 39462306a36Sopenharmony_ci fec_type = IONIC_PORT_FEC_TYPE_RS; 39562306a36Sopenharmony_ci break; 39662306a36Sopenharmony_ci case ETHTOOL_FEC_BASER: 39762306a36Sopenharmony_ci fec_type = IONIC_PORT_FEC_TYPE_FC; 39862306a36Sopenharmony_ci break; 39962306a36Sopenharmony_ci case ETHTOOL_FEC_AUTO: 40062306a36Sopenharmony_ci default: 40162306a36Sopenharmony_ci netdev_err(netdev, "FEC request 0x%04x not supported\n", 40262306a36Sopenharmony_ci fec->fec); 40362306a36Sopenharmony_ci return -EINVAL; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci if (fec_type != lif->ionic->idev.port_info->config.fec_type) { 40762306a36Sopenharmony_ci mutex_lock(&lif->ionic->dev_cmd_lock); 40862306a36Sopenharmony_ci ionic_dev_cmd_port_fec(&lif->ionic->idev, fec_type); 40962306a36Sopenharmony_ci ret = ionic_dev_cmd_wait(lif->ionic, DEVCMD_TIMEOUT); 41062306a36Sopenharmony_ci mutex_unlock(&lif->ionic->dev_cmd_lock); 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci return ret; 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic int ionic_get_coalesce(struct net_device *netdev, 41762306a36Sopenharmony_ci struct ethtool_coalesce *coalesce, 41862306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 41962306a36Sopenharmony_ci struct netlink_ext_ack *extack) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci struct ionic_lif *lif = netdev_priv(netdev); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci coalesce->tx_coalesce_usecs = lif->tx_coalesce_usecs; 42462306a36Sopenharmony_ci coalesce->rx_coalesce_usecs = lif->rx_coalesce_usecs; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state)) 42762306a36Sopenharmony_ci coalesce->use_adaptive_tx_coalesce = test_bit(IONIC_LIF_F_TX_DIM_INTR, lif->state); 42862306a36Sopenharmony_ci else 42962306a36Sopenharmony_ci coalesce->use_adaptive_tx_coalesce = 0; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci coalesce->use_adaptive_rx_coalesce = test_bit(IONIC_LIF_F_RX_DIM_INTR, lif->state); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci return 0; 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_cistatic int ionic_set_coalesce(struct net_device *netdev, 43762306a36Sopenharmony_ci struct ethtool_coalesce *coalesce, 43862306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 43962306a36Sopenharmony_ci struct netlink_ext_ack *extack) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci struct ionic_lif *lif = netdev_priv(netdev); 44262306a36Sopenharmony_ci struct ionic_identity *ident; 44362306a36Sopenharmony_ci u32 rx_coal, rx_dim; 44462306a36Sopenharmony_ci u32 tx_coal, tx_dim; 44562306a36Sopenharmony_ci unsigned int i; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci ident = &lif->ionic->ident; 44862306a36Sopenharmony_ci if (ident->dev.intr_coal_div == 0) { 44962306a36Sopenharmony_ci netdev_warn(netdev, "bad HW value in dev.intr_coal_div = %d\n", 45062306a36Sopenharmony_ci ident->dev.intr_coal_div); 45162306a36Sopenharmony_ci return -EIO; 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci /* Tx normally shares Rx interrupt, so only change Rx if not split */ 45562306a36Sopenharmony_ci if (!test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state) && 45662306a36Sopenharmony_ci (coalesce->tx_coalesce_usecs != lif->rx_coalesce_usecs || 45762306a36Sopenharmony_ci coalesce->use_adaptive_tx_coalesce)) { 45862306a36Sopenharmony_ci netdev_warn(netdev, "only rx parameters can be changed\n"); 45962306a36Sopenharmony_ci return -EINVAL; 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci /* Convert the usec request to a HW usable value. If they asked 46362306a36Sopenharmony_ci * for non-zero and it resolved to zero, bump it up 46462306a36Sopenharmony_ci */ 46562306a36Sopenharmony_ci rx_coal = ionic_coal_usec_to_hw(lif->ionic, coalesce->rx_coalesce_usecs); 46662306a36Sopenharmony_ci if (!rx_coal && coalesce->rx_coalesce_usecs) 46762306a36Sopenharmony_ci rx_coal = 1; 46862306a36Sopenharmony_ci tx_coal = ionic_coal_usec_to_hw(lif->ionic, coalesce->tx_coalesce_usecs); 46962306a36Sopenharmony_ci if (!tx_coal && coalesce->tx_coalesce_usecs) 47062306a36Sopenharmony_ci tx_coal = 1; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci if (rx_coal > IONIC_INTR_CTRL_COAL_MAX || 47362306a36Sopenharmony_ci tx_coal > IONIC_INTR_CTRL_COAL_MAX) 47462306a36Sopenharmony_ci return -ERANGE; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci /* Save the new values */ 47762306a36Sopenharmony_ci lif->rx_coalesce_usecs = coalesce->rx_coalesce_usecs; 47862306a36Sopenharmony_ci lif->rx_coalesce_hw = rx_coal; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state)) 48162306a36Sopenharmony_ci lif->tx_coalesce_usecs = coalesce->tx_coalesce_usecs; 48262306a36Sopenharmony_ci else 48362306a36Sopenharmony_ci lif->tx_coalesce_usecs = coalesce->rx_coalesce_usecs; 48462306a36Sopenharmony_ci lif->tx_coalesce_hw = tx_coal; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci if (coalesce->use_adaptive_rx_coalesce) { 48762306a36Sopenharmony_ci set_bit(IONIC_LIF_F_RX_DIM_INTR, lif->state); 48862306a36Sopenharmony_ci rx_dim = rx_coal; 48962306a36Sopenharmony_ci } else { 49062306a36Sopenharmony_ci clear_bit(IONIC_LIF_F_RX_DIM_INTR, lif->state); 49162306a36Sopenharmony_ci rx_dim = 0; 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (coalesce->use_adaptive_tx_coalesce) { 49562306a36Sopenharmony_ci set_bit(IONIC_LIF_F_TX_DIM_INTR, lif->state); 49662306a36Sopenharmony_ci tx_dim = tx_coal; 49762306a36Sopenharmony_ci } else { 49862306a36Sopenharmony_ci clear_bit(IONIC_LIF_F_TX_DIM_INTR, lif->state); 49962306a36Sopenharmony_ci tx_dim = 0; 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci if (test_bit(IONIC_LIF_F_UP, lif->state)) { 50362306a36Sopenharmony_ci for (i = 0; i < lif->nxqs; i++) { 50462306a36Sopenharmony_ci if (lif->rxqcqs[i]->flags & IONIC_QCQ_F_INTR) { 50562306a36Sopenharmony_ci ionic_intr_coal_init(lif->ionic->idev.intr_ctrl, 50662306a36Sopenharmony_ci lif->rxqcqs[i]->intr.index, 50762306a36Sopenharmony_ci lif->rx_coalesce_hw); 50862306a36Sopenharmony_ci lif->rxqcqs[i]->intr.dim_coal_hw = rx_dim; 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (lif->txqcqs[i]->flags & IONIC_QCQ_F_INTR) { 51262306a36Sopenharmony_ci ionic_intr_coal_init(lif->ionic->idev.intr_ctrl, 51362306a36Sopenharmony_ci lif->txqcqs[i]->intr.index, 51462306a36Sopenharmony_ci lif->tx_coalesce_hw); 51562306a36Sopenharmony_ci lif->txqcqs[i]->intr.dim_coal_hw = tx_dim; 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci return 0; 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic int ionic_validate_cmb_config(struct ionic_lif *lif, 52462306a36Sopenharmony_ci struct ionic_queue_params *qparam) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci int pages_have, pages_required = 0; 52762306a36Sopenharmony_ci unsigned long sz; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci if (!lif->ionic->idev.cmb_inuse && 53062306a36Sopenharmony_ci (qparam->cmb_tx || qparam->cmb_rx)) { 53162306a36Sopenharmony_ci netdev_info(lif->netdev, "CMB rings are not supported on this device\n"); 53262306a36Sopenharmony_ci return -EOPNOTSUPP; 53362306a36Sopenharmony_ci } 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci if (qparam->cmb_tx) { 53662306a36Sopenharmony_ci if (!(lif->qtype_info[IONIC_QTYPE_TXQ].features & IONIC_QIDENT_F_CMB)) { 53762306a36Sopenharmony_ci netdev_info(lif->netdev, 53862306a36Sopenharmony_ci "CMB rings for tx-push are not supported on this device\n"); 53962306a36Sopenharmony_ci return -EOPNOTSUPP; 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci sz = sizeof(struct ionic_txq_desc) * qparam->ntxq_descs * qparam->nxqs; 54362306a36Sopenharmony_ci pages_required += ALIGN(sz, PAGE_SIZE) / PAGE_SIZE; 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci if (qparam->cmb_rx) { 54762306a36Sopenharmony_ci if (!(lif->qtype_info[IONIC_QTYPE_RXQ].features & IONIC_QIDENT_F_CMB)) { 54862306a36Sopenharmony_ci netdev_info(lif->netdev, 54962306a36Sopenharmony_ci "CMB rings for rx-push are not supported on this device\n"); 55062306a36Sopenharmony_ci return -EOPNOTSUPP; 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci sz = sizeof(struct ionic_rxq_desc) * qparam->nrxq_descs * qparam->nxqs; 55462306a36Sopenharmony_ci pages_required += ALIGN(sz, PAGE_SIZE) / PAGE_SIZE; 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci pages_have = lif->ionic->bars[IONIC_PCI_BAR_CMB].len / PAGE_SIZE; 55862306a36Sopenharmony_ci if (pages_required > pages_have) { 55962306a36Sopenharmony_ci netdev_info(lif->netdev, 56062306a36Sopenharmony_ci "Not enough CMB pages for number of queues and size of descriptor rings, need %d have %d", 56162306a36Sopenharmony_ci pages_required, pages_have); 56262306a36Sopenharmony_ci return -ENOMEM; 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci return pages_required; 56662306a36Sopenharmony_ci} 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_cistatic int ionic_cmb_rings_toggle(struct ionic_lif *lif, bool cmb_tx, bool cmb_rx) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci struct ionic_queue_params qparam; 57162306a36Sopenharmony_ci int pages_used; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (netif_running(lif->netdev)) { 57462306a36Sopenharmony_ci netdev_info(lif->netdev, "Please stop device to toggle CMB for tx/rx-push\n"); 57562306a36Sopenharmony_ci return -EBUSY; 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci ionic_init_queue_params(lif, &qparam); 57962306a36Sopenharmony_ci qparam.cmb_tx = cmb_tx; 58062306a36Sopenharmony_ci qparam.cmb_rx = cmb_rx; 58162306a36Sopenharmony_ci pages_used = ionic_validate_cmb_config(lif, &qparam); 58262306a36Sopenharmony_ci if (pages_used < 0) 58362306a36Sopenharmony_ci return pages_used; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci if (cmb_tx) 58662306a36Sopenharmony_ci set_bit(IONIC_LIF_F_CMB_TX_RINGS, lif->state); 58762306a36Sopenharmony_ci else 58862306a36Sopenharmony_ci clear_bit(IONIC_LIF_F_CMB_TX_RINGS, lif->state); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci if (cmb_rx) 59162306a36Sopenharmony_ci set_bit(IONIC_LIF_F_CMB_RX_RINGS, lif->state); 59262306a36Sopenharmony_ci else 59362306a36Sopenharmony_ci clear_bit(IONIC_LIF_F_CMB_RX_RINGS, lif->state); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci if (cmb_tx || cmb_rx) 59662306a36Sopenharmony_ci netdev_info(lif->netdev, "Enabling CMB %s %s rings - %d pages\n", 59762306a36Sopenharmony_ci cmb_tx ? "TX" : "", cmb_rx ? "RX" : "", pages_used); 59862306a36Sopenharmony_ci else 59962306a36Sopenharmony_ci netdev_info(lif->netdev, "Disabling CMB rings\n"); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci return 0; 60262306a36Sopenharmony_ci} 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_cistatic void ionic_get_ringparam(struct net_device *netdev, 60562306a36Sopenharmony_ci struct ethtool_ringparam *ring, 60662306a36Sopenharmony_ci struct kernel_ethtool_ringparam *kernel_ring, 60762306a36Sopenharmony_ci struct netlink_ext_ack *extack) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci struct ionic_lif *lif = netdev_priv(netdev); 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci ring->tx_max_pending = IONIC_MAX_TX_DESC; 61262306a36Sopenharmony_ci ring->tx_pending = lif->ntxq_descs; 61362306a36Sopenharmony_ci ring->rx_max_pending = IONIC_MAX_RX_DESC; 61462306a36Sopenharmony_ci ring->rx_pending = lif->nrxq_descs; 61562306a36Sopenharmony_ci kernel_ring->tx_push = test_bit(IONIC_LIF_F_CMB_TX_RINGS, lif->state); 61662306a36Sopenharmony_ci kernel_ring->rx_push = test_bit(IONIC_LIF_F_CMB_RX_RINGS, lif->state); 61762306a36Sopenharmony_ci} 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_cistatic int ionic_set_ringparam(struct net_device *netdev, 62062306a36Sopenharmony_ci struct ethtool_ringparam *ring, 62162306a36Sopenharmony_ci struct kernel_ethtool_ringparam *kernel_ring, 62262306a36Sopenharmony_ci struct netlink_ext_ack *extack) 62362306a36Sopenharmony_ci{ 62462306a36Sopenharmony_ci struct ionic_lif *lif = netdev_priv(netdev); 62562306a36Sopenharmony_ci struct ionic_queue_params qparam; 62662306a36Sopenharmony_ci int err; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci if (test_bit(IONIC_LIF_F_FW_RESET, lif->state)) 62962306a36Sopenharmony_ci return -EBUSY; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci ionic_init_queue_params(lif, &qparam); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci if (ring->rx_mini_pending || ring->rx_jumbo_pending) { 63462306a36Sopenharmony_ci netdev_info(netdev, "Changing jumbo or mini descriptors not supported\n"); 63562306a36Sopenharmony_ci return -EINVAL; 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci if (!is_power_of_2(ring->tx_pending) || 63962306a36Sopenharmony_ci !is_power_of_2(ring->rx_pending)) { 64062306a36Sopenharmony_ci netdev_info(netdev, "Descriptor count must be a power of 2\n"); 64162306a36Sopenharmony_ci return -EINVAL; 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci /* if nothing to do return success */ 64562306a36Sopenharmony_ci if (ring->tx_pending == lif->ntxq_descs && 64662306a36Sopenharmony_ci ring->rx_pending == lif->nrxq_descs && 64762306a36Sopenharmony_ci kernel_ring->tx_push == test_bit(IONIC_LIF_F_CMB_TX_RINGS, lif->state) && 64862306a36Sopenharmony_ci kernel_ring->rx_push == test_bit(IONIC_LIF_F_CMB_RX_RINGS, lif->state)) 64962306a36Sopenharmony_ci return 0; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci qparam.ntxq_descs = ring->tx_pending; 65262306a36Sopenharmony_ci qparam.nrxq_descs = ring->rx_pending; 65362306a36Sopenharmony_ci qparam.cmb_tx = kernel_ring->tx_push; 65462306a36Sopenharmony_ci qparam.cmb_rx = kernel_ring->rx_push; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci err = ionic_validate_cmb_config(lif, &qparam); 65762306a36Sopenharmony_ci if (err < 0) 65862306a36Sopenharmony_ci return err; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci if (kernel_ring->tx_push != test_bit(IONIC_LIF_F_CMB_TX_RINGS, lif->state) || 66162306a36Sopenharmony_ci kernel_ring->rx_push != test_bit(IONIC_LIF_F_CMB_RX_RINGS, lif->state)) { 66262306a36Sopenharmony_ci err = ionic_cmb_rings_toggle(lif, kernel_ring->tx_push, 66362306a36Sopenharmony_ci kernel_ring->rx_push); 66462306a36Sopenharmony_ci if (err < 0) 66562306a36Sopenharmony_ci return err; 66662306a36Sopenharmony_ci } 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci if (ring->tx_pending != lif->ntxq_descs) 66962306a36Sopenharmony_ci netdev_info(netdev, "Changing Tx ring size from %d to %d\n", 67062306a36Sopenharmony_ci lif->ntxq_descs, ring->tx_pending); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci if (ring->rx_pending != lif->nrxq_descs) 67362306a36Sopenharmony_ci netdev_info(netdev, "Changing Rx ring size from %d to %d\n", 67462306a36Sopenharmony_ci lif->nrxq_descs, ring->rx_pending); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci /* if we're not running, just set the values and return */ 67762306a36Sopenharmony_ci if (!netif_running(lif->netdev)) { 67862306a36Sopenharmony_ci lif->ntxq_descs = ring->tx_pending; 67962306a36Sopenharmony_ci lif->nrxq_descs = ring->rx_pending; 68062306a36Sopenharmony_ci return 0; 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci mutex_lock(&lif->queue_lock); 68462306a36Sopenharmony_ci err = ionic_reconfigure_queues(lif, &qparam); 68562306a36Sopenharmony_ci mutex_unlock(&lif->queue_lock); 68662306a36Sopenharmony_ci if (err) 68762306a36Sopenharmony_ci netdev_info(netdev, "Ring reconfiguration failed, changes canceled: %d\n", err); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci return err; 69062306a36Sopenharmony_ci} 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_cistatic void ionic_get_channels(struct net_device *netdev, 69362306a36Sopenharmony_ci struct ethtool_channels *ch) 69462306a36Sopenharmony_ci{ 69562306a36Sopenharmony_ci struct ionic_lif *lif = netdev_priv(netdev); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci /* report maximum channels */ 69862306a36Sopenharmony_ci ch->max_combined = lif->ionic->ntxqs_per_lif; 69962306a36Sopenharmony_ci ch->max_rx = lif->ionic->ntxqs_per_lif / 2; 70062306a36Sopenharmony_ci ch->max_tx = lif->ionic->ntxqs_per_lif / 2; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci /* report current channels */ 70362306a36Sopenharmony_ci if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state)) { 70462306a36Sopenharmony_ci ch->rx_count = lif->nxqs; 70562306a36Sopenharmony_ci ch->tx_count = lif->nxqs; 70662306a36Sopenharmony_ci } else { 70762306a36Sopenharmony_ci ch->combined_count = lif->nxqs; 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci} 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_cistatic int ionic_set_channels(struct net_device *netdev, 71262306a36Sopenharmony_ci struct ethtool_channels *ch) 71362306a36Sopenharmony_ci{ 71462306a36Sopenharmony_ci struct ionic_lif *lif = netdev_priv(netdev); 71562306a36Sopenharmony_ci struct ionic_queue_params qparam; 71662306a36Sopenharmony_ci int max_cnt; 71762306a36Sopenharmony_ci int err; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci if (test_bit(IONIC_LIF_F_FW_RESET, lif->state)) 72062306a36Sopenharmony_ci return -EBUSY; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci ionic_init_queue_params(lif, &qparam); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci if (ch->rx_count != ch->tx_count) { 72562306a36Sopenharmony_ci netdev_info(netdev, "The rx and tx count must be equal\n"); 72662306a36Sopenharmony_ci return -EINVAL; 72762306a36Sopenharmony_ci } 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci if (ch->combined_count && ch->rx_count) { 73062306a36Sopenharmony_ci netdev_info(netdev, "Use either combined or rx and tx, not both\n"); 73162306a36Sopenharmony_ci return -EINVAL; 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci max_cnt = lif->ionic->ntxqs_per_lif; 73562306a36Sopenharmony_ci if (ch->combined_count) { 73662306a36Sopenharmony_ci if (ch->combined_count > max_cnt) 73762306a36Sopenharmony_ci return -EINVAL; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state)) 74062306a36Sopenharmony_ci netdev_info(lif->netdev, "Sharing queue interrupts\n"); 74162306a36Sopenharmony_ci else if (ch->combined_count == lif->nxqs) 74262306a36Sopenharmony_ci return 0; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci if (lif->nxqs != ch->combined_count) 74562306a36Sopenharmony_ci netdev_info(netdev, "Changing queue count from %d to %d\n", 74662306a36Sopenharmony_ci lif->nxqs, ch->combined_count); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci qparam.nxqs = ch->combined_count; 74962306a36Sopenharmony_ci qparam.intr_split = false; 75062306a36Sopenharmony_ci } else { 75162306a36Sopenharmony_ci max_cnt /= 2; 75262306a36Sopenharmony_ci if (ch->rx_count > max_cnt) 75362306a36Sopenharmony_ci return -EINVAL; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci if (!test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state)) 75662306a36Sopenharmony_ci netdev_info(lif->netdev, "Splitting queue interrupts\n"); 75762306a36Sopenharmony_ci else if (ch->rx_count == lif->nxqs) 75862306a36Sopenharmony_ci return 0; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci if (lif->nxqs != ch->rx_count) 76162306a36Sopenharmony_ci netdev_info(netdev, "Changing queue count from %d to %d\n", 76262306a36Sopenharmony_ci lif->nxqs, ch->rx_count); 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci qparam.nxqs = ch->rx_count; 76562306a36Sopenharmony_ci qparam.intr_split = true; 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci err = ionic_validate_cmb_config(lif, &qparam); 76962306a36Sopenharmony_ci if (err < 0) 77062306a36Sopenharmony_ci return err; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci /* if we're not running, just set the values and return */ 77362306a36Sopenharmony_ci if (!netif_running(lif->netdev)) { 77462306a36Sopenharmony_ci lif->nxqs = qparam.nxqs; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci if (qparam.intr_split) { 77762306a36Sopenharmony_ci set_bit(IONIC_LIF_F_SPLIT_INTR, lif->state); 77862306a36Sopenharmony_ci } else { 77962306a36Sopenharmony_ci clear_bit(IONIC_LIF_F_SPLIT_INTR, lif->state); 78062306a36Sopenharmony_ci lif->tx_coalesce_usecs = lif->rx_coalesce_usecs; 78162306a36Sopenharmony_ci lif->tx_coalesce_hw = lif->rx_coalesce_hw; 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci return 0; 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci mutex_lock(&lif->queue_lock); 78762306a36Sopenharmony_ci err = ionic_reconfigure_queues(lif, &qparam); 78862306a36Sopenharmony_ci mutex_unlock(&lif->queue_lock); 78962306a36Sopenharmony_ci if (err) 79062306a36Sopenharmony_ci netdev_info(netdev, "Queue reconfiguration failed, changes canceled: %d\n", err); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci return err; 79362306a36Sopenharmony_ci} 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_cistatic int ionic_get_rxnfc(struct net_device *netdev, 79662306a36Sopenharmony_ci struct ethtool_rxnfc *info, u32 *rules) 79762306a36Sopenharmony_ci{ 79862306a36Sopenharmony_ci struct ionic_lif *lif = netdev_priv(netdev); 79962306a36Sopenharmony_ci int err = 0; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci switch (info->cmd) { 80262306a36Sopenharmony_ci case ETHTOOL_GRXRINGS: 80362306a36Sopenharmony_ci info->data = lif->nxqs; 80462306a36Sopenharmony_ci break; 80562306a36Sopenharmony_ci default: 80662306a36Sopenharmony_ci netdev_dbg(netdev, "Command parameter %d is not supported\n", 80762306a36Sopenharmony_ci info->cmd); 80862306a36Sopenharmony_ci err = -EOPNOTSUPP; 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci return err; 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_cistatic u32 ionic_get_rxfh_indir_size(struct net_device *netdev) 81562306a36Sopenharmony_ci{ 81662306a36Sopenharmony_ci struct ionic_lif *lif = netdev_priv(netdev); 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci return le16_to_cpu(lif->ionic->ident.lif.eth.rss_ind_tbl_sz); 81962306a36Sopenharmony_ci} 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_cistatic u32 ionic_get_rxfh_key_size(struct net_device *netdev) 82262306a36Sopenharmony_ci{ 82362306a36Sopenharmony_ci return IONIC_RSS_HASH_KEY_SIZE; 82462306a36Sopenharmony_ci} 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_cistatic int ionic_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, 82762306a36Sopenharmony_ci u8 *hfunc) 82862306a36Sopenharmony_ci{ 82962306a36Sopenharmony_ci struct ionic_lif *lif = netdev_priv(netdev); 83062306a36Sopenharmony_ci unsigned int i, tbl_sz; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci if (indir) { 83362306a36Sopenharmony_ci tbl_sz = le16_to_cpu(lif->ionic->ident.lif.eth.rss_ind_tbl_sz); 83462306a36Sopenharmony_ci for (i = 0; i < tbl_sz; i++) 83562306a36Sopenharmony_ci indir[i] = lif->rss_ind_tbl[i]; 83662306a36Sopenharmony_ci } 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci if (key) 83962306a36Sopenharmony_ci memcpy(key, lif->rss_hash_key, IONIC_RSS_HASH_KEY_SIZE); 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci if (hfunc) 84262306a36Sopenharmony_ci *hfunc = ETH_RSS_HASH_TOP; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci return 0; 84562306a36Sopenharmony_ci} 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_cistatic int ionic_set_rxfh(struct net_device *netdev, const u32 *indir, 84862306a36Sopenharmony_ci const u8 *key, const u8 hfunc) 84962306a36Sopenharmony_ci{ 85062306a36Sopenharmony_ci struct ionic_lif *lif = netdev_priv(netdev); 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) 85362306a36Sopenharmony_ci return -EOPNOTSUPP; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci return ionic_lif_rss_config(lif, lif->rss_types, key, indir); 85662306a36Sopenharmony_ci} 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_cistatic int ionic_set_tunable(struct net_device *dev, 85962306a36Sopenharmony_ci const struct ethtool_tunable *tuna, 86062306a36Sopenharmony_ci const void *data) 86162306a36Sopenharmony_ci{ 86262306a36Sopenharmony_ci struct ionic_lif *lif = netdev_priv(dev); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci switch (tuna->id) { 86562306a36Sopenharmony_ci case ETHTOOL_RX_COPYBREAK: 86662306a36Sopenharmony_ci lif->rx_copybreak = *(u32 *)data; 86762306a36Sopenharmony_ci break; 86862306a36Sopenharmony_ci default: 86962306a36Sopenharmony_ci return -EOPNOTSUPP; 87062306a36Sopenharmony_ci } 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci return 0; 87362306a36Sopenharmony_ci} 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_cistatic int ionic_get_tunable(struct net_device *netdev, 87662306a36Sopenharmony_ci const struct ethtool_tunable *tuna, void *data) 87762306a36Sopenharmony_ci{ 87862306a36Sopenharmony_ci struct ionic_lif *lif = netdev_priv(netdev); 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci switch (tuna->id) { 88162306a36Sopenharmony_ci case ETHTOOL_RX_COPYBREAK: 88262306a36Sopenharmony_ci *(u32 *)data = lif->rx_copybreak; 88362306a36Sopenharmony_ci break; 88462306a36Sopenharmony_ci default: 88562306a36Sopenharmony_ci return -EOPNOTSUPP; 88662306a36Sopenharmony_ci } 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci return 0; 88962306a36Sopenharmony_ci} 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_cistatic int ionic_get_module_info(struct net_device *netdev, 89262306a36Sopenharmony_ci struct ethtool_modinfo *modinfo) 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci{ 89562306a36Sopenharmony_ci struct ionic_lif *lif = netdev_priv(netdev); 89662306a36Sopenharmony_ci struct ionic_dev *idev = &lif->ionic->idev; 89762306a36Sopenharmony_ci struct ionic_xcvr_status *xcvr; 89862306a36Sopenharmony_ci struct sfp_eeprom_base *sfp; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci xcvr = &idev->port_info->status.xcvr; 90162306a36Sopenharmony_ci sfp = (struct sfp_eeprom_base *) xcvr->sprom; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci /* report the module data type and length */ 90462306a36Sopenharmony_ci switch (sfp->phys_id) { 90562306a36Sopenharmony_ci case SFF8024_ID_SFP: 90662306a36Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8079; 90762306a36Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN; 90862306a36Sopenharmony_ci break; 90962306a36Sopenharmony_ci case SFF8024_ID_QSFP_8436_8636: 91062306a36Sopenharmony_ci case SFF8024_ID_QSFP28_8636: 91162306a36Sopenharmony_ci modinfo->type = ETH_MODULE_SFF_8436; 91262306a36Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; 91362306a36Sopenharmony_ci break; 91462306a36Sopenharmony_ci default: 91562306a36Sopenharmony_ci netdev_info(netdev, "unknown xcvr type 0x%02x\n", 91662306a36Sopenharmony_ci xcvr->sprom[0]); 91762306a36Sopenharmony_ci modinfo->type = 0; 91862306a36Sopenharmony_ci modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN; 91962306a36Sopenharmony_ci break; 92062306a36Sopenharmony_ci } 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci return 0; 92362306a36Sopenharmony_ci} 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_cistatic int ionic_get_module_eeprom(struct net_device *netdev, 92662306a36Sopenharmony_ci struct ethtool_eeprom *ee, 92762306a36Sopenharmony_ci u8 *data) 92862306a36Sopenharmony_ci{ 92962306a36Sopenharmony_ci struct ionic_lif *lif = netdev_priv(netdev); 93062306a36Sopenharmony_ci struct ionic_dev *idev = &lif->ionic->idev; 93162306a36Sopenharmony_ci struct ionic_xcvr_status *xcvr; 93262306a36Sopenharmony_ci char tbuf[sizeof(xcvr->sprom)]; 93362306a36Sopenharmony_ci int count = 10; 93462306a36Sopenharmony_ci u32 len; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci /* The NIC keeps the module prom up-to-date in the DMA space 93762306a36Sopenharmony_ci * so we can simply copy the module bytes into the data buffer. 93862306a36Sopenharmony_ci */ 93962306a36Sopenharmony_ci xcvr = &idev->port_info->status.xcvr; 94062306a36Sopenharmony_ci len = min_t(u32, sizeof(xcvr->sprom), ee->len); 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci do { 94362306a36Sopenharmony_ci memcpy(data, xcvr->sprom, len); 94462306a36Sopenharmony_ci memcpy(tbuf, xcvr->sprom, len); 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci /* Let's make sure we got a consistent copy */ 94762306a36Sopenharmony_ci if (!memcmp(data, tbuf, len)) 94862306a36Sopenharmony_ci break; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci } while (--count); 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci if (!count) 95362306a36Sopenharmony_ci return -ETIMEDOUT; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci return 0; 95662306a36Sopenharmony_ci} 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_cistatic int ionic_get_ts_info(struct net_device *netdev, 95962306a36Sopenharmony_ci struct ethtool_ts_info *info) 96062306a36Sopenharmony_ci{ 96162306a36Sopenharmony_ci struct ionic_lif *lif = netdev_priv(netdev); 96262306a36Sopenharmony_ci struct ionic *ionic = lif->ionic; 96362306a36Sopenharmony_ci __le64 mask; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci if (!lif->phc || !lif->phc->ptp) 96662306a36Sopenharmony_ci return ethtool_op_get_ts_info(netdev, info); 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci info->phc_index = ptp_clock_index(lif->phc->ptp); 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | 97162306a36Sopenharmony_ci SOF_TIMESTAMPING_RX_SOFTWARE | 97262306a36Sopenharmony_ci SOF_TIMESTAMPING_SOFTWARE | 97362306a36Sopenharmony_ci SOF_TIMESTAMPING_TX_HARDWARE | 97462306a36Sopenharmony_ci SOF_TIMESTAMPING_RX_HARDWARE | 97562306a36Sopenharmony_ci SOF_TIMESTAMPING_RAW_HARDWARE; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci /* tx modes */ 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci info->tx_types = BIT(HWTSTAMP_TX_OFF) | 98062306a36Sopenharmony_ci BIT(HWTSTAMP_TX_ON); 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci mask = cpu_to_le64(BIT_ULL(IONIC_TXSTAMP_ONESTEP_SYNC)); 98362306a36Sopenharmony_ci if (ionic->ident.lif.eth.hwstamp_tx_modes & mask) 98462306a36Sopenharmony_ci info->tx_types |= BIT(HWTSTAMP_TX_ONESTEP_SYNC); 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci mask = cpu_to_le64(BIT_ULL(IONIC_TXSTAMP_ONESTEP_P2P)); 98762306a36Sopenharmony_ci if (ionic->ident.lif.eth.hwstamp_tx_modes & mask) 98862306a36Sopenharmony_ci info->tx_types |= BIT(HWTSTAMP_TX_ONESTEP_P2P); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci /* rx filters */ 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | 99362306a36Sopenharmony_ci BIT(HWTSTAMP_FILTER_ALL); 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci mask = cpu_to_le64(IONIC_PKT_CLS_NTP_ALL); 99662306a36Sopenharmony_ci if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask) 99762306a36Sopenharmony_ci info->rx_filters |= BIT(HWTSTAMP_FILTER_NTP_ALL); 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci mask = cpu_to_le64(IONIC_PKT_CLS_PTP1_SYNC); 100062306a36Sopenharmony_ci if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask) 100162306a36Sopenharmony_ci info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V1_L4_SYNC); 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci mask = cpu_to_le64(IONIC_PKT_CLS_PTP1_DREQ); 100462306a36Sopenharmony_ci if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask) 100562306a36Sopenharmony_ci info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ); 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci mask = cpu_to_le64(IONIC_PKT_CLS_PTP1_ALL); 100862306a36Sopenharmony_ci if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask) 100962306a36Sopenharmony_ci info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V1_L4_EVENT); 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci mask = cpu_to_le64(IONIC_PKT_CLS_PTP2_L4_SYNC); 101262306a36Sopenharmony_ci if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask) 101362306a36Sopenharmony_ci info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_L4_SYNC); 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci mask = cpu_to_le64(IONIC_PKT_CLS_PTP2_L4_DREQ); 101662306a36Sopenharmony_ci if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask) 101762306a36Sopenharmony_ci info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ); 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci mask = cpu_to_le64(IONIC_PKT_CLS_PTP2_L4_ALL); 102062306a36Sopenharmony_ci if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask) 102162306a36Sopenharmony_ci info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_L4_EVENT); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci mask = cpu_to_le64(IONIC_PKT_CLS_PTP2_L2_SYNC); 102462306a36Sopenharmony_ci if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask) 102562306a36Sopenharmony_ci info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_L2_SYNC); 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci mask = cpu_to_le64(IONIC_PKT_CLS_PTP2_L2_DREQ); 102862306a36Sopenharmony_ci if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask) 102962306a36Sopenharmony_ci info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ); 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci mask = cpu_to_le64(IONIC_PKT_CLS_PTP2_L2_ALL); 103262306a36Sopenharmony_ci if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask) 103362306a36Sopenharmony_ci info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_L2_EVENT); 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci mask = cpu_to_le64(IONIC_PKT_CLS_PTP2_SYNC); 103662306a36Sopenharmony_ci if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask) 103762306a36Sopenharmony_ci info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_SYNC); 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci mask = cpu_to_le64(IONIC_PKT_CLS_PTP2_DREQ); 104062306a36Sopenharmony_ci if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask) 104162306a36Sopenharmony_ci info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_DELAY_REQ); 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci mask = cpu_to_le64(IONIC_PKT_CLS_PTP2_ALL); 104462306a36Sopenharmony_ci if ((ionic->ident.lif.eth.hwstamp_rx_filters & mask) == mask) 104562306a36Sopenharmony_ci info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_EVENT); 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci return 0; 104862306a36Sopenharmony_ci} 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_cistatic int ionic_nway_reset(struct net_device *netdev) 105162306a36Sopenharmony_ci{ 105262306a36Sopenharmony_ci struct ionic_lif *lif = netdev_priv(netdev); 105362306a36Sopenharmony_ci struct ionic *ionic = lif->ionic; 105462306a36Sopenharmony_ci int err = 0; 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci if (test_bit(IONIC_LIF_F_FW_RESET, lif->state)) 105762306a36Sopenharmony_ci return -EBUSY; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci /* flap the link to force auto-negotiation */ 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci mutex_lock(&ionic->dev_cmd_lock); 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci ionic_dev_cmd_port_state(&ionic->idev, IONIC_PORT_ADMIN_STATE_DOWN); 106462306a36Sopenharmony_ci err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT); 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci if (!err) { 106762306a36Sopenharmony_ci ionic_dev_cmd_port_state(&ionic->idev, IONIC_PORT_ADMIN_STATE_UP); 106862306a36Sopenharmony_ci err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT); 106962306a36Sopenharmony_ci } 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci mutex_unlock(&ionic->dev_cmd_lock); 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci return err; 107462306a36Sopenharmony_ci} 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_cistatic const struct ethtool_ops ionic_ethtool_ops = { 107762306a36Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 107862306a36Sopenharmony_ci ETHTOOL_COALESCE_USE_ADAPTIVE_RX | 107962306a36Sopenharmony_ci ETHTOOL_COALESCE_USE_ADAPTIVE_TX, 108062306a36Sopenharmony_ci .supported_ring_params = ETHTOOL_RING_USE_TX_PUSH | 108162306a36Sopenharmony_ci ETHTOOL_RING_USE_RX_PUSH, 108262306a36Sopenharmony_ci .get_drvinfo = ionic_get_drvinfo, 108362306a36Sopenharmony_ci .get_regs_len = ionic_get_regs_len, 108462306a36Sopenharmony_ci .get_regs = ionic_get_regs, 108562306a36Sopenharmony_ci .get_link = ethtool_op_get_link, 108662306a36Sopenharmony_ci .get_link_ext_stats = ionic_get_link_ext_stats, 108762306a36Sopenharmony_ci .get_link_ksettings = ionic_get_link_ksettings, 108862306a36Sopenharmony_ci .set_link_ksettings = ionic_set_link_ksettings, 108962306a36Sopenharmony_ci .get_coalesce = ionic_get_coalesce, 109062306a36Sopenharmony_ci .set_coalesce = ionic_set_coalesce, 109162306a36Sopenharmony_ci .get_ringparam = ionic_get_ringparam, 109262306a36Sopenharmony_ci .set_ringparam = ionic_set_ringparam, 109362306a36Sopenharmony_ci .get_channels = ionic_get_channels, 109462306a36Sopenharmony_ci .set_channels = ionic_set_channels, 109562306a36Sopenharmony_ci .get_strings = ionic_get_strings, 109662306a36Sopenharmony_ci .get_ethtool_stats = ionic_get_stats, 109762306a36Sopenharmony_ci .get_sset_count = ionic_get_sset_count, 109862306a36Sopenharmony_ci .get_rxnfc = ionic_get_rxnfc, 109962306a36Sopenharmony_ci .get_rxfh_indir_size = ionic_get_rxfh_indir_size, 110062306a36Sopenharmony_ci .get_rxfh_key_size = ionic_get_rxfh_key_size, 110162306a36Sopenharmony_ci .get_rxfh = ionic_get_rxfh, 110262306a36Sopenharmony_ci .set_rxfh = ionic_set_rxfh, 110362306a36Sopenharmony_ci .get_tunable = ionic_get_tunable, 110462306a36Sopenharmony_ci .set_tunable = ionic_set_tunable, 110562306a36Sopenharmony_ci .get_module_info = ionic_get_module_info, 110662306a36Sopenharmony_ci .get_module_eeprom = ionic_get_module_eeprom, 110762306a36Sopenharmony_ci .get_pauseparam = ionic_get_pauseparam, 110862306a36Sopenharmony_ci .set_pauseparam = ionic_set_pauseparam, 110962306a36Sopenharmony_ci .get_fecparam = ionic_get_fecparam, 111062306a36Sopenharmony_ci .set_fecparam = ionic_set_fecparam, 111162306a36Sopenharmony_ci .get_ts_info = ionic_get_ts_info, 111262306a36Sopenharmony_ci .nway_reset = ionic_nway_reset, 111362306a36Sopenharmony_ci}; 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_civoid ionic_ethtool_set_ops(struct net_device *netdev) 111662306a36Sopenharmony_ci{ 111762306a36Sopenharmony_ci netdev->ethtool_ops = &ionic_ethtool_ops; 111862306a36Sopenharmony_ci} 1119