Strip down i386 PCI configuration space I/O to the bare minimum. A
authorMichael Brown <mcb30@etherboot.org>
Wed, 17 May 2006 01:12:11 +0000 (01:12 +0000)
committerMichael Brown <mcb30@etherboot.org>
Wed, 17 May 2006 01:12:11 +0000 (01:12 +0000)
typical build will now include 880 bytes of PCI support code, compared to
2327 bytes in Etherboot 5.4.

(There is a slight cost of around 5 extra bytes per access to a
non-constant config space address; this should be an overall win.
Driver-specific accesses will usually be to constant addresses, for
which there is no additional cost.)

src/arch/i386/core/pci_io.c [deleted file]
src/arch/i386/core/pcibios.c [new file with mode: 0644]
src/arch/i386/core/pcidirect.c [new file with mode: 0644]
src/arch/i386/include/pci_io.h
src/arch/i386/include/pcibios.h [new file with mode: 0644]
src/arch/i386/include/pcidirect.h [new file with mode: 0644]
src/drivers/bus/pci.c
src/include/gpxe/pci.h

diff --git a/src/arch/i386/core/pci_io.c b/src/arch/i386/core/pci_io.c
deleted file mode 100644 (file)
index 2f3a9ac..0000000
+++ /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 <gpxe/init.h>
-#include <gpxe/pci.h>
-#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 ), <other output registers>
- *          : "S" ( entry_point ), <other input registers> );
- * "=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 (file)
index 0000000..390a587
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2006 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 <stdint.h>
+#include <gpxe/pci.h>
+#include <pcibios.h>
+#include <realmode.h>
+
+/** @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 (file)
index 0000000..2ed8c2a
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2006 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/pci.h>
+#include <pcidirect.h>
+
+/** @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 );
+}
+
index dce45b1..4888d55 100644 (file)
@@ -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 <pcibios.h>
+#include <pcidirect.h>
 
-#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 (file)
index 0000000..dcbffed
--- /dev/null
@@ -0,0 +1,122 @@
+#ifndef _PCIBIOS_H
+#define _PCIBIOS_H
+
+#include <stdint.h>
+
+/** @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 (file)
index 0000000..80e1401
--- /dev/null
@@ -0,0 +1,126 @@
+#ifndef _PCIDIRECT_H
+#define _PCIDIRECT_H
+
+#include <stdint.h>
+#include <io.h>
+
+/** @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 */
index 853dda6..222f3ee 100644 (file)
@@ -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 */
index 28fa93c..5fc2100 100644 (file)
@@ -19,6 +19,7 @@
 #include <stdint.h>
 #include <gpxe/device.h>
 #include <gpxe/tables.h>
+#include <pci_io.h>
 #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 );