mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Vineet Gupta <vgupta@kernel.org>
To: linux-snps-arc@lists.infradead.org
Cc: linux-kernel@vger.kernel.org, Arnd Bergmann <arnd@arndb.de>,
	Vineet Gupta <vgupta@kernel.org>
Subject: [PATCH 2/2] ARC: io: use asm-generic MMIO accessors
Date: Tue,  3 Nov 2026 20:35:35 -0800	[thread overview]
Message-ID: <20261104043535.2039948-3-vgupta@kernel.org> (raw)
In-Reply-To: <20261104043535.2039948-1-vgupta@kernel.org>

ARC MMIO accessors use inline asm, which isn't really needed. It was
introduced with the original port back in 2013.

As the previous patch showed, inline asm can be error-prone. Letting the
compiler emit the accesses also allows 16-bit encodings, scaled-index
loads and folding constant offsets (s9) into the access.

Without the asm, ARC's __raw_{read,write}{b,w,l}(), *_relaxed(),
{read,write}{b,w,l}() and io{read,write}{16,32}be() are the same as the
asm-generic/io.h versions, so drop them and use the generic ones.

Two things stay ARC-specific:

- The barriers, now hooked into the generic accessors through
  __io_ar()/__io_bw(). On ARCv2 they remain dmb (rmb()/wmb()).
  On ARCompact they were empty, relying on the asm "memory" clobber
  as a compiler barrier, so make them barrier() explicitly.
  The generic defaults would be mb(), i.e. the heavyweight SYNC.
  The *_relaxed() accessors only need ordering against other MMIO
  accesses, which volatile guarantees.

- The {read,write}s{b,w,l}() string helpers, which, unlike the generic
  ones, cope with an unaligned memory buffer. They are defined before
  asm-generic/io.h is included, as it calls them (e.g. ioread8_rep()),
  so they do the volatile access directly rather than via __raw_*().

As a side effect, readX()/writeX() gain MMIO access tracing
(CONFIG_TRACE_MMIO_ACCESS).

vmlinux .text with GCC 16.2 (hsdk_defconfig): -5412 bytes.

Signed-off-by: Vineet Gupta <vgupta@kernel.org>
Assisted-by: Claude:claude-opus-5
---
 arch/arc/include/asm/io.h | 139 ++++++--------------------------------
 1 file changed, 19 insertions(+), 120 deletions(-)

diff --git a/arch/arc/include/asm/io.h b/arch/arc/include/asm/io.h
index b4a3393d1bdc..de929136c1a3 100644
--- a/arch/arc/include/asm/io.h
+++ b/arch/arc/include/asm/io.h
@@ -11,15 +11,26 @@
 #include <asm/page.h>
 #include <linux/unaligned.h>
 
-#ifdef CONFIG_ISA_ARCV2
 #include <asm/barrier.h>
+
+#ifdef CONFIG_ISA_ARCV2
 #define __iormb()		rmb()
 #define __iowmb()		wmb()
 #else
-#define __iormb()		do { } while (0)
-#define __iowmb()		do { } while (0)
+/*
+ * The accessors are plain volatile accesses, which the compiler only orders
+ * against other volatile accesses. Make readX()/writeX() compiler barriers so
+ * that e.g. DMA buffer writes are not moved past the MMIO write that starts
+ * the DMA. The asm-generic default, mb(), would be the heavyweight SYNC.
+ */
+#define __iormb()		barrier()
+#define __iowmb()		barrier()
 #endif
 
+/* Barriers for the asm-generic readX()/writeX() */
+#define __io_ar(v)		__iormb()
+#define __io_bw()		__iowmb()
+
 extern void __iomem *ioremap(phys_addr_t paddr, unsigned long size);
 #define ioremap ioremap
 #define ioremap_prot ioremap_prot
@@ -33,57 +44,6 @@ static inline void ioport_unmap(void __iomem *addr)
 {
 }
 
-/*
- * io{read,write}{16,32}be() macros
- */
-#define ioread16be(p)		({ u16 __v = be16_to_cpu((__force __be16)__raw_readw(p)); __iormb(); __v; })
-#define ioread32be(p)		({ u32 __v = be32_to_cpu((__force __be32)__raw_readl(p)); __iormb(); __v; })
-
-#define iowrite16be(v,p)	({ __iowmb(); __raw_writew((__force u16)cpu_to_be16(v), p); })
-#define iowrite32be(v,p)	({ __iowmb(); __raw_writel((__force u32)cpu_to_be32(v), p); })
-
-#define __raw_readb __raw_readb
-static inline u8 __raw_readb(const volatile void __iomem *addr)
-{
-	u8 b;
-
-	__asm__ __volatile__(
-	"	ldb%U1 %0, %1	\n"
-	: "=r" (b)
-	: "m" (*(volatile u8 __force *)addr)
-	: "memory");
-
-	return b;
-}
-
-#define __raw_readw __raw_readw
-static inline u16 __raw_readw(const volatile void __iomem *addr)
-{
-	u16 s;
-
-	__asm__ __volatile__(
-	"	ldw%U1 %0, %1	\n"
-	: "=r" (s)
-	: "m" (*(volatile u16 __force *)addr)
-	: "memory");
-
-	return s;
-}
-
-#define __raw_readl __raw_readl
-static inline u32 __raw_readl(const volatile void __iomem *addr)
-{
-	u32 w;
-
-	__asm__ __volatile__(
-	"	ld%U1 %0, %1	\n"
-	: "=r" (w)
-	: "m" (*(volatile u32 __force *)addr)
-	: "memory");
-
-	return w;
-}
-
 /*
  * {read,write}s{b,w,l}() repeatedly access the same IO address in
  * native endianness in 8-, 16-, 32-bit chunks {into,from} memory,
@@ -102,12 +62,12 @@ static inline void __raw_reads##f(const volatile void __iomem *addr,	\
 	/* Some ARC CPU's don't support unaligned accesses */		\
 	if (is_aligned) {						\
 		do {							\
-			u##t x = __raw_read##f(addr);			\
+			u##t x = *(const volatile u##t __force *)addr;	\
 			*buf++ = x;					\
 		} while (--count);					\
 	} else {							\
 		do {							\
-			u##t x = __raw_read##f(addr);			\
+			u##t x = *(const volatile u##t __force *)addr;	\
 			put_unaligned(x, buf++);			\
 		} while (--count);					\
 	}								\
@@ -120,43 +80,6 @@ __raw_readsx(16, w)
 #define __raw_readsl __raw_readsl
 __raw_readsx(32, l)
 
-#define __raw_writeb __raw_writeb
-static inline void __raw_writeb(u8 b, volatile void __iomem *addr)
-{
-	__asm__ __volatile__(
-	"	stb%U1 %0, %1	\n"
-	:
-	: "r" (b), "m" (*(volatile u8 __force *)addr)
-	: "memory");
-}
-
-#define __raw_writew __raw_writew
-static inline void __raw_writew(u16 s, volatile void __iomem *addr)
-{
-	/*
-	 * Not an "m" operand: GCC can pick a register-indexed address for it,
-	 * which ST doesn't support (GCC PR target/127718).
-	 */
-	__asm__ __volatile__(
-	"	stw %0, [%1]	\n"
-	:
-	: "r" (s), "r" (addr)
-	: "memory");
-
-}
-
-#define __raw_writel __raw_writel
-static inline void __raw_writel(u32 w, volatile void __iomem *addr)
-{
-	/* See __raw_writew() above for why this doesn't use an "m" operand. */
-	__asm__ __volatile__(
-	"	st %0, [%1]	\n"
-	:
-	: "r" (w), "r" (addr)
-	: "memory");
-
-}
-
 #define __raw_writesx(t,f)						\
 static inline void __raw_writes##f(volatile void __iomem *addr, 	\
 				   const void *ptr, unsigned int count)	\
@@ -170,11 +93,12 @@ static inline void __raw_writes##f(volatile void __iomem *addr, 	\
 	/* Some ARC CPU's don't support unaligned accesses */		\
 	if (is_aligned) {						\
 		do {							\
-			__raw_write##f(*buf++, addr);			\
+			*(volatile u##t __force *)addr = *buf++;	\
 		} while (--count);					\
 	} else {							\
 		do {							\
-			__raw_write##f(get_unaligned(buf++), addr);	\
+			u##t x = get_unaligned(buf++);			\
+			*(volatile u##t __force *)addr = x;		\
 		} while (--count);					\
 	}								\
 }
@@ -198,39 +122,14 @@ __raw_writesx(32, l)
  *
  * http://lkml.kernel.org/r/20150622133656.GG1583@arm.com
  */
-#define readb(c)		({ u8  __v = readb_relaxed(c); __iormb(); __v; })
-#define readw(c)		({ u16 __v = readw_relaxed(c); __iormb(); __v; })
-#define readl(c)		({ u32 __v = readl_relaxed(c); __iormb(); __v; })
 #define readsb(p,d,l)		({ __raw_readsb(p,d,l); __iormb(); })
 #define readsw(p,d,l)		({ __raw_readsw(p,d,l); __iormb(); })
 #define readsl(p,d,l)		({ __raw_readsl(p,d,l); __iormb(); })
 
-#define writeb(v,c)		({ __iowmb(); writeb_relaxed(v,c); })
-#define writew(v,c)		({ __iowmb(); writew_relaxed(v,c); })
-#define writel(v,c)		({ __iowmb(); writel_relaxed(v,c); })
 #define writesb(p,d,l)		({ __iowmb(); __raw_writesb(p,d,l); })
 #define writesw(p,d,l)		({ __iowmb(); __raw_writesw(p,d,l); })
 #define writesl(p,d,l)		({ __iowmb(); __raw_writesl(p,d,l); })
 
-/*
- * Relaxed API for drivers which can handle barrier ordering themselves
- *
- * Also these are defined to perform little endian accesses.
- * To provide the typical device register semantics of fixed endian,
- * swap the byte order for Big Endian
- *
- * http://lkml.kernel.org/r/201603100845.30602.arnd@arndb.de
- */
-#define readb_relaxed(c)	__raw_readb(c)
-#define readw_relaxed(c) ({ u16 __r = le16_to_cpu((__force __le16) \
-					__raw_readw(c)); __r; })
-#define readl_relaxed(c) ({ u32 __r = le32_to_cpu((__force __le32) \
-					__raw_readl(c)); __r; })
-
-#define writeb_relaxed(v,c)	__raw_writeb(v,c)
-#define writew_relaxed(v,c)	__raw_writew((__force u16) cpu_to_le16(v),c)
-#define writel_relaxed(v,c)	__raw_writel((__force u32) cpu_to_le32(v),c)
-
 #include <asm-generic/io.h>
 
 #endif /* _ASM_ARC_IO_H */
-- 
2.53.0


  parent reply	other threads:[~2026-11-04  4:35 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-04  4:35 [PATCH 0/2] ARC io-accessors updates for 7.4 Vineet Gupta
2026-11-04  4:35 ` [PATCH 1/2] ARC: io: work around GCC PR127718 in __raw_write{w,l}() Vineet Gupta
2026-11-04  4:35 ` Vineet Gupta [this message]
2026-11-04  7:40   ` [PATCH 2/2] ARC: io: use asm-generic MMIO accessors Arnd Bergmann

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261104043535.2039948-3-vgupta@kernel.org \
    --to=vgupta@kernel.org \
    --cc=arnd@arndb.de \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-snps-arc@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®