From 5c221064ba549e195663a6d9b809e4ee0b6fedd6 Mon Sep 17 00:00:00 2001 From: markj Date: Fri, 11 Aug 2017 03:59:48 +0000 Subject: [PATCH] Add a specialized function for DRM drivers to register themselves. Such drivers attach to a vgapci bus rather than directly to a pci bus. For the rest of the LinuxKPI to work correctly in this case, we override the vgapci bus' ivars with those of the grandparent. Reviewed by: hselasky MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D11932 --- .../linuxkpi/common/include/linux/pci.h | 15 ++++- sys/compat/linuxkpi/common/src/linux_pci.c | 65 +++++++++++++++---- 2 files changed, 65 insertions(+), 15 deletions(-) diff --git a/sys/compat/linuxkpi/common/include/linux/pci.h b/sys/compat/linuxkpi/common/include/linux/pci.h index 0917c66f2ab..70e62b0a7db 100644 --- a/sys/compat/linuxkpi/common/include/linux/pci.h +++ b/sys/compat/linuxkpi/common/include/linux/pci.h @@ -187,6 +187,12 @@ struct pci_driver { devclass_t bsdclass; struct device_driver driver; const struct pci_error_handlers *err_handler; + bool isdrm; +}; + +struct pci_bus { + struct pci_dev *self; + int number; }; extern struct list_head pci_drivers; @@ -199,6 +205,7 @@ struct pci_dev { struct device dev; struct list_head links; struct pci_driver *pdrv; + struct pci_bus *bus; uint64_t dma_mask; uint16_t device; uint16_t vendor; @@ -502,8 +509,12 @@ pci_write_config_dword(struct pci_dev *pdev, int where, u32 val) return (0); } -extern int pci_register_driver(struct pci_driver *pdrv); -extern void pci_unregister_driver(struct pci_driver *pdrv); +int linux_pci_register_driver(struct pci_driver *pdrv); +int linux_pci_register_drm_driver(struct pci_driver *pdrv); +void linux_pci_unregister_driver(struct pci_driver *pdrv); + +#define pci_register_driver(pdrv) linux_pci_register_driver(pdrv) +#define pci_unregister_driver(pdrv) linux_pci_unregister_driver(pdrv) struct msix_entry { int entry; diff --git a/sys/compat/linuxkpi/common/src/linux_pci.c b/sys/compat/linuxkpi/common/src/linux_pci.c index 9756644f291..9220a2d9040 100644 --- a/sys/compat/linuxkpi/common/src/linux_pci.c +++ b/sys/compat/linuxkpi/common/src/linux_pci.c @@ -118,17 +118,29 @@ static int linux_pci_attach(device_t dev) { 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; + devclass_t devclass; int error; - dinfo = device_get_ivars(dev); - linux_set_current(curthread); + pdrv = linux_pci_find(dev, &id); pdev = device_get_softc(dev); + + parent = device_get_parent(dev); + devclass = device_get_devclass(parent); + if (pdrv->isdrm) { + dinfo = device_get_ivars(parent); + device_set_ivars(dev, dinfo); + } else { + dinfo = device_get_ivars(dev); + } + pdev->dev.parent = &linux_root_device; pdev->dev.bsddev = dev; INIT_LIST_HEAD(&pdev->dev.irqents); @@ -151,6 +163,13 @@ linux_pci_attach(device_t dev) else pdev->dev.irq = LINUX_IRQ_INVALID; pdev->irq = pdev->dev.irq; + + if (pdev->bus == NULL) { + pbus = malloc(sizeof(*pbus), M_DEVBUF, M_WAITOK | M_ZERO); + pbus->self = pdev; + pdev->bus = pbus; + } + DROP_GIANT(); spin_lock(&pci_lock); list_add(&pdev->links, &pci_devices); @@ -246,13 +265,10 @@ linux_pci_shutdown(device_t dev) return (0); } -int -pci_register_driver(struct pci_driver *pdrv) +static int +_linux_pci_register_driver(struct pci_driver *pdrv, devclass_t dc) { - devclass_t bus; - int error = 0; - - bus = devclass_find("pci"); + int error; linux_set_current(curthread); spin_lock(&pci_lock); @@ -263,16 +279,39 @@ pci_register_driver(struct pci_driver *pdrv) pdrv->bsddriver.size = sizeof(struct pci_dev); mtx_lock(&Giant); - if (bus != NULL) { - error = devclass_add_driver(bus, &pdrv->bsddriver, - BUS_PASS_DEFAULT, &pdrv->bsdclass); - } + error = devclass_add_driver(dc, &pdrv->bsddriver, + BUS_PASS_DEFAULT, &pdrv->bsdclass); mtx_unlock(&Giant); return (-error); } +int +linux_pci_register_driver(struct pci_driver *pdrv) +{ + devclass_t dc; + + dc = devclass_find("pci"); + if (dc == NULL) + return (-ENXIO); + pdrv->isdrm = false; + return (_linux_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 (_linux_pci_register_driver(pdrv, dc)); +} + void -pci_unregister_driver(struct pci_driver *pdrv) +linux_pci_unregister_driver(struct pci_driver *pdrv) { devclass_t bus; -- 2.45.0