Linux Audio

Check our new training course

Embedded Linux Audio

Check our new training course
with Creative Commons CC-BY-SA
lecture materials

Bootlin logo

Elixir Cross Referencer

Loading...
/*
 * SPDX-License-Identifier: Apache-2.0
 * Copyright (c) 2019 Intel Corp.
 */

#include <zephyr.h>
#include <arch/x86/acpi.h>

static void vtd_dev_scope_info(struct acpi_dmar_dev_scope *dev_scope)
{
	struct acpi_dmar_dev_path *path;
	int n_path;

	printk("\t\t\t. Type: ");

	switch (dev_scope->type) {
	case ACPI_DRHD_DEV_SCOPE_PCI_EPD:
		printk("PCI Endpoint");
		break;
	case ACPI_DRHD_DEV_SCOPE_PCI_SUB_H:
		printk("PCI Sub-hierarchy");
		break;
	case ACPI_DRHD_DEV_SCOPE_IOAPIC:
		printk("IOAPIC");
		break;
	case ACPI_DRHD_DEV_SCOPE_MSI_CAP_HPET:
		printk("MSI Capable HPET");
		break;
	case ACPI_DRHD_DEV_SCOPE_NAMESPACE_DEV:
		printk("ACPI name-space enumerated");
		break;
	default:
		printk("unknown\n");
		return;
	}

	printk("\n");

	printk("\t\t\t. Enumeration ID %u\n", dev_scope->enumeration_id);
	printk("\t\t\t. PCI Bus %u\n", dev_scope->start_bus_num);

	path = z_acpi_get_dev_scope_paths(dev_scope, &n_path);
	for (; n_path > 0; n_path--) {
		printk("\t\t\t. Path D:%u F:%u\n",
		       path->device, path->function);
		path = (struct acpi_dmar_dev_path *)(POINTER_TO_UINT(path) +
						     ACPI_DMAR_DEV_PATH_SIZE);
	}

	printk("\n");
}

static void vtd_drhd_info(struct acpi_drhd *drhd)
{
	struct acpi_dmar_dev_scope *dev_scope;
	int n_ds, i;

	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_num);
	printk("\t\t- Base Address 0x%llx\n", drhd->base_address);

	dev_scope = z_acpi_get_drhd_dev_scopes(drhd, &n_ds);
	if (dev_scope == NULL) {
		printk("\t\t- No device scopes\n");
		return;
	}

	printk("\t\t- Device Scopes:\n");
	for (i = 0; i < n_ds; i++) {
		vtd_dev_scope_info(dev_scope);
		dev_scope = (struct acpi_dmar_dev_scope *)(
			POINTER_TO_UINT(dev_scope) + dev_scope->length);
	}

	printk("\n");
}

static void vtd_info(void)
{
	struct acpi_dmar *dmar;

	dmar = z_acpi_find_dmar();
	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) {
		struct acpi_drhd *drhd;
		int hw_n, i;

		printk("\t-> Interrupt remapping supported\n");

		drhd = z_acpi_find_drhds(&hw_n);
		printk("\t-> %u remapping hardware found:\n", hw_n);

		for (i = 0; i < hw_n; i++) {
			printk("\t\tDRHD %u:\n", i);
			vtd_drhd_info(drhd);
			drhd = (struct acpi_drhd *)(POINTER_TO_UINT(drhd) +
						    drhd->entry.length);
		}
	} else {
		printk("\t-> Interrupt remapping not supported\n");
	}
}

void acpi(void)
{
	int nr_cpus;

	for (nr_cpus = 0; z_acpi_get_cpu(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 CPUs found\n", nr_cpus);

		for (int i = 0; i < nr_cpus; ++i) {
			struct acpi_cpu *cpu = z_acpi_get_cpu(i);
			printk("\tCPU #%d: APIC ID 0x%02x\n", i, cpu->apic_id);
		}
	}

	printk("\n");

	vtd_info();

	printk("\n");
}