blob: 56adc9b87e8d69e1abbe2bf2c1bb306dd26c9538 [file] [log] [blame]
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright (c) 2019 Intel Corp.
*/
#include <zephyr/kernel.h>
#include <zephyr/acpi/acpi.h>
static const char *get_dmar_scope_type(int type)
{
switch (type) {
case ACPI_DMAR_SCOPE_TYPE_ENDPOINT:
return "PCI Endpoint";
case ACPI_DMAR_SCOPE_TYPE_BRIDGE:
return "PCI Sub-hierarchy";
case ACPI_DMAR_SCOPE_TYPE_IOAPIC:
return "IOAPIC";
case ACPI_DMAR_SCOPE_TYPE_HPET:
return "MSI Capable HPET";
case ACPI_DMAR_SCOPE_TYPE_NAMESPACE:
return "ACPI name-space enumerated";
default:
return "unknown";
}
}
static void dmar_devsope_handler(ACPI_DMAR_DEVICE_SCOPE *devscope, void *arg)
{
ARG_UNUSED(arg);
printk("\t\t\t. Scope type %s\n", get_dmar_scope_type(devscope->EntryType));
printk("\t\t\t. Enumeration ID %u\n", devscope->EnumerationId);
if (devscope->EntryType < ACPI_DMAR_SCOPE_TYPE_RESERVED) {
ACPI_DMAR_PCI_PATH *devpath;
int num_path = (devscope->Length - 6u) / 2u;
int i = 0;
devpath = ACPI_ADD_PTR(ACPI_DMAR_PCI_PATH, devscope,
sizeof(ACPI_DMAR_DEVICE_SCOPE));
while (num_path--) {
printk("\t\t\t. PCI Path %02x:%02x.%02x\n", devscope->Bus,
devpath[i].Device, devpath[i].Function);
}
}
}
static void vtd_drhd_info(ACPI_DMAR_HEADER *subtable)
{
struct acpi_dmar_hardware_unit *drhd = (void *)subtable;
static int unit;
printk("\t\t[ Hardware Unit Definition %d ]\n", unit++);
if (drhd->Flags & ACPI_DRHD_FLAG_INCLUDE_PCI_ALL) {
printk("\t\t- Includes all PCI devices");
} else {
printk("\t\t- Includes only listed PCI devices");
}
printk(" under given Segment\n");
printk("\t\t- Segment number %u\n", drhd->Segment);
printk("\t\t- Base Address 0x%llx\n", drhd->Address);
printk("\t\t- Device Scopes:\n");
acpi_dmar_foreach_devscope(drhd, dmar_devsope_handler, NULL);
}
static void dmar_subtable_handler(ACPI_DMAR_HEADER *subtable, void *arg)
{
ARG_UNUSED(arg);
if (subtable->Type != ACPI_DMAR_TYPE_HARDWARE_UNIT) {
return;
}
vtd_drhd_info(subtable);
}
static void vtd_info(void)
{
struct acpi_table_dmar *dmar;
dmar = acpi_table_get("DMAR", 0);
if (dmar == NULL) {
printk("\tIntel VT-D not supported or exposed\n");
return;
}
printk("\tIntel VT-D Supported:\n");
printk("\t-> X2APIC ");
if (dmar->Flags & ACPI_DMAR_FLAG_X2APIC_OPT_OUT) {
printk("should be opted out\n");
} else {
printk("does not need to be opted out\n");
}
if (dmar->Flags & ACPI_DMAR_FLAG_INTR_REMAP) {
printk("\t-> Interrupt remapping supported\n");
acpi_dmar_foreach_subtable(dmar, dmar_subtable_handler, NULL);
} else {
printk("\t-> Interrupt remapping not supported\n");
}
}
void acpi(void)
{
int nr_cpus;
for (nr_cpus = 0; acpi_local_apic_get(nr_cpus); ++nr_cpus) {
/* count number of CPUs present */
}
if (nr_cpus == 0) {
printk("ACPI: no RSDT/MADT found\n\n");
} else {
printk("ACPI: %d CPU%s found\n", nr_cpus, nr_cpus == 1 ? "" : "s");
for (int i = 0; i < nr_cpus; ++i) {
struct acpi_madt_local_apic *cpu = acpi_local_apic_get(i);
printk("\tCPU #%d: APIC ID 0x%02x\n", i, cpu->Id);
}
}
printk("\n");
vtd_info();
printk("\n");
}