mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-01 06:43:53 -06:00
hw/riscv/virt-acpi-build: Add support for RIMT
RISC-V IO Mapping Table (RIMT) is a new static ACPI table used to communicate IOMMU information to the OS. Add support for creating this table when the IOMMU is present. The specification is frozen and available at [1]. [1] - https://github.com/riscv-non-isa/riscv-acpi-rimt/releases/download/v0.99/rimt-spec.pdf Signed-off-by: Sunil V L <sunilvl@ventanamicro.com> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Message-ID: <20250322043139.2003479-3-sunilvl@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
This commit is contained in:
parent
d2a88aca76
commit
cd18dbbf9d
1 changed files with 215 additions and 0 deletions
|
@ -198,6 +198,32 @@ acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap,
|
|||
aml_append(scope, dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add DSDT entry for the IOMMU platform device.
|
||||
* ACPI ID for IOMMU is defined in the section 6.2 of RISC-V BRS spec.
|
||||
* https://github.com/riscv-non-isa/riscv-brs/releases/download/v0.8/riscv-brs-spec.pdf
|
||||
*/
|
||||
static void acpi_dsdt_add_iommu_sys(Aml *scope, const MemMapEntry *iommu_memmap,
|
||||
uint32_t iommu_irq)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
Aml *dev = aml_device("IMU0");
|
||||
aml_append(dev, aml_name_decl("_HID", aml_string("RSCV0004")));
|
||||
aml_append(dev, aml_name_decl("_UID", aml_int(0)));
|
||||
|
||||
Aml *crs = aml_resource_template();
|
||||
aml_append(crs, aml_memory32_fixed(iommu_memmap->base,
|
||||
iommu_memmap->size, AML_READ_WRITE));
|
||||
for (i = iommu_irq; i < iommu_irq + 4; i++) {
|
||||
aml_append(crs, aml_interrupt(AML_CONSUMER, AML_EDGE, AML_ACTIVE_LOW,
|
||||
AML_EXCLUSIVE, &i, 1));
|
||||
}
|
||||
|
||||
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||
aml_append(scope, dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Serial Port Console Redirection Table (SPCR)
|
||||
* Rev: 1.10
|
||||
|
@ -450,6 +476,9 @@ static void build_dsdt(GArray *table_data,
|
|||
}
|
||||
|
||||
acpi_dsdt_add_uart(scope, &memmap[VIRT_UART0], UART0_IRQ);
|
||||
if (virt_is_iommu_sys_enabled(s)) {
|
||||
acpi_dsdt_add_iommu_sys(scope, &memmap[VIRT_IOMMU_SYS], IOMMU_SYS_IRQ);
|
||||
}
|
||||
|
||||
if (socket_count == 1) {
|
||||
virtio_acpi_dsdt_add(scope, memmap[VIRT_VIRTIO].base,
|
||||
|
@ -602,6 +631,187 @@ static void build_madt(GArray *table_data,
|
|||
acpi_table_end(linker, &table);
|
||||
}
|
||||
|
||||
#define ID_MAPPING_ENTRY_SIZE 20
|
||||
#define IOMMU_ENTRY_SIZE 40
|
||||
#define RISCV_INTERRUPT_WIRE_OFFSSET 40
|
||||
#define ROOT_COMPLEX_ENTRY_SIZE 20
|
||||
#define RIMT_NODE_OFFSET 48
|
||||
|
||||
/*
|
||||
* ID Mapping Structure
|
||||
*/
|
||||
static void build_rimt_id_mapping(GArray *table_data, uint32_t source_id_base,
|
||||
uint32_t num_ids, uint32_t dest_id_base)
|
||||
{
|
||||
/* Source ID Base */
|
||||
build_append_int_noprefix(table_data, source_id_base, 4);
|
||||
/* Number of IDs */
|
||||
build_append_int_noprefix(table_data, num_ids, 4);
|
||||
/* Destination Device ID Base */
|
||||
build_append_int_noprefix(table_data, source_id_base, 4);
|
||||
/* Destination IOMMU Offset */
|
||||
build_append_int_noprefix(table_data, dest_id_base, 4);
|
||||
/* Flags */
|
||||
build_append_int_noprefix(table_data, 0, 4);
|
||||
}
|
||||
|
||||
struct AcpiRimtIdMapping {
|
||||
uint32_t source_id_base;
|
||||
uint32_t num_ids;
|
||||
};
|
||||
typedef struct AcpiRimtIdMapping AcpiRimtIdMapping;
|
||||
|
||||
/* Build the rimt ID mapping to IOMMU for a given PCI host bridge */
|
||||
static int rimt_host_bridges(Object *obj, void *opaque)
|
||||
{
|
||||
GArray *idmap_blob = opaque;
|
||||
|
||||
if (object_dynamic_cast(obj, TYPE_PCI_HOST_BRIDGE)) {
|
||||
PCIBus *bus = PCI_HOST_BRIDGE(obj)->bus;
|
||||
|
||||
if (bus && !pci_bus_bypass_iommu(bus)) {
|
||||
int min_bus, max_bus;
|
||||
|
||||
pci_bus_range(bus, &min_bus, &max_bus);
|
||||
|
||||
AcpiRimtIdMapping idmap = {
|
||||
.source_id_base = min_bus << 8,
|
||||
.num_ids = (max_bus - min_bus + 1) << 8,
|
||||
};
|
||||
g_array_append_val(idmap_blob, idmap);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rimt_idmap_compare(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
AcpiRimtIdMapping *idmap_a = (AcpiRimtIdMapping *)a;
|
||||
AcpiRimtIdMapping *idmap_b = (AcpiRimtIdMapping *)b;
|
||||
|
||||
return idmap_a->source_id_base - idmap_b->source_id_base;
|
||||
}
|
||||
|
||||
/*
|
||||
* RISC-V IO Mapping Table (RIMT)
|
||||
* https://github.com/riscv-non-isa/riscv-acpi-rimt/releases/download/v0.99/rimt-spec.pdf
|
||||
*/
|
||||
static void build_rimt(GArray *table_data, BIOSLinker *linker,
|
||||
RISCVVirtState *s)
|
||||
{
|
||||
int i, nb_nodes, rc_mapping_count;
|
||||
size_t node_size, iommu_offset = 0;
|
||||
uint32_t id = 0;
|
||||
g_autoptr(GArray) iommu_idmaps = g_array_new(false, true,
|
||||
sizeof(AcpiRimtIdMapping));
|
||||
|
||||
AcpiTable table = { .sig = "RIMT", .rev = 1, .oem_id = s->oem_id,
|
||||
.oem_table_id = s->oem_table_id };
|
||||
|
||||
acpi_table_begin(&table, table_data);
|
||||
|
||||
object_child_foreach_recursive(object_get_root(),
|
||||
rimt_host_bridges, iommu_idmaps);
|
||||
|
||||
/* Sort the ID mapping by Source ID Base*/
|
||||
g_array_sort(iommu_idmaps, rimt_idmap_compare);
|
||||
|
||||
nb_nodes = 2; /* RC, IOMMU */
|
||||
rc_mapping_count = iommu_idmaps->len;
|
||||
/* Number of RIMT Nodes */
|
||||
build_append_int_noprefix(table_data, nb_nodes, 4);
|
||||
|
||||
/* Offset to Array of RIMT Nodes */
|
||||
build_append_int_noprefix(table_data, RIMT_NODE_OFFSET, 4);
|
||||
build_append_int_noprefix(table_data, 0, 4); /* Reserved */
|
||||
|
||||
iommu_offset = table_data->len - table.table_offset;
|
||||
/* IOMMU Device Structure */
|
||||
build_append_int_noprefix(table_data, 0, 1); /* Type - IOMMU*/
|
||||
build_append_int_noprefix(table_data, 1, 1); /* Revision */
|
||||
node_size = IOMMU_ENTRY_SIZE;
|
||||
build_append_int_noprefix(table_data, node_size, 2); /* Length */
|
||||
build_append_int_noprefix(table_data, 0, 2); /* Reserved */
|
||||
build_append_int_noprefix(table_data, id++, 2); /* ID */
|
||||
if (virt_is_iommu_sys_enabled(s)) {
|
||||
/* Hardware ID */
|
||||
build_append_int_noprefix(table_data, 'R', 1);
|
||||
build_append_int_noprefix(table_data, 'S', 1);
|
||||
build_append_int_noprefix(table_data, 'C', 1);
|
||||
build_append_int_noprefix(table_data, 'V', 1);
|
||||
build_append_int_noprefix(table_data, '0', 1);
|
||||
build_append_int_noprefix(table_data, '0', 1);
|
||||
build_append_int_noprefix(table_data, '0', 1);
|
||||
build_append_int_noprefix(table_data, '4', 1);
|
||||
/* Base Address */
|
||||
build_append_int_noprefix(table_data,
|
||||
s->memmap[VIRT_IOMMU_SYS].base, 8);
|
||||
build_append_int_noprefix(table_data, 0, 4); /* Flags */
|
||||
} else {
|
||||
/* Hardware ID */
|
||||
build_append_int_noprefix(table_data, '0', 1);
|
||||
build_append_int_noprefix(table_data, '0', 1);
|
||||
build_append_int_noprefix(table_data, '1', 1);
|
||||
build_append_int_noprefix(table_data, '0', 1);
|
||||
build_append_int_noprefix(table_data, '0', 1);
|
||||
build_append_int_noprefix(table_data, '0', 1);
|
||||
build_append_int_noprefix(table_data, '1', 1);
|
||||
build_append_int_noprefix(table_data, '4', 1);
|
||||
|
||||
build_append_int_noprefix(table_data, 0, 8); /* Base Address */
|
||||
build_append_int_noprefix(table_data, 1, 4); /* Flags */
|
||||
}
|
||||
|
||||
build_append_int_noprefix(table_data, 0, 4); /* Proximity Domain */
|
||||
build_append_int_noprefix(table_data, 0, 2); /* PCI Segment number */
|
||||
/* PCIe B/D/F */
|
||||
if (virt_is_iommu_sys_enabled(s)) {
|
||||
build_append_int_noprefix(table_data, 0, 2);
|
||||
} else {
|
||||
build_append_int_noprefix(table_data, s->pci_iommu_bdf, 2);
|
||||
}
|
||||
/* Number of interrupt wires */
|
||||
build_append_int_noprefix(table_data, 0, 2);
|
||||
/* Interrupt wire array offset */
|
||||
build_append_int_noprefix(table_data, RISCV_INTERRUPT_WIRE_OFFSSET, 2);
|
||||
|
||||
/* PCIe Root Complex Node */
|
||||
build_append_int_noprefix(table_data, 1, 1); /* Type */
|
||||
build_append_int_noprefix(table_data, 1, 1); /* Revision */
|
||||
node_size = ROOT_COMPLEX_ENTRY_SIZE +
|
||||
ID_MAPPING_ENTRY_SIZE * rc_mapping_count;
|
||||
build_append_int_noprefix(table_data, node_size, 2); /* Length */
|
||||
build_append_int_noprefix(table_data, 0, 2); /* Reserved */
|
||||
build_append_int_noprefix(table_data, id++, 2); /* ID */
|
||||
build_append_int_noprefix(table_data, 0, 4); /* Flags */
|
||||
build_append_int_noprefix(table_data, 0, 2); /* Reserved */
|
||||
/* PCI Segment number */
|
||||
build_append_int_noprefix(table_data, 0, 2);
|
||||
/* ID mapping array offset */
|
||||
build_append_int_noprefix(table_data, ROOT_COMPLEX_ENTRY_SIZE, 2);
|
||||
/* Number of ID mappings */
|
||||
build_append_int_noprefix(table_data, rc_mapping_count, 2);
|
||||
|
||||
/* Output Reference */
|
||||
AcpiRimtIdMapping *range;
|
||||
|
||||
/* ID mapping array */
|
||||
for (i = 0; i < iommu_idmaps->len; i++) {
|
||||
range = &g_array_index(iommu_idmaps, AcpiRimtIdMapping, i);
|
||||
if (virt_is_iommu_sys_enabled(s)) {
|
||||
range->source_id_base = 0;
|
||||
} else {
|
||||
range->source_id_base = s->pci_iommu_bdf + 1;
|
||||
}
|
||||
range->num_ids = 0xffff - s->pci_iommu_bdf;
|
||||
build_rimt_id_mapping(table_data, range->source_id_base,
|
||||
range->num_ids, iommu_offset);
|
||||
}
|
||||
|
||||
acpi_table_end(linker, &table);
|
||||
}
|
||||
|
||||
/*
|
||||
* ACPI spec, Revision 6.5+
|
||||
* 5.2.16 System Resource Affinity Table (SRAT)
|
||||
|
@ -679,6 +889,11 @@ static void virt_acpi_build(RISCVVirtState *s, AcpiBuildTables *tables)
|
|||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_rhct(tables_blob, tables->linker, s);
|
||||
|
||||
if (virt_is_iommu_sys_enabled(s) || s->pci_iommu_bdf) {
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_rimt(tables_blob, tables->linker, s);
|
||||
}
|
||||
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
spcr_setup(tables_blob, tables->linker, s);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue