Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 1999 - 2010 Intel Corporation.
0004  * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
0005  *
0006  * This code was derived from the Intel e1000e Linux driver.
0007  */
0008 #include "pch_gbe.h"
0009 #include "pch_gbe_phy.h"
0010 
0011 static const char pch_driver_version[] = "1.01";
0012 
0013 /*
0014  * pch_gbe_stats - Stats item information
0015  */
0016 struct pch_gbe_stats {
0017     char string[ETH_GSTRING_LEN];
0018     size_t size;
0019     size_t offset;
0020 };
0021 
0022 #define PCH_GBE_STAT(m)                     \
0023 {                               \
0024     .string = #m,                       \
0025     .size = sizeof_field(struct pch_gbe_hw_stats, m),   \
0026     .offset = offsetof(struct pch_gbe_hw_stats, m),     \
0027 }
0028 
0029 /*
0030  * pch_gbe_gstrings_stats - ethtool information status name list
0031  */
0032 static const struct pch_gbe_stats pch_gbe_gstrings_stats[] = {
0033     PCH_GBE_STAT(rx_packets),
0034     PCH_GBE_STAT(tx_packets),
0035     PCH_GBE_STAT(rx_bytes),
0036     PCH_GBE_STAT(tx_bytes),
0037     PCH_GBE_STAT(rx_errors),
0038     PCH_GBE_STAT(tx_errors),
0039     PCH_GBE_STAT(rx_dropped),
0040     PCH_GBE_STAT(tx_dropped),
0041     PCH_GBE_STAT(multicast),
0042     PCH_GBE_STAT(collisions),
0043     PCH_GBE_STAT(rx_crc_errors),
0044     PCH_GBE_STAT(rx_frame_errors),
0045     PCH_GBE_STAT(rx_alloc_buff_failed),
0046     PCH_GBE_STAT(tx_length_errors),
0047     PCH_GBE_STAT(tx_aborted_errors),
0048     PCH_GBE_STAT(tx_carrier_errors),
0049     PCH_GBE_STAT(tx_timeout_count),
0050     PCH_GBE_STAT(tx_restart_count),
0051     PCH_GBE_STAT(intr_rx_dsc_empty_count),
0052     PCH_GBE_STAT(intr_rx_frame_err_count),
0053     PCH_GBE_STAT(intr_rx_fifo_err_count),
0054     PCH_GBE_STAT(intr_rx_dma_err_count),
0055     PCH_GBE_STAT(intr_tx_fifo_err_count),
0056     PCH_GBE_STAT(intr_tx_dma_err_count),
0057     PCH_GBE_STAT(intr_tcpip_err_count)
0058 };
0059 
0060 #define PCH_GBE_QUEUE_STATS_LEN 0
0061 #define PCH_GBE_GLOBAL_STATS_LEN    ARRAY_SIZE(pch_gbe_gstrings_stats)
0062 #define PCH_GBE_STATS_LEN (PCH_GBE_GLOBAL_STATS_LEN + PCH_GBE_QUEUE_STATS_LEN)
0063 
0064 #define PCH_GBE_MAC_REGS_LEN    (sizeof(struct pch_gbe_regs) / 4)
0065 #define PCH_GBE_REGS_LEN        (PCH_GBE_MAC_REGS_LEN + PCH_GBE_PHY_REGS_LEN)
0066 /**
0067  * pch_gbe_get_link_ksettings - Get device-specific settings
0068  * @netdev: Network interface device structure
0069  * @ecmd:   Ethtool command
0070  * Returns:
0071  *  0:          Successful.
0072  *  Negative value:     Failed.
0073  */
0074 static int pch_gbe_get_link_ksettings(struct net_device *netdev,
0075                       struct ethtool_link_ksettings *ecmd)
0076 {
0077     struct pch_gbe_adapter *adapter = netdev_priv(netdev);
0078     u32 supported, advertising;
0079 
0080     mii_ethtool_get_link_ksettings(&adapter->mii, ecmd);
0081 
0082     ethtool_convert_link_mode_to_legacy_u32(&supported,
0083                         ecmd->link_modes.supported);
0084     ethtool_convert_link_mode_to_legacy_u32(&advertising,
0085                         ecmd->link_modes.advertising);
0086 
0087     supported &= ~(SUPPORTED_TP | SUPPORTED_1000baseT_Half);
0088     advertising &= ~(ADVERTISED_TP | ADVERTISED_1000baseT_Half);
0089 
0090     ethtool_convert_legacy_u32_to_link_mode(ecmd->link_modes.supported,
0091                         supported);
0092     ethtool_convert_legacy_u32_to_link_mode(ecmd->link_modes.advertising,
0093                         advertising);
0094 
0095     if (!netif_carrier_ok(adapter->netdev))
0096         ecmd->base.speed = SPEED_UNKNOWN;
0097 
0098     return 0;
0099 }
0100 
0101 /**
0102  * pch_gbe_set_link_ksettings - Set device-specific settings
0103  * @netdev: Network interface device structure
0104  * @ecmd:   Ethtool command
0105  * Returns:
0106  *  0:          Successful.
0107  *  Negative value:     Failed.
0108  */
0109 static int pch_gbe_set_link_ksettings(struct net_device *netdev,
0110                       const struct ethtool_link_ksettings *ecmd)
0111 {
0112     struct pch_gbe_adapter *adapter = netdev_priv(netdev);
0113     struct pch_gbe_hw *hw = &adapter->hw;
0114     struct ethtool_link_ksettings copy_ecmd;
0115     u32 speed = ecmd->base.speed;
0116     u32 advertising;
0117     int ret;
0118 
0119     pch_gbe_phy_write_reg_miic(hw, MII_BMCR, BMCR_RESET);
0120 
0121     memcpy(&copy_ecmd, ecmd, sizeof(*ecmd));
0122 
0123     /* when set_settings() is called with a ethtool_cmd previously
0124      * filled by get_settings() on a down link, speed is -1: */
0125     if (speed == UINT_MAX) {
0126         speed = SPEED_1000;
0127         copy_ecmd.base.speed = speed;
0128         copy_ecmd.base.duplex = DUPLEX_FULL;
0129     }
0130     ret = mii_ethtool_set_link_ksettings(&adapter->mii, &copy_ecmd);
0131     if (ret) {
0132         netdev_err(netdev, "Error: mii_ethtool_set_link_ksettings\n");
0133         return ret;
0134     }
0135     hw->mac.link_speed = speed;
0136     hw->mac.link_duplex = copy_ecmd.base.duplex;
0137     ethtool_convert_link_mode_to_legacy_u32(
0138         &advertising, copy_ecmd.link_modes.advertising);
0139     hw->phy.autoneg_advertised = advertising;
0140     hw->mac.autoneg = copy_ecmd.base.autoneg;
0141 
0142     /* reset the link */
0143     if (netif_running(adapter->netdev)) {
0144         pch_gbe_down(adapter);
0145         ret = pch_gbe_up(adapter);
0146     } else {
0147         pch_gbe_reset(adapter);
0148     }
0149     return ret;
0150 }
0151 
0152 /**
0153  * pch_gbe_get_regs_len - Report the size of device registers
0154  * @netdev: Network interface device structure
0155  * Returns: the size of device registers.
0156  */
0157 static int pch_gbe_get_regs_len(struct net_device *netdev)
0158 {
0159     return PCH_GBE_REGS_LEN * (int)sizeof(u32);
0160 }
0161 
0162 /**
0163  * pch_gbe_get_drvinfo - Report driver information
0164  * @netdev:  Network interface device structure
0165  * @drvinfo: Driver information structure
0166  */
0167 static void pch_gbe_get_drvinfo(struct net_device *netdev,
0168                  struct ethtool_drvinfo *drvinfo)
0169 {
0170     struct pch_gbe_adapter *adapter = netdev_priv(netdev);
0171 
0172     strlcpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver));
0173     strlcpy(drvinfo->version, pch_driver_version, sizeof(drvinfo->version));
0174     strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
0175         sizeof(drvinfo->bus_info));
0176 }
0177 
0178 /**
0179  * pch_gbe_get_regs - Get device registers
0180  * @netdev: Network interface device structure
0181  * @regs:   Ethtool register structure
0182  * @p:      Buffer pointer of read device register date
0183  */
0184 static void pch_gbe_get_regs(struct net_device *netdev,
0185                 struct ethtool_regs *regs, void *p)
0186 {
0187     struct pch_gbe_adapter *adapter = netdev_priv(netdev);
0188     struct pch_gbe_hw *hw = &adapter->hw;
0189     struct pci_dev *pdev = adapter->pdev;
0190     u32 *regs_buff = p;
0191     u16 i, tmp;
0192 
0193     regs->version = 0x1000000 | (__u32)pdev->revision << 16 | pdev->device;
0194     for (i = 0; i < PCH_GBE_MAC_REGS_LEN; i++)
0195         *regs_buff++ = ioread32(&hw->reg->INT_ST + i);
0196     /* PHY register */
0197     for (i = 0; i < PCH_GBE_PHY_REGS_LEN; i++) {
0198         pch_gbe_phy_read_reg_miic(&adapter->hw, i, &tmp);
0199         *regs_buff++ = tmp;
0200     }
0201 }
0202 
0203 /**
0204  * pch_gbe_get_wol - Report whether Wake-on-Lan is enabled
0205  * @netdev: Network interface device structure
0206  * @wol:    Wake-on-Lan information
0207  */
0208 static void pch_gbe_get_wol(struct net_device *netdev,
0209                 struct ethtool_wolinfo *wol)
0210 {
0211     struct pch_gbe_adapter *adapter = netdev_priv(netdev);
0212 
0213     wol->supported = WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC;
0214     wol->wolopts = 0;
0215 
0216     if ((adapter->wake_up_evt & PCH_GBE_WLC_IND))
0217         wol->wolopts |= WAKE_UCAST;
0218     if ((adapter->wake_up_evt & PCH_GBE_WLC_MLT))
0219         wol->wolopts |= WAKE_MCAST;
0220     if ((adapter->wake_up_evt & PCH_GBE_WLC_BR))
0221         wol->wolopts |= WAKE_BCAST;
0222     if ((adapter->wake_up_evt & PCH_GBE_WLC_MP))
0223         wol->wolopts |= WAKE_MAGIC;
0224 }
0225 
0226 /**
0227  * pch_gbe_set_wol - Turn Wake-on-Lan on or off
0228  * @netdev: Network interface device structure
0229  * @wol:    Pointer of wake-on-Lan information straucture
0230  * Returns:
0231  *  0:          Successful.
0232  *  Negative value:     Failed.
0233  */
0234 static int pch_gbe_set_wol(struct net_device *netdev,
0235                 struct ethtool_wolinfo *wol)
0236 {
0237     struct pch_gbe_adapter *adapter = netdev_priv(netdev);
0238 
0239     if ((wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE)))
0240         return -EOPNOTSUPP;
0241     /* these settings will always override what we currently have */
0242     adapter->wake_up_evt = 0;
0243 
0244     if ((wol->wolopts & WAKE_UCAST))
0245         adapter->wake_up_evt |= PCH_GBE_WLC_IND;
0246     if ((wol->wolopts & WAKE_MCAST))
0247         adapter->wake_up_evt |= PCH_GBE_WLC_MLT;
0248     if ((wol->wolopts & WAKE_BCAST))
0249         adapter->wake_up_evt |= PCH_GBE_WLC_BR;
0250     if ((wol->wolopts & WAKE_MAGIC))
0251         adapter->wake_up_evt |= PCH_GBE_WLC_MP;
0252     return 0;
0253 }
0254 
0255 /**
0256  * pch_gbe_nway_reset - Restart autonegotiation
0257  * @netdev: Network interface device structure
0258  * Returns:
0259  *  0:          Successful.
0260  *  Negative value:     Failed.
0261  */
0262 static int pch_gbe_nway_reset(struct net_device *netdev)
0263 {
0264     struct pch_gbe_adapter *adapter = netdev_priv(netdev);
0265 
0266     return mii_nway_restart(&adapter->mii);
0267 }
0268 
0269 /**
0270  * pch_gbe_get_ringparam - Report ring sizes
0271  * @netdev:  Network interface device structure
0272  * @ring:    Ring param structure
0273  * @kernel_ring:    Ring external param structure
0274  * @extack: netlink handle
0275  */
0276 static void pch_gbe_get_ringparam(struct net_device *netdev,
0277                   struct ethtool_ringparam *ring,
0278                   struct kernel_ethtool_ringparam *kernel_ring,
0279                   struct netlink_ext_ack *extack)
0280 {
0281     struct pch_gbe_adapter *adapter = netdev_priv(netdev);
0282     struct pch_gbe_tx_ring *txdr = adapter->tx_ring;
0283     struct pch_gbe_rx_ring *rxdr = adapter->rx_ring;
0284 
0285     ring->rx_max_pending = PCH_GBE_MAX_RXD;
0286     ring->tx_max_pending = PCH_GBE_MAX_TXD;
0287     ring->rx_pending = rxdr->count;
0288     ring->tx_pending = txdr->count;
0289 }
0290 
0291 /**
0292  * pch_gbe_set_ringparam - Set ring sizes
0293  * @netdev:  Network interface device structure
0294  * @ring:    Ring param structure
0295  * @kernel_ring:    Ring external param structure
0296  * @extack: netlink handle
0297  * Returns
0298  *  0:          Successful.
0299  *  Negative value:     Failed.
0300  */
0301 static int pch_gbe_set_ringparam(struct net_device *netdev,
0302                  struct ethtool_ringparam *ring,
0303                  struct kernel_ethtool_ringparam *kernel_ring,
0304                  struct netlink_ext_ack *extack)
0305 {
0306     struct pch_gbe_adapter *adapter = netdev_priv(netdev);
0307     struct pch_gbe_tx_ring *txdr, *tx_old;
0308     struct pch_gbe_rx_ring *rxdr, *rx_old;
0309     int tx_ring_size, rx_ring_size;
0310     int err = 0;
0311 
0312     if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
0313         return -EINVAL;
0314     tx_ring_size = (int)sizeof(struct pch_gbe_tx_ring);
0315     rx_ring_size = (int)sizeof(struct pch_gbe_rx_ring);
0316 
0317     if ((netif_running(adapter->netdev)))
0318         pch_gbe_down(adapter);
0319     tx_old = adapter->tx_ring;
0320     rx_old = adapter->rx_ring;
0321 
0322     txdr = kzalloc(tx_ring_size, GFP_KERNEL);
0323     if (!txdr) {
0324         err = -ENOMEM;
0325         goto err_alloc_tx;
0326     }
0327     rxdr = kzalloc(rx_ring_size, GFP_KERNEL);
0328     if (!rxdr) {
0329         err = -ENOMEM;
0330         goto err_alloc_rx;
0331     }
0332     adapter->tx_ring = txdr;
0333     adapter->rx_ring = rxdr;
0334 
0335     rxdr->count =
0336         clamp_val(ring->rx_pending, PCH_GBE_MIN_RXD, PCH_GBE_MAX_RXD);
0337     rxdr->count = roundup(rxdr->count, PCH_GBE_RX_DESC_MULTIPLE);
0338 
0339     txdr->count =
0340         clamp_val(ring->tx_pending, PCH_GBE_MIN_RXD, PCH_GBE_MAX_RXD);
0341     txdr->count = roundup(txdr->count, PCH_GBE_TX_DESC_MULTIPLE);
0342 
0343     if ((netif_running(adapter->netdev))) {
0344         /* Try to get new resources before deleting old */
0345         err = pch_gbe_setup_rx_resources(adapter, adapter->rx_ring);
0346         if (err)
0347             goto err_setup_rx;
0348         err = pch_gbe_setup_tx_resources(adapter, adapter->tx_ring);
0349         if (err)
0350             goto err_setup_tx;
0351         pch_gbe_free_rx_resources(adapter, rx_old);
0352         pch_gbe_free_tx_resources(adapter, tx_old);
0353         kfree(tx_old);
0354         kfree(rx_old);
0355         adapter->rx_ring = rxdr;
0356         adapter->tx_ring = txdr;
0357         err = pch_gbe_up(adapter);
0358     }
0359     return err;
0360 
0361 err_setup_tx:
0362     pch_gbe_free_rx_resources(adapter, adapter->rx_ring);
0363 err_setup_rx:
0364     adapter->rx_ring = rx_old;
0365     adapter->tx_ring = tx_old;
0366     kfree(rxdr);
0367 err_alloc_rx:
0368     kfree(txdr);
0369 err_alloc_tx:
0370     if (netif_running(adapter->netdev))
0371         pch_gbe_up(adapter);
0372     return err;
0373 }
0374 
0375 /**
0376  * pch_gbe_get_pauseparam - Report pause parameters
0377  * @netdev:  Network interface device structure
0378  * @pause:   Pause parameters structure
0379  */
0380 static void pch_gbe_get_pauseparam(struct net_device *netdev,
0381                        struct ethtool_pauseparam *pause)
0382 {
0383     struct pch_gbe_adapter *adapter = netdev_priv(netdev);
0384     struct pch_gbe_hw *hw = &adapter->hw;
0385 
0386     pause->autoneg =
0387         ((hw->mac.fc_autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE);
0388 
0389     if (hw->mac.fc == PCH_GBE_FC_RX_PAUSE) {
0390         pause->rx_pause = 1;
0391     } else if (hw->mac.fc == PCH_GBE_FC_TX_PAUSE) {
0392         pause->tx_pause = 1;
0393     } else if (hw->mac.fc == PCH_GBE_FC_FULL) {
0394         pause->rx_pause = 1;
0395         pause->tx_pause = 1;
0396     }
0397 }
0398 
0399 /**
0400  * pch_gbe_set_pauseparam - Set pause parameters
0401  * @netdev:  Network interface device structure
0402  * @pause:   Pause parameters structure
0403  * Returns:
0404  *  0:          Successful.
0405  *  Negative value:     Failed.
0406  */
0407 static int pch_gbe_set_pauseparam(struct net_device *netdev,
0408                        struct ethtool_pauseparam *pause)
0409 {
0410     struct pch_gbe_adapter *adapter = netdev_priv(netdev);
0411     struct pch_gbe_hw *hw = &adapter->hw;
0412     int ret = 0;
0413 
0414     hw->mac.fc_autoneg = pause->autoneg;
0415     if ((pause->rx_pause) && (pause->tx_pause))
0416         hw->mac.fc = PCH_GBE_FC_FULL;
0417     else if ((pause->rx_pause) && (!pause->tx_pause))
0418         hw->mac.fc = PCH_GBE_FC_RX_PAUSE;
0419     else if ((!pause->rx_pause) && (pause->tx_pause))
0420         hw->mac.fc = PCH_GBE_FC_TX_PAUSE;
0421     else if ((!pause->rx_pause) && (!pause->tx_pause))
0422         hw->mac.fc = PCH_GBE_FC_NONE;
0423 
0424     if (hw->mac.fc_autoneg == AUTONEG_ENABLE) {
0425         if ((netif_running(adapter->netdev))) {
0426             pch_gbe_down(adapter);
0427             ret = pch_gbe_up(adapter);
0428         } else {
0429             pch_gbe_reset(adapter);
0430         }
0431     } else {
0432         ret = pch_gbe_mac_force_mac_fc(hw);
0433     }
0434     return ret;
0435 }
0436 
0437 /**
0438  * pch_gbe_get_strings - Return a set of strings that describe the requested
0439  *           objects
0440  * @netdev:    Network interface device structure
0441  * @stringset: Select the stringset. [ETH_SS_TEST] [ETH_SS_STATS]
0442  * @data:      Pointer of read string data.
0443  */
0444 static void pch_gbe_get_strings(struct net_device *netdev, u32 stringset,
0445                     u8 *data)
0446 {
0447     u8 *p = data;
0448     int i;
0449 
0450     switch (stringset) {
0451     case (u32) ETH_SS_STATS:
0452         for (i = 0; i < PCH_GBE_GLOBAL_STATS_LEN; i++) {
0453             memcpy(p, pch_gbe_gstrings_stats[i].string,
0454                    ETH_GSTRING_LEN);
0455             p += ETH_GSTRING_LEN;
0456         }
0457         break;
0458     }
0459 }
0460 
0461 /**
0462  * pch_gbe_get_ethtool_stats - Return statistics about the device
0463  * @netdev: Network interface device structure
0464  * @stats:  Ethtool statue structure
0465  * @data:   Pointer of read status area
0466  */
0467 static void pch_gbe_get_ethtool_stats(struct net_device *netdev,
0468                   struct ethtool_stats *stats, u64 *data)
0469 {
0470     struct pch_gbe_adapter *adapter = netdev_priv(netdev);
0471     int i;
0472     const struct pch_gbe_stats *gstats = pch_gbe_gstrings_stats;
0473     char *hw_stats = (char *)&adapter->stats;
0474 
0475     pch_gbe_update_stats(adapter);
0476     for (i = 0; i < PCH_GBE_GLOBAL_STATS_LEN; i++) {
0477         char *p = hw_stats + gstats->offset;
0478         data[i] = gstats->size == sizeof(u64) ? *(u64 *)p:(*(u32 *)p);
0479         gstats++;
0480     }
0481 }
0482 
0483 static int pch_gbe_get_sset_count(struct net_device *netdev, int sset)
0484 {
0485     switch (sset) {
0486     case ETH_SS_STATS:
0487         return PCH_GBE_STATS_LEN;
0488     default:
0489         return -EOPNOTSUPP;
0490     }
0491 }
0492 
0493 static const struct ethtool_ops pch_gbe_ethtool_ops = {
0494     .get_drvinfo = pch_gbe_get_drvinfo,
0495     .get_regs_len = pch_gbe_get_regs_len,
0496     .get_regs = pch_gbe_get_regs,
0497     .get_wol = pch_gbe_get_wol,
0498     .set_wol = pch_gbe_set_wol,
0499     .nway_reset = pch_gbe_nway_reset,
0500     .get_link = ethtool_op_get_link,
0501     .get_ringparam = pch_gbe_get_ringparam,
0502     .set_ringparam = pch_gbe_set_ringparam,
0503     .get_pauseparam = pch_gbe_get_pauseparam,
0504     .set_pauseparam = pch_gbe_set_pauseparam,
0505     .get_strings = pch_gbe_get_strings,
0506     .get_ethtool_stats = pch_gbe_get_ethtool_stats,
0507     .get_sset_count = pch_gbe_get_sset_count,
0508     .get_link_ksettings = pch_gbe_get_link_ksettings,
0509     .set_link_ksettings = pch_gbe_set_link_ksettings,
0510 };
0511 
0512 void pch_gbe_set_ethtool_ops(struct net_device *netdev)
0513 {
0514     netdev->ethtool_ops = &pch_gbe_ethtool_ops;
0515 }