1df69ba43SShannon Nelson // SPDX-License-Identifier: GPL-2.0
2df69ba43SShannon Nelson /* Copyright(c) 2017 - 2019 Pensando Systems, Inc */
3df69ba43SShannon Nelson 
4df69ba43SShannon Nelson #include <linux/module.h>
5df69ba43SShannon Nelson #include <linux/netdevice.h>
6df69ba43SShannon Nelson #include <linux/etherdevice.h>
7df69ba43SShannon Nelson #include <linux/pci.h>
8df69ba43SShannon Nelson 
9df69ba43SShannon Nelson #include "ionic.h"
10df69ba43SShannon Nelson #include "ionic_bus.h"
11fbfb8031SShannon Nelson #include "ionic_debugfs.h"
12df69ba43SShannon Nelson 
13df69ba43SShannon Nelson /* Supported devices */
14df69ba43SShannon Nelson static const struct pci_device_id ionic_id_table[] = {
15df69ba43SShannon Nelson 	{ PCI_VDEVICE(PENSANDO, PCI_DEVICE_ID_PENSANDO_IONIC_ETH_PF) },
16df69ba43SShannon Nelson 	{ PCI_VDEVICE(PENSANDO, PCI_DEVICE_ID_PENSANDO_IONIC_ETH_VF) },
17df69ba43SShannon Nelson 	{ 0, }	/* end of table */
18df69ba43SShannon Nelson };
19df69ba43SShannon Nelson MODULE_DEVICE_TABLE(pci, ionic_id_table);
20df69ba43SShannon Nelson 
21fbfb8031SShannon Nelson const char *ionic_bus_info(struct ionic *ionic)
22fbfb8031SShannon Nelson {
23fbfb8031SShannon Nelson 	return pci_name(ionic->pdev);
24fbfb8031SShannon Nelson }
25fbfb8031SShannon Nelson 
26fbfb8031SShannon Nelson static int ionic_map_bars(struct ionic *ionic)
27fbfb8031SShannon Nelson {
28fbfb8031SShannon Nelson 	struct pci_dev *pdev = ionic->pdev;
29fbfb8031SShannon Nelson 	struct device *dev = ionic->dev;
30fbfb8031SShannon Nelson 	struct ionic_dev_bar *bars;
31fbfb8031SShannon Nelson 	unsigned int i, j;
32fbfb8031SShannon Nelson 
33fbfb8031SShannon Nelson 	bars = ionic->bars;
34fbfb8031SShannon Nelson 	ionic->num_bars = 0;
35fbfb8031SShannon Nelson 
36fbfb8031SShannon Nelson 	for (i = 0, j = 0; i < IONIC_BARS_MAX; i++) {
37fbfb8031SShannon Nelson 		if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM))
38fbfb8031SShannon Nelson 			continue;
39fbfb8031SShannon Nelson 		bars[j].len = pci_resource_len(pdev, i);
40fbfb8031SShannon Nelson 
41fbfb8031SShannon Nelson 		/* only map the whole bar 0 */
42fbfb8031SShannon Nelson 		if (j > 0) {
43fbfb8031SShannon Nelson 			bars[j].vaddr = NULL;
44fbfb8031SShannon Nelson 		} else {
45fbfb8031SShannon Nelson 			bars[j].vaddr = pci_iomap(pdev, i, bars[j].len);
46fbfb8031SShannon Nelson 			if (!bars[j].vaddr) {
47fbfb8031SShannon Nelson 				dev_err(dev,
48fbfb8031SShannon Nelson 					"Cannot memory-map BAR %d, aborting\n",
49fbfb8031SShannon Nelson 					i);
50fbfb8031SShannon Nelson 				return -ENODEV;
51fbfb8031SShannon Nelson 			}
52fbfb8031SShannon Nelson 		}
53fbfb8031SShannon Nelson 
54fbfb8031SShannon Nelson 		bars[j].bus_addr = pci_resource_start(pdev, i);
55fbfb8031SShannon Nelson 		bars[j].res_index = i;
56fbfb8031SShannon Nelson 		ionic->num_bars++;
57fbfb8031SShannon Nelson 		j++;
58fbfb8031SShannon Nelson 	}
59fbfb8031SShannon Nelson 
60fbfb8031SShannon Nelson 	return 0;
61fbfb8031SShannon Nelson }
62fbfb8031SShannon Nelson 
63fbfb8031SShannon Nelson static void ionic_unmap_bars(struct ionic *ionic)
64fbfb8031SShannon Nelson {
65fbfb8031SShannon Nelson 	struct ionic_dev_bar *bars = ionic->bars;
66fbfb8031SShannon Nelson 	unsigned int i;
67fbfb8031SShannon Nelson 
68fbfb8031SShannon Nelson 	for (i = 0; i < IONIC_BARS_MAX; i++) {
69fbfb8031SShannon Nelson 		if (bars[i].vaddr) {
70fbfb8031SShannon Nelson 			iounmap(bars[i].vaddr);
71fbfb8031SShannon Nelson 			bars[i].bus_addr = 0;
72fbfb8031SShannon Nelson 			bars[i].vaddr = NULL;
73fbfb8031SShannon Nelson 			bars[i].len = 0;
74fbfb8031SShannon Nelson 		}
75fbfb8031SShannon Nelson 	}
76fbfb8031SShannon Nelson }
77fbfb8031SShannon Nelson 
78df69ba43SShannon Nelson static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
79df69ba43SShannon Nelson {
80df69ba43SShannon Nelson 	struct device *dev = &pdev->dev;
81df69ba43SShannon Nelson 	struct ionic *ionic;
82fbfb8031SShannon Nelson 	int err;
83df69ba43SShannon Nelson 
84df69ba43SShannon Nelson 	ionic = ionic_devlink_alloc(dev);
85df69ba43SShannon Nelson 	if (!ionic)
86df69ba43SShannon Nelson 		return -ENOMEM;
87df69ba43SShannon Nelson 
88df69ba43SShannon Nelson 	ionic->pdev = pdev;
89df69ba43SShannon Nelson 	ionic->dev = dev;
90df69ba43SShannon Nelson 	pci_set_drvdata(pdev, ionic);
91fbfb8031SShannon Nelson 	mutex_init(&ionic->dev_cmd_lock);
92fbfb8031SShannon Nelson 
93fbfb8031SShannon Nelson 	/* Query system for DMA addressing limitation for the device. */
94fbfb8031SShannon Nelson 	err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(IONIC_ADDR_LEN));
95fbfb8031SShannon Nelson 	if (err) {
96fbfb8031SShannon Nelson 		dev_err(dev, "Unable to obtain 64-bit DMA for consistent allocations, aborting.  err=%d\n",
97fbfb8031SShannon Nelson 			err);
98fbfb8031SShannon Nelson 		goto err_out_clear_drvdata;
99fbfb8031SShannon Nelson 	}
100fbfb8031SShannon Nelson 
101fbfb8031SShannon Nelson 	ionic_debugfs_add_dev(ionic);
102fbfb8031SShannon Nelson 
103fbfb8031SShannon Nelson 	/* Setup PCI device */
104fbfb8031SShannon Nelson 	err = pci_enable_device_mem(pdev);
105fbfb8031SShannon Nelson 	if (err) {
106fbfb8031SShannon Nelson 		dev_err(dev, "Cannot enable PCI device: %d, aborting\n", err);
107fbfb8031SShannon Nelson 		goto err_out_debugfs_del_dev;
108fbfb8031SShannon Nelson 	}
109fbfb8031SShannon Nelson 
110fbfb8031SShannon Nelson 	err = pci_request_regions(pdev, IONIC_DRV_NAME);
111fbfb8031SShannon Nelson 	if (err) {
112fbfb8031SShannon Nelson 		dev_err(dev, "Cannot request PCI regions: %d, aborting\n", err);
113fbfb8031SShannon Nelson 		goto err_out_pci_disable_device;
114fbfb8031SShannon Nelson 	}
115fbfb8031SShannon Nelson 
116fbfb8031SShannon Nelson 	pci_set_master(pdev);
117fbfb8031SShannon Nelson 
118fbfb8031SShannon Nelson 	err = ionic_map_bars(ionic);
119fbfb8031SShannon Nelson 	if (err)
120fbfb8031SShannon Nelson 		goto err_out_pci_clear_master;
121fbfb8031SShannon Nelson 
122fbfb8031SShannon Nelson 	/* Configure the device */
123fbfb8031SShannon Nelson 	err = ionic_setup(ionic);
124fbfb8031SShannon Nelson 	if (err) {
125fbfb8031SShannon Nelson 		dev_err(dev, "Cannot setup device: %d, aborting\n", err);
126fbfb8031SShannon Nelson 		goto err_out_unmap_bars;
127fbfb8031SShannon Nelson 	}
128fbfb8031SShannon Nelson 
129fbfb8031SShannon Nelson 	err = ionic_identify(ionic);
130fbfb8031SShannon Nelson 	if (err) {
131fbfb8031SShannon Nelson 		dev_err(dev, "Cannot identify device: %d, aborting\n", err);
132fbfb8031SShannon Nelson 		goto err_out_teardown;
133fbfb8031SShannon Nelson 	}
134fbfb8031SShannon Nelson 
135fbfb8031SShannon Nelson 	err = ionic_init(ionic);
136fbfb8031SShannon Nelson 	if (err) {
137fbfb8031SShannon Nelson 		dev_err(dev, "Cannot init device: %d, aborting\n", err);
138fbfb8031SShannon Nelson 		goto err_out_teardown;
139fbfb8031SShannon Nelson 	}
140fbfb8031SShannon Nelson 
14104436595SShannon Nelson 	/* Configure the ports */
14204436595SShannon Nelson 	err = ionic_port_identify(ionic);
14304436595SShannon Nelson 	if (err) {
14404436595SShannon Nelson 		dev_err(dev, "Cannot identify port: %d, aborting\n", err);
14504436595SShannon Nelson 		goto err_out_reset;
14604436595SShannon Nelson 	}
14704436595SShannon Nelson 
14804436595SShannon Nelson 	err = ionic_port_init(ionic);
14904436595SShannon Nelson 	if (err) {
15004436595SShannon Nelson 		dev_err(dev, "Cannot init port: %d, aborting\n", err);
15104436595SShannon Nelson 		goto err_out_reset;
15204436595SShannon Nelson 	}
15304436595SShannon Nelson 
154fbfb8031SShannon Nelson 	err = ionic_devlink_register(ionic);
155fbfb8031SShannon Nelson 	if (err)
156fbfb8031SShannon Nelson 		dev_err(dev, "Cannot register devlink: %d\n", err);
157df69ba43SShannon Nelson 
158df69ba43SShannon Nelson 	return 0;
159fbfb8031SShannon Nelson 
16004436595SShannon Nelson err_out_reset:
16104436595SShannon Nelson 	ionic_reset(ionic);
162fbfb8031SShannon Nelson err_out_teardown:
163fbfb8031SShannon Nelson 	ionic_dev_teardown(ionic);
164fbfb8031SShannon Nelson err_out_unmap_bars:
165fbfb8031SShannon Nelson 	ionic_unmap_bars(ionic);
166fbfb8031SShannon Nelson 	pci_release_regions(pdev);
167fbfb8031SShannon Nelson err_out_pci_clear_master:
168fbfb8031SShannon Nelson 	pci_clear_master(pdev);
169fbfb8031SShannon Nelson err_out_pci_disable_device:
170fbfb8031SShannon Nelson 	pci_disable_device(pdev);
171fbfb8031SShannon Nelson err_out_debugfs_del_dev:
172fbfb8031SShannon Nelson 	ionic_debugfs_del_dev(ionic);
173fbfb8031SShannon Nelson err_out_clear_drvdata:
174fbfb8031SShannon Nelson 	mutex_destroy(&ionic->dev_cmd_lock);
175fbfb8031SShannon Nelson 	ionic_devlink_free(ionic);
176fbfb8031SShannon Nelson 
177fbfb8031SShannon Nelson 	return err;
178df69ba43SShannon Nelson }
179df69ba43SShannon Nelson 
180df69ba43SShannon Nelson static void ionic_remove(struct pci_dev *pdev)
181df69ba43SShannon Nelson {
182df69ba43SShannon Nelson 	struct ionic *ionic = pci_get_drvdata(pdev);
183df69ba43SShannon Nelson 
184fbfb8031SShannon Nelson 	if (!ionic)
185fbfb8031SShannon Nelson 		return;
186fbfb8031SShannon Nelson 
187fbfb8031SShannon Nelson 	ionic_devlink_unregister(ionic);
18804436595SShannon Nelson 	ionic_port_reset(ionic);
189fbfb8031SShannon Nelson 	ionic_reset(ionic);
190fbfb8031SShannon Nelson 	ionic_dev_teardown(ionic);
191fbfb8031SShannon Nelson 	ionic_unmap_bars(ionic);
192fbfb8031SShannon Nelson 	pci_release_regions(pdev);
193fbfb8031SShannon Nelson 	pci_clear_master(pdev);
194fbfb8031SShannon Nelson 	pci_disable_device(pdev);
195fbfb8031SShannon Nelson 	ionic_debugfs_del_dev(ionic);
196fbfb8031SShannon Nelson 	mutex_destroy(&ionic->dev_cmd_lock);
197df69ba43SShannon Nelson 	ionic_devlink_free(ionic);
198df69ba43SShannon Nelson }
199df69ba43SShannon Nelson 
200df69ba43SShannon Nelson static struct pci_driver ionic_driver = {
201df69ba43SShannon Nelson 	.name = IONIC_DRV_NAME,
202df69ba43SShannon Nelson 	.id_table = ionic_id_table,
203df69ba43SShannon Nelson 	.probe = ionic_probe,
204df69ba43SShannon Nelson 	.remove = ionic_remove,
205df69ba43SShannon Nelson };
206df69ba43SShannon Nelson 
207df69ba43SShannon Nelson int ionic_bus_register_driver(void)
208df69ba43SShannon Nelson {
209df69ba43SShannon Nelson 	return pci_register_driver(&ionic_driver);
210df69ba43SShannon Nelson }
211df69ba43SShannon Nelson 
212df69ba43SShannon Nelson void ionic_bus_unregister_driver(void)
213df69ba43SShannon Nelson {
214df69ba43SShannon Nelson 	pci_unregister_driver(&ionic_driver);
215df69ba43SShannon Nelson }
216