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 cmd->supported = SUPPORTED_1000baseT_Full | 69 SUPPORTED_Autoneg | SUPPORTED_MII; 70 cmd->advertising = cmd->supported; 71 ethtool_cmd_speed_set(cmd, SPEED_1000); 72 cmd->duplex = DUPLEX_FULL; 73 cmd->port = PORT_MII; 74 cmd->transceiver = XCVR_INTERNAL; 75 cmd->autoneg = AUTONEG_ENABLE; 76 } else { 77 cmd->supported = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE; 78 cmd->advertising = cmd->supported; 79 ethtool_cmd_speed_set(cmd, SPEED_10000); 80 cmd->duplex = DUPLEX_FULL; 81 cmd->port = PORT_FIBRE; 82 cmd->transceiver = XCVR_INTERNAL; 83 cmd->autoneg = AUTONEG_DISABLE; 84 } 85 86 return 0; 87 } 88 89 static int xgene_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd) 90 { 91 struct xgene_enet_pdata *pdata = netdev_priv(ndev); 92 struct phy_device *phydev = pdata->phy_dev; 93 94 if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { 95 if (phydev == NULL) 96 return -ENODEV; 97 98 return phy_ethtool_sset(phydev, cmd); 99 } 100 101 return -EINVAL; 102 } 103 104 static void xgene_get_strings(struct net_device *ndev, u32 stringset, u8 *data) 105 { 106 int i; 107 u8 *p = data; 108 109 if (stringset != ETH_SS_STATS) 110 return; 111 112 for (i = 0; i < XGENE_STATS_LEN; i++) { 113 memcpy(p, gstrings_stats[i].name, ETH_GSTRING_LEN); 114 p += ETH_GSTRING_LEN; 115 } 116 } 117 118 static int xgene_get_sset_count(struct net_device *ndev, int sset) 119 { 120 if (sset != ETH_SS_STATS) 121 return -EINVAL; 122 123 return XGENE_STATS_LEN; 124 } 125 126 static void xgene_get_ethtool_stats(struct net_device *ndev, 127 struct ethtool_stats *dummy, 128 u64 *data) 129 { 130 void *pdata = netdev_priv(ndev); 131 int i; 132 133 for (i = 0; i < XGENE_STATS_LEN; i++) 134 *data++ = *(u64 *)(pdata + gstrings_stats[i].offset); 135 } 136 137 static const struct ethtool_ops xgene_ethtool_ops = { 138 .get_drvinfo = xgene_get_drvinfo, 139 .get_settings = xgene_get_settings, 140 .set_settings = xgene_set_settings, 141 .get_link = ethtool_op_get_link, 142 .get_strings = xgene_get_strings, 143 .get_sset_count = xgene_get_sset_count, 144 .get_ethtool_stats = xgene_get_ethtool_stats 145 }; 146 147 void xgene_enet_set_ethtool_ops(struct net_device *ndev) 148 { 149 ndev->ethtool_ops = &xgene_ethtool_ops; 150 } 151