patch-2.1.54 linux/arch/i386/kernel/bios32.c

Next file: linux/arch/i386/kernel/irq.c
Previous file: linux/arch/i386/defconfig
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.53/linux/arch/i386/kernel/bios32.c linux/arch/i386/kernel/bios32.c
@@ -1,7 +1,7 @@
 /*
  * bios32.c - BIOS32, PCI BIOS functions.
  *
- * $Id: bios32.c,v 1.12 1997/06/26 13:33:46 mj Exp $
+ * $Id: bios32.c,v 1.14 1997/08/02 22:20:57 mj Exp $
  *
  * Sponsored by
  *	iX Multiuser Multitasking Magazine
@@ -61,6 +61,9 @@
  * 
  * Jun 20, 1997 : Corrected problems in "conf1" type accesses.
  *      (paubert@iram.es)
+ *
+ * Aug 2,  1997 : Split to PCI BIOS handling and direct PCI access parts
+ *	and cleaned it up...     Martin Mares <mj@atrey.karlin.mff.cuni.cz>
  */
 
 #include <linux/config.h>
@@ -75,69 +78,12 @@
 #include <asm/system.h>
 #include <asm/io.h>
 
-#define PCIBIOS_PCI_FUNCTION_ID 	0xb1XX
-#define PCIBIOS_PCI_BIOS_PRESENT 	0xb101
-#define PCIBIOS_FIND_PCI_DEVICE		0xb102
-#define PCIBIOS_FIND_PCI_CLASS_CODE	0xb103
-#define PCIBIOS_GENERATE_SPECIAL_CYCLE	0xb106
-#define PCIBIOS_READ_CONFIG_BYTE	0xb108
-#define PCIBIOS_READ_CONFIG_WORD	0xb109
-#define PCIBIOS_READ_CONFIG_DWORD	0xb10a
-#define PCIBIOS_WRITE_CONFIG_BYTE	0xb10b
-#define PCIBIOS_WRITE_CONFIG_WORD	0xb10c
-#define PCIBIOS_WRITE_CONFIG_DWORD	0xb10d
-
-
-/* BIOS32 signature: "_32_" */
-#define BIOS32_SIGNATURE	(('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24))
-
-/* PCI signature: "PCI " */
-#define PCI_SIGNATURE		(('P' << 0) + ('C' << 8) + ('I' << 16) + (' ' << 24))
-
-/* PCI service signature: "$PCI" */
-#define PCI_SERVICE		(('$' << 0) + ('P' << 8) + ('C' << 16) + ('I' << 24))
-
 /*
- * This is the standard structure used to identify the entry point
- * to the BIOS32 Service Directory, as documented in
- * 	Standard BIOS 32-bit Service Directory Proposal
- * 	Revision 0.4 May 24, 1993
- * 	Phoenix Technologies Ltd.
- *	Norwood, MA
- * and the PCI BIOS specification.
+ * Generic PCI access -- indirect calls according to detected HW.
  */
 
-union bios32 {
-	struct {
-		unsigned long signature;	/* _32_ */
-		unsigned long entry;		/* 32 bit physical address */
-		unsigned char revision;		/* Revision level, 0 */
-		unsigned char length;		/* Length in paragraphs should be 01 */
-		unsigned char checksum;		/* All bytes must add up to zero */
-		unsigned char reserved[5]; 	/* Must be zero */
-	} fields;
-	char chars[16];
-};
-
-#ifdef CONFIG_PCI
-/*
- * Physical address of the service directory.  I don't know if we're
- * allowed to have more than one of these or not, so just in case
- * we'll make pcibios_present() take a memory start parameter and store
- * the array there.
- */
-
-static unsigned long bios32_entry = 0;
-static struct {
-	unsigned long address;
-	unsigned short segment;
-} bios32_indirect = { 0, KERNEL_CS };
-
-
-/*
- * function table for accessing PCI configuration space
- */
 struct pci_access {
+    int pci_present;
     int (*find_device)(unsigned short, unsigned short, unsigned short, unsigned char *, unsigned char *);
     int (*find_class)(unsigned int, unsigned short, unsigned char *, unsigned char *);
     int (*read_config_byte)(unsigned char, unsigned char, unsigned char, unsigned char *);
@@ -148,363 +94,137 @@
     int (*write_config_dword)(unsigned char, unsigned char, unsigned char, unsigned int);
 };
 
-/*
- * pointer to selected PCI access function table
- */
-static struct pci_access *access_pci = NULL;
-
-
-
-/*
- * Returns the entry point for the given service, NULL on error
- */
-
-static unsigned long bios32_service(unsigned long service)
+static int pci_stub(void)
 {
-	unsigned char return_code;	/* %al */
-	unsigned long address;		/* %ebx */
-	unsigned long length;		/* %ecx */
-	unsigned long entry;		/* %edx */
-	unsigned long flags;
-
-	save_flags(flags); cli();
-	__asm__("lcall (%%edi)"
-		: "=a" (return_code),
-		  "=b" (address),
-		  "=c" (length),
-		  "=d" (entry)
-		: "0" (service),
-		  "1" (0),
-		  "D" (&bios32_indirect));
-	restore_flags(flags);
-
-	switch (return_code) {
-		case 0:
-			return address + entry;
-		case 0x80:	/* Not present */
-			printk("bios32_service(0x%lx) : not present\n", service);
-			return 0;
-		default: /* Shouldn't happen */
-			printk("bios32_service(0x%lx) : returned 0x%x, mail drew@colorado.edu\n",
-				service, return_code);
-			return 0;
-	}
+	return PCIBIOS_FUNC_NOT_SUPPORTED;
 }
 
-static long pcibios_entry = 0;
-static struct {
-	unsigned long address;
-	unsigned short segment;
-} pci_indirect = { 0, KERNEL_CS };
+static struct pci_access pci_access_none = {
+	0,		   		/* No PCI present */
+	(void *) pci_stub,	        /* No functions implemented */
+	(void *) pci_stub,
+	(void *) pci_stub,
+	(void *) pci_stub,
+	(void *) pci_stub,
+	(void *) pci_stub,
+	(void *) pci_stub,
+	(void *) pci_stub
+};
 
+static struct pci_access *access_pci = &pci_access_none;
 
-__initfunc(static int check_pcibios(void))
+int pcibios_present(void)
 {
-	unsigned long signature;
-	unsigned char present_status;
-	unsigned char major_revision;
-	unsigned char minor_revision;
-	unsigned long flags;
-	int pack;
-
-	if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
-		pci_indirect.address = pcibios_entry | PAGE_OFFSET;
-
-		save_flags(flags); cli();
-		__asm__("lcall (%%edi)\n\t"
-			"jc 1f\n\t"
-			"xor %%ah, %%ah\n"
-			"1:\tshl $8, %%eax\n\t"
-			"movw %%bx, %%ax"
-			: "=d" (signature),
-			  "=a" (pack)
-			: "1" (PCIBIOS_PCI_BIOS_PRESENT),
-			  "D" (&pci_indirect)
-			: "bx", "cx");
-		restore_flags(flags);
-
-		present_status = (pack >> 16) & 0xff;
-		major_revision = (pack >> 8) & 0xff;
-		minor_revision = pack & 0xff;
-		if (present_status || (signature != PCI_SIGNATURE)) {
-			printk ("pcibios_init : %s : BIOS32 Service Directory says PCI BIOS is present,\n"
-				"	but PCI_BIOS_PRESENT subfunction fails with present status of 0x%x\n"
-				"	and signature of 0x%08lx (%c%c%c%c).  mail drew@Colorado.EDU\n",
-				(signature == PCI_SIGNATURE) ?  "WARNING" : "ERROR",
-				present_status, signature,
-				(char) (signature >>  0), (char) (signature >>  8),
-				(char) (signature >> 16), (char) (signature >> 24));
-
-			if (signature != PCI_SIGNATURE)
-				pcibios_entry = 0;
-		}
-		if (pcibios_entry) {
-			printk ("pcibios_init : PCI BIOS revision %x.%02x entry at 0x%lx\n",
-				major_revision, minor_revision, pcibios_entry);
-			return 1;
-		}
-	}
-	return 0;
+	return access_pci->pci_present;
 }
 
-
-static int pci_bios_find_class (unsigned int class_code, unsigned short index,
+int pcibios_find_class (unsigned int class_code, unsigned short index,
 	unsigned char *bus, unsigned char *device_fn)
 {
-	unsigned long bx;
-	unsigned long ret;
-	unsigned long flags;
-
-	save_flags(flags); cli();
-	__asm__ ("lcall (%%edi)\n\t"
-		"jc 1f\n\t"
-		"xor %%ah, %%ah\n"
-		"1:"
-		: "=b" (bx),
-		  "=a" (ret)
-		: "1" (PCIBIOS_FIND_PCI_CLASS_CODE),
-		  "c" (class_code),
-		  "S" ((int) index),
-		  "D" (&pci_indirect));
-	restore_flags(flags);
-	*bus = (bx >> 8) & 0xff;
-	*device_fn = bx & 0xff;
-	return (int) (ret & 0xff00) >> 8;
+	return access_pci->find_class(class_code, index, bus, device_fn);
 }
 
-
-static int pci_bios_find_device (unsigned short vendor, unsigned short device_id,
+int pcibios_find_device (unsigned short vendor, unsigned short device_id,
 	unsigned short index, unsigned char *bus, unsigned char *device_fn)
 {
-	unsigned short bx;
-	unsigned short ret;
-	unsigned long flags;
-
-	save_flags(flags); cli();
-	__asm__("lcall (%%edi)\n\t"
-		"jc 1f\n\t"
-		"xor %%ah, %%ah\n"
-		"1:"
-		: "=b" (bx),
-		  "=a" (ret)
-		: "1" (PCIBIOS_FIND_PCI_DEVICE),
-		  "c" (device_id),
-		  "d" (vendor),
-		  "S" ((int) index),
-		  "D" (&pci_indirect));
-	restore_flags(flags);
-	*bus = (bx >> 8) & 0xff;
-	*device_fn = bx & 0xff;
-	return (int) (ret & 0xff00) >> 8;
+	return access_pci->find_device(vendor, device_id, index, bus, device_fn);
 }
 
-static int pci_bios_read_config_byte(unsigned char bus,
+int pcibios_read_config_byte (unsigned char bus,
 	unsigned char device_fn, unsigned char where, unsigned char *value)
 {
-	unsigned long ret;
-	unsigned long bx = (bus << 8) | device_fn;
-	unsigned long flags;
-
-	save_flags(flags); cli();
-	__asm__("lcall (%%esi)\n\t"
-		"jc 1f\n\t"
-		"xor %%ah, %%ah\n"
-		"1:"
-		: "=c" (*value),
-		  "=a" (ret)
-		: "1" (PCIBIOS_READ_CONFIG_BYTE),
-		  "b" (bx),
-		  "D" ((long) where),
-		  "S" (&pci_indirect));
-	restore_flags(flags);
-	return (int) (ret & 0xff00) >> 8;
+	return access_pci->read_config_byte(bus, device_fn, where, value);
 }
 
-static int pci_bios_read_config_word (unsigned char bus,
+int pcibios_read_config_word (unsigned char bus,
 	unsigned char device_fn, unsigned char where, unsigned short *value)
 {
-	unsigned long ret;
-	unsigned long bx = (bus << 8) | device_fn;
-	unsigned long flags;
-
-	save_flags(flags); cli();
-	__asm__("lcall (%%esi)\n\t"
-		"jc 1f\n\t"
-		"xor %%ah, %%ah\n"
-		"1:"
-		: "=c" (*value),
-		  "=a" (ret)
-		: "1" (PCIBIOS_READ_CONFIG_WORD),
-		  "b" (bx),
-		  "D" ((long) where),
-		  "S" (&pci_indirect));
-	restore_flags(flags);
-	return (int) (ret & 0xff00) >> 8;
+	return access_pci->read_config_word(bus, device_fn, where, value);
 }
 
-static int pci_bios_read_config_dword (unsigned char bus,
+int pcibios_read_config_dword (unsigned char bus,
 	unsigned char device_fn, unsigned char where, unsigned int *value)
 {
-	unsigned long ret;
-	unsigned long bx = (bus << 8) | device_fn;
-	unsigned long flags;
-
-	save_flags(flags); cli();
-	__asm__("lcall (%%esi)\n\t"
-		"jc 1f\n\t"
-		"xor %%ah, %%ah\n"
-		"1:"
-		: "=c" (*value),
-		  "=a" (ret)
-		: "1" (PCIBIOS_READ_CONFIG_DWORD),
-		  "b" (bx),
-		  "D" ((long) where),
-		  "S" (&pci_indirect));
-	restore_flags(flags);
-	return (int) (ret & 0xff00) >> 8;
+	return access_pci->read_config_dword(bus, device_fn, where, value);
 }
 
-static int pci_bios_write_config_byte (unsigned char bus,
+int pcibios_write_config_byte (unsigned char bus,
 	unsigned char device_fn, unsigned char where, unsigned char value)
 {
-	unsigned long ret;
-	unsigned long bx = (bus << 8) | device_fn;
-	unsigned long flags;
-
-	save_flags(flags); cli();
-	__asm__("lcall (%%esi)\n\t"
-		"jc 1f\n\t"
-		"xor %%ah, %%ah\n"
-		"1:"
-		: "=a" (ret)
-		: "0" (PCIBIOS_WRITE_CONFIG_BYTE),
-		  "c" (value),
-		  "b" (bx),
-		  "D" ((long) where),
-		  "S" (&pci_indirect));
-	restore_flags(flags);
-	return (int) (ret & 0xff00) >> 8;
+	return access_pci->write_config_byte(bus, device_fn, where, value);
 }
 
-static int pci_bios_write_config_word (unsigned char bus,
+int pcibios_write_config_word (unsigned char bus,
 	unsigned char device_fn, unsigned char where, unsigned short value)
 {
-	unsigned long ret;
-	unsigned long bx = (bus << 8) | device_fn;
-	unsigned long flags;
-
-	save_flags(flags); cli();
-	__asm__("lcall (%%esi)\n\t"
-		"jc 1f\n\t"
-		"xor %%ah, %%ah\n"
-		"1:"
-		: "=a" (ret)
-		: "0" (PCIBIOS_WRITE_CONFIG_WORD),
-		  "c" (value),
-		  "b" (bx),
-		  "D" ((long) where),
-		  "S" (&pci_indirect));
-	restore_flags(flags);
-	return (int) (ret & 0xff00) >> 8;
+	return access_pci->write_config_word(bus, device_fn, where, value);
 }
 
-static int pci_bios_write_config_dword (unsigned char bus,
+int pcibios_write_config_dword (unsigned char bus,
 	unsigned char device_fn, unsigned char where, unsigned int value)
 {
-	unsigned long ret;
-	unsigned long bx = (bus << 8) | device_fn;
-	unsigned long flags;
-
-	save_flags(flags); cli();
-	__asm__("lcall (%%esi)\n\t"
-		"jc 1f\n\t"
-		"xor %%ah, %%ah\n"
-		"1:"
-		: "=a" (ret)
-		: "0" (PCIBIOS_WRITE_CONFIG_DWORD),
-		  "c" (value),
-		  "b" (bx),
-		  "D" ((long) where),
-		  "S" (&pci_indirect));
-	restore_flags(flags);
-	return (int) (ret & 0xff00) >> 8;
+	return access_pci->write_config_dword(bus, device_fn, where, value);
 }
 
 /*
- * function table for BIOS32 access
+ * Direct access to PCI hardware...
  */
-static struct pci_access pci_bios_access = {
-      pci_bios_find_device,
-      pci_bios_find_class,
-      pci_bios_read_config_byte,
-      pci_bios_read_config_word,
-      pci_bios_read_config_dword,
-      pci_bios_write_config_byte,
-      pci_bios_write_config_word,
-      pci_bios_write_config_dword
-};
-
-
 
 /*
  * Given the vendor and device ids, find the n'th instance of that device
  * in the system.  
  */
+
+#ifdef CONFIG_PCI_DIRECT
+
 static int pci_direct_find_device (unsigned short vendor, unsigned short device_id,
 			   unsigned short index, unsigned char *bus,
 			   unsigned char *devfn)
 {
     unsigned int curr = 0;
     struct pci_dev *dev;
-    unsigned long flags;
 
-    save_flags(flags);
     for (dev = pci_devices; dev; dev = dev->next) {
 	if (dev->vendor == vendor && dev->device == device_id) {
 	    if (curr == index) {
 		*devfn = dev->devfn;
 		*bus = dev->bus->number;
-		restore_flags(flags);
 		return PCIBIOS_SUCCESSFUL;
 	    }
 	    ++curr;
 	}
     }
-    restore_flags(flags);
     return PCIBIOS_DEVICE_NOT_FOUND;
 }
 
-
 /*
  * Given the class, find the n'th instance of that device
  * in the system.
  */
+
 static int pci_direct_find_class (unsigned int class_code, unsigned short index,
 			  unsigned char *bus, unsigned char *devfn)
 {
     unsigned int curr = 0;
     struct pci_dev *dev;
-    unsigned long flags;
 
-    save_flags(flags); cli();
     for (dev = pci_devices; dev; dev = dev->next) {
 	if (dev->class == class_code) {
 	    if (curr == index) {
 		*devfn = dev->devfn;
 		*bus = dev->bus->number;
-		restore_flags(flags);
 		return PCIBIOS_SUCCESSFUL;
 	    }
 	    ++curr;
 	}
     }
-    restore_flags(flags);
     return PCIBIOS_DEVICE_NOT_FOUND;
 }
 
 /*
  * Functions for accessing PCI configuration space with type 1 accesses
  */
+
 #define CONFIG_CMD(bus, device_fn, where)   (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3))
 
 static int pci_conf1_read_config_byte(unsigned char bus, unsigned char device_fn,
@@ -585,10 +305,8 @@
 
 #undef CONFIG_CMD
 
-/*
- * functiontable for type 1
- */
 static struct pci_access pci_direct_conf1 = {
+      1,
       pci_direct_find_device,
       pci_direct_find_class,
       pci_conf1_read_config_byte,
@@ -602,6 +320,7 @@
 /*
  * Functions for accessing PCI configuration space with type 2 accesses
  */
+
 #define IOADDR(devfn, where)   ((0xC000 | ((devfn & 0x78) << 5)) + where)
 #define FUNC(devfn)            (((devfn & 7) << 1) | 0xf0)
 
@@ -698,10 +417,8 @@
 #undef IOADDR
 #undef FUNC
 
-/*
- * functiontable for type 2
- */
 static struct pci_access pci_direct_conf2 = {
+      1,
       pci_direct_find_device,
       pci_direct_find_class,
       pci_conf2_read_config_byte,
@@ -712,8 +429,7 @@
       pci_conf2_write_config_dword
 };
 
-
-__initfunc(static struct pci_access *check_direct_pci(void))
+__initfunc(static struct pci_access *pci_check_direct(void))
 {
     unsigned int tmp;
     unsigned long flags;
@@ -721,7 +437,7 @@
     save_flags(flags); cli();
 
     /*
-     * check if configuration type 1 works
+     * Check if configuration type 1 works.
      */
     outb (0x01, 0xCFB);
     tmp = inl (0xCF8);
@@ -729,153 +445,385 @@
     if (inl (0xCF8) == 0x80000000) {
 	outl (tmp, 0xCF8);
 	restore_flags(flags);
-	printk("pcibios_init: Using configuration type 1\n");
+	printk("PCI: Using configuration type 1\n");
 	return &pci_direct_conf1;
     }
     outl (tmp, 0xCF8);
 
     /*
-     * check if configuration type 2 works
+     * Check if configuration type 2 works.
      */
     outb (0x00, 0xCFB);
     outb (0x00, 0xCF8);
     outb (0x00, 0xCFA);
     if (inb (0xCF8) == 0x00 && inb (0xCFB) == 0x00) {
 	restore_flags(flags);
-	printk("pcibios_init: Using configuration type 2\n");
+	printk("PCI: Using configuration type 2\n");
 	return &pci_direct_conf2;
     }
     restore_flags(flags);
-    printk("pcibios_init: Not supported chipset for direct PCI access !\n");
+    printk("PCI: PCI hardware not found (i.e., not present or not supported).\n");
     return NULL;
 }
 
+#endif
+
+/*
+ * BIOS32 and PCI BIOS handling.
+ */
+
+#ifdef CONFIG_PCI_BIOS
+
+#define PCIBIOS_PCI_FUNCTION_ID 	0xb1XX
+#define PCIBIOS_PCI_BIOS_PRESENT 	0xb101
+#define PCIBIOS_FIND_PCI_DEVICE		0xb102
+#define PCIBIOS_FIND_PCI_CLASS_CODE	0xb103
+#define PCIBIOS_GENERATE_SPECIAL_CYCLE	0xb106
+#define PCIBIOS_READ_CONFIG_BYTE	0xb108
+#define PCIBIOS_READ_CONFIG_WORD	0xb109
+#define PCIBIOS_READ_CONFIG_DWORD	0xb10a
+#define PCIBIOS_WRITE_CONFIG_BYTE	0xb10b
+#define PCIBIOS_WRITE_CONFIG_WORD	0xb10c
+#define PCIBIOS_WRITE_CONFIG_DWORD	0xb10d
+
+/* BIOS32 signature: "_32_" */
+#define BIOS32_SIGNATURE	(('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24))
+
+/* PCI signature: "PCI " */
+#define PCI_SIGNATURE		(('P' << 0) + ('C' << 8) + ('I' << 16) + (' ' << 24))
+
+/* PCI service signature: "$PCI" */
+#define PCI_SERVICE		(('$' << 0) + ('P' << 8) + ('C' << 16) + ('I' << 24))
+
+/*
+ * This is the standard structure used to identify the entry point
+ * to the BIOS32 Service Directory, as documented in
+ * 	Standard BIOS 32-bit Service Directory Proposal
+ * 	Revision 0.4 May 24, 1993
+ * 	Phoenix Technologies Ltd.
+ *	Norwood, MA
+ * and the PCI BIOS specification.
+ */
+
+union bios32 {
+	struct {
+		unsigned long signature;	/* _32_ */
+		unsigned long entry;		/* 32 bit physical address */
+		unsigned char revision;		/* Revision level, 0 */
+		unsigned char length;		/* Length in paragraphs should be 01 */
+		unsigned char checksum;		/* All bytes must add up to zero */
+		unsigned char reserved[5]; 	/* Must be zero */
+	} fields;
+	char chars[16];
+};
+
+/*
+ * Physical address of the service directory.  I don't know if we're
+ * allowed to have more than one of these or not, so just in case
+ * we'll make pcibios_present() take a memory start parameter and store
+ * the array there.
+ */
+
+static unsigned long bios32_entry = 0;
+static struct {
+	unsigned long address;
+	unsigned short segment;
+} bios32_indirect = { 0, KERNEL_CS };
+
+/*
+ * Returns the entry point for the given service, NULL on error
+ */
+
+static unsigned long bios32_service(unsigned long service)
+{
+	unsigned char return_code;	/* %al */
+	unsigned long address;		/* %ebx */
+	unsigned long length;		/* %ecx */
+	unsigned long entry;		/* %edx */
+	unsigned long flags;
+
+	save_flags(flags); cli();
+	__asm__("lcall (%%edi)"
+		: "=a" (return_code),
+		  "=b" (address),
+		  "=c" (length),
+		  "=d" (entry)
+		: "0" (service),
+		  "1" (0),
+		  "D" (&bios32_indirect));
+	restore_flags(flags);
+
+	switch (return_code) {
+		case 0:
+			return address + entry;
+		case 0x80:	/* Not present */
+			printk("bios32_service(0x%lx): not present\n", service);
+			return 0;
+		default: /* Shouldn't happen */
+			printk("bios32_service(0x%lx): returned 0x%x, mail drew@colorado.edu\n",
+				service, return_code);
+			return 0;
+	}
+}
+
+static long pcibios_entry = 0;
+static struct {
+	unsigned long address;
+	unsigned short segment;
+} pci_indirect = { 0, KERNEL_CS };
+
+__initfunc(static int check_pcibios(void))
+{
+	unsigned long signature;
+	unsigned char present_status;
+	unsigned char major_revision;
+	unsigned char minor_revision;
+	unsigned long flags;
+	int pack;
 
-/*
- * access defined pcibios functions via
- * the function table
- */
+	if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
+		pci_indirect.address = pcibios_entry | PAGE_OFFSET;
 
-int pcibios_present(void)
-{
-	return access_pci ? 1 : 0;
+		save_flags(flags); cli();
+		__asm__("lcall (%%edi)\n\t"
+			"jc 1f\n\t"
+			"xor %%ah, %%ah\n"
+			"1:\tshl $8, %%eax\n\t"
+			"movw %%bx, %%ax"
+			: "=d" (signature),
+			  "=a" (pack)
+			: "1" (PCIBIOS_PCI_BIOS_PRESENT),
+			  "D" (&pci_indirect)
+			: "bx", "cx");
+		restore_flags(flags);
+
+		present_status = (pack >> 16) & 0xff;
+		major_revision = (pack >> 8) & 0xff;
+		minor_revision = pack & 0xff;
+		if (present_status || (signature != PCI_SIGNATURE)) {
+			printk ("PCI: %s: BIOS32 Service Directory says PCI BIOS is present,\n"
+				"	but PCI_BIOS_PRESENT subfunction fails with present status of 0x%x\n"
+				"	and signature of 0x%08lx (%c%c%c%c).  Mail drew@Colorado.EDU\n",
+				(signature == PCI_SIGNATURE) ?  "WARNING" : "ERROR",
+				present_status, signature,
+				(char) (signature >>  0), (char) (signature >>  8),
+				(char) (signature >> 16), (char) (signature >> 24));
+
+			if (signature != PCI_SIGNATURE)
+				pcibios_entry = 0;
+		}
+		if (pcibios_entry) {
+			printk ("PCI: PCI BIOS revision %x.%02x entry at 0x%lx\n",
+				major_revision, minor_revision, pcibios_entry);
+			return 1;
+		}
+	}
+	return 0;
 }
 
-int pcibios_find_class (unsigned int class_code, unsigned short index,
+static int pci_bios_find_class (unsigned int class_code, unsigned short index,
 	unsigned char *bus, unsigned char *device_fn)
 {
-   if (access_pci && access_pci->find_class)
-      return access_pci->find_class(class_code, index, bus, device_fn);
-    
-    return PCIBIOS_FUNC_NOT_SUPPORTED;
+	unsigned long bx;
+	unsigned long ret;
+	unsigned long flags;
+
+	save_flags(flags); cli();
+	__asm__ ("lcall (%%edi)\n\t"
+		"jc 1f\n\t"
+		"xor %%ah, %%ah\n"
+		"1:"
+		: "=b" (bx),
+		  "=a" (ret)
+		: "1" (PCIBIOS_FIND_PCI_CLASS_CODE),
+		  "c" (class_code),
+		  "S" ((int) index),
+		  "D" (&pci_indirect));
+	restore_flags(flags);
+	*bus = (bx >> 8) & 0xff;
+	*device_fn = bx & 0xff;
+	return (int) (ret & 0xff00) >> 8;
 }
 
-int pcibios_find_device (unsigned short vendor, unsigned short device_id,
+static int pci_bios_find_device (unsigned short vendor, unsigned short device_id,
 	unsigned short index, unsigned char *bus, unsigned char *device_fn)
 {
-    if (access_pci && access_pci->find_device)
-      return access_pci->find_device(vendor, device_id, index, bus, device_fn);
-    
-    return PCIBIOS_FUNC_NOT_SUPPORTED;
+	unsigned short bx;
+	unsigned short ret;
+	unsigned long flags;
+
+	save_flags(flags); cli();
+	__asm__("lcall (%%edi)\n\t"
+		"jc 1f\n\t"
+		"xor %%ah, %%ah\n"
+		"1:"
+		: "=b" (bx),
+		  "=a" (ret)
+		: "1" (PCIBIOS_FIND_PCI_DEVICE),
+		  "c" (device_id),
+		  "d" (vendor),
+		  "S" ((int) index),
+		  "D" (&pci_indirect));
+	restore_flags(flags);
+	*bus = (bx >> 8) & 0xff;
+	*device_fn = bx & 0xff;
+	return (int) (ret & 0xff00) >> 8;
 }
 
-int pcibios_read_config_byte (unsigned char bus,
+static int pci_bios_read_config_byte(unsigned char bus,
 	unsigned char device_fn, unsigned char where, unsigned char *value)
 {
-    if (access_pci && access_pci->read_config_byte)
-      return access_pci->read_config_byte(bus, device_fn, where, value);
-    
-    return PCIBIOS_FUNC_NOT_SUPPORTED;
+	unsigned long ret;
+	unsigned long bx = (bus << 8) | device_fn;
+	unsigned long flags;
+
+	save_flags(flags); cli();
+	__asm__("lcall (%%esi)\n\t"
+		"jc 1f\n\t"
+		"xor %%ah, %%ah\n"
+		"1:"
+		: "=c" (*value),
+		  "=a" (ret)
+		: "1" (PCIBIOS_READ_CONFIG_BYTE),
+		  "b" (bx),
+		  "D" ((long) where),
+		  "S" (&pci_indirect));
+	restore_flags(flags);
+	return (int) (ret & 0xff00) >> 8;
 }
 
-int pcibios_read_config_word (unsigned char bus,
+static int pci_bios_read_config_word (unsigned char bus,
 	unsigned char device_fn, unsigned char where, unsigned short *value)
 {
-    if (access_pci && access_pci->read_config_word)
-      return access_pci->read_config_word(bus, device_fn, where, value);
-    
-    return PCIBIOS_FUNC_NOT_SUPPORTED;
+	unsigned long ret;
+	unsigned long bx = (bus << 8) | device_fn;
+	unsigned long flags;
+
+	save_flags(flags); cli();
+	__asm__("lcall (%%esi)\n\t"
+		"jc 1f\n\t"
+		"xor %%ah, %%ah\n"
+		"1:"
+		: "=c" (*value),
+		  "=a" (ret)
+		: "1" (PCIBIOS_READ_CONFIG_WORD),
+		  "b" (bx),
+		  "D" ((long) where),
+		  "S" (&pci_indirect));
+	restore_flags(flags);
+	return (int) (ret & 0xff00) >> 8;
 }
 
-int pcibios_read_config_dword (unsigned char bus,
+static int pci_bios_read_config_dword (unsigned char bus,
 	unsigned char device_fn, unsigned char where, unsigned int *value)
 {
-    if (access_pci && access_pci->read_config_dword)
-      return access_pci->read_config_dword(bus, device_fn, where, value);
-    
-    return PCIBIOS_FUNC_NOT_SUPPORTED;
+	unsigned long ret;
+	unsigned long bx = (bus << 8) | device_fn;
+	unsigned long flags;
+
+	save_flags(flags); cli();
+	__asm__("lcall (%%esi)\n\t"
+		"jc 1f\n\t"
+		"xor %%ah, %%ah\n"
+		"1:"
+		: "=c" (*value),
+		  "=a" (ret)
+		: "1" (PCIBIOS_READ_CONFIG_DWORD),
+		  "b" (bx),
+		  "D" ((long) where),
+		  "S" (&pci_indirect));
+	restore_flags(flags);
+	return (int) (ret & 0xff00) >> 8;
 }
 
-int pcibios_write_config_byte (unsigned char bus,
+static int pci_bios_write_config_byte (unsigned char bus,
 	unsigned char device_fn, unsigned char where, unsigned char value)
 {
-    if (access_pci && access_pci->write_config_byte)
-      return access_pci->write_config_byte(bus, device_fn, where, value);
-    
-    return PCIBIOS_FUNC_NOT_SUPPORTED;
+	unsigned long ret;
+	unsigned long bx = (bus << 8) | device_fn;
+	unsigned long flags;
+
+	save_flags(flags); cli();
+	__asm__("lcall (%%esi)\n\t"
+		"jc 1f\n\t"
+		"xor %%ah, %%ah\n"
+		"1:"
+		: "=a" (ret)
+		: "0" (PCIBIOS_WRITE_CONFIG_BYTE),
+		  "c" (value),
+		  "b" (bx),
+		  "D" ((long) where),
+		  "S" (&pci_indirect));
+	restore_flags(flags);
+	return (int) (ret & 0xff00) >> 8;
 }
 
-int pcibios_write_config_word (unsigned char bus,
+static int pci_bios_write_config_word (unsigned char bus,
 	unsigned char device_fn, unsigned char where, unsigned short value)
 {
-    if (access_pci && access_pci->write_config_word)
-      return access_pci->write_config_word(bus, device_fn, where, value);
-    
-    return PCIBIOS_FUNC_NOT_SUPPORTED;    
-}
+	unsigned long ret;
+	unsigned long bx = (bus << 8) | device_fn;
+	unsigned long flags;
 
-int pcibios_write_config_dword (unsigned char bus,
-	unsigned char device_fn, unsigned char where, unsigned int value)
-{
-    if (access_pci && access_pci->write_config_dword)
-      return access_pci->write_config_dword(bus, device_fn, where, value);
-    
-    return PCIBIOS_FUNC_NOT_SUPPORTED;
+	save_flags(flags); cli();
+	__asm__("lcall (%%esi)\n\t"
+		"jc 1f\n\t"
+		"xor %%ah, %%ah\n"
+		"1:"
+		: "=a" (ret)
+		: "0" (PCIBIOS_WRITE_CONFIG_WORD),
+		  "c" (value),
+		  "b" (bx),
+		  "D" ((long) where),
+		  "S" (&pci_indirect));
+	restore_flags(flags);
+	return (int) (ret & 0xff00) >> 8;
 }
 
-const char *pcibios_strerror (int error)
+static int pci_bios_write_config_dword (unsigned char bus,
+	unsigned char device_fn, unsigned char where, unsigned int value)
 {
-	static char buf[80];
-
-	switch (error) {
-		case PCIBIOS_SUCCESSFUL:
-			return "SUCCESSFUL";
-
-		case PCIBIOS_FUNC_NOT_SUPPORTED:
-			return "FUNC_NOT_SUPPORTED";
-
-		case PCIBIOS_BAD_VENDOR_ID:
-			return "SUCCESSFUL";
-
-		case PCIBIOS_DEVICE_NOT_FOUND:
-			return "DEVICE_NOT_FOUND";
-
-		case PCIBIOS_BAD_REGISTER_NUMBER:
-			return "BAD_REGISTER_NUMBER";
-
-                case PCIBIOS_SET_FAILED:          
-			return "SET_FAILED";
-
-                case PCIBIOS_BUFFER_TOO_SMALL:    
-			return "BUFFER_TOO_SMALL";
+	unsigned long ret;
+	unsigned long bx = (bus << 8) | device_fn;
+	unsigned long flags;
 
-		default:
-			sprintf (buf, "UNKNOWN RETURN 0x%x", error);
-			return buf;
-	}
+	save_flags(flags); cli();
+	__asm__("lcall (%%esi)\n\t"
+		"jc 1f\n\t"
+		"xor %%ah, %%ah\n"
+		"1:"
+		: "=a" (ret)
+		: "0" (PCIBIOS_WRITE_CONFIG_DWORD),
+		  "c" (value),
+		  "b" (bx),
+		  "D" ((long) where),
+		  "S" (&pci_indirect));
+	restore_flags(flags);
+	return (int) (ret & 0xff00) >> 8;
 }
 
+/*
+ * Function table for BIOS32 access
+ */
 
-__initfunc(unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end))
-{
-    return mem_start;
-}
+static struct pci_access pci_bios_access = {
+      1,
+      pci_bios_find_device,
+      pci_bios_find_class,
+      pci_bios_read_config_byte,
+      pci_bios_read_config_word,
+      pci_bios_read_config_dword,
+      pci_bios_write_config_byte,
+      pci_bios_write_config_word,
+      pci_bios_write_config_dword
+};
 
-#endif
+/*
+ * Try to find PCI BIOS.
+ */
 
-__initfunc(unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end))
+__initfunc(static struct pci_access *pci_find_bios(void))
 {
-#ifdef CONFIG_PCI
 	union bios32 *check;
 	unsigned char sum;
 	int i, length;
@@ -884,7 +832,6 @@
 	 * 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 (check = (union bios32 *) __va(0xe0000);
@@ -901,24 +848,59 @@
 		if (sum != 0)
 			continue;
 		if (check->fields.revision != 0) {
-			printk("pcibios_init : unsupported revision %d at 0x%p, mail drew@colorado.edu\n",
+			printk("PCI: unsupported BIOS32 revision %d at 0x%p, mail drew@colorado.edu\n",
 				check->fields.revision, check);
 			continue;
 		}
-		printk ("pcibios_init : BIOS32 Service Directory structure at 0x%p\n", check);
-		if (!bios32_entry) {
-			if (check->fields.entry >= 0x100000) {
-				printk("pcibios_init: entry in high memory, trying direct PCI access\n");
- 				access_pci = check_direct_pci();
-			} else {
-				bios32_entry = check->fields.entry;
-				printk ("pcibios_init : BIOS32 Service Directory entry at 0x%lx\n", bios32_entry);
-				bios32_indirect.address = bios32_entry + PAGE_OFFSET;
-			}
+		printk ("PCI: BIOS32 Service Directory structure at 0x%p\n", check);
+		if (check->fields.entry >= 0x100000) {
+#ifdef CONFIG_PCI_DIRECT
+			printk("PCI: BIOS32 entry in high memory, trying direct PCI access.\n");
+			return pci_check_direct();
+#else
+			printk("PCI: BIOS32 entry in high memory, cannot use.\n");
+#endif
+		} else {
+			bios32_entry = check->fields.entry;
+			printk ("PCI: BIOS32 Service Directory entry at 0x%lx\n", bios32_entry);
+			bios32_indirect.address = bios32_entry + PAGE_OFFSET;
+			if (check_pcibios())
+				return &pci_bios_access;
 		}
+		break;	/* Hopefully more than one BIOS32 cannot happen... */
 	}
-	if (bios32_entry && check_pcibios())
- 		access_pci = &pci_bios_access;
+
+	return NULL;
+}
+
+#endif
+
+/*
+ * No fixup function used.
+ */
+
+__initfunc(unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end))
+{
+    return mem_start;
+}
+
+/*
+ * Initialization. Try all known PCI access methods.
+ */
+
+__initfunc(unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end))
+{
+	struct pci_access *a = NULL;
+
+#ifdef CONFIG_PCI_BIOS
+	a = pci_find_bios();
+#else
+#ifdef CONFIG_PCI_DIRECT
+	a = pci_check_direct();
 #endif
+#endif
+	if (a)
+		access_pci = a;
+
 	return memory_start;
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov