Index: sys/compat/linuxkpi/common/include/linux/pci.h =================================================================== --- sys/compat/linuxkpi/common/include/linux/pci.h +++ sys/compat/linuxkpi/common/include/linux/pci.h @@ -954,4 +954,14 @@ return (PCIE_LNK_WIDTH_UNKNOWN); } +/* + * The following functions can be used to attach/detach the LinuxKPI's + * PCI device runtime. The only requirement is that the softc of the + * passed device starts with a pci_dev structure as defined by this + * file. The pci_driver and pci_device_id pointer is allowed to be + * NULL. + */ +extern int linux_pci_attach_device(device_t, struct pci_driver *, const struct pci_device_id *); +extern int linux_pci_detach_device(device_t); + #endif /* _LINUX_PCI_H_ */ Index: sys/compat/linuxkpi/common/src/linux_pci.c =================================================================== --- sys/compat/linuxkpi/common/src/linux_pci.c +++ sys/compat/linuxkpi/common/src/linux_pci.c @@ -213,22 +213,32 @@ static int linux_pci_attach(device_t dev) { + struct pci_driver *pdrv; + const struct pci_device_id *id; + + pdrv = linux_pci_find(dev, &id); + + MPASS(pdrv != NULL); + + return (linux_pci_attach_device(dev, pdrv, id)); +} + +int +linux_pci_attach_device(device_t dev, struct pci_driver *pdrv, + const struct pci_device_id *id) +{ struct resource_list_entry *rle; struct pci_bus *pbus; struct pci_dev *pdev; struct pci_devinfo *dinfo; - struct pci_driver *pdrv; - const struct pci_device_id *id; device_t parent; int error; linux_set_current(curthread); - pdrv = linux_pci_find(dev, &id); pdev = device_get_softc(dev); - parent = device_get_parent(dev); - if (pdrv->isdrm) { + if (pdrv != NULL && pdrv->isdrm) { dinfo = device_get_ivars(parent); device_set_ivars(dev, dinfo); } else { @@ -270,9 +280,11 @@ list_add(&pdev->links, &pci_devices); spin_unlock(&pci_lock); - error = pdrv->probe(pdev, id); - if (error) - goto out_probe; + if (pdrv != NULL) { + error = pdrv->probe(pdev, id); + if (error) + goto out_probe; + } return (0); out_probe: @@ -289,12 +301,20 @@ static int linux_pci_detach(device_t dev) { + + return (linux_pci_detach_device(dev)); +} + +int +linux_pci_detach_device(device_t dev) +{ struct pci_dev *pdev; linux_set_current(curthread); pdev = device_get_softc(dev); - pdev->pdrv->remove(pdev); + if (pdev->pdrv != NULL) + pdev->pdrv->remove(pdev); free(pdev->bus, M_DEVBUF); linux_pdev_dma_uninit(pdev);