Tobias Diedrich has uploaded this change for review. ( https://review.coreboot.org/22810
Change subject: [draft] sb/intel/common: Automatically generate ACPI PIRQ ......................................................................
[draft] sb/intel/common: Automatically generate ACPI PIRQ
Based on https://review.coreboot.org/#/c/22803/
This function generates PIRQ ACPI tables automatically based on the chipset registers.
Linux 4.13.14 /proc/interrupts: CPU0 CPU1 0: 24 0 IO-APIC 2-edge timer 8: 1 0 IO-APIC 8-edge rtc0 9: 0 0 IO-APIC 9-fasteoi acpi 19: 86 0 IO-APIC 19-fasteoi ehci_hcd:usb1 23: 0 0 IO-APIC 23-fasteoi i801_smbus 24: 0 0 PCI-MSI 458752-edge PCIe PME 25: 0 0 PCI-MSI 460800-edge PCIe PME 26: 0 0 PCI-MSI 462848-edge PCIe PME 27: 166 0 PCI-MSI 32768-edge i915 28: 3953 0 PCI-MSI 512000-edge ahci[0000:00:1f.2] 29: 656 0 PCI-MSI 409600-edge eno1 30: 83 0 PCI-MSI 442368-edge snd_hda_intel:card0 [...]
Bootlog: PCI: 00:00.0: no pin PCI: 00:01.0: no pin slot=2 or pin1 out of bounds PCI: 00:02.0: pin=1 pirq=0 PCI: 00:16.0: no pin PCI: 00:16.1: no pin PCI: 00:16.2: no pin PCI: 00:16.3: no pin PCI: 00:19.0: no pin PCI: 00:1a.0: no pin slot=27 reg=0x3148 val=0x1070 PCI: 00:1b.0: pin=1 pirq=1 slot=28 reg=0x3146 val=0x4351 PCI: 00:1c.0: pin=1 pirq=2 slot=28 reg=0x3146 val=0x4351 PCI: 00:1c.1: pin=2 pirq=6 slot=28 reg=0x3146 val=0x4351 PCI: 00:1c.2: pin=3 pirq=4 PCI: 00:1c.3: no pin PCI: 00:1c.4: no pin PCI: 00:1c.5: no pin PCI: 00:1c.6: no pin PCI: 00:1c.7: no pin slot=29 reg=0x3144 val=0x6543 PCI: 00:1d.0: pin=1 pirq=4 PCI: 00:1e.0: no pin PCI: 00:1f.0: no pin slot=31 reg=0x3140 val=0x2071 PCI: 00:1f.2: pin=1 pirq=2 slot=31 reg=0x3140 val=0x2071 PCI: 00:1f.3: pin=2 pirq=8 PCI: 00:1f.5: no pin PCI: 00:1f.6: no pin slot=4 or pin1 out of bounds PCI: 00:04.0: pin=1 pirq=0 num_devs=7
Generated _PRT: Scope (_SB.PCI0) { Method (_PRT, 0, NotSerialized) // _PRT: PCI Routing Table { If (PICM) { Return (Package (0x07) { Package (0x04) { 0x001BFFFF, 0x00000000, 0x00000000, 0x00000010 },
Package (0x04) { 0x001CFFFF, 0x00000000, 0x00000000, 0x00000011 },
Package (0x04) { 0x001CFFFF, 0x00000001, 0x00000000, 0x00000015 },
Package (0x04) { 0x001CFFFF, 0x00000002, 0x00000000, 0x00000013 },
Package (0x04) { 0x001DFFFF, 0x00000000, 0x00000000, 0x00000013 },
Package (0x04) { 0x001FFFFF, 0x00000000, 0x00000000, 0x00000011 },
Package (0x04) { 0x001FFFFF, 0x00000001, 0x00000000, 0x00000017 } }) } Else { Return (Package (0x07) { Package (0x04) { 0x001BFFFF, 0x00000000, _SB.PCI0.LPCB.LNKA, 0x00000000 },
Package (0x04) { 0x001CFFFF, 0x00000000, _SB.PCI0.LPCB.LNKB, 0x00000000 },
Package (0x04) { 0x001CFFFF, 0x00000001, _SB.PCI0.LPCB.LNKF, 0x00000000 },
Package (0x04) { 0x001CFFFF, 0x00000002, _SB.PCI0.LPCB.LNKD, 0x00000000 },
Package (0x04) { 0x001DFFFF, 0x00000000, _SB.PCI0.LPCB.LNKD, 0x00000000 },
Package (0x04) { 0x001FFFFF, 0x00000000, _SB.PCI0.LPCB.LNKB, 0x00000000 },
Package (0x04) { 0x001FFFFF, 0x00000001, _SB.PCI0.LPCB.LNKH, 0x00000000 } }) } } } }
Change-Id: Ic6b8ce4a9db50211a9c26221ca10105c5a0829a0 Signed-off-by: Tobias Diedrich ranma+coreboot@tdiedrich.de --- M src/southbridge/intel/bd82x6x/Kconfig M src/southbridge/intel/bd82x6x/acpi/default_irq_route.asl M src/southbridge/intel/bd82x6x/lpc.c M src/southbridge/intel/common/Kconfig M src/southbridge/intel/common/Makefile.inc A src/southbridge/intel/common/acpi_pirq_gen.c A src/southbridge/intel/common/acpi_pirq_gen.h 7 files changed, 179 insertions(+), 61 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/10/22810/1
diff --git a/src/southbridge/intel/bd82x6x/Kconfig b/src/southbridge/intel/bd82x6x/Kconfig index fe1ca34..2266a48 100644 --- a/src/southbridge/intel/bd82x6x/Kconfig +++ b/src/southbridge/intel/bd82x6x/Kconfig @@ -25,6 +25,7 @@ def_bool y select ACPI_INTEL_HARDWARE_SLEEP_VALUES select SOUTHBRIDGE_INTEL_COMMON + select SOUTHBRIDGE_INTEL_COMMON_PIRQ_ACPI_GEN select SOUTHBRIDGE_INTEL_COMMON_SMBUS select SOUTHBRIDGE_INTEL_COMMON_SPI select IOAPIC diff --git a/src/southbridge/intel/bd82x6x/acpi/default_irq_route.asl b/src/southbridge/intel/bd82x6x/acpi/default_irq_route.asl index 0e6f960..c40f260 100644 --- a/src/southbridge/intel/bd82x6x/acpi/default_irq_route.asl +++ b/src/southbridge/intel/bd82x6x/acpi/default_irq_route.asl @@ -14,64 +14,4 @@ * GNU General Public License for more details. */
-/* PCI Interrupt Routing */ -Method(_PRT) -{ - If (PICM) { - Return (Package() { - /* Onboard graphics (IGD) 0:2.0 */ - Package() { 0x0002ffff, 0, 0, 16 },/* GFX INTA -> PIRQA (MSI) */ - /* PCI Express Graphics (PEG) 0:1.0 */ - Package() { 0x0001ffff, 0, 0, 16 },/* GFX PCIe INTA -> PIRQA (MSI) */ - Package() { 0x0001ffff, 0, 0, 17 },/* GFX PCIe INTB -> PIRQB (MSI) */ - Package() { 0x0001ffff, 0, 0, 18 },/* GFX PCIe INTC -> PIRQC (MSI) */ - Package() { 0x0001ffff, 0, 0, 19 },/* GFX PCIe INTD -> PIRQD (MSI) */ - /* XHCI 0:14.0 (ivy only) */ - Package() { 0x0014ffff, 0, 0, 19 }, - /* High Definition Audio 0:1b.0 */ - Package() { 0x001bffff, 0, 0, 16 },/* D27IP_ZIP HDA INTA -> PIRQA (MSI) */ - /* PCIe Root Ports 0:1c.x */ - Package() { 0x001cffff, 0, 0, 17 },/* D28IP_P1IP PCIe INTA -> PIRQB */ - Package() { 0x001cffff, 1, 0, 21 },/* D28IP_P2IP PCIe INTB -> PIRQF */ - Package() { 0x001cffff, 2, 0, 19 },/* D28IP_P3IP PCIe INTC -> PIRQD */ - Package() { 0x001cffff, 3, 0, 20 },/* D28IP_P3IP PCIe INTD -> PIRQE */ - /* EHCI #1 0:1d.0 */ - Package() { 0x001dffff, 0, 0, 19 },/* D29IP_E1P EHCI1 INTA -> PIRQD */ - /* EHCI #2 0:1a.0 */ - Package() { 0x001affff, 0, 0, 21 },/* D26IP_E2P EHCI2 INTA -> PIRQF */ - /* LPC devices 0:1f.0 */ - Package() { 0x001fffff, 0, 0, 17 }, /* D31IP_SIP SATA INTA -> PIRQB (MSI) */ - Package() { 0x001fffff, 1, 0, 23 }, /* D31IP_SMIP SMBUS INTB -> PIRQH */ - Package() { 0x001fffff, 2, 0, 16 }, /* D31IP_TTIP THRT INTC -> PIRQA */ - Package() { 0x001fffff, 3, 0, 18 }, - }) - } Else { - Return (Package() { - /* Onboard graphics (IGD) 0:2.0 */ - Package() { 0x0002ffff, 0, _SB.PCI0.LPCB.LNKA, 0 }, - /* PCI Express Graphics (PEG) 0:1.0 */ - Package() { 0x0001ffff, 0, _SB.PCI0.LPCB.LNKA, 0 }, - Package() { 0x0001ffff, 0, _SB.PCI0.LPCB.LNKB, 0 }, - Package() { 0x0001ffff, 0, _SB.PCI0.LPCB.LNKC, 0 }, - Package() { 0x0001ffff, 0, _SB.PCI0.LPCB.LNKD, 0 }, - /* XHCI 0:14.0 (ivy only) */ - Package() { 0x0014ffff, 0, _SB.PCI0.LPCB.LNKD, 0 }, - /* High Definition Audio 0:1b.0 */ - Package() { 0x001bffff, 0, _SB.PCI0.LPCB.LNKA, 0 }, - /* PCIe Root Ports 0:1c.x */ - Package() { 0x001cffff, 0, _SB.PCI0.LPCB.LNKB, 0 }, - Package() { 0x001cffff, 1, _SB.PCI0.LPCB.LNKF, 0 }, - Package() { 0x001cffff, 2, _SB.PCI0.LPCB.LNKD, 0 }, - Package() { 0x001cffff, 3, _SB.PCI0.LPCB.LNKE, 0 }, - /* EHCI #1 0:1d.0 */ - Package() { 0x001dffff, 0, _SB.PCI0.LPCB.LNKD, 0 }, - /* EHCI #2 0:1a.0 */ - Package() { 0x001affff, 0, _SB.PCI0.LPCB.LNKF, 0 }, - /* LPC device 0:1f.0 */ - Package() { 0x001fffff, 0, _SB.PCI0.LPCB.LNKB, 0 }, - Package() { 0x001fffff, 1, _SB.PCI0.LPCB.LNKH, 0 }, - Package() { 0x001fffff, 2, _SB.PCI0.LPCB.LNKA, 0 }, - Package() { 0x001fffff, 3, _SB.PCI0.LPCB.LNKC, 0 }, - }) - } -} +/* PCI Interrupt Routing is generated */ diff --git a/src/southbridge/intel/bd82x6x/lpc.c b/src/southbridge/intel/bd82x6x/lpc.c index 2bfc1e3..5224469 100644 --- a/src/southbridge/intel/bd82x6x/lpc.c +++ b/src/southbridge/intel/bd82x6x/lpc.c @@ -35,6 +35,7 @@ #include "pch.h" #include "nvs.h" #include <southbridge/intel/common/pciehp.h> +#include <southbridge/intel/common/acpi_pirq_gen.h>
#define NMI_OFF 0
@@ -815,12 +816,42 @@ return "LPCB"; }
+static const u32 pirq_dir_route_reg[] = { + D20IR, 0, D22IR, 0, 0, D25IR, D26IR, D27IR, D28IR, D29IR, 0, D31IR, +}; + +u8 intel_common_map_pirq(device_t dev, u8 pci_pin) +{ + u8 slot = PCI_SLOT(dev->path.pci.devfn); + u8 shift = 4 * (pci_pin - 1); + u8 pirq; + u32 reg; + + if (slot < 20 || slot > 31 || pci_pin < 1 || pci_pin > 4) { + printk(BIOS_DEBUG, "slot=%d or pin%d out of bounds\n", + slot, pci_pin); + return 0; + } + + reg = pirq_dir_route_reg[slot - 20]; + printk(BIOS_DEBUG, "slot=%d reg=0x%04x val=0x%04x\n", + slot, reg, RCBA16(reg)); + + pirq = ((RCBA16(reg) >> shift) & 0xf); + if (pirq > 8) { + printk(BIOS_DEBUG, "pirq=%d out of bounds\n", pirq); + return 0; + } + return 1 + pirq; +} + static void southbridge_fill_ssdt(device_t device) { device_t dev = dev_find_slot(0, PCI_DEVFN(0x1f,0)); config_t *chip = dev->chip_info;
intel_acpi_pcie_hotplug_generator(chip->pcie_hotplug_map, 8); + intel_acpi_gen_def_acpi_pirq(dev); }
static void lpc_final(struct device *dev) diff --git a/src/southbridge/intel/common/Kconfig b/src/southbridge/intel/common/Kconfig index 6ce6b33..f6a0180 100644 --- a/src/southbridge/intel/common/Kconfig +++ b/src/southbridge/intel/common/Kconfig @@ -15,6 +15,9 @@ config HAVE_INTEL_CHIPSET_LOCKDOWN def_bool n
+config SOUTHBRIDGE_INTEL_COMMON_PIRQ_ACPI_GEN + def_bool n + config INTEL_CHIPSET_LOCKDOWN depends on HAVE_INTEL_CHIPSET_LOCKDOWN && HAVE_SMI_HANDLER && !CHROMEOS #ChromeOS's payload seems to handle finalization on its on. diff --git a/src/southbridge/intel/common/Makefile.inc b/src/southbridge/intel/common/Makefile.inc index 0128505..13150d9 100644 --- a/src/southbridge/intel/common/Makefile.inc +++ b/src/southbridge/intel/common/Makefile.inc @@ -33,4 +33,6 @@ smm-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_SPI) += spi.c endif
+ramstage-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_PIRQ_ACPI_GEN) += acpi_pirq_gen.c + endif diff --git a/src/southbridge/intel/common/acpi_pirq_gen.c b/src/southbridge/intel/common/acpi_pirq_gen.c new file mode 100644 index 0000000..17d9d09 --- /dev/null +++ b/src/southbridge/intel/common/acpi_pirq_gen.c @@ -0,0 +1,119 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2017 Arthur Heymans arthur@aheymans.xyz + * + * 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; version 2 of the License. + * + * 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. + */ + +#include <arch/acpigen.h> +#include <arch/io.h> +#include <console/console.h> +#include <device/pci_def.h> +#include <string.h> + +#include "acpi_pirq_gen.h" + +enum emit_type { + EMIT_NONE, + EMIT_APIC, + EMIT_PICM, +}; + +static int enumerate_root_pci_pins(enum emit_type emit, const char *lpcb_path) +{ + static char buffer[DEVICE_PATH_MAX]; + device_t dev; + u8 prev_int_pin = 0; + u8 prev_pci_dev = 0; + int num_devs = 0; + + for (dev = all_devices; dev; dev = dev->next) { + u8 pci_dev; + u8 int_pin; + u8 pirq; + + if (dev->path.type != DEVICE_PATH_PCI || + dev->bus->secondary != 0) + continue; + + pci_dev = PCI_SLOT(dev->path.pci.devfn); + int_pin = pci_read_config8(dev, PCI_INTERRUPT_PIN); + + if (int_pin == 0 || int_pin > 4) { + printk(BIOS_DEBUG, "%s: no pin\n", dev_path(dev)); + continue; + } + + pirq = intel_common_map_pirq(dev, int_pin); + + printk(BIOS_DEBUG, "%s: pin=%d pirq=%d\n", + dev_path(dev), int_pin, pirq); + + if (pirq == 0) + continue; + + /* Avoid duplicate entries */ + if (prev_pci_dev == pci_dev && prev_int_pin == int_pin) { + continue; + } else { + prev_int_pin = int_pin; + prev_pci_dev = pci_dev; + } + if (emit != EMIT_NONE) { + acpigen_write_package(4); + acpigen_write_dword((pci_dev << 16) | 0xffff); + acpigen_write_dword(int_pin - 1); + if (emit == EMIT_APIC) { + acpigen_write_dword(0); + acpigen_write_dword(16 + (pirq - 1)); + } else { + snprintf(buffer, sizeof(buffer), + "%s.LNK%c", lpcb_path, 'A' + pirq - 1); + printk(BIOS_DEBUG, "path=%s\n", buffer); + acpigen_emit_namestring(buffer); + acpigen_write_dword(0); + } + acpigen_pop_len(); + } + num_devs++; + } + return num_devs; +} + +void intel_acpi_gen_def_acpi_pirq(device_t dev) +{ + const char *lpcb_path = acpi_device_path(dev); + int num_devs = enumerate_root_pci_pins(EMIT_NONE, lpcb_path); + + if (!lpcb_path) { + printk(BIOS_ERR, "Missing LPCB ACPI path\n"); + return; + } + printk(BIOS_INFO, "num_devs=%d\n", num_devs); + + acpigen_write_scope("\_SB.PCI0"); + acpigen_write_method("_PRT", 0); + acpigen_write_if(); + acpigen_emit_namestring("PICM"); + acpigen_emit_byte(RETURN_OP); + acpigen_write_package(num_devs); + enumerate_root_pci_pins(EMIT_APIC, lpcb_path); + acpigen_pop_len(); /* package */ + acpigen_pop_len(); /* if PICM */ + acpigen_write_else(); + acpigen_emit_byte(RETURN_OP); + acpigen_write_package(num_devs); + enumerate_root_pci_pins(EMIT_PICM, lpcb_path); + acpigen_pop_len(); /* package */ + acpigen_pop_len(); /* else PICM */ + acpigen_pop_len(); /* _PRT */ + acpigen_pop_len(); /* _SB */ +} diff --git a/src/southbridge/intel/common/acpi_pirq_gen.h b/src/southbridge/intel/common/acpi_pirq_gen.h new file mode 100644 index 0000000..d5c68f7 --- /dev/null +++ b/src/southbridge/intel/common/acpi_pirq_gen.h @@ -0,0 +1,22 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2017 Arthur Heymans arthur@aheymans.xyz + * + * 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; version 2 of the License. + * + * 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. + */ + +#ifndef INTEL_COMMON_ACPI_PIRQ_GEN_H +#define INTEL_COMMON_ACPI_PIRQ_GEN_H + +void intel_acpi_gen_def_acpi_pirq(device_t dev); +u8 intel_common_map_pirq(device_t dev, u8 int_pin); + +#endif