nb/amd/pi/00730F01: Add initial native IVRS support
- Iteration over devices in add_ivrs_device_entries were simplified to decrease complexity. - Code was structured to satisfy checkpatch Change-Id: I1ae789f75363435accd14a1b556e1570f43f94c4 Signed-off-by: Timothy Pearson <tpearson@raptorengineering.com> Signed-off-by: Piotr Król <piotr.krol@3mdeb.com> Reviewed-on: https://review.coreboot.org/15164 Reviewed-by: Patrick Georgi <pgeorgi@google.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
parent
03eb8a8515
commit
9ef07d8623
|
@ -2,6 +2,8 @@
|
||||||
* This file is part of the coreboot project.
|
* This file is part of the coreboot project.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012 Advanced Micro Devices, Inc.
|
* Copyright (C) 2012 Advanced Micro Devices, Inc.
|
||||||
|
* Copyright (C) 2016 Raptor Engineering, LLC
|
||||||
|
* Copyright (C) 2018 3mdeb Embedded Systems Consulting
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -437,6 +439,208 @@ static unsigned long acpi_fill_hest(acpi_hest_t *hest)
|
||||||
return (unsigned long)current;
|
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)
|
||||||
|
{
|
||||||
|
uint8_t *p;
|
||||||
|
p = (uint8_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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_ivrs_device_entries(struct device *parent, struct device *dev,
|
||||||
|
unsigned int depth, int linknum, int8_t *root_level,
|
||||||
|
unsigned long *current, uint16_t *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) {
|
||||||
|
|
||||||
|
if ((dev->bus->secondary == 0x0) &&
|
||||||
|
(dev->path.pci.devfn == 0x0))
|
||||||
|
*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 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long acpi_fill_ivrs_ioapic(acpi_ivrs_t *ivrs, unsigned long current)
|
||||||
|
{
|
||||||
|
uint8_t *p;
|
||||||
|
|
||||||
|
uint32_t apicid_sb800;
|
||||||
|
uint32_t apicid_northbridge;
|
||||||
|
|
||||||
|
apicid_sb800 = CONFIG_MAX_CPUS;
|
||||||
|
apicid_northbridge = CONFIG_MAX_CPUS + 1;
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
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, "%s: G-series northbridge device not present!\n", __func__);
|
||||||
|
printk(BIOS_WARNING, "%s: IVRS table not generated...\n", __func__);
|
||||||
|
|
||||||
|
return (unsigned long)ivrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
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->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.capability_offset = 0x40;
|
||||||
|
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.iommu_feature_info = 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(struct device *device)
|
static void northbridge_fill_ssdt_generator(struct device *device)
|
||||||
{
|
{
|
||||||
msr_t msr;
|
msr_t msr;
|
||||||
|
@ -466,7 +670,7 @@ static unsigned long agesa_write_acpi_tables(struct device *device,
|
||||||
acpi_slit_t *slit;
|
acpi_slit_t *slit;
|
||||||
acpi_header_t *ssdt;
|
acpi_header_t *ssdt;
|
||||||
acpi_header_t *alib;
|
acpi_header_t *alib;
|
||||||
acpi_header_t *ivrs;
|
acpi_ivrs_t *ivrs;
|
||||||
acpi_hest_t *hest;
|
acpi_hest_t *hest;
|
||||||
|
|
||||||
/* HEST */
|
/* HEST */
|
||||||
|
@ -476,17 +680,13 @@ static unsigned long agesa_write_acpi_tables(struct device *device,
|
||||||
acpi_add_table(rsdp, (void *)current);
|
acpi_add_table(rsdp, (void *)current);
|
||||||
current += ((acpi_header_t *)current)->length;
|
current += ((acpi_header_t *)current)->length;
|
||||||
|
|
||||||
current = ALIGN(current, 8);
|
/* IVRS */
|
||||||
printk(BIOS_DEBUG, "ACPI: * IVRS at %lx\n", current);
|
current = ALIGN(current, 8);
|
||||||
ivrs = agesawrapper_getlateinitptr(PICK_IVRS);
|
printk(BIOS_DEBUG, "ACPI: * IVRS at %lx\n", current);
|
||||||
if (ivrs != NULL) {
|
ivrs = (acpi_ivrs_t *) current;
|
||||||
memcpy((void *)current, ivrs, ivrs->length);
|
acpi_create_ivrs(ivrs, acpi_fill_ivrs);
|
||||||
ivrs = (acpi_header_t *) current;
|
current += ivrs->header.length;
|
||||||
current += ivrs->length;
|
acpi_add_table(rsdp, ivrs);
|
||||||
acpi_add_table(rsdp, ivrs);
|
|
||||||
} else {
|
|
||||||
printk(BIOS_DEBUG, " AGESA IVRS table NULL. Skipping.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* SRAT */
|
/* SRAT */
|
||||||
current = ALIGN(current, 8);
|
current = ALIGN(current, 8);
|
||||||
|
|
Loading…
Reference in New Issue