Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
0002 
0003 #include <linux/ethtool.h>
0004 #include <linux/linkmode.h>
0005 #include <linux/netdevice.h>
0006 #include <linux/nvme.h>
0007 #include <linux/io.h>
0008 #include <linux/io-64-nonatomic-lo-hi.h>
0009 #include <linux/pci.h>
0010 #include <linux/rtnetlink.h>
0011 #include "funeth.h"
0012 #include "fun_port.h"
0013 #include "funeth_txrx.h"
0014 
0015 /* Min queue depth. The smallest power-of-2 supporting jumbo frames with 4K
0016  * pages is 8. Require it for all types of queues though some could work with
0017  * fewer entries.
0018  */
0019 #define FUNETH_MIN_QDEPTH 8
0020 
0021 static const char mac_tx_stat_names[][ETH_GSTRING_LEN] = {
0022     "mac_tx_octets_total",
0023     "mac_tx_frames_total",
0024     "mac_tx_vlan_frames_ok",
0025     "mac_tx_unicast_frames",
0026     "mac_tx_multicast_frames",
0027     "mac_tx_broadcast_frames",
0028     "mac_tx_errors",
0029     "mac_tx_CBFCPAUSE0",
0030     "mac_tx_CBFCPAUSE1",
0031     "mac_tx_CBFCPAUSE2",
0032     "mac_tx_CBFCPAUSE3",
0033     "mac_tx_CBFCPAUSE4",
0034     "mac_tx_CBFCPAUSE5",
0035     "mac_tx_CBFCPAUSE6",
0036     "mac_tx_CBFCPAUSE7",
0037     "mac_tx_CBFCPAUSE8",
0038     "mac_tx_CBFCPAUSE9",
0039     "mac_tx_CBFCPAUSE10",
0040     "mac_tx_CBFCPAUSE11",
0041     "mac_tx_CBFCPAUSE12",
0042     "mac_tx_CBFCPAUSE13",
0043     "mac_tx_CBFCPAUSE14",
0044     "mac_tx_CBFCPAUSE15",
0045 };
0046 
0047 static const char mac_rx_stat_names[][ETH_GSTRING_LEN] = {
0048     "mac_rx_octets_total",
0049     "mac_rx_frames_total",
0050     "mac_rx_VLAN_frames_ok",
0051     "mac_rx_unicast_frames",
0052     "mac_rx_multicast_frames",
0053     "mac_rx_broadcast_frames",
0054     "mac_rx_drop_events",
0055     "mac_rx_errors",
0056     "mac_rx_alignment_errors",
0057     "mac_rx_CBFCPAUSE0",
0058     "mac_rx_CBFCPAUSE1",
0059     "mac_rx_CBFCPAUSE2",
0060     "mac_rx_CBFCPAUSE3",
0061     "mac_rx_CBFCPAUSE4",
0062     "mac_rx_CBFCPAUSE5",
0063     "mac_rx_CBFCPAUSE6",
0064     "mac_rx_CBFCPAUSE7",
0065     "mac_rx_CBFCPAUSE8",
0066     "mac_rx_CBFCPAUSE9",
0067     "mac_rx_CBFCPAUSE10",
0068     "mac_rx_CBFCPAUSE11",
0069     "mac_rx_CBFCPAUSE12",
0070     "mac_rx_CBFCPAUSE13",
0071     "mac_rx_CBFCPAUSE14",
0072     "mac_rx_CBFCPAUSE15",
0073 };
0074 
0075 static const char * const txq_stat_names[] = {
0076     "tx_pkts",
0077     "tx_bytes",
0078     "tx_cso",
0079     "tx_tso",
0080     "tx_encapsulated_tso",
0081     "tx_uso",
0082     "tx_more",
0083     "tx_queue_stops",
0084     "tx_queue_restarts",
0085     "tx_mapping_errors",
0086     "tx_tls_encrypted_packets",
0087     "tx_tls_encrypted_bytes",
0088     "tx_tls_ooo",
0089     "tx_tls_drop_no_sync_data",
0090 };
0091 
0092 static const char * const xdpq_stat_names[] = {
0093     "tx_xdp_pkts",
0094     "tx_xdp_bytes",
0095     "tx_xdp_full",
0096     "tx_xdp_mapping_errors",
0097 };
0098 
0099 static const char * const rxq_stat_names[] = {
0100     "rx_pkts",
0101     "rx_bytes",
0102     "rx_cso",
0103     "gro_pkts",
0104     "gro_merged",
0105     "rx_xdp_tx",
0106     "rx_xdp_redir",
0107     "rx_xdp_drops",
0108     "rx_buffers",
0109     "rx_page_allocs",
0110     "rx_drops",
0111     "rx_budget_exhausted",
0112     "rx_mapping_errors",
0113 };
0114 
0115 static const char * const tls_stat_names[] = {
0116     "tx_tls_ctx",
0117     "tx_tls_del",
0118     "tx_tls_resync",
0119 };
0120 
0121 static void fun_link_modes_to_ethtool(u64 modes,
0122                       unsigned long *ethtool_modes_map)
0123 {
0124 #define ADD_LINK_MODE(mode) \
0125     __set_bit(ETHTOOL_LINK_MODE_ ## mode ## _BIT, ethtool_modes_map)
0126 
0127     if (modes & FUN_PORT_CAP_AUTONEG)
0128         ADD_LINK_MODE(Autoneg);
0129     if (modes & FUN_PORT_CAP_1000_X)
0130         ADD_LINK_MODE(1000baseX_Full);
0131     if (modes & FUN_PORT_CAP_10G_R) {
0132         ADD_LINK_MODE(10000baseCR_Full);
0133         ADD_LINK_MODE(10000baseSR_Full);
0134         ADD_LINK_MODE(10000baseLR_Full);
0135         ADD_LINK_MODE(10000baseER_Full);
0136     }
0137     if (modes & FUN_PORT_CAP_25G_R) {
0138         ADD_LINK_MODE(25000baseCR_Full);
0139         ADD_LINK_MODE(25000baseSR_Full);
0140     }
0141     if (modes & FUN_PORT_CAP_40G_R4) {
0142         ADD_LINK_MODE(40000baseCR4_Full);
0143         ADD_LINK_MODE(40000baseSR4_Full);
0144         ADD_LINK_MODE(40000baseLR4_Full);
0145     }
0146     if (modes & FUN_PORT_CAP_50G_R2) {
0147         ADD_LINK_MODE(50000baseCR2_Full);
0148         ADD_LINK_MODE(50000baseSR2_Full);
0149     }
0150     if (modes & FUN_PORT_CAP_50G_R) {
0151         ADD_LINK_MODE(50000baseCR_Full);
0152         ADD_LINK_MODE(50000baseSR_Full);
0153         ADD_LINK_MODE(50000baseLR_ER_FR_Full);
0154     }
0155     if (modes & FUN_PORT_CAP_100G_R4) {
0156         ADD_LINK_MODE(100000baseCR4_Full);
0157         ADD_LINK_MODE(100000baseSR4_Full);
0158         ADD_LINK_MODE(100000baseLR4_ER4_Full);
0159     }
0160     if (modes & FUN_PORT_CAP_100G_R2) {
0161         ADD_LINK_MODE(100000baseCR2_Full);
0162         ADD_LINK_MODE(100000baseSR2_Full);
0163         ADD_LINK_MODE(100000baseLR2_ER2_FR2_Full);
0164     }
0165     if (modes & FUN_PORT_CAP_FEC_NONE)
0166         ADD_LINK_MODE(FEC_NONE);
0167     if (modes & FUN_PORT_CAP_FEC_FC)
0168         ADD_LINK_MODE(FEC_BASER);
0169     if (modes & FUN_PORT_CAP_FEC_RS)
0170         ADD_LINK_MODE(FEC_RS);
0171     if (modes & FUN_PORT_CAP_RX_PAUSE)
0172         ADD_LINK_MODE(Pause);
0173 
0174 #undef ADD_LINK_MODE
0175 }
0176 
0177 static void set_asym_pause(u64 advertising, struct ethtool_link_ksettings *ks)
0178 {
0179     bool rx_pause, tx_pause;
0180 
0181     rx_pause = advertising & FUN_PORT_CAP_RX_PAUSE;
0182     tx_pause = advertising & FUN_PORT_CAP_TX_PAUSE;
0183     if (tx_pause ^ rx_pause)
0184         ethtool_link_ksettings_add_link_mode(ks, advertising,
0185                              Asym_Pause);
0186 }
0187 
0188 static unsigned int fun_port_type(unsigned int xcvr)
0189 {
0190     if (!xcvr)
0191         return PORT_NONE;
0192 
0193     switch (xcvr & 7) {
0194     case FUN_XCVR_BASET:
0195         return PORT_TP;
0196     case FUN_XCVR_CU:
0197         return PORT_DA;
0198     default:
0199         return PORT_FIBRE;
0200     }
0201 }
0202 
0203 static int fun_get_link_ksettings(struct net_device *netdev,
0204                   struct ethtool_link_ksettings *ks)
0205 {
0206     const struct funeth_priv *fp = netdev_priv(netdev);
0207     unsigned int seq, speed, xcvr;
0208     u64 lp_advertising;
0209     bool link_up;
0210 
0211     ethtool_link_ksettings_zero_link_mode(ks, supported);
0212     ethtool_link_ksettings_zero_link_mode(ks, advertising);
0213     ethtool_link_ksettings_zero_link_mode(ks, lp_advertising);
0214 
0215     /* Link settings change asynchronously, take a consistent snapshot */
0216     do {
0217         seq = read_seqcount_begin(&fp->link_seq);
0218         link_up = netif_carrier_ok(netdev);
0219         speed = fp->link_speed;
0220         xcvr = fp->xcvr_type;
0221         lp_advertising = fp->lp_advertising;
0222     } while (read_seqcount_retry(&fp->link_seq, seq));
0223 
0224     if (link_up) {
0225         ks->base.speed = speed;
0226         ks->base.duplex = DUPLEX_FULL;
0227         fun_link_modes_to_ethtool(lp_advertising,
0228                       ks->link_modes.lp_advertising);
0229     } else {
0230         ks->base.speed = SPEED_UNKNOWN;
0231         ks->base.duplex = DUPLEX_UNKNOWN;
0232     }
0233 
0234     ks->base.autoneg = (fp->advertising & FUN_PORT_CAP_AUTONEG) ?
0235                AUTONEG_ENABLE : AUTONEG_DISABLE;
0236     ks->base.port = fun_port_type(xcvr);
0237 
0238     fun_link_modes_to_ethtool(fp->port_caps, ks->link_modes.supported);
0239     if (fp->port_caps & (FUN_PORT_CAP_RX_PAUSE | FUN_PORT_CAP_TX_PAUSE))
0240         ethtool_link_ksettings_add_link_mode(ks, supported, Asym_Pause);
0241 
0242     fun_link_modes_to_ethtool(fp->advertising, ks->link_modes.advertising);
0243     set_asym_pause(fp->advertising, ks);
0244     return 0;
0245 }
0246 
0247 static u64 fun_advert_modes(const struct ethtool_link_ksettings *ks)
0248 {
0249     u64 modes = 0;
0250 
0251 #define HAS_MODE(mode) \
0252     ethtool_link_ksettings_test_link_mode(ks, advertising, mode)
0253 
0254     if (HAS_MODE(1000baseX_Full))
0255         modes |= FUN_PORT_CAP_1000_X;
0256     if (HAS_MODE(10000baseCR_Full) || HAS_MODE(10000baseSR_Full) ||
0257         HAS_MODE(10000baseLR_Full) || HAS_MODE(10000baseER_Full))
0258         modes |= FUN_PORT_CAP_10G_R;
0259     if (HAS_MODE(25000baseCR_Full) || HAS_MODE(25000baseSR_Full))
0260         modes |= FUN_PORT_CAP_25G_R;
0261     if (HAS_MODE(40000baseCR4_Full) || HAS_MODE(40000baseSR4_Full) ||
0262         HAS_MODE(40000baseLR4_Full))
0263         modes |= FUN_PORT_CAP_40G_R4;
0264     if (HAS_MODE(50000baseCR2_Full) || HAS_MODE(50000baseSR2_Full))
0265         modes |= FUN_PORT_CAP_50G_R2;
0266     if (HAS_MODE(50000baseCR_Full) || HAS_MODE(50000baseSR_Full) ||
0267         HAS_MODE(50000baseLR_ER_FR_Full))
0268         modes |= FUN_PORT_CAP_50G_R;
0269     if (HAS_MODE(100000baseCR4_Full) || HAS_MODE(100000baseSR4_Full) ||
0270         HAS_MODE(100000baseLR4_ER4_Full))
0271         modes |= FUN_PORT_CAP_100G_R4;
0272     if (HAS_MODE(100000baseCR2_Full) || HAS_MODE(100000baseSR2_Full) ||
0273         HAS_MODE(100000baseLR2_ER2_FR2_Full))
0274         modes |= FUN_PORT_CAP_100G_R2;
0275 
0276     return modes;
0277 #undef HAS_MODE
0278 }
0279 
0280 static u64 fun_speed_to_link_mode(unsigned int speed)
0281 {
0282     switch (speed) {
0283     case SPEED_100000:
0284         return FUN_PORT_CAP_100G_R4 | FUN_PORT_CAP_100G_R2;
0285     case SPEED_50000:
0286         return FUN_PORT_CAP_50G_R | FUN_PORT_CAP_50G_R2;
0287     case SPEED_40000:
0288         return FUN_PORT_CAP_40G_R4;
0289     case SPEED_25000:
0290         return FUN_PORT_CAP_25G_R;
0291     case SPEED_10000:
0292         return FUN_PORT_CAP_10G_R;
0293     case SPEED_1000:
0294         return FUN_PORT_CAP_1000_X;
0295     default:
0296         return 0;
0297     }
0298 }
0299 
0300 static int fun_change_advert(struct funeth_priv *fp, u64 new_advert)
0301 {
0302     int err;
0303 
0304     if (new_advert == fp->advertising)
0305         return 0;
0306 
0307     err = fun_port_write_cmd(fp, FUN_ADMIN_PORT_KEY_ADVERT, new_advert);
0308     if (!err)
0309         fp->advertising = new_advert;
0310     return err;
0311 }
0312 
0313 #define FUN_PORT_CAP_FEC_MASK \
0314     (FUN_PORT_CAP_FEC_NONE | FUN_PORT_CAP_FEC_FC | FUN_PORT_CAP_FEC_RS)
0315 
0316 static int fun_set_link_ksettings(struct net_device *netdev,
0317                   const struct ethtool_link_ksettings *ks)
0318 {
0319     __ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = {};
0320     struct funeth_priv *fp = netdev_priv(netdev);
0321     u64 new_advert;
0322 
0323     /* eswitch ports don't support mode changes */
0324     if (fp->port_caps & FUN_PORT_CAP_VPORT)
0325         return -EOPNOTSUPP;
0326 
0327     if (ks->base.duplex == DUPLEX_HALF)
0328         return -EINVAL;
0329     if (ks->base.autoneg == AUTONEG_ENABLE &&
0330         !(fp->port_caps & FUN_PORT_CAP_AUTONEG))
0331         return -EINVAL;
0332 
0333     if (ks->base.autoneg == AUTONEG_ENABLE) {
0334         if (linkmode_empty(ks->link_modes.advertising))
0335             return -EINVAL;
0336 
0337         fun_link_modes_to_ethtool(fp->port_caps, supported);
0338         if (!linkmode_subset(ks->link_modes.advertising, supported))
0339             return -EINVAL;
0340 
0341         new_advert = fun_advert_modes(ks) | FUN_PORT_CAP_AUTONEG;
0342     } else {
0343         new_advert = fun_speed_to_link_mode(ks->base.speed);
0344         new_advert &= fp->port_caps;
0345         if (!new_advert)
0346             return -EINVAL;
0347     }
0348     new_advert |= fp->advertising &
0349               (FUN_PORT_CAP_PAUSE_MASK | FUN_PORT_CAP_FEC_MASK);
0350 
0351     return fun_change_advert(fp, new_advert);
0352 }
0353 
0354 static void fun_get_pauseparam(struct net_device *netdev,
0355                    struct ethtool_pauseparam *pause)
0356 {
0357     const struct funeth_priv *fp = netdev_priv(netdev);
0358     u8 active_pause = fp->active_fc;
0359 
0360     pause->rx_pause = !!(active_pause & FUN_PORT_CAP_RX_PAUSE);
0361     pause->tx_pause = !!(active_pause & FUN_PORT_CAP_TX_PAUSE);
0362     pause->autoneg = !!(fp->advertising & FUN_PORT_CAP_AUTONEG);
0363 }
0364 
0365 static int fun_set_pauseparam(struct net_device *netdev,
0366                   struct ethtool_pauseparam *pause)
0367 {
0368     struct funeth_priv *fp = netdev_priv(netdev);
0369     u64 new_advert;
0370 
0371     if (fp->port_caps & FUN_PORT_CAP_VPORT)
0372         return -EOPNOTSUPP;
0373     /* Forcing PAUSE settings with AN enabled is unsupported. */
0374     if (!pause->autoneg && (fp->advertising & FUN_PORT_CAP_AUTONEG))
0375         return -EOPNOTSUPP;
0376     if (pause->autoneg && !(fp->advertising & FUN_PORT_CAP_AUTONEG))
0377         return -EINVAL;
0378     if (pause->tx_pause && !(fp->port_caps & FUN_PORT_CAP_TX_PAUSE))
0379         return -EINVAL;
0380     if (pause->rx_pause && !(fp->port_caps & FUN_PORT_CAP_RX_PAUSE))
0381         return -EINVAL;
0382 
0383     new_advert = fp->advertising & ~FUN_PORT_CAP_PAUSE_MASK;
0384     if (pause->tx_pause)
0385         new_advert |= FUN_PORT_CAP_TX_PAUSE;
0386     if (pause->rx_pause)
0387         new_advert |= FUN_PORT_CAP_RX_PAUSE;
0388 
0389     return fun_change_advert(fp, new_advert);
0390 }
0391 
0392 static int fun_restart_an(struct net_device *netdev)
0393 {
0394     struct funeth_priv *fp = netdev_priv(netdev);
0395 
0396     if (!(fp->advertising & FUN_PORT_CAP_AUTONEG))
0397         return -EOPNOTSUPP;
0398 
0399     return fun_port_write_cmd(fp, FUN_ADMIN_PORT_KEY_ADVERT,
0400                   FUN_PORT_CAP_AUTONEG);
0401 }
0402 
0403 static int fun_set_phys_id(struct net_device *netdev,
0404                enum ethtool_phys_id_state state)
0405 {
0406     struct funeth_priv *fp = netdev_priv(netdev);
0407     unsigned int beacon;
0408 
0409     if (fp->port_caps & FUN_PORT_CAP_VPORT)
0410         return -EOPNOTSUPP;
0411     if (state != ETHTOOL_ID_ACTIVE && state != ETHTOOL_ID_INACTIVE)
0412         return -EOPNOTSUPP;
0413 
0414     beacon = state == ETHTOOL_ID_ACTIVE ? FUN_PORT_LED_BEACON_ON :
0415                           FUN_PORT_LED_BEACON_OFF;
0416     return fun_port_write_cmd(fp, FUN_ADMIN_PORT_KEY_LED, beacon);
0417 }
0418 
0419 static void fun_get_drvinfo(struct net_device *netdev,
0420                 struct ethtool_drvinfo *info)
0421 {
0422     const struct funeth_priv *fp = netdev_priv(netdev);
0423 
0424     strscpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
0425     strscpy(info->bus_info, pci_name(fp->pdev), sizeof(info->bus_info));
0426 }
0427 
0428 static u32 fun_get_msglevel(struct net_device *netdev)
0429 {
0430     const struct funeth_priv *fp = netdev_priv(netdev);
0431 
0432     return fp->msg_enable;
0433 }
0434 
0435 static void fun_set_msglevel(struct net_device *netdev, u32 value)
0436 {
0437     struct funeth_priv *fp = netdev_priv(netdev);
0438 
0439     fp->msg_enable = value;
0440 }
0441 
0442 static int fun_get_regs_len(struct net_device *dev)
0443 {
0444     return NVME_REG_ACQ + sizeof(u64);
0445 }
0446 
0447 static void fun_get_regs(struct net_device *dev, struct ethtool_regs *regs,
0448              void *buf)
0449 {
0450     const struct funeth_priv *fp = netdev_priv(dev);
0451     void __iomem *bar = fp->fdev->bar;
0452 
0453     regs->version = 0;
0454     *(u64 *)(buf + NVME_REG_CAP)   = readq(bar + NVME_REG_CAP);
0455     *(u32 *)(buf + NVME_REG_VS)    = readl(bar + NVME_REG_VS);
0456     *(u32 *)(buf + NVME_REG_INTMS) = readl(bar + NVME_REG_INTMS);
0457     *(u32 *)(buf + NVME_REG_INTMC) = readl(bar + NVME_REG_INTMC);
0458     *(u32 *)(buf + NVME_REG_CC)    = readl(bar + NVME_REG_CC);
0459     *(u32 *)(buf + NVME_REG_CSTS)  = readl(bar + NVME_REG_CSTS);
0460     *(u32 *)(buf + NVME_REG_AQA)   = readl(bar + NVME_REG_AQA);
0461     *(u64 *)(buf + NVME_REG_ASQ)   = readq(bar + NVME_REG_ASQ);
0462     *(u64 *)(buf + NVME_REG_ACQ)   = readq(bar + NVME_REG_ACQ);
0463 }
0464 
0465 static int fun_get_coalesce(struct net_device *netdev,
0466                 struct ethtool_coalesce *coal,
0467                 struct kernel_ethtool_coalesce *kcoal,
0468                 struct netlink_ext_ack *ext_ack)
0469 {
0470     const struct funeth_priv *fp = netdev_priv(netdev);
0471 
0472     coal->rx_coalesce_usecs        = fp->rx_coal_usec;
0473     coal->rx_max_coalesced_frames  = fp->rx_coal_count;
0474     coal->use_adaptive_rx_coalesce = !fp->cq_irq_db;
0475     coal->tx_coalesce_usecs        = fp->tx_coal_usec;
0476     coal->tx_max_coalesced_frames  = fp->tx_coal_count;
0477     return 0;
0478 }
0479 
0480 static int fun_set_coalesce(struct net_device *netdev,
0481                 struct ethtool_coalesce *coal,
0482                 struct kernel_ethtool_coalesce *kcoal,
0483                 struct netlink_ext_ack *ext_ack)
0484 {
0485     struct funeth_priv *fp = netdev_priv(netdev);
0486     struct funeth_rxq **rxqs;
0487     unsigned int i, db_val;
0488 
0489     if (coal->rx_coalesce_usecs > FUN_DB_INTCOAL_USEC_M ||
0490         coal->rx_max_coalesced_frames > FUN_DB_INTCOAL_ENTRIES_M ||
0491         (coal->rx_coalesce_usecs | coal->rx_max_coalesced_frames) == 0 ||
0492         coal->tx_coalesce_usecs > FUN_DB_INTCOAL_USEC_M ||
0493         coal->tx_max_coalesced_frames > FUN_DB_INTCOAL_ENTRIES_M ||
0494         (coal->tx_coalesce_usecs | coal->tx_max_coalesced_frames) == 0)
0495         return -EINVAL;
0496 
0497     /* a timer is required if there's any coalescing */
0498     if ((coal->rx_max_coalesced_frames > 1 && !coal->rx_coalesce_usecs) ||
0499         (coal->tx_max_coalesced_frames > 1 && !coal->tx_coalesce_usecs))
0500         return -EINVAL;
0501 
0502     fp->rx_coal_usec  = coal->rx_coalesce_usecs;
0503     fp->rx_coal_count = coal->rx_max_coalesced_frames;
0504     fp->tx_coal_usec  = coal->tx_coalesce_usecs;
0505     fp->tx_coal_count = coal->tx_max_coalesced_frames;
0506 
0507     db_val = FUN_IRQ_CQ_DB(fp->rx_coal_usec, fp->rx_coal_count);
0508     WRITE_ONCE(fp->cq_irq_db, db_val);
0509 
0510     rxqs = rtnl_dereference(fp->rxqs);
0511     if (!rxqs)
0512         return 0;
0513 
0514     for (i = 0; i < netdev->real_num_rx_queues; i++)
0515         WRITE_ONCE(rxqs[i]->irq_db_val, db_val);
0516 
0517     db_val = FUN_IRQ_SQ_DB(fp->tx_coal_usec, fp->tx_coal_count);
0518     for (i = 0; i < netdev->real_num_tx_queues; i++)
0519         WRITE_ONCE(fp->txqs[i]->irq_db_val, db_val);
0520 
0521     return 0;
0522 }
0523 
0524 static void fun_get_channels(struct net_device *netdev,
0525                  struct ethtool_channels *chan)
0526 {
0527     chan->max_rx   = netdev->num_rx_queues;
0528     chan->rx_count = netdev->real_num_rx_queues;
0529 
0530     chan->max_tx   = netdev->num_tx_queues;
0531     chan->tx_count = netdev->real_num_tx_queues;
0532 }
0533 
0534 static int fun_set_channels(struct net_device *netdev,
0535                 struct ethtool_channels *chan)
0536 {
0537     if (!chan->tx_count || !chan->rx_count)
0538         return -EINVAL;
0539 
0540     if (chan->tx_count == netdev->real_num_tx_queues &&
0541         chan->rx_count == netdev->real_num_rx_queues)
0542         return 0;
0543 
0544     if (netif_running(netdev))
0545         return fun_change_num_queues(netdev, chan->tx_count,
0546                          chan->rx_count);
0547 
0548     fun_set_ring_count(netdev, chan->tx_count, chan->rx_count);
0549     return 0;
0550 }
0551 
0552 static void fun_get_ringparam(struct net_device *netdev,
0553                   struct ethtool_ringparam *ring,
0554                   struct kernel_ethtool_ringparam *kring,
0555                   struct netlink_ext_ack *extack)
0556 {
0557     const struct funeth_priv *fp = netdev_priv(netdev);
0558     unsigned int max_depth = fp->fdev->q_depth;
0559 
0560     /* We size CQs to be twice the RQ depth so max RQ depth is half the
0561      * max queue depth.
0562      */
0563     ring->rx_max_pending = max_depth / 2;
0564     ring->tx_max_pending = max_depth;
0565 
0566     ring->rx_pending = fp->rq_depth;
0567     ring->tx_pending = fp->sq_depth;
0568 
0569     kring->rx_buf_len = PAGE_SIZE;
0570     kring->cqe_size = FUNETH_CQE_SIZE;
0571 }
0572 
0573 static int fun_set_ringparam(struct net_device *netdev,
0574                  struct ethtool_ringparam *ring,
0575                  struct kernel_ethtool_ringparam *kring,
0576                  struct netlink_ext_ack *extack)
0577 {
0578     struct funeth_priv *fp = netdev_priv(netdev);
0579     int rc;
0580 
0581     if (ring->rx_mini_pending || ring->rx_jumbo_pending)
0582         return -EINVAL;
0583 
0584     /* queue depths must be powers-of-2 */
0585     if (!is_power_of_2(ring->rx_pending) ||
0586         !is_power_of_2(ring->tx_pending))
0587         return -EINVAL;
0588 
0589     if (ring->rx_pending < FUNETH_MIN_QDEPTH ||
0590         ring->tx_pending < FUNETH_MIN_QDEPTH)
0591         return -EINVAL;
0592 
0593     if (fp->sq_depth == ring->tx_pending &&
0594         fp->rq_depth == ring->rx_pending)
0595         return 0;
0596 
0597     if (netif_running(netdev)) {
0598         struct fun_qset req = {
0599             .cq_depth = 2 * ring->rx_pending,
0600             .rq_depth = ring->rx_pending,
0601             .sq_depth = ring->tx_pending
0602         };
0603 
0604         rc = fun_replace_queues(netdev, &req, extack);
0605         if (rc)
0606             return rc;
0607     }
0608 
0609     fp->sq_depth = ring->tx_pending;
0610     fp->rq_depth = ring->rx_pending;
0611     fp->cq_depth = 2 * fp->rq_depth;
0612     return 0;
0613 }
0614 
0615 static int fun_get_sset_count(struct net_device *dev, int sset)
0616 {
0617     const struct funeth_priv *fp = netdev_priv(dev);
0618     int n;
0619 
0620     switch (sset) {
0621     case ETH_SS_STATS:
0622         n = (dev->real_num_tx_queues + 1) * ARRAY_SIZE(txq_stat_names) +
0623             (dev->real_num_rx_queues + 1) * ARRAY_SIZE(rxq_stat_names) +
0624             (fp->num_xdpqs + 1) * ARRAY_SIZE(xdpq_stat_names) +
0625             ARRAY_SIZE(tls_stat_names);
0626         if (fp->port_caps & FUN_PORT_CAP_STATS) {
0627             n += ARRAY_SIZE(mac_tx_stat_names) +
0628                  ARRAY_SIZE(mac_rx_stat_names);
0629         }
0630         return n;
0631     default:
0632         break;
0633     }
0634     return 0;
0635 }
0636 
0637 static void fun_get_strings(struct net_device *netdev, u32 sset, u8 *data)
0638 {
0639     const struct funeth_priv *fp = netdev_priv(netdev);
0640     unsigned int i, j;
0641     u8 *p = data;
0642 
0643     switch (sset) {
0644     case ETH_SS_STATS:
0645         if (fp->port_caps & FUN_PORT_CAP_STATS) {
0646             memcpy(p, mac_tx_stat_names, sizeof(mac_tx_stat_names));
0647             p += sizeof(mac_tx_stat_names);
0648             memcpy(p, mac_rx_stat_names, sizeof(mac_rx_stat_names));
0649             p += sizeof(mac_rx_stat_names);
0650         }
0651 
0652         for (i = 0; i < netdev->real_num_tx_queues; i++) {
0653             for (j = 0; j < ARRAY_SIZE(txq_stat_names); j++)
0654                 ethtool_sprintf(&p, "%s[%u]", txq_stat_names[j],
0655                         i);
0656         }
0657         for (j = 0; j < ARRAY_SIZE(txq_stat_names); j++)
0658             ethtool_sprintf(&p, txq_stat_names[j]);
0659 
0660         for (i = 0; i < fp->num_xdpqs; i++) {
0661             for (j = 0; j < ARRAY_SIZE(xdpq_stat_names); j++)
0662                 ethtool_sprintf(&p, "%s[%u]",
0663                         xdpq_stat_names[j], i);
0664         }
0665         for (j = 0; j < ARRAY_SIZE(xdpq_stat_names); j++)
0666             ethtool_sprintf(&p, xdpq_stat_names[j]);
0667 
0668         for (i = 0; i < netdev->real_num_rx_queues; i++) {
0669             for (j = 0; j < ARRAY_SIZE(rxq_stat_names); j++)
0670                 ethtool_sprintf(&p, "%s[%u]", rxq_stat_names[j],
0671                         i);
0672         }
0673         for (j = 0; j < ARRAY_SIZE(rxq_stat_names); j++)
0674             ethtool_sprintf(&p, rxq_stat_names[j]);
0675 
0676         for (j = 0; j < ARRAY_SIZE(tls_stat_names); j++)
0677             ethtool_sprintf(&p, tls_stat_names[j]);
0678         break;
0679     default:
0680         break;
0681     }
0682 }
0683 
0684 static u64 *get_mac_stats(const struct funeth_priv *fp, u64 *data)
0685 {
0686 #define TX_STAT(s) \
0687     *data++ = be64_to_cpu(fp->stats[PORT_MAC_RX_STATS_MAX + PORT_MAC_TX_##s])
0688 
0689     TX_STAT(etherStatsOctets);
0690     TX_STAT(etherStatsPkts);
0691     TX_STAT(VLANTransmittedOK);
0692     TX_STAT(ifOutUcastPkts);
0693     TX_STAT(ifOutMulticastPkts);
0694     TX_STAT(ifOutBroadcastPkts);
0695     TX_STAT(ifOutErrors);
0696     TX_STAT(CBFCPAUSEFramesTransmitted_0);
0697     TX_STAT(CBFCPAUSEFramesTransmitted_1);
0698     TX_STAT(CBFCPAUSEFramesTransmitted_2);
0699     TX_STAT(CBFCPAUSEFramesTransmitted_3);
0700     TX_STAT(CBFCPAUSEFramesTransmitted_4);
0701     TX_STAT(CBFCPAUSEFramesTransmitted_5);
0702     TX_STAT(CBFCPAUSEFramesTransmitted_6);
0703     TX_STAT(CBFCPAUSEFramesTransmitted_7);
0704     TX_STAT(CBFCPAUSEFramesTransmitted_8);
0705     TX_STAT(CBFCPAUSEFramesTransmitted_9);
0706     TX_STAT(CBFCPAUSEFramesTransmitted_10);
0707     TX_STAT(CBFCPAUSEFramesTransmitted_11);
0708     TX_STAT(CBFCPAUSEFramesTransmitted_12);
0709     TX_STAT(CBFCPAUSEFramesTransmitted_13);
0710     TX_STAT(CBFCPAUSEFramesTransmitted_14);
0711     TX_STAT(CBFCPAUSEFramesTransmitted_15);
0712 
0713 #define RX_STAT(s) *data++ = be64_to_cpu(fp->stats[PORT_MAC_RX_##s])
0714 
0715     RX_STAT(etherStatsOctets);
0716     RX_STAT(etherStatsPkts);
0717     RX_STAT(VLANReceivedOK);
0718     RX_STAT(ifInUcastPkts);
0719     RX_STAT(ifInMulticastPkts);
0720     RX_STAT(ifInBroadcastPkts);
0721     RX_STAT(etherStatsDropEvents);
0722     RX_STAT(ifInErrors);
0723     RX_STAT(aAlignmentErrors);
0724     RX_STAT(CBFCPAUSEFramesReceived_0);
0725     RX_STAT(CBFCPAUSEFramesReceived_1);
0726     RX_STAT(CBFCPAUSEFramesReceived_2);
0727     RX_STAT(CBFCPAUSEFramesReceived_3);
0728     RX_STAT(CBFCPAUSEFramesReceived_4);
0729     RX_STAT(CBFCPAUSEFramesReceived_5);
0730     RX_STAT(CBFCPAUSEFramesReceived_6);
0731     RX_STAT(CBFCPAUSEFramesReceived_7);
0732     RX_STAT(CBFCPAUSEFramesReceived_8);
0733     RX_STAT(CBFCPAUSEFramesReceived_9);
0734     RX_STAT(CBFCPAUSEFramesReceived_10);
0735     RX_STAT(CBFCPAUSEFramesReceived_11);
0736     RX_STAT(CBFCPAUSEFramesReceived_12);
0737     RX_STAT(CBFCPAUSEFramesReceived_13);
0738     RX_STAT(CBFCPAUSEFramesReceived_14);
0739     RX_STAT(CBFCPAUSEFramesReceived_15);
0740 
0741     return data;
0742 
0743 #undef TX_STAT
0744 #undef RX_STAT
0745 }
0746 
0747 static void fun_get_ethtool_stats(struct net_device *netdev,
0748                   struct ethtool_stats *stats, u64 *data)
0749 {
0750     const struct funeth_priv *fp = netdev_priv(netdev);
0751     struct funeth_txq_stats txs;
0752     struct funeth_rxq_stats rxs;
0753     struct funeth_txq **xdpqs;
0754     struct funeth_rxq **rxqs;
0755     unsigned int i, start;
0756     u64 *totals, *tot;
0757 
0758     if (fp->port_caps & FUN_PORT_CAP_STATS)
0759         data = get_mac_stats(fp, data);
0760 
0761     rxqs = rtnl_dereference(fp->rxqs);
0762     if (!rxqs)
0763         return;
0764 
0765 #define ADD_STAT(cnt) do { \
0766     *data = (cnt); *tot++ += *data++; \
0767 } while (0)
0768 
0769     /* Tx queues */
0770     totals = data + netdev->real_num_tx_queues * ARRAY_SIZE(txq_stat_names);
0771 
0772     for (i = 0; i < netdev->real_num_tx_queues; i++) {
0773         tot = totals;
0774 
0775         FUN_QSTAT_READ(fp->txqs[i], start, txs);
0776 
0777         ADD_STAT(txs.tx_pkts);
0778         ADD_STAT(txs.tx_bytes);
0779         ADD_STAT(txs.tx_cso);
0780         ADD_STAT(txs.tx_tso);
0781         ADD_STAT(txs.tx_encap_tso);
0782         ADD_STAT(txs.tx_uso);
0783         ADD_STAT(txs.tx_more);
0784         ADD_STAT(txs.tx_nstops);
0785         ADD_STAT(txs.tx_nrestarts);
0786         ADD_STAT(txs.tx_map_err);
0787         ADD_STAT(txs.tx_tls_pkts);
0788         ADD_STAT(txs.tx_tls_bytes);
0789         ADD_STAT(txs.tx_tls_fallback);
0790         ADD_STAT(txs.tx_tls_drops);
0791     }
0792     data += ARRAY_SIZE(txq_stat_names);
0793 
0794     /* XDP Tx queues */
0795     xdpqs = rtnl_dereference(fp->xdpqs);
0796     totals = data + fp->num_xdpqs * ARRAY_SIZE(xdpq_stat_names);
0797 
0798     for (i = 0; i < fp->num_xdpqs; i++) {
0799         tot = totals;
0800 
0801         FUN_QSTAT_READ(xdpqs[i], start, txs);
0802 
0803         ADD_STAT(txs.tx_pkts);
0804         ADD_STAT(txs.tx_bytes);
0805         ADD_STAT(txs.tx_xdp_full);
0806         ADD_STAT(txs.tx_map_err);
0807     }
0808     data += ARRAY_SIZE(xdpq_stat_names);
0809 
0810     /* Rx queues */
0811     totals = data + netdev->real_num_rx_queues * ARRAY_SIZE(rxq_stat_names);
0812 
0813     for (i = 0; i < netdev->real_num_rx_queues; i++) {
0814         tot = totals;
0815 
0816         FUN_QSTAT_READ(rxqs[i], start, rxs);
0817 
0818         ADD_STAT(rxs.rx_pkts);
0819         ADD_STAT(rxs.rx_bytes);
0820         ADD_STAT(rxs.rx_cso);
0821         ADD_STAT(rxs.gro_pkts);
0822         ADD_STAT(rxs.gro_merged);
0823         ADD_STAT(rxs.xdp_tx);
0824         ADD_STAT(rxs.xdp_redir);
0825         ADD_STAT(rxs.xdp_drops);
0826         ADD_STAT(rxs.rx_bufs);
0827         ADD_STAT(rxs.rx_page_alloc);
0828         ADD_STAT(rxs.rx_mem_drops + rxs.xdp_err);
0829         ADD_STAT(rxs.rx_budget);
0830         ADD_STAT(rxs.rx_map_err);
0831     }
0832     data += ARRAY_SIZE(rxq_stat_names);
0833 #undef ADD_STAT
0834 
0835     *data++ = atomic64_read(&fp->tx_tls_add);
0836     *data++ = atomic64_read(&fp->tx_tls_del);
0837     *data++ = atomic64_read(&fp->tx_tls_resync);
0838 }
0839 
0840 #define RX_STAT(fp, s) be64_to_cpu((fp)->stats[PORT_MAC_RX_##s])
0841 #define TX_STAT(fp, s) \
0842     be64_to_cpu((fp)->stats[PORT_MAC_RX_STATS_MAX + PORT_MAC_TX_##s])
0843 #define FEC_STAT(fp, s) \
0844     be64_to_cpu((fp)->stats[PORT_MAC_RX_STATS_MAX + \
0845                 PORT_MAC_TX_STATS_MAX + PORT_MAC_FEC_##s])
0846 
0847 static void fun_get_pause_stats(struct net_device *netdev,
0848                 struct ethtool_pause_stats *stats)
0849 {
0850     const struct funeth_priv *fp = netdev_priv(netdev);
0851 
0852     if (!(fp->port_caps & FUN_PORT_CAP_STATS))
0853         return;
0854 
0855     stats->tx_pause_frames = TX_STAT(fp, aPAUSEMACCtrlFramesTransmitted);
0856     stats->rx_pause_frames = RX_STAT(fp, aPAUSEMACCtrlFramesReceived);
0857 }
0858 
0859 static void fun_get_802_3_stats(struct net_device *netdev,
0860                 struct ethtool_eth_mac_stats *stats)
0861 {
0862     const struct funeth_priv *fp = netdev_priv(netdev);
0863 
0864     if (!(fp->port_caps & FUN_PORT_CAP_STATS))
0865         return;
0866 
0867     stats->FramesTransmittedOK = TX_STAT(fp, aFramesTransmittedOK);
0868     stats->FramesReceivedOK = RX_STAT(fp, aFramesReceivedOK);
0869     stats->FrameCheckSequenceErrors = RX_STAT(fp, aFrameCheckSequenceErrors);
0870     stats->OctetsTransmittedOK = TX_STAT(fp, OctetsTransmittedOK);
0871     stats->OctetsReceivedOK = RX_STAT(fp, OctetsReceivedOK);
0872     stats->InRangeLengthErrors = RX_STAT(fp, aInRangeLengthErrors);
0873     stats->FrameTooLongErrors = RX_STAT(fp, aFrameTooLongErrors);
0874 }
0875 
0876 static void fun_get_802_3_ctrl_stats(struct net_device *netdev,
0877                      struct ethtool_eth_ctrl_stats *stats)
0878 {
0879     const struct funeth_priv *fp = netdev_priv(netdev);
0880 
0881     if (!(fp->port_caps & FUN_PORT_CAP_STATS))
0882         return;
0883 
0884     stats->MACControlFramesTransmitted = TX_STAT(fp, MACControlFramesTransmitted);
0885     stats->MACControlFramesReceived = RX_STAT(fp, MACControlFramesReceived);
0886 }
0887 
0888 static void fun_get_rmon_stats(struct net_device *netdev,
0889                    struct ethtool_rmon_stats *stats,
0890                    const struct ethtool_rmon_hist_range **ranges)
0891 {
0892     static const struct ethtool_rmon_hist_range rmon_ranges[] = {
0893         {   64,    64 },
0894         {   65,   127 },
0895         {  128,   255 },
0896         {  256,   511 },
0897         {  512,  1023 },
0898         { 1024,  1518 },
0899         { 1519, 32767 },
0900         {}
0901     };
0902 
0903     const struct funeth_priv *fp = netdev_priv(netdev);
0904 
0905     if (!(fp->port_caps & FUN_PORT_CAP_STATS))
0906         return;
0907 
0908     stats->undersize_pkts = RX_STAT(fp, etherStatsUndersizePkts);
0909     stats->oversize_pkts = RX_STAT(fp, etherStatsOversizePkts);
0910     stats->fragments = RX_STAT(fp, etherStatsFragments);
0911     stats->jabbers = RX_STAT(fp, etherStatsJabbers);
0912 
0913     stats->hist[0] = RX_STAT(fp, etherStatsPkts64Octets);
0914     stats->hist[1] = RX_STAT(fp, etherStatsPkts65to127Octets);
0915     stats->hist[2] = RX_STAT(fp, etherStatsPkts128to255Octets);
0916     stats->hist[3] = RX_STAT(fp, etherStatsPkts256to511Octets);
0917     stats->hist[4] = RX_STAT(fp, etherStatsPkts512to1023Octets);
0918     stats->hist[5] = RX_STAT(fp, etherStatsPkts1024to1518Octets);
0919     stats->hist[6] = RX_STAT(fp, etherStatsPkts1519toMaxOctets);
0920 
0921     stats->hist_tx[0] = TX_STAT(fp, etherStatsPkts64Octets);
0922     stats->hist_tx[1] = TX_STAT(fp, etherStatsPkts65to127Octets);
0923     stats->hist_tx[2] = TX_STAT(fp, etherStatsPkts128to255Octets);
0924     stats->hist_tx[3] = TX_STAT(fp, etherStatsPkts256to511Octets);
0925     stats->hist_tx[4] = TX_STAT(fp, etherStatsPkts512to1023Octets);
0926     stats->hist_tx[5] = TX_STAT(fp, etherStatsPkts1024to1518Octets);
0927     stats->hist_tx[6] = TX_STAT(fp, etherStatsPkts1519toMaxOctets);
0928 
0929     *ranges = rmon_ranges;
0930 }
0931 
0932 static void fun_get_fec_stats(struct net_device *netdev,
0933                   struct ethtool_fec_stats *stats)
0934 {
0935     const struct funeth_priv *fp = netdev_priv(netdev);
0936 
0937     if (!(fp->port_caps & FUN_PORT_CAP_STATS))
0938         return;
0939 
0940     stats->corrected_blocks.total = FEC_STAT(fp, Correctable);
0941     stats->uncorrectable_blocks.total = FEC_STAT(fp, Uncorrectable);
0942 }
0943 
0944 #undef RX_STAT
0945 #undef TX_STAT
0946 #undef FEC_STAT
0947 
0948 static int fun_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
0949              u32 *rule_locs)
0950 {
0951     switch (cmd->cmd) {
0952     case ETHTOOL_GRXRINGS:
0953         cmd->data = netdev->real_num_rx_queues;
0954         return 0;
0955     default:
0956         break;
0957     }
0958     return -EOPNOTSUPP;
0959 }
0960 
0961 static int fun_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *info)
0962 {
0963     return 0;
0964 }
0965 
0966 static u32 fun_get_rxfh_indir_size(struct net_device *netdev)
0967 {
0968     const struct funeth_priv *fp = netdev_priv(netdev);
0969 
0970     return fp->indir_table_nentries;
0971 }
0972 
0973 static u32 fun_get_rxfh_key_size(struct net_device *netdev)
0974 {
0975     const struct funeth_priv *fp = netdev_priv(netdev);
0976 
0977     return sizeof(fp->rss_key);
0978 }
0979 
0980 static int fun_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
0981             u8 *hfunc)
0982 {
0983     const struct funeth_priv *fp = netdev_priv(netdev);
0984 
0985     if (!fp->rss_cfg)
0986         return -EOPNOTSUPP;
0987 
0988     if (indir)
0989         memcpy(indir, fp->indir_table,
0990                sizeof(u32) * fp->indir_table_nentries);
0991 
0992     if (key)
0993         memcpy(key, fp->rss_key, sizeof(fp->rss_key));
0994 
0995     if (hfunc)
0996         *hfunc = fp->hash_algo == FUN_ETH_RSS_ALG_TOEPLITZ ?
0997                 ETH_RSS_HASH_TOP : ETH_RSS_HASH_CRC32;
0998 
0999     return 0;
1000 }
1001 
1002 static int fun_set_rxfh(struct net_device *netdev, const u32 *indir,
1003             const u8 *key, const u8 hfunc)
1004 {
1005     struct funeth_priv *fp = netdev_priv(netdev);
1006     const u32 *rss_indir = indir ? indir : fp->indir_table;
1007     const u8 *rss_key = key ? key : fp->rss_key;
1008     enum fun_eth_hash_alg algo;
1009 
1010     if (!fp->rss_cfg)
1011         return -EOPNOTSUPP;
1012 
1013     if (hfunc == ETH_RSS_HASH_NO_CHANGE)
1014         algo = fp->hash_algo;
1015     else if (hfunc == ETH_RSS_HASH_CRC32)
1016         algo = FUN_ETH_RSS_ALG_CRC32;
1017     else if (hfunc == ETH_RSS_HASH_TOP)
1018         algo = FUN_ETH_RSS_ALG_TOEPLITZ;
1019     else
1020         return -EINVAL;
1021 
1022     /* If the port is enabled try to reconfigure RSS and keep the new
1023      * settings if successful. If it is down we update the RSS settings
1024      * and apply them at the next UP time.
1025      */
1026     if (netif_running(netdev)) {
1027         int rc = fun_config_rss(netdev, algo, rss_key, rss_indir,
1028                     FUN_ADMIN_SUBOP_MODIFY);
1029         if (rc)
1030             return rc;
1031     }
1032 
1033     fp->hash_algo = algo;
1034     if (key)
1035         memcpy(fp->rss_key, key, sizeof(fp->rss_key));
1036     if (indir)
1037         memcpy(fp->indir_table, indir,
1038                sizeof(u32) * fp->indir_table_nentries);
1039     return 0;
1040 }
1041 
1042 static int fun_get_ts_info(struct net_device *netdev,
1043                struct ethtool_ts_info *info)
1044 {
1045     info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE |
1046                 SOF_TIMESTAMPING_RX_HARDWARE |
1047                 SOF_TIMESTAMPING_TX_SOFTWARE |
1048                 SOF_TIMESTAMPING_SOFTWARE |
1049                 SOF_TIMESTAMPING_RAW_HARDWARE;
1050     info->phc_index = -1;
1051     info->tx_types = BIT(HWTSTAMP_TX_OFF);
1052     info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | BIT(HWTSTAMP_FILTER_ALL);
1053     return 0;
1054 }
1055 
1056 static unsigned int to_ethtool_fec(unsigned int fun_fec)
1057 {
1058     unsigned int fec = 0;
1059 
1060     if (fun_fec == FUN_PORT_FEC_NA)
1061         fec |= ETHTOOL_FEC_NONE;
1062     if (fun_fec & FUN_PORT_FEC_OFF)
1063         fec |= ETHTOOL_FEC_OFF;
1064     if (fun_fec & FUN_PORT_FEC_RS)
1065         fec |= ETHTOOL_FEC_RS;
1066     if (fun_fec & FUN_PORT_FEC_FC)
1067         fec |= ETHTOOL_FEC_BASER;
1068     if (fun_fec & FUN_PORT_FEC_AUTO)
1069         fec |= ETHTOOL_FEC_AUTO;
1070     return fec;
1071 }
1072 
1073 static int fun_get_fecparam(struct net_device *netdev,
1074                 struct ethtool_fecparam *fec)
1075 {
1076     struct funeth_priv *fp = netdev_priv(netdev);
1077     u64 fec_data;
1078     int rc;
1079 
1080     rc = fun_port_read_cmd(fp, FUN_ADMIN_PORT_KEY_FEC, &fec_data);
1081     if (rc)
1082         return rc;
1083 
1084     fec->active_fec = to_ethtool_fec(fec_data & 0xff);
1085     fec->fec = to_ethtool_fec(fec_data >> 8);
1086     return 0;
1087 }
1088 
1089 static int fun_set_fecparam(struct net_device *netdev,
1090                 struct ethtool_fecparam *fec)
1091 {
1092     struct funeth_priv *fp = netdev_priv(netdev);
1093     u64 fec_mode;
1094 
1095     switch (fec->fec) {
1096     case ETHTOOL_FEC_AUTO:
1097         fec_mode = FUN_PORT_FEC_AUTO;
1098         break;
1099     case ETHTOOL_FEC_OFF:
1100         if (!(fp->port_caps & FUN_PORT_CAP_FEC_NONE))
1101             return -EINVAL;
1102         fec_mode = FUN_PORT_FEC_OFF;
1103         break;
1104     case ETHTOOL_FEC_BASER:
1105         if (!(fp->port_caps & FUN_PORT_CAP_FEC_FC))
1106             return -EINVAL;
1107         fec_mode = FUN_PORT_FEC_FC;
1108         break;
1109     case ETHTOOL_FEC_RS:
1110         if (!(fp->port_caps & FUN_PORT_CAP_FEC_RS))
1111             return -EINVAL;
1112         fec_mode = FUN_PORT_FEC_RS;
1113         break;
1114     default:
1115         return -EINVAL;
1116     }
1117 
1118     return fun_port_write_cmd(fp, FUN_ADMIN_PORT_KEY_FEC, fec_mode);
1119 }
1120 
1121 static int fun_get_port_module_page(struct net_device *netdev,
1122                     const struct ethtool_module_eeprom *req,
1123                     struct netlink_ext_ack *extack)
1124 {
1125     union {
1126         struct fun_admin_port_req req;
1127         struct fun_admin_port_xcvr_read_rsp rsp;
1128     } cmd;
1129     struct funeth_priv *fp = netdev_priv(netdev);
1130     int rc;
1131 
1132     if (fp->port_caps & FUN_PORT_CAP_VPORT) {
1133         NL_SET_ERR_MSG_MOD(extack,
1134                    "Specified port is virtual, only physical ports have modules");
1135         return -EOPNOTSUPP;
1136     }
1137 
1138     cmd.req.common = FUN_ADMIN_REQ_COMMON_INIT2(FUN_ADMIN_OP_PORT,
1139                             sizeof(cmd.req));
1140     cmd.req.u.xcvr_read =
1141         FUN_ADMIN_PORT_XCVR_READ_REQ_INIT(0, netdev->dev_port,
1142                           req->bank, req->page,
1143                           req->offset, req->length,
1144                           req->i2c_address);
1145     rc = fun_submit_admin_sync_cmd(fp->fdev, &cmd.req.common, &cmd.rsp,
1146                        sizeof(cmd.rsp), 0);
1147     if (rc)
1148         return rc;
1149 
1150     memcpy(req->data, cmd.rsp.data, req->length);
1151     return req->length;
1152 }
1153 
1154 static const struct ethtool_ops fun_ethtool_ops = {
1155     .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
1156                      ETHTOOL_COALESCE_MAX_FRAMES,
1157     .get_link_ksettings  = fun_get_link_ksettings,
1158     .set_link_ksettings  = fun_set_link_ksettings,
1159     .set_phys_id         = fun_set_phys_id,
1160     .get_drvinfo         = fun_get_drvinfo,
1161     .get_msglevel        = fun_get_msglevel,
1162     .set_msglevel        = fun_set_msglevel,
1163     .get_regs_len        = fun_get_regs_len,
1164     .get_regs            = fun_get_regs,
1165     .get_link        = ethtool_op_get_link,
1166     .get_coalesce        = fun_get_coalesce,
1167     .set_coalesce        = fun_set_coalesce,
1168     .get_ts_info         = fun_get_ts_info,
1169     .get_ringparam       = fun_get_ringparam,
1170     .set_ringparam       = fun_set_ringparam,
1171     .get_sset_count      = fun_get_sset_count,
1172     .get_strings         = fun_get_strings,
1173     .get_ethtool_stats   = fun_get_ethtool_stats,
1174     .get_rxnfc       = fun_get_rxnfc,
1175     .set_rxnfc           = fun_set_rxnfc,
1176     .get_rxfh_indir_size = fun_get_rxfh_indir_size,
1177     .get_rxfh_key_size   = fun_get_rxfh_key_size,
1178     .get_rxfh            = fun_get_rxfh,
1179     .set_rxfh            = fun_set_rxfh,
1180     .get_channels        = fun_get_channels,
1181     .set_channels        = fun_set_channels,
1182     .get_fecparam        = fun_get_fecparam,
1183     .set_fecparam        = fun_set_fecparam,
1184     .get_pauseparam      = fun_get_pauseparam,
1185     .set_pauseparam      = fun_set_pauseparam,
1186     .nway_reset          = fun_restart_an,
1187     .get_pause_stats     = fun_get_pause_stats,
1188     .get_fec_stats       = fun_get_fec_stats,
1189     .get_eth_mac_stats   = fun_get_802_3_stats,
1190     .get_eth_ctrl_stats  = fun_get_802_3_ctrl_stats,
1191     .get_rmon_stats      = fun_get_rmon_stats,
1192     .get_module_eeprom_by_page = fun_get_port_module_page,
1193 };
1194 
1195 void fun_set_ethtool_ops(struct net_device *netdev)
1196 {
1197     netdev->ethtool_ops = &fun_ethtool_ops;
1198 }