diff options
author | Werner Zeh <werner.zeh@siemens.com> | 2018-12-14 13:26:04 +0100 |
---|---|---|
committer | Patrick Georgi <pgeorgi@google.com> | 2019-01-28 13:42:32 +0000 |
commit | 90cc7e24b05237e9b4e1dbd8f318fbf86e50d4e0 (patch) | |
tree | 62eab60464e6f65858022386ef4a9031aceb322a | |
parent | d12530cb838c4fa2d503d27c9ea19e8ffb515725 (diff) |
soc/apollolake: Generate DMAR table
Generate DMAR table if VTd feature is enabled.
Test=Booted into Linux on mc_apl2 and verified the DMAR table contents.
In addition turned off Vtd and verified that no DMAR table is generated
at all.
Change-Id: Ie3683a2f3578c141c691b2268e32f27ba2e772fa
Signed-off-by: Werner Zeh <werner.zeh@siemens.com>
Reviewed-on: https://review.coreboot.org/c/30990
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Nico Huber <nico.h@gmx.de>
4 files changed, 100 insertions, 3 deletions
diff --git a/src/soc/intel/apollolake/acpi.c b/src/soc/intel/apollolake/acpi.c index 0c4ff81e82..6780ec4860 100644 --- a/src/soc/intel/apollolake/acpi.c +++ b/src/soc/intel/apollolake/acpi.c @@ -2,7 +2,7 @@ * This file is part of the coreboot project. * * Copyright (C) 2016 Intel Corp. - * Copyright (C) 2017 Siemens AG + * Copyright (C) 2017-2019 Siemens AG * (Written by Lance Zhao <lijian.zhao@intel.com> for Intel Corp.) * * This program is free software; you can redistribute it and/or modify @@ -20,16 +20,19 @@ #include <arch/acpigen.h> #include <arch/io.h> #include <arch/smp/mpspec.h> +#include <device/pci_ops.h> #include <cbmem.h> #include <cpu/x86/smm.h> #include <gpio.h> #include <intelblocks/acpi.h> #include <intelblocks/pmclib.h> #include <intelblocks/sgx.h> +#include <intelblocks/p2sb.h> #include <soc/iomap.h> #include <soc/pm.h> #include <soc/nvs.h> #include <soc/pci_devs.h> +#include <soc/systemagent.h> #include <string.h> #include "chip.h" @@ -178,6 +181,88 @@ void soc_fill_fadt(acpi_fadt_t *fadt) fadt->flags |= ACPI_FADT_LOW_PWR_IDLE_S0; } +static unsigned long soc_fill_dmar(unsigned long current) +{ + struct device *const igfx_dev = dev_find_slot(0, SA_DEVFN_IGD); + uint64_t gfxvtbar = MCHBAR64(GFXVTBAR) & VTBAR_MASK; + uint64_t defvtbar = MCHBAR64(DEFVTBAR) & VTBAR_MASK; + bool gfxvten = MCHBAR32(GFXVTBAR) & VTBAR_ENABLED; + bool defvten = MCHBAR32(DEFVTBAR) & VTBAR_ENABLED; + unsigned long tmp; + + /* IGD has to be enabled, GFXVTBAR set and enabled. */ + if (igfx_dev && igfx_dev->enabled && gfxvtbar && gfxvten) { + tmp = current; + + current += acpi_create_dmar_drhd(current, 0, 0, gfxvtbar); + current += acpi_create_dmar_ds_pci(current, 0, 2, 0); + acpi_dmar_drhd_fixup(tmp, current); + + /* Add RMRR entry */ + tmp = current; + current += acpi_create_dmar_rmrr(current, 0, + sa_get_gsm_base(), sa_get_tolud_base() - 1); + current += acpi_create_dmar_ds_pci(current, 0, 2, 0); + acpi_dmar_rmrr_fixup(tmp, current); + } + + /* DEFVTBAR has to be set and enabled. */ + if (defvtbar && defvten) { + tmp = current; + /* + * P2SB may already be hidden. There's no clear rule, when. + * It is needed to get bus, device and function for IOAPIC and + * HPET device which is stored in P2SB device. So unhide it to + * get the info and hide it again when done. + */ + p2sb_unhide(); + struct device *p2sb_dev = dev_find_slot(0, PCH_DEVFN_P2SB); + uint16_t ibdf = pci_read_config16(p2sb_dev, PCH_P2SB_IBDF); + uint16_t hbdf = pci_read_config16(p2sb_dev, PCH_P2SB_HBDF); + p2sb_hide(); + + current += acpi_create_dmar_drhd(current, + DRHD_INCLUDE_PCI_ALL, 0, defvtbar); + current += acpi_create_dmar_ds_ioapic(current, + 2, ibdf >> 8, PCI_SLOT(ibdf), PCI_FUNC(ibdf)); + current += acpi_create_dmar_ds_msi_hpet(current, + 0, hbdf >> 8, PCI_SLOT(hbdf), PCI_FUNC(hbdf)); + acpi_dmar_drhd_fixup(tmp, current); + } + + return current; +} + +unsigned long sa_write_acpi_tables(struct device *const dev, + unsigned long current, + struct acpi_rsdp *const rsdp) +{ + acpi_dmar_t *const dmar = (acpi_dmar_t *)current; + + /* Create DMAR table only if virtualization is enabled. Due to some + * constraints on Apollo Lake SoC (some stepping affected), VTD could + * not be enabled together with IPU. Doing so will override and disable + * VTD while leaving CAPID0_A still reporting that VTD is available. + * As in this case FSP will lock VTD to disabled state, we need to make + * sure that DMAR table generation only happens when at least DEFVTBAR + * is enabled. Otherwise the DMAR header will be generated while the + * content of the table will be missing. + */ + + if ((pci_read_config32(dev, CAPID0_A) & VTD_DISABLE) || + !(MCHBAR32(DEFVTBAR) & VTBAR_ENABLED)) + return current; + + printk(BIOS_DEBUG, "ACPI: * DMAR\n"); + acpi_create_dmar(dmar, DMAR_INTR_REMAP, soc_fill_dmar); + current += dmar->header.length; + current = acpi_align_current(current); + acpi_add_table(rsdp, dmar); + current = acpi_align_current(current); + + return current; +} + void soc_power_states_generation(int core_id, int cores_per_package) { /* Generate P-state tables */ diff --git a/src/soc/intel/apollolake/include/soc/systemagent.h b/src/soc/intel/apollolake/include/soc/systemagent.h index fe9c15feaa..46c1d7d9c7 100644 --- a/src/soc/intel/apollolake/include/soc/systemagent.h +++ b/src/soc/intel/apollolake/include/soc/systemagent.h @@ -3,6 +3,7 @@ * * Copyright (C) 2015 Intel Corp. * (Written by Andrey Petrov <andrey.petrov@intel.com> for Intel Corp.) + * Copyright (C) 2019 Siemens AG * * 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 @@ -28,5 +29,12 @@ #define PCODE_INIT_DONE (1 << 8) #define MCHBAR_RAPL_PPL 0x70A8 #define CORE_DISABLE_MASK 0x7168 +#define CAPID0_A 0xE4 +#define VTD_DISABLE (1 << 23) +#define DEFVTBAR 0x6c80 +#define GFXVTBAR 0x6c88 +#define VTBAR_ENABLED 0x01 +#define VTBAR_MASK 0xfffffff000ull +#define VTBAR_SIZE 0x1000 #endif /* SOC_APOLLOLAKE_SYSTEMAGENT_H */ diff --git a/src/soc/intel/common/block/include/intelblocks/p2sb.h b/src/soc/intel/common/block/include/intelblocks/p2sb.h index e5c1f3ef6a..72a3a33774 100644 --- a/src/soc/intel/common/block/include/intelblocks/p2sb.h +++ b/src/soc/intel/common/block/include/intelblocks/p2sb.h @@ -2,6 +2,7 @@ * This file is part of the coreboot project. * * Copyright (C) 2017-2018 Intel Corporation. + * Copyright (C) 2019 Siemens AG * * 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 @@ -19,8 +20,10 @@ #include <stddef.h> #include <stdint.h> -#define PCH_P2SB_E0 0xe0 -#define P2SB_E0_MASKLOCK (1 << 1) +#define PCH_P2SB_E0 0xe0 +#define P2SB_E0_MASKLOCK (1 << 1) +#define PCH_P2SB_IBDF 0x6c +#define PCH_P2SB_HBDF 0x70 enum { P2SB_EP_MASK_0_REG, diff --git a/src/soc/intel/common/block/include/intelblocks/systemagent.h b/src/soc/intel/common/block/include/intelblocks/systemagent.h index babf9cec95..133047c5b7 100644 --- a/src/soc/intel/common/block/include/intelblocks/systemagent.h +++ b/src/soc/intel/common/block/include/intelblocks/systemagent.h @@ -33,6 +33,7 @@ #define MCHBAR8(x) (*(volatile u8 *)(MCH_BASE_ADDRESS + x)) #define MCHBAR16(x) (*(volatile u16 *)(MCH_BASE_ADDRESS + x)) #define MCHBAR32(x) (*(volatile u32 *)(MCH_BASE_ADDRESS + x)) +#define MCHBAR64(x) (*(volatile u64 *)(MCH_BASE_ADDRESS + x)) /* Perform System Agent Initialization during Bootblock phase */ void bootblock_systemagent_early_init(void); |