1 /* Applied Micro X-Gene SoC Ethernet Driver 2 * 3 * Copyright (c) 2014, Applied Micro Circuits Corporation 4 * Authors: Iyappan Subramanian <isubramanian@apm.com> 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the 8 * Free Software Foundation; either version 2 of the License, or (at your 9 * option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include <linux/ethtool.h> 21 #include "xgene_enet_main.h" 22 23 struct xgene_gstrings_stats { 24 char name[ETH_GSTRING_LEN]; 25 int offset; 26 }; 27 28 #define XGENE_STAT(m) { #m, offsetof(struct xgene_enet_pdata, stats.m) } 29 30 static const struct xgene_gstrings_stats gstrings_stats[] = { 31 XGENE_STAT(rx_packets), 32 XGENE_STAT(tx_packets), 33 XGENE_STAT(rx_bytes), 34 XGENE_STAT(tx_bytes), 35 XGENE_STAT(rx_errors), 36 XGENE_STAT(tx_errors), 37 XGENE_STAT(rx_length_errors), 38 XGENE_STAT(rx_crc_errors), 39 XGENE_STAT(rx_frame_errors), 40 XGENE_STAT(rx_fifo_errors) 41 }; 42 43 #define XGENE_STATS_LEN ARRAY_SIZE(gstrings_stats) 44 45 static void xgene_get_drvinfo(struct net_device *ndev, 46 struct ethtool_drvinfo *info) 47 { 48 struct xgene_enet_pdata *pdata = netdev_priv(ndev); 49 struct platform_device *pdev = pdata->pdev; 50 51 strcpy(info->driver, "xgene_enet"); 52 strcpy(info->version, XGENE_DRV_VERSION); 53 snprintf(info->fw_version, ETHTOOL_FWVERS_LEN, "N/A"); 54 sprintf(info->bus_info, "%s", pdev->name); 55 } 56 57 static int xgene_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd) 58 { 59 struct xgene_enet_pdata *pdata = netdev_priv(ndev); 60 struct phy_device *phydev = pdata->phy_dev; 61 62 if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { 63 if (phydev == NULL) 64 return -ENODEV; 65 66 return phy_ethtool_gset(phydev, cmd); 67 } else if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) { 68 if (pdata->mdio_driver) { 69 if (!phydev) 70 return -ENODEV; 71 72 return phy_ethtool_gset(phydev, cmd); 73 } 74 75 cmd->supported = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | 76 SUPPORTED_MII; 77 cmd->advertising = cmd->supported; 78 ethtool_cmd_speed_set(cmd, SPEED_1000); 79 cmd->duplex = DUPLEX_FULL; 80 cmd->port = PORT_MII; 81 cmd->transceiver = XCVR_INTERNAL; 82 cmd->autoneg = AUTONEG_ENABLE; 83 } else { 84 cmd->supported = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE; 85 cmd->advertising = cmd->supported; 86 ethtool_cmd_speed_set(cmd, SPEED_10000); 87 cmd->duplex = DUPLEX_FULL; 88 cmd->port = PORT_FIBRE; 89 cmd->transceiver = XCVR_INTERNAL; 90 cmd->autoneg = AUTONEG_DISABLE; 91 } 92 93 return 0; 94 } 95 96 static int xgene_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd) 97 { 98 struct xgene_enet_pdata *pdata = netdev_priv(ndev); 99 struct phy_device *phydev = pdata->phy_dev; 100 101 if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { 102 if (!phydev) 103 return -ENODEV; 104 105 return phy_ethtool_sset(phydev, cmd); 106 } 107 108 if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) { 109 if (pdata->mdio_driver) { 110 if (!phydev) 111 return -ENODEV; 112 113 return phy_ethtool_sset(phydev, cmd); 114 } 115 } 116 117 return -EINVAL; 118 } 119 120 static void xgene_get_strings(struct net_device *ndev, u32 stringset, u8 *data) 121 { 122 int i; 123 u8 *p = data; 124 125 if (stringset != ETH_SS_STATS) 126 return; 127 128 for (i = 0; i < XGENE_STATS_LEN; i++) { 129 memcpy(p, gstrings_stats[i].name, ETH_GSTRING_LEN); 130 p += ETH_GSTRING_LEN; 131 } 132 } 133 134 static int xgene_get_sset_count(struct net_device *ndev, int sset) 135 { 136 if (sset != ETH_SS_STATS) 137 return -EINVAL; 138 139 return XGENE_STATS_LEN; 140 } 141 142 static void xgene_get_ethtool_stats(struct net_device *ndev, 143 struct ethtool_stats *dummy, 144 u64 *data) 145 { 146 void *pdata = netdev_priv(ndev); 147 int i; 148 149 for (i = 0; i < XGENE_STATS_LEN; i++) 150 *data++ = *(u64 *)(pdata + gstrings_stats[i].offset); 151 } 152 153 static const struct ethtool_ops xgene_ethtool_ops = { 154 .get_drvinfo = xgene_get_drvinfo, 155 .get_settings = xgene_get_settings, 156 .set_settings = xgene_set_settings, 157 .get_link = ethtool_op_get_link, 158 .get_strings = xgene_get_strings, 159 .get_sset_count = xgene_get_sset_count, 160 .get_ethtool_stats = xgene_get_ethtool_stats 161 }; 162 163 void xgene_enet_set_ethtool_ops(struct net_device *ndev) 164 { 165 ndev->ethtool_ops = &xgene_ethtool_ops; 166 } 167