dwc-xlgmac-ethtool.c (8901B)
1/* Synopsys DesignWare Core Enterprise Ethernet (XLGMAC) Driver 2 * 3 * Copyright (c) 2017 Synopsys, Inc. (www.synopsys.com) 4 * 5 * This program is dual-licensed; you may select either version 2 of 6 * the GNU General Public License ("GPL") or BSD license ("BSD"). 7 * 8 * This Synopsys DWC XLGMAC software driver and associated documentation 9 * (hereinafter the "Software") is an unsupported proprietary work of 10 * Synopsys, Inc. unless otherwise expressly agreed to in writing between 11 * Synopsys and you. The Software IS NOT an item of Licensed Software or a 12 * Licensed Product under any End User Software License Agreement or 13 * Agreement for Licensed Products with Synopsys or any supplement thereto. 14 * Synopsys is a registered trademark of Synopsys, Inc. Other names included 15 * in the SOFTWARE may be the trademarks of their respective owners. 16 */ 17 18#include <linux/ethtool.h> 19#include <linux/kernel.h> 20#include <linux/netdevice.h> 21 22#include "dwc-xlgmac.h" 23#include "dwc-xlgmac-reg.h" 24 25struct xlgmac_stats_desc { 26 char stat_string[ETH_GSTRING_LEN]; 27 int stat_offset; 28}; 29 30#define XLGMAC_STAT(str, var) \ 31 { \ 32 str, \ 33 offsetof(struct xlgmac_pdata, stats.var), \ 34 } 35 36static const struct xlgmac_stats_desc xlgmac_gstring_stats[] = { 37 /* MMC TX counters */ 38 XLGMAC_STAT("tx_bytes", txoctetcount_gb), 39 XLGMAC_STAT("tx_bytes_good", txoctetcount_g), 40 XLGMAC_STAT("tx_packets", txframecount_gb), 41 XLGMAC_STAT("tx_packets_good", txframecount_g), 42 XLGMAC_STAT("tx_unicast_packets", txunicastframes_gb), 43 XLGMAC_STAT("tx_broadcast_packets", txbroadcastframes_gb), 44 XLGMAC_STAT("tx_broadcast_packets_good", txbroadcastframes_g), 45 XLGMAC_STAT("tx_multicast_packets", txmulticastframes_gb), 46 XLGMAC_STAT("tx_multicast_packets_good", txmulticastframes_g), 47 XLGMAC_STAT("tx_vlan_packets_good", txvlanframes_g), 48 XLGMAC_STAT("tx_64_byte_packets", tx64octets_gb), 49 XLGMAC_STAT("tx_65_to_127_byte_packets", tx65to127octets_gb), 50 XLGMAC_STAT("tx_128_to_255_byte_packets", tx128to255octets_gb), 51 XLGMAC_STAT("tx_256_to_511_byte_packets", tx256to511octets_gb), 52 XLGMAC_STAT("tx_512_to_1023_byte_packets", tx512to1023octets_gb), 53 XLGMAC_STAT("tx_1024_to_max_byte_packets", tx1024tomaxoctets_gb), 54 XLGMAC_STAT("tx_underflow_errors", txunderflowerror), 55 XLGMAC_STAT("tx_pause_frames", txpauseframes), 56 57 /* MMC RX counters */ 58 XLGMAC_STAT("rx_bytes", rxoctetcount_gb), 59 XLGMAC_STAT("rx_bytes_good", rxoctetcount_g), 60 XLGMAC_STAT("rx_packets", rxframecount_gb), 61 XLGMAC_STAT("rx_unicast_packets_good", rxunicastframes_g), 62 XLGMAC_STAT("rx_broadcast_packets_good", rxbroadcastframes_g), 63 XLGMAC_STAT("rx_multicast_packets_good", rxmulticastframes_g), 64 XLGMAC_STAT("rx_vlan_packets", rxvlanframes_gb), 65 XLGMAC_STAT("rx_64_byte_packets", rx64octets_gb), 66 XLGMAC_STAT("rx_65_to_127_byte_packets", rx65to127octets_gb), 67 XLGMAC_STAT("rx_128_to_255_byte_packets", rx128to255octets_gb), 68 XLGMAC_STAT("rx_256_to_511_byte_packets", rx256to511octets_gb), 69 XLGMAC_STAT("rx_512_to_1023_byte_packets", rx512to1023octets_gb), 70 XLGMAC_STAT("rx_1024_to_max_byte_packets", rx1024tomaxoctets_gb), 71 XLGMAC_STAT("rx_undersize_packets_good", rxundersize_g), 72 XLGMAC_STAT("rx_oversize_packets_good", rxoversize_g), 73 XLGMAC_STAT("rx_crc_errors", rxcrcerror), 74 XLGMAC_STAT("rx_crc_errors_small_packets", rxrunterror), 75 XLGMAC_STAT("rx_crc_errors_giant_packets", rxjabbererror), 76 XLGMAC_STAT("rx_length_errors", rxlengtherror), 77 XLGMAC_STAT("rx_out_of_range_errors", rxoutofrangetype), 78 XLGMAC_STAT("rx_fifo_overflow_errors", rxfifooverflow), 79 XLGMAC_STAT("rx_watchdog_errors", rxwatchdogerror), 80 XLGMAC_STAT("rx_pause_frames", rxpauseframes), 81 82 /* Extra counters */ 83 XLGMAC_STAT("tx_tso_packets", tx_tso_packets), 84 XLGMAC_STAT("rx_split_header_packets", rx_split_header_packets), 85 XLGMAC_STAT("tx_process_stopped", tx_process_stopped), 86 XLGMAC_STAT("rx_process_stopped", rx_process_stopped), 87 XLGMAC_STAT("tx_buffer_unavailable", tx_buffer_unavailable), 88 XLGMAC_STAT("rx_buffer_unavailable", rx_buffer_unavailable), 89 XLGMAC_STAT("fatal_bus_error", fatal_bus_error), 90 XLGMAC_STAT("tx_vlan_packets", tx_vlan_packets), 91 XLGMAC_STAT("rx_vlan_packets", rx_vlan_packets), 92 XLGMAC_STAT("napi_poll_isr", napi_poll_isr), 93 XLGMAC_STAT("napi_poll_txtimer", napi_poll_txtimer), 94}; 95 96#define XLGMAC_STATS_COUNT ARRAY_SIZE(xlgmac_gstring_stats) 97 98static void xlgmac_ethtool_get_drvinfo(struct net_device *netdev, 99 struct ethtool_drvinfo *drvinfo) 100{ 101 struct xlgmac_pdata *pdata = netdev_priv(netdev); 102 u32 ver = pdata->hw_feat.version; 103 u32 snpsver, devid, userver; 104 105 strlcpy(drvinfo->driver, pdata->drv_name, sizeof(drvinfo->driver)); 106 strlcpy(drvinfo->version, pdata->drv_ver, sizeof(drvinfo->version)); 107 strlcpy(drvinfo->bus_info, dev_name(pdata->dev), 108 sizeof(drvinfo->bus_info)); 109 /* S|SNPSVER: Synopsys-defined Version 110 * D|DEVID: Indicates the Device family 111 * U|USERVER: User-defined Version 112 */ 113 snpsver = XLGMAC_GET_REG_BITS(ver, MAC_VR_SNPSVER_POS, 114 MAC_VR_SNPSVER_LEN); 115 devid = XLGMAC_GET_REG_BITS(ver, MAC_VR_DEVID_POS, 116 MAC_VR_DEVID_LEN); 117 userver = XLGMAC_GET_REG_BITS(ver, MAC_VR_USERVER_POS, 118 MAC_VR_USERVER_LEN); 119 snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), 120 "S.D.U: %x.%x.%x", snpsver, devid, userver); 121} 122 123static u32 xlgmac_ethtool_get_msglevel(struct net_device *netdev) 124{ 125 struct xlgmac_pdata *pdata = netdev_priv(netdev); 126 127 return pdata->msg_enable; 128} 129 130static void xlgmac_ethtool_set_msglevel(struct net_device *netdev, 131 u32 msglevel) 132{ 133 struct xlgmac_pdata *pdata = netdev_priv(netdev); 134 135 pdata->msg_enable = msglevel; 136} 137 138static void xlgmac_ethtool_get_channels(struct net_device *netdev, 139 struct ethtool_channels *channel) 140{ 141 struct xlgmac_pdata *pdata = netdev_priv(netdev); 142 143 channel->max_rx = XLGMAC_MAX_DMA_CHANNELS; 144 channel->max_tx = XLGMAC_MAX_DMA_CHANNELS; 145 channel->rx_count = pdata->rx_q_count; 146 channel->tx_count = pdata->tx_q_count; 147} 148 149static int 150xlgmac_ethtool_get_coalesce(struct net_device *netdev, 151 struct ethtool_coalesce *ec, 152 struct kernel_ethtool_coalesce *kernel_coal, 153 struct netlink_ext_ack *extack) 154{ 155 struct xlgmac_pdata *pdata = netdev_priv(netdev); 156 157 ec->rx_coalesce_usecs = pdata->rx_usecs; 158 ec->rx_max_coalesced_frames = pdata->rx_frames; 159 ec->tx_max_coalesced_frames = pdata->tx_frames; 160 161 return 0; 162} 163 164static int 165xlgmac_ethtool_set_coalesce(struct net_device *netdev, 166 struct ethtool_coalesce *ec, 167 struct kernel_ethtool_coalesce *kernel_coal, 168 struct netlink_ext_ack *extack) 169{ 170 struct xlgmac_pdata *pdata = netdev_priv(netdev); 171 struct xlgmac_hw_ops *hw_ops = &pdata->hw_ops; 172 unsigned int rx_frames, rx_riwt, rx_usecs; 173 unsigned int tx_frames; 174 175 rx_usecs = ec->rx_coalesce_usecs; 176 rx_riwt = hw_ops->usec_to_riwt(pdata, rx_usecs); 177 rx_frames = ec->rx_max_coalesced_frames; 178 tx_frames = ec->tx_max_coalesced_frames; 179 180 if ((rx_riwt > XLGMAC_MAX_DMA_RIWT) || 181 (rx_riwt < XLGMAC_MIN_DMA_RIWT) || 182 (rx_frames > pdata->rx_desc_count)) 183 return -EINVAL; 184 185 if (tx_frames > pdata->tx_desc_count) 186 return -EINVAL; 187 188 pdata->rx_riwt = rx_riwt; 189 pdata->rx_usecs = rx_usecs; 190 pdata->rx_frames = rx_frames; 191 hw_ops->config_rx_coalesce(pdata); 192 193 pdata->tx_frames = tx_frames; 194 hw_ops->config_tx_coalesce(pdata); 195 196 return 0; 197} 198 199static void xlgmac_ethtool_get_strings(struct net_device *netdev, 200 u32 stringset, u8 *data) 201{ 202 int i; 203 204 switch (stringset) { 205 case ETH_SS_STATS: 206 for (i = 0; i < XLGMAC_STATS_COUNT; i++) { 207 memcpy(data, xlgmac_gstring_stats[i].stat_string, 208 ETH_GSTRING_LEN); 209 data += ETH_GSTRING_LEN; 210 } 211 break; 212 default: 213 WARN_ON(1); 214 break; 215 } 216} 217 218static int xlgmac_ethtool_get_sset_count(struct net_device *netdev, 219 int stringset) 220{ 221 int ret; 222 223 switch (stringset) { 224 case ETH_SS_STATS: 225 ret = XLGMAC_STATS_COUNT; 226 break; 227 228 default: 229 ret = -EOPNOTSUPP; 230 } 231 232 return ret; 233} 234 235static void xlgmac_ethtool_get_ethtool_stats(struct net_device *netdev, 236 struct ethtool_stats *stats, 237 u64 *data) 238{ 239 struct xlgmac_pdata *pdata = netdev_priv(netdev); 240 u8 *stat; 241 int i; 242 243 pdata->hw_ops.read_mmc_stats(pdata); 244 for (i = 0; i < XLGMAC_STATS_COUNT; i++) { 245 stat = (u8 *)pdata + xlgmac_gstring_stats[i].stat_offset; 246 *data++ = *(u64 *)stat; 247 } 248} 249 250static const struct ethtool_ops xlgmac_ethtool_ops = { 251 .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS | 252 ETHTOOL_COALESCE_MAX_FRAMES, 253 .get_drvinfo = xlgmac_ethtool_get_drvinfo, 254 .get_link = ethtool_op_get_link, 255 .get_msglevel = xlgmac_ethtool_get_msglevel, 256 .set_msglevel = xlgmac_ethtool_set_msglevel, 257 .get_channels = xlgmac_ethtool_get_channels, 258 .get_coalesce = xlgmac_ethtool_get_coalesce, 259 .set_coalesce = xlgmac_ethtool_set_coalesce, 260 .get_strings = xlgmac_ethtool_get_strings, 261 .get_sset_count = xlgmac_ethtool_get_sset_count, 262 .get_ethtool_stats = xlgmac_ethtool_get_ethtool_stats, 263}; 264 265const struct ethtool_ops *xlgmac_get_ethtool_ops(void) 266{ 267 return &xlgmac_ethtool_ops; 268}