This patch (which is NOT signed off) adds (or tries to) PIRQ support
for the alix1c.
it crashes and burns badly, however, I don' t know why. Marc, is
0xf0000 set up as memory in the v3 port? I am not sure.
It dies at a strange point:
PCI: devfn 0x9, bad id 0xffffffff
PCI: pci_scan_bus pci_probe_dev returns dev 0x00000000(c)
PCI: devfn 0xa
pci_scan_get_dev: list is 0x00087eb8, *list is 0x0000b060
pci_scan_get_dev: check dev southbridge
pci_scan_get_dev: check dev southbridge it has devfn 0x78
pci_scan_get_dev: check dev superio
superio: Unknown device path type: 0
pci_scan_get_dev: child superio() not a pci device: it's type 0
PCI: pci_scan_bus pci_scan_get_dev returns dev None (no dev in tree yet)
new_device: devcnt 1
I can't see why it would die here. At the same time, I am not sure
that we're not losing what's in the serial FIFO. Lots of FIFO action
here. In fact, to help serial out run faster, I do this:
cat /dev/ttyS0
instead of running minicom!
I have seen minicom buffering almost 30-40 seconds of serial output
once I turn the alix off. Or, something is buffering it. Flow control
is OFF in minicom.
Note that if I comment out this line:
select PIRQ_TABLE
in mainboard/pcengines/Kconfig, this bios builds and runs fine.
weird.
ron
Index: include/device/pci.h
===================================================================
--- include/device/pci.h (revision 578)
+++ include/device/pci.h (working copy)
@@ -99,8 +99,11 @@
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
#define PCI_MEM_BRIDGE_ALIGN (1024*1024)
Index: include/arch/x86/pirq_routing.h
===================================================================
--- include/arch/x86/pirq_routing.h (revision 0)
+++ include/arch/x86/pirq_routing.h (revision 0)
@@ -0,0 +1,35 @@
+#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 */
Index: mainboard/pcengines/Kconfig
===================================================================
--- mainboard/pcengines/Kconfig (revision 578)
+++ mainboard/pcengines/Kconfig (working copy)
@@ -31,6 +31,7 @@
select NORTHBRIDGE_AMD_GEODELX
select SOUTHBRIDGE_AMD_CS5536
select SUPERIO_WINBOND_W83627HF
+ select PIRQ_TABLE
help
PC Engines ALIX1.C.
Index: mainboard/pcengines/alix1c/irq_tables.c
===================================================================
--- mainboard/pcengines/alix1c/irq_tables.c (revision 0)
+++ mainboard/pcengines/alix1c/irq_tables.c (revision 0)
@@ -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 <types.h>
+#include <lib.h>
+#include <console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <string.h>
+#include <msr.h>
+#include <io.h>
+#include <pirq_routing.h>
+#include <amd_geodelx.h>
+#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;
+}
Index: mainboard/pcengines/alix1c/dts
===================================================================
--- mainboard/pcengines/alix1c/dts (revision 578)
+++ mainboard/pcengines/alix1c/dts (working copy)
@@ -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");
Index: mainboard/pcengines/alix1c/Makefile
===================================================================
--- mainboard/pcengines/alix1c/Makefile (revision 578)
+++ mainboard/pcengines/alix1c/Makefile (working copy)
@@ -27,6 +27,10 @@
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)
Index: device/device.c
===================================================================
--- device/device.c (revision 578)
+++ device/device.c (working copy)
@@ -126,7 +126,7 @@
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) || (!c->ops->constructor)) {
+ if (!c->ops) {
continue;
}
if (id_eq(&c->id, id)) {
@@ -182,8 +182,12 @@
c = find_constructor(id);
printk(BIOS_SPEW, "%s: constructor is %p\n", __func__, c);
- if(c && c->ops && c->ops->constructor)
- c->ops->constructor(dev, c);
+ if(c && c->ops) {
+ if(c->ops->constructor)
+ c->ops->constructor(dev, c);
+ else
+ default_device_constructor(dev, c);
+ }
else
printk(BIOS_INFO, "No constructor called for %s.\n",
dev_id_string(&c->id));
Index: util/lar/stream.c
===================================================================
--- util/lar/stream.c (revision 578)
+++ util/lar/stream.c (working copy)
@@ -74,8 +74,9 @@
int filelen, enum compalgo algo)
{
int ret;
- Elf32_Phdr *phdr;
+ Elf32_Phdr *phdr;
Elf32_Ehdr *ehdr;
+ Elf32_Shdr *shdr;
u32 entry;
int i;
int size;
@@ -121,11 +122,53 @@
ehdr->e_phnum,
ehdr->e_shentsize,
ehdr->e_shnum);
- phdr = (Elf32_Phdr *)&(header[ehdr->e_phoff]);
+ phdr = (Elf32_Phdr *)&(header[ehdr->e_phoff]);
+ shdr = (Elf32_Shdr *)&(header[ehdr->e_shoff]);
if (verbose())
fprintf(stderr, "%s: header %p #headers %d\n", __FUNCTION__, ehdr, headers);
+
entry = ehdr->e_entry;
+ /* bss segments are special. They are in the section headers,
+ * not program headers. So, sadly, we have to look at section headers.
+ */
+
+ for(i = 0; i < ehdr->e_shnum; i++) {
+ char *p, *q;
+ /* Ignore data that I don't need to handle */
+ if (shdr[i].sh_type != SHT_NOBITS) {
+ if (verbose())
+ fprintf(stderr, "Dropping non SHT_NOBITS section\n");
+ continue;
+ }
+ /* might need to test flags with SHF_ALLOC */
+ if (shdr[i].sh_size == 0) {
+ if (verbose())
+ fprintf(stderr, "Dropping empty section\n");
+ continue;
+ }
+ thisalgo = algo;
+ if (verbose())
+ fprintf(stderr, "New section addr %#x size %#x\n",
+ (u32)shdr[i].sh_addr, (u32)shdr[i].sh_size);
+ /* Clean up the values */
+ size = shdr[i].sh_size;
+ if (verbose()) {
+ fprintf(stderr, "(cleaned up) New section addr %p size 0x%#x\n",
+ (void *)shdr[i].sh_addr, (u32)shdr[i].sh_size);
+ }
+ /* ok, copy it out */
+ sprintf(ename, "%s/segment%d", name, segment++);
+ /* just allocate a bunch of zeros */
+ p = calloc(sizeof(*p), size);
+ q = calloc(sizeof(*q), size);
+ complen = lar_compress(p, size, q, &thisalgo);
+ ret = lar_add_entry(lar, ename, q, complen, size,
+ shdr[i].sh_addr, entry, thisalgo);
+ free(p);
+ free(q);
+ }
+
for(i = 0; i < headers; i++) {
/* Ignore data that I don't need to handle */
if (phdr[i].p_type != PT_LOAD) {
Index: arch/x86/Kconfig
===================================================================
--- arch/x86/Kconfig (revision 578)
+++ arch/x86/Kconfig (working copy)
@@ -55,6 +55,13 @@
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
Index: arch/x86/archtables.c
===================================================================
--- arch/x86/archtables.c (revision 578)
+++ arch/x86/archtables.c (working copy)
@@ -79,8 +79,13 @@
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_TABLES
+ 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
Index: arch/x86/pirq_routing.c
===================================================================
--- arch/x86/pirq_routing.c (revision 0)
+++ arch/x86/pirq_routing.c (revision 0)
@@ -0,0 +1,97 @@
+#include <types.h>
+#include <string.h>
+#include <lar.h>
+#include <console.h>
+#include <device/device.h>
+#include <tables.h>
+#include <pirq_routing.h>
+
+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; i<rt->size; 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;
+}
+
Index: arch/x86/Makefile
===================================================================
--- arch/x86/Makefile (revision 578)
+++ arch/x86/Makefile (working copy)
@@ -179,6 +179,10 @@
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)) \
--
coreboot mailing list
[email protected]
http://www.coreboot.org/mailman/listinfo/coreboot