Skip to contentSkip to conversation

Add memcpy_toio32, a 32-bit MMIO copy routine

PATCH New Bryan O'Sullivan 9 participants 26 messages Dec 27, 2005 – Jan 6, 2006

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Add memcpy_toio32, a 32-bit MMIO copy routine

Following some discussion with Matt, Andrew and Chris, here is a recast of the 32-bit MMIO patch I posted the other day. The routine is now named memcpy_toio32, and is provided in generic and x86_64-optimised forms.

I haven't added a memcpy_fromio32, or routines for other access sizes, because our hardware doesn't need them. If someone wants them for reasons of symmetry, I can introduce them.

#1 lore raw

PATCH 1/1 Introduce __memcpy_toio32

This routine is an arch-independent building block for memcpy_toio32. It copies data to a memory-mapped I/O region, using 32-bit accesses. This style of access is required by some devices.

include/asm-generic/iomap.h +6 -0
diff -r 789a24638663 -r 7b7b442a4d63 include/asm-generic/iomap.h
@@ -56,6 +56,12 @@
 extern void fastcall iowrite16_rep(void __iomem *port, const void *buf, unsigned long count);
 extern void fastcall iowrite32_rep(void __iomem *port, const void *buf, unsigned long count);
 
+/*
+ * MMIO copy routines.  These are guaranteed to operate in units denoted
+ * by their names.  This style of operation is required by some devices.
+ */
+extern void fastcall __memcpy_toio32(volatile void __iomem *to, const void *from, size_t count);
+
 /* Create a virtual mapping cookie for an IO port range */
 extern void __iomem *ioport_map(unsigned long port, unsigned int nr);
 extern void ioport_unmap(void __iomem *);
lib/iomap.c +16 -0
diff -r 789a24638663 -r 7b7b442a4d63 lib/iomap.c
@@ -187,6 +187,22 @@
 EXPORT_SYMBOL(iowrite16_rep);
 EXPORT_SYMBOL(iowrite32_rep);
 
+/*
+ * Copy data to an MMIO region.  MMIO space accesses are performed
+ * in the sizes indicated in each function's name.
+ */
+void fastcall __memcpy_toio32(volatile void __iomem *d, const void *s, size_t count)
+{
+	volatile u32 __iomem *dst = d;
+	const u32 *src = s;
+
+	while (--count >= 0) {
+		__raw_writel(*src++, dst++);
+	}
+}
+
+EXPORT_SYMBOL_GPL(__memcpy_toio32);
+
 /* Create a virtual mapping cookie for an IO port range */
 void __iomem *ioport_map(unsigned long port, unsigned int nr)
 {
#19 lore raw

PATCH 1/1 Add memcpy_toio32 to each arch

In reply to Bryan O'Sullivan

Most arches use the generic __memcpy_toio32 routine, while x86_64 uses memcpy32, which is substantially faster.

include/asm-alpha/io.h +2 -0
diff -r 042b7d9004ac -r 0441e7525e4e include/asm-alpha/io.h
@@ -504,6 +504,8 @@
 extern void memcpy_toio(volatile void __iomem *, const void *, long);
 extern void _memset_c_io(volatile void __iomem *, unsigned long, long);
 
+#define memcpy_toio32 __memcpy_toio32
+
 static inline void memset_io(volatile void __iomem *addr, u8 c, long len)
 {
 	_memset_c_io(addr, 0x0101010101010101UL * c, len);
include/asm-arm/io.h +2 -0
diff -r 042b7d9004ac -r 0441e7525e4e include/asm-arm/io.h
@@ -184,6 +184,8 @@
 #define memset_io(c,v,l)	_memset_io(__mem_pci(c),(v),(l))
 #define memcpy_fromio(a,c,l)	_memcpy_fromio((a),__mem_pci(c),(l))
 #define memcpy_toio(c,a,l)	_memcpy_toio(__mem_pci(c),(a),(l))
+
+#define memcpy_toio32 __memcpy_toio32
 
 #define eth_io_copy_and_sum(s,c,l,b) \
 				eth_copy_and_sum((s),__mem_pci(c),(l),(b))
include/asm-cris/io.h +2 -0
diff -r 042b7d9004ac -r 0441e7525e4e include/asm-cris/io.h
@@ -121,6 +121,8 @@
 #define memcpy_fromio(a,b,c)	memcpy((a),(void *)(b),(c))
 #define memcpy_toio(a,b,c)	memcpy((void *)(a),(b),(c))
 
+#define memcpy_toio32 __memcpy_toio32
+
 /*
  * Again, CRIS does not require mem IO specific function.
  */
include/asm-frv/io.h +2 -0
diff -r 042b7d9004ac -r 0441e7525e4e include/asm-frv/io.h
@@ -124,6 +124,8 @@
 	memcpy((void __force *) dst, src, count);
 }
 
+#define memcpy_toio32 __memcpy_toio32
+
 static inline uint8_t inb(unsigned long addr)
 {
 	return __builtin_read8((void *)addr);
include/asm-h8300/io.h +2 -0
diff -r 042b7d9004ac -r 0441e7525e4e include/asm-h8300/io.h
@@ -209,6 +209,8 @@
 #define memcpy_fromio(a,b,c)	memcpy((a),(void *)(b),(c))
 #define memcpy_toio(a,b,c)	memcpy((void *)(a),(b),(c))
 
+#define memcpy_toio32 __memcpy_toio32
+
 #define mmiowb()
 
 #define inb(addr)    ((h8300_buswidth(addr))?readw((addr) & ~1) & 0xff:readb(addr))
include/asm-i386/io.h +3 -0
diff -r 042b7d9004ac -r 0441e7525e4e include/asm-i386/io.h
@@ -203,6 +203,9 @@
 {
 	__memcpy((void __force *) dst, src, count);
 }
+
+#define memcpy_toio32 __memcpy_toio32
+
 
 /*
  * ISA space is 'always mapped' on a typical x86 system, no need to
include/asm-ia64/io.h +2 -0
diff -r 042b7d9004ac -r 0441e7525e4e include/asm-ia64/io.h
@@ -443,6 +443,8 @@
 extern void memcpy_toio(volatile void __iomem *dst, const void *src, long n);
 extern void memset_io(volatile void __iomem *s, int c, long n);
 
+#define memcpy_toio32 __memcpy_toio32
+
 #define dma_cache_inv(_start,_size)             do { } while (0)
 #define dma_cache_wback(_start,_size)           do { } while (0)
 #define dma_cache_wback_inv(_start,_size)       do { } while (0)
include/asm-m32r/io.h +2 -0
diff -r 042b7d9004ac -r 0441e7525e4e include/asm-m32r/io.h
@@ -216,6 +216,8 @@
 	memcpy((void __force *) dst, src, count);
 }
 
+#define memcpy_toio32 __memcpy_toio32
+
 /*
  * Convert a physical pointer to a virtual kernel pointer for /dev/mem
  * access
include/asm-m68knommu/io.h +2 -0
diff -r 042b7d9004ac -r 0441e7525e4e include/asm-m68knommu/io.h
@@ -113,6 +113,8 @@
 #define memcpy_fromio(a,b,c)	memcpy((a),(void *)(b),(c))
 #define memcpy_toio(a,b,c)	memcpy((void *)(a),(b),(c))
 
+#define memcpy_toio32 __memcpy_toio32
+
 #define inb(addr)    readb(addr)
 #define inw(addr)    readw(addr)
 #define inl(addr)    readl(addr)
include/asm-mips/io.h +2 -0
diff -r 042b7d9004ac -r 0441e7525e4e include/asm-mips/io.h
@@ -534,6 +534,8 @@
 	memcpy((void __force *) dst, src, count);
 }
 
+#define memcpy_toio32 __memcpy_toio32
+
 /*
  * Memory Mapped I/O
  */
include/asm-parisc/io.h +2 -0
diff -r 042b7d9004ac -r 0441e7525e4e include/asm-parisc/io.h
@@ -294,6 +294,8 @@
 void memcpy_fromio(void *dst, const volatile void __iomem *src, int count);
 void memcpy_toio(volatile void __iomem *dst, const void *src, int count);
 
+#define memcpy_toio32 __memcpy_toio32
+
 /* Support old drivers which don't ioremap.
  * NB this interface is scheduled to disappear in 2.5
  */
include/asm-powerpc/io.h +2 -0
diff -r 042b7d9004ac -r 0441e7525e4e include/asm-powerpc/io.h
@@ -63,6 +63,8 @@
 #define memcpy_fromio(a,b,c)	iSeries_memcpy_fromio((a), (b), (c))
 #define memcpy_toio(a,b,c)	iSeries_memcpy_toio((a), (b), (c))
 
+#define memcpy_toio32 __memcpy_toio32
+
 #define inb(addr)		readb(((void __iomem *)(long)(addr)))
 #define inw(addr)		readw(((void __iomem *)(long)(addr)))
 #define inl(addr)		readl(((void __iomem *)(long)(addr)))
include/asm-ppc/io.h +2 -0
diff -r 042b7d9004ac -r 0441e7525e4e include/asm-ppc/io.h
@@ -367,6 +367,8 @@
 }
 #endif
 
+#define memcpy_toio32 __memcpy_toio32
+
 #define eth_io_copy_and_sum(a,b,c,d)		eth_copy_and_sum((a),(void __force *)(void __iomem *)(b),(c),(d))
 
 /*
include/asm-s390/io.h +2 -0
diff -r 042b7d9004ac -r 0441e7525e4e include/asm-s390/io.h
@@ -99,6 +99,8 @@
 #define memcpy_fromio(a,b,c)    memcpy((a),__io_virt(b),(c))
 #define memcpy_toio(a,b,c)      memcpy(__io_virt(a),(b),(c))
 
+#define memcpy_toio32 __memcpy_toio32
+
 #define inb_p(addr) readb(addr)
 #define inb(addr) readb(addr)
 
include/asm-sh/io.h +2 -0
diff -r 042b7d9004ac -r 0441e7525e4e include/asm-sh/io.h
@@ -177,6 +177,8 @@
 extern void memcpy_toio(unsigned long, const void *, unsigned long);
 extern void memset_io(unsigned long, int, unsigned long);
 
+#define memcpy_toio32 __memcpy_toio32
+
 /* SuperH on-chip I/O functions */
 static __inline__ unsigned char ctrl_inb(unsigned long addr)
 {
include/asm-sh64/io.h +2 -0
diff -r 042b7d9004ac -r 0441e7525e4e include/asm-sh64/io.h
@@ -125,6 +125,8 @@
 
 void memcpy_toio(void __iomem *to, const void *from, long count);
 void memcpy_fromio(void *to, void __iomem *from, long count);
+
+#define memcpy_toio32 __memcpy_toio32
 
 #define mmiowb()
 
include/asm-sparc/io.h +2 -0
diff -r 042b7d9004ac -r 0441e7525e4e include/asm-sparc/io.h
@@ -239,6 +239,8 @@
 
 #define memcpy_toio(d,s,sz)	_memcpy_toio(d,s,sz)
 
+#define memcpy_toio32 __memcpy_toio32
+
 #ifdef __KERNEL__
 
 /*
include/asm-sparc64/io.h +2 -0
diff -r 042b7d9004ac -r 0441e7525e4e include/asm-sparc64/io.h
@@ -440,6 +440,8 @@
 
 #define memcpy_toio(d,s,sz)	_memcpy_toio(d,s,sz)
 
+#define memcpy_toio32 __memcpy_toio32
+
 static inline int check_signature(void __iomem *io_addr,
 				  const unsigned char *signature,
 				  int length)
include/asm-v850/io.h +2 -0
diff -r 042b7d9004ac -r 0441e7525e4e include/asm-v850/io.h
@@ -130,6 +130,8 @@
 #define memcpy_fromio(dst, src, len) memcpy (dst, (void *)src, len)
 #define memcpy_toio(dst, src, len) memcpy ((void *)dst, src, len)
 
+#define memcpy_toio32 __memcpy_toio32
+
 /*
  * Convert a physical pointer to a virtual kernel pointer for /dev/mem
  * access
include/asm-x86_64/io.h +7 -0
diff -r 042b7d9004ac -r 0441e7525e4e include/asm-x86_64/io.h
@@ -252,6 +252,13 @@
 	__memcpy_toio((unsigned long)to,from,len);
 }
 
+#include <asm/string.h>
+
+static inline void memcpy_toio32(volatile void __iomem *dst, const void *src, size_t count)
+{
+	memcpy32((void *) dst, src, count);
+}
+
 void memset_io(volatile void __iomem *a, int b, size_t c);
 
 /*
include/asm-xtensa/io.h +2 -0
diff -r 042b7d9004ac -r 0441e7525e4e include/asm-xtensa/io.h
@@ -159,6 +159,8 @@
 #define memcpy_fromio(a,b,c)   memcpy((a),(void *)(b),(c))
 #define memcpy_toio(a,b,c)      memcpy((void *)(a),(b),(c))
 
+#define memcpy_toio32 __memcpy_toio32
+
 /* At this point the Xtensa doesn't provide byte swap instructions */
 
 #ifdef __XTENSA_EB__
#20 lore raw

PATCH 1/1 memcpy32 for x86_64

In reply to Bryan O'Sullivan

Introduce an x86_64-specific memcpy32 routine. The routine is similar to memcpy, but is guaranteed to work in units of 32 bits at a time.

arch/x86_64/kernel/x8664_ksyms.c +4 -0
diff -r 7b7b442a4d63 -r 042b7d9004ac arch/x86_64/kernel/x8664_ksyms.c
@@ -150,6 +150,8 @@
 extern void * memcpy(void *,const void *,__kernel_size_t);
 extern void * __memcpy(void *,const void *,__kernel_size_t);
 
+extern void memcpy32(void *,const void *,__kernel_size_t);
+
 EXPORT_SYMBOL(memset);
 EXPORT_SYMBOL(strlen);
 EXPORT_SYMBOL(memmove);
@@ -164,6 +166,8 @@
 EXPORT_SYMBOL(memcpy);
 EXPORT_SYMBOL(__memcpy);
 
+EXPORT_SYMBOL_GPL(memcpy32);
+
 #ifdef CONFIG_RWSEM_XCHGADD_ALGORITHM
 /* prototypes are wrong, these are assembly with custom calling functions */
 extern void rwsem_down_read_failed_thunk(void);
arch/x86_64/lib/Makefile +1 -1
diff -r 7b7b442a4d63 -r 042b7d9004ac arch/x86_64/lib/Makefile
@@ -9,4 +9,4 @@
 lib-y := csum-partial.o csum-copy.o csum-wrappers.o delay.o \
 	usercopy.o getuser.o putuser.o  \
 	thunk.o clear_page.o copy_page.o bitstr.o bitops.o
-lib-y += memcpy.o memmove.o memset.o copy_user.o
+lib-y += memcpy.o memcpy32.o memmove.o memset.o copy_user.o
include/asm-x86_64/string.h +2 -0
diff -r 7b7b442a4d63 -r 042b7d9004ac include/asm-x86_64/string.h
@@ -45,6 +45,8 @@
 #define __HAVE_ARCH_MEMMOVE
 void * memmove(void * dest,const void *src,size_t count);
 
+void memcpy32(void *dst, const void *src, size_t count);
+
 /* Use C out of line version for memcmp */ 
 #define memcmp __builtin_memcmp
 int memcmp(const void * cs,const void * ct,size_t count);
arch/x86_64/lib/memcpy32.S new file +25 -0
diff -r 7b7b442a4d63 -r 042b7d9004ac arch/x86_64/lib/memcpy32.S
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2003, 2004, 2005 PathScale, Inc.
+ */
+
+/*
+ * memcpy32 - Copy a memory block, 32 bits at a time.
+ *
+ * Count is number of dwords; it need not be a qword multiple.
+ * Input:
+ * rdi destination
+ * rsi source
+ * rdx count
+ */
+
+ 	.globl memcpy32
+memcpy32:
+	movl %edx,%ecx
+	shrl $1,%ecx
+	andl $1,%edx
+	rep
+	movsq
+	movl %edx,%ecx
+	rep
+	movsd
+	ret
#2 lore raw

Re: [PATCH 1 of 3] Introduce __memcpy_toio32

In reply to Bryan O'Sullivan

A couple of comments here:

lib/iomap.c line 201

Quoted 12 lines
lib/iomap.c +12 -0
+/*
+ * Copy data to an MMIO region.  MMIO space accesses are performed
+ * in the sizes indicated in each function's name.
+ */
+void fastcall __memcpy_toio32(volatile void __iomem *d, const void *s, size_t count)
+{
+	volatile u32 __iomem *dst = d;
+	const u32 *src = s;
+
+	while (--count >= 0) {
+		__raw_writel(*src++, dst++);
+	}

I think the principle of least surprise calls for memcpy_toio32 to be ordered the same way memcpy_toio is. In other words there should be a wmb() after the loop.

Also, no need for the { } for the while loop.

lib/iomap.c line 204

Quoted 3 lines
lib/iomap.c +3 -0
+}
+
+EXPORT_SYMBOL_GPL(__memcpy_toio32);

You're adding this symbol and exporting it even if the arch will supply its own version. So this is pure kernel .text bloat...

- R.

#12 lore raw

Re: [PATCH 1 of 3] Introduce __memcpy_toio32

In reply to Bryan O'Sullivan

Oh yeah:

Quoted 1 line

+EXPORT_SYMBOL_GPL(__memcpy_toio32);

I think this is a sufficiently basic facility that it might as well be plain EXPORT_SYMBOL(), although I don't mind making things harder on non-GPL modules.

- R.

#14 lore raw

Re: [PATCH 1 of 3] Introduce __memcpy_toio32

In reply to Bryan O'Sullivan
Quoted 4 lines · Bryan O'Sullivan

+/*
+ * MMIO copy routines. These are guaranteed to operate in units denoted
+ * by their names. This style of operation is required by some devices.
+ */

Using kdoc style for new code is nice.

include/asm-generic/iomap.h line 64

Quoted 2 lines
include/asm-generic/iomap.h +2 -0
+extern void fastcall __memcpy_toio32(volatile void __iomem *to, const void *from, size_t count);
+

Minor rant: extern is always redundant for function prototypes in C. I'd prefer that we adopt a standard of not using extern for functions, as it would make use of extern for variables (almost always inappropriate, especially in C files) stick out more.

While people claim this has some documentation value ("I _meant_ for this to be exported"), I think it actually has a net negative effect, as quite a number of people actually think the "extern" keyword does some unspecified magic here and ignore the namespace pollution of their theoretically "un-externed" but not explicitly static functions.

There isn't any sort of consensus on this point as far as I know, so this is just me venting.

Quoted 12 lines

/* Create a virtual mapping cookie for an IO port range */ extern void __iomem *ioport_map(unsigned long port, unsigned int nr); extern void ioport_unmap(void __iomem *);
diff -r 789a24638663 -r 7b7b442a4d63 lib/iomap.c

lib/iomap.c +2 -0
@@ -187,6 +187,22 @@
 EXPORT_SYMBOL(iowrite16_rep);
 EXPORT_SYMBOL(iowrite32_rep);
 
+/*
+ * Copy data to an MMIO region.  MMIO space accesses are performed

lib/iomap.c line 201

Quoted 10 lines
lib/iomap.c +10 -0
+ * in the sizes indicated in each function's name.
+ */
+void fastcall __memcpy_toio32(volatile void __iomem *d, const void *s, size_t count)
+{
+	volatile u32 __iomem *dst = d;
+	const u32 *src = s;
+
+	while (--count >= 0) {
+		__raw_writel(*src++, dst++);
+}

Suspicious use of volatile - writel is doing the actual write, this function never does a dereference. As you've already got private copies of the pointers already in s and d, it's perfectily reasonable and idiomatic to do:

	while (--count >= 0)
		__raw_writel(*s++, d++);

I'd personally write this as:

	while (count--)
		__raw_writel(*s++, d++);

And as you appear to be using the __raw.. version to avoid repeated mb()s, you probably ought to tack one on at the end.

Signature · 1 line
Mathematics is the supreme nostalgia of our time.
#13 lore raw

Re: [PATCH 1 of 3] Introduce __memcpy_toio32

In reply to Roland Dreier
Quoted 7 lines · Roland Dreier

Oh yeah:

Quoted 1 line

+EXPORT_SYMBOL_GPL(__memcpy_toio32);

I think this is a sufficiently basic facility that it might as well be plain EXPORT_SYMBOL(), although I don't mind making things harder on non-GPL modules.

This area is so murky, it verges on religion. Thus, I really think this ought to be submitter's preference.

Any attempt to make a hard and fast rule of what's considered GPL or not will potentially dilute any legal protection for exported symbols predating the existence of the EXPORT_SYMBOL_GPL mechanism that are nonetheless only reasonably used by GPL code (which by some contributors' measures is all of them).

In other words, we must be careful not to directly or indirectly construe EXPORT_SYMBOL as a carte blanche for linking GPL-incompatible code.

Signature · 1 line
Mathematics is the supreme nostalgia of our time.
#21 lore raw

Re: [PATCH 2 of 3] memcpy32 for x86_64

In reply to Bryan O'Sullivan

arch/x86_64/kernel/x8664_ksyms.c line 153

Quoted 13 lines · Bryan O'Sullivan

Introduce an x86_64-specific memcpy32 routine. The routine is similar to memcpy, but is guaranteed to work in units of 32 bits at a time.

diff -r 7b7b442a4d63 -r 042b7d9004ac arch/x86_64/kernel/x8664_ksyms.c

arch/x86_64/kernel/x8664_ksyms.c +1 -0
@@ -150,6 +150,8 @@
 extern void * memcpy(void *,const void *,__kernel_size_t);
 extern void * __memcpy(void *,const void *,__kernel_size_t);
 
+extern void memcpy32(void *,const void *,__kernel_size_t);

It's better to do an include here. Duplicating prototypes in .c files is frowned upon (despite the fact that it's already done here).

arch/x86_64/kernel/x8664_ksyms.c line 170

Quoted 10 lines
arch/x86_64/kernel/x8664_ksyms.c +3 -0
+
 EXPORT_SYMBOL(memset);
 EXPORT_SYMBOL(strlen);
 EXPORT_SYMBOL(memmove);
@@ -164,6 +166,8 @@
 EXPORT_SYMBOL(memcpy);
 EXPORT_SYMBOL(__memcpy);
 
+EXPORT_SYMBOL_GPL(memcpy32);
+

We've been steadily moving towards grouping EXPORTs with function definitions. Do *_ksyms.c exist solely to provide exports for functions defined in assembly at this point? If so, perhaps we ought to come up with a suitable export macro for asm files.

Quoted 19 lines

diff -r 7b7b442a4d63 -r 042b7d9004ac arch/x86_64/lib/memcpy32.S

arch/x86_64/lib/memcpy32.S new file +15 -0
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2003, 2004, 2005 PathScale, Inc.
+ */
+
+/*
+ * memcpy32 - Copy a memory block, 32 bits at a time.
+ *
+ * Count is number of dwords; it need not be a qword multiple.
+ * Input:
+ * rdi destination
+ * rsi source
+ * rdx count
+ */
+
+ 	.globl memcpy32

arch/x86_64/lib/memcpy32.S line 25

Quoted 10 lines
arch/x86_64/lib/memcpy32.S new file +10 -0
+memcpy32:
+	movl %edx,%ecx
+	shrl $1,%ecx
+	andl $1,%edx
+	rep
+	movsq
+	movl %edx,%ecx
+	rep
+	movsd
+	ret

Any reason this needs its own .S file? One wonders if the

        .p2align 4

in memcpy.S is appropriate here too. Splitting rep movsq across two lines is a little weird to me too, but I see Andi did it too.

Signature · 1 line
Mathematics is the supreme nostalgia of our time.
#22 lore raw

Re: [PATCH 2 of 3] memcpy32 for x86_64

Quoted 8 lines

arch/x86_64/lib/memcpy32.S line 21

Quoted 8 lines
arch/x86_64/lib/memcpy32.S new file +8 -0
+
+ 	.globl memcpy32
+memcpy32:
+	movl %edx,%ecx
+	shrl $1,%ecx
+	andl $1,%edx
+	rep
+	movsq

Does this one really do 32-bit stores?! I doubt so...

Quoted 11 lines

arch/x86_64/lib/memcpy32.S line 25

Quoted 4 lines
arch/x86_64/lib/memcpy32.S new file +4 -0
+	movl %edx,%ecx
+	rep
+	movsd
+	ret

Any reason this needs its own .S file? One wonders if the

        .p2align 4

in memcpy.S is appropriate here too. Splitting rep movsq across two lines is a little weird to me too, but I see Andi did it too.

--
vda

#3 lore raw

Re: [PATCH 1 of 3] Introduce __memcpy_toio32

In reply to Roland Dreier
Quoted 3 lines · Roland Dreier

I think the principle of least surprise calls for memcpy_toio32 to be ordered the same way memcpy_toio is. In other words there should be a wmb() after the loop.

Will do.

Quoted 1 line

Also, no need for the { } for the while loop.

Fine. There doesn't seem to be much consistency in whether to use curlies for single-line blocks.

Quoted 2 lines

You're adding this symbol and exporting it even if the arch will supply its own version. So this is pure kernel .text bloat...

I don't know what you'd prefer, so let me enumerate a few alternatives, and you can either tell me which you'd prefer, or point out something I've missed that would be even better. I'm entirely flexible on this.

* Use the __HAVE_ARCH_* mechanism that include/asm-*/string.h uses. Caveat: Linus has lately come out as hating this style. It makes for the smallest patch, though.
* Define the generic code in lib/, and have each arch that really uses it export it.
* Put generic code in include/asm-generic/algo-memcpy_toio32.h, and have each arch that needs it #include it somewhere and use it.

Have I missed anything?

	<b
#15 lore raw

Re: [PATCH 1 of 3] Introduce __memcpy_toio32

In reply to Matt Mackall
Quoted 7 lines · Matt Mackall
Quoted 4 lines · Bryan O'Sullivan

+/*
+ * MMIO copy routines. These are guaranteed to operate in units denoted
+ * by their names. This style of operation is required by some devices.
+ */

Using kdoc style for new code is nice.

OK, will do.

Quoted 4 lines

include/asm-generic/iomap.h line 64

Quoted 2 lines
include/asm-generic/iomap.h +2 -0
+extern void fastcall __memcpy_toio32(volatile void __iomem *to, const void *from, size_t count);
+

Minor rant: extern is always redundant for function prototypes in C.

I know. My intent was to keep the prototype consistent with the prevailing style of other declarations in that same routine. If you think that cleanliness is more important, I'll be happy to change it.

Quoted 2 lines

Suspicious use of volatile - writel is doing the actual write, this function never does a dereference.

Yeah. I lost the plot there a bit. I'll remove the volatiles.

Quoted 6 lines

As you've already got private
copies of the pointers already in s and d, it's perfectily reasonable and idiomatic to do:

	while (--count >= 0)
		__raw_writel(*s++, d++);

But pointer arithmetic is undefined on void pointers. gcc lets you do it, but it treats sizeof(void) as 1, which gives entirely the wrong results in this case.

Quoted 2 lines

And as you appear to be using the __raw.. version to avoid repeated mb()s, you probably ought to tack one on at the end.

Well spotted, thanks.

	<b
#23 lore raw

Re: [PATCH 2 of 3] memcpy32 for x86_64

In reply to Matt Mackall
Quoted 2 lines · Matt Mackall

It's better to do an include here. Duplicating prototypes in .c files is frowned upon (despite the fact that it's already done here).

Yeah. I'm not thrilled about the existing style of that file, but I don't want to weed-whack it as I go. That turns a small patch into a case of mission creep.

Quoted 4 lines

We've been steadily moving towards grouping EXPORTs with function definitions. Do *_ksyms.c exist solely to provide exports for functions defined in assembly at this point? If so, perhaps we ought to come up with a suitable export macro for asm files.

That might make sense, but it's also beyond the scope of what I'm trying to do.

Quoted 1 line

Any reason this needs its own .S file?

Not really.

Quoted 5 lines

One wonders if the

        .p2align 4

in memcpy.S is appropriate here too.

It's not clear to me that it makes any difference either way. Both routines obviously work :-) Perhaps Andi can indicate his opinion.

	<b
#4 lore raw

Re: [PATCH 1 of 3] Introduce __memcpy_toio32

In reply to Bryan O'Sullivan
Quoted 6 lines · Bryan O'Sullivan
Quoted 3 lines · Roland Dreier

I think the principle of least surprise calls for memcpy_toio32 to be ordered the same way memcpy_toio is. In other words there should be a wmb() after the loop.

Quoted 6 lines

Will do.

Quoted 1 line

Also, no need for the { } for the while loop.

Fine. There doesn't seem to be much consistency in whether to use curlies for single-line blocks.

We've been very consistent in discouraging it in new code. Enforcement of fine points of coding style is a post-2.5 phenomenon, so it hasn't hit all the tree yet.

Quoted 7 lines
Quoted 2 lines

You're adding this symbol and exporting it even if the arch will supply its own version. So this is pure kernel .text bloat...

I don't know what you'd prefer, so let me enumerate a few alternatives, and you can either tell me which you'd prefer, or point out something I've missed that would be even better. I'm entirely flexible on this.

Quoted 5 lines

* Use the __HAVE_ARCH_* mechanism that include/asm-*/string.h uses. Caveat: Linus has lately come out as hating this style. It makes for the smallest patch, though.
* Define the generic code in lib/, and have each arch that really uses it export it.

I'd favor this, at least for this case. If it becomes more widely used, we'll relocate the export.

Quoted 3 lines

* Put generic code in include/asm-generic/algo-memcpy_toio32.h, and have each arch that needs it #include it somewhere and use it.

Signature · 1 line
Mathematics is the supreme nostalgia of our time.
#16 lore raw

Re: [PATCH 1 of 3] Introduce __memcpy_toio32

In reply to Bryan O'Sullivan
Quoted 8 lines · Bryan O'Sullivan
Quoted 4 lines

include/asm-generic/iomap.h line 64

Quoted 2 lines
include/asm-generic/iomap.h +2 -0
+extern void fastcall __memcpy_toio32(volatile void __iomem *to, const void *from, size_t count);
+

Minor rant: extern is always redundant for function prototypes in C.

I know. My intent was to keep the prototype consistent with the prevailing style of other declarations in that same routine. If you think that cleanliness is more important, I'll be happy to change it.

No, I'm actually just raising it for discussion. I personally don't add them, even for consistency, as I'd like to eventually see them gone. But if Christoph and Andrew won't care, my tiny crusade is probably lost.

Signature · 1 line
Mathematics is the supreme nostalgia of our time.
#17 lore raw

Re: [PATCH 1 of 3] Introduce __memcpy_toio32

In reply to Matt Mackall
Quoted 29 lines · Matt Mackall
Quoted 12 lines · Bryan O'Sullivan

/* Create a virtual mapping cookie for an IO port range */ extern void __iomem *ioport_map(unsigned long port, unsigned int nr); extern void ioport_unmap(void __iomem *);
diff -r 789a24638663 -r 7b7b442a4d63 lib/iomap.c

lib/iomap.c +2 -0
@@ -187,6 +187,22 @@
 EXPORT_SYMBOL(iowrite16_rep);
 EXPORT_SYMBOL(iowrite32_rep);
 
+/*
+ * Copy data to an MMIO region.  MMIO space accesses are performed

lib/iomap.c line 201

Quoted 10 lines
lib/iomap.c +10 -0
+ * in the sizes indicated in each function's name.
+ */
+void fastcall __memcpy_toio32(volatile void __iomem *d, const void *s, size_t count)
+{
+	volatile u32 __iomem *dst = d;
+	const u32 *src = s;
+
+	while (--count >= 0) {
+		__raw_writel(*src++, dst++);
+}

Suspicious use of volatile - writel is doing the actual write, this function never does a dereference. As you've already got private copies of the pointers already in s and d, it's perfectily reasonable and idiomatic to do:

Quoted 7 lines
	while (--count >= 0)
		__raw_writel(*s++, d++);

I'd personally write this as:

	while (count--)
		__raw_writel(*s++, d++);

Indeed.

BTW, does the original loop really work? Size size_t is unsigned, >= 0 is always true and we have a nice infinite loop?

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds

#18 lore raw

Re: [PATCH 1 of 3] Introduce __memcpy_toio32

Quoted 1 line · Geert Uytterhoeven

BTW, does the original loop really work?

I had to turn it into a for loop shortly after I posted it, for exactly the reason you pointed out.

	<b
#11 lore raw

Re: [PATCH 1 of 3] Introduce __memcpy_toio32

In reply to Bryan O'Sullivan
Quoted 7 lines
Quoted 2 lines

You're adding this symbol and exporting it even if the arch will supply its own version. So this is pure kernel .text bloat...

I don't know what you'd prefer, so let me enumerate a few alternatives, and you can either tell me which you'd prefer, or point out something I've missed that would be even better. I'm entirely flexible on this.

Quoted 8 lines

* Use the __HAVE_ARCH_* mechanism that include/asm-*/string.h uses. Caveat: Linus has lately come out as hating this style. It makes for the smallest patch, though.
* Define the generic code in lib/, and have each arch that really uses it export it.
* Put generic code in include/asm-generic/algo-memcpy_toio32.h, and have each arch that needs it #include it somewhere and use it.

The middle alternative seems the cleanest, although I'm not sure where the export really belongs.

I don't think I could really say the right way to do this without thinking some more -- but I am positive that exporting a function that will never ever be called is something we should work hard to avoid.

- R.

#5 lore raw

Re: [PATCH 1 of 3] Introduce __memcpy_toio32

In reply to Matt Mackall
Quoted 31 lines · Matt Mackall
Quoted 6 lines · Bryan O'Sullivan
Quoted 3 lines · Roland Dreier

I think the principle of least surprise calls for memcpy_toio32 to be ordered the same way memcpy_toio is. In other words there should be a wmb() after the loop.

Quoted 6 lines

Will do.

Quoted 1 line

Also, no need for the { } for the while loop.

Fine. There doesn't seem to be much consistency in whether to use curlies for single-line blocks.

We've been very consistent in discouraging it in new code. Enforcement of fine points of coding style is a post-2.5 phenomenon, so it hasn't hit all the tree yet.

Quoted 7 lines
Quoted 2 lines

You're adding this symbol and exporting it even if the arch will supply its own version. So this is pure kernel .text bloat...

I don't know what you'd prefer, so let me enumerate a few alternatives, and you can either tell me which you'd prefer, or point out something I've missed that would be even better. I'm entirely flexible on this.

Quoted 5 lines

* Use the __HAVE_ARCH_* mechanism that include/asm-*/string.h uses. Caveat: Linus has lately come out as hating this style. It makes for the smallest patch, though.
* Define the generic code in lib/, and have each arch that really uses it export it.

Quoted 3 lines

I'd favor this, at least for this case. If it becomes more widely used, we'll relocate the export.
...

I don't like this for two reasons:
- we are moving exports to the actual functions and steadily killing all *syms* files
- the lib-y approach has the disadvantage of completely omitting the function if it's used only in modules resulting in non-working modules

Where's the problem with the __HAVE_ARCH_* mechanism?

cu
Adrian

Signature · 4 lines
       "Is there not promise of rain?" Ling Tan asked suddenly out
        of the darkness. There had been need of rain for many days.
       "Only a promise," Lao Er said.
                                       Pearl S. Buck - Dragon Seed
#6 lore raw

Re: [PATCH 1 of 3] Introduce __memcpy_toio32

Quoted 36 lines · Adrian Bunk
Quoted 31 lines · Matt Mackall
Quoted 6 lines · Bryan O'Sullivan
Quoted 3 lines · Roland Dreier

I think the principle of least surprise calls for memcpy_toio32 to be ordered the same way memcpy_toio is. In other words there should be a wmb() after the loop.

Quoted 6 lines

Will do.

Quoted 1 line

Also, no need for the { } for the while loop.

Fine. There doesn't seem to be much consistency in whether to use curlies for single-line blocks.

We've been very consistent in discouraging it in new code. Enforcement of fine points of coding style is a post-2.5 phenomenon, so it hasn't hit all the tree yet.

Quoted 7 lines
Quoted 2 lines

You're adding this symbol and exporting it even if the arch will supply its own version. So this is pure kernel .text bloat...

I don't know what you'd prefer, so let me enumerate a few alternatives, and you can either tell me which you'd prefer, or point out something I've missed that would be even better. I'm entirely flexible on this.

Quoted 5 lines

* Use the __HAVE_ARCH_* mechanism that include/asm-*/string.h uses. Caveat: Linus has lately come out as hating this style. It makes for the smallest patch, though.
* Define the generic code in lib/, and have each arch that really uses it export it.

Quoted 3 lines

I'd favor this, at least for this case. If it becomes more widely used, we'll relocate the export.
...

Quoted 8 lines

I don't like this for two reasons:
- we are moving exports to the actual functions and steadily killing all *syms* files
- the lib-y approach has the disadvantage of completely omitting the function if it's used only in modules resulting in non-working modules

Where's the problem with the __HAVE_ARCH_* mechanism?

The head penguin peed on it last week.

Signature · 1 line
Mathematics is the supreme nostalgia of our time.
#7 lore raw

Re: [PATCH 1 of 3] Introduce __memcpy_toio32

Quoted 4 lines · Matt Mackall
Quoted 2 lines

Where's the problem with the __HAVE_ARCH_* mechanism?

The head penguin peed on it last week.

Actually "sprkinling with penguin pee" means that something is blessed (it's like a kernel baptism). Maybe that's not very civilized, but hey, penguins don't have thumbs, and are thus kind of limited in their actions. Don't be speciest.

So the head penguin didn't pee on it, it turned its back in disgust, and hoped that it would freeze to death in the arctic winter.

And no, I don't like the __HAVE_ARCH_xxx mechanisms at all. They are pointless, and hard to follow. If an architecture wants to use a generic mechanism, it should do one of the following (or a combination):

- use the config file mechanism, and use

	obj-$(CONFIG_GENERIC_FOO) += generic-foo.c

in a Makefile to link in the generic version.

Examples: CONFIG_RWSEM_GENERIC_SPINLOCK.

- just include the generic header from its own header, eg just do a

	#include <asm-generic/div64.h>

or similar.

Now, the latter in particular is very easy to follow: if you look into the <asm/div64.h> file and see that it just includes <asm-generic/div64.h>, it's very obvious what is going on and where to find the real implementation. You never have to wonder what the indirection means.

Similarly, anybody that fixes the generic header file can _trivially_ grep for its use. So the code stays clean, and there are absolutely zero compile-time conditionals, and the linkages both ways are obvious. And architectures that do _not_ use the generic routines are totally unaffected by them, and they don't need to specify any flags like "I have my own routines" to disable things.

Now, the CONFIG_GENERIC_FOO thing is a bit less obvious, and you may have to know about that config option in order to realize that a particular architecture is using a generic library routine, but at least with those Kconfig options, the language to describe them is clean these days, and it's _the_ standard way to express configuration information. So it may be a bit subtler and more indirect, but once you get used to it, it too is very clean.

In contrast, the __HAVE_ARCH_xxx thing has zero upsides. It just causes #ifdef mess in C source files, and unnecessary noise in standard header files. I know it's been there for a long time, but just grep for __HAVE_ARCH_MEMCPY and cry. Why the hell should all the architectures that have their own optimized memcpy() have to tell the rest of the world about it?

[ Yeah, I know why: bad implementation choice. It could easily have been
done with the asm-generic approach or CONFIG_GENERIC_MEMCPY, but it wasn't. Note that the __HAVE_ARCH_xxx thing isn't even a standard form:
sometimes it's the negation: __ARCH_WANT_xxx, and sometimes it's called something else entirely, like USE_ELF_CORE_DUMP or HAVE_PCI_MMAP, or ARCH_HAS_PREFETCH or HAVE_CSUM_COPY_USER. My point being that it's totally ad-hoc and random. ]

So we do have tons of ugly stuff, I just am trying to argue for not making more of it (I don't think it's a big enough deal that it would be worth it trying to clean up old uses).

If you look at the mutex patches, for example, I think everybody will agree that they look much _better_ after they moved to just using the trivial "#include <asm-generic/mutex-xyzzy.h>" format. At least I don't _think_ this is just a personal weird hang-up of mine. It's literally a cleanliness issue.

Linus

#8 lore raw

Re: (OT) [PATCH 1 of 3] Introduce __memcpy_toio32

Quoted 8 lines
Quoted 2 lines

The head penguin peed on it last week.

Actually "sprkinling with penguin pee" means that something is blessed (it's like a kernel baptism). Maybe that's not very civilized, but hey, penguins don't have thumbs, and are thus kind of limited in their actions. Don't be speciest.

At least they could have used water instead of pee.

Jan

#9 lore raw

Re: (OT) [PATCH 1 of 3] Introduce __memcpy_toio32

Quoted 9 lines · Jan Engelhardt
Quoted 7 lines
Quoted 2 lines

The head penguin peed on it last week.

Actually "sprinkling with penguin pee" means that something is blessed (it's like a kernel baptism). Maybe that's not very civilized, but hey, penguins don't have thumbs, and are thus kind of limited in their actions. Don't be speciest.

At least they could have used water instead of pee.

Hey, when you live at -40 deg C for long times, I challenge you to find some liquid water to sprinkle around.

Antarctica is one of the driest places on earth - never mind that there's tons of ice around.

You use what you have.

Linus

#10 lore raw

Re: [PATCH 1 of 3] Introduce __memcpy_toio32

In reply to Linus Torvalds
Quoted 21 lines · Linus Torvalds

...

Quoted 1 line
Quoted 1 line

Where's the problem with the __HAVE_ARCH_* mechanism?

...
And no, I don't like the __HAVE_ARCH_xxx mechanisms at all. They are pointless, and hard to follow. If an architecture wants to use a generic mechanism, it should do one of the following (or a combination):

- use the config file mechanism, and use

	obj-$(CONFIG_GENERIC_FOO) += generic-foo.c

in a Makefile to link in the generic version.

Examples: CONFIG_RWSEM_GENERIC_SPINLOCK.

- just include the generic header from its own header, eg just do a

	#include <asm-generic/div64.h>

or similar.

Quoted 13 lines

Now, the latter in particular is very easy to follow: if you look into the <asm/div64.h> file and see that it just includes <asm-generic/div64.h>, it's very obvious what is going on and where to find the real implementation. You never have to wonder what the indirection means.
...
Now, the CONFIG_GENERIC_FOO thing is a bit less obvious, and you may have to know about that config option in order to realize that a particular architecture is using a generic library routine, but at least with those Kconfig options, the language to describe them is clean these days, and it's _the_ standard way to express configuration information. So it may be a bit subtler and more indirect, but once you get used to it, it too is very clean.
...

OK, this I don't have any problem with.

I'm not yet fully convinced that __HAVE_ARCH_xxx is really that bad, but your proposed solution doesn't have the problems I had in mind.

What is OK:
obj-$(CONFIG_GENERIC_FOO) += generic-foo.o

What is not OK:
lib-y += generic-foo.o

The latter has the following disadvantages:
- it's non-obvious whether the object actually gets included in the kernel
- if the contents of generic-foo.o is only used in modules, generic-foo.o is _not_ included in the kernel resulting in an obvious breakage

Quoted 1 line

Linus

cu
Adrian

Signature · 4 lines
       "Is there not promise of rain?" Ling Tan asked suddenly out
        of the darkness. There had been need of rain for many days.
       "Only a promise," Lao Er said.
                                       Pearl S. Buck - Dragon Seed
#24 lore raw

Re: [PATCH 2 of 3] memcpy32 for x86_64

In reply to Bryan O'Sullivan

arch/x86_64/lib/memcpy32.S line 3

Quoted 12 lines · Bryan O'Sullivan

Introduce an x86_64-specific memcpy32 routine. The routine is similar to memcpy, but is guaranteed to work in units of 32 bits at a time.

diff -r 7b7b442a4d63 -r 042b7d9004ac arch/x86_64/lib/memcpy32.S

arch/x86_64/lib/memcpy32.S new file +3 -0
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2003, 2004, 2005 PathScale, Inc.
+ */

Did it really take 3 years to develop this? Anyway this contains copyright but not GPL, not allowing us to distribute it.
Pavel

Signature · 1 line
Thanks, Sharp!
#25 lore raw

Re: [PATCH 2 of 3] memcpy32 for x86_64

Quoted 1 line · Pavel Machek

Did it really take 3 years to develop this?

Each instruction is carefully aged in an oak barrel, in a climate-controlled cave.

Quoted 2 lines

Anyway this contains
copyright but not GPL, not allowing us to distribute it.

I'll fix that, next round.

	<b