From e5b5fc345a6a3bc527e4e259c76af2077251e631 Mon Sep 17 00:00:00 2001 From: Shuo Liu Date: Fri, 15 Nov 2024 19:41:01 +0800 Subject: [PATCH] soc/intel/xeon_sp: Improve PCI INTx IRQ routing for Gen6 1. Route IRQ for on-chip end-points only (e.g. 00:1f.4 i801_smbus) IRQ routing for devices under root ports needs additional swizzle per decided by root port configurations, which will postponed to later till there is actual usage. 2. Route IRQ based on FSP programmed end-point device ID <-> PIRQ mapping. TESTED=Build and boot on intel/avenuecity CRB Change-Id: Ibeb7c8fb3432e5cb240ac3b09c19d2c361e4b45a Signed-off-by: Shuo Liu Reviewed-on: https://review.coreboot.org/c/coreboot/+/85153 Tested-by: build bot (Jenkins) Reviewed-by: Angel Pons --- src/soc/intel/xeon_sp/include/soc/irq.h | 1 + src/soc/intel/xeon_sp/lpc_gen6.c | 58 ++++++++++++++++++++++--- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/src/soc/intel/xeon_sp/include/soc/irq.h b/src/soc/intel/xeon_sp/include/soc/irq.h index 4d3ad7a09f..209f69942e 100644 --- a/src/soc/intel/xeon_sp/include/soc/irq.h +++ b/src/soc/intel/xeon_sp/include/soc/irq.h @@ -6,5 +6,6 @@ #define PCH_IRQ10 10 #define PCH_IRQ11 11 #define PCH_IRQ14 14 +#define PCH_IRQ16 16 #endif /* _SOC_IRQ_H_ */ diff --git a/src/soc/intel/xeon_sp/lpc_gen6.c b/src/soc/intel/xeon_sp/lpc_gen6.c index d4045a877d..9455510118 100644 --- a/src/soc/intel/xeon_sp/lpc_gen6.c +++ b/src/soc/intel/xeon_sp/lpc_gen6.c @@ -1,9 +1,12 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ #include +#include +#include #include #include #include +#include #include #include @@ -30,15 +33,56 @@ void lpc_soc_fill_ssdt(const struct device *dev) acpigen_write_scope_end(); /* Scope */ } +uint32_t itss_soc_get_on_chip_dev_pir(const struct device *dev) +{ + assert(is_pci(dev)); + return PCI_ITSS_PIR(PCI_SLOT(dev->path.pci.devfn)); +} + +static void soc_itss_route_irq(const struct device *irq_dev, uint8_t int_pin) +{ + uint8_t pirq = itss_get_on_chip_dev_pirq(irq_dev, int_pin); + if (pirq == PIRQ_INVALID) + return; + + uint8_t pirq_rout = pcr_read8(PID_ITSS, + PCR_ITSS_PIRQA_ROUT + pirq_idx(pirq)); + uint8_t int_line = (pirq_rout & 0x80) ? pirq_idx(pirq) + PCH_IRQ16 : pirq_rout & 0xf; + + printk(BIOS_SPEW, "routing irq: dev %s, pin %d, pirq %d, intline %d\n", + dev_path(irq_dev), int_pin, pirq, int_line); + pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, int_line); +} + +static void soc_pch_pirq_init(void) +{ + /* Program irq pin/line for PCI devices using 8259 compatible mode */ + size_t pirq_routes; + const uint8_t *pirq_routing_legacy = lpc_get_pic_pirq_routing(&pirq_routes); + + itss_irq_init(pirq_routing_legacy); + for (int i = 0; i < PIRQ_COUNT; i++) + itss_set_irq_polarity(pirq_routing_legacy[i], 1); + + /* Route irq for end-points */ + struct device *domain = NULL; + while ((domain = dev_find_path(domain, DEVICE_PATH_DOMAIN))) { + struct device *irq_dev = NULL; + while ((irq_dev = dev_bus_each_child(domain->downstream, irq_dev))) { + if (!is_enabled_pci(irq_dev)) + continue; + uint8_t int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN); + if (int_pin < PCI_INT_A || int_pin > PCI_INT_D) + continue; + + soc_itss_route_irq(irq_dev, int_pin); + } + } +} + void lpc_soc_init(struct device *dev) { printk(BIOS_SPEW, "pch: lpc_init\n"); - /* Program irq pin/line for PCI devices by PCH convention */ - pch_pirq_init(); - - /* Explicitly set polarity low for PIRQA to PIRQH */ - for (int i = 0; i < PIRQ_COUNT; i++) { - itss_set_irq_polarity(pcr_read8(PID_ITSS, PCR_ITSS_PIRQA_ROUT + i), 1); - } + soc_pch_pirq_init(); }