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"
111a58e196SShannon Nelson #include "ionic_lif.h"
12fbfb8031SShannon Nelson #include "ionic_debugfs.h"
13df69ba43SShannon Nelson
14df69ba43SShannon Nelson /* Supported devices */
15df69ba43SShannon Nelson static const struct pci_device_id ionic_id_table[] = {
16df69ba43SShannon Nelson { PCI_VDEVICE(PENSANDO, PCI_DEVICE_ID_PENSANDO_IONIC_ETH_PF) },
17df69ba43SShannon Nelson { PCI_VDEVICE(PENSANDO, PCI_DEVICE_ID_PENSANDO_IONIC_ETH_VF) },
18df69ba43SShannon Nelson { 0, } /* end of table */
19df69ba43SShannon Nelson };
20df69ba43SShannon Nelson MODULE_DEVICE_TABLE(pci, ionic_id_table);
21df69ba43SShannon Nelson
ionic_bus_get_irq(struct ionic * ionic,unsigned int num)221d062b7bSShannon Nelson int ionic_bus_get_irq(struct ionic *ionic, unsigned int num)
231d062b7bSShannon Nelson {
241d062b7bSShannon Nelson return pci_irq_vector(ionic->pdev, num);
251d062b7bSShannon Nelson }
261d062b7bSShannon Nelson
ionic_bus_info(struct ionic * ionic)27fbfb8031SShannon Nelson const char *ionic_bus_info(struct ionic *ionic)
28fbfb8031SShannon Nelson {
29fbfb8031SShannon Nelson return pci_name(ionic->pdev);
30fbfb8031SShannon Nelson }
31fbfb8031SShannon Nelson
ionic_bus_alloc_irq_vectors(struct ionic * ionic,unsigned int nintrs)321a58e196SShannon Nelson int ionic_bus_alloc_irq_vectors(struct ionic *ionic, unsigned int nintrs)
331a58e196SShannon Nelson {
341a58e196SShannon Nelson return pci_alloc_irq_vectors(ionic->pdev, nintrs, nintrs,
351a58e196SShannon Nelson PCI_IRQ_MSIX);
361a58e196SShannon Nelson }
371a58e196SShannon Nelson
ionic_bus_free_irq_vectors(struct ionic * ionic)381a58e196SShannon Nelson void ionic_bus_free_irq_vectors(struct ionic *ionic)
391a58e196SShannon Nelson {
4030a1e6d0SShannon Nelson if (!ionic->nintrs)
4130a1e6d0SShannon Nelson return;
4230a1e6d0SShannon Nelson
431a58e196SShannon Nelson pci_free_irq_vectors(ionic->pdev);
441a58e196SShannon Nelson }
451a58e196SShannon Nelson
ionic_map_bars(struct ionic * ionic)46fbfb8031SShannon Nelson static int ionic_map_bars(struct ionic *ionic)
47fbfb8031SShannon Nelson {
48fbfb8031SShannon Nelson struct pci_dev *pdev = ionic->pdev;
49fbfb8031SShannon Nelson struct device *dev = ionic->dev;
50fbfb8031SShannon Nelson struct ionic_dev_bar *bars;
51fbfb8031SShannon Nelson unsigned int i, j;
52fbfb8031SShannon Nelson
53fbfb8031SShannon Nelson bars = ionic->bars;
54fbfb8031SShannon Nelson ionic->num_bars = 0;
55fbfb8031SShannon Nelson
56fbfb8031SShannon Nelson for (i = 0, j = 0; i < IONIC_BARS_MAX; i++) {
57fbfb8031SShannon Nelson if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM))
58fbfb8031SShannon Nelson continue;
59fbfb8031SShannon Nelson bars[j].len = pci_resource_len(pdev, i);
60fbfb8031SShannon Nelson
61fbfb8031SShannon Nelson /* only map the whole bar 0 */
62fbfb8031SShannon Nelson if (j > 0) {
63fbfb8031SShannon Nelson bars[j].vaddr = NULL;
64fbfb8031SShannon Nelson } else {
65fbfb8031SShannon Nelson bars[j].vaddr = pci_iomap(pdev, i, bars[j].len);
66fbfb8031SShannon Nelson if (!bars[j].vaddr) {
67fbfb8031SShannon Nelson dev_err(dev,
68fbfb8031SShannon Nelson "Cannot memory-map BAR %d, aborting\n",
69fbfb8031SShannon Nelson i);
70fbfb8031SShannon Nelson return -ENODEV;
71fbfb8031SShannon Nelson }
72fbfb8031SShannon Nelson }
73fbfb8031SShannon Nelson
74fbfb8031SShannon Nelson bars[j].bus_addr = pci_resource_start(pdev, i);
75fbfb8031SShannon Nelson bars[j].res_index = i;
76fbfb8031SShannon Nelson ionic->num_bars++;
77fbfb8031SShannon Nelson j++;
78fbfb8031SShannon Nelson }
79fbfb8031SShannon Nelson
80fbfb8031SShannon Nelson return 0;
81fbfb8031SShannon Nelson }
82fbfb8031SShannon Nelson
ionic_unmap_bars(struct ionic * ionic)83fbfb8031SShannon Nelson static void ionic_unmap_bars(struct ionic *ionic)
84fbfb8031SShannon Nelson {
85fbfb8031SShannon Nelson struct ionic_dev_bar *bars = ionic->bars;
86fbfb8031SShannon Nelson unsigned int i;
87fbfb8031SShannon Nelson
88fbfb8031SShannon Nelson for (i = 0; i < IONIC_BARS_MAX; i++) {
89fbfb8031SShannon Nelson if (bars[i].vaddr) {
90fbfb8031SShannon Nelson iounmap(bars[i].vaddr);
91fbfb8031SShannon Nelson bars[i].bus_addr = 0;
92fbfb8031SShannon Nelson bars[i].vaddr = NULL;
93fbfb8031SShannon Nelson bars[i].len = 0;
94fbfb8031SShannon Nelson }
95fbfb8031SShannon Nelson }
96fbfb8031SShannon Nelson }
97fbfb8031SShannon Nelson
ionic_bus_map_dbpage(struct ionic * ionic,int page_num)986461b446SShannon Nelson void __iomem *ionic_bus_map_dbpage(struct ionic *ionic, int page_num)
996461b446SShannon Nelson {
1006461b446SShannon Nelson return pci_iomap_range(ionic->pdev,
1016461b446SShannon Nelson ionic->bars[IONIC_PCI_BAR_DBELL].res_index,
1026461b446SShannon Nelson (u64)page_num << PAGE_SHIFT, PAGE_SIZE);
1036461b446SShannon Nelson }
1046461b446SShannon Nelson
ionic_bus_unmap_dbpage(struct ionic * ionic,void __iomem * page)1056461b446SShannon Nelson void ionic_bus_unmap_dbpage(struct ionic *ionic, void __iomem *page)
1066461b446SShannon Nelson {
1076461b446SShannon Nelson iounmap(page);
1086461b446SShannon Nelson }
1096461b446SShannon Nelson
ionic_vf_dealloc_locked(struct ionic * ionic)110fbb39807SShannon Nelson static void ionic_vf_dealloc_locked(struct ionic *ionic)
111fbb39807SShannon Nelson {
11236197d82SShannon Nelson struct ionic_vf_setattr_cmd vfc = { .attr = IONIC_VF_ATTR_STATSADDR };
113fbb39807SShannon Nelson struct ionic_vf *v;
114fbb39807SShannon Nelson int i;
115fbb39807SShannon Nelson
116fbb39807SShannon Nelson if (!ionic->vfs)
117fbb39807SShannon Nelson return;
118fbb39807SShannon Nelson
119fbb39807SShannon Nelson for (i = ionic->num_vfs - 1; i >= 0; i--) {
120fbb39807SShannon Nelson v = &ionic->vfs[i];
121fbb39807SShannon Nelson
122fbb39807SShannon Nelson if (v->stats_pa) {
12336197d82SShannon Nelson vfc.stats_pa = 0;
124896de449SShannon Nelson ionic_set_vf_config(ionic, i, &vfc);
125fbb39807SShannon Nelson dma_unmap_single(ionic->dev, v->stats_pa,
126fbb39807SShannon Nelson sizeof(v->stats), DMA_FROM_DEVICE);
127fbb39807SShannon Nelson v->stats_pa = 0;
128fbb39807SShannon Nelson }
129fbb39807SShannon Nelson }
130fbb39807SShannon Nelson
131fbb39807SShannon Nelson kfree(ionic->vfs);
132fbb39807SShannon Nelson ionic->vfs = NULL;
133fbb39807SShannon Nelson ionic->num_vfs = 0;
134fbb39807SShannon Nelson }
135fbb39807SShannon Nelson
ionic_vf_dealloc(struct ionic * ionic)136fbb39807SShannon Nelson static void ionic_vf_dealloc(struct ionic *ionic)
137fbb39807SShannon Nelson {
138fbb39807SShannon Nelson down_write(&ionic->vf_op_lock);
139fbb39807SShannon Nelson ionic_vf_dealloc_locked(ionic);
140fbb39807SShannon Nelson up_write(&ionic->vf_op_lock);
141fbb39807SShannon Nelson }
142fbb39807SShannon Nelson
ionic_vf_alloc(struct ionic * ionic,int num_vfs)143fbb39807SShannon Nelson static int ionic_vf_alloc(struct ionic *ionic, int num_vfs)
144fbb39807SShannon Nelson {
14536197d82SShannon Nelson struct ionic_vf_setattr_cmd vfc = { .attr = IONIC_VF_ATTR_STATSADDR };
146fbb39807SShannon Nelson struct ionic_vf *v;
147fbb39807SShannon Nelson int err = 0;
148fbb39807SShannon Nelson int i;
149fbb39807SShannon Nelson
150fbb39807SShannon Nelson down_write(&ionic->vf_op_lock);
151fbb39807SShannon Nelson
152fbb39807SShannon Nelson ionic->vfs = kcalloc(num_vfs, sizeof(struct ionic_vf), GFP_KERNEL);
153fbb39807SShannon Nelson if (!ionic->vfs) {
154fbb39807SShannon Nelson err = -ENOMEM;
155fbb39807SShannon Nelson goto out;
156fbb39807SShannon Nelson }
157fbb39807SShannon Nelson
158fbb39807SShannon Nelson for (i = 0; i < num_vfs; i++) {
159fbb39807SShannon Nelson v = &ionic->vfs[i];
160fbb39807SShannon Nelson v->stats_pa = dma_map_single(ionic->dev, &v->stats,
161fbb39807SShannon Nelson sizeof(v->stats), DMA_FROM_DEVICE);
162fbb39807SShannon Nelson if (dma_mapping_error(ionic->dev, v->stats_pa)) {
163fbb39807SShannon Nelson v->stats_pa = 0;
164fbb39807SShannon Nelson err = -ENODEV;
165fbb39807SShannon Nelson goto out;
166fbb39807SShannon Nelson }
167fbb39807SShannon Nelson
16873618201SShannon Nelson ionic->num_vfs++;
16936197d82SShannon Nelson
170fbb39807SShannon Nelson /* ignore failures from older FW, we just won't get stats */
17136197d82SShannon Nelson vfc.stats_pa = cpu_to_le64(v->stats_pa);
172896de449SShannon Nelson ionic_set_vf_config(ionic, i, &vfc);
173fbb39807SShannon Nelson }
174fbb39807SShannon Nelson
175fbb39807SShannon Nelson out:
176fbb39807SShannon Nelson if (err)
177fbb39807SShannon Nelson ionic_vf_dealloc_locked(ionic);
178fbb39807SShannon Nelson up_write(&ionic->vf_op_lock);
179fbb39807SShannon Nelson return err;
180fbb39807SShannon Nelson }
181fbb39807SShannon Nelson
ionic_sriov_configure(struct pci_dev * pdev,int num_vfs)182fbb39807SShannon Nelson static int ionic_sriov_configure(struct pci_dev *pdev, int num_vfs)
183fbb39807SShannon Nelson {
184fbb39807SShannon Nelson struct ionic *ionic = pci_get_drvdata(pdev);
185fbb39807SShannon Nelson struct device *dev = ionic->dev;
186fbb39807SShannon Nelson int ret = 0;
187fbb39807SShannon Nelson
1888c775344SShannon Nelson if (ionic->lif &&
1898c775344SShannon Nelson test_bit(IONIC_LIF_F_FW_RESET, ionic->lif->state))
1908c775344SShannon Nelson return -EBUSY;
1918c775344SShannon Nelson
192fbb39807SShannon Nelson if (num_vfs > 0) {
193fbb39807SShannon Nelson ret = pci_enable_sriov(pdev, num_vfs);
194fbb39807SShannon Nelson if (ret) {
195fbb39807SShannon Nelson dev_err(dev, "Cannot enable SRIOV: %d\n", ret);
196fbb39807SShannon Nelson goto out;
197fbb39807SShannon Nelson }
198fbb39807SShannon Nelson
199fbb39807SShannon Nelson ret = ionic_vf_alloc(ionic, num_vfs);
200fbb39807SShannon Nelson if (ret) {
201fbb39807SShannon Nelson dev_err(dev, "Cannot alloc VFs: %d\n", ret);
202fbb39807SShannon Nelson pci_disable_sriov(pdev);
203fbb39807SShannon Nelson goto out;
204fbb39807SShannon Nelson }
205fbb39807SShannon Nelson
206fbb39807SShannon Nelson ret = num_vfs;
207fbb39807SShannon Nelson } else {
208fbb39807SShannon Nelson pci_disable_sriov(pdev);
209fbb39807SShannon Nelson ionic_vf_dealloc(ionic);
210fbb39807SShannon Nelson }
211fbb39807SShannon Nelson
212fbb39807SShannon Nelson out:
213fbb39807SShannon Nelson return ret;
214fbb39807SShannon Nelson }
215fbb39807SShannon Nelson
ionic_clear_pci(struct ionic * ionic)21687d7a9f3SShannon Nelson static void ionic_clear_pci(struct ionic *ionic)
21787d7a9f3SShannon Nelson {
2189324cbc4SShannon Nelson ionic->idev.dev_info_regs = NULL;
2199324cbc4SShannon Nelson ionic->idev.dev_cmd_regs = NULL;
2209324cbc4SShannon Nelson ionic->idev.intr_status = NULL;
2219324cbc4SShannon Nelson ionic->idev.intr_ctrl = NULL;
2229324cbc4SShannon Nelson
22387d7a9f3SShannon Nelson ionic_unmap_bars(ionic);
22487d7a9f3SShannon Nelson pci_release_regions(ionic->pdev);
225b41d5ce6SShannon Nelson
2261ae3ff27SShannon Nelson if (pci_is_enabled(ionic->pdev))
22787d7a9f3SShannon Nelson pci_disable_device(ionic->pdev);
22887d7a9f3SShannon Nelson }
22987d7a9f3SShannon Nelson
ionic_setup_one(struct ionic * ionic)2300de38d9fSShannon Nelson static int ionic_setup_one(struct ionic *ionic)
231df69ba43SShannon Nelson {
2320de38d9fSShannon Nelson struct pci_dev *pdev = ionic->pdev;
2330de38d9fSShannon Nelson struct device *dev = ionic->dev;
234fbfb8031SShannon Nelson int err;
235df69ba43SShannon Nelson
236fbfb8031SShannon Nelson ionic_debugfs_add_dev(ionic);
237fbfb8031SShannon Nelson
238fbfb8031SShannon Nelson /* Setup PCI device */
239fbfb8031SShannon Nelson err = pci_enable_device_mem(pdev);
240fbfb8031SShannon Nelson if (err) {
241fbfb8031SShannon Nelson dev_err(dev, "Cannot enable PCI device: %d, aborting\n", err);
242fbfb8031SShannon Nelson goto err_out_debugfs_del_dev;
243fbfb8031SShannon Nelson }
244fbfb8031SShannon Nelson
245fbfb8031SShannon Nelson err = pci_request_regions(pdev, IONIC_DRV_NAME);
246fbfb8031SShannon Nelson if (err) {
247fbfb8031SShannon Nelson dev_err(dev, "Cannot request PCI regions: %d, aborting\n", err);
24887d7a9f3SShannon Nelson goto err_out_clear_pci;
249fbfb8031SShannon Nelson }
250c25cba36SShannon Nelson pcie_print_link_status(pdev);
251fbfb8031SShannon Nelson
252fbfb8031SShannon Nelson err = ionic_map_bars(ionic);
253fbfb8031SShannon Nelson if (err)
25487d7a9f3SShannon Nelson goto err_out_clear_pci;
255fbfb8031SShannon Nelson
256fbfb8031SShannon Nelson /* Configure the device */
257fbfb8031SShannon Nelson err = ionic_setup(ionic);
258fbfb8031SShannon Nelson if (err) {
259fbfb8031SShannon Nelson dev_err(dev, "Cannot setup device: %d, aborting\n", err);
26087d7a9f3SShannon Nelson goto err_out_clear_pci;
261fbfb8031SShannon Nelson }
2626a6014e2SShannon Nelson pci_set_master(pdev);
263fbfb8031SShannon Nelson
264fbfb8031SShannon Nelson err = ionic_identify(ionic);
265fbfb8031SShannon Nelson if (err) {
266fbfb8031SShannon Nelson dev_err(dev, "Cannot identify device: %d, aborting\n", err);
267fbfb8031SShannon Nelson goto err_out_teardown;
268fbfb8031SShannon Nelson }
269a21b5d49SShannon Nelson ionic_debugfs_add_ident(ionic);
270fbfb8031SShannon Nelson
271fbfb8031SShannon Nelson err = ionic_init(ionic);
272fbfb8031SShannon Nelson if (err) {
273fbfb8031SShannon Nelson dev_err(dev, "Cannot init device: %d, aborting\n", err);
274fbfb8031SShannon Nelson goto err_out_teardown;
275fbfb8031SShannon Nelson }
276fbfb8031SShannon Nelson
2770de38d9fSShannon Nelson /* Configure the port */
27804436595SShannon Nelson err = ionic_port_identify(ionic);
27904436595SShannon Nelson if (err) {
28004436595SShannon Nelson dev_err(dev, "Cannot identify port: %d, aborting\n", err);
2810de38d9fSShannon Nelson goto err_out_teardown;
28204436595SShannon Nelson }
28304436595SShannon Nelson
28404436595SShannon Nelson err = ionic_port_init(ionic);
28504436595SShannon Nelson if (err) {
28604436595SShannon Nelson dev_err(dev, "Cannot init port: %d, aborting\n", err);
2870de38d9fSShannon Nelson goto err_out_teardown;
28804436595SShannon Nelson }
28904436595SShannon Nelson
2900de38d9fSShannon Nelson return 0;
2910de38d9fSShannon Nelson
2920de38d9fSShannon Nelson err_out_teardown:
2930de38d9fSShannon Nelson ionic_dev_teardown(ionic);
2940de38d9fSShannon Nelson err_out_clear_pci:
2950de38d9fSShannon Nelson ionic_clear_pci(ionic);
2960de38d9fSShannon Nelson err_out_debugfs_del_dev:
2970de38d9fSShannon Nelson ionic_debugfs_del_dev(ionic);
2980de38d9fSShannon Nelson
2990de38d9fSShannon Nelson return err;
3000de38d9fSShannon Nelson }
3010de38d9fSShannon Nelson
ionic_probe(struct pci_dev * pdev,const struct pci_device_id * ent)3020de38d9fSShannon Nelson static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
3030de38d9fSShannon Nelson {
3040de38d9fSShannon Nelson struct device *dev = &pdev->dev;
3050de38d9fSShannon Nelson struct ionic *ionic;
3060de38d9fSShannon Nelson int num_vfs;
3070de38d9fSShannon Nelson int err;
3080de38d9fSShannon Nelson
3090de38d9fSShannon Nelson ionic = ionic_devlink_alloc(dev);
3100de38d9fSShannon Nelson if (!ionic)
3110de38d9fSShannon Nelson return -ENOMEM;
3120de38d9fSShannon Nelson
3130de38d9fSShannon Nelson ionic->pdev = pdev;
3140de38d9fSShannon Nelson ionic->dev = dev;
3150de38d9fSShannon Nelson pci_set_drvdata(pdev, ionic);
3160de38d9fSShannon Nelson mutex_init(&ionic->dev_cmd_lock);
3170de38d9fSShannon Nelson
3180de38d9fSShannon Nelson /* Query system for DMA addressing limitation for the device. */
3190de38d9fSShannon Nelson err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(IONIC_ADDR_LEN));
3200de38d9fSShannon Nelson if (err) {
3210de38d9fSShannon Nelson dev_err(dev, "Unable to obtain 64-bit DMA for consistent allocations, aborting. err=%d\n",
3220de38d9fSShannon Nelson err);
3230de38d9fSShannon Nelson goto err_out;
3240de38d9fSShannon Nelson }
3250de38d9fSShannon Nelson
3260de38d9fSShannon Nelson err = ionic_setup_one(ionic);
3270de38d9fSShannon Nelson if (err)
3280de38d9fSShannon Nelson goto err_out;
3290de38d9fSShannon Nelson
330a21b5d49SShannon Nelson /* Allocate and init the LIF */
33130b87ab4SShannon Nelson err = ionic_lif_size(ionic);
3321a58e196SShannon Nelson if (err) {
33330b87ab4SShannon Nelson dev_err(dev, "Cannot size LIF: %d, aborting\n", err);
3340de38d9fSShannon Nelson goto err_out_pci;
3351a58e196SShannon Nelson }
3361a58e196SShannon Nelson
33730b87ab4SShannon Nelson err = ionic_lif_alloc(ionic);
3381a58e196SShannon Nelson if (err) {
33930b87ab4SShannon Nelson dev_err(dev, "Cannot allocate LIF: %d, aborting\n", err);
3401a58e196SShannon Nelson goto err_out_free_irqs;
3411a58e196SShannon Nelson }
3421a58e196SShannon Nelson
34330b87ab4SShannon Nelson err = ionic_lif_init(ionic->lif);
3441a58e196SShannon Nelson if (err) {
34530b87ab4SShannon Nelson dev_err(dev, "Cannot init LIF: %d, aborting\n", err);
3461a58e196SShannon Nelson goto err_out_free_lifs;
3471a58e196SShannon Nelson }
3481a58e196SShannon Nelson
349fbb39807SShannon Nelson init_rwsem(&ionic->vf_op_lock);
350fbb39807SShannon Nelson num_vfs = pci_num_vf(pdev);
351fbb39807SShannon Nelson if (num_vfs) {
352fbb39807SShannon Nelson dev_info(dev, "%d VFs found already enabled\n", num_vfs);
353fbb39807SShannon Nelson err = ionic_vf_alloc(ionic, num_vfs);
354fbb39807SShannon Nelson if (err)
355fbb39807SShannon Nelson dev_err(dev, "Cannot enable existing VFs: %d\n", err);
356fbb39807SShannon Nelson }
357fbb39807SShannon Nelson
358fbfb8031SShannon Nelson err = ionic_devlink_register(ionic);
359beead698SShannon Nelson if (err) {
360fbfb8031SShannon Nelson dev_err(dev, "Cannot register devlink: %d\n", err);
3611fd7c082SJiri Pirko goto err_out_deinit_lifs;
3621fd7c082SJiri Pirko }
3631fd7c082SJiri Pirko
3641fd7c082SJiri Pirko err = ionic_lif_register(ionic->lif);
3651fd7c082SJiri Pirko if (err) {
3661fd7c082SJiri Pirko dev_err(dev, "Cannot register LIF: %d, aborting\n", err);
3671fd7c082SJiri Pirko goto err_out_deregister_devlink;
368beead698SShannon Nelson }
369df69ba43SShannon Nelson
3709ad2939aSShannon Nelson mod_timer(&ionic->watchdog_timer,
3719ad2939aSShannon Nelson round_jiffies(jiffies + ionic->watchdog_period));
3729ad2939aSShannon Nelson
373df69ba43SShannon Nelson return 0;
374fbfb8031SShannon Nelson
3751fd7c082SJiri Pirko err_out_deregister_devlink:
3761fd7c082SJiri Pirko ionic_devlink_unregister(ionic);
377beead698SShannon Nelson err_out_deinit_lifs:
378fbb39807SShannon Nelson ionic_vf_dealloc(ionic);
37930b87ab4SShannon Nelson ionic_lif_deinit(ionic->lif);
3801a58e196SShannon Nelson err_out_free_lifs:
38130b87ab4SShannon Nelson ionic_lif_free(ionic->lif);
38230b87ab4SShannon Nelson ionic->lif = NULL;
3831a58e196SShannon Nelson err_out_free_irqs:
3841a58e196SShannon Nelson ionic_bus_free_irq_vectors(ionic);
3850de38d9fSShannon Nelson err_out_pci:
38640bc471dSShannon Nelson ionic_dev_teardown(ionic);
38787d7a9f3SShannon Nelson ionic_clear_pci(ionic);
388*1947143cSWentao Liang ionic_debugfs_del_dev(ionic);
3890de38d9fSShannon Nelson err_out:
390fbfb8031SShannon Nelson mutex_destroy(&ionic->dev_cmd_lock);
391fbfb8031SShannon Nelson ionic_devlink_free(ionic);
392fbfb8031SShannon Nelson
393fbfb8031SShannon Nelson return err;
394df69ba43SShannon Nelson }
395df69ba43SShannon Nelson
ionic_remove(struct pci_dev * pdev)396df69ba43SShannon Nelson static void ionic_remove(struct pci_dev *pdev)
397df69ba43SShannon Nelson {
398df69ba43SShannon Nelson struct ionic *ionic = pci_get_drvdata(pdev);
399df69ba43SShannon Nelson
400df8aeaa8SShannon Nelson del_timer_sync(&ionic->watchdog_timer);
401df8aeaa8SShannon Nelson
40230b87ab4SShannon Nelson if (ionic->lif) {
4035e7213caSShannon Nelson /* prevent adminq cmds if already known as down */
4045e7213caSShannon Nelson if (test_and_clear_bit(IONIC_LIF_F_FW_RESET, ionic->lif->state))
4055e7213caSShannon Nelson set_bit(IONIC_LIF_F_FW_STOPPING, ionic->lif->state);
4065e7213caSShannon Nelson
40730b87ab4SShannon Nelson ionic_lif_unregister(ionic->lif);
4081fd7c082SJiri Pirko ionic_devlink_unregister(ionic);
40930b87ab4SShannon Nelson ionic_lif_deinit(ionic->lif);
41030b87ab4SShannon Nelson ionic_lif_free(ionic->lif);
41130b87ab4SShannon Nelson ionic->lif = NULL;
4121a58e196SShannon Nelson ionic_bus_free_irq_vectors(ionic);
41330a1e6d0SShannon Nelson }
41430a1e6d0SShannon Nelson
41504436595SShannon Nelson ionic_port_reset(ionic);
416fbfb8031SShannon Nelson ionic_reset(ionic);
41740bc471dSShannon Nelson ionic_dev_teardown(ionic);
41887d7a9f3SShannon Nelson ionic_clear_pci(ionic);
419fbfb8031SShannon Nelson ionic_debugfs_del_dev(ionic);
420fbfb8031SShannon Nelson mutex_destroy(&ionic->dev_cmd_lock);
421df69ba43SShannon Nelson ionic_devlink_free(ionic);
422df69ba43SShannon Nelson }
423df69ba43SShannon Nelson
ionic_reset_prepare(struct pci_dev * pdev)424a79b559eSShannon Nelson static void ionic_reset_prepare(struct pci_dev *pdev)
425a79b559eSShannon Nelson {
426a79b559eSShannon Nelson struct ionic *ionic = pci_get_drvdata(pdev);
427a79b559eSShannon Nelson struct ionic_lif *lif = ionic->lif;
428a79b559eSShannon Nelson
429a79b559eSShannon Nelson dev_dbg(ionic->dev, "%s: device stopping\n", __func__);
430a79b559eSShannon Nelson
431a79b559eSShannon Nelson del_timer_sync(&ionic->watchdog_timer);
432a79b559eSShannon Nelson cancel_work_sync(&lif->deferred.work);
433a79b559eSShannon Nelson
434a79b559eSShannon Nelson mutex_lock(&lif->queue_lock);
435a79b559eSShannon Nelson ionic_stop_queues_reconfig(lif);
436a79b559eSShannon Nelson ionic_txrx_free(lif);
437a79b559eSShannon Nelson ionic_lif_deinit(lif);
438a79b559eSShannon Nelson ionic_qcqs_free(lif);
439a79b559eSShannon Nelson mutex_unlock(&lif->queue_lock);
440a79b559eSShannon Nelson
441a79b559eSShannon Nelson ionic_dev_teardown(ionic);
442a79b559eSShannon Nelson ionic_clear_pci(ionic);
443a79b559eSShannon Nelson ionic_debugfs_del_dev(ionic);
444a79b559eSShannon Nelson }
445a79b559eSShannon Nelson
ionic_reset_done(struct pci_dev * pdev)446a79b559eSShannon Nelson static void ionic_reset_done(struct pci_dev *pdev)
447a79b559eSShannon Nelson {
448a79b559eSShannon Nelson struct ionic *ionic = pci_get_drvdata(pdev);
449a79b559eSShannon Nelson struct ionic_lif *lif = ionic->lif;
450a79b559eSShannon Nelson int err;
451a79b559eSShannon Nelson
452a79b559eSShannon Nelson err = ionic_setup_one(ionic);
453a79b559eSShannon Nelson if (err)
454a79b559eSShannon Nelson goto err_out;
455a79b559eSShannon Nelson
456a79b559eSShannon Nelson ionic_debugfs_add_sizes(ionic);
457a79b559eSShannon Nelson ionic_debugfs_add_lif(ionic->lif);
458a79b559eSShannon Nelson
459a79b559eSShannon Nelson err = ionic_restart_lif(lif);
460a79b559eSShannon Nelson if (err)
461a79b559eSShannon Nelson goto err_out;
462a79b559eSShannon Nelson
463a79b559eSShannon Nelson mod_timer(&ionic->watchdog_timer, jiffies + 1);
464a79b559eSShannon Nelson
465a79b559eSShannon Nelson err_out:
466a79b559eSShannon Nelson dev_dbg(ionic->dev, "%s: device recovery %s\n",
467a79b559eSShannon Nelson __func__, err ? "failed" : "done");
468a79b559eSShannon Nelson }
469a79b559eSShannon Nelson
470a79b559eSShannon Nelson static const struct pci_error_handlers ionic_err_handler = {
471a79b559eSShannon Nelson /* FLR handling */
472a79b559eSShannon Nelson .reset_prepare = ionic_reset_prepare,
473a79b559eSShannon Nelson .reset_done = ionic_reset_done,
474a79b559eSShannon Nelson };
475a79b559eSShannon Nelson
476df69ba43SShannon Nelson static struct pci_driver ionic_driver = {
477df69ba43SShannon Nelson .name = IONIC_DRV_NAME,
478df69ba43SShannon Nelson .id_table = ionic_id_table,
479df69ba43SShannon Nelson .probe = ionic_probe,
480df69ba43SShannon Nelson .remove = ionic_remove,
481fbb39807SShannon Nelson .sriov_configure = ionic_sriov_configure,
482a79b559eSShannon Nelson .err_handler = &ionic_err_handler
483df69ba43SShannon Nelson };
484df69ba43SShannon Nelson
ionic_bus_register_driver(void)485df69ba43SShannon Nelson int ionic_bus_register_driver(void)
486df69ba43SShannon Nelson {
487df69ba43SShannon Nelson return pci_register_driver(&ionic_driver);
488df69ba43SShannon Nelson }
489df69ba43SShannon Nelson
ionic_bus_unregister_driver(void)490df69ba43SShannon Nelson void ionic_bus_unregister_driver(void)
491df69ba43SShannon Nelson {
492df69ba43SShannon Nelson pci_unregister_driver(&ionic_driver);
493df69ba43SShannon Nelson }
494