1e6ad7673SIyappan Subramanian /* Applied Micro X-Gene SoC Ethernet Driver 2e6ad7673SIyappan Subramanian * 3e6ad7673SIyappan Subramanian * Copyright (c) 2014, Applied Micro Circuits Corporation 4e6ad7673SIyappan Subramanian * Authors: Iyappan Subramanian <isubramanian@apm.com> 5e6ad7673SIyappan Subramanian * 6e6ad7673SIyappan Subramanian * This program is free software; you can redistribute it and/or modify it 7e6ad7673SIyappan Subramanian * under the terms of the GNU General Public License as published by the 8e6ad7673SIyappan Subramanian * Free Software Foundation; either version 2 of the License, or (at your 9e6ad7673SIyappan Subramanian * option) any later version. 10e6ad7673SIyappan Subramanian * 11e6ad7673SIyappan Subramanian * This program is distributed in the hope that it will be useful, 12e6ad7673SIyappan Subramanian * but WITHOUT ANY WARRANTY; without even the implied warranty of 13e6ad7673SIyappan Subramanian * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14e6ad7673SIyappan Subramanian * GNU General Public License for more details. 15e6ad7673SIyappan Subramanian * 16e6ad7673SIyappan Subramanian * You should have received a copy of the GNU General Public License 17e6ad7673SIyappan Subramanian * along with this program. If not, see <http://www.gnu.org/licenses/>. 18e6ad7673SIyappan Subramanian */ 19e6ad7673SIyappan Subramanian 20e6ad7673SIyappan Subramanian #include <linux/ethtool.h> 21e6ad7673SIyappan Subramanian #include "xgene_enet_main.h" 22e6ad7673SIyappan Subramanian 23e6ad7673SIyappan Subramanian struct xgene_gstrings_stats { 24e6ad7673SIyappan Subramanian char name[ETH_GSTRING_LEN]; 25e6ad7673SIyappan Subramanian int offset; 262d07d8e4SQuan Nguyen u32 addr; 272d07d8e4SQuan Nguyen u32 mask; 28e6ad7673SIyappan Subramanian }; 29e6ad7673SIyappan Subramanian 303f5a2ef1SQuan Nguyen #define XGENE_STAT(m) { #m, offsetof(struct rtnl_link_stats64, m) } 312d07d8e4SQuan Nguyen #define XGENE_EXTD_STAT(s, a, m) \ 322d07d8e4SQuan Nguyen { \ 332d07d8e4SQuan Nguyen .name = #s, \ 342d07d8e4SQuan Nguyen .addr = a ## _ADDR, \ 352d07d8e4SQuan Nguyen .mask = m \ 362d07d8e4SQuan Nguyen } 37e6ad7673SIyappan Subramanian 38e6ad7673SIyappan Subramanian static const struct xgene_gstrings_stats gstrings_stats[] = { 39e6ad7673SIyappan Subramanian XGENE_STAT(rx_packets), 40e6ad7673SIyappan Subramanian XGENE_STAT(tx_packets), 41e6ad7673SIyappan Subramanian XGENE_STAT(rx_bytes), 42e6ad7673SIyappan Subramanian XGENE_STAT(tx_bytes), 43e6ad7673SIyappan Subramanian XGENE_STAT(rx_errors), 44e6ad7673SIyappan Subramanian XGENE_STAT(tx_errors), 45e6ad7673SIyappan Subramanian XGENE_STAT(rx_length_errors), 46e6ad7673SIyappan Subramanian XGENE_STAT(rx_crc_errors), 47e6ad7673SIyappan Subramanian XGENE_STAT(rx_frame_errors), 48e6ad7673SIyappan Subramanian XGENE_STAT(rx_fifo_errors) 49e6ad7673SIyappan Subramanian }; 50e6ad7673SIyappan Subramanian 512d07d8e4SQuan Nguyen static const struct xgene_gstrings_stats gstrings_extd_stats[] = { 522d07d8e4SQuan Nguyen XGENE_EXTD_STAT(tx_rx_64b_frame_cntr, TR64, 31), 532d07d8e4SQuan Nguyen XGENE_EXTD_STAT(tx_rx_127b_frame_cntr, TR127, 31), 542d07d8e4SQuan Nguyen XGENE_EXTD_STAT(tx_rx_255b_frame_cntr, TR255, 31), 552d07d8e4SQuan Nguyen XGENE_EXTD_STAT(tx_rx_511b_frame_cntr, TR511, 31), 562d07d8e4SQuan Nguyen XGENE_EXTD_STAT(tx_rx_1023b_frame_cntr, TR1K, 31), 572d07d8e4SQuan Nguyen XGENE_EXTD_STAT(tx_rx_1518b_frame_cntr, TRMAX, 31), 582d07d8e4SQuan Nguyen XGENE_EXTD_STAT(tx_rx_1522b_frame_cntr, TRMGV, 31), 592d07d8e4SQuan Nguyen XGENE_EXTD_STAT(rx_fcs_error_cntr, RFCS, 16), 602d07d8e4SQuan Nguyen XGENE_EXTD_STAT(rx_multicast_pkt_cntr, RMCA, 31), 612d07d8e4SQuan Nguyen XGENE_EXTD_STAT(rx_broadcast_pkt_cntr, RBCA, 31), 622d07d8e4SQuan Nguyen XGENE_EXTD_STAT(rx_ctrl_frame_pkt_cntr, RXCF, 16), 632d07d8e4SQuan Nguyen XGENE_EXTD_STAT(rx_pause_frame_pkt_cntr, RXPF, 16), 642d07d8e4SQuan Nguyen XGENE_EXTD_STAT(rx_unk_opcode_cntr, RXUO, 16), 652d07d8e4SQuan Nguyen XGENE_EXTD_STAT(rx_align_err_cntr, RALN, 16), 662d07d8e4SQuan Nguyen XGENE_EXTD_STAT(rx_frame_len_err_cntr, RFLR, 16), 67eaef62a4SQuan Nguyen XGENE_EXTD_STAT(rx_frame_len_err_recov_cntr, DUMP, 0), 682d07d8e4SQuan Nguyen XGENE_EXTD_STAT(rx_code_err_cntr, RCDE, 16), 692d07d8e4SQuan Nguyen XGENE_EXTD_STAT(rx_carrier_sense_err_cntr, RCSE, 16), 702d07d8e4SQuan Nguyen XGENE_EXTD_STAT(rx_undersize_pkt_cntr, RUND, 16), 712d07d8e4SQuan Nguyen XGENE_EXTD_STAT(rx_oversize_pkt_cntr, ROVR, 16), 722d07d8e4SQuan Nguyen XGENE_EXTD_STAT(rx_fragments_cntr, RFRG, 16), 732d07d8e4SQuan Nguyen XGENE_EXTD_STAT(rx_jabber_cntr, RJBR, 16), 7461c759cdSQuan Nguyen XGENE_EXTD_STAT(rx_jabber_recov_cntr, DUMP, 0), 752d07d8e4SQuan Nguyen XGENE_EXTD_STAT(rx_dropped_pkt_cntr, RDRP, 16), 76ca6d550cSIyappan Subramanian XGENE_EXTD_STAT(rx_overrun_cntr, DUMP, 0), 772d07d8e4SQuan Nguyen XGENE_EXTD_STAT(tx_multicast_pkt_cntr, TMCA, 31), 782d07d8e4SQuan Nguyen XGENE_EXTD_STAT(tx_broadcast_pkt_cntr, TBCA, 31), 792d07d8e4SQuan Nguyen XGENE_EXTD_STAT(tx_pause_ctrl_frame_cntr, TXPF, 16), 802d07d8e4SQuan Nguyen XGENE_EXTD_STAT(tx_defer_pkt_cntr, TDFR, 31), 812d07d8e4SQuan Nguyen XGENE_EXTD_STAT(tx_excv_defer_pkt_cntr, TEDF, 31), 822d07d8e4SQuan Nguyen XGENE_EXTD_STAT(tx_single_col_pkt_cntr, TSCL, 31), 832d07d8e4SQuan Nguyen XGENE_EXTD_STAT(tx_multi_col_pkt_cntr, TMCL, 31), 842d07d8e4SQuan Nguyen XGENE_EXTD_STAT(tx_late_col_pkt_cntr, TLCL, 31), 852d07d8e4SQuan Nguyen XGENE_EXTD_STAT(tx_excv_col_pkt_cntr, TXCL, 31), 862d07d8e4SQuan Nguyen XGENE_EXTD_STAT(tx_total_col_cntr, TNCL, 31), 872d07d8e4SQuan Nguyen XGENE_EXTD_STAT(tx_pause_frames_hnrd_cntr, TPFH, 16), 882d07d8e4SQuan Nguyen XGENE_EXTD_STAT(tx_drop_frame_cntr, TDRP, 16), 892d07d8e4SQuan Nguyen XGENE_EXTD_STAT(tx_jabber_frame_cntr, TJBR, 12), 902d07d8e4SQuan Nguyen XGENE_EXTD_STAT(tx_fcs_error_cntr, TFCS, 12), 912d07d8e4SQuan Nguyen XGENE_EXTD_STAT(tx_ctrl_frame_cntr, TXCF, 12), 922d07d8e4SQuan Nguyen XGENE_EXTD_STAT(tx_oversize_frame_cntr, TOVR, 12), 932d07d8e4SQuan Nguyen XGENE_EXTD_STAT(tx_undersize_frame_cntr, TUND, 12), 94ca6d550cSIyappan Subramanian XGENE_EXTD_STAT(tx_fragments_cntr, TFRG, 12), 95ca6d550cSIyappan Subramanian XGENE_EXTD_STAT(tx_underrun_cntr, DUMP, 0) 962d07d8e4SQuan Nguyen }; 972d07d8e4SQuan Nguyen 98e6ad7673SIyappan Subramanian #define XGENE_STATS_LEN ARRAY_SIZE(gstrings_stats) 992d07d8e4SQuan Nguyen #define XGENE_EXTD_STATS_LEN ARRAY_SIZE(gstrings_extd_stats) 10061c759cdSQuan Nguyen #define RFCS_IDX 7 10161c759cdSQuan Nguyen #define RALN_IDX 13 10261c759cdSQuan Nguyen #define RFLR_IDX 14 103eaef62a4SQuan Nguyen #define FALSE_RFLR_IDX 15 10461c759cdSQuan Nguyen #define RUND_IDX 18 10561c759cdSQuan Nguyen #define FALSE_RJBR_IDX 22 10661c759cdSQuan Nguyen #define RX_OVERRUN_IDX 24 10761c759cdSQuan Nguyen #define TFCS_IDX 38 10861c759cdSQuan Nguyen #define TFRG_IDX 42 10961c759cdSQuan Nguyen #define TX_UNDERRUN_IDX 43 110e6ad7673SIyappan Subramanian 111e6ad7673SIyappan Subramanian static void xgene_get_drvinfo(struct net_device *ndev, 112e6ad7673SIyappan Subramanian struct ethtool_drvinfo *info) 113e6ad7673SIyappan Subramanian { 114e6ad7673SIyappan Subramanian struct xgene_enet_pdata *pdata = netdev_priv(ndev); 115e6ad7673SIyappan Subramanian struct platform_device *pdev = pdata->pdev; 116e6ad7673SIyappan Subramanian 117e6ad7673SIyappan Subramanian strcpy(info->driver, "xgene_enet"); 118e6ad7673SIyappan Subramanian strcpy(info->version, XGENE_DRV_VERSION); 119e6ad7673SIyappan Subramanian snprintf(info->fw_version, ETHTOOL_FWVERS_LEN, "N/A"); 120e6ad7673SIyappan Subramanian sprintf(info->bus_info, "%s", pdev->name); 121e6ad7673SIyappan Subramanian } 122e6ad7673SIyappan Subramanian 12336a19b29SPhilippe Reynes static int xgene_get_link_ksettings(struct net_device *ndev, 12436a19b29SPhilippe Reynes struct ethtool_link_ksettings *cmd) 125e6ad7673SIyappan Subramanian { 126e6ad7673SIyappan Subramanian struct xgene_enet_pdata *pdata = netdev_priv(ndev); 127971d3a44SPhilippe Reynes struct phy_device *phydev = ndev->phydev; 12836a19b29SPhilippe Reynes u32 supported; 129e6ad7673SIyappan Subramanian 130326dde3eSIyappan Subramanian if (phy_interface_mode_is_rgmii(pdata->phy_mode)) { 131e6ad7673SIyappan Subramanian if (phydev == NULL) 132e6ad7673SIyappan Subramanian return -ENODEV; 133e6ad7673SIyappan Subramanian 1345514174fSyuval.shaia@oracle.com phy_ethtool_ksettings_get(phydev, cmd); 1355514174fSyuval.shaia@oracle.com 1365514174fSyuval.shaia@oracle.com return 0; 1375e6a024bSIyappan Subramanian } else if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) { 13852d1fd99SIyappan Subramanian if (pdata->mdio_driver) { 13952d1fd99SIyappan Subramanian if (!phydev) 14052d1fd99SIyappan Subramanian return -ENODEV; 14152d1fd99SIyappan Subramanian 1425514174fSyuval.shaia@oracle.com phy_ethtool_ksettings_get(phydev, cmd); 1435514174fSyuval.shaia@oracle.com 1445514174fSyuval.shaia@oracle.com return 0; 14552d1fd99SIyappan Subramanian } 14652d1fd99SIyappan Subramanian 14736a19b29SPhilippe Reynes supported = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | 14852d1fd99SIyappan Subramanian SUPPORTED_MII; 14936a19b29SPhilippe Reynes ethtool_convert_legacy_u32_to_link_mode( 15036a19b29SPhilippe Reynes cmd->link_modes.supported, 15136a19b29SPhilippe Reynes supported); 15236a19b29SPhilippe Reynes ethtool_convert_legacy_u32_to_link_mode( 15336a19b29SPhilippe Reynes cmd->link_modes.advertising, 15436a19b29SPhilippe Reynes supported); 15536a19b29SPhilippe Reynes 15636a19b29SPhilippe Reynes cmd->base.speed = SPEED_1000; 15736a19b29SPhilippe Reynes cmd->base.duplex = DUPLEX_FULL; 15836a19b29SPhilippe Reynes cmd->base.port = PORT_MII; 15936a19b29SPhilippe Reynes cmd->base.autoneg = AUTONEG_ENABLE; 1605e6a024bSIyappan Subramanian } else { 16136a19b29SPhilippe Reynes supported = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE; 16236a19b29SPhilippe Reynes ethtool_convert_legacy_u32_to_link_mode( 16336a19b29SPhilippe Reynes cmd->link_modes.supported, 16436a19b29SPhilippe Reynes supported); 16536a19b29SPhilippe Reynes ethtool_convert_legacy_u32_to_link_mode( 16636a19b29SPhilippe Reynes cmd->link_modes.advertising, 16736a19b29SPhilippe Reynes supported); 16836a19b29SPhilippe Reynes 16936a19b29SPhilippe Reynes cmd->base.speed = SPEED_10000; 17036a19b29SPhilippe Reynes cmd->base.duplex = DUPLEX_FULL; 17136a19b29SPhilippe Reynes cmd->base.port = PORT_FIBRE; 17236a19b29SPhilippe Reynes cmd->base.autoneg = AUTONEG_DISABLE; 1735e6a024bSIyappan Subramanian } 17441aace6eSIyappan Subramanian 17541aace6eSIyappan Subramanian return 0; 17641aace6eSIyappan Subramanian } 17741aace6eSIyappan Subramanian 17836a19b29SPhilippe Reynes static int xgene_set_link_ksettings(struct net_device *ndev, 17936a19b29SPhilippe Reynes const struct ethtool_link_ksettings *cmd) 180e6ad7673SIyappan Subramanian { 181e6ad7673SIyappan Subramanian struct xgene_enet_pdata *pdata = netdev_priv(ndev); 182971d3a44SPhilippe Reynes struct phy_device *phydev = ndev->phydev; 183e6ad7673SIyappan Subramanian 184326dde3eSIyappan Subramanian if (phy_interface_mode_is_rgmii(pdata->phy_mode)) { 18552d1fd99SIyappan Subramanian if (!phydev) 186e6ad7673SIyappan Subramanian return -ENODEV; 187e6ad7673SIyappan Subramanian 18836a19b29SPhilippe Reynes return phy_ethtool_ksettings_set(phydev, cmd); 189e6ad7673SIyappan Subramanian } 190e6ad7673SIyappan Subramanian 19152d1fd99SIyappan Subramanian if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) { 19252d1fd99SIyappan Subramanian if (pdata->mdio_driver) { 19352d1fd99SIyappan Subramanian if (!phydev) 19452d1fd99SIyappan Subramanian return -ENODEV; 19552d1fd99SIyappan Subramanian 19636a19b29SPhilippe Reynes return phy_ethtool_ksettings_set(phydev, cmd); 19752d1fd99SIyappan Subramanian } 19852d1fd99SIyappan Subramanian } 19952d1fd99SIyappan Subramanian 20041aace6eSIyappan Subramanian return -EINVAL; 20141aace6eSIyappan Subramanian } 20241aace6eSIyappan Subramanian 203e6ad7673SIyappan Subramanian static void xgene_get_strings(struct net_device *ndev, u32 stringset, u8 *data) 204e6ad7673SIyappan Subramanian { 205e6ad7673SIyappan Subramanian int i; 206e6ad7673SIyappan Subramanian u8 *p = data; 207e6ad7673SIyappan Subramanian 208e6ad7673SIyappan Subramanian if (stringset != ETH_SS_STATS) 209e6ad7673SIyappan Subramanian return; 210e6ad7673SIyappan Subramanian 211e6ad7673SIyappan Subramanian for (i = 0; i < XGENE_STATS_LEN; i++) { 212e6ad7673SIyappan Subramanian memcpy(p, gstrings_stats[i].name, ETH_GSTRING_LEN); 213e6ad7673SIyappan Subramanian p += ETH_GSTRING_LEN; 214e6ad7673SIyappan Subramanian } 2152d07d8e4SQuan Nguyen 2162d07d8e4SQuan Nguyen for (i = 0; i < XGENE_EXTD_STATS_LEN; i++) { 2172d07d8e4SQuan Nguyen memcpy(p, gstrings_extd_stats[i].name, ETH_GSTRING_LEN); 2182d07d8e4SQuan Nguyen p += ETH_GSTRING_LEN; 2192d07d8e4SQuan Nguyen } 220e6ad7673SIyappan Subramanian } 221e6ad7673SIyappan Subramanian 222e6ad7673SIyappan Subramanian static int xgene_get_sset_count(struct net_device *ndev, int sset) 223e6ad7673SIyappan Subramanian { 224e6ad7673SIyappan Subramanian if (sset != ETH_SS_STATS) 225e6ad7673SIyappan Subramanian return -EINVAL; 226e6ad7673SIyappan Subramanian 2272d07d8e4SQuan Nguyen return XGENE_STATS_LEN + XGENE_EXTD_STATS_LEN; 2282d07d8e4SQuan Nguyen } 2292d07d8e4SQuan Nguyen 2302d07d8e4SQuan Nguyen static void xgene_get_extd_stats(struct xgene_enet_pdata *pdata) 2312d07d8e4SQuan Nguyen { 232ca6d550cSIyappan Subramanian u32 rx_drop, tx_drop; 23361c759cdSQuan Nguyen u32 mask, tmp; 2342d07d8e4SQuan Nguyen int i; 2352d07d8e4SQuan Nguyen 2362d07d8e4SQuan Nguyen for (i = 0; i < XGENE_EXTD_STATS_LEN; i++) { 2372d07d8e4SQuan Nguyen tmp = xgene_enet_rd_stat(pdata, gstrings_extd_stats[i].addr); 23861c759cdSQuan Nguyen if (gstrings_extd_stats[i].mask) { 23961c759cdSQuan Nguyen mask = GENMASK(gstrings_extd_stats[i].mask - 1, 0); 24061c759cdSQuan Nguyen pdata->extd_stats[i] += (tmp & mask); 24161c759cdSQuan Nguyen } 24261c759cdSQuan Nguyen } 24361c759cdSQuan Nguyen 24461c759cdSQuan Nguyen if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) { 24561c759cdSQuan Nguyen /* Errata 10GE_10 - SW should intepret RALN as 0 */ 24661c759cdSQuan Nguyen pdata->extd_stats[RALN_IDX] = 0; 24761c759cdSQuan Nguyen } else { 24861c759cdSQuan Nguyen /* Errata ENET_15 - Fixes RFCS, RFLR, TFCS counter */ 24961c759cdSQuan Nguyen pdata->extd_stats[RFCS_IDX] -= pdata->extd_stats[RALN_IDX]; 25061c759cdSQuan Nguyen pdata->extd_stats[RFLR_IDX] -= pdata->extd_stats[RUND_IDX]; 25161c759cdSQuan Nguyen pdata->extd_stats[TFCS_IDX] -= pdata->extd_stats[TFRG_IDX]; 2522d07d8e4SQuan Nguyen } 253ca6d550cSIyappan Subramanian 254ca6d550cSIyappan Subramanian pdata->mac_ops->get_drop_cnt(pdata, &rx_drop, &tx_drop); 255ca6d550cSIyappan Subramanian pdata->extd_stats[RX_OVERRUN_IDX] += rx_drop; 256ca6d550cSIyappan Subramanian pdata->extd_stats[TX_UNDERRUN_IDX] += tx_drop; 257eaef62a4SQuan Nguyen 258eaef62a4SQuan Nguyen /* Errata 10GE_8 - Update Frame recovered from Errata 10GE_8/ENET_11 */ 259eaef62a4SQuan Nguyen pdata->extd_stats[FALSE_RFLR_IDX] = pdata->false_rflr; 26061c759cdSQuan Nguyen /* Errata ENET_15 - Jabber Frame recov'ed from Errata 10GE_10/ENET_15 */ 26161c759cdSQuan Nguyen pdata->extd_stats[FALSE_RJBR_IDX] = pdata->vlan_rjbr; 2622d07d8e4SQuan Nguyen } 2632d07d8e4SQuan Nguyen 2642d07d8e4SQuan Nguyen int xgene_extd_stats_init(struct xgene_enet_pdata *pdata) 2652d07d8e4SQuan Nguyen { 2662d07d8e4SQuan Nguyen pdata->extd_stats = devm_kmalloc_array(&pdata->pdev->dev, 2672d07d8e4SQuan Nguyen XGENE_EXTD_STATS_LEN, sizeof(u64), GFP_KERNEL); 2682d07d8e4SQuan Nguyen if (!pdata->extd_stats) 2692d07d8e4SQuan Nguyen return -ENOMEM; 2702d07d8e4SQuan Nguyen 2712d07d8e4SQuan Nguyen xgene_get_extd_stats(pdata); 2722d07d8e4SQuan Nguyen memset(pdata->extd_stats, 0, XGENE_EXTD_STATS_LEN * sizeof(u64)); 2732d07d8e4SQuan Nguyen 2742d07d8e4SQuan Nguyen return 0; 275e6ad7673SIyappan Subramanian } 276e6ad7673SIyappan Subramanian 277e6ad7673SIyappan Subramanian static void xgene_get_ethtool_stats(struct net_device *ndev, 278e6ad7673SIyappan Subramanian struct ethtool_stats *dummy, 279e6ad7673SIyappan Subramanian u64 *data) 280e6ad7673SIyappan Subramanian { 2812d07d8e4SQuan Nguyen struct xgene_enet_pdata *pdata = netdev_priv(ndev); 2823f5a2ef1SQuan Nguyen struct rtnl_link_stats64 stats; 283e6ad7673SIyappan Subramanian int i; 284e6ad7673SIyappan Subramanian 2853f5a2ef1SQuan Nguyen dev_get_stats(ndev, &stats); 286e6ad7673SIyappan Subramanian for (i = 0; i < XGENE_STATS_LEN; i++) 2873f5a2ef1SQuan Nguyen data[i] = *(u64 *)((char *)&stats + gstrings_stats[i].offset); 2882d07d8e4SQuan Nguyen 2892d07d8e4SQuan Nguyen xgene_get_extd_stats(pdata); 2902d07d8e4SQuan Nguyen for (i = 0; i < XGENE_EXTD_STATS_LEN; i++) 2912d07d8e4SQuan Nguyen data[i + XGENE_STATS_LEN] = pdata->extd_stats[i]; 292e6ad7673SIyappan Subramanian } 293e6ad7673SIyappan Subramanian 2940296fe4dSIyappan Subramanian static void xgene_get_pauseparam(struct net_device *ndev, 2950296fe4dSIyappan Subramanian struct ethtool_pauseparam *pp) 2960296fe4dSIyappan Subramanian { 2970296fe4dSIyappan Subramanian struct xgene_enet_pdata *pdata = netdev_priv(ndev); 2980296fe4dSIyappan Subramanian 2990296fe4dSIyappan Subramanian pp->autoneg = pdata->pause_autoneg; 3000296fe4dSIyappan Subramanian pp->tx_pause = pdata->tx_pause; 3010296fe4dSIyappan Subramanian pp->rx_pause = pdata->rx_pause; 3020296fe4dSIyappan Subramanian } 3030296fe4dSIyappan Subramanian 3040296fe4dSIyappan Subramanian static int xgene_set_pauseparam(struct net_device *ndev, 3050296fe4dSIyappan Subramanian struct ethtool_pauseparam *pp) 3060296fe4dSIyappan Subramanian { 3070296fe4dSIyappan Subramanian struct xgene_enet_pdata *pdata = netdev_priv(ndev); 3080296fe4dSIyappan Subramanian struct phy_device *phydev = ndev->phydev; 3090296fe4dSIyappan Subramanian u32 oldadv, newadv; 3100296fe4dSIyappan Subramanian 311326dde3eSIyappan Subramanian if (phy_interface_mode_is_rgmii(pdata->phy_mode) || 3120296fe4dSIyappan Subramanian pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) { 3130296fe4dSIyappan Subramanian if (!phydev) 3140296fe4dSIyappan Subramanian return -EINVAL; 3150296fe4dSIyappan Subramanian 3160296fe4dSIyappan Subramanian if (!(phydev->supported & SUPPORTED_Pause) || 3170296fe4dSIyappan Subramanian (!(phydev->supported & SUPPORTED_Asym_Pause) && 3180296fe4dSIyappan Subramanian pp->rx_pause != pp->tx_pause)) 3190296fe4dSIyappan Subramanian return -EINVAL; 3200296fe4dSIyappan Subramanian 3210296fe4dSIyappan Subramanian pdata->pause_autoneg = pp->autoneg; 3220296fe4dSIyappan Subramanian pdata->tx_pause = pp->tx_pause; 3230296fe4dSIyappan Subramanian pdata->rx_pause = pp->rx_pause; 3240296fe4dSIyappan Subramanian 3250296fe4dSIyappan Subramanian oldadv = phydev->advertising; 3260296fe4dSIyappan Subramanian newadv = oldadv & ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause); 3270296fe4dSIyappan Subramanian 3280296fe4dSIyappan Subramanian if (pp->rx_pause) 3290296fe4dSIyappan Subramanian newadv |= ADVERTISED_Pause | ADVERTISED_Asym_Pause; 3300296fe4dSIyappan Subramanian 3310296fe4dSIyappan Subramanian if (pp->tx_pause) 3320296fe4dSIyappan Subramanian newadv ^= ADVERTISED_Asym_Pause; 3330296fe4dSIyappan Subramanian 3340296fe4dSIyappan Subramanian if (oldadv ^ newadv) { 3350296fe4dSIyappan Subramanian phydev->advertising = newadv; 3360296fe4dSIyappan Subramanian 3370296fe4dSIyappan Subramanian if (phydev->autoneg) 3380296fe4dSIyappan Subramanian return phy_start_aneg(phydev); 3390296fe4dSIyappan Subramanian 3400296fe4dSIyappan Subramanian if (!pp->autoneg) { 3410296fe4dSIyappan Subramanian pdata->mac_ops->flowctl_tx(pdata, 3420296fe4dSIyappan Subramanian pdata->tx_pause); 3430296fe4dSIyappan Subramanian pdata->mac_ops->flowctl_rx(pdata, 3440296fe4dSIyappan Subramanian pdata->rx_pause); 3450296fe4dSIyappan Subramanian } 3460296fe4dSIyappan Subramanian } 3470296fe4dSIyappan Subramanian 3480296fe4dSIyappan Subramanian } else { 3490296fe4dSIyappan Subramanian if (pp->autoneg) 3500296fe4dSIyappan Subramanian return -EINVAL; 3510296fe4dSIyappan Subramanian 3520296fe4dSIyappan Subramanian pdata->tx_pause = pp->tx_pause; 3530296fe4dSIyappan Subramanian pdata->rx_pause = pp->rx_pause; 3540296fe4dSIyappan Subramanian 3550296fe4dSIyappan Subramanian pdata->mac_ops->flowctl_tx(pdata, pdata->tx_pause); 3560296fe4dSIyappan Subramanian pdata->mac_ops->flowctl_rx(pdata, pdata->rx_pause); 3570296fe4dSIyappan Subramanian } 3580296fe4dSIyappan Subramanian 3590296fe4dSIyappan Subramanian return 0; 3600296fe4dSIyappan Subramanian } 3610296fe4dSIyappan Subramanian 362e6ad7673SIyappan Subramanian static const struct ethtool_ops xgene_ethtool_ops = { 363e6ad7673SIyappan Subramanian .get_drvinfo = xgene_get_drvinfo, 364e6ad7673SIyappan Subramanian .get_link = ethtool_op_get_link, 365e6ad7673SIyappan Subramanian .get_strings = xgene_get_strings, 366e6ad7673SIyappan Subramanian .get_sset_count = xgene_get_sset_count, 36736a19b29SPhilippe Reynes .get_ethtool_stats = xgene_get_ethtool_stats, 36836a19b29SPhilippe Reynes .get_link_ksettings = xgene_get_link_ksettings, 36936a19b29SPhilippe Reynes .set_link_ksettings = xgene_set_link_ksettings, 3700296fe4dSIyappan Subramanian .get_pauseparam = xgene_get_pauseparam, 3710296fe4dSIyappan Subramanian .set_pauseparam = xgene_set_pauseparam 372e6ad7673SIyappan Subramanian }; 373e6ad7673SIyappan Subramanian 374e6ad7673SIyappan Subramanian void xgene_enet_set_ethtool_ops(struct net_device *ndev) 375e6ad7673SIyappan Subramanian { 376e6ad7673SIyappan Subramanian ndev->ethtool_ops = &xgene_ethtool_ops; 377e6ad7673SIyappan Subramanian } 378