From c37b0e3d07e453971e4778bb167030d335f946b8 Mon Sep 17 00:00:00 2001 From: Nico Huber Date: Mon, 18 Sep 2017 20:03:46 +0200 Subject: [PATCH] soc/intel/skylake: Generate ACPI DMAR table If the SoC is VT-d capable, write an ACPI DMAR table. The entry for the GFXVTBAR is only generated if the IGD is enabled. Change-Id: I8176401dd19aee7ad09a8a145b7a3801fe5b2ae1 Signed-off-by: Nico Huber Reviewed-on: https://review.coreboot.org/21588 Tested-by: build bot (Jenkins) Reviewed-by: Youness Alaoui --- src/soc/intel/skylake/acpi.c | 71 ++++++++++++++++++++++++ src/soc/intel/skylake/chip_fsp20.c | 3 +- src/soc/intel/skylake/include/soc/acpi.h | 2 + src/soc/intel/skylake/include/soc/p2sb.h | 3 + 4 files changed, 78 insertions(+), 1 deletion(-) diff --git a/src/soc/intel/skylake/acpi.c b/src/soc/intel/skylake/acpi.c index 2e0d87a0f5..699d76affa 100644 --- a/src/soc/intel/skylake/acpi.c +++ b/src/soc/intel/skylake/acpi.c @@ -34,14 +34,17 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include +#include #include #include #include @@ -534,6 +537,74 @@ void generate_cpu_entries(device_t device) } } +static unsigned long acpi_fill_dmar(unsigned long current) +{ + struct device *const igfx_dev = dev_find_slot(0, SA_DEVFN_IGD); + const u32 gfx_vtbar = MCHBAR32(GFXVTBAR) & ~0xfff; + const bool gfxvten = MCHBAR32(GFXVTBAR) & 1; + + /* iGFX has to be enabled, GFXVTBAR set and in 32-bit space. */ + if (igfx_dev && igfx_dev->enabled && gfxvten && + gfx_vtbar && !MCHBAR32(GFXVTBAR + 4)) { + const unsigned long tmp = current; + + current += acpi_create_dmar_drhd(current, 0, 0, gfx_vtbar); + current += acpi_create_dmar_drhd_ds_pci(current, 0, 2, 0); + + acpi_dmar_drhd_fixup(tmp, current); + } + + struct device *const p2sb_dev = dev_find_slot(0, PCH_DEVFN_P2SB); + const u32 vtvc0bar = MCHBAR32(VTVC0BAR) & ~0xfff; + const bool vtvc0en = MCHBAR32(VTVC0BAR) & 1; + + /* General VTBAR has to be set and in 32-bit space. */ + if (p2sb_dev && vtvc0bar && vtvc0en && !MCHBAR32(VTVC0BAR + 4)) { + const unsigned long tmp = current; + + /* P2SB may already be hidden. There's no clear rule, when. */ + const u8 p2sb_hidden = + pci_read_config8(p2sb_dev, PCH_P2SB_E0 + 1); + pci_write_config8(p2sb_dev, PCH_P2SB_E0 + 1, 0); + + const u16 ibdf = pci_read_config16(p2sb_dev, PCH_P2SB_IBDF); + const u16 hbdf = pci_read_config16(p2sb_dev, PCH_P2SB_HBDF); + + pci_write_config8(p2sb_dev, PCH_P2SB_E0 + 1, p2sb_hidden); + + current += acpi_create_dmar_drhd(current, + DRHD_INCLUDE_PCI_ALL, 0, vtvc0bar); + current += acpi_create_dmar_drhd_ds_ioapic(current, + 2, ibdf >> 8, PCI_SLOT(ibdf), PCI_FUNC(ibdf)); + current += acpi_create_dmar_drhd_ds_msi_hpet(current, + 0, hbdf >> 8, PCI_SLOT(hbdf), PCI_FUNC(hbdf)); + + acpi_dmar_drhd_fixup(tmp, current); + } + + return current; +} + +unsigned long northbridge_write_acpi_tables(struct device *const dev, + unsigned long current, + struct acpi_rsdp *const rsdp) +{ + const struct soc_intel_skylake_config *const config = dev->chip_info; + acpi_dmar_t *const dmar = (acpi_dmar_t *)current; + + /* Create DMAR table only if we have VT-d capability. */ + if ((config && config->ignore_vtd) || !soc_is_vtd_capable()) + return current; + + printk(BIOS_DEBUG, "ACPI: * DMAR\n"); + acpi_create_dmar(dmar, DMAR_INTR_REMAP, acpi_fill_dmar); + current += dmar->header.length; + current = acpi_align_current(current); + acpi_add_table(rsdp, dmar); + + return current; +} + unsigned long acpi_madt_irq_overrides(unsigned long current) { int sci = acpi_sci_irq(); diff --git a/src/soc/intel/skylake/chip_fsp20.c b/src/soc/intel/skylake/chip_fsp20.c index 4ac73b57c6..054ed089dc 100644 --- a/src/soc/intel/skylake/chip_fsp20.c +++ b/src/soc/intel/skylake/chip_fsp20.c @@ -60,7 +60,8 @@ static struct device_operations pci_domain_ops = { .scan_bus = &pci_domain_scan_bus, .ops_pci_bus = &pci_bus_default_ops, #if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES) - .acpi_name = &soc_acpi_name, + .write_acpi_tables = &northbridge_write_acpi_tables, + .acpi_name = &soc_acpi_name, #endif }; diff --git a/src/soc/intel/skylake/include/soc/acpi.h b/src/soc/intel/skylake/include/soc/acpi.h index b0d2194612..6d492acd67 100644 --- a/src/soc/intel/skylake/include/soc/acpi.h +++ b/src/soc/intel/skylake/include/soc/acpi.h @@ -32,5 +32,7 @@ void acpi_mainboard_gnvs(global_nvs_t *gnvs); void southbridge_inject_dsdt(device_t device); unsigned long southbridge_write_acpi_tables(device_t device, unsigned long current, struct acpi_rsdp *rsdp); +unsigned long northbridge_write_acpi_tables(struct device *, + unsigned long current, struct acpi_rsdp *); #endif /* _SOC_ACPI_H_ */ diff --git a/src/soc/intel/skylake/include/soc/p2sb.h b/src/soc/intel/skylake/include/soc/p2sb.h index d846dfc8f5..09e73fc254 100644 --- a/src/soc/intel/skylake/include/soc/p2sb.h +++ b/src/soc/intel/skylake/include/soc/p2sb.h @@ -19,6 +19,9 @@ #define HPTC_OFFSET 0x60 #define HPTC_ADDR_ENABLE_BIT (1 << 7) +#define PCH_P2SB_IBDF 0x6c +#define PCH_P2SB_HBDF 0x70 + #define PCH_P2SB_EPMASK0 0xB0 #define PCH_P2SB_EPMASK(mask_number) (PCH_P2SB_EPMASK0 + ((mask_number) * 4))