26:19 GMT Expires: Tue, 12 Aug 2036 12:26:19 GMT ETag: "e88e3dfac8c21124b8c6a83b69c3c8298392c222" // SPDX-License-Identifier: GPL-2.0 /* Copyright(c) 1999 - 2018 Intel Corporation. */ /* ethtool support for ixgbe */ #include #include #include #include #include #include #include #include #include #include #include "ixgbe.h" #include "ixgbe_phy.h" enum {NETDEV_STATS, IXGBE_STATS}; struct ixgbe_stats { char stat_string[ETH_GSTRING_LEN]; int type; int sizeof_stat; int stat_offset; }; #define IXGBE_STAT(m) IXGBE_STATS, \ sizeof(((struct ixgbe_adapter *)0)->m), \ offsetof(struct ixgbe_adapter, m) #define IXGBE_NETDEV_STAT(m) NETDEV_STATS, \ sizeof(((struct rtnl_link_stats64 *)0)->m), \ offsetof(struct rtnl_link_stats64, m) static const struct ixgbe_stats ixgbe_gstrings_stats[] = { {"rx_packets", IXGBE_NETDEV_STAT(rx_packets)}, {"tx_packets", IXGBE_NETDEV_STAT(tx_packets)}, {"rx_bytes", IXGBE_NETDEV_STAT(rx_bytes)}, {"tx_bytes", IXGBE_NETDEV_STAT(tx_bytes)}, {"rx_pkts_nic", IXGBE_STAT(stats.gprc)}, {"tx_pkts_nic", IXGBE_STAT(stats.gptc)}, {"rx_bytes_nic", IXGBE_STAT(stats.gorc)}, {"tx_bytes_nic", IXGBE_STAT(stats.gotc)}, {"lsc_int", IXGBE_STAT(lsc_int)}, {"tx_busy", IXGBE_STAT(tx_busy)}, {"non_eop_descs", IXGBE_STAT(non_eop_descs)}, {"rx_errors", IXGBE_NETDEV_STAT(rx_errors)}, {"tx_errors", IXGBE_NETDEV_STAT(tx_errors)}, {"rx_dropped", IXGBE_NETDEV_STAT(rx_dropped)}, {"tx_dropped", IXGBE_NETDEV_STAT(tx_dropped)}, {"multicast", IXGBE_NETDEV_STAT(multicast)}, {"broadcast", IXGBE_STAT(stats.bprc)}, {"rx_no_buffer_count", IXGBE_STAT(stats.rnbc[0]) }, {"collisions", IXGBE_NETDEV_STAT(collisions)}, {"rx_over_errors", IXGBE_NETDEV_STAT(rx_over_errors)}, {"rx_crc_errors", IXGBE_NETDEV_STAT(rx_crc_errors)}, {"rx_frame_errors", IXGBE_NETDEV_STAT(rx_frame_errors)}, {"hw_rsc_aggregated", IXGBE_STAT(rsc_total_count)}, {"hw_rsc_flushed", IXGBE_STAT(rsc_total_flush)}, {"fdir_match", IXGBE_STAT(stats.fdirmatch)}, {"fdir_miss", IXGBE_STAT(stats.fdirmiss)}, {"fdir_overflow", IXGBE_STAT(fdir_overflow)}, {"rx_fifo_errors", IXGBE_NETDEV_STAT(rx_fifo_errors)}, {"rx_missed_errors", IXGBE_NETDEV_STAT(rx_missed_errors)}, {"tx_aborted_errors", IXGBE_NETDEV_STAT(tx_aborted_errors)}, {"tx_carrier_errors", IXGBE_NETDEV_STAT(tx_carrier_errors)}, {"tx_fifo_errors", IXGBE_NETDEV_STAT(tx_fifo_errors)}, {"tx_heartbeat_errors", IXGBE_NETDEV_STAT(tx_heartbeat_errors)}, {"tx_timeout_count", IXGBE_STAT(tx_timeout_count)}, {"tx_restart_queue", IXGBE_STAT(restart_queue)}, {"rx_length_errors", IXGBE_STAT(stats.rlec)}, {"rx_long_length_errors", IXGBE_STAT(stats.roc)}, {"rx_short_length_errors", IXGBE_STAT(stats.ruc)}, {"tx_flow_control_xon", IXGBE_STAT(stats.lxontxc)}, {"rx_flow_control_xon", IXGBE_STAT(stats.lxonrxc)}, {"tx_flow_control_xoff", IXGBE_STAT(stats.lxofftxc)}, {"rx_flow_control_xoff", IXGBE_STAT(stats.lxoffrxc)}, {"rx_csum_offload_errors", IXGBE_STAT(hw_csum_rx_error)}, {"alloc_rx_page", IXGBE_STAT(alloc_rx_page)}, {"alloc_rx_page_failed", IXGBE_STAT(alloc_rx_page_failed)}, {"alloc_rx_buff_failed", IXGBE_STAT(alloc_rx_buff_failed)}, {"rx_no_dma_resources", IXGBE_STAT(hw_rx_no_dma_resources)}, {"os2bmc_rx_by_bmc", IXGBE_STAT(stats.o2bgptc)}, {"os2bmc_tx_by_bmc", IXGBE_STAT(stats.b2ospc)}, {"os2bmc_tx_by_host", IXGBE_STAT(stats.o2bspc)}, {"os2bmc_rx_by_host", IXGBE_STAT(stats.b2ogprc)}, {"tx_hwtstamp_timeouts", IXGBE_STAT(tx_hwtstamp_timeouts)}, {"tx_hwtstamp_skipped", IXGBE_STAT(tx_hwtstamp_skipped)}, {"rx_hwtstamp_cleared", IXGBE_STAT(rx_hwtstamp_cleared)}, {"tx_ipsec", IXGBE_STAT(tx_ipsec)}, {"rx_ipsec", IXGBE_STAT(rx_ipsec)}, #ifdef IXGBE_FCOE {"fcoe_bad_fccrc", IXGBE_STAT(stats.fccrc)}, {"rx_fcoe_dropped", IXGBE_STAT(stats.fcoerpdc)}, {"rx_fcoe_packets", IXGBE_STAT(stats.fcoeprc)}, {"rx_fcoe_dwords", IXGBE_STAT(stats.fcoedwrc)}, {"fcoe_noddp", IXGBE_STAT(stats.fcoe_noddp)}, {"fcoe_noddp_ext_buff", IXGBE_STAT(stats.fcoe_noddp_ext_buff)}, {"tx_fcoe_packets", IXGBE_STAT(stats.fcoeptc)}, {"tx_fcoe_dwords", IXGBE_STAT(stats.fcoedwtc)}, #endif /* IXGBE_FCOE */ }; /* ixgbe allocates num_tx_queues and num_rx_queues symmetrically so * we set the num_rx_queues to evaluate to num_tx_queues. This is * used because we do not have a good way to get the max number of * rx queues with CONFIG_RPS disabled. */ #define IXGBE_NUM_RX_QUEUES netdev->num_tx_queues #define IXGBE_QUEUE_STATS_LEN ( \ (netdev->num_tx_queues + IXGBE_NUM_RX_QUEUES) * \ (sizeof(struct ixgbe_queue_stats) / sizeof(u64))) #define IXGBE_GLOBAL_STATS_LEN ARRAY_SIZE(ixgbe_gstrings_stats) #define IXGBE_PB_STATS_LEN ( \ (sizeof(((struct ixgbe_adapter *)0)->stats.pxonrxc) + \ sizeof(((struct ixgbe_adapter *)0)->stats.pxontxc) + \ sizeof(((struct ixgbe_adapter *)0)->stats.pxoffrxc) + \ sizeof(((struct ixgbe_adapter *)0)->stats.pxofftxc)) \ / sizeof(u64)) #define IXGBE_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + \ IXGBE_PB_STATS_LEN + \ IXGBE_QUEUE_STATS_LEN) static const char ixgbe_gstrings_test[][ETH_GSTRING_LEN] = { "Register test (offline)", "Eeprom test (offline)", "Interrupt test (offline)", "Loopback test (offline)", "Link test (on/offline)" }; #define IXGBE_TEST_LEN sizeof(ixgbe_gstrings_test) / ETH_GSTRING_LEN static const char ixgbe_priv_flags_strings[][ETH_GSTRING_LEN] = { #define IXGBE_PRIV_FLAGS_LEGACY_RX BIT(0) "legacy-rx", #define IXGBE_PRIV_FLAGS_VF_IPSEC_EN BIT(1) "vf-ipsec", #define IXGBE_PRIV_FLAGS_AUTO_DISABLE_VF BIT(2) "mdd-disable-vf", }; #define IXGBE_PRIV_FLAGS_STR_LEN ARRAY_SIZE(ixgbe_priv_flags_strings) #define ixgbe_isbackplane(type) ((type) == ixgbe_media_type_backplane) static void ixgbe_set_supported_10gtypes(struct ixgbe_hw *hw, struct ethtool_link_ksettings *cmd) { if (!ixgbe_isbackplane(hw->phy.media_type)) { ethtool_link_ksettings_add_link_mode(cmd, supported, 10000baseT_Full); return; } switch (hw->device_id) { case IXGBE_DEV_ID_82598: case IXGBE_DEV_ID_82599_KX4: case IXGBE_DEV_ID_82599_KX4_MEZZ: case IXGBE_DEV_ID_X550EM_X_KX4: ethtool_link_ksettings_add_link_mode (cmd, supported, 10000baseKX4_Full); break; case IXGBE_DEV_ID_82598_BX: case IXGBE_DEV_ID_82599_KR: case IXGBE_DEV_ID_X550EM_X_KR: case IXGBE_DEV_ID_X550EM_X_XFI: ethtool_link_ksettings_add_link_mode (cmd, supported, 10000baseKR_Full); break; default: ethtool_link_ksettings_add_link_mode (cmd, supported, 10000baseKX4_Full); ethtool_link_ksettings_add_link_mode (cmd, supported, 10000baseKR_Full); break; } } static void ixgbe_set_advertising_10gtypes(struct ixgbe_hw *hw, struct ethtool_link_ksettings *cmd) { if (!ixgbe_isbackplane(hw->phy.media_type)) { ethtool_link_ksettings_add_link_mode(cmd, advertising, 10000baseT_Full); return; } switch (hw->device_id) { case IXGBE_DEV_ID_82598: case IXGBE_DEV_ID_82599_KX4: case IXGBE_DEV_ID_82599_KX4_MEZZ: case IXGBE_DEV_ID_X550EM_X_KX4: ethtool_link_ksettings_add_link_mode (cmd, advertising, 10000baseKX4_Full); break; case IXGBE_DEV_ID_82598_BX: case IXGBE_DEV_ID_82599_KR: case IXGBE_DEV_ID_X550EM_X_KR: case IXGBE_DEV_ID_X550EM_X_XFI: ethtool_link_ksettings_add_link_mode (cmd, advertising, 10000baseKR_Full); break; default: ethtool_link_ksettings_add_link_mode (cmd, advertising, 10000baseKX4_Full); ethtool_link_ksettings_add_link_mode (cmd, advertising, 10000baseKR_Full); break; } } static int ixgbe_get_link_ksettings(struct net_device *netdev, struct ethtool_link_ksettings *cmd) { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; ixgbe_link_speed supported_link; bool autoneg = false; ethtool_link_ksettings_zero_link_mode(cmd, supported); ethtool_link_ksettings_zero_link_mode(cmd, advertising); hw->mac.ops.get_link_capabilities(hw, &supported_link, &autoneg); /* set the supported link speeds */ if (supported_link & IXGBE_LINK_SPEED_10GB_FULL) { ixgbe_set_supported_10gtypes(hw, cmd); ixgbe_set_advertising_10gtypes(hw, cmd); } if (supported_link & IXGBE_LINK_SPEED_5GB_FULL) ethtool_link_ksettings_add_link_mode(cmd, supported, 5000baseT_Full); if (supported_link & IXGBE_LINK_SPEED_2_5GB_FULL) ethtool_link_ksettings_add_link_mode(cmd, supported, 2500baseT_Full); if (supported_link & IXGBE_LINK_SPEED_1GB_FULL) { if (ixgbe_isbackplane(hw->phy.media_type)) { ethtool_link_ksettings_add_link_mode(cmd, supported, 1000baseKX_Full); ethtool_link_ksettings_add_link_mode(cmd, advertising, 1000baseKX_Full); } else { ethtool_link_ksettings_add_link_mode(cmd, supported, 1000baseT_Full); ethtool_link_ksettings_add_link_mode(cmd, advertising, 1000baseT_Full); } } if (supported_link & IXGBE_LINK_SPEED_100_FULL) { ethtool_link_ksettings_add_link_mode(cmd, supported, 100baseT_Full); ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Full); } if (supported_link & IXGBE_LINK_SPEED_10_FULL) { ethtool_link_ksettings_add_link_mode(cmd, supported, 10baseT_Full); ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Full); } /* set the advertised speeds */ if (hw->phy.autoneg_advertised) { ethtool_link_ksettings_zero_link_mode(cmd, advertising); if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10_FULL) ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Full); if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL) ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Full); if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL) ixgbe_set_advertising_10gtypes(hw, cmd); if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) { if (ethtool_link_ksettings_test_link_mode (cmd, supported, 1000baseKX_Full)) ethtool_link_ksettings_add_link_mode (cmd, advertising, 1000baseKX_Full); else ethtool_link_ksettings_add_link_mode (cmd, advertising, 1000baseT_Full); } if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_5GB_FULL) ethtool_link_ksettings_add_link_mode(cmd, advertising, 5000baseT_Full); if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_2_5GB_FULL) ethtool_link_ksettings_add_link_mode(cmd, advertising, 2500baseT_Full); } else { if (hw->phy.multispeed_fiber && !autoneg) { if (supported_link & IXGBE_LINK_SPEED_10GB_FULL) ethtool_link_ksettings_add_link_mode (cmd, advertising, 10000baseT_Full); } } if (autoneg) { ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg); ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg); cmd->base.autoneg = AUTONEG_ENABLE; } else cmd->base.autoneg = AUTONEG_DISABLE; /* Determine the remaining settings based on the PHY type. */ switch (adapter->hw.phy.type) { case ixgbe_phy_tn: case ixgbe_phy_aq: case ixgbe_phy_x550em_ext_t: case ixgbe_phy_fw: case ixgbe_phy_cu_unknown: ethtool_link_ksettings_add_link_mode(cmd, supported, TP); ethtool_link_ksettings_add_link_mode(cmd, advertising, TP); cmd->base.port = PORT_TP; break; case ixgbe_phy_qt: ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE); ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE); cmd->base.port = PORT_FIBRE; break; case ixgbe_phy_nl: case ixgbe_phy_sfp_passive_tyco: case ixgbe_phy_sfp_passive_unknown: case ixgbe_phy_sfp_ftl: case ixgbe_phy_sfp_avago: case ixgbe_phy_sfp_intel: case ixgbe_phy_sfp_unknown: case ixgbe_phy_qsfp_passive_unknown: case ixgbe_phy_qsfp_active_unknown: case ixgbe_phy_qsfp_intel: case ixgbe_phy_qsfp_unknown: /* SFP+ devices, further checking needed */ switch (adapter->hw.phy.sfp_type) { case ixgbe_sfp_type_da_cu: case ixgbe_sfp_type_da_cu_core0: case ixgbe_sfp_type_da_cu_core1: ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE); ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE); cmd->base.port = PORT_DA; break; case ixgbe_sfp_type_sr: case ixgbe_sfp_type_lr: case ixgbe_sfp_type_srlr_core0: case ixgbe_sfp_type_srlr_core1: case ixgbe_sfp_type_1g_sx_core0: case ixgbe_sfp_type_1g_sx_core1: case ixgbe_sfp_type_1g_lx_core0: case ixgbe_sfp_type_1g_lx_core1: ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE); ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE); cmd->base.port = PORT_FIBRE; break; case ixgbe_sfp_type_not_present: ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE); ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE); cmd->base.port = PORT_NONE; break; case ixgbe_sfp_type_1g_cu_core0: case ixgbe_sfp_type_1g_cu_core1: ethtool_link_ksettings_add_link_mode(cmd, supported, TP); ethtool_link_ksettings_add_link_mode(cmd, advertising, TP); cmd->base.port = PORT_TP; break; case ixgbe_sfp_type_unknown: default: ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE); ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE); cmd->base.port = PORT_OTHER; break; } break; case ixgbe_phy_xaui: ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE); ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE); cmd->base.port = PORT_NONE; break; case ixgbe_phy_unknown: case ixgbe_phy_generic: case ixgbe_phy_sfp_unsupported: default: ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE); ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE); cmd->base.port = PORT_OTHER; break; } /* Indicate pause support */ ethtool_link_ksettings_add_link_mode(cmd, supported, Pause); switch (hw->fc.requested_mode) { case ixgbe_fc_full: ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause); break; case ixgbe_fc_rx_pause: ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause); ethtool_link_ksettings_add_link_mode(cmd, advertising, Asym_Pause); break; case ixgbe_fc_tx_pause: ethtool_link_ksettings_add_link_mode(cmd, advertising, Asym_Pause); break; default: ethtool_link_ksettings_del_link_mode(cmd, advertising, Pause); ethtool_link_ksettings_del_link_mode(cmd, advertising, Asym_Pause); } if (netif_carrier_ok(netdev)) { switch (adapter->link_speed) { case IXGBE_LINK_SPEED_10GB_FULL: cmd->base.speed = SPEED_10000; break; case IXGBE_LINK_SPEED_5GB_FULL: cmd->base.speed = SPEED_5000; break; case IXGBE_LINK_SPEED_2_5GB_FULL: cmd->base.speed = SPEED_2500; break; case IXGBE_LINK_SPEED_1GB_FULL: cmd->base.speed = SPEED_1000; break; case IXGBE_LINK_SPEED_100_FULL: cmd->base.speed = SPEED_100; break; case IXGBE_LINK_SPEED_10_FULL: cmd->base.speed = SPEED_10; break; default: break; } cmd->base.duplex = DUPLEX_FULL; } else { cmd->base.speed = SPEED_UNKNOWN; cmd->base.duplex = DUPLEX_UNKNOWN; } return 0; } static int ixgbe_set_link_ksettings(struct net_device *netdev, const struct ethtool_link_ksettings *cmd) { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; u32 advertised, old; s32 err = 0; if ((hw->phy.media_type == ixgbe_media_type_copper) || (hw->phy.multispeed_fiber)) { /* * this function does not support duplex forcing, but can * limit the advertising of the adapter to the specified speed */ if (!linkmode_subset(cmd->link_modes.advertising, cmd->link_modes.supported)) return -EINVAL; /* only allow one speed at a time if no autoneg */ if (!cmd->base.autoneg && hw->phy.multispeed_fiber) { if (ethtool_link_ksettings_test_link_mode(cmd, advertising, 10000baseT_Full) && ethtool_link_ksettings_test_link_mode(cmd, advertising, 1000baseT_Full)) return -EINVAL; } old = hw->phy.autoneg_advertised; advertised = 0; if (ethtool_link_ksettings_test_link_mode(cmd, advertising, 10000baseT_Full)) advertised |= IXGBE_LINK_SPEED_10GB_FULL; if (ethtool_link_ksettings_test_link_mode(cmd, advertising, 5000baseT_Full)) advertised |= IXGBE_LINK_SPEED_5GB_FULL; if (ethtool_link_ksettings_test_link_mode(cmd, advertising, 2500baseT_Full)) advertised |= IXGBE_LINK_SPEED_2_5GB_FULL; if (ethtool_link_ksettings_test_link_mode(cmd, advertising, 1000baseT_Full)) advertised |= IXGBE_LINK_SPEED_1GB_FULL; if (ethtool_link_ksettings_test_link_mode(cmd, advertising, 100baseT_Full)) advertised |= IXGBE_LINK_SPEED_100_FULL; if (ethtool_link_ksettings_test_link_mode(cmd, advertising, 10baseT_Full)) advertised |= IXGBE_LINK_SPEED_10_FULL; if (old == advertised) return err; /* this sets the link speed and restarts auto-neg */ while (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state)) usleep_range(1000, 2000); hw->mac.autotry_restart = true; err = hw->mac.ops.setup_link(hw, advertised, true); if (err) { e_info(probe, "setup link failed with code %d\n", err); hw->mac.ops.setup_link(hw, old, true); } clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state); } else { /* in this case we currently only support 10Gb/FULL */ u32 speed = cmd->base.speed; if ((cmd->base.autoneg == AUTONEG_ENABLE) || (!ethtool_link_ksettings_test_link_mode(cmd, advertising, 10000baseT_Full)) || (speed + cmd->base.duplex != SPEED_10000 + DUPLEX_FULL)) return -EINVAL; } return err; } static void ixgbe_get_pause_stats(struct net_device *netdev, struct ethtool_pause_stats *stats) { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw_stats *hwstats = &adapter->stats; stats->tx_pause_frames = hwstats->lxontxc + hwstats->lxofftxc; stats->rx_pause_frames = hwstats->lxonrxc + hwstats->lxoffrxc; } static void ixgbe_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; if (ixgbe_device_supports_autoneg_fc(hw) && !hw->fc.disable_fc_autoneg) pause->autoneg = 1; else pause->autoneg = 0; if (hw->fc.current_mode == ixgbe_fc_rx_pause) { pause->rx_pause = 1; } else if (hw->fc.current_mode == ixgbe_fc_tx_pause) { pause->tx_pause = 1; } else if (hw->fc.current_mode == ixgbe_fc_full) { pause->rx_pause = 1; pause->tx_pause = 1; } } static int ixgbe_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; struct ixgbe_fc_info fc = hw->fc; /* 82598 does no support link flow control with DCB enabled */ if ((hw->mac.type == ixgbe_mac_82598EB) && (adapter->flags & IXGBE_FLAG_DCB_ENABLED)) return -EINVAL; /* some devices do not support autoneg of link flow control */ if ((pause->autoneg == AUTONEG_ENABLE) && !ixgbe_device_supports_autoneg_fc(hw)) return -EINVAL; fc.disable_fc_autoneg = (pause->autoneg != AUTONEG_ENABLE); if ((pause->rx_pause && pause->tx_pause) || pause->autoneg) fc.requested_mode = ixgbe_fc_full; else if (pause->rx_pause && !pause->tx_pause) fc.requested_mode = ixgbe_fc_rx_pause; else if (!pause->rx_pause && pause->tx_pause) fc.requested_mode = ixgbe_fc_tx_pause; else fc.requested_mode = ixgbe_fc_none; /* if the thing changed then we'll update and use new autoneg */ if (memcmp(&fc, &hw->fc, sizeof(struct ixgbe_fc_info))) { hw->fc = fc; if (netif_running(netdev)) ixgbe_reinit_locked(adapter); else ixgbe_reset(adapter); } return 0; } static u32 ixgbe_get_msglevel(struct net_device *netdev) { struct ixgbe_adapter *adapter = netdev_priv(netdev); return adapter->msg_enable; } static void ixgbe_set_msglevel(struct net_device *netdev, u32 data) { struct ixgbe_adapter *adapter = netdev_priv(netdev); adapter->msg_enable = data; } static int ixgbe_get_regs_len(struct net_device *netdev) { #define IXGBE_REGS_LEN 1145 return IXGBE_REGS_LEN * sizeof(u32); } #define IXGBE_GET_STAT(_A_, _R_) _A_->stats._R_ static void ixgbe_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p) { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; u32 *regs_buff = p; u8 i; memset(p, 0, IXGBE_REGS_LEN * sizeof(u32)); regs->version = hw->mac.type << 24 | hw->revision_id << 16 | hw->device_id; /* General Registers */ regs_buff[0] = IXGBE_READ_REG(hw, IXGBE_CTRL); regs_buff[1] = IXGBE_READ_REG(hw, IXGBE_STATUS); regs_buff[2] = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); regs_buff[3] = IXGBE_READ_REG(hw, IXGBE_ESDP); regs_buff[4] = IXGBE_READ_REG(hw, IXGBE_EODSDP); regs_buff[5] = IXGBE_READ_REG(hw, IXGBE_LEDCTL); regs_buff[6] = IXGBE_READ_REG(hw, IXGBE_FRTIMER); regs_buff[7] = IXGBE_READ_REG(hw, IXGBE_TCPTIMER); /* NVM Register */ regs_buff[8] = IXGBE_READ_REG(hw, IXGBE_EEC(hw)); regs_buff[9] = IXGBE_READ_REG(hw, IXGBE_EERD); regs_buff[10] = IXGBE_READ_REG(hw, IXGBE_FLA(hw)); regs_buff[11] = IXGBE_READ_REG(hw, IXGBE_EEMNGCTL); regs_buff[12] = IXGBE_READ_REG(hw, IXGBE_EEMNGDATA); regs_buff[13] = IXGBE_READ_REG(hw, IXGBE_FLMNGCTL); regs_buff[14] = IXGBE_READ_REG(hw, IXGBE_FLMNGDATA); regs_buff[15] = IXGBE_READ_REG(hw, IXGBE_FLMNGCNT); regs_buff[16] = IXGBE_READ_REG(hw, IXGBE_FLOP); regs_buff[17] = IXGBE_READ_REG(hw, IXGBE_GRC(hw)); /* Interrupt */ /* don't read EICR because it can clear interrupt causes, instead * read EICS which is a shadow but doesn't clear EICR */ regs_buff[18] = IXGBE_READ_REG(hw, IXGBE_EICS); regs_buff[19] = IXGBE_READ_REG(hw, IXGBE_EICS); regs_buff[20] = IXGBE_READ_REG(hw, IXGBE_EIMS); regs_buff[21] = IXGBE_READ_REG(hw, IXGBE_EIMC); regs_buff[22] = IXGBE_READ_REG(hw, IXGBE_EIAC); regs_buff[23] = IXGBE_READ_REG(hw, IXGBE_EIAM); regs_buff[24] = IXGBE_READ_REG(hw, IXGBE_EITR(0)); regs_buff[25] = IXGBE_READ_REG(hw, IXGBE_IVAR(0)); regs_buff[26] = IXGBE_READ_REG(hw, IXGBE_MSIXT); regs_buff[27] = IXGBE_READ_REG(hw, IXGBE_MSIXPBA); regs_buff[28] = IXGBE_READ_REG(hw, IXGBE_PBACL(0)); regs_buff[29] = IXGBE_READ_REG(hw, IXGBE_GPIE); /* Flow Control */ regs_buff[30] = IXGBE_READ_REG(hw, IXGBE_PFCTOP); for (i = 0; i < 4; i++) regs_buff[31 + i] = IXGBE_READ_REG(hw, IXGBE_FCTTV(i)); for (i = 0; i < 8; i++) { switch (hw->mac.type) { case ixgbe_mac_82598EB: regs_buff[35 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTL(i)); regs_buff[43 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTH(i)); break; case ixgbe_mac_82599EB: case ixgbe_mac_X540: case ixgbe_mac_X550: case ixgbe_mac_X550EM_x: case ixgbe_mac_x550em_a: regs_buff[35 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTL_82599(i)); regs_buff[43 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTH_82599(i)); break; default: break; } } regs_buff[51] = IXGBE_READ_REG(hw, IXGBE_FCRTV); regs_buff[52] = IXGBE_READ_REG(hw, IXGBE_TFCS); /* Receive DMA */ for (i = 0; i < 64; i++) regs_buff[53 + i] = IXGBE_READ_REG(hw, IXGBE_RDBAL(i)); for (i = 0; i < 64; i++) regs_buff[117 + i] = IXGBE_READ_REG(hw, IXGBE_RDBAH(i)); for (i = 0; i < 64; i++) regs_buff[181 + i] = IXGBE_READ_REG(hw, IXGBE_RDLEN(i)); for (i = 0; i < 64; i++) regs_buff[245 + i] = IXGBE_READ_REG(hw, IXGBE_RDH(i)); for (i = 0; i < 64; i++) regs_buff[309 + i] = IXGBE_READ_REG(hw, IXGBE_RDT(i)); for (i = 0; i < 64; i++) regs_buff[373 + i] = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)); for (i = 0; i < 16; i++) regs_buff[437 + i] = IXGBE_READ_REG(hw, IXGBE_SRRCTL(i)); for (i = 0; i < 16; i++) regs_buff[453 + i] = IXGBE_READ_REG(hw, IXGBE_DCA_RXCTRL(i)); regs_buff[469] = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); for (i = 0; i < 8; i++) regs_buff[470 + i] = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i)); regs_buff[478] = IXGBE_READ_REG(hw, IXGBE_RXCTRL); regs_buff[479] = IXGBE_READ_REG(hw, IXGBE_DROPEN); /* Receive */ regs_buff[480] = IXGBE_READ_RE