|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v13 3/6] lib/arm: Add I/O memory copy helpers
Introduce memcpy_fromio() and memcpy_toio() helpers to copy between
regular memory and a memory-like I/O region on Arm. The generic
prototypes live in io.h so other architectures can provide their own
implementations.
The helpers copy a byte sequence: byte accesses are used until the I/O
pointer is 32-bit aligned and for the trailing count % 4 bytes, the
aligned bulk uses 32-bit accesses. Only the I/O pointer is aligned, the
regular memory side is accessed through get_unaligned_le32() /
put_unaligned_le32(), so the access widths issued on the I/O side do not
depend on the alignment of the memory buffer. These _le32 helpers pair
with readl()/writel(), which are little endian accessors, hence the byte
sequence is preserved on either CPU endianness.
The constraints on the I/O region are documented next to the
declarations in xen/io.h, the arch-specific access pattern next to the
implementation.
Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@xxxxxxxx>
Reviewed-by: Stefano Stabellini <sstabellini@xxxxxxxxxx>
---
Changes in v13:
- memcpy_{from,to}io(): align only the I/O pointer and access the
regular memory side through get_unaligned_le32()/put_unaligned_le32().
- document the contract of the helpers in xen/io.h
- reword the Arm implementation notes to state the concrete access
pattern
- drop the incorrect claim about avoiding endianness conversion from the
commit message; note instead that the _le32 helpers pair with
readl()/writel() so the byte sequence is preserved on either endianness
Changes in v12:
- Add missed R-B
- correct the Emacs footer of both files, which asked for 8 column
tab indentation while the code is in 4 column Xen style
Changes in v10:
- removed extra include in memcpy-{to/from}io.c files
Changes in v9:
- reword commit description to refer to memcpy_fromio and memcpy_toio
- ordering obj-y in Makefile
- rename ALL_LIBS to ARCH_LIBS
- drop io.h and move definitions to the common header, fix comments to
be arch neutral
- update comments for memcpy_{from/to}io implementation
Changes in v8:
- switched to ordered accessors to address the ordering and barrier
concerns.
- updated the documentation to match the implementation and explicitly
state the supported access sizes and granularity.
- rename memcpy_* implementation files to memcpu-* to follow naming
convension
- fix indentation to match Xen style
- fix intendation to match Xen style
- move memcpy-{from/to}io to more convenient library place
Changes in v7:
- x86 guidance: removed the speculative note; header now just says
each arch supplies its own implementation or macro.
- name spacing: dropped the double-underscore; the helpers are now
memcpy_fromio / memcpy_toio. The header also explicitly allows an
arch to define these as macros before including it.
- updated io.c to keep 32-bit transfers safe on arm32
- moved to __raw_read*/__raw_write* accessors to avoid endianness conversion.
- split the helpers into separate compilation units
Changes in v6:
- sorted objs in Makefile alhabetically
- added newline at the end of Makefile
- used uint{N}_t intead of u{N}
- add comment about why 32 bit IO operations were used
- updated cast opertaions to avoid dropping constness which is wrong
- move function definitions to generic place so the could be reused by
other arch
- add SPDX tag to io.c
Changes in v5:
- move memcpy_toio/fromio to the generic place
xen/arch/arm/Makefile | 1 +
xen/arch/arm/arch.mk | 1 +
xen/arch/arm/lib/Makefile | 2 ++
xen/arch/arm/lib/memcpy-fromio.c | 56 ++++++++++++++++++++++++++++++++
xen/arch/arm/lib/memcpy-toio.c | 56 ++++++++++++++++++++++++++++++++
xen/include/xen/io.h | 25 ++++++++++++++
6 files changed, 141 insertions(+)
create mode 100644 xen/arch/arm/lib/Makefile
create mode 100644 xen/arch/arm/lib/memcpy-fromio.c
create mode 100644 xen/arch/arm/lib/memcpy-toio.c
diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index b7afd3e58c..e448e69014 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -8,6 +8,7 @@ ifneq ($(CONFIG_NO_PLAT),y)
obj-y += platforms/
endif
obj-y += firmware/
+obj-y += lib/
obj-$(CONFIG_TEE) += tee/
obj-$(CONFIG_HAS_VPCI) += vpci.o
diff --git a/xen/arch/arm/arch.mk b/xen/arch/arm/arch.mk
index dea8dbd18a..009bb22c45 100644
--- a/xen/arch/arm/arch.mk
+++ b/xen/arch/arm/arch.mk
@@ -2,6 +2,7 @@
# arm-specific definitions
ARCH_LIBS-y += arch/arm/$(ARCH)/lib/lib.a
+ARCH_LIBS-y += arch/arm/lib/lib.a
$(call cc-options-add,CFLAGS,CC,$(EMBEDDED_EXTRA_CFLAGS))
$(call cc-option-add,CFLAGS,CC,-Wnested-externs)
diff --git a/xen/arch/arm/lib/Makefile b/xen/arch/arm/lib/Makefile
new file mode 100644
index 0000000000..07a0d9186c
--- /dev/null
+++ b/xen/arch/arm/lib/Makefile
@@ -0,0 +1,2 @@
+lib-y += memcpy-fromio.o
+lib-y += memcpy-toio.o
diff --git a/xen/arch/arm/lib/memcpy-fromio.c b/xen/arch/arm/lib/memcpy-fromio.c
new file mode 100644
index 0000000000..98339a5cfa
--- /dev/null
+++ b/xen/arch/arm/lib/memcpy-fromio.c
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <xen/io.h>
+#include <xen/unaligned.h>
+
+/*
+ * Arm implementation notes:
+ * - Byte accesses are issued until the I/O pointer is 32-bit aligned and
+ * for the trailing count % 4 bytes; the aligned bulk uses 32-bit
+ * accesses. No wider accesses are issued.
+ * - The access widths on the I/O side depend only on the alignment of the
+ * I/O pointer and on count. The regular memory side is accessed through
+ * put_unaligned_le32(), so its alignment has no influence on them.
+ * - put_unaligned_le32() pairs with readl(), which is a little endian
+ * accessor, so the byte sequence is preserved on either CPU endianness.
+ * - The I/O region must be mapped with device attributes; ordering is
+ * provided by the accessors themselves, no extra barriers are added.
+ */
+
+void memcpy_fromio(void *to, const volatile void __iomem *from,
+ size_t count)
+{
+ while ( count && !IS_ALIGNED((unsigned long)from, 4) )
+ {
+ *(uint8_t *)to = readb(from);
+ from++;
+ to++;
+ count--;
+ }
+
+ while ( count >= 4 )
+ {
+ put_unaligned_le32(readl(from), to);
+ from += 4;
+ to += 4;
+ count -= 4;
+ }
+
+ while ( count )
+ {
+ *(uint8_t *)to = readb(from);
+ from++;
+ to++;
+ count--;
+ }
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/lib/memcpy-toio.c b/xen/arch/arm/lib/memcpy-toio.c
new file mode 100644
index 0000000000..c0be79586d
--- /dev/null
+++ b/xen/arch/arm/lib/memcpy-toio.c
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <xen/io.h>
+#include <xen/unaligned.h>
+
+/*
+ * Arm implementation notes:
+ * - Byte accesses are issued until the I/O pointer is 32-bit aligned and
+ * for the trailing count % 4 bytes; the aligned bulk uses 32-bit
+ * accesses. No wider accesses are issued.
+ * - The access widths on the I/O side depend only on the alignment of the
+ * I/O pointer and on count. The regular memory side is accessed through
+ * get_unaligned_le32(), so its alignment has no influence on them.
+ * - get_unaligned_le32() pairs with writel(), which is a little endian
+ * accessor, so the byte sequence is preserved on either CPU endianness.
+ * - The I/O region must be mapped with device attributes; ordering is
+ * provided by the accessors themselves, no extra barriers are added.
+ */
+
+void memcpy_toio(volatile void __iomem *to, const void *from,
+ size_t count)
+{
+ while ( count && !IS_ALIGNED((unsigned long)to, 4) )
+ {
+ writeb(*(const uint8_t *)from, to);
+ from++;
+ to++;
+ count--;
+ }
+
+ while ( count >= 4 )
+ {
+ writel(get_unaligned_le32(from), to);
+ from += 4;
+ to += 4;
+ count -= 4;
+ }
+
+ while ( count )
+ {
+ writeb(*(const uint8_t *)from, to);
+ from++;
+ to++;
+ count--;
+ }
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/xen/io.h b/xen/include/xen/io.h
index 164a20c5d7..0b60be27c1 100644
--- a/xen/include/xen/io.h
+++ b/xen/include/xen/io.h
@@ -67,4 +67,29 @@ static inline bool write_mmio(volatile void __iomem *mem,
unsigned long data,
return true;
}
+/*
+ * Copy a sequence of bytes between regular memory and a memory-like I/O
+ * region, e.g. shared memory placed in RAM or SRAM mapped with device
+ * attributes.
+ *
+ * The I/O region must behave like byte-addressable storage: it has to
+ * accept 8-bit accesses at any byte address and naturally aligned 32-bit
+ * accesses, with plain byte-storage semantics in both cases (no side
+ * effects, no dependency on the access width). An implementation may use
+ * any of these widths, but never wider ones. The helpers are therefore
+ * not suitable for device registers with access-width requirements.
+ *
+ * Neither pointer needs to be aligned. The access widths issued on the
+ * I/O side depend only on the alignment of the I/O pointer and on count,
+ * never on the alignment of the regular memory pointer.
+ *
+ * Implementations are architecture-specific and may impose further
+ * constraints; see the respective arch/<arch>/lib/memcpy-{from,to}io.c
+ * for the exact access pattern.
+ */
+void memcpy_fromio(void *to, const volatile void __iomem *from,
+ size_t count);
+void memcpy_toio(volatile void __iomem *to, const void *from,
+ size_t count);
+
#endif /* XEN_IO_H */
--
2.43.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |