patch-2.1.108 linux/arch/i386/kernel/bios32.c
Next file: linux/arch/i386/kernel/entry.S
Previous file: linux/arch/alpha/kernel/setup.c
Back to the patch index
Back to the overall index
- Lines: 522
- Date:
Tue Jun 30 23:58:15 1998
- Orig file:
v2.1.107/linux/arch/i386/kernel/bios32.c
- Orig date:
Sun Jun 7 11:16:27 1998
diff -u --recursive --new-file v2.1.107/linux/arch/i386/kernel/bios32.c linux/arch/i386/kernel/bios32.c
@@ -1,7 +1,7 @@
/*
* bios32.c - Low-Level PCI Access
*
- * $Id: bios32.c,v 1.33 1998/05/12 07:30:11 mj Exp $
+ * $Id: bios32.c,v 1.37 1998/06/19 17:11:37 mj Exp $
*
* Copyright 1993, 1994 Drew Eckhardt
* Visionary Computing
@@ -62,6 +62,9 @@
* Feb 6, 1998 : No longer using BIOS to find devices and device classes. [mj]
*
* May 1, 1998 : Support for peer host bridges. [mj]
+ *
+ * Jun 19, 1998 : Changed to use spinlocks, so that PCI configuration space
+ * can be accessed from interrupts even on SMP systems. [mj]
*/
#include <linux/config.h>
@@ -71,16 +74,15 @@
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/malloc.h>
+#include <linux/smp_lock.h>
#include <asm/page.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <asm/io.h>
-
-#include <linux/smp_lock.h>
#include <asm/irq.h>
-#include <asm/bitops.h>
#include <asm/smp.h>
+#include <asm/spinlock.h>
#include "irq.h"
@@ -93,6 +95,13 @@
#endif
/*
+ * This interrupt-safe spinlock protects all accesses to PCI
+ * configuration space.
+ */
+
+spinlock_t pci_lock = SPIN_LOCK_UNLOCKED;
+
+/*
* Generic PCI access -- indirect calls according to detected HW.
*/
@@ -128,41 +137,28 @@
return access_pci->pci_present;
}
-int pcibios_read_config_byte (unsigned char bus,
- unsigned char device_fn, unsigned char where, unsigned char *value)
-{
- return access_pci->read_config_byte(bus, device_fn, where, value);
-}
-
-int pcibios_read_config_word (unsigned char bus,
- unsigned char device_fn, unsigned char where, unsigned short *value)
-{
- return access_pci->read_config_word(bus, device_fn, where, value);
-}
-
-int pcibios_read_config_dword (unsigned char bus,
- unsigned char device_fn, unsigned char where, unsigned int *value)
-{
- return access_pci->read_config_dword(bus, device_fn, where, value);
-}
-
-int pcibios_write_config_byte (unsigned char bus,
- unsigned char device_fn, unsigned char where, unsigned char value)
-{
- return access_pci->write_config_byte(bus, device_fn, where, value);
-}
-
-int pcibios_write_config_word (unsigned char bus,
- unsigned char device_fn, unsigned char where, unsigned short value)
-{
- return access_pci->write_config_word(bus, device_fn, where, value);
-}
-
-int pcibios_write_config_dword (unsigned char bus,
- unsigned char device_fn, unsigned char where, unsigned int value)
-{
- return access_pci->write_config_dword(bus, device_fn, where, value);
-}
+#define PCI_byte_BAD 0
+#define PCI_word_BAD (pos & 1)
+#define PCI_dword_BAD (pos & 3)
+
+#define PCI_STUB(rw,size,type) \
+int pcibios_##rw##_config_##size (u8 bus, u8 dfn, u8 pos, type value) \
+{ \
+ int res; \
+ unsigned long flags; \
+ if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \
+ spin_lock_irqsave(&pci_lock, flags); \
+ res = access_pci->rw##_config_##size(bus, dfn, pos, value); \
+ spin_unlock_irqrestore(&pci_lock, flags); \
+ return res; \
+}
+
+PCI_STUB(read, byte, u8 *)
+PCI_STUB(read, word, u16 *)
+PCI_STUB(read, dword, u32 *)
+PCI_STUB(write, byte, u8)
+PCI_STUB(write, word, u16)
+PCI_STUB(write, dword, u32)
#define PCI_PROBE_BIOS 1
#define PCI_PROBE_CONF1 2
@@ -187,76 +183,48 @@
static int pci_conf1_read_config_byte(unsigned char bus, unsigned char device_fn,
unsigned char where, unsigned char *value)
{
- unsigned long flags;
-
- save_flags(flags); cli();
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
*value = inb(0xCFC + (where&3));
- restore_flags(flags);
return PCIBIOS_SUCCESSFUL;
}
static int pci_conf1_read_config_word (unsigned char bus,
unsigned char device_fn, unsigned char where, unsigned short *value)
{
- unsigned long flags;
-
- if (where&1) return PCIBIOS_BAD_REGISTER_NUMBER;
- save_flags(flags); cli();
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
*value = inw(0xCFC + (where&2));
- restore_flags(flags);
return PCIBIOS_SUCCESSFUL;
}
static int pci_conf1_read_config_dword (unsigned char bus, unsigned char device_fn,
unsigned char where, unsigned int *value)
{
- unsigned long flags;
-
- if (where&3) return PCIBIOS_BAD_REGISTER_NUMBER;
- save_flags(flags); cli();
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
*value = inl(0xCFC);
- restore_flags(flags);
return PCIBIOS_SUCCESSFUL;
}
static int pci_conf1_write_config_byte (unsigned char bus, unsigned char device_fn,
unsigned char where, unsigned char value)
{
- unsigned long flags;
-
- save_flags(flags); cli();
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
outb(value, 0xCFC + (where&3));
- restore_flags(flags);
return PCIBIOS_SUCCESSFUL;
}
static int pci_conf1_write_config_word (unsigned char bus, unsigned char device_fn,
unsigned char where, unsigned short value)
{
- unsigned long flags;
-
- if (where&1) return PCIBIOS_BAD_REGISTER_NUMBER;
- save_flags(flags); cli();
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
outw(value, 0xCFC + (where&2));
- restore_flags(flags);
return PCIBIOS_SUCCESSFUL;
}
static int pci_conf1_write_config_dword (unsigned char bus, unsigned char device_fn,
unsigned char where, unsigned int value)
{
- unsigned long flags;
-
- if (where&3) return PCIBIOS_BAD_REGISTER_NUMBER;
- save_flags(flags); cli();
outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
outl(value, 0xCFC);
- restore_flags(flags);
return PCIBIOS_SUCCESSFUL;
}
@@ -282,90 +250,72 @@
static int pci_conf2_read_config_byte(unsigned char bus, unsigned char device_fn,
unsigned char where, unsigned char *value)
{
- unsigned long flags;
-
if (device_fn & 0x80)
return PCIBIOS_DEVICE_NOT_FOUND;
- save_flags(flags); cli();
outb (FUNC(device_fn), 0xCF8);
outb (bus, 0xCFA);
*value = inb(IOADDR(device_fn,where));
outb (0, 0xCF8);
- restore_flags(flags);
return PCIBIOS_SUCCESSFUL;
}
static int pci_conf2_read_config_word (unsigned char bus, unsigned char device_fn,
unsigned char where, unsigned short *value)
{
- unsigned long flags;
-
if (device_fn & 0x80)
return PCIBIOS_DEVICE_NOT_FOUND;
- save_flags(flags); cli();
outb (FUNC(device_fn), 0xCF8);
outb (bus, 0xCFA);
*value = inw(IOADDR(device_fn,where));
outb (0, 0xCF8);
- restore_flags(flags);
return PCIBIOS_SUCCESSFUL;
}
static int pci_conf2_read_config_dword (unsigned char bus, unsigned char device_fn,
unsigned char where, unsigned int *value)
{
- unsigned long flags;
-
if (device_fn & 0x80)
return PCIBIOS_DEVICE_NOT_FOUND;
- save_flags(flags); cli();
outb (FUNC(device_fn), 0xCF8);
outb (bus, 0xCFA);
*value = inl (IOADDR(device_fn,where));
outb (0, 0xCF8);
- restore_flags(flags);
return PCIBIOS_SUCCESSFUL;
}
static int pci_conf2_write_config_byte (unsigned char bus, unsigned char device_fn,
unsigned char where, unsigned char value)
{
- unsigned long flags;
-
- save_flags(flags); cli();
+ if (device_fn & 0x80)
+ return PCIBIOS_DEVICE_NOT_FOUND;
outb (FUNC(device_fn), 0xCF8);
outb (bus, 0xCFA);
outb (value, IOADDR(device_fn,where));
outb (0, 0xCF8);
- restore_flags(flags);
return PCIBIOS_SUCCESSFUL;
}
static int pci_conf2_write_config_word (unsigned char bus, unsigned char device_fn,
unsigned char where, unsigned short value)
{
- unsigned long flags;
-
- save_flags(flags); cli();
+ if (device_fn & 0x80)
+ return PCIBIOS_DEVICE_NOT_FOUND;
outb (FUNC(device_fn), 0xCF8);
outb (bus, 0xCFA);
outw (value, IOADDR(device_fn,where));
outb (0, 0xCF8);
- restore_flags(flags);
return PCIBIOS_SUCCESSFUL;
}
static int pci_conf2_write_config_dword (unsigned char bus, unsigned char device_fn,
unsigned char where, unsigned int value)
{
- unsigned long flags;
-
- save_flags(flags); cli();
+ if (device_fn & 0x80)
+ return PCIBIOS_DEVICE_NOT_FOUND;
outb (FUNC(device_fn), 0xCF8);
outb (bus, 0xCFA);
outl (value, IOADDR(device_fn,where));
outb (0, 0xCF8);
- restore_flags(flags);
return PCIBIOS_SUCCESSFUL;
}
@@ -387,7 +337,7 @@
unsigned int tmp;
unsigned long flags;
- save_flags(flags); cli();
+ __save_flags(flags); __cli();
/*
* Check if configuration type 1 works.
@@ -398,7 +348,7 @@
outl (0x80000000, 0xCF8);
if (inl (0xCF8) == 0x80000000) {
outl (tmp, 0xCF8);
- restore_flags(flags);
+ __restore_flags(flags);
printk("PCI: Using configuration type 1\n");
return &pci_direct_conf1;
}
@@ -413,13 +363,13 @@
outb (0x00, 0xCF8);
outb (0x00, 0xCFA);
if (inb (0xCF8) == 0x00 && inb (0xCFA) == 0x00) {
- restore_flags(flags);
+ __restore_flags(flags);
printk("PCI: Using configuration type 2\n");
return &pci_direct_conf2;
}
}
- restore_flags(flags);
+ __restore_flags(flags);
return NULL;
}
@@ -504,7 +454,7 @@
unsigned long entry; /* %edx */
unsigned long flags;
- save_flags(flags); cli();
+ spin_lock_irqsave(&pci_lock, flags);
__asm__("lcall (%%edi)"
: "=a" (return_code),
"=b" (address),
@@ -513,7 +463,7 @@
: "0" (service),
"1" (0),
"D" (&bios32_indirect));
- restore_flags(flags);
+ spin_unlock_irqrestore(&pci_lock, flags);
switch (return_code) {
case 0:
@@ -542,8 +492,8 @@
if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
pci_indirect.address = pcibios_entry + PAGE_OFFSET;
- save_flags(flags); cli();
- __asm__ __volatile__(
+ __save_flags(flags); __cli();
+ __asm__(
"lcall (%%edi)\n\t"
"jc 1f\n\t"
"xor %%ah, %%ah\n"
@@ -555,7 +505,7 @@
: "1" (PCIBIOS_PCI_BIOS_PRESENT),
"D" (&pci_indirect)
: "memory");
- restore_flags(flags);
+ __restore_flags(flags);
status = (eax >> 8) & 0xff;
hw_mech = eax & 0xff;
@@ -589,9 +539,7 @@
{
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"
@@ -602,7 +550,6 @@
"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;
@@ -615,9 +562,7 @@
{
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"
@@ -629,7 +574,6 @@
"d" (vendor),
"S" ((int) index),
"D" (&pci_indirect));
- restore_flags(flags);
*bus = (bx >> 8) & 0xff;
*device_fn = bx & 0xff;
return (int) (ret & 0xff00) >> 8;
@@ -640,9 +584,7 @@
{
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"
@@ -653,7 +595,6 @@
"b" (bx),
"D" ((long) where),
"S" (&pci_indirect));
- restore_flags(flags);
return (int) (ret & 0xff00) >> 8;
}
@@ -662,9 +603,7 @@
{
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"
@@ -675,7 +614,6 @@
"b" (bx),
"D" ((long) where),
"S" (&pci_indirect));
- restore_flags(flags);
return (int) (ret & 0xff00) >> 8;
}
@@ -684,9 +622,7 @@
{
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"
@@ -697,7 +633,6 @@
"b" (bx),
"D" ((long) where),
"S" (&pci_indirect));
- restore_flags(flags);
return (int) (ret & 0xff00) >> 8;
}
@@ -706,9 +641,7 @@
{
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"
@@ -719,7 +652,6 @@
"b" (bx),
"D" ((long) where),
"S" (&pci_indirect));
- restore_flags(flags);
return (int) (ret & 0xff00) >> 8;
}
@@ -728,9 +660,7 @@
{
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"
@@ -741,7 +671,6 @@
"b" (bx),
"D" ((long) where),
"S" (&pci_indirect));
- restore_flags(flags);
return (int) (ret & 0xff00) >> 8;
}
@@ -750,9 +679,7 @@
{
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"
@@ -763,7 +690,6 @@
"b" (bx),
"D" ((long) where),
"S" (&pci_indirect));
- restore_flags(flags);
return (int) (ret & 0xff00) >> 8;
}
@@ -860,8 +786,14 @@
break;
}
}
- if (!d)
+ if (!d) {
printk("PCI: BIOS reporting unknown device %02x:%02x\n", bus, devfn);
+ /*
+ * We must not continue scanning as several buggy BIOSes
+ * return garbage after the last device. Grr.
+ */
+ break;
+ }
}
if (!idx) {
printk("PCI: Device %02x:%02x not found by BIOS\n",
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov