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:
Timothy Pearson 2016-06-13 13:48:58 -05:00 committed by Patrick Georgi
parent 03eb8a8515
commit 9ef07d8623
1 changed files with 212 additions and 12 deletions

View File

@ -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, &current,
&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);