Skip site navigation (1)Skip section navigation (2)
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>