From 3b590ffeb4a10f4a394e242974488cbe29299a16 Mon Sep 17 00:00:00 2001 From: Patrick Georgi Date: Tue, 11 Sep 2012 15:21:01 +0200 Subject: acpi: Add support for DMAR tables (Intel IOMMU support) Adds lowlevel handling of DMAR tables for use by mainboards' ACPI code. Not much automagic (yet). Change-Id: Ia86e950dfcc5b9994202ec0e2f6d9a2912c74ad8 Signed-off-by: Patrick Georgi Reviewed-on: http://review.coreboot.org/1654 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer --- src/arch/x86/boot/acpi.c | 65 ++++++++++++++++++++++++++++++++++++++++ src/arch/x86/include/arch/acpi.h | 57 +++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) (limited to 'src/arch') diff --git a/src/arch/x86/boot/acpi.c b/src/arch/x86/boot/acpi.c index 9881ffe4ed..72b6d96576 100644 --- a/src/arch/x86/boot/acpi.c +++ b/src/arch/x86/boot/acpi.c @@ -334,6 +334,71 @@ void acpi_create_srat(acpi_srat_t *srat) header->checksum = acpi_checksum((void *)srat, header->length); } +unsigned long __attribute__((weak)) acpi_fill_dmar(unsigned long current) +{ + return current; +} + +void acpi_create_dmar(acpi_dmar_t *dmar) +{ + acpi_header_t *header = &(dmar->header); + unsigned long current = (unsigned long)dmar + sizeof(acpi_dmar_t); + + memset((void *)dmar, 0, sizeof(acpi_dmar_t)); + + /* Fill out header fields. */ + memcpy(header->signature, "DMAR", 4); + memcpy(header->oem_id, OEM_ID, 6); + memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); + memcpy(header->asl_compiler_id, ASLC, 4); + + header->length = sizeof(acpi_dmar_t); + header->revision = 1; + + dmar->host_address_width = 40 - 1; /* FIXME: == MTRR size? */ + dmar->flags = 0; + + current = acpi_fill_dmar(current); + + /* (Re)calculate length and checksum. */ + header->length = current - (unsigned long)dmar; + header->checksum = acpi_checksum((void *)dmar, header->length); +} + +unsigned long acpi_create_dmar_drhd(unsigned long current, u8 flags, + u16 segment, u32 bar) +{ + dmar_entry_t *drhd = (dmar_entry_t *)current; + memset(drhd, 0, sizeof(*drhd)); + drhd->type = DMAR_DRHD; + drhd->length = sizeof(*drhd); /* will be fixed up later */ + drhd->flags = flags; + drhd->segment = segment; + drhd->bar = bar; + + return drhd->length; +} + +void acpi_dmar_drhd_fixup(unsigned long base, unsigned long current) +{ + dmar_entry_t *drhd = (dmar_entry_t *)base; + drhd->length = current - base; +} + +unsigned long acpi_create_dmar_drhd_ds_pci(unsigned long current, u8 segment, + u8 dev, u8 fn) +{ + dev_scope_t *ds = (dev_scope_t *)current; + memset(ds, 0, sizeof(*ds)); + ds->type = SCOPE_PCI_ENDPOINT; + ds->length = sizeof(*ds) + 2; /* we don't support longer paths yet */ + ds->start_bus = segment; + ds->path[0].dev = dev; + ds->path[0].fn = fn; + + return ds->length; +} + /* http://h21007.www2.hp.com/portal/download/files/unprot/Itanium/slit.pdf */ void acpi_create_slit(acpi_slit_t *slit) { diff --git a/src/arch/x86/include/arch/acpi.h b/src/arch/x86/include/arch/acpi.h index 0b2cbf4492..b39e8c074c 100644 --- a/src/arch/x86/include/arch/acpi.h +++ b/src/arch/x86/include/arch/acpi.h @@ -187,6 +187,54 @@ typedef struct acpi_madt { u32 flags; /* Multiple APIC flags */ } __attribute__ ((packed)) acpi_madt_t; +enum dev_scope_type { + SCOPE_PCI_ENDPOINT = 1, + SCOPE_PCI_SUB = 2, + SCOPE_IOAPIC = 3, + SCOPE_MSI_HPET = 4 +}; + +typedef struct dev_scope { + u8 type; + u8 length; + u8 reserved[2]; + u8 enumeration; + u8 start_bus; + struct { + u8 dev; + u8 fn; + } __attribute__((packed)) path[0]; +} __attribute__ ((packed)) dev_scope_t; + +enum dmar_type { + DMAR_DRHD = 0, + DMAR_RMRR = 1, + DMAR_ATSR = 2, + DMAR_RHSA = 3 +}; + +enum { + DRHD_INCLUDE_PCI_ALL = 1 +}; + +typedef struct dmar_entry { + u16 type; + u16 length; + u8 flags; + u8 reserved; + u16 segment; + u64 bar; +} __attribute__ ((packed)) dmar_entry_t; + +/* DMAR (DMA Remapping Reporting Structure) */ +typedef struct acpi_dmar { + struct acpi_table_header header; + u8 host_address_width; + u8 flags; + u8 reserved[10]; + dmar_entry_t structure[0]; +} __attribute__ ((packed)) acpi_dmar_t; + /* MADT: APIC Structure Types */ /* TODO: Convert to ALLCAPS. */ enum acpi_apic_types { @@ -483,6 +531,15 @@ void acpi_create_mcfg(acpi_mcfg_t *mcfg); void acpi_create_facs(acpi_facs_t *facs); +void acpi_create_dmar(acpi_dmar_t *dmar); +unsigned long acpi_create_dmar_drhd(unsigned long current, u8 flags, + u16 segment, u32 bar); +void acpi_dmar_drhd_fixup(unsigned long base, unsigned long current); +unsigned long acpi_create_dmar_drhd_ds_pci(unsigned long current, u8 segment, + u8 dev, u8 fn); + +unsigned long acpi_fill_dmar(unsigned long); + #if CONFIG_HAVE_ACPI_SLIC unsigned long acpi_create_slic(unsigned long current); #endif -- cgit v1.2.3