git: 7c9ee41f4fe4 - main - LinuxKPI: pci: first round of file cleanup

From: Bjoern A. Zeeb <bz_at_FreeBSD.org>
Date: Sun, 11 Oct 2026 13:51:33 UTC
The branch main has been updated by bz:

URL: https://cgit.FreeBSD.org/src/commit/?id=7c9ee41f4fe4a6de6e5f4c3d7c3a38ff447c8cf3

commit 7c9ee41f4fe4a6de6e5f4c3d7c3a38ff447c8cf3
Author:     Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2026-06-03 05:36:35 +0000
Commit:     Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2026-10-11 13:51:11 +0000

    LinuxKPI: pci: first round of file cleanup
    
    While the multiple sections of the file are mostly clearly separated
    some bits were spread around.
    
    Get the device methods array to the end of the file saving us a lot
    of forward function delcarations and making it easier to rename them
    to a common lkpi_ prefix instead of linux_ showing that they are file
    local internal functions not part of any official LinuxKPI KPI.
    
    Sort the various lkpi_pci_* bus attachment functions together,
    followed by the lkpi_pci_iov_ ones.  Then add the
    pci_[un]register_driver* driver bits.  This keeps the group
    logically together.
    
    For the PCI functions then group the pdev allocations and free/release
    functions--for the two paths--together, giving them more homogeneous
    names and add comments to some of them so it is more clear which
    ones are shared ("common") and which ones belong to which code path.
    
    Move some helper function around to where they are needed now.
    
    There is still more to do for the resource section which sits somewhere
    in the middle but that will better be a separate pass.
    
    For the DMA and backlight parts, rename various private bits to
    a lkpi_ prefix as well (structures, variables, functions) away
    from the public linux_ prefix which should belong to the linuxolator
    in first place.
    
    No functional changes intended.
    
    Sponsored by:   The FreeBSD Foundation
    MFC after:      3 days
    Reviewed by:    dumbbell (before rebase)
    Differential Revision: https://reviews.freebsd.org/D57433
---
 sys/compat/linuxkpi/common/src/linux_pci.c | 806 +++++++++++++++--------------
 1 file changed, 420 insertions(+), 386 deletions(-)

diff --git a/sys/compat/linuxkpi/common/src/linux_pci.c b/sys/compat/linuxkpi/common/src/linux_pci.c
index 6b598eb82d76..bd51082fb4d1 100644
--- a/sys/compat/linuxkpi/common/src/linux_pci.c
+++ b/sys/compat/linuxkpi/common/src/linux_pci.c
@@ -33,6 +33,7 @@
  * (1) PCI
  * (2) DMA
  * (3) Backlight
+ * (4) Native bus attachment glue.
  */
 
 #include <sys/param.h>
@@ -97,27 +98,12 @@
 /* Undef the linux function macro defined in linux/pci.h */
 #undef pci_get_class
 
-extern int linuxkpi_debug;
+static void lkpi_pcim_iomap_table_release(struct device *, void *);
 
+extern int linuxkpi_debug;
 SYSCTL_DECL(_compat_linuxkpi);
 
-static counter_u64_t lkpi_pci_nseg1_fail;
-SYSCTL_COUNTER_U64(_compat_linuxkpi, OID_AUTO, lkpi_pci_nseg1_fail, CTLFLAG_RD,
-    &lkpi_pci_nseg1_fail, "Count of busdma mapping failures of single-segment");
-
-static device_probe_t linux_pci_probe;
-static device_attach_t linux_pci_attach;
-static device_detach_t linux_pci_detach;
-static device_suspend_t linux_pci_suspend;
-static device_resume_t linux_pci_resume;
-static device_shutdown_t linux_pci_shutdown;
-static pci_iov_init_t linux_pci_iov_init;
-static pci_iov_uninit_t linux_pci_iov_uninit;
-static pci_iov_add_vf_t linux_pci_iov_add_vf;
-static int linux_backlight_get_status(device_t dev, struct backlight_props *props);
-static int linux_backlight_update_status(device_t dev, struct backlight_props *props);
-static int linux_backlight_get_info(device_t dev, struct backlight_info *info);
-static void lkpi_pcim_iomap_table_release(struct device *, void *);
+static device_method_t pci_methods[];
 
 static struct list_head lkpi_pci_drivers;
 static struct list_head lkpi_pci_devices;
@@ -128,27 +114,6 @@ static spinlock_t lkpi_pci_lock;
 #define	LKPI_PCI_LOCK()			spin_lock(&lkpi_pci_lock)
 #define	LKPI_PCI_UNLOCK()		spin_unlock(&lkpi_pci_lock)
 
-static device_method_t pci_methods[] = {
-	DEVMETHOD(device_probe, linux_pci_probe),
-	DEVMETHOD(device_attach, linux_pci_attach),
-	DEVMETHOD(device_detach, linux_pci_detach),
-	DEVMETHOD(device_suspend, linux_pci_suspend),
-	DEVMETHOD(device_resume, linux_pci_resume),
-	DEVMETHOD(device_shutdown, linux_pci_shutdown),
-	DEVMETHOD(pci_iov_init, linux_pci_iov_init),
-	DEVMETHOD(pci_iov_uninit, linux_pci_iov_uninit),
-	DEVMETHOD(pci_iov_add_vf, linux_pci_iov_add_vf),
-
-	/* Bus interface. */
-	DEVMETHOD(bus_add_child, bus_generic_add_child),
-
-	/* backlight interface */
-	DEVMETHOD(backlight_update_status, linux_backlight_update_status),
-	DEVMETHOD(backlight_get_status, linux_backlight_get_status),
-	DEVMETHOD(backlight_get_info, linux_backlight_get_info),
-	DEVMETHOD_END
-};
-
 const char *pci_power_names[] = {
 	"UNKNOWN", "D0", "D1", "D2", "D3hot", "D3cold"
 };
@@ -176,21 +141,39 @@ struct linux_dma_priv {
 #define	DMA_PRIV_LOCK(priv) mtx_lock(&(priv)->lock)
 #define	DMA_PRIV_UNLOCK(priv) mtx_unlock(&(priv)->lock)
 
-static void
-lkpi_set_pcim_iomap_devres(struct pcim_iomap_devres *dr, int bar,
-    void *res)
+static struct resource_list_entry *
+lkpi_pci_reserve_bar(struct pci_dev *pdev, struct resource_list *rl,
+    int type, int rid)
 {
-	dr->mmio_table[bar] = (void *)rman_get_bushandle(res);
-	dr->res_table[bar] = res;
+	device_t dev;
+	struct resource *res;
+
+	KASSERT(type == SYS_RES_IOPORT || type == SYS_RES_MEMORY,
+	    ("trying to reserve non-BAR type %d", type));
+
+	dev = pdev->pdrv != NULL && pdev->pdrv->isdrm ?
+	    device_get_parent(pdev->dev.bsddev) : pdev->dev.bsddev;
+	res = pci_reserve_map(device_get_parent(dev), dev, type, rid, 0, ~0,
+	    1, 1, 0);
+	if (res == NULL)
+		return (NULL);
+	return (resource_list_find(rl, type, rid));
 }
 
-static bool
-lkpi_pci_bar_id_valid(int bar)
+static struct resource_list_entry *
+lkpi_pci_get_rle(struct pci_dev *pdev, int type, int rid, bool reserve_bar)
 {
-	if (bar < 0 || bar > PCIR_MAX_BAR_0)
-		return (false);
+	struct pci_devinfo *dinfo;
+	struct resource_list *rl;
+	struct resource_list_entry *rle;
 
-	return (true);
+	dinfo = device_get_ivars(pdev->dev.bsddev);
+	rl = &dinfo->resources;
+	rle = resource_list_find(rl, type, rid);
+	/* Reserve resources for this BAR if needed. */
+	if (rle == NULL && reserve_bar)
+		rle = lkpi_pci_reserve_bar(pdev, rl, type, rid);
+	return (rle);
 }
 
 static int
@@ -364,12 +347,12 @@ lkpi_pci_get_device(uint32_t vendor, uint32_t device, struct pci_dev *odev)
 }
 
 /*
- * Shared function releasing the bus resources which can be built independent
- * of the way we allocate/initialization the pdev [pci_upstream_bridge(),
- * pcie_find_root_port()].
+ * Shared helper function releasing the bus resources which can be built
+ * independent of the way we allocate/initialization the pdev
+ * [pci_upstream_bridge(), pcie_find_root_port()].
  */
 static void
-lkpi_pci_dev_bus_release(struct pci_dev *pdev)
+lkpi_pci_dev_release_common_bus(struct pci_dev *pdev)
 {
 	/* Clear the hierarchy recursively to root. */
 	if (pdev->bus->self != pdev) {
@@ -383,9 +366,9 @@ lkpi_pci_dev_bus_release(struct pci_dev *pdev)
 	}
 }
 
-/* Release resources acquired by lkpifill_pci_dev(). */
+/* Release helper function to free resources acquired by lkpi_pci_dev_init_common(). */
 static void
-lkpi_pci_dev_fill_release(struct device *dev)
+lkpi_pci_dev_release_common(struct device *dev)
 {
 	struct pci_dev *pdev;
 
@@ -419,6 +402,11 @@ lkpi_pci_dev_fill_release(struct device *dev)
 	kfree(pdev->path_name);
 }
 
+/*
+ * This is the .release function for the bus attachments
+ * [linux_pci_attach_device()], called when the kobj reference drops to 0.
+ * Note well: there should be no direct calls of this.
+ */
 static void
 lkpi_pci_dev_release(struct device *dev)
 {
@@ -445,7 +433,7 @@ lkpi_pci_dev_release(struct device *dev)
 	 */
 
 	/* Clear the hierarchy recursively to root. */
-	lkpi_pci_dev_bus_release(pdev);
+	lkpi_pci_dev_release_common_bus(pdev);
 
 	LKPI_PCI_LOCK();
 	list_del(&pdev->links);
@@ -455,9 +443,9 @@ lkpi_pci_dev_release(struct device *dev)
 
 	/* irq? */
 
-	/* Undo lkpifill_pci_dev(). */
+	/* Undo lkpi_pci_dev_init_common(). */
 	/* devres is gone already; went at the very top. */
-	lkpi_pci_dev_fill_release(dev);
+	lkpi_pci_dev_release_common(dev);
 
 	/*
 	 * Lastly, apply an internal hack in order to signal
@@ -467,8 +455,32 @@ lkpi_pci_dev_release(struct device *dev)
 	pdev->dev.release = NULL;
 }
 
+/*
+ * This is the .release function for lkpinew_pci_dev(), called when the kobj
+ * reference drops to 0.
+ * Note well: there should be no direct calls of this.
+ */
+static void
+lkpinew_pci_dev_release(struct device *dev)
+{
+	struct pci_dev *pdev;
+
+	pdev = to_pci_dev(dev);
+
+	/* The root/bus structure could be built up w/o us having asked for it. */
+	lkpi_pci_dev_release_common_bus(pdev);
+	/* Cleanup the lkpi_pci_dev_init_common() resources. */
+	lkpi_pci_dev_release_common(dev);
+
+	free(pdev, M_DEVBUF);
+}
+
+/*
+ * Helper function to iniatlize most of the pdev, dev, .. parts.
+ * This is share by both pdev creation code paths (bus or function call).
+ */
 static int
-lkpifill_pci_dev(device_t dev, struct pci_dev *pdev)
+lkpi_pci_dev_init_common(device_t dev, struct pci_dev *pdev)
 {
 	struct pci_devinfo *dinfo;
 	int error;
@@ -511,7 +523,6 @@ lkpifill_pci_dev(device_t dev, struct pci_dev *pdev)
 	}
 	pdev->dev.bsddev = dev;
 	pdev->dev.parent = &linux_root_device;
-	pdev->dev.release = lkpi_pci_dev_release;
 
 	if (pci_msi_count(dev) > 0)
 		pdev->msi_desc = malloc(pci_msi_count(dev) *
@@ -528,24 +539,8 @@ lkpifill_pci_dev(device_t dev, struct pci_dev *pdev)
 }
 
 /*
- * This is the .release function called when the kobj reference drops to 0.
- * There should be no direct calls of this.
+ * LinuxKPI PCI dev (pdev) creation by function call.
  */
-static void
-lkpinew_pci_dev_release(struct device *dev)
-{
-	struct pci_dev *pdev;
-
-	pdev = to_pci_dev(dev);
-
-	/* The root/bus structure could be built up w/o us having asked for it. */
-	lkpi_pci_dev_bus_release(pdev);
-	/* Cleanup the lkpifill_pci_dev() resources. */
-	lkpi_pci_dev_fill_release(dev);
-
-	free(pdev, M_DEVBUF);
-}
-
 struct pci_dev *
 lkpinew_pci_dev(device_t dev)
 {
@@ -553,7 +548,7 @@ lkpinew_pci_dev(device_t dev)
 	int error;
 
 	pdev = malloc(sizeof(*pdev), M_DEVBUF, M_WAITOK|M_ZERO);
-	error = lkpifill_pci_dev(dev, pdev);
+	error = lkpi_pci_dev_init_common(dev, pdev);
 	if (error != 0) {
 		free(pdev, M_DEVBUF);
 		return (NULL);
@@ -628,76 +623,11 @@ lkpi_pci_get_slot(struct pci_bus *pbus, unsigned int devfn)
 	return (pdev);
 }
 
-static int
-linux_pci_probe(device_t dev)
-{
-	const struct pci_device_id *id;
-	struct pci_driver *pdrv;
-
-	if ((pdrv = linux_pci_find(dev, &id)) == NULL)
-		return (ENXIO);
-	if (device_get_driver(dev) != &pdrv->bsddriver)
-		return (ENXIO);
-	device_set_desc(dev, pdrv->name);
-
-	/* Assume BSS initialized (should never return BUS_PROBE_SPECIFIC). */
-	if (pdrv->bsd_probe_return == 0)
-		return (BUS_PROBE_DEFAULT);
-	else
-		return (pdrv->bsd_probe_return);
-}
-
-static int
-linux_pci_attach(device_t dev)
-{
-	const struct pci_device_id *id;
-	struct pci_driver *pdrv;
-	struct pci_dev *pdev;
-
-	pdrv = linux_pci_find(dev, &id);
-	pdev = device_get_softc(dev);
-
-	MPASS(pdrv != NULL);
-	MPASS(pdev != NULL);
-
-	return (linux_pci_attach_device(dev, pdrv, id, pdev));
-}
-
-static struct resource_list_entry *
-linux_pci_reserve_bar(struct pci_dev *pdev, struct resource_list *rl,
-    int type, int rid)
-{
-	device_t dev;
-	struct resource *res;
-
-	KASSERT(type == SYS_RES_IOPORT || type == SYS_RES_MEMORY,
-	    ("trying to reserve non-BAR type %d", type));
-
-	dev = pdev->pdrv != NULL && pdev->pdrv->isdrm ?
-	    device_get_parent(pdev->dev.bsddev) : pdev->dev.bsddev;
-	res = pci_reserve_map(device_get_parent(dev), dev, type, rid, 0, ~0,
-	    1, 1, 0);
-	if (res == NULL)
-		return (NULL);
-	return (resource_list_find(rl, type, rid));
-}
-
-static struct resource_list_entry *
-linux_pci_get_rle(struct pci_dev *pdev, int type, int rid, bool reserve_bar)
-{
-	struct pci_devinfo *dinfo;
-	struct resource_list *rl;
-	struct resource_list_entry *rle;
-
-	dinfo = device_get_ivars(pdev->dev.bsddev);
-	rl = &dinfo->resources;
-	rle = resource_list_find(rl, type, rid);
-	/* Reserve resources for this BAR if needed. */
-	if (rle == NULL && reserve_bar)
-		rle = linux_pci_reserve_bar(pdev, rl, type, rid);
-	return (rle);
-}
 
+/*
+ * LinuxKPI PCI dev (pdev) initialization/free from the BUS functions.
+ */
+/* Note well: this function is public and used by, e.g. nvidia-drm. */
 int
 linux_pci_attach_device(device_t dev, struct pci_driver *pdrv,
     const struct pci_device_id *id, struct pci_dev *pdev)
@@ -721,9 +651,10 @@ linux_pci_attach_device(device_t dev, struct pci_driver *pdrv,
 		device_set_ivars(dev, dinfo);
 	}
 
-	error = lkpifill_pci_dev(dev, pdev);
+	error = lkpi_pci_dev_init_common(dev, pdev);
 	if (error != 0)
 		return (error);
+	pdev->dev.release = lkpi_pci_dev_release;
 
 	if (isdrm)
 		PCI_GET_ID(device_get_parent(parent), parent, PCI_ID_RID, &rid);
@@ -731,7 +662,7 @@ linux_pci_attach_device(device_t dev, struct pci_driver *pdrv,
 		PCI_GET_ID(parent, dev, PCI_ID_RID, &rid);
 	pdev->devfn = rid;
 	pdev->pdrv = pdrv;
-	rle = linux_pci_get_rle(pdev, SYS_RES_IRQ, 0, false);
+	rle = lkpi_pci_get_rle(pdev, SYS_RES_IRQ, 0, false);
 	if (rle != NULL)
 		pdev->dev.irq = rle->start;
 	else
@@ -778,22 +709,7 @@ out_err:
 	return (-error);
 }
 
-static int
-linux_pci_detach(device_t dev)
-{
-	struct pci_dev *pdev;
-	int error;
-
-	pdev = device_get_softc(dev);
-	MPASS(pdev != NULL);
-
-	error = linux_pci_detach_device(pdev);
-	if (error == 0)
-		device_set_desc(dev, NULL);
-
-	return (error);
-}
-
+/* Note well: this function is public and used by, e.g. nvidia-drm. */
 int
 linux_pci_detach_device(struct pci_dev *pdev)
 {
@@ -804,7 +720,7 @@ linux_pci_detach_device(struct pci_dev *pdev)
 	 * We cannot do much here as almost everything will have
 	 * to happen as the last reference to the LinuxKPI device
 	 * goes away.  That will call the release function,
-	 * which lkpifill_pci_dev() set.  That is were most
+	 * which lkpi_pci_dev_init_common() set.  That is were most
 	 * of the cleanup will happen.  But before that give
 	 * the driver a chance to cleanup.
 	 * The big problem is that the Linux KPI does not
@@ -847,6 +763,9 @@ linux_pci_detach_device(struct pci_dev *pdev)
 	return (EBUSY);
 }
 
+/*
+ * Devres resource functions.
+ */
 static int
 lkpi_pci_disable_dev(struct device *dev)
 {
@@ -974,6 +893,15 @@ linuxkpi_pcim_iomap_table(struct pci_dev *pdev)
 	return (dr->mmio_table);
 }
 
+static bool
+lkpi_pci_bar_id_valid(int bar)
+{
+	if (bar < 0 || bar > PCIR_MAX_BAR_0)
+		return (false);
+
+	return (true);
+}
+
 static struct resource *
 _lkpi_pci_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen __unused)
 {
@@ -1045,6 +973,14 @@ linuxkpi_pci_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen)
 	return (linuxkpi_pci_iomap_range(pdev, bar, 0, maxlen));
 }
 
+static void
+lkpi_set_pcim_iomap_devres(struct pcim_iomap_devres *dr, int bar,
+    void *res)
+{
+	dr->mmio_table[bar] = (void *)rman_get_bushandle(res);
+	dr->res_table[bar] = res;
+}
+
 void *
 linuxkpi_pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen)
 {
@@ -1162,140 +1098,9 @@ lkpi_pcim_iomap_table_release(struct device *dev, void *p)
 	}
 }
 
-static int
-linux_pci_suspend(device_t dev)
-{
-	const struct dev_pm_ops *pmops;
-	struct pm_message pm = { };
-	struct pci_dev *pdev;
-	int error;
-
-	error = 0;
-	linux_set_current(curthread);
-	pdev = device_get_softc(dev);
-	pmops = pdev->pdrv->driver.pm;
-
-	if (pdev->pdrv->suspend != NULL)
-		error = -pdev->pdrv->suspend(pdev, pm);
-	else if (pmops != NULL && pmops->suspend != NULL) {
-		error = -pmops->suspend(&pdev->dev);
-		if (error == 0 && pmops->suspend_late != NULL)
-			error = -pmops->suspend_late(&pdev->dev);
-		if (error == 0 && pmops->suspend_noirq != NULL)
-			error = -pmops->suspend_noirq(&pdev->dev);
-	}
-	return (error);
-}
-
-static int
-linux_pci_resume(device_t dev)
-{
-	const struct dev_pm_ops *pmops;
-	struct pci_dev *pdev;
-	int error;
-
-	error = 0;
-	linux_set_current(curthread);
-	pdev = device_get_softc(dev);
-	pmops = pdev->pdrv->driver.pm;
-
-	if (pdev->pdrv->resume != NULL)
-		error = -pdev->pdrv->resume(pdev);
-	else if (pmops != NULL && pmops->resume != NULL) {
-		if (pmops->resume_early != NULL)
-			error = -pmops->resume_early(&pdev->dev);
-		if (error == 0 && pmops->resume != NULL)
-			error = -pmops->resume(&pdev->dev);
-	}
-	return (error);
-}
-
-static int
-linux_pci_shutdown(device_t dev)
-{
-	struct pci_dev *pdev;
-
-	linux_set_current(curthread);
-	pdev = device_get_softc(dev);
-	if (pdev->pdrv->shutdown != NULL)
-		pdev->pdrv->shutdown(pdev);
-	return (0);
-}
-
-static int
-linux_pci_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *pf_config)
-{
-	struct pci_dev *pdev;
-	int error;
-
-	linux_set_current(curthread);
-	pdev = device_get_softc(dev);
-	if (pdev->pdrv->bsd_iov_init != NULL)
-		error = pdev->pdrv->bsd_iov_init(dev, num_vfs, pf_config);
-	else
-		error = EINVAL;
-	return (error);
-}
-
-static void
-linux_pci_iov_uninit(device_t dev)
-{
-	struct pci_dev *pdev;
-
-	linux_set_current(curthread);
-	pdev = device_get_softc(dev);
-	if (pdev->pdrv->bsd_iov_uninit != NULL)
-		pdev->pdrv->bsd_iov_uninit(dev);
-}
-
-static int
-linux_pci_iov_add_vf(device_t dev, uint16_t vfnum, const nvlist_t *vf_config)
-{
-	struct pci_dev *pdev;
-	int error;
-
-	linux_set_current(curthread);
-	pdev = device_get_softc(dev);
-	if (pdev->pdrv->bsd_iov_add_vf != NULL)
-		error = pdev->pdrv->bsd_iov_add_vf(dev, vfnum, vf_config);
-	else
-		error = EINVAL;
-	return (error);
-}
-
-static int
-_linux_pci_register_driver(struct pci_driver *pdrv, devclass_t dc)
-{
-	int error;
-
-	linux_set_current(curthread);
-	LKPI_PCI_LOCK();
-	list_add(&pdrv->node, &lkpi_pci_drivers);
-	LKPI_PCI_UNLOCK();
-	if (pdrv->bsddriver.name == NULL)
-		pdrv->bsddriver.name = pdrv->name;
-	pdrv->bsddriver.methods = pci_methods;
-	pdrv->bsddriver.size = sizeof(struct pci_dev);
-
-	bus_topo_lock();
-	error = devclass_add_driver(dc, &pdrv->bsddriver,
-	    BUS_PASS_DEFAULT, &pdrv->bsdclass);
-	bus_topo_unlock();
-	return (-error);
-}
-
-int
-linux_pci_register_driver(struct pci_driver *pdrv)
-{
-	devclass_t dc;
-
-	pdrv->isdrm = strcmp(pdrv->name, "drmn") == 0;
-	dc = pdrv->isdrm ? devclass_create("vgapci") : devclass_find("pci");
-	if (dc == NULL)
-		return (-ENXIO);
-	return (_linux_pci_register_driver(pdrv, dc));
-}
-
+/*
+ * Resource functions.
+ */
 static struct resource_list_entry *
 lkpi_pci_get_bar(struct pci_dev *pdev, int bar, bool reserve)
 {
@@ -1305,7 +1110,7 @@ lkpi_pci_get_bar(struct pci_dev *pdev, int bar, bool reserve)
 	if (type < 0)
 		return (NULL);
 	bar = PCIR_BAR(bar);
-	return (linux_pci_get_rle(pdev, type, bar, reserve));
+	return (lkpi_pci_get_rle(pdev, type, bar, reserve));
 }
 
 struct device *
@@ -1489,57 +1294,15 @@ linuxkpi_pci_release_region(struct pci_dev *pdev, int bar)
 void
 linuxkpi_pci_release_regions(struct pci_dev *pdev)
 {
-	int i;
-
-	for (i = 0; i <= PCIR_MAX_BAR_0; i++)
-		pci_release_region(pdev, i);
-}
-
-int
-linux_pci_register_drm_driver(struct pci_driver *pdrv)
-{
-	devclass_t dc;
-
-	dc = devclass_create("vgapci");
-	if (dc == NULL)
-		return (-ENXIO);
-	pdrv->isdrm = true;
-	pdrv->name = "drmn";
-	return (_linux_pci_register_driver(pdrv, dc));
-}
-
-void
-linux_pci_unregister_driver(struct pci_driver *pdrv)
-{
-	devclass_t bus;
-
-	bus = devclass_find(pdrv->isdrm ? "vgapci" : "pci");
-
-	LKPI_PCI_LOCK();
-	list_del(&pdrv->node);
-	LKPI_PCI_UNLOCK();
-	bus_topo_lock();
-	if (bus != NULL)
-		devclass_delete_driver(bus, &pdrv->bsddriver);
-	bus_topo_unlock();
-}
-
-void
-linux_pci_unregister_drm_driver(struct pci_driver *pdrv)
-{
-	devclass_t bus;
-
-	bus = devclass_find("vgapci");
+	int i;
 
-	LKPI_PCI_LOCK();
-	list_del(&pdrv->node);
-	LKPI_PCI_UNLOCK();
-	bus_topo_lock();
-	if (bus != NULL)
-		devclass_delete_driver(bus, &pdrv->bsddriver);
-	bus_topo_unlock();
+	for (i = 0; i <= PCIR_MAX_BAR_0; i++)
+		pci_release_region(pdev, i);
 }
 
+/*
+ * MSI(-X) functions.
+ */
 int
 linuxkpi_pci_enable_msix(struct pci_dev *pdev, struct msix_entry *entries,
     int nreq)
@@ -1566,7 +1329,7 @@ linuxkpi_pci_enable_msix(struct pci_dev *pdev, struct msix_entry *entries,
 		pci_release_msi(pdev->dev.bsddev);
 		return avail;
 	}
-	rle = linux_pci_get_rle(pdev, SYS_RES_IRQ, 1, false);
+	rle = lkpi_pci_get_rle(pdev, SYS_RES_IRQ, 1, false);
 	pdev->dev.irq_start = rle->start;
 	pdev->dev.irq_end = rle->start + avail;
 	for (i = 0; i < nreq; i++)
@@ -1599,7 +1362,7 @@ _lkpi_pci_enable_msi_range(struct pci_dev *pdev, int minvec, int maxvec)
 		return (-ENOSPC);
 	}
 
-	rle = linux_pci_get_rle(pdev, SYS_RES_IRQ, 1, false);
+	rle = lkpi_pci_get_rle(pdev, SYS_RES_IRQ, 1, false);
 	pdev->dev.irq_start = rle->start;
 	pdev->dev.irq_end = rle->start + nvec;
 	pdev->irq = rle->start;
@@ -1726,6 +1489,248 @@ linuxkpi_pci_unmap_rom(struct pci_dev *pdev, void *rom)
 	vga_pci_unmap_bios(device_get_parent(dev), rom);
 }
 
+/*
+ * device_* bus functions for PCI.
+ */
+static int
+lkpi_pci_probe(device_t dev)
+{
+	const struct pci_device_id *id;
+	struct pci_driver *pdrv;
+
+	if ((pdrv = linux_pci_find(dev, &id)) == NULL)
+		return (ENXIO);
+	if (device_get_driver(dev) != &pdrv->bsddriver)
+		return (ENXIO);
+	device_set_desc(dev, pdrv->name);
+
+	/* Assume BSS initialized (should never return BUS_PROBE_SPECIFIC). */
+	if (pdrv->bsd_probe_return == 0)
+		return (BUS_PROBE_DEFAULT);
+	else
+		return (pdrv->bsd_probe_return);
+}
+
+static int
+lkpi_pci_attach(device_t dev)
+{
+	const struct pci_device_id *id;
+	struct pci_driver *pdrv;
+	struct pci_dev *pdev;
+
+	pdrv = linux_pci_find(dev, &id);
+	pdev = device_get_softc(dev);
+
+	MPASS(pdrv != NULL);
+	MPASS(pdev != NULL);
+
+	return (linux_pci_attach_device(dev, pdrv, id, pdev));
+}
+
+static int
+lkpi_pci_detach(device_t dev)
+{
+	struct pci_dev *pdev;
+	int error;
+
+	pdev = device_get_softc(dev);
+	MPASS(pdev != NULL);
+
+	error = linux_pci_detach_device(pdev);
+	if (error == 0)
+		device_set_desc(dev, NULL);
+
+	return (error);
+}
+
+static int
+lkpi_pci_suspend(device_t dev)
+{
+	const struct dev_pm_ops *pmops;
+	struct pm_message pm = { };
+	struct pci_dev *pdev;
+	int error;
+
+	error = 0;
+	linux_set_current(curthread);
+	pdev = device_get_softc(dev);
+	pmops = pdev->pdrv->driver.pm;
+
+	if (pdev->pdrv->suspend != NULL)
+		error = -pdev->pdrv->suspend(pdev, pm);
+	else if (pmops != NULL && pmops->suspend != NULL) {
+		error = -pmops->suspend(&pdev->dev);
+		if (error == 0 && pmops->suspend_late != NULL)
+			error = -pmops->suspend_late(&pdev->dev);
+		if (error == 0 && pmops->suspend_noirq != NULL)
+			error = -pmops->suspend_noirq(&pdev->dev);
+	}
+	return (error);
+}
+
+static int
+lkpi_pci_resume(device_t dev)
+{
+	const struct dev_pm_ops *pmops;
+	struct pci_dev *pdev;
+	int error;
+
+	error = 0;
+	linux_set_current(curthread);
+	pdev = device_get_softc(dev);
+	pmops = pdev->pdrv->driver.pm;
+
+	if (pdev->pdrv->resume != NULL)
+		error = -pdev->pdrv->resume(pdev);
+	else if (pmops != NULL && pmops->resume != NULL) {
+		if (pmops->resume_early != NULL)
+			error = -pmops->resume_early(&pdev->dev);
+		if (error == 0 && pmops->resume != NULL)
+			error = -pmops->resume(&pdev->dev);
+	}
+	return (error);
+}
+
+static int
+lkpi_pci_shutdown(device_t dev)
+{
+	struct pci_dev *pdev;
+
+	linux_set_current(curthread);
+	pdev = device_get_softc(dev);
+	if (pdev->pdrv->shutdown != NULL)
+		pdev->pdrv->shutdown(pdev);
+	return (0);
+}
+
+/*
+ * PCI IOV bus functions.
+ */
+static int
+lkpi_pci_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *pf_config)
+{
+	struct pci_dev *pdev;
+	int error;
+
+	linux_set_current(curthread);
+	pdev = device_get_softc(dev);
+	if (pdev->pdrv->bsd_iov_init != NULL)
+		error = pdev->pdrv->bsd_iov_init(dev, num_vfs, pf_config);
+	else
+		error = EINVAL;
+	return (error);
+}
+
+static void
+lkpi_pci_iov_uninit(device_t dev)
+{
+	struct pci_dev *pdev;
+
+	linux_set_current(curthread);
+	pdev = device_get_softc(dev);
+	if (pdev->pdrv->bsd_iov_uninit != NULL)
+		pdev->pdrv->bsd_iov_uninit(dev);
+}
+
+static int
+lkpi_pci_iov_add_vf(device_t dev, uint16_t vfnum, const nvlist_t *vf_config)
+{
+	struct pci_dev *pdev;
+	int error;
+
+	linux_set_current(curthread);
+	pdev = device_get_softc(dev);
+	if (pdev->pdrv->bsd_iov_add_vf != NULL)
+		error = pdev->pdrv->bsd_iov_add_vf(dev, vfnum, vf_config);
+	else
+		error = EINVAL;
+	return (error);
+}
+
+/*
+ * LinuxKPI driver (un)registration.
+ */
+static int
+lkpi_pci_register_driver(struct pci_driver *pdrv, devclass_t dc)
+{
+	int error;
+
+	linux_set_current(curthread);
+	LKPI_PCI_LOCK();
+	list_add(&pdrv->node, &lkpi_pci_drivers);
+	LKPI_PCI_UNLOCK();
+	if (pdrv->bsddriver.name == NULL)
+		pdrv->bsddriver.name = pdrv->name;
+	pdrv->bsddriver.methods = pci_methods;
+	pdrv->bsddriver.size = sizeof(struct pci_dev);
+
+	bus_topo_lock();
+	error = devclass_add_driver(dc, &pdrv->bsddriver,
+	    BUS_PASS_DEFAULT, &pdrv->bsdclass);
+	bus_topo_unlock();
+	return (-error);
+}
+
+int
+linux_pci_register_driver(struct pci_driver *pdrv)
+{
+	devclass_t dc;
+
+	pdrv->isdrm = strcmp(pdrv->name, "drmn") == 0;
+	dc = pdrv->isdrm ? devclass_create("vgapci") : devclass_find("pci");
+	if (dc == NULL)
+		return (-ENXIO);
+	return (lkpi_pci_register_driver(pdrv, dc));
+}
+
+int
+linux_pci_register_drm_driver(struct pci_driver *pdrv)
+{
+	devclass_t dc;
+
+	dc = devclass_create("vgapci");
+	if (dc == NULL)
+		return (-ENXIO);
+	pdrv->isdrm = true;
+	pdrv->name = "drmn";
+	return (lkpi_pci_register_driver(pdrv, dc));
+}
+
+void
+linux_pci_unregister_driver(struct pci_driver *pdrv)
+{
+	devclass_t bus;
+
+	bus = devclass_find(pdrv->isdrm ? "vgapci" : "pci");
+
+	LKPI_PCI_LOCK();
+	list_del(&pdrv->node);
+	LKPI_PCI_UNLOCK();
+	bus_topo_lock();
+	if (bus != NULL)
+		devclass_delete_driver(bus, &pdrv->bsddriver);
+	bus_topo_unlock();
+}
+
+void
+linux_pci_unregister_drm_driver(struct pci_driver *pdrv)
+{
+	devclass_t bus;
+
+	bus = devclass_find("vgapci");
+
+	LKPI_PCI_LOCK();
+	list_del(&pdrv->node);
+	LKPI_PCI_UNLOCK();
+	bus_topo_lock();
+	if (bus != NULL)
+		devclass_delete_driver(bus, &pdrv->bsddriver);
+	bus_topo_unlock();
+}
+
+/*
+ * PCI SYSINIT.
+ */
 static void
 lkpi_pci_init(void *arg __unused)
 {
@@ -1745,57 +1750,61 @@ SYSUNINIT(lkpi_pci_uninit, SI_SUB_DRIVERS, SI_ORDER_SECOND, lkpi_pci_uninit, NUL
 /* -------------------------------------------------------------------------- */
 /* DMA */
 
+static counter_u64_t lkpi_pci_nseg1_fail;
+SYSCTL_COUNTER_U64(_compat_linuxkpi, OID_AUTO, lkpi_pci_nseg1_fail, CTLFLAG_RD,
+    &lkpi_pci_nseg1_fail, "Count of busdma mapping failures of single-segment");
+
 CTASSERT(sizeof(dma_addr_t) <= sizeof(uint64_t));
 
-struct linux_dma_obj {
+struct lkpi_dma_obj {
 	void		*vaddr;
 	uint64_t	dma_addr;
 	bus_dmamap_t	dmamap;
 	bus_dma_tag_t	dmat;
 };
*** 262 LINES SKIPPED ***