1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* Applied Micro X-Gene SoC Ethernet Driver 3 * 4 * Copyright (c) 2014, Applied Micro Circuits Corporation 5 * Authors: Iyappan Subramanian <isubramanian@apm.com> 6 */ 7 8 #include <linux/ethtool.h> 9 #include "xgene_enet_main.h" 10 11 struct xgene_gstrings_stats { 12 char name[ETH_GSTRING_LEN]; 13 int offset; 14 u32 addr; 15 u32 mask; 16 }; 17 18 #define XGENE_STAT(m) { #m, offsetof(struct rtnl_link_stats64, m) } 19 #define XGENE_EXTD_STAT(s, a, m) \ 20 { \ 21 .name = #s, \ 22 .addr = a ## _ADDR, \ 23 .mask = m \ 24 } 25 26 static const struct xgene_gstrings_stats gstrings_stats[] = { 27 XGENE_STAT(rx_packets), 28 XGENE_STAT(tx_packets), 29 XGENE_STAT(rx_bytes), 30 XGENE_STAT(tx_bytes), 31 XGENE_STAT(rx_errors), 32 XGENE_STAT(tx_errors), 33 XGENE_STAT(rx_length_errors), 34 XGENE_STAT(rx_crc_errors), 35 XGENE_STAT(rx_frame_errors), 36 XGENE_STAT(rx_fifo_errors) 37 }; 38 39 static const struct xgene_gstrings_stats gstrings_extd_stats[] = { 40 XGENE_EXTD_STAT(tx_rx_64b_frame_cntr, TR64, 31), 41 XGENE_EXTD_STAT(tx_rx_127b_frame_cntr, TR127, 31), 42 XGENE_EXTD_STAT(tx_rx_255b_frame_cntr, TR255, 31), 43 XGENE_EXTD_STAT(tx_rx_511b_frame_cntr, TR511, 31), 44 XGENE_EXTD_STAT(tx_rx_1023b_frame_cntr, TR1K, 31), 45 XGENE_EXTD_STAT(tx_rx_1518b_frame_cntr, TRMAX, 31), 46 XGENE_EXTD_STAT(tx_rx_1522b_frame_cntr, TRMGV, 31), 47 XGENE_EXTD_STAT(rx_fcs_error_cntr, RFCS, 16), 48 XGENE_EXTD_STAT(rx_multicast_pkt_cntr, RMCA, 31), 49 XGENE_EXTD_STAT(rx_broadcast_pkt_cntr, RBCA, 31), 50 XGENE_EXTD_STAT(rx_ctrl_frame_pkt_cntr, RXCF, 16), 51 XGENE_EXTD_STAT(rx_pause_frame_pkt_cntr, RXPF, 16), 52 XGENE_EXTD_STAT(rx_unk_opcode_cntr, RXUO, 16), 53 XGENE_EXTD_STAT(rx_align_err_cntr, RALN, 16), 54 XGENE_EXTD_STAT(rx_frame_len_err_cntr, RFLR, 16), 55 XGENE_EXTD_STAT(rx_frame_len_err_recov_cntr, DUMP, 0), 56 XGENE_EXTD_STAT(rx_code_err_cntr, RCDE, 16), 57 XGENE_EXTD_STAT(rx_carrier_sense_err_cntr, RCSE, 16), 58 XGENE_EXTD_STAT(rx_undersize_pkt_cntr, RUND, 16), 59 XGENE_EXTD_STAT(rx_oversize_pkt_cntr, ROVR, 16), 60 XGENE_EXTD_STAT(rx_fragments_cntr, RFRG, 16), 61 XGENE_EXTD_STAT(rx_jabber_cntr, RJBR, 16), 62 XGENE_EXTD_STAT(rx_jabber_recov_cntr, DUMP, 0), 63 XGENE_EXTD_STAT(rx_dropped_pkt_cntr, RDRP, 16), 64 XGENE_EXTD_STAT(rx_overrun_cntr, DUMP, 0), 65 XGENE_EXTD_STAT(tx_multicast_pkt_cntr, TMCA, 31), 66 XGENE_EXTD_STAT(tx_broadcast_pkt_cntr, TBCA, 31), 67 XGENE_EXTD_STAT(tx_pause_ctrl_frame_cntr, TXPF, 16), 68 XGENE_EXTD_STAT(tx_defer_pkt_cntr, TDFR, 31), 69 XGENE_EXTD_STAT(tx_excv_defer_pkt_cntr, TEDF, 31), 70 XGENE_EXTD_STAT(tx_single_col_pkt_cntr, TSCL, 31), 71 XGENE_EXTD_STAT(tx_multi_col_pkt_cntr, TMCL, 31), 72 XGENE_EXTD_STAT(tx_late_col_pkt_cntr, TLCL, 31), 73 XGENE_EXTD_STAT(tx_excv_col_pkt_cntr, TXCL, 31), 74 XGENE_EXTD_STAT(tx_total_col_cntr, TNCL, 31), 75 XGENE_EXTD_STAT(tx_pause_frames_hnrd_cntr, TPFH, 16), 76 XGENE_EXTD_STAT(tx_drop_frame_cntr, TDRP, 16), 77 XGENE_EXTD_STAT(tx_jabber_frame_cntr, TJBR, 12), 78 XGENE_EXTD_STAT(tx_fcs_error_cntr, TFCS, 12), 79 XGENE_EXTD_STAT(tx_ctrl_frame_cntr, TXCF, 12), 80 XGENE_EXTD_STAT(tx_oversize_frame_cntr, TOVR, 12), 81 XGENE_EXTD_STAT(tx_undersize_frame_cntr, TUND, 12), 82 XGENE_EXTD_STAT(tx_fragments_cntr, TFRG, 12), 83 XGENE_EXTD_STAT(tx_underrun_cntr, DUMP, 0) 84 }; 85 86 #define XGENE_STATS_LEN ARRAY_SIZE(gstrings_stats) 87 #define XGENE_EXTD_STATS_LEN ARRAY_SIZE(gstrings_extd_stats) 88 #define RFCS_IDX 7 89 #define RALN_IDX 13 90 #define RFLR_IDX 14 91 #define FALSE_RFLR_IDX 15 92 #define RUND_IDX 18 93 #define FALSE_RJBR_IDX 22 94 #define RX_OVERRUN_IDX 24 95 #define TFCS_IDX 38 96 #define TFRG_IDX 42 97 #define TX_UNDERRUN_IDX 43 98 99 static void xgene_get_drvinfo(struct net_device *ndev, 100 struct ethtool_drvinfo *info) 101 { 102 struct xgene_enet_pdata *pdata = netdev_priv(ndev); 103 struct platform_device *pdev = pdata->pdev; 104 105 strcpy(info->driver, "xgene_enet"); 106 strcpy(info->version, XGENE_DRV_VERSION); 107 snprintf(info->fw_version, ETHTOOL_FWVERS_LEN, "N/A"); 108 sprintf(info->bus_info, "%s", pdev->name); 109 } 110 111 static int xgene_get_link_ksettings(struct net_device *ndev, 112 struct ethtool_link_ksettings *cmd) 113 { 114 struct xgene_enet_pdata *pdata = netdev_priv(ndev); 115 struct phy_device *phydev = ndev->phydev; 116 u32 supported; 117 118 if (phy_interface_mode_is_rgmii(pdata->phy_mode)) { 119 if (phydev == NULL) 120 return -ENODEV; 121 122 phy_ethtool_ksettings_get(phydev, cmd); 123 124 return 0; 125 } else if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) { 126 if (pdata->mdio_driver) { 127 if (!phydev) 128 return -ENODEV; 129 130 phy_ethtool_ksettings_get(phydev, cmd); 131 132 return 0; 133 } 134 135 supported = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | 136 SUPPORTED_MII; 137 ethtool_convert_legacy_u32_to_link_mode( 138 cmd->link_modes.supported, 139 supported); 140 ethtool_convert_legacy_u32_to_link_mode( 141 cmd->link_modes.advertising, 142 supported); 143 144 cmd->base.speed = SPEED_1000; 145 cmd->base.duplex = DUPLEX_FULL; 146 cmd->base.port = PORT_MII; 147 cmd->base.autoneg = AUTONEG_ENABLE; 148 } else { 149 supported = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE; 150 ethtool_convert_legacy_u32_to_link_mode( 151 cmd->link_modes.supported, 152 supported); 153 ethtool_convert_legacy_u32_to_link_mode( 154 cmd->link_modes.advertising, 155 supported); 156 157 cmd->base.speed = SPEED_10000; 158 cmd->base.duplex = DUPLEX_FULL; 159 cmd->base.port = PORT_FIBRE; 160 cmd->base.autoneg = AUTONEG_DISABLE; 161 } 162 163 return 0; 164 } 165 166 static int xgene_set_link_ksettings(struct net_device *ndev, 167 const struct ethtool_link_ksettings *cmd) 168 { 169 struct xgene_enet_pdata *pdata = netdev_priv(ndev); 170 struct phy_device *phydev = ndev->phydev; 171 172 if (phy_interface_mode_is_rgmii(pdata->phy_mode)) { 173 if (!phydev) 174 return -ENODEV; 175 176 return phy_ethtool_ksettings_set(phydev, cmd); 177 } 178 179 if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) { 180 if (pdata->mdio_driver) { 181 if (!phydev) 182 return -ENODEV; 183 184 return phy_ethtool_ksettings_set(phydev, cmd); 185 } 186 } 187 188 return -EINVAL; 189 } 190 191 static void xgene_get_strings(struct net_device *ndev, u32 stringset, u8 *data) 192 { 193 int i; 194 u8 *p = data; 195 196 if (stringset != ETH_SS_STATS) 197 return; 198 199 for (i = 0; i < XGENE_STATS_LEN; i++) { 200 memcpy(p, gstrings_stats[i].name, ETH_GSTRING_LEN); 201 p += ETH_GSTRING_LEN; 202 } 203 204 for (i = 0; i < XGENE_EXTD_STATS_LEN; i++) { 205 memcpy(p, gstrings_extd_stats[i].name, ETH_GSTRING_LEN); 206 p += ETH_GSTRING_LEN; 207 } 208 } 209 210 static int xgene_get_sset_count(struct net_device *ndev, int sset) 211 { 212 if (sset != ETH_SS_STATS) 213 return -EINVAL; 214 215 return XGENE_STATS_LEN + XGENE_EXTD_STATS_LEN; 216 } 217 218 static void xgene_get_extd_stats(struct xgene_enet_pdata *pdata) 219 { 220 u32 rx_drop, tx_drop; 221 u32 mask, tmp; 222 int i; 223 224 for (i = 0; i < XGENE_EXTD_STATS_LEN; i++) { 225 tmp = xgene_enet_rd_stat(pdata, gstrings_extd_stats[i].addr); 226 if (gstrings_extd_stats[i].mask) { 227 mask = GENMASK(gstrings_extd_stats[i].mask - 1, 0); 228 pdata->extd_stats[i] += (tmp & mask); 229 } 230 } 231 232 if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) { 233 /* Errata 10GE_10 - SW should intepret RALN as 0 */ 234 pdata->extd_stats[RALN_IDX] = 0; 235 } else { 236 /* Errata ENET_15 - Fixes RFCS, RFLR, TFCS counter */ 237 pdata->extd_stats[RFCS_IDX] -= pdata->extd_stats[RALN_IDX]; 238 pdata->extd_stats[RFLR_IDX] -= pdata->extd_stats[RUND_IDX]; 239 pdata->extd_stats[TFCS_IDX] -= pdata->extd_stats[TFRG_IDX]; 240 } 241 242 pdata->mac_ops->get_drop_cnt(pdata, &rx_drop, &tx_drop); 243 pdata->extd_stats[RX_OVERRUN_IDX] += rx_drop; 244 pdata->extd_stats[TX_UNDERRUN_IDX] += tx_drop; 245 246 /* Errata 10GE_8 - Update Frame recovered from Errata 10GE_8/ENET_11 */ 247 pdata->extd_stats[FALSE_RFLR_IDX] = pdata->false_rflr; 248 /* Errata ENET_15 - Jabber Frame recov'ed from Errata 10GE_10/ENET_15 */ 249 pdata->extd_stats[FALSE_RJBR_IDX] = pdata->vlan_rjbr; 250 } 251 252 int xgene_extd_stats_init(struct xgene_enet_pdata *pdata) 253 { 254 pdata->extd_stats = devm_kmalloc_array(&pdata->pdev->dev, 255 XGENE_EXTD_STATS_LEN, sizeof(u64), GFP_KERNEL); 256 if (!pdata->extd_stats) 257 return -ENOMEM; 258 259 xgene_get_extd_stats(pdata); 260 memset(pdata->extd_stats, 0, XGENE_EXTD_STATS_LEN * sizeof(u64)); 261 262 return 0; 263 } 264 265 static void xgene_get_ethtool_stats(struct net_device *ndev, 266 struct ethtool_stats *dummy, 267 u64 *data) 268 { 269 struct xgene_enet_pdata *pdata = netdev_priv(ndev); 270 struct rtnl_link_stats64 stats; 271 int i; 272 273 dev_get_stats(ndev, &stats); 274 for (i = 0; i < XGENE_STATS_LEN; i++) 275 data[i] = *(u64 *)((char *)&stats + gstrings_stats[i].offset); 276 277 xgene_get_extd_stats(pdata); 278 for (i = 0; i < XGENE_EXTD_STATS_LEN; i++) 279 data[i + XGENE_STATS_LEN] = pdata->extd_stats[i]; 280 } 281 282 static void xgene_get_pauseparam(struct net_device *ndev, 283 struct ethtool_pauseparam *pp) 284 { 285 struct xgene_enet_pdata *pdata = netdev_priv(ndev); 286 287 pp->autoneg = pdata->pause_autoneg; 288 pp->tx_pause = pdata->tx_pause; 289 pp->rx_pause = pdata->rx_pause; 290 } 291 292 static int xgene_set_pauseparam(struct net_device *ndev, 293 struct ethtool_pauseparam *pp) 294 { 295 struct xgene_enet_pdata *pdata = netdev_priv(ndev); 296 struct phy_device *phydev = ndev->phydev; 297 298 if (phy_interface_mode_is_rgmii(pdata->phy_mode) || 299 pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) { 300 if (!phydev) 301 return -EINVAL; 302 303 if (!phy_validate_pause(phydev, pp)) 304 return -EINVAL; 305 306 pdata->pause_autoneg = pp->autoneg; 307 pdata->tx_pause = pp->tx_pause; 308 pdata->rx_pause = pp->rx_pause; 309 310 phy_set_asym_pause(phydev, pp->rx_pause, pp->tx_pause); 311 312 if (!pp->autoneg) { 313 pdata->mac_ops->flowctl_tx(pdata, pdata->tx_pause); 314 pdata->mac_ops->flowctl_rx(pdata, pdata->rx_pause); 315 } 316 } else { 317 if (pp->autoneg) 318 return -EINVAL; 319 320 pdata->tx_pause = pp->tx_pause; 321 pdata->rx_pause = pp->rx_pause; 322 323 pdata->mac_ops->flowctl_tx(pdata, pdata->tx_pause); 324 pdata->mac_ops->flowctl_rx(pdata, pdata->rx_pause); 325 } 326 327 return 0; 328 } 329 330 static const struct ethtool_ops xgene_ethtool_ops = { 331 .get_drvinfo = xgene_get_drvinfo, 332 .get_link = ethtool_op_get_link, 333 .get_strings = xgene_get_strings, 334 .get_sset_count = xgene_get_sset_count, 335 .get_ethtool_stats = xgene_get_ethtool_stats, 336 .get_link_ksettings = xgene_get_link_ksettings, 337 .set_link_ksettings = xgene_set_link_ksettings, 338 .get_pauseparam = xgene_get_pauseparam, 339 .set_pauseparam = xgene_set_pauseparam 340 }; 341 342 void xgene_enet_set_ethtool_ops(struct net_device *ndev) 343 { 344 ndev->ethtool_ops = &xgene_ethtool_ops; 345 } 346