123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443 |
- /*
- ** Support for NE2000 PCI clones added David Monro June 1997
- ** Generalised to other NICs by Ken Yap July 1997
- **
- ** Most of this is taken from:
- **
- ** /usr/src/linux/drivers/pci/pci.c
- ** /usr/src/linux/include/linux/pci.h
- ** /usr/src/linux/arch/i386/bios32.c
- ** /usr/src/linux/include/linux/bios32.h
- ** /usr/src/linux/drivers/net/ne.c
- */
- #include "etherboot.h"
- #include "init.h"
- #include "pci.h"
- #include "pci_io.h"
- #ifdef KEEP_IT_REAL
- #include "realmode.h"
- #endif
-
- #define DEBUG_PCI_IO
-
- #undef DBG
- #ifdef DEBUG_PCI_IO
- #define DBG(...) printf ( __VA_ARGS__ )
- #else
- #define DBG(...)
- #endif
-
- /* Macros for direct PCI access */
- #define CONFIG_ADDRESS 0xcf8
- #define CONFIG_DATA 0xcfc
- #define CONFIG_CMD( pci, where ) \
- ( 0x80000000 | (pci->busdevfn << 8) | (where & ~3) )
-
- /* Signatures for PCI BIOS */
- #define BIOS_SIG(a,b,c,d) ( ( a<<0 ) + ( b<<8 ) + ( c<<16 ) + ( d<<24 ) )
- #define PRINT_BIOS_SIG(x) ( (x) & 0xff ), ( ( (x)>>8 ) & 0xff ), \
- ( ( (x)>>16 ) & 0xff ),( ( (x)>>24 ) & 0xff )
- #define BIOS32_SIGNATURE BIOS_SIG ( '_', '3', '2', '_' )
- #define PCI_SIGNATURE BIOS_SIG ( 'P', 'C', 'I', ' ' )
- #define PCI_SERVICE BIOS_SIG ( '$', 'P', 'C', 'I' )
-
- /* BIOS32 structure as found in PCI BIOS ROM */
- struct bios32 {
- unsigned long signature; /* _32_ */
- unsigned long entry; /* 32 bit physical address */
- unsigned char revision; /* Revision level, 0 */
- unsigned char length; /* Length in paragraphs */
- unsigned char checksum; /* Should byte sum to zero */
- unsigned char reserved[5]; /* Must be zero */
- };
-
- /* Values returned by BIOS32 service directory */
- #define BIOS32_SERVICE_PRESENT 0x00
- #define BIOS32_SERVICE_NOT_PRESENT 0x80
- #define CF ( 1 << 0 )
-
- /* PCI BIOS entry point */
- #ifndef KEEP_IT_REAL
- static unsigned long pcibios32_entry;
- #endif
- static int have_pcibios;
-
- /* Macro for calling a 32-bit entry point with flat physical
- * addresses. Use in a statement such as
- * __asm__ ( FLAT_FAR_CALL_ESI,
- * : <output registers>
- * : "S" ( entry_point ), <other input registers> );
- */
- #define FLAT_FAR_CALL_ESI "call _virt_to_phys\n\t" \
- "pushl %%cs\n\t" \
- "call *%%esi\n\t" \
- "cli\n\t" \
- "cld\n\t" \
- "call _phys_to_virt\n\t"
-
- /*
- * Functions for accessing PCI configuration space directly with type
- * 1 accesses.
- *
- */
-
- static inline int pcidirect_read_config_byte ( struct pci_device *pci,
- unsigned int where,
- uint8_t *value ) {
- outl ( CONFIG_CMD ( pci, where ), CONFIG_ADDRESS );
- *value = inb ( CONFIG_DATA + ( where & 3 ) );
- return 0;
- }
-
- static inline int pcidirect_read_config_word ( struct pci_device *pci,
- unsigned int where,
- uint16_t *value ) {
- outl ( CONFIG_CMD ( pci, where ), CONFIG_ADDRESS );
- *value = inw ( CONFIG_DATA + ( where & 2 ) );
- return 0;
- }
-
- static inline int pcidirect_read_config_dword ( struct pci_device *pci,
- unsigned int where,
- uint32_t *value ) {
- outl ( CONFIG_CMD ( pci, where ), CONFIG_ADDRESS );
- *value = inl ( CONFIG_DATA );
- return 0;
- }
-
- static inline int pcidirect_write_config_byte ( struct pci_device *pci,
- unsigned int where,
- uint8_t value ) {
- outl ( CONFIG_CMD ( pci, where ), CONFIG_ADDRESS );
- outb ( value, CONFIG_DATA + ( where & 3 ) );
- return 0;
- }
-
- static inline int pcidirect_write_config_word ( struct pci_device *pci,
- unsigned int where,
- uint16_t value ) {
- outl ( CONFIG_CMD ( pci, where ), CONFIG_ADDRESS );
- outw ( value, CONFIG_DATA + ( where & 2 ) );
- return 0;
- }
-
- static inline int pcidirect_write_config_dword ( struct pci_device *pci,
- unsigned int where,
- uint32_t value ) {
- outl ( CONFIG_CMD ( pci, where ), CONFIG_ADDRESS );
- outl ( value, CONFIG_DATA );
- return 0;
- }
-
- /*
- * Functions for accessing PCI configuration space directly via the
- * PCI BIOS.
- *
- * Under -DKEEP_IT_REAL, we use INT 1A, otherwise we use the BIOS32
- * interface.
- */
-
- #ifdef KEEP_IT_REAL
-
- static void find_pcibios16 ( void ) {
- uint16_t present;
- uint32_t signature;
- uint16_t flags;
- uint16_t revision;
-
- /* PCI BIOS installation check */
- REAL_EXEC ( rm_pcibios_check,
- "int $0x1a\n\t"
- "pushfw\n\t"
- "popw %%cx\n\t",
- 4,
- OUT_CONSTRAINTS ( "=a" ( present ), "=b" ( revision ),
- "=c" ( flags ), "=d" ( signature ) ),
- IN_CONSTRAINTS ( "a" ( ( PCIBIOS_PCI_FUNCTION_ID << 8 ) +
- PCIBIOS_PCI_BIOS_PRESENT ) ),
- CLOBBER ( "esi", "edi", "ebp" ) );
-
- if ( ( flags & CF ) ||
- ( ( present >> 8 ) != 0 ) ||
- ( signature != PCI_SIGNATURE ) ) {
- DBG ( "PCI BIOS installation check failed\n" );
- return;
- }
-
- /* We have a PCI BIOS */
- have_pcibios = 1;
- return;
- }
-
- INIT_FN ( INIT_PCIBIOS, find_pcibios16, NULL, NULL );
-
- #define pcibios16_read_write( command, pci, where, value ) \
- ( { \
- uint32_t discard_b, discard_D; \
- uint16_t ret; \
- \
- REAL_EXEC ( 999, /* need a local label */ \
- "int $0x1a\n\t" \
- "jc 1f\n\t" \
- "xorw %%ax, %%ax\n\t" \
- "\n1:\n\t", \
- 5, \
- OUT_CONSTRAINTS ( "=a" ( ret ), \
- "=b" ( discard_b ), \
- "=c" ( value ), \
- "=D" ( discard_D ) ), \
- IN_CONSTRAINTS ( "a" ( command + \
- ( PCIBIOS_PCI_FUNCTION_ID << 8 ) ), \
- "b" ( pci->busdevfn ), \
- "c" ( value ), \
- "D" ( where ) ), \
- CLOBBER ( "edx", "esi", "ebp" ) ); \
- \
- ( ret >> 8 ); \
- } )
- #define pcibios_read_write pcibios16_read_write
-
- #else /* KEEP_IT_REAL */
-
- /*
- * Locate the BIOS32 service directory by scanning for a valid BIOS32
- * structure
- *
- */
- static struct bios32 * find_bios32 ( void ) {
- uint32_t address;
-
- /*
- * Follow the standard procedure for locating the BIOS32 Service
- * directory by scanning the permissible address range from
- * 0xe0000 through 0xfffff for a valid BIOS32 structure.
- *
- */
- for ( address = 0xe0000 ; address < 0xffff0 ; address += 16 ) {
- struct bios32 * candidate = phys_to_virt ( address );
- unsigned int length, i;
- unsigned char sum;
-
- if ( candidate->signature != BIOS32_SIGNATURE )
- continue;
-
- length = candidate->length * 16;
- if ( ! length )
- continue;
-
- for ( sum = 0, i = 0 ; i < length ; i++ )
- sum += ( ( char * ) candidate ) [i];
- if ( sum != 0 )
- continue;
-
- if ( candidate->revision != 0 ) {
- DBG ( "unsupported BIOS32 revision %d at %#x\n",
- candidate->revision, address );
- continue;
- }
-
- DBG ( "BIOS32 Service Directory structure at %#x\n", address );
-
- return candidate;
- }
-
- return NULL;
- }
-
- /*
- * Look up a service in the BIOS32 service directory
- *
- */
- static unsigned long find_bios32_service ( struct bios32 * bios32,
- unsigned long service ) {
- uint8_t return_code;
- uint32_t address;
- uint32_t length;
- uint32_t entry;
- uint32_t discard;
-
- __asm__ ( FLAT_FAR_CALL_ESI
- : "=a" ( return_code ), "=b" ( address ),
- "=c" ( length ), "=d" ( entry ), "=S" ( discard )
- : "a" ( service ), "b" ( 0 ), "S" ( bios32->entry )
- : "edi", "ebp" );
-
- switch ( return_code ) {
- case BIOS32_SERVICE_PRESENT:
- return ( address + entry );
- case BIOS32_SERVICE_NOT_PRESENT:
- DBG ( "BIOS32 service %c%c%c%c : not present\n",
- PRINT_BIOS_SIG ( service ) );
- return 0;
- default: /* Shouldn't happen */
- DBG ( "BIOS32 returned %#x for service %c%c%c%c!\n",
- return_code, PRINT_BIOS_SIG ( service ) );
- return 0;
- }
- }
-
- static void find_pcibios32 ( void ) {
- struct bios32 *bios32;
- uint32_t signature;
- uint16_t present;
- uint32_t flags;
- uint16_t revision;
- uint32_t discard;
-
- /* Locate BIOS32 service directory */
- bios32 = find_bios32 ();
- if ( ! bios32 ) {
- DBG ( "No BIOS32\n" );
- return;
- }
-
- /* Locate PCI BIOS service */
- pcibios32_entry = find_bios32_service ( bios32, PCI_SERVICE );
- if ( ! pcibios32_entry ) {
- DBG ( "No PCI BIOS\n" );
- return;
- }
-
- /* PCI BIOS installation check */
- __asm__ ( FLAT_FAR_CALL_ESI
- "pushfl\n\t"
- "popl %%ecx\n\t"
- : "=a" ( present ), "=b" ( revision ), "=c" ( flags ),
- "=d" ( signature ), "=S" ( discard )
- : "a" ( ( PCIBIOS_PCI_FUNCTION_ID << 8 )
- + PCIBIOS_PCI_BIOS_PRESENT ),
- "S" ( pcibios32_entry )
- : "edi", "ebp" );
-
- if ( ( flags & CF ) ||
- ( ( present >> 8 ) != 0 ) ||
- ( signature != PCI_SIGNATURE ) ) {
- DBG ( "PCI BIOS installation check failed\n" );
- return;
- }
-
- /* We have a PCI BIOS */
- have_pcibios = 1;
- return;
- }
-
- INIT_FN ( INIT_PCIBIOS, find_pcibios32, NULL, NULL );
-
- #define pcibios32_read_write( command, pci, where, value ) \
- ( { \
- uint32_t discard_b, discard_D, discard_S; \
- uint16_t ret; \
- \
- __asm__ ( FLAT_FAR_CALL_ESI \
- "jc 1f\n\t" \
- "xorl %%eax, %%eax\n\t" \
- "\n1:\n\t" \
- : "=a" ( ret ), "=b" ( discard_b ), \
- "=c" ( value ), \
- "=S" ( discard_S ), "=D" ( discard_D ) \
- : "a" ( ( PCIBIOS_PCI_FUNCTION_ID << 8 ) \
- + command ), \
- "b" ( pci->busdevfn ), "c" ( value ), \
- "D" ( where ), "S" ( pcibios32_entry ) \
- : "edx", "ebp" ); \
- \
- ( ret >> 8 ); \
- } )
- #define pcibios_read_write pcibios32_read_write
-
- #endif /* KEEP_IT_REAL */
-
- static inline int pcibios_read_config_byte ( struct pci_device *pci,
- unsigned int where,
- uint8_t *value ) {
- return pcibios_read_write ( PCIBIOS_READ_CONFIG_BYTE,
- pci, where, *value );
- }
-
- static inline int pcibios_read_config_word ( struct pci_device *pci,
- unsigned int where,
- uint16_t *value ) {
- return pcibios_read_write ( PCIBIOS_READ_CONFIG_WORD,
- pci, where, *value );
- }
-
- static inline int pcibios_read_config_dword ( struct pci_device *pci,
- unsigned int where,
- uint32_t *value ) {
- return pcibios_read_write ( PCIBIOS_READ_CONFIG_DWORD,
- pci, where, *value );
- }
-
- static inline int pcibios_write_config_byte ( struct pci_device *pci,
- unsigned int where,
- uint8_t value ) {
- return pcibios_read_write ( PCIBIOS_WRITE_CONFIG_BYTE,
- pci, where, value );
- }
-
- static inline int pcibios_write_config_word ( struct pci_device *pci,
- unsigned int where,
- uint16_t value ) {
- return pcibios_read_write ( PCIBIOS_WRITE_CONFIG_WORD,
- pci, where, value );
- }
-
- static inline int pcibios_write_config_dword ( struct pci_device *pci,
- unsigned int where,
- uint32_t value ) {
- return pcibios_read_write ( PCIBIOS_WRITE_CONFIG_DWORD,
- pci, where, value );
- }
-
- /*
- * Functions for accessing PCI configuration space via the PCI BIOS if
- * present, otherwise directly via type 1 accesses.
- *
- */
-
- int pci_read_config_byte ( struct pci_device *pci, unsigned int where,
- uint8_t *value ) {
- return have_pcibios ?
- pcibios_read_config_byte ( pci, where, value ) :
- pcidirect_read_config_byte ( pci, where, value );
- }
-
- int pci_read_config_word ( struct pci_device *pci, unsigned int where,
- uint16_t *value ) {
- return have_pcibios ?
- pcibios_read_config_word ( pci, where, value ) :
- pcidirect_read_config_word ( pci, where, value );
- }
-
- int pci_read_config_dword ( struct pci_device *pci, unsigned int where,
- uint32_t *value ) {
- return have_pcibios ?
- pcibios_read_config_dword ( pci, where, value ) :
- pcidirect_read_config_dword ( pci, where, value );
- }
-
- int pci_write_config_byte ( struct pci_device *pci, unsigned int where,
- uint8_t value ) {
- return have_pcibios ?
- pcibios_write_config_byte ( pci, where, value ) :
- pcidirect_write_config_byte ( pci, where, value );
- }
-
- int pci_write_config_word ( struct pci_device *pci, unsigned int where,
- uint16_t value ) {
- return have_pcibios ?
- pcibios_write_config_word ( pci, where, value ) :
- pcidirect_write_config_word ( pci, where, value );
- }
-
- int pci_write_config_dword ( struct pci_device *pci, unsigned int where,
- uint32_t value ) {
- return have_pcibios ?
- pcibios_write_config_dword ( pci, where, value ) :
- pcidirect_write_config_dword ( pci, where, value );
- }
-
- unsigned long pci_bus_base ( struct pci_device *pci __unused ) {
- /* architecturally this must be 0 */
- return 0;
- }
|