322 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Texas Instruments ICSSG Ethernet driver3 *4 * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/5 *6 */7 8#include "icssg_prueth.h"9#include "icssg_stats.h"10 11static void emac_get_drvinfo(struct net_device *ndev,12 struct ethtool_drvinfo *info)13{14 struct prueth_emac *emac = netdev_priv(ndev);15 struct prueth *prueth = emac->prueth;16 17 strscpy(info->driver, dev_driver_string(prueth->dev),18 sizeof(info->driver));19 strscpy(info->bus_info, dev_name(prueth->dev), sizeof(info->bus_info));20}21 22static u32 emac_get_msglevel(struct net_device *ndev)23{24 struct prueth_emac *emac = netdev_priv(ndev);25 26 return emac->msg_enable;27}28 29static void emac_set_msglevel(struct net_device *ndev, u32 value)30{31 struct prueth_emac *emac = netdev_priv(ndev);32 33 emac->msg_enable = value;34}35 36static int emac_get_link_ksettings(struct net_device *ndev,37 struct ethtool_link_ksettings *ecmd)38{39 return phy_ethtool_get_link_ksettings(ndev, ecmd);40}41 42static int emac_set_link_ksettings(struct net_device *ndev,43 const struct ethtool_link_ksettings *ecmd)44{45 return phy_ethtool_set_link_ksettings(ndev, ecmd);46}47 48static int emac_get_eee(struct net_device *ndev, struct ethtool_keee *edata)49{50 if (!ndev->phydev)51 return -EOPNOTSUPP;52 53 return phy_ethtool_get_eee(ndev->phydev, edata);54}55 56static int emac_set_eee(struct net_device *ndev, struct ethtool_keee *edata)57{58 if (!ndev->phydev)59 return -EOPNOTSUPP;60 61 return phy_ethtool_set_eee(ndev->phydev, edata);62}63 64static int emac_nway_reset(struct net_device *ndev)65{66 return phy_ethtool_nway_reset(ndev);67}68 69static int emac_get_sset_count(struct net_device *ndev, int stringset)70{71 struct prueth_emac *emac = netdev_priv(ndev);72 switch (stringset) {73 case ETH_SS_STATS:74 if (emac->prueth->pa_stats)75 return ICSSG_NUM_ETHTOOL_STATS;76 else77 return ICSSG_NUM_ETHTOOL_STATS - ICSSG_NUM_PA_STATS;78 default:79 return -EOPNOTSUPP;80 }81}82 83static void emac_get_strings(struct net_device *ndev, u32 stringset, u8 *data)84{85 struct prueth_emac *emac = netdev_priv(ndev);86 u8 *p = data;87 int i;88 89 switch (stringset) {90 case ETH_SS_STATS:91 for (i = 0; i < ARRAY_SIZE(icssg_all_miig_stats); i++)92 if (!icssg_all_miig_stats[i].standard_stats)93 ethtool_puts(&p, icssg_all_miig_stats[i].name);94 if (emac->prueth->pa_stats)95 for (i = 0; i < ARRAY_SIZE(icssg_all_pa_stats); i++)96 ethtool_puts(&p, icssg_all_pa_stats[i].name);97 break;98 default:99 break;100 }101}102 103static void emac_get_ethtool_stats(struct net_device *ndev,104 struct ethtool_stats *stats, u64 *data)105{106 struct prueth_emac *emac = netdev_priv(ndev);107 int i;108 109 emac_update_hardware_stats(emac);110 111 for (i = 0; i < ARRAY_SIZE(icssg_all_miig_stats); i++)112 if (!icssg_all_miig_stats[i].standard_stats)113 *(data++) = emac->stats[i];114 115 if (emac->prueth->pa_stats)116 for (i = 0; i < ARRAY_SIZE(icssg_all_pa_stats); i++)117 *(data++) = emac->pa_stats[i];118}119 120static int emac_get_ts_info(struct net_device *ndev,121 struct kernel_ethtool_ts_info *info)122{123 struct prueth_emac *emac = netdev_priv(ndev);124 125 info->so_timestamping =126 SOF_TIMESTAMPING_TX_HARDWARE |127 SOF_TIMESTAMPING_TX_SOFTWARE |128 SOF_TIMESTAMPING_RX_HARDWARE |129 SOF_TIMESTAMPING_RAW_HARDWARE;130 131 info->phc_index = icss_iep_get_ptp_clock_idx(emac->iep);132 info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON);133 info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | BIT(HWTSTAMP_FILTER_ALL);134 135 return 0;136}137 138static int emac_set_channels(struct net_device *ndev,139 struct ethtool_channels *ch)140{141 struct prueth_emac *emac = netdev_priv(ndev);142 143 /* Check if interface is up. Can change the num queues when144 * the interface is down.145 */146 if (netif_running(emac->ndev))147 return -EBUSY;148 149 emac->tx_ch_num = ch->tx_count;150 151 if (emac->is_sr1)152 emac->tx_ch_num++;153 154 return 0;155}156 157static void emac_get_channels(struct net_device *ndev,158 struct ethtool_channels *ch)159{160 struct prueth_emac *emac = netdev_priv(ndev);161 162 ch->max_rx = 1;163 ch->max_tx = PRUETH_MAX_TX_QUEUES;164 165 /* Disable multiple TX channels due to timeouts166 * when using more than one queue */167 if (emac->is_sr1)168 ch->max_tx = 1;169 170 ch->rx_count = 1;171 ch->tx_count = emac->tx_ch_num;172 173 if (emac->is_sr1)174 ch->tx_count--;175}176 177static const struct ethtool_rmon_hist_range emac_rmon_ranges[] = {178 { 0, 64},179 { 65, 128},180 { 129, 256},181 { 257, 512},182 { 513, PRUETH_MAX_PKT_SIZE},183 {}184};185 186static void emac_get_rmon_stats(struct net_device *ndev,187 struct ethtool_rmon_stats *rmon_stats,188 const struct ethtool_rmon_hist_range **ranges)189{190 struct prueth_emac *emac = netdev_priv(ndev);191 192 *ranges = emac_rmon_ranges;193 194 rmon_stats->undersize_pkts = emac_get_stat_by_name(emac, "rx_bucket1_frames") -195 emac_get_stat_by_name(emac, "rx_64B_frames");196 197 rmon_stats->hist[0] = emac_get_stat_by_name(emac, "rx_bucket1_frames");198 rmon_stats->hist[1] = emac_get_stat_by_name(emac, "rx_bucket2_frames");199 rmon_stats->hist[2] = emac_get_stat_by_name(emac, "rx_bucket3_frames");200 rmon_stats->hist[3] = emac_get_stat_by_name(emac, "rx_bucket4_frames");201 rmon_stats->hist[4] = emac_get_stat_by_name(emac, "rx_bucket5_frames");202 203 rmon_stats->hist_tx[0] = emac_get_stat_by_name(emac, "tx_bucket1_frames");204 rmon_stats->hist_tx[1] = emac_get_stat_by_name(emac, "tx_bucket2_frames");205 rmon_stats->hist_tx[2] = emac_get_stat_by_name(emac, "tx_bucket3_frames");206 rmon_stats->hist_tx[3] = emac_get_stat_by_name(emac, "tx_bucket4_frames");207 rmon_stats->hist_tx[4] = emac_get_stat_by_name(emac, "tx_bucket5_frames");208}209 210static int emac_get_coalesce(struct net_device *ndev,211 struct ethtool_coalesce *coal,212 struct kernel_ethtool_coalesce *kernel_coal,213 struct netlink_ext_ack *extack)214{215 struct prueth_emac *emac = netdev_priv(ndev);216 struct prueth_tx_chn *tx_chn;217 218 tx_chn = &emac->tx_chns[0];219 220 coal->rx_coalesce_usecs = emac->rx_pace_timeout_ns / 1000;221 coal->tx_coalesce_usecs = tx_chn->tx_pace_timeout_ns / 1000;222 223 return 0;224}225 226static int emac_get_per_queue_coalesce(struct net_device *ndev, u32 queue,227 struct ethtool_coalesce *coal)228{229 struct prueth_emac *emac = netdev_priv(ndev);230 struct prueth_tx_chn *tx_chn;231 232 if (queue >= PRUETH_MAX_TX_QUEUES)233 return -EINVAL;234 235 tx_chn = &emac->tx_chns[queue];236 237 coal->tx_coalesce_usecs = tx_chn->tx_pace_timeout_ns / 1000;238 239 return 0;240}241 242static int emac_set_coalesce(struct net_device *ndev,243 struct ethtool_coalesce *coal,244 struct kernel_ethtool_coalesce *kernel_coal,245 struct netlink_ext_ack *extack)246{247 struct prueth_emac *emac = netdev_priv(ndev);248 struct prueth *prueth = emac->prueth;249 struct prueth_tx_chn *tx_chn;250 251 tx_chn = &emac->tx_chns[0];252 253 if (coal->rx_coalesce_usecs &&254 coal->rx_coalesce_usecs < ICSSG_MIN_COALESCE_USECS) {255 dev_info(prueth->dev, "defaulting to min value of %dus for rx-usecs\n",256 ICSSG_MIN_COALESCE_USECS);257 coal->rx_coalesce_usecs = ICSSG_MIN_COALESCE_USECS;258 }259 260 if (coal->tx_coalesce_usecs &&261 coal->tx_coalesce_usecs < ICSSG_MIN_COALESCE_USECS) {262 dev_info(prueth->dev, "defaulting to min value of %dus for tx-usecs\n",263 ICSSG_MIN_COALESCE_USECS);264 coal->tx_coalesce_usecs = ICSSG_MIN_COALESCE_USECS;265 }266 267 emac->rx_pace_timeout_ns = coal->rx_coalesce_usecs * 1000;268 tx_chn->tx_pace_timeout_ns = coal->tx_coalesce_usecs * 1000;269 270 return 0;271}272 273static int emac_set_per_queue_coalesce(struct net_device *ndev, u32 queue,274 struct ethtool_coalesce *coal)275{276 struct prueth_emac *emac = netdev_priv(ndev);277 struct prueth *prueth = emac->prueth;278 struct prueth_tx_chn *tx_chn;279 280 if (queue >= PRUETH_MAX_TX_QUEUES)281 return -EINVAL;282 283 tx_chn = &emac->tx_chns[queue];284 285 if (coal->tx_coalesce_usecs &&286 coal->tx_coalesce_usecs < ICSSG_MIN_COALESCE_USECS) {287 dev_info(prueth->dev, "defaulting to min value of %dus for tx-usecs for tx-%u\n",288 ICSSG_MIN_COALESCE_USECS, queue);289 coal->tx_coalesce_usecs = ICSSG_MIN_COALESCE_USECS;290 }291 292 tx_chn->tx_pace_timeout_ns = coal->tx_coalesce_usecs * 1000;293 294 return 0;295}296 297const struct ethtool_ops icssg_ethtool_ops = {298 .get_drvinfo = emac_get_drvinfo,299 .get_msglevel = emac_get_msglevel,300 .set_msglevel = emac_set_msglevel,301 .get_sset_count = emac_get_sset_count,302 .get_ethtool_stats = emac_get_ethtool_stats,303 .get_strings = emac_get_strings,304 .get_ts_info = emac_get_ts_info,305 .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS |306 ETHTOOL_COALESCE_TX_USECS,307 .get_coalesce = emac_get_coalesce,308 .set_coalesce = emac_set_coalesce,309 .get_per_queue_coalesce = emac_get_per_queue_coalesce,310 .set_per_queue_coalesce = emac_set_per_queue_coalesce,311 .get_channels = emac_get_channels,312 .set_channels = emac_set_channels,313 .get_link_ksettings = emac_get_link_ksettings,314 .set_link_ksettings = emac_set_link_ksettings,315 .get_link = ethtool_op_get_link,316 .get_eee = emac_get_eee,317 .set_eee = emac_set_eee,318 .nway_reset = emac_nway_reset,319 .get_rmon_stats = emac_get_rmon_stats,320};321EXPORT_SYMBOL_GPL(icssg_ethtool_ops);322