8 * x86 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 * under i386, and will crash original Pentium and earlier CPUs.
14 * Fortunately, no hardware that requires atomic 64-bit accesses will
15 * physically fit into a machine with such an old CPU anyway.
18 FILE_LICENCE ( GPL2_OR_LATER );
21 #define IOAPI_PREFIX_x86
23 #define IOAPI_PREFIX_x86 __x86_
27 * Memory space mappings
35 * Physical<->Bus and Bus<->I/O address mappings
39 static inline __always_inline unsigned long
40 IOAPI_INLINE ( x86, phys_to_bus ) ( unsigned long phys_addr ) {
44 static inline __always_inline unsigned long
45 IOAPI_INLINE ( x86, bus_to_phys ) ( unsigned long bus_addr ) {
49 static inline __always_inline void *
50 IOAPI_INLINE ( x86, ioremap ) ( unsigned long bus_addr, size_t len __unused ) {
51 return ( bus_addr ? phys_to_virt ( bus_addr ) : NULL );
54 static inline __always_inline void
55 IOAPI_INLINE ( x86, iounmap ) ( volatile const void *io_addr __unused ) {
59 static inline __always_inline unsigned long
60 IOAPI_INLINE ( x86, io_to_bus ) ( volatile const void *io_addr ) {
61 return virt_to_phys ( io_addr );
65 * MMIO reads and writes up to native word size
69 #define X86_READX( _api_func, _type ) \
70 static inline __always_inline _type \
71 IOAPI_INLINE ( x86, _api_func ) ( volatile _type *io_addr ) { \
74 X86_READX ( readb, uint8_t );
75 X86_READX ( readw, uint16_t );
76 X86_READX ( readl, uint32_t );
78 X86_READX ( readq, uint64_t );
81 #define X86_WRITEX( _api_func, _type ) \
82 static inline __always_inline void \
83 IOAPI_INLINE ( x86, _api_func ) ( _type data, \
84 volatile _type *io_addr ) { \
87 X86_WRITEX ( writeb, uint8_t );
88 X86_WRITEX ( writew, uint16_t );
89 X86_WRITEX ( writel, uint32_t );
91 X86_WRITEX ( writeq, uint64_t );
95 * PIO reads and writes up to 32 bits
99 #define X86_INX( _insn_suffix, _type, _reg_prefix ) \
100 static inline __always_inline _type \
101 IOAPI_INLINE ( x86, in ## _insn_suffix ) ( volatile _type *io_addr ) { \
103 __asm__ __volatile__ ( "in" #_insn_suffix " %w1, %" _reg_prefix "0" \
104 : "=a" ( data ) : "Nd" ( io_addr ) ); \
107 static inline __always_inline void \
108 IOAPI_INLINE ( x86, ins ## _insn_suffix ) ( volatile _type *io_addr, \
110 unsigned int count ) { \
111 unsigned int discard_D; \
112 __asm__ __volatile__ ( "rep ins" #_insn_suffix \
113 : "=D" ( discard_D ) \
114 : "d" ( io_addr ), "c" ( count ), \
117 X86_INX ( b, uint8_t, "b" );
118 X86_INX ( w, uint16_t, "w" );
119 X86_INX ( l, uint32_t, "k" );
121 #define X86_OUTX( _insn_suffix, _type, _reg_prefix ) \
122 static inline __always_inline void \
123 IOAPI_INLINE ( x86, out ## _insn_suffix ) ( _type data, \
124 volatile _type *io_addr ) { \
125 __asm__ __volatile__ ( "out" #_insn_suffix " %" _reg_prefix "0, %w1" \
126 : : "a" ( data ), "Nd" ( io_addr ) ); \
128 static inline __always_inline void \
129 IOAPI_INLINE ( x86, outs ## _insn_suffix ) ( volatile _type *io_addr, \
131 unsigned int count ) { \
132 unsigned int discard_S; \
133 __asm__ __volatile__ ( "rep outs" #_insn_suffix \
134 : "=S" ( discard_S ) \
135 : "d" ( io_addr ), "c" ( count ), \
138 X86_OUTX ( b, uint8_t, "b" );
139 X86_OUTX ( w, uint16_t, "w" );
140 X86_OUTX ( l, uint32_t, "k" );
147 static inline __always_inline void
148 IOAPI_INLINE ( x86, iodelay ) ( void ) {
149 __asm__ __volatile__ ( "outb %al, $0x80" );
157 static inline __always_inline void
158 IOAPI_INLINE ( x86, mb ) ( void ) {
159 __asm__ __volatile__ ( "lock; addl $0, 0(%%esp)" : : : "memory" );
162 #endif /* _IPXE_X86_IO_H */