xref: /linux/drivers/net/ethernet/wangxun/ngbevf/ngbevf_main.c (revision 8be4d31cb8aaeea27bde4b7ddb26e28a89062ebf)
1a0008a36SMengyuan Lou // SPDX-License-Identifier: GPL-2.0
2a0008a36SMengyuan Lou /* Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd. */
3a0008a36SMengyuan Lou 
4a0008a36SMengyuan Lou #include <linux/types.h>
5a0008a36SMengyuan Lou #include <linux/module.h>
6a0008a36SMengyuan Lou #include <linux/pci.h>
7a0008a36SMengyuan Lou #include <linux/netdevice.h>
8a0008a36SMengyuan Lou #include <linux/string.h>
9a0008a36SMengyuan Lou #include <linux/etherdevice.h>
10a0008a36SMengyuan Lou 
11a0008a36SMengyuan Lou #include "../libwx/wx_type.h"
1285494c9bSMengyuan Lou #include "../libwx/wx_hw.h"
130f71e3a6SMengyuan Lou #include "../libwx/wx_lib.h"
1485494c9bSMengyuan Lou #include "../libwx/wx_mbx.h"
1585494c9bSMengyuan Lou #include "../libwx/wx_vf.h"
16a0008a36SMengyuan Lou #include "../libwx/wx_vf_common.h"
17a0008a36SMengyuan Lou #include "ngbevf_type.h"
18a0008a36SMengyuan Lou 
19a0008a36SMengyuan Lou /* ngbevf_pci_tbl - PCI Device ID Table
20a0008a36SMengyuan Lou  *
21a0008a36SMengyuan Lou  * Wildcard entries (PCI_ANY_ID) should come last
22a0008a36SMengyuan Lou  * Last entry must be all 0s
23a0008a36SMengyuan Lou  *
24a0008a36SMengyuan Lou  * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
25a0008a36SMengyuan Lou  *   Class, Class Mask, private data (not used) }
26a0008a36SMengyuan Lou  */
27a0008a36SMengyuan Lou static const struct pci_device_id ngbevf_pci_tbl[] = {
28a0008a36SMengyuan Lou 	{ PCI_VDEVICE(WANGXUN, NGBEVF_DEV_ID_EM_WX1860AL_W), 0},
29a0008a36SMengyuan Lou 	{ PCI_VDEVICE(WANGXUN, NGBEVF_DEV_ID_EM_WX1860A2), 0},
30a0008a36SMengyuan Lou 	{ PCI_VDEVICE(WANGXUN, NGBEVF_DEV_ID_EM_WX1860A2S), 0},
31a0008a36SMengyuan Lou 	{ PCI_VDEVICE(WANGXUN, NGBEVF_DEV_ID_EM_WX1860A4), 0},
32a0008a36SMengyuan Lou 	{ PCI_VDEVICE(WANGXUN, NGBEVF_DEV_ID_EM_WX1860A4S), 0},
33a0008a36SMengyuan Lou 	{ PCI_VDEVICE(WANGXUN, NGBEVF_DEV_ID_EM_WX1860AL2), 0},
34a0008a36SMengyuan Lou 	{ PCI_VDEVICE(WANGXUN, NGBEVF_DEV_ID_EM_WX1860AL2S), 0},
35a0008a36SMengyuan Lou 	{ PCI_VDEVICE(WANGXUN, NGBEVF_DEV_ID_EM_WX1860AL4), 0},
36a0008a36SMengyuan Lou 	{ PCI_VDEVICE(WANGXUN, NGBEVF_DEV_ID_EM_WX1860AL4S), 0},
37a0008a36SMengyuan Lou 	{ PCI_VDEVICE(WANGXUN, NGBEVF_DEV_ID_EM_WX1860NCSI), 0},
38a0008a36SMengyuan Lou 	{ PCI_VDEVICE(WANGXUN, NGBEVF_DEV_ID_EM_WX1860A1), 0},
39a0008a36SMengyuan Lou 	{ PCI_VDEVICE(WANGXUN, NGBEVF_DEV_ID_EM_WX1860AL1), 0},
40a0008a36SMengyuan Lou 	/* required last entry */
41a0008a36SMengyuan Lou 	{ .device = 0 }
42a0008a36SMengyuan Lou };
43a0008a36SMengyuan Lou 
4485494c9bSMengyuan Lou static const struct net_device_ops ngbevf_netdev_ops = {
4585494c9bSMengyuan Lou 	.ndo_open               = wxvf_open,
4685494c9bSMengyuan Lou 	.ndo_stop               = wxvf_close,
470f71e3a6SMengyuan Lou 	.ndo_start_xmit         = wx_xmit_frame,
4885494c9bSMengyuan Lou 	.ndo_validate_addr      = eth_validate_addr,
4985494c9bSMengyuan Lou 	.ndo_set_mac_address    = wx_set_mac_vf,
5085494c9bSMengyuan Lou };
5185494c9bSMengyuan Lou 
ngbevf_set_num_queues(struct wx * wx)520f71e3a6SMengyuan Lou static void ngbevf_set_num_queues(struct wx *wx)
530f71e3a6SMengyuan Lou {
540f71e3a6SMengyuan Lou 	/* Start with base case */
550f71e3a6SMengyuan Lou 	wx->num_rx_queues = 1;
560f71e3a6SMengyuan Lou 	wx->num_tx_queues = 1;
570f71e3a6SMengyuan Lou }
580f71e3a6SMengyuan Lou 
ngbevf_sw_init(struct wx * wx)5985494c9bSMengyuan Lou static int ngbevf_sw_init(struct wx *wx)
6085494c9bSMengyuan Lou {
6185494c9bSMengyuan Lou 	struct net_device *netdev = wx->netdev;
6285494c9bSMengyuan Lou 	struct pci_dev *pdev = wx->pdev;
6385494c9bSMengyuan Lou 	int err;
6485494c9bSMengyuan Lou 
6585494c9bSMengyuan Lou 	/* Initialize pcie info and common capability flags */
6685494c9bSMengyuan Lou 	err = wx_sw_init(wx);
6785494c9bSMengyuan Lou 	if (err < 0)
6885494c9bSMengyuan Lou 		goto err_wx_sw_init;
6985494c9bSMengyuan Lou 
7085494c9bSMengyuan Lou 	/* Initialize the mailbox */
7185494c9bSMengyuan Lou 	err = wx_init_mbx_params_vf(wx);
7285494c9bSMengyuan Lou 	if (err)
7385494c9bSMengyuan Lou 		goto err_init_mbx_params;
7485494c9bSMengyuan Lou 
7585494c9bSMengyuan Lou 	/* Initialize the device type */
7685494c9bSMengyuan Lou 	wx->mac.type = wx_mac_em;
770f71e3a6SMengyuan Lou 	wx->mac.max_msix_vectors = NGBEVF_MAX_MSIX_VECTORS;
7885494c9bSMengyuan Lou 	/* lock to protect mailbox accesses */
7985494c9bSMengyuan Lou 	spin_lock_init(&wx->mbx.mbx_lock);
8085494c9bSMengyuan Lou 
8185494c9bSMengyuan Lou 	err = wx_reset_hw_vf(wx);
8285494c9bSMengyuan Lou 	if (err) {
8385494c9bSMengyuan Lou 		wx_err(wx, "PF still in reset state. Is the PF interface up?\n");
8485494c9bSMengyuan Lou 		goto err_reset_hw;
8585494c9bSMengyuan Lou 	}
8685494c9bSMengyuan Lou 	wx_init_hw_vf(wx);
8785494c9bSMengyuan Lou 	wx_negotiate_api_vf(wx);
8885494c9bSMengyuan Lou 	if (is_zero_ether_addr(wx->mac.addr))
8985494c9bSMengyuan Lou 		dev_info(&pdev->dev,
9085494c9bSMengyuan Lou 			 "MAC address not assigned by administrator.\n");
9185494c9bSMengyuan Lou 	eth_hw_addr_set(netdev, wx->mac.addr);
9285494c9bSMengyuan Lou 
9385494c9bSMengyuan Lou 	if (!is_valid_ether_addr(netdev->dev_addr)) {
9485494c9bSMengyuan Lou 		dev_info(&pdev->dev, "Assigning random MAC address\n");
9585494c9bSMengyuan Lou 		eth_hw_addr_random(netdev);
9685494c9bSMengyuan Lou 		ether_addr_copy(wx->mac.addr, netdev->dev_addr);
9785494c9bSMengyuan Lou 		ether_addr_copy(wx->mac.perm_addr, netdev->dev_addr);
9885494c9bSMengyuan Lou 	}
9985494c9bSMengyuan Lou 
10085494c9bSMengyuan Lou 	wx->mac.max_tx_queues = NGBEVF_MAX_TX_QUEUES;
10185494c9bSMengyuan Lou 	wx->mac.max_rx_queues = NGBEVF_MAX_RX_QUEUES;
10285494c9bSMengyuan Lou 	/* Enable dynamic interrupt throttling rates */
10385494c9bSMengyuan Lou 	wx->rx_itr_setting = 1;
10485494c9bSMengyuan Lou 	wx->tx_itr_setting = 1;
10585494c9bSMengyuan Lou 	/* set default ring sizes */
10685494c9bSMengyuan Lou 	wx->tx_ring_count = NGBEVF_DEFAULT_TXD;
10785494c9bSMengyuan Lou 	wx->rx_ring_count = NGBEVF_DEFAULT_RXD;
10885494c9bSMengyuan Lou 	/* set default work limits */
10985494c9bSMengyuan Lou 	wx->tx_work_limit = NGBEVF_DEFAULT_TX_WORK;
11085494c9bSMengyuan Lou 	wx->rx_work_limit = NGBEVF_DEFAULT_RX_WORK;
1110f71e3a6SMengyuan Lou 	wx->set_num_queues = ngbevf_set_num_queues;
11285494c9bSMengyuan Lou 
11385494c9bSMengyuan Lou 	return 0;
11485494c9bSMengyuan Lou err_reset_hw:
11585494c9bSMengyuan Lou 	kfree(wx->vfinfo);
11685494c9bSMengyuan Lou err_init_mbx_params:
11785494c9bSMengyuan Lou 	kfree(wx->rss_key);
11885494c9bSMengyuan Lou 	kfree(wx->mac_table);
11985494c9bSMengyuan Lou err_wx_sw_init:
12085494c9bSMengyuan Lou 	return err;
12185494c9bSMengyuan Lou }
12285494c9bSMengyuan Lou 
123a0008a36SMengyuan Lou /**
124a0008a36SMengyuan Lou  * ngbevf_probe - Device Initialization Routine
125a0008a36SMengyuan Lou  * @pdev: PCI device information struct
126a0008a36SMengyuan Lou  * @ent: entry in ngbevf_pci_tbl
127a0008a36SMengyuan Lou  *
128a0008a36SMengyuan Lou  * Return: return 0 on success, negative on failure
129a0008a36SMengyuan Lou  *
130a0008a36SMengyuan Lou  * ngbevf_probe initializes an adapter identified by a pci_dev structure.
131a0008a36SMengyuan Lou  * The OS initialization, configuring of the adapter private structure,
132a0008a36SMengyuan Lou  * and a hardware reset occur.
133a0008a36SMengyuan Lou  **/
ngbevf_probe(struct pci_dev * pdev,const struct pci_device_id __always_unused * ent)134a0008a36SMengyuan Lou static int ngbevf_probe(struct pci_dev *pdev,
135a0008a36SMengyuan Lou 			const struct pci_device_id __always_unused *ent)
136a0008a36SMengyuan Lou {
137a0008a36SMengyuan Lou 	struct net_device *netdev;
138a0008a36SMengyuan Lou 	struct wx *wx = NULL;
139a0008a36SMengyuan Lou 	int err;
140a0008a36SMengyuan Lou 
141a0008a36SMengyuan Lou 	err = pci_enable_device_mem(pdev);
142a0008a36SMengyuan Lou 	if (err)
143a0008a36SMengyuan Lou 		return err;
144a0008a36SMengyuan Lou 
145a0008a36SMengyuan Lou 	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
146a0008a36SMengyuan Lou 	if (err) {
147a0008a36SMengyuan Lou 		dev_err(&pdev->dev,
148a0008a36SMengyuan Lou 			"No usable DMA configuration, aborting\n");
149a0008a36SMengyuan Lou 		goto err_pci_disable_dev;
150a0008a36SMengyuan Lou 	}
151a0008a36SMengyuan Lou 
152a0008a36SMengyuan Lou 	err = pci_request_selected_regions(pdev,
153a0008a36SMengyuan Lou 					   pci_select_bars(pdev, IORESOURCE_MEM),
154a0008a36SMengyuan Lou 					   dev_driver_string(&pdev->dev));
155a0008a36SMengyuan Lou 	if (err) {
156a0008a36SMengyuan Lou 		dev_err(&pdev->dev,
157a0008a36SMengyuan Lou 			"pci_request_selected_regions failed 0x%x\n", err);
158a0008a36SMengyuan Lou 		goto err_pci_disable_dev;
159a0008a36SMengyuan Lou 	}
160a0008a36SMengyuan Lou 
161a0008a36SMengyuan Lou 	pci_set_master(pdev);
162a0008a36SMengyuan Lou 
163a0008a36SMengyuan Lou 	netdev = devm_alloc_etherdev_mqs(&pdev->dev,
164a0008a36SMengyuan Lou 					 sizeof(struct wx),
165a0008a36SMengyuan Lou 					 NGBEVF_MAX_TX_QUEUES,
166a0008a36SMengyuan Lou 					 NGBEVF_MAX_RX_QUEUES);
167a0008a36SMengyuan Lou 	if (!netdev) {
168a0008a36SMengyuan Lou 		err = -ENOMEM;
169a0008a36SMengyuan Lou 		goto err_pci_release_regions;
170a0008a36SMengyuan Lou 	}
171a0008a36SMengyuan Lou 
172a0008a36SMengyuan Lou 	SET_NETDEV_DEV(netdev, &pdev->dev);
173a0008a36SMengyuan Lou 
174a0008a36SMengyuan Lou 	wx = netdev_priv(netdev);
175a0008a36SMengyuan Lou 	wx->netdev = netdev;
176a0008a36SMengyuan Lou 	wx->pdev = pdev;
177a0008a36SMengyuan Lou 
178a0008a36SMengyuan Lou 	wx->msg_enable = netif_msg_init(-1, NETIF_MSG_DRV |
179a0008a36SMengyuan Lou 					NETIF_MSG_PROBE | NETIF_MSG_LINK);
180a0008a36SMengyuan Lou 	wx->hw_addr = devm_ioremap(&pdev->dev,
181a0008a36SMengyuan Lou 				   pci_resource_start(pdev, 0),
182a0008a36SMengyuan Lou 				   pci_resource_len(pdev, 0));
183a0008a36SMengyuan Lou 	if (!wx->hw_addr) {
184a0008a36SMengyuan Lou 		err = -EIO;
185a0008a36SMengyuan Lou 		goto err_pci_release_regions;
186a0008a36SMengyuan Lou 	}
187a0008a36SMengyuan Lou 
18885494c9bSMengyuan Lou 	netdev->netdev_ops = &ngbevf_netdev_ops;
18985494c9bSMengyuan Lou 
19085494c9bSMengyuan Lou 	/* setup the private structure */
19185494c9bSMengyuan Lou 	err = ngbevf_sw_init(wx);
19285494c9bSMengyuan Lou 	if (err)
19385494c9bSMengyuan Lou 		goto err_pci_release_regions;
19485494c9bSMengyuan Lou 
195a0008a36SMengyuan Lou 	netdev->features |= NETIF_F_HIGHDMA;
19685494c9bSMengyuan Lou 
19785494c9bSMengyuan Lou 	eth_hw_addr_set(netdev, wx->mac.perm_addr);
19885494c9bSMengyuan Lou 	ether_addr_copy(netdev->perm_addr, wx->mac.addr);
19985494c9bSMengyuan Lou 
200*cfeedf6aSMengyuan Lou 	wxvf_init_service(wx);
2010f71e3a6SMengyuan Lou 	err = wx_init_interrupt_scheme(wx);
2020f71e3a6SMengyuan Lou 	if (err)
2030f71e3a6SMengyuan Lou 		goto err_free_sw_init;
2040f71e3a6SMengyuan Lou 
20585494c9bSMengyuan Lou 	err = register_netdev(netdev);
20685494c9bSMengyuan Lou 	if (err)
20785494c9bSMengyuan Lou 		goto err_register;
20885494c9bSMengyuan Lou 
209a0008a36SMengyuan Lou 	pci_set_drvdata(pdev, wx);
2100f71e3a6SMengyuan Lou 	netif_tx_stop_all_queues(netdev);
211a0008a36SMengyuan Lou 
212a0008a36SMengyuan Lou 	return 0;
213a0008a36SMengyuan Lou 
21485494c9bSMengyuan Lou err_register:
2150f71e3a6SMengyuan Lou 	wx_clear_interrupt_scheme(wx);
2160f71e3a6SMengyuan Lou err_free_sw_init:
217*cfeedf6aSMengyuan Lou 	timer_delete_sync(&wx->service_timer);
218*cfeedf6aSMengyuan Lou 	cancel_work_sync(&wx->service_task);
21985494c9bSMengyuan Lou 	kfree(wx->vfinfo);
22085494c9bSMengyuan Lou 	kfree(wx->rss_key);
22185494c9bSMengyuan Lou 	kfree(wx->mac_table);
222a0008a36SMengyuan Lou err_pci_release_regions:
223a0008a36SMengyuan Lou 	pci_release_selected_regions(pdev,
224a0008a36SMengyuan Lou 				     pci_select_bars(pdev, IORESOURCE_MEM));
225a0008a36SMengyuan Lou err_pci_disable_dev:
226a0008a36SMengyuan Lou 	pci_disable_device(pdev);
227a0008a36SMengyuan Lou 	return err;
228a0008a36SMengyuan Lou }
229a0008a36SMengyuan Lou 
230a0008a36SMengyuan Lou /**
231a0008a36SMengyuan Lou  * ngbevf_remove - Device Removal Routine
232a0008a36SMengyuan Lou  * @pdev: PCI device information struct
233a0008a36SMengyuan Lou  *
234a0008a36SMengyuan Lou  * ngbevf_remove is called by the PCI subsystem to alert the driver
235a0008a36SMengyuan Lou  * that it should release a PCI device.  The could be caused by a
236a0008a36SMengyuan Lou  * Hot-Plug event, or because the driver is going to be removed from
237a0008a36SMengyuan Lou  * memory.
238a0008a36SMengyuan Lou  **/
ngbevf_remove(struct pci_dev * pdev)239a0008a36SMengyuan Lou static void ngbevf_remove(struct pci_dev *pdev)
240a0008a36SMengyuan Lou {
241a0008a36SMengyuan Lou 	wxvf_remove(pdev);
242a0008a36SMengyuan Lou }
243a0008a36SMengyuan Lou 
244a0008a36SMengyuan Lou static DEFINE_SIMPLE_DEV_PM_OPS(ngbevf_pm_ops, wxvf_suspend, wxvf_resume);
245a0008a36SMengyuan Lou 
246a0008a36SMengyuan Lou static struct pci_driver ngbevf_driver = {
247a0008a36SMengyuan Lou 	.name     = KBUILD_MODNAME,
248a0008a36SMengyuan Lou 	.id_table = ngbevf_pci_tbl,
249a0008a36SMengyuan Lou 	.probe    = ngbevf_probe,
250a0008a36SMengyuan Lou 	.remove   = ngbevf_remove,
251a0008a36SMengyuan Lou 	.shutdown = wxvf_shutdown,
252a0008a36SMengyuan Lou 	/* Power Management Hooks */
253a0008a36SMengyuan Lou 	.driver.pm	= pm_sleep_ptr(&ngbevf_pm_ops)
254a0008a36SMengyuan Lou };
255a0008a36SMengyuan Lou 
256a0008a36SMengyuan Lou module_pci_driver(ngbevf_driver);
257a0008a36SMengyuan Lou 
258a0008a36SMengyuan Lou MODULE_DEVICE_TABLE(pci, ngbevf_pci_tbl);
259a0008a36SMengyuan Lou MODULE_AUTHOR("Beijing WangXun Technology Co., Ltd, <software@trustnetic.com>");
260a0008a36SMengyuan Lou MODULE_DESCRIPTION("WangXun(R) Gigabit PCI Express Network Driver");
261a0008a36SMengyuan Lou MODULE_LICENSE("GPL");
262