162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright (C) 2021 Gerhard Engleder <gerhard@engleder-embedded.com> */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include "tsnep.h" 562306a36Sopenharmony_ci 662306a36Sopenharmony_cistatic const char tsnep_stats_strings[][ETH_GSTRING_LEN] = { 762306a36Sopenharmony_ci "rx_packets", 862306a36Sopenharmony_ci "rx_bytes", 962306a36Sopenharmony_ci "rx_dropped", 1062306a36Sopenharmony_ci "rx_multicast", 1162306a36Sopenharmony_ci "rx_alloc_failed", 1262306a36Sopenharmony_ci "rx_phy_errors", 1362306a36Sopenharmony_ci "rx_forwarded_phy_errors", 1462306a36Sopenharmony_ci "rx_invalid_frame_errors", 1562306a36Sopenharmony_ci "tx_packets", 1662306a36Sopenharmony_ci "tx_bytes", 1762306a36Sopenharmony_ci "tx_dropped", 1862306a36Sopenharmony_ci}; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistruct tsnep_stats { 2162306a36Sopenharmony_ci u64 rx_packets; 2262306a36Sopenharmony_ci u64 rx_bytes; 2362306a36Sopenharmony_ci u64 rx_dropped; 2462306a36Sopenharmony_ci u64 rx_multicast; 2562306a36Sopenharmony_ci u64 rx_alloc_failed; 2662306a36Sopenharmony_ci u64 rx_phy_errors; 2762306a36Sopenharmony_ci u64 rx_forwarded_phy_errors; 2862306a36Sopenharmony_ci u64 rx_invalid_frame_errors; 2962306a36Sopenharmony_ci u64 tx_packets; 3062306a36Sopenharmony_ci u64 tx_bytes; 3162306a36Sopenharmony_ci u64 tx_dropped; 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define TSNEP_STATS_COUNT (sizeof(struct tsnep_stats) / sizeof(u64)) 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic const char tsnep_rx_queue_stats_strings[][ETH_GSTRING_LEN] = { 3762306a36Sopenharmony_ci "rx_%d_packets", 3862306a36Sopenharmony_ci "rx_%d_bytes", 3962306a36Sopenharmony_ci "rx_%d_dropped", 4062306a36Sopenharmony_ci "rx_%d_multicast", 4162306a36Sopenharmony_ci "rx_%d_alloc_failed", 4262306a36Sopenharmony_ci "rx_%d_no_descriptor_errors", 4362306a36Sopenharmony_ci "rx_%d_buffer_too_small_errors", 4462306a36Sopenharmony_ci "rx_%d_fifo_overflow_errors", 4562306a36Sopenharmony_ci "rx_%d_invalid_frame_errors", 4662306a36Sopenharmony_ci}; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistruct tsnep_rx_queue_stats { 4962306a36Sopenharmony_ci u64 rx_packets; 5062306a36Sopenharmony_ci u64 rx_bytes; 5162306a36Sopenharmony_ci u64 rx_dropped; 5262306a36Sopenharmony_ci u64 rx_multicast; 5362306a36Sopenharmony_ci u64 rx_alloc_failed; 5462306a36Sopenharmony_ci u64 rx_no_descriptor_errors; 5562306a36Sopenharmony_ci u64 rx_buffer_too_small_errors; 5662306a36Sopenharmony_ci u64 rx_fifo_overflow_errors; 5762306a36Sopenharmony_ci u64 rx_invalid_frame_errors; 5862306a36Sopenharmony_ci}; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define TSNEP_RX_QUEUE_STATS_COUNT (sizeof(struct tsnep_rx_queue_stats) / \ 6162306a36Sopenharmony_ci sizeof(u64)) 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic const char tsnep_tx_queue_stats_strings[][ETH_GSTRING_LEN] = { 6462306a36Sopenharmony_ci "tx_%d_packets", 6562306a36Sopenharmony_ci "tx_%d_bytes", 6662306a36Sopenharmony_ci "tx_%d_dropped", 6762306a36Sopenharmony_ci}; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistruct tsnep_tx_queue_stats { 7062306a36Sopenharmony_ci u64 tx_packets; 7162306a36Sopenharmony_ci u64 tx_bytes; 7262306a36Sopenharmony_ci u64 tx_dropped; 7362306a36Sopenharmony_ci}; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci#define TSNEP_TX_QUEUE_STATS_COUNT (sizeof(struct tsnep_tx_queue_stats) / \ 7662306a36Sopenharmony_ci sizeof(u64)) 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic void tsnep_ethtool_get_drvinfo(struct net_device *netdev, 7962306a36Sopenharmony_ci struct ethtool_drvinfo *drvinfo) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci struct tsnep_adapter *adapter = netdev_priv(netdev); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci strscpy(drvinfo->driver, TSNEP, sizeof(drvinfo->driver)); 8462306a36Sopenharmony_ci strscpy(drvinfo->bus_info, dev_name(&adapter->pdev->dev), 8562306a36Sopenharmony_ci sizeof(drvinfo->bus_info)); 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic int tsnep_ethtool_get_regs_len(struct net_device *netdev) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci struct tsnep_adapter *adapter = netdev_priv(netdev); 9162306a36Sopenharmony_ci int len; 9262306a36Sopenharmony_ci int num_additional_queues; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci len = TSNEP_MAC_SIZE; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci /* first queue pair is within TSNEP_MAC_SIZE, only queues additional to 9762306a36Sopenharmony_ci * the first queue pair extend the register length by TSNEP_QUEUE_SIZE 9862306a36Sopenharmony_ci */ 9962306a36Sopenharmony_ci num_additional_queues = 10062306a36Sopenharmony_ci max(adapter->num_tx_queues, adapter->num_rx_queues) - 1; 10162306a36Sopenharmony_ci len += TSNEP_QUEUE_SIZE * num_additional_queues; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci return len; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic void tsnep_ethtool_get_regs(struct net_device *netdev, 10762306a36Sopenharmony_ci struct ethtool_regs *regs, 10862306a36Sopenharmony_ci void *p) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci struct tsnep_adapter *adapter = netdev_priv(netdev); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci regs->version = 1; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci memcpy_fromio(p, adapter->addr, regs->len); 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic u32 tsnep_ethtool_get_msglevel(struct net_device *netdev) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct tsnep_adapter *adapter = netdev_priv(netdev); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci return adapter->msg_enable; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic void tsnep_ethtool_set_msglevel(struct net_device *netdev, u32 data) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct tsnep_adapter *adapter = netdev_priv(netdev); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci adapter->msg_enable = data; 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic void tsnep_ethtool_get_strings(struct net_device *netdev, u32 stringset, 13262306a36Sopenharmony_ci u8 *data) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci struct tsnep_adapter *adapter = netdev_priv(netdev); 13562306a36Sopenharmony_ci int rx_count = adapter->num_rx_queues; 13662306a36Sopenharmony_ci int tx_count = adapter->num_tx_queues; 13762306a36Sopenharmony_ci int i, j; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci switch (stringset) { 14062306a36Sopenharmony_ci case ETH_SS_STATS: 14162306a36Sopenharmony_ci memcpy(data, tsnep_stats_strings, sizeof(tsnep_stats_strings)); 14262306a36Sopenharmony_ci data += sizeof(tsnep_stats_strings); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci for (i = 0; i < rx_count; i++) { 14562306a36Sopenharmony_ci for (j = 0; j < TSNEP_RX_QUEUE_STATS_COUNT; j++) { 14662306a36Sopenharmony_ci snprintf(data, ETH_GSTRING_LEN, 14762306a36Sopenharmony_ci tsnep_rx_queue_stats_strings[j], i); 14862306a36Sopenharmony_ci data += ETH_GSTRING_LEN; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci for (i = 0; i < tx_count; i++) { 15362306a36Sopenharmony_ci for (j = 0; j < TSNEP_TX_QUEUE_STATS_COUNT; j++) { 15462306a36Sopenharmony_ci snprintf(data, ETH_GSTRING_LEN, 15562306a36Sopenharmony_ci tsnep_tx_queue_stats_strings[j], i); 15662306a36Sopenharmony_ci data += ETH_GSTRING_LEN; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci break; 16062306a36Sopenharmony_ci case ETH_SS_TEST: 16162306a36Sopenharmony_ci tsnep_ethtool_get_test_strings(data); 16262306a36Sopenharmony_ci break; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic void tsnep_ethtool_get_ethtool_stats(struct net_device *netdev, 16762306a36Sopenharmony_ci struct ethtool_stats *stats, 16862306a36Sopenharmony_ci u64 *data) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci struct tsnep_adapter *adapter = netdev_priv(netdev); 17162306a36Sopenharmony_ci int rx_count = adapter->num_rx_queues; 17262306a36Sopenharmony_ci int tx_count = adapter->num_tx_queues; 17362306a36Sopenharmony_ci struct tsnep_stats tsnep_stats; 17462306a36Sopenharmony_ci struct tsnep_rx_queue_stats tsnep_rx_queue_stats; 17562306a36Sopenharmony_ci struct tsnep_tx_queue_stats tsnep_tx_queue_stats; 17662306a36Sopenharmony_ci u32 reg; 17762306a36Sopenharmony_ci int i; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci memset(&tsnep_stats, 0, sizeof(tsnep_stats)); 18062306a36Sopenharmony_ci for (i = 0; i < adapter->num_rx_queues; i++) { 18162306a36Sopenharmony_ci tsnep_stats.rx_packets += adapter->rx[i].packets; 18262306a36Sopenharmony_ci tsnep_stats.rx_bytes += adapter->rx[i].bytes; 18362306a36Sopenharmony_ci tsnep_stats.rx_dropped += adapter->rx[i].dropped; 18462306a36Sopenharmony_ci tsnep_stats.rx_multicast += adapter->rx[i].multicast; 18562306a36Sopenharmony_ci tsnep_stats.rx_alloc_failed += adapter->rx[i].alloc_failed; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci reg = ioread32(adapter->addr + ECM_STAT); 18862306a36Sopenharmony_ci tsnep_stats.rx_phy_errors = 18962306a36Sopenharmony_ci (reg & ECM_STAT_RX_ERR_MASK) >> ECM_STAT_RX_ERR_SHIFT; 19062306a36Sopenharmony_ci tsnep_stats.rx_forwarded_phy_errors = 19162306a36Sopenharmony_ci (reg & ECM_STAT_FWD_RX_ERR_MASK) >> ECM_STAT_FWD_RX_ERR_SHIFT; 19262306a36Sopenharmony_ci tsnep_stats.rx_invalid_frame_errors = 19362306a36Sopenharmony_ci (reg & ECM_STAT_INV_FRM_MASK) >> ECM_STAT_INV_FRM_SHIFT; 19462306a36Sopenharmony_ci for (i = 0; i < adapter->num_tx_queues; i++) { 19562306a36Sopenharmony_ci tsnep_stats.tx_packets += adapter->tx[i].packets; 19662306a36Sopenharmony_ci tsnep_stats.tx_bytes += adapter->tx[i].bytes; 19762306a36Sopenharmony_ci tsnep_stats.tx_dropped += adapter->tx[i].dropped; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci memcpy(data, &tsnep_stats, sizeof(tsnep_stats)); 20062306a36Sopenharmony_ci data += TSNEP_STATS_COUNT; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci for (i = 0; i < rx_count; i++) { 20362306a36Sopenharmony_ci memset(&tsnep_rx_queue_stats, 0, sizeof(tsnep_rx_queue_stats)); 20462306a36Sopenharmony_ci tsnep_rx_queue_stats.rx_packets = adapter->rx[i].packets; 20562306a36Sopenharmony_ci tsnep_rx_queue_stats.rx_bytes = adapter->rx[i].bytes; 20662306a36Sopenharmony_ci tsnep_rx_queue_stats.rx_dropped = adapter->rx[i].dropped; 20762306a36Sopenharmony_ci tsnep_rx_queue_stats.rx_multicast = adapter->rx[i].multicast; 20862306a36Sopenharmony_ci tsnep_rx_queue_stats.rx_alloc_failed = 20962306a36Sopenharmony_ci adapter->rx[i].alloc_failed; 21062306a36Sopenharmony_ci reg = ioread32(adapter->addr + TSNEP_QUEUE(i) + 21162306a36Sopenharmony_ci TSNEP_RX_STATISTIC); 21262306a36Sopenharmony_ci tsnep_rx_queue_stats.rx_no_descriptor_errors = 21362306a36Sopenharmony_ci (reg & TSNEP_RX_STATISTIC_NO_DESC_MASK) >> 21462306a36Sopenharmony_ci TSNEP_RX_STATISTIC_NO_DESC_SHIFT; 21562306a36Sopenharmony_ci tsnep_rx_queue_stats.rx_buffer_too_small_errors = 21662306a36Sopenharmony_ci (reg & TSNEP_RX_STATISTIC_BUFFER_TOO_SMALL_MASK) >> 21762306a36Sopenharmony_ci TSNEP_RX_STATISTIC_BUFFER_TOO_SMALL_SHIFT; 21862306a36Sopenharmony_ci tsnep_rx_queue_stats.rx_fifo_overflow_errors = 21962306a36Sopenharmony_ci (reg & TSNEP_RX_STATISTIC_FIFO_OVERFLOW_MASK) >> 22062306a36Sopenharmony_ci TSNEP_RX_STATISTIC_FIFO_OVERFLOW_SHIFT; 22162306a36Sopenharmony_ci tsnep_rx_queue_stats.rx_invalid_frame_errors = 22262306a36Sopenharmony_ci (reg & TSNEP_RX_STATISTIC_INVALID_FRAME_MASK) >> 22362306a36Sopenharmony_ci TSNEP_RX_STATISTIC_INVALID_FRAME_SHIFT; 22462306a36Sopenharmony_ci memcpy(data, &tsnep_rx_queue_stats, 22562306a36Sopenharmony_ci sizeof(tsnep_rx_queue_stats)); 22662306a36Sopenharmony_ci data += TSNEP_RX_QUEUE_STATS_COUNT; 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci for (i = 0; i < tx_count; i++) { 23062306a36Sopenharmony_ci memset(&tsnep_tx_queue_stats, 0, sizeof(tsnep_tx_queue_stats)); 23162306a36Sopenharmony_ci tsnep_tx_queue_stats.tx_packets += adapter->tx[i].packets; 23262306a36Sopenharmony_ci tsnep_tx_queue_stats.tx_bytes += adapter->tx[i].bytes; 23362306a36Sopenharmony_ci tsnep_tx_queue_stats.tx_dropped += adapter->tx[i].dropped; 23462306a36Sopenharmony_ci memcpy(data, &tsnep_tx_queue_stats, 23562306a36Sopenharmony_ci sizeof(tsnep_tx_queue_stats)); 23662306a36Sopenharmony_ci data += TSNEP_TX_QUEUE_STATS_COUNT; 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistatic int tsnep_ethtool_get_sset_count(struct net_device *netdev, int sset) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci struct tsnep_adapter *adapter = netdev_priv(netdev); 24362306a36Sopenharmony_ci int rx_count; 24462306a36Sopenharmony_ci int tx_count; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci switch (sset) { 24762306a36Sopenharmony_ci case ETH_SS_STATS: 24862306a36Sopenharmony_ci rx_count = adapter->num_rx_queues; 24962306a36Sopenharmony_ci tx_count = adapter->num_tx_queues; 25062306a36Sopenharmony_ci return TSNEP_STATS_COUNT + 25162306a36Sopenharmony_ci TSNEP_RX_QUEUE_STATS_COUNT * rx_count + 25262306a36Sopenharmony_ci TSNEP_TX_QUEUE_STATS_COUNT * tx_count; 25362306a36Sopenharmony_ci case ETH_SS_TEST: 25462306a36Sopenharmony_ci return tsnep_ethtool_get_test_count(); 25562306a36Sopenharmony_ci default: 25662306a36Sopenharmony_ci return -EOPNOTSUPP; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic int tsnep_ethtool_get_rxnfc(struct net_device *netdev, 26162306a36Sopenharmony_ci struct ethtool_rxnfc *cmd, u32 *rule_locs) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci struct tsnep_adapter *adapter = netdev_priv(netdev); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci switch (cmd->cmd) { 26662306a36Sopenharmony_ci case ETHTOOL_GRXRINGS: 26762306a36Sopenharmony_ci cmd->data = adapter->num_rx_queues; 26862306a36Sopenharmony_ci return 0; 26962306a36Sopenharmony_ci case ETHTOOL_GRXCLSRLCNT: 27062306a36Sopenharmony_ci cmd->rule_cnt = adapter->rxnfc_count; 27162306a36Sopenharmony_ci cmd->data = adapter->rxnfc_max; 27262306a36Sopenharmony_ci cmd->data |= RX_CLS_LOC_SPECIAL; 27362306a36Sopenharmony_ci return 0; 27462306a36Sopenharmony_ci case ETHTOOL_GRXCLSRULE: 27562306a36Sopenharmony_ci return tsnep_rxnfc_get_rule(adapter, cmd); 27662306a36Sopenharmony_ci case ETHTOOL_GRXCLSRLALL: 27762306a36Sopenharmony_ci return tsnep_rxnfc_get_all(adapter, cmd, rule_locs); 27862306a36Sopenharmony_ci default: 27962306a36Sopenharmony_ci return -EOPNOTSUPP; 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic int tsnep_ethtool_set_rxnfc(struct net_device *netdev, 28462306a36Sopenharmony_ci struct ethtool_rxnfc *cmd) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci struct tsnep_adapter *adapter = netdev_priv(netdev); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci switch (cmd->cmd) { 28962306a36Sopenharmony_ci case ETHTOOL_SRXCLSRLINS: 29062306a36Sopenharmony_ci return tsnep_rxnfc_add_rule(adapter, cmd); 29162306a36Sopenharmony_ci case ETHTOOL_SRXCLSRLDEL: 29262306a36Sopenharmony_ci return tsnep_rxnfc_del_rule(adapter, cmd); 29362306a36Sopenharmony_ci default: 29462306a36Sopenharmony_ci return -EOPNOTSUPP; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic void tsnep_ethtool_get_channels(struct net_device *netdev, 29962306a36Sopenharmony_ci struct ethtool_channels *ch) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci struct tsnep_adapter *adapter = netdev_priv(netdev); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci ch->max_combined = adapter->num_queues; 30462306a36Sopenharmony_ci ch->combined_count = adapter->num_queues; 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic int tsnep_ethtool_get_ts_info(struct net_device *netdev, 30862306a36Sopenharmony_ci struct ethtool_ts_info *info) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci struct tsnep_adapter *adapter = netdev_priv(netdev); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | 31362306a36Sopenharmony_ci SOF_TIMESTAMPING_RX_SOFTWARE | 31462306a36Sopenharmony_ci SOF_TIMESTAMPING_SOFTWARE | 31562306a36Sopenharmony_ci SOF_TIMESTAMPING_TX_HARDWARE | 31662306a36Sopenharmony_ci SOF_TIMESTAMPING_RX_HARDWARE | 31762306a36Sopenharmony_ci SOF_TIMESTAMPING_RAW_HARDWARE; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci if (adapter->ptp_clock) 32062306a36Sopenharmony_ci info->phc_index = ptp_clock_index(adapter->ptp_clock); 32162306a36Sopenharmony_ci else 32262306a36Sopenharmony_ci info->phc_index = -1; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci info->tx_types = BIT(HWTSTAMP_TX_OFF) | 32562306a36Sopenharmony_ci BIT(HWTSTAMP_TX_ON); 32662306a36Sopenharmony_ci info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | 32762306a36Sopenharmony_ci BIT(HWTSTAMP_FILTER_ALL); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci return 0; 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_cistatic struct tsnep_queue *tsnep_get_queue_with_tx(struct tsnep_adapter *adapter, 33362306a36Sopenharmony_ci int index) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci int i; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci for (i = 0; i < adapter->num_queues; i++) { 33862306a36Sopenharmony_ci if (adapter->queue[i].tx) { 33962306a36Sopenharmony_ci if (index == 0) 34062306a36Sopenharmony_ci return &adapter->queue[i]; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci index--; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci return NULL; 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic struct tsnep_queue *tsnep_get_queue_with_rx(struct tsnep_adapter *adapter, 35062306a36Sopenharmony_ci int index) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci int i; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci for (i = 0; i < adapter->num_queues; i++) { 35562306a36Sopenharmony_ci if (adapter->queue[i].rx) { 35662306a36Sopenharmony_ci if (index == 0) 35762306a36Sopenharmony_ci return &adapter->queue[i]; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci index--; 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci return NULL; 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_cistatic int tsnep_ethtool_get_coalesce(struct net_device *netdev, 36762306a36Sopenharmony_ci struct ethtool_coalesce *ec, 36862306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 36962306a36Sopenharmony_ci struct netlink_ext_ack *extack) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci struct tsnep_adapter *adapter = netdev_priv(netdev); 37262306a36Sopenharmony_ci struct tsnep_queue *queue; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci queue = tsnep_get_queue_with_rx(adapter, 0); 37562306a36Sopenharmony_ci if (queue) 37662306a36Sopenharmony_ci ec->rx_coalesce_usecs = tsnep_get_irq_coalesce(queue); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci queue = tsnep_get_queue_with_tx(adapter, 0); 37962306a36Sopenharmony_ci if (queue) 38062306a36Sopenharmony_ci ec->tx_coalesce_usecs = tsnep_get_irq_coalesce(queue); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci return 0; 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cistatic int tsnep_ethtool_set_coalesce(struct net_device *netdev, 38662306a36Sopenharmony_ci struct ethtool_coalesce *ec, 38762306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 38862306a36Sopenharmony_ci struct netlink_ext_ack *extack) 38962306a36Sopenharmony_ci{ 39062306a36Sopenharmony_ci struct tsnep_adapter *adapter = netdev_priv(netdev); 39162306a36Sopenharmony_ci int i; 39262306a36Sopenharmony_ci int retval; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci for (i = 0; i < adapter->num_queues; i++) { 39562306a36Sopenharmony_ci /* RX coalesce has priority for queues with TX and RX */ 39662306a36Sopenharmony_ci if (adapter->queue[i].rx) 39762306a36Sopenharmony_ci retval = tsnep_set_irq_coalesce(&adapter->queue[i], 39862306a36Sopenharmony_ci ec->rx_coalesce_usecs); 39962306a36Sopenharmony_ci else 40062306a36Sopenharmony_ci retval = tsnep_set_irq_coalesce(&adapter->queue[i], 40162306a36Sopenharmony_ci ec->tx_coalesce_usecs); 40262306a36Sopenharmony_ci if (retval != 0) 40362306a36Sopenharmony_ci return retval; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci return 0; 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cistatic int tsnep_ethtool_get_per_queue_coalesce(struct net_device *netdev, 41062306a36Sopenharmony_ci u32 queue, 41162306a36Sopenharmony_ci struct ethtool_coalesce *ec) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci struct tsnep_adapter *adapter = netdev_priv(netdev); 41462306a36Sopenharmony_ci struct tsnep_queue *queue_with_rx; 41562306a36Sopenharmony_ci struct tsnep_queue *queue_with_tx; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci if (queue >= max(adapter->num_tx_queues, adapter->num_rx_queues)) 41862306a36Sopenharmony_ci return -EINVAL; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci queue_with_rx = tsnep_get_queue_with_rx(adapter, queue); 42162306a36Sopenharmony_ci if (queue_with_rx) 42262306a36Sopenharmony_ci ec->rx_coalesce_usecs = tsnep_get_irq_coalesce(queue_with_rx); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci queue_with_tx = tsnep_get_queue_with_tx(adapter, queue); 42562306a36Sopenharmony_ci if (queue_with_tx) 42662306a36Sopenharmony_ci ec->tx_coalesce_usecs = tsnep_get_irq_coalesce(queue_with_tx); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci return 0; 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic int tsnep_ethtool_set_per_queue_coalesce(struct net_device *netdev, 43262306a36Sopenharmony_ci u32 queue, 43362306a36Sopenharmony_ci struct ethtool_coalesce *ec) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci struct tsnep_adapter *adapter = netdev_priv(netdev); 43662306a36Sopenharmony_ci struct tsnep_queue *queue_with_rx; 43762306a36Sopenharmony_ci struct tsnep_queue *queue_with_tx; 43862306a36Sopenharmony_ci int retval; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if (queue >= max(adapter->num_tx_queues, adapter->num_rx_queues)) 44162306a36Sopenharmony_ci return -EINVAL; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci queue_with_rx = tsnep_get_queue_with_rx(adapter, queue); 44462306a36Sopenharmony_ci if (queue_with_rx) { 44562306a36Sopenharmony_ci retval = tsnep_set_irq_coalesce(queue_with_rx, ec->rx_coalesce_usecs); 44662306a36Sopenharmony_ci if (retval != 0) 44762306a36Sopenharmony_ci return retval; 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci /* RX coalesce has priority for queues with TX and RX */ 45162306a36Sopenharmony_ci queue_with_tx = tsnep_get_queue_with_tx(adapter, queue); 45262306a36Sopenharmony_ci if (queue_with_tx && !queue_with_tx->rx) { 45362306a36Sopenharmony_ci retval = tsnep_set_irq_coalesce(queue_with_tx, ec->tx_coalesce_usecs); 45462306a36Sopenharmony_ci if (retval != 0) 45562306a36Sopenharmony_ci return retval; 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci return 0; 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ciconst struct ethtool_ops tsnep_ethtool_ops = { 46262306a36Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_USECS, 46362306a36Sopenharmony_ci .get_drvinfo = tsnep_ethtool_get_drvinfo, 46462306a36Sopenharmony_ci .get_regs_len = tsnep_ethtool_get_regs_len, 46562306a36Sopenharmony_ci .get_regs = tsnep_ethtool_get_regs, 46662306a36Sopenharmony_ci .get_msglevel = tsnep_ethtool_get_msglevel, 46762306a36Sopenharmony_ci .set_msglevel = tsnep_ethtool_set_msglevel, 46862306a36Sopenharmony_ci .nway_reset = phy_ethtool_nway_reset, 46962306a36Sopenharmony_ci .get_link = ethtool_op_get_link, 47062306a36Sopenharmony_ci .self_test = tsnep_ethtool_self_test, 47162306a36Sopenharmony_ci .get_strings = tsnep_ethtool_get_strings, 47262306a36Sopenharmony_ci .get_ethtool_stats = tsnep_ethtool_get_ethtool_stats, 47362306a36Sopenharmony_ci .get_sset_count = tsnep_ethtool_get_sset_count, 47462306a36Sopenharmony_ci .get_rxnfc = tsnep_ethtool_get_rxnfc, 47562306a36Sopenharmony_ci .set_rxnfc = tsnep_ethtool_set_rxnfc, 47662306a36Sopenharmony_ci .get_channels = tsnep_ethtool_get_channels, 47762306a36Sopenharmony_ci .get_ts_info = tsnep_ethtool_get_ts_info, 47862306a36Sopenharmony_ci .get_coalesce = tsnep_ethtool_get_coalesce, 47962306a36Sopenharmony_ci .set_coalesce = tsnep_ethtool_set_coalesce, 48062306a36Sopenharmony_ci .get_per_queue_coalesce = tsnep_ethtool_get_per_queue_coalesce, 48162306a36Sopenharmony_ci .set_per_queue_coalesce = tsnep_ethtool_set_per_queue_coalesce, 48262306a36Sopenharmony_ci .get_link_ksettings = phy_ethtool_get_link_ksettings, 48362306a36Sopenharmony_ci .set_link_ksettings = phy_ethtool_set_link_ksettings, 48462306a36Sopenharmony_ci}; 485