[coreboot] Correct value for PCI_INTERRUPT_LINE register

Аладышев Константин aladyshev at nicevt.ru
Wed Jan 10 09:56:51 CET 2018


I know that today nobody is really interested in support of legacy boot
options like 'acpi=off', 'noapic', 'nolapic', irq tables like MP table and
$PIR, but sometimes booting with these legacy modes can help you to debug
BIOS issues. So I've wanted to implement support of these options for my
board (Haswell CPU + LynxpointLP PCH).

I've implemented MP table and $PIR and came to fact, that linux can't boot
with 'acpi=off nolapic' options combination. Through some investigation of
Linux boot process I've found out that the problem can be in wrong PCI IRQ
routing. I've enabled debug information in file "arch/x86/pci/irq.c"
("dyndbg='file arch/x86/pci/irq.c +pmf;'") and got this:


 [    0.080004] irq:pcibios_fixup_irqs: pci 0000:00:02.0: ignoring bogus IRQ
139
[    0.080008] irq:pcibios_fixup_irqs: pci 0000:00:03.0: ignoring bogus IRQ
139
[    0.080012] irq:pcibios_fixup_irqs: pci 0000:00:16.0: ignoring bogus IRQ
139
[    0.080017] irq:pcibios_fixup_irqs: pci 0000:00:1b.0: ignoring bogus IRQ
139
[    0.080021] irq:pcibios_fixup_irqs: pci 0000:00:1c.0: ignoring bogus IRQ
139
[    0.080025] irq:pcibios_fixup_irqs: pci 0000:00:1c.1: ignoring bogus IRQ
139
[    0.080029] irq:pcibios_fixup_irqs: pci 0000:00:1c.2: ignoring bogus IRQ
138
[    0.080033] irq:pcibios_fixup_irqs: pci 0000:00:1c.3: ignoring bogus IRQ
138
[    0.080037] irq:pcibios_fixup_irqs: pci 0000:00:1c.4: ignoring bogus IRQ
139
[    0.080041] irq:pcibios_fixup_irqs: pci 0000:00:1c.5: ignoring bogus IRQ
139
[    0.080046] irq:pcibios_fixup_irqs: pci 0000:00:1d.0: ignoring bogus IRQ
139
[    0.080050] irq:pcibios_fixup_irqs: pci 0000:00:1f.3: ignoring bogus IRQ
138
[    0.080055] irq:pcibios_fixup_irqs: pci 0000:05:00.0: ignoring bogus IRQ
139
[    0.080059] irq:pcibios_fixup_irqs: pci 0000:05:00.1: ignoring bogus IRQ
139
[    0.080069] irq:pcibios_lookup_irq: pci 0000:00:02.0: PCI INT A -> PIRQ
60, mask dc78, excl 0000
[    0.080073] irq:pcibios_lookup_irq: pci 0000:00:02.0: PCI INT A -> newirq
0
[    0.080079] irq:pcibios_lookup_irq: pci 0000:00:02.0: can't route
interrupt
[    0.080086] irq:pcibios_lookup_irq: pci 0000:00:03.0: PCI INT A -> PIRQ
60, mask dc78, excl 0000
[    0.080090] irq:pcibios_lookup_irq: pci 0000:00:03.0: PCI INT A -> newirq
0
[    0.080095] irq:pcibios_lookup_irq: pci 0000:00:03.0: can't route
interrupt
[    0.080111] irq:pcibios_lookup_irq: pci 0000:00:16.0: PCI INT A -> PIRQ
60, mask dc78, excl 0000
[    0.080115] irq:pcibios_lookup_irq: pci 0000:00:16.0: PCI INT A -> newirq
0
[    0.080120] irq:pcibios_lookup_irq: pci 0000:00:16.0: can't route
interrupt
[    0.080128] irq:pcibios_lookup_irq: pci 0000:00:1b.0: PCI INT A -> PIRQ
6a, mask dc78, excl 0000
[    0.080131] irq:pcibios_lookup_irq: pci 0000:00:1b.0: PCI INT A -> newirq
0
[    0.080137] irq:pcibios_lookup_irq: pci 0000:00:1b.0: can't route
interrupt
[    0.080144] irq:pcibios_lookup_irq: pci 0000:00:1c.0: PCI INT A -> PIRQ
60, mask dc78, excl 0000
[    0.080148] irq:pcibios_lookup_irq: pci 0000:00:1c.0: PCI INT A -> newirq
0
[    0.080154] irq:pcibios_lookup_irq: pci 0000:00:1c.0: can't route
interrupt
[    0.080161] irq:pcibios_lookup_irq: pci 0000:00:1c.1: PCI INT B -> PIRQ
61, mask dc78, excl 0000
[    0.080165] irq:pcibios_lookup_irq: pci 0000:00:1c.1: PCI INT B -> newirq
0
[    0.080171] irq:pcibios_lookup_irq: pci 0000:00:1c.1: can't route
interrupt
[    0.080178] irq:pcibios_lookup_irq: pci 0000:00:1c.2: PCI INT C -> PIRQ
62, mask dc78, excl 0000
[    0.080182] irq:pcibios_lookup_irq: pci 0000:00:1c.2: PCI INT C -> newirq
0
[    0.080188] irq:pcibios_lookup_irq: pci 0000:00:1c.2: can't route
interrupt
[    0.080195] irq:pcibios_lookup_irq: pci 0000:00:1c.3: PCI INT D -> PIRQ
63, mask dc78, excl 0000
[    0.080199] irq:pcibios_lookup_irq: pci 0000:00:1c.3: PCI INT D -> newirq
0
[    0.080204] irq:pcibios_lookup_irq: pci 0000:00:1c.3: can't route
interrupt
[    0.080212] irq:pcibios_lookup_irq: pci 0000:00:1c.4: PCI INT A -> PIRQ
60, mask dc78, excl 0000
[    0.080216] irq:pcibios_lookup_irq: pci 0000:00:1c.4: PCI INT A -> newirq
0
[    0.080221] irq:pcibios_lookup_irq: pci 0000:00:1c.4: can't route
interrupt
[    0.080228] irq:pcibios_lookup_irq: pci 0000:00:1c.5: PCI INT B -> PIRQ
61, mask dc78, excl 0000
[    0.080232] irq:pcibios_lookup_irq: pci 0000:00:1c.5: PCI INT B -> newirq
0
[    0.080238] irq:pcibios_lookup_irq: pci 0000:00:1c.5: can't route
interrupt
[    0.080245] irq:pcibios_lookup_irq: pci 0000:00:1d.0: PCI INT A -> PIRQ
6b, mask dc78, excl 0000
[    0.080249] irq:pcibios_lookup_irq: pci 0000:00:1d.0: PCI INT A -> newirq
0
[    0.080255] irq:pcibios_lookup_irq: pci 0000:00:1d.0: can't route
interrupt
[    0.080266] irq:pcibios_lookup_irq: pci 0000:00:1f.3: PCI INT C -> PIRQ
62, mask dc78, excl 0000
[    0.080270] irq:pcibios_lookup_irq: pci 0000:00:1f.3: PCI INT C -> newirq
0
[    0.080275] irq:pcibios_lookup_irq: pci 0000:00:1f.3: can't route
interrupt
[    0.080320] irq:pcibios_lookup_irq: pci 0000:05:00.0: PCI INT A not found
in routing table
[    0.080365] irq:pcibios_lookup_irq: pci 0000:05:00.1: PCI INT B not found
in routing table


So the problem is in strings: 
irq:pcibios_fixup_irqs: pci 0000:00:XX.0: ignoring bogus IRQ 139

139 (=0x8b) is value from my board devicetree.cb:

			register "pirqa_routing" = "0x8b"
			register "pirqb_routing" = "0x8b"
			register "pirqc_routing" = "0x8a"
			register "pirqd_routing" = "0x8a"
			register "pirqe_routing" = "0x85"
			register "pirqf_routing" = "0x80"
			register "pirqg_routing" = "0x8b"
			register "pirqh_routing" = "0x85"

0x8b means IRQ 0xb (=IRQ11) and Interrupt Routing Enable bit = 1.

This value is written to PCH in file "southbridge\intel\lynxpoint\lpc.c"

static void pch_pirq_init(device_t dev)
{
	device_t irq_dev;
	/* Get the chip configuration */
	config_t *config = dev->chip_info;

	pci_write_config8(dev, PIRQA_ROUT, config->pirqa_routing);
	pci_write_config8(dev, PIRQB_ROUT, config->pirqb_routing);
	pci_write_config8(dev, PIRQC_ROUT, config->pirqc_routing);
	pci_write_config8(dev, PIRQD_ROUT, config->pirqd_routing);

	pci_write_config8(dev, PIRQE_ROUT, config->pirqe_routing);
	pci_write_config8(dev, PIRQF_ROUT, config->pirqf_routing);
	pci_write_config8(dev, PIRQG_ROUT, config->pirqg_routing);
	pci_write_config8(dev, PIRQH_ROUT, config->pirqh_routing);

	/* Eric Biederman once said we should let the OS do this.
	 * I am not so sure anymore he was right.
	 */

	for(irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) {
		u8 int_pin=0, int_line=0;

		if (!irq_dev->enabled || irq_dev->path.type !=
DEVICE_PATH_PCI)
			continue;

		int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN);

		switch (int_pin) {
		case 1: /* INTA# */ int_line = config->pirqa_routing; break;
		case 2: /* INTB# */ int_line = config->pirqb_routing; break;
		case 3: /* INTC# */ int_line = config->pirqc_routing; break;
		case 4: /* INTD# */ int_line = config->pirqd_routing; break;
		}

		if (!int_line)
			continue;

		pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, int_line);
	}
}

It is correct and right to write values like 0x8b to PIRQX_ROUT registers
but in PCI_INTERRUPT_LINE registers Linux Kernel seems to expect values <16
(http://elixir.free-electrons.com/linux/v3.13/source/arch/x86/pci/irq.c#L102
6). So maybe the correct way to write these registers is:

pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, int_line & 0xf);

After this change Linux boots correctly with 'acpi=off nolapic' options
combination.

PCI specification states:
"For x86 based PCs, the values in this register correspond to IRQ numbers
(0-15) of the standard dual
8259 configuration. The value 255 is defined as meaning "unknown" or "no
connection" to the interrupt
controller. Values between 15 and 254 are reserved."
(https://www.xilinx.com/Attachment/PCI_SPEV_V3_0.pdf - page 223)

I'm not an expert with IRQs and also I see that many other southbridges in
coreboot fill this registers like Lynxpoint with values >=16, so before
creating a patch I've wanted to ask you if I'm wrong with this?


Best regards,
Aladyshev Konstantin




More information about the coreboot mailing list