aboutsummaryrefslogtreecommitdiff
path: root/src/southbridge/intel/common/acpi_pirq_gen.c
diff options
context:
space:
mode:
authorTobias Diedrich <ranma+coreboot@tdiedrich.de>2017-12-13 23:25:32 +0100
committerMartin Roth <martinroth@google.com>2017-12-20 16:48:05 +0000
commit9d8be5a857dfcd10449fad58c514f7a95e4a7cb8 (patch)
treecf39d59530133b343625b21984e10c0d9b1f7252 /src/southbridge/intel/common/acpi_pirq_gen.c
parentfd305156cda099ae99b7077c87ef1dc8b33d255d (diff)
sb/intel/common: Automatically generate ACPI PIRQ
Based on change I2b5d68adabf0840162c6f295af8d10d8d3007a34 (sb/intel/common: Add function to automatically generate ACPI PIRQ). This adds functionality to generate PIRQ ACPI tables automatically based on the chipset registers. Mapping of PCI interrupt pin to PIRQ is done by the chipset-specific intel_common_map_pirq() function, an shared implementation of which is provided for the bd82x6x, i82801, i89xx, ibexpeak and lynxpoint chipsets. Example generated _PRT: Scope (\_SB.PCI0) { Method (_PRT, 0, NotSerialized) // _PRT: PCI Routing Table { If (PICM) { Return (Package (0x09) { Package (0x04) { 0x0002FFFF, 0x00000000, 0x00000000, 0x00000010 }, 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 }, Package (0x04) { 0x0004FFFF, 0x00000000, 0x00000000, 0x00000010 } }) } Else { Return (Package (0x09) { Package (0x04) { 0x0002FFFF, 0x00000000, \_SB.PCI0.LPCB.LNKA, 0x00000000 }, 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 }, Package (0x04) { 0x0004FFFF, 0x00000000, \_SB.PCI0.LPCB.LNKA, 0x00000000 } }) } } } Change-Id: Ic6b8ce4a9db50211a9c26221ca10105c5a0829a0 Signed-off-by: Tobias Diedrich <ranma+coreboot@tdiedrich.de> Reviewed-on: https://review.coreboot.org/22810 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
Diffstat (limited to 'src/southbridge/intel/common/acpi_pirq_gen.c')
-rw-r--r--src/southbridge/intel/common/acpi_pirq_gen.c115
1 files changed, 115 insertions, 0 deletions
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 0000000000..3ff591c1e5
--- /dev/null
+++ b/src/southbridge/intel/common/acpi_pirq_gen.c
@@ -0,0 +1,115 @@
+/*
+ * 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 size_t enumerate_root_pci_pins(const enum emit_type emit,
+ const char *lpcb_path)
+{
+ char buffer[DEVICE_PATH_MAX];
+ device_t dev;
+ pci_pin_t prev_int_pin = PCI_INT_NONE;
+ u8 prev_pci_dev = 0;
+ size_t num_devs = 0;
+
+ for (dev = all_devices; dev; dev = dev->next) {
+ u8 pci_dev;
+ u8 int_pin;
+ pirq_t 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 == PCI_INT_NONE || int_pin > PCI_INT_D)
+ continue;
+
+ pirq = intel_common_map_pirq(dev, int_pin);
+ if (emit == EMIT_NONE) /* Only print on the first pass */
+ printk(BIOS_SPEW, "ACPI_PIRQ_GEN: %s: pin=%d pirq=%d\n",
+ dev_path(dev), int_pin, pirq);
+
+ if (pirq == PIRQ_NONE)
+ 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 - PCI_INT_A);
+ if (emit == EMIT_APIC) {
+ acpigen_write_dword(0);
+ acpigen_write_dword(16 + (pirq - PIRQ_A));
+ } else {
+ snprintf(buffer, sizeof(buffer),
+ "%s.LNK%c",
+ lpcb_path, 'A' + pirq - PIRQ_A);
+ 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);
+ const size_t num_devs = enumerate_root_pci_pins(EMIT_NONE, lpcb_path);
+
+ if (!lpcb_path)
+ die("ACPI_PIRQ_GEN: Missing LPCB ACPI path\n");
+
+ 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 */
+}