Skip to content

Commit b660d0a

Browse files
Julian Vetterarndb
authored andcommitted
New implementation for IO memcpy and IO memset
The IO memcpy and IO memset functions in asm-generic/io.h simply call memcpy and memset. This can lead to alignment problems or faults on architectures that do not define their own version and fall back to these defaults. This patch introduces new implementations for IO memcpy and IO memset, that use read{l,q} accessor functions, align accesses to machine word size, and resort to byte accesses when the target memory is not aligned. For new architectures and existing ones that were using the old fallbacks these functions are save to use, because IO memory constraints are taken into account. Moreover, architectures with similar implementations can now use these new versions, not needing to implement their own. Reviewed-by: Yann Sionneau <ysionneau@kalrayinc.com> Signed-off-by: Julian Vetter <jvetter@kalrayinc.com> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
1 parent d4d3125 commit b660d0a

3 files changed

Lines changed: 140 additions & 20 deletions

File tree

include/asm-generic/io.h

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,7 +1211,6 @@ static inline void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr)
12111211
#endif
12121212

12131213
#ifndef memset_io
1214-
#define memset_io memset_io
12151214
/**
12161215
* memset_io Set a range of I/O memory to a constant value
12171216
* @addr: The beginning of the I/O-memory range to set
@@ -1220,15 +1219,10 @@ static inline void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr)
12201219
*
12211220
* Set a range of I/O memory to a given value.
12221221
*/
1223-
static inline void memset_io(volatile void __iomem *addr, int value,
1224-
size_t size)
1225-
{
1226-
memset(__io_virt(addr), value, size);
1227-
}
1222+
void memset_io(volatile void __iomem *addr, int val, size_t count);
12281223
#endif
12291224

12301225
#ifndef memcpy_fromio
1231-
#define memcpy_fromio memcpy_fromio
12321226
/**
12331227
* memcpy_fromio Copy a block of data from I/O memory
12341228
* @dst: The (RAM) destination for the copy
@@ -1237,16 +1231,10 @@ static inline void memset_io(volatile void __iomem *addr, int value,
12371231
*
12381232
* Copy a block of data from I/O memory.
12391233
*/
1240-
static inline void memcpy_fromio(void *buffer,
1241-
const volatile void __iomem *addr,
1242-
size_t size)
1243-
{
1244-
memcpy(buffer, __io_virt(addr), size);
1245-
}
1234+
void memcpy_fromio(void *dst, const volatile void __iomem *src, size_t count);
12461235
#endif
12471236

12481237
#ifndef memcpy_toio
1249-
#define memcpy_toio memcpy_toio
12501238
/**
12511239
* memcpy_toio Copy a block of data into I/O memory
12521240
* @dst: The (I/O memory) destination for the copy
@@ -1255,11 +1243,7 @@ static inline void memcpy_fromio(void *buffer,
12551243
*
12561244
* Copy a block of data to I/O memory.
12571245
*/
1258-
static inline void memcpy_toio(volatile void __iomem *addr, const void *buffer,
1259-
size_t size)
1260-
{
1261-
memcpy(__io_virt(addr), buffer, size);
1262-
}
1246+
void memcpy_toio(volatile void __iomem *dst, const void *src, size_t count);
12631247
#endif
12641248

12651249
extern int devmem_is_allowed(unsigned long pfn);

lib/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \
3535
is_single_threaded.o plist.o decompress.o kobject_uevent.o \
3636
earlycpio.o seq_buf.o siphash.o dec_and_lock.o \
3737
nmi_backtrace.o win_minmax.o memcat_p.o \
38-
buildid.o objpool.o union_find.o
38+
buildid.o objpool.o union_find.o iomem_copy.o
3939

4040
lib-$(CONFIG_PRINTK) += dump_stack.o
4141
lib-$(CONFIG_SMP) += cpumask.o

lib/iomem_copy.c

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Copyright 2024 Kalray, Inc. All Rights Reserved.
4+
*/
5+
6+
#include <linux/align.h>
7+
#include <linux/export.h>
8+
#include <linux/io.h>
9+
#include <linux/types.h>
10+
#include <linux/unaligned.h>
11+
12+
#ifndef memset_io
13+
/**
14+
* memset_io Set a range of I/O memory to a constant value
15+
* @addr: The beginning of the I/O-memory range to set
16+
* @val: The value to set the memory to
17+
* @count: The number of bytes to set
18+
*
19+
* Set a range of I/O memory to a given value.
20+
*/
21+
void memset_io(volatile void __iomem *addr, int val, size_t count)
22+
{
23+
long qc = (u8)val;
24+
25+
qc *= ~0UL / 0xff;
26+
27+
while (count && !IS_ALIGNED((long)addr, sizeof(long))) {
28+
__raw_writeb(val, addr);
29+
addr++;
30+
count--;
31+
}
32+
33+
while (count >= sizeof(long)) {
34+
#ifdef CONFIG_64BIT
35+
__raw_writeq(qc, addr);
36+
#else
37+
__raw_writel(qc, addr);
38+
#endif
39+
40+
addr += sizeof(long);
41+
count -= sizeof(long);
42+
}
43+
44+
while (count) {
45+
__raw_writeb(val, addr);
46+
addr++;
47+
count--;
48+
}
49+
}
50+
EXPORT_SYMBOL(memset_io);
51+
#endif
52+
53+
#ifndef memcpy_fromio
54+
/**
55+
* memcpy_fromio Copy a block of data from I/O memory
56+
* @dst: The (RAM) destination for the copy
57+
* @src: The (I/O memory) source for the data
58+
* @count: The number of bytes to copy
59+
*
60+
* Copy a block of data from I/O memory.
61+
*/
62+
void memcpy_fromio(void *dst, const volatile void __iomem *src, size_t count)
63+
{
64+
while (count && !IS_ALIGNED((long)src, sizeof(long))) {
65+
*(u8 *)dst = __raw_readb(src);
66+
src++;
67+
dst++;
68+
count--;
69+
}
70+
71+
while (count >= sizeof(long)) {
72+
#ifdef CONFIG_64BIT
73+
long val = __raw_readq(src);
74+
#else
75+
long val = __raw_readl(src);
76+
#endif
77+
put_unaligned(val, (long *)dst);
78+
79+
80+
src += sizeof(long);
81+
dst += sizeof(long);
82+
count -= sizeof(long);
83+
}
84+
85+
while (count) {
86+
*(u8 *)dst = __raw_readb(src);
87+
src++;
88+
dst++;
89+
count--;
90+
}
91+
}
92+
EXPORT_SYMBOL(memcpy_fromio);
93+
#endif
94+
95+
#ifndef memcpy_toio
96+
/**
97+
* memcpy_toio Copy a block of data into I/O memory
98+
* @dst: The (I/O memory) destination for the copy
99+
* @src: The (RAM) source for the data
100+
* @count: The number of bytes to copy
101+
*
102+
* Copy a block of data to I/O memory.
103+
*/
104+
void memcpy_toio(volatile void __iomem *dst, const void *src, size_t count)
105+
{
106+
while (count && !IS_ALIGNED((long)dst, sizeof(long))) {
107+
__raw_writeb(*(u8 *)src, dst);
108+
src++;
109+
dst++;
110+
count--;
111+
}
112+
113+
while (count >= sizeof(long)) {
114+
long val = get_unaligned((long *)src);
115+
#ifdef CONFIG_64BIT
116+
__raw_writeq(val, dst);
117+
#else
118+
__raw_writel(val, dst);
119+
#endif
120+
121+
src += sizeof(long);
122+
dst += sizeof(long);
123+
count -= sizeof(long);
124+
}
125+
126+
while (count) {
127+
__raw_writeb(*(u8 *)src, dst);
128+
src++;
129+
dst++;
130+
count--;
131+
}
132+
}
133+
EXPORT_SYMBOL(memcpy_toio);
134+
#endif
135+
136+

0 commit comments

Comments
 (0)