lkml.org 
[lkml]   [1998]   [Jun]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectRe: Yet another panic
Hi,

> Well, as Alan pointed out, that's an error recovery routine only triggered
> by large numbers of spurious interrupts. Since we can't always be sure that
> spurios interrupts are an error, we read STATUS1 in order to find out if
> there *is* an actual error condition outstanding. If there is, we clear it
> and go on. Without this code, it's possible to have a single PCI error
> condition throw the machine into an interrupt storm under 2.1.x and lock the
> machine under 2.0.x. Now, these conditions are rare, and the PCI parity
> checking stuff is turned off at detect time by default (at least in the
> latest driver), but if it is enabled, then we need to either be able to get
> at that register, or I have to create some sort of timer/bottom_half/other
> non-interrupt function to correct the error condition.

Try the following patch. If it works, I'll send it to Linus for inclusion
in 2.1.107.

Have a nice fortnight
--
Martin `MJ' Mares <mj@ucw.cz> http://atrey.karlin.mff.cuni.cz/~mj/
Faculty of Math and Physics, Charles University, Prague, Czech Rep., Earth
"Ctrl and Alt keys stuck -- press Del to continue."


--- linux-2.1/arch/i386/kernel/bios32.c Fri Jun 19 19:19:09 1998
+++ linux/arch/i386/kernel/bios32.c Fri Jun 19 19:25:47 1998
@@ -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>
@@ -76,11 +79,8 @@
#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 +93,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 +135,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 +181,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 +248,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 +335,7 @@
unsigned int tmp;
unsigned long flags;

- save_flags(flags); cli();
+ __save_flags(flags); __cli();

/*
* Check if configuration type 1 works.
@@ -398,7 +346,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 +361,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 +452,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 +461,7 @@
: "0" (service),
"1" (0),
"D" (&bios32_indirect));
- restore_flags(flags);
+ spin_unlock_irqrestore(&pci_lock, flags);

switch (return_code) {
case 0:
@@ -542,8 +490,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 +503,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 +537,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 +548,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 +560,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 +572,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 +582,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 +593,6 @@
"b" (bx),
"D" ((long) where),
"S" (&pci_indirect));
- restore_flags(flags);
return (int) (ret & 0xff00) >> 8;
}

@@ -662,9 +601,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 +612,6 @@
"b" (bx),
"D" ((long) where),
"S" (&pci_indirect));
- restore_flags(flags);
return (int) (ret & 0xff00) >> 8;
}

@@ -684,9 +620,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 +631,6 @@
"b" (bx),
"D" ((long) where),
"S" (&pci_indirect));
- restore_flags(flags);
return (int) (ret & 0xff00) >> 8;
}

@@ -706,9 +639,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 +650,6 @@
"b" (bx),
"D" ((long) where),
"S" (&pci_indirect));
- restore_flags(flags);
return (int) (ret & 0xff00) >> 8;
}

@@ -728,9 +658,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 +669,6 @@
"b" (bx),
"D" ((long) where),
"S" (&pci_indirect));
- restore_flags(flags);
return (int) (ret & 0xff00) >> 8;
}

@@ -750,9 +677,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 +688,6 @@
"b" (bx),
"D" ((long) where),
"S" (&pci_indirect));
- restore_flags(flags);
return (int) (ret & 0xff00) >> 8;
}

@@ -860,8 +784,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",
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu

\
 
 \ /
  Last update: 2005-03-22 13:43    [W:0.178 / U:0.128 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site