269 lines · c
1/* Synopsys DesignWare Core Enterprise Ethernet (XLGMAC) Driver2 *3 * Copyright (c) 2017 Synopsys, Inc. (www.synopsys.com)4 *5 * This program is dual-licensed; you may select either version 2 of6 * the GNU General Public License ("GPL") or BSD license ("BSD").7 *8 * This Synopsys DWC XLGMAC software driver and associated documentation9 * (hereinafter the "Software") is an unsupported proprietary work of10 * Synopsys, Inc. unless otherwise expressly agreed to in writing between11 * Synopsys and you. The Software IS NOT an item of Licensed Software or a12 * Licensed Product under any End User Software License Agreement or13 * Agreement for Licensed Products with Synopsys or any supplement thereto.14 * Synopsys is a registered trademark of Synopsys, Inc. Other names included15 * 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 strscpy(drvinfo->driver, pdata->drv_name, sizeof(drvinfo->driver));106 strscpy(drvinfo->version, pdata->drv_ver, sizeof(drvinfo->version));107 strscpy(drvinfo->bus_info, dev_name(pdata->dev),108 sizeof(drvinfo->bus_info));109 /* S|SNPSVER: Synopsys-defined Version110 * D|DEVID: Indicates the Device family111 * U|USERVER: User-defined Version112 */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 int150xlgmac_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 int165xlgmac_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}269