diff mbox series

[v2,10/25] asm-generic/io.h: Add a non-posted variant of ioremap()

Message ID 20210215121713.57687-11-marcan@marcan.st (mailing list archive)
State New, archived
Headers show
Series Apple M1 SoC platform bring-up | expand

Commit Message

Hector Martin Feb. 15, 2021, 12:16 p.m. UTC
ARM64 currently defaults to posted MMIO (nGnRnE), but some devices
require the use of non-posted MMIO (nGnRE). Introduce a new ioremap()
variant to handle this case. ioremap_np() is aliased to ioremap() by
default on arches that do not implement this variant.

This adds the IORESOURCE_MEM_NONPOSTED flag, which maps to this
variant and marks a given resource as requiring non-posted mappings.
This is implemented in the resource system because it is a SoC-level
requirement, so existing drivers do not need special-case code to pick
this ioremap variant.

Then this is implemented in devres by introducing devm_ioremap_np(),
and making devm_ioremap_resource() automatically select this variant
when the resource has the IORESOURCE_MEM_NONPOSTED flag set.

Signed-off-by: Hector Martin <marcan@marcan.st>
---
 include/asm-generic/io.h |  8 +++++++-
 include/linux/io.h       |  2 ++
 include/linux/ioport.h   |  1 +
 lib/devres.c             | 22 ++++++++++++++++++++++
 4 files changed, 32 insertions(+), 1 deletion(-)

Comments

kernel test robot Feb. 15, 2021, 3:27 p.m. UTC | #1
Hi Hector,

I love your patch! Yet something to improve:

[auto build test ERROR on arm64/for-next/core]
[also build test ERROR on robh/for-next tty/tty-testing linus/master v5.11 next-20210212]
[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]

url:    https://github.com/0day-ci/linux/commits/Hector-Martin/Apple-M1-SoC-platform-bring-up/20210215-202520
base:   https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-next/core
config: mips-randconfig-r002-20210215 (attached as .config)
compiler: mips64-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/9785be3c8ec6cb8530d72cff794f5c22414f5a3e
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Hector-Martin/Apple-M1-SoC-platform-bring-up/20210215-202520
        git checkout 9785be3c8ec6cb8530d72cff794f5c22414f5a3e
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=mips 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   lib/devres.c: In function '__devm_ioremap':
>> lib/devres.c:47:10: error: implicit declaration of function 'ioremap_np'; did you mean 'ioremap_uc'? [-Werror=implicit-function-declaration]
      47 |   addr = ioremap_np(offset, size);
         |          ^~~~~~~~~~
         |          ioremap_uc
   lib/devres.c:47:8: warning: assignment to 'void *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
      47 |   addr = ioremap_np(offset, size);
         |        ^
   cc1: some warnings being treated as errors


vim +47 lib/devres.c

    25	
    26	static void __iomem *__devm_ioremap(struct device *dev, resource_size_t offset,
    27					    resource_size_t size,
    28					    enum devm_ioremap_type type)
    29	{
    30		void __iomem **ptr, *addr = NULL;
    31	
    32		ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL);
    33		if (!ptr)
    34			return NULL;
    35	
    36		switch (type) {
    37		case DEVM_IOREMAP:
    38			addr = ioremap(offset, size);
    39			break;
    40		case DEVM_IOREMAP_UC:
    41			addr = ioremap_uc(offset, size);
    42			break;
    43		case DEVM_IOREMAP_WC:
    44			addr = ioremap_wc(offset, size);
    45			break;
    46		case DEVM_IOREMAP_NP:
  > 47			addr = ioremap_np(offset, size);
    48			break;
    49		}
    50	
    51		if (addr) {
    52			*ptr = addr;
    53			devres_add(dev, ptr);
    54		} else
    55			devres_free(ptr);
    56	
    57		return addr;
    58	}
    59	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Hector Martin Feb. 15, 2021, 4:47 p.m. UTC | #2
On 16/02/2021 00.27, kernel test robot wrote:
> config: mips-randconfig-r002-20210215 (attached as .config)
> compiler: mips64-linux-gcc (GCC) 9.3.0

>>> lib/devres.c:47:10: error: implicit declaration of function 'ioremap_np'; did you mean 'ioremap_uc'? [-Werror=implicit-function-declaration]
Well, today I learned that some architectures, like mips, only include
asm-generic/iomap.h, not asm-generic/io.h... and one, sparc64, includes
neither. That's unfortunate.

I added the missing bit to iomap.h, and a one-off patch to
arch/sparc/include/asm/io_64.h:

diff --git a/arch/sparc/include/asm/io_64.h b/arch/sparc/include/asm/io_64.h
index 9bb27e5c22f1..35470d275ddc 100644
--- a/arch/sparc/include/asm/io_64.h
+++ b/arch/sparc/include/asm/io_64.h
@@ -409,6 +409,7 @@ static inline void __iomem *ioremap(unsigned long offset, unsigned long size)
  #define ioremap_uc(X,Y)			ioremap((X),(Y))
  #define ioremap_wc(X,Y)			ioremap((X),(Y))
  #define ioremap_wt(X,Y)			ioremap((X),(Y))
+#define ioremap_np(X,Y)			ioremap((X),(Y))
  
  static inline void iounmap(volatile void __iomem *addr)
  {

David, is this okay? This series is headed for the soc tree, but I
wasn't expecting to have to touch arch-specific code for anything but
arm... you can see the rest of it here:

https://lore.kernel.org/linux-arm-kernel/YCqdi%2F5TSlbt0w%2F2@kroah.com/T/

I'll CC you on v3 if this works for you.
Christoph Hellwig Feb. 16, 2021, 10:53 a.m. UTC | #3
Your new iomremap variant needs proper documentation explaining the
semantics in detail.
Hector Martin Feb. 18, 2021, 1:08 p.m. UTC | #4
On 16/02/2021 19.53, Christoph Hellwig wrote:
> Your new iomremap variant needs proper documentation explaining the
> semantics in detail.

What's the right place for this? I haven't found any generic ioremap 
documentation page in the tree yet. I suppose I could write an 
ARM64-specific blurb on IO mapping modes, much like x86 has one...
diff mbox series

Patch

diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
index c6af40ce03be..43e4bb8d633c 100644
--- a/include/asm-generic/io.h
+++ b/include/asm-generic/io.h
@@ -942,7 +942,9 @@  static inline void *phys_to_virt(unsigned long address)
  *
  * ioremap_wc() and ioremap_wt() can provide more relaxed caching attributes
  * for specific drivers if the architecture choses to implement them.  If they
- * are not implemented we fall back to plain ioremap.
+ * are not implemented we fall back to plain ioremap. Conversely, ioremap_np()
+ * can provide stricter non-posted write semantics if the architecture
+ * implements them.
  */
 #ifndef CONFIG_MMU
 #ifndef ioremap
@@ -980,6 +982,10 @@  static inline void __iomem *ioremap(phys_addr_t addr, size_t size)
 #define ioremap_wt ioremap
 #endif
 
+#ifndef ioremap_np
+#define ioremap_np ioremap
+#endif
+
 /*
  * ioremap_uc is special in that we do require an explicit architecture
  * implementation.  In general you do not want to use this function in a
diff --git a/include/linux/io.h b/include/linux/io.h
index 8394c56babc2..d718354ed3e1 100644
--- a/include/linux/io.h
+++ b/include/linux/io.h
@@ -68,6 +68,8 @@  void __iomem *devm_ioremap_uc(struct device *dev, resource_size_t offset,
 				   resource_size_t size);
 void __iomem *devm_ioremap_wc(struct device *dev, resource_size_t offset,
 				   resource_size_t size);
+void __iomem *devm_ioremap_np(struct device *dev, resource_size_t offset,
+				   resource_size_t size);
 void devm_iounmap(struct device *dev, void __iomem *addr);
 int check_signature(const volatile void __iomem *io_addr,
 			const unsigned char *signature, int length);
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index fe48b7840665..5929a67570ae 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -108,6 +108,7 @@  struct resource {
 #define IORESOURCE_MEM_32BIT		(3<<3)
 #define IORESOURCE_MEM_SHADOWABLE	(1<<5)	/* dup: IORESOURCE_SHADOWABLE */
 #define IORESOURCE_MEM_EXPANSIONROM	(1<<6)
+#define IORESOURCE_MEM_NONPOSTED	(1<<7)
 
 /* PnP I/O specific bits (IORESOURCE_BITS) */
 #define IORESOURCE_IO_16BIT_ADDR	(1<<0)
diff --git a/lib/devres.c b/lib/devres.c
index 2a4ff5d64288..4679dbb1bf5f 100644
--- a/lib/devres.c
+++ b/lib/devres.c
@@ -10,6 +10,7 @@  enum devm_ioremap_type {
 	DEVM_IOREMAP = 0,
 	DEVM_IOREMAP_UC,
 	DEVM_IOREMAP_WC,
+	DEVM_IOREMAP_NP,
 };
 
 void devm_ioremap_release(struct device *dev, void *res)
@@ -42,6 +43,9 @@  static void __iomem *__devm_ioremap(struct device *dev, resource_size_t offset,
 	case DEVM_IOREMAP_WC:
 		addr = ioremap_wc(offset, size);
 		break;
+	case DEVM_IOREMAP_NP:
+		addr = ioremap_np(offset, size);
+		break;
 	}
 
 	if (addr) {
@@ -98,6 +102,21 @@  void __iomem *devm_ioremap_wc(struct device *dev, resource_size_t offset,
 }
 EXPORT_SYMBOL(devm_ioremap_wc);
 
+/**
+ * devm_ioremap_np - Managed ioremap_np()
+ * @dev: Generic device to remap IO address for
+ * @offset: Resource address to map
+ * @size: Size of map
+ *
+ * Managed ioremap_np().  Map is automatically unmapped on driver detach.
+ */
+void __iomem *devm_ioremap_np(struct device *dev, resource_size_t offset,
+			      resource_size_t size)
+{
+	return __devm_ioremap(dev, offset, size, DEVM_IOREMAP_NP);
+}
+EXPORT_SYMBOL(devm_ioremap_np);
+
 /**
  * devm_iounmap - Managed iounmap()
  * @dev: Generic device to unmap for
@@ -128,6 +147,9 @@  __devm_ioremap_resource(struct device *dev, const struct resource *res,
 		return IOMEM_ERR_PTR(-EINVAL);
 	}
 
+	if (type == DEVM_IOREMAP && res->flags & IORESOURCE_MEM_NONPOSTED)
+		type = DEVM_IOREMAP_NP;
+
 	size = resource_size(res);
 
 	if (res->name)