diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-05-07 02:55:41 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-05-07 02:55:41 +0000 |
commit | dcec8a13bf565e47942a1751a9cec21bec5648fe (patch) | |
tree | 548b69625b18cc2e88c3e68d0923be546c9ebb03 /arch/ppc/kernel/pci.c | |
parent | 2e0f55e79c49509b7ff70ff1a10e1e9e90a3dfd4 (diff) |
o Merge with Linux 2.1.99.
o Fix ancient bug in the ELF loader making ldd crash.
o Fix ancient bug in the keyboard code for SGI, SNI and Jazz.
Diffstat (limited to 'arch/ppc/kernel/pci.c')
-rw-r--r-- | arch/ppc/kernel/pci.c | 116 |
1 files changed, 70 insertions, 46 deletions
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index 7e39487d8..186165a46 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -1,24 +1,27 @@ /* - * $Id: pci.c,v 1.18 1997/10/29 03:35:07 cort Exp $ + * $Id: pci.c,v 1.24 1998/02/19 21:29:49 cort Exp $ * Common pmac/prep/chrp pci routines. -- Cort */ #include <linux/kernel.h> #include <linux/pci.h> -#include <linux/bios32.h> #include <linux/delay.h> #include <linux/string.h> #include <linux/init.h> #include <linux/config.h> #include <linux/pci.h> +#include <linux/openpic.h> #include <asm/processor.h> #include <asm/io.h> #include <asm/prom.h> #include <asm/pci-bridge.h> +#include <asm/irq.h> -#if !defined(CONFIG_MACH_SPECIFIC) +#if !defined(CONFIG_MACH_SPECIFIC) || defined(CONFIG_PMAC) unsigned long isa_io_base; +#endif /* CONFIG_MACH_SPECIFIC || CONFIG_PMAC */ +#if !defined(CONFIG_MACH_SPECIFIC) unsigned long isa_mem_base; unsigned long pci_dram_offset; #endif /* CONFIG_MACH_SPECIFIC */ @@ -121,49 +124,6 @@ int pcibios_present(void) return 1; } -int pcibios_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; - 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; - return PCIBIOS_SUCCESSFUL; - } - ++curr; - } - } - return PCIBIOS_DEVICE_NOT_FOUND; -} - -/* - * Given the class, find the n'th instance of that device - * in the system. - */ -int pcibios_find_class (unsigned int class_code, unsigned short index, - unsigned char *bus, unsigned char *devfn) -{ - unsigned int curr = 0; - struct pci_dev *dev; - - for (dev = pci_devices; dev; dev = dev->next) { - if (dev->class == class_code) { - if (curr == index) { - *devfn = dev->devfn; - *bus = dev->bus->number; - return PCIBIOS_SUCCESSFUL; - } - ++curr; - } - } - return PCIBIOS_DEVICE_NOT_FOUND; -} - - __initfunc(unsigned long pcibios_init(unsigned long mem_start,unsigned long mem_end)) { @@ -203,6 +163,70 @@ __initfunc(void __initfunc(unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end)) + { + extern route_pci_interrupts(void); + struct pci_dev *dev; + extern struct bridge_data **bridges; + extern unsigned char *Motherboard_map; + extern unsigned char *Motherboard_routes; + + /* + * FIXME: This is broken: We should not assign IRQ's to IRQless + * devices (look at PCI_INTERRUPT_PIN) and we also should + * honor the existence of multi-function devices where + * different functions have different interrupt pins. [mj] + */ + switch (_machine ) + { + case _MACH_prep: + route_pci_interrupts(); + for(dev=pci_devices; dev; dev=dev->next) + { + unsigned char d = PCI_SLOT(dev->devfn); + dev->irq = Motherboard_routes[Motherboard_map[d]]; + } + break; + case _MACH_chrp: + /* PCI interrupts are controlled by the OpenPIC */ + for(dev=pci_devices; dev; dev=dev->next) + if (dev->irq) + dev->irq = openpic_to_irq(dev->irq); + break; + case _MACH_Pmac: + for(dev=pci_devices; dev; dev=dev->next) + { + /* + * Open Firmware often doesn't initialize the, + * PCI_INTERRUPT_LINE config register properly, so we + * should find the device node and se if it has an + * AAPL,interrupts property. + */ + struct bridge_data *bp = bridges[dev->bus->number]; + struct device_node *node; + unsigned int *reg; + unsigned char pin; + + if (pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin) || + !pin) + continue; /* No interrupt generated -> no fixup */ + for (node = bp->node->child; node != 0; + node = node->sibling) { + reg = (unsigned int *) get_property(node, "reg", 0); + if (reg == 0 || ((reg[0] >> 8) & 0xff) != dev->devfn) + continue; + /* this is the node, see if it has interrupts */ + if (node->n_intrs > 0) + dev->irq = node->intrs[0].line; + break; + } + } + break; + } return mem_start; } + +__initfunc(char *pcibios_setup(char *str)) +{ + return str; +} |