git: 2f9064a5d2b5 - main - LinuxKPI: pci: implement pcim_iomap()

From: Bjoern A. Zeeb <bz_at_FreeBSD.org>
Date: Fri, 05 Sep 2025 23:28:55 UTC
The branch main has been updated by bz:

URL: https://cgit.FreeBSD.org/src/commit/?id=2f9064a5d2b50f292cc8699d2be5c66c317f1dc7

commit 2f9064a5d2b50f292cc8699d2be5c66c317f1dc7
Author:     Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2025-07-31 17:45:26 +0000
Commit:     Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2025-09-05 23:24:13 +0000

    LinuxKPI: pci: implement pcim_iomap()
    
    Like pci_iomap() add the devres version pcim_iomap() using the former
    to get the resource.
    
    Add a helper function to validate that the bar is within a valid range
    and sprinkle that check also to other related functions.
    
    Sponsored by:   The FreeBSD Foundation (intially)
    MFC after:      3 days
    Reviewed by:    dumbbell
    Differential Revision:  https://reviews.freebsd.org/D52067
---
 sys/compat/linuxkpi/common/include/linux/pci.h |  3 ++
 sys/compat/linuxkpi/common/src/linux_pci.c     | 58 +++++++++++++++++++++++++-
 2 files changed, 59 insertions(+), 2 deletions(-)

diff --git a/sys/compat/linuxkpi/common/include/linux/pci.h b/sys/compat/linuxkpi/common/include/linux/pci.h
index df29af87f160..49d2cd79d474 100644
--- a/sys/compat/linuxkpi/common/include/linux/pci.h
+++ b/sys/compat/linuxkpi/common/include/linux/pci.h
@@ -365,6 +365,7 @@ void __iomem **linuxkpi_pcim_iomap_table(struct pci_dev *pdev);
 void *linuxkpi_pci_iomap_range(struct pci_dev *, int,
     unsigned long, unsigned long);
 void *linuxkpi_pci_iomap(struct pci_dev *, int, unsigned long);
+void *linuxkpi_pcim_iomap(struct pci_dev *, int, unsigned long);
 void linuxkpi_pci_iounmap(struct pci_dev *pdev, void *res);
 int linuxkpi_pcim_iomap_regions(struct pci_dev *pdev, uint32_t mask,
     const char *name);
@@ -803,6 +804,8 @@ static inline void pci_disable_sriov(struct pci_dev *dev)
     linuxkpi_pci_iomap_range(pdev, mmio_bar, mmio_off, mmio_size)
 #define	pci_iomap(pdev, mmio_bar, mmio_size)				\
     linuxkpi_pci_iomap(pdev, mmio_bar, mmio_size)
+#define	pcim_iomap(pdev, bar, maxlen)					\
+    linuxkpi_pcim_iomap(pdev, bar, maxlen)
 #define	pci_iounmap(pdev, res)						\
     linuxkpi_pci_iounmap(pdev, res)
 
diff --git a/sys/compat/linuxkpi/common/src/linux_pci.c b/sys/compat/linuxkpi/common/src/linux_pci.c
index 00d4a25e86ed..44024e495bb2 100644
--- a/sys/compat/linuxkpi/common/src/linux_pci.c
+++ b/sys/compat/linuxkpi/common/src/linux_pci.c
@@ -145,6 +145,23 @@ 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)
+{
+	dr->mmio_table[bar] = (void *)rman_get_bushandle(res);
+	dr->res_table[bar] = res;
+}
+
+static bool
+lkpi_pci_bar_id_valid(int bar)
+{
+	if (bar < 0 || bar > PCIR_MAX_BAR_0)
+		return (false);
+
+	return (true);
+}
+
 static int
 linux_pdev_dma_uninit(struct pci_dev *pdev)
 {
@@ -763,6 +780,9 @@ _lkpi_pci_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen __unused)
 	struct pci_mmio_region *mmio, *p;
 	int type;
 
+	if (!lkpi_pci_bar_id_valid(bar))
+		return (NULL);
+
 	type = pci_resource_type(pdev, bar);
 	if (type < 0) {
 		device_printf(pdev->dev.bsddev, "%s: bar %d type %d\n",
@@ -803,6 +823,9 @@ linuxkpi_pci_iomap_range(struct pci_dev *pdev, int bar,
 {
 	struct resource *res;
 
+	if (!lkpi_pci_bar_id_valid(bar))
+		return (NULL);
+
 	res = _lkpi_pci_iomap(pdev, bar, maxlen);
 	if (res == NULL)
 		return (NULL);
@@ -816,9 +839,41 @@ linuxkpi_pci_iomap_range(struct pci_dev *pdev, int bar,
 void *
 linuxkpi_pci_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen)
 {
+	if (!lkpi_pci_bar_id_valid(bar))
+		return (NULL);
+
 	return (linuxkpi_pci_iomap_range(pdev, bar, 0, maxlen));
 }
 
+void *
+linuxkpi_pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen)
+{
+	struct pcim_iomap_devres *dr;
+	void *res;
+
+	if (!lkpi_pci_bar_id_valid(bar))
+		return (NULL);
+
+	dr = lkpi_pcim_iomap_devres_find(pdev);
+	if (dr == NULL)
+		return (NULL);
+
+	if (dr->res_table[bar] != NULL)
+		return (dr->res_table[bar]);
+
+	res = linuxkpi_pci_iomap(pdev, bar, maxlen);
+	if (res == NULL) {
+		/*
+		 * Do not free the devres in case there were
+		 * other valid mappings before already.
+		 */
+		return (NULL);
+	}
+	lkpi_set_pcim_iomap_devres(dr, bar, res);
+
+	return (res);
+}
+
 void
 linuxkpi_pci_iounmap(struct pci_dev *pdev, void *res)
 {
@@ -870,8 +925,7 @@ linuxkpi_pcim_iomap_regions(struct pci_dev *pdev, uint32_t mask, const char *nam
 		res = _lkpi_pci_iomap(pdev, bar, 0);
 		if (res == NULL)
 			goto err;
-		dr->mmio_table[bar] = (void *)rman_get_bushandle(res);
-		dr->res_table[bar] = res;
+		lkpi_set_pcim_iomap_devres(dr, bar, res);
 
 		mappings |= (1 << bar);
 	}