Messages in this thread Patches in this message |  | | Date | Wed, 12 Feb 1997 19:14:22 +0100 | From | "Dr. Werner Fink" <> | Subject | Re: Compaq PCI probs |
| |
> > Hi all > > I wonder if there is anyone that has managed to use the > built-in PCI devices (ie Netflex/3 network adapter) on the > newer kernels. I have tried to hardcode IRQ's and I/O space > addresses, but there is not even a "probing..." message=20 > during startup. > > I have an Compaq Deskpro 4000 that I really would like to > have working. During startup there is 3 lines of PCI32 bios > messages that looks normal (directory entries found etc), > but then it goes on abount "unknown PCI device at xxx:yyy". > There is no problem with the CL5446 PCI/Video adapter though. > It works like a charm. > > I did try the (old) Compaq boot image from redhat's ftp site, but > I get the same problems with that one as with the newer kernels. > =20 > ANy clues ? > > /Anders >
Try one of following of two patches. You should know how to build a kernel (see /usr/src/linux/Documentation/Changes).
First patch should work on 2.1.2x. Second patch adapted from 2.1.2x is against 2.0.29.
First: ---------------------------* 2.1.2x *--------------------------------------- diff -urN linux-clean/arch/i386/kernel/bios32.c linux/arch/i386/kernel/bios32.c --- linux-clean/arch/i386/kernel/bios32.c Mon Dec 23 18:25:31 1996 +++ linux/arch/i386/kernel/bios32.c Wed Feb 12 19:00:07 1997 @@ -49,6 +49,9 @@ * Dec 7, 1996 : Added support for direct configuration access of boards * with Intel compatible access schemes (tsbogend@alpha.franken.de) * + * Feb 3, 1997 : Set internal functions to static, save/restore flags + * avoid dead locks reading broken PCI BIOS, werner@suse.de + * */ #include <linux/config.h> @@ -137,7 +140,7 @@ /* * pointer to selected PCI access function table */ -struct pci_access *access_pci = NULL; +static struct pci_access *access_pci = NULL; @@ -151,7 +154,9 @@ unsigned long address; /* %ebx */ unsigned long length; /* %ecx */ unsigned long entry; /* %edx */ + unsigned long flags; + save_flags(flags); __asm__("lcall (%%edi)" : "=a" (return_code), "=b" (address), @@ -160,6 +165,7 @@ : "0" (service), "1" (0), "D" (&bios32_indirect)); + restore_flags(flags); switch (return_code) { case 0: @@ -187,11 +193,13 @@ 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); __asm__("lcall (%%edi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -202,6 +210,7 @@ : "1" (PCIBIOS_PCI_BIOS_PRESENT), "D" (&pci_indirect) : "bx", "cx"); + restore_flags(flags); present_status = (pack >> 16) & 0xff; major_revision = (pack >> 8) & 0xff; @@ -227,12 +236,14 @@ } -int pci_bios_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) { unsigned long bx; unsigned long ret; + unsigned long flags; + save_flags(flags); __asm__ ("lcall (%%edi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -243,18 +254,21 @@ "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 pci_bios_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) { unsigned short bx; unsigned short ret; + unsigned long flags; + save_flags(flags); __asm__("lcall (%%edi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -266,17 +280,20 @@ "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 pci_bios_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) { unsigned long ret; unsigned long bx = (bus << 8) | device_fn; + unsigned long flags; + save_flags(flags); __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -287,15 +304,18 @@ "b" (bx), "D" ((long) where), "S" (&pci_indirect)); + restore_flags(flags); return (int) (ret & 0xff00) >> 8; } -int pci_bios_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) { unsigned long ret; unsigned long bx = (bus << 8) | device_fn; + unsigned long flags; + save_flags(flags); __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -306,15 +326,18 @@ "b" (bx), "D" ((long) where), "S" (&pci_indirect)); + restore_flags(flags); return (int) (ret & 0xff00) >> 8; } -int pci_bios_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) { unsigned long ret; unsigned long bx = (bus << 8) | device_fn; + unsigned long flags; + save_flags(flags); __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -325,15 +348,18 @@ "b" (bx), "D" ((long) where), "S" (&pci_indirect)); + restore_flags(flags); return (int) (ret & 0xff00) >> 8; } -int pci_bios_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) { unsigned long ret; unsigned long bx = (bus << 8) | device_fn; + unsigned long flags; + save_flags(flags); __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -344,15 +370,18 @@ "b" (bx), "D" ((long) where), "S" (&pci_indirect)); + restore_flags(flags); return (int) (ret & 0xff00) >> 8; } -int pci_bios_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) { unsigned long ret; unsigned long bx = (bus << 8) | device_fn; + unsigned long flags; + save_flags(flags); __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -363,15 +392,18 @@ "b" (bx), "D" ((long) where), "S" (&pci_indirect)); + restore_flags(flags); return (int) (ret & 0xff00) >> 8; } -int pci_bios_write_config_dword (unsigned char bus, +static int pci_bios_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); __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -382,13 +414,14 @@ "b" (bx), "D" ((long) where), "S" (&pci_indirect)); + restore_flags(flags); return (int) (ret & 0xff00) >> 8; } /* * function table for BIOS32 access */ -struct pci_access pci_bios_access = { +static struct pci_access pci_bios_access = { pci_bios_find_device, pci_bios_find_class, pci_bios_read_config_byte, @@ -405,23 +438,27 @@ * Given the vendor and device ids, find the n'th instance of that device * in the system. */ -int pci_direct_find_device (unsigned short vendor, unsigned short device_id, +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; } @@ -430,22 +467,26 @@ * Given the class, find the n'th instance of that device * in the system. */ -int pci_direct_find_class (unsigned int class_code, unsigned short index, +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); 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; } @@ -454,9 +495,12 @@ */ #define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3)) -int pci_conf1_read_config_byte(unsigned char bus, unsigned char device_fn, +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); outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); switch (where & 3) { case 0: *value = inb(0xCFC); @@ -468,49 +512,70 @@ case 3: *value = inb(0xCFF); break; } + restore_flags(flags); return PCIBIOS_SUCCESSFUL; } -int pci_conf1_read_config_word (unsigned char bus, +static int pci_conf1_read_config_word (unsigned char bus, unsigned char device_fn, unsigned char where, unsigned short *value) { + unsigned long flags; + + save_flags(flags); outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); if (where & 2) *value = inw(0xCFE); else *value = inw(0xCFC); + restore_flags(flags); return PCIBIOS_SUCCESSFUL; } -int pci_conf1_read_config_dword (unsigned char bus, unsigned char device_fn, +static int pci_conf1_read_config_dword (unsigned char bus, unsigned char device_fn, unsigned char where, unsigned int *value) { + unsigned long flags; + + save_flags(flags); outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); *value = inl(0xCFC); + restore_flags(flags); return PCIBIOS_SUCCESSFUL; } -int pci_conf1_write_config_byte (unsigned char bus, unsigned char device_fn, +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); outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); outb(value, 0xCFC); + restore_flags(flags); return PCIBIOS_SUCCESSFUL; } -int pci_conf1_write_config_word (unsigned char bus, unsigned char device_fn, +static int pci_conf1_write_config_word (unsigned char bus, unsigned char device_fn, unsigned char where, unsigned short value) { + unsigned long flags; + + save_flags(flags); outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); outw(value, 0xCFC); + restore_flags(flags); return PCIBIOS_SUCCESSFUL; } -int pci_conf1_write_config_dword (unsigned char bus, unsigned char device_fn, +static int pci_conf1_write_config_dword (unsigned char bus, unsigned char device_fn, unsigned char where, unsigned int value) { + unsigned long flags; + + save_flags(flags); outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); outl(value, 0xCFC); + restore_flags(flags); return PCIBIOS_SUCCESSFUL; } @@ -519,7 +584,7 @@ /* * functiontable for type 1 */ -struct pci_access pci_direct_conf1 = { +static struct pci_access pci_direct_conf1 = { pci_direct_find_device, pci_direct_find_class, pci_conf1_read_config_byte, @@ -536,69 +601,93 @@ #define IOADDR(devfn, where) ((0xC000 | ((devfn & 0x78) << 5)) + where) #define FUNC(devfn) (((devfn & 7) << 1) | 0xf0) -int pci_conf2_read_config_byte(unsigned char bus, unsigned char device_fn, +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); outb (FUNC(device_fn), 0xCF8); outb (bus, 0xCFA); *value = inb(IOADDR(device_fn,where)); outb (0, 0xCF8); + restore_flags(flags); return PCIBIOS_SUCCESSFUL; } -int pci_conf2_read_config_word (unsigned char bus, unsigned char device_fn, +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); outb (FUNC(device_fn), 0xCF8); outb (bus, 0xCFA); *value = inw(IOADDR(device_fn,where)); - outb (0, 0xCF8); + outb (0, 0xCF8); + restore_flags(flags); return PCIBIOS_SUCCESSFUL; } -int pci_conf2_read_config_dword (unsigned char bus, unsigned char device_fn, +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); outb (FUNC(device_fn), 0xCF8); outb (bus, 0xCFA); *value = inl (IOADDR(device_fn,where)); outb (0, 0xCF8); + restore_flags(flags); return PCIBIOS_SUCCESSFUL; } -int pci_conf2_write_config_byte (unsigned char bus, unsigned char device_fn, +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); outb (FUNC(device_fn), 0xCF8); outb (bus, 0xCFA); outb (value, IOADDR(device_fn,where)); outb (0, 0xCF8); + restore_flags(flags); return PCIBIOS_SUCCESSFUL; } -int pci_conf2_write_config_word (unsigned char bus, unsigned char device_fn, +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); outb (FUNC(device_fn), 0xCF8); outb (bus, 0xCFA); outw (value, IOADDR(device_fn,where)); outb (0, 0xCF8); + restore_flags(flags); return PCIBIOS_SUCCESSFUL; } -int pci_conf2_write_config_dword (unsigned char bus, unsigned char device_fn, +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); outb (FUNC(device_fn), 0xCF8); outb (bus, 0xCFA); outl (value, IOADDR(device_fn,where)); outb (0, 0xCF8); + restore_flags(flags); return PCIBIOS_SUCCESSFUL; } @@ -608,7 +697,7 @@ /* * functiontable for type 2 */ -struct pci_access pci_direct_conf2 = { +static struct pci_access pci_direct_conf2 = { pci_direct_find_device, pci_direct_find_class, pci_conf2_read_config_byte, @@ -620,9 +709,12 @@ }; -struct pci_access *check_direct_pci(void) +static struct pci_access *check_direct_pci(void) { unsigned int tmp; + unsigned long flags; + + save_flags(flags); /* * check if configuration type 1 works @@ -632,6 +724,7 @@ outl (0x80000000, 0xCF8); if (inl (0xCF8) == 0x80000000) { outl (tmp, 0xCF8); + restore_flags(flags); printk("pcibios_init: Using configuration type 1\n"); return &pci_direct_conf1; } @@ -644,9 +737,11 @@ outb (0x00, 0xCF8); outb (0x00, 0xCFA); if (inb (0xCF8) == 0x00 && inb (0xCFC) == 0x00) { + restore_flags(flags); printk("pcibios_init: Using configuration type 2\n"); return &pci_direct_conf2; } + restore_flags(flags); printk("pcibios_init: Not supported chipset for direct PCI access !\n"); return NULL; } ---------------------------* 2.1.2x *--------------------------------------- Second: ---------------------------* 2.0.29 *--------------------------------------- --- linux/arch/i386/kernel/bios32.c.orig Sat Jun 8 10:10:49 1996 +++ linux/arch/i386/kernel/bios32.c Mon Feb 3 13:16:37 1997 @@ -46,6 +46,11 @@ * Apr 16, 1995 : Source merge with the DEC Alpha PCI support. Most of the code * moved to drivers/pci/pci.c. * + * Dec 7, 1996 : Added support for direct configuration access of boards + * with Intel compatible access schemes (tsbogend@alpha.franken.de) + * + * Feb 3, 1997 : Set internal functions to static, save/restore flags + * avoid dead locks reading broken PCI BIOS, werner@suse.de * */ @@ -56,6 +61,8 @@ #include <linux/pci.h> #include <asm/segment.h> +#include <asm/system.h> +#include <asm/io.h> #define PCIBIOS_PCI_FUNCTION_ID 0xb1XX #define PCIBIOS_PCI_BIOS_PRESENT 0xb101 @@ -101,6 +108,7 @@ 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 @@ -114,7 +122,28 @@ unsigned short segment; } bios32_indirect = { 0, KERNEL_CS }; -#ifdef CONFIG_PCI + +/* + * function table for accessing PCI configuration space + */ +struct pci_access { + 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 *); + int (*read_config_word)(unsigned char, unsigned char, unsigned char, unsigned short *); + int (*read_config_dword)(unsigned char, unsigned char, unsigned char, unsigned int *); + int (*write_config_byte)(unsigned char, unsigned char, unsigned char, unsigned char); + int (*write_config_word)(unsigned char, unsigned char, unsigned char, unsigned short); + 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 */ @@ -125,7 +154,9 @@ unsigned long address; /* %ebx */ unsigned long length; /* %ecx */ unsigned long entry; /* %edx */ + unsigned long flags; + save_flags(flags); __asm__("lcall (%%edi)" : "=a" (return_code), "=b" (address), @@ -134,6 +165,7 @@ : "0" (service), "1" (0), "D" (&bios32_indirect)); + restore_flags(flags); switch (return_code) { case 0: @@ -161,11 +193,13 @@ 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; + save_flags(flags); __asm__("lcall (%%edi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -176,6 +210,7 @@ : "1" (PCIBIOS_PCI_BIOS_PRESENT), "D" (&pci_indirect) : "bx", "cx"); + restore_flags(flags); present_status = (pack >> 16) & 0xff; major_revision = (pack >> 8) & 0xff; @@ -200,17 +235,15 @@ return memory_start; } -int pcibios_present(void) -{ - return pcibios_entry ? 1 : 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) { unsigned long bx; unsigned long ret; + unsigned long flags; + save_flags(flags); __asm__ ("lcall (%%edi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -221,18 +254,21 @@ "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) { unsigned short bx; unsigned short ret; + unsigned long flags; + save_flags(flags); __asm__("lcall (%%edi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -244,17 +280,20 @@ "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) { unsigned long ret; unsigned long bx = (bus << 8) | device_fn; + unsigned long flags; + save_flags(flags); __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -265,15 +304,18 @@ "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) { unsigned long ret; unsigned long bx = (bus << 8) | device_fn; + unsigned long flags; + save_flags(flags); __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -284,15 +326,18 @@ "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) { unsigned long ret; unsigned long bx = (bus << 8) | device_fn; + unsigned long flags; + save_flags(flags); __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -303,15 +348,18 @@ "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) { unsigned long ret; unsigned long bx = (bus << 8) | device_fn; + unsigned long flags; + save_flags(flags); __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -322,15 +370,18 @@ "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) { unsigned long ret; unsigned long bx = (bus << 8) | device_fn; + unsigned long flags; + save_flags(flags); __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -341,15 +392,18 @@ "b" (bx), "D" ((long) where), "S" (&pci_indirect)); + restore_flags(flags); return (int) (ret & 0xff00) >> 8; } -int pcibios_write_config_dword (unsigned char bus, +static int pci_bios_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); __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -360,9 +414,421 @@ "b" (bx), "D" ((long) where), "S" (&pci_indirect)); + restore_flags(flags); return (int) (ret & 0xff00) >> 8; } +/* + * function table for BIOS32 access + */ +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. + */ +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); + 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, + unsigned char where, unsigned char *value) +{ + unsigned long flags; + + save_flags(flags); + outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); + switch (where & 3) { + case 0: *value = inb(0xCFC); + break; + case 1: *value = inb(0xCFD); + break; + case 2: *value = inb(0xCFE); + break; + case 3: *value = inb(0xCFF); + break; + } + 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; + + save_flags(flags); + outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); + if (where & 2) + *value = inw(0xCFE); + else + *value = inw(0xCFC); + 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; + + save_flags(flags); + 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); + outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); + outb(value, 0xCFC); + 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; + + save_flags(flags); + outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); + outw(value, 0xCFC); + 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; + + save_flags(flags); + outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); + outl(value, 0xCFC); + restore_flags(flags); + return PCIBIOS_SUCCESSFUL; +} + +#undef CONFIG_CMD + +/* + * functiontable for type 1 + */ +static struct pci_access pci_direct_conf1 = { + pci_direct_find_device, + pci_direct_find_class, + pci_conf1_read_config_byte, + pci_conf1_read_config_word, + pci_conf1_read_config_dword, + pci_conf1_write_config_byte, + pci_conf1_write_config_word, + pci_conf1_write_config_dword +}; + +/* + * 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) + +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); + 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); + 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); + 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); + 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); + 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); + outb (FUNC(device_fn), 0xCF8); + outb (bus, 0xCFA); + outl (value, IOADDR(device_fn,where)); + outb (0, 0xCF8); + restore_flags(flags); + return PCIBIOS_SUCCESSFUL; +} + +#undef IOADDR +#undef FUNC + +/* + * functiontable for type 2 + */ +static struct pci_access pci_direct_conf2 = { + pci_direct_find_device, + pci_direct_find_class, + pci_conf2_read_config_byte, + pci_conf2_read_config_word, + pci_conf2_read_config_dword, + pci_conf2_write_config_byte, + pci_conf2_write_config_word, + pci_conf2_write_config_dword +}; + + +static struct pci_access *check_direct_pci(void) +{ + unsigned int tmp; + unsigned long flags; + + save_flags(flags); + + /* + * check if configuration type 1 works + */ + outb (0x01, 0xCFB); + tmp = inl (0xCF8); + outl (0x80000000, 0xCF8); + if (inl (0xCF8) == 0x80000000) { + outl (tmp, 0xCF8); + restore_flags(flags); + printk("pcibios_init: Using configuration type 1\n"); + return &pci_direct_conf1; + } + outl (tmp, 0xCF8); + + /* + * check if configuration type 2 works + */ + outb (0x00, 0xCFB); + outb (0x00, 0xCF8); + outb (0x00, 0xCFA); + if (inb (0xCF8) == 0x00 && inb (0xCFC) == 0x00) { + restore_flags(flags); + printk("pcibios_init: Using configuration type 2\n"); + return &pci_direct_conf2; + } + restore_flags(flags); + printk("pcibios_init: Not supported chipset for direct PCI access !\n"); + return NULL; +} + + +/* + * access defined pcibios functions via + * the function table + */ + +int pcibios_present(void) +{ + return access_pci ? 1 : 0; +} + +int pcibios_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; +} + +int pcibios_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; +} + +int pcibios_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; +} + +int pcibios_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; +} + +int pcibios_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; +} + +int pcibios_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; +} + +int pcibios_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; +} + +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; +} + const char *pcibios_strerror (int error) { static char buf[80]; @@ -398,14 +864,14 @@ unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end) { -return mem_start; + return mem_start; } - #endif unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end) { +#ifdef CONFIG_PCI union bios32 *check; unsigned char sum; int i, length; @@ -436,14 +902,16 @@ 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, unable to access\n"); + printk("pcibios_init: entry in high memory, trying direct PCI access\n"); + access_pci = check_direct_pci(); } else { - bios32_indirect.address = bios32_entry = check->fields.entry; + bios32_entry = check->fields.entry; printk ("pcibios_init : BIOS32 Service Directory entry at 0x%lx\n", bios32_entry); + bios32_indirect.address = bios32_entry; + access_pci = &pci_bios_access; } } } -#ifdef CONFIG_PCI if (bios32_entry) { memory_start = check_pcibios (memory_start, memory_end); } ---------------------------* 2.0.29 *---------------------------------------
Hope it helps
Werner
|  |