* [PATCH v3 1/5] lib/pci_iomap.c: fix cleanup bugs in pci_iounmap()
2023-12-04 12:38 [PATCH v3 0/5] Regather scattered PCI-Code Philipp Stanner
@ 2023-12-04 12:38 ` Philipp Stanner
2023-12-04 13:35 ` Arnd Bergmann
2023-12-04 12:38 ` [PATCH v3 2/5] lib: move pci_iomap.c to drivers/pci/ Philipp Stanner
` (3 subsequent siblings)
4 siblings, 1 reply; 16+ messages in thread
From: Philipp Stanner @ 2023-12-04 12:38 UTC (permalink / raw)
To: Bjorn Helgaas, Arnd Bergmann, Hanjun Guo, NeilBrown,
Kent Overstreet, Jakub Kicinski, Niklas Schnelle,
Uladzislau Koshchanka, John Sanpe, Dave Jiang, Philipp Stanner,
Masami Hiramatsu (Google), Kees Cook, David Gow, Herbert Xu,
Shuah Khan, wuqiang.matt, Yury Norov, Jason Baron, Andrew Morton,
Ben Dooks, dakr
Cc: linux-kernel, linux-pci, linux-arch, stable, Arnd Bergmann
pci_iounmap() in lib/pci_iomap.c is supposed to check whether an address
is within ioport-range IF the config specifies that ioports exist. If
so, the port should be unmapped with ioport_unmap(). If not, it's a
generic MMIO address that has to be passed to iounmap().
The bugs are:
1. ioport_unmap() is missing entirely, so this function will never
actually unmap a port.
2. the #ifdef for the ioport-ranges accidentally also guards
iounmap(), potentially compiling an empty function. This would
cause the mapping to be leaked.
Implement the missing call to ioport_unmap().
Move the guard so that iounmap() will always be part of the function.
CC: <stable@vger.kernel.org> # v5.15+
Fixes: 316e8d79a095 ("pci_iounmap'2: Electric Boogaloo: try to make sense of it all")
Reported-by: Danilo Krummrich <dakr@redhat.com>
Suggested-by: Arnd Bergmann <arnd@kernel.org>
Signed-off-by: Philipp Stanner <pstanner@redhat.com>
---
In case someone wants to look into that and provide patches for kernels
older than v5.15:
Note that this patch only applies to v5.15+ – the leaks, however, are
older. I went through the log briefly and it seems f5810e5c32923 already
contains them in asm-generic/io.h.
---
lib/pci_iomap.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/lib/pci_iomap.c b/lib/pci_iomap.c
index ce39ce9f3526..6e144b017c48 100644
--- a/lib/pci_iomap.c
+++ b/lib/pci_iomap.c
@@ -168,10 +168,12 @@ void pci_iounmap(struct pci_dev *dev, void __iomem *p)
uintptr_t start = (uintptr_t) PCI_IOBASE;
uintptr_t addr = (uintptr_t) p;
- if (addr >= start && addr < start + IO_SPACE_LIMIT)
+ if (addr >= start && addr < start + IO_SPACE_LIMIT) {
+ ioport_unmap(p);
return;
- iounmap(p);
+ }
#endif
+ iounmap(p);
}
EXPORT_SYMBOL(pci_iounmap);
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH v3 1/5] lib/pci_iomap.c: fix cleanup bugs in pci_iounmap()
2023-12-04 12:38 ` [PATCH v3 1/5] lib/pci_iomap.c: fix cleanup bugs in pci_iounmap() Philipp Stanner
@ 2023-12-04 13:35 ` Arnd Bergmann
0 siblings, 0 replies; 16+ messages in thread
From: Arnd Bergmann @ 2023-12-04 13:35 UTC (permalink / raw)
To: Philipp Stanner, Bjorn Helgaas, Hanjun Guo, Neil Brown,
Kent Overstreet, Jakub Kicinski, Niklas Schnelle,
Uladzislau Koshchanka, John Sanpe, Dave Jiang, Masami Hiramatsu,
Kees Cook, David Gow, Herbert Xu, Shuah Khan, wuqiang.matt,
Yury Norov, Jason Baron, Andrew Morton, Ben Dooks,
Danilo Krummrich
Cc: linux-kernel, linux-pci, Linux-Arch, stable, Arnd Bergmann
On Mon, Dec 4, 2023, at 13:38, Philipp Stanner wrote:
> pci_iounmap() in lib/pci_iomap.c is supposed to check whether an address
> is within ioport-range IF the config specifies that ioports exist. If
> so, the port should be unmapped with ioport_unmap(). If not, it's a
> generic MMIO address that has to be passed to iounmap().
>
> The bugs are:
> 1. ioport_unmap() is missing entirely, so this function will never
> actually unmap a port.
> 2. the #ifdef for the ioport-ranges accidentally also guards
> iounmap(), potentially compiling an empty function. This would
> cause the mapping to be leaked.
>
> Implement the missing call to ioport_unmap().
>
> Move the guard so that iounmap() will always be part of the function.
>
> CC: <stable@vger.kernel.org> # v5.15+
> Fixes: 316e8d79a095 ("pci_iounmap'2: Electric Boogaloo: try to make
> sense of it all")
> Reported-by: Danilo Krummrich <dakr@redhat.com>
> Suggested-by: Arnd Bergmann <arnd@kernel.org>
> Signed-off-by: Philipp Stanner <pstanner@redhat.com>
> ---
> In case someone wants to look into that and provide patches for kernels
> older than v5.15:
> Note that this patch only applies to v5.15+ – the leaks, however, are
> older. I went through the log briefly and it seems f5810e5c32923 already
> contains them in asm-generic/io.h.
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v3 2/5] lib: move pci_iomap.c to drivers/pci/
2023-12-04 12:38 [PATCH v3 0/5] Regather scattered PCI-Code Philipp Stanner
2023-12-04 12:38 ` [PATCH v3 1/5] lib/pci_iomap.c: fix cleanup bugs in pci_iounmap() Philipp Stanner
@ 2023-12-04 12:38 ` Philipp Stanner
2023-12-04 13:37 ` Arnd Bergmann
2023-12-04 12:38 ` [PATCH v3 3/5] lib: move pci-specific devres code " Philipp Stanner
` (2 subsequent siblings)
4 siblings, 1 reply; 16+ messages in thread
From: Philipp Stanner @ 2023-12-04 12:38 UTC (permalink / raw)
To: Bjorn Helgaas, Arnd Bergmann, Hanjun Guo, NeilBrown,
Kent Overstreet, Jakub Kicinski, Niklas Schnelle,
Uladzislau Koshchanka, John Sanpe, Dave Jiang, Philipp Stanner,
Masami Hiramatsu (Google), Kees Cook, David Gow, Herbert Xu,
Shuah Khan, wuqiang.matt, Yury Norov, Jason Baron, Andrew Morton,
Ben Dooks, dakr
Cc: linux-kernel, linux-pci, linux-arch, stable
This file is guarded by an #ifdef CONFIG_PCI. It, consequently, does not
belong to lib/ because it is not generic infrastructure.
Move the file to drivers/pci/ and implement the necessary changes to
Makefiles and Kconfigs.
Suggested-by: Danilo Krummrich <dakr@redhat.com>
Signed-off-by: Philipp Stanner <pstanner@redhat.com>
---
drivers/pci/Kconfig | 5 +++++
drivers/pci/Makefile | 1 +
lib/pci_iomap.c => drivers/pci/iomap.c | 3 ---
lib/Kconfig | 3 ---
lib/Makefile | 1 -
5 files changed, 6 insertions(+), 7 deletions(-)
rename lib/pci_iomap.c => drivers/pci/iomap.c (99%)
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 74147262625b..d35001589d88 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -13,6 +13,11 @@ config FORCE_PCI
select HAVE_PCI
select PCI
+# select this to provide a generic PCI iomap,
+# without PCI itself having to be defined
+config GENERIC_PCI_IOMAP
+ bool
+
menuconfig PCI
bool "PCI support"
depends on HAVE_PCI
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index cc8b4e01e29d..64dcedccfc87 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -14,6 +14,7 @@ ifdef CONFIG_PCI
obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_SYSFS) += slot.o
obj-$(CONFIG_ACPI) += pci-acpi.o
+obj-$(CONFIG_GENERIC_PCI_IOMAP) += iomap.o
endif
obj-$(CONFIG_OF) += of.o
diff --git a/lib/pci_iomap.c b/drivers/pci/iomap.c
similarity index 99%
rename from lib/pci_iomap.c
rename to drivers/pci/iomap.c
index 6e144b017c48..91285fcff1ba 100644
--- a/lib/pci_iomap.c
+++ b/drivers/pci/iomap.c
@@ -9,7 +9,6 @@
#include <linux/export.h>
-#ifdef CONFIG_PCI
/**
* pci_iomap_range - create a virtual mapping cookie for a PCI BAR
* @dev: PCI device that owns the BAR
@@ -178,5 +177,3 @@ void pci_iounmap(struct pci_dev *dev, void __iomem *p)
EXPORT_SYMBOL(pci_iounmap);
#endif /* ARCH_WANTS_GENERIC_PCI_IOUNMAP */
-
-#endif /* CONFIG_PCI */
diff --git a/lib/Kconfig b/lib/Kconfig
index 3ea1c830efab..1bf859166ac7 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -70,9 +70,6 @@ source "lib/math/Kconfig"
config NO_GENERIC_PCI_IOPORT_MAP
bool
-config GENERIC_PCI_IOMAP
- bool
-
config GENERIC_IOMAP
bool
select GENERIC_PCI_IOMAP
diff --git a/lib/Makefile b/lib/Makefile
index 6b09731d8e61..0800289ec6c5 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -153,7 +153,6 @@ CFLAGS_debug_info.o += $(call cc-option, -femit-struct-debug-detailed=any)
obj-y += math/ crypto/
obj-$(CONFIG_GENERIC_IOMAP) += iomap.o
-obj-$(CONFIG_GENERIC_PCI_IOMAP) += pci_iomap.o
obj-$(CONFIG_HAS_IOMEM) += iomap_copy.o devres.o
obj-$(CONFIG_CHECK_SIGNATURE) += check_signature.o
obj-$(CONFIG_DEBUG_LOCKING_API_SELFTESTS) += locking-selftest.o
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH v3 2/5] lib: move pci_iomap.c to drivers/pci/
2023-12-04 12:38 ` [PATCH v3 2/5] lib: move pci_iomap.c to drivers/pci/ Philipp Stanner
@ 2023-12-04 13:37 ` Arnd Bergmann
0 siblings, 0 replies; 16+ messages in thread
From: Arnd Bergmann @ 2023-12-04 13:37 UTC (permalink / raw)
To: Philipp Stanner, Bjorn Helgaas, Hanjun Guo, Neil Brown,
Kent Overstreet, Jakub Kicinski, Niklas Schnelle,
Uladzislau Koshchanka, John Sanpe, Dave Jiang, Masami Hiramatsu,
Kees Cook, David Gow, Herbert Xu, Shuah Khan, wuqiang.matt,
Yury Norov, Jason Baron, Andrew Morton, Ben Dooks,
Danilo Krummrich
Cc: linux-kernel, linux-pci, Linux-Arch, stable
On Mon, Dec 4, 2023, at 13:38, Philipp Stanner wrote:
> This file is guarded by an #ifdef CONFIG_PCI. It, consequently, does not
> belong to lib/ because it is not generic infrastructure.
>
> Move the file to drivers/pci/ and implement the necessary changes to
> Makefiles and Kconfigs.
>
> Suggested-by: Danilo Krummrich <dakr@redhat.com>
> Signed-off-by: Philipp Stanner <pstanner@redhat.com>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v3 3/5] lib: move pci-specific devres code to drivers/pci/
2023-12-04 12:38 [PATCH v3 0/5] Regather scattered PCI-Code Philipp Stanner
2023-12-04 12:38 ` [PATCH v3 1/5] lib/pci_iomap.c: fix cleanup bugs in pci_iounmap() Philipp Stanner
2023-12-04 12:38 ` [PATCH v3 2/5] lib: move pci_iomap.c to drivers/pci/ Philipp Stanner
@ 2023-12-04 12:38 ` Philipp Stanner
2023-12-04 12:38 ` [PATCH v3 4/5] pci: move devres code from pci.c to devres.c Philipp Stanner
2023-12-04 12:38 ` [PATCH v3 5/5] lib, pci: unify generic pci_iounmap() Philipp Stanner
4 siblings, 0 replies; 16+ messages in thread
From: Philipp Stanner @ 2023-12-04 12:38 UTC (permalink / raw)
To: Bjorn Helgaas, Arnd Bergmann, Hanjun Guo, NeilBrown,
Kent Overstreet, Jakub Kicinski, Niklas Schnelle,
Uladzislau Koshchanka, John Sanpe, Dave Jiang, Philipp Stanner,
Masami Hiramatsu (Google), Kees Cook, David Gow, Herbert Xu,
Shuah Khan, wuqiang.matt, Yury Norov, Jason Baron, Andrew Morton,
Ben Dooks, dakr
Cc: linux-kernel, linux-pci, linux-arch, stable
The pcim_*() functions in lib/devres.c are guarded by an #ifdef
CONFIG_PCI and, thus, don't belong to this file. They are only ever used
for pci and are not generic infrastructure.
Move all pcim_*() functions in lib/devres.c to drivers/pci/devres.c.
Adjust the Makefile.
Suggested-by: Danilo Krummrich <dakr@redhat.com>
Signed-off-by: Philipp Stanner <pstanner@redhat.com>
---
drivers/pci/Makefile | 2 +-
drivers/pci/devres.c | 207 ++++++++++++++++++++++++++++++++++++++++++
lib/devres.c | 208 +------------------------------------------
3 files changed, 209 insertions(+), 208 deletions(-)
create mode 100644 drivers/pci/devres.c
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 64dcedccfc87..ed65299b42b5 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -5,7 +5,7 @@
obj-$(CONFIG_PCI) += access.o bus.o probe.o host-bridge.o \
remove.o pci.o pci-driver.o search.o \
pci-sysfs.o rom.o setup-res.o irq.o vpd.o \
- setup-bus.o vc.o mmap.o setup-irq.o
+ setup-bus.o vc.o mmap.o setup-irq.o devres.o
obj-$(CONFIG_PCI) += msi/
obj-$(CONFIG_PCI) += pcie/
diff --git a/drivers/pci/devres.c b/drivers/pci/devres.c
new file mode 100644
index 000000000000..a3fd0d65cef1
--- /dev/null
+++ b/drivers/pci/devres.c
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/pci.h>
+#include "pci.h"
+
+/*
+ * PCI iomap devres
+ */
+#define PCIM_IOMAP_MAX PCI_STD_NUM_BARS
+
+struct pcim_iomap_devres {
+ void __iomem *table[PCIM_IOMAP_MAX];
+};
+
+static void pcim_iomap_release(struct device *gendev, void *res)
+{
+ struct pci_dev *dev = to_pci_dev(gendev);
+ struct pcim_iomap_devres *this = res;
+ int i;
+
+ for (i = 0; i < PCIM_IOMAP_MAX; i++)
+ if (this->table[i])
+ pci_iounmap(dev, this->table[i]);
+}
+
+/**
+ * pcim_iomap_table - access iomap allocation table
+ * @pdev: PCI device to access iomap table for
+ *
+ * Access iomap allocation table for @dev. If iomap table doesn't
+ * exist and @pdev is managed, it will be allocated. All iomaps
+ * recorded in the iomap table are automatically unmapped on driver
+ * detach.
+ *
+ * This function might sleep when the table is first allocated but can
+ * be safely called without context and guaranteed to succeed once
+ * allocated.
+ */
+void __iomem * const *pcim_iomap_table(struct pci_dev *pdev)
+{
+ struct pcim_iomap_devres *dr, *new_dr;
+
+ dr = devres_find(&pdev->dev, pcim_iomap_release, NULL, NULL);
+ if (dr)
+ return dr->table;
+
+ new_dr = devres_alloc_node(pcim_iomap_release, sizeof(*new_dr), GFP_KERNEL,
+ dev_to_node(&pdev->dev));
+ if (!new_dr)
+ return NULL;
+ dr = devres_get(&pdev->dev, new_dr, NULL, NULL);
+ return dr->table;
+}
+EXPORT_SYMBOL(pcim_iomap_table);
+
+/**
+ * pcim_iomap - Managed pcim_iomap()
+ * @pdev: PCI device to iomap for
+ * @bar: BAR to iomap
+ * @maxlen: Maximum length of iomap
+ *
+ * Managed pci_iomap(). Map is automatically unmapped on driver
+ * detach.
+ */
+void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen)
+{
+ void __iomem **tbl;
+
+ BUG_ON(bar >= PCIM_IOMAP_MAX);
+
+ tbl = (void __iomem **)pcim_iomap_table(pdev);
+ if (!tbl || tbl[bar]) /* duplicate mappings not allowed */
+ return NULL;
+
+ tbl[bar] = pci_iomap(pdev, bar, maxlen);
+ return tbl[bar];
+}
+EXPORT_SYMBOL(pcim_iomap);
+
+/**
+ * pcim_iounmap - Managed pci_iounmap()
+ * @pdev: PCI device to iounmap for
+ * @addr: Address to unmap
+ *
+ * Managed pci_iounmap(). @addr must have been mapped using pcim_iomap().
+ */
+void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr)
+{
+ void __iomem **tbl;
+ int i;
+
+ pci_iounmap(pdev, addr);
+
+ tbl = (void __iomem **)pcim_iomap_table(pdev);
+ BUG_ON(!tbl);
+
+ for (i = 0; i < PCIM_IOMAP_MAX; i++)
+ if (tbl[i] == addr) {
+ tbl[i] = NULL;
+ return;
+ }
+ WARN_ON(1);
+}
+EXPORT_SYMBOL(pcim_iounmap);
+
+/**
+ * pcim_iomap_regions - Request and iomap PCI BARs
+ * @pdev: PCI device to map IO resources for
+ * @mask: Mask of BARs to request and iomap
+ * @name: Name used when requesting regions
+ *
+ * Request and iomap regions specified by @mask.
+ */
+int pcim_iomap_regions(struct pci_dev *pdev, int mask, const char *name)
+{
+ void __iomem * const *iomap;
+ int i, rc;
+
+ iomap = pcim_iomap_table(pdev);
+ if (!iomap)
+ return -ENOMEM;
+
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+ unsigned long len;
+
+ if (!(mask & (1 << i)))
+ continue;
+
+ rc = -EINVAL;
+ len = pci_resource_len(pdev, i);
+ if (!len)
+ goto err_inval;
+
+ rc = pci_request_region(pdev, i, name);
+ if (rc)
+ goto err_inval;
+
+ rc = -ENOMEM;
+ if (!pcim_iomap(pdev, i, 0))
+ goto err_region;
+ }
+
+ return 0;
+
+ err_region:
+ pci_release_region(pdev, i);
+ err_inval:
+ while (--i >= 0) {
+ if (!(mask & (1 << i)))
+ continue;
+ pcim_iounmap(pdev, iomap[i]);
+ pci_release_region(pdev, i);
+ }
+
+ return rc;
+}
+EXPORT_SYMBOL(pcim_iomap_regions);
+
+/**
+ * pcim_iomap_regions_request_all - Request all BARs and iomap specified ones
+ * @pdev: PCI device to map IO resources for
+ * @mask: Mask of BARs to iomap
+ * @name: Name used when requesting regions
+ *
+ * Request all PCI BARs and iomap regions specified by @mask.
+ */
+int pcim_iomap_regions_request_all(struct pci_dev *pdev, int mask,
+ const char *name)
+{
+ int request_mask = ((1 << 6) - 1) & ~mask;
+ int rc;
+
+ rc = pci_request_selected_regions(pdev, request_mask, name);
+ if (rc)
+ return rc;
+
+ rc = pcim_iomap_regions(pdev, mask, name);
+ if (rc)
+ pci_release_selected_regions(pdev, request_mask);
+ return rc;
+}
+EXPORT_SYMBOL(pcim_iomap_regions_request_all);
+
+/**
+ * pcim_iounmap_regions - Unmap and release PCI BARs
+ * @pdev: PCI device to map IO resources for
+ * @mask: Mask of BARs to unmap and release
+ *
+ * Unmap and release regions specified by @mask.
+ */
+void pcim_iounmap_regions(struct pci_dev *pdev, int mask)
+{
+ void __iomem * const *iomap;
+ int i;
+
+ iomap = pcim_iomap_table(pdev);
+ if (!iomap)
+ return;
+
+ for (i = 0; i < PCIM_IOMAP_MAX; i++) {
+ if (!(mask & (1 << i)))
+ continue;
+
+ pcim_iounmap(pdev, iomap[i]);
+ pci_release_region(pdev, i);
+ }
+}
+EXPORT_SYMBOL(pcim_iounmap_regions);
diff --git a/lib/devres.c b/lib/devres.c
index c44f104b58d5..fe0c63caeb68 100644
--- a/lib/devres.c
+++ b/lib/devres.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
+#include <linux/device.h>
#include <linux/err.h>
-#include <linux/pci.h>
#include <linux/io.h>
#include <linux/gfp.h>
#include <linux/export.h>
@@ -311,212 +311,6 @@ void devm_ioport_unmap(struct device *dev, void __iomem *addr)
EXPORT_SYMBOL(devm_ioport_unmap);
#endif /* CONFIG_HAS_IOPORT_MAP */
-#ifdef CONFIG_PCI
-/*
- * PCI iomap devres
- */
-#define PCIM_IOMAP_MAX PCI_STD_NUM_BARS
-
-struct pcim_iomap_devres {
- void __iomem *table[PCIM_IOMAP_MAX];
-};
-
-static void pcim_iomap_release(struct device *gendev, void *res)
-{
- struct pci_dev *dev = to_pci_dev(gendev);
- struct pcim_iomap_devres *this = res;
- int i;
-
- for (i = 0; i < PCIM_IOMAP_MAX; i++)
- if (this->table[i])
- pci_iounmap(dev, this->table[i]);
-}
-
-/**
- * pcim_iomap_table - access iomap allocation table
- * @pdev: PCI device to access iomap table for
- *
- * Access iomap allocation table for @dev. If iomap table doesn't
- * exist and @pdev is managed, it will be allocated. All iomaps
- * recorded in the iomap table are automatically unmapped on driver
- * detach.
- *
- * This function might sleep when the table is first allocated but can
- * be safely called without context and guaranteed to succeed once
- * allocated.
- */
-void __iomem * const *pcim_iomap_table(struct pci_dev *pdev)
-{
- struct pcim_iomap_devres *dr, *new_dr;
-
- dr = devres_find(&pdev->dev, pcim_iomap_release, NULL, NULL);
- if (dr)
- return dr->table;
-
- new_dr = devres_alloc_node(pcim_iomap_release, sizeof(*new_dr), GFP_KERNEL,
- dev_to_node(&pdev->dev));
- if (!new_dr)
- return NULL;
- dr = devres_get(&pdev->dev, new_dr, NULL, NULL);
- return dr->table;
-}
-EXPORT_SYMBOL(pcim_iomap_table);
-
-/**
- * pcim_iomap - Managed pcim_iomap()
- * @pdev: PCI device to iomap for
- * @bar: BAR to iomap
- * @maxlen: Maximum length of iomap
- *
- * Managed pci_iomap(). Map is automatically unmapped on driver
- * detach.
- */
-void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen)
-{
- void __iomem **tbl;
-
- BUG_ON(bar >= PCIM_IOMAP_MAX);
-
- tbl = (void __iomem **)pcim_iomap_table(pdev);
- if (!tbl || tbl[bar]) /* duplicate mappings not allowed */
- return NULL;
-
- tbl[bar] = pci_iomap(pdev, bar, maxlen);
- return tbl[bar];
-}
-EXPORT_SYMBOL(pcim_iomap);
-
-/**
- * pcim_iounmap - Managed pci_iounmap()
- * @pdev: PCI device to iounmap for
- * @addr: Address to unmap
- *
- * Managed pci_iounmap(). @addr must have been mapped using pcim_iomap().
- */
-void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr)
-{
- void __iomem **tbl;
- int i;
-
- pci_iounmap(pdev, addr);
-
- tbl = (void __iomem **)pcim_iomap_table(pdev);
- BUG_ON(!tbl);
-
- for (i = 0; i < PCIM_IOMAP_MAX; i++)
- if (tbl[i] == addr) {
- tbl[i] = NULL;
- return;
- }
- WARN_ON(1);
-}
-EXPORT_SYMBOL(pcim_iounmap);
-
-/**
- * pcim_iomap_regions - Request and iomap PCI BARs
- * @pdev: PCI device to map IO resources for
- * @mask: Mask of BARs to request and iomap
- * @name: Name used when requesting regions
- *
- * Request and iomap regions specified by @mask.
- */
-int pcim_iomap_regions(struct pci_dev *pdev, int mask, const char *name)
-{
- void __iomem * const *iomap;
- int i, rc;
-
- iomap = pcim_iomap_table(pdev);
- if (!iomap)
- return -ENOMEM;
-
- for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
- unsigned long len;
-
- if (!(mask & (1 << i)))
- continue;
-
- rc = -EINVAL;
- len = pci_resource_len(pdev, i);
- if (!len)
- goto err_inval;
-
- rc = pci_request_region(pdev, i, name);
- if (rc)
- goto err_inval;
-
- rc = -ENOMEM;
- if (!pcim_iomap(pdev, i, 0))
- goto err_region;
- }
-
- return 0;
-
- err_region:
- pci_release_region(pdev, i);
- err_inval:
- while (--i >= 0) {
- if (!(mask & (1 << i)))
- continue;
- pcim_iounmap(pdev, iomap[i]);
- pci_release_region(pdev, i);
- }
-
- return rc;
-}
-EXPORT_SYMBOL(pcim_iomap_regions);
-
-/**
- * pcim_iomap_regions_request_all - Request all BARs and iomap specified ones
- * @pdev: PCI device to map IO resources for
- * @mask: Mask of BARs to iomap
- * @name: Name used when requesting regions
- *
- * Request all PCI BARs and iomap regions specified by @mask.
- */
-int pcim_iomap_regions_request_all(struct pci_dev *pdev, int mask,
- const char *name)
-{
- int request_mask = ((1 << 6) - 1) & ~mask;
- int rc;
-
- rc = pci_request_selected_regions(pdev, request_mask, name);
- if (rc)
- return rc;
-
- rc = pcim_iomap_regions(pdev, mask, name);
- if (rc)
- pci_release_selected_regions(pdev, request_mask);
- return rc;
-}
-EXPORT_SYMBOL(pcim_iomap_regions_request_all);
-
-/**
- * pcim_iounmap_regions - Unmap and release PCI BARs
- * @pdev: PCI device to map IO resources for
- * @mask: Mask of BARs to unmap and release
- *
- * Unmap and release regions specified by @mask.
- */
-void pcim_iounmap_regions(struct pci_dev *pdev, int mask)
-{
- void __iomem * const *iomap;
- int i;
-
- iomap = pcim_iomap_table(pdev);
- if (!iomap)
- return;
-
- for (i = 0; i < PCIM_IOMAP_MAX; i++) {
- if (!(mask & (1 << i)))
- continue;
-
- pcim_iounmap(pdev, iomap[i]);
- pci_release_region(pdev, i);
- }
-}
-EXPORT_SYMBOL(pcim_iounmap_regions);
-#endif /* CONFIG_PCI */
-
static void devm_arch_phys_ac_add_release(struct device *dev, void *res)
{
arch_phys_wc_del(*((int *)res));
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v3 4/5] pci: move devres code from pci.c to devres.c
2023-12-04 12:38 [PATCH v3 0/5] Regather scattered PCI-Code Philipp Stanner
` (2 preceding siblings ...)
2023-12-04 12:38 ` [PATCH v3 3/5] lib: move pci-specific devres code " Philipp Stanner
@ 2023-12-04 12:38 ` Philipp Stanner
2023-12-04 12:38 ` [PATCH v3 5/5] lib, pci: unify generic pci_iounmap() Philipp Stanner
4 siblings, 0 replies; 16+ messages in thread
From: Philipp Stanner @ 2023-12-04 12:38 UTC (permalink / raw)
To: Bjorn Helgaas, Arnd Bergmann, Hanjun Guo, NeilBrown,
Kent Overstreet, Jakub Kicinski, Niklas Schnelle,
Uladzislau Koshchanka, John Sanpe, Dave Jiang, Philipp Stanner,
Masami Hiramatsu (Google), Kees Cook, David Gow, Herbert Xu,
Shuah Khan, wuqiang.matt, Yury Norov, Jason Baron, Andrew Morton,
Ben Dooks, dakr
Cc: linux-kernel, linux-pci, linux-arch, stable
The file pci.c is very large and contains a number of devres-functions.
These functions should now reside in devres.c
There are a few callers left in pci.c that do devres operations. These
should be ported in the future. Corresponding TODOs are added by this
commit.
The reason they are not moved right now in this commit is that pci's
devres currently implements a sort of "hybrid-mode":
pci_request_region(), for instance, does not have a corresponding pcim_
equivalent, yet. Instead, the function can be made managed by previously
calling pcim_enable_device() (instead of pci_enable_device()). This
makes it unreasonable to move pci_request_region() to devres.c
Moving the functions would require changes to pci's API and is,
therefore, left for future work.
In summary, this commit serves as a preparation step for a following
patch-series that will cleanly separate the PCI's managed and unmanaged
API.
Move as much devres-specific code from pci.c to devres.c as possible.
Suggested-by: Danilo Krummrich <dakr@redhat.com>
Signed-off-by: Philipp Stanner <pstanner@redhat.com>
---
drivers/pci/devres.c | 243 +++++++++++++++++++++++++++++++++++++++++
drivers/pci/pci.c | 249 -------------------------------------------
drivers/pci/pci.h | 24 +++++
3 files changed, 267 insertions(+), 249 deletions(-)
diff --git a/drivers/pci/devres.c b/drivers/pci/devres.c
index a3fd0d65cef1..4bd1e125bca1 100644
--- a/drivers/pci/devres.c
+++ b/drivers/pci/devres.c
@@ -1,4 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
+#include <linux/device.h>
#include <linux/pci.h>
#include "pci.h"
@@ -11,6 +12,248 @@ struct pcim_iomap_devres {
void __iomem *table[PCIM_IOMAP_MAX];
};
+
+static void devm_pci_unmap_iospace(struct device *dev, void *ptr)
+{
+ struct resource **res = ptr;
+
+ pci_unmap_iospace(*res);
+}
+
+/**
+ * devm_pci_remap_iospace - Managed pci_remap_iospace()
+ * @dev: Generic device to remap IO address for
+ * @res: Resource describing the I/O space
+ * @phys_addr: physical address of range to be mapped
+ *
+ * Managed pci_remap_iospace(). Map is automatically unmapped on driver
+ * detach.
+ */
+int devm_pci_remap_iospace(struct device *dev, const struct resource *res,
+ phys_addr_t phys_addr)
+{
+ const struct resource **ptr;
+ int error;
+
+ ptr = devres_alloc(devm_pci_unmap_iospace, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+
+ error = pci_remap_iospace(res, phys_addr);
+ if (error) {
+ devres_free(ptr);
+ } else {
+ *ptr = res;
+ devres_add(dev, ptr);
+ }
+
+ return error;
+}
+EXPORT_SYMBOL(devm_pci_remap_iospace);
+
+/**
+ * devm_pci_remap_cfgspace - Managed pci_remap_cfgspace()
+ * @dev: Generic device to remap IO address for
+ * @offset: Resource address to map
+ * @size: Size of map
+ *
+ * Managed pci_remap_cfgspace(). Map is automatically unmapped on driver
+ * detach.
+ */
+void __iomem *devm_pci_remap_cfgspace(struct device *dev,
+ resource_size_t offset,
+ resource_size_t size)
+{
+ void __iomem **ptr, *addr;
+
+ ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return NULL;
+
+ addr = pci_remap_cfgspace(offset, size);
+ if (addr) {
+ *ptr = addr;
+ devres_add(dev, ptr);
+ } else
+ devres_free(ptr);
+
+ return addr;
+}
+EXPORT_SYMBOL(devm_pci_remap_cfgspace);
+
+/**
+ * devm_pci_remap_cfg_resource - check, request region and ioremap cfg resource
+ * @dev: generic device to handle the resource for
+ * @res: configuration space resource to be handled
+ *
+ * Checks that a resource is a valid memory region, requests the memory
+ * region and ioremaps with pci_remap_cfgspace() API that ensures the
+ * proper PCI configuration space memory attributes are guaranteed.
+ *
+ * All operations are managed and will be undone on driver detach.
+ *
+ * Returns a pointer to the remapped memory or an ERR_PTR() encoded error code
+ * on failure. Usage example::
+ *
+ * res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ * base = devm_pci_remap_cfg_resource(&pdev->dev, res);
+ * if (IS_ERR(base))
+ * return PTR_ERR(base);
+ */
+void __iomem *devm_pci_remap_cfg_resource(struct device *dev,
+ struct resource *res)
+{
+ resource_size_t size;
+ const char *name;
+ void __iomem *dest_ptr;
+
+ BUG_ON(!dev);
+
+ if (!res || resource_type(res) != IORESOURCE_MEM) {
+ dev_err(dev, "invalid resource\n");
+ return IOMEM_ERR_PTR(-EINVAL);
+ }
+
+ size = resource_size(res);
+
+ if (res->name)
+ name = devm_kasprintf(dev, GFP_KERNEL, "%s %s", dev_name(dev),
+ res->name);
+ else
+ name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL);
+ if (!name)
+ return IOMEM_ERR_PTR(-ENOMEM);
+
+ if (!devm_request_mem_region(dev, res->start, size, name)) {
+ dev_err(dev, "can't request region for resource %pR\n", res);
+ return IOMEM_ERR_PTR(-EBUSY);
+ }
+
+ dest_ptr = devm_pci_remap_cfgspace(dev, res->start, size);
+ if (!dest_ptr) {
+ dev_err(dev, "ioremap failed for resource %pR\n", res);
+ devm_release_mem_region(dev, res->start, size);
+ dest_ptr = IOMEM_ERR_PTR(-ENOMEM);
+ }
+
+ return dest_ptr;
+}
+EXPORT_SYMBOL(devm_pci_remap_cfg_resource);
+
+/**
+ * pcim_set_mwi - a device-managed pci_set_mwi()
+ * @dev: the PCI device for which MWI is enabled
+ *
+ * Managed pci_set_mwi().
+ *
+ * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
+ */
+int pcim_set_mwi(struct pci_dev *dev)
+{
+ struct pci_devres *dr;
+
+ dr = find_pci_dr(dev);
+ if (!dr)
+ return -ENOMEM;
+
+ dr->mwi = 1;
+ return pci_set_mwi(dev);
+}
+EXPORT_SYMBOL(pcim_set_mwi);
+
+
+static void pcim_release(struct device *gendev, void *res)
+{
+ struct pci_dev *dev = to_pci_dev(gendev);
+ struct pci_devres *this = res;
+ int i;
+
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++)
+ if (this->region_mask & (1 << i))
+ pci_release_region(dev, i);
+
+ if (this->mwi)
+ pci_clear_mwi(dev);
+
+ if (this->restore_intx)
+ pci_intx(dev, this->orig_intx);
+
+ if (this->enabled && !this->pinned)
+ pci_disable_device(dev);
+}
+
+/*
+ * TODO:
+ * Once the last four callers in pci.c are ported, this function here needs to
+ * be made static again.
+ */
+struct pci_devres *find_pci_dr(struct pci_dev *pdev)
+{
+ if (pci_is_managed(pdev))
+ return devres_find(&pdev->dev, pcim_release, NULL, NULL);
+ return NULL;
+}
+EXPORT_SYMBOL(find_pci_dr);
+
+static struct pci_devres *get_pci_dr(struct pci_dev *pdev)
+{
+ struct pci_devres *dr, *new_dr;
+
+ dr = devres_find(&pdev->dev, pcim_release, NULL, NULL);
+ if (dr)
+ return dr;
+
+ new_dr = devres_alloc(pcim_release, sizeof(*new_dr), GFP_KERNEL);
+ if (!new_dr)
+ return NULL;
+ return devres_get(&pdev->dev, new_dr, NULL, NULL);
+}
+
+/**
+ * pcim_enable_device - Managed pci_enable_device()
+ * @pdev: PCI device to be initialized
+ *
+ * Managed pci_enable_device().
+ */
+int pcim_enable_device(struct pci_dev *pdev)
+{
+ struct pci_devres *dr;
+ int rc;
+
+ dr = get_pci_dr(pdev);
+ if (unlikely(!dr))
+ return -ENOMEM;
+ if (dr->enabled)
+ return 0;
+
+ rc = pci_enable_device(pdev);
+ if (!rc) {
+ pdev->is_managed = 1;
+ dr->enabled = 1;
+ }
+ return rc;
+}
+EXPORT_SYMBOL(pcim_enable_device);
+
+/**
+ * pcim_pin_device - Pin managed PCI device
+ * @pdev: PCI device to pin
+ *
+ * Pin managed PCI device @pdev. Pinned device won't be disabled on
+ * driver detach. @pdev must have been enabled with
+ * pcim_enable_device().
+ */
+void pcim_pin_device(struct pci_dev *pdev)
+{
+ struct pci_devres *dr;
+
+ dr = find_pci_dr(pdev);
+ WARN_ON(!dr || !dr->enabled);
+ if (dr)
+ dr->pinned = 1;
+}
+EXPORT_SYMBOL(pcim_pin_device);
+
static void pcim_iomap_release(struct device *gendev, void *res)
{
struct pci_dev *dev = to_pci_dev(gendev);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 55bc3576a985..742b0a6545b6 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -2088,107 +2088,6 @@ int pci_enable_device(struct pci_dev *dev)
}
EXPORT_SYMBOL(pci_enable_device);
-/*
- * Managed PCI resources. This manages device on/off, INTx/MSI/MSI-X
- * on/off and BAR regions. pci_dev itself records MSI/MSI-X status, so
- * there's no need to track it separately. pci_devres is initialized
- * when a device is enabled using managed PCI device enable interface.
- */
-struct pci_devres {
- unsigned int enabled:1;
- unsigned int pinned:1;
- unsigned int orig_intx:1;
- unsigned int restore_intx:1;
- unsigned int mwi:1;
- u32 region_mask;
-};
-
-static void pcim_release(struct device *gendev, void *res)
-{
- struct pci_dev *dev = to_pci_dev(gendev);
- struct pci_devres *this = res;
- int i;
-
- for (i = 0; i < DEVICE_COUNT_RESOURCE; i++)
- if (this->region_mask & (1 << i))
- pci_release_region(dev, i);
-
- if (this->mwi)
- pci_clear_mwi(dev);
-
- if (this->restore_intx)
- pci_intx(dev, this->orig_intx);
-
- if (this->enabled && !this->pinned)
- pci_disable_device(dev);
-}
-
-static struct pci_devres *get_pci_dr(struct pci_dev *pdev)
-{
- struct pci_devres *dr, *new_dr;
-
- dr = devres_find(&pdev->dev, pcim_release, NULL, NULL);
- if (dr)
- return dr;
-
- new_dr = devres_alloc(pcim_release, sizeof(*new_dr), GFP_KERNEL);
- if (!new_dr)
- return NULL;
- return devres_get(&pdev->dev, new_dr, NULL, NULL);
-}
-
-static struct pci_devres *find_pci_dr(struct pci_dev *pdev)
-{
- if (pci_is_managed(pdev))
- return devres_find(&pdev->dev, pcim_release, NULL, NULL);
- return NULL;
-}
-
-/**
- * pcim_enable_device - Managed pci_enable_device()
- * @pdev: PCI device to be initialized
- *
- * Managed pci_enable_device().
- */
-int pcim_enable_device(struct pci_dev *pdev)
-{
- struct pci_devres *dr;
- int rc;
-
- dr = get_pci_dr(pdev);
- if (unlikely(!dr))
- return -ENOMEM;
- if (dr->enabled)
- return 0;
-
- rc = pci_enable_device(pdev);
- if (!rc) {
- pdev->is_managed = 1;
- dr->enabled = 1;
- }
- return rc;
-}
-EXPORT_SYMBOL(pcim_enable_device);
-
-/**
- * pcim_pin_device - Pin managed PCI device
- * @pdev: PCI device to pin
- *
- * Pin managed PCI device @pdev. Pinned device won't be disabled on
- * driver detach. @pdev must have been enabled with
- * pcim_enable_device().
- */
-void pcim_pin_device(struct pci_dev *pdev)
-{
- struct pci_devres *dr;
-
- dr = find_pci_dr(pdev);
- WARN_ON(!dr || !dr->enabled);
- if (dr)
- dr->pinned = 1;
-}
-EXPORT_SYMBOL(pcim_pin_device);
-
/*
* pcibios_device_add - provide arch specific hooks when adding device dev
* @dev: the PCI device being added
@@ -4281,133 +4180,6 @@ void pci_unmap_iospace(struct resource *res)
}
EXPORT_SYMBOL(pci_unmap_iospace);
-static void devm_pci_unmap_iospace(struct device *dev, void *ptr)
-{
- struct resource **res = ptr;
-
- pci_unmap_iospace(*res);
-}
-
-/**
- * devm_pci_remap_iospace - Managed pci_remap_iospace()
- * @dev: Generic device to remap IO address for
- * @res: Resource describing the I/O space
- * @phys_addr: physical address of range to be mapped
- *
- * Managed pci_remap_iospace(). Map is automatically unmapped on driver
- * detach.
- */
-int devm_pci_remap_iospace(struct device *dev, const struct resource *res,
- phys_addr_t phys_addr)
-{
- const struct resource **ptr;
- int error;
-
- ptr = devres_alloc(devm_pci_unmap_iospace, sizeof(*ptr), GFP_KERNEL);
- if (!ptr)
- return -ENOMEM;
-
- error = pci_remap_iospace(res, phys_addr);
- if (error) {
- devres_free(ptr);
- } else {
- *ptr = res;
- devres_add(dev, ptr);
- }
-
- return error;
-}
-EXPORT_SYMBOL(devm_pci_remap_iospace);
-
-/**
- * devm_pci_remap_cfgspace - Managed pci_remap_cfgspace()
- * @dev: Generic device to remap IO address for
- * @offset: Resource address to map
- * @size: Size of map
- *
- * Managed pci_remap_cfgspace(). Map is automatically unmapped on driver
- * detach.
- */
-void __iomem *devm_pci_remap_cfgspace(struct device *dev,
- resource_size_t offset,
- resource_size_t size)
-{
- void __iomem **ptr, *addr;
-
- ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL);
- if (!ptr)
- return NULL;
-
- addr = pci_remap_cfgspace(offset, size);
- if (addr) {
- *ptr = addr;
- devres_add(dev, ptr);
- } else
- devres_free(ptr);
-
- return addr;
-}
-EXPORT_SYMBOL(devm_pci_remap_cfgspace);
-
-/**
- * devm_pci_remap_cfg_resource - check, request region and ioremap cfg resource
- * @dev: generic device to handle the resource for
- * @res: configuration space resource to be handled
- *
- * Checks that a resource is a valid memory region, requests the memory
- * region and ioremaps with pci_remap_cfgspace() API that ensures the
- * proper PCI configuration space memory attributes are guaranteed.
- *
- * All operations are managed and will be undone on driver detach.
- *
- * Returns a pointer to the remapped memory or an ERR_PTR() encoded error code
- * on failure. Usage example::
- *
- * res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- * base = devm_pci_remap_cfg_resource(&pdev->dev, res);
- * if (IS_ERR(base))
- * return PTR_ERR(base);
- */
-void __iomem *devm_pci_remap_cfg_resource(struct device *dev,
- struct resource *res)
-{
- resource_size_t size;
- const char *name;
- void __iomem *dest_ptr;
-
- BUG_ON(!dev);
-
- if (!res || resource_type(res) != IORESOURCE_MEM) {
- dev_err(dev, "invalid resource\n");
- return IOMEM_ERR_PTR(-EINVAL);
- }
-
- size = resource_size(res);
-
- if (res->name)
- name = devm_kasprintf(dev, GFP_KERNEL, "%s %s", dev_name(dev),
- res->name);
- else
- name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL);
- if (!name)
- return IOMEM_ERR_PTR(-ENOMEM);
-
- if (!devm_request_mem_region(dev, res->start, size, name)) {
- dev_err(dev, "can't request region for resource %pR\n", res);
- return IOMEM_ERR_PTR(-EBUSY);
- }
-
- dest_ptr = devm_pci_remap_cfgspace(dev, res->start, size);
- if (!dest_ptr) {
- dev_err(dev, "ioremap failed for resource %pR\n", res);
- devm_release_mem_region(dev, res->start, size);
- dest_ptr = IOMEM_ERR_PTR(-ENOMEM);
- }
-
- return dest_ptr;
-}
-EXPORT_SYMBOL(devm_pci_remap_cfg_resource);
-
static void __pci_set_master(struct pci_dev *dev, bool enable)
{
u16 old_cmd, cmd;
@@ -4557,27 +4329,6 @@ int pci_set_mwi(struct pci_dev *dev)
}
EXPORT_SYMBOL(pci_set_mwi);
-/**
- * pcim_set_mwi - a device-managed pci_set_mwi()
- * @dev: the PCI device for which MWI is enabled
- *
- * Managed pci_set_mwi().
- *
- * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
- */
-int pcim_set_mwi(struct pci_dev *dev)
-{
- struct pci_devres *dr;
-
- dr = find_pci_dr(dev);
- if (!dr)
- return -ENOMEM;
-
- dr->mwi = 1;
- return pci_set_mwi(dev);
-}
-EXPORT_SYMBOL(pcim_set_mwi);
-
/**
* pci_try_set_mwi - enables memory-write-invalidate PCI transaction
* @dev: the PCI device for which MWI is enabled
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 5ecbcf041179..69052059dbd2 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -793,6 +793,30 @@ static inline pci_power_t mid_pci_get_power_state(struct pci_dev *pdev)
}
#endif
+/*
+ * TODO:
+ * The following two components wouldn't need to be here if they weren't used at
+ * four last places in pci.c
+ * Port or move these functions to devres.c and then remove the
+ * pci_devres-components from this header file here.
+ */
+/*
+ * Managed PCI resources. This manages device on/off, INTx/MSI/MSI-X
+ * on/off and BAR regions. pci_dev itself records MSI/MSI-X status, so
+ * there's no need to track it separately. pci_devres is initialized
+ * when a device is enabled using managed PCI device enable interface.
+ */
+struct pci_devres {
+ unsigned int enabled:1;
+ unsigned int pinned:1;
+ unsigned int orig_intx:1;
+ unsigned int restore_intx:1;
+ unsigned int mwi:1;
+ u32 region_mask;
+};
+
+struct pci_devres *find_pci_dr(struct pci_dev *pdev);
+
/*
* Config Address for PCI Configuration Mechanism #1
*
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v3 5/5] lib, pci: unify generic pci_iounmap()
2023-12-04 12:38 [PATCH v3 0/5] Regather scattered PCI-Code Philipp Stanner
` (3 preceding siblings ...)
2023-12-04 12:38 ` [PATCH v3 4/5] pci: move devres code from pci.c to devres.c Philipp Stanner
@ 2023-12-04 12:38 ` Philipp Stanner
2023-12-04 13:39 ` Philipp Stanner
` (2 more replies)
4 siblings, 3 replies; 16+ messages in thread
From: Philipp Stanner @ 2023-12-04 12:38 UTC (permalink / raw)
To: Bjorn Helgaas, Arnd Bergmann, Hanjun Guo, NeilBrown,
Kent Overstreet, Jakub Kicinski, Niklas Schnelle,
Uladzislau Koshchanka, John Sanpe, Dave Jiang, Philipp Stanner,
Masami Hiramatsu (Google), Kees Cook, David Gow, Herbert Xu,
Shuah Khan, wuqiang.matt, Yury Norov, Jason Baron, Andrew Morton,
Ben Dooks, dakr
Cc: linux-kernel, linux-pci, linux-arch, stable, Arnd Bergmann
The implementation of pci_iounmap() is currently scattered over two
files, drivers/pci/iomap.c and lib/iomap.c. Additionally,
architectures can define their own version.
To have only one version, it's necessary to create a helper function,
iomem_is_ioport(), that tells pci_iounmap() whether the passed address
points to an ioport or normal memory.
iomem_is_ioport() can be provided through two different ways:
1. The architecture itself provides it. As of today, the version
coming from lib/iomap.c de facto is the x86-specific version and
comes into play when CONFIG_GENERIC_IOMAP is selected. This rather
confusing naming is an artifact left by the removal of IA64.
2. As a default version in include/asm-generic/io.h for those
architectures that don't use CONFIG_GENERIC_IOMAP, but also don't
provide their own version of iomem_is_ioport().
Once all architectures that support ports provide iomem_is_ioport(), the
arch-specific definitions for pci_iounmap() can be removed and the archs
can use the generic implementation, instead.
Create a unified version of pci_iounmap() in drivers/pci/iomap.c.
Provide the function iomem_is_ioport() in include/asm-generic/io.h
(generic) and lib/iomap.c ("pseudo-generic" for x86).
Remove the CONFIG_GENERIC_IOMAP guard around
ARCH_WANTS_GENERIC_PCI_IOUNMAP so that configs that set
CONFIG_GENERIC_PCI_IOMAP without CONFIG_GENERIC_IOMAP still get the
function.
Add TODOs for follow-up work on the "generic is not generic but
x86-spcific"-Problem.
Suggested-by: Arnd Bergmann <arnd@kernel.org>
Signed-off-by: Philipp Stanner <pstanner@redhat.com>
---
drivers/pci/iomap.c | 46 ++++++++++++-------------------------
include/asm-generic/io.h | 27 ++++++++++++++++++++--
include/asm-generic/iomap.h | 21 +++++++++++++++++
lib/iomap.c | 28 ++++++++++++++++------
4 files changed, 82 insertions(+), 40 deletions(-)
diff --git a/drivers/pci/iomap.c b/drivers/pci/iomap.c
index 91285fcff1ba..439ba2e9710f 100644
--- a/drivers/pci/iomap.c
+++ b/drivers/pci/iomap.c
@@ -135,44 +135,28 @@ void __iomem *pci_iomap_wc(struct pci_dev *dev, int bar, unsigned long maxlen)
EXPORT_SYMBOL_GPL(pci_iomap_wc);
/*
- * pci_iounmap() somewhat illogically comes from lib/iomap.c for the
- * CONFIG_GENERIC_IOMAP case, because that's the code that knows about
- * the different IOMAP ranges.
+ * This check is still necessary due to legacy reasons.
*
- * But if the architecture does not use the generic iomap code, and if
- * it has _not_ defined it's own private pci_iounmap function, we define
- * it here.
- *
- * NOTE! This default implementation assumes that if the architecture
- * support ioport mapping (HAS_IOPORT_MAP), the ioport mapping will
- * be fixed to the range [ PCI_IOBASE, PCI_IOBASE+IO_SPACE_LIMIT [,
- * and does not need unmapping with 'ioport_unmap()'.
- *
- * If you have different rules for your architecture, you need to
- * implement your own pci_iounmap() that knows the rules for where
- * and how IO vs MEM get mapped.
- *
- * This code is odd, and the ARCH_HAS/ARCH_WANTS #define logic comes
- * from legacy <asm-generic/io.h> header file behavior. In particular,
- * it would seem to make sense to do the iounmap(p) for the non-IO-space
- * case here regardless, but that's not what the old header file code
- * did. Probably incorrectly, but this is meant to be bug-for-bug
- * compatible.
+ * TODO: Have all architectures that provide their own pci_iounmap() provide
+ * iomem_is_ioport() instead. Remove this #if afterwards.
*/
#if defined(ARCH_WANTS_GENERIC_PCI_IOUNMAP)
-void pci_iounmap(struct pci_dev *dev, void __iomem *p)
+/**
+ * pci_iounmap - Unmapp a mapping
+ * @dev: PCI device the mapping belongs to
+ * @addr: start address of the mapping
+ *
+ * Unmapp a PIO or MMIO mapping.
+ */
+void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
{
-#ifdef ARCH_HAS_GENERIC_IOPORT_MAP
- uintptr_t start = (uintptr_t) PCI_IOBASE;
- uintptr_t addr = (uintptr_t) p;
-
- if (addr >= start && addr < start + IO_SPACE_LIMIT) {
- ioport_unmap(p);
+ if (iomem_is_ioport(addr)) {
+ ioport_unmap(addr);
return;
}
-#endif
- iounmap(p);
+
+ iounmap(addr);
}
EXPORT_SYMBOL(pci_iounmap);
diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
index bac63e874c7b..58c7bf4080da 100644
--- a/include/asm-generic/io.h
+++ b/include/asm-generic/io.h
@@ -1129,11 +1129,34 @@ extern void ioport_unmap(void __iomem *p);
#endif /* CONFIG_GENERIC_IOMAP */
#endif /* CONFIG_HAS_IOPORT_MAP */
-#ifndef CONFIG_GENERIC_IOMAP
+/*
+ * TODO:
+ * remove this once all architectures replaced their pci_iounmap() with
+ * a custom implementation of iomem_is_ioport().
+ */
#ifndef pci_iounmap
+#define pci_iounmap pci_iounmap
#define ARCH_WANTS_GENERIC_PCI_IOUNMAP
+#endif /* pci_iounmap */
+
+/*
+ * This function is a helper only needed for the generic pci_iounmap().
+ * It's provided here if the architecture does not provide its own version.
+ */
+#ifndef iomem_is_ioport
+#define iomem_is_ioport iomem_is_ioport
+static inline bool iomem_is_ioport(void __iomem *addr_raw)
+{
+#ifdef CONFIG_HAS_IOPORT
+ uintptr_t start = (uintptr_t)PCI_IOBASE;
+ uintptr_t addr = (uintptr_t)addr_raw;
+
+ if (addr >= start && addr < start + IO_SPACE_LIMIT)
+ return true;
#endif
-#endif
+ return false;
+}
+#endif /* iomem_is_ioport */
#ifndef xlate_dev_mem_ptr
#define xlate_dev_mem_ptr xlate_dev_mem_ptr
diff --git a/include/asm-generic/iomap.h b/include/asm-generic/iomap.h
index 196087a8126e..2cdc6988a102 100644
--- a/include/asm-generic/iomap.h
+++ b/include/asm-generic/iomap.h
@@ -110,6 +110,27 @@ static inline void __iomem *ioremap_np(phys_addr_t offset, size_t size)
}
#endif
+/*
+ * If CONFIG_GENERIC_IOMAP is selected and the architecture does NOT provide its
+ * own version, ARCH_WANTS_GENERIC_IOMEM_IS_IOPORT makes sure that the generic
+ * version from asm-generic/io.h is NOT used and instead the second "generic"
+ * version from lib/iomap.c is used.
+ *
+ * There are currently two generic versions because of a difficult cleanup
+ * process. Namely, the version in lib/iomap.c once was really generic when IA64
+ * still existed. Today, it's only really used by x86.
+ *
+ * TODO: Move the version from lib/iomap.c to x86 specific code. Then, remove
+ * this ARCH_WANTS_GENERIC_IOMEM_IS_IOPORT-mechanism.
+ */
+#ifdef CONFIG_GENERIC_IOMAP
+#ifndef iomem_is_ioport
+#define iomem_is_ioport iomem_is_ioport
+bool iomem_is_ioport(void __iomem *addr);
+#define ARCH_WANTS_GENERIC_IOMEM_IS_IOPORT
+#endif /* iomem_is_ioport */
+#endif /* CONFIG_GENERIC_IOMAP */
+
#include <asm-generic/pci_iomap.h>
#endif
diff --git a/lib/iomap.c b/lib/iomap.c
index 4f8b31baa575..eb9a879ebf42 100644
--- a/lib/iomap.c
+++ b/lib/iomap.c
@@ -418,12 +418,26 @@ EXPORT_SYMBOL(ioport_map);
EXPORT_SYMBOL(ioport_unmap);
#endif /* CONFIG_HAS_IOPORT_MAP */
-#ifdef CONFIG_PCI
-/* Hide the details if this is a MMIO or PIO address space and just do what
- * you expect in the correct way. */
-void pci_iounmap(struct pci_dev *dev, void __iomem * addr)
+/*
+ * If CONFIG_GENERIC_IOMAP is selected and the architecture does NOT provide its
+ * own version, ARCH_WANTS_GENERIC_IOMEM_IS_IOPORT makes sure that the generic
+ * version from asm-generic/io.h is NOT used and instead the second "generic"
+ * version from this file here is used.
+ *
+ * There are currently two generic versions because of a difficult cleanup
+ * process. Namely, the version in lib/iomap.c once was really generic when IA64
+ * still existed. Today, it's only really used by x86.
+ *
+ * TODO: Move this function to x86-specific code.
+ */
+#if defined(ARCH_WANTS_GENERIC_IOMEM_IS_IOPORT)
+bool iomem_is_ioport(void __iomem *addr)
{
- IO_COND(addr, /* nothing */, iounmap(addr));
+ unsigned long port = (unsigned long __force)addr;
+
+ if (port > PIO_OFFSET && port < PIO_RESERVED)
+ return true;
+
+ return false;
}
-EXPORT_SYMBOL(pci_iounmap);
-#endif /* CONFIG_PCI */
+#endif /* ARCH_WANTS_GENERIC_IOMEM_IS_IOPORT */
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH v3 5/5] lib, pci: unify generic pci_iounmap()
2023-12-04 12:38 ` [PATCH v3 5/5] lib, pci: unify generic pci_iounmap() Philipp Stanner
@ 2023-12-04 13:39 ` Philipp Stanner
2023-12-04 13:50 ` Arnd Bergmann
2023-12-04 13:53 ` Arnd Bergmann
2023-12-05 10:44 ` kernel test robot
2 siblings, 1 reply; 16+ messages in thread
From: Philipp Stanner @ 2023-12-04 13:39 UTC (permalink / raw)
To: Bjorn Helgaas, Arnd Bergmann, Hanjun Guo, NeilBrown,
Kent Overstreet, Jakub Kicinski, Niklas Schnelle,
Uladzislau Koshchanka, John Sanpe, Dave Jiang,
Masami Hiramatsu (Google), Kees Cook, David Gow, Herbert Xu,
Shuah Khan, wuqiang.matt, Yury Norov, Jason Baron, Andrew Morton,
Ben Dooks, dakr
Cc: linux-kernel, linux-pci, linux-arch, stable, Arnd Bergmann
On Mon, 2023-12-04 at 13:38 +0100, Philipp Stanner wrote:
> The implementation of pci_iounmap() is currently scattered over two
> files, drivers/pci/iomap.c and lib/iomap.c. Additionally,
> architectures can define their own version.
>
> To have only one version, it's necessary to create a helper function,
> iomem_is_ioport(), that tells pci_iounmap() whether the passed
> address
> points to an ioport or normal memory.
>
> iomem_is_ioport() can be provided through two different ways:
> 1. The architecture itself provides it. As of today, the version
> coming from lib/iomap.c de facto is the x86-specific version and
> comes into play when CONFIG_GENERIC_IOMAP is selected. This
> rather
> confusing naming is an artifact left by the removal of IA64.
> 2. As a default version in include/asm-generic/io.h for those
> architectures that don't use CONFIG_GENERIC_IOMAP, but also
> don't
> provide their own version of iomem_is_ioport().
>
> Once all architectures that support ports provide iomem_is_ioport(),
> the
> arch-specific definitions for pci_iounmap() can be removed and the
> archs
> can use the generic implementation, instead.
>
> Create a unified version of pci_iounmap() in drivers/pci/iomap.c.
> Provide the function iomem_is_ioport() in include/asm-generic/io.h
> (generic) and lib/iomap.c ("pseudo-generic" for x86).
>
> Remove the CONFIG_GENERIC_IOMAP guard around
> ARCH_WANTS_GENERIC_PCI_IOUNMAP so that configs that set
> CONFIG_GENERIC_PCI_IOMAP without CONFIG_GENERIC_IOMAP still get the
> function.
>
> Add TODOs for follow-up work on the "generic is not generic but
> x86-spcific"-Problem.
>
> Suggested-by: Arnd Bergmann <arnd@kernel.org>
> Signed-off-by: Philipp Stanner <pstanner@redhat.com>
> ---
> drivers/pci/iomap.c | 46 ++++++++++++-----------------------
> --
> include/asm-generic/io.h | 27 ++++++++++++++++++++--
> include/asm-generic/iomap.h | 21 +++++++++++++++++
> lib/iomap.c | 28 ++++++++++++++++------
> 4 files changed, 82 insertions(+), 40 deletions(-)
>
> diff --git a/drivers/pci/iomap.c b/drivers/pci/iomap.c
> index 91285fcff1ba..439ba2e9710f 100644
> --- a/drivers/pci/iomap.c
> +++ b/drivers/pci/iomap.c
> @@ -135,44 +135,28 @@ void __iomem *pci_iomap_wc(struct pci_dev *dev,
> int bar, unsigned long maxlen)
> EXPORT_SYMBOL_GPL(pci_iomap_wc);
>
> /*
> - * pci_iounmap() somewhat illogically comes from lib/iomap.c for the
> - * CONFIG_GENERIC_IOMAP case, because that's the code that knows
> about
> - * the different IOMAP ranges.
> + * This check is still necessary due to legacy reasons.
> *
> - * But if the architecture does not use the generic iomap code, and
> if
> - * it has _not_ defined it's own private pci_iounmap function, we
> define
> - * it here.
> - *
> - * NOTE! This default implementation assumes that if the
> architecture
> - * support ioport mapping (HAS_IOPORT_MAP), the ioport mapping will
> - * be fixed to the range [ PCI_IOBASE, PCI_IOBASE+IO_SPACE_LIMIT [,
> - * and does not need unmapping with 'ioport_unmap()'.
> - *
> - * If you have different rules for your architecture, you need to
> - * implement your own pci_iounmap() that knows the rules for where
> - * and how IO vs MEM get mapped.
> - *
> - * This code is odd, and the ARCH_HAS/ARCH_WANTS #define logic comes
> - * from legacy <asm-generic/io.h> header file behavior. In
> particular,
> - * it would seem to make sense to do the iounmap(p) for the non-IO-
> space
> - * case here regardless, but that's not what the old header file
> code
> - * did. Probably incorrectly, but this is meant to be bug-for-bug
> - * compatible.
> + * TODO: Have all architectures that provide their own pci_iounmap()
> provide
> + * iomem_is_ioport() instead. Remove this #if afterwards.
> */
> #if defined(ARCH_WANTS_GENERIC_PCI_IOUNMAP)
>
> -void pci_iounmap(struct pci_dev *dev, void __iomem *p)
> +/**
> + * pci_iounmap - Unmapp a mapping
> + * @dev: PCI device the mapping belongs to
> + * @addr: start address of the mapping
> + *
> + * Unmapp a PIO or MMIO mapping.
> + */
> +void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
> {
> -#ifdef ARCH_HAS_GENERIC_IOPORT_MAP
> - uintptr_t start = (uintptr_t) PCI_IOBASE;
> - uintptr_t addr = (uintptr_t) p;
> -
> - if (addr >= start && addr < start + IO_SPACE_LIMIT) {
> - ioport_unmap(p);
> + if (iomem_is_ioport(addr)) {
> + ioport_unmap(addr);
> return;
> }
> -#endif
> - iounmap(p);
> +
> + iounmap(addr);
> }
> EXPORT_SYMBOL(pci_iounmap);
>
> diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
> index bac63e874c7b..58c7bf4080da 100644
> --- a/include/asm-generic/io.h
> +++ b/include/asm-generic/io.h
> @@ -1129,11 +1129,34 @@ extern void ioport_unmap(void __iomem *p);
> #endif /* CONFIG_GENERIC_IOMAP */
> #endif /* CONFIG_HAS_IOPORT_MAP */
>
> -#ifndef CONFIG_GENERIC_IOMAP
> +/*
> + * TODO:
> + * remove this once all architectures replaced their pci_iounmap()
> with
> + * a custom implementation of iomem_is_ioport().
> + */
> #ifndef pci_iounmap
> +#define pci_iounmap pci_iounmap
> #define ARCH_WANTS_GENERIC_PCI_IOUNMAP
> +#endif /* pci_iounmap */
> +
> +/*
> + * This function is a helper only needed for the generic
> pci_iounmap().
> + * It's provided here if the architecture does not provide its own
> version.
> + */
> +#ifndef iomem_is_ioport
> +#define iomem_is_ioport iomem_is_ioport
> +static inline bool iomem_is_ioport(void __iomem *addr_raw)
> +{
> +#ifdef CONFIG_HAS_IOPORT
> + uintptr_t start = (uintptr_t)PCI_IOBASE;
> + uintptr_t addr = (uintptr_t)addr_raw;
> +
> + if (addr >= start && addr < start + IO_SPACE_LIMIT)
> + return true;
> #endif
> -#endif
> + return false;
> +}
> +#endif /* iomem_is_ioport */
>
> #ifndef xlate_dev_mem_ptr
> #define xlate_dev_mem_ptr xlate_dev_mem_ptr
> diff --git a/include/asm-generic/iomap.h b/include/asm-
> generic/iomap.h
> index 196087a8126e..2cdc6988a102 100644
> --- a/include/asm-generic/iomap.h
> +++ b/include/asm-generic/iomap.h
> @@ -110,6 +110,27 @@ static inline void __iomem
> *ioremap_np(phys_addr_t offset, size_t size)
> }
> #endif
>
> +/*
> + * If CONFIG_GENERIC_IOMAP is selected and the architecture does NOT
> provide its
> + * own version, ARCH_WANTS_GENERIC_IOMEM_IS_IOPORT makes sure that
> the generic
> + * version from asm-generic/io.h is NOT used and instead the second
> "generic"
> + * version from lib/iomap.c is used.
> + *
> + * There are currently two generic versions because of a difficult
> cleanup
> + * process. Namely, the version in lib/iomap.c once was really
> generic when IA64
> + * still existed. Today, it's only really used by x86.
> + *
> + * TODO: Move the version from lib/iomap.c to x86 specific code.
> Then, remove
> + * this ARCH_WANTS_GENERIC_IOMEM_IS_IOPORT-mechanism.
> + */
> +#ifdef CONFIG_GENERIC_IOMAP
> +#ifndef iomem_is_ioport
> +#define iomem_is_ioport iomem_is_ioport
> +bool iomem_is_ioport(void __iomem *addr);
> +#define ARCH_WANTS_GENERIC_IOMEM_IS_IOPORT
> +#endif /* iomem_is_ioport */
> +#endif /* CONFIG_GENERIC_IOMAP */
> +
> #include <asm-generic/pci_iomap.h>
>
> #endif
> diff --git a/lib/iomap.c b/lib/iomap.c
> index 4f8b31baa575..eb9a879ebf42 100644
> --- a/lib/iomap.c
> +++ b/lib/iomap.c
> @@ -418,12 +418,26 @@ EXPORT_SYMBOL(ioport_map);
> EXPORT_SYMBOL(ioport_unmap);
> #endif /* CONFIG_HAS_IOPORT_MAP */
>
> -#ifdef CONFIG_PCI
> -/* Hide the details if this is a MMIO or PIO address space and just
> do what
> - * you expect in the correct way. */
> -void pci_iounmap(struct pci_dev *dev, void __iomem * addr)
> +/*
> + * If CONFIG_GENERIC_IOMAP is selected and the architecture does NOT
> provide its
> + * own version, ARCH_WANTS_GENERIC_IOMEM_IS_IOPORT makes sure that
> the generic
> + * version from asm-generic/io.h is NOT used and instead the second
> "generic"
> + * version from this file here is used.
> + *
> + * There are currently two generic versions because of a difficult
> cleanup
> + * process. Namely, the version in lib/iomap.c once was really
> generic when IA64
> + * still existed. Today, it's only really used by x86.
> + *
> + * TODO: Move this function to x86-specific code.
> + */
> +#if defined(ARCH_WANTS_GENERIC_IOMEM_IS_IOPORT)
> +bool iomem_is_ioport(void __iomem *addr)
> {
> - IO_COND(addr, /* nothing */, iounmap(addr));
> + unsigned long port = (unsigned long __force)addr;
> +
> + if (port > PIO_OFFSET && port < PIO_RESERVED)
by the way:
Reading that again my instinctive feeling would be that it should be
port >= PIO_OFFSET.
This is, however, the exactly copied logic from the IO_COND macro in
lib/iomap.c. Is it possible that this macro contains a bug here?
P.
> + return true;
> +
> + return false;
> }
> -EXPORT_SYMBOL(pci_iounmap);
> -#endif /* CONFIG_PCI */
> +#endif /* ARCH_WANTS_GENERIC_IOMEM_IS_IOPORT */
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v3 5/5] lib, pci: unify generic pci_iounmap()
2023-12-04 13:39 ` Philipp Stanner
@ 2023-12-04 13:50 ` Arnd Bergmann
2023-12-04 14:09 ` Philipp Stanner
0 siblings, 1 reply; 16+ messages in thread
From: Arnd Bergmann @ 2023-12-04 13:50 UTC (permalink / raw)
To: Philipp Stanner, Bjorn Helgaas, Hanjun Guo, Neil Brown,
Kent Overstreet, Jakub Kicinski, Niklas Schnelle,
Uladzislau Koshchanka, John Sanpe, Dave Jiang, Masami Hiramatsu,
Kees Cook, David Gow, Herbert Xu, Shuah Khan, wuqiang.matt,
Yury Norov, Jason Baron, Andrew Morton, Ben Dooks,
Danilo Krummrich
Cc: linux-kernel, linux-pci, Linux-Arch, stable, Arnd Bergmann
On Mon, Dec 4, 2023, at 14:39, Philipp Stanner wrote:
> On Mon, 2023-12-04 at 13:38 +0100, Philipp Stanner wrote:
>> + */
>> +#if defined(ARCH_WANTS_GENERIC_IOMEM_IS_IOPORT)
>> +bool iomem_is_ioport(void __iomem *addr)
>> {
>> - IO_COND(addr, /* nothing */, iounmap(addr));
>> + unsigned long port = (unsigned long __force)addr;
>> +
>> + if (port > PIO_OFFSET && port < PIO_RESERVED)
>
> by the way:
> Reading that again my instinctive feeling would be that it should be
> port >= PIO_OFFSET.
>
> This is, however, the exactly copied logic from the IO_COND macro in
> lib/iomap.c. Is it possible that this macro contains a bug here?
Right, I think that would make more sense, but there is no
practical difference as long as I/O port 0 is always unused,
which is at least true on x86 because of PCIBIOS_MIN_IO.
Commit bb356ddb78b2 ("RISC-V: PCI: Avoid handing out address
0 to devices") describes how setting PCIBIOS_MIN_IO to 0
caused other problems.
I would just leave the logic consistent with IO_COND here,
or maybe use IO_COND() directly, like
IO_COND(addr, return true, /* nothing */);
return false;
Arnd
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v3 5/5] lib, pci: unify generic pci_iounmap()
2023-12-04 13:50 ` Arnd Bergmann
@ 2023-12-04 14:09 ` Philipp Stanner
2023-12-04 14:29 ` Arnd Bergmann
0 siblings, 1 reply; 16+ messages in thread
From: Philipp Stanner @ 2023-12-04 14:09 UTC (permalink / raw)
To: Arnd Bergmann, Bjorn Helgaas, Hanjun Guo, Neil Brown,
Kent Overstreet, Jakub Kicinski, Niklas Schnelle,
Uladzislau Koshchanka, John Sanpe, Dave Jiang, Masami Hiramatsu,
Kees Cook, David Gow, Herbert Xu, Shuah Khan, wuqiang.matt,
Yury Norov, Jason Baron, Andrew Morton, Ben Dooks,
Danilo Krummrich
Cc: linux-kernel, linux-pci, Linux-Arch, stable, Arnd Bergmann,
pstanner
On Mon, 2023-12-04 at 14:50 +0100, Arnd Bergmann wrote:
> On Mon, Dec 4, 2023, at 14:39, Philipp Stanner wrote:
> > On Mon, 2023-12-04 at 13:38 +0100, Philipp Stanner wrote:
>
> > > + */
> > > +#if defined(ARCH_WANTS_GENERIC_IOMEM_IS_IOPORT)
> > > +bool iomem_is_ioport(void __iomem *addr)
> > > {
> > > - IO_COND(addr, /* nothing */, iounmap(addr));
> > > + unsigned long port = (unsigned long __force)addr;
> > > +
> > > + if (port > PIO_OFFSET && port < PIO_RESERVED)
> >
> > by the way:
> > Reading that again my instinctive feeling would be that it should
> > be
> > port >= PIO_OFFSET.
> >
> > This is, however, the exactly copied logic from the IO_COND macro
> > in
> > lib/iomap.c. Is it possible that this macro contains a bug here?
>
> Right, I think that would make more sense, but there is no
> practical difference as long as I/O port 0 is always unused,
> which is at least true on x86 because of PCIBIOS_MIN_IO.
> Commit bb356ddb78b2 ("RISC-V: PCI: Avoid handing out address
> 0 to devices") describes how setting PCIBIOS_MIN_IO to 0
> caused other problems.
Ok, makes sense.
But should we then adjust iomem_is_ioport() in asm-generic/io.h, as
well, so that it matches IO_COND()'s behavior?
It currently does this:
uintptr_t start = (uintptr_t)PCI_IOBASE;
uintptr_t addr = (uintptr_t)addr_raw;
if (addr >= start && addr < start + IO_SPACE_LIMIT)
return true;
and if the architecture does not set PCI_IOBASE, then it's set per
default to 0, as well.
So we have two inconsistent definitons
>
> I would just leave the logic consistent with IO_COND here,
> or maybe use IO_COND() directly, like
>
> IO_COND(addr, return true, /* nothing */);
> return false;
I considered using it to increase consistency. However, I valued
improved readability more. Considering that the mid-term goal is to
move it to x86 anyways I'd like to leave it that way for now.
P.
>
> Arnd
>
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v3 5/5] lib, pci: unify generic pci_iounmap()
2023-12-04 14:09 ` Philipp Stanner
@ 2023-12-04 14:29 ` Arnd Bergmann
0 siblings, 0 replies; 16+ messages in thread
From: Arnd Bergmann @ 2023-12-04 14:29 UTC (permalink / raw)
To: Philipp Stanner, Bjorn Helgaas, Hanjun Guo, Neil Brown,
Kent Overstreet, Jakub Kicinski, Niklas Schnelle,
Uladzislau Koshchanka, John Sanpe, Dave Jiang, Masami Hiramatsu,
Kees Cook, David Gow, Herbert Xu, Shuah Khan, wuqiang.matt,
Yury Norov, Jason Baron, Andrew Morton, Ben Dooks,
Danilo Krummrich
Cc: linux-kernel, linux-pci, Linux-Arch, stable, Arnd Bergmann
On Mon, Dec 4, 2023, at 15:09, Philipp Stanner wrote:
> On Mon, 2023-12-04 at 14:50 +0100, Arnd Bergmann wrote:
>> On Mon, Dec 4, 2023, at 14:39, Philipp Stanner wrote:
>> > On Mon, 2023-12-04 at 13:38 +0100, Philipp Stanner wrote:
>
> Ok, makes sense.
>
> But should we then adjust iomem_is_ioport() in asm-generic/io.h, as
> well, so that it matches IO_COND()'s behavior?
>
> It currently does this:
>
> uintptr_t start = (uintptr_t)PCI_IOBASE;
> uintptr_t addr = (uintptr_t)addr_raw;
>
> if (addr >= start && addr < start + IO_SPACE_LIMIT)
> return true;
>
> and if the architecture does not set PCI_IOBASE, then it's set per
> default to 0, as well.
>
> So we have two inconsistent definitons
No, I would also keep the logic here, since it makes more sense
and the inconsistency is only for the corner case that doesn't
hit in practice.
The PCI_IOBASE==0 case should never happen here, as that doesn't
work with the generic inb(). I think the only target left that
has I/O ports but doesn't set PCI_IOBASE at all is sparc, but
that is special in a number of ways.
Arnd
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v3 5/5] lib, pci: unify generic pci_iounmap()
2023-12-04 12:38 ` [PATCH v3 5/5] lib, pci: unify generic pci_iounmap() Philipp Stanner
2023-12-04 13:39 ` Philipp Stanner
@ 2023-12-04 13:53 ` Arnd Bergmann
2023-12-05 10:44 ` kernel test robot
2 siblings, 0 replies; 16+ messages in thread
From: Arnd Bergmann @ 2023-12-04 13:53 UTC (permalink / raw)
To: Philipp Stanner, Bjorn Helgaas, Hanjun Guo, Neil Brown,
Kent Overstreet, Jakub Kicinski, Niklas Schnelle,
Uladzislau Koshchanka, John Sanpe, Dave Jiang, Masami Hiramatsu,
Kees Cook, David Gow, Herbert Xu, Shuah Khan, wuqiang.matt,
Yury Norov, Jason Baron, Andrew Morton, Ben Dooks,
Danilo Krummrich
Cc: linux-kernel, linux-pci, Linux-Arch, stable, Arnd Bergmann
On Mon, Dec 4, 2023, at 13:38, Philipp Stanner wrote:
> The implementation of pci_iounmap() is currently scattered over two
> files, drivers/pci/iomap.c and lib/iomap.c. Additionally,
> architectures can define their own version.
>
> To have only one version, it's necessary to create a helper function,
> iomem_is_ioport(), that tells pci_iounmap() whether the passed address
> points to an ioport or normal memory.
>
> iomem_is_ioport() can be provided through two different ways:
> 1. The architecture itself provides it. As of today, the version
> coming from lib/iomap.c de facto is the x86-specific version and
> comes into play when CONFIG_GENERIC_IOMAP is selected. This rather
> confusing naming is an artifact left by the removal of IA64.
> 2. As a default version in include/asm-generic/io.h for those
> architectures that don't use CONFIG_GENERIC_IOMAP, but also don't
> provide their own version of iomem_is_ioport().
>
> Once all architectures that support ports provide iomem_is_ioport(), the
> arch-specific definitions for pci_iounmap() can be removed and the archs
> can use the generic implementation, instead.
>
> Create a unified version of pci_iounmap() in drivers/pci/iomap.c.
> Provide the function iomem_is_ioport() in include/asm-generic/io.h
> (generic) and lib/iomap.c ("pseudo-generic" for x86).
>
> Remove the CONFIG_GENERIC_IOMAP guard around
> ARCH_WANTS_GENERIC_PCI_IOUNMAP so that configs that set
> CONFIG_GENERIC_PCI_IOMAP without CONFIG_GENERIC_IOMAP still get the
> function.
>
> Add TODOs for follow-up work on the "generic is not generic but
> x86-spcific"-Problem.
>
> Suggested-by: Arnd Bergmann <arnd@kernel.org>
> Signed-off-by: Philipp Stanner <pstanner@redhat.com>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v3 5/5] lib, pci: unify generic pci_iounmap()
2023-12-04 12:38 ` [PATCH v3 5/5] lib, pci: unify generic pci_iounmap() Philipp Stanner
2023-12-04 13:39 ` Philipp Stanner
2023-12-04 13:53 ` Arnd Bergmann
@ 2023-12-05 10:44 ` kernel test robot
2023-12-05 14:34 ` Philipp Stanner
2 siblings, 1 reply; 16+ messages in thread
From: kernel test robot @ 2023-12-05 10:44 UTC (permalink / raw)
To: Philipp Stanner, Bjorn Helgaas, Arnd Bergmann, Hanjun Guo,
NeilBrown, Kent Overstreet, Jakub Kicinski, Niklas Schnelle,
Uladzislau Koshchanka, John Sanpe, Dave Jiang,
Masami Hiramatsu (Google), Kees Cook, David Gow, Herbert Xu,
Shuah Khan, wuqiang.matt, Yury Norov, Jason Baron, Andrew Morton,
Ben Dooks, dakr
Cc: oe-kbuild-all, Linux Memory Management List, linux-kernel,
linux-pci, linux-arch, stable
Hi Philipp,
kernel test robot noticed the following build errors:
[auto build test ERROR on pci/next]
[also build test ERROR on pci/for-linus arnd-asm-generic/master kees/for-next/pstore kees/for-next/kspp linus/master v6.7-rc4 next-20231205]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Philipp-Stanner/lib-pci_iomap-c-fix-cleanup-bugs-in-pci_iounmap/20231204-204128
base: https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git next
patch link: https://lore.kernel.org/r/20231204123834.29247-6-pstanner%40redhat.com
patch subject: [PATCH v3 5/5] lib, pci: unify generic pci_iounmap()
config: openrisc-virt_defconfig (https://download.01.org/0day-ci/archive/20231205/202312051813.09WbvusW-lkp@intel.com/config)
compiler: or1k-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231205/202312051813.09WbvusW-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202312051813.09WbvusW-lkp@intel.com/
All errors (new ones prefixed by >>):
drivers/pci/iomap.c: In function 'pci_iounmap':
>> drivers/pci/iomap.c:155:17: error: implicit declaration of function 'ioport_unmap'; did you mean 'devm_ioport_unmap'? [-Werror=implicit-function-declaration]
155 | ioport_unmap(addr);
| ^~~~~~~~~~~~
| devm_ioport_unmap
cc1: some warnings being treated as errors
vim +155 drivers/pci/iomap.c
144
145 /**
146 * pci_iounmap - Unmapp a mapping
147 * @dev: PCI device the mapping belongs to
148 * @addr: start address of the mapping
149 *
150 * Unmapp a PIO or MMIO mapping.
151 */
152 void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
153 {
154 if (iomem_is_ioport(addr)) {
> 155 ioport_unmap(addr);
156 return;
157 }
158
159 iounmap(addr);
160 }
161 EXPORT_SYMBOL(pci_iounmap);
162
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v3 5/5] lib, pci: unify generic pci_iounmap()
2023-12-05 10:44 ` kernel test robot
@ 2023-12-05 14:34 ` Philipp Stanner
2023-12-05 14:43 ` Arnd Bergmann
0 siblings, 1 reply; 16+ messages in thread
From: Philipp Stanner @ 2023-12-05 14:34 UTC (permalink / raw)
To: kernel test robot, Bjorn Helgaas, Arnd Bergmann, Hanjun Guo,
NeilBrown, Kent Overstreet, Jakub Kicinski, Niklas Schnelle,
Uladzislau Koshchanka, John Sanpe, Dave Jiang,
Masami Hiramatsu (Google), Kees Cook, David Gow, Herbert Xu,
Shuah Khan, wuqiang.matt, Yury Norov, Jason Baron, Andrew Morton,
Ben Dooks, dakr
Cc: oe-kbuild-all, Linux Memory Management List, linux-kernel,
linux-pci, linux-arch, stable
Alright, so it seems that not all architectures provide ioport_unmap().
So I'll provide yet another preprocessor guard in v4. Wohooo, we love
them...
P.
On Tue, 2023-12-05 at 18:44 +0800, kernel test robot wrote:
> Hi Philipp,
>
> kernel test robot noticed the following build errors:
>
> [auto build test ERROR on pci/next]
> [also build test ERROR on pci/for-linus arnd-asm-generic/master
> kees/for-next/pstore kees/for-next/kspp linus/master v6.7-rc4 next-
> 20231205]
> [If your patch is applied to the wrong git tree, kindly drop us a
> note.
> And when submitting patch, we suggest to use '--base' as documented
> in
> https://git-scm.com/docs/git-format-patch#_base_tree_information]
>
> url:
> https://github.com/intel-lab-lkp/linux/commits/Philipp-Stanner/lib-pci_iomap-c-fix-cleanup-bugs-in-pci_iounmap/20231204-204128
> base:
> https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git next
> patch link:
> https://lore.kernel.org/r/20231204123834.29247-6-pstanner%40redhat.com
> patch subject: [PATCH v3 5/5] lib, pci: unify generic pci_iounmap()
> config: openrisc-virt_defconfig
> (https://download.01.org/0day-ci/archive/20231205/202312051813.09Wbvu
> sW-lkp@intel.com/config)
> compiler: or1k-linux-gcc (GCC) 13.2.0
> reproduce (this is a W=1 build):
> (https://download.01.org/0day-ci/archive/20231205/202312051813.09Wbvu
> sW-lkp@intel.com/reproduce)
>
> If you fix the issue in a separate patch/commit (i.e. not just a new
> version of
> the same patch/commit), kindly add following tags
> > Reported-by: kernel test robot <lkp@intel.com>
> > Closes:
> > https://lore.kernel.org/oe-kbuild-all/202312051813.09WbvusW-lkp@intel.com/
>
> All errors (new ones prefixed by >>):
>
> drivers/pci/iomap.c: In function 'pci_iounmap':
> > > drivers/pci/iomap.c:155:17: error: implicit declaration of
> > > function 'ioport_unmap'; did you mean 'devm_ioport_unmap'? [-
> > > Werror=implicit-function-declaration]
> 155 | ioport_unmap(addr);
> | ^~~~~~~~~~~~
> | devm_ioport_unmap
> cc1: some warnings being treated as errors
>
>
> vim +155 drivers/pci/iomap.c
>
> 144
> 145 /**
> 146 * pci_iounmap - Unmapp a mapping
> 147 * @dev: PCI device the mapping belongs to
> 148 * @addr: start address of the mapping
> 149 *
> 150 * Unmapp a PIO or MMIO mapping.
> 151 */
> 152 void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
> 153 {
> 154 if (iomem_is_ioport(addr)) {
> > 155 ioport_unmap(addr);
> 156 return;
> 157 }
> 158
> 159 iounmap(addr);
> 160 }
> 161 EXPORT_SYMBOL(pci_iounmap);
> 162
>
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v3 5/5] lib, pci: unify generic pci_iounmap()
2023-12-05 14:34 ` Philipp Stanner
@ 2023-12-05 14:43 ` Arnd Bergmann
0 siblings, 0 replies; 16+ messages in thread
From: Arnd Bergmann @ 2023-12-05 14:43 UTC (permalink / raw)
To: Philipp Stanner, kernel test robot, Bjorn Helgaas, Hanjun Guo,
Neil Brown, Kent Overstreet, Jakub Kicinski, Niklas Schnelle,
Uladzislau Koshchanka, John Sanpe, Dave Jiang, Masami Hiramatsu,
Kees Cook, David Gow, Herbert Xu, Shuah Khan, wuqiang.matt,
Yury Norov, Jason Baron, Andrew Morton, Ben Dooks,
Danilo Krummrich
Cc: oe-kbuild-all, Linux Memory Management List, linux-kernel,
linux-pci, Linux-Arch, stable
On Tue, Dec 5, 2023, at 15:34, Philipp Stanner wrote:
> Alright, so it seems that not all architectures provide ioport_unmap().
> So I'll provide yet another preprocessor guard in v4. Wohooo, we love
> them...
Right, I think CONFIG_HAS_IOPORT_MAP is the symbol you
need to check here. There are a few targets that have inb/outb
but can't map them to __iomem pointers for some reason,
as well as more that have neither CONFIG_HAS_IOPORT nor
CONFIG_HAS_IOPORT_MAP.
Arnd
^ permalink raw reply [flat|nested] 16+ messages in thread