mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-28 16:56:26 +00:00
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>
This commit is contained in:
parent
d4d3125a34
commit
b660d0a2ac
@ -1211,7 +1211,6 @@ static inline void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr)
|
||||
#endif
|
||||
|
||||
#ifndef memset_io
|
||||
#define memset_io memset_io
|
||||
/**
|
||||
* memset_io Set a range of I/O memory to a constant value
|
||||
* @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)
|
||||
*
|
||||
* Set a range of I/O memory to a given value.
|
||||
*/
|
||||
static inline void memset_io(volatile void __iomem *addr, int value,
|
||||
size_t size)
|
||||
{
|
||||
memset(__io_virt(addr), value, size);
|
||||
}
|
||||
void memset_io(volatile void __iomem *addr, int val, size_t count);
|
||||
#endif
|
||||
|
||||
#ifndef memcpy_fromio
|
||||
#define memcpy_fromio memcpy_fromio
|
||||
/**
|
||||
* memcpy_fromio Copy a block of data from I/O memory
|
||||
* @dst: The (RAM) destination for the copy
|
||||
@ -1237,16 +1231,10 @@ static inline void memset_io(volatile void __iomem *addr, int value,
|
||||
*
|
||||
* Copy a block of data from I/O memory.
|
||||
*/
|
||||
static inline void memcpy_fromio(void *buffer,
|
||||
const volatile void __iomem *addr,
|
||||
size_t size)
|
||||
{
|
||||
memcpy(buffer, __io_virt(addr), size);
|
||||
}
|
||||
void memcpy_fromio(void *dst, const volatile void __iomem *src, size_t count);
|
||||
#endif
|
||||
|
||||
#ifndef memcpy_toio
|
||||
#define memcpy_toio memcpy_toio
|
||||
/**
|
||||
* memcpy_toio Copy a block of data into I/O memory
|
||||
* @dst: The (I/O memory) destination for the copy
|
||||
@ -1255,11 +1243,7 @@ static inline void memcpy_fromio(void *buffer,
|
||||
*
|
||||
* Copy a block of data to I/O memory.
|
||||
*/
|
||||
static inline void memcpy_toio(volatile void __iomem *addr, const void *buffer,
|
||||
size_t size)
|
||||
{
|
||||
memcpy(__io_virt(addr), buffer, size);
|
||||
}
|
||||
void memcpy_toio(volatile void __iomem *dst, const void *src, size_t count);
|
||||
#endif
|
||||
|
||||
extern int devmem_is_allowed(unsigned long pfn);
|
||||
|
@ -35,7 +35,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \
|
||||
is_single_threaded.o plist.o decompress.o kobject_uevent.o \
|
||||
earlycpio.o seq_buf.o siphash.o dec_and_lock.o \
|
||||
nmi_backtrace.o win_minmax.o memcat_p.o \
|
||||
buildid.o objpool.o union_find.o
|
||||
buildid.o objpool.o union_find.o iomem_copy.o
|
||||
|
||||
lib-$(CONFIG_PRINTK) += dump_stack.o
|
||||
lib-$(CONFIG_SMP) += cpumask.o
|
||||
|
136
lib/iomem_copy.c
Normal file
136
lib/iomem_copy.c
Normal file
@ -0,0 +1,136 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright 2024 Kalray, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
#include <linux/align.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/unaligned.h>
|
||||
|
||||
#ifndef memset_io
|
||||
/**
|
||||
* memset_io Set a range of I/O memory to a constant value
|
||||
* @addr: The beginning of the I/O-memory range to set
|
||||
* @val: The value to set the memory to
|
||||
* @count: The number of bytes to set
|
||||
*
|
||||
* Set a range of I/O memory to a given value.
|
||||
*/
|
||||
void memset_io(volatile void __iomem *addr, int val, size_t count)
|
||||
{
|
||||
long qc = (u8)val;
|
||||
|
||||
qc *= ~0UL / 0xff;
|
||||
|
||||
while (count && !IS_ALIGNED((long)addr, sizeof(long))) {
|
||||
__raw_writeb(val, addr);
|
||||
addr++;
|
||||
count--;
|
||||
}
|
||||
|
||||
while (count >= sizeof(long)) {
|
||||
#ifdef CONFIG_64BIT
|
||||
__raw_writeq(qc, addr);
|
||||
#else
|
||||
__raw_writel(qc, addr);
|
||||
#endif
|
||||
|
||||
addr += sizeof(long);
|
||||
count -= sizeof(long);
|
||||
}
|
||||
|
||||
while (count) {
|
||||
__raw_writeb(val, addr);
|
||||
addr++;
|
||||
count--;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(memset_io);
|
||||
#endif
|
||||
|
||||
#ifndef memcpy_fromio
|
||||
/**
|
||||
* memcpy_fromio Copy a block of data from I/O memory
|
||||
* @dst: The (RAM) destination for the copy
|
||||
* @src: The (I/O memory) source for the data
|
||||
* @count: The number of bytes to copy
|
||||
*
|
||||
* Copy a block of data from I/O memory.
|
||||
*/
|
||||
void memcpy_fromio(void *dst, const volatile void __iomem *src, size_t count)
|
||||
{
|
||||
while (count && !IS_ALIGNED((long)src, sizeof(long))) {
|
||||
*(u8 *)dst = __raw_readb(src);
|
||||
src++;
|
||||
dst++;
|
||||
count--;
|
||||
}
|
||||
|
||||
while (count >= sizeof(long)) {
|
||||
#ifdef CONFIG_64BIT
|
||||
long val = __raw_readq(src);
|
||||
#else
|
||||
long val = __raw_readl(src);
|
||||
#endif
|
||||
put_unaligned(val, (long *)dst);
|
||||
|
||||
|
||||
src += sizeof(long);
|
||||
dst += sizeof(long);
|
||||
count -= sizeof(long);
|
||||
}
|
||||
|
||||
while (count) {
|
||||
*(u8 *)dst = __raw_readb(src);
|
||||
src++;
|
||||
dst++;
|
||||
count--;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(memcpy_fromio);
|
||||
#endif
|
||||
|
||||
#ifndef memcpy_toio
|
||||
/**
|
||||
* memcpy_toio Copy a block of data into I/O memory
|
||||
* @dst: The (I/O memory) destination for the copy
|
||||
* @src: The (RAM) source for the data
|
||||
* @count: The number of bytes to copy
|
||||
*
|
||||
* Copy a block of data to I/O memory.
|
||||
*/
|
||||
void memcpy_toio(volatile void __iomem *dst, const void *src, size_t count)
|
||||
{
|
||||
while (count && !IS_ALIGNED((long)dst, sizeof(long))) {
|
||||
__raw_writeb(*(u8 *)src, dst);
|
||||
src++;
|
||||
dst++;
|
||||
count--;
|
||||
}
|
||||
|
||||
while (count >= sizeof(long)) {
|
||||
long val = get_unaligned((long *)src);
|
||||
#ifdef CONFIG_64BIT
|
||||
__raw_writeq(val, dst);
|
||||
#else
|
||||
__raw_writel(val, dst);
|
||||
#endif
|
||||
|
||||
src += sizeof(long);
|
||||
dst += sizeof(long);
|
||||
count -= sizeof(long);
|
||||
}
|
||||
|
||||
while (count) {
|
||||
__raw_writeb(*(u8 *)src, dst);
|
||||
src++;
|
||||
dst++;
|
||||
count--;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(memcpy_toio);
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user