sh: More I/O routine overhauling.

This tidies up a lot of the PIO/MMIO split. No in-tree platforms were
making use of the MMIO overloading through the machvec (nor have any of
them been in some time), so we just kill all of that off. The ISA I/O
routine wrapping remains unaffected, which remains the only special
casing outside of the iomap API that boards need to think about.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
This commit is contained in:
Paul Mundt
2008-10-04 05:25:52 +09:00
parent bc0f424faa
commit 14866543ad
6 changed files with 109 additions and 226 deletions

View File

@@ -1,27 +1,26 @@
#ifndef __ASM_SH_IO_H #ifndef __ASM_SH_IO_H
#define __ASM_SH_IO_H #define __ASM_SH_IO_H
/* /*
* Convention: * Convention:
* read{b,w,l}/write{b,w,l} are for PCI, * read{b,w,l,q}/write{b,w,l,q} are for PCI,
* while in{b,w,l}/out{b,w,l} are for ISA * while in{b,w,l}/out{b,w,l} are for ISA
* These may (will) be platform specific function. *
* In addition we have 'pausing' versions: in{b,w,l}_p/out{b,w,l}_p * In addition we have 'pausing' versions: in{b,w,l}_p/out{b,w,l}_p
* and 'string' versions: ins{b,w,l}/outs{b,w,l} * and 'string' versions: ins{b,w,l}/outs{b,w,l}
* For read{b,w,l} and write{b,w,l} there are also __raw versions, which
* do not have a memory barrier after them.
* *
* In addition, we have * While read{b,w,l,q} and write{b,w,l,q} contain memory barriers
* ctrl_in{b,w,l}/ctrl_out{b,w,l} for SuperH specific I/O. * automatically, there are also __raw versions, which do not.
* which are processor specific. *
*/ * Historically, we have also had ctrl_in{b,w,l,q}/ctrl_out{b,w,l,q} for
* SuperH specific I/O (raw I/O to on-chip CPU peripherals). In practice
/* * these have the same semantics as the __raw variants, and as such, all
* We follow the Alpha convention here: * new code should be using the __raw versions.
* __inb expands to an inline function call (which calls via the mv) *
* _inb is a real function call (note ___raw fns are _ version of __raw) * All ISA I/O routines are wrapped through the machine vector. If a
* inb by default expands to _inb, but the machine specific code may * board does not provide overrides, a generic set that are copied in
* define it to __inb if it chooses. * from the default machine vector are used instead. These are largely
* for old compat code for I/O offseting to SuperIOs, all of which are
* better handled through the machvec ioport mapping routines these days.
*/ */
#include <asm/cache.h> #include <asm/cache.h>
#include <asm/system.h> #include <asm/system.h>
@@ -31,7 +30,6 @@
#include <asm-generic/iomap.h> #include <asm-generic/iomap.h>
#ifdef __KERNEL__ #ifdef __KERNEL__
/* /*
* Depending on which platform we are running on, we need different * Depending on which platform we are running on, we need different
* I/O functions. * I/O functions.
@@ -40,90 +38,64 @@
#include <asm/io_generic.h> #include <asm/io_generic.h>
#include <asm/io_trapped.h> #include <asm/io_trapped.h>
#define maybebadio(port) \ #define inb(p) sh_mv.mv_inb((p))
printk(KERN_ERR "bad PC-like io %s:%u for port 0x%lx at 0x%08x\n", \ #define inw(p) sh_mv.mv_inw((p))
__FUNCTION__, __LINE__, (port), (u32)__builtin_return_address(0)) #define inl(p) sh_mv.mv_inl((p))
#define outb(x,p) sh_mv.mv_outb((x),(p))
#define outw(x,p) sh_mv.mv_outw((x),(p))
#define outl(x,p) sh_mv.mv_outl((x),(p))
/* #define inb_p(p) sh_mv.mv_inb_p((p))
* Since boards are able to define their own set of I/O routines through #define inw_p(p) sh_mv.mv_inw_p((p))
* their respective machine vector, we always wrap through the mv. #define inl_p(p) sh_mv.mv_inl_p((p))
* #define outb_p(x,p) sh_mv.mv_outb_p((x),(p))
* Also, in the event that a board hasn't provided its own definition for #define outw_p(x,p) sh_mv.mv_outw_p((x),(p))
* a given routine, it will be wrapped to generic code at run-time. #define outl_p(x,p) sh_mv.mv_outl_p((x),(p))
*/
#define __inb(p) sh_mv.mv_inb((p)) #define insb(p,b,c) sh_mv.mv_insb((p), (b), (c))
#define __inw(p) sh_mv.mv_inw((p)) #define insw(p,b,c) sh_mv.mv_insw((p), (b), (c))
#define __inl(p) sh_mv.mv_inl((p)) #define insl(p,b,c) sh_mv.mv_insl((p), (b), (c))
#define __outb(x,p) sh_mv.mv_outb((x),(p)) #define outsb(p,b,c) sh_mv.mv_outsb((p), (b), (c))
#define __outw(x,p) sh_mv.mv_outw((x),(p)) #define outsw(p,b,c) sh_mv.mv_outsw((p), (b), (c))
#define __outl(x,p) sh_mv.mv_outl((x),(p)) #define outsl(p,b,c) sh_mv.mv_outsl((p), (b), (c))
#define __inb_p(p) sh_mv.mv_inb_p((p)) #define __raw_writeb(v,a) (__chk_io_ptr(a), *(volatile u8 __force *)(a) = (v))
#define __inw_p(p) sh_mv.mv_inw_p((p)) #define __raw_writew(v,a) (__chk_io_ptr(a), *(volatile u16 __force *)(a) = (v))
#define __inl_p(p) sh_mv.mv_inl_p((p)) #define __raw_writel(v,a) (__chk_io_ptr(a), *(volatile u32 __force *)(a) = (v))
#define __outb_p(x,p) sh_mv.mv_outb_p((x),(p)) #define __raw_writeq(v,a) (__chk_io_ptr(a), *(volatile u64 __force *)(a) = (v))
#define __outw_p(x,p) sh_mv.mv_outw_p((x),(p))
#define __outl_p(x,p) sh_mv.mv_outl_p((x),(p))
#define __insb(p,b,c) sh_mv.mv_insb((p), (b), (c)) #define __raw_readb(a) (__chk_io_ptr(a), *(volatile u8 __force *)(a))
#define __insw(p,b,c) sh_mv.mv_insw((p), (b), (c)) #define __raw_readw(a) (__chk_io_ptr(a), *(volatile u16 __force *)(a))
#define __insl(p,b,c) sh_mv.mv_insl((p), (b), (c)) #define __raw_readl(a) (__chk_io_ptr(a), *(volatile u32 __force *)(a))
#define __outsb(p,b,c) sh_mv.mv_outsb((p), (b), (c)) #define __raw_readq(a) (__chk_io_ptr(a), *(volatile u64 __force *)(a))
#define __outsw(p,b,c) sh_mv.mv_outsw((p), (b), (c))
#define __outsl(p,b,c) sh_mv.mv_outsl((p), (b), (c))
#define __readb(a) sh_mv.mv_readb((a)) #define readb(a) ({ u8 r_ = __raw_readb(a); mb(); r_; })
#define __readw(a) sh_mv.mv_readw((a)) #define readw(a) ({ u16 r_ = __raw_readw(a); mb(); r_; })
#define __readl(a) sh_mv.mv_readl((a)) #define readl(a) ({ u32 r_ = __raw_readl(a); mb(); r_; })
#define __writeb(v,a) sh_mv.mv_writeb((v),(a)) #define readq(a) ({ u64 r_ = __raw_readq(a); mb(); r_; })
#define __writew(v,a) sh_mv.mv_writew((v),(a))
#define __writel(v,a) sh_mv.mv_writel((v),(a))
#define inb __inb #define writeb(v,a) ({ __raw_writeb((v),(a)); mb(); })
#define inw __inw #define writew(v,a) ({ __raw_writew((v),(a)); mb(); })
#define inl __inl #define writel(v,a) ({ __raw_writel((v),(a)); mb(); })
#define outb __outb #define writeq(v,a) ({ __raw_writeq((v),(a)); mb(); })
#define outw __outw
#define outl __outl
#define inb_p __inb_p /* SuperH on-chip I/O functions */
#define inw_p __inw_p #define ctrl_inb __raw_readb
#define inl_p __inl_p #define ctrl_inw __raw_readw
#define outb_p __outb_p #define ctrl_inl __raw_readl
#define outw_p __outw_p #define ctrl_inq __raw_readq
#define outl_p __outl_p
#define insb __insb #define ctrl_outb __raw_writeb
#define insw __insw #define ctrl_outw __raw_writew
#define insl __insl #define ctrl_outl __raw_writel
#define outsb __outsb #define ctrl_outq __raw_writeq
#define outsw __outsw
#define outsl __outsl
#define __raw_writeb(v,a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a) = (v)) static inline void ctrl_delay(void)
#define __raw_writew(v,a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a) = (v)) {
#define __raw_writel(v,a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a) = (v)) #ifdef P2SEG
__raw_readw(P2SEG);
#define __raw_readb(a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a)) #endif
#define __raw_readw(a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a)) }
#define __raw_readl(a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a))
void __raw_writesl(void __iomem *addr, const void *data, int longlen);
void __raw_readsl(const void __iomem *addr, void *data, int longlen);
/*
* The platform header files may define some of these macros to use
* the inlined versions where appropriate. These macros may also be
* redefined by userlevel programs.
*/
#define readb(a) ({ unsigned int r_ = __readb(a); mb(); r_; })
#define readw(a) ({ unsigned int r_ = __readw(a); mb(); r_; })
#define readl(a) ({ unsigned int r_ = __readl(a); mb(); r_; })
#define writeb(v,a) ({ __writeb((v),(a)); mb(); })
#define writew(v,a) ({ __writew((v),(a)); mb(); })
#define writel(v,a) ({ __writel((v),(a)); mb(); })
#define __BUILD_MEMORY_STRING(bwlq, type) \ #define __BUILD_MEMORY_STRING(bwlq, type) \
\ \
@@ -151,18 +123,23 @@ static inline void __raw_reads##bwlq(volatile void __iomem *mem, \
__BUILD_MEMORY_STRING(b, u8) __BUILD_MEMORY_STRING(b, u8)
__BUILD_MEMORY_STRING(w, u16) __BUILD_MEMORY_STRING(w, u16)
__BUILD_MEMORY_STRING(q, u64)
#define writesb __raw_writesb void __raw_writesl(void __iomem *addr, const void *data, int longlen);
#define writesw __raw_writesw void __raw_readsl(const void __iomem *addr, void *data, int longlen);
#define writesl __raw_writesl
#define readsb __raw_readsb #define writesb __raw_writesb
#define readsw __raw_readsw #define writesw __raw_writesw
#define readsl __raw_readsl #define writesl __raw_writesl
#define readb_relaxed(a) readb(a) #define readsb __raw_readsb
#define readw_relaxed(a) readw(a) #define readsw __raw_readsw
#define readl_relaxed(a) readl(a) #define readsl __raw_readsl
#define readb_relaxed(a) readb(a)
#define readw_relaxed(a) readw(a)
#define readl_relaxed(a) readl(a)
#define readq_relaxed(a) readq(a)
/* Simple MMIO */ /* Simple MMIO */
#define ioread8(a) __raw_readb(a) #define ioread8(a) __raw_readb(a)
@@ -185,15 +162,17 @@ __BUILD_MEMORY_STRING(w, u16)
#define iowrite16_rep(a, s, c) __raw_writesw((a), (s), (c)) #define iowrite16_rep(a, s, c) __raw_writesw((a), (s), (c))
#define iowrite32_rep(a, s, c) __raw_writesl((a), (s), (c)) #define iowrite32_rep(a, s, c) __raw_writesl((a), (s), (c))
#define mmiowb() wmb() /* synco on SH-4A, otherwise a nop */ /* synco on SH-4A, otherwise a nop */
#define mmiowb() wmb()
#define IO_SPACE_LIMIT 0xffffffff #define IO_SPACE_LIMIT 0xffffffff
extern unsigned long generic_io_base; extern unsigned long generic_io_base;
/* /*
* This function provides a method for the generic case where a board-specific * This function provides a method for the generic case where a
* ioport_map simply needs to return the port + some arbitrary port base. * board-specific ioport_map simply needs to return the port + some
* arbitrary port base.
* *
* We use this at board setup time to implicitly set the port base, and * We use this at board setup time to implicitly set the port base, and
* as a result, we can use the generic ioport_map. * as a result, we can use the generic ioport_map.
@@ -206,57 +185,9 @@ static inline void __set_io_port_base(unsigned long pbase)
#define __ioport_map(p, n) sh_mv.mv_ioport_map((p), (n)) #define __ioport_map(p, n) sh_mv.mv_ioport_map((p), (n))
/* We really want to try and get these to memcpy etc */ /* We really want to try and get these to memcpy etc */
extern void memcpy_fromio(void *, volatile void __iomem *, unsigned long); void memcpy_fromio(void *, const volatile void __iomem *, unsigned long);
extern void memcpy_toio(volatile void __iomem *, const void *, unsigned long); void memcpy_toio(volatile void __iomem *, const void *, unsigned long);
extern void memset_io(volatile void __iomem *, int, unsigned long); void memset_io(volatile void __iomem *, int, unsigned long);
/* SuperH on-chip I/O functions */
static inline unsigned char ctrl_inb(unsigned long addr)
{
return *(volatile unsigned char*)addr;
}
static inline unsigned short ctrl_inw(unsigned long addr)
{
return *(volatile unsigned short*)addr;
}
static inline unsigned int ctrl_inl(unsigned long addr)
{
return *(volatile unsigned long*)addr;
}
static inline unsigned long long ctrl_inq(unsigned long addr)
{
return *(volatile unsigned long long*)addr;
}
static inline void ctrl_outb(unsigned char b, unsigned long addr)
{
*(volatile unsigned char*)addr = b;
}
static inline void ctrl_outw(unsigned short b, unsigned long addr)
{
*(volatile unsigned short*)addr = b;
}
static inline void ctrl_outl(unsigned int b, unsigned long addr)
{
*(volatile unsigned long*)addr = b;
}
static inline void ctrl_outq(unsigned long long b, unsigned long addr)
{
*(volatile unsigned long long*)addr = b;
}
static inline void ctrl_delay(void)
{
#ifdef P2SEG
ctrl_inw(P2SEG);
#endif
}
/* Quad-word real-mode I/O, don't ask.. */ /* Quad-word real-mode I/O, don't ask.. */
unsigned long long peek_real_address_q(unsigned long long addr); unsigned long long peek_real_address_q(unsigned long long addr);
@@ -347,6 +278,10 @@ __ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags)
#define iounmap(addr) \ #define iounmap(addr) \
__iounmap((addr)) __iounmap((addr))
#define maybebadio(port) \
printk(KERN_ERR "bad PC-like io %s:%u for port 0x%lx at 0x%08x\n", \
__func__, __LINE__, (port), (u32)__builtin_return_address(0))
/* /*
* Convert a physical pointer to a virtual kernel pointer for /dev/mem * Convert a physical pointer to a virtual kernel pointer for /dev/mem
* access * access

View File

@@ -33,13 +33,6 @@ void IO_CONCAT(__IO_PREFIX,outsb)(unsigned long, const void *src, unsigned long
void IO_CONCAT(__IO_PREFIX,outsw)(unsigned long, const void *src, unsigned long count); void IO_CONCAT(__IO_PREFIX,outsw)(unsigned long, const void *src, unsigned long count);
void IO_CONCAT(__IO_PREFIX,outsl)(unsigned long, const void *src, unsigned long count); void IO_CONCAT(__IO_PREFIX,outsl)(unsigned long, const void *src, unsigned long count);
u8 IO_CONCAT(__IO_PREFIX,readb)(void __iomem *);
u16 IO_CONCAT(__IO_PREFIX,readw)(void __iomem *);
u32 IO_CONCAT(__IO_PREFIX,readl)(void __iomem *);
void IO_CONCAT(__IO_PREFIX,writeb)(u8, void __iomem *);
void IO_CONCAT(__IO_PREFIX,writew)(u16, void __iomem *);
void IO_CONCAT(__IO_PREFIX,writel)(u32, void __iomem *);
void *IO_CONCAT(__IO_PREFIX,ioremap)(unsigned long offset, unsigned long size); void *IO_CONCAT(__IO_PREFIX,ioremap)(unsigned long offset, unsigned long size);
void IO_CONCAT(__IO_PREFIX,iounmap)(void *addr); void IO_CONCAT(__IO_PREFIX,iounmap)(void *addr);

View File

@@ -42,13 +42,6 @@ struct sh_machine_vector {
void (*mv_outsw)(unsigned long, const void *src, unsigned long count); void (*mv_outsw)(unsigned long, const void *src, unsigned long count);
void (*mv_outsl)(unsigned long, const void *src, unsigned long count); void (*mv_outsl)(unsigned long, const void *src, unsigned long count);
u8 (*mv_readb)(void __iomem *);
u16 (*mv_readw)(void __iomem *);
u32 (*mv_readl)(void __iomem *);
void (*mv_writeb)(u8, void __iomem *);
void (*mv_writew)(u16, void __iomem *);
void (*mv_writel)(u32, void __iomem *);
int (*mv_irq_demux)(int irq); int (*mv_irq_demux)(int irq);
void (*mv_init_irq)(void); void (*mv_init_irq)(void);

View File

@@ -19,12 +19,12 @@
* Copy data from IO memory space to "real" memory space. * Copy data from IO memory space to "real" memory space.
* This needs to be optimized. * This needs to be optimized.
*/ */
void memcpy_fromio(void *to, volatile void __iomem *from, unsigned long count) void memcpy_fromio(void *to, const volatile void __iomem *from, unsigned long count)
{ {
char *p = to; unsigned char *p = to;
while (count) { while (count) {
count--; count--;
*p = readb((void __iomem *)from); *p = readb(from);
p++; p++;
from++; from++;
} }
@@ -37,10 +37,10 @@ EXPORT_SYMBOL(memcpy_fromio);
*/ */
void memcpy_toio(volatile void __iomem *to, const void *from, unsigned long count) void memcpy_toio(volatile void __iomem *to, const void *from, unsigned long count)
{ {
const char *p = from; const unsigned char *p = from;
while (count) { while (count) {
count--; count--;
writeb(*p, (void __iomem *)to); writeb(*p, to);
p++; p++;
to++; to++;
} }
@@ -55,7 +55,7 @@ void memset_io(volatile void __iomem *dst, int c, unsigned long count)
{ {
while (count) { while (count) {
count--; count--;
writeb(c, (void __iomem *)dst); writeb(c, dst);
dst++; dst++;
} }
} }

View File

@@ -19,38 +19,33 @@
/* SH3 has a PCMCIA bug that needs a dummy read from area 6 for a /* SH3 has a PCMCIA bug that needs a dummy read from area 6 for a
* workaround. */ * workaround. */
/* I'm not sure SH7709 has this kind of bug */ /* I'm not sure SH7709 has this kind of bug */
#define dummy_read() ctrl_inb(0xba000000) #define dummy_read() __raw_readb(0xba000000)
#else #else
#define dummy_read() #define dummy_read()
#endif #endif
unsigned long generic_io_base; unsigned long generic_io_base;
static inline void delay(void)
{
ctrl_inw(0xa0000000);
}
u8 generic_inb(unsigned long port) u8 generic_inb(unsigned long port)
{ {
return ctrl_inb((unsigned long __force)__ioport_map(port, 1)); return __raw_readb(__ioport_map(port, 1));
} }
u16 generic_inw(unsigned long port) u16 generic_inw(unsigned long port)
{ {
return ctrl_inw((unsigned long __force)__ioport_map(port, 2)); return __raw_readw(__ioport_map(port, 2));
} }
u32 generic_inl(unsigned long port) u32 generic_inl(unsigned long port)
{ {
return ctrl_inl((unsigned long __force)__ioport_map(port, 4)); return __raw_readl(__ioport_map(port, 4));
} }
u8 generic_inb_p(unsigned long port) u8 generic_inb_p(unsigned long port)
{ {
unsigned long v = generic_inb(port); unsigned long v = generic_inb(port);
delay(); ctrl_delay();
return v; return v;
} }
@@ -58,7 +53,7 @@ u16 generic_inw_p(unsigned long port)
{ {
unsigned long v = generic_inw(port); unsigned long v = generic_inw(port);
delay(); ctrl_delay();
return v; return v;
} }
@@ -66,7 +61,7 @@ u32 generic_inl_p(unsigned long port)
{ {
unsigned long v = generic_inl(port); unsigned long v = generic_inl(port);
delay(); ctrl_delay();
return v; return v;
} }
@@ -112,35 +107,35 @@ void generic_insl(unsigned long port, void *dst, unsigned long count)
void generic_outb(u8 b, unsigned long port) void generic_outb(u8 b, unsigned long port)
{ {
ctrl_outb(b, (unsigned long __force)__ioport_map(port, 1)); __raw_writeb(b, __ioport_map(port, 1));
} }
void generic_outw(u16 b, unsigned long port) void generic_outw(u16 b, unsigned long port)
{ {
ctrl_outw(b, (unsigned long __force)__ioport_map(port, 2)); __raw_writew(b, __ioport_map(port, 2));
} }
void generic_outl(u32 b, unsigned long port) void generic_outl(u32 b, unsigned long port)
{ {
ctrl_outl(b, (unsigned long __force)__ioport_map(port, 4)); __raw_writel(b, __ioport_map(port, 4));
} }
void generic_outb_p(u8 b, unsigned long port) void generic_outb_p(u8 b, unsigned long port)
{ {
generic_outb(b, port); generic_outb(b, port);
delay(); ctrl_delay();
} }
void generic_outw_p(u16 b, unsigned long port) void generic_outw_p(u16 b, unsigned long port)
{ {
generic_outw(b, port); generic_outw(b, port);
delay(); ctrl_delay();
} }
void generic_outl_p(u32 b, unsigned long port) void generic_outl_p(u32 b, unsigned long port)
{ {
generic_outl(b, port); generic_outl(b, port);
delay(); ctrl_delay();
} }
/* /*
@@ -184,36 +179,6 @@ void generic_outsl(unsigned long port, const void *src, unsigned long count)
dummy_read(); dummy_read();
} }
u8 generic_readb(void __iomem *addr)
{
return ctrl_inb((unsigned long __force)addr);
}
u16 generic_readw(void __iomem *addr)
{
return ctrl_inw((unsigned long __force)addr);
}
u32 generic_readl(void __iomem *addr)
{
return ctrl_inl((unsigned long __force)addr);
}
void generic_writeb(u8 b, void __iomem *addr)
{
ctrl_outb(b, (unsigned long __force)addr);
}
void generic_writew(u16 b, void __iomem *addr)
{
ctrl_outw(b, (unsigned long __force)addr);
}
void generic_writel(u32 b, void __iomem *addr)
{
ctrl_outl(b, (unsigned long __force)addr);
}
void __iomem *generic_ioport_map(unsigned long addr, unsigned int size) void __iomem *generic_ioport_map(unsigned long addr, unsigned int size)
{ {
return (void __iomem *)(addr + generic_io_base); return (void __iomem *)(addr + generic_io_base);

View File

@@ -126,9 +126,6 @@ void __init sh_mv_setup(void)
mv_set(insb); mv_set(insw); mv_set(insl); mv_set(insb); mv_set(insw); mv_set(insl);
mv_set(outsb); mv_set(outsw); mv_set(outsl); mv_set(outsb); mv_set(outsw); mv_set(outsl);
mv_set(readb); mv_set(readw); mv_set(readl);
mv_set(writeb); mv_set(writew); mv_set(writel);
mv_set(ioport_map); mv_set(ioport_map);
mv_set(ioport_unmap); mv_set(ioport_unmap);
mv_set(irq_demux); mv_set(irq_demux);