1*5f4f7bc0SXuan Zhuo // SPDX-License-Identifier: GPL-2.0-or-later 2*5f4f7bc0SXuan Zhuo /* 3*5f4f7bc0SXuan Zhuo * Driver for Alibaba Elastic Ethernet Adapter. 4*5f4f7bc0SXuan Zhuo * 5*5f4f7bc0SXuan Zhuo * Copyright (C) 2025 Alibaba Inc. 6*5f4f7bc0SXuan Zhuo */ 7*5f4f7bc0SXuan Zhuo 8*5f4f7bc0SXuan Zhuo #include <linux/ethtool.h> 9*5f4f7bc0SXuan Zhuo #include <linux/ethtool_netlink.h> 10*5f4f7bc0SXuan Zhuo #include <linux/rtnetlink.h> 11*5f4f7bc0SXuan Zhuo 12*5f4f7bc0SXuan Zhuo #include "eea_adminq.h" 13*5f4f7bc0SXuan Zhuo #include "eea_net.h" 14*5f4f7bc0SXuan Zhuo #include "eea_pci.h" 15*5f4f7bc0SXuan Zhuo 16*5f4f7bc0SXuan Zhuo struct eea_stat_desc { 17*5f4f7bc0SXuan Zhuo char desc[ETH_GSTRING_LEN]; 18*5f4f7bc0SXuan Zhuo size_t offset; 19*5f4f7bc0SXuan Zhuo }; 20*5f4f7bc0SXuan Zhuo 21*5f4f7bc0SXuan Zhuo #define EEA_TX_STAT(m) {#m, offsetof(struct eea_tx_stats, m)} 22*5f4f7bc0SXuan Zhuo #define EEA_RX_STAT(m) {#m, offsetof(struct eea_rx_stats, m)} 23*5f4f7bc0SXuan Zhuo 24*5f4f7bc0SXuan Zhuo static const struct eea_stat_desc eea_rx_stats_desc[] = { 25*5f4f7bc0SXuan Zhuo EEA_RX_STAT(descs), 26*5f4f7bc0SXuan Zhuo EEA_RX_STAT(kicks), 27*5f4f7bc0SXuan Zhuo }; 28*5f4f7bc0SXuan Zhuo 29*5f4f7bc0SXuan Zhuo static const struct eea_stat_desc eea_tx_stats_desc[] = { 30*5f4f7bc0SXuan Zhuo EEA_TX_STAT(descs), 31*5f4f7bc0SXuan Zhuo EEA_TX_STAT(kicks), 32*5f4f7bc0SXuan Zhuo }; 33*5f4f7bc0SXuan Zhuo 34*5f4f7bc0SXuan Zhuo #define EEA_TX_STATS_LEN ARRAY_SIZE(eea_tx_stats_desc) 35*5f4f7bc0SXuan Zhuo #define EEA_RX_STATS_LEN ARRAY_SIZE(eea_rx_stats_desc) 36*5f4f7bc0SXuan Zhuo 37*5f4f7bc0SXuan Zhuo static void eea_get_drvinfo(struct net_device *netdev, 38*5f4f7bc0SXuan Zhuo struct ethtool_drvinfo *info) 39*5f4f7bc0SXuan Zhuo { 40*5f4f7bc0SXuan Zhuo struct eea_net *enet = netdev_priv(netdev); 41*5f4f7bc0SXuan Zhuo struct eea_device *edev = enet->edev; 42*5f4f7bc0SXuan Zhuo 43*5f4f7bc0SXuan Zhuo strscpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); 44*5f4f7bc0SXuan Zhuo strscpy(info->bus_info, eea_pci_name(edev), sizeof(info->bus_info)); 45*5f4f7bc0SXuan Zhuo } 46*5f4f7bc0SXuan Zhuo 47*5f4f7bc0SXuan Zhuo static void eea_get_ringparam(struct net_device *netdev, 48*5f4f7bc0SXuan Zhuo struct ethtool_ringparam *ring, 49*5f4f7bc0SXuan Zhuo struct kernel_ethtool_ringparam *kernel_ring, 50*5f4f7bc0SXuan Zhuo struct netlink_ext_ack *extack) 51*5f4f7bc0SXuan Zhuo { 52*5f4f7bc0SXuan Zhuo struct eea_net *enet = netdev_priv(netdev); 53*5f4f7bc0SXuan Zhuo 54*5f4f7bc0SXuan Zhuo ring->rx_max_pending = enet->cfg_hw.rx_ring_depth; 55*5f4f7bc0SXuan Zhuo ring->tx_max_pending = enet->cfg_hw.tx_ring_depth; 56*5f4f7bc0SXuan Zhuo ring->rx_pending = enet->cfg.rx_ring_depth; 57*5f4f7bc0SXuan Zhuo ring->tx_pending = enet->cfg.tx_ring_depth; 58*5f4f7bc0SXuan Zhuo 59*5f4f7bc0SXuan Zhuo kernel_ring->tcp_data_split = enet->cfg.split_hdr ? 60*5f4f7bc0SXuan Zhuo ETHTOOL_TCP_DATA_SPLIT_ENABLED : 61*5f4f7bc0SXuan Zhuo ETHTOOL_TCP_DATA_SPLIT_DISABLED; 62*5f4f7bc0SXuan Zhuo } 63*5f4f7bc0SXuan Zhuo 64*5f4f7bc0SXuan Zhuo static int eea_set_ringparam(struct net_device *netdev, 65*5f4f7bc0SXuan Zhuo struct ethtool_ringparam *ring, 66*5f4f7bc0SXuan Zhuo struct kernel_ethtool_ringparam *kernel_ring, 67*5f4f7bc0SXuan Zhuo struct netlink_ext_ack *extack) 68*5f4f7bc0SXuan Zhuo { 69*5f4f7bc0SXuan Zhuo struct eea_net *enet = netdev_priv(netdev); 70*5f4f7bc0SXuan Zhuo struct eea_net_init_ctx ctx; 71*5f4f7bc0SXuan Zhuo bool need_update = false; 72*5f4f7bc0SXuan Zhuo struct eea_net_cfg *cfg; 73*5f4f7bc0SXuan Zhuo bool sh; 74*5f4f7bc0SXuan Zhuo 75*5f4f7bc0SXuan Zhuo if (ring->rx_pending < EEA_NET_IO_RING_DEPTH_MIN || 76*5f4f7bc0SXuan Zhuo ring->tx_pending < EEA_NET_IO_RING_DEPTH_MIN) 77*5f4f7bc0SXuan Zhuo return -EINVAL; 78*5f4f7bc0SXuan Zhuo 79*5f4f7bc0SXuan Zhuo if (!is_power_of_2(ring->rx_pending) || 80*5f4f7bc0SXuan Zhuo !is_power_of_2(ring->tx_pending)) 81*5f4f7bc0SXuan Zhuo return -EINVAL; 82*5f4f7bc0SXuan Zhuo 83*5f4f7bc0SXuan Zhuo eea_init_ctx(enet, &ctx); 84*5f4f7bc0SXuan Zhuo 85*5f4f7bc0SXuan Zhuo cfg = &ctx.cfg; 86*5f4f7bc0SXuan Zhuo 87*5f4f7bc0SXuan Zhuo if (ring->rx_pending != cfg->rx_ring_depth) 88*5f4f7bc0SXuan Zhuo need_update = true; 89*5f4f7bc0SXuan Zhuo 90*5f4f7bc0SXuan Zhuo if (ring->tx_pending != cfg->tx_ring_depth) 91*5f4f7bc0SXuan Zhuo need_update = true; 92*5f4f7bc0SXuan Zhuo 93*5f4f7bc0SXuan Zhuo sh = false; 94*5f4f7bc0SXuan Zhuo 95*5f4f7bc0SXuan Zhuo switch (kernel_ring->tcp_data_split) { 96*5f4f7bc0SXuan Zhuo case ETHTOOL_TCP_DATA_SPLIT_ENABLED: 97*5f4f7bc0SXuan Zhuo sh = true; 98*5f4f7bc0SXuan Zhuo break; 99*5f4f7bc0SXuan Zhuo 100*5f4f7bc0SXuan Zhuo case ETHTOOL_TCP_DATA_SPLIT_DISABLED: 101*5f4f7bc0SXuan Zhuo sh = false; 102*5f4f7bc0SXuan Zhuo break; 103*5f4f7bc0SXuan Zhuo 104*5f4f7bc0SXuan Zhuo case ETHTOOL_TCP_DATA_SPLIT_UNKNOWN: 105*5f4f7bc0SXuan Zhuo sh = !!cfg->split_hdr; 106*5f4f7bc0SXuan Zhuo break; 107*5f4f7bc0SXuan Zhuo } 108*5f4f7bc0SXuan Zhuo 109*5f4f7bc0SXuan Zhuo if (sh != !!(cfg->split_hdr)) 110*5f4f7bc0SXuan Zhuo need_update = true; 111*5f4f7bc0SXuan Zhuo 112*5f4f7bc0SXuan Zhuo if (!need_update) 113*5f4f7bc0SXuan Zhuo return 0; 114*5f4f7bc0SXuan Zhuo 115*5f4f7bc0SXuan Zhuo cfg->rx_ring_depth = ring->rx_pending; 116*5f4f7bc0SXuan Zhuo cfg->tx_ring_depth = ring->tx_pending; 117*5f4f7bc0SXuan Zhuo 118*5f4f7bc0SXuan Zhuo /* By default, enet->cfg_hw.split_hdr is 128. */ 119*5f4f7bc0SXuan Zhuo cfg->split_hdr = sh ? enet->cfg_hw.split_hdr : 0; 120*5f4f7bc0SXuan Zhuo 121*5f4f7bc0SXuan Zhuo return eea_reset_hw_resources(enet, &ctx); 122*5f4f7bc0SXuan Zhuo } 123*5f4f7bc0SXuan Zhuo 124*5f4f7bc0SXuan Zhuo static int eea_set_channels(struct net_device *netdev, 125*5f4f7bc0SXuan Zhuo struct ethtool_channels *channels) 126*5f4f7bc0SXuan Zhuo { 127*5f4f7bc0SXuan Zhuo struct eea_net *enet = netdev_priv(netdev); 128*5f4f7bc0SXuan Zhuo u16 queue_pairs = channels->combined_count; 129*5f4f7bc0SXuan Zhuo struct eea_net_init_ctx ctx; 130*5f4f7bc0SXuan Zhuo struct eea_net_cfg *cfg; 131*5f4f7bc0SXuan Zhuo 132*5f4f7bc0SXuan Zhuo eea_init_ctx(enet, &ctx); 133*5f4f7bc0SXuan Zhuo 134*5f4f7bc0SXuan Zhuo cfg = &ctx.cfg; 135*5f4f7bc0SXuan Zhuo 136*5f4f7bc0SXuan Zhuo cfg->rx_ring_num = queue_pairs; 137*5f4f7bc0SXuan Zhuo cfg->tx_ring_num = queue_pairs; 138*5f4f7bc0SXuan Zhuo 139*5f4f7bc0SXuan Zhuo return eea_reset_hw_resources(enet, &ctx); 140*5f4f7bc0SXuan Zhuo } 141*5f4f7bc0SXuan Zhuo 142*5f4f7bc0SXuan Zhuo static void eea_get_channels(struct net_device *netdev, 143*5f4f7bc0SXuan Zhuo struct ethtool_channels *channels) 144*5f4f7bc0SXuan Zhuo { 145*5f4f7bc0SXuan Zhuo struct eea_net *enet = netdev_priv(netdev); 146*5f4f7bc0SXuan Zhuo 147*5f4f7bc0SXuan Zhuo channels->combined_count = enet->cfg.rx_ring_num; 148*5f4f7bc0SXuan Zhuo channels->max_combined = enet->cfg_hw.rx_ring_num; 149*5f4f7bc0SXuan Zhuo } 150*5f4f7bc0SXuan Zhuo 151*5f4f7bc0SXuan Zhuo static void eea_get_strings(struct net_device *netdev, u32 stringset, u8 *data) 152*5f4f7bc0SXuan Zhuo { 153*5f4f7bc0SXuan Zhuo struct eea_net *enet = netdev_priv(netdev); 154*5f4f7bc0SXuan Zhuo u8 *p = data; 155*5f4f7bc0SXuan Zhuo u32 i, j; 156*5f4f7bc0SXuan Zhuo 157*5f4f7bc0SXuan Zhuo if (stringset != ETH_SS_STATS) 158*5f4f7bc0SXuan Zhuo return; 159*5f4f7bc0SXuan Zhuo 160*5f4f7bc0SXuan Zhuo for (i = 0; i < enet->cfg.rx_ring_num; i++) { 161*5f4f7bc0SXuan Zhuo for (j = 0; j < EEA_RX_STATS_LEN; j++) 162*5f4f7bc0SXuan Zhuo ethtool_sprintf(&p, "rx%u_%s", i, 163*5f4f7bc0SXuan Zhuo eea_rx_stats_desc[j].desc); 164*5f4f7bc0SXuan Zhuo } 165*5f4f7bc0SXuan Zhuo 166*5f4f7bc0SXuan Zhuo for (i = 0; i < enet->cfg.tx_ring_num; i++) { 167*5f4f7bc0SXuan Zhuo for (j = 0; j < EEA_TX_STATS_LEN; j++) 168*5f4f7bc0SXuan Zhuo ethtool_sprintf(&p, "tx%u_%s", i, 169*5f4f7bc0SXuan Zhuo eea_tx_stats_desc[j].desc); 170*5f4f7bc0SXuan Zhuo } 171*5f4f7bc0SXuan Zhuo } 172*5f4f7bc0SXuan Zhuo 173*5f4f7bc0SXuan Zhuo static int eea_get_sset_count(struct net_device *netdev, int sset) 174*5f4f7bc0SXuan Zhuo { 175*5f4f7bc0SXuan Zhuo struct eea_net *enet = netdev_priv(netdev); 176*5f4f7bc0SXuan Zhuo 177*5f4f7bc0SXuan Zhuo if (sset != ETH_SS_STATS) 178*5f4f7bc0SXuan Zhuo return -EOPNOTSUPP; 179*5f4f7bc0SXuan Zhuo 180*5f4f7bc0SXuan Zhuo return enet->cfg.rx_ring_num * EEA_RX_STATS_LEN + 181*5f4f7bc0SXuan Zhuo enet->cfg.tx_ring_num * EEA_TX_STATS_LEN; 182*5f4f7bc0SXuan Zhuo } 183*5f4f7bc0SXuan Zhuo 184*5f4f7bc0SXuan Zhuo static void eea_stats_fill_for_q(struct u64_stats_sync *syncp, u32 num, 185*5f4f7bc0SXuan Zhuo const struct eea_stat_desc *desc, 186*5f4f7bc0SXuan Zhuo u64 *data, u32 idx) 187*5f4f7bc0SXuan Zhuo { 188*5f4f7bc0SXuan Zhuo void *stats_base = syncp; 189*5f4f7bc0SXuan Zhuo u32 start, i; 190*5f4f7bc0SXuan Zhuo 191*5f4f7bc0SXuan Zhuo do { 192*5f4f7bc0SXuan Zhuo start = u64_stats_fetch_begin(syncp); 193*5f4f7bc0SXuan Zhuo for (i = 0; i < num; i++) 194*5f4f7bc0SXuan Zhuo data[idx + i] = 195*5f4f7bc0SXuan Zhuo u64_stats_read(stats_base + desc[i].offset); 196*5f4f7bc0SXuan Zhuo 197*5f4f7bc0SXuan Zhuo } while (u64_stats_fetch_retry(syncp, start)); 198*5f4f7bc0SXuan Zhuo 199*5f4f7bc0SXuan Zhuo BUILD_BUG_ON(offsetof(struct eea_tx_stats, syncp)); 200*5f4f7bc0SXuan Zhuo BUILD_BUG_ON(offsetof(struct eea_rx_stats, syncp)); 201*5f4f7bc0SXuan Zhuo } 202*5f4f7bc0SXuan Zhuo 203*5f4f7bc0SXuan Zhuo static void eea_get_ethtool_stats(struct net_device *netdev, 204*5f4f7bc0SXuan Zhuo struct ethtool_stats *stats, u64 *data) 205*5f4f7bc0SXuan Zhuo { 206*5f4f7bc0SXuan Zhuo struct eea_net *enet = netdev_priv(netdev); 207*5f4f7bc0SXuan Zhuo u32 i, idx = 0; 208*5f4f7bc0SXuan Zhuo 209*5f4f7bc0SXuan Zhuo ASSERT_RTNL(); 210*5f4f7bc0SXuan Zhuo 211*5f4f7bc0SXuan Zhuo if (enet->rx) { 212*5f4f7bc0SXuan Zhuo for (i = 0; i < enet->cfg.rx_ring_num; i++) { 213*5f4f7bc0SXuan Zhuo struct eea_net_rx *rx = enet->rx[i]; 214*5f4f7bc0SXuan Zhuo 215*5f4f7bc0SXuan Zhuo eea_stats_fill_for_q(&rx->stats.syncp, EEA_RX_STATS_LEN, 216*5f4f7bc0SXuan Zhuo eea_rx_stats_desc, data, idx); 217*5f4f7bc0SXuan Zhuo 218*5f4f7bc0SXuan Zhuo idx += EEA_RX_STATS_LEN; 219*5f4f7bc0SXuan Zhuo } 220*5f4f7bc0SXuan Zhuo } 221*5f4f7bc0SXuan Zhuo 222*5f4f7bc0SXuan Zhuo if (enet->tx) { 223*5f4f7bc0SXuan Zhuo for (i = 0; i < enet->cfg.tx_ring_num; i++) { 224*5f4f7bc0SXuan Zhuo struct eea_net_tx *tx = &enet->tx[i]; 225*5f4f7bc0SXuan Zhuo 226*5f4f7bc0SXuan Zhuo eea_stats_fill_for_q(&tx->stats.syncp, EEA_TX_STATS_LEN, 227*5f4f7bc0SXuan Zhuo eea_tx_stats_desc, data, idx); 228*5f4f7bc0SXuan Zhuo 229*5f4f7bc0SXuan Zhuo idx += EEA_TX_STATS_LEN; 230*5f4f7bc0SXuan Zhuo } 231*5f4f7bc0SXuan Zhuo } 232*5f4f7bc0SXuan Zhuo } 233*5f4f7bc0SXuan Zhuo 234*5f4f7bc0SXuan Zhuo void eea_update_rx_stats(struct eea_rx_stats *rx_stats, 235*5f4f7bc0SXuan Zhuo struct eea_rx_ctx_stats *stats) 236*5f4f7bc0SXuan Zhuo { 237*5f4f7bc0SXuan Zhuo u64_stats_update_begin(&rx_stats->syncp); 238*5f4f7bc0SXuan Zhuo u64_stats_add(&rx_stats->descs, stats->descs); 239*5f4f7bc0SXuan Zhuo u64_stats_add(&rx_stats->packets, stats->packets); 240*5f4f7bc0SXuan Zhuo u64_stats_add(&rx_stats->bytes, stats->bytes); 241*5f4f7bc0SXuan Zhuo u64_stats_add(&rx_stats->drops, stats->drops); 242*5f4f7bc0SXuan Zhuo u64_stats_add(&rx_stats->split_hdr_bytes, stats->split_hdr_bytes); 243*5f4f7bc0SXuan Zhuo u64_stats_add(&rx_stats->split_hdr_packets, stats->split_hdr_packets); 244*5f4f7bc0SXuan Zhuo u64_stats_add(&rx_stats->length_errors, stats->length_errors); 245*5f4f7bc0SXuan Zhuo u64_stats_add(&rx_stats->kicks, stats->kicks); 246*5f4f7bc0SXuan Zhuo u64_stats_update_end(&rx_stats->syncp); 247*5f4f7bc0SXuan Zhuo } 248*5f4f7bc0SXuan Zhuo 249*5f4f7bc0SXuan Zhuo static int eea_get_link_ksettings(struct net_device *netdev, 250*5f4f7bc0SXuan Zhuo struct ethtool_link_ksettings *cmd) 251*5f4f7bc0SXuan Zhuo { 252*5f4f7bc0SXuan Zhuo struct eea_net *enet = netdev_priv(netdev); 253*5f4f7bc0SXuan Zhuo 254*5f4f7bc0SXuan Zhuo cmd->base.speed = enet->speed; 255*5f4f7bc0SXuan Zhuo cmd->base.duplex = enet->duplex; 256*5f4f7bc0SXuan Zhuo cmd->base.port = PORT_OTHER; 257*5f4f7bc0SXuan Zhuo 258*5f4f7bc0SXuan Zhuo return 0; 259*5f4f7bc0SXuan Zhuo } 260*5f4f7bc0SXuan Zhuo 261*5f4f7bc0SXuan Zhuo const struct ethtool_ops eea_ethtool_ops = { 262*5f4f7bc0SXuan Zhuo .supported_ring_params = ETHTOOL_RING_USE_TCP_DATA_SPLIT, 263*5f4f7bc0SXuan Zhuo .get_drvinfo = eea_get_drvinfo, 264*5f4f7bc0SXuan Zhuo .get_link = ethtool_op_get_link, 265*5f4f7bc0SXuan Zhuo .get_ringparam = eea_get_ringparam, 266*5f4f7bc0SXuan Zhuo .set_ringparam = eea_set_ringparam, 267*5f4f7bc0SXuan Zhuo .set_channels = eea_set_channels, 268*5f4f7bc0SXuan Zhuo .get_channels = eea_get_channels, 269*5f4f7bc0SXuan Zhuo .get_strings = eea_get_strings, 270*5f4f7bc0SXuan Zhuo .get_sset_count = eea_get_sset_count, 271*5f4f7bc0SXuan Zhuo .get_ethtool_stats = eea_get_ethtool_stats, 272*5f4f7bc0SXuan Zhuo .get_link_ksettings = eea_get_link_ksettings, 273*5f4f7bc0SXuan Zhuo }; 274