blob: 83a876c2879e8dc06ff6f44c0b15ecdbda1a2a1d [file] [log] [blame]
/* SPDX-License-Identifier: GPL-2.0-only */
#include <acpi/acpi.h>
#include <arch/ioapic.h>
#include <cpu/cpu.h>
#include <version.h>
void acpi_create_dmar(acpi_dmar_t *dmar, enum dmar_flags flags,
unsigned long (*acpi_fill_dmar)(unsigned long))
{
acpi_header_t *header = &(dmar->header);
unsigned long current = (unsigned long)dmar + sizeof(acpi_dmar_t);
memset((void *)dmar, 0, sizeof(acpi_dmar_t));
if (!header)
return;
/* Fill out header fields. */
memcpy(header->signature, "DMAR", 4);
memcpy(header->oem_id, OEM_ID, 6);
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
memcpy(header->asl_compiler_id, ASLC, 4);
header->asl_compiler_revision = asl_revision;
header->length = sizeof(acpi_dmar_t);
header->revision = get_acpi_table_revision(DMAR);
dmar->host_address_width = cpu_phys_address_size() - 1;
dmar->flags = flags;
current = acpi_fill_dmar(current);
/* (Re)calculate length and checksum. */
header->length = current - (unsigned long)dmar;
header->checksum = acpi_checksum((void *)dmar, header->length);
}
unsigned long acpi_create_dmar_drhd(unsigned long current, u8 flags,
u16 segment, u64 bar)
{
dmar_entry_t *drhd = (dmar_entry_t *)current;
memset(drhd, 0, sizeof(*drhd));
drhd->type = DMAR_DRHD;
drhd->length = sizeof(*drhd); /* will be fixed up later */
drhd->flags = flags;
drhd->segment = segment;
drhd->bar = bar;
return drhd->length;
}
unsigned long acpi_create_dmar_rmrr(unsigned long current, u16 segment,
u64 bar, u64 limit)
{
dmar_rmrr_entry_t *rmrr = (dmar_rmrr_entry_t *)current;
memset(rmrr, 0, sizeof(*rmrr));
rmrr->type = DMAR_RMRR;
rmrr->length = sizeof(*rmrr); /* will be fixed up later */
rmrr->segment = segment;
rmrr->bar = bar;
rmrr->limit = limit;
return rmrr->length;
}
unsigned long acpi_create_dmar_atsr(unsigned long current, u8 flags,
u16 segment)
{
dmar_atsr_entry_t *atsr = (dmar_atsr_entry_t *)current;
memset(atsr, 0, sizeof(*atsr));
atsr->type = DMAR_ATSR;
atsr->length = sizeof(*atsr); /* will be fixed up later */
atsr->flags = flags;
atsr->segment = segment;
return atsr->length;
}
unsigned long acpi_create_dmar_rhsa(unsigned long current, u64 base_addr,
u32 proximity_domain)
{
dmar_rhsa_entry_t *rhsa = (dmar_rhsa_entry_t *)current;
memset(rhsa, 0, sizeof(*rhsa));
rhsa->type = DMAR_RHSA;
rhsa->length = sizeof(*rhsa);
rhsa->base_address = base_addr;
rhsa->proximity_domain = proximity_domain;
return rhsa->length;
}
unsigned long acpi_create_dmar_andd(unsigned long current, u8 device_number,
const char *device_name)
{
dmar_andd_entry_t *andd = (dmar_andd_entry_t *)current;
int andd_len = sizeof(dmar_andd_entry_t) + strlen(device_name) + 1;
memset(andd, 0, andd_len);
andd->type = DMAR_ANDD;
andd->length = andd_len;
andd->device_number = device_number;
memcpy(&andd->device_name, device_name, strlen(device_name));
return andd->length;
}
unsigned long acpi_create_dmar_satc(unsigned long current, u8 flags, u16 segment)
{
dmar_satc_entry_t *satc = (dmar_satc_entry_t *)current;
int satc_len = sizeof(dmar_satc_entry_t);
memset(satc, 0, satc_len);
satc->type = DMAR_SATC;
satc->length = satc_len;
satc->flags = flags;
satc->segment_number = segment;
return satc->length;
}
void acpi_dmar_drhd_fixup(unsigned long base, unsigned long current)
{
dmar_entry_t *drhd = (dmar_entry_t *)base;
drhd->length = current - base;
}
void acpi_dmar_rmrr_fixup(unsigned long base, unsigned long current)
{
dmar_rmrr_entry_t *rmrr = (dmar_rmrr_entry_t *)base;
rmrr->length = current - base;
}
void acpi_dmar_atsr_fixup(unsigned long base, unsigned long current)
{
dmar_atsr_entry_t *atsr = (dmar_atsr_entry_t *)base;
atsr->length = current - base;
}
void acpi_dmar_satc_fixup(unsigned long base, unsigned long current)
{
dmar_satc_entry_t *satc = (dmar_satc_entry_t *)base;
satc->length = current - base;
}
static unsigned long acpi_create_dmar_ds(unsigned long current,
enum dev_scope_type type, u8 enumeration_id, u8 bus, u8 dev, u8 fn)
{
/* we don't support longer paths yet */
const size_t dev_scope_length = sizeof(dev_scope_t) + 2;
dev_scope_t *ds = (dev_scope_t *)current;
memset(ds, 0, dev_scope_length);
ds->type = type;
ds->length = dev_scope_length;
ds->enumeration = enumeration_id;
ds->start_bus = bus;
ds->path[0].dev = dev;
ds->path[0].fn = fn;
return ds->length;
}
unsigned long acpi_create_dmar_ds_pci_br(unsigned long current, u8 bus,
u8 dev, u8 fn)
{
return acpi_create_dmar_ds(current,
SCOPE_PCI_SUB, 0, bus, dev, fn);
}
unsigned long acpi_create_dmar_ds_pci(unsigned long current, u8 bus,
u8 dev, u8 fn)
{
return acpi_create_dmar_ds(current,
SCOPE_PCI_ENDPOINT, 0, bus, dev, fn);
}
unsigned long acpi_create_dmar_ds_ioapic(unsigned long current,
u8 enumeration_id, u8 bus, u8 dev, u8 fn)
{
return acpi_create_dmar_ds(current,
SCOPE_IOAPIC, enumeration_id, bus, dev, fn);
}
unsigned long acpi_create_dmar_ds_ioapic_from_hw(unsigned long current,
u32 addr, u8 bus, u8 dev, u8 fn)
{
u8 enumeration_id = get_ioapic_id((void *)(uintptr_t)addr);
return acpi_create_dmar_ds(current,
SCOPE_IOAPIC, enumeration_id, bus, dev, fn);
}
unsigned long acpi_create_dmar_ds_msi_hpet(unsigned long current,
u8 enumeration_id, u8 bus, u8 dev, u8 fn)
{
return acpi_create_dmar_ds(current,
SCOPE_MSI_HPET, enumeration_id, bus, dev, fn);
}