diff --git a/src/arch/i386/core/pci_io.c b/src/arch/i386/core/pci_io.c deleted file mode 100644 index 2f3a9ac0..00000000 --- a/src/arch/i386/core/pci_io.c +++ /dev/null @@ -1,451 +0,0 @@ -/* -** 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 -#include -#include "pci_io.h" -#ifdef KEEP_IT_REAL -#include "realmode.h" -#endif - -/* Macros for direct PCI access */ -#define CONFIG_ADDRESS 0xcf8 -#define CONFIG_DATA 0xcfc -#define CONFIG_CMD( pci, where ) \ - ( 0x80000000 | ( pci->bus << 16 ) | ( pci->devfn << 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, - * : "=S" ( discard, or real output ), - * : "S" ( entry_point ), ); - * "=S" *must* be specified as an output, otherwise the compiler will - * assume that it remains unaltered. - */ -#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; - uint8_t max_bus; - - /* PCI BIOS installation check */ - REAL_EXEC ( rm_pcibios_check, - "int $0x1a\n\t" - "pushfw\n\t" - "popw %%si\n\t", - 5, - OUT_CONSTRAINTS ( "=a" ( present ), "=b" ( revision ), - "=c" ( max_bus ), "=d" ( signature ), - "=S" ( flags ) ), - IN_CONSTRAINTS ( "a" ( ( PCIBIOS_PCI_FUNCTION_ID << 8 ) + - PCIBIOS_PCI_BIOS_PRESENT ) ), - CLOBBER ( "edi", "ebp" ) ); - - if ( ( flags & CF ) || - ( ( present >> 8 ) != 0 ) || - ( signature != PCI_SIGNATURE ) ) { - DBG ( "PCI BIOS installation check failed\n" ); - return; - } - - /* We have a PCI BIOS */ - DBG ( "Found 16-bit PCI BIOS interface with %d buses\n", max_bus + 1 ); - have_pcibios = 1; - pci_max_bus = max_bus; - 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: - DBG ( "BIOS32 service %c%c%c%c present at %#x\n", - PRINT_BIOS_SIG ( service ), ( address + entry ) ); - 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; - } -} - -/* - * Find the 32-bit PCI BIOS interface, if present. - * - */ -static void find_pcibios32 ( void ) { - struct bios32 *bios32; - uint32_t signature; - uint16_t present; - uint32_t flags; - uint16_t revision; - uint8_t max_bus; - - /* 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 %%esi\n\t" - : "=a" ( present ), "=b" ( revision ), "=c" ( max_bus ), - "=d" ( signature ), "=S" ( flags ) - : "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 */ - DBG ( "Found 32-bit PCI BIOS interface at %#x with %d bus(es)\n", - pcibios32_entry, max_bus + 1 ); - have_pcibios = 1; - pci_max_bus = max_bus; - 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->bus << 8 ) | pci->devfn ), \ - "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; -} diff --git a/src/arch/i386/core/pcibios.c b/src/arch/i386/core/pcibios.c new file mode 100644 index 00000000..390a5878 --- /dev/null +++ b/src/arch/i386/core/pcibios.c @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2006 Michael Brown . + * + * 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 +#include +#include +#include + +/** @file + * + * PCI configuration space access via PCI BIOS + * + */ + +/** + * Determine maximum PCI bus number within system + * + * @ret max_bus Maximum bus number + */ +int pcibios_max_bus ( void ) { + int discard_a; + uint8_t max_bus; + + REAL_EXEC ( rm_pcibios_check, + "stc\n\t" + "int $0x1a\n\t" + "jnc 1f\n\t" + "xorw %%cx, %%cx\n\t" + "\n1:\n\t", + 2, + OUT_CONSTRAINTS ( "=a" ( discard_a ), "=c" ( max_bus ) ), + IN_CONSTRAINTS ( "a" ( PCIBIOS_INSTALLATION_CHECK >> 16 )), + CLOBBER ( "ebx", "edx", "edi" ) ); + + return max_bus; +} + +/** + * Read configuration space via PCI BIOS + * + * @v pci PCI device + * @v command PCI BIOS command + * @v value Value read + * @ret rc Return status code + */ +int pcibios_read ( struct pci_device *pci, uint32_t command, uint32_t *value ){ + int discard_b, discard_D; + int status; + + REAL_EXEC ( rm_pcibios_read, + "stc\n\t" + "int $0x1a\n\t" + "jnc 1f\n\t" + "xorl %%eax, %%eax\n\t" + "decl %%eax\n\t" + "movl %%eax, %%ecx\n\t" + "\n1:\n\t", + 4, + OUT_CONSTRAINTS ( "=a" ( status ), "=b" ( discard_b ), + "=c" ( *value ), "=D" ( discard_D ) ), + IN_CONSTRAINTS ( "a" ( command >> 16 ), + "b" ( ( pci->bus << 8 ) | pci->devfn ), + "D" ( command ) ), + CLOBBER ( "edx" ) ); + + return ( ( status >> 8 ) & 0xff ); +} + +/** + * Write configuration space via PCI BIOS + * + * @v pci PCI device + * @v command PCI BIOS command + * @v value Value to be written + * @ret rc Return status code + */ +int pcibios_write ( struct pci_device *pci, uint32_t command, uint32_t value ){ + int discard_b, discard_c, discard_D; + int status; + + REAL_EXEC ( rm_pcibios_write, + "stc\n\t" + "int $0x1a\n\t" + "jnc 1f\n\t" + "movb $0xff, %%ah\n\t" + "\n1:\n\t", + 4, + OUT_CONSTRAINTS ( "=a" ( status ), "=b" ( discard_b ), + "=c" ( discard_c ), "=D" ( discard_D ) ), + IN_CONSTRAINTS ( "a" ( command >> 16 ), + "b" ( ( pci->bus << 8 ) | pci->devfn ), + "c" ( value ), "D" ( command ) ), + CLOBBER ( "edx" ) ); + + return ( ( status >> 8 ) & 0xff ); +} diff --git a/src/arch/i386/core/pcidirect.c b/src/arch/i386/core/pcidirect.c new file mode 100644 index 00000000..2ed8c2ad --- /dev/null +++ b/src/arch/i386/core/pcidirect.c @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2006 Michael Brown . + * + * 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 +#include + +/** @file + * + * PCI configuration space access via Type 1 accesses + * + */ + +/** + * Prepare for Type 1 PCI configuration space access + * + * @v pci PCI device + * @v where Location within PCI configuration space + */ +void pcidirect_prepare ( struct pci_device *pci, int where ) { + outl ( ( 0x80000000 | ( pci->bus << 16 ) | ( pci->devfn << 8 ) | + ( where & ~3 ) ), PCIDIRECT_CONFIG_ADDRESS ); +} + diff --git a/src/arch/i386/include/pci_io.h b/src/arch/i386/include/pci_io.h index dce45b13..4888d557 100644 --- a/src/arch/i386/include/pci_io.h +++ b/src/arch/i386/include/pci_io.h @@ -1,20 +1,35 @@ -#ifndef PCI_IO_H -#define PCI_IO_H +#ifndef _PCI_IO_H +#define _PCI_IO_H -/* %ah */ -#define PCIBIOS_PCI_FUNCTION_ID ( 0xb1 ) -/* %al */ -#define PCIBIOS_PCI_BIOS_PRESENT ( 0x01 ) -#define PCIBIOS_FIND_PCI_DEVICE ( 0x02 ) -#define PCIBIOS_FIND_PCI_CLASS_CODE ( 0x03 ) -#define PCIBIOS_GENERATE_SPECIAL_CYCLE ( 0x06 ) -#define PCIBIOS_READ_CONFIG_BYTE ( 0x08 ) -#define PCIBIOS_READ_CONFIG_WORD ( 0x09 ) -#define PCIBIOS_READ_CONFIG_DWORD ( 0x0a ) -#define PCIBIOS_WRITE_CONFIG_BYTE ( 0x0b ) -#define PCIBIOS_WRITE_CONFIG_WORD ( 0x0c ) -#define PCIBIOS_WRITE_CONFIG_DWORD ( 0x0d ) -#define PCIBIOS_GET_IRQ_ROUTING_OPTIONS ( 0x0e ) -#define PCIBIOS_SET_PCI_IRQ ( 0x0f ) +#include +#include -#endif /* PCI_IO_H */ +/** @file + * + * i386 PCI configuration space access + * + * We have two methods of PCI configuration space access: the PCI BIOS + * and direct Type 1 accesses. Selecting between them is via the + * compile-time switch -DCONFIG_PCI_DIRECT. + * + */ + +#if CONFIG_PCI_DIRECT +#define pci_max_bus pcidirect_max_bus +#define pci_read_config_byte pcidirect_read_config_byte +#define pci_read_config_word pcidirect_read_config_word +#define pci_read_config_dword pcidirect_read_config_dword +#define pci_write_config_byte pcidirect_write_config_byte +#define pci_write_config_word pcidirect_write_config_word +#define pci_write_config_dword pcidirect_write_config_dword +#else /* CONFIG_PCI_DIRECT */ +#define pci_max_bus pcibios_max_bus +#define pci_read_config_byte pcibios_read_config_byte +#define pci_read_config_word pcibios_read_config_word +#define pci_read_config_dword pcibios_read_config_dword +#define pci_write_config_byte pcibios_write_config_byte +#define pci_write_config_word pcibios_write_config_word +#define pci_write_config_dword pcibios_write_config_dword +#endif /* CONFIG_PCI_DIRECT */ + +#endif /* _PCI_IO_H */ diff --git a/src/arch/i386/include/pcibios.h b/src/arch/i386/include/pcibios.h new file mode 100644 index 00000000..dcbffedc --- /dev/null +++ b/src/arch/i386/include/pcibios.h @@ -0,0 +1,122 @@ +#ifndef _PCIBIOS_H +#define _PCIBIOS_H + +#include + +/** @file + * + * PCI configuration space access via PCI BIOS + * + */ + +struct pci_device; + +#define PCIBIOS_INSTALLATION_CHECK 0xb1010000 +#define PCIBIOS_READ_CONFIG_BYTE 0xb1080000 +#define PCIBIOS_READ_CONFIG_WORD 0xb1090000 +#define PCIBIOS_READ_CONFIG_DWORD 0xb10a0000 +#define PCIBIOS_WRITE_CONFIG_BYTE 0xb10b0000 +#define PCIBIOS_WRITE_CONFIG_WORD 0xb10c0000 +#define PCIBIOS_WRITE_CONFIG_DWORD 0xb10d0000 + +extern int pcibios_max_bus ( void ); +extern int pcibios_read ( struct pci_device *pci, uint32_t command, + uint32_t *value ); +extern int pcibios_write ( struct pci_device *pci, uint32_t command, + uint32_t value ); + +/** + * Read byte from PCI configuration space via PCI BIOS + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value read + * @ret rc Return status code + */ +static inline __attribute__ (( always_inline )) int +pcibios_read_config_byte ( struct pci_device *pci, unsigned int where, + uint8_t *value ) { + uint32_t tmp; + int rc; + + rc = pcibios_read ( pci, PCIBIOS_READ_CONFIG_BYTE | where, &tmp ); + *value = tmp; + return rc; +} + +/** + * Read word from PCI configuration space via PCI BIOS + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value read + * @ret rc Return status code + */ +static inline __attribute__ (( always_inline )) int +pcibios_read_config_word ( struct pci_device *pci, unsigned int where, + uint16_t *value ) { + uint32_t tmp; + int rc; + + rc = pcibios_read ( pci, PCIBIOS_READ_CONFIG_WORD | where, &tmp ); + *value = tmp; + return rc; +} + +/** + * Read dword from PCI configuration space via PCI BIOS + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value read + * @ret rc Return status code + */ +static inline __attribute__ (( always_inline )) int +pcibios_read_config_dword ( struct pci_device *pci, unsigned int where, + uint32_t *value ) { + return pcibios_read ( pci, PCIBIOS_READ_CONFIG_DWORD | where, value ); +} + +/** + * Write byte to PCI configuration space via PCI BIOS + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value to be written + * @ret rc Return status code + */ +static inline __attribute__ (( always_inline )) int +pcibios_write_config_byte ( struct pci_device *pci, unsigned int where, + uint8_t value ) { + return pcibios_write ( pci, PCIBIOS_WRITE_CONFIG_BYTE | where, value ); +} + +/** + * Write word to PCI configuration space via PCI BIOS + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value to be written + * @ret rc Return status code + */ +static inline __attribute__ (( always_inline )) int +pcibios_write_config_word ( struct pci_device *pci, unsigned int where, + uint16_t value ) { + return pcibios_write ( pci, PCIBIOS_WRITE_CONFIG_BYTE | where, value ); +} + +/** + * Write dword to PCI configuration space via PCI BIOS + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value to be written + * @ret rc Return status code + */ +static inline __attribute__ (( always_inline )) int +pcibios_write_config_dword ( struct pci_device *pci, unsigned int where, + uint32_t value ) { + return pcibios_write ( pci, PCIBIOS_WRITE_CONFIG_BYTE | where, value ); +} + +#endif /* _PCIBIOS_H */ diff --git a/src/arch/i386/include/pcidirect.h b/src/arch/i386/include/pcidirect.h new file mode 100644 index 00000000..80e14019 --- /dev/null +++ b/src/arch/i386/include/pcidirect.h @@ -0,0 +1,126 @@ +#ifndef _PCIDIRECT_H +#define _PCIDIRECT_H + +#include +#include + +/** @file + * + * PCI configuration space access via Type 1 accesses + * + */ + +#define PCIDIRECT_CONFIG_ADDRESS 0xcf8 +#define PCIDIRECT_CONFIG_DATA 0xcfc + +struct pci_device; + +extern void pcidirect_prepare ( struct pci_device *pci, int where ); + +/** + * Determine maximum PCI bus number within system + * + * @ret max_bus Maximum bus number + */ +static inline int pcidirect_max_bus ( void ) { + /* No way to work this out via Type 1 accesses */ + return 0xff; +} + +/** + * Read byte from PCI configuration space via Type 1 access + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value read + * @ret rc Return status code + */ +static inline __attribute__ (( always_inline )) int +pcidirect_read_config_byte ( struct pci_device *pci, unsigned int where, + uint8_t *value ) { + pcidirect_prepare ( pci, where ); + *value = inb ( PCIDIRECT_CONFIG_DATA + ( where & 3 ) ); + return 0; +} + +/** + * Read word from PCI configuration space via Type 1 access + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value read + * @ret rc Return status code + */ +static inline __attribute__ (( always_inline )) int +pcidirect_read_config_word ( struct pci_device *pci, unsigned int where, + uint16_t *value ) { + pcidirect_prepare ( pci, where ); + *value = inw ( PCIDIRECT_CONFIG_DATA + ( where & 2 ) ); + return 0; +} + +/** + * Read dword from PCI configuration space via Type 1 access + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value read + * @ret rc Return status code + */ +static inline __attribute__ (( always_inline )) int +pcidirect_read_config_dword ( struct pci_device *pci, unsigned int where, + uint32_t *value ) { + pcidirect_prepare ( pci, where ); + *value = inl ( PCIDIRECT_CONFIG_DATA + where ); + return 0; +} + +/** + * Write byte to PCI configuration space via Type 1 access + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value to be written + * @ret rc Return status code + */ +static inline __attribute__ (( always_inline )) int +pcidirect_write_config_byte ( struct pci_device *pci, unsigned int where, + uint8_t value ) { + pcidirect_prepare ( pci, where ); + outb ( value, PCIDIRECT_CONFIG_DATA + ( where & 3 ) ); + return 0; +} + +/** + * Write word to PCI configuration space via Type 1 access + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value to be written + * @ret rc Return status code + */ +static inline __attribute__ (( always_inline )) int +pcidirect_write_config_word ( struct pci_device *pci, unsigned int where, + uint16_t value ) { + pcidirect_prepare ( pci, where ); + outb ( value, PCIDIRECT_CONFIG_DATA + ( where & 2 ) ); + return 0; +} + +/** + * Write dword to PCI configuration space via Type 1 access + * + * @v pci PCI device + * @v where Location within PCI configuration space + * @v value Value to be written + * @ret rc Return status code + */ +static inline __attribute__ (( always_inline )) int +pcidirect_write_config_dword ( struct pci_device *pci, unsigned int where, + uint32_t value ) { + pcidirect_prepare ( pci, where ); + outb ( value, PCIDIRECT_CONFIG_DATA + where ); + return 0; +} + +#endif /* _PCIDIRECT_H */ diff --git a/src/drivers/bus/pci.c b/src/drivers/bus/pci.c index 853dda64..222f3eea 100644 --- a/src/drivers/bus/pci.c +++ b/src/drivers/bus/pci.c @@ -38,15 +38,6 @@ static struct pci_driver pci_drivers_end[0] __table_end ( pci_drivers ); static void pcibus_remove ( struct root_device *rootdev ); -/** - * Maximum PCI bus number - * - * Architecture-specific code may know how many buses we have, in - * which case it can overwrite this value. - * - */ -unsigned int pci_max_bus = 0xff; - /** * Read PCI BAR * @@ -242,13 +233,15 @@ static void unregister_pcidev ( struct pci_device *pci ) { */ static int pcibus_probe ( struct root_device *rootdev ) { struct pci_device *pci = NULL; + unsigned int max_bus; unsigned int bus; unsigned int devfn; - uint8_t hdrtype; + uint8_t hdrtype = 0; uint32_t tmp; int rc; - for ( bus = 0 ; bus <= pci_max_bus ; bus++ ) { + max_bus = pci_max_bus(); + for ( bus = 0 ; bus <= max_bus ; bus++ ) { for ( devfn = 0 ; devfn <= 0xff ; devfn++ ) { /* Allocate struct pci_device */ diff --git a/src/include/gpxe/pci.h b/src/include/gpxe/pci.h index 28fa93c5..5fc21009 100644 --- a/src/include/gpxe/pci.h +++ b/src/include/gpxe/pci.h @@ -19,6 +19,7 @@ #include #include #include +#include #include "pci_ids.h" /* @@ -318,19 +319,6 @@ struct pci_driver { .name = _name, \ } -extern unsigned int pci_max_bus; -extern int pci_read_config_byte ( struct pci_device *pci, unsigned int where, - uint8_t *value ); -extern int pci_write_config_byte ( struct pci_device *pci, unsigned int where, - uint8_t value ); -extern int pci_read_config_word ( struct pci_device *pci, unsigned int where, - uint16_t *value ); -extern int pci_write_config_word ( struct pci_device *pci, unsigned int where, - uint16_t value ); -extern int pci_read_config_dword ( struct pci_device *pci, unsigned int where, - uint32_t *value ); -extern int pci_write_config_dword ( struct pci_device *pci, unsigned int where, - uint32_t value ); extern void adjust_pci_device ( struct pci_device *pci ); extern unsigned long pci_bar_start ( struct pci_device *pci, unsigned int reg );