2002-01-10 21:52:48

by Jesse Barnes

[permalink] [raw]
Subject: memory-mapped i/o barrier

Here's a copy of a patch I just got accepted into the 2.5 patch for
ia64, and I'm wondering if you guys will accept something similar. On
mips64, mmiob() could just be implemented as a 'sync', but I'm not
sure how to do it (or if it's even necessary) on other platforms.
Please let me know what you think. I wrote a small documentation file
for the macro that appears at the top of the patch.

Thanks,
Jesse


diff -Naur --exclude=*~ --exclude=TAGS linux-2.4.17-ia64/Documentation/mmio_barrier.txt linux-2.4.17-ia64-mmiob/Documentation/mmio_barrier.txt
--- linux-2.4.17-ia64/Documentation/mmio_barrier.txt Wed Dec 31 16:00:00 1969
+++ linux-2.4.17-ia64-mmiob/Documentation/mmio_barrier.txt Tue Jan 8 15:57:37 2002
@@ -0,0 +1,15 @@
+On some platforms, so-called memory-mapped I/O is weakly ordered. For
+example, the following might occur:
+
+CPU A writes 0x1 to Device #1
+CPU B writes 0x2 to Device #1
+Device #1 sees 0x2
+Device #1 sees 0x1
+
+On such platforms, driver writers are responsible for guaranteeing that I/O
+writes to memory-mapped addresses on their device arrive in the order
+intended. The mmiob() macro is provided for this purpose. A typical use
+of this macro might be immediately prior to the exit of a critical
+section of code proteced by spinlocks. This would ensure that subsequent
+writes to I/O space arrived only after all prior writes (much like a
+typical memory barrier op, mb(), only with respect to I/O).
diff -Naur --exclude=*~ --exclude=TAGS linux-2.4.17-ia64/arch/ia64/sn/kernel/sn1/iomv.c linux-2.4.17-ia64-mmiob/arch/ia64/sn/kernel/sn1/iomv.c
--- linux-2.4.17-ia64/arch/ia64/sn/kernel/sn1/iomv.c Tue Jan 8 15:45:11 2002
+++ linux-2.4.17-ia64-mmiob/arch/ia64/sn/kernel/sn1/iomv.c Tue Jan 8 15:58:54 2002
@@ -9,6 +9,8 @@
#include <asm/io.h>
#include <linux/pci.h>
#include <asm/sn/simulator.h>
+#include <asm/pio_flush.h>
+#include <asm/delay.h>

static inline void *
sn1_io_addr(unsigned long port)
@@ -134,3 +136,9 @@
__ia64_mf_a();
}
#endif /* SN1_IOPORTS */
+
+void
+sn_mmiob ()
+{
+ PIO_FLUSH();
+}
diff -Naur --exclude=*~ --exclude=TAGS linux-2.4.17-ia64/include/asm-ia64/io.h linux-2.4.17-ia64-mmiob/include/asm-ia64/io.h
--- linux-2.4.17-ia64/include/asm-ia64/io.h Fri Nov 9 14:26:17 2001
+++ linux-2.4.17-ia64-mmiob/include/asm-ia64/io.h Wed Jan 9 10:53:46 2002
@@ -69,6 +69,21 @@
*/
#define __ia64_mf_a() __asm__ __volatile__ ("mf.a" ::: "memory")

+/**
+ * __ia64_mmiob - I/O space memory barrier
+ *
+ * Acts as a memory mapped I/O barrier for platforms that queue writes to
+ * I/O space. This ensures that subsequent writes to I/O space arrive after
+ * all previous writes. For most ia64 platforms, this is a simple
+ * 'mf.a' instruction. For other platforms, mmiob() may have to read
+ * a chipset register to ensure ordering.
+ */
+static inline void
+__ia64_mmiob ()
+{
+ __ia64_mf_a();
+}
+
static inline const unsigned long
__ia64_get_io_port_base (void)
{
@@ -271,6 +286,7 @@
#define __outb platform_outb
#define __outw platform_outw
#define __outl platform_outl
+#define __mmiob platform_mmiob

#define inb __inb
#define inw __inw
@@ -284,6 +300,7 @@
#define outsb __outsb
#define outsw __outsw
#define outsl __outsl
+#define mmiob __mmiob

/*
* The address passed to these functions are ioremap()ped already.
diff -Naur --exclude=*~ --exclude=TAGS linux-2.4.17-ia64/include/asm-ia64/machvec.h linux-2.4.17-ia64-mmiob/include/asm-ia64/machvec.h
--- linux-2.4.17-ia64/include/asm-ia64/machvec.h Tue Jan 8 15:45:11 2002
+++ linux-2.4.17-ia64-mmiob/include/asm-ia64/machvec.h Tue Jan 8 15:59:44 2002
@@ -60,6 +60,7 @@
typedef void ia64_mv_outb_t (unsigned char, unsigned long);
typedef void ia64_mv_outw_t (unsigned short, unsigned long);
typedef void ia64_mv_outl_t (unsigned int, unsigned long);
+typedef void ia64_mv_mmiob_t (void);

extern void machvec_noop (void);

@@ -107,6 +108,7 @@
# define platform_outb ia64_mv.outb
# define platform_outw ia64_mv.outw
# define platform_outl ia64_mv.outl
+# define platofrm_mmiob ia64_mv.mmiob
# endif

struct ia64_machine_vector {
@@ -140,6 +142,7 @@
ia64_mv_outb_t *outb;
ia64_mv_outw_t *outw;
ia64_mv_outl_t *outl;
+ ia64_mv_mmiob_t *mmiob;
};

#define MACHVEC_INIT(name) \
@@ -173,7 +176,8 @@
platform_inl, \
platform_outb, \
platform_outw, \
- platform_outl \
+ platform_outl, \
+ platform_mmiob \
}

extern struct ia64_machine_vector ia64_mv;
@@ -287,6 +291,9 @@
#endif
#ifndef platform_outl
# define platform_outl __ia64_outl
+#endif
+#ifndef platform_mmiob
+# define platform_mmiob __ia64_mmiob
#endif

#endif /* _ASM_IA64_MACHVEC_H */
diff -Naur --exclude=*~ --exclude=TAGS linux-2.4.17-ia64/include/asm-ia64/machvec_sn1.h linux-2.4.17-ia64-mmiob/include/asm-ia64/machvec_sn1.h
--- linux-2.4.17-ia64/include/asm-ia64/machvec_sn1.h Tue Jan 8 15:45:11 2002
+++ linux-2.4.17-ia64-mmiob/include/asm-ia64/machvec_sn1.h Tue Jan 8 15:45:54 2002
@@ -14,6 +14,7 @@
extern ia64_mv_outb_t sn1_outb;
extern ia64_mv_outw_t sn1_outw;
extern ia64_mv_outl_t sn1_outl;
+extern ia64_mv_mmiob_t sn_mmiob;
extern ia64_mv_pci_alloc_consistent sn1_pci_alloc_consistent;
extern ia64_mv_pci_free_consistent sn1_pci_free_consistent;
extern ia64_mv_pci_map_single sn1_pci_map_single;
@@ -45,6 +46,7 @@
#define platform_outb sn1_outb
#define platform_outw sn1_outw
#define platform_outl sn1_outl
+#define platform_mmiob sn_mmiob
#define platform_pci_dma_init machvec_noop
#define platform_pci_alloc_consistent sn1_pci_alloc_consistent
#define platform_pci_free_consistent sn1_pci_free_consistent


2002-01-10 22:54:00

by Alan

[permalink] [raw]
Subject: Re: memory-mapped i/o barrier

> ia64, and I'm wondering if you guys will accept something similar. On
> mips64, mmiob() could just be implemented as a 'sync', but I'm not
> sure how to do it (or if it's even necessary) on other platforms.

Wouldn't it be wise to pass the device to this. Someone somewhere is going
to have to read a bus dependant chipset register and need to know which
pci_device * is involved ?

2002-01-10 23:03:00

by Jesse Barnes

[permalink] [raw]
Subject: Re: memory-mapped i/o barrier

On Thu, Jan 10, 2002 at 11:05:04PM +0000, Alan Cox wrote:
> > ia64, and I'm wondering if you guys will accept something similar. On
> > mips64, mmiob() could just be implemented as a 'sync', but I'm not
> > sure how to do it (or if it's even necessary) on other platforms.
>
> Wouldn't it be wise to pass the device to this. Someone somewhere is going
> to have to read a bus dependant chipset register and need to know which
> pci_device * is involved ?

David and I went back and forth on that a little. My hope is that
most platforms will have a reasonable way (i.e. no pci_device needed)
to ensure ordering. I'm only aware of two platforms at the moment
that have i/o ordering issues: mips64 and ia64/sn. On the former, a
simple 'sync' instruction is sufficient to barrier i/o, while on the
latter, a read from the local numa hub suffices.

If only a few platforms need info about which busses have outstanding
i/o, it should be possible to build a list of bridge chips or devices
and loop, reading from each (where presumably the read would act as
the barrier op).

If, OTOH, there are lots of platforms that need a pci_device so they
can read from a corresponding bridge to ensure ordering, it would be a
good idea to add an argument to the macro, as David initially
suggested.

Thoughts?

Jesse

2002-01-15 00:30:40

by Anton Blanchard

[permalink] [raw]
Subject: Re: memory-mapped i/o barrier


Hi,

> Here's a copy of a patch I just got accepted into the 2.5 patch for
> ia64, and I'm wondering if you guys will accept something similar. On
> mips64, mmiob() could just be implemented as a 'sync', but I'm not
> sure how to do it (or if it's even necessary) on other platforms.
> Please let me know what you think. I wrote a small documentation file
> for the macro that appears at the top of the patch.
>
> Thanks,
> Jesse
>
>
> diff -Naur --exclude=*~ --exclude=TAGS linux-2.4.17-ia64/Documentation/mmio_barrier.txt linux-2.4.17-ia64-mmiob/Documentation/mmio_barrier.txt
> --- linux-2.4.17-ia64/Documentation/mmio_barrier.txt Wed Dec 31 16:00:00 1969
> +++ linux-2.4.17-ia64-mmiob/Documentation/mmio_barrier.txt Tue Jan 8 15:57:37 2002
> @@ -0,0 +1,15 @@
> +On some platforms, so-called memory-mapped I/O is weakly ordered. For
> +example, the following might occur:
> +
> +CPU A writes 0x1 to Device #1
> +CPU B writes 0x2 to Device #1
> +Device #1 sees 0x2
> +Device #1 sees 0x1

Can loads/stores also complete out of order to IO? (the example just shows
a store from one cpu passing one from another cpu)

On ppc32/ppc64 this can happen, it is fixed up in the low level pci
routines. Is there a case where you cant wrap it up in the low level
routines like ppc32/ppc64?

Anton

2002-01-15 01:06:22

by Jesse Barnes

[permalink] [raw]
Subject: Re: memory-mapped i/o barrier

On Mon, Jan 14, 2002 at 05:24:54PM +1100, Anton Blanchard wrote:
> Can loads/stores also complete out of order to IO? (the example just shows
> a store from one cpu passing one from another cpu)

I'm not sure what you mean, do you have an example?

> On ppc32/ppc64 this can happen, it is fixed up in the low level pci
> routines. Is there a case where you cant wrap it up in the low level
> routines like ppc32/ppc64?

You mean in each outX routine you essentially do an mmiob()?

Jesse