8 * i386 uses direct pointer dereferences for accesses to memory-mapped
9 * I/O space, and the inX/outX instructions for accesses to
10 * port-mapped I/O space.
12 * 64-bit atomic accesses (readq() and writeq()) use MMX instructions,
13 * and will crash original Pentium and earlier CPUs. Fortunately, no
14 * hardware that requires atomic 64-bit accesses will physically fit
15 * into a machine with such an old CPU anyway.
21 #define IOAPI_PREFIX_x86
23 #define IOAPI_PREFIX_x86 __x86_
27 * Memory space mappings
31 static inline __always_inline void *
32 IOAPI_INLINE ( x86, ioremap ) ( unsigned long bus_addr, size_t len __unused ) {
33 return phys_to_virt ( bus_addr );
36 static inline __always_inline void
37 IOAPI_INLINE ( x86, iounmap ) ( volatile const void *io_addr __unused ) {
41 static inline __always_inline unsigned long
42 IOAPI_INLINE ( x86, io_to_bus ) ( volatile const void *io_addr ) {
43 return virt_to_phys ( io_addr );
46 static inline __always_inline unsigned long
47 IOAPI_INLINE ( x86, virt_to_bus ) ( volatile const void *addr ) {
48 return virt_to_phys ( addr );
51 static inline __always_inline void *
52 IOAPI_INLINE ( x86, bus_to_virt ) ( unsigned long bus_addr ) {
53 return phys_to_virt ( bus_addr );
57 * MMIO reads and writes up to 32 bits
61 #define X86_READX( _api_func, _type ) \
62 static inline __always_inline _type \
63 IOAPI_INLINE ( x86, _api_func ) ( volatile _type *io_addr ) { \
66 X86_READX ( readb, uint8_t );
67 X86_READX ( readw, uint16_t );
68 X86_READX ( readl, uint32_t );
70 #define X86_WRITEX( _api_func, _type ) \
71 static inline __always_inline void \
72 IOAPI_INLINE ( x86, _api_func ) ( _type data, \
73 volatile _type *io_addr ) { \
76 X86_WRITEX ( writeb, uint8_t );
77 X86_WRITEX ( writew, uint16_t );
78 X86_WRITEX ( writel, uint32_t );
81 * PIO reads and writes up to 32 bits
85 #define X86_INX( _insn_suffix, _type, _reg_prefix ) \
86 static inline __always_inline _type \
87 IOAPI_INLINE ( x86, in ## _insn_suffix ) ( volatile _type *io_addr ) { \
89 __asm__ __volatile__ ( "in" #_insn_suffix " %w1, %" _reg_prefix "0" \
90 : "=a" ( data ) : "Nd" ( io_addr ) ); \
93 static inline __always_inline void \
94 IOAPI_INLINE ( x86, ins ## _insn_suffix ) ( volatile _type *io_addr, \
96 unsigned int count ) { \
97 unsigned int discard_D; \
98 __asm__ __volatile__ ( "rep ins" #_insn_suffix \
99 : "=D" ( discard_D ) \
100 : "d" ( io_addr ), "c" ( count ), \
103 X86_INX ( b, uint8_t, "b" );
104 X86_INX ( w, uint16_t, "w" );
105 X86_INX ( l, uint32_t, "k" );
107 #define X86_OUTX( _insn_suffix, _type, _reg_prefix ) \
108 static inline __always_inline void \
109 IOAPI_INLINE ( x86, out ## _insn_suffix ) ( _type data, \
110 volatile _type *io_addr ) { \
111 __asm__ __volatile__ ( "out" #_insn_suffix " %" _reg_prefix "0, %w1" \
112 : : "a" ( data ), "Nd" ( io_addr ) ); \
114 static inline __always_inline void \
115 IOAPI_INLINE ( x86, outs ## _insn_suffix ) ( volatile _type *io_addr, \
117 unsigned int count ) { \
118 unsigned int discard_D; \
119 __asm__ __volatile__ ( "rep outs" #_insn_suffix \
120 : "=D" ( discard_D ) \
121 : "d" ( io_addr ), "c" ( count ), \
124 X86_OUTX ( b, uint8_t, "b" );
125 X86_OUTX ( w, uint16_t, "w" );
126 X86_OUTX ( l, uint32_t, "k" );
133 static inline __always_inline void
134 IOAPI_INLINE ( x86, iodelay ) ( void ) {
135 __asm__ __volatile__ ( "outb %al, $0x80" );
143 static inline __always_inline void
144 IOAPI_INLINE ( x86, mb ) ( void ) {
145 __asm__ __volatile__ ( "lock; addl $0, 0(%%esp)" : : : "memory" );
148 #endif /* _GPXE_X86_IO_H */