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
- Lines: 1100
- Date:
Sat Sep 6 10:43:49 1997
- Orig file:
v2.1.53/linux/arch/i386/kernel/bios32.c
- Orig date:
Thu Jul 17 10:06:03 1997
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