[ioapi] Formalise the I/O API as used in i386-pcbios
This commit is contained in:
parent
b40b4f2dbf
commit
8956a36be5
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <gpxe/io.h>
|
||||
#include <gpxe/x86_io.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* gPXE I/O API for x86
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Read 64-bit qword from memory-mapped device
|
||||
*
|
||||
* @v io_addr I/O address
|
||||
* @ret data Value read
|
||||
*
|
||||
* This routine uses MMX instructions.
|
||||
*/
|
||||
static uint64_t x86_readq ( volatile uint64_t *io_addr ) {
|
||||
uint64_t data;
|
||||
__asm__ __volatile__ ( "pushl %%edx\n\t"
|
||||
"pushl %%eax\n\t"
|
||||
"movq (%1), %%mm0\n\t"
|
||||
"movq %%mm0, (%%esp)\n\t"
|
||||
"popl %%eax\n\t"
|
||||
"popl %%edx\n\t"
|
||||
"emms\n\t"
|
||||
: "=A" ( data ) : "r" ( io_addr ) );
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write 64-bit qword to memory-mapped device
|
||||
*
|
||||
* @v data Value to write
|
||||
* @v io_addr I/O address
|
||||
*
|
||||
* This routine uses MMX instructions.
|
||||
*/
|
||||
static void x86_writeq ( uint64_t data, volatile uint64_t *io_addr ) {
|
||||
__asm__ __volatile__ ( "pushl %%edx\n\t"
|
||||
"pushl %%eax\n\t"
|
||||
"movq (%%esp), %%mm0\n\t"
|
||||
"movq %%mm0, (%1)\n\t"
|
||||
"popl %%eax\n\t"
|
||||
"popl %%edx\n\t"
|
||||
"emms\n\t"
|
||||
: : "A" ( data ), "r" ( io_addr ) );
|
||||
}
|
||||
|
||||
PROVIDE_IOAPI_INLINE ( x86, iounmap );
|
||||
PROVIDE_IOAPI_INLINE ( x86, io_to_bus );
|
||||
PROVIDE_IOAPI_INLINE ( x86, virt_to_bus );
|
||||
PROVIDE_IOAPI_INLINE ( x86, bus_to_virt );
|
||||
PROVIDE_IOAPI_INLINE ( x86, readb );
|
||||
PROVIDE_IOAPI_INLINE ( x86, readw );
|
||||
PROVIDE_IOAPI_INLINE ( x86, readl );
|
||||
PROVIDE_IOAPI ( x86, readq, x86_readq );
|
||||
PROVIDE_IOAPI_INLINE ( x86, writeb );
|
||||
PROVIDE_IOAPI_INLINE ( x86, writew );
|
||||
PROVIDE_IOAPI_INLINE ( x86, writel );
|
||||
PROVIDE_IOAPI ( x86, writeq, x86_writeq );
|
||||
PROVIDE_IOAPI_INLINE ( x86, inb );
|
||||
PROVIDE_IOAPI_INLINE ( x86, inw );
|
||||
PROVIDE_IOAPI_INLINE ( x86, inl );
|
||||
PROVIDE_IOAPI_INLINE ( x86, outb );
|
||||
PROVIDE_IOAPI_INLINE ( x86, outw );
|
||||
PROVIDE_IOAPI_INLINE ( x86, outl );
|
||||
PROVIDE_IOAPI_INLINE ( x86, insb );
|
||||
PROVIDE_IOAPI_INLINE ( x86, insw );
|
||||
PROVIDE_IOAPI_INLINE ( x86, insl );
|
||||
PROVIDE_IOAPI_INLINE ( x86, outsb );
|
||||
PROVIDE_IOAPI_INLINE ( x86, outsw );
|
||||
PROVIDE_IOAPI_INLINE ( x86, outsl );
|
||||
PROVIDE_IOAPI_INLINE ( x86, iodelay );
|
||||
PROVIDE_IOAPI_INLINE ( x86, mb );
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef _BITS_IO_H
|
||||
#define _BITS_IO_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* i386-specific I/O API implementations
|
||||
*
|
||||
*/
|
||||
|
||||
#include <gpxe/x86_io.h>
|
||||
|
||||
#endif /* _BITS_IO_H */
|
|
@ -0,0 +1,148 @@
|
|||
#ifndef _GPXE_X86_IO_H
|
||||
#define _GPXE_X86_IO_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* gPXE I/O API for x86
|
||||
*
|
||||
* i386 uses direct pointer dereferences for accesses to memory-mapped
|
||||
* I/O space, and the inX/outX instructions for accesses to
|
||||
* port-mapped I/O space.
|
||||
*
|
||||
* 64-bit atomic accesses (readq() and writeq()) use MMX instructions,
|
||||
* and will crash original Pentium and earlier CPUs. Fortunately, no
|
||||
* hardware that requires atomic 64-bit accesses will physically fit
|
||||
* into a machine with such an old CPU anyway.
|
||||
*/
|
||||
|
||||
#include <virtaddr.h>
|
||||
|
||||
#ifdef IOAPI_X86
|
||||
#define IOAPI_PREFIX_x86
|
||||
#else
|
||||
#define IOAPI_PREFIX_x86 __x86_
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Memory space mappings
|
||||
*
|
||||
*/
|
||||
|
||||
static inline __always_inline void *
|
||||
IOAPI_INLINE ( x86, ioremap ) ( unsigned long bus_addr, size_t len __unused ) {
|
||||
return phys_to_virt ( bus_addr );
|
||||
}
|
||||
|
||||
static inline __always_inline void
|
||||
IOAPI_INLINE ( x86, iounmap ) ( volatile const void *io_addr __unused ) {
|
||||
/* Nothing to do */
|
||||
}
|
||||
|
||||
static inline __always_inline unsigned long
|
||||
IOAPI_INLINE ( x86, io_to_bus ) ( volatile const void *io_addr ) {
|
||||
return virt_to_phys ( io_addr );
|
||||
}
|
||||
|
||||
static inline __always_inline unsigned long
|
||||
IOAPI_INLINE ( x86, virt_to_bus ) ( volatile const void *addr ) {
|
||||
return virt_to_phys ( addr );
|
||||
}
|
||||
|
||||
static inline __always_inline void *
|
||||
IOAPI_INLINE ( x86, bus_to_virt ) ( unsigned long bus_addr ) {
|
||||
return phys_to_virt ( bus_addr );
|
||||
}
|
||||
|
||||
/*
|
||||
* MMIO reads and writes up to 32 bits
|
||||
*
|
||||
*/
|
||||
|
||||
#define X86_READX( _api_func, _type ) \
|
||||
static inline __always_inline _type \
|
||||
IOAPI_INLINE ( x86, _api_func ) ( volatile _type *io_addr ) { \
|
||||
return *io_addr; \
|
||||
}
|
||||
X86_READX ( readb, uint8_t );
|
||||
X86_READX ( readw, uint16_t );
|
||||
X86_READX ( readl, uint32_t );
|
||||
|
||||
#define X86_WRITEX( _api_func, _type ) \
|
||||
static inline __always_inline void \
|
||||
IOAPI_INLINE ( x86, _api_func ) ( _type data, \
|
||||
volatile _type *io_addr ) { \
|
||||
*io_addr = data; \
|
||||
}
|
||||
X86_WRITEX ( writeb, uint8_t );
|
||||
X86_WRITEX ( writew, uint16_t );
|
||||
X86_WRITEX ( writel, uint32_t );
|
||||
|
||||
/*
|
||||
* PIO reads and writes up to 32 bits
|
||||
*
|
||||
*/
|
||||
|
||||
#define X86_INX( _insn_suffix, _type, _reg_prefix ) \
|
||||
static inline __always_inline _type \
|
||||
IOAPI_INLINE ( x86, in ## _insn_suffix ) ( volatile _type *io_addr ) { \
|
||||
_type data; \
|
||||
__asm__ __volatile__ ( "in" #_insn_suffix " %w1, %" _reg_prefix "0" \
|
||||
: "=a" ( data ) : "Nd" ( io_addr ) ); \
|
||||
return data; \
|
||||
} \
|
||||
static inline __always_inline void \
|
||||
IOAPI_INLINE ( x86, ins ## _insn_suffix ) ( volatile _type *io_addr, \
|
||||
_type *data, \
|
||||
unsigned int count ) { \
|
||||
unsigned int discard_D; \
|
||||
__asm__ __volatile__ ( "rep ins" #_insn_suffix \
|
||||
: "=D" ( discard_D ) \
|
||||
: "d" ( io_addr ), "c" ( count ), \
|
||||
"0" ( data ) ); \
|
||||
}
|
||||
X86_INX ( b, uint8_t, "b" );
|
||||
X86_INX ( w, uint16_t, "w" );
|
||||
X86_INX ( l, uint32_t, "k" );
|
||||
|
||||
#define X86_OUTX( _insn_suffix, _type, _reg_prefix ) \
|
||||
static inline __always_inline void \
|
||||
IOAPI_INLINE ( x86, out ## _insn_suffix ) ( _type data, \
|
||||
volatile _type *io_addr ) { \
|
||||
__asm__ __volatile__ ( "out" #_insn_suffix " %" _reg_prefix "0, %w1" \
|
||||
: : "a" ( data ), "Nd" ( io_addr ) ); \
|
||||
} \
|
||||
static inline __always_inline void \
|
||||
IOAPI_INLINE ( x86, outs ## _insn_suffix ) ( volatile _type *io_addr, \
|
||||
const _type *data, \
|
||||
unsigned int count ) { \
|
||||
unsigned int discard_D; \
|
||||
__asm__ __volatile__ ( "rep outs" #_insn_suffix \
|
||||
: "=D" ( discard_D ) \
|
||||
: "d" ( io_addr ), "c" ( count ), \
|
||||
"0" ( data ) ); \
|
||||
}
|
||||
X86_OUTX ( b, uint8_t, "b" );
|
||||
X86_OUTX ( w, uint16_t, "w" );
|
||||
X86_OUTX ( l, uint32_t, "k" );
|
||||
|
||||
/*
|
||||
* Slow down I/O
|
||||
*
|
||||
*/
|
||||
|
||||
static inline __always_inline void
|
||||
IOAPI_INLINE ( x86, iodelay ) ( void ) {
|
||||
__asm__ __volatile__ ( "outb %al, $0x80" );
|
||||
}
|
||||
|
||||
/*
|
||||
* Memory barrier
|
||||
*
|
||||
*/
|
||||
|
||||
static inline __always_inline void
|
||||
IOAPI_INLINE ( x86, mb ) ( void ) {
|
||||
__asm__ __volatile__ ( "lock; addl $0, 0(%%esp)" : : : "memory" );
|
||||
}
|
||||
|
||||
#endif /* _GPXE_X86_IO_H */
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef CONFIG_DEFAULTS_H
|
||||
#define CONFIG_DEFAULTS_H
|
||||
|
||||
#define CONFIG_DEFAULTS(_platform) <config/defaults/_platform.h>
|
||||
|
||||
#include CONFIG_DEFAULTS(PLATFORM)
|
||||
|
||||
#endif /* CONFIG_DEFAULTS_H */
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef CONFIG_DEFAULTS_PCBIOS_H
|
||||
#define CONFIG_DEFAULTS_PCBIOS_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Configuration defaults for PCBIOS
|
||||
*
|
||||
*/
|
||||
|
||||
#define IOAPI_X86
|
||||
|
||||
#endif /* CONFIG_DEFAULTS_PCBIOS_H */
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef CONFIG_IOAPI_H
|
||||
#define CONFIG_IOAPI_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* I/O API configuration
|
||||
*
|
||||
*/
|
||||
|
||||
#include <config/defaults.h>
|
||||
|
||||
#endif /* CONFIG_IOAPI_H */
|
|
@ -0,0 +1,82 @@
|
|||
#ifndef _GPXE_API_H
|
||||
#define _GPXE_API_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* gPXE internal APIs
|
||||
*
|
||||
* There are various formally-defined APIs internal to gPXE, with
|
||||
* several differing implementations specific to particular execution
|
||||
* environments (e.g. PC BIOS, EFI, LinuxBIOS).
|
||||
*
|
||||
*/
|
||||
|
||||
/** @defgroup Single-implementation APIs
|
||||
*
|
||||
* These are APIs for which only a single implementation may be
|
||||
* compiled in at any given time.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Calculate function implementation name
|
||||
*
|
||||
* @v _prefix Subsystem prefix
|
||||
* @v _api_func API function
|
||||
* @ret _subsys_func Subsystem API function
|
||||
*
|
||||
* The subsystem prefix should be an empty string for the currently
|
||||
* selected subsystem, and should be a subsystem-unique string for all
|
||||
* other subsystems.
|
||||
*/
|
||||
#define SINGLE_API_NAME( _prefix, _api_func ) _prefix ## _api_func
|
||||
|
||||
/**
|
||||
* Calculate static inline function name
|
||||
*
|
||||
* @v _prefix Subsystem prefix
|
||||
* @v _api_func API function
|
||||
* @ret _subsys_func Subsystem API function
|
||||
*/
|
||||
#define SINGLE_API_INLINE( _prefix, _api_func ) \
|
||||
SINGLE_API_NAME ( _prefix, _api_func )
|
||||
|
||||
/**
|
||||
* Provide an API implementation
|
||||
*
|
||||
* @v _prefix Subsystem prefix
|
||||
* @v _api_func API function
|
||||
* @v _func Implementing function
|
||||
*/
|
||||
#define PROVIDE_SINGLE_API( _prefix, _api_func, _func ) \
|
||||
/* Ensure that _api_func exists */ \
|
||||
typeof ( _api_func ) _api_func; \
|
||||
/* Ensure that _func exists */ \
|
||||
typeof ( _func ) _func; \
|
||||
/* Ensure that _func is type-compatible with _api_func */ \
|
||||
typeof ( _api_func ) _func; \
|
||||
/* Ensure that _subsys_func is non-static */ \
|
||||
extern typeof ( _api_func ) SINGLE_API_NAME ( _prefix, _api_func ); \
|
||||
/* Provide symbol alias from _subsys_func to _func */ \
|
||||
typeof ( _api_func ) SINGLE_API_NAME ( _prefix, _api_func ) \
|
||||
__attribute__ (( alias ( #_func ) ));
|
||||
|
||||
/**
|
||||
* Provide a static inline API implementation
|
||||
*
|
||||
* @v _prefix Subsystem prefix
|
||||
* @v _api_func API function
|
||||
*/
|
||||
#define PROVIDE_SINGLE_API_INLINE( _prefix, _api_func ) \
|
||||
/* Ensure that _api_func exists */ \
|
||||
typeof ( _api_func ) _api_func; \
|
||||
/* Ensure that _subsys_func exists and is static */ \
|
||||
static typeof ( SINGLE_API_INLINE ( _prefix, _api_func ) ) \
|
||||
SINGLE_API_INLINE ( _prefix, _api_func ); \
|
||||
/* Ensure that _subsys_func is type-compatible with _api_func */ \
|
||||
typeof ( _api_func ) SINGLE_API_INLINE ( _prefix, _api_func );
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* _GPXE_API_H */
|
|
@ -0,0 +1,483 @@
|
|||
#ifndef _GPXE_IO_H
|
||||
#define _GPXE_IO_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* gPXE I/O API
|
||||
*
|
||||
* The I/O API provides methods for reading from and writing to
|
||||
* memory-mapped and I/O-mapped devices.
|
||||
*
|
||||
* The standard methods (readl()/writel() etc.) do not strictly check
|
||||
* the type of the address parameter; this is because traditional
|
||||
* usage does not necessarily provide the correct pointer type. For
|
||||
* example, code written for ISA devices at fixed I/O addresses (such
|
||||
* as the keyboard controller) tend to use plain integer constants for
|
||||
* the address parameter.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <gpxe/api.h>
|
||||
#include <config/ioapi.h>
|
||||
|
||||
/**
|
||||
* Calculate static inline I/O API function name
|
||||
*
|
||||
* @v _prefix Subsystem prefix
|
||||
* @v _api_func API function
|
||||
* @ret _subsys_func Subsystem API function
|
||||
*/
|
||||
#define IOAPI_INLINE( _subsys, _api_func ) \
|
||||
SINGLE_API_INLINE ( IOAPI_PREFIX_ ## _subsys, _api_func )
|
||||
|
||||
/**
|
||||
* Provide an I/O API implementation
|
||||
*
|
||||
* @v _prefix Subsystem prefix
|
||||
* @v _api_func API function
|
||||
* @v _func Implementing function
|
||||
*/
|
||||
#define PROVIDE_IOAPI( _subsys, _api_func, _func ) \
|
||||
PROVIDE_SINGLE_API ( IOAPI_PREFIX_ ## _subsys, _api_func, _func )
|
||||
|
||||
/**
|
||||
* Provide a static inline I/O API implementation
|
||||
*
|
||||
* @v _prefix Subsystem prefix
|
||||
* @v _api_func API function
|
||||
*/
|
||||
#define PROVIDE_IOAPI_INLINE( _subsys, _api_func ) \
|
||||
PROVIDE_SINGLE_API_INLINE ( IOAPI_PREFIX_ ## _subsys, _api_func )
|
||||
|
||||
/* Include all architecture-independent I/O API headers */
|
||||
|
||||
/* Include all architecture-dependent I/O API headers */
|
||||
#include <bits/io.h>
|
||||
|
||||
/**
|
||||
* Wrap an I/O read
|
||||
*
|
||||
* @v _func I/O API function
|
||||
* @v _type Data type
|
||||
* @v io_addr I/O address
|
||||
* @v _prefix Prefix for address in debug message
|
||||
* @v _ndigits Number of hex digits for this data type
|
||||
*/
|
||||
#define IOAPI_READ( _func, _type, io_addr, _prefix, _ndigits ) ( { \
|
||||
volatile _type *_io_addr = \
|
||||
( ( volatile _type * ) ( intptr_t ) (io_addr) ); \
|
||||
_type _data = _func ( _io_addr ); \
|
||||
DBGIO ( "[" _prefix " %08lx] => %0" #_ndigits "llx\n", \
|
||||
io_to_bus ( _io_addr ), ( unsigned long long ) _data ); \
|
||||
_data; } )
|
||||
|
||||
/**
|
||||
* Wrap an I/O write
|
||||
*
|
||||
* @v _func I/O API function
|
||||
* @v _type Data type
|
||||
* @v data Value to write
|
||||
* @v io_addr I/O address
|
||||
* @v _prefix Prefix for address in debug message
|
||||
* @v _ndigits Number of hex digits for this data type
|
||||
*/
|
||||
#define IOAPI_WRITE( _func, _type, data, io_addr, _prefix, _ndigits ) do { \
|
||||
volatile _type *_io_addr = \
|
||||
( ( volatile _type * ) ( intptr_t ) (io_addr) ); \
|
||||
_type _data = (data); \
|
||||
DBGIO ( "[" _prefix " %08lx] <= %0" #_ndigits "llx\n", \
|
||||
io_to_bus ( _io_addr ), ( unsigned long long ) _data ); \
|
||||
_func ( _data, _io_addr ); \
|
||||
} while ( 0 )
|
||||
|
||||
/**
|
||||
* Wrap an I/O string read
|
||||
*
|
||||
* @v _func I/O API function
|
||||
* @v _type Data type
|
||||
* @v io_addr I/O address
|
||||
* @v data Data buffer
|
||||
* @v count Number of elements to read
|
||||
* @v _prefix Prefix for address in debug message
|
||||
* @v _ndigits Number of hex digits for this data type
|
||||
*/
|
||||
#define IOAPI_READS( _func, _type, io_addr, data, count, _prefix, _ndigits ) \
|
||||
do { \
|
||||
volatile _type *_io_addr = \
|
||||
( ( volatile _type * ) ( intptr_t ) (io_addr) ); \
|
||||
void *_data_void = (data); /* Check data is a pointer */ \
|
||||
_type * _data = ( ( _type * ) _data_void ); \
|
||||
const _type * _dbg_data = _data; \
|
||||
unsigned int _count = (count); \
|
||||
unsigned int _dbg_count = _count; \
|
||||
_func ( _io_addr, _data, _count ); \
|
||||
DBGIO ( "[" _prefix " %08lx] =>", io_to_bus ( _io_addr ) ); \
|
||||
while ( _dbg_count-- ) { \
|
||||
DBGIO ( " %0" #_ndigits "llx", \
|
||||
( ( unsigned long long ) *(_dbg_data++) ) ); \
|
||||
} \
|
||||
DBGIO ( "\n" ); \
|
||||
} while ( 0 )
|
||||
|
||||
/**
|
||||
* Wrap an I/O string write
|
||||
*
|
||||
* @v _func I/O API function
|
||||
* @v _type Data type
|
||||
* @v io_addr I/O address
|
||||
* @v data Data buffer
|
||||
* @v count Number of elements to write
|
||||
* @v _prefix Prefix for address in debug message
|
||||
* @v _ndigits Number of hex digits for this data type
|
||||
*/
|
||||
#define IOAPI_WRITES( _func, _type, io_addr, data, count, _prefix, _ndigits ) \
|
||||
do { \
|
||||
volatile _type *_io_addr = \
|
||||
( ( volatile _type * ) ( intptr_t ) (io_addr) ); \
|
||||
const void *_data_void = (data); /* Check data is a pointer */ \
|
||||
const _type * _data = ( ( const _type * ) _data_void ); \
|
||||
const _type * _dbg_data = _data; \
|
||||
unsigned int _count = (count); \
|
||||
unsigned int _dbg_count = _count; \
|
||||
DBGIO ( "[" _prefix " %08lx] <=", io_to_bus ( _io_addr ) ); \
|
||||
while ( _dbg_count-- ) { \
|
||||
DBGIO ( " %0" #_ndigits "llx", \
|
||||
( ( unsigned long long ) *(_dbg_data++) ) ); \
|
||||
} \
|
||||
DBGIO ( "\n" ); \
|
||||
_func ( _io_addr, _data, _count ); \
|
||||
} while ( 0 )
|
||||
|
||||
/**
|
||||
* Map bus address as an I/O address
|
||||
*
|
||||
* @v bus_addr Bus address
|
||||
* @v len Length of region
|
||||
* @ret io_addr I/O address
|
||||
*/
|
||||
void * ioremap ( unsigned long bus_addr, size_t len );
|
||||
|
||||
/**
|
||||
* Unmap I/O address
|
||||
*
|
||||
* @v io_addr I/O address
|
||||
*/
|
||||
void iounmap ( volatile const void *io_addr );
|
||||
|
||||
/**
|
||||
* Convert I/O address to bus address (for debug only)
|
||||
*
|
||||
* @v io_addr I/O address
|
||||
* @ret bus_addr Bus address
|
||||
*/
|
||||
unsigned long io_to_bus ( volatile const void *io_addr );
|
||||
|
||||
/**
|
||||
* Convert virtual address to a bus address
|
||||
*
|
||||
* @v addr Virtual address
|
||||
* @ret bus_addr Bus address
|
||||
*/
|
||||
unsigned long virt_to_bus ( volatile const void *addr );
|
||||
|
||||
/**
|
||||
* Convert bus address to a virtual address
|
||||
*
|
||||
* @v bus_addr Bus address
|
||||
* @ret addr Virtual address
|
||||
*
|
||||
* This operation isn't actually valid within our memory model, and is
|
||||
* impossible to achieve under -DKEEP_IT_REAL. Some drivers haven't
|
||||
* been updated to avoid it yet, though.
|
||||
*/
|
||||
void * bus_to_virt ( unsigned long bus_addr );
|
||||
|
||||
/**
|
||||
* Read byte from memory-mapped device
|
||||
*
|
||||
* @v io_addr I/O address
|
||||
* @ret data Value read
|
||||
*/
|
||||
uint8_t readb ( volatile uint8_t *io_addr );
|
||||
#define readb( io_addr ) IOAPI_READ ( readb, uint8_t, io_addr, "MEM", 2 )
|
||||
|
||||
/**
|
||||
* Read 16-bit word from memory-mapped device
|
||||
*
|
||||
* @v io_addr I/O address
|
||||
* @ret data Value read
|
||||
*/
|
||||
uint16_t readw ( volatile uint16_t *io_addr );
|
||||
#define readw( io_addr ) IOAPI_READ ( readw, uint16_t, io_addr, "MEM", 4 )
|
||||
|
||||
/**
|
||||
* Read 32-bit dword from memory-mapped device
|
||||
*
|
||||
* @v io_addr I/O address
|
||||
* @ret data Value read
|
||||
*/
|
||||
uint32_t readl ( volatile uint32_t *io_addr );
|
||||
#define readl( io_addr ) IOAPI_READ ( readl, uint32_t, io_addr, "MEM", 8 )
|
||||
|
||||
/**
|
||||
* Read 64-bit qword from memory-mapped device
|
||||
*
|
||||
* @v io_addr I/O address
|
||||
* @ret data Value read
|
||||
*/
|
||||
uint64_t readq ( volatile uint64_t *io_addr );
|
||||
#define readq( io_addr ) IOAPI_READ ( readq, uint64_t, io_addr, "MEM", 16 )
|
||||
|
||||
/**
|
||||
* Write byte to memory-mapped device
|
||||
*
|
||||
* @v data Value to write
|
||||
* @v io_addr I/O address
|
||||
*/
|
||||
void writeb ( uint8_t data, volatile uint8_t *io_addr );
|
||||
#define writeb( data, io_addr ) \
|
||||
IOAPI_WRITE ( writeb, uint8_t, data, io_addr, "MEM", 2 )
|
||||
|
||||
/**
|
||||
* Write 16-bit word to memory-mapped device
|
||||
*
|
||||
* @v data Value to write
|
||||
* @v io_addr I/O address
|
||||
*/
|
||||
void writew ( uint16_t data, volatile uint16_t *io_addr );
|
||||
#define writew( data, io_addr ) \
|
||||
IOAPI_WRITE ( writew, uint16_t, data, io_addr, "MEM", 4 )
|
||||
|
||||
/**
|
||||
* Write 32-bit dword to memory-mapped device
|
||||
*
|
||||
* @v data Value to write
|
||||
* @v io_addr I/O address
|
||||
*/
|
||||
void writel ( uint32_t data, volatile uint32_t *io_addr );
|
||||
#define writel( data, io_addr ) \
|
||||
IOAPI_WRITE ( writel, uint32_t, data, io_addr, "MEM", 8 )
|
||||
|
||||
/**
|
||||
* Write 64-bit qword to memory-mapped device
|
||||
*
|
||||
* @v data Value to write
|
||||
* @v io_addr I/O address
|
||||
*/
|
||||
void writeq ( uint64_t data, volatile uint64_t *io_addr );
|
||||
#define writeq( data, io_addr ) \
|
||||
IOAPI_WRITE ( writeq, uint64_t, data, io_addr, "MEM", 16 )
|
||||
|
||||
/**
|
||||
* Read byte from I/O-mapped device
|
||||
*
|
||||
* @v io_addr I/O address
|
||||
* @ret data Value read
|
||||
*/
|
||||
uint8_t inb ( volatile uint8_t *io_addr );
|
||||
#define inb( io_addr ) IOAPI_READ ( inb, uint8_t, io_addr, "IO", 2 )
|
||||
|
||||
/**
|
||||
* Read 16-bit word from I/O-mapped device
|
||||
*
|
||||
* @v io_addr I/O address
|
||||
* @ret data Value read
|
||||
*/
|
||||
uint16_t inw ( volatile uint16_t *io_addr );
|
||||
#define inw( io_addr ) IOAPI_READ ( inw, uint16_t, io_addr, "IO", 4 )
|
||||
|
||||
/**
|
||||
* Read 32-bit dword from I/O-mapped device
|
||||
*
|
||||
* @v io_addr I/O address
|
||||
* @ret data Value read
|
||||
*/
|
||||
uint32_t inl ( volatile uint32_t *io_addr );
|
||||
#define inl( io_addr ) IOAPI_READ ( inl, uint32_t, io_addr, "IO", 8 )
|
||||
|
||||
/**
|
||||
* Write byte to I/O-mapped device
|
||||
*
|
||||
* @v data Value to write
|
||||
* @v io_addr I/O address
|
||||
*/
|
||||
void outb ( uint8_t data, volatile uint8_t *io_addr );
|
||||
#define outb( data, io_addr ) \
|
||||
IOAPI_WRITE ( outb, uint8_t, data, io_addr, "IO", 2 )
|
||||
|
||||
/**
|
||||
* Write 16-bit word to I/O-mapped device
|
||||
*
|
||||
* @v data Value to write
|
||||
* @v io_addr I/O address
|
||||
*/
|
||||
void outw ( uint16_t data, volatile uint16_t *io_addr );
|
||||
#define outw( data, io_addr ) \
|
||||
IOAPI_WRITE ( outw, uint16_t, data, io_addr, "IO", 4 )
|
||||
|
||||
/**
|
||||
* Write 32-bit dword to I/O-mapped device
|
||||
*
|
||||
* @v data Value to write
|
||||
* @v io_addr I/O address
|
||||
*/
|
||||
void outl ( uint32_t data, volatile uint32_t *io_addr );
|
||||
#define outl( data, io_addr ) \
|
||||
IOAPI_WRITE ( outl, uint32_t, data, io_addr, "IO", 8 )
|
||||
|
||||
/**
|
||||
* Read bytes from I/O-mapped device
|
||||
*
|
||||
* @v io_addr I/O address
|
||||
* @v data Data buffer
|
||||
* @v count Number of bytes to read
|
||||
*/
|
||||
void insb ( volatile uint8_t *io_addr, uint8_t *data, unsigned int count );
|
||||
#define insb( io_addr, data, count ) \
|
||||
IOAPI_READS ( insb, uint8_t, io_addr, data, count, "IO", 2 )
|
||||
|
||||
/**
|
||||
* Read 16-bit words from I/O-mapped device
|
||||
*
|
||||
* @v io_addr I/O address
|
||||
* @v data Data buffer
|
||||
* @v count Number of words to read
|
||||
*/
|
||||
void insw ( volatile uint16_t *io_addr, uint16_t *data, unsigned int count );
|
||||
#define insw( io_addr, data, count ) \
|
||||
IOAPI_READS ( insw, uint16_t, io_addr, data, count, "IO", 4 )
|
||||
|
||||
/**
|
||||
* Read 32-bit words from I/O-mapped device
|
||||
*
|
||||
* @v io_addr I/O address
|
||||
* @v data Data buffer
|
||||
* @v count Number of words to read
|
||||
*/
|
||||
void insl ( volatile uint32_t *io_addr, uint32_t *data, unsigned int count );
|
||||
#define insl( io_addr, data, count ) \
|
||||
IOAPI_READS ( insl, uint32_t, io_addr, data, count, "IO", 8 )
|
||||
|
||||
/**
|
||||
* Write bytes to I/O-mapped device
|
||||
*
|
||||
* @v io_addr I/O address
|
||||
* @v data Data buffer
|
||||
* @v count Number of bytes to write
|
||||
*/
|
||||
void outsb ( volatile uint8_t *io_addr, const uint8_t *data,
|
||||
unsigned int count );
|
||||
#define outsb( io_addr, data, count ) \
|
||||
IOAPI_WRITES ( outsb, uint8_t, io_addr, data, count, "IO", 2 )
|
||||
|
||||
/**
|
||||
* Write 16-bit words to I/O-mapped device
|
||||
*
|
||||
* @v io_addr I/O address
|
||||
* @v data Data buffer
|
||||
* @v count Number of words to write
|
||||
*/
|
||||
void outsw ( volatile uint16_t *io_addr, const uint16_t *data,
|
||||
unsigned int count );
|
||||
#define outsw( io_addr, data, count ) \
|
||||
IOAPI_WRITES ( outsw, uint16_t, io_addr, data, count, "IO", 4 )
|
||||
|
||||
/**
|
||||
* Write 32-bit words to I/O-mapped device
|
||||
*
|
||||
* @v io_addr I/O address
|
||||
* @v data Data buffer
|
||||
* @v count Number of words to write
|
||||
*/
|
||||
void outsl ( volatile uint32_t *io_addr, const uint32_t *data,
|
||||
unsigned int count );
|
||||
#define outsl( io_addr, data, count ) \
|
||||
IOAPI_WRITES ( outsl, uint32_t, io_addr, data, count, "IO", 8 )
|
||||
|
||||
/**
|
||||
* Slow down I/O
|
||||
*
|
||||
*/
|
||||
void iodelay ( void );
|
||||
|
||||
/**
|
||||
* Read value from I/O-mapped device, slowly
|
||||
*
|
||||
* @v _func Function to use to read value
|
||||
* @v data Value to write
|
||||
* @v io_addr I/O address
|
||||
*/
|
||||
#define INX_P( _func, _type, io_addr ) ( { \
|
||||
_type _data = _func ( (io_addr) ); \
|
||||
iodelay(); \
|
||||
_data; } )
|
||||
|
||||
/**
|
||||
* Read byte from I/O-mapped device
|
||||
*
|
||||
* @v io_addr I/O address
|
||||
* @ret data Value read
|
||||
*/
|
||||
#define inb_p( io_addr ) INX_P ( inb, uint8_t, io_addr )
|
||||
|
||||
/**
|
||||
* Read 16-bit word from I/O-mapped device
|
||||
*
|
||||
* @v io_addr I/O address
|
||||
* @ret data Value read
|
||||
*/
|
||||
#define inw_p( io_addr ) INX_P ( inw, uint16_t, io_addr )
|
||||
|
||||
/**
|
||||
* Read 32-bit dword from I/O-mapped device
|
||||
*
|
||||
* @v io_addr I/O address
|
||||
* @ret data Value read
|
||||
*/
|
||||
#define inl_p( io_addr ) INX_P ( inl, uint32_t, io_addr )
|
||||
|
||||
/**
|
||||
* Write value to I/O-mapped device, slowly
|
||||
*
|
||||
* @v _func Function to use to write value
|
||||
* @v data Value to write
|
||||
* @v io_addr I/O address
|
||||
*/
|
||||
#define OUTX_P( _func, data, io_addr ) do { \
|
||||
_func ( (data), (io_addr) ); \
|
||||
iodelay(); \
|
||||
} while ( 0 )
|
||||
|
||||
/**
|
||||
* Write byte to I/O-mapped device, slowly
|
||||
*
|
||||
* @v data Value to write
|
||||
* @v io_addr I/O address
|
||||
*/
|
||||
#define outb_p( data, io_addr ) OUTX_P ( outb, data, io_addr )
|
||||
|
||||
/**
|
||||
* Write 16-bit word to I/O-mapped device, slowly
|
||||
*
|
||||
* @v data Value to write
|
||||
* @v io_addr I/O address
|
||||
*/
|
||||
#define outw_p( data, io_addr ) OUTX_P ( outw, data, io_addr )
|
||||
|
||||
/**
|
||||
* Write 32-bit dword to I/O-mapped device, slowly
|
||||
*
|
||||
* @v data Value to write
|
||||
* @v io_addr I/O address
|
||||
*/
|
||||
#define outl_p( data, io_addr ) OUTX_P ( outl, data, io_addr )
|
||||
|
||||
/**
|
||||
* Memory barrier
|
||||
*
|
||||
*/
|
||||
void mb ( void );
|
||||
#define rmb() mb()
|
||||
#define wmb() mb()
|
||||
|
||||
#endif /* _GPXE_IO_H */
|
Reference in New Issue