Youness Alaoui has uploaded this change for review. ( https://review.coreboot.org/23682
Change subject: soc/intel/skylake: Add IOMMU support ......................................................................
soc/intel/skylake: Add IOMMU support
Sets up the IOMMU if VT-d is supported by the chipset. Once the MCHBAR and the IBDF/HBDF are set, the ACPI DMAR table should be properly filled with those values.
This work is based on the IOMMU work on sandybridge [1] by Nico Huber.
Tested on Purism Librem 13 v2
[1] Commits bb9469c4 and b2dae793
Change-Id: Ifadaa11340406d1da0f98813589d20118744cc6f Signed-off-by: Youness Alaoui youness.alaoui@puri.sm --- M src/soc/intel/skylake/Makefile.inc M src/soc/intel/skylake/bootblock/pch.c M src/soc/intel/skylake/include/soc/iomap.h A src/soc/intel/skylake/include/soc/iommu.h A src/soc/intel/skylake/iommu.c M src/soc/intel/skylake/romstage/systemagent.c M src/soc/intel/skylake/systemagent.c 7 files changed, 112 insertions(+), 3 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/82/23682/1
diff --git a/src/soc/intel/skylake/Makefile.inc b/src/soc/intel/skylake/Makefile.inc index ef95cf7..a358f35 100644 --- a/src/soc/intel/skylake/Makefile.inc +++ b/src/soc/intel/skylake/Makefile.inc @@ -37,6 +37,7 @@ romstage-y += pmutil.c romstage-$(CONFIG_PLATFORM_USES_FSP2_0) += reset.c romstage-y += spi.c +romstage-y += iommu.c romstage-$(CONFIG_UART_DEBUG) += uart.c
ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpi.c diff --git a/src/soc/intel/skylake/bootblock/pch.c b/src/soc/intel/skylake/bootblock/pch.c index 34cfaa3..0f97d1d 100644 --- a/src/soc/intel/skylake/bootblock/pch.c +++ b/src/soc/intel/skylake/bootblock/pch.c @@ -28,6 +28,7 @@ #include <intelblocks/smbus.h> #include <soc/bootblock.h> #include <soc/iomap.h> +#include <soc/iommu.h> #include <soc/p2sb.h> #include <soc/pch.h> #include <soc/pci_devs.h> @@ -59,6 +60,13 @@ * selected by bits 1:0 */ pci_write_config8(dev, HPTC_OFFSET, HPTC_ADDR_ENABLE_BIT); + + /* Assign unique bus/dev/fn for I/O APIC and HPET */ + pci_write_config16(dev, PCH_P2SB_IBDF, + PCH_IOAPIC_PCI_BUS << 8 | PCH_IOAPIC_PCI_SLOT << 3); + + pci_write_config16(dev, PCH_P2SB_HBDF, + PCH_HPET_PCI_BUS << 8 | PCH_HPET_PCI_SLOT << 3); }
void bootblock_pch_early_init(void) diff --git a/src/soc/intel/skylake/include/soc/iomap.h b/src/soc/intel/skylake/include/soc/iomap.h index 0a573ac..cc38e2e 100644 --- a/src/soc/intel/skylake/include/soc/iomap.h +++ b/src/soc/intel/skylake/include/soc/iomap.h @@ -54,6 +54,10 @@
#define HPET_BASE_ADDRESS 0xfed00000
+#define IOMMU_BASE_ADDRESS1 0xfed90000ULL +#define IOMMU_BASE_ADDRESS2 0xfed91000ULL +#define IOMMU_BASE_SIZE 0x1000 + #define PCH_PWRM_BASE_ADDRESS 0xfe000000 #define PCH_PWRM_BASE_SIZE 0x10000
diff --git a/src/soc/intel/skylake/include/soc/iommu.h b/src/soc/intel/skylake/include/soc/iommu.h new file mode 100644 index 0000000..56df714 --- /dev/null +++ b/src/soc/intel/skylake/include/soc/iommu.h @@ -0,0 +1,30 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2018 Purism SPC + * + * 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. + */ + + +#ifndef _SOC_IOMMU_H_ +#define _SOC_IOMMU_H_ + +#include <stdint.h> + +#define PCH_IOAPIC_PCI_BUS 0xF0 +#define PCH_IOAPIC_PCI_SLOT 0x1F + +#define PCH_HPET_PCI_BUS 0x00 +#define PCH_HPET_PCI_SLOT 0x1F + +void skylake_init_iommu(void); + +#endif diff --git a/src/soc/intel/skylake/iommu.c b/src/soc/intel/skylake/iommu.c new file mode 100644 index 0000000..81028de --- /dev/null +++ b/src/soc/intel/skylake/iommu.c @@ -0,0 +1,50 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 secunet Security Networks 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 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 <stdint.h> + +#include <device/device.h> +#include <intelblocks/systemagent.h> +#include <soc/iomap.h> +#include <soc/iommu.h> +#include <soc/pci_devs.h> +#include <soc/systemagent.h> + +void skylake_init_iommu(void) +{ + static const struct sa_mmio_descriptor iommu_fixed_mch_resources[] = { + {IOMMU1BAR, IOMMU_BASE_ADDRESS1, IOMMU_BASE_SIZE, "IOMMU1BAR"}, + {IOMMU2BAR, IOMMU_BASE_ADDRESS2, IOMMU_BASE_SIZE, "IOMMU2BAR"}, + }; + + if (pci_read_config32(SA_DEV_ROOT, CAPID0_A) & VTDD) + return; + + /* setup BARs */ + sa_set_mch_bar(iommu_fixed_mch_resources, + ARRAY_SIZE(iommu_fixed_mch_resources)); + + /* lock policies */ + write32((void *)(IOMMU_BASE_ADDRESS1 + 0xff0), 0x80000000); + + const struct device *const azalia = dev_find_slot(0, PCH_DEVFN_HDA); + if (azalia && azalia->enabled) { + write32((void *)(IOMMU_BASE_ADDRESS2 + 0xff0), 0x20000000); + write32((void *)(IOMMU_BASE_ADDRESS2 + 0xff0), 0xa0000000); + } else { + write32((void *)(IOMMU_BASE_ADDRESS2 + 0xff0), 0x80000000); + } +} diff --git a/src/soc/intel/skylake/romstage/systemagent.c b/src/soc/intel/skylake/romstage/systemagent.c index 8f2fb33..e7a2f4a 100644 --- a/src/soc/intel/skylake/romstage/systemagent.c +++ b/src/soc/intel/skylake/romstage/systemagent.c @@ -18,6 +18,7 @@ #include <device/device.h> #include <intelblocks/systemagent.h> #include <soc/iomap.h> +#include <soc/iommu.h> #include <soc/romstage.h> #include <soc/systemagent.h>
@@ -34,12 +35,15 @@ { EDRAMBAR, EDRAM_BASE_ADDRESS, EDRAM_BASE_SIZE, "EDRAMBAR" }, };
- /* Set Fixed MMIO addresss into PCI configuration space */ + /* Set Fixed MMIO addresses into PCI configuration space */ sa_set_pci_bar(soc_fixed_pci_resources, ARRAY_SIZE(soc_fixed_pci_resources)); - /* Set Fixed MMIO addresss into MCH base address */ + /* Set Fixed MMIO addresses into MCH base address */ sa_set_mch_bar(soc_fixed_mch_resources, ARRAY_SIZE(soc_fixed_mch_resources)); - /* Enable PAM regisers */ + /* Enable PAM registers */ enable_pam_region(); + /* Enable IOMMU. This will set the IOMMU Fixed MMIO addresses into + * MCH base address if device has IOMMU capabilities */ + skylake_init_iommu(); } diff --git a/src/soc/intel/skylake/systemagent.c b/src/soc/intel/skylake/systemagent.c index 8af995d..880593d 100644 --- a/src/soc/intel/skylake/systemagent.c +++ b/src/soc/intel/skylake/systemagent.c @@ -15,6 +15,7 @@ * GNU General Public License for more details. */
+#include <arch/io.h> #include <cpu/x86/msr.h> #include <console/console.h> #include <delay.h> @@ -23,6 +24,7 @@ #include <soc/cpu.h> #include <soc/iomap.h> #include <soc/msr.h> +#include <soc/pci_devs.h> #include <soc/systemagent.h>
/* @@ -42,9 +44,19 @@ { GDXCBAR, GDXC_BASE_ADDRESS, GDXC_BASE_SIZE, "GDXCBAR" }, { EDRAMBAR, EDRAM_BASE_ADDRESS, EDRAM_BASE_SIZE, "EDRAMBAR" }, }; + static const struct sa_mmio_descriptor iommu_fixed_resources[] = { + { IOMMU1BAR, IOMMU_BASE_ADDRESS1, IOMMU_BASE_SIZE, "IOMMU1" }, + { IOMMU2BAR, IOMMU_BASE_ADDRESS2, IOMMU_BASE_SIZE, "IOMMU2" }, + }; + struct device *const root_dev = dev_find_slot(0, SA_DEVFN_ROOT);
sa_add_fixed_mmio_resources(dev, index, soc_fixed_resources, ARRAY_SIZE(soc_fixed_resources)); + + /* Add IOMMU Fixed resources only if we have VT-d capability. */ + if (root_dev && !(pci_read_config32(root_dev, CAPID0_A) & VTDD)) + sa_add_fixed_mmio_resources(dev, index, iommu_fixed_resources, + ARRAY_SIZE(iommu_fixed_resources)); }
/*