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; 26e6ad7673SIyappan Subramanian }; 27e6ad7673SIyappan Subramanian 28e6ad7673SIyappan Subramanian #define XGENE_STAT(m) { #m, offsetof(struct xgene_enet_pdata, stats.m) } 29e6ad7673SIyappan Subramanian 30e6ad7673SIyappan Subramanian static const struct xgene_gstrings_stats gstrings_stats[] = { 31e6ad7673SIyappan Subramanian XGENE_STAT(rx_packets), 32e6ad7673SIyappan Subramanian XGENE_STAT(tx_packets), 33e6ad7673SIyappan Subramanian XGENE_STAT(rx_bytes), 34e6ad7673SIyappan Subramanian XGENE_STAT(tx_bytes), 35e6ad7673SIyappan Subramanian XGENE_STAT(rx_errors), 36e6ad7673SIyappan Subramanian XGENE_STAT(tx_errors), 37e6ad7673SIyappan Subramanian XGENE_STAT(rx_length_errors), 38e6ad7673SIyappan Subramanian XGENE_STAT(rx_crc_errors), 39e6ad7673SIyappan Subramanian XGENE_STAT(rx_frame_errors), 40e6ad7673SIyappan Subramanian XGENE_STAT(rx_fifo_errors) 41e6ad7673SIyappan Subramanian }; 42e6ad7673SIyappan Subramanian 43e6ad7673SIyappan Subramanian #define XGENE_STATS_LEN ARRAY_SIZE(gstrings_stats) 44e6ad7673SIyappan Subramanian 45e6ad7673SIyappan Subramanian static void xgene_get_drvinfo(struct net_device *ndev, 46e6ad7673SIyappan Subramanian struct ethtool_drvinfo *info) 47e6ad7673SIyappan Subramanian { 48e6ad7673SIyappan Subramanian struct xgene_enet_pdata *pdata = netdev_priv(ndev); 49e6ad7673SIyappan Subramanian struct platform_device *pdev = pdata->pdev; 50e6ad7673SIyappan Subramanian 51e6ad7673SIyappan Subramanian strcpy(info->driver, "xgene_enet"); 52e6ad7673SIyappan Subramanian strcpy(info->version, XGENE_DRV_VERSION); 53e6ad7673SIyappan Subramanian snprintf(info->fw_version, ETHTOOL_FWVERS_LEN, "N/A"); 54e6ad7673SIyappan Subramanian sprintf(info->bus_info, "%s", pdev->name); 55e6ad7673SIyappan Subramanian } 56e6ad7673SIyappan Subramanian 5736a19b29SPhilippe Reynes static int xgene_get_link_ksettings(struct net_device *ndev, 5836a19b29SPhilippe Reynes struct ethtool_link_ksettings *cmd) 59e6ad7673SIyappan Subramanian { 60e6ad7673SIyappan Subramanian struct xgene_enet_pdata *pdata = netdev_priv(ndev); 61971d3a44SPhilippe Reynes struct phy_device *phydev = ndev->phydev; 6236a19b29SPhilippe Reynes u32 supported; 63e6ad7673SIyappan Subramanian 6441aace6eSIyappan Subramanian if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { 65e6ad7673SIyappan Subramanian if (phydev == NULL) 66e6ad7673SIyappan Subramanian return -ENODEV; 67e6ad7673SIyappan Subramanian 6836a19b29SPhilippe Reynes return phy_ethtool_ksettings_get(phydev, cmd); 695e6a024bSIyappan Subramanian } else if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) { 7052d1fd99SIyappan Subramanian if (pdata->mdio_driver) { 7152d1fd99SIyappan Subramanian if (!phydev) 7252d1fd99SIyappan Subramanian return -ENODEV; 7352d1fd99SIyappan Subramanian 7436a19b29SPhilippe Reynes return phy_ethtool_ksettings_get(phydev, cmd); 7552d1fd99SIyappan Subramanian } 7652d1fd99SIyappan Subramanian 7736a19b29SPhilippe Reynes supported = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | 7852d1fd99SIyappan Subramanian SUPPORTED_MII; 7936a19b29SPhilippe Reynes ethtool_convert_legacy_u32_to_link_mode( 8036a19b29SPhilippe Reynes cmd->link_modes.supported, 8136a19b29SPhilippe Reynes supported); 8236a19b29SPhilippe Reynes ethtool_convert_legacy_u32_to_link_mode( 8336a19b29SPhilippe Reynes cmd->link_modes.advertising, 8436a19b29SPhilippe Reynes supported); 8536a19b29SPhilippe Reynes 8636a19b29SPhilippe Reynes cmd->base.speed = SPEED_1000; 8736a19b29SPhilippe Reynes cmd->base.duplex = DUPLEX_FULL; 8836a19b29SPhilippe Reynes cmd->base.port = PORT_MII; 8936a19b29SPhilippe Reynes cmd->base.autoneg = AUTONEG_ENABLE; 905e6a024bSIyappan Subramanian } else { 9136a19b29SPhilippe Reynes supported = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE; 9236a19b29SPhilippe Reynes ethtool_convert_legacy_u32_to_link_mode( 9336a19b29SPhilippe Reynes cmd->link_modes.supported, 9436a19b29SPhilippe Reynes supported); 9536a19b29SPhilippe Reynes ethtool_convert_legacy_u32_to_link_mode( 9636a19b29SPhilippe Reynes cmd->link_modes.advertising, 9736a19b29SPhilippe Reynes supported); 9836a19b29SPhilippe Reynes 9936a19b29SPhilippe Reynes cmd->base.speed = SPEED_10000; 10036a19b29SPhilippe Reynes cmd->base.duplex = DUPLEX_FULL; 10136a19b29SPhilippe Reynes cmd->base.port = PORT_FIBRE; 10236a19b29SPhilippe Reynes cmd->base.autoneg = AUTONEG_DISABLE; 1035e6a024bSIyappan Subramanian } 10441aace6eSIyappan Subramanian 10541aace6eSIyappan Subramanian return 0; 10641aace6eSIyappan Subramanian } 10741aace6eSIyappan Subramanian 10836a19b29SPhilippe Reynes static int xgene_set_link_ksettings(struct net_device *ndev, 10936a19b29SPhilippe Reynes const struct ethtool_link_ksettings *cmd) 110e6ad7673SIyappan Subramanian { 111e6ad7673SIyappan Subramanian struct xgene_enet_pdata *pdata = netdev_priv(ndev); 112971d3a44SPhilippe Reynes struct phy_device *phydev = ndev->phydev; 113e6ad7673SIyappan Subramanian 11441aace6eSIyappan Subramanian if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { 11552d1fd99SIyappan Subramanian if (!phydev) 116e6ad7673SIyappan Subramanian return -ENODEV; 117e6ad7673SIyappan Subramanian 11836a19b29SPhilippe Reynes return phy_ethtool_ksettings_set(phydev, cmd); 119e6ad7673SIyappan Subramanian } 120e6ad7673SIyappan Subramanian 12152d1fd99SIyappan Subramanian if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) { 12252d1fd99SIyappan Subramanian if (pdata->mdio_driver) { 12352d1fd99SIyappan Subramanian if (!phydev) 12452d1fd99SIyappan Subramanian return -ENODEV; 12552d1fd99SIyappan Subramanian 12636a19b29SPhilippe Reynes return phy_ethtool_ksettings_set(phydev, cmd); 12752d1fd99SIyappan Subramanian } 12852d1fd99SIyappan Subramanian } 12952d1fd99SIyappan Subramanian 13041aace6eSIyappan Subramanian return -EINVAL; 13141aace6eSIyappan Subramanian } 13241aace6eSIyappan Subramanian 133e6ad7673SIyappan Subramanian static void xgene_get_strings(struct net_device *ndev, u32 stringset, u8 *data) 134e6ad7673SIyappan Subramanian { 135e6ad7673SIyappan Subramanian int i; 136e6ad7673SIyappan Subramanian u8 *p = data; 137e6ad7673SIyappan Subramanian 138e6ad7673SIyappan Subramanian if (stringset != ETH_SS_STATS) 139e6ad7673SIyappan Subramanian return; 140e6ad7673SIyappan Subramanian 141e6ad7673SIyappan Subramanian for (i = 0; i < XGENE_STATS_LEN; i++) { 142e6ad7673SIyappan Subramanian memcpy(p, gstrings_stats[i].name, ETH_GSTRING_LEN); 143e6ad7673SIyappan Subramanian p += ETH_GSTRING_LEN; 144e6ad7673SIyappan Subramanian } 145e6ad7673SIyappan Subramanian } 146e6ad7673SIyappan Subramanian 147e6ad7673SIyappan Subramanian static int xgene_get_sset_count(struct net_device *ndev, int sset) 148e6ad7673SIyappan Subramanian { 149e6ad7673SIyappan Subramanian if (sset != ETH_SS_STATS) 150e6ad7673SIyappan Subramanian return -EINVAL; 151e6ad7673SIyappan Subramanian 152e6ad7673SIyappan Subramanian return XGENE_STATS_LEN; 153e6ad7673SIyappan Subramanian } 154e6ad7673SIyappan Subramanian 155e6ad7673SIyappan Subramanian static void xgene_get_ethtool_stats(struct net_device *ndev, 156e6ad7673SIyappan Subramanian struct ethtool_stats *dummy, 157e6ad7673SIyappan Subramanian u64 *data) 158e6ad7673SIyappan Subramanian { 159e6ad7673SIyappan Subramanian void *pdata = netdev_priv(ndev); 160e6ad7673SIyappan Subramanian int i; 161e6ad7673SIyappan Subramanian 162e6ad7673SIyappan Subramanian for (i = 0; i < XGENE_STATS_LEN; i++) 163e6ad7673SIyappan Subramanian *data++ = *(u64 *)(pdata + gstrings_stats[i].offset); 164e6ad7673SIyappan Subramanian } 165e6ad7673SIyappan Subramanian 166e6ad7673SIyappan Subramanian static const struct ethtool_ops xgene_ethtool_ops = { 167e6ad7673SIyappan Subramanian .get_drvinfo = xgene_get_drvinfo, 168e6ad7673SIyappan Subramanian .get_link = ethtool_op_get_link, 169e6ad7673SIyappan Subramanian .get_strings = xgene_get_strings, 170e6ad7673SIyappan Subramanian .get_sset_count = xgene_get_sset_count, 17136a19b29SPhilippe Reynes .get_ethtool_stats = xgene_get_ethtool_stats, 17236a19b29SPhilippe Reynes .get_link_ksettings = xgene_get_link_ksettings, 17336a19b29SPhilippe Reynes .set_link_ksettings = xgene_set_link_ksettings, 174e6ad7673SIyappan Subramanian }; 175e6ad7673SIyappan Subramanian 176e6ad7673SIyappan Subramanian void xgene_enet_set_ethtool_ops(struct net_device *ndev) 177e6ad7673SIyappan Subramanian { 178e6ad7673SIyappan Subramanian ndev->ethtool_ops = &xgene_ethtool_ops; 179e6ad7673SIyappan Subramanian } 180