Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* Applied Micro X-Gene SoC Ethernet Driver
0003  *
0004  * Copyright (c) 2014, Applied Micro Circuits Corporation
0005  * Authors: Iyappan Subramanian <isubramanian@apm.com>
0006  */
0007 
0008 #include <linux/ethtool.h>
0009 #include "xgene_enet_main.h"
0010 
0011 struct xgene_gstrings_stats {
0012     char name[ETH_GSTRING_LEN];
0013     int offset;
0014     u32 addr;
0015     u32 mask;
0016 };
0017 
0018 #define XGENE_STAT(m) { #m, offsetof(struct rtnl_link_stats64, m) }
0019 #define XGENE_EXTD_STAT(s, a, m)        \
0020         {           \
0021         .name = #s,     \
0022         .addr = a ## _ADDR, \
0023         .mask = m       \
0024         }
0025 
0026 static const struct xgene_gstrings_stats gstrings_stats[] = {
0027     XGENE_STAT(rx_packets),
0028     XGENE_STAT(tx_packets),
0029     XGENE_STAT(rx_bytes),
0030     XGENE_STAT(tx_bytes),
0031     XGENE_STAT(rx_errors),
0032     XGENE_STAT(tx_errors),
0033     XGENE_STAT(rx_length_errors),
0034     XGENE_STAT(rx_crc_errors),
0035     XGENE_STAT(rx_frame_errors),
0036     XGENE_STAT(rx_fifo_errors)
0037 };
0038 
0039 static const struct xgene_gstrings_stats gstrings_extd_stats[] = {
0040     XGENE_EXTD_STAT(tx_rx_64b_frame_cntr, TR64, 31),
0041     XGENE_EXTD_STAT(tx_rx_127b_frame_cntr, TR127, 31),
0042     XGENE_EXTD_STAT(tx_rx_255b_frame_cntr, TR255, 31),
0043     XGENE_EXTD_STAT(tx_rx_511b_frame_cntr, TR511, 31),
0044     XGENE_EXTD_STAT(tx_rx_1023b_frame_cntr, TR1K, 31),
0045     XGENE_EXTD_STAT(tx_rx_1518b_frame_cntr, TRMAX, 31),
0046     XGENE_EXTD_STAT(tx_rx_1522b_frame_cntr, TRMGV, 31),
0047     XGENE_EXTD_STAT(rx_fcs_error_cntr, RFCS, 16),
0048     XGENE_EXTD_STAT(rx_multicast_pkt_cntr, RMCA, 31),
0049     XGENE_EXTD_STAT(rx_broadcast_pkt_cntr, RBCA, 31),
0050     XGENE_EXTD_STAT(rx_ctrl_frame_pkt_cntr, RXCF, 16),
0051     XGENE_EXTD_STAT(rx_pause_frame_pkt_cntr, RXPF, 16),
0052     XGENE_EXTD_STAT(rx_unk_opcode_cntr, RXUO, 16),
0053     XGENE_EXTD_STAT(rx_align_err_cntr, RALN, 16),
0054     XGENE_EXTD_STAT(rx_frame_len_err_cntr, RFLR, 16),
0055     XGENE_EXTD_STAT(rx_frame_len_err_recov_cntr, DUMP, 0),
0056     XGENE_EXTD_STAT(rx_code_err_cntr, RCDE, 16),
0057     XGENE_EXTD_STAT(rx_carrier_sense_err_cntr, RCSE, 16),
0058     XGENE_EXTD_STAT(rx_undersize_pkt_cntr, RUND, 16),
0059     XGENE_EXTD_STAT(rx_oversize_pkt_cntr, ROVR, 16),
0060     XGENE_EXTD_STAT(rx_fragments_cntr, RFRG, 16),
0061     XGENE_EXTD_STAT(rx_jabber_cntr, RJBR, 16),
0062     XGENE_EXTD_STAT(rx_jabber_recov_cntr, DUMP, 0),
0063     XGENE_EXTD_STAT(rx_dropped_pkt_cntr, RDRP, 16),
0064     XGENE_EXTD_STAT(rx_overrun_cntr, DUMP, 0),
0065     XGENE_EXTD_STAT(tx_multicast_pkt_cntr, TMCA, 31),
0066     XGENE_EXTD_STAT(tx_broadcast_pkt_cntr, TBCA, 31),
0067     XGENE_EXTD_STAT(tx_pause_ctrl_frame_cntr, TXPF, 16),
0068     XGENE_EXTD_STAT(tx_defer_pkt_cntr, TDFR, 31),
0069     XGENE_EXTD_STAT(tx_excv_defer_pkt_cntr, TEDF, 31),
0070     XGENE_EXTD_STAT(tx_single_col_pkt_cntr, TSCL, 31),
0071     XGENE_EXTD_STAT(tx_multi_col_pkt_cntr, TMCL, 31),
0072     XGENE_EXTD_STAT(tx_late_col_pkt_cntr, TLCL, 31),
0073     XGENE_EXTD_STAT(tx_excv_col_pkt_cntr, TXCL, 31),
0074     XGENE_EXTD_STAT(tx_total_col_cntr, TNCL, 31),
0075     XGENE_EXTD_STAT(tx_pause_frames_hnrd_cntr, TPFH, 16),
0076     XGENE_EXTD_STAT(tx_drop_frame_cntr, TDRP, 16),
0077     XGENE_EXTD_STAT(tx_jabber_frame_cntr, TJBR, 12),
0078     XGENE_EXTD_STAT(tx_fcs_error_cntr, TFCS, 12),
0079     XGENE_EXTD_STAT(tx_ctrl_frame_cntr, TXCF, 12),
0080     XGENE_EXTD_STAT(tx_oversize_frame_cntr, TOVR, 12),
0081     XGENE_EXTD_STAT(tx_undersize_frame_cntr, TUND, 12),
0082     XGENE_EXTD_STAT(tx_fragments_cntr, TFRG, 12),
0083     XGENE_EXTD_STAT(tx_underrun_cntr, DUMP, 0)
0084 };
0085 
0086 #define XGENE_STATS_LEN     ARRAY_SIZE(gstrings_stats)
0087 #define XGENE_EXTD_STATS_LEN    ARRAY_SIZE(gstrings_extd_stats)
0088 #define RFCS_IDX        7
0089 #define RALN_IDX        13
0090 #define RFLR_IDX        14
0091 #define FALSE_RFLR_IDX      15
0092 #define RUND_IDX        18
0093 #define FALSE_RJBR_IDX      22
0094 #define RX_OVERRUN_IDX      24
0095 #define TFCS_IDX        38
0096 #define TFRG_IDX        42
0097 #define TX_UNDERRUN_IDX     43
0098 
0099 static void xgene_get_drvinfo(struct net_device *ndev,
0100                   struct ethtool_drvinfo *info)
0101 {
0102     struct xgene_enet_pdata *pdata = netdev_priv(ndev);
0103     struct platform_device *pdev = pdata->pdev;
0104 
0105     strcpy(info->driver, "xgene_enet");
0106     sprintf(info->bus_info, "%s", pdev->name);
0107 }
0108 
0109 static int xgene_get_link_ksettings(struct net_device *ndev,
0110                     struct ethtool_link_ksettings *cmd)
0111 {
0112     struct xgene_enet_pdata *pdata = netdev_priv(ndev);
0113     struct phy_device *phydev = ndev->phydev;
0114     u32 supported;
0115 
0116     if (phy_interface_mode_is_rgmii(pdata->phy_mode)) {
0117         if (phydev == NULL)
0118             return -ENODEV;
0119 
0120         phy_ethtool_ksettings_get(phydev, cmd);
0121 
0122         return 0;
0123     } else if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) {
0124         if (pdata->mdio_driver) {
0125             if (!phydev)
0126                 return -ENODEV;
0127 
0128             phy_ethtool_ksettings_get(phydev, cmd);
0129 
0130             return 0;
0131         }
0132 
0133         supported = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
0134             SUPPORTED_MII;
0135         ethtool_convert_legacy_u32_to_link_mode(
0136             cmd->link_modes.supported,
0137             supported);
0138         ethtool_convert_legacy_u32_to_link_mode(
0139             cmd->link_modes.advertising,
0140             supported);
0141 
0142         cmd->base.speed = SPEED_1000;
0143         cmd->base.duplex = DUPLEX_FULL;
0144         cmd->base.port = PORT_MII;
0145         cmd->base.autoneg = AUTONEG_ENABLE;
0146     } else {
0147         supported = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE;
0148         ethtool_convert_legacy_u32_to_link_mode(
0149             cmd->link_modes.supported,
0150             supported);
0151         ethtool_convert_legacy_u32_to_link_mode(
0152             cmd->link_modes.advertising,
0153             supported);
0154 
0155         cmd->base.speed = SPEED_10000;
0156         cmd->base.duplex = DUPLEX_FULL;
0157         cmd->base.port = PORT_FIBRE;
0158         cmd->base.autoneg = AUTONEG_DISABLE;
0159     }
0160 
0161     return 0;
0162 }
0163 
0164 static int xgene_set_link_ksettings(struct net_device *ndev,
0165                     const struct ethtool_link_ksettings *cmd)
0166 {
0167     struct xgene_enet_pdata *pdata = netdev_priv(ndev);
0168     struct phy_device *phydev = ndev->phydev;
0169 
0170     if (phy_interface_mode_is_rgmii(pdata->phy_mode)) {
0171         if (!phydev)
0172             return -ENODEV;
0173 
0174         return phy_ethtool_ksettings_set(phydev, cmd);
0175     }
0176 
0177     if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) {
0178         if (pdata->mdio_driver) {
0179             if (!phydev)
0180                 return -ENODEV;
0181 
0182             return phy_ethtool_ksettings_set(phydev, cmd);
0183         }
0184     }
0185 
0186     return -EINVAL;
0187 }
0188 
0189 static void xgene_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
0190 {
0191     int i;
0192     u8 *p = data;
0193 
0194     if (stringset != ETH_SS_STATS)
0195         return;
0196 
0197     for (i = 0; i < XGENE_STATS_LEN; i++) {
0198         memcpy(p, gstrings_stats[i].name, ETH_GSTRING_LEN);
0199         p += ETH_GSTRING_LEN;
0200     }
0201 
0202     for (i = 0; i < XGENE_EXTD_STATS_LEN; i++) {
0203         memcpy(p, gstrings_extd_stats[i].name, ETH_GSTRING_LEN);
0204         p += ETH_GSTRING_LEN;
0205     }
0206 }
0207 
0208 static int xgene_get_sset_count(struct net_device *ndev, int sset)
0209 {
0210     if (sset != ETH_SS_STATS)
0211         return -EINVAL;
0212 
0213     return XGENE_STATS_LEN + XGENE_EXTD_STATS_LEN;
0214 }
0215 
0216 static void xgene_get_extd_stats(struct xgene_enet_pdata *pdata)
0217 {
0218     u32 rx_drop, tx_drop;
0219     u32 mask, tmp;
0220     int i;
0221 
0222     for (i = 0; i < XGENE_EXTD_STATS_LEN; i++) {
0223         tmp = xgene_enet_rd_stat(pdata, gstrings_extd_stats[i].addr);
0224         if (gstrings_extd_stats[i].mask) {
0225             mask = GENMASK(gstrings_extd_stats[i].mask - 1, 0);
0226             pdata->extd_stats[i] += (tmp & mask);
0227         }
0228     }
0229 
0230     if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) {
0231         /* Errata 10GE_10 - SW should intepret RALN as 0 */
0232         pdata->extd_stats[RALN_IDX] = 0;
0233     } else {
0234         /* Errata ENET_15 - Fixes RFCS, RFLR, TFCS counter */
0235         pdata->extd_stats[RFCS_IDX] -= pdata->extd_stats[RALN_IDX];
0236         pdata->extd_stats[RFLR_IDX] -= pdata->extd_stats[RUND_IDX];
0237         pdata->extd_stats[TFCS_IDX] -= pdata->extd_stats[TFRG_IDX];
0238     }
0239 
0240     pdata->mac_ops->get_drop_cnt(pdata, &rx_drop, &tx_drop);
0241     pdata->extd_stats[RX_OVERRUN_IDX] += rx_drop;
0242     pdata->extd_stats[TX_UNDERRUN_IDX] += tx_drop;
0243 
0244     /* Errata 10GE_8 -  Update Frame recovered from Errata 10GE_8/ENET_11 */
0245     pdata->extd_stats[FALSE_RFLR_IDX] = pdata->false_rflr;
0246     /* Errata ENET_15 - Jabber Frame recov'ed from Errata 10GE_10/ENET_15 */
0247     pdata->extd_stats[FALSE_RJBR_IDX] = pdata->vlan_rjbr;
0248 }
0249 
0250 int xgene_extd_stats_init(struct xgene_enet_pdata *pdata)
0251 {
0252     pdata->extd_stats = devm_kmalloc_array(&pdata->pdev->dev,
0253             XGENE_EXTD_STATS_LEN, sizeof(u64), GFP_KERNEL);
0254     if (!pdata->extd_stats)
0255         return -ENOMEM;
0256 
0257     xgene_get_extd_stats(pdata);
0258     memset(pdata->extd_stats, 0, XGENE_EXTD_STATS_LEN * sizeof(u64));
0259 
0260     return 0;
0261 }
0262 
0263 static void xgene_get_ethtool_stats(struct net_device *ndev,
0264                     struct ethtool_stats *dummy,
0265                     u64 *data)
0266 {
0267     struct xgene_enet_pdata *pdata = netdev_priv(ndev);
0268     struct rtnl_link_stats64 stats;
0269     int i;
0270 
0271     dev_get_stats(ndev, &stats);
0272     for (i = 0; i < XGENE_STATS_LEN; i++)
0273         data[i] = *(u64 *)((char *)&stats + gstrings_stats[i].offset);
0274 
0275     xgene_get_extd_stats(pdata);
0276     for (i = 0; i < XGENE_EXTD_STATS_LEN; i++)
0277         data[i + XGENE_STATS_LEN] = pdata->extd_stats[i];
0278 }
0279 
0280 static void xgene_get_pauseparam(struct net_device *ndev,
0281                  struct ethtool_pauseparam *pp)
0282 {
0283     struct xgene_enet_pdata *pdata = netdev_priv(ndev);
0284 
0285     pp->autoneg = pdata->pause_autoneg;
0286     pp->tx_pause = pdata->tx_pause;
0287     pp->rx_pause = pdata->rx_pause;
0288 }
0289 
0290 static int xgene_set_pauseparam(struct net_device *ndev,
0291                 struct ethtool_pauseparam *pp)
0292 {
0293     struct xgene_enet_pdata *pdata = netdev_priv(ndev);
0294     struct phy_device *phydev = ndev->phydev;
0295 
0296     if (phy_interface_mode_is_rgmii(pdata->phy_mode) ||
0297         pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) {
0298         if (!phydev)
0299             return -EINVAL;
0300 
0301         if (!phy_validate_pause(phydev, pp))
0302             return -EINVAL;
0303 
0304         pdata->pause_autoneg = pp->autoneg;
0305         pdata->tx_pause = pp->tx_pause;
0306         pdata->rx_pause = pp->rx_pause;
0307 
0308         phy_set_asym_pause(phydev, pp->rx_pause,  pp->tx_pause);
0309 
0310         if (!pp->autoneg) {
0311             pdata->mac_ops->flowctl_tx(pdata, pdata->tx_pause);
0312             pdata->mac_ops->flowctl_rx(pdata, pdata->rx_pause);
0313         }
0314     } else {
0315         if (pp->autoneg)
0316             return -EINVAL;
0317 
0318         pdata->tx_pause = pp->tx_pause;
0319         pdata->rx_pause = pp->rx_pause;
0320 
0321         pdata->mac_ops->flowctl_tx(pdata, pdata->tx_pause);
0322         pdata->mac_ops->flowctl_rx(pdata, pdata->rx_pause);
0323     }
0324 
0325     return 0;
0326 }
0327 
0328 static const struct ethtool_ops xgene_ethtool_ops = {
0329     .get_drvinfo = xgene_get_drvinfo,
0330     .get_link = ethtool_op_get_link,
0331     .get_strings = xgene_get_strings,
0332     .get_sset_count = xgene_get_sset_count,
0333     .get_ethtool_stats = xgene_get_ethtool_stats,
0334     .get_link_ksettings = xgene_get_link_ksettings,
0335     .set_link_ksettings = xgene_set_link_ksettings,
0336     .get_pauseparam = xgene_get_pauseparam,
0337     .set_pauseparam = xgene_set_pauseparam
0338 };
0339 
0340 void xgene_enet_set_ethtool_ops(struct net_device *ndev)
0341 {
0342     ndev->ethtool_ops = &xgene_ethtool_ops;
0343 }