[ioapi] Formalise the I/O API as used in i386-pcbios
[people/asdlkf/gpxe.git] / src / arch / i386 / include / gpxe / x86_io.h
1 #ifndef _GPXE_X86_IO_H
2 #define _GPXE_X86_IO_H
3
4 /** @file
5  *
6  * gPXE I/O API for x86
7  *
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.
11  *
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.
16  */
17
18 #include <virtaddr.h>
19
20 #ifdef IOAPI_X86
21 #define IOAPI_PREFIX_x86
22 #else
23 #define IOAPI_PREFIX_x86 __x86_
24 #endif
25
26 /*
27  * Memory space mappings
28  *
29  */
30
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 );
34 }
35
36 static inline __always_inline void
37 IOAPI_INLINE ( x86, iounmap ) ( volatile const void *io_addr __unused ) {
38         /* Nothing to do */
39 }
40
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 );
44 }
45
46 static inline __always_inline unsigned long
47 IOAPI_INLINE ( x86, virt_to_bus ) ( volatile const void *addr ) {
48         return virt_to_phys ( addr );
49 }
50
51 static inline __always_inline void *
52 IOAPI_INLINE ( x86, bus_to_virt ) ( unsigned long bus_addr ) {
53         return phys_to_virt ( bus_addr );
54 }
55
56 /*
57  * MMIO reads and writes up to 32 bits
58  *
59  */
60
61 #define X86_READX( _api_func, _type )                                         \
62 static inline __always_inline _type                                           \
63 IOAPI_INLINE ( x86, _api_func ) ( volatile _type *io_addr ) {                 \
64         return *io_addr;                                                      \
65 }
66 X86_READX ( readb, uint8_t );
67 X86_READX ( readw, uint16_t );
68 X86_READX ( readl, uint32_t );
69
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 ) {                 \
74         *io_addr = data;                                                      \
75 }
76 X86_WRITEX ( writeb, uint8_t );
77 X86_WRITEX ( writew, uint16_t );
78 X86_WRITEX ( writel, uint32_t );
79
80 /*
81  * PIO reads and writes up to 32 bits
82  *
83  */
84
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 ) {        \
88         _type data;                                                           \
89         __asm__ __volatile__ ( "in" #_insn_suffix " %w1, %" _reg_prefix "0"   \
90                                : "=a" ( data ) : "Nd" ( io_addr ) );          \
91         return data;                                                          \
92 }                                                                             \
93 static inline __always_inline void                                            \
94 IOAPI_INLINE ( x86, ins ## _insn_suffix ) ( volatile _type *io_addr,          \
95                                             _type *data,                      \
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 ),              \
101                                  "0" ( data ) );                              \
102 }
103 X86_INX ( b, uint8_t, "b" );
104 X86_INX ( w, uint16_t, "w" );
105 X86_INX ( l, uint32_t, "k" );
106
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 ) );          \
113 }                                                                             \
114 static inline __always_inline void                                            \
115 IOAPI_INLINE ( x86, outs ## _insn_suffix ) ( volatile _type *io_addr,         \
116                                              const _type *data,               \
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 ),              \
122                                  "0" ( data ) );                              \
123 }
124 X86_OUTX ( b, uint8_t, "b" );
125 X86_OUTX ( w, uint16_t, "w" );
126 X86_OUTX ( l, uint32_t, "k" );
127
128 /*
129  * Slow down I/O
130  *
131  */
132
133 static inline __always_inline void
134 IOAPI_INLINE ( x86, iodelay ) ( void ) {
135         __asm__ __volatile__ ( "outb %al, $0x80" );
136 }
137
138 /*
139  * Memory barrier
140  *
141  */
142
143 static inline __always_inline void
144 IOAPI_INLINE ( x86, mb ) ( void ) {
145         __asm__ __volatile__ ( "lock; addl $0, 0(%%esp)" : : : "memory" );
146 }
147
148 #endif /* _GPXE_X86_IO_H */