]>
Commit | Line | Data |
---|---|---|
51ba902a AK |
1 | /* |
2 | * Huawei HiNIC PCI Express Linux driver | |
3 | * Copyright(c) 2017 Huawei Technologies Co., Ltd | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms and conditions of the GNU General Public License, | |
7 | * version 2, as published by the Free Software Foundation. | |
8 | * | |
9 | * This program is distributed in the hope it will be useful, but WITHOUT | |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 | * for more details. | |
13 | * | |
14 | */ | |
15 | ||
25a3ba61 | 16 | #include <linux/kernel.h> |
51ba902a | 17 | #include <linux/module.h> |
e2585ea7 | 18 | #include <linux/moduleparam.h> |
51ba902a AK |
19 | #include <linux/pci.h> |
20 | #include <linux/device.h> | |
21 | #include <linux/errno.h> | |
22 | #include <linux/types.h> | |
23 | #include <linux/etherdevice.h> | |
24 | #include <linux/netdevice.h> | |
25a3ba61 AK |
25 | #include <linux/slab.h> |
26 | #include <linux/if_vlan.h> | |
27 | #include <linux/semaphore.h> | |
c4d06d2d | 28 | #include <linux/workqueue.h> |
25a3ba61 AK |
29 | #include <net/ip.h> |
30 | #include <linux/bitops.h> | |
31 | #include <linux/bitmap.h> | |
c4d06d2d | 32 | #include <linux/delay.h> |
51ba902a AK |
33 | #include <linux/err.h> |
34 | ||
c3e79baf | 35 | #include "hinic_hw_qp.h" |
51ba902a | 36 | #include "hinic_hw_dev.h" |
25a3ba61 | 37 | #include "hinic_port.h" |
c3e79baf AK |
38 | #include "hinic_tx.h" |
39 | #include "hinic_rx.h" | |
51ba902a AK |
40 | #include "hinic_dev.h" |
41 | ||
42 | MODULE_AUTHOR("Huawei Technologies CO., Ltd"); | |
43 | MODULE_DESCRIPTION("Huawei Intelligent NIC driver"); | |
44 | MODULE_LICENSE("GPL"); | |
45 | ||
00e57a6d AK |
46 | static unsigned int tx_weight = 64; |
47 | module_param(tx_weight, uint, 0644); | |
48 | MODULE_PARM_DESC(tx_weight, "Number Tx packets for NAPI budget (default=64)"); | |
49 | ||
e2585ea7 AK |
50 | static unsigned int rx_weight = 64; |
51 | module_param(rx_weight, uint, 0644); | |
52 | MODULE_PARM_DESC(rx_weight, "Number Rx packets for NAPI budget (default=64)"); | |
53 | ||
e0b4774a ZC |
54 | #define HINIC_DEV_ID_QUAD_PORT_25GE 0x1822 |
55 | #define HINIC_DEV_ID_DUAL_PORT_25GE 0x0200 | |
56 | #define HINIC_DEV_ID_DUAL_PORT_100GE 0x0201 | |
51ba902a | 57 | |
c4d06d2d AK |
58 | #define HINIC_WQ_NAME "hinic_dev" |
59 | ||
51ba902a AK |
60 | #define MSG_ENABLE_DEFAULT (NETIF_MSG_DRV | NETIF_MSG_PROBE | \ |
61 | NETIF_MSG_IFUP | \ | |
62 | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR) | |
63 | ||
25a3ba61 AK |
64 | #define VLAN_BITMAP_SIZE(nic_dev) (ALIGN(VLAN_N_VID, 8) / 8) |
65 | ||
c4d06d2d AK |
66 | #define work_to_rx_mode_work(work) \ |
67 | container_of(work, struct hinic_rx_mode_work, work) | |
68 | ||
69 | #define rx_mode_work_to_nic_dev(rx_mode_work) \ | |
70 | container_of(rx_mode_work, struct hinic_dev, rx_mode_work) | |
71 | ||
72 | static int change_mac_addr(struct net_device *netdev, const u8 *addr); | |
73 | ||
edd384f6 AK |
74 | static void set_link_speed(struct ethtool_link_ksettings *link_ksettings, |
75 | enum hinic_speed speed) | |
76 | { | |
77 | switch (speed) { | |
78 | case HINIC_SPEED_10MB_LINK: | |
79 | link_ksettings->base.speed = SPEED_10; | |
80 | break; | |
81 | ||
82 | case HINIC_SPEED_100MB_LINK: | |
83 | link_ksettings->base.speed = SPEED_100; | |
84 | break; | |
85 | ||
86 | case HINIC_SPEED_1000MB_LINK: | |
87 | link_ksettings->base.speed = SPEED_1000; | |
88 | break; | |
89 | ||
90 | case HINIC_SPEED_10GB_LINK: | |
91 | link_ksettings->base.speed = SPEED_10000; | |
92 | break; | |
93 | ||
94 | case HINIC_SPEED_25GB_LINK: | |
95 | link_ksettings->base.speed = SPEED_25000; | |
96 | break; | |
97 | ||
98 | case HINIC_SPEED_40GB_LINK: | |
99 | link_ksettings->base.speed = SPEED_40000; | |
100 | break; | |
101 | ||
102 | case HINIC_SPEED_100GB_LINK: | |
103 | link_ksettings->base.speed = SPEED_100000; | |
104 | break; | |
105 | ||
106 | default: | |
107 | link_ksettings->base.speed = SPEED_UNKNOWN; | |
108 | break; | |
109 | } | |
110 | } | |
111 | ||
112 | static int hinic_get_link_ksettings(struct net_device *netdev, | |
113 | struct ethtool_link_ksettings | |
114 | *link_ksettings) | |
115 | { | |
116 | struct hinic_dev *nic_dev = netdev_priv(netdev); | |
117 | enum hinic_port_link_state link_state; | |
118 | struct hinic_port_cap port_cap; | |
119 | int err; | |
120 | ||
121 | ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising); | |
122 | ethtool_link_ksettings_add_link_mode(link_ksettings, supported, | |
123 | Autoneg); | |
124 | ||
125 | link_ksettings->base.speed = SPEED_UNKNOWN; | |
126 | link_ksettings->base.autoneg = AUTONEG_DISABLE; | |
127 | link_ksettings->base.duplex = DUPLEX_UNKNOWN; | |
128 | ||
129 | err = hinic_port_get_cap(nic_dev, &port_cap); | |
130 | if (err) { | |
131 | netif_err(nic_dev, drv, netdev, | |
132 | "Failed to get port capabilities\n"); | |
133 | return err; | |
134 | } | |
135 | ||
136 | err = hinic_port_link_state(nic_dev, &link_state); | |
137 | if (err) { | |
138 | netif_err(nic_dev, drv, netdev, | |
139 | "Failed to get port link state\n"); | |
140 | return err; | |
141 | } | |
142 | ||
143 | if (link_state != HINIC_LINK_STATE_UP) { | |
144 | netif_info(nic_dev, drv, netdev, "No link\n"); | |
145 | return err; | |
146 | } | |
147 | ||
148 | set_link_speed(link_ksettings, port_cap.speed); | |
149 | ||
150 | if (!!(port_cap.autoneg_cap & HINIC_AUTONEG_SUPPORTED)) | |
151 | ethtool_link_ksettings_add_link_mode(link_ksettings, | |
152 | advertising, Autoneg); | |
153 | ||
154 | if (port_cap.autoneg_state == HINIC_AUTONEG_ACTIVE) | |
155 | link_ksettings->base.autoneg = AUTONEG_ENABLE; | |
156 | ||
157 | link_ksettings->base.duplex = (port_cap.duplex == HINIC_DUPLEX_FULL) ? | |
158 | DUPLEX_FULL : DUPLEX_HALF; | |
159 | return 0; | |
160 | } | |
161 | ||
162 | static void hinic_get_drvinfo(struct net_device *netdev, | |
163 | struct ethtool_drvinfo *info) | |
164 | { | |
165 | struct hinic_dev *nic_dev = netdev_priv(netdev); | |
166 | struct hinic_hwdev *hwdev = nic_dev->hwdev; | |
167 | struct hinic_hwif *hwif = hwdev->hwif; | |
168 | ||
169 | strlcpy(info->driver, HINIC_DRV_NAME, sizeof(info->driver)); | |
170 | strlcpy(info->bus_info, pci_name(hwif->pdev), sizeof(info->bus_info)); | |
171 | } | |
172 | ||
173 | static void hinic_get_ringparam(struct net_device *netdev, | |
174 | struct ethtool_ringparam *ring) | |
175 | { | |
176 | ring->rx_max_pending = HINIC_RQ_DEPTH; | |
177 | ring->tx_max_pending = HINIC_SQ_DEPTH; | |
178 | ring->rx_pending = HINIC_RQ_DEPTH; | |
179 | ring->tx_pending = HINIC_SQ_DEPTH; | |
180 | } | |
181 | ||
182 | static void hinic_get_channels(struct net_device *netdev, | |
183 | struct ethtool_channels *channels) | |
184 | { | |
185 | struct hinic_dev *nic_dev = netdev_priv(netdev); | |
186 | struct hinic_hwdev *hwdev = nic_dev->hwdev; | |
187 | ||
188 | channels->max_rx = hwdev->nic_cap.max_qps; | |
189 | channels->max_tx = hwdev->nic_cap.max_qps; | |
190 | channels->max_other = 0; | |
191 | channels->max_combined = 0; | |
192 | channels->rx_count = hinic_hwdev_num_qps(hwdev); | |
193 | channels->tx_count = hinic_hwdev_num_qps(hwdev); | |
194 | channels->other_count = 0; | |
195 | channels->combined_count = 0; | |
196 | } | |
197 | ||
198 | static const struct ethtool_ops hinic_ethtool_ops = { | |
199 | .get_link_ksettings = hinic_get_link_ksettings, | |
200 | .get_drvinfo = hinic_get_drvinfo, | |
201 | .get_link = ethtool_op_get_link, | |
202 | .get_ringparam = hinic_get_ringparam, | |
203 | .get_channels = hinic_get_channels, | |
204 | }; | |
205 | ||
206 | static void update_rx_stats(struct hinic_dev *nic_dev, struct hinic_rxq *rxq) | |
207 | { | |
208 | struct hinic_rxq_stats *nic_rx_stats = &nic_dev->rx_stats; | |
209 | struct hinic_rxq_stats rx_stats; | |
210 | ||
211 | u64_stats_init(&rx_stats.syncp); | |
212 | ||
213 | hinic_rxq_get_stats(rxq, &rx_stats); | |
214 | ||
215 | u64_stats_update_begin(&nic_rx_stats->syncp); | |
216 | nic_rx_stats->bytes += rx_stats.bytes; | |
217 | nic_rx_stats->pkts += rx_stats.pkts; | |
218 | u64_stats_update_end(&nic_rx_stats->syncp); | |
219 | ||
220 | hinic_rxq_clean_stats(rxq); | |
221 | } | |
222 | ||
223 | static void update_tx_stats(struct hinic_dev *nic_dev, struct hinic_txq *txq) | |
224 | { | |
225 | struct hinic_txq_stats *nic_tx_stats = &nic_dev->tx_stats; | |
226 | struct hinic_txq_stats tx_stats; | |
227 | ||
228 | u64_stats_init(&tx_stats.syncp); | |
229 | ||
230 | hinic_txq_get_stats(txq, &tx_stats); | |
231 | ||
232 | u64_stats_update_begin(&nic_tx_stats->syncp); | |
233 | nic_tx_stats->bytes += tx_stats.bytes; | |
234 | nic_tx_stats->pkts += tx_stats.pkts; | |
235 | nic_tx_stats->tx_busy += tx_stats.tx_busy; | |
236 | nic_tx_stats->tx_wake += tx_stats.tx_wake; | |
237 | nic_tx_stats->tx_dropped += tx_stats.tx_dropped; | |
238 | u64_stats_update_end(&nic_tx_stats->syncp); | |
239 | ||
240 | hinic_txq_clean_stats(txq); | |
241 | } | |
242 | ||
243 | static void update_nic_stats(struct hinic_dev *nic_dev) | |
244 | { | |
245 | int i, num_qps = hinic_hwdev_num_qps(nic_dev->hwdev); | |
246 | ||
247 | for (i = 0; i < num_qps; i++) | |
248 | update_rx_stats(nic_dev, &nic_dev->rxqs[i]); | |
249 | ||
250 | for (i = 0; i < num_qps; i++) | |
251 | update_tx_stats(nic_dev, &nic_dev->txqs[i]); | |
252 | } | |
253 | ||
c3e79baf AK |
254 | /** |
255 | * create_txqs - Create the Logical Tx Queues of specific NIC device | |
256 | * @nic_dev: the specific NIC device | |
257 | * | |
258 | * Return 0 - Success, negative - Failure | |
259 | **/ | |
260 | static int create_txqs(struct hinic_dev *nic_dev) | |
261 | { | |
262 | int err, i, j, num_txqs = hinic_hwdev_num_qps(nic_dev->hwdev); | |
263 | struct net_device *netdev = nic_dev->netdev; | |
264 | size_t txq_size; | |
265 | ||
266 | if (nic_dev->txqs) | |
267 | return -EINVAL; | |
268 | ||
269 | txq_size = num_txqs * sizeof(*nic_dev->txqs); | |
270 | nic_dev->txqs = devm_kzalloc(&netdev->dev, txq_size, GFP_KERNEL); | |
271 | if (!nic_dev->txqs) | |
272 | return -ENOMEM; | |
273 | ||
274 | for (i = 0; i < num_txqs; i++) { | |
275 | struct hinic_sq *sq = hinic_hwdev_get_sq(nic_dev->hwdev, i); | |
276 | ||
277 | err = hinic_init_txq(&nic_dev->txqs[i], sq, netdev); | |
278 | if (err) { | |
279 | netif_err(nic_dev, drv, netdev, | |
280 | "Failed to init Txq\n"); | |
281 | goto err_init_txq; | |
282 | } | |
283 | } | |
284 | ||
285 | return 0; | |
286 | ||
287 | err_init_txq: | |
288 | for (j = 0; j < i; j++) | |
289 | hinic_clean_txq(&nic_dev->txqs[j]); | |
290 | ||
291 | devm_kfree(&netdev->dev, nic_dev->txqs); | |
292 | return err; | |
293 | } | |
294 | ||
295 | /** | |
296 | * free_txqs - Free the Logical Tx Queues of specific NIC device | |
297 | * @nic_dev: the specific NIC device | |
298 | **/ | |
299 | static void free_txqs(struct hinic_dev *nic_dev) | |
300 | { | |
301 | int i, num_txqs = hinic_hwdev_num_qps(nic_dev->hwdev); | |
302 | struct net_device *netdev = nic_dev->netdev; | |
303 | ||
304 | if (!nic_dev->txqs) | |
305 | return; | |
306 | ||
307 | for (i = 0; i < num_txqs; i++) | |
308 | hinic_clean_txq(&nic_dev->txqs[i]); | |
309 | ||
310 | devm_kfree(&netdev->dev, nic_dev->txqs); | |
311 | nic_dev->txqs = NULL; | |
312 | } | |
313 | ||
314 | /** | |
315 | * create_txqs - Create the Logical Rx Queues of specific NIC device | |
316 | * @nic_dev: the specific NIC device | |
317 | * | |
318 | * Return 0 - Success, negative - Failure | |
319 | **/ | |
320 | static int create_rxqs(struct hinic_dev *nic_dev) | |
321 | { | |
322 | int err, i, j, num_rxqs = hinic_hwdev_num_qps(nic_dev->hwdev); | |
323 | struct net_device *netdev = nic_dev->netdev; | |
324 | size_t rxq_size; | |
325 | ||
326 | if (nic_dev->rxqs) | |
327 | return -EINVAL; | |
328 | ||
329 | rxq_size = num_rxqs * sizeof(*nic_dev->rxqs); | |
330 | nic_dev->rxqs = devm_kzalloc(&netdev->dev, rxq_size, GFP_KERNEL); | |
331 | if (!nic_dev->rxqs) | |
332 | return -ENOMEM; | |
333 | ||
334 | for (i = 0; i < num_rxqs; i++) { | |
335 | struct hinic_rq *rq = hinic_hwdev_get_rq(nic_dev->hwdev, i); | |
336 | ||
337 | err = hinic_init_rxq(&nic_dev->rxqs[i], rq, netdev); | |
338 | if (err) { | |
339 | netif_err(nic_dev, drv, netdev, | |
340 | "Failed to init rxq\n"); | |
341 | goto err_init_rxq; | |
342 | } | |
343 | } | |
344 | ||
345 | return 0; | |
346 | ||
347 | err_init_rxq: | |
348 | for (j = 0; j < i; j++) | |
349 | hinic_clean_rxq(&nic_dev->rxqs[j]); | |
350 | ||
351 | devm_kfree(&netdev->dev, nic_dev->rxqs); | |
352 | return err; | |
353 | } | |
354 | ||
355 | /** | |
356 | * free_txqs - Free the Logical Rx Queues of specific NIC device | |
357 | * @nic_dev: the specific NIC device | |
358 | **/ | |
359 | static void free_rxqs(struct hinic_dev *nic_dev) | |
360 | { | |
361 | int i, num_rxqs = hinic_hwdev_num_qps(nic_dev->hwdev); | |
362 | struct net_device *netdev = nic_dev->netdev; | |
363 | ||
364 | if (!nic_dev->rxqs) | |
365 | return; | |
366 | ||
367 | for (i = 0; i < num_rxqs; i++) | |
368 | hinic_clean_rxq(&nic_dev->rxqs[i]); | |
369 | ||
370 | devm_kfree(&netdev->dev, nic_dev->rxqs); | |
371 | nic_dev->rxqs = NULL; | |
372 | } | |
373 | ||
c4d06d2d AK |
374 | static int hinic_open(struct net_device *netdev) |
375 | { | |
376 | struct hinic_dev *nic_dev = netdev_priv(netdev); | |
377 | enum hinic_port_link_state link_state; | |
c3e79baf AK |
378 | int err, ret, num_qps; |
379 | ||
380 | if (!(nic_dev->flags & HINIC_INTF_UP)) { | |
381 | err = hinic_hwdev_ifup(nic_dev->hwdev); | |
382 | if (err) { | |
383 | netif_err(nic_dev, drv, netdev, | |
384 | "Failed - HW interface up\n"); | |
385 | return err; | |
386 | } | |
387 | } | |
388 | ||
389 | err = create_txqs(nic_dev); | |
390 | if (err) { | |
391 | netif_err(nic_dev, drv, netdev, | |
392 | "Failed to create Tx queues\n"); | |
393 | goto err_create_txqs; | |
394 | } | |
395 | ||
396 | err = create_rxqs(nic_dev); | |
397 | if (err) { | |
398 | netif_err(nic_dev, drv, netdev, | |
399 | "Failed to create Rx queues\n"); | |
400 | goto err_create_rxqs; | |
401 | } | |
402 | ||
403 | num_qps = hinic_hwdev_num_qps(nic_dev->hwdev); | |
404 | netif_set_real_num_tx_queues(netdev, num_qps); | |
405 | netif_set_real_num_rx_queues(netdev, num_qps); | |
c4d06d2d AK |
406 | |
407 | err = hinic_port_set_state(nic_dev, HINIC_PORT_ENABLE); | |
408 | if (err) { | |
409 | netif_err(nic_dev, drv, netdev, | |
410 | "Failed to set port state\n"); | |
c3e79baf | 411 | goto err_port_state; |
c4d06d2d AK |
412 | } |
413 | ||
e2585ea7 AK |
414 | err = hinic_port_set_func_state(nic_dev, HINIC_FUNC_PORT_ENABLE); |
415 | if (err) { | |
416 | netif_err(nic_dev, drv, netdev, | |
417 | "Failed to set func port state\n"); | |
418 | goto err_func_port_state; | |
419 | } | |
420 | ||
c4d06d2d AK |
421 | /* Wait up to 3 sec between port enable to link state */ |
422 | msleep(3000); | |
423 | ||
424 | down(&nic_dev->mgmt_lock); | |
425 | ||
426 | err = hinic_port_link_state(nic_dev, &link_state); | |
427 | if (err) { | |
428 | netif_err(nic_dev, drv, netdev, "Failed to get link state\n"); | |
429 | goto err_port_link; | |
430 | } | |
431 | ||
432 | if (link_state == HINIC_LINK_STATE_UP) | |
433 | nic_dev->flags |= HINIC_LINK_UP; | |
434 | ||
435 | nic_dev->flags |= HINIC_INTF_UP; | |
436 | ||
437 | if ((nic_dev->flags & (HINIC_LINK_UP | HINIC_INTF_UP)) == | |
438 | (HINIC_LINK_UP | HINIC_INTF_UP)) { | |
439 | netif_info(nic_dev, drv, netdev, "link + intf UP\n"); | |
440 | netif_carrier_on(netdev); | |
441 | netif_tx_wake_all_queues(netdev); | |
442 | } | |
443 | ||
444 | up(&nic_dev->mgmt_lock); | |
445 | ||
446 | netif_info(nic_dev, drv, netdev, "HINIC_INTF is UP\n"); | |
447 | return 0; | |
448 | ||
449 | err_port_link: | |
450 | up(&nic_dev->mgmt_lock); | |
e2585ea7 AK |
451 | ret = hinic_port_set_func_state(nic_dev, HINIC_FUNC_PORT_DISABLE); |
452 | if (ret) | |
453 | netif_warn(nic_dev, drv, netdev, | |
454 | "Failed to revert func port state\n"); | |
455 | ||
456 | err_func_port_state: | |
c4d06d2d AK |
457 | ret = hinic_port_set_state(nic_dev, HINIC_PORT_DISABLE); |
458 | if (ret) | |
459 | netif_warn(nic_dev, drv, netdev, | |
460 | "Failed to revert port state\n"); | |
c3e79baf AK |
461 | |
462 | err_port_state: | |
463 | free_rxqs(nic_dev); | |
464 | ||
465 | err_create_rxqs: | |
466 | free_txqs(nic_dev); | |
467 | ||
468 | err_create_txqs: | |
469 | if (!(nic_dev->flags & HINIC_INTF_UP)) | |
470 | hinic_hwdev_ifdown(nic_dev->hwdev); | |
c4d06d2d AK |
471 | return err; |
472 | } | |
473 | ||
474 | static int hinic_close(struct net_device *netdev) | |
475 | { | |
476 | struct hinic_dev *nic_dev = netdev_priv(netdev); | |
477 | unsigned int flags; | |
478 | int err; | |
479 | ||
480 | down(&nic_dev->mgmt_lock); | |
481 | ||
482 | flags = nic_dev->flags; | |
483 | nic_dev->flags &= ~HINIC_INTF_UP; | |
484 | ||
485 | netif_carrier_off(netdev); | |
486 | netif_tx_disable(netdev); | |
487 | ||
edd384f6 AK |
488 | update_nic_stats(nic_dev); |
489 | ||
c4d06d2d AK |
490 | up(&nic_dev->mgmt_lock); |
491 | ||
e2585ea7 AK |
492 | err = hinic_port_set_func_state(nic_dev, HINIC_FUNC_PORT_DISABLE); |
493 | if (err) { | |
494 | netif_err(nic_dev, drv, netdev, | |
495 | "Failed to set func port state\n"); | |
496 | nic_dev->flags |= (flags & HINIC_INTF_UP); | |
497 | return err; | |
498 | } | |
499 | ||
c4d06d2d AK |
500 | err = hinic_port_set_state(nic_dev, HINIC_PORT_DISABLE); |
501 | if (err) { | |
502 | netif_err(nic_dev, drv, netdev, "Failed to set port state\n"); | |
503 | nic_dev->flags |= (flags & HINIC_INTF_UP); | |
504 | return err; | |
505 | } | |
506 | ||
c3e79baf AK |
507 | free_rxqs(nic_dev); |
508 | free_txqs(nic_dev); | |
509 | ||
510 | if (flags & HINIC_INTF_UP) | |
511 | hinic_hwdev_ifdown(nic_dev->hwdev); | |
512 | ||
c4d06d2d AK |
513 | netif_info(nic_dev, drv, netdev, "HINIC_INTF is DOWN\n"); |
514 | return 0; | |
515 | } | |
516 | ||
25a3ba61 AK |
517 | static int hinic_change_mtu(struct net_device *netdev, int new_mtu) |
518 | { | |
519 | struct hinic_dev *nic_dev = netdev_priv(netdev); | |
520 | int err; | |
521 | ||
522 | netif_info(nic_dev, drv, netdev, "set_mtu = %d\n", new_mtu); | |
523 | ||
524 | err = hinic_port_set_mtu(nic_dev, new_mtu); | |
525 | if (err) | |
526 | netif_err(nic_dev, drv, netdev, "Failed to set port mtu\n"); | |
527 | else | |
528 | netdev->mtu = new_mtu; | |
529 | ||
530 | return err; | |
531 | } | |
532 | ||
533 | /** | |
534 | * change_mac_addr - change the main mac address of network device | |
535 | * @netdev: network device | |
536 | * @addr: mac address to set | |
537 | * | |
538 | * Return 0 - Success, negative - Failure | |
539 | **/ | |
540 | static int change_mac_addr(struct net_device *netdev, const u8 *addr) | |
541 | { | |
542 | struct hinic_dev *nic_dev = netdev_priv(netdev); | |
543 | u16 vid = 0; | |
544 | int err; | |
545 | ||
546 | if (!is_valid_ether_addr(addr)) | |
547 | return -EADDRNOTAVAIL; | |
548 | ||
549 | netif_info(nic_dev, drv, netdev, "change mac addr = %02x %02x %02x %02x %02x %02x\n", | |
550 | addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); | |
551 | ||
552 | down(&nic_dev->mgmt_lock); | |
553 | ||
554 | do { | |
555 | err = hinic_port_del_mac(nic_dev, netdev->dev_addr, vid); | |
556 | if (err) { | |
557 | netif_err(nic_dev, drv, netdev, | |
558 | "Failed to delete mac\n"); | |
559 | break; | |
560 | } | |
561 | ||
562 | err = hinic_port_add_mac(nic_dev, addr, vid); | |
563 | if (err) { | |
564 | netif_err(nic_dev, drv, netdev, "Failed to add mac\n"); | |
565 | break; | |
566 | } | |
567 | ||
568 | vid = find_next_bit(nic_dev->vlan_bitmap, VLAN_N_VID, vid + 1); | |
569 | } while (vid != VLAN_N_VID); | |
570 | ||
571 | up(&nic_dev->mgmt_lock); | |
572 | return err; | |
573 | } | |
574 | ||
575 | static int hinic_set_mac_addr(struct net_device *netdev, void *addr) | |
576 | { | |
577 | unsigned char new_mac[ETH_ALEN]; | |
578 | struct sockaddr *saddr = addr; | |
579 | int err; | |
580 | ||
581 | memcpy(new_mac, saddr->sa_data, ETH_ALEN); | |
582 | ||
583 | err = change_mac_addr(netdev, new_mac); | |
584 | if (!err) | |
585 | memcpy(netdev->dev_addr, new_mac, ETH_ALEN); | |
586 | ||
587 | return err; | |
588 | } | |
589 | ||
c4d06d2d AK |
590 | /** |
591 | * add_mac_addr - add mac address to network device | |
592 | * @netdev: network device | |
593 | * @addr: mac address to add | |
594 | * | |
595 | * Return 0 - Success, negative - Failure | |
596 | **/ | |
597 | static int add_mac_addr(struct net_device *netdev, const u8 *addr) | |
598 | { | |
599 | struct hinic_dev *nic_dev = netdev_priv(netdev); | |
600 | u16 vid = 0; | |
601 | int err; | |
602 | ||
c4d06d2d AK |
603 | netif_info(nic_dev, drv, netdev, "set mac addr = %02x %02x %02x %02x %02x %02x\n", |
604 | addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); | |
605 | ||
606 | down(&nic_dev->mgmt_lock); | |
607 | ||
608 | do { | |
609 | err = hinic_port_add_mac(nic_dev, addr, vid); | |
610 | if (err) { | |
611 | netif_err(nic_dev, drv, netdev, "Failed to add mac\n"); | |
612 | break; | |
613 | } | |
614 | ||
615 | vid = find_next_bit(nic_dev->vlan_bitmap, VLAN_N_VID, vid + 1); | |
616 | } while (vid != VLAN_N_VID); | |
617 | ||
618 | up(&nic_dev->mgmt_lock); | |
619 | return err; | |
620 | } | |
621 | ||
622 | /** | |
623 | * remove_mac_addr - remove mac address from network device | |
624 | * @netdev: network device | |
625 | * @addr: mac address to remove | |
626 | * | |
627 | * Return 0 - Success, negative - Failure | |
628 | **/ | |
629 | static int remove_mac_addr(struct net_device *netdev, const u8 *addr) | |
630 | { | |
631 | struct hinic_dev *nic_dev = netdev_priv(netdev); | |
632 | u16 vid = 0; | |
633 | int err; | |
634 | ||
635 | if (!is_valid_ether_addr(addr)) | |
636 | return -EADDRNOTAVAIL; | |
637 | ||
638 | netif_info(nic_dev, drv, netdev, "remove mac addr = %02x %02x %02x %02x %02x %02x\n", | |
639 | addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); | |
640 | ||
641 | down(&nic_dev->mgmt_lock); | |
642 | ||
643 | do { | |
644 | err = hinic_port_del_mac(nic_dev, addr, vid); | |
645 | if (err) { | |
646 | netif_err(nic_dev, drv, netdev, | |
647 | "Failed to delete mac\n"); | |
648 | break; | |
649 | } | |
650 | ||
651 | vid = find_next_bit(nic_dev->vlan_bitmap, VLAN_N_VID, vid + 1); | |
652 | } while (vid != VLAN_N_VID); | |
653 | ||
654 | up(&nic_dev->mgmt_lock); | |
655 | return err; | |
656 | } | |
657 | ||
25a3ba61 AK |
658 | static int hinic_vlan_rx_add_vid(struct net_device *netdev, |
659 | __always_unused __be16 proto, u16 vid) | |
660 | { | |
661 | struct hinic_dev *nic_dev = netdev_priv(netdev); | |
662 | int ret, err; | |
663 | ||
664 | netif_info(nic_dev, drv, netdev, "add vid = %d\n", vid); | |
665 | ||
666 | down(&nic_dev->mgmt_lock); | |
667 | ||
668 | err = hinic_port_add_vlan(nic_dev, vid); | |
669 | if (err) { | |
670 | netif_err(nic_dev, drv, netdev, "Failed to add vlan\n"); | |
671 | goto err_vlan_add; | |
672 | } | |
673 | ||
674 | err = hinic_port_add_mac(nic_dev, netdev->dev_addr, vid); | |
675 | if (err) { | |
676 | netif_err(nic_dev, drv, netdev, "Failed to set mac\n"); | |
677 | goto err_add_mac; | |
678 | } | |
679 | ||
680 | bitmap_set(nic_dev->vlan_bitmap, vid, 1); | |
681 | ||
682 | up(&nic_dev->mgmt_lock); | |
683 | return 0; | |
684 | ||
685 | err_add_mac: | |
686 | ret = hinic_port_del_vlan(nic_dev, vid); | |
687 | if (ret) | |
688 | netif_err(nic_dev, drv, netdev, | |
689 | "Failed to revert by removing vlan\n"); | |
690 | ||
691 | err_vlan_add: | |
692 | up(&nic_dev->mgmt_lock); | |
693 | return err; | |
694 | } | |
695 | ||
696 | static int hinic_vlan_rx_kill_vid(struct net_device *netdev, | |
697 | __always_unused __be16 proto, u16 vid) | |
698 | { | |
699 | struct hinic_dev *nic_dev = netdev_priv(netdev); | |
700 | int err; | |
701 | ||
702 | netif_info(nic_dev, drv, netdev, "remove vid = %d\n", vid); | |
703 | ||
704 | down(&nic_dev->mgmt_lock); | |
705 | ||
706 | err = hinic_port_del_vlan(nic_dev, vid); | |
707 | if (err) { | |
708 | netif_err(nic_dev, drv, netdev, "Failed to delete vlan\n"); | |
709 | goto err_del_vlan; | |
710 | } | |
711 | ||
712 | bitmap_clear(nic_dev->vlan_bitmap, vid, 1); | |
713 | ||
714 | up(&nic_dev->mgmt_lock); | |
715 | return 0; | |
716 | ||
717 | err_del_vlan: | |
718 | up(&nic_dev->mgmt_lock); | |
719 | return err; | |
720 | } | |
721 | ||
c4d06d2d AK |
722 | static void set_rx_mode(struct work_struct *work) |
723 | { | |
724 | struct hinic_rx_mode_work *rx_mode_work = work_to_rx_mode_work(work); | |
725 | struct hinic_dev *nic_dev = rx_mode_work_to_nic_dev(rx_mode_work); | |
10467d92 | 726 | struct netdev_hw_addr *ha; |
c4d06d2d AK |
727 | |
728 | netif_info(nic_dev, drv, nic_dev->netdev, "set rx mode work\n"); | |
729 | ||
730 | hinic_port_set_rx_mode(nic_dev, rx_mode_work->rx_mode); | |
731 | ||
732 | __dev_uc_sync(nic_dev->netdev, add_mac_addr, remove_mac_addr); | |
733 | __dev_mc_sync(nic_dev->netdev, add_mac_addr, remove_mac_addr); | |
10467d92 XC |
734 | |
735 | netdev_for_each_mc_addr(ha, nic_dev->netdev) | |
736 | add_mac_addr(nic_dev->netdev, ha->addr); | |
c4d06d2d AK |
737 | } |
738 | ||
739 | static void hinic_set_rx_mode(struct net_device *netdev) | |
740 | { | |
741 | struct hinic_dev *nic_dev = netdev_priv(netdev); | |
742 | struct hinic_rx_mode_work *rx_mode_work; | |
743 | u32 rx_mode; | |
744 | ||
745 | rx_mode_work = &nic_dev->rx_mode_work; | |
746 | ||
747 | rx_mode = HINIC_RX_MODE_UC | | |
748 | HINIC_RX_MODE_MC | | |
749 | HINIC_RX_MODE_BC; | |
750 | ||
751 | if (netdev->flags & IFF_PROMISC) | |
752 | rx_mode |= HINIC_RX_MODE_PROMISC; | |
753 | else if (netdev->flags & IFF_ALLMULTI) | |
754 | rx_mode |= HINIC_RX_MODE_MC_ALL; | |
755 | ||
756 | rx_mode_work->rx_mode = rx_mode; | |
757 | ||
758 | queue_work(nic_dev->workq, &rx_mode_work->work); | |
759 | } | |
760 | ||
00e57a6d | 761 | static void hinic_tx_timeout(struct net_device *netdev) |
c4d06d2d | 762 | { |
00e57a6d AK |
763 | struct hinic_dev *nic_dev = netdev_priv(netdev); |
764 | ||
765 | netif_err(nic_dev, drv, netdev, "Tx timeout\n"); | |
c4d06d2d AK |
766 | } |
767 | ||
edd384f6 AK |
768 | static void hinic_get_stats64(struct net_device *netdev, |
769 | struct rtnl_link_stats64 *stats) | |
770 | { | |
771 | struct hinic_dev *nic_dev = netdev_priv(netdev); | |
772 | struct hinic_rxq_stats *nic_rx_stats; | |
773 | struct hinic_txq_stats *nic_tx_stats; | |
774 | ||
775 | nic_rx_stats = &nic_dev->rx_stats; | |
776 | nic_tx_stats = &nic_dev->tx_stats; | |
777 | ||
778 | down(&nic_dev->mgmt_lock); | |
779 | ||
780 | if (nic_dev->flags & HINIC_INTF_UP) | |
781 | update_nic_stats(nic_dev); | |
782 | ||
783 | up(&nic_dev->mgmt_lock); | |
784 | ||
785 | stats->rx_bytes = nic_rx_stats->bytes; | |
786 | stats->rx_packets = nic_rx_stats->pkts; | |
787 | ||
788 | stats->tx_bytes = nic_tx_stats->bytes; | |
789 | stats->tx_packets = nic_tx_stats->pkts; | |
790 | stats->tx_errors = nic_tx_stats->tx_dropped; | |
791 | } | |
792 | ||
51ba902a | 793 | static const struct net_device_ops hinic_netdev_ops = { |
c4d06d2d AK |
794 | .ndo_open = hinic_open, |
795 | .ndo_stop = hinic_close, | |
25a3ba61 AK |
796 | .ndo_change_mtu = hinic_change_mtu, |
797 | .ndo_set_mac_address = hinic_set_mac_addr, | |
798 | .ndo_validate_addr = eth_validate_addr, | |
799 | .ndo_vlan_rx_add_vid = hinic_vlan_rx_add_vid, | |
800 | .ndo_vlan_rx_kill_vid = hinic_vlan_rx_kill_vid, | |
c4d06d2d AK |
801 | .ndo_set_rx_mode = hinic_set_rx_mode, |
802 | .ndo_start_xmit = hinic_xmit_frame, | |
00e57a6d | 803 | .ndo_tx_timeout = hinic_tx_timeout, |
edd384f6 | 804 | .ndo_get_stats64 = hinic_get_stats64, |
51ba902a AK |
805 | }; |
806 | ||
25a3ba61 AK |
807 | static void netdev_features_init(struct net_device *netdev) |
808 | { | |
49ea1963 | 809 | netdev->hw_features = NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_IP_CSUM | |
c71b8f9c XC |
810 | NETIF_F_IPV6_CSUM | NETIF_F_TSO | NETIF_F_TSO6 | |
811 | NETIF_F_RXCSUM; | |
25a3ba61 AK |
812 | |
813 | netdev->vlan_features = netdev->hw_features; | |
814 | ||
815 | netdev->features = netdev->hw_features | NETIF_F_HW_VLAN_CTAG_FILTER; | |
816 | } | |
817 | ||
c4d06d2d AK |
818 | /** |
819 | * link_status_event_handler - link event handler | |
820 | * @handle: nic device for the handler | |
821 | * @buf_in: input buffer | |
822 | * @in_size: input size | |
823 | * @buf_in: output buffer | |
824 | * @out_size: returned output size | |
825 | * | |
826 | * Return 0 - Success, negative - Failure | |
827 | **/ | |
828 | static void link_status_event_handler(void *handle, void *buf_in, u16 in_size, | |
829 | void *buf_out, u16 *out_size) | |
830 | { | |
831 | struct hinic_port_link_status *link_status, *ret_link_status; | |
832 | struct hinic_dev *nic_dev = handle; | |
833 | ||
834 | link_status = buf_in; | |
835 | ||
836 | if (link_status->link == HINIC_LINK_STATE_UP) { | |
837 | down(&nic_dev->mgmt_lock); | |
838 | ||
839 | nic_dev->flags |= HINIC_LINK_UP; | |
840 | ||
841 | if ((nic_dev->flags & (HINIC_LINK_UP | HINIC_INTF_UP)) == | |
842 | (HINIC_LINK_UP | HINIC_INTF_UP)) { | |
843 | netif_carrier_on(nic_dev->netdev); | |
844 | netif_tx_wake_all_queues(nic_dev->netdev); | |
845 | } | |
846 | ||
847 | up(&nic_dev->mgmt_lock); | |
848 | ||
849 | netif_info(nic_dev, drv, nic_dev->netdev, "HINIC_Link is UP\n"); | |
850 | } else { | |
851 | down(&nic_dev->mgmt_lock); | |
852 | ||
853 | nic_dev->flags &= ~HINIC_LINK_UP; | |
854 | ||
855 | netif_carrier_off(nic_dev->netdev); | |
856 | netif_tx_disable(nic_dev->netdev); | |
857 | ||
858 | up(&nic_dev->mgmt_lock); | |
859 | ||
860 | netif_info(nic_dev, drv, nic_dev->netdev, "HINIC_Link is DOWN\n"); | |
861 | } | |
862 | ||
863 | ret_link_status = buf_out; | |
864 | ret_link_status->status = 0; | |
865 | ||
866 | *out_size = sizeof(*ret_link_status); | |
867 | } | |
868 | ||
49ea1963 ZC |
869 | static int set_features(struct hinic_dev *nic_dev, |
870 | netdev_features_t pre_features, | |
871 | netdev_features_t features, bool force_change) | |
872 | { | |
873 | netdev_features_t changed = force_change ? ~0 : pre_features ^ features; | |
c71b8f9c | 874 | u32 csum_en = HINIC_RX_CSUM_OFFLOAD_EN; |
49ea1963 ZC |
875 | int err = 0; |
876 | ||
877 | if (changed & NETIF_F_TSO) | |
878 | err = hinic_port_set_tso(nic_dev, (features & NETIF_F_TSO) ? | |
879 | HINIC_TSO_ENABLE : HINIC_TSO_DISABLE); | |
880 | ||
c71b8f9c XC |
881 | if (changed & NETIF_F_RXCSUM) |
882 | err = hinic_set_rx_csum_offload(nic_dev, csum_en); | |
883 | ||
49ea1963 ZC |
884 | return err; |
885 | } | |
886 | ||
51ba902a AK |
887 | /** |
888 | * nic_dev_init - Initialize the NIC device | |
889 | * @pdev: the NIC pci device | |
890 | * | |
891 | * Return 0 - Success, negative - Failure | |
892 | **/ | |
893 | static int nic_dev_init(struct pci_dev *pdev) | |
894 | { | |
c4d06d2d | 895 | struct hinic_rx_mode_work *rx_mode_work; |
edd384f6 AK |
896 | struct hinic_txq_stats *tx_stats; |
897 | struct hinic_rxq_stats *rx_stats; | |
51ba902a AK |
898 | struct hinic_dev *nic_dev; |
899 | struct net_device *netdev; | |
900 | struct hinic_hwdev *hwdev; | |
901 | int err, num_qps; | |
902 | ||
903 | hwdev = hinic_init_hwdev(pdev); | |
904 | if (IS_ERR(hwdev)) { | |
905 | dev_err(&pdev->dev, "Failed to initialize HW device\n"); | |
906 | return PTR_ERR(hwdev); | |
907 | } | |
908 | ||
909 | num_qps = hinic_hwdev_num_qps(hwdev); | |
910 | if (num_qps <= 0) { | |
911 | dev_err(&pdev->dev, "Invalid number of QPS\n"); | |
912 | err = -EINVAL; | |
913 | goto err_num_qps; | |
914 | } | |
915 | ||
916 | netdev = alloc_etherdev_mq(sizeof(*nic_dev), num_qps); | |
917 | if (!netdev) { | |
918 | dev_err(&pdev->dev, "Failed to allocate Ethernet device\n"); | |
919 | err = -ENOMEM; | |
920 | goto err_alloc_etherdev; | |
921 | } | |
922 | ||
923 | netdev->netdev_ops = &hinic_netdev_ops; | |
edd384f6 | 924 | netdev->ethtool_ops = &hinic_ethtool_ops; |
52f31422 | 925 | netdev->max_mtu = ETH_MAX_MTU; |
51ba902a AK |
926 | |
927 | nic_dev = netdev_priv(netdev); | |
928 | nic_dev->netdev = netdev; | |
929 | nic_dev->hwdev = hwdev; | |
930 | nic_dev->msg_enable = MSG_ENABLE_DEFAULT; | |
c4d06d2d | 931 | nic_dev->flags = 0; |
c3e79baf AK |
932 | nic_dev->txqs = NULL; |
933 | nic_dev->rxqs = NULL; | |
00e57a6d | 934 | nic_dev->tx_weight = tx_weight; |
e2585ea7 | 935 | nic_dev->rx_weight = rx_weight; |
51ba902a | 936 | |
25a3ba61 AK |
937 | sema_init(&nic_dev->mgmt_lock, 1); |
938 | ||
edd384f6 AK |
939 | tx_stats = &nic_dev->tx_stats; |
940 | rx_stats = &nic_dev->rx_stats; | |
941 | ||
942 | u64_stats_init(&tx_stats->syncp); | |
943 | u64_stats_init(&rx_stats->syncp); | |
944 | ||
25a3ba61 AK |
945 | nic_dev->vlan_bitmap = devm_kzalloc(&pdev->dev, |
946 | VLAN_BITMAP_SIZE(nic_dev), | |
947 | GFP_KERNEL); | |
948 | if (!nic_dev->vlan_bitmap) { | |
949 | err = -ENOMEM; | |
950 | goto err_vlan_bitmap; | |
951 | } | |
952 | ||
c4d06d2d AK |
953 | nic_dev->workq = create_singlethread_workqueue(HINIC_WQ_NAME); |
954 | if (!nic_dev->workq) { | |
955 | err = -ENOMEM; | |
956 | goto err_workq; | |
957 | } | |
958 | ||
51ba902a AK |
959 | pci_set_drvdata(pdev, netdev); |
960 | ||
25a3ba61 AK |
961 | err = hinic_port_get_mac(nic_dev, netdev->dev_addr); |
962 | if (err) | |
963 | dev_warn(&pdev->dev, "Failed to get mac address\n"); | |
964 | ||
965 | err = hinic_port_add_mac(nic_dev, netdev->dev_addr, 0); | |
966 | if (err) { | |
967 | dev_err(&pdev->dev, "Failed to add mac\n"); | |
968 | goto err_add_mac; | |
969 | } | |
970 | ||
971 | err = hinic_port_set_mtu(nic_dev, netdev->mtu); | |
972 | if (err) { | |
973 | dev_err(&pdev->dev, "Failed to set mtu\n"); | |
974 | goto err_set_mtu; | |
975 | } | |
976 | ||
c4d06d2d AK |
977 | rx_mode_work = &nic_dev->rx_mode_work; |
978 | INIT_WORK(&rx_mode_work->work, set_rx_mode); | |
979 | ||
25a3ba61 AK |
980 | netdev_features_init(netdev); |
981 | ||
51ba902a AK |
982 | netif_carrier_off(netdev); |
983 | ||
c4d06d2d AK |
984 | hinic_hwdev_cb_register(nic_dev->hwdev, HINIC_MGMT_MSG_CMD_LINK_STATUS, |
985 | nic_dev, link_status_event_handler); | |
986 | ||
49ea1963 ZC |
987 | err = set_features(nic_dev, 0, nic_dev->netdev->features, true); |
988 | if (err) | |
989 | goto err_set_features; | |
990 | ||
c9c67fc1 | 991 | SET_NETDEV_DEV(netdev, &pdev->dev); |
49ea1963 | 992 | |
51ba902a AK |
993 | err = register_netdev(netdev); |
994 | if (err) { | |
995 | dev_err(&pdev->dev, "Failed to register netdev\n"); | |
996 | goto err_reg_netdev; | |
997 | } | |
998 | ||
999 | return 0; | |
1000 | ||
1001 | err_reg_netdev: | |
49ea1963 | 1002 | err_set_features: |
c4d06d2d AK |
1003 | hinic_hwdev_cb_unregister(nic_dev->hwdev, |
1004 | HINIC_MGMT_MSG_CMD_LINK_STATUS); | |
1005 | cancel_work_sync(&rx_mode_work->work); | |
1006 | ||
25a3ba61 AK |
1007 | err_set_mtu: |
1008 | err_add_mac: | |
51ba902a | 1009 | pci_set_drvdata(pdev, NULL); |
c4d06d2d | 1010 | destroy_workqueue(nic_dev->workq); |
25a3ba61 | 1011 | |
c4d06d2d | 1012 | err_workq: |
25a3ba61 | 1013 | err_vlan_bitmap: |
51ba902a AK |
1014 | free_netdev(netdev); |
1015 | ||
1016 | err_alloc_etherdev: | |
1017 | err_num_qps: | |
1018 | hinic_free_hwdev(hwdev); | |
1019 | return err; | |
1020 | } | |
1021 | ||
1022 | static int hinic_probe(struct pci_dev *pdev, | |
1023 | const struct pci_device_id *id) | |
1024 | { | |
1025 | int err = pci_enable_device(pdev); | |
1026 | ||
1027 | if (err) { | |
1028 | dev_err(&pdev->dev, "Failed to enable PCI device\n"); | |
1029 | return err; | |
1030 | } | |
1031 | ||
1032 | err = pci_request_regions(pdev, HINIC_DRV_NAME); | |
1033 | if (err) { | |
1034 | dev_err(&pdev->dev, "Failed to request PCI regions\n"); | |
1035 | goto err_pci_regions; | |
1036 | } | |
1037 | ||
1038 | pci_set_master(pdev); | |
1039 | ||
1040 | err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); | |
1041 | if (err) { | |
1042 | dev_warn(&pdev->dev, "Couldn't set 64-bit DMA mask\n"); | |
1043 | err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); | |
1044 | if (err) { | |
1045 | dev_err(&pdev->dev, "Failed to set DMA mask\n"); | |
1046 | goto err_dma_mask; | |
1047 | } | |
1048 | } | |
1049 | ||
1050 | err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); | |
1051 | if (err) { | |
1052 | dev_warn(&pdev->dev, | |
1053 | "Couldn't set 64-bit consistent DMA mask\n"); | |
1054 | err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); | |
1055 | if (err) { | |
1056 | dev_err(&pdev->dev, | |
1057 | "Failed to set consistent DMA mask\n"); | |
1058 | goto err_dma_consistent_mask; | |
1059 | } | |
1060 | } | |
1061 | ||
1062 | err = nic_dev_init(pdev); | |
1063 | if (err) { | |
1064 | dev_err(&pdev->dev, "Failed to initialize NIC device\n"); | |
1065 | goto err_nic_dev_init; | |
1066 | } | |
1067 | ||
1068 | dev_info(&pdev->dev, "HiNIC driver - probed\n"); | |
1069 | return 0; | |
1070 | ||
1071 | err_nic_dev_init: | |
1072 | err_dma_consistent_mask: | |
1073 | err_dma_mask: | |
1074 | pci_release_regions(pdev); | |
1075 | ||
1076 | err_pci_regions: | |
1077 | pci_disable_device(pdev); | |
1078 | return err; | |
1079 | } | |
1080 | ||
1081 | static void hinic_remove(struct pci_dev *pdev) | |
1082 | { | |
1083 | struct net_device *netdev = pci_get_drvdata(pdev); | |
1084 | struct hinic_dev *nic_dev = netdev_priv(netdev); | |
c4d06d2d | 1085 | struct hinic_rx_mode_work *rx_mode_work; |
51ba902a AK |
1086 | |
1087 | unregister_netdev(netdev); | |
1088 | ||
c4d06d2d AK |
1089 | hinic_hwdev_cb_unregister(nic_dev->hwdev, |
1090 | HINIC_MGMT_MSG_CMD_LINK_STATUS); | |
1091 | ||
1092 | rx_mode_work = &nic_dev->rx_mode_work; | |
1093 | cancel_work_sync(&rx_mode_work->work); | |
1094 | ||
51ba902a AK |
1095 | pci_set_drvdata(pdev, NULL); |
1096 | ||
c4d06d2d AK |
1097 | destroy_workqueue(nic_dev->workq); |
1098 | ||
51ba902a AK |
1099 | hinic_free_hwdev(nic_dev->hwdev); |
1100 | ||
1101 | free_netdev(netdev); | |
1102 | ||
1103 | pci_release_regions(pdev); | |
1104 | pci_disable_device(pdev); | |
1105 | ||
1106 | dev_info(&pdev->dev, "HiNIC driver - removed\n"); | |
1107 | } | |
1108 | ||
ac632682 XC |
1109 | static void hinic_shutdown(struct pci_dev *pdev) |
1110 | { | |
1111 | pci_disable_device(pdev); | |
1112 | } | |
1113 | ||
51ba902a | 1114 | static const struct pci_device_id hinic_pci_table[] = { |
e0b4774a ZC |
1115 | { PCI_VDEVICE(HUAWEI, HINIC_DEV_ID_QUAD_PORT_25GE), 0}, |
1116 | { PCI_VDEVICE(HUAWEI, HINIC_DEV_ID_DUAL_PORT_25GE), 0}, | |
1117 | { PCI_VDEVICE(HUAWEI, HINIC_DEV_ID_DUAL_PORT_100GE), 0}, | |
51ba902a AK |
1118 | { 0, 0} |
1119 | }; | |
1120 | MODULE_DEVICE_TABLE(pci, hinic_pci_table); | |
1121 | ||
1122 | static struct pci_driver hinic_driver = { | |
1123 | .name = HINIC_DRV_NAME, | |
1124 | .id_table = hinic_pci_table, | |
1125 | .probe = hinic_probe, | |
1126 | .remove = hinic_remove, | |
ac632682 | 1127 | .shutdown = hinic_shutdown, |
51ba902a AK |
1128 | }; |
1129 | ||
1130 | module_pci_driver(hinic_driver); |