Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (c) 2007 Freescale Semiconductor, Inc. All rights reserved.
0004  *
0005  * Description: QE UCC Gigabit Ethernet Ethtool API Set
0006  *
0007  * Author: Li Yang <leoli@freescale.com>
0008  *
0009  * Limitation:
0010  * Can only get/set settings of the first queue.
0011  * Need to re-open the interface manually after changing some parameters.
0012  */
0013 
0014 #include <linux/kernel.h>
0015 #include <linux/errno.h>
0016 #include <linux/stddef.h>
0017 #include <linux/interrupt.h>
0018 #include <linux/netdevice.h>
0019 #include <linux/etherdevice.h>
0020 #include <linux/skbuff.h>
0021 #include <linux/spinlock.h>
0022 #include <linux/mm.h>
0023 #include <linux/delay.h>
0024 #include <linux/dma-mapping.h>
0025 #include <linux/ethtool.h>
0026 #include <linux/mii.h>
0027 #include <linux/phy.h>
0028 
0029 #include <asm/io.h>
0030 #include <asm/irq.h>
0031 #include <linux/uaccess.h>
0032 #include <asm/types.h>
0033 
0034 #include "ucc_geth.h"
0035 
0036 static const char hw_stat_gstrings[][ETH_GSTRING_LEN] = {
0037     "tx-64-frames",
0038     "tx-65-127-frames",
0039     "tx-128-255-frames",
0040     "rx-64-frames",
0041     "rx-65-127-frames",
0042     "rx-128-255-frames",
0043     "tx-bytes-ok",
0044     "tx-pause-frames",
0045     "tx-multicast-frames",
0046     "tx-broadcast-frames",
0047     "rx-frames",
0048     "rx-bytes-ok",
0049     "rx-bytes-all",
0050     "rx-multicast-frames",
0051     "rx-broadcast-frames",
0052     "stats-counter-carry",
0053     "stats-counter-mask",
0054     "rx-dropped-frames",
0055 };
0056 
0057 static const char tx_fw_stat_gstrings[][ETH_GSTRING_LEN] = {
0058     "tx-single-collision",
0059     "tx-multiple-collision",
0060     "tx-late-collision",
0061     "tx-aborted-frames",
0062     "tx-lost-frames",
0063     "tx-carrier-sense-errors",
0064     "tx-frames-ok",
0065     "tx-excessive-differ-frames",
0066     "tx-256-511-frames",
0067     "tx-512-1023-frames",
0068     "tx-1024-1518-frames",
0069     "tx-jumbo-frames",
0070 };
0071 
0072 static const char rx_fw_stat_gstrings[][ETH_GSTRING_LEN] = {
0073     "rx-crc-errors",
0074     "rx-alignment-errors",
0075     "rx-in-range-length-errors",
0076     "rx-out-of-range-length-errors",
0077     "rx-too-long-frames",
0078     "rx-runt",
0079     "rx-very-long-event",
0080     "rx-symbol-errors",
0081     "rx-busy-drop-frames",
0082     "reserved",
0083     "reserved",
0084     "rx-mismatch-drop-frames",
0085     "rx-small-than-64",
0086     "rx-256-511-frames",
0087     "rx-512-1023-frames",
0088     "rx-1024-1518-frames",
0089     "rx-jumbo-frames",
0090     "rx-mac-error-loss",
0091     "rx-pause-frames",
0092     "reserved",
0093     "rx-vlan-removed",
0094     "rx-vlan-replaced",
0095     "rx-vlan-inserted",
0096     "rx-ip-checksum-errors",
0097 };
0098 
0099 #define UEC_HW_STATS_LEN ARRAY_SIZE(hw_stat_gstrings)
0100 #define UEC_TX_FW_STATS_LEN ARRAY_SIZE(tx_fw_stat_gstrings)
0101 #define UEC_RX_FW_STATS_LEN ARRAY_SIZE(rx_fw_stat_gstrings)
0102 
0103 static int
0104 uec_get_ksettings(struct net_device *netdev, struct ethtool_link_ksettings *cmd)
0105 {
0106     struct ucc_geth_private *ugeth = netdev_priv(netdev);
0107     struct phy_device *phydev = ugeth->phydev;
0108 
0109     if (!phydev)
0110         return -ENODEV;
0111 
0112     phy_ethtool_ksettings_get(phydev, cmd);
0113 
0114     return 0;
0115 }
0116 
0117 static int
0118 uec_set_ksettings(struct net_device *netdev,
0119           const struct ethtool_link_ksettings *cmd)
0120 {
0121     struct ucc_geth_private *ugeth = netdev_priv(netdev);
0122     struct phy_device *phydev = ugeth->phydev;
0123 
0124     if (!phydev)
0125         return -ENODEV;
0126 
0127     return phy_ethtool_ksettings_set(phydev, cmd);
0128 }
0129 
0130 static void
0131 uec_get_pauseparam(struct net_device *netdev,
0132                      struct ethtool_pauseparam *pause)
0133 {
0134     struct ucc_geth_private *ugeth = netdev_priv(netdev);
0135 
0136     pause->autoneg = ugeth->phydev->autoneg;
0137 
0138     if (ugeth->ug_info->receiveFlowControl)
0139         pause->rx_pause = 1;
0140     if (ugeth->ug_info->transmitFlowControl)
0141         pause->tx_pause = 1;
0142 }
0143 
0144 static int
0145 uec_set_pauseparam(struct net_device *netdev,
0146                      struct ethtool_pauseparam *pause)
0147 {
0148     struct ucc_geth_private *ugeth = netdev_priv(netdev);
0149     int ret = 0;
0150 
0151     ugeth->ug_info->receiveFlowControl = pause->rx_pause;
0152     ugeth->ug_info->transmitFlowControl = pause->tx_pause;
0153 
0154     if (ugeth->phydev->autoneg) {
0155         if (netif_running(netdev)) {
0156             /* FIXME: automatically restart */
0157             netdev_info(netdev, "Please re-open the interface\n");
0158         }
0159     } else {
0160         struct ucc_geth_info *ug_info = ugeth->ug_info;
0161 
0162         ret = init_flow_control_params(ug_info->aufc,
0163                     ug_info->receiveFlowControl,
0164                     ug_info->transmitFlowControl,
0165                     ug_info->pausePeriod,
0166                     ug_info->extensionField,
0167                     &ugeth->uccf->uf_regs->upsmr,
0168                     &ugeth->ug_regs->uempr,
0169                     &ugeth->ug_regs->maccfg1);
0170     }
0171 
0172     return ret;
0173 }
0174 
0175 static uint32_t
0176 uec_get_msglevel(struct net_device *netdev)
0177 {
0178     struct ucc_geth_private *ugeth = netdev_priv(netdev);
0179     return ugeth->msg_enable;
0180 }
0181 
0182 static void
0183 uec_set_msglevel(struct net_device *netdev, uint32_t data)
0184 {
0185     struct ucc_geth_private *ugeth = netdev_priv(netdev);
0186     ugeth->msg_enable = data;
0187 }
0188 
0189 static int
0190 uec_get_regs_len(struct net_device *netdev)
0191 {
0192     return sizeof(struct ucc_geth);
0193 }
0194 
0195 static void
0196 uec_get_regs(struct net_device *netdev,
0197                struct ethtool_regs *regs, void *p)
0198 {
0199     int i;
0200     struct ucc_geth_private *ugeth = netdev_priv(netdev);
0201     u32 __iomem *ug_regs = (u32 __iomem *)ugeth->ug_regs;
0202     u32 *buff = p;
0203 
0204     for (i = 0; i < sizeof(struct ucc_geth) / sizeof(u32); i++)
0205         buff[i] = in_be32(&ug_regs[i]);
0206 }
0207 
0208 static void
0209 uec_get_ringparam(struct net_device *netdev,
0210           struct ethtool_ringparam *ring,
0211           struct kernel_ethtool_ringparam *kernel_ring,
0212           struct netlink_ext_ack *extack)
0213 {
0214     struct ucc_geth_private *ugeth = netdev_priv(netdev);
0215     struct ucc_geth_info *ug_info = ugeth->ug_info;
0216     int queue = 0;
0217 
0218     ring->rx_max_pending = UCC_GETH_BD_RING_SIZE_MAX;
0219     ring->rx_mini_max_pending = UCC_GETH_BD_RING_SIZE_MAX;
0220     ring->rx_jumbo_max_pending = UCC_GETH_BD_RING_SIZE_MAX;
0221     ring->tx_max_pending = UCC_GETH_BD_RING_SIZE_MAX;
0222 
0223     ring->rx_pending = ug_info->bdRingLenRx[queue];
0224     ring->rx_mini_pending = ug_info->bdRingLenRx[queue];
0225     ring->rx_jumbo_pending = ug_info->bdRingLenRx[queue];
0226     ring->tx_pending = ug_info->bdRingLenTx[queue];
0227 }
0228 
0229 static int
0230 uec_set_ringparam(struct net_device *netdev,
0231           struct ethtool_ringparam *ring,
0232           struct kernel_ethtool_ringparam *kernel_ring,
0233           struct netlink_ext_ack *extack)
0234 {
0235     struct ucc_geth_private *ugeth = netdev_priv(netdev);
0236     struct ucc_geth_info *ug_info = ugeth->ug_info;
0237     int queue = 0, ret = 0;
0238 
0239     if (ring->rx_pending < UCC_GETH_RX_BD_RING_SIZE_MIN) {
0240         netdev_info(netdev, "RxBD ring size must be no smaller than %d\n",
0241                 UCC_GETH_RX_BD_RING_SIZE_MIN);
0242         return -EINVAL;
0243     }
0244     if (ring->rx_pending % UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT) {
0245         netdev_info(netdev, "RxBD ring size must be multiple of %d\n",
0246                 UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT);
0247         return -EINVAL;
0248     }
0249     if (ring->tx_pending < UCC_GETH_TX_BD_RING_SIZE_MIN) {
0250         netdev_info(netdev, "TxBD ring size must be no smaller than %d\n",
0251                 UCC_GETH_TX_BD_RING_SIZE_MIN);
0252         return -EINVAL;
0253     }
0254 
0255     if (netif_running(netdev))
0256         return -EBUSY;
0257 
0258     ug_info->bdRingLenRx[queue] = ring->rx_pending;
0259     ug_info->bdRingLenTx[queue] = ring->tx_pending;
0260 
0261     return ret;
0262 }
0263 
0264 static int uec_get_sset_count(struct net_device *netdev, int sset)
0265 {
0266     struct ucc_geth_private *ugeth = netdev_priv(netdev);
0267     u32 stats_mode = ugeth->ug_info->statisticsMode;
0268     int len = 0;
0269 
0270     switch (sset) {
0271     case ETH_SS_STATS:
0272         if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE)
0273             len += UEC_HW_STATS_LEN;
0274         if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX)
0275             len += UEC_TX_FW_STATS_LEN;
0276         if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX)
0277             len += UEC_RX_FW_STATS_LEN;
0278 
0279         return len;
0280 
0281     default:
0282         return -EOPNOTSUPP;
0283     }
0284 }
0285 
0286 static void uec_get_strings(struct net_device *netdev, u32 stringset, u8 *buf)
0287 {
0288     struct ucc_geth_private *ugeth = netdev_priv(netdev);
0289     u32 stats_mode = ugeth->ug_info->statisticsMode;
0290 
0291     if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE) {
0292         memcpy(buf, hw_stat_gstrings, UEC_HW_STATS_LEN *
0293                     ETH_GSTRING_LEN);
0294         buf += UEC_HW_STATS_LEN * ETH_GSTRING_LEN;
0295     }
0296     if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) {
0297         memcpy(buf, tx_fw_stat_gstrings, UEC_TX_FW_STATS_LEN *
0298                     ETH_GSTRING_LEN);
0299         buf += UEC_TX_FW_STATS_LEN * ETH_GSTRING_LEN;
0300     }
0301     if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX)
0302         memcpy(buf, rx_fw_stat_gstrings, UEC_RX_FW_STATS_LEN *
0303                     ETH_GSTRING_LEN);
0304 }
0305 
0306 static void uec_get_ethtool_stats(struct net_device *netdev,
0307         struct ethtool_stats *stats, uint64_t *data)
0308 {
0309     struct ucc_geth_private *ugeth = netdev_priv(netdev);
0310     u32 stats_mode = ugeth->ug_info->statisticsMode;
0311     u32 __iomem *base;
0312     int i, j = 0;
0313 
0314     if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE) {
0315         if (ugeth->ug_regs)
0316             base = (u32 __iomem *)&ugeth->ug_regs->tx64;
0317         else
0318             base = NULL;
0319 
0320         for (i = 0; i < UEC_HW_STATS_LEN; i++)
0321             data[j++] = base ? in_be32(&base[i]) : 0;
0322     }
0323     if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) {
0324         base = (u32 __iomem *)ugeth->p_tx_fw_statistics_pram;
0325         for (i = 0; i < UEC_TX_FW_STATS_LEN; i++)
0326             data[j++] = base ? in_be32(&base[i]) : 0;
0327     }
0328     if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX) {
0329         base = (u32 __iomem *)ugeth->p_rx_fw_statistics_pram;
0330         for (i = 0; i < UEC_RX_FW_STATS_LEN; i++)
0331             data[j++] = base ? in_be32(&base[i]) : 0;
0332     }
0333 }
0334 
0335 /* Report driver information */
0336 static void
0337 uec_get_drvinfo(struct net_device *netdev,
0338                        struct ethtool_drvinfo *drvinfo)
0339 {
0340     strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
0341     strlcpy(drvinfo->bus_info, "QUICC ENGINE", sizeof(drvinfo->bus_info));
0342 }
0343 
0344 #ifdef CONFIG_PM
0345 
0346 static void uec_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
0347 {
0348     struct ucc_geth_private *ugeth = netdev_priv(netdev);
0349     struct phy_device *phydev = ugeth->phydev;
0350 
0351     if (phydev && phydev->irq)
0352         wol->supported |= WAKE_PHY;
0353     if (qe_alive_during_sleep())
0354         wol->supported |= WAKE_MAGIC;
0355 
0356     wol->wolopts = ugeth->wol_en;
0357 }
0358 
0359 static int uec_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
0360 {
0361     struct ucc_geth_private *ugeth = netdev_priv(netdev);
0362     struct phy_device *phydev = ugeth->phydev;
0363 
0364     if (wol->wolopts & ~(WAKE_PHY | WAKE_MAGIC))
0365         return -EINVAL;
0366     else if (wol->wolopts & WAKE_PHY && (!phydev || !phydev->irq))
0367         return -EINVAL;
0368     else if (wol->wolopts & WAKE_MAGIC && !qe_alive_during_sleep())
0369         return -EINVAL;
0370 
0371     ugeth->wol_en = wol->wolopts;
0372     device_set_wakeup_enable(&netdev->dev, ugeth->wol_en);
0373 
0374     return 0;
0375 }
0376 
0377 #else
0378 #define uec_get_wol NULL
0379 #define uec_set_wol NULL
0380 #endif /* CONFIG_PM */
0381 
0382 static const struct ethtool_ops uec_ethtool_ops = {
0383     .get_drvinfo            = uec_get_drvinfo,
0384     .get_regs_len           = uec_get_regs_len,
0385     .get_regs               = uec_get_regs,
0386     .get_msglevel           = uec_get_msglevel,
0387     .set_msglevel           = uec_set_msglevel,
0388     .nway_reset             = phy_ethtool_nway_reset,
0389     .get_link               = ethtool_op_get_link,
0390     .get_ringparam          = uec_get_ringparam,
0391     .set_ringparam          = uec_set_ringparam,
0392     .get_pauseparam         = uec_get_pauseparam,
0393     .set_pauseparam         = uec_set_pauseparam,
0394     .get_sset_count     = uec_get_sset_count,
0395     .get_strings            = uec_get_strings,
0396     .get_ethtool_stats      = uec_get_ethtool_stats,
0397     .get_wol        = uec_get_wol,
0398     .set_wol        = uec_set_wol,
0399     .get_ts_info        = ethtool_op_get_ts_info,
0400     .get_link_ksettings = uec_get_ksettings,
0401     .set_link_ksettings = uec_set_ksettings,
0402 };
0403 
0404 void uec_set_ethtool_ops(struct net_device *netdev)
0405 {
0406     netdev->ethtool_ops = &uec_ethtool_ops;
0407 }