xref: /linux/drivers/net/ethernet/wangxun/txgbevf/txgbevf_main.c (revision 8be4d31cb8aaeea27bde4b7ddb26e28a89062ebf)
1377d180bSMengyuan Lou // SPDX-License-Identifier: GPL-2.0
2377d180bSMengyuan Lou /* Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd. */
3377d180bSMengyuan Lou 
4377d180bSMengyuan Lou #include <linux/types.h>
5377d180bSMengyuan Lou #include <linux/module.h>
6377d180bSMengyuan Lou #include <linux/pci.h>
7377d180bSMengyuan Lou #include <linux/netdevice.h>
8377d180bSMengyuan Lou #include <linux/string.h>
9377d180bSMengyuan Lou #include <linux/etherdevice.h>
10377d180bSMengyuan Lou 
11377d180bSMengyuan Lou #include "../libwx/wx_type.h"
124ee8afb4SMengyuan Lou #include "../libwx/wx_hw.h"
13fd0a2e03SMengyuan Lou #include "../libwx/wx_lib.h"
144ee8afb4SMengyuan Lou #include "../libwx/wx_mbx.h"
154ee8afb4SMengyuan Lou #include "../libwx/wx_vf.h"
16377d180bSMengyuan Lou #include "../libwx/wx_vf_common.h"
17377d180bSMengyuan Lou #include "txgbevf_type.h"
18377d180bSMengyuan Lou 
19377d180bSMengyuan Lou /* txgbevf_pci_tbl - PCI Device ID Table
20377d180bSMengyuan Lou  *
21377d180bSMengyuan Lou  * Wildcard entries (PCI_ANY_ID) should come last
22377d180bSMengyuan Lou  * Last entry must be all 0s
23377d180bSMengyuan Lou  *
24377d180bSMengyuan Lou  * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
25377d180bSMengyuan Lou  *   Class, Class Mask, private data (not used) }
26377d180bSMengyuan Lou  */
27377d180bSMengyuan Lou static const struct pci_device_id txgbevf_pci_tbl[] = {
28377d180bSMengyuan Lou 	{ PCI_VDEVICE(WANGXUN, TXGBEVF_DEV_ID_SP1000), 0},
29377d180bSMengyuan Lou 	{ PCI_VDEVICE(WANGXUN, TXGBEVF_DEV_ID_WX1820), 0},
30377d180bSMengyuan Lou 	{ PCI_VDEVICE(WANGXUN, TXGBEVF_DEV_ID_AML500F), 0},
31377d180bSMengyuan Lou 	{ PCI_VDEVICE(WANGXUN, TXGBEVF_DEV_ID_AML510F), 0},
32377d180bSMengyuan Lou 	{ PCI_VDEVICE(WANGXUN, TXGBEVF_DEV_ID_AML5024), 0},
33377d180bSMengyuan Lou 	{ PCI_VDEVICE(WANGXUN, TXGBEVF_DEV_ID_AML5124), 0},
34377d180bSMengyuan Lou 	{ PCI_VDEVICE(WANGXUN, TXGBEVF_DEV_ID_AML503F), 0},
35377d180bSMengyuan Lou 	{ PCI_VDEVICE(WANGXUN, TXGBEVF_DEV_ID_AML513F), 0},
36377d180bSMengyuan Lou 	/* required last entry */
37377d180bSMengyuan Lou 	{ .device = 0 }
38377d180bSMengyuan Lou };
39377d180bSMengyuan Lou 
404ee8afb4SMengyuan Lou static const struct net_device_ops txgbevf_netdev_ops = {
414ee8afb4SMengyuan Lou 	.ndo_open               = wxvf_open,
424ee8afb4SMengyuan Lou 	.ndo_stop               = wxvf_close,
43ce12ba25SMengyuan Lou 	.ndo_start_xmit         = wx_xmit_frame,
444ee8afb4SMengyuan Lou 	.ndo_validate_addr      = eth_validate_addr,
454ee8afb4SMengyuan Lou 	.ndo_set_mac_address    = wx_set_mac_vf,
464ee8afb4SMengyuan Lou };
474ee8afb4SMengyuan Lou 
txgbevf_set_num_queues(struct wx * wx)48fd0a2e03SMengyuan Lou static void txgbevf_set_num_queues(struct wx *wx)
49fd0a2e03SMengyuan Lou {
50fd0a2e03SMengyuan Lou 	u32 def_q = 0, num_tcs = 0;
51fd0a2e03SMengyuan Lou 	u16 rss, queue;
52fd0a2e03SMengyuan Lou 	int ret = 0;
53fd0a2e03SMengyuan Lou 
54fd0a2e03SMengyuan Lou 	/* Start with base case */
55fd0a2e03SMengyuan Lou 	wx->num_rx_queues = 1;
56fd0a2e03SMengyuan Lou 	wx->num_tx_queues = 1;
57fd0a2e03SMengyuan Lou 
58fd0a2e03SMengyuan Lou 	spin_lock_bh(&wx->mbx.mbx_lock);
59fd0a2e03SMengyuan Lou 	/* fetch queue configuration from the PF */
60fd0a2e03SMengyuan Lou 	ret = wx_get_queues_vf(wx, &num_tcs, &def_q);
61fd0a2e03SMengyuan Lou 	spin_unlock_bh(&wx->mbx.mbx_lock);
62fd0a2e03SMengyuan Lou 
63fd0a2e03SMengyuan Lou 	if (ret)
64fd0a2e03SMengyuan Lou 		return;
65fd0a2e03SMengyuan Lou 
66fd0a2e03SMengyuan Lou 	/* we need as many queues as traffic classes */
67fd0a2e03SMengyuan Lou 	if (num_tcs > 1) {
68fd0a2e03SMengyuan Lou 		wx->num_rx_queues = num_tcs;
69fd0a2e03SMengyuan Lou 	} else {
70fd0a2e03SMengyuan Lou 		rss = min_t(u16, num_online_cpus(), TXGBEVF_MAX_RSS_NUM);
71fd0a2e03SMengyuan Lou 		queue = min_t(u16, wx->mac.max_rx_queues, wx->mac.max_tx_queues);
72fd0a2e03SMengyuan Lou 		rss = min_t(u16, queue, rss);
73fd0a2e03SMengyuan Lou 
74fd0a2e03SMengyuan Lou 		if (wx->vfinfo->vf_api >= wx_mbox_api_13) {
75fd0a2e03SMengyuan Lou 			wx->num_rx_queues = rss;
76fd0a2e03SMengyuan Lou 			wx->num_tx_queues = rss;
77fd0a2e03SMengyuan Lou 		}
78fd0a2e03SMengyuan Lou 	}
79fd0a2e03SMengyuan Lou }
80fd0a2e03SMengyuan Lou 
txgbevf_init_type_code(struct wx * wx)814ee8afb4SMengyuan Lou static void txgbevf_init_type_code(struct wx *wx)
824ee8afb4SMengyuan Lou {
834ee8afb4SMengyuan Lou 	switch (wx->device_id) {
844ee8afb4SMengyuan Lou 	case TXGBEVF_DEV_ID_SP1000:
854ee8afb4SMengyuan Lou 	case TXGBEVF_DEV_ID_WX1820:
864ee8afb4SMengyuan Lou 		wx->mac.type = wx_mac_sp;
874ee8afb4SMengyuan Lou 		break;
884ee8afb4SMengyuan Lou 	case TXGBEVF_DEV_ID_AML500F:
894ee8afb4SMengyuan Lou 	case TXGBEVF_DEV_ID_AML510F:
904ee8afb4SMengyuan Lou 	case TXGBEVF_DEV_ID_AML5024:
914ee8afb4SMengyuan Lou 	case TXGBEVF_DEV_ID_AML5124:
924ee8afb4SMengyuan Lou 	case TXGBEVF_DEV_ID_AML503F:
934ee8afb4SMengyuan Lou 	case TXGBEVF_DEV_ID_AML513F:
944ee8afb4SMengyuan Lou 		wx->mac.type = wx_mac_aml;
954ee8afb4SMengyuan Lou 		break;
964ee8afb4SMengyuan Lou 	default:
974ee8afb4SMengyuan Lou 		wx->mac.type = wx_mac_unknown;
984ee8afb4SMengyuan Lou 		break;
994ee8afb4SMengyuan Lou 	}
1004ee8afb4SMengyuan Lou }
1014ee8afb4SMengyuan Lou 
txgbevf_sw_init(struct wx * wx)1024ee8afb4SMengyuan Lou static int txgbevf_sw_init(struct wx *wx)
1034ee8afb4SMengyuan Lou {
1044ee8afb4SMengyuan Lou 	struct net_device *netdev = wx->netdev;
1054ee8afb4SMengyuan Lou 	struct pci_dev *pdev = wx->pdev;
1064ee8afb4SMengyuan Lou 	int err;
1074ee8afb4SMengyuan Lou 
1084ee8afb4SMengyuan Lou 	/* Initialize pcie info and common capability flags */
1094ee8afb4SMengyuan Lou 	err = wx_sw_init(wx);
1104ee8afb4SMengyuan Lou 	if (err < 0)
1114ee8afb4SMengyuan Lou 		goto err_wx_sw_init;
1124ee8afb4SMengyuan Lou 
1134ee8afb4SMengyuan Lou 	/* Initialize the mailbox */
1144ee8afb4SMengyuan Lou 	err = wx_init_mbx_params_vf(wx);
1154ee8afb4SMengyuan Lou 	if (err)
1164ee8afb4SMengyuan Lou 		goto err_init_mbx_params;
1174ee8afb4SMengyuan Lou 
118fd0a2e03SMengyuan Lou 	/* max q_vectors */
119fd0a2e03SMengyuan Lou 	wx->mac.max_msix_vectors = TXGBEVF_MAX_MSIX_VECTORS;
1204ee8afb4SMengyuan Lou 	/* Initialize the device type */
1214ee8afb4SMengyuan Lou 	txgbevf_init_type_code(wx);
1224ee8afb4SMengyuan Lou 	/* lock to protect mailbox accesses */
1234ee8afb4SMengyuan Lou 	spin_lock_init(&wx->mbx.mbx_lock);
1244ee8afb4SMengyuan Lou 
1254ee8afb4SMengyuan Lou 	err = wx_reset_hw_vf(wx);
1264ee8afb4SMengyuan Lou 	if (err) {
1274ee8afb4SMengyuan Lou 		wx_err(wx, "PF still in reset state. Is the PF interface up?\n");
1284ee8afb4SMengyuan Lou 		goto err_reset_hw;
1294ee8afb4SMengyuan Lou 	}
1304ee8afb4SMengyuan Lou 	wx_init_hw_vf(wx);
1314ee8afb4SMengyuan Lou 	wx_negotiate_api_vf(wx);
1324ee8afb4SMengyuan Lou 	if (is_zero_ether_addr(wx->mac.addr))
1334ee8afb4SMengyuan Lou 		dev_info(&pdev->dev,
1344ee8afb4SMengyuan Lou 			 "MAC address not assigned by administrator.\n");
1354ee8afb4SMengyuan Lou 	eth_hw_addr_set(netdev, wx->mac.addr);
1364ee8afb4SMengyuan Lou 
1374ee8afb4SMengyuan Lou 	if (!is_valid_ether_addr(netdev->dev_addr)) {
1384ee8afb4SMengyuan Lou 		dev_info(&pdev->dev, "Assigning random MAC address\n");
1394ee8afb4SMengyuan Lou 		eth_hw_addr_random(netdev);
1404ee8afb4SMengyuan Lou 		ether_addr_copy(wx->mac.addr, netdev->dev_addr);
1414ee8afb4SMengyuan Lou 		ether_addr_copy(wx->mac.perm_addr, netdev->dev_addr);
1424ee8afb4SMengyuan Lou 	}
1434ee8afb4SMengyuan Lou 
1444ee8afb4SMengyuan Lou 	wx->mac.max_tx_queues = TXGBEVF_MAX_TX_QUEUES;
1454ee8afb4SMengyuan Lou 	wx->mac.max_rx_queues = TXGBEVF_MAX_RX_QUEUES;
1464ee8afb4SMengyuan Lou 	/* Enable dynamic interrupt throttling rates */
1474ee8afb4SMengyuan Lou 	wx->rx_itr_setting = 1;
1484ee8afb4SMengyuan Lou 	wx->tx_itr_setting = 1;
1494ee8afb4SMengyuan Lou 	/* set default ring sizes */
1504ee8afb4SMengyuan Lou 	wx->tx_ring_count = TXGBEVF_DEFAULT_TXD;
1514ee8afb4SMengyuan Lou 	wx->rx_ring_count = TXGBEVF_DEFAULT_RXD;
1524ee8afb4SMengyuan Lou 	/* set default work limits */
1534ee8afb4SMengyuan Lou 	wx->tx_work_limit = TXGBEVF_DEFAULT_TX_WORK;
1544ee8afb4SMengyuan Lou 	wx->rx_work_limit = TXGBEVF_DEFAULT_RX_WORK;
1554ee8afb4SMengyuan Lou 
156fd0a2e03SMengyuan Lou 	wx->set_num_queues = txgbevf_set_num_queues;
157fd0a2e03SMengyuan Lou 
1584ee8afb4SMengyuan Lou 	return 0;
1594ee8afb4SMengyuan Lou err_reset_hw:
1604ee8afb4SMengyuan Lou 	kfree(wx->vfinfo);
1614ee8afb4SMengyuan Lou err_init_mbx_params:
1624ee8afb4SMengyuan Lou 	kfree(wx->rss_key);
1634ee8afb4SMengyuan Lou 	kfree(wx->mac_table);
1644ee8afb4SMengyuan Lou err_wx_sw_init:
1654ee8afb4SMengyuan Lou 	return err;
1664ee8afb4SMengyuan Lou }
1674ee8afb4SMengyuan Lou 
168377d180bSMengyuan Lou /**
169377d180bSMengyuan Lou  * txgbevf_probe - Device Initialization Routine
170377d180bSMengyuan Lou  * @pdev: PCI device information struct
171377d180bSMengyuan Lou  * @ent: entry in txgbevf_pci_tbl
172377d180bSMengyuan Lou  *
173377d180bSMengyuan Lou  * Return: return 0 on success, negative on failure
174377d180bSMengyuan Lou  *
175377d180bSMengyuan Lou  * txgbevf_probe initializes an adapter identified by a pci_dev structure.
176377d180bSMengyuan Lou  * The OS initialization, configuring of the adapter private structure,
177377d180bSMengyuan Lou  * and a hardware reset occur.
178377d180bSMengyuan Lou  **/
txgbevf_probe(struct pci_dev * pdev,const struct pci_device_id __always_unused * ent)179377d180bSMengyuan Lou static int txgbevf_probe(struct pci_dev *pdev,
180377d180bSMengyuan Lou 			 const struct pci_device_id __always_unused *ent)
181377d180bSMengyuan Lou {
182377d180bSMengyuan Lou 	struct net_device *netdev;
183377d180bSMengyuan Lou 	struct wx *wx = NULL;
184377d180bSMengyuan Lou 	int err;
185377d180bSMengyuan Lou 
186377d180bSMengyuan Lou 	err = pci_enable_device_mem(pdev);
187377d180bSMengyuan Lou 	if (err)
188377d180bSMengyuan Lou 		return err;
189377d180bSMengyuan Lou 
190377d180bSMengyuan Lou 	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
191377d180bSMengyuan Lou 	if (err) {
192377d180bSMengyuan Lou 		dev_err(&pdev->dev,
193377d180bSMengyuan Lou 			"No usable DMA configuration, aborting\n");
194377d180bSMengyuan Lou 		goto err_pci_disable_dev;
195377d180bSMengyuan Lou 	}
196377d180bSMengyuan Lou 
197377d180bSMengyuan Lou 	err = pci_request_selected_regions(pdev,
198377d180bSMengyuan Lou 					   pci_select_bars(pdev, IORESOURCE_MEM),
199377d180bSMengyuan Lou 					   dev_driver_string(&pdev->dev));
200377d180bSMengyuan Lou 	if (err) {
201377d180bSMengyuan Lou 		dev_err(&pdev->dev,
202377d180bSMengyuan Lou 			"pci_request_selected_regions failed 0x%x\n", err);
203377d180bSMengyuan Lou 		goto err_pci_disable_dev;
204377d180bSMengyuan Lou 	}
205377d180bSMengyuan Lou 
206377d180bSMengyuan Lou 	pci_set_master(pdev);
207377d180bSMengyuan Lou 
208377d180bSMengyuan Lou 	netdev = devm_alloc_etherdev_mqs(&pdev->dev,
209377d180bSMengyuan Lou 					 sizeof(struct wx),
210377d180bSMengyuan Lou 					 TXGBEVF_MAX_TX_QUEUES,
211377d180bSMengyuan Lou 					 TXGBEVF_MAX_RX_QUEUES);
212377d180bSMengyuan Lou 	if (!netdev) {
213377d180bSMengyuan Lou 		err = -ENOMEM;
214377d180bSMengyuan Lou 		goto err_pci_release_regions;
215377d180bSMengyuan Lou 	}
216377d180bSMengyuan Lou 
217377d180bSMengyuan Lou 	SET_NETDEV_DEV(netdev, &pdev->dev);
218377d180bSMengyuan Lou 
219377d180bSMengyuan Lou 	wx = netdev_priv(netdev);
220377d180bSMengyuan Lou 	wx->netdev = netdev;
221377d180bSMengyuan Lou 	wx->pdev = pdev;
222377d180bSMengyuan Lou 
223377d180bSMengyuan Lou 	wx->msg_enable = netif_msg_init(-1, NETIF_MSG_DRV |
224377d180bSMengyuan Lou 					NETIF_MSG_PROBE | NETIF_MSG_LINK);
225377d180bSMengyuan Lou 	wx->hw_addr = devm_ioremap(&pdev->dev,
226377d180bSMengyuan Lou 				   pci_resource_start(pdev, 0),
227377d180bSMengyuan Lou 				   pci_resource_len(pdev, 0));
228377d180bSMengyuan Lou 	if (!wx->hw_addr) {
229377d180bSMengyuan Lou 		err = -EIO;
230377d180bSMengyuan Lou 		goto err_pci_release_regions;
231377d180bSMengyuan Lou 	}
232377d180bSMengyuan Lou 
233377d180bSMengyuan Lou 	wx->b4_addr = devm_ioremap(&pdev->dev,
234377d180bSMengyuan Lou 				   pci_resource_start(pdev, 4),
235377d180bSMengyuan Lou 				   pci_resource_len(pdev, 4));
236377d180bSMengyuan Lou 	if (!wx->b4_addr) {
237377d180bSMengyuan Lou 		err = -EIO;
238377d180bSMengyuan Lou 		goto err_pci_release_regions;
239377d180bSMengyuan Lou 	}
240377d180bSMengyuan Lou 
2414ee8afb4SMengyuan Lou 	netdev->netdev_ops = &txgbevf_netdev_ops;
2424ee8afb4SMengyuan Lou 
2434ee8afb4SMengyuan Lou 	/* setup the private structure */
2444ee8afb4SMengyuan Lou 	err = txgbevf_sw_init(wx);
2454ee8afb4SMengyuan Lou 	if (err)
2464ee8afb4SMengyuan Lou 		goto err_pci_release_regions;
2474ee8afb4SMengyuan Lou 
248377d180bSMengyuan Lou 	netdev->features |= NETIF_F_HIGHDMA;
249377d180bSMengyuan Lou 
2504ee8afb4SMengyuan Lou 	eth_hw_addr_set(netdev, wx->mac.perm_addr);
2514ee8afb4SMengyuan Lou 	ether_addr_copy(netdev->perm_addr, wx->mac.addr);
2524ee8afb4SMengyuan Lou 
253*bf68010aSMengyuan Lou 	wxvf_init_service(wx);
254fd0a2e03SMengyuan Lou 	err = wx_init_interrupt_scheme(wx);
255fd0a2e03SMengyuan Lou 	if (err)
256fd0a2e03SMengyuan Lou 		goto err_free_sw_init;
257fd0a2e03SMengyuan Lou 
2584ee8afb4SMengyuan Lou 	err = register_netdev(netdev);
2594ee8afb4SMengyuan Lou 	if (err)
2604ee8afb4SMengyuan Lou 		goto err_register;
2614ee8afb4SMengyuan Lou 
262377d180bSMengyuan Lou 	pci_set_drvdata(pdev, wx);
263ce12ba25SMengyuan Lou 	netif_tx_stop_all_queues(netdev);
264377d180bSMengyuan Lou 
265377d180bSMengyuan Lou 	return 0;
266377d180bSMengyuan Lou 
2674ee8afb4SMengyuan Lou err_register:
268fd0a2e03SMengyuan Lou 	wx_clear_interrupt_scheme(wx);
269fd0a2e03SMengyuan Lou err_free_sw_init:
270*bf68010aSMengyuan Lou 	timer_delete_sync(&wx->service_timer);
271*bf68010aSMengyuan Lou 	cancel_work_sync(&wx->service_task);
2724ee8afb4SMengyuan Lou 	kfree(wx->vfinfo);
2734ee8afb4SMengyuan Lou 	kfree(wx->rss_key);
2744ee8afb4SMengyuan Lou 	kfree(wx->mac_table);
275377d180bSMengyuan Lou err_pci_release_regions:
276377d180bSMengyuan Lou 	pci_release_selected_regions(pdev,
277377d180bSMengyuan Lou 				     pci_select_bars(pdev, IORESOURCE_MEM));
278377d180bSMengyuan Lou err_pci_disable_dev:
279377d180bSMengyuan Lou 	pci_disable_device(pdev);
280377d180bSMengyuan Lou 	return err;
281377d180bSMengyuan Lou }
282377d180bSMengyuan Lou 
283377d180bSMengyuan Lou /**
284377d180bSMengyuan Lou  * txgbevf_remove - Device Removal Routine
285377d180bSMengyuan Lou  * @pdev: PCI device information struct
286377d180bSMengyuan Lou  *
287377d180bSMengyuan Lou  * txgbevf_remove is called by the PCI subsystem to alert the driver
288377d180bSMengyuan Lou  * that it should release a PCI device.  The could be caused by a
289377d180bSMengyuan Lou  * Hot-Plug event, or because the driver is going to be removed from
290377d180bSMengyuan Lou  * memory.
291377d180bSMengyuan Lou  **/
txgbevf_remove(struct pci_dev * pdev)292377d180bSMengyuan Lou static void txgbevf_remove(struct pci_dev *pdev)
293377d180bSMengyuan Lou {
294377d180bSMengyuan Lou 	wxvf_remove(pdev);
295377d180bSMengyuan Lou }
296377d180bSMengyuan Lou 
297377d180bSMengyuan Lou static DEFINE_SIMPLE_DEV_PM_OPS(txgbevf_pm_ops, wxvf_suspend, wxvf_resume);
298377d180bSMengyuan Lou 
299377d180bSMengyuan Lou static struct pci_driver txgbevf_driver = {
300377d180bSMengyuan Lou 	.name     = KBUILD_MODNAME,
301377d180bSMengyuan Lou 	.id_table = txgbevf_pci_tbl,
302377d180bSMengyuan Lou 	.probe    = txgbevf_probe,
303377d180bSMengyuan Lou 	.remove   = txgbevf_remove,
304377d180bSMengyuan Lou 	.shutdown = wxvf_shutdown,
305377d180bSMengyuan Lou 	/* Power Management Hooks */
306377d180bSMengyuan Lou 	.driver.pm	= pm_sleep_ptr(&txgbevf_pm_ops)
307377d180bSMengyuan Lou };
308377d180bSMengyuan Lou 
309377d180bSMengyuan Lou module_pci_driver(txgbevf_driver);
310377d180bSMengyuan Lou 
311377d180bSMengyuan Lou MODULE_DEVICE_TABLE(pci, txgbevf_pci_tbl);
312377d180bSMengyuan Lou MODULE_AUTHOR("Beijing WangXun Technology Co., Ltd, <software@trustnetic.com>");
313377d180bSMengyuan Lou MODULE_DESCRIPTION("WangXun(R) 10/25/40 Gigabit Virtual Function Network Driver");
314377d180bSMengyuan Lou MODULE_LICENSE("GPL");
315