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

Reply via email to