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 25 struct 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 36 static 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 98 static 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 123 static 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 130 static 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 138 static 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 149 static int 150 xlgmac_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 164 static int 165 xlgmac_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 199 static 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 218 static 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 235 static 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 250 static 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 265 const struct ethtool_ops *xlgmac_get_ethtool_ops(void) 266 { 267 return &xlgmac_ethtool_ops; 268 } 269