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
next prev 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®