fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / include / asm-powerpc / io.h
index 68efbea..40edd19 100644 (file)
  * 2 of the License, or (at your option) any later version.
  */
 
-#ifndef CONFIG_PPC64
-#include <asm-ppc/io.h>
-#else
+/* Check of existence of legacy devices */
+extern int check_legacy_ioport(unsigned long base_port);
+#define PNPBIOS_BASE   0xf000  /* only relevant for PReP */
 
 #include <linux/compiler.h>
 #include <asm/page.h>
 #include <asm/byteorder.h>
-#ifdef CONFIG_PPC_ISERIES 
-#include <asm/iseries/iseries_io.h>
-#endif  
 #include <asm/synch.h>
 #include <asm/delay.h>
+#include <asm/mmu.h>
 
 #include <asm-generic/iomap.h>
 
-#define __ide_mm_insw(p, a, c) _insw_ns((volatile u16 __iomem *)(p), (a), (c))
-#define __ide_mm_insl(p, a, c) _insl_ns((volatile u32 __iomem *)(p), (a), (c))
-#define __ide_mm_outsw(p, a, c) _outsw_ns((volatile u16 __iomem *)(p), (a), (c))
-#define __ide_mm_outsl(p, a, c) _outsl_ns((volatile u32 __iomem *)(p), (a), (c))
-
+#ifdef CONFIG_PPC64
+#include <asm/paca.h>
+#endif
 
 #define SIO_CONFIG_RA  0x398
 #define SIO_CONFIG_RD  0x399
 
 #define SLOW_DOWN_IO
 
+/* 32 bits uses slightly different variables for the various IO
+ * bases. Most of this file only uses _IO_BASE though which we
+ * define properly based on the platform
+ */
+#ifndef CONFIG_PCI
+#define _IO_BASE       0
+#define _ISA_MEM_BASE  0
+#define PCI_DRAM_OFFSET 0
+#elif defined(CONFIG_PPC32)
+#define _IO_BASE       isa_io_base
+#define _ISA_MEM_BASE  isa_mem_base
+#define PCI_DRAM_OFFSET        pci_dram_offset
+#else
+#define _IO_BASE       pci_io_base
+#define _ISA_MEM_BASE  0
+#define PCI_DRAM_OFFSET        0
+#endif
+
 extern unsigned long isa_io_base;
+extern unsigned long isa_mem_base;
 extern unsigned long pci_io_base;
-extern unsigned long io_page_mask;
-
-#define MAX_ISA_PORT 0x10000
-
-#define _IO_IS_VALID(port) ((port) >= MAX_ISA_PORT || (1 << (port>>PAGE_SHIFT)) \
-                           & io_page_mask)
-
-#ifdef CONFIG_PPC_ISERIES
-/* __raw_* accessors aren't supported on iSeries */
-#define __raw_readb(addr)      { BUG(); 0; }
-#define __raw_readw(addr)       { BUG(); 0; }
-#define __raw_readl(addr)       { BUG(); 0; }
-#define __raw_readq(addr)       { BUG(); 0; }
-#define __raw_writeb(v, addr)   { BUG(); 0; }
-#define __raw_writew(v, addr)   { BUG(); 0; }
-#define __raw_writel(v, addr)   { BUG(); 0; }
-#define __raw_writeq(v, addr)   { BUG(); 0; }
-#define readb(addr)            iSeries_Read_Byte(addr)
-#define readw(addr)            iSeries_Read_Word(addr)
-#define readl(addr)            iSeries_Read_Long(addr)
-#define writeb(data, addr)     iSeries_Write_Byte((data),(addr))
-#define writew(data, addr)     iSeries_Write_Word((data),(addr))
-#define writel(data, addr)     iSeries_Write_Long((data),(addr))
-#define memset_io(a,b,c)       iSeries_memset_io((a),(b),(c))
-#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 inb(addr)              readb(((void __iomem *)(long)(addr)))
-#define inw(addr)              readw(((void __iomem *)(long)(addr)))
-#define inl(addr)              readl(((void __iomem *)(long)(addr)))
-#define outb(data,addr)                writeb(data,((void __iomem *)(long)(addr)))
-#define outw(data,addr)                writew(data,((void __iomem *)(long)(addr)))
-#define outl(data,addr)                writel(data,((void __iomem *)(long)(addr)))
+extern unsigned long pci_dram_offset;
+
+#if defined(CONFIG_PPC32) && defined(CONFIG_PPC_INDIRECT_IO)
+#error CONFIG_PPC_INDIRECT_IO is not yet supported on 32 bits
+#endif
+
 /*
- * The *_ns versions below don't do byte-swapping.
- * Neither do the standard versions now, these are just here
- * for older code.
+ *
+ * Low level MMIO accessors
+ *
+ * This provides the non-bus specific accessors to MMIO. Those are PowerPC
+ * specific and thus shouldn't be used in generic code. The accessors
+ * provided here are:
+ *
+ *     in_8, in_le16, in_be16, in_le32, in_be32, in_le64, in_be64
+ *     out_8, out_le16, out_be16, out_le32, out_be32, out_le64, out_be64
+ *     _insb, _insw_ns, _insl_ns, _outsb, _outsw_ns, _outsl_ns
+ *
+ * Those operate directly on a kernel virtual address. Note that the prototype
+ * for the out_* accessors has the arguments in opposite order from the usual
+ * linux PCI accessors. Unlike those, they take the address first and the value
+ * next.
+ *
+ * Note: I might drop the _ns suffix on the stream operations soon as it is
+ * simply normal for stream operations to not swap in the first place.
+ *
  */
-#define insw_ns(port, buf, ns) _insw_ns((u16 __iomem *)((port)+pci_io_base), (buf), (ns))
-#define insl_ns(port, buf, nl) _insl_ns((u32 __iomem *)((port)+pci_io_base), (buf), (nl))
+
+#ifdef CONFIG_PPC64
+#define IO_SET_SYNC_FLAG()     do { get_paca()->io_sync = 1; } while(0)
 #else
+#define IO_SET_SYNC_FLAG()
+#endif
+
+#define DEF_MMIO_IN(name, type, insn)                                  \
+static inline type name(const volatile type __iomem *addr)             \
+{                                                                      \
+       type ret;                                                       \
+       __asm__ __volatile__("sync;" insn ";twi 0,%0,0;isync"           \
+               : "=r" (ret) : "r" (addr), "m" (*addr));                \
+       return ret;                                                     \
+}
+
+#define DEF_MMIO_OUT(name, type, insn)                                 \
+static inline void name(volatile type __iomem *addr, type val)         \
+{                                                                      \
+       __asm__ __volatile__("sync;" insn                               \
+               : "=m" (*addr) : "r" (val), "r" (addr));                \
+       IO_SET_SYNC_FLAG();                                     \
+}
+
+
+#define DEF_MMIO_IN_BE(name, size, insn) \
+       DEF_MMIO_IN(name, u##size, __stringify(insn)"%U2%X2 %0,%2")
+#define DEF_MMIO_IN_LE(name, size, insn) \
+       DEF_MMIO_IN(name, u##size, __stringify(insn)" %0,0,%1")
+
+#define DEF_MMIO_OUT_BE(name, size, insn) \
+       DEF_MMIO_OUT(name, u##size, __stringify(insn)"%U0%X0 %1,%0")
+#define DEF_MMIO_OUT_LE(name, size, insn) \
+       DEF_MMIO_OUT(name, u##size, __stringify(insn)" %1,0,%2")
+
+DEF_MMIO_IN_BE(in_8,     8, lbz);
+DEF_MMIO_IN_BE(in_be16, 16, lhz);
+DEF_MMIO_IN_BE(in_be32, 32, lwz);
+DEF_MMIO_IN_LE(in_le16, 16, lhbrx);
+DEF_MMIO_IN_LE(in_le32, 32, lwbrx);
+
+DEF_MMIO_OUT_BE(out_8,     8, stb);
+DEF_MMIO_OUT_BE(out_be16, 16, sth);
+DEF_MMIO_OUT_BE(out_be32, 32, stw);
+DEF_MMIO_OUT_LE(out_le16, 16, sthbrx);
+DEF_MMIO_OUT_LE(out_le32, 32, stwbrx);
+
+#ifdef __powerpc64__
+DEF_MMIO_OUT_BE(out_be64, 64, std);
+DEF_MMIO_IN_BE(in_be64, 64, ld);
+
+/* There is no asm instructions for 64 bits reverse loads and stores */
+static inline u64 in_le64(const volatile u64 __iomem *addr)
+{
+       return le64_to_cpu(in_be64(addr));
+}
+
+static inline void out_le64(volatile u64 __iomem *addr, u64 val)
+{
+       out_be64(addr, cpu_to_le64(val));
+}
+#endif /* __powerpc64__ */
+
+/*
+ * Low level IO stream instructions are defined out of line for now
+ */
+extern void _insb(const volatile u8 __iomem *addr, void *buf, long count);
+extern void _outsb(volatile u8 __iomem *addr,const void *buf,long count);
+extern void _insw_ns(const volatile u16 __iomem *addr, void *buf, long count);
+extern void _outsw_ns(volatile u16 __iomem *addr, const void *buf, long count);
+extern void _insl_ns(const volatile u32 __iomem *addr, void *buf, long count);
+extern void _outsl_ns(volatile u32 __iomem *addr, const void *buf, long count);
+
+/* The _ns naming is historical and will be removed. For now, just #define
+ * the non _ns equivalent names
+ */
+#define _insw  _insw_ns
+#define _insl  _insl_ns
+#define _outsw _outsw_ns
+#define _outsl _outsl_ns
+
+
+/*
+ * memset_io, memcpy_toio, memcpy_fromio base implementations are out of line
+ */
+
+extern void _memset_io(volatile void __iomem *addr, int c, unsigned long n);
+extern void _memcpy_fromio(void *dest, const volatile void __iomem *src,
+                          unsigned long n);
+extern void _memcpy_toio(volatile void __iomem *dest, const void *src,
+                        unsigned long n);
+
+/*
+ *
+ * PCI and standard ISA accessors
+ *
+ * Those are globally defined linux accessors for devices on PCI or ISA
+ * busses. They follow the Linux defined semantics. The current implementation
+ * for PowerPC is as close as possible to the x86 version of these, and thus
+ * provides fairly heavy weight barriers for the non-raw versions
+ *
+ * In addition, they support a hook mechanism when CONFIG_PPC_INDIRECT_IO
+ * allowing the platform to provide its own implementation of some or all
+ * of the accessors.
+ */
+
+/*
+ * Include the EEH definitions when EEH is enabled only so they don't get
+ * in the way when building for 32 bits
+ */
+#ifdef CONFIG_EEH
+#include <asm/eeh.h>
+#endif
+
+/* Shortcut to the MMIO argument pointer */
+#define PCI_IO_ADDR    volatile void __iomem *
+
+/* Indirect IO address tokens:
+ *
+ * When CONFIG_PPC_INDIRECT_IO is set, the platform can provide hooks
+ * on all IOs. (Note that this is all 64 bits only for now)
+ *
+ * To help platforms who may need to differenciate MMIO addresses in
+ * their hooks, a bitfield is reserved for use by the platform near the
+ * top of MMIO addresses (not PIO, those have to cope the hard way).
+ *
+ * This bit field is 12 bits and is at the top of the IO virtual
+ * addresses PCI_IO_INDIRECT_TOKEN_MASK.
+ *
+ * The kernel virtual space is thus:
+ *
+ *  0xD000000000000000         : vmalloc
+ *  0xD000080000000000         : PCI PHB IO space
+ *  0xD000080080000000         : ioremap
+ *  0xD0000fffffffffff         : end of ioremap region
+ *
+ * Since the top 4 bits are reserved as the region ID, we use thus
+ * the next 12 bits and keep 4 bits available for the future if the
+ * virtual address space is ever to be extended.
+ *
+ * The direct IO mapping operations will then mask off those bits
+ * before doing the actual access, though that only happen when
+ * CONFIG_PPC_INDIRECT_IO is set, thus be careful when you use that
+ * mechanism
+ */
+
+#ifdef CONFIG_PPC_INDIRECT_IO
+#define PCI_IO_IND_TOKEN_MASK  0x0fff000000000000ul
+#define PCI_IO_IND_TOKEN_SHIFT 48
+#define PCI_FIX_ADDR(addr)                                             \
+       ((PCI_IO_ADDR)(((unsigned long)(addr)) & ~PCI_IO_IND_TOKEN_MASK))
+#define PCI_GET_ADDR_TOKEN(addr)                                       \
+       (((unsigned long)(addr) & PCI_IO_IND_TOKEN_MASK) >>             \
+               PCI_IO_IND_TOKEN_SHIFT)
+#define PCI_SET_ADDR_TOKEN(addr, token)                                \
+do {                                                                   \
+       unsigned long __a = (unsigned long)(addr);                      \
+       __a &= ~PCI_IO_IND_TOKEN_MASK;                                  \
+       __a |= ((unsigned long)(token)) << PCI_IO_IND_TOKEN_SHIFT;      \
+       (addr) = (void __iomem *)__a;                                   \
+} while(0)
+#else
+#define PCI_FIX_ADDR(addr) (addr)
+#endif
+
+
+/*
+ * Non ordered and non-swapping "raw" accessors
+ */
 
 static inline unsigned char __raw_readb(const volatile void __iomem *addr)
 {
-       return *(volatile unsigned char __force *)addr;
+       return *(volatile unsigned char __force *)PCI_FIX_ADDR(addr);
 }
 static inline unsigned short __raw_readw(const volatile void __iomem *addr)
 {
-       return *(volatile unsigned short __force *)addr;
+       return *(volatile unsigned short __force *)PCI_FIX_ADDR(addr);
 }
 static inline unsigned int __raw_readl(const volatile void __iomem *addr)
 {
-       return *(volatile unsigned int __force *)addr;
-}
-static inline unsigned long __raw_readq(const volatile void __iomem *addr)
-{
-       return *(volatile unsigned long __force *)addr;
+       return *(volatile unsigned int __force *)PCI_FIX_ADDR(addr);
 }
 static inline void __raw_writeb(unsigned char v, volatile void __iomem *addr)
 {
-       *(volatile unsigned char __force *)addr = v;
+       *(volatile unsigned char __force *)PCI_FIX_ADDR(addr) = v;
 }
 static inline void __raw_writew(unsigned short v, volatile void __iomem *addr)
 {
-       *(volatile unsigned short __force *)addr = v;
+       *(volatile unsigned short __force *)PCI_FIX_ADDR(addr) = v;
 }
 static inline void __raw_writel(unsigned int v, volatile void __iomem *addr)
 {
-       *(volatile unsigned int __force *)addr = v;
+       *(volatile unsigned int __force *)PCI_FIX_ADDR(addr) = v;
+}
+
+#ifdef __powerpc64__
+static inline unsigned long __raw_readq(const volatile void __iomem *addr)
+{
+       return *(volatile unsigned long __force *)PCI_FIX_ADDR(addr);
 }
 static inline void __raw_writeq(unsigned long v, volatile void __iomem *addr)
 {
-       *(volatile unsigned long __force *)addr = v;
+       *(volatile unsigned long __force *)PCI_FIX_ADDR(addr) = v;
 }
-#define readb(addr)            eeh_readb(addr)
-#define readw(addr)            eeh_readw(addr)
-#define readl(addr)            eeh_readl(addr)
-#define readq(addr)            eeh_readq(addr)
-#define writeb(data, addr)     eeh_writeb((data), (addr))
-#define writew(data, addr)     eeh_writew((data), (addr))
-#define writel(data, addr)     eeh_writel((data), (addr))
-#define writeq(data, addr)     eeh_writeq((data), (addr))
-#define memset_io(a,b,c)       eeh_memset_io((a),(b),(c))
-#define memcpy_fromio(a,b,c)   eeh_memcpy_fromio((a),(b),(c))
-#define memcpy_toio(a,b,c)     eeh_memcpy_toio((a),(b),(c))
-#define inb(port)              eeh_inb((unsigned long)port)
-#define outb(val, port)                eeh_outb(val, (unsigned long)port)
-#define inw(port)              eeh_inw((unsigned long)port)
-#define outw(val, port)                eeh_outw(val, (unsigned long)port)
-#define inl(port)              eeh_inl((unsigned long)port)
-#define outl(val, port)                eeh_outl(val, (unsigned long)port)
+#endif /* __powerpc64__ */
 
 /*
- * The insw/outsw/insl/outsl macros don't do byte-swapping.
- * They are only used in practice for transferring buffers which
- * are arrays of bytes, and byte-swapping is not appropriate in
- * that case.  - paulus */
-#define insb(port, buf, ns)    eeh_insb((port), (buf), (ns))
-#define insw(port, buf, ns)    eeh_insw_ns((port), (buf), (ns))
-#define insl(port, buf, nl)    eeh_insl_ns((port), (buf), (nl))
-#define insw_ns(port, buf, ns) eeh_insw_ns((port), (buf), (ns))
-#define insl_ns(port, buf, nl) eeh_insl_ns((port), (buf), (nl))
-
-#define outsb(port, buf, ns)  _outsb((u8 __iomem *)((port)+pci_io_base), (buf), (ns))
-#define outsw(port, buf, ns)  _outsw_ns((u16 __iomem *)((port)+pci_io_base), (buf), (ns))
-#define outsl(port, buf, nl)  _outsl_ns((u32 __iomem *)((port)+pci_io_base), (buf), (nl))
+ *
+ * PCI PIO and MMIO accessors.
+ *
+ *
+ * On 32 bits, PIO operations have a recovery mechanism in case they trigger
+ * machine checks (which they occasionally do when probing non existing
+ * IO ports on some platforms, like PowerMac and 8xx).
+ * I always found it to be of dubious reliability and I am tempted to get
+ * rid of it one of these days. So if you think it's important to keep it,
+ * please voice up asap. We never had it for 64 bits and I do not intend
+ * to port it over
+ */
+
+#ifdef CONFIG_PPC32
+
+#define __do_in_asm(name, op)                          \
+static inline unsigned int name(unsigned int port)     \
+{                                                      \
+       unsigned int x;                                 \
+       __asm__ __volatile__(                           \
+               "sync\n"                                \
+               "0:"    op "    %0,0,%1\n"              \
+               "1:     twi     0,%0,0\n"               \
+               "2:     isync\n"                        \
+               "3:     nop\n"                          \
+               "4:\n"                                  \
+               ".section .fixup,\"ax\"\n"              \
+               "5:     li      %0,-1\n"                \
+               "       b       4b\n"                   \
+               ".previous\n"                           \
+               ".section __ex_table,\"a\"\n"           \
+               "       .align  2\n"                    \
+               "       .long   0b,5b\n"                \
+               "       .long   1b,5b\n"                \
+               "       .long   2b,5b\n"                \
+               "       .long   3b,5b\n"                \
+               ".previous"                             \
+               : "=&r" (x)                             \
+               : "r" (port + _IO_BASE));               \
+       return x;                                       \
+}
+
+#define __do_out_asm(name, op)                         \
+static inline void name(unsigned int val, unsigned int port) \
+{                                                      \
+       __asm__ __volatile__(                           \
+               "sync\n"                                \
+               "0:" op " %0,0,%1\n"                    \
+               "1:     sync\n"                         \
+               "2:\n"                                  \
+               ".section __ex_table,\"a\"\n"           \
+               "       .align  2\n"                    \
+               "       .long   0b,2b\n"                \
+               "       .long   1b,2b\n"                \
+               ".previous"                             \
+               : : "r" (val), "r" (port + _IO_BASE));  \
+}
 
+__do_in_asm(_rec_inb, "lbzx")
+__do_in_asm(_rec_inw, "lhbrx")
+__do_in_asm(_rec_inl, "lwbrx")
+__do_out_asm(_rec_outb, "stbx")
+__do_out_asm(_rec_outw, "sthbrx")
+__do_out_asm(_rec_outl, "stwbrx")
+
+#endif /* CONFIG_PPC32 */
+
+/* The "__do_*" operations below provide the actual "base" implementation
+ * for each of the defined acccessor. Some of them use the out_* functions
+ * directly, some of them still use EEH, though we might change that in the
+ * future. Those macros below provide the necessary argument swapping and
+ * handling of the IO base for PIO.
+ *
+ * They are themselves used by the macros that define the actual accessors
+ * and can be used by the hooks if any.
+ *
+ * Note that PIO operations are always defined in terms of their corresonding
+ * MMIO operations. That allows platforms like iSeries who want to modify the
+ * behaviour of both to only hook on the MMIO version and get both. It's also
+ * possible to hook directly at the toplevel PIO operation if they have to
+ * be handled differently
+ */
+#define __do_writeb(val, addr) out_8(PCI_FIX_ADDR(addr), val)
+#define __do_writew(val, addr) out_le16(PCI_FIX_ADDR(addr), val)
+#define __do_writel(val, addr) out_le32(PCI_FIX_ADDR(addr), val)
+#define __do_writeq(val, addr) out_le64(PCI_FIX_ADDR(addr), val)
+#define __do_writew_be(val, addr) out_be16(PCI_FIX_ADDR(addr), val)
+#define __do_writel_be(val, addr) out_be32(PCI_FIX_ADDR(addr), val)
+#define __do_writeq_be(val, addr) out_be64(PCI_FIX_ADDR(addr), val)
+
+#ifdef CONFIG_EEH
+#define __do_readb(addr)       eeh_readb(PCI_FIX_ADDR(addr))
+#define __do_readw(addr)       eeh_readw(PCI_FIX_ADDR(addr))
+#define __do_readl(addr)       eeh_readl(PCI_FIX_ADDR(addr))
+#define __do_readq(addr)       eeh_readq(PCI_FIX_ADDR(addr))
+#define __do_readw_be(addr)    eeh_readw_be(PCI_FIX_ADDR(addr))
+#define __do_readl_be(addr)    eeh_readl_be(PCI_FIX_ADDR(addr))
+#define __do_readq_be(addr)    eeh_readq_be(PCI_FIX_ADDR(addr))
+#else /* CONFIG_EEH */
+#define __do_readb(addr)       in_8(PCI_FIX_ADDR(addr))
+#define __do_readw(addr)       in_le16(PCI_FIX_ADDR(addr))
+#define __do_readl(addr)       in_le32(PCI_FIX_ADDR(addr))
+#define __do_readq(addr)       in_le64(PCI_FIX_ADDR(addr))
+#define __do_readw_be(addr)    in_be16(PCI_FIX_ADDR(addr))
+#define __do_readl_be(addr)    in_be32(PCI_FIX_ADDR(addr))
+#define __do_readq_be(addr)    in_be64(PCI_FIX_ADDR(addr))
+#endif /* !defined(CONFIG_EEH) */
+
+#ifdef CONFIG_PPC32
+#define __do_outb(val, port)   _rec_outb(val, port)
+#define __do_outw(val, port)   _rec_outw(val, port)
+#define __do_outl(val, port)   _rec_outl(val, port)
+#define __do_inb(port)         _rec_inb(port)
+#define __do_inw(port)         _rec_inw(port)
+#define __do_inl(port)         _rec_inl(port)
+#else /* CONFIG_PPC32 */
+#define __do_outb(val, port)   writeb(val,(PCI_IO_ADDR)_IO_BASE+port);
+#define __do_outw(val, port)   writew(val,(PCI_IO_ADDR)_IO_BASE+port);
+#define __do_outl(val, port)   writel(val,(PCI_IO_ADDR)_IO_BASE+port);
+#define __do_inb(port)         readb((PCI_IO_ADDR)_IO_BASE + port);
+#define __do_inw(port)         readw((PCI_IO_ADDR)_IO_BASE + port);
+#define __do_inl(port)         readl((PCI_IO_ADDR)_IO_BASE + port);
+#endif /* !CONFIG_PPC32 */
+
+#ifdef CONFIG_EEH
+#define __do_readsb(a, b, n)   eeh_readsb(PCI_FIX_ADDR(a), (b), (n))
+#define __do_readsw(a, b, n)   eeh_readsw(PCI_FIX_ADDR(a), (b), (n))
+#define __do_readsl(a, b, n)   eeh_readsl(PCI_FIX_ADDR(a), (b), (n))
+#else /* CONFIG_EEH */
+#define __do_readsb(a, b, n)   _insb(PCI_FIX_ADDR(a), (b), (n))
+#define __do_readsw(a, b, n)   _insw(PCI_FIX_ADDR(a), (b), (n))
+#define __do_readsl(a, b, n)   _insl(PCI_FIX_ADDR(a), (b), (n))
+#endif /* !CONFIG_EEH */
+#define __do_writesb(a, b, n)  _outsb(PCI_FIX_ADDR(a),(b),(n))
+#define __do_writesw(a, b, n)  _outsw(PCI_FIX_ADDR(a),(b),(n))
+#define __do_writesl(a, b, n)  _outsl(PCI_FIX_ADDR(a),(b),(n))
+
+#define __do_insb(p, b, n)     readsb((PCI_IO_ADDR)_IO_BASE+(p), (b), (n))
+#define __do_insw(p, b, n)     readsw((PCI_IO_ADDR)_IO_BASE+(p), (b), (n))
+#define __do_insl(p, b, n)     readsl((PCI_IO_ADDR)_IO_BASE+(p), (b), (n))
+#define __do_outsb(p, b, n)    writesb((PCI_IO_ADDR)_IO_BASE+(p),(b),(n))
+#define __do_outsw(p, b, n)    writesw((PCI_IO_ADDR)_IO_BASE+(p),(b),(n))
+#define __do_outsl(p, b, n)    writesl((PCI_IO_ADDR)_IO_BASE+(p),(b),(n))
+
+#define __do_memset_io(addr, c, n)     \
+                               _memset_io(PCI_FIX_ADDR(addr), c, n)
+#define __do_memcpy_toio(dst, src, n)  \
+                               _memcpy_toio(PCI_FIX_ADDR(dst), src, n)
+
+#ifdef CONFIG_EEH
+#define __do_memcpy_fromio(dst, src, n)        \
+                               eeh_memcpy_fromio(dst, PCI_FIX_ADDR(src), n)
+#else /* CONFIG_EEH */
+#define __do_memcpy_fromio(dst, src, n)        \
+                               _memcpy_fromio(dst,PCI_FIX_ADDR(src),n)
+#endif /* !CONFIG_EEH */
+
+#ifdef CONFIG_PPC_INDIRECT_IO
+#define DEF_PCI_HOOK(x)                x
+#else
+#define DEF_PCI_HOOK(x)                NULL
 #endif
 
+/* Structure containing all the hooks */
+extern struct ppc_pci_io {
+
+#define DEF_PCI_AC_RET(name, ret, at, al)      ret (*name) at;
+#define DEF_PCI_AC_NORET(name, at, al)         void (*name) at;
+
+#include <asm/io-defs.h>
+
+#undef DEF_PCI_AC_RET
+#undef DEF_PCI_AC_NORET
+
+} ppc_pci_io;
+
+/* The inline wrappers */
+#define DEF_PCI_AC_RET(name, ret, at, al)                      \
+static inline ret name at                                      \
+{                                                              \
+       if (DEF_PCI_HOOK(ppc_pci_io.name) != NULL)              \
+               return ppc_pci_io.name al;                      \
+       return __do_##name al;                                  \
+}
+
+#define DEF_PCI_AC_NORET(name, at, al)                         \
+static inline void name at                                     \
+{                                                              \
+       if (DEF_PCI_HOOK(ppc_pci_io.name) != NULL)              \
+               ppc_pci_io.name al;                             \
+       else                                                    \
+               __do_##name al;                                 \
+}
+
+#include <asm/io-defs.h>
+
+#undef DEF_PCI_AC_RET
+#undef DEF_PCI_AC_NORET
+
+/* Some drivers check for the presence of readq & writeq with
+ * a #ifdef, so we make them happy here.
+ */
+#ifdef __powerpc64__
+#define readq  readq
+#define writeq writeq
+#endif
+
+#ifdef CONFIG_NOT_COHERENT_CACHE
+
+#define dma_cache_inv(_start,_size) \
+       invalidate_dcache_range(_start, (_start + _size))
+#define dma_cache_wback(_start,_size) \
+       clean_dcache_range(_start, (_start + _size))
+#define dma_cache_wback_inv(_start,_size) \
+       flush_dcache_range(_start, (_start + _size))
+
+#else /* CONFIG_NOT_COHERENT_CACHE */
+
+#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)
+
+#endif /* !CONFIG_NOT_COHERENT_CACHE */
+
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p)   __va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer
+ */
+#define xlate_dev_kmem_ptr(p)  p
+
+/*
+ * We don't do relaxed operations yet, at least not with this semantic
+ */
 #define readb_relaxed(addr) readb(addr)
 #define readw_relaxed(addr) readw(addr)
 #define readl_relaxed(addr) readl(addr)
 #define readq_relaxed(addr) readq(addr)
 
-extern void _insb(volatile u8 __iomem *port, void *buf, int ns);
-extern void _outsb(volatile u8 __iomem *port, const void *buf, int ns);
-extern void _insw(volatile u16 __iomem *port, void *buf, int ns);
-extern void _outsw(volatile u16 __iomem *port, const void *buf, int ns);
-extern void _insl(volatile u32 __iomem *port, void *buf, int nl);
-extern void _outsl(volatile u32 __iomem *port, const void *buf, int nl);
-extern void _insw_ns(volatile u16 __iomem *port, void *buf, int ns);
-extern void _outsw_ns(volatile u16 __iomem *port, const void *buf, int ns);
-extern void _insl_ns(volatile u32 __iomem *port, void *buf, int nl);
-extern void _outsl_ns(volatile u32 __iomem *port, const void *buf, int nl);
-
+#ifdef CONFIG_PPC32
 #define mmiowb()
+#else
+/*
+ * Enforce synchronisation of stores vs. spin_unlock
+ * (this does it explicitely, though our implementation of spin_unlock
+ * does it implicitely too)
+ */
+static inline void mmiowb(void)
+{
+       unsigned long tmp;
+
+       __asm__ __volatile__("sync; li %0,0; stb %0,%1(13)"
+       : "=&r" (tmp) : "i" (offsetof(struct paca_struct, io_sync))
+       : "memory");
+}
+#endif /* !CONFIG_PPC32 */
+
+static inline void iosync(void)
+{
+        __asm__ __volatile__ ("sync" : : : "memory");
+}
+
+/* Enforce in-order execution of data I/O.
+ * No distinction between read/write on PPC; use eieio for all three.
+ * Those are fairly week though. They don't provide a barrier between
+ * MMIO and cacheable storage nor do they provide a barrier vs. locks,
+ * they only provide barriers between 2 __raw MMIO operations and
+ * possibly break write combining.
+ */
+#define iobarrier_rw() eieio()
+#define iobarrier_r()  eieio()
+#define iobarrier_w()  eieio()
+
 
 /*
  * output pause versions need a delay at least for the
@@ -175,23 +575,10 @@ extern void _outsl_ns(volatile u32 __iomem *port, const void *buf, int nl);
 #define inl_p(port)             inl(port)
 #define outl_p(val, port)       (udelay(1), outl((val), (port)))
 
-/*
- * The *_ns versions below don't do byte-swapping.
- * Neither do the standard versions now, these are just here
- * for older code.
- */
-#define outsw_ns(port, buf, ns)        _outsw_ns((u16 __iomem *)((port)+pci_io_base), (buf), (ns))
-#define outsl_ns(port, buf, nl)        _outsl_ns((u32 __iomem *)((port)+pci_io_base), (buf), (nl))
-
 
 #define IO_SPACE_LIMIT ~(0UL)
 
 
-extern int __ioremap_explicit(unsigned long p_addr, unsigned long v_addr,
-                             unsigned long size, unsigned long flags);
-extern void __iomem *__ioremap(unsigned long address, unsigned long size,
-                      unsigned long flags);
-
 /**
  * ioremap     -   map bus memory into CPU space
  * @address:   bus address of the memory
@@ -202,14 +589,77 @@ extern void __iomem *__ioremap(unsigned long address, unsigned long size,
  * writew/writel functions and the other mmio helpers. The returned
  * address is not guaranteed to be usable directly as a virtual
  * address.
+ *
+ * We provide a few variations of it:
+ *
+ * * ioremap is the standard one and provides non-cacheable guarded mappings
+ *   and can be hooked by the platform via ppc_md
+ *
+ * * ioremap_flags allows to specify the page flags as an argument and can
+ *   also be hooked by the platform via ppc_md
+ *
+ * * ioremap_nocache is identical to ioremap
+ *
+ * * iounmap undoes such a mapping and can be hooked
+ *
+ * * __ioremap_explicit (and the pending __iounmap_explicit) are low level
+ *   functions to create hand-made mappings for use only by the PCI code
+ *   and cannot currently be hooked.
+ *
+ * * __ioremap is the low level implementation used by ioremap and
+ *   ioremap_flags and cannot be hooked (but can be used by a hook on one
+ *   of the previous ones)
+ *
+ * * __iounmap, is the low level implementation used by iounmap and cannot
+ *   be hooked (but can be used by a hook on iounmap)
+ *
  */
-extern void __iomem *ioremap(unsigned long address, unsigned long size);
-
+extern void __iomem *ioremap(phys_addr_t address, unsigned long size);
+extern void __iomem *ioremap_flags(phys_addr_t address, unsigned long size,
+                                  unsigned long flags);
 #define ioremap_nocache(addr, size)    ioremap((addr), (size))
-extern int iounmap_explicit(volatile void __iomem *addr, unsigned long size);
 extern void iounmap(volatile void __iomem *addr);
+
+extern void __iomem *__ioremap(phys_addr_t, unsigned long size,
+                              unsigned long flags);
+extern void __iounmap(volatile void __iomem *addr);
+
+extern int __ioremap_explicit(phys_addr_t p_addr, unsigned long v_addr,
+                             unsigned long size, unsigned long flags);
+extern int __iounmap_explicit(volatile void __iomem *start,
+                             unsigned long size);
+
 extern void __iomem * reserve_phb_iospace(unsigned long size);
 
+/* Those are more 32 bits only functions */
+extern unsigned long iopa(unsigned long addr);
+extern unsigned long mm_ptov(unsigned long addr) __attribute_const__;
+extern void io_block_mapping(unsigned long virt, phys_addr_t phys,
+                            unsigned int size, int flags);
+
+
+/*
+ * When CONFIG_PPC_INDIRECT_IO is set, we use the generic iomap implementation
+ * which needs some additional definitions here. They basically allow PIO
+ * space overall to be 1GB. This will work as long as we never try to use
+ * iomap to map MMIO below 1GB which should be fine on ppc64
+ */
+#define HAVE_ARCH_PIO_SIZE             1
+#define PIO_OFFSET                     0x00000000UL
+#define PIO_MASK                       0x3fffffffUL
+#define PIO_RESERVED                   0x40000000UL
+
+#define mmio_read16be(addr)            readw_be(addr)
+#define mmio_read32be(addr)            readl_be(addr)
+#define mmio_write16be(val, addr)      writew_be(val, addr)
+#define mmio_write32be(val, addr)      writel_be(val, addr)
+#define mmio_insb(addr, dst, count)    readsb(addr, dst, count)
+#define mmio_insw(addr, dst, count)    readsw(addr, dst, count)
+#define mmio_insl(addr, dst, count)    readsl(addr, dst, count)
+#define mmio_outsb(addr, src, count)   writesb(addr, src, count)
+#define mmio_outsw(addr, src, count)   writesw(addr, src, count)
+#define mmio_outsl(addr, src, count)   writesl(addr, src, count)
+
 /**
  *     virt_to_phys    -       map virtual addresses to physical
  *     @address: address to remap
@@ -256,203 +706,34 @@ static inline void * phys_to_virt(unsigned long address)
  */
 #define BIO_VMERGE_BOUNDARY    0
 
-static inline void iosync(void)
-{
-        __asm__ __volatile__ ("sync" : : : "memory");
-}
-
-/* Enforce in-order execution of data I/O. 
- * No distinction between read/write on PPC; use eieio for all three.
- */
-#define iobarrier_rw() eieio()
-#define iobarrier_r()  eieio()
-#define iobarrier_w()  eieio()
-
 /*
- * 8, 16 and 32 bit, big and little endian I/O operations, with barrier.
- * These routines do not perform EEH-related I/O address translation,
- * and should not be used directly by device drivers.  Use inb/readb
- * instead.
+ * 32 bits still uses virt_to_bus() for it's implementation of DMA
+ * mappings se we have to keep it defined here. We also have some old
+ * drivers (shame shame shame) that use bus_to_virt() and haven't been
+ * fixed yet so I need to define it here.
  */
-static inline int in_8(const volatile unsigned char __iomem *addr)
-{
-       int ret;
-
-       __asm__ __volatile__("lbz%U1%X1 %0,%1; twi 0,%0,0; isync"
-                            : "=r" (ret) : "m" (*addr));
-       return ret;
-}
-
-static inline void out_8(volatile unsigned char __iomem *addr, int val)
-{
-       __asm__ __volatile__("stb%U0%X0 %1,%0; sync"
-                            : "=m" (*addr) : "r" (val));
-}
+#ifdef CONFIG_PPC32
 
-static inline int in_le16(const volatile unsigned short __iomem *addr)
+static inline unsigned long virt_to_bus(volatile void * address)
 {
-       int ret;
-
-       __asm__ __volatile__("lhbrx %0,0,%1; twi 0,%0,0; isync"
-                            : "=r" (ret) : "r" (addr), "m" (*addr));
-       return ret;
-}
-
-static inline int in_be16(const volatile unsigned short __iomem *addr)
-{
-       int ret;
-
-       __asm__ __volatile__("lhz%U1%X1 %0,%1; twi 0,%0,0; isync"
-                            : "=r" (ret) : "m" (*addr));
-       return ret;
-}
-
-static inline void out_le16(volatile unsigned short __iomem *addr, int val)
-{
-       __asm__ __volatile__("sthbrx %1,0,%2; sync"
-                            : "=m" (*addr) : "r" (val), "r" (addr));
-}
-
-static inline void out_be16(volatile unsigned short __iomem *addr, int val)
-{
-       __asm__ __volatile__("sth%U0%X0 %1,%0; sync"
-                            : "=m" (*addr) : "r" (val));
-}
-
-static inline unsigned in_le32(const volatile unsigned __iomem *addr)
-{
-       unsigned ret;
-
-       __asm__ __volatile__("lwbrx %0,0,%1; twi 0,%0,0; isync"
-                            : "=r" (ret) : "r" (addr), "m" (*addr));
-       return ret;
-}
-
-static inline unsigned in_be32(const volatile unsigned __iomem *addr)
-{
-       unsigned ret;
-
-       __asm__ __volatile__("lwz%U1%X1 %0,%1; twi 0,%0,0; isync"
-                            : "=r" (ret) : "m" (*addr));
-       return ret;
-}
-
-static inline void out_le32(volatile unsigned __iomem *addr, int val)
-{
-       __asm__ __volatile__("stwbrx %1,0,%2; sync" : "=m" (*addr)
-                            : "r" (val), "r" (addr));
-}
-
-static inline void out_be32(volatile unsigned __iomem *addr, int val)
-{
-       __asm__ __volatile__("stw%U0%X0 %1,%0; sync"
-                            : "=m" (*addr) : "r" (val));
-}
-
-static inline unsigned long in_le64(const volatile unsigned long __iomem *addr)
-{
-       unsigned long tmp, ret;
-
-       __asm__ __volatile__(
-                            "ld %1,0(%2)\n"
-                            "twi 0,%1,0\n"
-                            "isync\n"
-                            "rldimi %0,%1,5*8,1*8\n"
-                            "rldimi %0,%1,3*8,2*8\n"
-                            "rldimi %0,%1,1*8,3*8\n"
-                            "rldimi %0,%1,7*8,4*8\n"
-                            "rldicl %1,%1,32,0\n"
-                            "rlwimi %0,%1,8,8,31\n"
-                            "rlwimi %0,%1,24,16,23\n"
-                            : "=r" (ret) , "=r" (tmp) : "b" (addr) , "m" (*addr));
-       return ret;
+        if (address == NULL)
+               return 0;
+        return __pa(address) + PCI_DRAM_OFFSET;
 }
 
-static inline unsigned long in_be64(const volatile unsigned long __iomem *addr)
+static inline void * bus_to_virt(unsigned long address)
 {
-       unsigned long ret;
-
-       __asm__ __volatile__("ld%U1%X1 %0,%1; twi 0,%0,0; isync"
-                            : "=r" (ret) : "m" (*addr));
-       return ret;
+        if (address == 0)
+               return NULL;
+        return __va(address - PCI_DRAM_OFFSET);
 }
 
-static inline void out_le64(volatile unsigned long __iomem *addr, unsigned long val)
-{
-       unsigned long tmp;
+#define page_to_bus(page)      (page_to_phys(page) + PCI_DRAM_OFFSET)
+#define eth_io_copy_and_sum(a,b,c,d)   eth_copy_and_sum((a),(void __force *)(void __iomem *)(b),(c),(d))
 
-       __asm__ __volatile__(
-                            "rldimi %0,%1,5*8,1*8\n"
-                            "rldimi %0,%1,3*8,2*8\n"
-                            "rldimi %0,%1,1*8,3*8\n"
-                            "rldimi %0,%1,7*8,4*8\n"
-                            "rldicl %1,%1,32,0\n"
-                            "rlwimi %0,%1,8,8,31\n"
-                            "rlwimi %0,%1,24,16,23\n"
-                            "std %0,0(%3)\n"
-                            "sync"
-                            : "=&r" (tmp) , "=&r" (val) : "1" (val) , "b" (addr) , "m" (*addr));
-}
+#endif /* CONFIG_PPC32 */
 
-static inline void out_be64(volatile unsigned long __iomem *addr, unsigned long val)
-{
-       __asm__ __volatile__("std%U0%X0 %1,%0; sync" : "=m" (*addr) : "r" (val));
-}
-
-#ifndef CONFIG_PPC_ISERIES 
-#include <asm/eeh.h>
-#endif
-
-/**
- *     check_signature         -       find BIOS signatures
- *     @io_addr: mmio address to check
- *     @signature:  signature block
- *     @length: length of signature
- *
- *     Perform a signature comparison with the mmio address io_addr. This
- *     address should have been obtained by ioremap.
- *     Returns 1 on a match.
- */
-static inline int check_signature(const volatile void __iomem * io_addr,
-       const unsigned char *signature, int length)
-{
-       int retval = 0;
-#ifndef CONFIG_PPC_ISERIES 
-       do {
-               if (readb(io_addr) != *signature)
-                       goto out;
-               io_addr++;
-               signature++;
-               length--;
-       } while (length);
-       retval = 1;
-out:
-#endif
-       return retval;
-}
-
-/* Nothing to do */
-
-#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)
-
-/* Check of existence of legacy devices */
-extern int check_legacy_ioport(unsigned long base_port);
-
-
-/*
- * Convert a physical pointer to a virtual kernel pointer for /dev/mem
- * access
- */
-#define xlate_dev_mem_ptr(p)   __va(p)
-
-/*
- * Convert a virtual cached pointer to an uncached pointer
- */
-#define xlate_dev_kmem_ptr(p)  p
 
 #endif /* __KERNEL__ */
 
-#endif /* CONFIG_PPC64 */
 #endif /* _ASM_POWERPC_IO_H */