1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright (c) 2015 - 2023 Beijing WangXun Technology Co., Ltd. */ |
3 | |
4 | #include <linux/pci.h> |
5 | #include <linux/phy.h> |
6 | #include <linux/netdevice.h> |
7 | |
8 | #include "../libwx/wx_ethtool.h" |
9 | #include "../libwx/wx_type.h" |
10 | #include "../libwx/wx_lib.h" |
11 | #include "../libwx/wx_hw.h" |
12 | #include "ngbe_ethtool.h" |
13 | #include "ngbe_type.h" |
14 | |
15 | static void ngbe_get_wol(struct net_device *netdev, |
16 | struct ethtool_wolinfo *wol) |
17 | { |
18 | struct wx *wx = netdev_priv(dev: netdev); |
19 | |
20 | if (!wx->wol_hw_supported) |
21 | return; |
22 | wol->supported = WAKE_MAGIC; |
23 | wol->wolopts = 0; |
24 | if (wx->wol & WX_PSR_WKUP_CTL_MAG) |
25 | wol->wolopts |= WAKE_MAGIC; |
26 | } |
27 | |
28 | static int ngbe_set_wol(struct net_device *netdev, |
29 | struct ethtool_wolinfo *wol) |
30 | { |
31 | struct wx *wx = netdev_priv(dev: netdev); |
32 | struct pci_dev *pdev = wx->pdev; |
33 | |
34 | if (!wx->wol_hw_supported) |
35 | return -EOPNOTSUPP; |
36 | |
37 | wx->wol = 0; |
38 | if (wol->wolopts & WAKE_MAGIC) |
39 | wx->wol = WX_PSR_WKUP_CTL_MAG; |
40 | netdev->wol_enabled = !!(wx->wol); |
41 | wr32(wx, WX_PSR_WKUP_CTL, wx->wol); |
42 | device_set_wakeup_enable(dev: &pdev->dev, enable: netdev->wol_enabled); |
43 | |
44 | return 0; |
45 | } |
46 | |
47 | static int ngbe_set_ringparam(struct net_device *netdev, |
48 | struct ethtool_ringparam *ring, |
49 | struct kernel_ethtool_ringparam *kernel_ring, |
50 | struct netlink_ext_ack *extack) |
51 | { |
52 | struct wx *wx = netdev_priv(dev: netdev); |
53 | u32 new_rx_count, new_tx_count; |
54 | struct wx_ring *temp_ring; |
55 | int i; |
56 | |
57 | new_tx_count = clamp_t(u32, ring->tx_pending, WX_MIN_TXD, WX_MAX_TXD); |
58 | new_tx_count = ALIGN(new_tx_count, WX_REQ_TX_DESCRIPTOR_MULTIPLE); |
59 | |
60 | new_rx_count = clamp_t(u32, ring->rx_pending, WX_MIN_RXD, WX_MAX_RXD); |
61 | new_rx_count = ALIGN(new_rx_count, WX_REQ_RX_DESCRIPTOR_MULTIPLE); |
62 | |
63 | if (new_tx_count == wx->tx_ring_count && |
64 | new_rx_count == wx->rx_ring_count) |
65 | return 0; |
66 | |
67 | if (!netif_running(dev: wx->netdev)) { |
68 | for (i = 0; i < wx->num_tx_queues; i++) |
69 | wx->tx_ring[i]->count = new_tx_count; |
70 | for (i = 0; i < wx->num_rx_queues; i++) |
71 | wx->rx_ring[i]->count = new_rx_count; |
72 | wx->tx_ring_count = new_tx_count; |
73 | wx->rx_ring_count = new_rx_count; |
74 | |
75 | return 0; |
76 | } |
77 | |
78 | /* allocate temporary buffer to store rings in */ |
79 | i = max_t(int, wx->num_tx_queues, wx->num_rx_queues); |
80 | temp_ring = kvmalloc_array(n: i, size: sizeof(struct wx_ring), GFP_KERNEL); |
81 | if (!temp_ring) |
82 | return -ENOMEM; |
83 | |
84 | ngbe_down(wx); |
85 | |
86 | wx_set_ring(wx, new_tx_count, new_rx_count, temp_ring); |
87 | kvfree(addr: temp_ring); |
88 | |
89 | wx_configure(wx); |
90 | ngbe_up(wx); |
91 | |
92 | return 0; |
93 | } |
94 | |
95 | static int ngbe_set_channels(struct net_device *dev, |
96 | struct ethtool_channels *ch) |
97 | { |
98 | int err; |
99 | |
100 | err = wx_set_channels(dev, ch); |
101 | if (err < 0) |
102 | return err; |
103 | |
104 | /* use setup TC to update any traffic class queue mapping */ |
105 | return ngbe_setup_tc(dev, tc: netdev_get_num_tc(dev)); |
106 | } |
107 | |
108 | static const struct ethtool_ops ngbe_ethtool_ops = { |
109 | .supported_coalesce_params = ETHTOOL_COALESCE_USECS | |
110 | ETHTOOL_COALESCE_TX_MAX_FRAMES_IRQ, |
111 | .get_drvinfo = wx_get_drvinfo, |
112 | .get_link = ethtool_op_get_link, |
113 | .get_link_ksettings = wx_get_link_ksettings, |
114 | .set_link_ksettings = wx_set_link_ksettings, |
115 | .nway_reset = wx_nway_reset, |
116 | .get_wol = ngbe_get_wol, |
117 | .set_wol = ngbe_set_wol, |
118 | .get_sset_count = wx_get_sset_count, |
119 | .get_strings = wx_get_strings, |
120 | .get_ethtool_stats = wx_get_ethtool_stats, |
121 | .get_eth_mac_stats = wx_get_mac_stats, |
122 | .get_pause_stats = wx_get_pause_stats, |
123 | .get_pauseparam = wx_get_pauseparam, |
124 | .set_pauseparam = wx_set_pauseparam, |
125 | .get_ringparam = wx_get_ringparam, |
126 | .set_ringparam = ngbe_set_ringparam, |
127 | .get_coalesce = wx_get_coalesce, |
128 | .set_coalesce = wx_set_coalesce, |
129 | .get_channels = wx_get_channels, |
130 | .set_channels = ngbe_set_channels, |
131 | .get_msglevel = wx_get_msglevel, |
132 | .set_msglevel = wx_set_msglevel, |
133 | }; |
134 | |
135 | void ngbe_set_ethtool_ops(struct net_device *netdev) |
136 | { |
137 | netdev->ethtool_ops = &ngbe_ethtool_ops; |
138 | } |
139 | |