/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 2000, 2001 Keith M Wesolowski */ #include #include #include #include #include #include #include #include #include #include #undef DEBUG_MACE_PCI /* * O2 has up to 5 PCI devices connected into the MACE bridge. The device * map looks like this: * * 0 aic7xxx 0 * 1 aic7xxx 1 * 2 expansion slot * 3 N/C * 4 N/C */ #define chkslot(dev) \ do { \ if ((dev)->bus->number > 0 || PCI_SLOT ((dev)->devfn) < 1 \ || PCI_SLOT ((dev)->devfn) > 3) \ return PCIBIOS_DEVICE_NOT_FOUND; \ } while (0) #define mkaddr(dev, where) \ ((((dev)->devfn & 0xffUL) << 8) | ((where) & 0xfcUL)) void macepci_error (int irq, void *dev, struct pt_regs *regs); static int macepci_read_config_byte (struct pci_dev *dev, int where, u8 *val) { *val = 0xff; chkslot (dev); mace_write_32 (MACEPCI_CONFIG_ADDR, mkaddr (dev, where)); *val = mace_read_8 (MACEPCI_CONFIG_DATA + ((where & 3UL) ^ 3UL)); return PCIBIOS_SUCCESSFUL; } static int macepci_read_config_word (struct pci_dev *dev, int where, u16 *val) { *val = 0xffff; chkslot (dev); if (where & 1) return PCIBIOS_BAD_REGISTER_NUMBER; mace_write_32 (MACEPCI_CONFIG_ADDR, mkaddr (dev, where)); *val = mace_read_16 (MACEPCI_CONFIG_DATA + ((where & 2UL) ^ 2UL)); return PCIBIOS_SUCCESSFUL; } static int macepci_read_config_dword (struct pci_dev *dev, int where, u32 *val) { *val = 0xffffffff; chkslot (dev); if (where & 3) return PCIBIOS_BAD_REGISTER_NUMBER; mace_write_32 (MACEPCI_CONFIG_ADDR, mkaddr (dev, where)); *val = mace_read_32 (MACEPCI_CONFIG_DATA); return PCIBIOS_SUCCESSFUL; } static int macepci_write_config_byte (struct pci_dev *dev, int where, u8 val) { chkslot (dev); mace_write_32 (MACEPCI_CONFIG_ADDR, mkaddr (dev, where)); mace_write_8 (MACEPCI_CONFIG_DATA + ((where & 3UL) ^ 3UL), val); return PCIBIOS_SUCCESSFUL; } static int macepci_write_config_word (struct pci_dev *dev, int where, u16 val) { chkslot (dev); if (where & 1) return PCIBIOS_BAD_REGISTER_NUMBER; mace_write_32 (MACEPCI_CONFIG_ADDR, mkaddr (dev, where)); mace_write_16 (MACEPCI_CONFIG_DATA + ((where & 2UL) ^ 2UL), val); return PCIBIOS_SUCCESSFUL; } static int macepci_write_config_dword (struct pci_dev *dev, int where, u32 val) { chkslot (dev); if (where & 3) return PCIBIOS_BAD_REGISTER_NUMBER; mace_write_32 (MACEPCI_CONFIG_ADDR, mkaddr (dev, where)); mace_write_32 (MACEPCI_CONFIG_DATA, val); return PCIBIOS_SUCCESSFUL; } static struct pci_ops macepci_ops = { macepci_read_config_byte, macepci_read_config_word, macepci_read_config_dword, macepci_write_config_byte, macepci_write_config_word, macepci_write_config_dword }; struct pci_fixup pcibios_fixups[] = { { 0 } }; void __init pcibios_init (void) { struct pci_dev *dev; u32 start, size; u16 cmd; u32 base_io = 0x3000; /* The first i/o address to assign after SCSI */ u32 base_mem = 0x80100000; /* Likewise */ u32 rev = mace_read_32 (MACEPCI_REV); int i; printk ("MACE: PCI rev %d detected at %016lx\n", rev, (u64) MACE_BASE + MACE_PCI); /* These are *bus* addresses */ ioport_resource.start = 0; ioport_resource.end = 0xffffffffUL; iomem_resource.start = 0x80000000UL; iomem_resource.end = 0xffffffffUL; /* Clear any outstanding errors and enable interrupts */ mace_write_32 (MACEPCI_ERROR_ADDR, 0); mace_write_32 (MACEPCI_ERROR_FLAGS, 0); mace_write_32 (MACEPCI_CONTROL, 0xff008500); crime_write_64 (CRIME_HARD_INT, 0UL); crime_write_64 (CRIME_SOFT_INT, 0UL); crime_write_64 (CRIME_INT_STAT, 0x000000000000ff00UL); if (request_irq (MACE_PCI_BRIDGE_IRQ, macepci_error, 0, "MACE PCI error", NULL)) panic("PCI bridge can't get interrupt; can't happen."); pci_scan_bus (0, &macepci_ops, NULL); #ifdef DEBUG_MACE_PCI pci_for_each_dev (dev) { printk ("Device: %d/%d/%d ARCS-assigned bus resource map\n", dev->bus->number, PCI_SLOT (dev->devfn), PCI_FUNC (dev->devfn)); for (i=0; i < DEVICE_COUNT_RESOURCE; i++) { if (dev->resource[i].start == 0) continue; printk ("%d: %016lx - %016lx (flags %04lx)\n", i, dev->resource[i].start, dev->resource[i].end, dev->resource[i].flags); } } #endif /* * Assign sane resources to and enable all devices. The requirement * for the SCSI controllers is well-known: a 256-byte I/O region * which we must assign, and a 1-page memory region which is * assigned by the system firmware. */ pci_for_each_dev (dev) { switch (PCI_SLOT (dev->devfn)) { case 1: /* SCSI bus 0 */ dev->resource[0].start = 0x1000UL; dev->resource[0].end = 0x10ffUL; break; case 2: /* SCSI bus 1 */ dev->resource[0].start = 0x2000UL; dev->resource[0].end = 0x20ffUL; break; default: /* Slots - I guess we have only 1 */ for (i=0; i < 6; i++) { size = dev->resource[i].end - dev->resource[i].start; if (!size || !(dev->resource[i].flags & (IORESOURCE_IO|IORESOURCE_MEM))) { dev->resource[i].start = dev->resource[i].end = 0UL; continue; } if (dev->resource[i].flags & IORESOURCE_IO) { dev->resource[i].start = base_io; base_io += PAGE_ALIGN (size); } else { dev->resource[i].start = base_mem; base_mem += 0x100000UL; } dev->resource[i].end = dev->resource[i].start + size; } break; } for (i=0; i < 6; i++) { if (dev->resource[i].start == 0) continue; start = dev->resource[i].start; if (dev->resource[i].flags & IORESOURCE_IO) start |= 1; pci_write_config_dword (dev, PCI_BASE_ADDRESS_0 + (i << 2), (u32) start); } pci_write_config_byte (dev, PCI_CACHE_LINE_SIZE, 0x20); pci_write_config_byte (dev, PCI_LATENCY_TIMER, 0x30); pci_read_config_word (dev, PCI_COMMAND, &cmd); cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_SPECIAL | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY); pci_write_config_word (dev, PCI_COMMAND, cmd); pci_set_master (dev); } /* * Fixup O2 PCI slot. Bad hack. */ /* devtag = pci_make_tag(0, 0, 3, 0); slot = macepci_conf_read(0, devtag, PCI_COMMAND_STATUS_REG); slot |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE; macepci_conf_write(0, devtag, PCI_COMMAND_STATUS_REG, slot); slot = macepci_conf_read(0, devtag, PCI_MAPREG_START); if (slot == 0xffffffe1) macepci_conf_write(0, devtag, PCI_MAPREG_START, 0x00001000); slot = macepci_conf_read(0, devtag, PCI_MAPREG_START + (2 << 2)); if ((slot & 0xffff0000) == 0) { slot += 0x00010000; macepci_conf_write(0, devtag, PCI_MAPREG_START + (2 << 2), 0x00000000); } */ #ifdef DEBUG_MACE_PCI printk ("Triggering PCI bridge interrupt...\n"); mace_write_32 (MACEPCI_ERROR_FLAGS, MACEPCI_ERROR_INTERRUPT_TEST); pci_for_each_dev (dev) { printk ("Device: %d/%d/%d final bus resource map\n", dev->bus->number, PCI_SLOT (dev->devfn), PCI_FUNC (dev->devfn)); for (i=0; i < DEVICE_COUNT_RESOURCE; i++) { if (dev->resource[i].start == 0) continue; printk ("%d: %016lx - %016lx (flags %04lx)\n", i, dev->resource[i].start, dev->resource[i].end, dev->resource[i].flags); } } #endif } /* * Given a PCI slot number (a la PCI_SLOT(...)) and the interrupt pin of * the device (1-4 => A-D), tell what irq to use. Note that we don't * in theory have slots 4 and 5, and we never normally use the shared * irqs. I suppose a device without a pin A will thank us for doing it * right if there exists such a broken piece of crap. */ static int __init macepci_map_irq (struct pci_dev *dev, u8 slot, u8 pin) { chkslot (dev); if (pin == 0) pin = 1; switch (slot) { case 1: return MACEPCI_SCSI0_IRQ; case 2: return MACEPCI_SCSI1_IRQ; case 3: switch (pin) { case 2: return MACEPCI_SHARED0_IRQ; case 3: return MACEPCI_SHARED1_IRQ; case 4: return MACEPCI_SHARED2_IRQ; case 1: default: return MACEPCI_SLOT0_IRQ; } case 4: switch (pin) { case 2: return MACEPCI_SHARED2_IRQ; case 3: return MACEPCI_SHARED0_IRQ; case 4: return MACEPCI_SHARED1_IRQ; case 1: default: return MACEPCI_SLOT1_IRQ; } return MACEPCI_SLOT1_IRQ; case 5: switch (pin) { case 2: return MACEPCI_SHARED1_IRQ; case 3: return MACEPCI_SHARED2_IRQ; case 4: return MACEPCI_SHARED0_IRQ; case 1: default: return MACEPCI_SLOT2_IRQ; } default: return 0; } } /* * It's not entirely clear what this does in a system with no bridges. * In any case, bridges are not supported by Linux in O2. */ static u8 __init macepci_swizzle (struct pci_dev *dev, u8 *pinp) { if (PCI_SLOT (dev->devfn) == 2) *pinp = 2; else *pinp = 1; return PCI_SLOT (dev->devfn); } /* All devices are enabled during initialization. */ int pcibios_enable_device (struct pci_dev *dev) { return PCIBIOS_SUCCESSFUL; } char * __init pcibios_setup (char *str) { return str; } void __init pcibios_align_resource (void *data, struct resource *res, unsigned long size) { } void __init pcibios_update_resource (struct pci_dev *dev, struct resource *root, struct resource *res, int resource) { } void __init pcibios_update_irq (struct pci_dev *dev, int irq) { pci_write_config_byte (dev, PCI_INTERRUPT_LINE, irq); } void __init pcibios_fixup_bus (struct pci_bus *b) { pci_fixup_irqs (macepci_swizzle, macepci_map_irq); } /* XXX anybody know what this is supposed to do? */ void __init pcibios_fixup_pbus_ranges(struct pci_bus * bus, struct pbus_set_ranges_data * ranges) { ranges->io_start -= bus->resource[0]->start; ranges->io_end -= bus->resource[0]->start; ranges->mem_start -= bus->resource[1]->start; ranges->mem_end -= bus->resource[1]->start; } /* * Handle errors from the bridge. This includes master and target aborts, * various command and address errors, and the interrupt test. This gets * registered on the bridge error irq. It's conceivable that some of these * conditions warrant a panic. Anybody care to say which ones? */ void macepci_error (int irq, void *dev, struct pt_regs *regs) { u32 flags, error_addr; char space; flags = mace_read_32 (MACEPCI_ERROR_FLAGS); error_addr = mace_read_32 (MACEPCI_ERROR_ADDR); if (flags & MACEPCI_ERROR_MEMORY_ADDR) space = 'M'; else if (flags & MACEPCI_ERROR_CONFIG_ADDR) space = 'C'; else space = 'X'; if (flags & MACEPCI_ERROR_MASTER_ABORT) { printk ("MACEPCI: Master abort at 0x%08x (%c)\n", error_addr, space); mace_write_32 (MACEPCI_ERROR_FLAGS, flags & ~MACEPCI_ERROR_MASTER_ABORT); } if (flags & MACEPCI_ERROR_TARGET_ABORT) { printk ("MACEPCI: Target abort at 0x%08x (%c)\n", error_addr, space); mace_write_32 (MACEPCI_ERROR_FLAGS, flags & ~MACEPCI_ERROR_TARGET_ABORT); } if (flags & MACEPCI_ERROR_DATA_PARITY_ERR) { printk ("MACEPCI: Data parity error at 0x%08x (%c)\n", error_addr, space); mace_write_32 (MACEPCI_ERROR_FLAGS, flags & ~MACEPCI_ERROR_DATA_PARITY_ERR); } if (flags & MACEPCI_ERROR_RETRY_ERR) { printk ("MACEPCI: Retry error at 0x%08x (%c)\n", error_addr, space); mace_write_32 (MACEPCI_ERROR_FLAGS, flags & ~MACEPCI_ERROR_RETRY_ERR); } if (flags & MACEPCI_ERROR_ILLEGAL_CMD) { printk ("MACEPCI: Illegal command at 0x%08x (%c)\n", error_addr, space); mace_write_32 (MACEPCI_ERROR_FLAGS, flags & ~MACEPCI_ERROR_ILLEGAL_CMD); } if (flags & MACEPCI_ERROR_SYSTEM_ERR) { printk ("MACEPCI: System error at 0x%08x (%c)\n", error_addr, space); mace_write_32 (MACEPCI_ERROR_FLAGS, flags & ~MACEPCI_ERROR_SYSTEM_ERR); } if (flags & MACEPCI_ERROR_PARITY_ERR) { printk ("MACEPCI: Parity error at 0x%08x (%c)\n", error_addr, space); mace_write_32 (MACEPCI_ERROR_FLAGS, flags & ~MACEPCI_ERROR_PARITY_ERR); } if (flags & MACEPCI_ERROR_OVERRUN) { printk ("MACEPCI: Overrun error at 0x%08x (%c)\n", error_addr, space); mace_write_32 (MACEPCI_ERROR_FLAGS, flags & ~MACEPCI_ERROR_OVERRUN); } if (flags & MACEPCI_ERROR_SIG_TABORT) { printk ("MACEPCI: Signaled target abort (clearing)\n"); mace_write_32 (MACEPCI_ERROR_FLAGS, flags & ~MACEPCI_ERROR_SIG_TABORT); } if (flags & MACEPCI_ERROR_INTERRUPT_TEST) { printk ("MACEPCI: Interrupt test triggered (clearing)\n"); mace_write_32 (MACEPCI_ERROR_FLAGS, flags & ~MACEPCI_ERROR_INTERRUPT_TEST); } } unsigned __init int pcibios_assign_all_busses(void) { return 0; }