1 // SPDX-License-Identifier: GPL-2.0-only
3 * FUJITSU Extended Socket Network Device driver
4 * Copyright (c) 2015 FUJITSU LIMITED
7 /* ethtool support for fjes */
9 #include <linux/vmalloc.h>
10 #include <linux/netdevice.h>
11 #include <linux/ethtool.h>
12 #include <linux/platform_device.h>
17 char stat_string
[ETH_GSTRING_LEN
];
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) \
28 static 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
),
37 #define FJES_EP_STATS_LEN 14
38 #define FJES_STATS_LEN \
39 (ARRAY_SIZE(fjes_gstrings_stats) + \
40 ((&((struct fjes_adapter *)netdev_priv(netdev))->hw)->max_epid - 1) * \
43 static void fjes_get_ethtool_stats(struct net_device
*netdev
,
44 struct ethtool_stats
*stats
, u64
*data
)
46 struct fjes_adapter
*adapter
= netdev_priv(netdev
);
47 struct fjes_hw
*hw
= &adapter
->hw
;
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
;
57 for (epidx
= 0; epidx
< hw
->max_epid
; epidx
++) {
58 if (epidx
== hw
->my_epid
)
60 data
[i
++] = hw
->ep_shm_info
[epidx
].ep_stats
62 data
[i
++] = hw
->ep_shm_info
[epidx
].ep_stats
63 .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_stats
67 .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_stats
72 .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_stats
75 .tx_dropped_not_shared
;
76 data
[i
++] = hw
->ep_shm_info
[epidx
].ep_stats
77 .tx_dropped_ver_mismatch
;
78 data
[i
++] = hw
->ep_shm_info
[epidx
].ep_stats
79 .tx_dropped_buf_size_mismatch
;
80 data
[i
++] = hw
->ep_shm_info
[epidx
].ep_stats
81 .tx_dropped_vlanid_mismatch
;
85 static void fjes_get_strings(struct net_device
*netdev
,
86 u32 stringset
, u8
*data
)
88 struct fjes_adapter
*adapter
= netdev_priv(netdev
);
89 struct fjes_hw
*hw
= &adapter
->hw
;
95 for (i
= 0; i
< ARRAY_SIZE(fjes_gstrings_stats
); i
++) {
96 memcpy(p
, fjes_gstrings_stats
[i
].stat_string
,
100 for (i
= 0; i
< hw
->max_epid
; i
++) {
101 if (i
== hw
->my_epid
)
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
;
136 static int fjes_get_sset_count(struct net_device
*netdev
, int sset
)
140 return FJES_STATS_LEN
;
146 static void fjes_get_drvinfo(struct net_device
*netdev
,
147 struct ethtool_drvinfo
*drvinfo
)
149 struct fjes_adapter
*adapter
= netdev_priv(netdev
);
150 struct platform_device
*plat_dev
;
152 plat_dev
= adapter
->plat_dev
;
154 strlcpy(drvinfo
->driver
, fjes_driver_name
, sizeof(drvinfo
->driver
));
155 strlcpy(drvinfo
->version
, fjes_driver_version
,
156 sizeof(drvinfo
->version
));
158 strlcpy(drvinfo
->fw_version
, "none", sizeof(drvinfo
->fw_version
));
159 snprintf(drvinfo
->bus_info
, sizeof(drvinfo
->bus_info
),
160 "platform:%s", plat_dev
->name
);
163 static int fjes_get_link_ksettings(struct net_device
*netdev
,
164 struct ethtool_link_ksettings
*ecmd
)
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 */
176 static int fjes_get_regs_len(struct net_device
*netdev
)
178 #define FJES_REGS_LEN 37
179 return FJES_REGS_LEN
* sizeof(u32
);
182 static void fjes_get_regs(struct net_device
*netdev
,
183 struct ethtool_regs
*regs
, void *p
)
185 struct fjes_adapter
*adapter
= netdev_priv(netdev
);
186 struct fjes_hw
*hw
= &adapter
->hw
;
189 memset(p
, 0, FJES_REGS_LEN
* sizeof(u32
));
193 /* Information registers */
194 regs_buff
[0] = rd32(XSCT_OWNER_EPID
);
195 regs_buff
[1] = rd32(XSCT_MAX_EP
);
197 /* Device Control registers */
198 regs_buff
[4] = rd32(XSCT_DCTL
);
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
);
206 regs_buff
[13] = rd32(XSCT_REQBL
);
207 regs_buff
[14] = rd32(XSCT_REQBAL
);
208 regs_buff
[15] = rd32(XSCT_REQBAH
);
210 regs_buff
[17] = rd32(XSCT_RESPBL
);
211 regs_buff
[18] = rd32(XSCT_RESPBAL
);
212 regs_buff
[19] = rd32(XSCT_RESPBAH
);
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
);
222 static int fjes_set_dump(struct net_device
*netdev
, struct ethtool_dump
*dump
)
224 struct fjes_adapter
*adapter
= netdev_priv(netdev
);
225 struct fjes_hw
*hw
= &adapter
->hw
;
232 hw
->debug_mode
= dump
->flag
;
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
);
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
);
254 static int fjes_get_dump_flag(struct net_device
*netdev
,
255 struct ethtool_dump
*dump
)
257 struct fjes_adapter
*adapter
= netdev_priv(netdev
);
258 struct fjes_hw
*hw
= &adapter
->hw
;
260 dump
->len
= hw
->hw_info
.trace_size
;
262 dump
->flag
= hw
->debug_mode
;
267 static int fjes_get_dump_data(struct net_device
*netdev
,
268 struct ethtool_dump
*dump
, void *buf
)
270 struct fjes_adapter
*adapter
= netdev_priv(netdev
);
271 struct fjes_hw
*hw
= &adapter
->hw
;
274 if (hw
->hw_info
.trace
)
275 memcpy(buf
, hw
->hw_info
.trace
, hw
->hw_info
.trace_size
);
282 static 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
,
295 void fjes_set_ethtool_ops(struct net_device
*netdev
)
297 netdev
->ethtool_ops
= &fjes_ethtool_ops
;