diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 9895b5f79c..65432e6904 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -55,6 +55,13 @@ config OPTION_TABLE a battery backed up real time clock with CMOS NVRAM. It is usually set in mainboard/*/Kconfig. +config PIRQ_TABLE + boolean + help + This option is used to determine whether the mainboard has + a PIRQ table, which is the old way to set up interrupt routing. + It is usually set in mainboard/*/Kconfig. + config SMP boolean help diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 487a8c3de2..872c24c8fe 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -179,6 +179,10 @@ STAGE2_ARCH_X86_OBJ = archtables.o coreboot_table.o udelay_io.o STAGE2_ARCH_X86_OBJ += pci_ops_auto.o pci_ops_conf1.o pci_ops_conf2.o STAGE2_ARCH_X86_OBJ += keyboard.o i8259.o isa-dma.o +ifeq ($(CONFIG_PIRQ_TABLE),y) +STAGE2_ARCH_X86_OBJ += pirq_routing.o +endif + STAGE2_DYNAMIC_OBJ = statictree.o STAGE2_OBJ := $(patsubst %,$(obj)/lib/%,$(STAGE2_LIB_OBJ)) \ diff --git a/arch/x86/archtables.c b/arch/x86/archtables.c index 844fe5c849..aefcbab256 100644 --- a/arch/x86/archtables.c +++ b/arch/x86/archtables.c @@ -79,8 +79,13 @@ struct lb_memory *arch_write_tables(void) post_code(POST_STAGE2_ARCH_WRITE_TABLES_ENTER); /* This table must be betweeen 0xf0000 & 0x100000 */ -// rom_table_end = write_pirq_routing_table(rom_table_end); -// rom_table_end = (rom_table_end + 1023) & ~1023; + /* we need to make a decision: create empty functions + * in .h files if the cpp variable is undefined, or #ifdef? + */ +#ifdef CONFIG_PIRQ_TABLE + rom_table_end = write_pirq_routing_table(rom_table_end); + rom_table_end = (rom_table_end + 1023) & ~1023; +#endif /* Write ACPI tables */ /* write them in the rom area because DSDT can be large (8K on epia-m) which diff --git a/arch/x86/pirq_routing.c b/arch/x86/pirq_routing.c new file mode 100644 index 0000000000..b9c57d8b4d --- /dev/null +++ b/arch/x86/pirq_routing.c @@ -0,0 +1,120 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2000 Ollie Lo, Silicon Integrated Systems + * Copyright (C) 2000 Ron Minnich + * Copyright (C) 2001 Eric Biederman + * Copyright (C) 2002 Andrew Ip + * Copyright (C) 2008 Ron Minnich + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include +#include +#include +#include +#include +#include + +static void check_pirq_routing_table(struct irq_routing_table *rt) +{ + u8 *addr = (u8 *)rt; + u8 sum=0; + int i; + + printk(BIOS_INFO, "Checking IRQ routing table consistency...\n"); + +#if defined(IRQ_SLOT_COUNT) + if (sizeof(struct irq_routing_table) != rt->size) { + printk_warning("Inconsistent IRQ routing table size (0x%x/0x%x)\n", + sizeof(struct irq_routing_table), + rt->size + ); + rt->size=sizeof(struct irq_routing_table); + } +#endif + + for (i = 0; i < rt->size; i++) + sum += addr[i]; + + printk(BIOS_DEBUG, "%s() - irq_routing_table located at: 0x%p\n", + __FUNCTION__, addr); + + + sum = rt->checksum - sum; + + if (sum != rt->checksum) { + printk(BIOS_WARNING, "%s:%6d:%s() - " + "checksum is: 0x%02x but should be: 0x%02x\n", + __FILE__, __LINE__, __FUNCTION__, rt->checksum, sum); + rt->checksum = sum; + } + + if (rt->signature != PIRQ_SIGNATURE || rt->version != PIRQ_VERSION || + rt->size % 16 ) { + printk(BIOS_WARNING, "%s:%6d:%s() - " + "Interrupt Routing Table not valid\n", + __FILE__, __LINE__, __FUNCTION__); + return; + } + + sum = 0; + for (i=0; isize; i++) + sum += addr[i]; + + if (sum) { + printk(BIOS_WARNING, "%s:%6d:%s() - " + "checksum error in irq routing table\n", + __FILE__, __LINE__, __FUNCTION__); + } + + printk(BIOS_INFO, "done.\n"); +} + +static int verify_copy_pirq_routing_table(unsigned long addr) +{ + int i; + u8 *rt_orig, *rt_curr; + + rt_curr = (u8*)addr; + rt_orig = (u8*)&intel_irq_routing_table; + printk(BIOS_INFO, "Verifing copy of IRQ routing tables at 0x%lux...", addr); + for (i = 0; i < intel_irq_routing_table.size; i++) { + if (*(rt_curr + i) != *(rt_orig + i)) { + printk(BIOS_INFO, "failed\n"); + return -1; + } + } + printk(BIOS_INFO, "done\n"); + + check_pirq_routing_table((struct irq_routing_table *)addr); + + return 0; +} +unsigned long copy_pirq_routing_table(unsigned long addr) +{ + /* Align the table to be 16 byte aligned. */ + addr += 15; + addr &= ~15; + + /* This table must be betweeen 0xf0000 & 0x100000 */ + printk(BIOS_INFO, "Copying IRQ routing tables to 0x%lux...", addr); + memcpy((void *)addr, &intel_irq_routing_table, intel_irq_routing_table.size); + printk(BIOS_INFO, "done.\n"); + verify_copy_pirq_routing_table(addr); + return addr + intel_irq_routing_table.size; +} + diff --git a/device/device.c b/device/device.c index 3694276a92..5d45de566f 100644 --- a/device/device.c +++ b/device/device.c @@ -119,16 +119,13 @@ struct constructor *find_constructor(struct device_id *id) extern struct constructor *all_constructors[]; struct constructor *c; int i; - printk(BIOS_SPEW, "%s: find %s\n", __func__, dev_id_string(id)); + for (i = 0; all_constructors[i]; i++) { printk(BIOS_SPEW, "%s: check all_constructors[i] %p\n", __func__, all_constructors[i]); for (c = all_constructors[i]; c->ops; c++) { printk(BIOS_SPEW, "%s: cons %p, cons id %s\n", __func__, c, dev_id_string(&c->id)); - if (!c->ops) { - continue; - } if (id_eq(&c->id, id)) { printk(BIOS_SPEW, "%s: match\n", __func__); return c; @@ -180,6 +177,7 @@ void constructor(struct device *dev, struct device_id *id) struct constructor *c; c = find_constructor(id); + printk(BIOS_SPEW, "%s: constructor is %p\n", __func__, c); if(c && c->ops) { @@ -190,7 +188,7 @@ void constructor(struct device *dev, struct device_id *id) } else printk(BIOS_INFO, "No constructor called for %s.\n", - dev_id_string(&c->id)); + dev_id_string(id)); } /** @@ -211,7 +209,6 @@ struct device *alloc_dev(struct bus *parent, struct device_path *path, { struct device *dev, *child; int link; - spin_lock(&dev_lock); /* Find the last child of our parent. */ diff --git a/include/arch/x86/pirq_routing.h b/include/arch/x86/pirq_routing.h new file mode 100644 index 0000000000..031b610e2c --- /dev/null +++ b/include/arch/x86/pirq_routing.h @@ -0,0 +1,55 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2000 Ollie Lo, Silicon Integrated Systems + * Copyright (C) 2008 Ron Minnich + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef ARCH_PIRQ_ROUTING_H +#define ARCH_PIRQ_ROUTING_H + +#define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24)) +#define PIRQ_VERSION 0x0100 + +struct irq_info { + u8 bus, devfn; /* Bus, device and function */ + struct { + u8 link; /* IRQ line ID, chipset dependent, 0=not routed */ + u16 bitmap; /* Available IRQs */ + } __attribute__((packed)) irq[4]; + u8 slot; /* Slot number, 0=onboard */ + u8 rfu; +} __attribute__((packed)); + +struct irq_routing_table { + u32 signature; /* PIRQ_SIGNATURE should be here */ + u16 version; /* PIRQ_VERSION */ + u16 size; /* Table size in bytes */ + u8 rtr_bus, rtr_devfn; /* Where the interrupt router lies */ + u16 exclusive_irqs; /* IRQs devoted exclusively to PCI usage */ + u16 rtr_vendor, rtr_device; /* Vendor and device ID of interrupt router */ + u32 miniport_data; /* Crap */ + u8 rfu[11]; + u8 checksum; /* Modulo 256 checksum must give zero */ + struct irq_info slots[]; +} __attribute__((packed)); + +extern const struct irq_routing_table intel_irq_routing_table; + +unsigned long copy_pirq_routing_table(unsigned long start); +unsigned long write_pirq_routing_table(unsigned long start); + +#endif /* ARCH_PIRQ_ROUTING_H */ diff --git a/include/device/pci.h b/include/device/pci.h index ae56729777..07a24527e3 100644 --- a/include/device/pci.h +++ b/include/device/pci.h @@ -99,6 +99,9 @@ void pci_domain_read_resources(struct device *dev); void ram_resource(struct device *dev, unsigned long index, unsigned long basek, unsigned long sizek); unsigned int pci_domain_scan_bus(struct device *dev, unsigned int max); +void pci_assign_irqs(unsigned int bus, unsigned int slot, + const unsigned char pIntAtoD[4]); + #define PCI_IO_BRIDGE_ALIGN 4096 diff --git a/include/tables.h b/include/tables.h index 6ee51f2d95..f468348e55 100644 --- a/include/tables.h +++ b/include/tables.h @@ -269,4 +269,9 @@ struct lb_memory *get_lb_mem(void); struct cmos_option_table *get_option_table(void); +#ifdef CONFIG_PIRQ_TABLE +unsigned long write_pirq_routing_table(unsigned long addr); +#endif + + #endif /* TABLES_H */ diff --git a/mainboard/pcengines/Kconfig b/mainboard/pcengines/Kconfig index 63d046bc25..a17bde991a 100644 --- a/mainboard/pcengines/Kconfig +++ b/mainboard/pcengines/Kconfig @@ -31,6 +31,7 @@ config BOARD_PCENGINES_ALIX1C select NORTHBRIDGE_AMD_GEODELX select SOUTHBRIDGE_AMD_CS5536 select SUPERIO_WINBOND_W83627HF + select PIRQ_TABLE help PC Engines ALIX1.C. diff --git a/mainboard/pcengines/alix1c/Makefile b/mainboard/pcengines/alix1c/Makefile index da4c25a6c6..bcb216f2c5 100644 --- a/mainboard/pcengines/alix1c/Makefile +++ b/mainboard/pcengines/alix1c/Makefile @@ -27,6 +27,10 @@ INITRAM_OBJ = $(src)/mainboard/$(MAINBOARDDIR)/initram.c \ STAGE2_MAINBOARD_OBJ = +ifeq ($(CONFIG_PIRQ_TABLE),y) +STAGE2_MAINBOARD_OBJ += irq_tables.o +endif + $(obj)/coreboot.vpd: $(Q)printf " BUILD DUMMY VPD\n" $(Q)dd if=/dev/zero of=$(obj)/coreboot.vpd bs=256 count=1 $(SILENT) diff --git a/mainboard/pcengines/alix1c/dts b/mainboard/pcengines/alix1c/dts index b3b2c968af..a615fce28d 100644 --- a/mainboard/pcengines/alix1c/dts +++ b/mainboard/pcengines/alix1c/dts @@ -43,6 +43,16 @@ pcipath = "0xf,0"; enabled; enable_ide = "1"; + /* Interrupt enables for LPC bus. + * Each bit is an IRQ 0-15. */ + lpc_serirq_enable = "0x000010da"; + /* LPC IRQ polarity. Each bit is an IRQ 0-15. */ + lpc_serirq_polarity = "0x0000EF25"; + /* 0:continuous 1:quiet */ + lpc_serirq_mode = "1"; + /* GPIO(0-0x20) for INT D:C:B:A, 0xFF=none. + * See virtual PIC spec. */ + enable_gpio_int_route = "0x0D0C0700"; }; superio { /config/("superio/winbond/w83627hf/dts"); diff --git a/mainboard/pcengines/alix1c/irq_tables.c b/mainboard/pcengines/alix1c/irq_tables.c new file mode 100644 index 0000000000..169d553e67 --- /dev/null +++ b/mainboard/pcengines/alix1c/irq_tables.c @@ -0,0 +1,160 @@ +/* +* This file is part of the coreboot project. +* +* Copyright (C) 2007 Advanced Micro Devices, Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../../southbridge/amd/cs5536/cs5536.h" + + + +/* Platform IRQs */ +#define PIRQA 11 +#define PIRQB 10 +#define PIRQC 11 +#define PIRQD 9 + +/* Map */ +#define M_PIRQA (1 << PIRQA) /* Bitmap of supported IRQs */ +#define M_PIRQB (1 << PIRQB) /* Bitmap of supported IRQs */ +#define M_PIRQC (1 << PIRQC) /* Bitmap of supported IRQs */ +#define M_PIRQD (1 << PIRQD) /* Bitmap of supported IRQs */ + +/* Link */ +#define L_PIRQA 1 /* Means Slot INTx# Connects To Chipset INTA# */ +#define L_PIRQB 2 /* Means Slot INTx# Connects To Chipset INTB# */ +#define L_PIRQC 3 /* Means Slot INTx# Connects To Chipset INTC# */ +#define L_PIRQD 4 /* Means Slot INTx# Connects To Chipset INTD# */ + +/* + * ALIX1.C interrupt wiring. + * + * Devices are: + * + * 00:01.0 Host bridge: Advanced Micro Devices [AMD] CS5536 [Geode companion] Host Bridge (rev 31) + * 00:01.2 Entertainment encryption device: Advanced Micro Devices [AMD] Geode LX AES Security Block + * 00:0d.0 Ethernet controller: VIA Technologies, Inc. VT6105M [Rhine-III] (rev 96) + * 00:0e.0 Network controller: Intersil Corporation Prism 2.5 Wavelan chipset (rev 01) + * 00:0f.0 ISA bridge: Advanced Micro Devices [AMD] CS5536 [Geode companion] ISA (rev 03) + * 00:0f.2 IDE interface: Advanced Micro Devices [AMD] CS5536 [Geode companion] IDE (rev 01) + * 00:0f.3 Multimedia audio controller: Advanced Micro Devices [AMD] CS5536 [Geode companion] Audio (rev 01) + * 00:0f.4 USB Controller: Advanced Micro Devices [AMD] CS5536 [Geode companion] OHC (rev 02) + * 00:0f.5 USB Controller: Advanced Micro Devices [AMD] CS5536 [Geode companion] EHC (rev 02) + * + * The only devices that interrupt are: + * + * What Device IRQ PIN PIN WIRED TO + * ------------------------------------------------- + * AES 00:01.2 0a 01 A A + * 3VPCI 00:0c.0 0a 01 A A + * eth0 00:0d.0 0b 01 A B + * mpci 00:0e.0 0a 01 A A + * usb 00:0f.3 0b 02 B B + * usb 00:0f.4 0b 04 D D + * usb 00:0f.5 0b 04 D D + * + * The only swizzled interrupt is eth0, where INTA is wired to interrupt controller line B. + */ + +const struct irq_routing_table intel_irq_routing_table = { + PIRQ_SIGNATURE, + PIRQ_VERSION, + 32 + 16 * 5, /* Max. number of devices on the bus */ + 0x00, /* Where the interrupt router lies (bus) */ + (0x0F << 3) | 0x0, /* Where the interrupt router lies (dev) */ + 0x00, /* IRQs devoted exclusively to PCI usage */ + 0x100B, /* Vendor */ + 0x002B, /* Device */ + 0, /* Crap (miniport) */ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* u8 rfu[11] */ + 0x00, /* Checksum */ + { + /* If you change the number of entries, change IRQ_SLOT_COUNT above! */ + + /* bus, dev|fn, {link, bitmap}, {link, bitmap}, {link, bitmap}, {link, bitmap}, slot, rfu */ + + /* CPU */ + {0x00, (0x01 << 3) | 0x0, {{L_PIRQA, M_PIRQA}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}}, 0x0, 0x0}, + + /* PCI (slot 1) */ + {0x00, (0x0C << 3) | 0x0, {{L_PIRQC, M_PIRQC}, {L_PIRQD, M_PIRQD}, {L_PIRQA, M_PIRQA}, {L_PIRQB, M_PIRQB}}, 0x4, 0x0}, + + /* On-board ethernet */ + {0x00, (0x0D << 3) | 0x0, {{L_PIRQB, M_PIRQB}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}}, 0x0, 0x0}, + + /* Mini PCI (slot 2) */ + {0x00, (0x0E << 3) | 0x0, {{L_PIRQA, M_PIRQA}, {L_PIRQB, M_PIRQB}, {L_PIRQC, M_PIRQC}, {L_PIRQD, M_PIRQD}}, 0x1, 0x0}, + + /* Chipset slots -- f.3 wires to B, and f.4 and f.5 wires to D. */ + {0x00, (0x0F << 3) | 0x0, {{L_PIRQA, M_PIRQA}, {L_PIRQB, M_PIRQB}, {L_PIRQC, M_PIRQC}, {L_PIRQD, M_PIRQD}}, 0x0, 0x0}, + } +}; + +unsigned long write_pirq_routing_table(unsigned long addr) +{ + int i, j, k, num_entries; + unsigned char pirq[4]; + u16 chipset_irq_map; + u32 pciAddr, pirtable_end; + struct irq_routing_table *pirq_tbl; + + pirtable_end = copy_pirq_routing_table(addr); + + /* Set up chipset IRQ steering. */ + pciAddr = 0x80000000 | (CHIPSET_DEV_NUM << 11) | 0x5C; + chipset_irq_map = (PIRQD << 12 | PIRQC << 8 | PIRQB << 4 | PIRQA); + printk(BIOS_DEBUG, "%s(%08X, %04X)\n", __FUNCTION__, pciAddr, + chipset_irq_map); + outl(pciAddr & ~3, 0xCF8); + outl(chipset_irq_map, 0xCFC); + + pirq_tbl = (struct irq_routing_table *) (addr); + num_entries = (pirq_tbl->size - 32) / 16; + + /* Set PCI IRQs. */ + for (i = 0; i < num_entries; i++) { + printk(BIOS_DEBUG, "PIR Entry %d Dev/Fn: %X Slot: %d\n", i, + pirq_tbl->slots[i].devfn, pirq_tbl->slots[i].slot); + for (j = 0; j < 4; j++) { + printk(BIOS_DEBUG, "INT: %c bitmap: %x ", 'A' + j, + pirq_tbl->slots[i].irq[j].bitmap); + /* Finds lsb in bitmap to IRQ#. */ + for (k = 0; + (!((pirq_tbl->slots[i].irq[j].bitmap >> k) & 1)) + && (pirq_tbl->slots[i].irq[j].bitmap != 0); + k++); + pirq[j] = k; + printk(BIOS_DEBUG, "PIRQ: %d\n", k); + } + + /* Bus, device, slots IRQs for {A,B,C,D}. */ + pci_assign_irqs(pirq_tbl->slots[i].bus, + pirq_tbl->slots[i].devfn >> 3, pirq); + } + + /* Put the PIR table in memory and checksum. */ + return pirtable_end; +} diff --git a/util/x86emu/vm86.c b/util/x86emu/vm86.c index c9e4b6a280..fe0db7a678 100644 --- a/util/x86emu/vm86.c +++ b/util/x86emu/vm86.c @@ -595,11 +595,23 @@ void setup_realmode_idt(void) intbyte = codeptr + 3; *intbyte = 0x42; /* int42 is the relocated int10 */ + /* The source of the following code is not yet known. + * We feel it may be useful someday, but right now it + * scribbles over code space. We are leaving it here as a + * "Living comment" since it may at some point be needed + * again. It is a very intriguing idea -- one could run + * vm86 code with TF set and set programmable times + * between instructions to slow them down. For those who + * recall the "turbo" switch on old PCs, this is the + * software equivalent. + */ +#if 0 /* debug handler - useful to set a programmable delay between instructions if the TF bit is set upon call to real mode */ idts[1].cs = 0; idts[1].offset = 16384; memcpy((void *)16384, &debughandle, &end_debughandle - &debughandle); +#endif }