1dcc4086dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2786eec27STaku Izumi /*
3786eec27STaku Izumi * FUJITSU Extended Socket Network Device driver
4786eec27STaku Izumi * Copyright (c) 2015 FUJITSU LIMITED
5786eec27STaku Izumi */
6786eec27STaku Izumi
7786eec27STaku Izumi /* ethtool support for fjes */
8786eec27STaku Izumi
9786eec27STaku Izumi #include <linux/vmalloc.h>
10786eec27STaku Izumi #include <linux/netdevice.h>
11786eec27STaku Izumi #include <linux/ethtool.h>
12786eec27STaku Izumi #include <linux/platform_device.h>
13786eec27STaku Izumi
14786eec27STaku Izumi #include "fjes.h"
15786eec27STaku Izumi
16786eec27STaku Izumi struct fjes_stats {
17786eec27STaku Izumi char stat_string[ETH_GSTRING_LEN];
18786eec27STaku Izumi int sizeof_stat;
19786eec27STaku Izumi int stat_offset;
20786eec27STaku Izumi };
21786eec27STaku Izumi
22786eec27STaku Izumi #define FJES_STAT(name, stat) { \
23786eec27STaku Izumi .stat_string = name, \
24c593642cSPankaj Bharadiya .sizeof_stat = sizeof_field(struct fjes_adapter, stat), \
25786eec27STaku Izumi .stat_offset = offsetof(struct fjes_adapter, stat) \
26786eec27STaku Izumi }
27786eec27STaku Izumi
28786eec27STaku Izumi static const struct fjes_stats fjes_gstrings_stats[] = {
29786eec27STaku Izumi FJES_STAT("rx_packets", stats64.rx_packets),
30786eec27STaku Izumi FJES_STAT("tx_packets", stats64.tx_packets),
31786eec27STaku Izumi FJES_STAT("rx_bytes", stats64.rx_bytes),
32786eec27STaku Izumi FJES_STAT("tx_bytes", stats64.rx_bytes),
33786eec27STaku Izumi FJES_STAT("rx_dropped", stats64.rx_dropped),
34786eec27STaku Izumi FJES_STAT("tx_dropped", stats64.tx_dropped),
35786eec27STaku Izumi };
36786eec27STaku Izumi
3721b7efbcSTaku Izumi #define FJES_EP_STATS_LEN 14
3821b7efbcSTaku Izumi #define FJES_STATS_LEN \
3921b7efbcSTaku Izumi (ARRAY_SIZE(fjes_gstrings_stats) + \
4021b7efbcSTaku Izumi ((&((struct fjes_adapter *)netdev_priv(netdev))->hw)->max_epid - 1) * \
4121b7efbcSTaku Izumi FJES_EP_STATS_LEN)
4221b7efbcSTaku Izumi
fjes_get_ethtool_stats(struct net_device * netdev,struct ethtool_stats * stats,u64 * data)43786eec27STaku Izumi static void fjes_get_ethtool_stats(struct net_device *netdev,
44786eec27STaku Izumi struct ethtool_stats *stats, u64 *data)
45786eec27STaku Izumi {
46786eec27STaku Izumi struct fjes_adapter *adapter = netdev_priv(netdev);
4721b7efbcSTaku Izumi struct fjes_hw *hw = &adapter->hw;
4821b7efbcSTaku Izumi int epidx;
49786eec27STaku Izumi char *p;
50786eec27STaku Izumi int i;
51786eec27STaku Izumi
52786eec27STaku Izumi for (i = 0; i < ARRAY_SIZE(fjes_gstrings_stats); i++) {
53786eec27STaku Izumi p = (char *)adapter + fjes_gstrings_stats[i].stat_offset;
54786eec27STaku Izumi data[i] = (fjes_gstrings_stats[i].sizeof_stat == sizeof(u64))
55786eec27STaku Izumi ? *(u64 *)p : *(u32 *)p;
56786eec27STaku Izumi }
5721b7efbcSTaku Izumi for (epidx = 0; epidx < hw->max_epid; epidx++) {
5821b7efbcSTaku Izumi if (epidx == hw->my_epid)
5921b7efbcSTaku Izumi continue;
6021b7efbcSTaku Izumi data[i++] = hw->ep_shm_info[epidx].ep_stats
6121b7efbcSTaku Izumi .com_regist_buf_exec;
6221b7efbcSTaku Izumi data[i++] = hw->ep_shm_info[epidx].ep_stats
6321b7efbcSTaku Izumi .com_unregist_buf_exec;
6421b7efbcSTaku Izumi data[i++] = hw->ep_shm_info[epidx].ep_stats.send_intr_rx;
6521b7efbcSTaku Izumi data[i++] = hw->ep_shm_info[epidx].ep_stats.send_intr_unshare;
6621b7efbcSTaku Izumi data[i++] = hw->ep_shm_info[epidx].ep_stats
6721b7efbcSTaku Izumi .send_intr_zoneupdate;
6821b7efbcSTaku Izumi data[i++] = hw->ep_shm_info[epidx].ep_stats.recv_intr_rx;
6921b7efbcSTaku Izumi data[i++] = hw->ep_shm_info[epidx].ep_stats.recv_intr_unshare;
7021b7efbcSTaku Izumi data[i++] = hw->ep_shm_info[epidx].ep_stats.recv_intr_stop;
7121b7efbcSTaku Izumi data[i++] = hw->ep_shm_info[epidx].ep_stats
7221b7efbcSTaku Izumi .recv_intr_zoneupdate;
7321b7efbcSTaku Izumi data[i++] = hw->ep_shm_info[epidx].ep_stats.tx_buffer_full;
7421b7efbcSTaku Izumi data[i++] = hw->ep_shm_info[epidx].ep_stats
7521b7efbcSTaku Izumi .tx_dropped_not_shared;
7621b7efbcSTaku Izumi data[i++] = hw->ep_shm_info[epidx].ep_stats
7721b7efbcSTaku Izumi .tx_dropped_ver_mismatch;
7821b7efbcSTaku Izumi data[i++] = hw->ep_shm_info[epidx].ep_stats
7921b7efbcSTaku Izumi .tx_dropped_buf_size_mismatch;
8021b7efbcSTaku Izumi data[i++] = hw->ep_shm_info[epidx].ep_stats
8121b7efbcSTaku Izumi .tx_dropped_vlanid_mismatch;
8221b7efbcSTaku Izumi }
83786eec27STaku Izumi }
84786eec27STaku Izumi
fjes_get_strings(struct net_device * netdev,u32 stringset,u8 * data)85786eec27STaku Izumi static void fjes_get_strings(struct net_device *netdev,
86786eec27STaku Izumi u32 stringset, u8 *data)
87786eec27STaku Izumi {
8821b7efbcSTaku Izumi struct fjes_adapter *adapter = netdev_priv(netdev);
8921b7efbcSTaku Izumi struct fjes_hw *hw = &adapter->hw;
90786eec27STaku Izumi u8 *p = data;
91786eec27STaku Izumi int i;
92786eec27STaku Izumi
93786eec27STaku Izumi switch (stringset) {
94786eec27STaku Izumi case ETH_SS_STATS:
95786eec27STaku Izumi for (i = 0; i < ARRAY_SIZE(fjes_gstrings_stats); i++) {
96786eec27STaku Izumi memcpy(p, fjes_gstrings_stats[i].stat_string,
97786eec27STaku Izumi ETH_GSTRING_LEN);
98786eec27STaku Izumi p += ETH_GSTRING_LEN;
99786eec27STaku Izumi }
10021b7efbcSTaku Izumi for (i = 0; i < hw->max_epid; i++) {
10121b7efbcSTaku Izumi if (i == hw->my_epid)
10221b7efbcSTaku Izumi continue;
10321b7efbcSTaku Izumi sprintf(p, "ep%u_com_regist_buf_exec", i);
10421b7efbcSTaku Izumi p += ETH_GSTRING_LEN;
10521b7efbcSTaku Izumi sprintf(p, "ep%u_com_unregist_buf_exec", i);
10621b7efbcSTaku Izumi p += ETH_GSTRING_LEN;
10721b7efbcSTaku Izumi sprintf(p, "ep%u_send_intr_rx", i);
10821b7efbcSTaku Izumi p += ETH_GSTRING_LEN;
10921b7efbcSTaku Izumi sprintf(p, "ep%u_send_intr_unshare", i);
11021b7efbcSTaku Izumi p += ETH_GSTRING_LEN;
11121b7efbcSTaku Izumi sprintf(p, "ep%u_send_intr_zoneupdate", i);
11221b7efbcSTaku Izumi p += ETH_GSTRING_LEN;
11321b7efbcSTaku Izumi sprintf(p, "ep%u_recv_intr_rx", i);
11421b7efbcSTaku Izumi p += ETH_GSTRING_LEN;
11521b7efbcSTaku Izumi sprintf(p, "ep%u_recv_intr_unshare", i);
11621b7efbcSTaku Izumi p += ETH_GSTRING_LEN;
11721b7efbcSTaku Izumi sprintf(p, "ep%u_recv_intr_stop", i);
11821b7efbcSTaku Izumi p += ETH_GSTRING_LEN;
11921b7efbcSTaku Izumi sprintf(p, "ep%u_recv_intr_zoneupdate", i);
12021b7efbcSTaku Izumi p += ETH_GSTRING_LEN;
12121b7efbcSTaku Izumi sprintf(p, "ep%u_tx_buffer_full", i);
12221b7efbcSTaku Izumi p += ETH_GSTRING_LEN;
12321b7efbcSTaku Izumi sprintf(p, "ep%u_tx_dropped_not_shared", i);
12421b7efbcSTaku Izumi p += ETH_GSTRING_LEN;
12521b7efbcSTaku Izumi sprintf(p, "ep%u_tx_dropped_ver_mismatch", i);
12621b7efbcSTaku Izumi p += ETH_GSTRING_LEN;
12721b7efbcSTaku Izumi sprintf(p, "ep%u_tx_dropped_buf_size_mismatch", i);
12821b7efbcSTaku Izumi p += ETH_GSTRING_LEN;
12921b7efbcSTaku Izumi sprintf(p, "ep%u_tx_dropped_vlanid_mismatch", i);
13021b7efbcSTaku Izumi p += ETH_GSTRING_LEN;
13121b7efbcSTaku Izumi }
132786eec27STaku Izumi break;
133786eec27STaku Izumi }
134786eec27STaku Izumi }
135786eec27STaku Izumi
fjes_get_sset_count(struct net_device * netdev,int sset)136786eec27STaku Izumi static int fjes_get_sset_count(struct net_device *netdev, int sset)
137786eec27STaku Izumi {
138786eec27STaku Izumi switch (sset) {
139786eec27STaku Izumi case ETH_SS_STATS:
14021b7efbcSTaku Izumi return FJES_STATS_LEN;
141786eec27STaku Izumi default:
142786eec27STaku Izumi return -EOPNOTSUPP;
143786eec27STaku Izumi }
144786eec27STaku Izumi }
145786eec27STaku Izumi
fjes_get_drvinfo(struct net_device * netdev,struct ethtool_drvinfo * drvinfo)146786eec27STaku Izumi static void fjes_get_drvinfo(struct net_device *netdev,
147786eec27STaku Izumi struct ethtool_drvinfo *drvinfo)
148786eec27STaku Izumi {
149786eec27STaku Izumi struct fjes_adapter *adapter = netdev_priv(netdev);
150786eec27STaku Izumi struct platform_device *plat_dev;
151786eec27STaku Izumi
152786eec27STaku Izumi plat_dev = adapter->plat_dev;
153786eec27STaku Izumi
154*fb3ceec1SWolfram Sang strscpy(drvinfo->driver, fjes_driver_name, sizeof(drvinfo->driver));
155*fb3ceec1SWolfram Sang strscpy(drvinfo->version, fjes_driver_version,
156786eec27STaku Izumi sizeof(drvinfo->version));
157786eec27STaku Izumi
158*fb3ceec1SWolfram Sang strscpy(drvinfo->fw_version, "none", sizeof(drvinfo->fw_version));
159786eec27STaku Izumi snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info),
160786eec27STaku Izumi "platform:%s", plat_dev->name);
161786eec27STaku Izumi }
162786eec27STaku Izumi
fjes_get_link_ksettings(struct net_device * netdev,struct ethtool_link_ksettings * ecmd)163031e5144SPhilippe Reynes static int fjes_get_link_ksettings(struct net_device *netdev,
164031e5144SPhilippe Reynes struct ethtool_link_ksettings *ecmd)
165786eec27STaku Izumi {
166031e5144SPhilippe Reynes ethtool_link_ksettings_zero_link_mode(ecmd, supported);
167031e5144SPhilippe Reynes ethtool_link_ksettings_zero_link_mode(ecmd, advertising);
168031e5144SPhilippe Reynes ecmd->base.duplex = DUPLEX_FULL;
169031e5144SPhilippe Reynes ecmd->base.autoneg = AUTONEG_DISABLE;
170031e5144SPhilippe Reynes ecmd->base.port = PORT_NONE;
171031e5144SPhilippe Reynes ecmd->base.speed = 20000; /* 20Gb/s */
172786eec27STaku Izumi
173786eec27STaku Izumi return 0;
174786eec27STaku Izumi }
175786eec27STaku Izumi
fjes_get_regs_len(struct net_device * netdev)176462d8074STaku Izumi static int fjes_get_regs_len(struct net_device *netdev)
177462d8074STaku Izumi {
178462d8074STaku Izumi #define FJES_REGS_LEN 37
179462d8074STaku Izumi return FJES_REGS_LEN * sizeof(u32);
180462d8074STaku Izumi }
181462d8074STaku Izumi
fjes_get_regs(struct net_device * netdev,struct ethtool_regs * regs,void * p)182462d8074STaku Izumi static void fjes_get_regs(struct net_device *netdev,
183462d8074STaku Izumi struct ethtool_regs *regs, void *p)
184462d8074STaku Izumi {
185462d8074STaku Izumi struct fjes_adapter *adapter = netdev_priv(netdev);
186462d8074STaku Izumi struct fjes_hw *hw = &adapter->hw;
187462d8074STaku Izumi u32 *regs_buff = p;
188462d8074STaku Izumi
189462d8074STaku Izumi memset(p, 0, FJES_REGS_LEN * sizeof(u32));
190462d8074STaku Izumi
191462d8074STaku Izumi regs->version = 1;
192462d8074STaku Izumi
193462d8074STaku Izumi /* Information registers */
194462d8074STaku Izumi regs_buff[0] = rd32(XSCT_OWNER_EPID);
195462d8074STaku Izumi regs_buff[1] = rd32(XSCT_MAX_EP);
196462d8074STaku Izumi
197462d8074STaku Izumi /* Device Control registers */
198462d8074STaku Izumi regs_buff[4] = rd32(XSCT_DCTL);
199462d8074STaku Izumi
200462d8074STaku Izumi /* Command Control registers */
201462d8074STaku Izumi regs_buff[8] = rd32(XSCT_CR);
202462d8074STaku Izumi regs_buff[9] = rd32(XSCT_CS);
203462d8074STaku Izumi regs_buff[10] = rd32(XSCT_SHSTSAL);
204462d8074STaku Izumi regs_buff[11] = rd32(XSCT_SHSTSAH);
205462d8074STaku Izumi
206462d8074STaku Izumi regs_buff[13] = rd32(XSCT_REQBL);
207462d8074STaku Izumi regs_buff[14] = rd32(XSCT_REQBAL);
208462d8074STaku Izumi regs_buff[15] = rd32(XSCT_REQBAH);
209462d8074STaku Izumi
210462d8074STaku Izumi regs_buff[17] = rd32(XSCT_RESPBL);
211462d8074STaku Izumi regs_buff[18] = rd32(XSCT_RESPBAL);
212462d8074STaku Izumi regs_buff[19] = rd32(XSCT_RESPBAH);
213462d8074STaku Izumi
214462d8074STaku Izumi /* Interrupt Control registers */
215462d8074STaku Izumi regs_buff[32] = rd32(XSCT_IS);
216462d8074STaku Izumi regs_buff[33] = rd32(XSCT_IMS);
217462d8074STaku Izumi regs_buff[34] = rd32(XSCT_IMC);
218462d8074STaku Izumi regs_buff[35] = rd32(XSCT_IG);
219462d8074STaku Izumi regs_buff[36] = rd32(XSCT_ICTL);
220462d8074STaku Izumi }
221462d8074STaku Izumi
fjes_set_dump(struct net_device * netdev,struct ethtool_dump * dump)222b6ba737dSTaku Izumi static int fjes_set_dump(struct net_device *netdev, struct ethtool_dump *dump)
223b6ba737dSTaku Izumi {
224b6ba737dSTaku Izumi struct fjes_adapter *adapter = netdev_priv(netdev);
225b6ba737dSTaku Izumi struct fjes_hw *hw = &adapter->hw;
226b6ba737dSTaku Izumi int ret = 0;
227b6ba737dSTaku Izumi
228b6ba737dSTaku Izumi if (dump->flag) {
229b6ba737dSTaku Izumi if (hw->debug_mode)
230b6ba737dSTaku Izumi return -EPERM;
231b6ba737dSTaku Izumi
232b6ba737dSTaku Izumi hw->debug_mode = dump->flag;
233b6ba737dSTaku Izumi
234b6ba737dSTaku Izumi /* enable debug mode */
235b6ba737dSTaku Izumi mutex_lock(&hw->hw_info.lock);
236b6ba737dSTaku Izumi ret = fjes_hw_start_debug(hw);
237b6ba737dSTaku Izumi mutex_unlock(&hw->hw_info.lock);
238b6ba737dSTaku Izumi
239b6ba737dSTaku Izumi if (ret)
240b6ba737dSTaku Izumi hw->debug_mode = 0;
241b6ba737dSTaku Izumi } else {
242b6ba737dSTaku Izumi if (!hw->debug_mode)
243b6ba737dSTaku Izumi return -EPERM;
244b6ba737dSTaku Izumi
245b6ba737dSTaku Izumi /* disable debug mode */
246b6ba737dSTaku Izumi mutex_lock(&hw->hw_info.lock);
247b6ba737dSTaku Izumi ret = fjes_hw_stop_debug(hw);
248b6ba737dSTaku Izumi mutex_unlock(&hw->hw_info.lock);
249b6ba737dSTaku Izumi }
250b6ba737dSTaku Izumi
251b6ba737dSTaku Izumi return ret;
252b6ba737dSTaku Izumi }
253b6ba737dSTaku Izumi
fjes_get_dump_flag(struct net_device * netdev,struct ethtool_dump * dump)254b6ba737dSTaku Izumi static int fjes_get_dump_flag(struct net_device *netdev,
255b6ba737dSTaku Izumi struct ethtool_dump *dump)
256b6ba737dSTaku Izumi {
257b6ba737dSTaku Izumi struct fjes_adapter *adapter = netdev_priv(netdev);
258b6ba737dSTaku Izumi struct fjes_hw *hw = &adapter->hw;
259b6ba737dSTaku Izumi
260b6ba737dSTaku Izumi dump->len = hw->hw_info.trace_size;
261b6ba737dSTaku Izumi dump->version = 1;
262b6ba737dSTaku Izumi dump->flag = hw->debug_mode;
263b6ba737dSTaku Izumi
264b6ba737dSTaku Izumi return 0;
265b6ba737dSTaku Izumi }
266b6ba737dSTaku Izumi
fjes_get_dump_data(struct net_device * netdev,struct ethtool_dump * dump,void * buf)267b6ba737dSTaku Izumi static int fjes_get_dump_data(struct net_device *netdev,
268b6ba737dSTaku Izumi struct ethtool_dump *dump, void *buf)
269b6ba737dSTaku Izumi {
270b6ba737dSTaku Izumi struct fjes_adapter *adapter = netdev_priv(netdev);
271b6ba737dSTaku Izumi struct fjes_hw *hw = &adapter->hw;
272b6ba737dSTaku Izumi int ret = 0;
273b6ba737dSTaku Izumi
274b6ba737dSTaku Izumi if (hw->hw_info.trace)
275b6ba737dSTaku Izumi memcpy(buf, hw->hw_info.trace, hw->hw_info.trace_size);
276b6ba737dSTaku Izumi else
277b6ba737dSTaku Izumi ret = -EPERM;
278b6ba737dSTaku Izumi
279b6ba737dSTaku Izumi return ret;
280b6ba737dSTaku Izumi }
281b6ba737dSTaku Izumi
282786eec27STaku Izumi static const struct ethtool_ops fjes_ethtool_ops = {
283786eec27STaku Izumi .get_drvinfo = fjes_get_drvinfo,
284786eec27STaku Izumi .get_ethtool_stats = fjes_get_ethtool_stats,
285786eec27STaku Izumi .get_strings = fjes_get_strings,
286786eec27STaku Izumi .get_sset_count = fjes_get_sset_count,
287462d8074STaku Izumi .get_regs = fjes_get_regs,
288462d8074STaku Izumi .get_regs_len = fjes_get_regs_len,
289b6ba737dSTaku Izumi .set_dump = fjes_set_dump,
290b6ba737dSTaku Izumi .get_dump_flag = fjes_get_dump_flag,
291b6ba737dSTaku Izumi .get_dump_data = fjes_get_dump_data,
292031e5144SPhilippe Reynes .get_link_ksettings = fjes_get_link_ksettings,
293786eec27STaku Izumi };
294786eec27STaku Izumi
fjes_set_ethtool_ops(struct net_device * netdev)295786eec27STaku Izumi void fjes_set_ethtool_ops(struct net_device *netdev)
296786eec27STaku Izumi {
297786eec27STaku Izumi netdev->ethtool_ops = &fjes_ethtool_ops;
298786eec27STaku Izumi }
299