1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* 10G controller driver for Samsung SoCs |
3 | * |
4 | * Copyright (C) 2013 Samsung Electronics Co., Ltd. |
5 | * http://www.samsung.com |
6 | * |
7 | * Author: Siva Reddy Kallam <siva.kallam@samsung.com> |
8 | */ |
9 | |
10 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
11 | |
12 | #include <linux/clk.h> |
13 | #include <linux/interrupt.h> |
14 | #include <linux/kernel.h> |
15 | #include <linux/netdevice.h> |
16 | #include <linux/net_tstamp.h> |
17 | #include <linux/phy.h> |
18 | #include <linux/ptp_clock_kernel.h> |
19 | |
20 | #include "sxgbe_common.h" |
21 | #include "sxgbe_reg.h" |
22 | #include "sxgbe_dma.h" |
23 | |
24 | struct sxgbe_stats { |
25 | char stat_string[ETH_GSTRING_LEN]; |
26 | int sizeof_stat; |
27 | int stat_offset; |
28 | }; |
29 | |
30 | #define SXGBE_STAT(m) \ |
31 | { \ |
32 | #m, \ |
33 | sizeof_field(struct sxgbe_extra_stats, m), \ |
34 | offsetof(struct sxgbe_priv_data, xstats.m) \ |
35 | } |
36 | |
37 | static const struct sxgbe_stats sxgbe_gstrings_stats[] = { |
38 | /* TX/RX IRQ events */ |
39 | SXGBE_STAT(tx_process_stopped_irq), |
40 | SXGBE_STAT(tx_ctxt_desc_err), |
41 | SXGBE_STAT(tx_threshold), |
42 | SXGBE_STAT(rx_threshold), |
43 | SXGBE_STAT(tx_pkt_n), |
44 | SXGBE_STAT(rx_pkt_n), |
45 | SXGBE_STAT(normal_irq_n), |
46 | SXGBE_STAT(tx_normal_irq_n), |
47 | SXGBE_STAT(rx_normal_irq_n), |
48 | SXGBE_STAT(napi_poll), |
49 | SXGBE_STAT(tx_clean), |
50 | SXGBE_STAT(tx_reset_ic_bit), |
51 | SXGBE_STAT(rx_process_stopped_irq), |
52 | SXGBE_STAT(rx_underflow_irq), |
53 | |
54 | /* Bus access errors */ |
55 | SXGBE_STAT(fatal_bus_error_irq), |
56 | SXGBE_STAT(tx_read_transfer_err), |
57 | SXGBE_STAT(tx_write_transfer_err), |
58 | SXGBE_STAT(tx_desc_access_err), |
59 | SXGBE_STAT(tx_buffer_access_err), |
60 | SXGBE_STAT(tx_data_transfer_err), |
61 | SXGBE_STAT(rx_read_transfer_err), |
62 | SXGBE_STAT(rx_write_transfer_err), |
63 | SXGBE_STAT(rx_desc_access_err), |
64 | SXGBE_STAT(rx_buffer_access_err), |
65 | SXGBE_STAT(rx_data_transfer_err), |
66 | |
67 | /* EEE-LPI stats */ |
68 | SXGBE_STAT(tx_lpi_entry_n), |
69 | SXGBE_STAT(tx_lpi_exit_n), |
70 | SXGBE_STAT(rx_lpi_entry_n), |
71 | SXGBE_STAT(rx_lpi_exit_n), |
72 | SXGBE_STAT(eee_wakeup_error_n), |
73 | |
74 | /* RX specific */ |
75 | /* L2 error */ |
76 | SXGBE_STAT(rx_code_gmii_err), |
77 | SXGBE_STAT(rx_watchdog_err), |
78 | SXGBE_STAT(rx_crc_err), |
79 | SXGBE_STAT(rx_gaint_pkt_err), |
80 | SXGBE_STAT(ip_hdr_err), |
81 | SXGBE_STAT(ip_payload_err), |
82 | SXGBE_STAT(overflow_error), |
83 | |
84 | /* L2 Pkt type */ |
85 | SXGBE_STAT(len_pkt), |
86 | SXGBE_STAT(mac_ctl_pkt), |
87 | SXGBE_STAT(dcb_ctl_pkt), |
88 | SXGBE_STAT(arp_pkt), |
89 | SXGBE_STAT(oam_pkt), |
90 | SXGBE_STAT(untag_okt), |
91 | SXGBE_STAT(other_pkt), |
92 | SXGBE_STAT(svlan_tag_pkt), |
93 | SXGBE_STAT(cvlan_tag_pkt), |
94 | SXGBE_STAT(dvlan_ocvlan_icvlan_pkt), |
95 | SXGBE_STAT(dvlan_osvlan_isvlan_pkt), |
96 | SXGBE_STAT(dvlan_osvlan_icvlan_pkt), |
97 | SXGBE_STAT(dvan_ocvlan_icvlan_pkt), |
98 | |
99 | /* L3/L4 Pkt type */ |
100 | SXGBE_STAT(not_ip_pkt), |
101 | SXGBE_STAT(ip4_tcp_pkt), |
102 | SXGBE_STAT(ip4_udp_pkt), |
103 | SXGBE_STAT(ip4_icmp_pkt), |
104 | SXGBE_STAT(ip4_unknown_pkt), |
105 | SXGBE_STAT(ip6_tcp_pkt), |
106 | SXGBE_STAT(ip6_udp_pkt), |
107 | SXGBE_STAT(ip6_icmp_pkt), |
108 | SXGBE_STAT(ip6_unknown_pkt), |
109 | |
110 | /* Filter specific */ |
111 | SXGBE_STAT(vlan_filter_match), |
112 | SXGBE_STAT(sa_filter_fail), |
113 | SXGBE_STAT(da_filter_fail), |
114 | SXGBE_STAT(hash_filter_pass), |
115 | SXGBE_STAT(l3_filter_match), |
116 | SXGBE_STAT(l4_filter_match), |
117 | |
118 | /* RX context specific */ |
119 | SXGBE_STAT(timestamp_dropped), |
120 | SXGBE_STAT(rx_msg_type_no_ptp), |
121 | SXGBE_STAT(rx_ptp_type_sync), |
122 | SXGBE_STAT(rx_ptp_type_follow_up), |
123 | SXGBE_STAT(rx_ptp_type_delay_req), |
124 | SXGBE_STAT(rx_ptp_type_delay_resp), |
125 | SXGBE_STAT(rx_ptp_type_pdelay_req), |
126 | SXGBE_STAT(rx_ptp_type_pdelay_resp), |
127 | SXGBE_STAT(rx_ptp_type_pdelay_follow_up), |
128 | SXGBE_STAT(rx_ptp_announce), |
129 | SXGBE_STAT(rx_ptp_mgmt), |
130 | SXGBE_STAT(rx_ptp_signal), |
131 | SXGBE_STAT(rx_ptp_resv_msg_type), |
132 | }; |
133 | #define SXGBE_STATS_LEN ARRAY_SIZE(sxgbe_gstrings_stats) |
134 | |
135 | static int sxgbe_get_eee(struct net_device *dev, |
136 | struct ethtool_keee *edata) |
137 | { |
138 | struct sxgbe_priv_data *priv = netdev_priv(dev); |
139 | |
140 | if (!priv->hw_cap.eee) |
141 | return -EOPNOTSUPP; |
142 | |
143 | edata->tx_lpi_timer = priv->tx_lpi_timer; |
144 | |
145 | return phy_ethtool_get_eee(phydev: dev->phydev, data: edata); |
146 | } |
147 | |
148 | static int sxgbe_set_eee(struct net_device *dev, |
149 | struct ethtool_keee *edata) |
150 | { |
151 | struct sxgbe_priv_data *priv = netdev_priv(dev); |
152 | |
153 | priv->eee_enabled = edata->eee_enabled; |
154 | |
155 | if (!priv->eee_enabled) { |
156 | sxgbe_disable_eee_mode(priv); |
157 | } else { |
158 | /* We are asking for enabling the EEE but it is safe |
159 | * to verify all by invoking the eee_init function. |
160 | * In case of failure it will return an error. |
161 | */ |
162 | priv->eee_enabled = sxgbe_eee_init(priv); |
163 | if (!priv->eee_enabled) |
164 | return -EOPNOTSUPP; |
165 | |
166 | /* Do not change tx_lpi_timer in case of failure */ |
167 | priv->tx_lpi_timer = edata->tx_lpi_timer; |
168 | } |
169 | |
170 | return phy_ethtool_set_eee(phydev: dev->phydev, data: edata); |
171 | } |
172 | |
173 | static void sxgbe_getdrvinfo(struct net_device *dev, |
174 | struct ethtool_drvinfo *info) |
175 | { |
176 | strscpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); |
177 | strscpy(info->version, DRV_VERSION, sizeof(info->version)); |
178 | } |
179 | |
180 | static u32 sxgbe_getmsglevel(struct net_device *dev) |
181 | { |
182 | struct sxgbe_priv_data *priv = netdev_priv(dev); |
183 | return priv->msg_enable; |
184 | } |
185 | |
186 | static void sxgbe_setmsglevel(struct net_device *dev, u32 level) |
187 | { |
188 | struct sxgbe_priv_data *priv = netdev_priv(dev); |
189 | priv->msg_enable = level; |
190 | } |
191 | |
192 | static void sxgbe_get_strings(struct net_device *dev, u32 stringset, u8 *data) |
193 | { |
194 | int i; |
195 | u8 *p = data; |
196 | |
197 | switch (stringset) { |
198 | case ETH_SS_STATS: |
199 | for (i = 0; i < SXGBE_STATS_LEN; i++) { |
200 | memcpy(p, sxgbe_gstrings_stats[i].stat_string, |
201 | ETH_GSTRING_LEN); |
202 | p += ETH_GSTRING_LEN; |
203 | } |
204 | break; |
205 | default: |
206 | WARN_ON(1); |
207 | break; |
208 | } |
209 | } |
210 | |
211 | static int sxgbe_get_sset_count(struct net_device *netdev, int sset) |
212 | { |
213 | int len; |
214 | |
215 | switch (sset) { |
216 | case ETH_SS_STATS: |
217 | len = SXGBE_STATS_LEN; |
218 | return len; |
219 | default: |
220 | return -EINVAL; |
221 | } |
222 | } |
223 | |
224 | static void sxgbe_get_ethtool_stats(struct net_device *dev, |
225 | struct ethtool_stats *dummy, u64 *data) |
226 | { |
227 | struct sxgbe_priv_data *priv = netdev_priv(dev); |
228 | int i; |
229 | char *p; |
230 | |
231 | if (priv->eee_enabled) { |
232 | int val = phy_get_eee_err(phydev: dev->phydev); |
233 | |
234 | if (val) |
235 | priv->xstats.eee_wakeup_error_n = val; |
236 | } |
237 | |
238 | for (i = 0; i < SXGBE_STATS_LEN; i++) { |
239 | p = (char *)priv + sxgbe_gstrings_stats[i].stat_offset; |
240 | data[i] = (sxgbe_gstrings_stats[i].sizeof_stat == sizeof(u64)) |
241 | ? (*(u64 *)p) : (*(u32 *)p); |
242 | } |
243 | } |
244 | |
245 | static void sxgbe_get_channels(struct net_device *dev, |
246 | struct ethtool_channels *channel) |
247 | { |
248 | channel->max_rx = SXGBE_MAX_RX_CHANNELS; |
249 | channel->max_tx = SXGBE_MAX_TX_CHANNELS; |
250 | channel->rx_count = SXGBE_RX_QUEUES; |
251 | channel->tx_count = SXGBE_TX_QUEUES; |
252 | } |
253 | |
254 | static u32 sxgbe_riwt2usec(u32 riwt, struct sxgbe_priv_data *priv) |
255 | { |
256 | unsigned long clk = clk_get_rate(clk: priv->sxgbe_clk); |
257 | |
258 | if (!clk) |
259 | return 0; |
260 | |
261 | return (riwt * 256) / (clk / 1000000); |
262 | } |
263 | |
264 | static u32 sxgbe_usec2riwt(u32 usec, struct sxgbe_priv_data *priv) |
265 | { |
266 | unsigned long clk = clk_get_rate(clk: priv->sxgbe_clk); |
267 | |
268 | if (!clk) |
269 | return 0; |
270 | |
271 | return (usec * (clk / 1000000)) / 256; |
272 | } |
273 | |
274 | static int sxgbe_get_coalesce(struct net_device *dev, |
275 | struct ethtool_coalesce *ec, |
276 | struct kernel_ethtool_coalesce *kernel_coal, |
277 | struct netlink_ext_ack *extack) |
278 | { |
279 | struct sxgbe_priv_data *priv = netdev_priv(dev); |
280 | |
281 | if (priv->use_riwt) |
282 | ec->rx_coalesce_usecs = sxgbe_riwt2usec(riwt: priv->rx_riwt, priv); |
283 | |
284 | return 0; |
285 | } |
286 | |
287 | static int sxgbe_set_coalesce(struct net_device *dev, |
288 | struct ethtool_coalesce *ec, |
289 | struct kernel_ethtool_coalesce *kernel_coal, |
290 | struct netlink_ext_ack *extack) |
291 | { |
292 | struct sxgbe_priv_data *priv = netdev_priv(dev); |
293 | unsigned int rx_riwt; |
294 | |
295 | if (!ec->rx_coalesce_usecs) |
296 | return -EINVAL; |
297 | |
298 | rx_riwt = sxgbe_usec2riwt(usec: ec->rx_coalesce_usecs, priv); |
299 | |
300 | if ((rx_riwt > SXGBE_MAX_DMA_RIWT) || (rx_riwt < SXGBE_MIN_DMA_RIWT)) |
301 | return -EINVAL; |
302 | else if (!priv->use_riwt) |
303 | return -EOPNOTSUPP; |
304 | |
305 | priv->rx_riwt = rx_riwt; |
306 | priv->hw->dma->rx_watchdog(priv->ioaddr, priv->rx_riwt); |
307 | |
308 | return 0; |
309 | } |
310 | |
311 | static int (struct sxgbe_priv_data *priv, |
312 | struct ethtool_rxnfc *cmd) |
313 | { |
314 | cmd->data = 0; |
315 | |
316 | /* Report default options for RSS on sxgbe */ |
317 | switch (cmd->flow_type) { |
318 | case TCP_V4_FLOW: |
319 | case UDP_V4_FLOW: |
320 | cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; |
321 | fallthrough; |
322 | case SCTP_V4_FLOW: |
323 | case AH_ESP_V4_FLOW: |
324 | case AH_V4_FLOW: |
325 | case ESP_V4_FLOW: |
326 | case IPV4_FLOW: |
327 | cmd->data |= RXH_IP_SRC | RXH_IP_DST; |
328 | break; |
329 | case TCP_V6_FLOW: |
330 | case UDP_V6_FLOW: |
331 | cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; |
332 | fallthrough; |
333 | case SCTP_V6_FLOW: |
334 | case AH_ESP_V6_FLOW: |
335 | case AH_V6_FLOW: |
336 | case ESP_V6_FLOW: |
337 | case IPV6_FLOW: |
338 | cmd->data |= RXH_IP_SRC | RXH_IP_DST; |
339 | break; |
340 | default: |
341 | return -EINVAL; |
342 | } |
343 | |
344 | return 0; |
345 | } |
346 | |
347 | static int sxgbe_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, |
348 | u32 *rule_locs) |
349 | { |
350 | struct sxgbe_priv_data *priv = netdev_priv(dev); |
351 | int ret = -EOPNOTSUPP; |
352 | |
353 | switch (cmd->cmd) { |
354 | case ETHTOOL_GRXFH: |
355 | ret = sxgbe_get_rss_hash_opts(priv, cmd); |
356 | break; |
357 | default: |
358 | break; |
359 | } |
360 | |
361 | return ret; |
362 | } |
363 | |
364 | static int (struct sxgbe_priv_data *priv, |
365 | struct ethtool_rxnfc *cmd) |
366 | { |
367 | u32 reg_val = 0; |
368 | |
369 | /* RSS does not support anything other than hashing |
370 | * to queues on src and dst IPs and ports |
371 | */ |
372 | if (cmd->data & ~(RXH_IP_SRC | RXH_IP_DST | |
373 | RXH_L4_B_0_1 | RXH_L4_B_2_3)) |
374 | return -EINVAL; |
375 | |
376 | switch (cmd->flow_type) { |
377 | case TCP_V4_FLOW: |
378 | case TCP_V6_FLOW: |
379 | if (!(cmd->data & RXH_IP_SRC) || |
380 | !(cmd->data & RXH_IP_DST) || |
381 | !(cmd->data & RXH_L4_B_0_1) || |
382 | !(cmd->data & RXH_L4_B_2_3)) |
383 | return -EINVAL; |
384 | reg_val = SXGBE_CORE_RSS_CTL_TCP4TE; |
385 | break; |
386 | case UDP_V4_FLOW: |
387 | case UDP_V6_FLOW: |
388 | if (!(cmd->data & RXH_IP_SRC) || |
389 | !(cmd->data & RXH_IP_DST) || |
390 | !(cmd->data & RXH_L4_B_0_1) || |
391 | !(cmd->data & RXH_L4_B_2_3)) |
392 | return -EINVAL; |
393 | reg_val = SXGBE_CORE_RSS_CTL_UDP4TE; |
394 | break; |
395 | case SCTP_V4_FLOW: |
396 | case AH_ESP_V4_FLOW: |
397 | case AH_V4_FLOW: |
398 | case ESP_V4_FLOW: |
399 | case AH_ESP_V6_FLOW: |
400 | case AH_V6_FLOW: |
401 | case ESP_V6_FLOW: |
402 | case SCTP_V6_FLOW: |
403 | case IPV4_FLOW: |
404 | case IPV6_FLOW: |
405 | if (!(cmd->data & RXH_IP_SRC) || |
406 | !(cmd->data & RXH_IP_DST) || |
407 | (cmd->data & RXH_L4_B_0_1) || |
408 | (cmd->data & RXH_L4_B_2_3)) |
409 | return -EINVAL; |
410 | reg_val = SXGBE_CORE_RSS_CTL_IP2TE; |
411 | break; |
412 | default: |
413 | return -EINVAL; |
414 | } |
415 | |
416 | /* Read SXGBE RSS control register and update */ |
417 | reg_val |= readl(addr: priv->ioaddr + SXGBE_CORE_RSS_CTL_REG); |
418 | writel(val: reg_val, addr: priv->ioaddr + SXGBE_CORE_RSS_CTL_REG); |
419 | readl(addr: priv->ioaddr + SXGBE_CORE_RSS_CTL_REG); |
420 | |
421 | return 0; |
422 | } |
423 | |
424 | static int sxgbe_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) |
425 | { |
426 | struct sxgbe_priv_data *priv = netdev_priv(dev); |
427 | int ret = -EOPNOTSUPP; |
428 | |
429 | switch (cmd->cmd) { |
430 | case ETHTOOL_SRXFH: |
431 | ret = sxgbe_set_rss_hash_opt(priv, cmd); |
432 | break; |
433 | default: |
434 | break; |
435 | } |
436 | |
437 | return ret; |
438 | } |
439 | |
440 | static void sxgbe_get_regs(struct net_device *dev, |
441 | struct ethtool_regs *regs, void *space) |
442 | { |
443 | struct sxgbe_priv_data *priv = netdev_priv(dev); |
444 | u32 *reg_space = (u32 *)space; |
445 | int reg_offset; |
446 | int reg_ix = 0; |
447 | void __iomem *ioaddr = priv->ioaddr; |
448 | |
449 | memset(reg_space, 0x0, REG_SPACE_SIZE); |
450 | |
451 | /* MAC registers */ |
452 | for (reg_offset = START_MAC_REG_OFFSET; |
453 | reg_offset <= MAX_MAC_REG_OFFSET; reg_offset += 4) { |
454 | reg_space[reg_ix] = readl(addr: ioaddr + reg_offset); |
455 | reg_ix++; |
456 | } |
457 | |
458 | /* MTL registers */ |
459 | for (reg_offset = START_MTL_REG_OFFSET; |
460 | reg_offset <= MAX_MTL_REG_OFFSET; reg_offset += 4) { |
461 | reg_space[reg_ix] = readl(addr: ioaddr + reg_offset); |
462 | reg_ix++; |
463 | } |
464 | |
465 | /* DMA registers */ |
466 | for (reg_offset = START_DMA_REG_OFFSET; |
467 | reg_offset <= MAX_DMA_REG_OFFSET; reg_offset += 4) { |
468 | reg_space[reg_ix] = readl(addr: ioaddr + reg_offset); |
469 | reg_ix++; |
470 | } |
471 | |
472 | BUG_ON(reg_ix * 4 > REG_SPACE_SIZE); |
473 | } |
474 | |
475 | static int sxgbe_get_regs_len(struct net_device *dev) |
476 | { |
477 | return REG_SPACE_SIZE; |
478 | } |
479 | |
480 | static const struct ethtool_ops sxgbe_ethtool_ops = { |
481 | .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS, |
482 | .get_drvinfo = sxgbe_getdrvinfo, |
483 | .get_msglevel = sxgbe_getmsglevel, |
484 | .set_msglevel = sxgbe_setmsglevel, |
485 | .get_link = ethtool_op_get_link, |
486 | .get_strings = sxgbe_get_strings, |
487 | .get_ethtool_stats = sxgbe_get_ethtool_stats, |
488 | .get_sset_count = sxgbe_get_sset_count, |
489 | .get_channels = sxgbe_get_channels, |
490 | .get_coalesce = sxgbe_get_coalesce, |
491 | .set_coalesce = sxgbe_set_coalesce, |
492 | .get_rxnfc = sxgbe_get_rxnfc, |
493 | .set_rxnfc = sxgbe_set_rxnfc, |
494 | .get_regs = sxgbe_get_regs, |
495 | .get_regs_len = sxgbe_get_regs_len, |
496 | .get_eee = sxgbe_get_eee, |
497 | .set_eee = sxgbe_set_eee, |
498 | .get_link_ksettings = phy_ethtool_get_link_ksettings, |
499 | .set_link_ksettings = phy_ethtool_set_link_ksettings, |
500 | }; |
501 | |
502 | void sxgbe_set_ethtool_ops(struct net_device *netdev) |
503 | { |
504 | netdev->ethtool_ops = &sxgbe_ethtool_ops; |
505 | } |
506 | |