155435ea7SShannon Nelson // SPDX-License-Identifier: GPL-2.0 255435ea7SShannon Nelson /* Copyright(c) 2023 Advanced Micro Devices, Inc */ 355435ea7SShannon Nelson 455435ea7SShannon Nelson #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 555435ea7SShannon Nelson 655435ea7SShannon Nelson #include <linux/pci.h> 755435ea7SShannon Nelson 855435ea7SShannon Nelson #include <linux/pds/pds_common.h> 955435ea7SShannon Nelson 1055435ea7SShannon Nelson #include "core.h" 1155435ea7SShannon Nelson 1255435ea7SShannon Nelson MODULE_DESCRIPTION(PDSC_DRV_DESCRIPTION); 1355435ea7SShannon Nelson MODULE_AUTHOR("Advanced Micro Devices, Inc"); 1455435ea7SShannon Nelson MODULE_LICENSE("GPL"); 1555435ea7SShannon Nelson 1655435ea7SShannon Nelson /* Supported devices */ 1755435ea7SShannon Nelson static const struct pci_device_id pdsc_id_table[] = { 1855435ea7SShannon Nelson { PCI_VDEVICE(PENSANDO, PCI_DEVICE_ID_PENSANDO_CORE_PF) }, 19f53d9311SShannon Nelson { PCI_VDEVICE(PENSANDO, PCI_DEVICE_ID_PENSANDO_VDPA_VF) }, 2055435ea7SShannon Nelson { 0, } /* end of table */ 2155435ea7SShannon Nelson }; 2255435ea7SShannon Nelson MODULE_DEVICE_TABLE(pci, pdsc_id_table); 2355435ea7SShannon Nelson 24c2dbb090SShannon Nelson static void pdsc_wdtimer_cb(struct timer_list *t) 25c2dbb090SShannon Nelson { 26c2dbb090SShannon Nelson struct pdsc *pdsc = from_timer(pdsc, t, wdtimer); 27c2dbb090SShannon Nelson 28c2dbb090SShannon Nelson dev_dbg(pdsc->dev, "%s: jiffies %ld\n", __func__, jiffies); 29c2dbb090SShannon Nelson mod_timer(&pdsc->wdtimer, 30c2dbb090SShannon Nelson round_jiffies(jiffies + pdsc->wdtimer_period)); 31c2dbb090SShannon Nelson 32c2dbb090SShannon Nelson queue_work(pdsc->wq, &pdsc->health_work); 33c2dbb090SShannon Nelson } 34c2dbb090SShannon Nelson 3555435ea7SShannon Nelson static void pdsc_unmap_bars(struct pdsc *pdsc) 3655435ea7SShannon Nelson { 3755435ea7SShannon Nelson struct pdsc_dev_bar *bars = pdsc->bars; 3855435ea7SShannon Nelson unsigned int i; 3955435ea7SShannon Nelson 4055435ea7SShannon Nelson for (i = 0; i < PDS_CORE_BARS_MAX; i++) { 4155435ea7SShannon Nelson if (bars[i].vaddr) 4255435ea7SShannon Nelson pci_iounmap(pdsc->pdev, bars[i].vaddr); 4355435ea7SShannon Nelson } 4455435ea7SShannon Nelson } 4555435ea7SShannon Nelson 4655435ea7SShannon Nelson static int pdsc_map_bars(struct pdsc *pdsc) 4755435ea7SShannon Nelson { 4855435ea7SShannon Nelson struct pdsc_dev_bar *bar = pdsc->bars; 4955435ea7SShannon Nelson struct pci_dev *pdev = pdsc->pdev; 5055435ea7SShannon Nelson struct device *dev = pdsc->dev; 5155435ea7SShannon Nelson struct pdsc_dev_bar *bars; 5255435ea7SShannon Nelson unsigned int i, j; 5355435ea7SShannon Nelson int num_bars = 0; 5455435ea7SShannon Nelson int err; 5555435ea7SShannon Nelson u32 sig; 5655435ea7SShannon Nelson 5755435ea7SShannon Nelson bars = pdsc->bars; 5855435ea7SShannon Nelson 5955435ea7SShannon Nelson /* Since the PCI interface in the hardware is configurable, 6055435ea7SShannon Nelson * we need to poke into all the bars to find the set we're 6155435ea7SShannon Nelson * expecting. 6255435ea7SShannon Nelson */ 6355435ea7SShannon Nelson for (i = 0, j = 0; i < PDS_CORE_BARS_MAX; i++) { 6455435ea7SShannon Nelson if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM)) 6555435ea7SShannon Nelson continue; 6655435ea7SShannon Nelson 6755435ea7SShannon Nelson bars[j].len = pci_resource_len(pdev, i); 6855435ea7SShannon Nelson bars[j].bus_addr = pci_resource_start(pdev, i); 6955435ea7SShannon Nelson bars[j].res_index = i; 7055435ea7SShannon Nelson 7155435ea7SShannon Nelson /* only map the whole bar 0 */ 7255435ea7SShannon Nelson if (j > 0) { 7355435ea7SShannon Nelson bars[j].vaddr = NULL; 7455435ea7SShannon Nelson } else { 7555435ea7SShannon Nelson bars[j].vaddr = pci_iomap(pdev, i, bars[j].len); 7655435ea7SShannon Nelson if (!bars[j].vaddr) { 7755435ea7SShannon Nelson dev_err(dev, "Cannot map BAR %d, aborting\n", i); 7855435ea7SShannon Nelson return -ENODEV; 7955435ea7SShannon Nelson } 8055435ea7SShannon Nelson } 8155435ea7SShannon Nelson 8255435ea7SShannon Nelson j++; 8355435ea7SShannon Nelson } 8455435ea7SShannon Nelson num_bars = j; 8555435ea7SShannon Nelson 8655435ea7SShannon Nelson /* BAR0: dev_cmd and interrupts */ 8755435ea7SShannon Nelson if (num_bars < 1) { 8855435ea7SShannon Nelson dev_err(dev, "No bars found\n"); 8955435ea7SShannon Nelson err = -EFAULT; 9055435ea7SShannon Nelson goto err_out; 9155435ea7SShannon Nelson } 9255435ea7SShannon Nelson 9355435ea7SShannon Nelson if (bar->len < PDS_CORE_BAR0_SIZE) { 9455435ea7SShannon Nelson dev_err(dev, "Resource bar size %lu too small\n", bar->len); 9555435ea7SShannon Nelson err = -EFAULT; 9655435ea7SShannon Nelson goto err_out; 9755435ea7SShannon Nelson } 9855435ea7SShannon Nelson 9955435ea7SShannon Nelson pdsc->info_regs = bar->vaddr + PDS_CORE_BAR0_DEV_INFO_REGS_OFFSET; 10055435ea7SShannon Nelson pdsc->cmd_regs = bar->vaddr + PDS_CORE_BAR0_DEV_CMD_REGS_OFFSET; 10155435ea7SShannon Nelson pdsc->intr_status = bar->vaddr + PDS_CORE_BAR0_INTR_STATUS_OFFSET; 10255435ea7SShannon Nelson pdsc->intr_ctrl = bar->vaddr + PDS_CORE_BAR0_INTR_CTRL_OFFSET; 10355435ea7SShannon Nelson 10455435ea7SShannon Nelson sig = ioread32(&pdsc->info_regs->signature); 10555435ea7SShannon Nelson if (sig != PDS_CORE_DEV_INFO_SIGNATURE) { 10655435ea7SShannon Nelson dev_err(dev, "Incompatible firmware signature %x", sig); 10755435ea7SShannon Nelson err = -EFAULT; 10855435ea7SShannon Nelson goto err_out; 10955435ea7SShannon Nelson } 11055435ea7SShannon Nelson 11155435ea7SShannon Nelson /* BAR1: doorbells */ 11255435ea7SShannon Nelson bar++; 11355435ea7SShannon Nelson if (num_bars < 2) { 11455435ea7SShannon Nelson dev_err(dev, "Doorbell bar missing\n"); 11555435ea7SShannon Nelson err = -EFAULT; 11655435ea7SShannon Nelson goto err_out; 11755435ea7SShannon Nelson } 11855435ea7SShannon Nelson 11955435ea7SShannon Nelson pdsc->db_pages = bar->vaddr; 12055435ea7SShannon Nelson pdsc->phy_db_pages = bar->bus_addr; 12155435ea7SShannon Nelson 12255435ea7SShannon Nelson return 0; 12355435ea7SShannon Nelson 12455435ea7SShannon Nelson err_out: 12555435ea7SShannon Nelson pdsc_unmap_bars(pdsc); 12655435ea7SShannon Nelson return err; 12755435ea7SShannon Nelson } 12855435ea7SShannon Nelson 12945d76f49SShannon Nelson void __iomem *pdsc_map_dbpage(struct pdsc *pdsc, int page_num) 13045d76f49SShannon Nelson { 13145d76f49SShannon Nelson return pci_iomap_range(pdsc->pdev, 13245d76f49SShannon Nelson pdsc->bars[PDS_CORE_PCI_BAR_DBELL].res_index, 13345d76f49SShannon Nelson (u64)page_num << PAGE_SHIFT, PAGE_SIZE); 13445d76f49SShannon Nelson } 13545d76f49SShannon Nelson 136f53d9311SShannon Nelson static int pdsc_sriov_configure(struct pci_dev *pdev, int num_vfs) 137f53d9311SShannon Nelson { 138f53d9311SShannon Nelson struct pdsc *pdsc = pci_get_drvdata(pdev); 139f53d9311SShannon Nelson struct device *dev = pdsc->dev; 140f53d9311SShannon Nelson int ret = 0; 141f53d9311SShannon Nelson 142f53d9311SShannon Nelson if (num_vfs > 0) { 143f53d9311SShannon Nelson pdsc->vfs = kcalloc(num_vfs, sizeof(struct pdsc_vf), 144f53d9311SShannon Nelson GFP_KERNEL); 145f53d9311SShannon Nelson if (!pdsc->vfs) 146f53d9311SShannon Nelson return -ENOMEM; 147f53d9311SShannon Nelson pdsc->num_vfs = num_vfs; 148f53d9311SShannon Nelson 149f53d9311SShannon Nelson ret = pci_enable_sriov(pdev, num_vfs); 150f53d9311SShannon Nelson if (ret) { 151f53d9311SShannon Nelson dev_err(dev, "Cannot enable SRIOV: %pe\n", 152f53d9311SShannon Nelson ERR_PTR(ret)); 153f53d9311SShannon Nelson goto no_vfs; 154f53d9311SShannon Nelson } 155f53d9311SShannon Nelson 156f53d9311SShannon Nelson return num_vfs; 157f53d9311SShannon Nelson } 158f53d9311SShannon Nelson 159f53d9311SShannon Nelson no_vfs: 160f53d9311SShannon Nelson pci_disable_sriov(pdev); 161f53d9311SShannon Nelson 162f53d9311SShannon Nelson kfree(pdsc->vfs); 163f53d9311SShannon Nelson pdsc->vfs = NULL; 164f53d9311SShannon Nelson pdsc->num_vfs = 0; 165f53d9311SShannon Nelson 166f53d9311SShannon Nelson return ret; 167f53d9311SShannon Nelson } 168f53d9311SShannon Nelson 16955435ea7SShannon Nelson static int pdsc_init_vf(struct pdsc *vf) 17055435ea7SShannon Nelson { 171f53d9311SShannon Nelson struct devlink *dl; 172*4569cce4SShannon Nelson struct pdsc *pf; 173*4569cce4SShannon Nelson int err; 174*4569cce4SShannon Nelson 175*4569cce4SShannon Nelson pf = pdsc_get_pf_struct(vf->pdev); 176*4569cce4SShannon Nelson if (IS_ERR_OR_NULL(pf)) 177*4569cce4SShannon Nelson return PTR_ERR(pf) ?: -1; 178f53d9311SShannon Nelson 179f53d9311SShannon Nelson vf->vf_id = pci_iov_vf_id(vf->pdev); 180f53d9311SShannon Nelson 181f53d9311SShannon Nelson dl = priv_to_devlink(vf); 182f53d9311SShannon Nelson devl_lock(dl); 183f53d9311SShannon Nelson devl_register(dl); 184f53d9311SShannon Nelson devl_unlock(dl); 185f53d9311SShannon Nelson 186*4569cce4SShannon Nelson pf->vfs[vf->vf_id].vf = vf; 187*4569cce4SShannon Nelson err = pdsc_auxbus_dev_add(vf, pf); 188*4569cce4SShannon Nelson if (err) { 189*4569cce4SShannon Nelson devl_lock(dl); 190*4569cce4SShannon Nelson devl_unregister(dl); 191*4569cce4SShannon Nelson devl_unlock(dl); 192*4569cce4SShannon Nelson } 193*4569cce4SShannon Nelson 194*4569cce4SShannon Nelson return err; 19555435ea7SShannon Nelson } 19655435ea7SShannon Nelson 19725b450c0SShannon Nelson static const struct devlink_health_reporter_ops pdsc_fw_reporter_ops = { 19825b450c0SShannon Nelson .name = "fw", 19925b450c0SShannon Nelson .diagnose = pdsc_fw_reporter_diagnose, 20025b450c0SShannon Nelson }; 20125b450c0SShannon Nelson 202c2dbb090SShannon Nelson #define PDSC_WQ_NAME_LEN 24 203c2dbb090SShannon Nelson 20455435ea7SShannon Nelson static int pdsc_init_pf(struct pdsc *pdsc) 20555435ea7SShannon Nelson { 20625b450c0SShannon Nelson struct devlink_health_reporter *hr; 207c2dbb090SShannon Nelson char wq_name[PDSC_WQ_NAME_LEN]; 20855435ea7SShannon Nelson struct devlink *dl; 20955435ea7SShannon Nelson int err; 21055435ea7SShannon Nelson 21155435ea7SShannon Nelson pcie_print_link_status(pdsc->pdev); 21255435ea7SShannon Nelson 21355435ea7SShannon Nelson err = pci_request_regions(pdsc->pdev, PDS_CORE_DRV_NAME); 21455435ea7SShannon Nelson if (err) { 21555435ea7SShannon Nelson dev_err(pdsc->dev, "Cannot request PCI regions: %pe\n", 21655435ea7SShannon Nelson ERR_PTR(err)); 21755435ea7SShannon Nelson return err; 21855435ea7SShannon Nelson } 21955435ea7SShannon Nelson 22055435ea7SShannon Nelson err = pdsc_map_bars(pdsc); 22155435ea7SShannon Nelson if (err) 22255435ea7SShannon Nelson goto err_out_release_regions; 22355435ea7SShannon Nelson 224c2dbb090SShannon Nelson /* General workqueue and timer, but don't start timer yet */ 225c2dbb090SShannon Nelson snprintf(wq_name, sizeof(wq_name), "%s.%d", PDS_CORE_DRV_NAME, pdsc->uid); 226c2dbb090SShannon Nelson pdsc->wq = create_singlethread_workqueue(wq_name); 227c2dbb090SShannon Nelson INIT_WORK(&pdsc->health_work, pdsc_health_thread); 228c2dbb090SShannon Nelson timer_setup(&pdsc->wdtimer, pdsc_wdtimer_cb, 0); 229c2dbb090SShannon Nelson pdsc->wdtimer_period = PDSC_WATCHDOG_SECS * HZ; 230c2dbb090SShannon Nelson 231523847dfSShannon Nelson mutex_init(&pdsc->devcmd_lock); 232523847dfSShannon Nelson mutex_init(&pdsc->config_lock); 23345d76f49SShannon Nelson spin_lock_init(&pdsc->adminq_lock); 234523847dfSShannon Nelson 235523847dfSShannon Nelson mutex_lock(&pdsc->config_lock); 236523847dfSShannon Nelson set_bit(PDSC_S_FW_DEAD, &pdsc->state); 237523847dfSShannon Nelson 238523847dfSShannon Nelson err = pdsc_setup(pdsc, PDSC_SETUP_INIT); 239523847dfSShannon Nelson if (err) 240523847dfSShannon Nelson goto err_out_unmap_bars; 24145d76f49SShannon Nelson err = pdsc_start(pdsc); 24245d76f49SShannon Nelson if (err) 24345d76f49SShannon Nelson goto err_out_teardown; 244523847dfSShannon Nelson 245523847dfSShannon Nelson mutex_unlock(&pdsc->config_lock); 246523847dfSShannon Nelson 24755435ea7SShannon Nelson dl = priv_to_devlink(pdsc); 24855435ea7SShannon Nelson devl_lock(dl); 24925b450c0SShannon Nelson 25025b450c0SShannon Nelson hr = devl_health_reporter_create(dl, &pdsc_fw_reporter_ops, 0, pdsc); 25125b450c0SShannon Nelson if (IS_ERR(hr)) { 25225b450c0SShannon Nelson dev_warn(pdsc->dev, "Failed to create fw reporter: %pe\n", hr); 25325b450c0SShannon Nelson err = PTR_ERR(hr); 25425b450c0SShannon Nelson devl_unlock(dl); 25545d76f49SShannon Nelson goto err_out_stop; 25625b450c0SShannon Nelson } 25725b450c0SShannon Nelson pdsc->fw_reporter = hr; 25825b450c0SShannon Nelson 25955435ea7SShannon Nelson devl_register(dl); 26055435ea7SShannon Nelson devl_unlock(dl); 26155435ea7SShannon Nelson 262c2dbb090SShannon Nelson /* Lastly, start the health check timer */ 263c2dbb090SShannon Nelson mod_timer(&pdsc->wdtimer, round_jiffies(jiffies + pdsc->wdtimer_period)); 264c2dbb090SShannon Nelson 26555435ea7SShannon Nelson return 0; 26655435ea7SShannon Nelson 26745d76f49SShannon Nelson err_out_stop: 26845d76f49SShannon Nelson pdsc_stop(pdsc); 26925b450c0SShannon Nelson err_out_teardown: 27025b450c0SShannon Nelson pdsc_teardown(pdsc, PDSC_TEARDOWN_REMOVING); 271523847dfSShannon Nelson err_out_unmap_bars: 272523847dfSShannon Nelson mutex_unlock(&pdsc->config_lock); 273c2dbb090SShannon Nelson del_timer_sync(&pdsc->wdtimer); 274c2dbb090SShannon Nelson if (pdsc->wq) 275c2dbb090SShannon Nelson destroy_workqueue(pdsc->wq); 276523847dfSShannon Nelson mutex_destroy(&pdsc->config_lock); 277523847dfSShannon Nelson mutex_destroy(&pdsc->devcmd_lock); 278523847dfSShannon Nelson pci_free_irq_vectors(pdsc->pdev); 279523847dfSShannon Nelson pdsc_unmap_bars(pdsc); 28055435ea7SShannon Nelson err_out_release_regions: 28155435ea7SShannon Nelson pci_release_regions(pdsc->pdev); 28255435ea7SShannon Nelson 28355435ea7SShannon Nelson return err; 28455435ea7SShannon Nelson } 28555435ea7SShannon Nelson 28655435ea7SShannon Nelson static const struct devlink_ops pdsc_dl_ops = { 28745d76f49SShannon Nelson .info_get = pdsc_dl_info_get, 28849ce92fbSShannon Nelson .flash_update = pdsc_dl_flash_update, 28955435ea7SShannon Nelson }; 29055435ea7SShannon Nelson 29155435ea7SShannon Nelson static const struct devlink_ops pdsc_dl_vf_ops = { 29255435ea7SShannon Nelson }; 29355435ea7SShannon Nelson 29455435ea7SShannon Nelson static DEFINE_IDA(pdsc_ida); 29555435ea7SShannon Nelson 29655435ea7SShannon Nelson static int pdsc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 29755435ea7SShannon Nelson { 29855435ea7SShannon Nelson struct device *dev = &pdev->dev; 29955435ea7SShannon Nelson const struct devlink_ops *ops; 30055435ea7SShannon Nelson struct devlink *dl; 30155435ea7SShannon Nelson struct pdsc *pdsc; 30255435ea7SShannon Nelson bool is_pf; 30355435ea7SShannon Nelson int err; 30455435ea7SShannon Nelson 30555435ea7SShannon Nelson is_pf = !pdev->is_virtfn; 30655435ea7SShannon Nelson ops = is_pf ? &pdsc_dl_ops : &pdsc_dl_vf_ops; 30755435ea7SShannon Nelson dl = devlink_alloc(ops, sizeof(struct pdsc), dev); 30855435ea7SShannon Nelson if (!dl) 30955435ea7SShannon Nelson return -ENOMEM; 31055435ea7SShannon Nelson pdsc = devlink_priv(dl); 31155435ea7SShannon Nelson 31255435ea7SShannon Nelson pdsc->pdev = pdev; 31355435ea7SShannon Nelson pdsc->dev = &pdev->dev; 31455435ea7SShannon Nelson set_bit(PDSC_S_INITING_DRIVER, &pdsc->state); 31555435ea7SShannon Nelson pci_set_drvdata(pdev, pdsc); 31655435ea7SShannon Nelson pdsc_debugfs_add_dev(pdsc); 31755435ea7SShannon Nelson 31855435ea7SShannon Nelson err = ida_alloc(&pdsc_ida, GFP_KERNEL); 31955435ea7SShannon Nelson if (err < 0) { 32055435ea7SShannon Nelson dev_err(pdsc->dev, "%s: id alloc failed: %pe\n", 32155435ea7SShannon Nelson __func__, ERR_PTR(err)); 32255435ea7SShannon Nelson goto err_out_free_devlink; 32355435ea7SShannon Nelson } 32455435ea7SShannon Nelson pdsc->uid = err; 32555435ea7SShannon Nelson 32655435ea7SShannon Nelson /* Query system for DMA addressing limitation for the device. */ 32755435ea7SShannon Nelson err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(PDS_CORE_ADDR_LEN)); 32855435ea7SShannon Nelson if (err) { 32955435ea7SShannon Nelson dev_err(dev, "Unable to obtain 64-bit DMA for consistent allocations, aborting: %pe\n", 33055435ea7SShannon Nelson ERR_PTR(err)); 33155435ea7SShannon Nelson goto err_out_free_ida; 33255435ea7SShannon Nelson } 33355435ea7SShannon Nelson 33455435ea7SShannon Nelson err = pci_enable_device(pdev); 33555435ea7SShannon Nelson if (err) { 33655435ea7SShannon Nelson dev_err(dev, "Cannot enable PCI device: %pe\n", ERR_PTR(err)); 33755435ea7SShannon Nelson goto err_out_free_ida; 33855435ea7SShannon Nelson } 33955435ea7SShannon Nelson pci_set_master(pdev); 34055435ea7SShannon Nelson 34155435ea7SShannon Nelson if (is_pf) 34255435ea7SShannon Nelson err = pdsc_init_pf(pdsc); 34355435ea7SShannon Nelson else 34455435ea7SShannon Nelson err = pdsc_init_vf(pdsc); 34555435ea7SShannon Nelson if (err) { 34655435ea7SShannon Nelson dev_err(dev, "Cannot init device: %pe\n", ERR_PTR(err)); 34755435ea7SShannon Nelson goto err_out_clear_master; 34855435ea7SShannon Nelson } 34955435ea7SShannon Nelson 35055435ea7SShannon Nelson clear_bit(PDSC_S_INITING_DRIVER, &pdsc->state); 35155435ea7SShannon Nelson return 0; 35255435ea7SShannon Nelson 35355435ea7SShannon Nelson err_out_clear_master: 35455435ea7SShannon Nelson pci_clear_master(pdev); 35555435ea7SShannon Nelson pci_disable_device(pdev); 35655435ea7SShannon Nelson err_out_free_ida: 35755435ea7SShannon Nelson ida_free(&pdsc_ida, pdsc->uid); 35855435ea7SShannon Nelson err_out_free_devlink: 35955435ea7SShannon Nelson pdsc_debugfs_del_dev(pdsc); 36055435ea7SShannon Nelson devlink_free(dl); 36155435ea7SShannon Nelson 36255435ea7SShannon Nelson return err; 36355435ea7SShannon Nelson } 36455435ea7SShannon Nelson 36555435ea7SShannon Nelson static void pdsc_remove(struct pci_dev *pdev) 36655435ea7SShannon Nelson { 36755435ea7SShannon Nelson struct pdsc *pdsc = pci_get_drvdata(pdev); 36855435ea7SShannon Nelson struct devlink *dl; 36955435ea7SShannon Nelson 37055435ea7SShannon Nelson /* Unhook the registrations first to be sure there 37155435ea7SShannon Nelson * are no requests while we're stopping. 37255435ea7SShannon Nelson */ 37355435ea7SShannon Nelson dl = priv_to_devlink(pdsc); 37455435ea7SShannon Nelson devl_lock(dl); 37555435ea7SShannon Nelson devl_unregister(dl); 37625b450c0SShannon Nelson if (pdsc->fw_reporter) { 37725b450c0SShannon Nelson devl_health_reporter_destroy(pdsc->fw_reporter); 37825b450c0SShannon Nelson pdsc->fw_reporter = NULL; 37925b450c0SShannon Nelson } 38055435ea7SShannon Nelson devl_unlock(dl); 38155435ea7SShannon Nelson 382*4569cce4SShannon Nelson if (pdev->is_virtfn) { 383*4569cce4SShannon Nelson struct pdsc *pf; 384*4569cce4SShannon Nelson 385*4569cce4SShannon Nelson pf = pdsc_get_pf_struct(pdsc->pdev); 386*4569cce4SShannon Nelson if (!IS_ERR(pf)) { 387*4569cce4SShannon Nelson pdsc_auxbus_dev_del(pdsc, pf); 388*4569cce4SShannon Nelson pf->vfs[pdsc->vf_id].vf = NULL; 389*4569cce4SShannon Nelson } 390*4569cce4SShannon Nelson } else { 391*4569cce4SShannon Nelson /* Remove the VFs and their aux_bus connections before other 392*4569cce4SShannon Nelson * cleanup so that the clients can use the AdminQ to cleanly 393*4569cce4SShannon Nelson * shut themselves down. 394*4569cce4SShannon Nelson */ 395f53d9311SShannon Nelson pdsc_sriov_configure(pdev, 0); 396f53d9311SShannon Nelson 397c2dbb090SShannon Nelson del_timer_sync(&pdsc->wdtimer); 398c2dbb090SShannon Nelson if (pdsc->wq) 399c2dbb090SShannon Nelson destroy_workqueue(pdsc->wq); 400c2dbb090SShannon Nelson 401523847dfSShannon Nelson mutex_lock(&pdsc->config_lock); 402523847dfSShannon Nelson set_bit(PDSC_S_STOPPING_DRIVER, &pdsc->state); 403523847dfSShannon Nelson 40445d76f49SShannon Nelson pdsc_stop(pdsc); 405523847dfSShannon Nelson pdsc_teardown(pdsc, PDSC_TEARDOWN_REMOVING); 406523847dfSShannon Nelson mutex_unlock(&pdsc->config_lock); 407523847dfSShannon Nelson mutex_destroy(&pdsc->config_lock); 408523847dfSShannon Nelson mutex_destroy(&pdsc->devcmd_lock); 409523847dfSShannon Nelson 410523847dfSShannon Nelson pci_free_irq_vectors(pdev); 41155435ea7SShannon Nelson pdsc_unmap_bars(pdsc); 41255435ea7SShannon Nelson pci_release_regions(pdev); 413523847dfSShannon Nelson } 41455435ea7SShannon Nelson 41555435ea7SShannon Nelson pci_clear_master(pdev); 41655435ea7SShannon Nelson pci_disable_device(pdev); 41755435ea7SShannon Nelson 41855435ea7SShannon Nelson ida_free(&pdsc_ida, pdsc->uid); 41955435ea7SShannon Nelson pdsc_debugfs_del_dev(pdsc); 42055435ea7SShannon Nelson devlink_free(dl); 42155435ea7SShannon Nelson } 42255435ea7SShannon Nelson 42355435ea7SShannon Nelson static struct pci_driver pdsc_driver = { 42455435ea7SShannon Nelson .name = PDS_CORE_DRV_NAME, 42555435ea7SShannon Nelson .id_table = pdsc_id_table, 42655435ea7SShannon Nelson .probe = pdsc_probe, 42755435ea7SShannon Nelson .remove = pdsc_remove, 428f53d9311SShannon Nelson .sriov_configure = pdsc_sriov_configure, 42955435ea7SShannon Nelson }; 43055435ea7SShannon Nelson 431*4569cce4SShannon Nelson void *pdsc_get_pf_struct(struct pci_dev *vf_pdev) 432*4569cce4SShannon Nelson { 433*4569cce4SShannon Nelson return pci_iov_get_pf_drvdata(vf_pdev, &pdsc_driver); 434*4569cce4SShannon Nelson } 435*4569cce4SShannon Nelson EXPORT_SYMBOL_GPL(pdsc_get_pf_struct); 436*4569cce4SShannon Nelson 43755435ea7SShannon Nelson static int __init pdsc_init_module(void) 43855435ea7SShannon Nelson { 43955435ea7SShannon Nelson if (strcmp(KBUILD_MODNAME, PDS_CORE_DRV_NAME)) 44055435ea7SShannon Nelson return -EINVAL; 44155435ea7SShannon Nelson 44255435ea7SShannon Nelson pdsc_debugfs_create(); 44355435ea7SShannon Nelson return pci_register_driver(&pdsc_driver); 44455435ea7SShannon Nelson } 44555435ea7SShannon Nelson 44655435ea7SShannon Nelson static void __exit pdsc_cleanup_module(void) 44755435ea7SShannon Nelson { 44855435ea7SShannon Nelson pci_unregister_driver(&pdsc_driver); 44955435ea7SShannon Nelson pdsc_debugfs_destroy(); 45055435ea7SShannon Nelson } 45155435ea7SShannon Nelson 45255435ea7SShannon Nelson module_init(pdsc_init_module); 45355435ea7SShannon Nelson module_exit(pdsc_cleanup_module); 454