Date: Sun, 24 Oct 2021 18:54:07 GMT From: Jessica Clarke <jrtc27@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org Subject: git: fa82e6a10305 - stable/13 - LinuxKPI: Support lazy BAR allocation Message-ID: <202110241854.19OIs7ux080978@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch stable/13 has been updated by jrtc27: URL: https://cgit.FreeBSD.org/src/commit/?id=fa82e6a103050299629e62c2289e31946734c277 commit fa82e6a103050299629e62c2289e31946734c277 Author: Jessica Clarke <jrtc27@FreeBSD.org> AuthorDate: 2021-10-17 14:32:35 +0000 Commit: Jessica Clarke <jrtc27@FreeBSD.org> CommitDate: 2021-10-24 18:51:15 +0000 LinuxKPI: Support lazy BAR allocation Linux KPIs like pci_resource_start/len assume that BARs have been allocated, but FreeBSD lazily allocates BARs if it cannot allocate the firmware-allocated BARs. Thus using the Linux KPIs must force allocation of the BARs rather than returning 0 for the start and length, which can crash drm-kmod drivers that assume the BARs are valid. This is needed for the AMDGPU driver to be able to attach on SiFive's HiFive Unmatched. Reviewed by: hselasky, jhb, mav MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D32447 (cherry picked from commit 82098c8bb5b303c7c8b48e7537fadfe74b375bd3) --- sys/compat/linuxkpi/common/include/linux/pci.h | 22 +++++++++++++++------- sys/compat/linuxkpi/common/src/linux_pci.c | 25 ++++++++++++++++++++++--- sys/dev/pci/pci.c | 2 +- sys/dev/pci/pci_private.h | 4 ++++ 4 files changed, 42 insertions(+), 11 deletions(-) diff --git a/sys/compat/linuxkpi/common/include/linux/pci.h b/sys/compat/linuxkpi/common/include/linux/pci.h index 1ec7fe75388d..5b3c7c292921 100644 --- a/sys/compat/linuxkpi/common/include/linux/pci.h +++ b/sys/compat/linuxkpi/common/include/linux/pci.h @@ -292,19 +292,27 @@ pci_resource_type(struct pci_dev *pdev, int bar) return (SYS_RES_MEMORY); } +struct resource_list_entry *linux_pci_reserve_bar(struct pci_dev *pdev, + struct resource_list *rl, int type, int rid); + static inline struct resource_list_entry * -linux_pci_get_rle(struct pci_dev *pdev, int type, int rid) +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; - return resource_list_find(rl, type, rid); + 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); } static inline struct resource_list_entry * -linux_pci_get_bar(struct pci_dev *pdev, int bar) +linux_pci_get_bar(struct pci_dev *pdev, int bar, bool reserve) { int type; @@ -312,7 +320,7 @@ linux_pci_get_bar(struct pci_dev *pdev, int bar) if (type < 0) return (NULL); bar = PCIR_BAR(bar); - return (linux_pci_get_rle(pdev, type, bar)); + return (linux_pci_get_rle(pdev, type, bar, reserve)); } static inline struct device * @@ -502,7 +510,7 @@ pci_release_region(struct pci_dev *pdev, int bar) struct pci_devres *dr; struct pci_mmio_region *mmio, *p; - if ((rle = linux_pci_get_bar(pdev, bar)) == NULL) + if ((rle = linux_pci_get_bar(pdev, bar, false)) == NULL) return; /* @@ -760,7 +768,7 @@ pci_enable_msix(struct pci_dev *pdev, struct msix_entry *entries, int nreq) pci_release_msi(pdev->dev.bsddev); return avail; } - rle = linux_pci_get_rle(pdev, SYS_RES_IRQ, 1); + rle = linux_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++) @@ -813,7 +821,7 @@ pci_enable_msi(struct pci_dev *pdev) if ((error = -pci_alloc_msi(pdev->dev.bsddev, &avail)) != 0) return error; - rle = linux_pci_get_rle(pdev, SYS_RES_IRQ, 1); + rle = linux_pci_get_rle(pdev, SYS_RES_IRQ, 1, false); pdev->dev.irq_start = rle->start; pdev->dev.irq_end = rle->start + avail; pdev->irq = rle->start; diff --git a/sys/compat/linuxkpi/common/src/linux_pci.c b/sys/compat/linuxkpi/common/src/linux_pci.c index b5bb87b5f2ae..c8f473205ede 100644 --- a/sys/compat/linuxkpi/common/src/linux_pci.c +++ b/sys/compat/linuxkpi/common/src/linux_pci.c @@ -368,7 +368,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); + rle = linux_pci_get_rle(pdev, SYS_RES_IRQ, 0, false); if (rle != NULL) pdev->dev.irq = rle->start; else @@ -624,6 +624,25 @@ linux_pci_register_driver(struct pci_driver *pdrv) return (_linux_pci_register_driver(pdrv, dc)); } +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)); +} + unsigned long pci_resource_start(struct pci_dev *pdev, int bar) { @@ -631,7 +650,7 @@ pci_resource_start(struct pci_dev *pdev, int bar) rman_res_t newstart; device_t dev; - if ((rle = linux_pci_get_bar(pdev, bar)) == NULL) + if ((rle = linux_pci_get_bar(pdev, bar, true)) == NULL) return (0); dev = pdev->pdrv != NULL && pdev->pdrv->isdrm ? device_get_parent(pdev->dev.bsddev) : pdev->dev.bsddev; @@ -648,7 +667,7 @@ pci_resource_len(struct pci_dev *pdev, int bar) { struct resource_list_entry *rle; - if ((rle = linux_pci_get_bar(pdev, bar)) == NULL) + if ((rle = linux_pci_get_bar(pdev, bar, true)) == NULL) return (0); return (rle->count); } diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index ef138e926b6f..530526adb7b3 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -5364,7 +5364,7 @@ DB_SHOW_COMMAND(pciregs, db_pci_dump) } #endif /* DDB */ -static struct resource * +struct resource * pci_reserve_map(device_t dev, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int num, u_int flags) diff --git a/sys/dev/pci/pci_private.h b/sys/dev/pci/pci_private.h index d891f592bdbd..fec5db2e4ad5 100644 --- a/sys/dev/pci/pci_private.h +++ b/sys/dev/pci/pci_private.h @@ -163,6 +163,10 @@ void pci_read_bar(device_t dev, int reg, pci_addr_t *mapp, struct pci_map *pci_add_bar(device_t dev, int reg, pci_addr_t value, pci_addr_t size); +struct resource *pci_reserve_map(device_t dev, device_t child, int type, + int *rid, rman_res_t start, rman_res_t end, + rman_res_t count, u_int num, u_int flags); + struct resource *pci_alloc_multi_resource(device_t dev, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_long num, u_int flags);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202110241854.19OIs7ux080978>