Philipp Deppenwiese (zaolin.daisuki@googlemail.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/15164
-gerrit
commit d1f414137b19558edc2ea640808c7d1d98938732 Author: Timothy Pearson tpearson@raptorengineering.com Date: Mon Jun 13 13:48:58 2016 -0500
nb/amd/pi/00730F01: Add initial native IVRS support
Change-Id: I1ae789f75363435accd14a1b556e1570f43f94c4 Signed-off-by: Timothy Pearson tpearson@raptorengineering.com --- src/mainboard/amd/olivehillplus/acpi_tables.c | 9 ++ src/mainboard/pcengines/apu2/acpi_tables.c | 9 ++ src/northbridge/amd/pi/00730F01/northbridge.c | 208 ++++++++++++++++++++++++-- 3 files changed, 214 insertions(+), 12 deletions(-)
diff --git a/src/mainboard/amd/olivehillplus/acpi_tables.c b/src/mainboard/amd/olivehillplus/acpi_tables.c index d5ebad4..a1a5a6b 100644 --- a/src/mainboard/amd/olivehillplus/acpi_tables.c +++ b/src/mainboard/amd/olivehillplus/acpi_tables.c @@ -54,3 +54,12 @@ unsigned long acpi_fill_madt(unsigned long current)
return current; } + +unsigned long acpi_fill_ivrs_ioapic(acpi_ivrs_t* ivrs, unsigned long current) +{ + /* TODO + * Add IVRS entries + */ + + return current; +} diff --git a/src/mainboard/pcengines/apu2/acpi_tables.c b/src/mainboard/pcengines/apu2/acpi_tables.c index d5ebad4..17995ce 100644 --- a/src/mainboard/pcengines/apu2/acpi_tables.c +++ b/src/mainboard/pcengines/apu2/acpi_tables.c @@ -54,3 +54,12 @@ unsigned long acpi_fill_madt(unsigned long current)
return current; } + +unsigned long acpi_fill_ivrs_ioapic(acpi_ivrs_t* ivrs, unsigned long current) +{ + /* TODO + * Add IVRS entries + */ + + return current; +} diff --git a/src/northbridge/amd/pi/00730F01/northbridge.c b/src/northbridge/amd/pi/00730F01/northbridge.c index 9b1c1b1..44b1501 100644 --- a/src/northbridge/amd/pi/00730F01/northbridge.c +++ b/src/northbridge/amd/pi/00730F01/northbridge.c @@ -2,6 +2,7 @@ * This file is part of the coreboot project. * * Copyright (C) 2012 Advanced Micro Devices, Inc. + * Copyright (C) 2016 Raptor Engineering, LLC * * 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 @@ -478,6 +479,193 @@ static unsigned long acpi_fill_hest(acpi_hest_t *hest) return (unsigned long)current; }
+static void add_ivrs_device_entries(struct device *parent, struct device *dev, int depth, int linknum, int8_t *root_level, unsigned long *current, uint16_t *length) +{ + uint8_t *p; + struct device *sibling; + struct bus *link; + + if (!root_level) { + root_level = malloc(sizeof(int8_t)); + *root_level = -1; + } + + if (dev->path.type == DEVICE_PATH_PCI) { + if ((dev->bus->secondary == 0x0) && (dev->path.pci.devfn == 0x0)) + *root_level = depth; + + if (*root_level != -1) { + if (depth >= *root_level) { + if (dev->enabled) { + if (depth == *root_level) { + if (dev->path.pci.devfn == 0x2) { + /* IOMMU */ + p = (uint8_t *) *current; + p[0] = 0x2; /* Entry type */ + p[1] = dev->path.pci.devfn; /* Device */ + p[2] = dev->bus->secondary; /* Bus */ + p[3] = 0x0; /* Data */ + p[4] = 0x0; /* Padding */ + p[5] = 0x0; /* Padding */ + p[6] = 0x0; /* Padding */ + p[7] = 0x0; /* Padding */ + *length += 8; + *current += 8; + } else if (dev->path.pci.devfn < (0x2 << 3)) { + /* FCH control device */ + } else if ((dev->path.pci.devfn >= (0x2 << 3)) && (dev->path.pci.devfn < (0x3 << 3))) { + /* FCH PCIe bridge device */ + p = (uint8_t *) *current; + p[0] = 0x2; /* Entry type */ + p[1] = dev->path.pci.devfn; /* Device */ + p[2] = dev->bus->secondary; /* Bus */ + p[3] = 0x0; /* Data */ + p[4] = 0x0; /* Padding */ + p[5] = 0x0; /* Padding */ + p[6] = 0x0; /* Padding */ + p[7] = 0x0; /* Padding */ + *length += 8; + *current += 8; + } else { + if (dev->path.pci.devfn == (0x14 << 3)) { + /* SMBUS controller */ + p = (uint8_t *) *current; + p[0] = 0x2; /* Entry type */ + p[1] = dev->path.pci.devfn; /* Device */ + p[2] = dev->bus->secondary; /* Bus */ + p[3] = 0x97; /* Data */ + p[4] = 0x0; /* Padding */ + p[5] = 0x0; /* Padding */ + p[6] = 0x0; /* Padding */ + p[7] = 0x0; /* Padding */ + *length += 8; + *current += 8; + } else { + /* Other southbridge device */ + p = (uint8_t *) *current; + p[0] = 0x2; /* Entry type */ + p[1] = dev->path.pci.devfn; /* Device */ + p[2] = dev->bus->secondary; /* Bus */ + p[3] = 0x0; /* Data */ + p[4] = 0x0; /* Padding */ + p[5] = 0x0; /* Padding */ + p[6] = 0x0; /* Padding */ + p[7] = 0x0; /* Padding */ + *length += 8; + *current += 8; + } + } + } else { + if ((dev->hdr_type & 0x7f) == PCI_HEADER_TYPE_NORMAL) { + /* Device behind bridge */ + if (pci_find_capability(dev, PCI_CAP_ID_PCIE)) { + /* Device is PCIe */ + p = (uint8_t *) *current; + p[0] = 0x2; /* Entry type */ + p[1] = dev->path.pci.devfn; /* Device */ + p[2] = dev->bus->secondary; /* Bus */ + p[3] = 0x0; /* Data */ + p[4] = 0x0; /* Padding */ + p[5] = 0x0; /* Padding */ + p[6] = 0x0; /* Padding */ + p[7] = 0x0; /* Padding */ + *length += 8; + *current += 8; + } else { + /* Device is legacy PCI or PCI-X */ + p = (uint8_t *) *current; + p[0] = 0x42; /* Entry type */ + p[1] = dev->path.pci.devfn; /* Device */ + p[2] = dev->bus->secondary; /* Bus */ + p[3] = 0x0; /* Data */ + p[4] = 0x0; /* Reserved */ + p[5] = parent->path.pci.devfn; /* Device */ + p[6] = parent->bus->secondary; /* Bus */ + p[7] = 0x0; /* Reserved */ + *length += 8; + *current += 8; + } + } else if ((dev->hdr_type & 0x7f) == PCI_HEADER_TYPE_BRIDGE) { + if (pci_find_capability(dev, PCI_CAP_ID_PCIE)) { + /* Bridge is PCIe */ + p = (uint8_t *) *current; + p[0] = 0x2; /* Entry type */ + p[1] = dev->path.pci.devfn; /* Device */ + p[2] = dev->bus->secondary; /* Bus */ + p[3] = 0x0; /* Data */ + p[4] = 0x0; /* Padding */ + p[5] = 0x0; /* Padding */ + p[6] = 0x0; /* Padding */ + p[7] = 0x0; /* Padding */ + *length += 8; + *current += 8; + } + } + } + } + } + } + } + + for (link = dev->link_list; link; link = link->next) + for (sibling = link->children; sibling; sibling = sibling->sibling) + add_ivrs_device_entries(dev, sibling, depth + 1, depth, root_level, current, length); + + free(root_level); +} + +static unsigned long acpi_fill_ivrs(acpi_ivrs_t* ivrs, unsigned long current) +{ + uint8_t *p; + + device_t nb_dev = dev_find_slot(0, PCI_DEVFN(0, 0)); + if (!nb_dev) { + printk(BIOS_WARNING, "acpi_fill_ivrs: Unable to locate G-series northbridge device! IVRS table not generated...\n"); + return (unsigned long)ivrs; + } + + ivrs->iv_info = 0x0; + ivrs->iv_info |= (0x40 << 15); /* Maximum supported virtual address size */ + ivrs->iv_info |= (0x30 << 8); /* Maximum supported physical address size */ + ivrs->iv_info |= (0x2 << 5); /* Guest virtual address width */ + + ivrs->ivhd.type = 0x10; + ivrs->ivhd.flags = 0x0e; + ivrs->ivhd.flags |= 0x10; /* Enable ATS support */ + ivrs->ivhd.length = sizeof(struct acpi_ivrs_ivhd); + ivrs->ivhd.device_id = 0x2 | (nb_dev->bus->secondary << 8); /* BDF <bus>:00.2 */ + ivrs->ivhd.capability_offset = 0x40; /* Capability block 0x40 (type 0xf, "Secure device") */ + ivrs->ivhd.iommu_base_low = 0xfeb00000; + ivrs->ivhd.iommu_base_high = 0x0; + ivrs->ivhd.pci_segment_group = 0x0; + ivrs->ivhd.iommu_info = 0x0; + ivrs->ivhd.iommu_info |= (0x13 << 8); + ivrs->ivhd.efr = 0x0; + + /* Describe HPET */ + p = (uint8_t *)current; + p[0] = 0x48; /* Entry type */ + p[1] = 0; /* Device */ + p[2] = 0; /* Bus */ + p[3] = 0xd7; /* Data */ + p[4] = 0x0; /* HPET number */ + p[5] = 0x14 << 3; /* HPET device */ + p[6] = nb_dev->bus->secondary; /* HPET bus */ + p[7] = 0x2; /* Variety */ + ivrs->ivhd.length += 8; + current += 8; + + /* Describe PCI devices */ + add_ivrs_device_entries(NULL, all_devices, 0, -1, NULL, ¤t, &ivrs->ivhd.length); + + /* Describe IOAPICs */ + unsigned long prev_current = current; + current = acpi_fill_ivrs_ioapic(ivrs, current); + ivrs->ivhd.length += (current - prev_current); + + return current; +} + static void northbridge_fill_ssdt_generator(device_t device) { msr_t msr; @@ -507,7 +695,7 @@ static unsigned long agesa_write_acpi_tables(device_t device, acpi_slit_t *slit; acpi_header_t *ssdt; acpi_header_t *alib; - acpi_header_t *ivrs; + acpi_ivrs_t *ivrs; acpi_hest_t *hest;
/* HEST */ @@ -517,17 +705,13 @@ static unsigned long agesa_write_acpi_tables(device_t device, acpi_add_table(rsdp, (void *)current); current += ((acpi_header_t *)current)->length;
- current = ALIGN(current, 8); - printk(BIOS_DEBUG, "ACPI: * IVRS at %lx\n", current); - ivrs = agesawrapper_getlateinitptr(PICK_IVRS); - if (ivrs != NULL) { - memcpy((void *)current, ivrs, ivrs->length); - ivrs = (acpi_header_t *) current; - current += ivrs->length; - acpi_add_table(rsdp, ivrs); - } else { - printk(BIOS_DEBUG, " AGESA IVRS table NULL. Skipping.\n"); - } + /* IVRS */ + current = ALIGN(current, 8); + printk(BIOS_DEBUG, "ACPI: * IVRS at %lx\n", current); + ivrs = (acpi_ivrs_t *) current; + acpi_create_ivrs(ivrs, acpi_fill_ivrs); + current += ivrs->header.length; + acpi_add_table(rsdp, ivrs);
/* SRAT */ current = ALIGN(current, 8);