/* * 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"); }