299 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * FUJITSU Extended Socket Network Device driver4 * Copyright (c) 2015 FUJITSU LIMITED5 */6 7/* ethtool support for fjes */8 9#include <linux/vmalloc.h>10#include <linux/netdevice.h>11#include <linux/ethtool.h>12#include <linux/platform_device.h>13 14#include "fjes.h"15 16struct fjes_stats {17 char stat_string[ETH_GSTRING_LEN];18 int sizeof_stat;19 int stat_offset;20};21 22#define FJES_STAT(name, stat) { \23 .stat_string = name, \24 .sizeof_stat = sizeof_field(struct fjes_adapter, stat), \25 .stat_offset = offsetof(struct fjes_adapter, stat) \26}27 28static const struct fjes_stats fjes_gstrings_stats[] = {29 FJES_STAT("rx_packets", stats64.rx_packets),30 FJES_STAT("tx_packets", stats64.tx_packets),31 FJES_STAT("rx_bytes", stats64.rx_bytes),32 FJES_STAT("tx_bytes", stats64.rx_bytes),33 FJES_STAT("rx_dropped", stats64.rx_dropped),34 FJES_STAT("tx_dropped", stats64.tx_dropped),35};36 37#define FJES_EP_STATS_LEN 1438#define FJES_STATS_LEN \39 (ARRAY_SIZE(fjes_gstrings_stats) + \40 ((&((struct fjes_adapter *)netdev_priv(netdev))->hw)->max_epid - 1) * \41 FJES_EP_STATS_LEN)42 43static void fjes_get_ethtool_stats(struct net_device *netdev,44 struct ethtool_stats *stats, u64 *data)45{46 struct fjes_adapter *adapter = netdev_priv(netdev);47 struct fjes_hw *hw = &adapter->hw;48 int epidx;49 char *p;50 int i;51 52 for (i = 0; i < ARRAY_SIZE(fjes_gstrings_stats); i++) {53 p = (char *)adapter + fjes_gstrings_stats[i].stat_offset;54 data[i] = (fjes_gstrings_stats[i].sizeof_stat == sizeof(u64))55 ? *(u64 *)p : *(u32 *)p;56 }57 for (epidx = 0; epidx < hw->max_epid; epidx++) {58 if (epidx == hw->my_epid)59 continue;60 data[i++] = hw->ep_shm_info[epidx].ep_stats61 .com_regist_buf_exec;62 data[i++] = hw->ep_shm_info[epidx].ep_stats63 .com_unregist_buf_exec;64 data[i++] = hw->ep_shm_info[epidx].ep_stats.send_intr_rx;65 data[i++] = hw->ep_shm_info[epidx].ep_stats.send_intr_unshare;66 data[i++] = hw->ep_shm_info[epidx].ep_stats67 .send_intr_zoneupdate;68 data[i++] = hw->ep_shm_info[epidx].ep_stats.recv_intr_rx;69 data[i++] = hw->ep_shm_info[epidx].ep_stats.recv_intr_unshare;70 data[i++] = hw->ep_shm_info[epidx].ep_stats.recv_intr_stop;71 data[i++] = hw->ep_shm_info[epidx].ep_stats72 .recv_intr_zoneupdate;73 data[i++] = hw->ep_shm_info[epidx].ep_stats.tx_buffer_full;74 data[i++] = hw->ep_shm_info[epidx].ep_stats75 .tx_dropped_not_shared;76 data[i++] = hw->ep_shm_info[epidx].ep_stats77 .tx_dropped_ver_mismatch;78 data[i++] = hw->ep_shm_info[epidx].ep_stats79 .tx_dropped_buf_size_mismatch;80 data[i++] = hw->ep_shm_info[epidx].ep_stats81 .tx_dropped_vlanid_mismatch;82 }83}84 85static void fjes_get_strings(struct net_device *netdev,86 u32 stringset, u8 *data)87{88 struct fjes_adapter *adapter = netdev_priv(netdev);89 struct fjes_hw *hw = &adapter->hw;90 u8 *p = data;91 int i;92 93 switch (stringset) {94 case ETH_SS_STATS:95 for (i = 0; i < ARRAY_SIZE(fjes_gstrings_stats); i++) {96 memcpy(p, fjes_gstrings_stats[i].stat_string,97 ETH_GSTRING_LEN);98 p += ETH_GSTRING_LEN;99 }100 for (i = 0; i < hw->max_epid; i++) {101 if (i == hw->my_epid)102 continue;103 sprintf(p, "ep%u_com_regist_buf_exec", i);104 p += ETH_GSTRING_LEN;105 sprintf(p, "ep%u_com_unregist_buf_exec", i);106 p += ETH_GSTRING_LEN;107 sprintf(p, "ep%u_send_intr_rx", i);108 p += ETH_GSTRING_LEN;109 sprintf(p, "ep%u_send_intr_unshare", i);110 p += ETH_GSTRING_LEN;111 sprintf(p, "ep%u_send_intr_zoneupdate", i);112 p += ETH_GSTRING_LEN;113 sprintf(p, "ep%u_recv_intr_rx", i);114 p += ETH_GSTRING_LEN;115 sprintf(p, "ep%u_recv_intr_unshare", i);116 p += ETH_GSTRING_LEN;117 sprintf(p, "ep%u_recv_intr_stop", i);118 p += ETH_GSTRING_LEN;119 sprintf(p, "ep%u_recv_intr_zoneupdate", i);120 p += ETH_GSTRING_LEN;121 sprintf(p, "ep%u_tx_buffer_full", i);122 p += ETH_GSTRING_LEN;123 sprintf(p, "ep%u_tx_dropped_not_shared", i);124 p += ETH_GSTRING_LEN;125 sprintf(p, "ep%u_tx_dropped_ver_mismatch", i);126 p += ETH_GSTRING_LEN;127 sprintf(p, "ep%u_tx_dropped_buf_size_mismatch", i);128 p += ETH_GSTRING_LEN;129 sprintf(p, "ep%u_tx_dropped_vlanid_mismatch", i);130 p += ETH_GSTRING_LEN;131 }132 break;133 }134}135 136static int fjes_get_sset_count(struct net_device *netdev, int sset)137{138 switch (sset) {139 case ETH_SS_STATS:140 return FJES_STATS_LEN;141 default:142 return -EOPNOTSUPP;143 }144}145 146static void fjes_get_drvinfo(struct net_device *netdev,147 struct ethtool_drvinfo *drvinfo)148{149 struct fjes_adapter *adapter = netdev_priv(netdev);150 struct platform_device *plat_dev;151 152 plat_dev = adapter->plat_dev;153 154 strscpy(drvinfo->driver, fjes_driver_name, sizeof(drvinfo->driver));155 strscpy(drvinfo->version, fjes_driver_version,156 sizeof(drvinfo->version));157 158 strscpy(drvinfo->fw_version, "none", sizeof(drvinfo->fw_version));159 snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info),160 "platform:%s", plat_dev->name);161}162 163static int fjes_get_link_ksettings(struct net_device *netdev,164 struct ethtool_link_ksettings *ecmd)165{166 ethtool_link_ksettings_zero_link_mode(ecmd, supported);167 ethtool_link_ksettings_zero_link_mode(ecmd, advertising);168 ecmd->base.duplex = DUPLEX_FULL;169 ecmd->base.autoneg = AUTONEG_DISABLE;170 ecmd->base.port = PORT_NONE;171 ecmd->base.speed = 20000; /* 20Gb/s */172 173 return 0;174}175 176static int fjes_get_regs_len(struct net_device *netdev)177{178#define FJES_REGS_LEN 37179 return FJES_REGS_LEN * sizeof(u32);180}181 182static void fjes_get_regs(struct net_device *netdev,183 struct ethtool_regs *regs, void *p)184{185 struct fjes_adapter *adapter = netdev_priv(netdev);186 struct fjes_hw *hw = &adapter->hw;187 u32 *regs_buff = p;188 189 memset(p, 0, FJES_REGS_LEN * sizeof(u32));190 191 regs->version = 1;192 193 /* Information registers */194 regs_buff[0] = rd32(XSCT_OWNER_EPID);195 regs_buff[1] = rd32(XSCT_MAX_EP);196 197 /* Device Control registers */198 regs_buff[4] = rd32(XSCT_DCTL);199 200 /* Command Control registers */201 regs_buff[8] = rd32(XSCT_CR);202 regs_buff[9] = rd32(XSCT_CS);203 regs_buff[10] = rd32(XSCT_SHSTSAL);204 regs_buff[11] = rd32(XSCT_SHSTSAH);205 206 regs_buff[13] = rd32(XSCT_REQBL);207 regs_buff[14] = rd32(XSCT_REQBAL);208 regs_buff[15] = rd32(XSCT_REQBAH);209 210 regs_buff[17] = rd32(XSCT_RESPBL);211 regs_buff[18] = rd32(XSCT_RESPBAL);212 regs_buff[19] = rd32(XSCT_RESPBAH);213 214 /* Interrupt Control registers */215 regs_buff[32] = rd32(XSCT_IS);216 regs_buff[33] = rd32(XSCT_IMS);217 regs_buff[34] = rd32(XSCT_IMC);218 regs_buff[35] = rd32(XSCT_IG);219 regs_buff[36] = rd32(XSCT_ICTL);220}221 222static int fjes_set_dump(struct net_device *netdev, struct ethtool_dump *dump)223{224 struct fjes_adapter *adapter = netdev_priv(netdev);225 struct fjes_hw *hw = &adapter->hw;226 int ret = 0;227 228 if (dump->flag) {229 if (hw->debug_mode)230 return -EPERM;231 232 hw->debug_mode = dump->flag;233 234 /* enable debug mode */235 mutex_lock(&hw->hw_info.lock);236 ret = fjes_hw_start_debug(hw);237 mutex_unlock(&hw->hw_info.lock);238 239 if (ret)240 hw->debug_mode = 0;241 } else {242 if (!hw->debug_mode)243 return -EPERM;244 245 /* disable debug mode */246 mutex_lock(&hw->hw_info.lock);247 ret = fjes_hw_stop_debug(hw);248 mutex_unlock(&hw->hw_info.lock);249 }250 251 return ret;252}253 254static int fjes_get_dump_flag(struct net_device *netdev,255 struct ethtool_dump *dump)256{257 struct fjes_adapter *adapter = netdev_priv(netdev);258 struct fjes_hw *hw = &adapter->hw;259 260 dump->len = hw->hw_info.trace_size;261 dump->version = 1;262 dump->flag = hw->debug_mode;263 264 return 0;265}266 267static int fjes_get_dump_data(struct net_device *netdev,268 struct ethtool_dump *dump, void *buf)269{270 struct fjes_adapter *adapter = netdev_priv(netdev);271 struct fjes_hw *hw = &adapter->hw;272 int ret = 0;273 274 if (hw->hw_info.trace)275 memcpy(buf, hw->hw_info.trace, hw->hw_info.trace_size);276 else277 ret = -EPERM;278 279 return ret;280}281 282static const struct ethtool_ops fjes_ethtool_ops = {283 .get_drvinfo = fjes_get_drvinfo,284 .get_ethtool_stats = fjes_get_ethtool_stats,285 .get_strings = fjes_get_strings,286 .get_sset_count = fjes_get_sset_count,287 .get_regs = fjes_get_regs,288 .get_regs_len = fjes_get_regs_len,289 .set_dump = fjes_set_dump,290 .get_dump_flag = fjes_get_dump_flag,291 .get_dump_data = fjes_get_dump_data,292 .get_link_ksettings = fjes_get_link_ksettings,293};294 295void fjes_set_ethtool_ops(struct net_device *netdev)296{297 netdev->ethtool_ops = &fjes_ethtool_ops;298}299