1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright (c) 2019 - 2022 Beijing WangXun Technology Co., Ltd. */ |
3 | |
4 | #include <linux/types.h> |
5 | #include <linux/module.h> |
6 | #include <linux/pci.h> |
7 | #include <linux/netdevice.h> |
8 | #include <linux/string.h> |
9 | #include <linux/etherdevice.h> |
10 | #include <net/ip.h> |
11 | #include <linux/phy.h> |
12 | #include <linux/if_vlan.h> |
13 | |
14 | #include "../libwx/wx_type.h" |
15 | #include "../libwx/wx_hw.h" |
16 | #include "../libwx/wx_lib.h" |
17 | #include "ngbe_type.h" |
18 | #include "ngbe_mdio.h" |
19 | #include "ngbe_hw.h" |
20 | #include "ngbe_ethtool.h" |
21 | |
22 | char ngbe_driver_name[] = "ngbe" ; |
23 | |
24 | /* ngbe_pci_tbl - PCI Device ID Table |
25 | * |
26 | * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, |
27 | * Class, Class Mask, private data (not used) } |
28 | */ |
29 | static const struct pci_device_id ngbe_pci_tbl[] = { |
30 | { PCI_VDEVICE(WANGXUN, NGBE_DEV_ID_EM_WX1860AL_W), 0}, |
31 | { PCI_VDEVICE(WANGXUN, NGBE_DEV_ID_EM_WX1860A2), 0}, |
32 | { PCI_VDEVICE(WANGXUN, NGBE_DEV_ID_EM_WX1860A2S), 0}, |
33 | { PCI_VDEVICE(WANGXUN, NGBE_DEV_ID_EM_WX1860A4), 0}, |
34 | { PCI_VDEVICE(WANGXUN, NGBE_DEV_ID_EM_WX1860A4S), 0}, |
35 | { PCI_VDEVICE(WANGXUN, NGBE_DEV_ID_EM_WX1860AL2), 0}, |
36 | { PCI_VDEVICE(WANGXUN, NGBE_DEV_ID_EM_WX1860AL2S), 0}, |
37 | { PCI_VDEVICE(WANGXUN, NGBE_DEV_ID_EM_WX1860AL4), 0}, |
38 | { PCI_VDEVICE(WANGXUN, NGBE_DEV_ID_EM_WX1860AL4S), 0}, |
39 | { PCI_VDEVICE(WANGXUN, NGBE_DEV_ID_EM_WX1860LC), 0}, |
40 | { PCI_VDEVICE(WANGXUN, NGBE_DEV_ID_EM_WX1860A1), 0}, |
41 | { PCI_VDEVICE(WANGXUN, NGBE_DEV_ID_EM_WX1860A1L), 0}, |
42 | /* required last entry */ |
43 | { .device = 0 } |
44 | }; |
45 | |
46 | /** |
47 | * ngbe_init_type_code - Initialize the shared code |
48 | * @wx: pointer to hardware structure |
49 | **/ |
50 | static void ngbe_init_type_code(struct wx *wx) |
51 | { |
52 | int wol_mask = 0, ncsi_mask = 0; |
53 | u16 type_mask = 0, val; |
54 | |
55 | wx->mac.type = wx_mac_em; |
56 | type_mask = (u16)(wx->subsystem_device_id & NGBE_OEM_MASK); |
57 | ncsi_mask = wx->subsystem_device_id & NGBE_NCSI_MASK; |
58 | wol_mask = wx->subsystem_device_id & NGBE_WOL_MASK; |
59 | |
60 | val = rd32(wx, WX_CFG_PORT_ST); |
61 | wx->mac_type = (val & BIT(7)) >> 7 ? |
62 | em_mac_type_rgmii : |
63 | em_mac_type_mdi; |
64 | |
65 | wx->wol_hw_supported = (wol_mask == NGBE_WOL_SUP) ? 1 : 0; |
66 | wx->ncsi_enabled = (ncsi_mask == NGBE_NCSI_MASK || |
67 | type_mask == NGBE_SUBID_OCP_CARD) ? 1 : 0; |
68 | |
69 | switch (type_mask) { |
70 | case NGBE_SUBID_LY_YT8521S_SFP: |
71 | case NGBE_SUBID_LY_M88E1512_SFP: |
72 | case NGBE_SUBID_YT8521S_SFP_GPIO: |
73 | case NGBE_SUBID_INTERNAL_YT8521S_SFP_GPIO: |
74 | wx->gpio_ctrl = 1; |
75 | break; |
76 | default: |
77 | wx->gpio_ctrl = 0; |
78 | break; |
79 | } |
80 | } |
81 | |
82 | /** |
83 | * ngbe_sw_init - Initialize general software structures |
84 | * @wx: board private structure to initialize |
85 | **/ |
86 | static int ngbe_sw_init(struct wx *wx) |
87 | { |
88 | struct pci_dev *pdev = wx->pdev; |
89 | u16 msix_count = 0; |
90 | int err = 0; |
91 | |
92 | wx->mac.num_rar_entries = NGBE_RAR_ENTRIES; |
93 | wx->mac.max_rx_queues = NGBE_MAX_RX_QUEUES; |
94 | wx->mac.max_tx_queues = NGBE_MAX_TX_QUEUES; |
95 | wx->mac.mcft_size = NGBE_MC_TBL_SIZE; |
96 | wx->mac.vft_size = NGBE_SP_VFT_TBL_SIZE; |
97 | wx->mac.rx_pb_size = NGBE_RX_PB_SIZE; |
98 | wx->mac.tx_pb_size = NGBE_TDB_PB_SZ; |
99 | |
100 | /* PCI config space info */ |
101 | err = wx_sw_init(wx); |
102 | if (err < 0) |
103 | return err; |
104 | |
105 | /* mac type, phy type , oem type */ |
106 | ngbe_init_type_code(wx); |
107 | |
108 | /* Set common capability flags and settings */ |
109 | wx->max_q_vectors = NGBE_MAX_MSIX_VECTORS; |
110 | err = wx_get_pcie_msix_counts(wx, msix_count: &msix_count, NGBE_MAX_MSIX_VECTORS); |
111 | if (err) |
112 | dev_err(&pdev->dev, "Do not support MSI-X\n" ); |
113 | wx->mac.max_msix_vectors = msix_count; |
114 | |
115 | wx->ring_feature[RING_F_RSS].limit = min_t(int, NGBE_MAX_RSS_INDICES, |
116 | num_online_cpus()); |
117 | wx->rss_enabled = true; |
118 | |
119 | /* enable itr by default in dynamic mode */ |
120 | wx->rx_itr_setting = 1; |
121 | wx->tx_itr_setting = 1; |
122 | |
123 | /* set default ring sizes */ |
124 | wx->tx_ring_count = NGBE_DEFAULT_TXD; |
125 | wx->rx_ring_count = NGBE_DEFAULT_RXD; |
126 | |
127 | /* set default work limits */ |
128 | wx->tx_work_limit = NGBE_DEFAULT_TX_WORK; |
129 | wx->rx_work_limit = NGBE_DEFAULT_RX_WORK; |
130 | |
131 | return 0; |
132 | } |
133 | |
134 | /** |
135 | * ngbe_irq_enable - Enable default interrupt generation settings |
136 | * @wx: board private structure |
137 | * @queues: enable all queues interrupts |
138 | **/ |
139 | static void ngbe_irq_enable(struct wx *wx, bool queues) |
140 | { |
141 | u32 mask; |
142 | |
143 | /* enable misc interrupt */ |
144 | mask = NGBE_PX_MISC_IEN_MASK; |
145 | |
146 | wr32(wx, WX_GPIO_DDR, WX_GPIO_DDR_0); |
147 | wr32(wx, WX_GPIO_INTEN, WX_GPIO_INTEN_0 | WX_GPIO_INTEN_1); |
148 | wr32(wx, WX_GPIO_INTTYPE_LEVEL, 0x0); |
149 | wr32(wx, WX_GPIO_POLARITY, wx->gpio_ctrl ? 0 : 0x3); |
150 | |
151 | wr32(wx, WX_PX_MISC_IEN, mask); |
152 | |
153 | /* mask interrupt */ |
154 | if (queues) |
155 | wx_intr_enable(wx, NGBE_INTR_ALL); |
156 | else |
157 | wx_intr_enable(wx, NGBE_INTR_MISC); |
158 | } |
159 | |
160 | /** |
161 | * ngbe_intr - msi/legacy mode Interrupt Handler |
162 | * @irq: interrupt number |
163 | * @data: pointer to a network interface device structure |
164 | **/ |
165 | static irqreturn_t ngbe_intr(int __always_unused irq, void *data) |
166 | { |
167 | struct wx_q_vector *q_vector; |
168 | struct wx *wx = data; |
169 | struct pci_dev *pdev; |
170 | u32 eicr; |
171 | |
172 | q_vector = wx->q_vector[0]; |
173 | pdev = wx->pdev; |
174 | |
175 | eicr = wx_misc_isb(wx, idx: WX_ISB_VEC0); |
176 | if (!eicr) { |
177 | /* shared interrupt alert! |
178 | * the interrupt that we masked before the EICR read. |
179 | */ |
180 | if (netif_running(dev: wx->netdev)) |
181 | ngbe_irq_enable(wx, queues: true); |
182 | return IRQ_NONE; /* Not our interrupt */ |
183 | } |
184 | wx->isb_mem[WX_ISB_VEC0] = 0; |
185 | if (!(pdev->msi_enabled)) |
186 | wr32(wx, WX_PX_INTA, 1); |
187 | |
188 | wx->isb_mem[WX_ISB_MISC] = 0; |
189 | /* would disable interrupts here but it is auto disabled */ |
190 | napi_schedule_irqoff(n: &q_vector->napi); |
191 | |
192 | if (netif_running(dev: wx->netdev)) |
193 | ngbe_irq_enable(wx, queues: false); |
194 | |
195 | return IRQ_HANDLED; |
196 | } |
197 | |
198 | static irqreturn_t ngbe_msix_other(int __always_unused irq, void *data) |
199 | { |
200 | struct wx *wx = data; |
201 | |
202 | /* re-enable the original interrupt state, no lsc, no queues */ |
203 | if (netif_running(dev: wx->netdev)) |
204 | ngbe_irq_enable(wx, queues: false); |
205 | |
206 | return IRQ_HANDLED; |
207 | } |
208 | |
209 | /** |
210 | * ngbe_request_msix_irqs - Initialize MSI-X interrupts |
211 | * @wx: board private structure |
212 | * |
213 | * ngbe_request_msix_irqs allocates MSI-X vectors and requests |
214 | * interrupts from the kernel. |
215 | **/ |
216 | static int ngbe_request_msix_irqs(struct wx *wx) |
217 | { |
218 | struct net_device *netdev = wx->netdev; |
219 | int vector, err; |
220 | |
221 | for (vector = 0; vector < wx->num_q_vectors; vector++) { |
222 | struct wx_q_vector *q_vector = wx->q_vector[vector]; |
223 | struct msix_entry *entry = &wx->msix_q_entries[vector]; |
224 | |
225 | if (q_vector->tx.ring && q_vector->rx.ring) |
226 | snprintf(buf: q_vector->name, size: sizeof(q_vector->name) - 1, |
227 | fmt: "%s-TxRx-%d" , netdev->name, entry->entry); |
228 | else |
229 | /* skip this unused q_vector */ |
230 | continue; |
231 | |
232 | err = request_irq(irq: entry->vector, handler: wx_msix_clean_rings, flags: 0, |
233 | name: q_vector->name, dev: q_vector); |
234 | if (err) { |
235 | wx_err(wx, "request_irq failed for MSIX interrupt %s Error: %d\n" , |
236 | q_vector->name, err); |
237 | goto free_queue_irqs; |
238 | } |
239 | } |
240 | |
241 | err = request_irq(irq: wx->msix_entry->vector, |
242 | handler: ngbe_msix_other, flags: 0, name: netdev->name, dev: wx); |
243 | |
244 | if (err) { |
245 | wx_err(wx, "request_irq for msix_other failed: %d\n" , err); |
246 | goto free_queue_irqs; |
247 | } |
248 | |
249 | return 0; |
250 | |
251 | free_queue_irqs: |
252 | while (vector) { |
253 | vector--; |
254 | free_irq(wx->msix_q_entries[vector].vector, |
255 | wx->q_vector[vector]); |
256 | } |
257 | wx_reset_interrupt_capability(wx); |
258 | return err; |
259 | } |
260 | |
261 | /** |
262 | * ngbe_request_irq - initialize interrupts |
263 | * @wx: board private structure |
264 | * |
265 | * Attempts to configure interrupts using the best available |
266 | * capabilities of the hardware and kernel. |
267 | **/ |
268 | static int ngbe_request_irq(struct wx *wx) |
269 | { |
270 | struct net_device *netdev = wx->netdev; |
271 | struct pci_dev *pdev = wx->pdev; |
272 | int err; |
273 | |
274 | if (pdev->msix_enabled) |
275 | err = ngbe_request_msix_irqs(wx); |
276 | else if (pdev->msi_enabled) |
277 | err = request_irq(irq: pdev->irq, handler: ngbe_intr, flags: 0, |
278 | name: netdev->name, dev: wx); |
279 | else |
280 | err = request_irq(irq: pdev->irq, handler: ngbe_intr, IRQF_SHARED, |
281 | name: netdev->name, dev: wx); |
282 | |
283 | if (err) |
284 | wx_err(wx, "request_irq failed, Error %d\n" , err); |
285 | |
286 | return err; |
287 | } |
288 | |
289 | static void ngbe_disable_device(struct wx *wx) |
290 | { |
291 | struct net_device *netdev = wx->netdev; |
292 | u32 i; |
293 | |
294 | /* disable all enabled rx queues */ |
295 | for (i = 0; i < wx->num_rx_queues; i++) |
296 | /* this call also flushes the previous write */ |
297 | wx_disable_rx_queue(wx, ring: wx->rx_ring[i]); |
298 | /* disable receives */ |
299 | wx_disable_rx(wx); |
300 | wx_napi_disable_all(wx); |
301 | netif_tx_stop_all_queues(dev: netdev); |
302 | netif_tx_disable(dev: netdev); |
303 | if (wx->gpio_ctrl) |
304 | ngbe_sfp_modules_txrx_powerctl(wx, swi: false); |
305 | wx_irq_disable(wx); |
306 | /* disable transmits in the hardware now that interrupts are off */ |
307 | for (i = 0; i < wx->num_tx_queues; i++) { |
308 | u8 reg_idx = wx->tx_ring[i]->reg_idx; |
309 | |
310 | wr32(wx, WX_PX_TR_CFG(reg_idx), WX_PX_TR_CFG_SWFLSH); |
311 | } |
312 | |
313 | wx_update_stats(wx); |
314 | } |
315 | |
316 | void ngbe_down(struct wx *wx) |
317 | { |
318 | phylink_stop(wx->phylink); |
319 | ngbe_disable_device(wx); |
320 | wx_clean_all_tx_rings(wx); |
321 | wx_clean_all_rx_rings(wx); |
322 | } |
323 | |
324 | void ngbe_up(struct wx *wx) |
325 | { |
326 | wx_configure_vectors(wx); |
327 | |
328 | /* make sure to complete pre-operations */ |
329 | smp_mb__before_atomic(); |
330 | wx_napi_enable_all(wx); |
331 | /* enable transmits */ |
332 | netif_tx_start_all_queues(dev: wx->netdev); |
333 | |
334 | /* clear any pending interrupts, may auto mask */ |
335 | rd32(wx, WX_PX_IC(0)); |
336 | rd32(wx, WX_PX_MISC_IC); |
337 | ngbe_irq_enable(wx, queues: true); |
338 | if (wx->gpio_ctrl) |
339 | ngbe_sfp_modules_txrx_powerctl(wx, swi: true); |
340 | |
341 | phylink_start(wx->phylink); |
342 | } |
343 | |
344 | /** |
345 | * ngbe_open - Called when a network interface is made active |
346 | * @netdev: network interface device structure |
347 | * |
348 | * Returns 0 on success, negative value on failure |
349 | * |
350 | * The open entry point is called when a network interface is made |
351 | * active by the system (IFF_UP). |
352 | **/ |
353 | static int ngbe_open(struct net_device *netdev) |
354 | { |
355 | struct wx *wx = netdev_priv(dev: netdev); |
356 | int err; |
357 | |
358 | wx_control_hw(wx, drv: true); |
359 | |
360 | err = wx_setup_resources(wx); |
361 | if (err) |
362 | return err; |
363 | |
364 | wx_configure(wx); |
365 | |
366 | err = ngbe_request_irq(wx); |
367 | if (err) |
368 | goto err_free_resources; |
369 | |
370 | err = phylink_connect_phy(wx->phylink, wx->phydev); |
371 | if (err) |
372 | goto err_free_irq; |
373 | |
374 | err = netif_set_real_num_tx_queues(dev: netdev, txq: wx->num_tx_queues); |
375 | if (err) |
376 | goto err_dis_phy; |
377 | |
378 | err = netif_set_real_num_rx_queues(dev: netdev, rxq: wx->num_rx_queues); |
379 | if (err) |
380 | goto err_dis_phy; |
381 | |
382 | ngbe_up(wx); |
383 | |
384 | return 0; |
385 | err_dis_phy: |
386 | phylink_disconnect_phy(wx->phylink); |
387 | err_free_irq: |
388 | wx_free_irq(wx); |
389 | err_free_resources: |
390 | wx_free_resources(wx); |
391 | return err; |
392 | } |
393 | |
394 | /** |
395 | * ngbe_close - Disables a network interface |
396 | * @netdev: network interface device structure |
397 | * |
398 | * Returns 0, this is not allowed to fail |
399 | * |
400 | * The close entry point is called when an interface is de-activated |
401 | * by the OS. The hardware is still under the drivers control, but |
402 | * needs to be disabled. A global MAC reset is issued to stop the |
403 | * hardware, and all transmit and receive resources are freed. |
404 | **/ |
405 | static int ngbe_close(struct net_device *netdev) |
406 | { |
407 | struct wx *wx = netdev_priv(dev: netdev); |
408 | |
409 | ngbe_down(wx); |
410 | wx_free_irq(wx); |
411 | wx_free_resources(wx); |
412 | phylink_disconnect_phy(wx->phylink); |
413 | wx_control_hw(wx, drv: false); |
414 | |
415 | return 0; |
416 | } |
417 | |
418 | static void ngbe_dev_shutdown(struct pci_dev *pdev, bool *enable_wake) |
419 | { |
420 | struct wx *wx = pci_get_drvdata(pdev); |
421 | struct net_device *netdev; |
422 | u32 wufc = wx->wol; |
423 | |
424 | netdev = wx->netdev; |
425 | rtnl_lock(); |
426 | netif_device_detach(dev: netdev); |
427 | |
428 | if (netif_running(dev: netdev)) |
429 | ngbe_close(netdev); |
430 | wx_clear_interrupt_scheme(wx); |
431 | rtnl_unlock(); |
432 | |
433 | if (wufc) { |
434 | wx_set_rx_mode(netdev); |
435 | wx_configure_rx(wx); |
436 | wr32(wx, NGBE_PSR_WKUP_CTL, wufc); |
437 | } else { |
438 | wr32(wx, NGBE_PSR_WKUP_CTL, 0); |
439 | } |
440 | pci_wake_from_d3(dev: pdev, enable: !!wufc); |
441 | *enable_wake = !!wufc; |
442 | wx_control_hw(wx, drv: false); |
443 | |
444 | pci_disable_device(dev: pdev); |
445 | } |
446 | |
447 | static void ngbe_shutdown(struct pci_dev *pdev) |
448 | { |
449 | struct wx *wx = pci_get_drvdata(pdev); |
450 | bool wake; |
451 | |
452 | wake = !!wx->wol; |
453 | |
454 | ngbe_dev_shutdown(pdev, enable_wake: &wake); |
455 | |
456 | if (system_state == SYSTEM_POWER_OFF) { |
457 | pci_wake_from_d3(dev: pdev, enable: wake); |
458 | pci_set_power_state(dev: pdev, PCI_D3hot); |
459 | } |
460 | } |
461 | |
462 | /** |
463 | * ngbe_setup_tc - routine to configure net_device for multiple traffic |
464 | * classes. |
465 | * |
466 | * @dev: net device to configure |
467 | * @tc: number of traffic classes to enable |
468 | */ |
469 | int ngbe_setup_tc(struct net_device *dev, u8 tc) |
470 | { |
471 | struct wx *wx = netdev_priv(dev); |
472 | |
473 | /* Hardware has to reinitialize queues and interrupts to |
474 | * match packet buffer alignment. Unfortunately, the |
475 | * hardware is not flexible enough to do this dynamically. |
476 | */ |
477 | if (netif_running(dev)) |
478 | ngbe_close(netdev: dev); |
479 | |
480 | wx_clear_interrupt_scheme(wx); |
481 | |
482 | if (tc) |
483 | netdev_set_num_tc(dev, num_tc: tc); |
484 | else |
485 | netdev_reset_tc(dev); |
486 | |
487 | wx_init_interrupt_scheme(wx); |
488 | |
489 | if (netif_running(dev)) |
490 | ngbe_open(netdev: dev); |
491 | |
492 | return 0; |
493 | } |
494 | |
495 | static const struct net_device_ops ngbe_netdev_ops = { |
496 | .ndo_open = ngbe_open, |
497 | .ndo_stop = ngbe_close, |
498 | .ndo_change_mtu = wx_change_mtu, |
499 | .ndo_start_xmit = wx_xmit_frame, |
500 | .ndo_set_rx_mode = wx_set_rx_mode, |
501 | .ndo_set_features = wx_set_features, |
502 | .ndo_validate_addr = eth_validate_addr, |
503 | .ndo_set_mac_address = wx_set_mac, |
504 | .ndo_get_stats64 = wx_get_stats64, |
505 | .ndo_vlan_rx_add_vid = wx_vlan_rx_add_vid, |
506 | .ndo_vlan_rx_kill_vid = wx_vlan_rx_kill_vid, |
507 | }; |
508 | |
509 | /** |
510 | * ngbe_probe - Device Initialization Routine |
511 | * @pdev: PCI device information struct |
512 | * @ent: entry in ngbe_pci_tbl |
513 | * |
514 | * Returns 0 on success, negative on failure |
515 | * |
516 | * ngbe_probe initializes an wx identified by a pci_dev structure. |
517 | * The OS initialization, configuring of the wx private structure, |
518 | * and a hardware reset occur. |
519 | **/ |
520 | static int ngbe_probe(struct pci_dev *pdev, |
521 | const struct pci_device_id __always_unused *ent) |
522 | { |
523 | struct net_device *netdev; |
524 | u32 e2rom_cksum_cap = 0; |
525 | struct wx *wx = NULL; |
526 | static int func_nums; |
527 | u16 e2rom_ver = 0; |
528 | u32 etrack_id = 0; |
529 | u32 saved_ver = 0; |
530 | int err; |
531 | |
532 | err = pci_enable_device_mem(dev: pdev); |
533 | if (err) |
534 | return err; |
535 | |
536 | err = dma_set_mask_and_coherent(dev: &pdev->dev, DMA_BIT_MASK(64)); |
537 | if (err) { |
538 | dev_err(&pdev->dev, |
539 | "No usable DMA configuration, aborting\n" ); |
540 | goto err_pci_disable_dev; |
541 | } |
542 | |
543 | err = pci_request_selected_regions(pdev, |
544 | pci_select_bars(dev: pdev, IORESOURCE_MEM), |
545 | ngbe_driver_name); |
546 | if (err) { |
547 | dev_err(&pdev->dev, |
548 | "pci_request_selected_regions failed %d\n" , err); |
549 | goto err_pci_disable_dev; |
550 | } |
551 | |
552 | pci_set_master(dev: pdev); |
553 | |
554 | netdev = devm_alloc_etherdev_mqs(dev: &pdev->dev, |
555 | sizeof_priv: sizeof(struct wx), |
556 | NGBE_MAX_TX_QUEUES, |
557 | NGBE_MAX_RX_QUEUES); |
558 | if (!netdev) { |
559 | err = -ENOMEM; |
560 | goto err_pci_release_regions; |
561 | } |
562 | |
563 | SET_NETDEV_DEV(netdev, &pdev->dev); |
564 | |
565 | wx = netdev_priv(dev: netdev); |
566 | wx->netdev = netdev; |
567 | wx->pdev = pdev; |
568 | wx->msg_enable = BIT(3) - 1; |
569 | |
570 | wx->hw_addr = devm_ioremap(dev: &pdev->dev, |
571 | pci_resource_start(pdev, 0), |
572 | pci_resource_len(pdev, 0)); |
573 | if (!wx->hw_addr) { |
574 | err = -EIO; |
575 | goto err_pci_release_regions; |
576 | } |
577 | |
578 | wx->driver_name = ngbe_driver_name; |
579 | ngbe_set_ethtool_ops(netdev); |
580 | netdev->netdev_ops = &ngbe_netdev_ops; |
581 | |
582 | netdev->features = NETIF_F_SG | NETIF_F_IP_CSUM | |
583 | NETIF_F_TSO | NETIF_F_TSO6 | |
584 | NETIF_F_RXHASH | NETIF_F_RXCSUM; |
585 | netdev->features |= NETIF_F_SCTP_CRC | NETIF_F_TSO_MANGLEID; |
586 | netdev->vlan_features |= netdev->features; |
587 | netdev->features |= NETIF_F_IPV6_CSUM | NETIF_F_VLAN_FEATURES; |
588 | /* copy netdev features into list of user selectable features */ |
589 | netdev->hw_features |= netdev->features | NETIF_F_RXALL; |
590 | netdev->hw_features |= NETIF_F_NTUPLE | NETIF_F_HW_TC; |
591 | netdev->features |= NETIF_F_HIGHDMA; |
592 | netdev->hw_features |= NETIF_F_GRO; |
593 | netdev->features |= NETIF_F_GRO; |
594 | |
595 | netdev->priv_flags |= IFF_UNICAST_FLT; |
596 | netdev->priv_flags |= IFF_SUPP_NOFCS; |
597 | netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE; |
598 | |
599 | netdev->min_mtu = ETH_MIN_MTU; |
600 | netdev->max_mtu = WX_MAX_JUMBO_FRAME_SIZE - |
601 | (ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN); |
602 | |
603 | wx->bd_number = func_nums; |
604 | /* setup the private structure */ |
605 | err = ngbe_sw_init(wx); |
606 | if (err) |
607 | goto err_free_mac_table; |
608 | |
609 | /* check if flash load is done after hw power up */ |
610 | err = wx_check_flash_load(wx, NGBE_SPI_ILDR_STATUS_PERST); |
611 | if (err) |
612 | goto err_free_mac_table; |
613 | err = wx_check_flash_load(wx, NGBE_SPI_ILDR_STATUS_PWRRST); |
614 | if (err) |
615 | goto err_free_mac_table; |
616 | |
617 | err = wx_mng_present(wx); |
618 | if (err) { |
619 | dev_err(&pdev->dev, "Management capability is not present\n" ); |
620 | goto err_free_mac_table; |
621 | } |
622 | |
623 | err = ngbe_reset_hw(wx); |
624 | if (err) { |
625 | dev_err(&pdev->dev, "HW Init failed: %d\n" , err); |
626 | goto err_free_mac_table; |
627 | } |
628 | |
629 | if (wx->bus.func == 0) { |
630 | wr32(wx, NGBE_CALSUM_CAP_STATUS, 0x0); |
631 | wr32(wx, NGBE_EEPROM_VERSION_STORE_REG, 0x0); |
632 | } else { |
633 | e2rom_cksum_cap = rd32(wx, NGBE_CALSUM_CAP_STATUS); |
634 | saved_ver = rd32(wx, NGBE_EEPROM_VERSION_STORE_REG); |
635 | } |
636 | |
637 | wx_init_eeprom_params(wx); |
638 | if (wx->bus.func == 0 || e2rom_cksum_cap == 0) { |
639 | /* make sure the EEPROM is ready */ |
640 | err = ngbe_eeprom_chksum_hostif(wx); |
641 | if (err) { |
642 | dev_err(&pdev->dev, "The EEPROM Checksum Is Not Valid\n" ); |
643 | err = -EIO; |
644 | goto err_free_mac_table; |
645 | } |
646 | } |
647 | |
648 | wx->wol = 0; |
649 | if (wx->wol_hw_supported) |
650 | wx->wol = NGBE_PSR_WKUP_CTL_MAG; |
651 | |
652 | netdev->wol_enabled = !!(wx->wol); |
653 | wr32(wx, NGBE_PSR_WKUP_CTL, wx->wol); |
654 | device_set_wakeup_enable(dev: &pdev->dev, enable: wx->wol); |
655 | |
656 | /* Save off EEPROM version number and Option Rom version which |
657 | * together make a unique identify for the eeprom |
658 | */ |
659 | if (saved_ver) { |
660 | etrack_id = saved_ver; |
661 | } else { |
662 | wx_read_ee_hostif(wx, |
663 | offset: wx->eeprom.sw_region_offset + NGBE_EEPROM_VERSION_H, |
664 | data: &e2rom_ver); |
665 | etrack_id = e2rom_ver << 16; |
666 | wx_read_ee_hostif(wx, |
667 | offset: wx->eeprom.sw_region_offset + NGBE_EEPROM_VERSION_L, |
668 | data: &e2rom_ver); |
669 | etrack_id |= e2rom_ver; |
670 | wr32(wx, NGBE_EEPROM_VERSION_STORE_REG, etrack_id); |
671 | } |
672 | snprintf(buf: wx->eeprom_id, size: sizeof(wx->eeprom_id), |
673 | fmt: "0x%08x" , etrack_id); |
674 | |
675 | eth_hw_addr_set(dev: netdev, addr: wx->mac.perm_addr); |
676 | wx_mac_set_default_filter(wx, addr: wx->mac.perm_addr); |
677 | |
678 | err = wx_init_interrupt_scheme(wx); |
679 | if (err) |
680 | goto err_free_mac_table; |
681 | |
682 | /* phy Interface Configuration */ |
683 | err = ngbe_mdio_init(wx); |
684 | if (err) |
685 | goto err_clear_interrupt_scheme; |
686 | |
687 | err = register_netdev(dev: netdev); |
688 | if (err) |
689 | goto err_register; |
690 | |
691 | pci_set_drvdata(pdev, data: wx); |
692 | |
693 | return 0; |
694 | |
695 | err_register: |
696 | phylink_destroy(wx->phylink); |
697 | wx_control_hw(wx, drv: false); |
698 | err_clear_interrupt_scheme: |
699 | wx_clear_interrupt_scheme(wx); |
700 | err_free_mac_table: |
701 | kfree(objp: wx->mac_table); |
702 | err_pci_release_regions: |
703 | pci_release_selected_regions(pdev, |
704 | pci_select_bars(dev: pdev, IORESOURCE_MEM)); |
705 | err_pci_disable_dev: |
706 | pci_disable_device(dev: pdev); |
707 | return err; |
708 | } |
709 | |
710 | /** |
711 | * ngbe_remove - Device Removal Routine |
712 | * @pdev: PCI device information struct |
713 | * |
714 | * ngbe_remove is called by the PCI subsystem to alert the driver |
715 | * that it should release a PCI device. The could be caused by a |
716 | * Hot-Plug event, or because the driver is going to be removed from |
717 | * memory. |
718 | **/ |
719 | static void ngbe_remove(struct pci_dev *pdev) |
720 | { |
721 | struct wx *wx = pci_get_drvdata(pdev); |
722 | struct net_device *netdev; |
723 | |
724 | netdev = wx->netdev; |
725 | unregister_netdev(dev: netdev); |
726 | phylink_destroy(wx->phylink); |
727 | pci_release_selected_regions(pdev, |
728 | pci_select_bars(dev: pdev, IORESOURCE_MEM)); |
729 | |
730 | kfree(objp: wx->rss_key); |
731 | kfree(objp: wx->mac_table); |
732 | wx_clear_interrupt_scheme(wx); |
733 | |
734 | pci_disable_device(dev: pdev); |
735 | } |
736 | |
737 | static int ngbe_suspend(struct pci_dev *pdev, pm_message_t state) |
738 | { |
739 | bool wake; |
740 | |
741 | ngbe_dev_shutdown(pdev, enable_wake: &wake); |
742 | device_set_wakeup_enable(dev: &pdev->dev, enable: wake); |
743 | |
744 | return 0; |
745 | } |
746 | |
747 | static int ngbe_resume(struct pci_dev *pdev) |
748 | { |
749 | struct net_device *netdev; |
750 | struct wx *wx; |
751 | u32 err; |
752 | |
753 | wx = pci_get_drvdata(pdev); |
754 | netdev = wx->netdev; |
755 | |
756 | err = pci_enable_device_mem(dev: pdev); |
757 | if (err) { |
758 | wx_err(wx, "Cannot enable PCI device from suspend\n" ); |
759 | return err; |
760 | } |
761 | pci_set_master(dev: pdev); |
762 | device_wakeup_disable(dev: &pdev->dev); |
763 | |
764 | ngbe_reset_hw(wx); |
765 | rtnl_lock(); |
766 | err = wx_init_interrupt_scheme(wx); |
767 | if (!err && netif_running(dev: netdev)) |
768 | err = ngbe_open(netdev); |
769 | if (!err) |
770 | netif_device_attach(dev: netdev); |
771 | rtnl_unlock(); |
772 | |
773 | return 0; |
774 | } |
775 | |
776 | static struct pci_driver ngbe_driver = { |
777 | .name = ngbe_driver_name, |
778 | .id_table = ngbe_pci_tbl, |
779 | .probe = ngbe_probe, |
780 | .remove = ngbe_remove, |
781 | .suspend = ngbe_suspend, |
782 | .resume = ngbe_resume, |
783 | .shutdown = ngbe_shutdown, |
784 | }; |
785 | |
786 | module_pci_driver(ngbe_driver); |
787 | |
788 | MODULE_DEVICE_TABLE(pci, ngbe_pci_tbl); |
789 | MODULE_AUTHOR("Beijing WangXun Technology Co., Ltd, <software@net-swift.com>" ); |
790 | MODULE_DESCRIPTION("WangXun(R) Gigabit PCI Express Network Driver" ); |
791 | MODULE_LICENSE("GPL" ); |
792 | |