Michał Żygowski has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/40042 )
Change subject: nb/amd/pi/00730F01/northbridge.c: refactor IVRS generation ......................................................................
nb/amd/pi/00730F01/northbridge.c: refactor IVRS generation
Use defined structures to assemble IVRS and IVHD entries. Additionally assemble IVHD type 11h which supersedes IVHD type 10h. In order to utilize all IOMMU features firmware should also expose IVHD type 11h. The new type is already supported and parsed since Xen 1.13. IVHD type 10h should still be present for backwards compatibility.
TEST=boot PC Engines apu2 and disassemble IVRS using newest IASL
Signed-off-by: Michał Żygowski michal.zygowski@3mdeb.com Change-Id: I9a2c24b67adfa8ebd718caeb5eec88687dcbcc9d --- M src/northbridge/amd/pi/00730F01/northbridge.c 1 file changed, 239 insertions(+), 145 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/42/40042/1
diff --git a/src/northbridge/amd/pi/00730F01/northbridge.c b/src/northbridge/amd/pi/00730F01/northbridge.c index f611bd6..56fab07 100644 --- a/src/northbridge/amd/pi/00730F01/northbridge.c +++ b/src/northbridge/amd/pi/00730F01/northbridge.c @@ -15,6 +15,7 @@ #include <console/console.h> #include <device/pci_ops.h> #include <arch/acpi.h> +#include <arch/acpi_ivrs.h> #include <arch/ioapic.h> #include <stdint.h> #include <device/device.h> @@ -22,6 +23,7 @@ #include <device/pci_ids.h> #include <device/hypertransport.h> #include <string.h> +#include <stdlib.h> #include <lib.h> #include <cpu/cpu.h> #include <Porting.h> @@ -33,6 +35,7 @@ #include <arch/acpigen.h> #include <northbridge/amd/pi/nb_common.h> #include <northbridge/amd/agesa/agesa_helper.h> +#include <southbridge/amd/pi/hudson/pci_devs.h>
#define MAX_NODE_NUMS MAX_NODES #define PCIE_CAP_AER BIT(5) @@ -439,59 +442,145 @@ return (unsigned long)current; }
-static void add_ivhd_dev_entry(struct device *parent, struct device *dev, - unsigned long *current, uint16_t *length, - uint8_t type, uint8_t data) +unsigned long acpi_fill_ivrs_ioapic(acpi_ivrs_t *ivrs, unsigned long current) { - uint8_t *p; - p = (uint8_t *) *current; + /* 8-byte IVHD structures must be aligned to the 8-byte boundary. */ + unsigned long offset = ((current + 0x7) & (~ 0x7)) - current; + ivrs_ivhd_special_t *ivhd_ioapic = (ivrs_ivhd_special_t *)(current + offset);
- if (type == 0x2) { - /* Entry type */ - p[0] = type; - /* Device */ - p[1] = dev->path.pci.devfn; - /* Bus */ - p[2] = dev->bus->secondary; - /* Data */ - p[3] = data; - /* [4:7] Padding */ - p[4] = 0x0; - p[5] = 0x0; - p[6] = 0x0; - p[7] = 0x0; - *length += 8; - *current += 8; - } else if (type == 0x42) { - /* Entry type */ - p[0] = type; - /* Device */ - p[1] = dev->path.pci.devfn; - /* Bus */ - p[2] = dev->bus->secondary; - /* Data */ - p[3] = 0x0; - /* Reserved */ - p[4] = 0x0; - /* Device */ - p[5] = parent->path.pci.devfn; - /* Bus */ - p[6] = parent->bus->secondary; - /* Reserved */ - p[7] = 0x0; - *length += 8; - *current += 8; + ivhd_ioapic->type = IVHD_DEV_8_BYTE_EXT_SPECIAL_DEV; + ivhd_ioapic->reserved = 0x0000; + ivhd_ioapic->dte_setting = IVHD_DTE_LINT_1_PASS | IVHD_DTE_LINT_0_PASS | + IVHD_DTE_SYS_MGT_NO_TRANS | IVHD_DTE_NMI_PASS | + IVHD_DTE_EXT_INT_PASS | IVHD_DTE_INIT_PASS; + ivhd_ioapic->handle = CONFIG_MAX_CPUS; /* FCH IOAPIC ID */ + ivhd_ioapic->source_dev_id = PCI_DEVFN(SMBUS_DEV, SMBUS_FUNC); + ivhd_ioapic->variety = IVHD_SPECIAL_DEV_IOAPIC; + current += sizeof(ivrs_ivhd_special_t) + offset; + + ivhd_ioapic = (ivrs_ivhd_special_t *)current; + + ivhd_ioapic->type = IVHD_DEV_8_BYTE_EXT_SPECIAL_DEV; + ivhd_ioapic->reserved = 0x0000; + ivhd_ioapic->dte_setting = 0x00; + ivhd_ioapic->handle = CONFIG_MAX_CPUS + 1; /* GNB IOAPIC ID */ + ivhd_ioapic->source_dev_id = PCI_DEVFN(0, 1); + ivhd_ioapic->variety = IVHD_SPECIAL_DEV_IOAPIC; + current += sizeof(ivrs_ivhd_special_t); + + return current; +} + +static unsigned long ivhd_describe_hpet(unsigned long current, uint16_t *ivhd_length) +{ + /* 8-byte IVHD structures must be aligned to the 8-byte boundary. */ + unsigned long offset = ((current + 0x7) & (~ 0x7)) - current; + ivrs_ivhd_special_t *ivhd_hpet = (ivrs_ivhd_special_t *)(current + offset); + + ivhd_hpet->type = IVHD_DEV_8_BYTE_EXT_SPECIAL_DEV; + ivhd_hpet->reserved = 0x0000; + ivhd_hpet->dte_setting = 0x00; + ivhd_hpet->handle = 0x00; + ivhd_hpet->source_dev_id = PCI_DEVFN(SMBUS_DEV, SMBUS_FUNC); + ivhd_hpet->variety = IVHD_SPECIAL_DEV_HPET; + current += sizeof(ivrs_ivhd_special_t) + offset; + *ivhd_length += sizeof(ivrs_ivhd_special_t) + offset; + + return current; +} + +static unsigned long ivhd_dev_range(unsigned long current, uint16_t start_devid, + uint16_t end_devid, uint8_t setting, uint16_t *ivhd_length) +{ + /* 4-byte IVHD structures must be aligned to the 4-byte boundary. */ + unsigned long offset = ((current + 0x3) & (~ 0x3)) - current; + ivrs_ivhd_generic_t *ivhd_range = (ivrs_ivhd_generic_t *)(current + offset); + + /* Create the start range IVHD entry */ + ivhd_range->type = IVHD_DEV_4_BYTE_START_RANGE; + ivhd_range->dev_id = start_devid; + ivhd_range->dte_setting = setting; + + current += sizeof(ivrs_ivhd_generic_t) + offset; + *ivhd_length += sizeof(ivrs_ivhd_generic_t) + offset; + + /* Create the end range IVHD entry */ + ivhd_range = (ivrs_ivhd_generic_t *)current; + ivhd_range->type = IVHD_DEV_4_BYTE_END_RANGE; + ivhd_range->dev_id = end_devid; + ivhd_range->dte_setting = setting; + + current += sizeof(ivrs_ivhd_generic_t) + offset; + *ivhd_length += sizeof(ivrs_ivhd_generic_t) + offset; + + return current; +} + +static void add_ivhd_dev_entry(struct device *parent, struct device *dev, + unsigned long *current, uint16_t *ivhd_length, uint8_t type, + uint8_t data) +{ + unsigned long offset; + + if (type == IVHD_DEV_4_BYTE_SELECT) { + /* 4-byte IVHD structures must be aligned to the 4-byte boundary. */ + offset = ((*current + 0x3) & (~ 0x3)) - *current; + ivrs_ivhd_generic_t *ivhd_entry = (ivrs_ivhd_generic_t *)(*current + offset); + + ivhd_entry->type = type; + ivhd_entry->dev_id = dev->path.pci.devfn | (dev->bus->secondary << 8); + ivhd_entry->dte_setting = data; + + *current += sizeof(ivrs_ivhd_generic_t) + offset; + *ivhd_length += sizeof(ivrs_ivhd_generic_t) + offset; + } else if (type == IVHD_DEV_8_BYTE_ALIAS_SELECT) { + /* 8-byte IVHD structures must be aligned to the 8-byte boundary. */ + offset = ((*current + 0x7) & (~ 0x7)) - *current; + ivrs_ivhd_alias_t *ivhd_entry = (ivrs_ivhd_alias_t *)(*current + offset); + + ivhd_entry->type = type; + ivhd_entry->dev_id = dev->path.pci.devfn | (dev->bus->secondary << 8); + ivhd_entry->dte_setting = data; + ivhd_entry->reserved1 = 0; + ivhd_entry->reserved2 = 0; + ivhd_entry->source_dev_id = parent->path.pci.devfn | (parent->bus->secondary << 8); + + *current += sizeof(ivrs_ivhd_alias_t) + offset; + *ivhd_length += sizeof(ivrs_ivhd_alias_t) + offset; } }
-static void add_ivrs_device_entries(struct device *parent, struct device *dev, +static void ivrs_add_device_or_bridge(struct device *parent, struct device *dev, + unsigned long *current, uint16_t *ivhd_length) +{ + unsigned int header_type, is_pcie; + + header_type = dev->hdr_type & 0x7f; + is_pcie = pci_find_capability(dev, PCI_CAP_ID_PCIE); + + if (((header_type == PCI_HEADER_TYPE_NORMAL) || + (header_type == PCI_HEADER_TYPE_BRIDGE)) && is_pcie) { + /* Device or Bridge is PCIe */ + add_ivhd_dev_entry(parent, dev, current, ivhd_length, IVHD_DEV_4_BYTE_SELECT, + 0x0); + } else if ((header_type == PCI_HEADER_TYPE_NORMAL) && !is_pcie) { + /* Device is legacy PCI or PCI-X */ + add_ivhd_dev_entry(parent, dev, current, ivhd_length, + IVHD_DEV_8_BYTE_ALIAS_SELECT, 0x0); + } +} + +static void add_ivhd_device_entries(struct device *parent, struct device *dev, unsigned int depth, int linknum, int8_t *root_level, - unsigned long *current, uint16_t *length) + unsigned long *current, uint16_t *ivhd_length) { struct device *sibling; struct bus *link; - unsigned int header_type; - unsigned int is_pcie; + + if (!root_level) { + root_level = malloc(sizeof(int8_t)); + *root_level = -1; + }
if (dev->path.type == DEVICE_PATH_PCI) {
@@ -500,30 +589,8 @@ *root_level = depth;
if ((*root_level != -1) && (dev->enabled)) { - if (depth == *root_level) { - if (dev->path.pci.devfn == (0x14 << 3)) { - /* SMBUS controller */ - add_ivhd_dev_entry(parent, dev, current, length, 0x2, 0x97); - } else if (dev->path.pci.devfn != 0x2 && - dev->path.pci.devfn < (0x2 << 3)) { - /* FCH control device */ - } else { - /* Other devices */ - add_ivhd_dev_entry(parent, dev, current, length, 0x2, 0x0); - } - } else { - header_type = dev->hdr_type & 0x7f; - is_pcie = pci_find_capability(dev, PCI_CAP_ID_PCIE); - if (((header_type == PCI_HEADER_TYPE_NORMAL) || - (header_type == PCI_HEADER_TYPE_BRIDGE)) - && is_pcie) { - /* Device or Bridge is PCIe */ - add_ivhd_dev_entry(parent, dev, current, length, 0x2, 0x0); - } else if ((header_type == PCI_HEADER_TYPE_NORMAL) && - !is_pcie) { - add_ivhd_dev_entry(parent, dev, current, length, 0x42, 0x0); - /* Device is legacy PCI or PCI-X */ - } + if (depth != *root_level) { + ivrs_add_device_or_bridge(parent, dev, current, ivhd_length); } } } @@ -531,123 +598,150 @@ 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); + add_ivhd_device_entries(dev, sibling, depth + 1, depth, root_level, + current, ivhd_length); + + free(root_level); }
-unsigned long acpi_fill_ivrs_ioapic(acpi_ivrs_t *ivrs, unsigned long current) +#define IOMMU_MMIO32(x) *((volatile uint32_t *)(x)) +#define EFR_SUPPORT BIT(27) + +static unsigned long acpi_fill_ivrs11(unsigned long current, acpi_ivrs_t *ivrs_agesa) { - uint8_t *p; + acpi_ivrs_ivhd11_t *ivhd_11; + unsigned long current_backup;
- uint32_t apicid_sb800; - uint32_t apicid_northbridge; + /* + * These devices should be already found by previous function. + * Do not perform NULL checks. + */ + struct device *nb_dev = pcidev_on_root(0, 0); + struct device *iommu_dev = pcidev_on_root(0, 2);
- apicid_sb800 = CONFIG_MAX_CPUS; - apicid_northbridge = CONFIG_MAX_CPUS + 1; + /* + * In order ot utilize all features, firmware should expose type 11h + * IVHD which supersedes the type 10h. + */ + memset((void *)current, 0, sizeof(acpi_ivrs_ivhd11_t)); + ivhd_11 = (acpi_ivrs_ivhd11_t *)current;
- /* Describe NB IOAPIC */ - p = (uint8_t *)current; - p[0] = 0x48; /* Entry type */ - p[1] = 0; /* Device */ - p[2] = 0; /* Bus */ - p[3] = 0x0; /* Data */ - p[4] = apicid_northbridge; /* IOAPIC ID */ - p[5] = 0x0; /* Device 0 Function 0 */ - p[6] = 0x0; /* Northbridge bus */ - p[7] = 0x1; /* Variety */ - current += 8; + /* Enable EFR */ + ivhd_11->type = IVHD_BLOCK_TYPE_FULL__FIXED; + /* For type 11h bits 6 and 7 are reserved */ + ivhd_11->flags = ivrs_agesa->ivhd.flags & 0x3f; + ivhd_11->length = sizeof(struct acpi_ivrs_ivhd_11); + /* BDF <bus>:00.2 */ + ivhd_11->device_id = 0x02 | (nb_dev->bus->secondary << 8); + /* PCI Capability block 0x40 (type 0xf, "Secure device") */ + ivhd_11->capability_offset = 0x40; + ivhd_11->iommu_base_low = ivrs_agesa->ivhd.iommu_base_low; + ivhd_11->iommu_base_high = ivrs_agesa->ivhd.iommu_base_high; + ivhd_11->pci_segment_group = 0x0000; + ivhd_11->iommu_info = ivrs_agesa->ivhd.iommu_info; + ivhd_11->iommu_attributes.perf_counters = + (IOMMU_MMIO32(ivhd_11->iommu_base_low + 0x4000) >> 7) & 0xf; + ivhd_11->iommu_attributes.perf_counter_banks = + (IOMMU_MMIO32(ivhd_11->iommu_base_low + 0x4000) >> 12) & 0x3f; + ivhd_11->iommu_attributes.msi_num_ppr = + (pci_read_config32(iommu_dev, ivhd_11->capability_offset + 0x10) >> 27) & 0x1f;
- /* Describe SB IOAPIC */ - p = (uint8_t *)current; - p[0] = 0x48; /* Entry type */ - p[1] = 0; /* Device */ - p[2] = 0; /* Bus */ - p[3] = 0xd7; /* Data */ - p[4] = apicid_sb800; /* IOAPIC ID */ - p[5] = 0x14 << 3; /* Device 0x14 Function 0 */ - p[6] = 0x0; /* Southbridge bus */ - p[7] = 0x1; /* Variety */ - current += 8; + if (pci_read_config32(iommu_dev, ivhd_11->capability_offset) & EFR_SUPPORT) { + ivhd_11->efr_reg_image_low = IOMMU_MMIO32(ivhd_11->iommu_base_low + 0x30); + ivhd_11->efr_reg_image_high = IOMMU_MMIO32(ivhd_11->iommu_base_low + 0x34); + }
- return current; + current += sizeof(acpi_ivrs_ivhd11_t); + + /* Now repeat all the device entries from type 10h */ + current = ivhd_dev_range(current, PCI_DEVFN(1, 0), PCI_DEVFN(0x1f, 6), + 0, &ivhd_11->length); + + add_ivhd_device_entries(NULL, all_devices, 0, -1, NULL, ¤t, &ivhd_11->length); + + current = ivhd_describe_hpet(current, &ivhd_11->length); + + current_backup = current; + + current = acpi_fill_ivrs_ioapic(ivrs_agesa, current); + + ivhd_11->length += (current - current_backup); + + return current; }
static unsigned long acpi_fill_ivrs(acpi_ivrs_t *ivrs, unsigned long current) { - uint8_t *p; acpi_ivrs_t *ivrs_agesa; + unsigned long current_backup;
- struct device *nb_dev = pcidev_on_root(0x0, 0); + struct device *nb_dev = pcidev_on_root(0, 0); if (!nb_dev) { - printk(BIOS_WARNING, "%s: G-series northbridge device not present!\n", __func__); printk(BIOS_WARNING, "%s: IVRS table not generated...\n", __func__);
return (unsigned long)ivrs; }
+ struct device *iommu_dev = pcidev_on_root(0, 2);
- /* obtain IOMMU base address */ + if (!iommu_dev) { + printk(BIOS_WARNING, "%s: IOMMU device not found\n", __func__); + + return (unsigned long)ivrs; + } + ivrs_agesa = agesawrapper_getlateinitptr(PICK_IVRS); if (ivrs_agesa != NULL) { - ivrs->iv_info = 0x0; - /* Maximum supported virtual address size */ - ivrs->iv_info |= (0x40 << 15); - /* Maximum supported physical address size */ - ivrs->iv_info |= (0x30 << 8); - /* Guest virtual address width */ - ivrs->iv_info |= (0x2 << 5); - - ivrs->ivhd.type = 0x10; - ivrs->ivhd.flags = 0x0e; - /* Enable ATS support */ - ivrs->ivhd.flags |= 0x10; + ivrs->iv_info = ivrs_agesa->iv_info; + ivrs->ivhd.type = IVHD_BLOCK_TYPE_LEGACY__FIXED; + ivrs->ivhd.flags = ivrs_agesa->ivhd.flags; ivrs->ivhd.length = sizeof(struct acpi_ivrs_ivhd); /* BDF <bus>:00.2 */ - ivrs->ivhd.device_id = 0x2 | (nb_dev->bus->secondary << 8); - /* Capability block 0x40 (type 0xf, "Secure device") */ + ivrs->ivhd.device_id = 0x02 | (nb_dev->bus->secondary << 8); + /* PCI Capability block 0x40 (type 0xf, "Secure device") */ ivrs->ivhd.capability_offset = 0x40; ivrs->ivhd.iommu_base_low = ivrs_agesa->ivhd.iommu_base_low; ivrs->ivhd.iommu_base_high = ivrs_agesa->ivhd.iommu_base_high; - ivrs->ivhd.pci_segment_group = 0x0; - ivrs->ivhd.iommu_info = 0x0; - ivrs->ivhd.iommu_info |= (0x13 << 8); - /* use only performance counters related bits: - * PNCounters[16:13] and - * PNBanks[22:17], - * otherwise 0 */ - ivrs->ivhd.iommu_feature_info = - ivrs_agesa->ivhd.iommu_feature_info & 0x7fe000; + ivrs->ivhd.pci_segment_group = 0x0000; + ivrs->ivhd.iommu_info = ivrs_agesa->ivhd.iommu_info; + ivrs->ivhd.iommu_feature_info = ivrs_agesa->ivhd.iommu_feature_info; + /* Enable EFR if supported */ + if (pci_read_config32(iommu_dev, ivrs->ivhd.capability_offset) & EFR_SUPPORT) + ivrs->iv_info |= IVINFO_EFR_SUPPORTED; } else { printk(BIOS_WARNING, "%s: AGESA returned NULL IVRS\n", __func__);
return (unsigned long)ivrs; }
- /* 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; + /* + * Add all possible PCI devices on bus 0 that can generate transactions + * processed by IOMMU. Start with device 00:01.0 since IOMMU does not + * translate transactions generated by itself. + */ + current = ivhd_dev_range(current, PCI_DEVFN(1, 0), PCI_DEVFN(0x1f, 6), + 0, &ivrs->ivhd.length);
/* Describe PCI devices */ - int8_t root_level = -1; - add_ivrs_device_entries(NULL, all_devices, 0, -1, &root_level, ¤t, + add_ivhd_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); + /* Describe HPET */ + current = ivhd_describe_hpet(current, &ivrs->ivhd.length);
- return current; + current_backup = current; + + /* Describe IOAPICs */ + current = acpi_fill_ivrs_ioapic(ivrs, current); + /* Add IOAPIC entries size to currently assembled IVHD */ + ivrs->ivhd.length += (current - current_backup); + + /* If EFR is not supported, IVHD type 11h is reserved */ + if (!(ivrs->iv_info & IVINFO_EFR_SUPPORTED)) + return current; + + return acpi_fill_ivrs11(current, ivrs_agesa); }
static void northbridge_fill_ssdt_generator(struct device *device)
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/40042 )
Change subject: nb/amd/pi/00730F01/northbridge.c: refactor IVRS generation ......................................................................
Patch Set 1:
(11 comments)
https://review.coreboot.org/c/coreboot/+/40042/1/src/northbridge/amd/pi/0073... File src/northbridge/amd/pi/00730F01/northbridge.c:
https://review.coreboot.org/c/coreboot/+/40042/1/src/northbridge/amd/pi/0073... PS1, Line 448: unsigned long offset = ((current + 0x7) & (~ 0x7)) - current; space prohibited after that '~' (ctx:BxW)
https://review.coreboot.org/c/coreboot/+/40042/1/src/northbridge/amd/pi/0073... PS1, Line 477: unsigned long offset = ((current + 0x7) & (~ 0x7)) - current; space prohibited after that '~' (ctx:BxW)
https://review.coreboot.org/c/coreboot/+/40042/1/src/northbridge/amd/pi/0073... PS1, Line 496: unsigned long offset = ((current + 0x3) & (~ 0x3)) - current; space prohibited after that '~' (ctx:BxW)
https://review.coreboot.org/c/coreboot/+/40042/1/src/northbridge/amd/pi/0073... PS1, Line 527: offset = ((*current + 0x3) & (~ 0x3)) - *current; space prohibited after that '~' (ctx:BxW)
https://review.coreboot.org/c/coreboot/+/40042/1/src/northbridge/amd/pi/0073... PS1, Line 538: offset = ((*current + 0x7) & (~ 0x7)) - *current; space prohibited after that '~' (ctx:BxW)
https://review.coreboot.org/c/coreboot/+/40042/1/src/northbridge/amd/pi/0073... PS1, Line 546: ivhd_entry->source_dev_id = parent->path.pci.devfn | (parent->bus->secondary << 8); line over 96 characters
https://review.coreboot.org/c/coreboot/+/40042/1/src/northbridge/amd/pi/0073... PS1, Line 592: if (depth != *root_level) { braces {} are not necessary for single statement blocks
https://review.coreboot.org/c/coreboot/+/40042/1/src/northbridge/amd/pi/0073... PS1, Line 607: #define IOMMU_MMIO32(x) *((volatile uint32_t *)(x)) Macros with complex values should be enclosed in parentheses
https://review.coreboot.org/c/coreboot/+/40042/1/src/northbridge/amd/pi/0073... PS1, Line 623: * In order ot utilize all features, firmware should expose type 11h 'ot' may be misspelled - perhaps 'to'?
https://review.coreboot.org/c/coreboot/+/40042/1/src/northbridge/amd/pi/0073... PS1, Line 642: ivhd_11->iommu_attributes.perf_counters = trailing whitespace
https://review.coreboot.org/c/coreboot/+/40042/1/src/northbridge/amd/pi/0073... PS1, Line 670: return current; trailing whitespace
Hello build bot (Jenkins),
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/40042
to look at the new patch set (#2).
Change subject: nb/amd/pi/00730F01/northbridge.c: refactor IVRS generation ......................................................................
nb/amd/pi/00730F01/northbridge.c: refactor IVRS generation
Use defined structures to assemble IVRS and IVHD entries. Additionally assemble IVHD type 11h which supersedes IVHD type 10h. In order to utilize all IOMMU features firmware should also expose IVHD type 11h. The new type is already supported and parsed since Xen 1.13. IVHD type 10h should still be present for backwards compatibility.
TEST=boot PC Engines apu2 and disassemble IVRS using newest IASL
Signed-off-by: Michał Żygowski michal.zygowski@3mdeb.com Change-Id: I9a2c24b67adfa8ebd718caeb5eec88687dcbcc9d --- M src/northbridge/amd/pi/00730F01/northbridge.c 1 file changed, 239 insertions(+), 145 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/42/40042/2
Michał Żygowski has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/40042 )
Change subject: nb/amd/pi/00730F01/northbridge.c: refactor IVRS generation ......................................................................
Patch Set 2:
using most recent iASL the result is like this: https://pastebin.com/iU3vmrDg
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/40042 )
Change subject: nb/amd/pi/00730F01/northbridge.c: refactor IVRS generation ......................................................................
Patch Set 2: Code-Review+1
(1 comment)
https://review.coreboot.org/c/coreboot/+/40042/2/src/northbridge/amd/pi/0073... File src/northbridge/amd/pi/00730F01/northbridge.c:
https://review.coreboot.org/c/coreboot/+/40042/2/src/northbridge/amd/pi/0073... PS2, Line 448: ((current + 7) & ~7) - current Could this be replaced with ALIGN_UP ?
Hello build bot (Jenkins), Angel Pons,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/40042
to look at the new patch set (#3).
Change subject: nb/amd/pi/00730F01/northbridge.c: refactor IVRS generation ......................................................................
nb/amd/pi/00730F01/northbridge.c: refactor IVRS generation
Use defined structures to assemble IVRS and IVHD entries. Additionally assemble IVHD type 11h which supersedes IVHD type 10h. In order to utilize all IOMMU features firmware should also expose IVHD type 11h. The new type is already supported and parsed since Xen 1.13. IVHD type 10h should still be present for backwards compatibility.
TEST=boot PC Engines apu2 and disassemble IVRS using newest IASL
Signed-off-by: Michał Żygowski michal.zygowski@3mdeb.com Change-Id: I9a2c24b67adfa8ebd718caeb5eec88687dcbcc9d --- M src/northbridge/amd/pi/00730F01/northbridge.c 1 file changed, 234 insertions(+), 147 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/42/40042/3
Michał Żygowski has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/40042 )
Change subject: nb/amd/pi/00730F01/northbridge.c: refactor IVRS generation ......................................................................
Patch Set 3:
(1 comment)
https://review.coreboot.org/c/coreboot/+/40042/2/src/northbridge/amd/pi/0073... File src/northbridge/amd/pi/00730F01/northbridge.c:
https://review.coreboot.org/c/coreboot/+/40042/2/src/northbridge/amd/pi/0073... PS2, Line 448: ((current + 7) & ~7) - current
Could this be replaced with ALIGN_UP ?
Done
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/40042 )
Change subject: nb/amd/pi/00730F01/northbridge.c: refactor IVRS generation ......................................................................
Patch Set 3: Code-Review+1
(1 comment)
https://review.coreboot.org/c/coreboot/+/40042/3/src/northbridge/amd/pi/0073... File src/northbridge/amd/pi/00730F01/northbridge.c:
https://review.coreboot.org/c/coreboot/+/40042/3/src/northbridge/amd/pi/0073... PS3, Line 495: 3 Um, not 3
Hello build bot (Jenkins), Angel Pons,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/40042
to look at the new patch set (#4).
Change subject: nb/amd/pi/00730F01/northbridge.c: refactor IVRS generation ......................................................................
nb/amd/pi/00730F01/northbridge.c: refactor IVRS generation
Use defined structures to assemble IVRS and IVHD entries. Additionally assemble IVHD type 11h which supersedes IVHD type 10h. In order to utilize all IOMMU features firmware should also expose IVHD type 11h. The new type is already supported and parsed since Xen 1.13. IVHD type 10h should still be present for backwards compatibility.
TEST=boot PC Engines apu2 and disassemble IVRS using newest IASL
Signed-off-by: Michał Żygowski michal.zygowski@3mdeb.com Change-Id: I9a2c24b67adfa8ebd718caeb5eec88687dcbcc9d --- M src/northbridge/amd/pi/00730F01/northbridge.c 1 file changed, 234 insertions(+), 147 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/42/40042/4
Michał Żygowski has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/40042 )
Change subject: nb/amd/pi/00730F01/northbridge.c: refactor IVRS generation ......................................................................
Patch Set 4:
(1 comment)
https://review.coreboot.org/c/coreboot/+/40042/3/src/northbridge/amd/pi/0073... File src/northbridge/amd/pi/00730F01/northbridge.c:
https://review.coreboot.org/c/coreboot/+/40042/3/src/northbridge/amd/pi/0073... PS3, Line 495: 3
Um, not 3
Typo... Thanks.
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/40042 )
Change subject: nb/amd/pi/00730F01/northbridge.c: refactor IVRS generation ......................................................................
Patch Set 4: Code-Review+2
HAOUAS Elyes has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/40042 )
Change subject: nb/amd/pi/00730F01/northbridge.c: refactor IVRS generation ......................................................................
Patch Set 4: Code-Review+1
Hello build bot (Jenkins), Angel Pons, HAOUAS Elyes,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/40042
to look at the new patch set (#5).
Change subject: nb/amd/pi/00730F01/northbridge.c: refactor IVRS generation ......................................................................
nb/amd/pi/00730F01/northbridge.c: refactor IVRS generation
Use defined structures to assemble IVRS and IVHD entries. Additionally assemble IVHD type 11h which supersedes IVHD type 10h. In order to utilize all IOMMU features firmware should also expose IVHD type 11h. The new type is already supported and parsed since Xen 1.13. IVHD type 10h should still be present for backwards compatibility.
TEST=boot PC Engines apu2 and disassemble IVRS using newest IASL, boot Xen 1.13 or newer with debug enabled and see IVRS IVHD 11h parsed in xl dmesg
Signed-off-by: Michał Żygowski michal.zygowski@3mdeb.com Change-Id: I9a2c24b67adfa8ebd718caeb5eec88687dcbcc9d --- M src/northbridge/amd/pi/00730F01/northbridge.c 1 file changed, 234 insertions(+), 146 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/42/40042/5
HAOUAS Elyes has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/40042 )
Change subject: nb/amd/pi/00730F01/northbridge.c: refactor IVRS generation ......................................................................
Patch Set 5: Code-Review+2
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/40042 )
Change subject: nb/amd/pi/00730F01/northbridge.c: refactor IVRS generation ......................................................................
Patch Set 5: Code-Review+2
Michał Żygowski has submitted this change. ( https://review.coreboot.org/c/coreboot/+/40042 )
Change subject: nb/amd/pi/00730F01/northbridge.c: refactor IVRS generation ......................................................................
nb/amd/pi/00730F01/northbridge.c: refactor IVRS generation
Use defined structures to assemble IVRS and IVHD entries. Additionally assemble IVHD type 11h which supersedes IVHD type 10h. In order to utilize all IOMMU features firmware should also expose IVHD type 11h. The new type is already supported and parsed since Xen 1.13. IVHD type 10h should still be present for backwards compatibility.
TEST=boot PC Engines apu2 and disassemble IVRS using newest IASL, boot Xen 1.13 or newer with debug enabled and see IVRS IVHD 11h parsed in xl dmesg
Signed-off-by: Michał Żygowski michal.zygowski@3mdeb.com Change-Id: I9a2c24b67adfa8ebd718caeb5eec88687dcbcc9d Reviewed-on: https://review.coreboot.org/c/coreboot/+/40042 Tested-by: build bot (Jenkins) no-reply@coreboot.org Reviewed-by: HAOUAS Elyes ehaouas@noos.fr Reviewed-by: Angel Pons th3fanbus@gmail.com --- M src/northbridge/amd/pi/00730F01/northbridge.c 1 file changed, 234 insertions(+), 146 deletions(-)
Approvals: build bot (Jenkins): Verified HAOUAS Elyes: Looks good to me, approved Angel Pons: Looks good to me, approved
diff --git a/src/northbridge/amd/pi/00730F01/northbridge.c b/src/northbridge/amd/pi/00730F01/northbridge.c index d324689..4a24d35 100644 --- a/src/northbridge/amd/pi/00730F01/northbridge.c +++ b/src/northbridge/amd/pi/00730F01/northbridge.c @@ -1,9 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* This file is part of the coreboot project. */
+#include <commonlib/helpers.h> #include <console/console.h> #include <device/pci_ops.h> #include <arch/acpi.h> +#include <arch/acpi_ivrs.h> #include <arch/ioapic.h> #include <stdint.h> #include <device/device.h> @@ -11,6 +13,7 @@ #include <device/pci_ids.h> #include <device/hypertransport.h> #include <string.h> +#include <stdlib.h> #include <lib.h> #include <cpu/cpu.h> #include <Porting.h> @@ -22,6 +25,7 @@ #include <arch/acpigen.h> #include <northbridge/amd/pi/nb_common.h> #include <northbridge/amd/agesa/agesa_helper.h> +#include <southbridge/amd/pi/hudson/pci_devs.h>
#define MAX_NODE_NUMS MAX_NODES #define PCIE_CAP_AER BIT(5) @@ -428,59 +432,139 @@ return (unsigned long)current; }
-static void add_ivhd_dev_entry(struct device *parent, struct device *dev, - unsigned long *current, uint16_t *length, - uint8_t type, uint8_t data) +unsigned long acpi_fill_ivrs_ioapic(acpi_ivrs_t *ivrs, unsigned long current) { - uint8_t *p; - p = (uint8_t *) *current; + /* 8-byte IVHD structures must be aligned to the 8-byte boundary. */ + current = ALIGN_UP(current, 8); + ivrs_ivhd_special_t *ivhd_ioapic = (ivrs_ivhd_special_t *)current;
- if (type == 0x2) { - /* Entry type */ - p[0] = type; - /* Device */ - p[1] = dev->path.pci.devfn; - /* Bus */ - p[2] = dev->bus->secondary; - /* Data */ - p[3] = data; - /* [4:7] Padding */ - p[4] = 0x0; - p[5] = 0x0; - p[6] = 0x0; - p[7] = 0x0; - *length += 8; - *current += 8; - } else if (type == 0x42) { - /* Entry type */ - p[0] = type; - /* Device */ - p[1] = dev->path.pci.devfn; - /* Bus */ - p[2] = dev->bus->secondary; - /* Data */ - p[3] = 0x0; - /* Reserved */ - p[4] = 0x0; - /* Device */ - p[5] = parent->path.pci.devfn; - /* Bus */ - p[6] = parent->bus->secondary; - /* Reserved */ - p[7] = 0x0; - *length += 8; - *current += 8; + ivhd_ioapic->type = IVHD_DEV_8_BYTE_EXT_SPECIAL_DEV; + ivhd_ioapic->reserved = 0x0000; + ivhd_ioapic->dte_setting = IVHD_DTE_LINT_1_PASS | IVHD_DTE_LINT_0_PASS | + IVHD_DTE_SYS_MGT_NO_TRANS | IVHD_DTE_NMI_PASS | + IVHD_DTE_EXT_INT_PASS | IVHD_DTE_INIT_PASS; + ivhd_ioapic->handle = CONFIG_MAX_CPUS; /* FCH IOAPIC ID */ + ivhd_ioapic->source_dev_id = PCI_DEVFN(SMBUS_DEV, SMBUS_FUNC); + ivhd_ioapic->variety = IVHD_SPECIAL_DEV_IOAPIC; + current += sizeof(ivrs_ivhd_special_t); + + ivhd_ioapic = (ivrs_ivhd_special_t *)current; + + ivhd_ioapic->type = IVHD_DEV_8_BYTE_EXT_SPECIAL_DEV; + ivhd_ioapic->reserved = 0x0000; + ivhd_ioapic->dte_setting = 0x00; + ivhd_ioapic->handle = CONFIG_MAX_CPUS + 1; /* GNB IOAPIC ID */ + ivhd_ioapic->source_dev_id = PCI_DEVFN(0, 1); + ivhd_ioapic->variety = IVHD_SPECIAL_DEV_IOAPIC; + current += sizeof(ivrs_ivhd_special_t); + + return current; +} + +static unsigned long ivhd_describe_hpet(unsigned long current) +{ + /* 8-byte IVHD structures must be aligned to the 8-byte boundary. */ + current = ALIGN_UP(current, 8); + ivrs_ivhd_special_t *ivhd_hpet = (ivrs_ivhd_special_t *)current; + + ivhd_hpet->type = IVHD_DEV_8_BYTE_EXT_SPECIAL_DEV; + ivhd_hpet->reserved = 0x0000; + ivhd_hpet->dte_setting = 0x00; + ivhd_hpet->handle = 0x00; + ivhd_hpet->source_dev_id = PCI_DEVFN(SMBUS_DEV, SMBUS_FUNC); + ivhd_hpet->variety = IVHD_SPECIAL_DEV_HPET; + current += sizeof(ivrs_ivhd_special_t); + + return current; +} + +static unsigned long ivhd_dev_range(unsigned long current, uint16_t start_devid, + uint16_t end_devid, uint8_t setting) +{ + /* 4-byte IVHD structures must be aligned to the 4-byte boundary. */ + current = ALIGN_UP(current, 4); + ivrs_ivhd_generic_t *ivhd_range = (ivrs_ivhd_generic_t *)current; + + /* Create the start range IVHD entry */ + ivhd_range->type = IVHD_DEV_4_BYTE_START_RANGE; + ivhd_range->dev_id = start_devid; + ivhd_range->dte_setting = setting; + current += sizeof(ivrs_ivhd_generic_t); + + /* Create the end range IVHD entry */ + ivhd_range = (ivrs_ivhd_generic_t *)current; + ivhd_range->type = IVHD_DEV_4_BYTE_END_RANGE; + ivhd_range->dev_id = end_devid; + ivhd_range->dte_setting = setting; + current += sizeof(ivrs_ivhd_generic_t); + + return current; +} + +static unsigned long add_ivhd_dev_entry(struct device *parent, struct device *dev, + unsigned long *current, uint8_t type, uint8_t data) +{ + if (type == IVHD_DEV_4_BYTE_SELECT) { + /* 4-byte IVHD structures must be aligned to the 4-byte boundary. */ + *current = ALIGN_UP(*current, 4); + ivrs_ivhd_generic_t *ivhd_entry = (ivrs_ivhd_generic_t *)*current; + + ivhd_entry->type = type; + ivhd_entry->dev_id = dev->path.pci.devfn | (dev->bus->secondary << 8); + ivhd_entry->dte_setting = data; + *current += sizeof(ivrs_ivhd_generic_t); + } else if (type == IVHD_DEV_8_BYTE_ALIAS_SELECT) { + /* 8-byte IVHD structures must be aligned to the 8-byte boundary. */ + *current = ALIGN_UP(*current, 8); + ivrs_ivhd_alias_t *ivhd_entry = (ivrs_ivhd_alias_t *)*current; + + ivhd_entry->type = type; + ivhd_entry->dev_id = dev->path.pci.devfn | (dev->bus->secondary << 8); + ivhd_entry->dte_setting = data; + ivhd_entry->reserved1 = 0; + ivhd_entry->reserved2 = 0; + ivhd_entry->source_dev_id = parent->path.pci.devfn | + (parent->bus->secondary << 8); + *current += sizeof(ivrs_ivhd_alias_t); + } + + return *current; +} + +static void ivrs_add_device_or_bridge(struct device *parent, struct device *dev, + unsigned long *current, uint16_t *ivhd_length) +{ + unsigned int header_type, is_pcie; + unsigned long current_backup; + + header_type = dev->hdr_type & 0x7f; + is_pcie = pci_find_capability(dev, PCI_CAP_ID_PCIE); + + if (((header_type == PCI_HEADER_TYPE_NORMAL) || + (header_type == PCI_HEADER_TYPE_BRIDGE)) && is_pcie) { + /* Device or Bridge is PCIe */ + current_backup = *current; + add_ivhd_dev_entry(parent, dev, current, IVHD_DEV_4_BYTE_SELECT, 0x0); + *ivhd_length += (*current - current_backup); + } else if ((header_type == PCI_HEADER_TYPE_NORMAL) && !is_pcie) { + /* Device is legacy PCI or PCI-X */ + current_backup = *current; + add_ivhd_dev_entry(parent, dev, current, IVHD_DEV_8_BYTE_ALIAS_SELECT, 0x0); + *ivhd_length += (*current - current_backup); } }
-static void add_ivrs_device_entries(struct device *parent, struct device *dev, +static void add_ivhd_device_entries(struct device *parent, struct device *dev, unsigned int depth, int linknum, int8_t *root_level, - unsigned long *current, uint16_t *length) + unsigned long *current, uint16_t *ivhd_length) { struct device *sibling; struct bus *link; - unsigned int header_type; - unsigned int is_pcie; + + if (!root_level) { + root_level = malloc(sizeof(int8_t)); + *root_level = -1; + }
if (dev->path.type == DEVICE_PATH_PCI) {
@@ -489,154 +573,158 @@ *root_level = depth;
if ((*root_level != -1) && (dev->enabled)) { - if (depth == *root_level) { - if (dev->path.pci.devfn == (0x14 << 3)) { - /* SMBUS controller */ - add_ivhd_dev_entry(parent, dev, current, length, 0x2, 0x97); - } else if (dev->path.pci.devfn != 0x2 && - dev->path.pci.devfn < (0x2 << 3)) { - /* FCH control device */ - } else { - /* Other devices */ - add_ivhd_dev_entry(parent, dev, current, length, 0x2, 0x0); - } - } else { - header_type = dev->hdr_type & 0x7f; - is_pcie = pci_find_capability(dev, PCI_CAP_ID_PCIE); - if (((header_type == PCI_HEADER_TYPE_NORMAL) || - (header_type == PCI_HEADER_TYPE_BRIDGE)) - && is_pcie) { - /* Device or Bridge is PCIe */ - add_ivhd_dev_entry(parent, dev, current, length, 0x2, 0x0); - } else if ((header_type == PCI_HEADER_TYPE_NORMAL) && - !is_pcie) { - add_ivhd_dev_entry(parent, dev, current, length, 0x42, 0x0); - /* Device is legacy PCI or PCI-X */ - } - } + if (depth != *root_level) + ivrs_add_device_or_bridge(parent, dev, current, ivhd_length); } }
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); + add_ivhd_device_entries(dev, sibling, depth + 1, depth, root_level, + current, ivhd_length); + + free(root_level); }
-unsigned long acpi_fill_ivrs_ioapic(acpi_ivrs_t *ivrs, unsigned long current) +#define IOMMU_MMIO32(x) (*((volatile uint32_t *)(x))) +#define EFR_SUPPORT BIT(27) + +static unsigned long acpi_fill_ivrs11(unsigned long current, acpi_ivrs_t *ivrs_agesa) { - uint8_t *p; + acpi_ivrs_ivhd11_t *ivhd_11; + unsigned long current_backup;
- uint32_t apicid_sb800; - uint32_t apicid_northbridge; + /* + * These devices should be already found by previous function. + * Do not perform NULL checks. + */ + struct device *nb_dev = pcidev_on_root(0, 0); + struct device *iommu_dev = pcidev_on_root(0, 2);
- apicid_sb800 = CONFIG_MAX_CPUS; - apicid_northbridge = CONFIG_MAX_CPUS + 1; + /* + * In order to utilize all features, firmware should expose type 11h + * IVHD which supersedes the type 10h. + */ + memset((void *)current, 0, sizeof(acpi_ivrs_ivhd11_t)); + ivhd_11 = (acpi_ivrs_ivhd11_t *)current;
- /* Describe NB IOAPIC */ - p = (uint8_t *)current; - p[0] = 0x48; /* Entry type */ - p[1] = 0; /* Device */ - p[2] = 0; /* Bus */ - p[3] = 0x0; /* Data */ - p[4] = apicid_northbridge; /* IOAPIC ID */ - p[5] = 0x0; /* Device 0 Function 0 */ - p[6] = 0x0; /* Northbridge bus */ - p[7] = 0x1; /* Variety */ - current += 8; + /* Enable EFR */ + ivhd_11->type = IVHD_BLOCK_TYPE_FULL__FIXED; + /* For type 11h bits 6 and 7 are reserved */ + ivhd_11->flags = ivrs_agesa->ivhd.flags & 0x3f; + ivhd_11->length = sizeof(struct acpi_ivrs_ivhd_11); + /* BDF <bus>:00.2 */ + ivhd_11->device_id = 0x02 | (nb_dev->bus->secondary << 8); + /* PCI Capability block 0x40 (type 0xf, "Secure device") */ + ivhd_11->capability_offset = 0x40; + ivhd_11->iommu_base_low = ivrs_agesa->ivhd.iommu_base_low; + ivhd_11->iommu_base_high = ivrs_agesa->ivhd.iommu_base_high; + ivhd_11->pci_segment_group = 0x0000; + ivhd_11->iommu_info = ivrs_agesa->ivhd.iommu_info; + ivhd_11->iommu_attributes.perf_counters = + (IOMMU_MMIO32(ivhd_11->iommu_base_low + 0x4000) >> 7) & 0xf; + ivhd_11->iommu_attributes.perf_counter_banks = + (IOMMU_MMIO32(ivhd_11->iommu_base_low + 0x4000) >> 12) & 0x3f; + ivhd_11->iommu_attributes.msi_num_ppr = + (pci_read_config32(iommu_dev, ivhd_11->capability_offset + 0x10) >> 27) & 0x1f;
- /* Describe SB IOAPIC */ - p = (uint8_t *)current; - p[0] = 0x48; /* Entry type */ - p[1] = 0; /* Device */ - p[2] = 0; /* Bus */ - p[3] = 0xd7; /* Data */ - p[4] = apicid_sb800; /* IOAPIC ID */ - p[5] = 0x14 << 3; /* Device 0x14 Function 0 */ - p[6] = 0x0; /* Southbridge bus */ - p[7] = 0x1; /* Variety */ - current += 8; + if (pci_read_config32(iommu_dev, ivhd_11->capability_offset) & EFR_SUPPORT) { + ivhd_11->efr_reg_image_low = IOMMU_MMIO32(ivhd_11->iommu_base_low + 0x30); + ivhd_11->efr_reg_image_high = IOMMU_MMIO32(ivhd_11->iommu_base_low + 0x34); + } + + current += sizeof(acpi_ivrs_ivhd11_t); + + /* Now repeat all the device entries from type 10h */ + current_backup = current; + current = ivhd_dev_range(current, PCI_DEVFN(1, 0), PCI_DEVFN(0x1f, 6), 0); + ivhd_11->length += (current - current_backup); + add_ivhd_device_entries(NULL, all_devices, 0, -1, NULL, ¤t, &ivhd_11->length); + + /* Describe HPET */ + current_backup = current; + current = ivhd_describe_hpet(current); + ivhd_11->length += (current - current_backup); + + /* Describe IOAPICs */ + current_backup = current; + current = acpi_fill_ivrs_ioapic(ivrs_agesa, current); + ivhd_11->length += (current - current_backup);
return current; }
static unsigned long acpi_fill_ivrs(acpi_ivrs_t *ivrs, unsigned long current) { - uint8_t *p; acpi_ivrs_t *ivrs_agesa; + unsigned long current_backup;
- struct device *nb_dev = pcidev_on_root(0x0, 0); + struct device *nb_dev = pcidev_on_root(0, 0); if (!nb_dev) { - printk(BIOS_WARNING, "%s: G-series northbridge device not present!\n", __func__); printk(BIOS_WARNING, "%s: IVRS table not generated...\n", __func__);
return (unsigned long)ivrs; }
+ struct device *iommu_dev = pcidev_on_root(0, 2);
- /* obtain IOMMU base address */ + if (!iommu_dev) { + printk(BIOS_WARNING, "%s: IOMMU device not found\n", __func__); + + return (unsigned long)ivrs; + } + ivrs_agesa = agesawrapper_getlateinitptr(PICK_IVRS); if (ivrs_agesa != NULL) { - ivrs->iv_info = 0x0; - /* Maximum supported virtual address size */ - ivrs->iv_info |= (0x40 << 15); - /* Maximum supported physical address size */ - ivrs->iv_info |= (0x30 << 8); - /* Guest virtual address width */ - ivrs->iv_info |= (0x2 << 5); - - ivrs->ivhd.type = 0x10; - ivrs->ivhd.flags = 0x0e; - /* Enable ATS support */ - ivrs->ivhd.flags |= 0x10; + ivrs->iv_info = ivrs_agesa->iv_info; + ivrs->ivhd.type = IVHD_BLOCK_TYPE_LEGACY__FIXED; + ivrs->ivhd.flags = ivrs_agesa->ivhd.flags; ivrs->ivhd.length = sizeof(struct acpi_ivrs_ivhd); /* BDF <bus>:00.2 */ - ivrs->ivhd.device_id = 0x2 | (nb_dev->bus->secondary << 8); - /* Capability block 0x40 (type 0xf, "Secure device") */ + ivrs->ivhd.device_id = 0x02 | (nb_dev->bus->secondary << 8); + /* PCI Capability block 0x40 (type 0xf, "Secure device") */ ivrs->ivhd.capability_offset = 0x40; ivrs->ivhd.iommu_base_low = ivrs_agesa->ivhd.iommu_base_low; ivrs->ivhd.iommu_base_high = ivrs_agesa->ivhd.iommu_base_high; - ivrs->ivhd.pci_segment_group = 0x0; - ivrs->ivhd.iommu_info = 0x0; - ivrs->ivhd.iommu_info |= (0x13 << 8); - /* use only performance counters related bits: - * PNCounters[16:13] and - * PNBanks[22:17], - * otherwise 0 */ - ivrs->ivhd.iommu_feature_info = - ivrs_agesa->ivhd.iommu_feature_info & 0x7fe000; + ivrs->ivhd.pci_segment_group = 0x0000; + ivrs->ivhd.iommu_info = ivrs_agesa->ivhd.iommu_info; + ivrs->ivhd.iommu_feature_info = ivrs_agesa->ivhd.iommu_feature_info; + /* Enable EFR if supported */ + if (pci_read_config32(iommu_dev, ivrs->ivhd.capability_offset) & EFR_SUPPORT) + ivrs->iv_info |= IVINFO_EFR_SUPPORTED; } else { printk(BIOS_WARNING, "%s: AGESA returned NULL IVRS\n", __func__);
return (unsigned long)ivrs; }
- /* 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; + /* + * Add all possible PCI devices on bus 0 that can generate transactions + * processed by IOMMU. Start with device 00:01.0 since IOMMU does not + * translate transactions generated by itself. + */ + current_backup = current; + current = ivhd_dev_range(current, PCI_DEVFN(1, 0), PCI_DEVFN(0x1f, 6), 0); + ivrs->ivhd.length += (current - current_backup); + add_ivhd_device_entries(NULL, all_devices, 0, -1, NULL, ¤t, &ivrs->ivhd.length);
- /* Describe PCI devices */ - int8_t root_level = -1; - add_ivrs_device_entries(NULL, all_devices, 0, -1, &root_level, ¤t, - &ivrs->ivhd.length); + /* Describe HPET */ + current_backup = current; + current = ivhd_describe_hpet(current); + ivrs->ivhd.length += (current - current_backup);
/* Describe IOAPICs */ - unsigned long prev_current = current; - current = acpi_fill_ivrs_ioapic(ivrs, current); - ivrs->ivhd.length += (current - prev_current); + current_backup = current; + current = acpi_fill_ivrs_ioapic(ivrs_agesa, current); + ivrs->ivhd.length += (current - current_backup);
- return current; + /* If EFR is not supported, IVHD type 11h is reserved */ + if (!(ivrs->iv_info & IVINFO_EFR_SUPPORTED)) + return current; + + return acpi_fill_ivrs11(current, ivrs_agesa); }
static void northbridge_fill_ssdt_generator(struct device *device)
9elements QA has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/40042 )
Change subject: nb/amd/pi/00730F01/northbridge.c: refactor IVRS generation ......................................................................
Patch Set 6:
Automatic boot test returned (PASS/FAIL/TOTAL): 3/0/3 Emulation targets: EMULATION_QEMU_X86_Q35 using payload TianoCore : SUCCESS : https://lava.9esec.io/r/2151 EMULATION_QEMU_X86_Q35 using payload SeaBIOS : SUCCESS : https://lava.9esec.io/r/2150 EMULATION_QEMU_X86_I440FX using payload SeaBIOS : SUCCESS : https://lava.9esec.io/r/2149
Please note: This test is under development and might not be accurate at all!