1
2
3
4
5
6
7
8
9#include "aq_main.h"
10#include "aq_nic.h"
11#include "aq_pci_func.h"
12#include "aq_ethtool.h"
13#include "aq_filters.h"
14
15#include <linux/netdevice.h>
16#include <linux/module.h>
17
18MODULE_LICENSE("GPL v2");
19MODULE_VERSION(AQ_CFG_DRV_VERSION);
20MODULE_AUTHOR(AQ_CFG_DRV_AUTHOR);
21MODULE_DESCRIPTION(AQ_CFG_DRV_DESC);
22
23static const char aq_ndev_driver_name[] = AQ_CFG_DRV_NAME;
24
25static const struct net_device_ops aq_ndev_ops;
26
27static struct workqueue_struct *aq_ndev_wq;
28
29void aq_ndev_schedule_work(struct work_struct *work)
30{
31 queue_work(aq_ndev_wq, work);
32}
33
34struct net_device *aq_ndev_alloc(void)
35{
36 struct net_device *ndev = NULL;
37 struct aq_nic_s *aq_nic = NULL;
38
39 ndev = alloc_etherdev_mq(sizeof(struct aq_nic_s), AQ_CFG_VECS_MAX);
40 if (!ndev)
41 return NULL;
42
43 aq_nic = netdev_priv(ndev);
44 aq_nic->ndev = ndev;
45 ndev->netdev_ops = &aq_ndev_ops;
46 ndev->ethtool_ops = &aq_ethtool_ops;
47
48 return ndev;
49}
50
51static int aq_ndev_open(struct net_device *ndev)
52{
53 int err = 0;
54 struct aq_nic_s *aq_nic = netdev_priv(ndev);
55
56 err = aq_nic_init(aq_nic);
57 if (err < 0)
58 goto err_exit;
59
60 err = aq_reapply_rxnfc_all_rules(aq_nic);
61 if (err < 0)
62 goto err_exit;
63
64 err = aq_filters_vlans_update(aq_nic);
65 if (err < 0)
66 goto err_exit;
67
68 err = aq_nic_start(aq_nic);
69 if (err < 0)
70 goto err_exit;
71
72err_exit:
73 if (err < 0)
74 aq_nic_deinit(aq_nic);
75 return err;
76}
77
78static int aq_ndev_close(struct net_device *ndev)
79{
80 int err = 0;
81 struct aq_nic_s *aq_nic = netdev_priv(ndev);
82
83 err = aq_nic_stop(aq_nic);
84 if (err < 0)
85 goto err_exit;
86 aq_nic_deinit(aq_nic);
87
88err_exit:
89 return err;
90}
91
92static int aq_ndev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
93{
94 struct aq_nic_s *aq_nic = netdev_priv(ndev);
95
96 return aq_nic_xmit(aq_nic, skb);
97}
98
99static int aq_ndev_change_mtu(struct net_device *ndev, int new_mtu)
100{
101 struct aq_nic_s *aq_nic = netdev_priv(ndev);
102 int err = aq_nic_set_mtu(aq_nic, new_mtu + ETH_HLEN);
103
104 if (err < 0)
105 goto err_exit;
106 ndev->mtu = new_mtu;
107
108err_exit:
109 return err;
110}
111
112static int aq_ndev_set_features(struct net_device *ndev,
113 netdev_features_t features)
114{
115 bool is_vlan_rx_strip = !!(features & NETIF_F_HW_VLAN_CTAG_RX);
116 bool is_vlan_tx_insert = !!(features & NETIF_F_HW_VLAN_CTAG_TX);
117 struct aq_nic_s *aq_nic = netdev_priv(ndev);
118 bool need_ndev_restart = false;
119 struct aq_nic_cfg_s *aq_cfg;
120 bool is_lro = false;
121 int err = 0;
122
123 aq_cfg = aq_nic_get_cfg(aq_nic);
124
125 if (!(features & NETIF_F_NTUPLE)) {
126 if (aq_nic->ndev->features & NETIF_F_NTUPLE) {
127 err = aq_clear_rxnfc_all_rules(aq_nic);
128 if (unlikely(err))
129 goto err_exit;
130 }
131 }
132 if (!(features & NETIF_F_HW_VLAN_CTAG_FILTER)) {
133 if (aq_nic->ndev->features & NETIF_F_HW_VLAN_CTAG_FILTER) {
134 err = aq_filters_vlan_offload_off(aq_nic);
135 if (unlikely(err))
136 goto err_exit;
137 }
138 }
139
140 aq_cfg->features = features;
141
142 if (aq_cfg->aq_hw_caps->hw_features & NETIF_F_LRO) {
143 is_lro = features & NETIF_F_LRO;
144
145 if (aq_cfg->is_lro != is_lro) {
146 aq_cfg->is_lro = is_lro;
147 need_ndev_restart = true;
148 }
149 }
150
151 if ((aq_nic->ndev->features ^ features) & NETIF_F_RXCSUM) {
152 err = aq_nic->aq_hw_ops->hw_set_offload(aq_nic->aq_hw,
153 aq_cfg);
154
155 if (unlikely(err))
156 goto err_exit;
157 }
158
159 if (aq_cfg->is_vlan_rx_strip != is_vlan_rx_strip) {
160 aq_cfg->is_vlan_rx_strip = is_vlan_rx_strip;
161 need_ndev_restart = true;
162 }
163 if (aq_cfg->is_vlan_tx_insert != is_vlan_tx_insert) {
164 aq_cfg->is_vlan_tx_insert = is_vlan_tx_insert;
165 need_ndev_restart = true;
166 }
167
168 if (need_ndev_restart && netif_running(ndev)) {
169 aq_ndev_close(ndev);
170 aq_ndev_open(ndev);
171 }
172
173err_exit:
174 return err;
175}
176
177static int aq_ndev_set_mac_address(struct net_device *ndev, void *addr)
178{
179 struct aq_nic_s *aq_nic = netdev_priv(ndev);
180 int err = 0;
181
182 err = eth_mac_addr(ndev, addr);
183 if (err < 0)
184 goto err_exit;
185 err = aq_nic_set_mac(aq_nic, ndev);
186 if (err < 0)
187 goto err_exit;
188
189err_exit:
190 return err;
191}
192
193static void aq_ndev_set_multicast_settings(struct net_device *ndev)
194{
195 struct aq_nic_s *aq_nic = netdev_priv(ndev);
196
197 aq_nic_set_packet_filter(aq_nic, ndev->flags);
198
199 aq_nic_set_multicast_list(aq_nic, ndev);
200}
201
202static int aq_ndo_vlan_rx_add_vid(struct net_device *ndev, __be16 proto,
203 u16 vid)
204{
205 struct aq_nic_s *aq_nic = netdev_priv(ndev);
206
207 if (!aq_nic->aq_hw_ops->hw_filter_vlan_set)
208 return -EOPNOTSUPP;
209
210 set_bit(vid, aq_nic->active_vlans);
211
212 return aq_filters_vlans_update(aq_nic);
213}
214
215static int aq_ndo_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto,
216 u16 vid)
217{
218 struct aq_nic_s *aq_nic = netdev_priv(ndev);
219
220 if (!aq_nic->aq_hw_ops->hw_filter_vlan_set)
221 return -EOPNOTSUPP;
222
223 clear_bit(vid, aq_nic->active_vlans);
224
225 if (-ENOENT == aq_del_fvlan_by_vlan(aq_nic, vid))
226 return aq_filters_vlans_update(aq_nic);
227
228 return 0;
229}
230
231static const struct net_device_ops aq_ndev_ops = {
232 .ndo_open = aq_ndev_open,
233 .ndo_stop = aq_ndev_close,
234 .ndo_start_xmit = aq_ndev_start_xmit,
235 .ndo_set_rx_mode = aq_ndev_set_multicast_settings,
236 .ndo_change_mtu = aq_ndev_change_mtu,
237 .ndo_set_mac_address = aq_ndev_set_mac_address,
238 .ndo_set_features = aq_ndev_set_features,
239 .ndo_vlan_rx_add_vid = aq_ndo_vlan_rx_add_vid,
240 .ndo_vlan_rx_kill_vid = aq_ndo_vlan_rx_kill_vid,
241};
242
243static int __init aq_ndev_init_module(void)
244{
245 int ret;
246
247 aq_ndev_wq = create_singlethread_workqueue(aq_ndev_driver_name);
248 if (!aq_ndev_wq) {
249 pr_err("Failed to create workqueue\n");
250 return -ENOMEM;
251 }
252
253 ret = aq_pci_func_register_driver();
254 if (ret) {
255 destroy_workqueue(aq_ndev_wq);
256 return ret;
257 }
258
259 return 0;
260}
261
262static void __exit aq_ndev_exit_module(void)
263{
264 aq_pci_func_unregister_driver();
265
266 if (aq_ndev_wq) {
267 destroy_workqueue(aq_ndev_wq);
268 aq_ndev_wq = NULL;
269 }
270}
271
272module_init(aq_ndev_init_module);
273module_exit(aq_ndev_exit_module);
274