Youness Alaoui has uploaded this change for review. ( https://review.coreboot.org/23681
Change subject: soc/intel/skylake: Generate ACPI DMAR table ......................................................................
soc/intel/skylake: Generate ACPI DMAR table
The DMAR ACPI table gets added if VT-d is supported and if IOMMU is enabled and properly configured.
This code was influenced by Nico Huber's implementation [1].
[1] https://review.coreboot.org/#/c/coreboot/+/21588/
Change-Id: Iea48a349d60bdd2e7d3bc74b4e1036b050d2ae71 Signed-off-by: Youness Alaoui youness.alaoui@puri.sm --- M src/soc/intel/skylake/acpi.c M src/soc/intel/skylake/chip.c M src/soc/intel/skylake/chip_fsp20.c M src/soc/intel/skylake/include/soc/acpi.h M src/soc/intel/skylake/include/soc/p2sb.h M src/soc/intel/skylake/include/soc/systemagent.h 6 files changed, 79 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/81/23681/1
diff --git a/src/soc/intel/skylake/acpi.c b/src/soc/intel/skylake/acpi.c index a0be5f5..42c7350 100644 --- a/src/soc/intel/skylake/acpi.c +++ b/src/soc/intel/skylake/acpi.c @@ -39,9 +39,11 @@ #include <soc/cpu.h> #include <soc/iomap.h> #include <soc/msr.h> +#include <soc/p2sb.h> #include <soc/pci_devs.h> #include <soc/pm.h> #include <soc/ramstage.h> +#include <soc/systemagent.h> #include <string.h> #include <types.h> #include <vendorcode/google/chromeos/gnvs.h> @@ -341,6 +343,51 @@ fadt->x_gpe1_blk.addrh = 0x0; }
+static unsigned long acpi_fill_dmar(unsigned long current) +{ + struct device *const igfx_dev = dev_find_slot(0, SA_DEVFN_IGD); + struct device *const p2sb_dev = dev_find_slot(0, PCH_DEVFN_P2SB); + const u32 gfx_vtbar = MCHBAR32(IOMMU1BAR) & ~0xfff; + const u32 vtdpvc0_bar = MCHBAR32(IOMMU2BAR) & ~0xfff; + + /* iGFX has to be enabled, GFXVTBAR set and in 32-bit space. */ + if (igfx_dev && igfx_dev->enabled && + gfx_vtbar && !MCHBAR32(IOMMU1BAR + 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); + } + + + /* General VTBAR has to be set and in 32-bit space. */ + if (p2sb_dev && vtdpvc0_bar && !MCHBAR32(IOMMU2BAR + 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, vtdpvc0_bar); + 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; +} + static void generate_c_state_entries(int s0ix_enable, int max_cstate) {
@@ -566,6 +613,27 @@ return acpi_align_current(current); }
+unsigned long northbridge_write_acpi_tables(device_t device, + unsigned long current, + struct acpi_rsdp *rsdp) +{ + acpi_dmar_t *const dmar = (acpi_dmar_t *) current; + struct device *const root_dev = dev_find_slot(0, SA_DEVFN_ROOT); + + /* Create DMAR table only if we have VT-d capability. */ + if (!root_dev || pci_read_config32(root_dev, CAPID0_A) & VTDD) + return current; + + printk(BIOS_DEBUG, "ACPI: * DMAR\n"); + + acpi_create_dmar(dmar, DMAR_INTR_REMAP, acpi_fill_dmar); + if (dmar->header.length > sizeof(acpi_dmar_t)) { + current += dmar->header.length; + acpi_add_table(rsdp, dmar); + } + return acpi_align_current(current); +} + void southbridge_inject_dsdt(device_t device) { global_nvs_t *gnvs; diff --git a/src/soc/intel/skylake/chip.c b/src/soc/intel/skylake/chip.c index f60c08d..f2fd9fe 100644 --- a/src/soc/intel/skylake/chip.c +++ b/src/soc/intel/skylake/chip.c @@ -49,6 +49,7 @@ .scan_bus = &pci_domain_scan_bus, .ops_pci_bus = &pci_bus_default_ops, #if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES) + .write_acpi_tables = &northbridge_write_acpi_tables, .acpi_name = &soc_acpi_name, #endif }; diff --git a/src/soc/intel/skylake/chip_fsp20.c b/src/soc/intel/skylake/chip_fsp20.c index 3bc66b2..abfb049 100644 --- a/src/soc/intel/skylake/chip_fsp20.c +++ b/src/soc/intel/skylake/chip_fsp20.c @@ -57,6 +57,7 @@ .scan_bus = &pci_domain_scan_bus, .ops_pci_bus = &pci_bus_default_ops, #if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES) + .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 b0d2194..d9524e6 100644 --- a/src/soc/intel/skylake/include/soc/acpi.h +++ b/src/soc/intel/skylake/include/soc/acpi.h @@ -32,5 +32,7 @@ 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(device_t device, + unsigned long current, struct acpi_rsdp *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 d846dfc..9fb2653 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))
diff --git a/src/soc/intel/skylake/include/soc/systemagent.h b/src/soc/intel/skylake/include/soc/systemagent.h index d8192a3..54ff121 100644 --- a/src/soc/intel/skylake/include/soc/systemagent.h +++ b/src/soc/intel/skylake/include/soc/systemagent.h @@ -32,9 +32,13 @@ #define D_LCK (1 << 4) #define G_SMRAME (1 << 3) #define C_BASE_SEG ((0 << 2) | (1 << 1) | (0 << 0)) +#define CAPID0_A 0x94 +#define VTDD (1 << 23)
#define BIOS_RESET_CPL 0x5da8 #define EDRAMBAR 0x5408 +#define IOMMU1BAR 0x5400 +#define IOMMU2BAR 0x5410 #define GDXCBAR 0x5420
#define MCH_PKG_POWER_LIMIT_LO 0x59a0