diff --git a/src/soc/intel/fsp_broadwell_de/acpi.c b/src/soc/intel/fsp_broadwell_de/acpi.c index 1e088684c0..1647505820 100644 --- a/src/soc/intel/fsp_broadwell_de/acpi.c +++ b/src/soc/intel/fsp_broadwell_de/acpi.c @@ -4,6 +4,7 @@ * Copyright (C) 2007-2009 coresystems GmbH * Copyright (C) 2013 Google Inc. * Copyright (C) 2015-2016 Intel Corp. + * Copyright (C) 2016 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 @@ -35,6 +36,7 @@ #include #include #include +#include #include uint16_t get_pmbase(void) @@ -312,6 +314,103 @@ void acpi_fill_in_fadt(acpi_fadt_t *fadt, acpi_facs_t *facs, void *dsdt) header->checksum = acpi_checksum((void *) fadt, sizeof(acpi_fadt_t)); } +static unsigned long acpi_fill_dmar(unsigned long current) +{ + uint32_t vtbar, tmp = current; + struct device *dev = dev_find_slot(0, VTD_DEV_FUNC); + uint16_t bdf, hpet_bdf[8]; + uint8_t i, j; + + if (!dev) + return current; + + vtbar = pci_read_config32(dev, VTBAR_OFFSET) & VTBAR_MASK; + if (!vtbar) + return current; + + current += acpi_create_dmar_drhd(current, + DRHD_INCLUDE_PCI_ALL, 0, vtbar); + /* The IIO I/O APIC is fixed on PCI 00:05.4 on Broadwell-DE */ + current += acpi_create_dmar_drhd_ds_ioapic(current, + 9, 0, 5, 4); + /* Get the PCI BDF for the PCH I/O APIC */ + dev = dev_find_slot(0, LPC_DEV_FUNC); + bdf = pci_read_config16(dev, 0x6c); + current += acpi_create_dmar_drhd_ds_ioapic(current, + 8, (bdf >> 8), PCI_SLOT(bdf), PCI_FUNC(bdf)); + + /* + * Check if there are different PCI paths for the 8 HPET timers + * and add every different PCI path as a separate HPET entry. + * Although the DMAR specification talks about HPET block for this + * entry, it is possible to assign a unique PCI BDF to every single + * timer within a HPET block which will result in different source + * IDs reported by a generated MSI. + * In default configuration every single timer will have the same + * PCI BDF which will result in a single HPET entry in DMAR table. + * I have checked several different systems and all of them had one + * single entry for HPET in DMAR. + */ + memset(hpet_bdf, 0, sizeof(hpet_bdf)); + /* Get all unique HPET paths. */ + for (i = 0; i < ARRAY_SIZE(hpet_bdf); i++) { + bdf = pci_read_config16(dev, 0x70 + (i * 2)); + for (j = 0; j < i; j++) { + if (hpet_bdf[j] == bdf) + break; + } + if (j == i) + hpet_bdf[i] = bdf; + } + /* Create one HPET entry in DMAR for every unique HPET PCI path. */ + for (i = 0; i < ARRAY_SIZE(hpet_bdf); i++) { + if (hpet_bdf[i]) + current += acpi_create_dmar_drhd_ds_msi_hpet(current, + 0, (hpet_bdf[i] >> 8), PCI_SLOT(hpet_bdf[i]), + PCI_FUNC(hpet_bdf[i])); + } + acpi_dmar_drhd_fixup(tmp, current); + + /* Create root port ATSR capability */ + tmp = current; + current += acpi_create_dmar_atsr(current, 0, 0); + /* Add one entry to ATSR for each PCI root port */ + dev = all_devices; + do { + dev = dev_find_class(PCI_CLASS_BRIDGE_PCI << 8, dev); + if (dev && dev->bus->secondary == 0 && + PCI_SLOT(dev->path.pci.devfn) <= 3) + current += acpi_create_dmar_drhd_ds_pci_br(current, + dev->bus->secondary, + PCI_SLOT(dev->path.pci.devfn), + PCI_FUNC(dev->path.pci.devfn)); + } while (dev); + acpi_dmar_atsr_fixup(tmp, current); + + return current; +} + +unsigned long northcluster_write_acpi_tables(struct device *const dev, + unsigned long current, + struct acpi_rsdp *const rsdp) +{ + acpi_dmar_t *const dmar = (acpi_dmar_t *)current; + device_t vtdev = dev_find_slot(0, PCI_DEVFN(5, 0)); + + /* Create DMAR table only if virtualization is enabled */ + if (!(pci_read_config32(vtdev, 0x180) & 0x01)) + 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); + current = acpi_align_current(current); + + return current; +} + static int calculate_power(int tdp, int p1_ratio, int ratio) { u32 m; diff --git a/src/soc/intel/fsp_broadwell_de/include/soc/acpi.h b/src/soc/intel/fsp_broadwell_de/include/soc/acpi.h index f717d15a3b..da552cc615 100644 --- a/src/soc/intel/fsp_broadwell_de/include/soc/acpi.h +++ b/src/soc/intel/fsp_broadwell_de/include/soc/acpi.h @@ -3,6 +3,7 @@ * * Copyright (C) 2013 Google, Inc. * Copyright (C) 2015-2016 Intel Corp. + * Copyright (C) 2016 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 @@ -23,5 +24,8 @@ void acpi_create_intel_hpet(acpi_hpet_t *hpet); void acpi_fill_in_fadt(acpi_fadt_t *fadt, acpi_facs_t *facs, void *dsdt); unsigned long acpi_madt_irq_overrides(unsigned long current); uint16_t get_pmbase(void); +unsigned long northcluster_write_acpi_tables(struct device *const dev, + unsigned long current, + struct acpi_rsdp *const rsdp); #endif /* _SOC_ACPI_H_ */ diff --git a/src/soc/intel/fsp_broadwell_de/include/soc/broadwell_de.h b/src/soc/intel/fsp_broadwell_de/include/soc/broadwell_de.h index 6828d03dc9..85298a5ccd 100644 --- a/src/soc/intel/fsp_broadwell_de/include/soc/broadwell_de.h +++ b/src/soc/intel/fsp_broadwell_de/include/soc/broadwell_de.h @@ -17,4 +17,7 @@ #ifndef _SOC_BROADWELL_DE_H_ #define _SOC_BROADWELL_DE_H_ +#define VTBAR_OFFSET 0x180 +#define VTBAR_MASK 0xffffe000 + #endif /* _SOC_BROADWELL_DE_H_ */ diff --git a/src/soc/intel/fsp_broadwell_de/include/soc/pci_devs.h b/src/soc/intel/fsp_broadwell_de/include/soc/pci_devs.h index 5f3cfb963a..c5bb77ab75 100644 --- a/src/soc/intel/fsp_broadwell_de/include/soc/pci_devs.h +++ b/src/soc/intel/fsp_broadwell_de/include/soc/pci_devs.h @@ -27,6 +27,11 @@ #define SOC_DEVID_ES2 0x6F00 #define SOC_DEV_FUNC PCI_DEVFN(SOC_DEV, SOC_FUNC) +#define VTD_DEV 5 +#define VTD_FUNC 0 +#define VTD_DEVID 0x6f28 +#define VTD_DEV_FUNC PCI_DEVFN(VTD_DEV, VTD_FUNC) + #define LPC_DEV 31 #define LPC_FUNC 0 #define LPC_DEVID 0x8C42 diff --git a/src/soc/intel/fsp_broadwell_de/northcluster.c b/src/soc/intel/fsp_broadwell_de/northcluster.c index 38872b4435..c15ff5f2fe 100644 --- a/src/soc/intel/fsp_broadwell_de/northcluster.c +++ b/src/soc/intel/fsp_broadwell_de/northcluster.c @@ -3,6 +3,7 @@ * * Copyright (C) 2013 Google Inc. * Copyright (C) 2015-2016 Intel Corp. + * Copyright (C) 2016 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 @@ -24,6 +25,7 @@ #include #include #include +#include static const int legacy_hole_base_k = 0xa0000 / 1024; static const int legacy_hole_size_k = 384; @@ -133,14 +135,15 @@ static void nc_enable(device_t dev) } static struct device_operations nc_ops = { - .read_resources = nc_read_resources, + .read_resources = nc_read_resources, .acpi_fill_ssdt_generator = generate_cpu_entries, - .set_resources = pci_dev_set_resources, - .enable_resources = pci_dev_enable_resources, - .init = NULL, - .enable = &nc_enable, - .scan_bus = 0, - .ops_pci = &soc_pci_ops, + .write_acpi_tables = northcluster_write_acpi_tables, + .set_resources = pci_dev_set_resources, + .enable_resources = pci_dev_enable_resources, + .init = NULL, + .enable = &nc_enable, + .scan_bus = 0, + .ops_pci = &soc_pci_ops, }; static const struct pci_driver nc_driver __pci_driver = {