2020-03-04 15:10:45 +01:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
2004-01-28 17:56:14 +01:00
|
|
|
/*
|
2019-08-31 05:09:37 +02:00
|
|
|
* coreboot ACPI Table support
|
2005-01-19 15:06:41 +01:00
|
|
|
*/
|
|
|
|
|
2010-04-27 08:56:47 +02:00
|
|
|
/*
|
2005-01-19 15:06:41 +01:00
|
|
|
* Each system port implementing ACPI has to provide two functions:
|
2010-04-27 08:56:47 +02:00
|
|
|
*
|
2005-01-19 15:06:41 +01:00
|
|
|
* write_acpi_tables()
|
|
|
|
* acpi_dump_apics()
|
2010-04-27 08:56:47 +02:00
|
|
|
*
|
2009-11-10 23:17:15 +01:00
|
|
|
* See Kontron 986LCD-M port for a good example of an ACPI implementation
|
|
|
|
* in coreboot.
|
2004-10-06 19:33:54 +02:00
|
|
|
*/
|
2004-01-28 17:56:14 +01:00
|
|
|
|
|
|
|
#include <console/console.h>
|
|
|
|
#include <string.h>
|
2020-05-02 19:24:23 +02:00
|
|
|
#include <acpi/acpi.h>
|
|
|
|
#include <acpi/acpi_ivrs.h>
|
|
|
|
#include <acpi/acpigen.h>
|
2005-01-19 15:06:41 +01:00
|
|
|
#include <device/pci.h>
|
2009-11-10 23:17:15 +01:00
|
|
|
#include <cbmem.h>
|
2019-06-21 07:06:50 +02:00
|
|
|
#include <commonlib/helpers.h>
|
2012-10-04 04:07:05 +02:00
|
|
|
#include <cpu/cpu.h>
|
2014-10-26 20:42:08 +01:00
|
|
|
#include <cbfs.h>
|
2021-02-11 19:37:11 +01:00
|
|
|
#include <types.h>
|
2019-02-15 08:21:33 +01:00
|
|
|
#include <version.h>
|
2019-02-19 13:39:56 +01:00
|
|
|
#include <commonlib/sort.h>
|
2004-10-06 19:33:54 +02:00
|
|
|
|
2019-09-10 15:40:47 +02:00
|
|
|
static acpi_rsdp_t *valid_rsdp(acpi_rsdp_t *rsdp);
|
|
|
|
|
2004-10-06 19:33:54 +02:00
|
|
|
u8 acpi_checksum(u8 *table, u32 length)
|
2004-01-28 17:56:14 +01:00
|
|
|
{
|
2010-11-19 16:14:42 +01:00
|
|
|
u8 ret = 0;
|
2004-01-28 17:56:14 +01:00
|
|
|
while (length--) {
|
|
|
|
ret += *table;
|
|
|
|
table++;
|
|
|
|
}
|
2004-01-29 18:31:34 +01:00
|
|
|
return -ret;
|
2004-01-28 17:56:14 +01:00
|
|
|
}
|
|
|
|
|
2009-11-10 23:17:15 +01:00
|
|
|
/**
|
2010-11-19 16:14:42 +01:00
|
|
|
* Add an ACPI table to the RSDT (and XSDT) structure, recalculate length
|
|
|
|
* and checksum.
|
2004-02-03 17:11:35 +01:00
|
|
|
*/
|
2009-07-21 23:38:33 +02:00
|
|
|
void acpi_add_table(acpi_rsdp_t *rsdp, void *table)
|
2004-01-28 17:56:14 +01:00
|
|
|
{
|
2009-11-10 23:17:15 +01:00
|
|
|
int i, entries_num;
|
2009-07-21 23:38:33 +02:00
|
|
|
acpi_rsdt_t *rsdt;
|
|
|
|
acpi_xsdt_t *xsdt = NULL;
|
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* The RSDT is mandatory... */
|
2015-06-18 10:11:19 +02:00
|
|
|
rsdt = (acpi_rsdt_t *)(uintptr_t)rsdp->rsdt_address;
|
2009-11-10 23:17:15 +01:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* ...while the XSDT is not. */
|
|
|
|
if (rsdp->xsdt_address)
|
2015-06-18 10:11:19 +02:00
|
|
|
xsdt = (acpi_xsdt_t *)((uintptr_t)rsdp->xsdt_address);
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* This should always be MAX_ACPI_TABLES. */
|
2009-11-10 23:17:15 +01:00
|
|
|
entries_num = ARRAY_SIZE(rsdt->entry);
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2009-11-10 23:17:15 +01:00
|
|
|
for (i = 0; i < entries_num; i++) {
|
2010-11-19 16:14:42 +01:00
|
|
|
if (rsdt->entry[i] == 0)
|
2009-11-10 23:17:15 +01:00
|
|
|
break;
|
2004-01-28 17:56:14 +01:00
|
|
|
}
|
|
|
|
|
2009-11-10 23:17:15 +01:00
|
|
|
if (i >= entries_num) {
|
2010-11-19 16:14:42 +01:00
|
|
|
printk(BIOS_ERR, "ACPI: Error: Could not add ACPI table, "
|
2011-07-01 23:57:07 +02:00
|
|
|
"too many tables.\n");
|
2009-11-10 23:17:15 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* Add table to the RSDT. */
|
2015-06-18 10:11:19 +02:00
|
|
|
rsdt->entry[i] = (uintptr_t)table;
|
2009-11-10 23:17:15 +01:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* Fix RSDT length or the kernel will assume invalid entries. */
|
|
|
|
rsdt->header.length = sizeof(acpi_header_t) + (sizeof(u32) * (i + 1));
|
2009-11-10 23:17:15 +01:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* Re-calculate checksum. */
|
2009-11-10 23:17:15 +01:00
|
|
|
rsdt->header.checksum = 0; /* Hope this won't get optimized away */
|
2010-11-19 16:14:42 +01:00
|
|
|
rsdt->header.checksum = acpi_checksum((u8 *)rsdt, rsdt->header.length);
|
2009-11-10 23:17:15 +01:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/*
|
|
|
|
* And now the same thing for the XSDT. We use the same index as for
|
2009-11-10 23:17:15 +01:00
|
|
|
* now we want the XSDT and RSDT to always be in sync in coreboot.
|
|
|
|
*/
|
|
|
|
if (xsdt) {
|
2010-11-19 16:14:42 +01:00
|
|
|
/* Add table to the XSDT. */
|
2015-06-18 10:11:19 +02:00
|
|
|
xsdt->entry[i] = (u64)(uintptr_t)table;
|
2009-11-10 23:17:15 +01:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* Fix XSDT length. */
|
2009-11-10 23:17:15 +01:00
|
|
|
xsdt->header.length = sizeof(acpi_header_t) +
|
2011-07-01 23:57:07 +02:00
|
|
|
(sizeof(u64) * (i + 1));
|
2009-11-10 23:17:15 +01:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* Re-calculate checksum. */
|
|
|
|
xsdt->header.checksum = 0;
|
|
|
|
xsdt->header.checksum = acpi_checksum((u8 *)xsdt,
|
2011-07-01 23:57:07 +02:00
|
|
|
xsdt->header.length);
|
2009-11-10 23:17:15 +01:00
|
|
|
}
|
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
printk(BIOS_DEBUG, "ACPI: added table %d/%d, length now %d\n",
|
2011-07-01 23:57:07 +02:00
|
|
|
i + 1, entries_num, rsdt->header.length);
|
2004-01-28 17:56:14 +01:00
|
|
|
}
|
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
int acpi_create_mcfg_mmconfig(acpi_mcfg_mmconfig_t *mmconfig, u32 base,
|
2011-07-01 23:57:07 +02:00
|
|
|
u16 seg_nr, u8 start, u8 end)
|
2009-01-20 20:17:51 +01:00
|
|
|
{
|
2014-10-05 11:05:16 +02:00
|
|
|
memset(mmconfig, 0, sizeof(*mmconfig));
|
2007-11-03 13:50:26 +01:00
|
|
|
mmconfig->base_address = base;
|
|
|
|
mmconfig->base_reserved = 0;
|
|
|
|
mmconfig->pci_segment_group_number = seg_nr;
|
|
|
|
mmconfig->start_bus_number = start;
|
|
|
|
mmconfig->end_bus_number = end;
|
2010-11-19 16:14:42 +01:00
|
|
|
|
|
|
|
return sizeof(acpi_mcfg_mmconfig_t);
|
2007-11-03 13:50:26 +01:00
|
|
|
}
|
|
|
|
|
2005-01-19 15:06:41 +01:00
|
|
|
int acpi_create_madt_lapic(acpi_madt_lapic_t *lapic, u8 cpu, u8 apic)
|
2004-02-03 17:11:35 +01:00
|
|
|
{
|
2019-10-21 15:20:50 +02:00
|
|
|
lapic->type = LOCAL_APIC; /* Local APIC structure */
|
2010-11-19 16:14:42 +01:00
|
|
|
lapic->length = sizeof(acpi_madt_lapic_t);
|
|
|
|
lapic->flags = (1 << 0); /* Processor/LAPIC enabled */
|
|
|
|
lapic->processor_id = cpu;
|
|
|
|
lapic->apic_id = apic;
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
return lapic->length;
|
2004-02-03 17:11:35 +01:00
|
|
|
}
|
|
|
|
|
2020-03-24 17:29:49 +01:00
|
|
|
int acpi_create_madt_lx2apic(acpi_madt_lx2apic_t *lapic, u32 cpu, u32 apic)
|
|
|
|
{
|
|
|
|
lapic->type = LOCAL_X2APIC; /* Local APIC structure */
|
|
|
|
lapic->reserved = 0;
|
|
|
|
lapic->length = sizeof(acpi_madt_lx2apic_t);
|
|
|
|
lapic->flags = (1 << 0); /* Processor/LAPIC enabled */
|
|
|
|
lapic->processor_id = cpu;
|
|
|
|
lapic->x2apic_id = apic;
|
|
|
|
|
|
|
|
return lapic->length;
|
|
|
|
}
|
|
|
|
|
2009-04-22 10:18:37 +02:00
|
|
|
unsigned long acpi_create_madt_lapics(unsigned long current)
|
|
|
|
{
|
2014-10-27 13:29:29 +01:00
|
|
|
struct device *cpu;
|
2019-03-06 09:31:02 +01:00
|
|
|
int index, apic_ids[CONFIG_MAX_CPUS] = {0}, num_cpus = 0;
|
2009-04-22 10:18:37 +02:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
for (cpu = all_devices; cpu; cpu = cpu->next) {
|
2009-04-22 10:18:37 +02:00
|
|
|
if ((cpu->path.type != DEVICE_PATH_APIC) ||
|
2013-02-13 00:20:54 +01:00
|
|
|
(cpu->bus->dev->path.type != DEVICE_PATH_CPU_CLUSTER)) {
|
2009-04-22 10:18:37 +02:00
|
|
|
continue;
|
|
|
|
}
|
2010-11-19 16:14:42 +01:00
|
|
|
if (!cpu->enabled)
|
2009-04-22 10:18:37 +02:00
|
|
|
continue;
|
2019-02-19 13:39:56 +01:00
|
|
|
if (num_cpus >= ARRAY_SIZE(apic_ids))
|
|
|
|
break;
|
|
|
|
apic_ids[num_cpus++] = cpu->path.apic.apic_id;
|
|
|
|
}
|
2019-03-12 07:07:50 +01:00
|
|
|
if (num_cpus > 1)
|
|
|
|
bubblesort(apic_ids, num_cpus, NUM_ASCENDING);
|
2019-02-19 13:39:56 +01:00
|
|
|
for (index = 0; index < num_cpus; index++) {
|
2020-03-24 17:29:49 +01:00
|
|
|
if (apic_ids[index] < 0xff)
|
|
|
|
current += acpi_create_madt_lapic((acpi_madt_lapic_t *)current,
|
|
|
|
index, apic_ids[index]);
|
|
|
|
else
|
|
|
|
current += acpi_create_madt_lx2apic((acpi_madt_lx2apic_t *)current,
|
|
|
|
index, apic_ids[index]);
|
2009-04-22 10:18:37 +02:00
|
|
|
}
|
2010-11-19 16:14:42 +01:00
|
|
|
|
2009-04-22 10:18:37 +02:00
|
|
|
return current;
|
|
|
|
}
|
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
int acpi_create_madt_ioapic(acpi_madt_ioapic_t *ioapic, u8 id, u32 addr,
|
2011-07-01 23:57:07 +02:00
|
|
|
u32 gsi_base)
|
2004-02-03 17:11:35 +01:00
|
|
|
{
|
2019-10-21 15:20:50 +02:00
|
|
|
ioapic->type = IO_APIC; /* I/O APIC structure */
|
2010-11-19 16:14:42 +01:00
|
|
|
ioapic->length = sizeof(acpi_madt_ioapic_t);
|
|
|
|
ioapic->reserved = 0x00;
|
|
|
|
ioapic->gsi_base = gsi_base;
|
|
|
|
ioapic->ioapic_id = id;
|
|
|
|
ioapic->ioapic_addr = addr;
|
|
|
|
|
|
|
|
return ioapic->length;
|
2004-02-03 17:11:35 +01:00
|
|
|
}
|
|
|
|
|
2005-01-19 15:06:41 +01:00
|
|
|
int acpi_create_madt_irqoverride(acpi_madt_irqoverride_t *irqoverride,
|
2004-02-03 17:11:35 +01:00
|
|
|
u8 bus, u8 source, u32 gsirq, u16 flags)
|
|
|
|
{
|
2019-10-21 15:20:50 +02:00
|
|
|
irqoverride->type = IRQ_SOURCE_OVERRIDE; /* Interrupt source override */
|
2010-11-19 16:14:42 +01:00
|
|
|
irqoverride->length = sizeof(acpi_madt_irqoverride_t);
|
|
|
|
irqoverride->bus = bus;
|
|
|
|
irqoverride->source = source;
|
|
|
|
irqoverride->gsirq = gsirq;
|
|
|
|
irqoverride->flags = flags;
|
|
|
|
|
|
|
|
return irqoverride->length;
|
2004-02-03 17:11:35 +01:00
|
|
|
}
|
|
|
|
|
2005-01-19 15:06:41 +01:00
|
|
|
int acpi_create_madt_lapic_nmi(acpi_madt_lapic_nmi_t *lapic_nmi, u8 cpu,
|
2011-07-01 23:57:07 +02:00
|
|
|
u16 flags, u8 lint)
|
2004-02-03 17:11:35 +01:00
|
|
|
{
|
2019-10-21 15:20:50 +02:00
|
|
|
lapic_nmi->type = LOCAL_APIC_NMI; /* Local APIC NMI structure */
|
2010-11-19 16:14:42 +01:00
|
|
|
lapic_nmi->length = sizeof(acpi_madt_lapic_nmi_t);
|
|
|
|
lapic_nmi->flags = flags;
|
|
|
|
lapic_nmi->processor_id = cpu;
|
|
|
|
lapic_nmi->lint = lint;
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
return lapic_nmi->length;
|
2004-02-03 17:11:35 +01:00
|
|
|
}
|
|
|
|
|
2020-03-24 17:29:49 +01:00
|
|
|
int acpi_create_madt_lx2apic_nmi(acpi_madt_lx2apic_nmi_t *lapic_nmi, u32 cpu,
|
|
|
|
u16 flags, u8 lint)
|
|
|
|
{
|
|
|
|
lapic_nmi->type = LOCAL_X2APIC_NMI; /* Local APIC NMI structure */
|
|
|
|
lapic_nmi->length = sizeof(acpi_madt_lx2apic_nmi_t);
|
|
|
|
lapic_nmi->flags = flags;
|
|
|
|
lapic_nmi->processor_id = cpu;
|
|
|
|
lapic_nmi->lint = lint;
|
|
|
|
lapic_nmi->reserved[0] = 0;
|
|
|
|
lapic_nmi->reserved[1] = 0;
|
|
|
|
lapic_nmi->reserved[2] = 0;
|
|
|
|
|
|
|
|
return lapic_nmi->length;
|
|
|
|
}
|
|
|
|
|
2020-05-01 06:27:47 +02:00
|
|
|
__weak uintptr_t cpu_get_lapic_addr(void)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If an architecture does not support LAPIC, this weak implementation returns LAPIC
|
|
|
|
* addr as 0.
|
|
|
|
*/
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-01-19 15:06:41 +01:00
|
|
|
void acpi_create_madt(acpi_madt_t *madt)
|
2004-02-03 17:11:35 +01:00
|
|
|
{
|
2010-11-19 16:14:42 +01:00
|
|
|
acpi_header_t *header = &(madt->header);
|
|
|
|
unsigned long current = (unsigned long)madt + sizeof(acpi_madt_t);
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2004-02-03 17:11:35 +01:00
|
|
|
memset((void *)madt, 0, sizeof(acpi_madt_t));
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2019-05-29 01:48:14 +02:00
|
|
|
if (!header)
|
|
|
|
return;
|
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* Fill out header fields. */
|
2009-07-22 00:15:43 +02:00
|
|
|
memcpy(header->signature, "APIC", 4);
|
2004-02-03 17:11:35 +01:00
|
|
|
memcpy(header->oem_id, OEM_ID, 6);
|
2009-07-22 00:15:43 +02:00
|
|
|
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
|
2004-02-03 17:11:35 +01:00
|
|
|
memcpy(header->asl_compiler_id, ASLC, 4);
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2019-02-25 15:42:07 +01:00
|
|
|
header->asl_compiler_revision = asl_revision;
|
2004-02-03 17:11:35 +01:00
|
|
|
header->length = sizeof(acpi_madt_t);
|
2018-08-23 02:57:24 +02:00
|
|
|
header->revision = get_acpi_table_revision(MADT);
|
2004-02-03 17:11:35 +01:00
|
|
|
|
2020-05-01 06:27:47 +02:00
|
|
|
madt->lapic_addr = cpu_get_lapic_addr();
|
2018-11-24 18:25:50 +01:00
|
|
|
if (CONFIG(ACPI_HAVE_PCAT_8259))
|
|
|
|
madt->flags |= 1;
|
2004-02-03 17:11:35 +01:00
|
|
|
|
2005-11-26 17:56:05 +01:00
|
|
|
current = acpi_fill_madt(current);
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* (Re)calculate length and checksum. */
|
|
|
|
header->length = current - (unsigned long)madt;
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
header->checksum = acpi_checksum((void *)madt, header->length);
|
2005-11-26 17:56:05 +01:00
|
|
|
}
|
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* MCFG is defined in the PCI Firmware Specification 3.0. */
|
2007-11-03 13:50:26 +01:00
|
|
|
void acpi_create_mcfg(acpi_mcfg_t *mcfg)
|
|
|
|
{
|
2010-11-19 16:14:42 +01:00
|
|
|
acpi_header_t *header = &(mcfg->header);
|
|
|
|
unsigned long current = (unsigned long)mcfg + sizeof(acpi_mcfg_t);
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2007-11-03 13:50:26 +01:00
|
|
|
memset((void *)mcfg, 0, sizeof(acpi_mcfg_t));
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2019-05-29 01:48:14 +02:00
|
|
|
if (!header)
|
|
|
|
return;
|
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* Fill out header fields. */
|
2009-07-22 00:15:43 +02:00
|
|
|
memcpy(header->signature, "MCFG", 4);
|
2007-11-03 13:50:26 +01:00
|
|
|
memcpy(header->oem_id, OEM_ID, 6);
|
2009-07-22 00:15:43 +02:00
|
|
|
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
|
2007-11-03 13:50:26 +01:00
|
|
|
memcpy(header->asl_compiler_id, ASLC, 4);
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2019-02-25 15:42:07 +01:00
|
|
|
header->asl_compiler_revision = asl_revision;
|
2007-11-03 13:50:26 +01:00
|
|
|
header->length = sizeof(acpi_mcfg_t);
|
2018-08-23 02:57:24 +02:00
|
|
|
header->revision = get_acpi_table_revision(MCFG);
|
2007-11-03 13:50:26 +01:00
|
|
|
|
|
|
|
current = acpi_fill_mcfg(current);
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* (Re)calculate length and checksum. */
|
|
|
|
header->length = current - (unsigned long)mcfg;
|
|
|
|
header->checksum = acpi_checksum((void *)mcfg, header->length);
|
2007-11-03 13:50:26 +01:00
|
|
|
}
|
|
|
|
|
2015-05-20 19:52:01 +02:00
|
|
|
static void *get_tcpa_log(u32 *size)
|
|
|
|
{
|
|
|
|
const struct cbmem_entry *ce;
|
|
|
|
const u32 tcpa_default_log_len = 0x10000;
|
|
|
|
void *lasa;
|
2018-07-30 01:15:20 +02:00
|
|
|
ce = cbmem_entry_find(CBMEM_ID_TCPA_TCG_LOG);
|
2015-05-20 19:52:01 +02:00
|
|
|
if (ce) {
|
|
|
|
lasa = cbmem_entry_start(ce);
|
|
|
|
*size = cbmem_entry_size(ce);
|
|
|
|
printk(BIOS_DEBUG, "TCPA log found at %p\n", lasa);
|
|
|
|
return lasa;
|
|
|
|
}
|
2018-07-30 01:15:20 +02:00
|
|
|
lasa = cbmem_add(CBMEM_ID_TCPA_TCG_LOG, tcpa_default_log_len);
|
2015-05-20 19:52:01 +02:00
|
|
|
if (!lasa) {
|
|
|
|
printk(BIOS_ERR, "TCPA log creation failed\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
printk(BIOS_DEBUG, "TCPA log created at %p\n", lasa);
|
2017-03-16 21:41:11 +01:00
|
|
|
memset(lasa, 0, tcpa_default_log_len);
|
2015-05-20 19:52:01 +02:00
|
|
|
|
|
|
|
*size = tcpa_default_log_len;
|
|
|
|
return lasa;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void acpi_create_tcpa(acpi_tcpa_t *tcpa)
|
|
|
|
{
|
|
|
|
acpi_header_t *header = &(tcpa->header);
|
|
|
|
u32 tcpa_log_len;
|
|
|
|
void *lasa;
|
|
|
|
|
|
|
|
memset((void *)tcpa, 0, sizeof(acpi_tcpa_t));
|
|
|
|
|
|
|
|
lasa = get_tcpa_log(&tcpa_log_len);
|
2017-03-16 19:24:09 +01:00
|
|
|
if (!lasa)
|
2015-05-20 19:52:01 +02:00
|
|
|
return;
|
|
|
|
|
2019-05-29 01:48:14 +02:00
|
|
|
if (!header)
|
|
|
|
return;
|
|
|
|
|
2015-05-20 19:52:01 +02:00
|
|
|
/* Fill out header fields. */
|
|
|
|
memcpy(header->signature, "TCPA", 4);
|
|
|
|
memcpy(header->oem_id, OEM_ID, 6);
|
|
|
|
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
|
|
|
|
memcpy(header->asl_compiler_id, ASLC, 4);
|
|
|
|
|
2019-02-25 15:42:07 +01:00
|
|
|
header->asl_compiler_revision = asl_revision;
|
2015-05-20 19:52:01 +02:00
|
|
|
header->length = sizeof(acpi_tcpa_t);
|
2018-08-23 02:57:24 +02:00
|
|
|
header->revision = get_acpi_table_revision(TCPA);
|
2015-05-20 19:52:01 +02:00
|
|
|
|
|
|
|
tcpa->platform_class = 0;
|
|
|
|
tcpa->laml = tcpa_log_len;
|
2015-06-18 10:11:19 +02:00
|
|
|
tcpa->lasa = (uintptr_t) lasa;
|
2015-05-20 19:52:01 +02:00
|
|
|
|
|
|
|
/* Calculate checksum. */
|
|
|
|
header->checksum = acpi_checksum((void *)tcpa, header->length);
|
|
|
|
}
|
|
|
|
|
2018-11-22 16:57:50 +01:00
|
|
|
static void *get_tpm2_log(u32 *size)
|
|
|
|
{
|
|
|
|
const struct cbmem_entry *ce;
|
|
|
|
const u32 tpm2_default_log_len = 0x10000;
|
|
|
|
void *lasa;
|
|
|
|
ce = cbmem_entry_find(CBMEM_ID_TPM2_TCG_LOG);
|
|
|
|
if (ce) {
|
|
|
|
lasa = cbmem_entry_start(ce);
|
|
|
|
*size = cbmem_entry_size(ce);
|
|
|
|
printk(BIOS_DEBUG, "TPM2 log found at %p\n", lasa);
|
|
|
|
return lasa;
|
|
|
|
}
|
|
|
|
lasa = cbmem_add(CBMEM_ID_TPM2_TCG_LOG, tpm2_default_log_len);
|
|
|
|
if (!lasa) {
|
|
|
|
printk(BIOS_ERR, "TPM2 log creation failed\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
printk(BIOS_DEBUG, "TPM2 log created at %p\n", lasa);
|
|
|
|
memset(lasa, 0, tpm2_default_log_len);
|
|
|
|
|
|
|
|
*size = tpm2_default_log_len;
|
|
|
|
return lasa;
|
|
|
|
}
|
|
|
|
|
2018-10-18 15:39:34 +02:00
|
|
|
static void acpi_create_tpm2(acpi_tpm2_t *tpm2)
|
|
|
|
{
|
|
|
|
acpi_header_t *header = &(tpm2->header);
|
2018-11-22 16:57:50 +01:00
|
|
|
u32 tpm2_log_len;
|
|
|
|
void *lasa;
|
2018-10-18 15:39:34 +02:00
|
|
|
|
|
|
|
memset((void *)tpm2, 0, sizeof(acpi_tpm2_t));
|
|
|
|
|
2018-11-22 16:57:50 +01:00
|
|
|
/*
|
|
|
|
* Some payloads like SeaBIOS depend on log area to use TPM2.
|
|
|
|
* Get the memory size and address of TPM2 log area or initialize it.
|
|
|
|
*/
|
|
|
|
lasa = get_tpm2_log(&tpm2_log_len);
|
|
|
|
if (!lasa)
|
|
|
|
tpm2_log_len = 0;
|
|
|
|
|
2019-05-29 01:48:14 +02:00
|
|
|
if (!header)
|
|
|
|
return;
|
|
|
|
|
2018-10-18 15:39:34 +02:00
|
|
|
/* Fill out header fields. */
|
|
|
|
memcpy(header->signature, "TPM2", 4);
|
|
|
|
memcpy(header->oem_id, OEM_ID, 6);
|
|
|
|
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
|
|
|
|
memcpy(header->asl_compiler_id, ASLC, 4);
|
|
|
|
|
2019-02-25 15:42:07 +01:00
|
|
|
header->asl_compiler_revision = asl_revision;
|
2018-10-18 15:39:34 +02:00
|
|
|
header->length = sizeof(acpi_tpm2_t);
|
|
|
|
header->revision = get_acpi_table_revision(TPM2);
|
|
|
|
|
|
|
|
/* Hard to detect for coreboot. Just set it to 0 */
|
|
|
|
tpm2->platform_class = 0;
|
2019-07-14 15:47:23 +02:00
|
|
|
if (CONFIG(CRB_TPM)) {
|
|
|
|
/* Must be set to 7 for CRB Support */
|
|
|
|
tpm2->control_area = CONFIG_CRB_TPM_BASE_ADDRESS + 0x40;
|
|
|
|
tpm2->start_method = 7;
|
|
|
|
} else {
|
|
|
|
/* Must be set to 0 for FIFO interface support */
|
|
|
|
tpm2->control_area = 0;
|
|
|
|
tpm2->start_method = 6;
|
|
|
|
}
|
2018-10-18 15:39:34 +02:00
|
|
|
memset(tpm2->msp, 0, sizeof(tpm2->msp));
|
|
|
|
|
2018-11-22 16:57:50 +01:00
|
|
|
/* Fill the log area size and start address fields. */
|
|
|
|
tpm2->laml = tpm2_log_len;
|
|
|
|
tpm2->lasa = (uintptr_t) lasa;
|
|
|
|
|
2018-10-18 15:39:34 +02:00
|
|
|
/* Calculate checksum. */
|
|
|
|
header->checksum = acpi_checksum((void *)tpm2, header->length);
|
|
|
|
}
|
|
|
|
|
acpi: Generate object for coreboot table region
Generate an object to describe the coreboot table region in ACPI
with the HID "CORE0000" so it can be used by kernel drivers.
To keep track of the "CORE" HID usage add them to an enum and add
a function to generate the HID in AML: Name (_HID, "CORExxxx")
BUG=chromium:589817
BRANCH=none
TEST=build and boot on chell, dump SSDT to verify contents:
Device (CTBL)
{
Name (_HID, "CORE0000") // _HID: Hardware ID
Name (_UID, Zero) // _UID: Unique ID
Method (_STA, 0, NotSerialized) // _STA: Status
{
Return (0x0F)
}
Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings
{
Memory32Fixed (ReadOnly,
0x7AB84000, // Address Base
0x00008000, // Address Length
)
})
}
Change-Id: I2c681c1fee02d52b8df2e72f6f6f0b76fa9592fb
Signed-off-by: Duncan Laurie <dlaurie@chromium.org>
Reviewed-on: https://review.coreboot.org/16056
Tested-by: build bot (Jenkins)
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
2016-05-26 21:47:05 +02:00
|
|
|
static void acpi_ssdt_write_cbtable(void)
|
|
|
|
{
|
|
|
|
const struct cbmem_entry *cbtable;
|
|
|
|
uintptr_t base;
|
|
|
|
uint32_t size;
|
|
|
|
|
|
|
|
cbtable = cbmem_entry_find(CBMEM_ID_CBTABLE);
|
|
|
|
if (!cbtable)
|
|
|
|
return;
|
|
|
|
base = (uintptr_t)cbmem_entry_start(cbtable);
|
|
|
|
size = cbmem_entry_size(cbtable);
|
|
|
|
|
|
|
|
acpigen_write_device("CTBL");
|
|
|
|
acpigen_write_coreboot_hid(COREBOOT_ACPI_ID_CBTABLE);
|
|
|
|
acpigen_write_name_integer("_UID", 0);
|
2018-03-21 09:48:53 +01:00
|
|
|
acpigen_write_STA(ACPI_STATUS_DEVICE_HIDDEN_ON);
|
acpi: Generate object for coreboot table region
Generate an object to describe the coreboot table region in ACPI
with the HID "CORE0000" so it can be used by kernel drivers.
To keep track of the "CORE" HID usage add them to an enum and add
a function to generate the HID in AML: Name (_HID, "CORExxxx")
BUG=chromium:589817
BRANCH=none
TEST=build and boot on chell, dump SSDT to verify contents:
Device (CTBL)
{
Name (_HID, "CORE0000") // _HID: Hardware ID
Name (_UID, Zero) // _UID: Unique ID
Method (_STA, 0, NotSerialized) // _STA: Status
{
Return (0x0F)
}
Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings
{
Memory32Fixed (ReadOnly,
0x7AB84000, // Address Base
0x00008000, // Address Length
)
})
}
Change-Id: I2c681c1fee02d52b8df2e72f6f6f0b76fa9592fb
Signed-off-by: Duncan Laurie <dlaurie@chromium.org>
Reviewed-on: https://review.coreboot.org/16056
Tested-by: build bot (Jenkins)
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
2016-05-26 21:47:05 +02:00
|
|
|
acpigen_write_name("_CRS");
|
|
|
|
acpigen_write_resourcetemplate_header();
|
|
|
|
acpigen_write_mem32fixed(0, base, size);
|
|
|
|
acpigen_write_resourcetemplate_footer();
|
|
|
|
acpigen_pop_len();
|
|
|
|
}
|
|
|
|
|
2009-10-09 22:13:43 +02:00
|
|
|
void acpi_create_ssdt_generator(acpi_header_t *ssdt, const char *oem_table_id)
|
2009-02-01 19:35:15 +01:00
|
|
|
{
|
2010-11-19 16:14:42 +01:00
|
|
|
unsigned long current = (unsigned long)ssdt + sizeof(acpi_header_t);
|
|
|
|
|
2009-02-01 19:35:15 +01:00
|
|
|
memset((void *)ssdt, 0, sizeof(acpi_header_t));
|
2010-11-19 16:14:42 +01:00
|
|
|
|
2009-07-22 00:15:43 +02:00
|
|
|
memcpy(&ssdt->signature, "SSDT", 4);
|
2018-08-23 02:57:24 +02:00
|
|
|
ssdt->revision = get_acpi_table_revision(SSDT);
|
2009-02-01 19:35:15 +01:00
|
|
|
memcpy(&ssdt->oem_id, OEM_ID, 6);
|
|
|
|
memcpy(&ssdt->oem_table_id, oem_table_id, 8);
|
|
|
|
ssdt->oem_revision = 42;
|
2010-11-19 16:14:42 +01:00
|
|
|
memcpy(&ssdt->asl_compiler_id, ASLC, 4);
|
2019-02-15 08:21:33 +01:00
|
|
|
ssdt->asl_compiler_revision = asl_revision;
|
2009-02-01 19:35:15 +01:00
|
|
|
ssdt->length = sizeof(acpi_header_t);
|
|
|
|
|
2009-03-06 18:24:29 +01:00
|
|
|
acpigen_set_current((char *) current);
|
acpi: Generate object for coreboot table region
Generate an object to describe the coreboot table region in ACPI
with the HID "CORE0000" so it can be used by kernel drivers.
To keep track of the "CORE" HID usage add them to an enum and add
a function to generate the HID in AML: Name (_HID, "CORExxxx")
BUG=chromium:589817
BRANCH=none
TEST=build and boot on chell, dump SSDT to verify contents:
Device (CTBL)
{
Name (_HID, "CORE0000") // _HID: Hardware ID
Name (_UID, Zero) // _UID: Unique ID
Method (_STA, 0, NotSerialized) // _STA: Status
{
Return (0x0F)
}
Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings
{
Memory32Fixed (ReadOnly,
0x7AB84000, // Address Base
0x00008000, // Address Length
)
})
}
Change-Id: I2c681c1fee02d52b8df2e72f6f6f0b76fa9592fb
Signed-off-by: Duncan Laurie <dlaurie@chromium.org>
Reviewed-on: https://review.coreboot.org/16056
Tested-by: build bot (Jenkins)
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
2016-05-26 21:47:05 +02:00
|
|
|
|
|
|
|
/* Write object to declare coreboot tables */
|
|
|
|
acpi_ssdt_write_cbtable();
|
|
|
|
|
2014-08-30 19:28:05 +02:00
|
|
|
{
|
2014-10-27 13:29:29 +01:00
|
|
|
struct device *dev;
|
2014-08-30 19:28:05 +02:00
|
|
|
for (dev = all_devices; dev; dev = dev->next)
|
2020-11-03 00:26:52 +01:00
|
|
|
if (dev->enabled && dev->ops && dev->ops->acpi_fill_ssdt)
|
2020-03-31 17:34:52 +02:00
|
|
|
dev->ops->acpi_fill_ssdt(dev);
|
2014-10-05 14:34:17 +02:00
|
|
|
current = (unsigned long) acpigen_get_current();
|
2014-08-30 19:28:05 +02:00
|
|
|
}
|
2009-02-01 19:35:15 +01:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* (Re)calculate length and checksum. */
|
2009-02-01 19:35:15 +01:00
|
|
|
ssdt->length = current - (unsigned long)ssdt;
|
|
|
|
ssdt->checksum = acpi_checksum((void *)ssdt, ssdt->length);
|
|
|
|
}
|
|
|
|
|
2005-11-26 17:56:05 +01:00
|
|
|
int acpi_create_srat_lapic(acpi_srat_lapic_t *lapic, u8 node, u8 apic)
|
|
|
|
{
|
2009-03-10 19:06:47 +01:00
|
|
|
memset((void *)lapic, 0, sizeof(acpi_srat_lapic_t));
|
2005-11-26 17:56:05 +01:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
lapic->type = 0; /* Processor local APIC/SAPIC affinity structure */
|
|
|
|
lapic->length = sizeof(acpi_srat_lapic_t);
|
|
|
|
lapic->flags = (1 << 0); /* Enabled (the use of this structure). */
|
|
|
|
lapic->proximity_domain_7_0 = node;
|
|
|
|
/* TODO: proximity_domain_31_8, local SAPIC EID, clock domain. */
|
|
|
|
lapic->apic_id = apic;
|
2005-11-26 17:56:05 +01:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
return lapic->length;
|
2005-11-26 17:56:05 +01:00
|
|
|
}
|
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
int acpi_create_srat_mem(acpi_srat_mem_t *mem, u8 node, u32 basek, u32 sizek,
|
2011-07-01 23:57:07 +02:00
|
|
|
u32 flags)
|
2005-11-26 17:56:05 +01:00
|
|
|
{
|
2010-11-19 16:14:42 +01:00
|
|
|
mem->type = 1; /* Memory affinity structure */
|
|
|
|
mem->length = sizeof(acpi_srat_mem_t);
|
|
|
|
mem->base_address_low = (basek << 10);
|
|
|
|
mem->base_address_high = (basek >> (32 - 10));
|
|
|
|
mem->length_low = (sizek << 10);
|
|
|
|
mem->length_high = (sizek >> (32 - 10));
|
|
|
|
mem->proximity_domain = node;
|
2010-04-27 08:56:47 +02:00
|
|
|
mem->flags = flags;
|
2005-11-26 17:56:05 +01:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
return mem->length;
|
2005-11-26 17:56:05 +01:00
|
|
|
}
|
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* http://www.microsoft.com/whdc/system/sysinternals/sratdwn.mspx */
|
2014-10-11 23:45:40 +02:00
|
|
|
void acpi_create_srat(acpi_srat_t *srat,
|
|
|
|
unsigned long (*acpi_fill_srat)(unsigned long current))
|
2005-11-26 17:56:05 +01:00
|
|
|
{
|
2010-11-19 16:14:42 +01:00
|
|
|
acpi_header_t *header = &(srat->header);
|
|
|
|
unsigned long current = (unsigned long)srat + sizeof(acpi_srat_t);
|
2005-11-26 17:56:05 +01:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
memset((void *)srat, 0, sizeof(acpi_srat_t));
|
2005-11-26 17:56:05 +01:00
|
|
|
|
2019-05-29 01:48:14 +02:00
|
|
|
if (!header)
|
|
|
|
return;
|
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* Fill out header fields. */
|
|
|
|
memcpy(header->signature, "SRAT", 4);
|
|
|
|
memcpy(header->oem_id, OEM_ID, 6);
|
|
|
|
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
|
|
|
|
memcpy(header->asl_compiler_id, ASLC, 4);
|
2005-11-26 17:56:05 +01:00
|
|
|
|
2019-02-25 15:42:07 +01:00
|
|
|
header->asl_compiler_revision = asl_revision;
|
2010-11-19 16:14:42 +01:00
|
|
|
header->length = sizeof(acpi_srat_t);
|
2018-08-23 02:57:24 +02:00
|
|
|
header->revision = get_acpi_table_revision(SRAT);
|
2005-11-26 17:56:05 +01:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
srat->resv = 1; /* Spec: Reserved to 1 for backwards compatibility. */
|
2005-11-26 17:56:05 +01:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
current = acpi_fill_srat(current);
|
2005-11-26 17:56:05 +01:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* (Re)calculate length and checksum. */
|
|
|
|
header->length = current - (unsigned long)srat;
|
|
|
|
header->checksum = acpi_checksum((void *)srat, header->length);
|
2006-10-04 22:46:15 +02:00
|
|
|
}
|
|
|
|
|
2021-04-01 20:43:37 +02:00
|
|
|
int acpi_create_hmat_mpda(acpi_hmat_mpda_t *mpda, u32 initiator, u32 memory)
|
|
|
|
{
|
|
|
|
memset((void *)mpda, 0, sizeof(acpi_hmat_mpda_t));
|
|
|
|
|
|
|
|
mpda->type = 0; /* Memory Proximity Domain Attributes structure */
|
|
|
|
mpda->length = sizeof(acpi_hmat_mpda_t);
|
|
|
|
/*
|
|
|
|
* Proximity Domain for Attached Initiator field is valid.
|
|
|
|
* Bit 1 and bit 2 are reserved since HMAT revision 2.
|
|
|
|
*/
|
|
|
|
mpda->flags = (1 << 0);
|
|
|
|
mpda->proximity_domain_initiator = initiator;
|
|
|
|
mpda->proximity_domain_memory = memory;
|
|
|
|
|
|
|
|
return mpda->length;
|
|
|
|
}
|
|
|
|
|
|
|
|
void acpi_create_hmat(acpi_hmat_t *hmat,
|
|
|
|
unsigned long (*acpi_fill_hmat)(unsigned long current))
|
|
|
|
{
|
|
|
|
acpi_header_t *header = &(hmat->header);
|
|
|
|
unsigned long current = (unsigned long)hmat + sizeof(acpi_hmat_t);
|
|
|
|
|
|
|
|
memset((void *)hmat, 0, sizeof(acpi_hmat_t));
|
|
|
|
|
|
|
|
if (!header)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Fill out header fields. */
|
|
|
|
memcpy(header->signature, "HMAT", 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_hmat_t);
|
|
|
|
header->revision = get_acpi_table_revision(HMAT);
|
|
|
|
|
|
|
|
current = acpi_fill_hmat(current);
|
|
|
|
|
|
|
|
/* (Re)calculate length and checksum. */
|
|
|
|
header->length = current - (unsigned long)hmat;
|
|
|
|
header->checksum = acpi_checksum((void *)hmat, header->length);
|
|
|
|
}
|
|
|
|
|
2015-10-26 11:51:25 +01:00
|
|
|
void acpi_create_dmar(acpi_dmar_t *dmar, enum dmar_flags flags,
|
2017-03-16 21:41:11 +01:00
|
|
|
unsigned long (*acpi_fill_dmar)(unsigned long))
|
2012-09-11 15:21:01 +02:00
|
|
|
{
|
|
|
|
acpi_header_t *header = &(dmar->header);
|
|
|
|
unsigned long current = (unsigned long)dmar + sizeof(acpi_dmar_t);
|
|
|
|
|
|
|
|
memset((void *)dmar, 0, sizeof(acpi_dmar_t));
|
|
|
|
|
2019-05-29 01:48:14 +02:00
|
|
|
if (!header)
|
|
|
|
return;
|
|
|
|
|
2012-09-11 15:21:01 +02:00
|
|
|
/* 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);
|
|
|
|
|
2019-02-25 15:42:07 +01:00
|
|
|
header->asl_compiler_revision = asl_revision;
|
2012-09-11 15:21:01 +02:00
|
|
|
header->length = sizeof(acpi_dmar_t);
|
2018-08-23 02:57:24 +02:00
|
|
|
header->revision = get_acpi_table_revision(DMAR);
|
2012-09-11 15:21:01 +02:00
|
|
|
|
2016-03-16 03:53:27 +01:00
|
|
|
dmar->host_address_width = cpu_phys_address_size() - 1;
|
2015-10-26 11:51:25 +01:00
|
|
|
dmar->flags = flags;
|
2012-09-11 15:21:01 +02:00
|
|
|
|
|
|
|
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,
|
2018-03-29 14:59:57 +02:00
|
|
|
u16 segment, u64 bar)
|
2012-09-11 15:21:01 +02:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-03-29 14:59:57 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-07-27 06:56:36 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-04-04 20:03:28 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2021-04-18 01:03:21 +02:00
|
|
|
unsigned long acpi_create_dmar_satc(unsigned long current, u8 flags, u16 segment)
|
2021-03-24 19:55:09 +01:00
|
|
|
{
|
|
|
|
dmar_satc_entry_t *satc = (dmar_satc_entry_t *)current;
|
2021-04-18 01:03:21 +02:00
|
|
|
int satc_len = sizeof(dmar_satc_entry_t);
|
2021-03-24 19:55:09 +01:00
|
|
|
memset(satc, 0, satc_len);
|
|
|
|
satc->type = DMAR_SATC;
|
|
|
|
satc->length = satc_len;
|
|
|
|
satc->flags = flags;
|
|
|
|
satc->segment_number = segment;
|
|
|
|
|
|
|
|
return satc->length;
|
|
|
|
}
|
|
|
|
|
2012-09-11 15:21:01 +02:00
|
|
|
void acpi_dmar_drhd_fixup(unsigned long base, unsigned long current)
|
|
|
|
{
|
|
|
|
dmar_entry_t *drhd = (dmar_entry_t *)base;
|
|
|
|
drhd->length = current - base;
|
|
|
|
}
|
|
|
|
|
2018-03-29 14:59:57 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-07-27 06:56:36 +02:00
|
|
|
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;
|
2021-03-24 19:55:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2016-07-27 06:56:36 +02:00
|
|
|
}
|
|
|
|
|
2018-03-29 14:59:57 +02:00
|
|
|
static unsigned long acpi_create_dmar_ds(unsigned long current,
|
2015-10-26 12:03:54 +01:00
|
|
|
enum dev_scope_type type, u8 enumeration_id, u8 bus, u8 dev, u8 fn)
|
2012-09-11 15:21:01 +02:00
|
|
|
{
|
2015-10-26 12:03:54 +01:00
|
|
|
/* we don't support longer paths yet */
|
|
|
|
const size_t dev_scope_length = sizeof(dev_scope_t) + 2;
|
|
|
|
|
2012-09-11 15:21:01 +02:00
|
|
|
dev_scope_t *ds = (dev_scope_t *)current;
|
2015-10-26 12:03:54 +01:00
|
|
|
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;
|
2012-09-11 15:21:01 +02:00
|
|
|
|
|
|
|
return ds->length;
|
|
|
|
}
|
|
|
|
|
2018-03-29 14:59:57 +02:00
|
|
|
unsigned long acpi_create_dmar_ds_pci_br(unsigned long current, u8 bus,
|
2016-07-27 07:07:20 +02:00
|
|
|
u8 dev, u8 fn)
|
|
|
|
{
|
2018-03-29 14:59:57 +02:00
|
|
|
return acpi_create_dmar_ds(current,
|
2016-07-27 07:07:20 +02:00
|
|
|
SCOPE_PCI_SUB, 0, bus, dev, fn);
|
|
|
|
}
|
|
|
|
|
2018-03-29 14:59:57 +02:00
|
|
|
unsigned long acpi_create_dmar_ds_pci(unsigned long current, u8 bus,
|
2015-10-26 12:03:54 +01:00
|
|
|
u8 dev, u8 fn)
|
|
|
|
{
|
2018-03-29 14:59:57 +02:00
|
|
|
return acpi_create_dmar_ds(current,
|
2015-10-26 12:03:54 +01:00
|
|
|
SCOPE_PCI_ENDPOINT, 0, bus, dev, fn);
|
|
|
|
}
|
|
|
|
|
2018-03-29 14:59:57 +02:00
|
|
|
unsigned long acpi_create_dmar_ds_ioapic(unsigned long current,
|
2015-10-26 12:03:54 +01:00
|
|
|
u8 enumeration_id, u8 bus, u8 dev, u8 fn)
|
|
|
|
{
|
2018-03-29 14:59:57 +02:00
|
|
|
return acpi_create_dmar_ds(current,
|
2015-10-26 12:03:54 +01:00
|
|
|
SCOPE_IOAPIC, enumeration_id, bus, dev, fn);
|
|
|
|
}
|
|
|
|
|
2018-03-29 14:59:57 +02:00
|
|
|
unsigned long acpi_create_dmar_ds_msi_hpet(unsigned long current,
|
2015-10-26 12:03:54 +01:00
|
|
|
u8 enumeration_id, u8 bus, u8 dev, u8 fn)
|
|
|
|
{
|
2018-03-29 14:59:57 +02:00
|
|
|
return acpi_create_dmar_ds(current,
|
2015-10-26 12:03:54 +01:00
|
|
|
SCOPE_MSI_HPET, enumeration_id, bus, dev, fn);
|
|
|
|
}
|
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* http://h21007.www2.hp.com/portal/download/files/unprot/Itanium/slit.pdf */
|
2014-10-11 23:45:40 +02:00
|
|
|
void acpi_create_slit(acpi_slit_t *slit,
|
|
|
|
unsigned long (*acpi_fill_slit)(unsigned long current))
|
2006-10-04 22:46:15 +02:00
|
|
|
{
|
2010-11-19 16:14:42 +01:00
|
|
|
acpi_header_t *header = &(slit->header);
|
|
|
|
unsigned long current = (unsigned long)slit + sizeof(acpi_slit_t);
|
2006-10-04 22:46:15 +02:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
memset((void *)slit, 0, sizeof(acpi_slit_t));
|
2006-10-04 22:46:15 +02:00
|
|
|
|
2019-05-29 01:48:14 +02:00
|
|
|
if (!header)
|
|
|
|
return;
|
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* Fill out header fields. */
|
|
|
|
memcpy(header->signature, "SLIT", 4);
|
|
|
|
memcpy(header->oem_id, OEM_ID, 6);
|
|
|
|
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
|
|
|
|
memcpy(header->asl_compiler_id, ASLC, 4);
|
2006-10-04 22:46:15 +02:00
|
|
|
|
2019-02-25 15:42:07 +01:00
|
|
|
header->asl_compiler_revision = asl_revision;
|
2010-11-19 16:14:42 +01:00
|
|
|
header->length = sizeof(acpi_slit_t);
|
2018-08-23 02:57:24 +02:00
|
|
|
header->revision = get_acpi_table_revision(SLIT);
|
2006-10-04 22:46:15 +02:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
current = acpi_fill_slit(current);
|
2006-10-04 22:46:15 +02:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* (Re)calculate length and checksum. */
|
|
|
|
header->length = current - (unsigned long)slit;
|
|
|
|
header->checksum = acpi_checksum((void *)slit, header->length);
|
2004-02-03 17:11:35 +01:00
|
|
|
}
|
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* http://www.intel.com/hardwaredesign/hpetspec_1.pdf */
|
2005-01-19 15:06:41 +01:00
|
|
|
void acpi_create_hpet(acpi_hpet_t *hpet)
|
2004-01-28 17:56:14 +01:00
|
|
|
{
|
2010-11-19 16:14:42 +01:00
|
|
|
acpi_header_t *header = &(hpet->header);
|
|
|
|
acpi_addr_t *addr = &(hpet->addr);
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2004-01-29 18:31:34 +01:00
|
|
|
memset((void *)hpet, 0, sizeof(acpi_hpet_t));
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2019-05-29 01:48:14 +02:00
|
|
|
if (!header)
|
|
|
|
return;
|
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* Fill out header fields. */
|
2009-07-22 03:11:37 +02:00
|
|
|
memcpy(header->signature, "HPET", 4);
|
2004-01-28 17:56:14 +01:00
|
|
|
memcpy(header->oem_id, OEM_ID, 6);
|
2009-07-22 00:15:43 +02:00
|
|
|
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
|
2004-01-28 17:56:14 +01:00
|
|
|
memcpy(header->asl_compiler_id, ASLC, 4);
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2019-02-25 15:42:07 +01:00
|
|
|
header->asl_compiler_revision = asl_revision;
|
2004-01-28 17:56:14 +01:00
|
|
|
header->length = sizeof(acpi_hpet_t);
|
2018-08-23 02:57:24 +02:00
|
|
|
header->revision = get_acpi_table_revision(HPET);
|
2004-01-28 17:56:14 +01:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* Fill out HPET address. */
|
2020-07-20 17:05:24 +02:00
|
|
|
addr->space_id = ACPI_ADDRESS_SPACE_MEMORY;
|
2010-11-19 16:14:42 +01:00
|
|
|
addr->bit_width = 64;
|
|
|
|
addr->bit_offset = 0;
|
2012-10-05 21:54:38 +02:00
|
|
|
addr->addrl = CONFIG_HPET_ADDRESS & 0xffffffff;
|
|
|
|
addr->addrh = ((unsigned long long)CONFIG_HPET_ADDRESS) >> 32;
|
2004-01-28 17:56:14 +01:00
|
|
|
|
2017-03-16 21:41:11 +01:00
|
|
|
hpet->id = *(unsigned int *)CONFIG_HPET_ADDRESS;
|
2010-11-19 16:14:42 +01:00
|
|
|
hpet->number = 0;
|
2012-10-05 21:54:38 +02:00
|
|
|
hpet->min_tick = CONFIG_HPET_MIN_TICKS;
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
header->checksum = acpi_checksum((void *)hpet, sizeof(acpi_hpet_t));
|
2004-01-28 17:56:14 +01:00
|
|
|
}
|
2010-11-19 16:14:42 +01:00
|
|
|
|
2021-01-11 00:42:50 +01:00
|
|
|
/*
|
|
|
|
* This method adds the ACPI error injection capability. It fills the default information.
|
|
|
|
* HW dependent code (caller) can modify the defaults upon return. If no changes are necessary
|
|
|
|
* and the defaults are acceptable then caller can simply add the table (acpi_add_table).
|
|
|
|
* INPUTS:
|
|
|
|
* einj - ptr to the starting location of EINJ table
|
|
|
|
* actions - number of actions to trigger an error (HW dependent)
|
|
|
|
* addr - address of trigger action table. This should be ACPI reserved memory and it will be
|
|
|
|
* shared between OS and FW.
|
|
|
|
*/
|
|
|
|
void acpi_create_einj(acpi_einj_t *einj, uintptr_t addr, u8 actions)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
acpi_header_t *header = &(einj->header);
|
|
|
|
acpi_injection_header_t *inj_header = &(einj->inj_header);
|
|
|
|
acpi_einj_smi_t *einj_smi = (acpi_einj_smi_t *)addr;
|
|
|
|
acpi_einj_trigger_table_t *tat;
|
|
|
|
if (!header)
|
|
|
|
return;
|
|
|
|
|
|
|
|
printk(BIOS_DEBUG, "%s einj_smi = %p\n", __func__, einj_smi);
|
|
|
|
memset(einj_smi, 0, sizeof(acpi_einj_smi_t));
|
|
|
|
tat = (acpi_einj_trigger_table_t *)(einj_smi + sizeof(acpi_einj_smi_t));
|
|
|
|
tat->header_size = 16;
|
|
|
|
tat->revision = 0;
|
|
|
|
tat->table_size = sizeof(acpi_einj_trigger_table_t) +
|
|
|
|
sizeof(acpi_einj_action_table_t) * actions - 1;
|
|
|
|
tat->entry_count = actions;
|
|
|
|
printk(BIOS_DEBUG, "%s trigger_action_table = %p\n", __func__, tat);
|
|
|
|
|
|
|
|
for (i = 0; i < actions; i++) {
|
|
|
|
tat->trigger_action[i].action = TRIGGER_ERROR;
|
|
|
|
tat->trigger_action[i].instruction = NO_OP;
|
|
|
|
tat->trigger_action[i].flags = FLAG_IGNORE;
|
|
|
|
tat->trigger_action[i].reg.space_id = ACPI_ADDRESS_SPACE_MEMORY;
|
|
|
|
tat->trigger_action[i].reg.bit_width = 64;
|
|
|
|
tat->trigger_action[i].reg.bit_offset = 0;
|
|
|
|
tat->trigger_action[i].reg.access_size = ACPI_ACCESS_SIZE_QWORD_ACCESS;
|
|
|
|
tat->trigger_action[i].reg.addr = 0;
|
|
|
|
tat->trigger_action[i].value = 0;
|
|
|
|
tat->trigger_action[i].mask = 0xFFFFFFFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
acpi_einj_action_table_t default_actions[ACTION_COUNT] = {
|
|
|
|
[0] = {
|
|
|
|
.action = BEGIN_INJECT_OP,
|
|
|
|
.instruction = WRITE_REGISTER_VALUE,
|
|
|
|
.flags = FLAG_PRESERVE,
|
|
|
|
.reg = EINJ_REG_MEMORY((u64)(uintptr_t)&einj_smi->op_state),
|
|
|
|
.value = 0,
|
|
|
|
.mask = 0xFFFFFFFF
|
|
|
|
},
|
|
|
|
[1] = {
|
|
|
|
.action = GET_TRIGGER_ACTION_TABLE,
|
|
|
|
.instruction = READ_REGISTER,
|
|
|
|
.flags = FLAG_IGNORE,
|
|
|
|
.reg = EINJ_REG_MEMORY((u64)(uintptr_t)&einj_smi->trigger_action_table),
|
|
|
|
.value = 0,
|
|
|
|
.mask = 0xFFFFFFFFFFFFFFFF
|
|
|
|
},
|
|
|
|
[2] = {
|
|
|
|
.action = SET_ERROR_TYPE,
|
|
|
|
.instruction = WRITE_REGISTER,
|
|
|
|
.flags = FLAG_PRESERVE,
|
|
|
|
.reg = EINJ_REG_MEMORY((u64)(uintptr_t)&einj_smi->err_inject[0]),
|
|
|
|
.value = 0,
|
|
|
|
.mask = 0xFFFFFFFF
|
|
|
|
},
|
|
|
|
[3] = {
|
|
|
|
.action = GET_ERROR_TYPE,
|
|
|
|
.instruction = READ_REGISTER,
|
|
|
|
.flags = FLAG_IGNORE,
|
|
|
|
.reg = EINJ_REG_MEMORY((u64)(uintptr_t)&einj_smi->err_inj_cap),
|
|
|
|
.value = 0,
|
|
|
|
.mask = 0xFFFFFFFF
|
|
|
|
},
|
|
|
|
[4] = {
|
|
|
|
.action = END_INJECT_OP,
|
|
|
|
.instruction = WRITE_REGISTER_VALUE,
|
|
|
|
.flags = FLAG_PRESERVE,
|
|
|
|
.reg = EINJ_REG_MEMORY((u64)(uintptr_t)&einj_smi->op_state),
|
|
|
|
.value = 0,
|
|
|
|
.mask = 0xFFFFFFFF
|
|
|
|
|
|
|
|
},
|
|
|
|
[5] = {
|
|
|
|
.action = EXECUTE_INJECT_OP,
|
|
|
|
.instruction = WRITE_REGISTER_VALUE,
|
|
|
|
.flags = FLAG_PRESERVE,
|
|
|
|
.reg = EINJ_REG_IO(),
|
|
|
|
.value = 0x9a,
|
|
|
|
.mask = 0xFFFF,
|
|
|
|
},
|
|
|
|
[6] = {
|
|
|
|
.action = CHECK_BUSY_STATUS,
|
|
|
|
.instruction = READ_REGISTER_VALUE,
|
|
|
|
.flags = FLAG_IGNORE,
|
|
|
|
.reg = EINJ_REG_MEMORY((u64)(uintptr_t)&einj_smi->op_status),
|
|
|
|
.value = 1,
|
|
|
|
.mask = 1,
|
|
|
|
},
|
|
|
|
[7] = {
|
|
|
|
.action = GET_CMD_STATUS,
|
|
|
|
.instruction = READ_REGISTER,
|
|
|
|
.flags = FLAG_PRESERVE,
|
|
|
|
.reg = EINJ_REG_MEMORY((u64)(uintptr_t)&einj_smi->cmd_sts),
|
|
|
|
.value = 0,
|
|
|
|
.mask = 0x1fe,
|
|
|
|
},
|
|
|
|
[8] = {
|
|
|
|
.action = SET_ERROR_TYPE_WITH_ADDRESS,
|
|
|
|
.instruction = WRITE_REGISTER,
|
|
|
|
.flags = FLAG_PRESERVE,
|
|
|
|
.reg = EINJ_REG_MEMORY((u64)(uintptr_t)&einj_smi->setaddrtable),
|
|
|
|
.value = 1,
|
|
|
|
.mask = 0xffffffff
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
einj_smi->err_inj_cap = ACPI_EINJ_DEFAULT_CAP;
|
|
|
|
einj_smi->trigger_action_table = (u64) (uintptr_t)tat;
|
|
|
|
|
|
|
|
for (i = 0; i < ACTION_COUNT; i++)
|
|
|
|
printk(BIOS_DEBUG, "default_actions[%d].reg.addr is %llx\n", i,
|
|
|
|
default_actions[i].reg.addr);
|
|
|
|
|
2021-05-21 22:34:03 +02:00
|
|
|
memset((void *)einj, 0, sizeof(*einj));
|
2021-01-11 00:42:50 +01:00
|
|
|
|
|
|
|
/* Fill out header fields. */
|
|
|
|
memcpy(header->signature, "EINJ", 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_einj_t);
|
|
|
|
header->revision = 1;
|
|
|
|
inj_header->einj_header_size = sizeof(acpi_injection_header_t);
|
|
|
|
inj_header->entry_count = ACTION_COUNT;
|
|
|
|
|
|
|
|
printk(BIOS_DEBUG, "%s einj->action_table = %p\n",
|
|
|
|
__func__, einj->action_table);
|
|
|
|
memcpy((void *)einj->action_table, (void *)default_actions, sizeof(einj->action_table));
|
2021-05-21 22:34:03 +02:00
|
|
|
header->checksum = acpi_checksum((void *)einj, sizeof(*einj));
|
2021-01-11 00:42:50 +01:00
|
|
|
}
|
|
|
|
|
2020-04-24 15:41:18 +02:00
|
|
|
void acpi_create_vfct(const struct device *device,
|
2019-10-21 11:57:19 +02:00
|
|
|
acpi_vfct_t *vfct,
|
2020-04-24 15:41:18 +02:00
|
|
|
unsigned long (*acpi_fill_vfct)(const struct device *device,
|
2019-10-21 11:57:19 +02:00
|
|
|
acpi_vfct_t *vfct_struct, unsigned long current))
|
2016-03-31 20:04:23 +02:00
|
|
|
{
|
|
|
|
acpi_header_t *header = &(vfct->header);
|
2019-10-21 11:57:19 +02:00
|
|
|
unsigned long current = (unsigned long)vfct + sizeof(acpi_vfct_t);
|
2016-03-31 20:04:23 +02:00
|
|
|
|
2019-10-21 11:57:19 +02:00
|
|
|
memset((void *)vfct, 0, sizeof(acpi_vfct_t));
|
2016-03-31 20:04:23 +02:00
|
|
|
|
2019-05-29 01:48:14 +02:00
|
|
|
if (!header)
|
|
|
|
return;
|
|
|
|
|
2016-03-31 20:04:23 +02:00
|
|
|
/* Fill out header fields. */
|
|
|
|
memcpy(header->signature, "VFCT", 4);
|
|
|
|
memcpy(header->oem_id, OEM_ID, 6);
|
|
|
|
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
|
|
|
|
memcpy(header->asl_compiler_id, ASLC, 4);
|
|
|
|
|
2019-02-25 15:42:07 +01:00
|
|
|
header->asl_compiler_revision = asl_revision;
|
2018-08-23 02:57:24 +02:00
|
|
|
header->revision = get_acpi_table_revision(VFCT);
|
2016-03-31 20:04:23 +02:00
|
|
|
|
|
|
|
current = acpi_fill_vfct(device, vfct, current);
|
|
|
|
|
2019-06-30 05:29:52 +02:00
|
|
|
/* If no BIOS image, return with header->length == 0. */
|
|
|
|
if (!vfct->VBIOSImageOffset)
|
|
|
|
return;
|
|
|
|
|
2016-03-31 20:04:23 +02:00
|
|
|
/* (Re)calculate length and checksum. */
|
|
|
|
header->length = current - (unsigned long)vfct;
|
|
|
|
header->checksum = acpi_checksum((void *)vfct, header->length);
|
|
|
|
}
|
|
|
|
|
2020-04-24 15:41:18 +02:00
|
|
|
void acpi_create_ipmi(const struct device *device,
|
2019-06-14 19:00:04 +02:00
|
|
|
struct acpi_spmi *spmi,
|
|
|
|
const u16 ipmi_revision,
|
|
|
|
const acpi_addr_t *addr,
|
|
|
|
const enum acpi_ipmi_interface_type type,
|
|
|
|
const s8 gpe_interrupt,
|
|
|
|
const u32 apic_interrupt,
|
|
|
|
const u32 uid)
|
|
|
|
{
|
|
|
|
acpi_header_t *header = &(spmi->header);
|
|
|
|
memset((void *)spmi, 0, sizeof(struct acpi_spmi));
|
|
|
|
|
|
|
|
/* Fill out header fields. */
|
|
|
|
memcpy(header->signature, "SPMI", 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(struct acpi_spmi);
|
|
|
|
header->revision = get_acpi_table_revision(SPMI);
|
|
|
|
|
|
|
|
spmi->reserved = 1;
|
|
|
|
|
|
|
|
if (device->path.type == DEVICE_PATH_PCI) {
|
|
|
|
spmi->pci_device_flag = ACPI_IPMI_PCI_DEVICE_FLAG;
|
|
|
|
spmi->pci_bus = device->bus->secondary;
|
|
|
|
spmi->pci_device = device->path.pci.devfn >> 3;
|
|
|
|
spmi->pci_function = device->path.pci.devfn & 0x7;
|
|
|
|
} else if (type != IPMI_INTERFACE_SSIF) {
|
|
|
|
memcpy(spmi->uid, &uid, sizeof(spmi->uid));
|
|
|
|
}
|
|
|
|
|
|
|
|
spmi->base_address = *addr;
|
|
|
|
spmi->specification_revision = ipmi_revision;
|
|
|
|
|
|
|
|
spmi->interface_type = type;
|
|
|
|
|
|
|
|
if (gpe_interrupt >= 0 && gpe_interrupt < 32) {
|
|
|
|
spmi->gpe = gpe_interrupt;
|
|
|
|
spmi->interrupt_type |= ACPI_IPMI_INT_TYPE_SCI;
|
|
|
|
}
|
|
|
|
if (apic_interrupt > 0) {
|
|
|
|
spmi->global_system_interrupt = apic_interrupt;
|
|
|
|
spmi->interrupt_type |= ACPI_IPMI_INT_TYPE_APIC;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Calculate checksum. */
|
|
|
|
header->checksum = acpi_checksum((void *)spmi, header->length);
|
|
|
|
}
|
|
|
|
|
2015-08-12 00:48:32 +02:00
|
|
|
void acpi_create_ivrs(acpi_ivrs_t *ivrs,
|
2017-03-16 23:18:22 +01:00
|
|
|
unsigned long (*acpi_fill_ivrs)(acpi_ivrs_t *ivrs_struct,
|
|
|
|
unsigned long current))
|
2015-08-12 00:48:32 +02:00
|
|
|
{
|
|
|
|
acpi_header_t *header = &(ivrs->header);
|
|
|
|
unsigned long current = (unsigned long)ivrs + sizeof(acpi_ivrs_t);
|
|
|
|
|
|
|
|
memset((void *)ivrs, 0, sizeof(acpi_ivrs_t));
|
|
|
|
|
2019-05-29 01:48:14 +02:00
|
|
|
if (!header)
|
|
|
|
return;
|
|
|
|
|
2015-08-12 00:48:32 +02:00
|
|
|
/* Fill out header fields. */
|
|
|
|
memcpy(header->signature, "IVRS", 4);
|
|
|
|
memcpy(header->oem_id, OEM_ID, 6);
|
|
|
|
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
|
|
|
|
memcpy(header->asl_compiler_id, ASLC, 4);
|
|
|
|
|
2019-02-25 15:42:07 +01:00
|
|
|
header->asl_compiler_revision = asl_revision;
|
2015-08-12 00:48:32 +02:00
|
|
|
header->length = sizeof(acpi_ivrs_t);
|
2018-08-23 02:57:24 +02:00
|
|
|
header->revision = get_acpi_table_revision(IVRS);
|
2015-08-12 00:48:32 +02:00
|
|
|
|
|
|
|
current = acpi_fill_ivrs(ivrs, current);
|
|
|
|
|
|
|
|
/* (Re)calculate length and checksum. */
|
|
|
|
header->length = current - (unsigned long)ivrs;
|
|
|
|
header->checksum = acpi_checksum((void *)ivrs, header->length);
|
|
|
|
}
|
|
|
|
|
2020-11-03 05:06:23 +01:00
|
|
|
void acpi_create_crat(struct acpi_crat_header *crat,
|
|
|
|
unsigned long (*acpi_fill_crat)(struct acpi_crat_header *crat_struct,
|
|
|
|
unsigned long current))
|
|
|
|
{
|
|
|
|
acpi_header_t *header = &(crat->header);
|
|
|
|
unsigned long current = (unsigned long)crat + sizeof(struct acpi_crat_header);
|
|
|
|
|
|
|
|
memset((void *)crat, 0, sizeof(struct acpi_crat_header));
|
|
|
|
|
|
|
|
if (!header)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Fill out header fields. */
|
|
|
|
memcpy(header->signature, "CRAT", 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(struct acpi_crat_header);
|
|
|
|
header->revision = get_acpi_table_revision(CRAT);
|
|
|
|
|
|
|
|
current = acpi_fill_crat(crat, current);
|
|
|
|
|
|
|
|
/* (Re)calculate length and checksum. */
|
|
|
|
header->length = current - (unsigned long)crat;
|
|
|
|
header->checksum = acpi_checksum((void *)crat, header->length);
|
|
|
|
}
|
|
|
|
|
2020-04-24 15:41:18 +02:00
|
|
|
unsigned long acpi_write_hpet(const struct device *device, unsigned long current,
|
2017-03-16 23:18:22 +01:00
|
|
|
acpi_rsdp_t *rsdp)
|
2014-08-30 19:28:05 +02:00
|
|
|
{
|
|
|
|
acpi_hpet_t *hpet;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We explicitly add these tables later on:
|
|
|
|
*/
|
|
|
|
printk(BIOS_DEBUG, "ACPI: * HPET\n");
|
|
|
|
|
|
|
|
hpet = (acpi_hpet_t *) current;
|
|
|
|
current += sizeof(acpi_hpet_t);
|
2019-06-20 13:50:17 +02:00
|
|
|
current = ALIGN_UP(current, 16);
|
2014-08-30 19:28:05 +02:00
|
|
|
acpi_create_hpet(hpet);
|
|
|
|
acpi_add_table(rsdp, hpet);
|
|
|
|
|
|
|
|
return current;
|
|
|
|
}
|
|
|
|
|
2017-11-12 04:33:25 +01:00
|
|
|
void acpi_create_dbg2(acpi_dbg2_header_t *dbg2,
|
|
|
|
int port_type, int port_subtype,
|
|
|
|
acpi_addr_t *address, uint32_t address_size,
|
|
|
|
const char *device_path)
|
|
|
|
{
|
|
|
|
uintptr_t current;
|
|
|
|
acpi_dbg2_device_t *device;
|
|
|
|
uint32_t *dbg2_addr_size;
|
|
|
|
acpi_header_t *header;
|
|
|
|
size_t path_len;
|
|
|
|
const char *path;
|
|
|
|
char *namespace;
|
|
|
|
|
|
|
|
/* Fill out header fields. */
|
|
|
|
current = (uintptr_t)dbg2;
|
|
|
|
memset(dbg2, 0, sizeof(acpi_dbg2_header_t));
|
|
|
|
header = &(dbg2->header);
|
2019-05-29 01:48:14 +02:00
|
|
|
|
|
|
|
if (!header)
|
|
|
|
return;
|
|
|
|
|
2018-08-23 02:57:24 +02:00
|
|
|
header->revision = get_acpi_table_revision(DBG2);
|
2017-11-12 04:33:25 +01:00
|
|
|
memcpy(header->signature, "DBG2", 4);
|
|
|
|
memcpy(header->oem_id, OEM_ID, 6);
|
|
|
|
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
|
|
|
|
memcpy(header->asl_compiler_id, ASLC, 4);
|
2019-02-25 15:42:07 +01:00
|
|
|
header->asl_compiler_revision = asl_revision;
|
2017-11-12 04:33:25 +01:00
|
|
|
|
|
|
|
/* One debug device defined */
|
|
|
|
dbg2->devices_offset = sizeof(acpi_dbg2_header_t);
|
|
|
|
dbg2->devices_count = 1;
|
|
|
|
current += sizeof(acpi_dbg2_header_t);
|
|
|
|
|
|
|
|
/* Device comes after the header */
|
|
|
|
device = (acpi_dbg2_device_t *)current;
|
|
|
|
memset(device, 0, sizeof(acpi_dbg2_device_t));
|
|
|
|
current += sizeof(acpi_dbg2_device_t);
|
|
|
|
|
|
|
|
device->revision = 0;
|
|
|
|
device->address_count = 1;
|
|
|
|
device->port_type = port_type;
|
|
|
|
device->port_subtype = port_subtype;
|
|
|
|
|
|
|
|
/* Base Address comes after device structure */
|
|
|
|
memcpy((void *)current, address, sizeof(acpi_addr_t));
|
|
|
|
device->base_address_offset = current - (uintptr_t)device;
|
|
|
|
current += sizeof(acpi_addr_t);
|
|
|
|
|
|
|
|
/* Address Size comes after address structure */
|
|
|
|
dbg2_addr_size = (uint32_t *)current;
|
|
|
|
device->address_size_offset = current - (uintptr_t)device;
|
|
|
|
*dbg2_addr_size = address_size;
|
|
|
|
current += sizeof(uint32_t);
|
|
|
|
|
|
|
|
/* Namespace string comes last, use '.' if not provided */
|
|
|
|
path = device_path ? : ".";
|
|
|
|
/* Namespace string length includes NULL terminator */
|
|
|
|
path_len = strlen(path) + 1;
|
|
|
|
namespace = (char *)current;
|
|
|
|
device->namespace_string_length = path_len;
|
|
|
|
device->namespace_string_offset = current - (uintptr_t)device;
|
|
|
|
strncpy(namespace, path, path_len);
|
|
|
|
current += path_len;
|
|
|
|
|
|
|
|
/* Update structure lengths and checksum */
|
|
|
|
device->length = current - (uintptr_t)device;
|
|
|
|
header->length = current - (uintptr_t)dbg2;
|
|
|
|
header->checksum = acpi_checksum((uint8_t *)dbg2, header->length);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long acpi_write_dbg2_pci_uart(acpi_rsdp_t *rsdp, unsigned long current,
|
2019-07-30 06:41:41 +02:00
|
|
|
const struct device *dev, uint8_t access_size)
|
2017-11-12 04:33:25 +01:00
|
|
|
{
|
|
|
|
acpi_dbg2_header_t *dbg2 = (acpi_dbg2_header_t *)current;
|
|
|
|
struct resource *res;
|
|
|
|
acpi_addr_t address;
|
|
|
|
|
|
|
|
if (!dev) {
|
2020-02-03 14:41:46 +01:00
|
|
|
printk(BIOS_DEBUG, "%s: Device not found\n", __func__);
|
2017-11-12 04:33:25 +01:00
|
|
|
return current;
|
|
|
|
}
|
2017-11-21 13:52:53 +01:00
|
|
|
if (!dev->enabled) {
|
|
|
|
printk(BIOS_INFO, "%s: Device not enabled\n", __func__);
|
|
|
|
return current;
|
|
|
|
}
|
2017-11-12 04:33:25 +01:00
|
|
|
res = find_resource(dev, PCI_BASE_ADDRESS_0);
|
|
|
|
if (!res) {
|
|
|
|
printk(BIOS_ERR, "%s: Unable to find resource for %s\n",
|
|
|
|
__func__, dev_path(dev));
|
|
|
|
return current;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&address, 0, sizeof(address));
|
|
|
|
if (res->flags & IORESOURCE_IO)
|
|
|
|
address.space_id = ACPI_ADDRESS_SPACE_IO;
|
|
|
|
else if (res->flags & IORESOURCE_MEM)
|
|
|
|
address.space_id = ACPI_ADDRESS_SPACE_MEMORY;
|
|
|
|
else {
|
|
|
|
printk(BIOS_ERR, "%s: Unknown address space type\n", __func__);
|
|
|
|
return current;
|
|
|
|
}
|
|
|
|
|
|
|
|
address.addrl = (uint32_t)res->base;
|
|
|
|
address.addrh = (uint32_t)((res->base >> 32) & 0xffffffff);
|
|
|
|
address.access_size = access_size;
|
|
|
|
|
|
|
|
acpi_create_dbg2(dbg2,
|
|
|
|
ACPI_DBG2_PORT_SERIAL,
|
|
|
|
ACPI_DBG2_PORT_SERIAL_16550,
|
|
|
|
&address, res->size,
|
|
|
|
acpi_device_path(dev));
|
|
|
|
|
|
|
|
if (dbg2->header.length) {
|
|
|
|
current += dbg2->header.length;
|
|
|
|
current = acpi_align_current(current);
|
|
|
|
acpi_add_table(rsdp, dbg2);
|
|
|
|
}
|
|
|
|
|
|
|
|
return current;
|
|
|
|
}
|
|
|
|
|
2005-01-19 15:06:41 +01:00
|
|
|
void acpi_create_facs(acpi_facs_t *facs)
|
2004-10-06 19:33:54 +02:00
|
|
|
{
|
2010-11-19 16:14:42 +01:00
|
|
|
memset((void *)facs, 0, sizeof(acpi_facs_t));
|
2004-10-06 19:33:54 +02:00
|
|
|
|
2009-07-22 00:15:43 +02:00
|
|
|
memcpy(facs->signature, "FACS", 4);
|
2004-10-06 19:33:54 +02:00
|
|
|
facs->length = sizeof(acpi_facs_t);
|
|
|
|
facs->hardware_signature = 0;
|
|
|
|
facs->firmware_waking_vector = 0;
|
|
|
|
facs->global_lock = 0;
|
|
|
|
facs->flags = 0;
|
|
|
|
facs->x_firmware_waking_vector_l = 0;
|
|
|
|
facs->x_firmware_waking_vector_h = 0;
|
2018-08-23 02:57:24 +02:00
|
|
|
facs->version = get_acpi_table_revision(FACS);
|
2004-10-06 19:33:54 +02:00
|
|
|
}
|
2005-01-19 15:06:41 +01:00
|
|
|
|
2014-10-26 20:42:08 +01:00
|
|
|
static void acpi_write_rsdt(acpi_rsdt_t *rsdt, char *oem_id, char *oem_table_id)
|
2010-04-27 08:56:47 +02:00
|
|
|
{
|
2010-11-19 16:14:42 +01:00
|
|
|
acpi_header_t *header = &(rsdt->header);
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2019-05-29 01:48:14 +02:00
|
|
|
if (!header)
|
|
|
|
return;
|
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* Fill out header fields. */
|
2009-07-22 00:15:43 +02:00
|
|
|
memcpy(header->signature, "RSDT", 4);
|
2014-10-26 20:42:08 +01:00
|
|
|
memcpy(header->oem_id, oem_id, 6);
|
|
|
|
memcpy(header->oem_table_id, oem_table_id, 8);
|
2004-01-28 17:56:14 +01:00
|
|
|
memcpy(header->asl_compiler_id, ASLC, 4);
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2019-02-25 15:42:07 +01:00
|
|
|
header->asl_compiler_revision = asl_revision;
|
2004-01-28 17:56:14 +01:00
|
|
|
header->length = sizeof(acpi_rsdt_t);
|
2018-08-23 02:57:24 +02:00
|
|
|
header->revision = get_acpi_table_revision(RSDT);
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* Entries are filled in later, we come with an empty set. */
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* Fix checksum. */
|
2009-07-21 23:38:33 +02:00
|
|
|
header->checksum = acpi_checksum((void *)rsdt, sizeof(acpi_rsdt_t));
|
|
|
|
}
|
|
|
|
|
2014-10-26 20:42:08 +01:00
|
|
|
static void acpi_write_xsdt(acpi_xsdt_t *xsdt, char *oem_id, char *oem_table_id)
|
2010-04-27 08:56:47 +02:00
|
|
|
{
|
2010-11-19 16:14:42 +01:00
|
|
|
acpi_header_t *header = &(xsdt->header);
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2019-05-29 01:48:14 +02:00
|
|
|
if (!header)
|
|
|
|
return;
|
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* Fill out header fields. */
|
2009-07-22 00:15:43 +02:00
|
|
|
memcpy(header->signature, "XSDT", 4);
|
2014-10-26 20:42:08 +01:00
|
|
|
memcpy(header->oem_id, oem_id, 6);
|
|
|
|
memcpy(header->oem_table_id, oem_table_id, 8);
|
2009-07-21 23:38:33 +02:00
|
|
|
memcpy(header->asl_compiler_id, ASLC, 4);
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2019-02-25 15:42:07 +01:00
|
|
|
header->asl_compiler_revision = asl_revision;
|
2009-07-21 23:38:33 +02:00
|
|
|
header->length = sizeof(acpi_xsdt_t);
|
2018-08-23 02:57:24 +02:00
|
|
|
header->revision = get_acpi_table_revision(XSDT);
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* Entries are filled in later, we come with an empty set. */
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* Fix checksum. */
|
2009-07-21 23:38:33 +02:00
|
|
|
header->checksum = acpi_checksum((void *)xsdt, sizeof(acpi_xsdt_t));
|
2004-01-28 17:56:14 +01:00
|
|
|
}
|
|
|
|
|
2014-10-26 20:42:08 +01:00
|
|
|
static void acpi_write_rsdp(acpi_rsdp_t *rsdp, acpi_rsdt_t *rsdt,
|
|
|
|
acpi_xsdt_t *xsdt, char *oem_id)
|
2004-01-28 17:56:14 +01:00
|
|
|
{
|
2009-11-05 19:06:43 +01:00
|
|
|
memset(rsdp, 0, sizeof(acpi_rsdp_t));
|
2010-11-19 16:14:42 +01:00
|
|
|
|
2004-01-28 17:56:14 +01:00
|
|
|
memcpy(rsdp->signature, RSDP_SIG, 8);
|
2014-10-26 20:42:08 +01:00
|
|
|
memcpy(rsdp->oem_id, oem_id, 6);
|
2010-11-19 16:14:42 +01:00
|
|
|
|
|
|
|
rsdp->length = sizeof(acpi_rsdp_t);
|
2015-06-18 10:11:19 +02:00
|
|
|
rsdp->rsdt_address = (uintptr_t)rsdt;
|
2010-11-19 16:14:42 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Revision: ACPI 1.0: 0, ACPI 2.0/3.0/4.0: 2.
|
|
|
|
*
|
|
|
|
* Some OSes expect an XSDT to be present for RSD PTR revisions >= 2.
|
|
|
|
* If we don't have an ACPI XSDT, force ACPI 1.0 (and thus RSD PTR
|
|
|
|
* revision 0).
|
2009-07-21 23:38:33 +02:00
|
|
|
*/
|
|
|
|
if (xsdt == NULL) {
|
2010-11-19 16:14:42 +01:00
|
|
|
rsdp->revision = 0;
|
2009-07-21 23:38:33 +02:00
|
|
|
} else {
|
2015-06-18 10:11:19 +02:00
|
|
|
rsdp->xsdt_address = (u64)(uintptr_t)xsdt;
|
2018-08-23 02:57:24 +02:00
|
|
|
rsdp->revision = get_acpi_table_revision(RSDP);
|
2009-07-21 23:38:33 +02:00
|
|
|
}
|
2010-11-19 16:14:42 +01:00
|
|
|
|
|
|
|
/* Calculate checksums. */
|
|
|
|
rsdp->checksum = acpi_checksum((void *)rsdp, 20);
|
|
|
|
rsdp->ext_checksum = acpi_checksum((void *)rsdp, sizeof(acpi_rsdp_t));
|
2004-01-28 17:56:14 +01:00
|
|
|
}
|
|
|
|
|
2017-03-16 23:18:22 +01:00
|
|
|
unsigned long acpi_create_hest_error_source(acpi_hest_t *hest,
|
|
|
|
acpi_hest_esd_t *esd, u16 type, void *data, u16 data_len)
|
2012-04-13 07:57:14 +02:00
|
|
|
{
|
|
|
|
acpi_header_t *header = &(hest->header);
|
|
|
|
acpi_hest_hen_t *hen;
|
|
|
|
void *pos;
|
|
|
|
u16 len;
|
|
|
|
|
|
|
|
pos = esd;
|
|
|
|
memset(pos, 0, sizeof(acpi_hest_esd_t));
|
|
|
|
len = 0;
|
|
|
|
esd->type = type; /* MCE */
|
|
|
|
esd->source_id = hest->error_source_count;
|
|
|
|
esd->flags = 0; /* FIRMWARE_FIRST */
|
|
|
|
esd->enabled = 1;
|
|
|
|
esd->prealloc_erecords = 1;
|
|
|
|
esd->max_section_per_record = 0x1;
|
|
|
|
|
|
|
|
len += sizeof(acpi_hest_esd_t);
|
|
|
|
pos = esd + 1;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case 0: /* MCE */
|
|
|
|
break;
|
|
|
|
case 1: /* CMC */
|
|
|
|
hen = (acpi_hest_hen_t *) (pos);
|
|
|
|
memset(pos, 0, sizeof(acpi_hest_hen_t));
|
|
|
|
hen->type = 3; /* SCI? */
|
|
|
|
hen->length = sizeof(acpi_hest_hen_t);
|
2017-03-16 23:18:22 +01:00
|
|
|
hen->conf_we = 0; /* Configuration Write Enable. */
|
2012-04-13 07:57:14 +02:00
|
|
|
hen->poll_interval = 0;
|
|
|
|
hen->vector = 0;
|
|
|
|
hen->sw2poll_threshold_val = 0;
|
|
|
|
hen->sw2poll_threshold_win = 0;
|
|
|
|
hen->error_threshold_val = 0;
|
|
|
|
hen->error_threshold_win = 0;
|
|
|
|
len += sizeof(acpi_hest_hen_t);
|
|
|
|
pos = hen + 1;
|
|
|
|
break;
|
|
|
|
case 2: /* NMI */
|
|
|
|
case 6: /* AER Root Port */
|
|
|
|
case 7: /* AER Endpoint */
|
|
|
|
case 8: /* AER Bridge */
|
|
|
|
case 9: /* Generic Hardware Error Source. */
|
|
|
|
/* TODO: */
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
printk(BIOS_DEBUG, "Invalid type of Error Source.");
|
|
|
|
break;
|
|
|
|
}
|
2017-03-16 21:41:11 +01:00
|
|
|
hest->error_source_count++;
|
2012-04-13 07:57:14 +02:00
|
|
|
|
|
|
|
memcpy(pos, data, data_len);
|
|
|
|
len += data_len;
|
2019-05-29 01:48:14 +02:00
|
|
|
if (header)
|
|
|
|
header->length += len;
|
2012-04-13 07:57:14 +02:00
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ACPI 4.0 */
|
2014-11-09 13:36:18 +01:00
|
|
|
void acpi_write_hest(acpi_hest_t *hest,
|
|
|
|
unsigned long (*acpi_fill_hest)(acpi_hest_t *hest))
|
2012-04-13 07:57:14 +02:00
|
|
|
{
|
|
|
|
acpi_header_t *header = &(hest->header);
|
|
|
|
|
|
|
|
memset(hest, 0, sizeof(acpi_hest_t));
|
|
|
|
|
2019-05-29 01:48:14 +02:00
|
|
|
if (!header)
|
|
|
|
return;
|
|
|
|
|
2012-04-13 07:57:14 +02:00
|
|
|
memcpy(header->signature, "HEST", 4);
|
|
|
|
memcpy(header->oem_id, OEM_ID, 6);
|
|
|
|
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
|
|
|
|
memcpy(header->asl_compiler_id, ASLC, 4);
|
2019-02-25 15:42:07 +01:00
|
|
|
header->asl_compiler_revision = asl_revision;
|
2012-04-13 07:57:14 +02:00
|
|
|
header->length += sizeof(acpi_hest_t);
|
2018-08-23 02:57:24 +02:00
|
|
|
header->revision = get_acpi_table_revision(HEST);
|
2012-04-13 07:57:14 +02:00
|
|
|
|
|
|
|
acpi_fill_hest(hest);
|
|
|
|
|
|
|
|
/* Calculate checksums. */
|
|
|
|
header->checksum = acpi_checksum((void *)hest, header->length);
|
|
|
|
}
|
|
|
|
|
2018-09-04 21:45:26 +02:00
|
|
|
/* ACPI 3.0b */
|
|
|
|
void acpi_write_bert(acpi_bert_t *bert, uintptr_t region, size_t length)
|
|
|
|
{
|
|
|
|
acpi_header_t *header = &(bert->header);
|
|
|
|
|
|
|
|
memset(bert, 0, sizeof(acpi_bert_t));
|
|
|
|
|
2019-05-29 01:48:14 +02:00
|
|
|
if (!header)
|
|
|
|
return;
|
|
|
|
|
2018-09-04 21:45:26 +02:00
|
|
|
memcpy(header->signature, "BERT", 4);
|
|
|
|
memcpy(header->oem_id, OEM_ID, 6);
|
|
|
|
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
|
|
|
|
memcpy(header->asl_compiler_id, ASLC, 4);
|
2019-02-25 15:42:07 +01:00
|
|
|
header->asl_compiler_revision = asl_revision;
|
2018-09-04 21:45:26 +02:00
|
|
|
header->length += sizeof(acpi_bert_t);
|
|
|
|
header->revision = get_acpi_table_revision(BERT);
|
|
|
|
|
|
|
|
bert->error_region = region;
|
|
|
|
bert->region_length = length;
|
|
|
|
|
|
|
|
/* Calculate checksums. */
|
|
|
|
header->checksum = acpi_checksum((void *)bert, header->length);
|
|
|
|
}
|
|
|
|
|
2020-07-13 00:17:43 +02:00
|
|
|
__weak void arch_fill_fadt(acpi_fadt_t *fadt) { }
|
2020-05-30 15:16:28 +02:00
|
|
|
__weak void soc_fill_fadt(acpi_fadt_t *fadt) { }
|
2020-06-02 02:34:43 +02:00
|
|
|
__weak void mainboard_fill_fadt(acpi_fadt_t *fadt) { }
|
2020-05-30 15:16:28 +02:00
|
|
|
|
2017-03-16 21:41:11 +01:00
|
|
|
void acpi_create_fadt(acpi_fadt_t *fadt, acpi_facs_t *facs, void *dsdt)
|
2014-10-16 12:48:19 +02:00
|
|
|
{
|
|
|
|
acpi_header_t *header = &(fadt->header);
|
|
|
|
|
|
|
|
memset((void *) fadt, 0, sizeof(acpi_fadt_t));
|
2019-05-29 01:48:14 +02:00
|
|
|
|
|
|
|
if (!header)
|
|
|
|
return;
|
|
|
|
|
2014-10-16 12:48:19 +02:00
|
|
|
memcpy(header->signature, "FACP", 4);
|
|
|
|
header->length = sizeof(acpi_fadt_t);
|
2018-08-23 02:57:24 +02:00
|
|
|
header->revision = get_acpi_table_revision(FADT);
|
2014-10-16 12:48:19 +02:00
|
|
|
memcpy(header->oem_id, OEM_ID, 6);
|
|
|
|
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
|
|
|
|
memcpy(header->asl_compiler_id, ASLC, 4);
|
2019-02-15 08:21:33 +01:00
|
|
|
header->asl_compiler_revision = asl_revision;
|
2014-10-16 12:48:19 +02:00
|
|
|
|
|
|
|
fadt->firmware_ctrl = (unsigned long) facs;
|
|
|
|
fadt->x_firmware_ctl_l = (unsigned long)facs;
|
|
|
|
fadt->x_firmware_ctl_h = 0;
|
2020-06-03 06:20:55 +02:00
|
|
|
|
|
|
|
fadt->dsdt = (unsigned long) dsdt;
|
2014-10-16 12:48:19 +02:00
|
|
|
fadt->x_dsdt_l = (unsigned long)dsdt;
|
|
|
|
fadt->x_dsdt_h = 0;
|
|
|
|
|
2020-06-03 06:20:55 +02:00
|
|
|
/* should be 0 ACPI 3.0 */
|
|
|
|
fadt->reserved = 0;
|
|
|
|
|
2020-06-07 11:01:58 +02:00
|
|
|
fadt->preferred_pm_profile = acpi_get_preferred_pm_profile();
|
2014-10-16 12:48:19 +02:00
|
|
|
|
2020-07-13 00:17:43 +02:00
|
|
|
arch_fill_fadt(fadt);
|
|
|
|
|
2014-10-25 15:18:25 +02:00
|
|
|
acpi_fill_fadt(fadt);
|
2014-10-16 12:48:19 +02:00
|
|
|
|
2020-05-30 15:16:28 +02:00
|
|
|
soc_fill_fadt(fadt);
|
2020-06-02 02:34:43 +02:00
|
|
|
mainboard_fill_fadt(fadt);
|
2020-05-30 15:16:28 +02:00
|
|
|
|
2014-10-16 12:48:19 +02:00
|
|
|
header->checksum =
|
|
|
|
acpi_checksum((void *) fadt, header->length);
|
|
|
|
}
|
|
|
|
|
2021-01-01 21:04:09 +01:00
|
|
|
void acpi_create_lpit(acpi_lpit_t *lpit)
|
|
|
|
{
|
|
|
|
acpi_header_t *header = &(lpit->header);
|
|
|
|
unsigned long current = (unsigned long)lpit + sizeof(acpi_lpit_t);
|
|
|
|
|
|
|
|
memset((void *)lpit, 0, sizeof(acpi_lpit_t));
|
|
|
|
|
|
|
|
if (!header)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Fill out header fields. */
|
|
|
|
memcpy(header->signature, "LPIT", 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->revision = get_acpi_table_revision(LPIT);
|
|
|
|
header->oem_revision = 42;
|
|
|
|
header->length = sizeof(acpi_lpit_t);
|
|
|
|
|
|
|
|
current = acpi_fill_lpit(current);
|
|
|
|
|
|
|
|
/* (Re)calculate length and checksum. */
|
|
|
|
header->length = current - (unsigned long)lpit;
|
|
|
|
header->checksum = acpi_checksum((void *)lpit, header->length);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long acpi_create_lpi_desc_ncst(acpi_lpi_desc_ncst_t *lpi_desc, uint16_t uid)
|
|
|
|
{
|
|
|
|
memset(lpi_desc, 0, sizeof(acpi_lpi_desc_ncst_t));
|
|
|
|
lpi_desc->header.length = sizeof(acpi_lpi_desc_ncst_t);
|
|
|
|
lpi_desc->header.type = ACPI_LPI_DESC_TYPE_NATIVE_CSTATE;
|
|
|
|
lpi_desc->header.uid = uid;
|
|
|
|
|
|
|
|
return lpi_desc->header.length;
|
|
|
|
}
|
|
|
|
|
2021-01-21 18:55:19 +01:00
|
|
|
/* BERT helpers */
|
|
|
|
bool __weak acpi_is_boot_error_src_present(void)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
__weak void acpi_soc_fill_bert(acpi_bert_t *bert, void **region, size_t *length) {}
|
|
|
|
|
2018-04-21 22:45:32 +02:00
|
|
|
unsigned long __weak fw_cfg_acpi_tables(unsigned long start)
|
2014-09-01 22:18:01 +02:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-08-30 19:28:05 +02:00
|
|
|
unsigned long write_acpi_tables(unsigned long start)
|
|
|
|
{
|
|
|
|
unsigned long current;
|
|
|
|
acpi_rsdp_t *rsdp;
|
|
|
|
acpi_rsdt_t *rsdt;
|
|
|
|
acpi_xsdt_t *xsdt;
|
|
|
|
acpi_fadt_t *fadt;
|
|
|
|
acpi_facs_t *facs;
|
2014-10-26 20:42:08 +01:00
|
|
|
acpi_header_t *slic_file, *slic;
|
2014-08-30 19:28:05 +02:00
|
|
|
acpi_header_t *ssdt;
|
2015-05-31 12:31:59 +02:00
|
|
|
acpi_header_t *dsdt_file, *dsdt;
|
2014-08-30 19:28:05 +02:00
|
|
|
acpi_mcfg_t *mcfg;
|
2015-05-20 19:52:01 +02:00
|
|
|
acpi_tcpa_t *tcpa;
|
2018-10-18 15:39:34 +02:00
|
|
|
acpi_tpm2_t *tpm2;
|
2014-08-30 19:28:05 +02:00
|
|
|
acpi_madt_t *madt;
|
2021-01-01 21:04:09 +01:00
|
|
|
acpi_lpit_t *lpit;
|
2021-01-21 18:55:19 +01:00
|
|
|
acpi_bert_t *bert;
|
2014-10-27 13:29:29 +01:00
|
|
|
struct device *dev;
|
2014-09-01 22:18:01 +02:00
|
|
|
unsigned long fw;
|
2015-05-31 12:31:59 +02:00
|
|
|
size_t slic_size, dsdt_size;
|
2014-10-26 20:42:08 +01:00
|
|
|
char oem_id[6], oem_table_id[8];
|
2014-08-30 19:28:05 +02:00
|
|
|
|
|
|
|
current = start;
|
|
|
|
|
|
|
|
/* Align ACPI tables to 16byte */
|
2015-12-11 00:07:38 +01:00
|
|
|
current = acpi_align_current(current);
|
2014-08-30 19:28:05 +02:00
|
|
|
|
2019-09-10 15:40:47 +02:00
|
|
|
/* Special case for qemu */
|
2014-09-01 22:18:01 +02:00
|
|
|
fw = fw_cfg_acpi_tables(current);
|
2019-09-10 15:40:47 +02:00
|
|
|
if (fw) {
|
|
|
|
rsdp = NULL;
|
|
|
|
/* Find RSDP. */
|
|
|
|
for (void *p = (void *)current; p < (void *)fw; p += 16) {
|
|
|
|
if (valid_rsdp((acpi_rsdp_t *)p)) {
|
|
|
|
rsdp = p;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!rsdp)
|
|
|
|
return fw;
|
|
|
|
|
|
|
|
/* Add BOOT0000 for Linux google firmware driver */
|
|
|
|
printk(BIOS_DEBUG, "ACPI: * SSDT\n");
|
|
|
|
ssdt = (acpi_header_t *)fw;
|
|
|
|
current = (unsigned long)ssdt + sizeof(acpi_header_t);
|
|
|
|
|
|
|
|
memset((void *)ssdt, 0, sizeof(acpi_header_t));
|
|
|
|
|
|
|
|
memcpy(&ssdt->signature, "SSDT", 4);
|
|
|
|
ssdt->revision = get_acpi_table_revision(SSDT);
|
|
|
|
memcpy(&ssdt->oem_id, OEM_ID, 6);
|
|
|
|
memcpy(&ssdt->oem_table_id, oem_table_id, 8);
|
|
|
|
ssdt->oem_revision = 42;
|
|
|
|
memcpy(&ssdt->asl_compiler_id, ASLC, 4);
|
|
|
|
ssdt->asl_compiler_revision = asl_revision;
|
|
|
|
ssdt->length = sizeof(acpi_header_t);
|
|
|
|
|
|
|
|
acpigen_set_current((char *) current);
|
|
|
|
|
|
|
|
/* Write object to declare coreboot tables */
|
|
|
|
acpi_ssdt_write_cbtable();
|
|
|
|
|
|
|
|
/* (Re)calculate length and checksum. */
|
|
|
|
ssdt->length = current - (unsigned long)ssdt;
|
|
|
|
ssdt->checksum = acpi_checksum((void *)ssdt, ssdt->length);
|
|
|
|
|
|
|
|
acpi_create_ssdt_generator(ssdt, ACPI_TABLE_CREATOR);
|
|
|
|
|
|
|
|
acpi_add_table(rsdp, ssdt);
|
|
|
|
|
2014-09-01 22:18:01 +02:00
|
|
|
return fw;
|
2019-09-10 15:40:47 +02:00
|
|
|
}
|
2014-09-01 22:18:01 +02:00
|
|
|
|
cbfs: Simplify load/map API names, remove type arguments
This patch renames cbfs_boot_map_with_leak() and cbfs_boot_load_file()
to cbfs_map() and cbfs_load() respectively. This is supposed to be the
start of a new, better organized CBFS API where the most common
operations have the most simple and straight-forward names. Less
commonly used variants of these operations (e.g. cbfs_ro_load() or
cbfs_region_load()) can be introduced later. It seems unnecessary to
keep carrying around "boot" in the names of most CBFS APIs if the vast
majority of accesses go to the boot CBFS (instead, more unusual
operations should have longer names that describe how they diverge from
the common ones).
cbfs_map() is paired with a new cbfs_unmap() to allow callers to cleanly
reap mappings when desired. A few new cbfs_unmap() calls are added to
generic code where it makes sense, but it seems unnecessary to introduce
this everywhere in platform or architecture specific code where the boot
medium is known to be memory-mapped anyway. In fact, even for
non-memory-mapped platforms, sometimes leaking a mapping to the CBFS
cache is a much cleaner solution than jumping through hoops to provide
some other storage for some long-lived file object, and it shouldn't be
outright forbidden when it makes sense.
Additionally, remove the type arguments from these function signatures.
The goal is to eventually remove type arguments for lookup from the
whole CBFS API. Filenames already uniquely identify CBFS files. The type
field is just informational, and there should be APIs to allow callers
to check it when desired, but it's not clear what we gain from forcing
this as a parameter into every single CBFS access when the vast majority
of the time it provides no additional value and is just clutter.
Signed-off-by: Julius Werner <jwerner@chromium.org>
Change-Id: Ib24325400815a9c3d25f66c61829a24a239bb88e
Reviewed-on: https://review.coreboot.org/c/coreboot/+/39304
Reviewed-by: Hung-Te Lin <hungte@chromium.org>
Reviewed-by: Wim Vervoorn <wvervoorn@eltan.com>
Reviewed-by: Mariusz Szafrański <mariuszx.szafranski@intel.com>
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2020-03-05 01:52:08 +01:00
|
|
|
dsdt_file = cbfs_map(CONFIG_CBFS_PREFIX "/dsdt.aml", &dsdt_size);
|
2015-05-31 12:31:59 +02:00
|
|
|
if (!dsdt_file) {
|
|
|
|
printk(BIOS_ERR, "No DSDT file, skipping ACPI tables\n");
|
|
|
|
return current;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dsdt_file->length > dsdt_size
|
2016-10-03 22:11:07 +02:00
|
|
|
|| dsdt_file->length < sizeof(acpi_header_t)
|
2015-05-31 12:31:59 +02:00
|
|
|
|| memcmp(dsdt_file->signature, "DSDT", 4) != 0) {
|
|
|
|
printk(BIOS_ERR, "Invalid DSDT file, skipping ACPI tables\n");
|
|
|
|
return current;
|
|
|
|
}
|
|
|
|
|
cbfs: Simplify load/map API names, remove type arguments
This patch renames cbfs_boot_map_with_leak() and cbfs_boot_load_file()
to cbfs_map() and cbfs_load() respectively. This is supposed to be the
start of a new, better organized CBFS API where the most common
operations have the most simple and straight-forward names. Less
commonly used variants of these operations (e.g. cbfs_ro_load() or
cbfs_region_load()) can be introduced later. It seems unnecessary to
keep carrying around "boot" in the names of most CBFS APIs if the vast
majority of accesses go to the boot CBFS (instead, more unusual
operations should have longer names that describe how they diverge from
the common ones).
cbfs_map() is paired with a new cbfs_unmap() to allow callers to cleanly
reap mappings when desired. A few new cbfs_unmap() calls are added to
generic code where it makes sense, but it seems unnecessary to introduce
this everywhere in platform or architecture specific code where the boot
medium is known to be memory-mapped anyway. In fact, even for
non-memory-mapped platforms, sometimes leaking a mapping to the CBFS
cache is a much cleaner solution than jumping through hoops to provide
some other storage for some long-lived file object, and it shouldn't be
outright forbidden when it makes sense.
Additionally, remove the type arguments from these function signatures.
The goal is to eventually remove type arguments for lookup from the
whole CBFS API. Filenames already uniquely identify CBFS files. The type
field is just informational, and there should be APIs to allow callers
to check it when desired, but it's not clear what we gain from forcing
this as a parameter into every single CBFS access when the vast majority
of the time it provides no additional value and is just clutter.
Signed-off-by: Julius Werner <jwerner@chromium.org>
Change-Id: Ib24325400815a9c3d25f66c61829a24a239bb88e
Reviewed-on: https://review.coreboot.org/c/coreboot/+/39304
Reviewed-by: Hung-Te Lin <hungte@chromium.org>
Reviewed-by: Wim Vervoorn <wvervoorn@eltan.com>
Reviewed-by: Mariusz Szafrański <mariuszx.szafranski@intel.com>
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
2020-03-05 01:52:08 +01:00
|
|
|
slic_file = cbfs_map(CONFIG_CBFS_PREFIX "/slic", &slic_size);
|
2015-05-31 11:32:09 +02:00
|
|
|
if (slic_file
|
|
|
|
&& (slic_file->length > slic_size
|
2016-10-03 22:11:07 +02:00
|
|
|
|| slic_file->length < sizeof(acpi_header_t)
|
2020-09-12 04:55:57 +02:00
|
|
|
|| (memcmp(slic_file->signature, "SLIC", 4) != 0
|
|
|
|
&& memcmp(slic_file->signature, "MSDM", 4) != 0))) {
|
2014-10-26 20:42:08 +01:00
|
|
|
slic_file = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (slic_file) {
|
|
|
|
memcpy(oem_id, slic_file->oem_id, 6);
|
|
|
|
memcpy(oem_table_id, slic_file->oem_table_id, 8);
|
|
|
|
} else {
|
|
|
|
memcpy(oem_id, OEM_ID, 6);
|
|
|
|
memcpy(oem_table_id, ACPI_TABLE_CREATOR, 8);
|
|
|
|
}
|
|
|
|
|
2014-08-30 19:28:05 +02:00
|
|
|
printk(BIOS_INFO, "ACPI: Writing ACPI tables at %lx.\n", start);
|
|
|
|
|
|
|
|
/* We need at least an RSDP and an RSDT Table */
|
|
|
|
rsdp = (acpi_rsdp_t *) current;
|
|
|
|
current += sizeof(acpi_rsdp_t);
|
2015-12-11 00:07:38 +01:00
|
|
|
current = acpi_align_current(current);
|
2014-08-30 19:28:05 +02:00
|
|
|
rsdt = (acpi_rsdt_t *) current;
|
|
|
|
current += sizeof(acpi_rsdt_t);
|
2015-12-11 00:07:38 +01:00
|
|
|
current = acpi_align_current(current);
|
2014-08-30 19:28:05 +02:00
|
|
|
xsdt = (acpi_xsdt_t *) current;
|
|
|
|
current += sizeof(acpi_xsdt_t);
|
2015-12-11 00:07:38 +01:00
|
|
|
current = acpi_align_current(current);
|
2014-08-30 19:28:05 +02:00
|
|
|
|
|
|
|
/* clear all table memory */
|
|
|
|
memset((void *) start, 0, current - start);
|
|
|
|
|
2014-10-26 20:42:08 +01:00
|
|
|
acpi_write_rsdp(rsdp, rsdt, xsdt, oem_id);
|
|
|
|
acpi_write_rsdt(rsdt, oem_id, oem_table_id);
|
|
|
|
acpi_write_xsdt(xsdt, oem_id, oem_table_id);
|
2014-08-30 19:28:05 +02:00
|
|
|
|
|
|
|
printk(BIOS_DEBUG, "ACPI: * FACS\n");
|
2019-06-20 13:50:17 +02:00
|
|
|
current = ALIGN_UP(current, 64);
|
2014-08-30 19:28:05 +02:00
|
|
|
facs = (acpi_facs_t *) current;
|
|
|
|
current += sizeof(acpi_facs_t);
|
2015-12-11 00:07:38 +01:00
|
|
|
current = acpi_align_current(current);
|
2014-08-30 19:28:05 +02:00
|
|
|
acpi_create_facs(facs);
|
|
|
|
|
|
|
|
printk(BIOS_DEBUG, "ACPI: * DSDT\n");
|
|
|
|
dsdt = (acpi_header_t *) current;
|
2015-05-31 12:31:59 +02:00
|
|
|
memcpy(dsdt, dsdt_file, sizeof(acpi_header_t));
|
2014-10-05 11:10:35 +02:00
|
|
|
if (dsdt->length >= sizeof(acpi_header_t)) {
|
|
|
|
current += sizeof(acpi_header_t);
|
|
|
|
|
|
|
|
acpigen_set_current((char *) current);
|
2020-06-30 10:41:47 +02:00
|
|
|
|
2021-01-11 17:40:37 +01:00
|
|
|
if (CONFIG(ACPI_SOC_NVS))
|
|
|
|
acpi_fill_gnvs();
|
2020-06-30 10:41:47 +02:00
|
|
|
|
2014-10-05 11:10:35 +02:00
|
|
|
for (dev = all_devices; dev; dev = dev->next)
|
2020-03-31 17:34:52 +02:00
|
|
|
if (dev->ops && dev->ops->acpi_inject_dsdt)
|
|
|
|
dev->ops->acpi_inject_dsdt(dev);
|
2014-10-05 11:10:35 +02:00
|
|
|
current = (unsigned long) acpigen_get_current();
|
|
|
|
memcpy((char *)current,
|
2015-05-31 12:31:59 +02:00
|
|
|
(char *)dsdt_file + sizeof(acpi_header_t),
|
2014-10-05 11:10:35 +02:00
|
|
|
dsdt->length - sizeof(acpi_header_t));
|
|
|
|
current += dsdt->length - sizeof(acpi_header_t);
|
|
|
|
|
|
|
|
/* (Re)calculate length and checksum. */
|
|
|
|
dsdt->length = current - (unsigned long)dsdt;
|
|
|
|
dsdt->checksum = 0;
|
|
|
|
dsdt->checksum = acpi_checksum((void *)dsdt, dsdt->length);
|
|
|
|
}
|
2014-08-30 19:28:05 +02:00
|
|
|
|
2015-12-11 00:07:38 +01:00
|
|
|
current = acpi_align_current(current);
|
2014-08-30 19:28:05 +02:00
|
|
|
|
|
|
|
printk(BIOS_DEBUG, "ACPI: * FADT\n");
|
|
|
|
fadt = (acpi_fadt_t *) current;
|
|
|
|
current += sizeof(acpi_fadt_t);
|
2015-12-11 00:07:38 +01:00
|
|
|
current = acpi_align_current(current);
|
2014-08-30 19:28:05 +02:00
|
|
|
|
|
|
|
acpi_create_fadt(fadt, facs, dsdt);
|
|
|
|
acpi_add_table(rsdp, fadt);
|
|
|
|
|
2014-10-26 20:42:08 +01:00
|
|
|
if (slic_file) {
|
|
|
|
printk(BIOS_DEBUG, "ACPI: * SLIC\n");
|
|
|
|
slic = (acpi_header_t *)current;
|
|
|
|
memcpy(slic, slic_file, slic_file->length);
|
|
|
|
current += slic_file->length;
|
2015-12-11 00:07:38 +01:00
|
|
|
current = acpi_align_current(current);
|
2014-10-26 20:42:08 +01:00
|
|
|
acpi_add_table(rsdp, slic);
|
|
|
|
}
|
2014-08-30 19:28:05 +02:00
|
|
|
|
|
|
|
printk(BIOS_DEBUG, "ACPI: * SSDT\n");
|
|
|
|
ssdt = (acpi_header_t *)current;
|
|
|
|
acpi_create_ssdt_generator(ssdt, ACPI_TABLE_CREATOR);
|
2014-10-10 20:40:41 +02:00
|
|
|
if (ssdt->length > sizeof(acpi_header_t)) {
|
|
|
|
current += ssdt->length;
|
|
|
|
acpi_add_table(rsdp, ssdt);
|
2015-12-11 00:07:38 +01:00
|
|
|
current = acpi_align_current(current);
|
2014-10-10 20:40:41 +02:00
|
|
|
}
|
2014-08-30 19:28:05 +02:00
|
|
|
|
|
|
|
printk(BIOS_DEBUG, "ACPI: * MCFG\n");
|
|
|
|
mcfg = (acpi_mcfg_t *) current;
|
|
|
|
acpi_create_mcfg(mcfg);
|
|
|
|
if (mcfg->header.length > sizeof(acpi_mcfg_t)) {
|
|
|
|
current += mcfg->header.length;
|
2015-12-11 00:07:38 +01:00
|
|
|
current = acpi_align_current(current);
|
2014-08-30 19:28:05 +02:00
|
|
|
acpi_add_table(rsdp, mcfg);
|
|
|
|
}
|
|
|
|
|
2019-03-06 01:53:33 +01:00
|
|
|
if (CONFIG(TPM1)) {
|
2018-10-18 15:39:34 +02:00
|
|
|
printk(BIOS_DEBUG, "ACPI: * TCPA\n");
|
|
|
|
tcpa = (acpi_tcpa_t *) current;
|
|
|
|
acpi_create_tcpa(tcpa);
|
|
|
|
if (tcpa->header.length >= sizeof(acpi_tcpa_t)) {
|
|
|
|
current += tcpa->header.length;
|
|
|
|
current = acpi_align_current(current);
|
|
|
|
acpi_add_table(rsdp, tcpa);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-06 01:53:33 +01:00
|
|
|
if (CONFIG(TPM2)) {
|
2018-10-18 15:39:34 +02:00
|
|
|
printk(BIOS_DEBUG, "ACPI: * TPM2\n");
|
|
|
|
tpm2 = (acpi_tpm2_t *) current;
|
|
|
|
acpi_create_tpm2(tpm2);
|
|
|
|
if (tpm2->header.length >= sizeof(acpi_tpm2_t)) {
|
|
|
|
current += tpm2->header.length;
|
|
|
|
current = acpi_align_current(current);
|
|
|
|
acpi_add_table(rsdp, tpm2);
|
|
|
|
}
|
2015-05-20 19:52:01 +02:00
|
|
|
}
|
|
|
|
|
2021-01-01 21:04:09 +01:00
|
|
|
if (CONFIG(ACPI_LPIT)) {
|
|
|
|
printk(BIOS_DEBUG, "ACPI: * LPIT\n");
|
|
|
|
|
|
|
|
lpit = (acpi_lpit_t *)current;
|
|
|
|
acpi_create_lpit(lpit);
|
|
|
|
if (lpit->header.length >= sizeof(acpi_lpit_t)) {
|
|
|
|
current += lpit->header.length;
|
|
|
|
current = acpi_align_current(current);
|
|
|
|
acpi_add_table(rsdp, lpit);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-30 19:28:05 +02:00
|
|
|
printk(BIOS_DEBUG, "ACPI: * MADT\n");
|
|
|
|
|
|
|
|
madt = (acpi_madt_t *) current;
|
|
|
|
acpi_create_madt(madt);
|
|
|
|
if (madt->header.length > sizeof(acpi_madt_t)) {
|
2017-03-16 21:41:11 +01:00
|
|
|
current += madt->header.length;
|
|
|
|
acpi_add_table(rsdp, madt);
|
2014-08-30 19:28:05 +02:00
|
|
|
}
|
2021-01-01 21:04:09 +01:00
|
|
|
|
2015-12-11 00:07:38 +01:00
|
|
|
current = acpi_align_current(current);
|
2014-08-30 19:28:05 +02:00
|
|
|
|
2021-01-21 18:55:19 +01:00
|
|
|
if (acpi_is_boot_error_src_present()) {
|
|
|
|
void *region;
|
|
|
|
size_t size;
|
|
|
|
printk(BIOS_DEBUG, "ACPI: * BERT\n");
|
|
|
|
bert = (acpi_bert_t *) current;
|
|
|
|
acpi_soc_fill_bert(bert, ®ion, &size);
|
|
|
|
acpi_write_bert(bert, (uintptr_t)region, size);
|
|
|
|
if (bert->header.length >= sizeof(acpi_bert_t)) {
|
|
|
|
current += bert->header.length;
|
|
|
|
acpi_add_table(rsdp, bert);
|
|
|
|
}
|
|
|
|
current = acpi_align_current(current);
|
|
|
|
}
|
|
|
|
|
2014-08-30 19:28:05 +02:00
|
|
|
printk(BIOS_DEBUG, "current = %lx\n", current);
|
|
|
|
|
|
|
|
for (dev = all_devices; dev; dev = dev->next) {
|
|
|
|
if (dev->ops && dev->ops->write_acpi_tables) {
|
2017-03-16 23:18:22 +01:00
|
|
|
current = dev->ops->write_acpi_tables(dev, current,
|
|
|
|
rsdp);
|
2015-12-11 00:07:38 +01:00
|
|
|
current = acpi_align_current(current);
|
2014-08-30 19:28:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
printk(BIOS_INFO, "ACPI: done.\n");
|
|
|
|
return current;
|
|
|
|
}
|
|
|
|
|
2009-04-13 20:07:02 +02:00
|
|
|
static acpi_rsdp_t *valid_rsdp(acpi_rsdp_t *rsdp)
|
|
|
|
{
|
|
|
|
if (strncmp((char *)rsdp, RSDP_SIG, sizeof(RSDP_SIG) - 1) != 0)
|
|
|
|
return NULL;
|
|
|
|
|
2010-03-22 12:42:32 +01:00
|
|
|
printk(BIOS_DEBUG, "Looking on %p for valid checksum\n", rsdp);
|
2009-04-13 20:07:02 +02:00
|
|
|
|
|
|
|
if (acpi_checksum((void *)rsdp, 20) != 0)
|
|
|
|
return NULL;
|
2010-03-22 12:42:32 +01:00
|
|
|
printk(BIOS_DEBUG, "Checksum 1 passed\n");
|
2009-04-13 20:07:02 +02:00
|
|
|
|
|
|
|
if ((rsdp->revision > 1) && (acpi_checksum((void *)rsdp,
|
|
|
|
rsdp->length) != 0))
|
|
|
|
return NULL;
|
2010-03-22 12:42:32 +01:00
|
|
|
printk(BIOS_DEBUG, "Checksum 2 passed all OK\n");
|
2009-04-13 20:07:02 +02:00
|
|
|
|
|
|
|
return rsdp;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *acpi_find_wakeup_vector(void)
|
|
|
|
{
|
|
|
|
char *p, *end;
|
|
|
|
acpi_rsdt_t *rsdt;
|
|
|
|
acpi_facs_t *facs;
|
2012-12-15 03:17:55 +01:00
|
|
|
acpi_fadt_t *fadt = NULL;
|
2016-06-17 07:44:40 +02:00
|
|
|
acpi_rsdp_t *rsdp = NULL;
|
2010-11-19 16:14:42 +01:00
|
|
|
void *wake_vec;
|
2009-04-13 20:07:02 +02:00
|
|
|
int i;
|
|
|
|
|
2020-11-17 15:41:38 +01:00
|
|
|
if (!acpi_is_wakeup_s3())
|
2009-04-13 20:07:02 +02:00
|
|
|
return NULL;
|
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
printk(BIOS_DEBUG, "Trying to find the wakeup vector...\n");
|
2009-04-13 20:07:02 +02:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* Find RSDP. */
|
|
|
|
for (p = (char *)0xe0000; p < (char *)0xfffff; p += 16) {
|
2017-03-17 00:01:40 +01:00
|
|
|
rsdp = valid_rsdp((acpi_rsdp_t *)p);
|
|
|
|
if (rsdp)
|
2009-04-13 20:07:02 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-11-04 12:25:25 +01:00
|
|
|
if (rsdp == NULL) {
|
|
|
|
printk(BIOS_ALERT,
|
|
|
|
"No RSDP found, wake up from S3 not possible.\n");
|
2009-04-13 20:07:02 +02:00
|
|
|
return NULL;
|
2018-11-04 12:25:25 +01:00
|
|
|
}
|
2009-04-13 20:07:02 +02:00
|
|
|
|
2010-03-22 12:42:32 +01:00
|
|
|
printk(BIOS_DEBUG, "RSDP found at %p\n", rsdp);
|
2015-07-31 01:28:13 +02:00
|
|
|
rsdt = (acpi_rsdt_t *)(uintptr_t)rsdp->rsdt_address;
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
end = (char *)rsdt + rsdt->header.length;
|
2010-03-22 12:42:32 +01:00
|
|
|
printk(BIOS_DEBUG, "RSDT found at %p ends at %p\n", rsdt, end);
|
2009-04-13 20:07:02 +02:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
for (i = 0; ((char *)&rsdt->entry[i]) < end; i++) {
|
2015-07-31 01:28:13 +02:00
|
|
|
fadt = (acpi_fadt_t *)(uintptr_t)rsdt->entry[i];
|
2009-07-22 00:15:43 +02:00
|
|
|
if (strncmp((char *)fadt, "FACP", 4) == 0)
|
2009-04-13 20:07:02 +02:00
|
|
|
break;
|
|
|
|
fadt = NULL;
|
|
|
|
}
|
|
|
|
|
2018-11-04 12:25:25 +01:00
|
|
|
if (fadt == NULL) {
|
|
|
|
printk(BIOS_ALERT,
|
|
|
|
"No FADT found, wake up from S3 not possible.\n");
|
2009-04-13 20:07:02 +02:00
|
|
|
return NULL;
|
2018-11-04 12:25:25 +01:00
|
|
|
}
|
2009-04-13 20:07:02 +02:00
|
|
|
|
2010-03-22 12:42:32 +01:00
|
|
|
printk(BIOS_DEBUG, "FADT found at %p\n", fadt);
|
2015-07-31 01:28:13 +02:00
|
|
|
facs = (acpi_facs_t *)(uintptr_t)fadt->firmware_ctrl;
|
2009-04-13 20:07:02 +02:00
|
|
|
|
2009-04-22 10:17:38 +02:00
|
|
|
if (facs == NULL) {
|
2018-11-04 12:25:25 +01:00
|
|
|
printk(BIOS_ALERT,
|
|
|
|
"No FACS found, wake up from S3 not possible.\n");
|
2009-04-13 20:07:02 +02:00
|
|
|
return NULL;
|
2009-04-22 10:17:38 +02:00
|
|
|
}
|
2009-04-13 20:07:02 +02:00
|
|
|
|
2010-03-22 12:42:32 +01:00
|
|
|
printk(BIOS_DEBUG, "FACS found at %p\n", facs);
|
2015-07-31 01:28:13 +02:00
|
|
|
wake_vec = (void *)(uintptr_t)facs->firmware_waking_vector;
|
2010-03-22 12:42:32 +01:00
|
|
|
printk(BIOS_DEBUG, "OS waking vector is %p\n", wake_vec);
|
2010-11-19 16:14:42 +01:00
|
|
|
|
2009-04-13 20:07:02 +02:00
|
|
|
return wake_vec;
|
|
|
|
}
|
|
|
|
|
2018-04-21 22:45:32 +02:00
|
|
|
__weak int acpi_get_gpe(int gpe)
|
2016-09-19 21:04:19 +02:00
|
|
|
{
|
|
|
|
return -1; /* implemented by SOC */
|
|
|
|
}
|
2018-08-23 02:57:24 +02:00
|
|
|
|
|
|
|
int get_acpi_table_revision(enum acpi_tables table)
|
|
|
|
{
|
|
|
|
switch (table) {
|
|
|
|
case FADT:
|
2020-02-28 10:19:41 +01:00
|
|
|
return ACPI_FADT_REV_ACPI_6_0;
|
2018-11-11 15:22:30 +01:00
|
|
|
case MADT: /* ACPI 3.0: 2, ACPI 4.0/5.0: 3, ACPI 6.2b/6.3: 5 */
|
2020-03-24 17:29:49 +01:00
|
|
|
return 3;
|
2018-08-23 02:57:24 +02:00
|
|
|
case MCFG:
|
|
|
|
return 1;
|
|
|
|
case TCPA:
|
|
|
|
return 2;
|
2018-10-18 15:39:34 +02:00
|
|
|
case TPM2:
|
|
|
|
return 4;
|
2018-11-11 15:22:30 +01:00
|
|
|
case SSDT: /* ACPI 3.0 upto 6.3: 2 */
|
2018-08-23 02:57:24 +02:00
|
|
|
return 2;
|
2018-11-11 15:22:30 +01:00
|
|
|
case SRAT: /* ACPI 2.0: 1, ACPI 3.0: 2, ACPI 4.0 upto 6.3: 3 */
|
2018-08-23 02:57:24 +02:00
|
|
|
return 1; /* TODO Should probably be upgraded to 2 */
|
2021-04-01 20:43:37 +02:00
|
|
|
case HMAT: /* ACPI 6.4: 2 */
|
|
|
|
return 2;
|
2018-08-23 02:57:24 +02:00
|
|
|
case DMAR:
|
|
|
|
return 1;
|
2018-11-11 15:22:30 +01:00
|
|
|
case SLIT: /* ACPI 2.0 upto 6.3: 1 */
|
2018-08-23 02:57:24 +02:00
|
|
|
return 1;
|
2019-06-14 19:00:04 +02:00
|
|
|
case SPMI: /* IMPI 2.0 */
|
|
|
|
return 5;
|
2018-08-23 02:57:24 +02:00
|
|
|
case HPET: /* Currently 1. Table added in ACPI 2.0. */
|
|
|
|
return 1;
|
2018-11-11 15:22:30 +01:00
|
|
|
case VFCT: /* ACPI 2.0/3.0/4.0: 1 */
|
2018-08-23 02:57:24 +02:00
|
|
|
return 1;
|
|
|
|
case IVRS:
|
2020-07-24 11:51:30 +02:00
|
|
|
return IVRS_FORMAT_MIXED;
|
2018-08-23 02:57:24 +02:00
|
|
|
case DBG2:
|
|
|
|
return 0;
|
2018-11-11 15:22:30 +01:00
|
|
|
case FACS: /* ACPI 2.0/3.0: 1, ACPI 4.0 upto 6.3: 2 */
|
2018-08-23 02:57:24 +02:00
|
|
|
return 1;
|
2018-11-11 15:22:30 +01:00
|
|
|
case RSDT: /* ACPI 1.0 upto 6.3: 1 */
|
2018-08-23 02:57:24 +02:00
|
|
|
return 1;
|
2018-11-11 15:22:30 +01:00
|
|
|
case XSDT: /* ACPI 2.0 upto 6.3: 1 */
|
2018-08-23 02:57:24 +02:00
|
|
|
return 1;
|
2018-11-11 15:22:30 +01:00
|
|
|
case RSDP: /* ACPI 2.0 upto 6.3: 2 */
|
2018-08-23 02:57:24 +02:00
|
|
|
return 2;
|
2021-01-11 00:42:50 +01:00
|
|
|
case EINJ:
|
|
|
|
return 1;
|
2018-08-23 02:57:24 +02:00
|
|
|
case HEST:
|
|
|
|
return 1;
|
|
|
|
case NHLT:
|
|
|
|
return 5;
|
2018-09-04 21:47:15 +02:00
|
|
|
case BERT:
|
|
|
|
return 1;
|
2020-11-03 05:06:23 +01:00
|
|
|
case CRAT:
|
|
|
|
return 1;
|
2021-01-01 21:04:09 +01:00
|
|
|
case LPIT: /* ACPI 5.1 up to 6.3: 0 */
|
|
|
|
return 0;
|
2018-08-23 02:57:24 +02:00
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|