diff options
Diffstat (limited to 'drivers/net/ethernet/wangxun/libwx/wx_ethtool.c')
| -rw-r--r-- | drivers/net/ethernet/wangxun/libwx/wx_ethtool.c | 352 |
1 files changed, 330 insertions, 22 deletions
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c index abe5921dde02..f362e51c73ee 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c @@ -41,6 +41,9 @@ static const struct wx_stats wx_gstrings_stats[] = { WX_STAT("rx_csum_offload_good_count", hw_csum_rx_good), WX_STAT("rx_csum_offload_errors", hw_csum_rx_error), WX_STAT("alloc_rx_buff_failed", alloc_rx_buff_failed), + WX_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts), + WX_STAT("tx_hwtstamp_skipped", tx_hwtstamp_skipped), + WX_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared), }; static const struct wx_stats wx_gstrings_fdir_stats[] = { @@ -48,6 +51,11 @@ static const struct wx_stats wx_gstrings_fdir_stats[] = { WX_STAT("fdir_miss", stats.fdirmiss), }; +static const struct wx_stats wx_gstrings_rsc_stats[] = { + WX_STAT("rsc_aggregated", rsc_count), + WX_STAT("rsc_flushed", rsc_flush), +}; + /* drivers 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 @@ -61,16 +69,21 @@ static const struct wx_stats wx_gstrings_fdir_stats[] = { (sizeof(struct wx_queue_stats) / sizeof(u64))) #define WX_GLOBAL_STATS_LEN ARRAY_SIZE(wx_gstrings_stats) #define WX_FDIR_STATS_LEN ARRAY_SIZE(wx_gstrings_fdir_stats) +#define WX_RSC_STATS_LEN ARRAY_SIZE(wx_gstrings_rsc_stats) #define WX_STATS_LEN (WX_GLOBAL_STATS_LEN + WX_QUEUE_STATS_LEN) int wx_get_sset_count(struct net_device *netdev, int sset) { struct wx *wx = netdev_priv(netdev); + int len = WX_STATS_LEN; switch (sset) { case ETH_SS_STATS: - return (wx->mac.type == wx_mac_sp) ? - WX_STATS_LEN + WX_FDIR_STATS_LEN : WX_STATS_LEN; + if (test_bit(WX_FLAG_FDIR_CAPABLE, wx->flags)) + len += WX_FDIR_STATS_LEN; + if (test_bit(WX_FLAG_RSC_CAPABLE, wx->flags)) + len += WX_RSC_STATS_LEN; + return len; default: return -EOPNOTSUPP; } @@ -87,10 +100,14 @@ void wx_get_strings(struct net_device *netdev, u32 stringset, u8 *data) case ETH_SS_STATS: for (i = 0; i < WX_GLOBAL_STATS_LEN; i++) ethtool_puts(&p, wx_gstrings_stats[i].stat_string); - if (wx->mac.type == wx_mac_sp) { + if (test_bit(WX_FLAG_FDIR_CAPABLE, wx->flags)) { for (i = 0; i < WX_FDIR_STATS_LEN; i++) ethtool_puts(&p, wx_gstrings_fdir_stats[i].stat_string); } + if (test_bit(WX_FLAG_RSC_CAPABLE, wx->flags)) { + for (i = 0; i < WX_RSC_STATS_LEN; i++) + ethtool_puts(&p, wx_gstrings_rsc_stats[i].stat_string); + } for (i = 0; i < netdev->num_tx_queues; i++) { ethtool_sprintf(&p, "tx_queue_%u_packets", i); ethtool_sprintf(&p, "tx_queue_%u_bytes", i); @@ -121,13 +138,20 @@ void wx_get_ethtool_stats(struct net_device *netdev, sizeof(u64)) ? *(u64 *)p : *(u32 *)p; } - if (wx->mac.type == wx_mac_sp) { + if (test_bit(WX_FLAG_FDIR_CAPABLE, wx->flags)) { for (k = 0; k < WX_FDIR_STATS_LEN; k++) { p = (char *)wx + wx_gstrings_fdir_stats[k].stat_offset; data[i++] = *(u64 *)p; } } + if (test_bit(WX_FLAG_RSC_CAPABLE, wx->flags)) { + for (k = 0; k < WX_RSC_STATS_LEN; k++) { + p = (char *)wx + wx_gstrings_rsc_stats[k].stat_offset; + data[i++] = *(u64 *)p; + } + } + for (j = 0; j < netdev->num_tx_queues; j++) { ring = wx->tx_ring[j]; if (!ring) { @@ -196,7 +220,7 @@ void wx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info) unsigned int stats_len = WX_STATS_LEN; struct wx *wx = netdev_priv(netdev); - if (wx->mac.type == wx_mac_sp) + if (test_bit(WX_FLAG_FDIR_CAPABLE, wx->flags)) stats_len += WX_FDIR_STATS_LEN; strscpy(info->driver, wx->driver_name, sizeof(info->driver)); @@ -288,6 +312,11 @@ int wx_get_coalesce(struct net_device *netdev, else ec->rx_coalesce_usecs = wx->rx_itr_setting >> 2; + if (wx->adaptive_itr) { + ec->use_adaptive_rx_coalesce = 1; + ec->use_adaptive_tx_coalesce = 1; + } + /* if in mixed tx/rx queues per vector mode, report only rx settings */ if (wx->q_vector[0]->tx.count && wx->q_vector[0]->rx.count) return 0; @@ -302,6 +331,40 @@ int wx_get_coalesce(struct net_device *netdev, } EXPORT_SYMBOL(wx_get_coalesce); +static void wx_update_rsc(struct wx *wx) +{ + struct net_device *netdev = wx->netdev; + bool need_reset = false; + + /* nothing to do if LRO or RSC are not enabled */ + if (!test_bit(WX_FLAG_RSC_CAPABLE, wx->flags) || + !(netdev->features & NETIF_F_LRO)) + return; + + /* check the feature flag value and enable RSC if necessary */ + if (wx->rx_itr_setting == 1 || + wx->rx_itr_setting > WX_MIN_RSC_ITR) { + if (!test_bit(WX_FLAG_RSC_ENABLED, wx->flags)) { + set_bit(WX_FLAG_RSC_ENABLED, wx->flags); + dev_info(&wx->pdev->dev, + "rx-usecs value high enough to re-enable RSC\n"); + + need_reset = true; + } + /* if interrupt rate is too high then disable RSC */ + } else if (test_bit(WX_FLAG_RSC_ENABLED, wx->flags)) { + clear_bit(WX_FLAG_RSC_ENABLED, wx->flags); + dev_info(&wx->pdev->dev, + "rx-usecs set too low, disabling RSC\n"); + + need_reset = true; + } + + /* reset the device to apply the new RSC setting */ + if (need_reset && wx->do_reset) + wx->do_reset(netdev); +} + int wx_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec, struct kernel_ethtool_coalesce *kernel_coal, @@ -319,42 +382,66 @@ int wx_set_coalesce(struct net_device *netdev, return -EOPNOTSUPP; } - if (ec->tx_max_coalesced_frames_irq) - wx->tx_work_limit = ec->tx_max_coalesced_frames_irq; + if (ec->tx_max_coalesced_frames_irq > U16_MAX || + !ec->tx_max_coalesced_frames_irq) + return -EINVAL; + + wx->tx_work_limit = ec->tx_max_coalesced_frames_irq; - if (wx->mac.type == wx_mac_sp) + switch (wx->mac.type) { + case wx_mac_sp: max_eitr = WX_SP_MAX_EITR; - else + rx_itr_param = WX_20K_ITR; + tx_itr_param = WX_12K_ITR; + break; + case wx_mac_aml: + case wx_mac_aml40: + max_eitr = WX_AML_MAX_EITR; + rx_itr_param = WX_20K_ITR; + tx_itr_param = WX_12K_ITR; + break; + default: max_eitr = WX_EM_MAX_EITR; + rx_itr_param = WX_7K_ITR; + tx_itr_param = WX_7K_ITR; + break; + } if ((ec->rx_coalesce_usecs > (max_eitr >> 2)) || (ec->tx_coalesce_usecs > (max_eitr >> 2))) return -EINVAL; + if (ec->use_adaptive_rx_coalesce) { + wx->adaptive_itr = true; + wx->rx_itr_setting = 1; + wx->tx_itr_setting = 1; + return 0; + } + if (ec->rx_coalesce_usecs > 1) wx->rx_itr_setting = ec->rx_coalesce_usecs << 2; else wx->rx_itr_setting = ec->rx_coalesce_usecs; - if (wx->rx_itr_setting == 1) - rx_itr_param = WX_20K_ITR; - else - rx_itr_param = wx->rx_itr_setting; - if (ec->tx_coalesce_usecs > 1) wx->tx_itr_setting = ec->tx_coalesce_usecs << 2; else wx->tx_itr_setting = ec->tx_coalesce_usecs; - if (wx->tx_itr_setting == 1) { - if (wx->mac.type == wx_mac_sp) - tx_itr_param = WX_12K_ITR; - else - tx_itr_param = WX_20K_ITR; - } else { - tx_itr_param = wx->tx_itr_setting; + if (wx->adaptive_itr) { + wx->adaptive_itr = false; + wx->rx_itr_setting = rx_itr_param; + wx->tx_itr_setting = tx_itr_param; + } else if (wx->rx_itr_setting == 1 || wx->tx_itr_setting == 1) { + wx->adaptive_itr = true; } + if (wx->rx_itr_setting != 1) + rx_itr_param = wx->rx_itr_setting; + + if (wx->tx_itr_setting != 1) + tx_itr_param = wx->tx_itr_setting; + /* mixed Rx/Tx */ if (wx->q_vector[0]->tx.count && wx->q_vector[0]->rx.count) wx->tx_itr_setting = wx->rx_itr_setting; @@ -370,6 +457,8 @@ int wx_set_coalesce(struct net_device *netdev, wx_write_eitr(q_vector); } + wx_update_rsc(wx); + return 0; } EXPORT_SYMBOL(wx_set_coalesce); @@ -383,7 +472,7 @@ static unsigned int wx_max_channels(struct wx *wx) max_combined = 1; } else { /* support up to max allowed queues with RSS */ - if (wx->mac.type == wx_mac_sp) + if (test_bit(WX_FLAG_MULTI_64_FUNC, wx->flags)) max_combined = 63; else max_combined = 8; @@ -437,6 +526,142 @@ int wx_set_channels(struct net_device *dev, } EXPORT_SYMBOL(wx_set_channels); +u32 wx_rss_indir_size(struct net_device *netdev) +{ + struct wx *wx = netdev_priv(netdev); + + return wx_rss_indir_tbl_entries(wx); +} +EXPORT_SYMBOL(wx_rss_indir_size); + +u32 wx_get_rxfh_key_size(struct net_device *netdev) +{ + return WX_RSS_KEY_SIZE; +} +EXPORT_SYMBOL(wx_get_rxfh_key_size); + +static void wx_get_reta(struct wx *wx, u32 *indir) +{ + u32 reta_size = wx_rss_indir_tbl_entries(wx); + u16 rss_m = wx->ring_feature[RING_F_RSS].mask; + + if (test_bit(WX_FLAG_SRIOV_ENABLED, wx->flags)) + rss_m = wx->ring_feature[RING_F_RSS].indices - 1; + + for (u32 i = 0; i < reta_size; i++) + indir[i] = wx->rss_indir_tbl[i] & rss_m; +} + +int wx_get_rxfh(struct net_device *netdev, + struct ethtool_rxfh_param *rxfh) +{ + struct wx *wx = netdev_priv(netdev); + + rxfh->hfunc = ETH_RSS_HASH_TOP; + + if (rxfh->indir) + wx_get_reta(wx, rxfh->indir); + + if (rxfh->key) + memcpy(rxfh->key, wx->rss_key, WX_RSS_KEY_SIZE); + + return 0; +} +EXPORT_SYMBOL(wx_get_rxfh); + +int wx_set_rxfh(struct net_device *netdev, + struct ethtool_rxfh_param *rxfh, + struct netlink_ext_ack *extack) +{ + struct wx *wx = netdev_priv(netdev); + u32 reta_entries, i; + + if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE && + rxfh->hfunc != ETH_RSS_HASH_TOP) + return -EOPNOTSUPP; + + reta_entries = wx_rss_indir_tbl_entries(wx); + /* Fill out the redirection table */ + if (rxfh->indir) { + for (i = 0; i < reta_entries; i++) + wx->rss_indir_tbl[i] = rxfh->indir[i]; + + wx_store_reta(wx); + } + + /* Fill out the rss hash key */ + if (rxfh->key) { + memcpy(wx->rss_key, rxfh->key, WX_RSS_KEY_SIZE); + wx_store_rsskey(wx); + } + + return 0; +} +EXPORT_SYMBOL(wx_set_rxfh); + +static const struct wx_rss_flow_map rss_flow_table[] = { + { TCP_V4_FLOW, RXH_L4_B_0_1 | RXH_L4_B_2_3, WX_RSS_FIELD_IPV4_TCP }, + { TCP_V6_FLOW, RXH_L4_B_0_1 | RXH_L4_B_2_3, WX_RSS_FIELD_IPV6_TCP }, + { UDP_V4_FLOW, RXH_L4_B_0_1 | RXH_L4_B_2_3, WX_RSS_FIELD_IPV4_UDP }, + { UDP_V6_FLOW, RXH_L4_B_0_1 | RXH_L4_B_2_3, WX_RSS_FIELD_IPV6_UDP }, + { SCTP_V4_FLOW, RXH_L4_B_0_1 | RXH_L4_B_2_3, WX_RSS_FIELD_IPV4_SCTP }, + { SCTP_V6_FLOW, RXH_L4_B_0_1 | RXH_L4_B_2_3, WX_RSS_FIELD_IPV6_SCTP }, +}; + +int wx_get_rxfh_fields(struct net_device *dev, + struct ethtool_rxfh_fields *nfc) +{ + struct wx *wx = netdev_priv(dev); + + nfc->data = RXH_IP_SRC | RXH_IP_DST; + + for (u32 i = 0; i < ARRAY_SIZE(rss_flow_table); i++) { + const struct wx_rss_flow_map *entry = &rss_flow_table[i]; + + if (entry->flow_type == nfc->flow_type) { + if (wx->rss_flags & entry->flag) + nfc->data |= entry->data; + break; + } + } + + return 0; +} +EXPORT_SYMBOL(wx_get_rxfh_fields); + +int wx_set_rxfh_fields(struct net_device *dev, + const struct ethtool_rxfh_fields *nfc, + struct netlink_ext_ack *extack) +{ + struct wx *wx = netdev_priv(dev); + u8 flags = wx->rss_flags; + + if (!(nfc->data & RXH_IP_SRC) || + !(nfc->data & RXH_IP_DST)) + return -EINVAL; + + for (u32 i = 0; i < ARRAY_SIZE(rss_flow_table); i++) { + const struct wx_rss_flow_map *entry = &rss_flow_table[i]; + + if (entry->flow_type == nfc->flow_type) { + if (nfc->data & entry->data) + flags |= entry->flag; + else + flags &= ~entry->flag; + + if (flags != wx->rss_flags) { + wx->rss_flags = flags; + wx_config_rss_field(wx); + } + + return 0; + } + } + + return -EINVAL; +} +EXPORT_SYMBOL(wx_set_rxfh_fields); + u32 wx_get_msglevel(struct net_device *netdev) { struct wx *wx = netdev_priv(netdev); @@ -452,3 +677,86 @@ void wx_set_msglevel(struct net_device *netdev, u32 data) wx->msg_enable = data; } EXPORT_SYMBOL(wx_set_msglevel); + +int wx_get_ts_info(struct net_device *dev, + struct kernel_ethtool_ts_info *info) +{ + struct wx *wx = netdev_priv(dev); + + info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | + BIT(HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | + BIT(HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) | + BIT(HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | + BIT(HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | + BIT(HWTSTAMP_FILTER_PTP_V2_SYNC) | + BIT(HWTSTAMP_FILTER_PTP_V2_L2_SYNC) | + BIT(HWTSTAMP_FILTER_PTP_V2_L4_SYNC) | + BIT(HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) | + BIT(HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) | + BIT(HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) | + BIT(HWTSTAMP_FILTER_PTP_V2_EVENT); + + info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + + if (wx->ptp_clock) + info->phc_index = ptp_clock_index(wx->ptp_clock); + else + info->phc_index = -1; + + info->tx_types = BIT(HWTSTAMP_TX_OFF) | + BIT(HWTSTAMP_TX_ON); + + return 0; +} +EXPORT_SYMBOL(wx_get_ts_info); + +void wx_get_ptp_stats(struct net_device *dev, + struct ethtool_ts_stats *ts_stats) +{ + struct wx *wx = netdev_priv(dev); + + if (wx->ptp_clock) { + ts_stats->pkts = wx->tx_hwtstamp_pkts; + ts_stats->lost = wx->tx_hwtstamp_timeouts + + wx->tx_hwtstamp_skipped + + wx->rx_hwtstamp_cleared; + ts_stats->err = wx->tx_hwtstamp_errors; + } +} +EXPORT_SYMBOL(wx_get_ptp_stats); + +static int wx_get_link_ksettings_vf(struct net_device *netdev, + struct ethtool_link_ksettings *cmd) +{ + struct wx *wx = netdev_priv(netdev); + + ethtool_link_ksettings_zero_link_mode(cmd, supported); + cmd->base.autoneg = AUTONEG_DISABLE; + cmd->base.port = PORT_NONE; + cmd->base.duplex = DUPLEX_FULL; + cmd->base.speed = wx->speed; + + return 0; +} + +static const struct ethtool_ops wx_ethtool_ops_vf = { + .supported_coalesce_params = ETHTOOL_COALESCE_USECS | + ETHTOOL_COALESCE_TX_MAX_FRAMES_IRQ | + ETHTOOL_COALESCE_USE_ADAPTIVE, + .get_drvinfo = wx_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_ringparam = wx_get_ringparam, + .get_msglevel = wx_get_msglevel, + .get_coalesce = wx_get_coalesce, + .get_ts_info = ethtool_op_get_ts_info, + .get_link_ksettings = wx_get_link_ksettings_vf, +}; + +void wx_set_ethtool_ops_vf(struct net_device *netdev) +{ + netdev->ethtool_ops = &wx_ethtool_ops_vf; +} +EXPORT_SYMBOL(wx_set_ethtool_ops_vf); |
