diff -uNr linux-2.2.11/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c --- linux-2.2.11/arch/ppc/kernel/pci.c Sun Aug 15 19:54:40 1999 +++ linux/arch/ppc/kernel/pci.c Sun Aug 22 12:41:31 1999 @@ -99,8 +99,11 @@ if (reg == 0 || ((reg[0] >> 8) & 0xff) != dev->devfn) continue; /* this is the node, see if it has interrupts */ - if (node->n_intrs > 0) + if (node->n_intrs > 0) { dev->irq = node->intrs[0].line; + printk ("PCI: setting IRQ %d on device %02x:%02x.\n", + dev->irq, dev->bus->number, dev->devfn); + } break; } } diff -uNr linux-2.2.11/arch/ppc/kernel/pmac_pci.c linux/arch/ppc/kernel/pmac_pci.c --- linux-2.2.11/arch/ppc/kernel/pmac_pci.c Sat Aug 7 17:09:25 1999 +++ linux/arch/ppc/kernel/pmac_pci.c Tue Aug 24 22:56:14 1999 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -418,7 +419,7 @@ ioremap(addr->address + 0x800000, 0x1000); bp->cfg_data = (volatile unsigned char *) ioremap(addr->address + 0xc00000, 0x1000); - bp->io_base = (void *) ioremap(addr->address, 0x10000); + bp->io_base = (void *) ioremap(addr->address, 0x800000); } else { /* XXX */ bp->cfg_addr = (volatile unsigned int *) @@ -447,20 +448,30 @@ pmac_pcibios_fixup(void)) { struct pci_dev *dev; - + int i, has_io, has_mem; + unsigned short cmd; + struct bridge_data *bp; + /* - * 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] + * The generic PCI code scans only bus 0 for devices and P2P + * bridges. We fix this here based on the array of host + * bridges. */ + for (bp = bridge_list; bp != NULL; bp = bp->next) { + if (bp->bus_number == 0) continue; + + pci_scan_peer_bridge (bp->bus_number); + } + 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. + * Open Firmware doesn't initialize the PCI_INTERRUPT_LINE + * config register, so we need to find the device node and + * see if it has an AAPL,interrupts property. + * + * Note that INTA# - INTD# are OR'ed together per slot, + # so no need to worry about multifunction cards. */ struct bridge_data *bp = bridges[dev->bus->number]; unsigned char pin; @@ -469,6 +480,63 @@ !pin) continue; /* No interrupt generated -> no fixup */ fix_intr(bp->node->child, dev); + + /* + * Open Firmware does not enable I/O and memory space + * response on PCI devices. We try to fix this, but we need + * to be sure that OF didn't forget to assign an address + * to the device. [mj] + * + * FIXME: How can we know? We should use OF properties.... + * + * In addition, we correct any I/O space address by adding + * the offset provided by the corresponding host bridge. + */ + has_io = has_mem = 0; + for(i=0; i<6; i++) { + unsigned long base; + unsigned long a = dev->base_address[i]; + if (a & PCI_BASE_ADDRESS_SPACE_IO) { + has_io = 1; + base = (unsigned long) + pci_io_base(dev->bus->number); + if (a < base) a += base; + if (a > base) { + dev->base_address[i] = a; + printk (KERN_INFO "PCI: Correcting IO" + "address %d on device %02x:" + "%02x, now %08lx.\n", i, + dev->bus->number,dev->devfn,a); + } + } else if (a & PCI_BASE_ADDRESS_MEM_MASK) + has_mem = 1; + } + /* + * Don't enable VGA-compatible cards since they have + * fixed I/O and memory space. + * + * Don't enabled disabled IDE interfaces either because + * some BIOSes may reallocate the same address when they + * find that no devices are attached. + * + * FIXME: Is this really relevant here? + */ + if (((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) && + ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE)) { + pci_read_config_word(dev, PCI_COMMAND, &cmd); + if (has_io && !(cmd & PCI_COMMAND_IO)) { + printk("PCI: Enabling I/O for device %02x:" + "%02x\n", dev->bus->number, dev->devfn); + cmd |= PCI_COMMAND_IO; + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + if (has_mem && !(cmd & PCI_COMMAND_MEMORY)) { + printk("PCI: Enabling memory for device %02x:" + "%02x\n", dev->bus->number, dev->devfn); + cmd |= PCI_COMMAND_MEMORY; + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + } } } diff -uNr linux-2.2.11/include/asm-ppc/io.h linux/include/asm-ppc/io.h --- linux-2.2.11/include/asm-ppc/io.h Sun Aug 15 19:54:48 1999 +++ linux/include/asm-ppc/io.h Fri Aug 20 19:59:16 1999 @@ -32,7 +32,9 @@ extern unsigned long isa_io_base; extern unsigned long isa_mem_base; extern unsigned long pci_dram_offset; -#define _IO_BASE isa_io_base +/* We're correcting io base addresses in pci fixup code */ +/* #define _IO_BASE isa_io_base */ +#define _IO_BASE 0 #define _ISA_MEM_BASE isa_mem_base #define PCI_DRAM_OFFSET pci_dram_offset #endif /* CONFIG_APUS */ diff -uNr linux-2.2.11/drivers/block/ide-pmac.c linux/drivers/block/ide-pmac.c --- linux-2.2.11/drivers/block/ide-pmac.c Wed Aug 25 18:59:00 1999 +++ linux/drivers/block/ide-pmac.c Wed Aug 25 18:53:22 1999 @@ -109,10 +109,10 @@ pio = ide_get_best_pio_mode(drive, pio, 4, &d); switch (pio) { case 4: - out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), 0x211025); + out_le32((unsigned *)(IDE_DATA_REG + 0x200), 0x211025); break; default: - out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), 0x2f8526); + out_le32((unsigned *)(IDE_DATA_REG + 0x200), 0x2f8526); break; } } @@ -182,7 +182,7 @@ if (i >= MAX_HWIFS) break; - base = (unsigned long) ioremap(np->addrs[0].address, 0x200) - _IO_BASE; + base = (unsigned long) ioremap(np->addrs[0].address, 0x200); /* XXX This is bogus. Should be fixed in the registry by checking the kind of host interrupt controller, a bit like gatwick