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.
18 FILE_LICENCE ( GPL2_OR_LATER
);
21 #define IOAPI_PREFIX_x86
23 #define IOAPI_PREFIX_x86 __x86_
27 * Memory space mappings
32 * Physical<->Bus and Bus<->I/O address mappings
36 static inline __always_inline
unsigned long
37 IOAPI_INLINE ( x86
, phys_to_bus
) ( unsigned long phys_addr
) {
41 static inline __always_inline
unsigned long
42 IOAPI_INLINE ( x86
, bus_to_phys
) ( unsigned long bus_addr
) {
46 static inline __always_inline
void *
47 IOAPI_INLINE ( x86
, ioremap
) ( unsigned long bus_addr
, size_t len __unused
) {
48 return phys_to_virt ( bus_addr
);
51 static inline __always_inline
void
52 IOAPI_INLINE ( x86
, iounmap
) ( volatile const void *io_addr __unused
) {
56 static inline __always_inline
unsigned long
57 IOAPI_INLINE ( x86
, io_to_bus
) ( volatile const void *io_addr
) {
58 return virt_to_phys ( io_addr
);
62 * MMIO reads and writes up to 32 bits
66 #define X86_READX( _api_func, _type ) \
67 static inline __always_inline _type \
68 IOAPI_INLINE ( x86, _api_func ) ( volatile _type *io_addr ) { \
71 X86_READX ( readb
, uint8_t );
72 X86_READX ( readw
, uint16_t );
73 X86_READX ( readl
, uint32_t );
75 #define X86_WRITEX( _api_func, _type ) \
76 static inline __always_inline void \
77 IOAPI_INLINE ( x86, _api_func ) ( _type data, \
78 volatile _type *io_addr ) { \
81 X86_WRITEX ( writeb
, uint8_t );
82 X86_WRITEX ( writew
, uint16_t );
83 X86_WRITEX ( writel
, uint32_t );
86 * PIO reads and writes up to 32 bits
90 #define X86_INX( _insn_suffix, _type, _reg_prefix ) \
91 static inline __always_inline _type \
92 IOAPI_INLINE ( x86, in ## _insn_suffix ) ( volatile _type *io_addr ) { \
94 __asm__ __volatile__ ( "in" #_insn_suffix " %w1, %" _reg_prefix "0" \
95 : "=a" ( data ) : "Nd" ( io_addr ) ); \
98 static inline __always_inline void \
99 IOAPI_INLINE ( x86, ins ## _insn_suffix ) ( volatile _type *io_addr, \
101 unsigned int count ) { \
102 unsigned int discard_D; \
103 __asm__ __volatile__ ( "rep ins" #_insn_suffix \
104 : "=D" ( discard_D ) \
105 : "d" ( io_addr ), "c" ( count ), \
108 X86_INX ( b
, uint8_t, "b" );
109 X86_INX ( w
, uint16_t, "w" );
110 X86_INX ( l
, uint32_t, "k" );
112 #define X86_OUTX( _insn_suffix, _type, _reg_prefix ) \
113 static inline __always_inline void \
114 IOAPI_INLINE ( x86, out ## _insn_suffix ) ( _type data, \
115 volatile _type *io_addr ) { \
116 __asm__ __volatile__ ( "out" #_insn_suffix " %" _reg_prefix "0, %w1" \
117 : : "a" ( data ), "Nd" ( io_addr ) ); \
119 static inline __always_inline void \
120 IOAPI_INLINE ( x86, outs ## _insn_suffix ) ( volatile _type *io_addr, \
122 unsigned int count ) { \
123 unsigned int discard_S; \
124 __asm__ __volatile__ ( "rep outs" #_insn_suffix \
125 : "=S" ( discard_S ) \
126 : "d" ( io_addr ), "c" ( count ), \
129 X86_OUTX ( b
, uint8_t, "b" );
130 X86_OUTX ( w
, uint16_t, "w" );
131 X86_OUTX ( l
, uint32_t, "k" );
138 static inline __always_inline
void
139 IOAPI_INLINE ( x86
, iodelay
) ( void ) {
140 __asm__
__volatile__ ( "outb %al, $0x80" );
148 static inline __always_inline
void
149 IOAPI_INLINE ( x86
, mb
) ( void ) {
150 __asm__
__volatile__ ( "lock; addl $0, 0(%%esp)" : : : "memory" );
153 #endif /* _GPXE_X86_IO_H */