2015-08-29 00:17:35

by Luis Chamberlain

[permalink] [raw]
Subject: [RFC] asm-generic/pci_iomap.h: make custom PCI BAR requirements explicit

From: "Luis R. Rodriguez" <[email protected]>

The S390 architecture requires a custom pci_iomap() implementation
as the asm-generic implementation assumes there are disjunctions
between PCI BARs, and on S390 PCI BAR are not disjunctive, S390 requires
the bar parameter in order to find the corresponding device and create
the mapping cookie.

This clash with the asm-generic pci_iomap() implementation is implicit,
there are no current semantics to make this incompatability explicit.
Make the S390 PCI BAR non-disjunction incompatibility explicit, and
also pave the way for alternative incompatibilities to be defined.

While at it, as with the ioremap*() variants, since we have no clear
semantics yet well defined provide a solution for them that returns
NULL. This allows architectures to move forward by defining pci_ioremap*()
variants without requiring immediate changes to all architectures. Each
architecture then can implement their own solution as needed and
when they get to it.

Build tested with allyesconfig on:

* S390
* x86_64

Signed-off-by: Luis R. Rodriguez <[email protected]>
---

This came up as an idea after noting that S390 has no way to be
explicit about its requirements, this also means we don't have a
quick easy way to ensure that other architectures might have a
conflict as well. This provides an easy way to do that by having
the architectures define their incompatibilities and allowing those
then to negate GENERIC_PCI_IOMAP on lib/Kconfig.

I think a next cleanup could be the move of the pci_iounmap() out to
pci_iomap.h to avoid having each arch having to declare it. That's
a separate atomic change though so should go in separately.

I am not sure if this is the best name for this incompatibility, please
let me know.

arch/s390/Kconfig | 8 +++++
arch/s390/include/asm/io.h | 11 -------
arch/s390/include/asm/pci.h | 2 --
arch/s390/include/asm/pci_iomap.h | 33 +++++++++++++++++++++
arch/s390/pci/pci.c | 2 ++
include/asm-generic/io.h | 12 --------
include/asm-generic/iomap.h | 10 -------
include/asm-generic/pci_iomap.h | 62 +++++++++++++++++++++++++++++++++++----
lib/Kconfig | 1 +
lib/pci_iomap.c | 5 ++++
10 files changed, 105 insertions(+), 41 deletions(-)
create mode 100644 arch/s390/include/asm/pci_iomap.h

diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 1d57000b1b24..1217b7db4265 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -614,6 +614,14 @@ endif # PCI
config PCI_DOMAINS
def_bool PCI

+config ARCH_PCI_NON_DISJUNCTIVE
+ def_bool PCI
+ help
+ On the S390 architecture PCI BAR spaces are not disjunctive, as such
+ the PCI bar is required on a series of otherwise asm generic PCI
+ routines, as such S390 requires itw own implemention for these
+ routines.
+
config HAS_IOMEM
def_bool PCI

diff --git a/arch/s390/include/asm/io.h b/arch/s390/include/asm/io.h
index 437e9af96688..27443c778367 100644
--- a/arch/s390/include/asm/io.h
+++ b/arch/s390/include/asm/io.h
@@ -49,17 +49,6 @@ static inline void ioport_unmap(void __iomem *p)
{
}

-/*
- * s390 needs a private implementation of pci_iomap since ioremap with its
- * offset parameter isn't sufficient. That's because BAR spaces are not
- * disjunctive on s390 so we need the bar parameter of pci_iomap to find
- * the corresponding device and create the mapping cookie.
- */
-#define pci_iomap pci_iomap
-#define pci_iounmap pci_iounmap
-#define pci_iomap_wc pci_iomap
-#define pci_iomap_wc_range pci_iomap_range
-
#define memcpy_fromio(dst, src, count) zpci_memcpy_fromio(dst, src, count)
#define memcpy_toio(dst, src, count) zpci_memcpy_toio(dst, src, count)
#define memset_io(dst, val, count) zpci_memset_io(dst, val, count)
diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h
index 34d960353a08..51a0a426a6e3 100644
--- a/arch/s390/include/asm/pci.h
+++ b/arch/s390/include/asm/pci.h
@@ -18,8 +18,6 @@

#define pcibios_assign_all_busses() (0)

-void __iomem *pci_iomap(struct pci_dev *, int, unsigned long);
-void pci_iounmap(struct pci_dev *, void __iomem *);
int pci_domain_nr(struct pci_bus *);
int pci_proc_domain(struct pci_bus *);

diff --git a/arch/s390/include/asm/pci_iomap.h b/arch/s390/include/asm/pci_iomap.h
new file mode 100644
index 000000000000..b897ff4cac59
--- /dev/null
+++ b/arch/s390/include/asm/pci_iomap.h
@@ -0,0 +1,33 @@
+#ifndef _S390_ASM_PCI_IOMAP_H
+#define _S390_ASM_PCI_IOMAP_H
+/*
+ * S390 version
+ */
+#include <linux/kernel.h>
+#include <asm/page.h>
+#include <asm/pci_io.h>
+
+#ifdef CONFIG_PCI
+
+struct pci_dev;
+
+/*
+ * s390 needs a private implementation of pci_iomap since ioremap with its
+ * offset parameter isn't sufficient. That's because BAR spaces are not
+ * disjunctive on s390 so we need the bar parameter of pci_iomap to find
+ * the corresponding device and create the mapping cookie.
+ */
+
+/* XXX: in the future we'll remove these */
+#define pci_iounmap pci_iounmap
+void pci_iounmap(struct pci_dev *, void __iomem *);
+
+/* Annotate pci_iomap*() variant solutions have been reviewed and vetted */
+#define pci_iomap_wc pci_iomap
+#define pci_iomap_wc_range pci_iomap_range
+
+#include <asm-generic/pci_iomap.h>
+
+#endif /* CONFIG_PCI */
+
+#endif /* _S390_ASM_PCI_IOMAP_H */
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index 7ef12a3ace3a..92dd561bc89f 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -18,6 +18,8 @@
#define KMSG_COMPONENT "zpci"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt

+#include <asm/pci_iomap.h>
+
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/err.h>
diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
index eed3bbe88c8a..1f230d390740 100644
--- a/include/asm-generic/io.h
+++ b/include/asm-generic/io.h
@@ -704,18 +704,6 @@ static inline void iowrite32_rep(volatile void __iomem *addr,
#include <linux/vmalloc.h>
#define __io_virt(x) ((void __force *)(x))

-#ifndef CONFIG_GENERIC_IOMAP
-struct pci_dev;
-extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
-
-#ifndef pci_iounmap
-#define pci_iounmap pci_iounmap
-static inline void pci_iounmap(struct pci_dev *dev, void __iomem *p)
-{
-}
-#endif
-#endif /* CONFIG_GENERIC_IOMAP */
-
/*
* Change virtual addresses to physical addresses and vv.
* These are pretty trivial
diff --git a/include/asm-generic/iomap.h b/include/asm-generic/iomap.h
index d8f8622fa044..af49a46585ad 100644
--- a/include/asm-generic/iomap.h
+++ b/include/asm-generic/iomap.h
@@ -70,16 +70,6 @@ extern void ioport_unmap(void __iomem *);
#define ioremap_wt ioremap_nocache
#endif

-#ifdef CONFIG_PCI
-/* Destroy a virtual mapping cookie for a PCI BAR (memory or IO) */
-struct pci_dev;
-extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
-#elif defined(CONFIG_GENERIC_IOMAP)
-struct pci_dev;
-static inline void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
-{ }
-#endif
-
#include <asm-generic/pci_iomap.h>

#endif
diff --git a/include/asm-generic/pci_iomap.h b/include/asm-generic/pci_iomap.h
index b1e17fcee2d0..9f04547a00a9 100644
--- a/include/asm-generic/pci_iomap.h
+++ b/include/asm-generic/pci_iomap.h
@@ -12,16 +12,62 @@
#define __ASM_GENERIC_PCI_IOMAP_H

struct pci_dev;
+
#ifdef CONFIG_PCI
-/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
-extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
-extern void __iomem *pci_iomap_wc(struct pci_dev *dev, int bar, unsigned long max);
extern void __iomem *pci_iomap_range(struct pci_dev *dev, int bar,
unsigned long offset,
unsigned long maxlen);
+extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
+extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
+
+/**
+ * DOC: pci_iomap(), pci_iomap_range() and pci_iomap*() variants
+ *
+ * pci_iomap() creates a virtual mapping cookie for a PCI BAR (memory or IO).
+ *
+ * If your architecture supports PCI you must either rely on the asm-generic
+ * solution for pci_iomap() and pci_iomap_range() or your architecture must
+ * implement your own solution. You may require your own implementation if
+ * your architecture PCI requirements are outside the norm of other
+ * architectures. If your architecture adheres to the norm your architecture
+ * will select GENERIC_PCI_IOMAP. GENERIC_PCI_IOMAP will negate known
+ * incompatible architecture PCI solutions which require more special
+ * handling.
+ *
+ * There are also pci_iomap*() and pci_iomap_*_range() call variants, if you
+ * have custom PCI requirements you must define the proper implementation
+ * for these otherwise the defaults defined here will return NULL.
+ *
+ * If you selected CONFIG_GENERIC_PCI_IOMAP you can also override default
+ * pci_iomap*() variants by defining them in your architecture pci_iomap.h.
+ */
+#ifdef CONFIG_GENERIC_PCI_IOMAP
extern void __iomem *pci_iomap_wc_range(struct pci_dev *dev, int bar,
unsigned long offset,
unsigned long maxlen);
+extern void __iomem *pci_iomap_wc(struct pci_dev *dev, int bar, unsigned long max);
+#else /* !CONFIG_GENERIC_PCI_IOMAP */
+
+#ifndef pci_iomap_wc
+#define pci_iomap_wc pci_iomap_wc
+static inline void __iomem *pci_iomap_wc(struct pci_dev *dev, int bar, unsigned long max)
+{
+ return NULL;
+}
+#endif
+
+#ifndef pci_iomap_wc_range
+#define pci_iomap_wc_range pci_iomap_wc_range
+static inline void __iomem *pci_iomap_wc_range(struct pci_dev *dev, int bar,
+ unsigned long offset,
+ unsigned long maxlen)
+{
+ return NULL;
+}
+#endif
+
+#endif /* !CONFIG_GENERIC_PCI_IOMAP */
+
/* Create a virtual mapping cookie for a port on a given PCI device.
* Do not call this directly, it exists to make it easier for architectures
* to override */
@@ -32,7 +78,7 @@ extern void __iomem *__pci_ioport_map(struct pci_dev *dev, unsigned long port,
#define __pci_ioport_map(dev, port, nr) ioport_map((port), (nr))
#endif

-#elif defined(CONFIG_GENERIC_PCI_IOMAP)
+#else /* !CONFIG_PCI */
static inline void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max)
{
return NULL;
@@ -54,6 +100,10 @@ static inline void __iomem *pci_iomap_wc_range(struct pci_dev *dev, int bar,
{
return NULL;
}
-#endif

-#endif /* __ASM_GENERIC_IO_H */
+static inline void pci_iounmap(struct pci_dev *dev, void __iomem *p)
+{
+}
+#endif /* !CONFIG_PCI */
+
+#endif /* __ASM_GENERIC_PCI_IOMAP_H */
diff --git a/lib/Kconfig b/lib/Kconfig
index 34f99838c20f..1416a41e9ea7 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -41,6 +41,7 @@ config NO_GENERIC_PCI_IOPORT_MAP

config GENERIC_PCI_IOMAP
bool
+ depends on !ARCH_PCI_NON_DISJUNCTIVE

config GENERIC_IOMAP
bool
diff --git a/lib/pci_iomap.c b/lib/pci_iomap.c
index c10fba461454..2502711c06ed 100644
--- a/lib/pci_iomap.c
+++ b/lib/pci_iomap.c
@@ -48,6 +48,7 @@ void __iomem *pci_iomap_range(struct pci_dev *dev,
}
EXPORT_SYMBOL(pci_iomap_range);

+#ifndef pci_iomap_wc_range
/**
* pci_iomap_wc_range - create a virtual WC mapping cookie for a PCI BAR
* @dev: PCI device that owns the BAR
@@ -92,6 +93,7 @@ void __iomem *pci_iomap_wc_range(struct pci_dev *dev,
return NULL;
}
EXPORT_SYMBOL_GPL(pci_iomap_wc_range);
+#endif

/**
* pci_iomap - create a virtual mapping cookie for a PCI BAR
@@ -113,6 +115,7 @@ void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
}
EXPORT_SYMBOL(pci_iomap);

+#ifndef pci_iomap_wc
/**
* pci_iomap_wc - create a virtual WC mapping cookie for a PCI BAR
* @dev: PCI device that owns the BAR
@@ -133,4 +136,6 @@ void __iomem *pci_iomap_wc(struct pci_dev *dev, int bar, unsigned long maxlen)
return pci_iomap_wc_range(dev, bar, 0, maxlen);
}
EXPORT_SYMBOL_GPL(pci_iomap_wc);
+#endif
+
#endif /* CONFIG_PCI */
--
2.4.3


2015-08-29 02:13:33

by Randy Dunlap

[permalink] [raw]
Subject: Re: [RFC] asm-generic/pci_iomap.h: make custom PCI BAR requirements explicit

On 08/28/15 17:17, Luis R. Rodriguez wrote:
>
> arch/s390/Kconfig | 8 +++++
> arch/s390/include/asm/io.h | 11 -------
> arch/s390/include/asm/pci.h | 2 --
> arch/s390/include/asm/pci_iomap.h | 33 +++++++++++++++++++++
> arch/s390/pci/pci.c | 2 ++
> include/asm-generic/io.h | 12 --------
> include/asm-generic/iomap.h | 10 -------
> include/asm-generic/pci_iomap.h | 62 +++++++++++++++++++++++++++++++++++----
> lib/Kconfig | 1 +
> lib/pci_iomap.c | 5 ++++
> 10 files changed, 105 insertions(+), 41 deletions(-)
> create mode 100644 arch/s390/include/asm/pci_iomap.h
>
> diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
> index 1d57000b1b24..1217b7db4265 100644
> --- a/arch/s390/Kconfig
> +++ b/arch/s390/Kconfig
> @@ -614,6 +614,14 @@ endif # PCI
> config PCI_DOMAINS
> def_bool PCI
>
> +config ARCH_PCI_NON_DISJUNCTIVE
> + def_bool PCI
> + help
> + On the S390 architecture PCI BAR spaces are not disjunctive, as such

are not disjoint? may be overlapping?

> + the PCI bar is required on a series of otherwise asm generic PCI
> + routines, as such S390 requires itw own implemention for these

its own implementation

> + routines.
> +
> config HAS_IOMEM
> def_bool PCI
>


--
~Randy

2015-08-29 15:25:12

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [RFC] asm-generic/pci_iomap.h: make custom PCI BAR requirements explicit

On Fri, Aug 28, 2015 at 05:17:27PM -0700, Luis R. Rodriguez wrote:
> From: "Luis R. Rodriguez" <[email protected]>
>
> The S390 architecture requires a custom pci_iomap() implementation
> as the asm-generic implementation assumes there are disjunctions
> between PCI BARs, and on S390 PCI BAR are not disjunctive, S390 requires
> the bar parameter in order to find the corresponding device and create
> the mapping cookie.
>
> This clash with the asm-generic pci_iomap() implementation is implicit,
> there are no current semantics to make this incompatability explicit.
> Make the S390 PCI BAR non-disjunction incompatibility explicit, and
> also pave the way for alternative incompatibilities to be defined.
>
> While at it, as with the ioremap*() variants, since we have no clear
> semantics yet well defined provide a solution for them that returns
> NULL. This allows architectures to move forward by defining pci_ioremap*()
> variants without requiring immediate changes to all architectures. Each
> architecture then can implement their own solution as needed and
> when they get to it.

Now that you have the config symbol available why not move the S390
implementation to generic code based on that can kill of
asm/pci_iomap.h? Seems like we're really not dealing with something
inherent to the architecture, but two possible implementations based
on architecture constraints.

2015-08-30 19:30:48

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [RFC] asm-generic/pci_iomap.h: make custom PCI BAR requirements explicit

On Friday 28 August 2015 17:17:27 Luis R. Rodriguez wrote:
> From: "Luis R. Rodriguez" <[email protected]>
>
> The S390 architecture requires a custom pci_iomap() implementation
> as the asm-generic implementation assumes there are disjunctions
> between PCI BARs, and on S390 PCI BAR are not disjunctive, S390 requires
> the bar parameter in order to find the corresponding device and create
> the mapping cookie.
>
> This clash with the asm-generic pci_iomap() implementation is implicit,
> there are no current semantics to make this incompatability explicit.
> Make the S390 PCI BAR non-disjunction incompatibility explicit, and
> also pave the way for alternative incompatibilities to be defined.

I don't think we really need to spell it out here. s390 PCI is different
from everybody else's in a lot of ways, so a simple 'depends on PCI &&
!S390' for CONFIG_PCI_IOMAP seems simpler and more intuitive.

> While at it, as with the ioremap*() variants, since we have no clear
> semantics yet well defined provide a solution for them that returns
> NULL. This allows architectures to move forward by defining pci_ioremap*()
> variants without requiring immediate changes to all architectures. Each
> architecture then can implement their own solution as needed and
> when they get to it.

Which architectures are you thinking about here?

> Build tested with allyesconfig on:
>
> * S390
> * x86_64
>
> Signed-off-by: Luis R. Rodriguez <[email protected]>

It's not really clear to me what the purpose of the patch is, is this
meant as a cleanup, or are you trying to avoid some real-life bugs
you ran into?

> This came up as an idea after noting that S390 has no way to be
> explicit about its requirements, this also means we don't have a
> quick easy way to ensure that other architectures might have a
> conflict as well. This provides an easy way to do that by having
> the architectures define their incompatibilities and allowing those
> then to negate GENERIC_PCI_IOMAP on lib/Kconfig.

PCI_IOMAP seems much simpler than ioport_map here, as a lot of
architectures can have overlapping port numbers across PCI host
bridges.

> I think a next cleanup could be the move of the pci_iounmap() out to
> pci_iomap.h to avoid having each arch having to declare it. That's
> a separate atomic change though so should go in separately.

pci_iounmap() is rather tricky, and I think some architectures currently
get it wrong and will actually unmap parts of the I/O port ranges from
the PCI host controller mapping. It might be rare enough that it never
caused problems (that got reported), but it might be nice to actually
provide an implementation that has a chance of working.

The version from lib/iomap.c seems correct for uses of CONFIG_GENERIC_IOMAP,
but most architectures can do better without that option.

Arnd