2004-01-28 17:56:14 +01:00
|
|
|
/*
|
2010-02-16 00:10:19 +01:00
|
|
|
* This file is part of the coreboot project.
|
|
|
|
*
|
2008-01-18 16:08:58 +01:00
|
|
|
* coreboot ACPI Table support
|
2004-01-28 17:56:14 +01:00
|
|
|
* written by Stefan Reinauer <stepan@openbios.org>
|
2010-02-16 00:10:19 +01:00
|
|
|
*
|
|
|
|
* Copyright (C) 2004 SUSE LINUX AG
|
|
|
|
* Copyright (C) 2005-2009 coresystems GmbH
|
2005-01-19 15:06:41 +01:00
|
|
|
*
|
2010-04-27 08:56:47 +02:00
|
|
|
* ACPI FADT, FACS, and DSDT table support added by
|
2004-10-06 19:33:54 +02:00
|
|
|
* Nick Barker <nick.barker9@btinternet.com>, and those portions
|
2010-02-16 00:10:19 +01:00
|
|
|
* Copyright (C) 2004 Nick Barker
|
2005-11-26 17:56:05 +01:00
|
|
|
*
|
2010-02-16 00:10:19 +01:00
|
|
|
* Copyright (C) 2005 ADVANCED MICRO DEVICES, INC. All Rights Reserved.
|
2006-01-05 01:19:52 +01:00
|
|
|
* 2005.9 yhlu add SRAT table generation
|
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>
|
|
|
|
#include <arch/acpi.h>
|
2009-02-01 19:35:15 +01:00
|
|
|
#include <arch/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>
|
2012-02-16 18:43:25 +01:00
|
|
|
#include <cpu/x86/lapic_def.h>
|
2012-10-04 04:07:05 +02:00
|
|
|
#include <cpu/cpu.h>
|
2011-10-20 00:32:39 +02:00
|
|
|
#if CONFIG_COLLECT_TIMESTAMPS
|
|
|
|
#include <timestamp.h>
|
|
|
|
#endif
|
Implement GCC code coverage analysis
In order to provide some insight on what code is executed during
coreboot's run time and how well our test scenarios work, this
adds code coverage support to coreboot's ram stage. This should
be easily adaptable for payloads, and maybe even romstage.
See http://gcc.gnu.org/onlinedocs/gcc/Gcov.html for
more information.
To instrument coreboot, select CONFIG_COVERAGE ("Code coverage
support") in Kconfig, and recompile coreboot. coreboot will then
store its code coverage information into CBMEM, if possible.
Then, run "cbmem -CV" as root on the target system running the
instrumented coreboot binary. This will create a whole bunch of
.gcda files that contain coverage information. Tar them up, copy
them to your build system machine, and untar them. Then you can
use your favorite coverage utility (gcov, lcov, ...) to visualize
code coverage.
For a sneak peak of what will expect you, please take a look
at http://www.coreboot.org/~stepan/coreboot-coverage/
Change-Id: Ib287d8309878a1f5c4be770c38b1bc0bb3aa6ec7
Signed-off-by: Stefan Reinauer <reinauer@google.com>
Reviewed-on: http://review.coreboot.org/2052
Tested-by: build bot (Jenkins)
Reviewed-by: David Hendricks <dhendrix@chromium.org>
Reviewed-by: Martin Roth <martin@se-eng.com>
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
2012-12-19 01:23:28 +01:00
|
|
|
#include <coverage.h>
|
2004-10-06 19:33:54 +02:00
|
|
|
|
2012-10-05 21:54:38 +02:00
|
|
|
/* FIXME: Kconfig doesn't support overridable defaults :-( */
|
|
|
|
#ifndef CONFIG_HPET_MIN_TICKS
|
|
|
|
#define CONFIG_HPET_MIN_TICKS 0x1000
|
|
|
|
#endif
|
|
|
|
|
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... */
|
2009-07-21 23:38:33 +02:00
|
|
|
rsdt = (acpi_rsdt_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)
|
2009-07-21 23:38:33 +02:00
|
|
|
xsdt = (acpi_xsdt_t *)((u32)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. */
|
2009-11-10 23:17:15 +01:00
|
|
|
rsdt->entry[i] = (u32)table;
|
|
|
|
|
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. */
|
|
|
|
xsdt->entry[i] = (u64)(u32)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
|
|
|
{
|
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
|
|
|
{
|
2010-11-19 16:14:42 +01:00
|
|
|
lapic->type = 0; /* Local APIC structure */
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2009-04-22 10:18:37 +02:00
|
|
|
unsigned long acpi_create_madt_lapics(unsigned long current)
|
|
|
|
{
|
|
|
|
device_t cpu;
|
2012-10-04 04:07:05 +02:00
|
|
|
int index = 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;
|
2010-11-19 16:14:42 +01:00
|
|
|
current += acpi_create_madt_lapic((acpi_madt_lapic_t *)current,
|
2012-10-04 04:07:05 +02:00
|
|
|
index, cpu->path.apic.apic_id);
|
|
|
|
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
|
|
|
{
|
2010-11-19 16:14:42 +01:00
|
|
|
ioapic->type = 1; /* I/O APIC structure */
|
|
|
|
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)
|
|
|
|
{
|
2010-11-19 16:14:42 +01:00
|
|
|
irqoverride->type = 2; /* Interrupt source override */
|
|
|
|
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
|
|
|
{
|
2010-11-19 16:14:42 +01:00
|
|
|
lapic_nmi->type = 4; /* Local APIC NMI structure */
|
|
|
|
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
|
|
|
}
|
|
|
|
|
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
|
|
|
|
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
|
|
|
|
2004-02-03 17:11:35 +01:00
|
|
|
header->length = sizeof(acpi_madt_t);
|
2010-11-19 16:14:42 +01:00
|
|
|
header->revision = 1; /* ACPI 1.0/2.0: 1, ACPI 3.0: 2, ACPI 4.0: 3 */
|
2004-02-03 17:11:35 +01:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
madt->lapic_addr = LOCAL_APIC_ADDR;
|
|
|
|
madt->flags = 0x1; /* PCAT_COMPAT */
|
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
|
|
|
|
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
|
|
|
|
2007-11-03 13:50:26 +01:00
|
|
|
header->length = sizeof(acpi_mcfg_t);
|
|
|
|
header->revision = 1;
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/*
|
|
|
|
* This can be overriden by platform ACPI setup code, if it calls
|
|
|
|
* acpi_create_ssdt_generator().
|
2009-11-10 23:17:15 +01:00
|
|
|
*/
|
2010-11-19 16:14:42 +01:00
|
|
|
unsigned long __attribute__((weak)) acpi_fill_ssdt_generator(
|
|
|
|
unsigned long current, const char *oem_table_id)
|
|
|
|
{
|
2009-02-01 19:35:15 +01:00
|
|
|
return current;
|
|
|
|
}
|
|
|
|
|
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);
|
2010-11-19 16:14:42 +01:00
|
|
|
ssdt->revision = 2; /* ACPI 1.0/2.0: ?, ACPI 3.0/4.0: 2 */
|
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);
|
2009-02-01 19:35:15 +01:00
|
|
|
ssdt->asl_compiler_revision = 42;
|
|
|
|
ssdt->length = sizeof(acpi_header_t);
|
|
|
|
|
2009-03-06 18:24:29 +01:00
|
|
|
acpigen_set_current((char *) current);
|
2009-02-01 19:35:15 +01:00
|
|
|
current = acpi_fill_ssdt_generator(current, oem_table_id);
|
|
|
|
|
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 */
|
2005-11-26 17:56:05 +01:00
|
|
|
void acpi_create_srat(acpi_srat_t *srat)
|
|
|
|
{
|
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
|
|
|
|
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
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
header->length = sizeof(acpi_srat_t);
|
|
|
|
header->revision = 1; /* ACPI 1.0: N/A, 2.0: 1, 3.0: 2, 4.0: 3 */
|
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
|
|
|
}
|
|
|
|
|
2012-09-11 15:21:01 +02:00
|
|
|
unsigned long __attribute__((weak)) acpi_fill_dmar(unsigned long current)
|
|
|
|
{
|
|
|
|
return current;
|
|
|
|
}
|
|
|
|
|
|
|
|
void acpi_create_dmar(acpi_dmar_t *dmar)
|
|
|
|
{
|
|
|
|
acpi_header_t *header = &(dmar->header);
|
|
|
|
unsigned long current = (unsigned long)dmar + sizeof(acpi_dmar_t);
|
|
|
|
|
|
|
|
memset((void *)dmar, 0, sizeof(acpi_dmar_t));
|
|
|
|
|
|
|
|
/* Fill out header fields. */
|
|
|
|
memcpy(header->signature, "DMAR", 4);
|
|
|
|
memcpy(header->oem_id, OEM_ID, 6);
|
|
|
|
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
|
|
|
|
memcpy(header->asl_compiler_id, ASLC, 4);
|
|
|
|
|
|
|
|
header->length = sizeof(acpi_dmar_t);
|
|
|
|
header->revision = 1;
|
|
|
|
|
|
|
|
dmar->host_address_width = 40 - 1; /* FIXME: == MTRR size? */
|
|
|
|
dmar->flags = 0;
|
|
|
|
|
|
|
|
current = acpi_fill_dmar(current);
|
|
|
|
|
|
|
|
/* (Re)calculate length and checksum. */
|
|
|
|
header->length = current - (unsigned long)dmar;
|
|
|
|
header->checksum = acpi_checksum((void *)dmar, header->length);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long acpi_create_dmar_drhd(unsigned long current, u8 flags,
|
|
|
|
u16 segment, u32 bar)
|
|
|
|
{
|
|
|
|
dmar_entry_t *drhd = (dmar_entry_t *)current;
|
|
|
|
memset(drhd, 0, sizeof(*drhd));
|
|
|
|
drhd->type = DMAR_DRHD;
|
|
|
|
drhd->length = sizeof(*drhd); /* will be fixed up later */
|
|
|
|
drhd->flags = flags;
|
|
|
|
drhd->segment = segment;
|
|
|
|
drhd->bar = bar;
|
|
|
|
|
|
|
|
return drhd->length;
|
|
|
|
}
|
|
|
|
|
|
|
|
void acpi_dmar_drhd_fixup(unsigned long base, unsigned long current)
|
|
|
|
{
|
|
|
|
dmar_entry_t *drhd = (dmar_entry_t *)base;
|
|
|
|
drhd->length = current - base;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long acpi_create_dmar_drhd_ds_pci(unsigned long current, u8 segment,
|
|
|
|
u8 dev, u8 fn)
|
|
|
|
{
|
|
|
|
dev_scope_t *ds = (dev_scope_t *)current;
|
|
|
|
memset(ds, 0, sizeof(*ds));
|
|
|
|
ds->type = SCOPE_PCI_ENDPOINT;
|
|
|
|
ds->length = sizeof(*ds) + 2; /* we don't support longer paths yet */
|
|
|
|
ds->start_bus = segment;
|
|
|
|
ds->path[0].dev = dev;
|
|
|
|
ds->path[0].fn = fn;
|
|
|
|
|
|
|
|
return ds->length;
|
|
|
|
}
|
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* http://h21007.www2.hp.com/portal/download/files/unprot/Itanium/slit.pdf */
|
2006-10-04 22:46:15 +02:00
|
|
|
void acpi_create_slit(acpi_slit_t *slit)
|
|
|
|
{
|
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
|
|
|
|
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
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
header->length = sizeof(acpi_slit_t);
|
|
|
|
header->revision = 1; /* ACPI 1.0: N/A, ACPI 2.0/3.0/4.0: 1 */
|
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
|
|
|
|
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
|
|
|
|
2004-01-28 17:56:14 +01:00
|
|
|
header->length = sizeof(acpi_hpet_t);
|
2010-11-19 16:14:42 +01:00
|
|
|
header->revision = 1; /* Currently 1. Table added in ACPI 2.0. */
|
2004-01-28 17:56:14 +01:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* Fill out HPET address. */
|
|
|
|
addr->space_id = 0; /* Memory */
|
|
|
|
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
|
|
|
|
2012-10-05 21:54:38 +02: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
|
|
|
|
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;
|
2010-11-19 16:14:42 +01:00
|
|
|
facs->version = 1; /* ACPI 1.0: 0, ACPI 2.0/3.0: 1, ACPI 4.0: 2 */
|
2004-10-06 19:33:54 +02:00
|
|
|
}
|
2005-01-19 15:06:41 +01:00
|
|
|
|
|
|
|
void acpi_write_rsdt(acpi_rsdt_t *rsdt)
|
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
|
|
|
|
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);
|
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
|
|
|
|
2004-01-28 17:56:14 +01:00
|
|
|
header->length = sizeof(acpi_rsdt_t);
|
2010-11-19 16:14:42 +01:00
|
|
|
header->revision = 1; /* ACPI 1.0/2.0/3.0/4.0: 1 */
|
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));
|
|
|
|
}
|
|
|
|
|
|
|
|
void acpi_write_xsdt(acpi_xsdt_t *xsdt)
|
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
|
|
|
|
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);
|
2009-07-21 23:38:33 +02: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);
|
2009-07-21 23:38:33 +02:00
|
|
|
memcpy(header->asl_compiler_id, ASLC, 4);
|
2010-04-27 08:56:47 +02:00
|
|
|
|
2009-07-21 23:38:33 +02:00
|
|
|
header->length = sizeof(acpi_xsdt_t);
|
2010-11-19 16:14:42 +01:00
|
|
|
header->revision = 1; /* ACPI 1.0: N/A, 2.0/3.0/4.0: 1 */
|
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
|
|
|
}
|
|
|
|
|
2009-07-21 23:38:33 +02:00
|
|
|
void acpi_write_rsdp(acpi_rsdp_t *rsdp, acpi_rsdt_t *rsdt, acpi_xsdt_t *xsdt)
|
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);
|
|
|
|
memcpy(rsdp->oem_id, OEM_ID, 6);
|
2010-11-19 16:14:42 +01:00
|
|
|
|
|
|
|
rsdp->length = sizeof(acpi_rsdp_t);
|
|
|
|
rsdp->rsdt_address = (u32)rsdt;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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 {
|
2010-11-19 16:14:42 +01:00
|
|
|
rsdp->xsdt_address = (u64)(u32)xsdt;
|
|
|
|
rsdp->revision = 2;
|
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
|
|
|
}
|
|
|
|
|
2012-04-13 07:57:14 +02:00
|
|
|
unsigned long __attribute__((weak)) acpi_fill_hest(acpi_hest_t *hest)
|
|
|
|
{
|
|
|
|
return (unsigned long)hest;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long acpi_create_hest_error_source(acpi_hest_t *hest, acpi_hest_esd_t *esd, u16 type, void *data, u16 data_len)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
hen->conf_we = 0; /* Configuration Write Enable. */
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
hest->error_source_count ++;
|
|
|
|
|
|
|
|
memcpy(pos, data, data_len);
|
|
|
|
len += data_len;
|
|
|
|
header->length += len;
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ACPI 4.0 */
|
|
|
|
void acpi_write_hest(acpi_hest_t *hest)
|
|
|
|
{
|
|
|
|
acpi_header_t *header = &(hest->header);
|
|
|
|
|
|
|
|
memset(hest, 0, sizeof(acpi_hest_t));
|
|
|
|
|
|
|
|
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);
|
|
|
|
header->length += sizeof(acpi_hest_t);
|
|
|
|
header->revision = 1;
|
|
|
|
|
|
|
|
acpi_fill_hest(hest);
|
|
|
|
|
|
|
|
/* Calculate checksums. */
|
|
|
|
header->checksum = acpi_checksum((void *)hest, header->length);
|
|
|
|
}
|
|
|
|
|
Clean up #ifs
Replace #if CONFIG_FOO==1 with #if CONFIG_FOO:
find src -name \*.[ch] -exec sed -i "s,#if[[:space:]]*\(CONFIG_[A-Z0-9_]*\)[[:space:]]*==[[:space:]]*1[[:space:]]*\$,#if \1," {} +
Replace #if (CONFIG_FOO==1) with #if CONFIG_FOO:
find src -name \*.[ch] -exec sed -i "s,#if[[:space:]]*(\(CONFIG_[A-Z0-9_]*\)[[:space:]]*==[[:space:]]*1)[[:space:]]*\$,#if \1," {} +
Replace #if CONFIG_FOO==0 with #if !CONFIG_FOO:
find src -name \*.[ch] -exec sed -i "s,#if[[:space:]]*\(CONFIG_[A-Z0-9_]*\)[[:space:]]*==[[:space:]]*0[[:space:]]*\$,#if \!\1," {} +
Replace #if (CONFIG_FOO==0) with #if !CONFIG_FOO:
find src -name \*.[ch] -exec sed -i "s,#if[[:space:]]*(\(CONFIG_[A-Z0-9_]*\)[[:space:]]*==[[:space:]]*0)[[:space:]]*\$,#if \!\1," {} +
(and some manual changes to fix false positives)
Change-Id: Iac6ca7605a5f99885258cf1a9a2473a92de27c42
Signed-off-by: Patrick Georgi <patrick@georgi-clan.de>
Reviewed-on: http://review.coreboot.org/1004
Tested-by: build bot (Jenkins)
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
Reviewed-by: Martin Roth <martin@se-eng.com>
2012-05-05 15:29:32 +02:00
|
|
|
#if CONFIG_HAVE_ACPI_RESUME
|
2009-04-22 10:17:38 +02:00
|
|
|
void suspend_resume(void)
|
|
|
|
{
|
|
|
|
void *wake_vec;
|
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* If we happen to be resuming find wakeup vector and jump to OS. */
|
2009-04-22 10:17:38 +02:00
|
|
|
wake_vec = acpi_find_wakeup_vector();
|
2012-04-03 23:28:22 +02:00
|
|
|
if (wake_vec) {
|
2012-10-04 04:07:05 +02:00
|
|
|
#if CONFIG_HAVE_SMI_HANDLER
|
|
|
|
u32 *gnvs_address = cbmem_find(CBMEM_ID_ACPI_GNVS);
|
|
|
|
|
|
|
|
/* Restore GNVS pointer in SMM if found */
|
|
|
|
if (gnvs_address && *gnvs_address) {
|
|
|
|
printk(BIOS_DEBUG, "Restore GNVS pointer to 0x%08x\n",
|
|
|
|
*gnvs_address);
|
|
|
|
smm_setup_structures((void *)*gnvs_address, NULL, NULL);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-04-03 23:28:22 +02:00
|
|
|
/* Call mainboard resume handler first, if defined. */
|
|
|
|
if (mainboard_suspend_resume)
|
|
|
|
mainboard_suspend_resume();
|
Implement GCC code coverage analysis
In order to provide some insight on what code is executed during
coreboot's run time and how well our test scenarios work, this
adds code coverage support to coreboot's ram stage. This should
be easily adaptable for payloads, and maybe even romstage.
See http://gcc.gnu.org/onlinedocs/gcc/Gcov.html for
more information.
To instrument coreboot, select CONFIG_COVERAGE ("Code coverage
support") in Kconfig, and recompile coreboot. coreboot will then
store its code coverage information into CBMEM, if possible.
Then, run "cbmem -CV" as root on the target system running the
instrumented coreboot binary. This will create a whole bunch of
.gcda files that contain coverage information. Tar them up, copy
them to your build system machine, and untar them. Then you can
use your favorite coverage utility (gcov, lcov, ...) to visualize
code coverage.
For a sneak peak of what will expect you, please take a look
at http://www.coreboot.org/~stepan/coreboot-coverage/
Change-Id: Ib287d8309878a1f5c4be770c38b1bc0bb3aa6ec7
Signed-off-by: Stefan Reinauer <reinauer@google.com>
Reviewed-on: http://review.coreboot.org/2052
Tested-by: build bot (Jenkins)
Reviewed-by: David Hendricks <dhendrix@chromium.org>
Reviewed-by: Martin Roth <martin@se-eng.com>
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
2012-12-19 01:23:28 +01:00
|
|
|
#if CONFIG_COVERAGE
|
|
|
|
coverage_exit();
|
|
|
|
#endif
|
2012-08-13 18:37:42 +02:00
|
|
|
post_code(POST_OS_RESUME);
|
2009-04-22 10:17:38 +02:00
|
|
|
acpi_jump_to_wakeup(wake_vec);
|
2012-04-03 23:28:22 +02:00
|
|
|
}
|
2009-04-22 10:17:38 +02:00
|
|
|
}
|
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* This is to be filled by SB code - startup value what was found. */
|
2009-04-22 10:17:38 +02:00
|
|
|
u8 acpi_slp_type = 0;
|
2009-04-13 20:07:02 +02:00
|
|
|
|
2010-02-22 07:09:43 +01:00
|
|
|
static int acpi_is_wakeup(void)
|
2009-04-13 20:07:02 +02:00
|
|
|
{
|
2010-12-13 22:39:46 +01:00
|
|
|
/* Both resume from S2 and resume from S3 restart at CPU reset */
|
|
|
|
return (acpi_slp_type == 3 || acpi_slp_type == 2);
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static acpi_rsdp_t *rsdp;
|
|
|
|
|
|
|
|
void *acpi_get_wakeup_rsdp(void)
|
|
|
|
{
|
|
|
|
return rsdp;
|
|
|
|
}
|
2004-01-28 17:56:14 +01:00
|
|
|
|
2009-04-13 20:07:02 +02:00
|
|
|
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;
|
2010-11-19 16:14:42 +01:00
|
|
|
void *wake_vec;
|
2009-04-13 20:07:02 +02:00
|
|
|
int i;
|
|
|
|
|
|
|
|
rsdp = NULL;
|
|
|
|
|
|
|
|
if (!acpi_is_wakeup())
|
|
|
|
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) {
|
|
|
|
if ((rsdp = valid_rsdp((acpi_rsdp_t *)p)))
|
2009-04-13 20:07:02 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rsdp == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2010-03-22 12:42:32 +01:00
|
|
|
printk(BIOS_DEBUG, "RSDP found at %p\n", rsdp);
|
2009-04-13 20:07:02 +02:00
|
|
|
rsdt = (acpi_rsdt_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++) {
|
|
|
|
fadt = (acpi_fadt_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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fadt == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2010-03-22 12:42:32 +01:00
|
|
|
printk(BIOS_DEBUG, "FADT found at %p\n", fadt);
|
2009-05-26 14:33:52 +02:00
|
|
|
facs = (acpi_facs_t *)fadt->firmware_ctrl;
|
2009-04-13 20:07:02 +02:00
|
|
|
|
2009-04-22 10:17:38 +02:00
|
|
|
if (facs == NULL) {
|
2010-11-19 16:14:42 +01:00
|
|
|
printk(BIOS_DEBUG, "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);
|
2010-11-19 16:14:42 +01:00
|
|
|
wake_vec = (void *)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;
|
|
|
|
}
|
|
|
|
|
2010-12-13 22:39:46 +01:00
|
|
|
#if CONFIG_SMP
|
2009-04-13 20:07:02 +02:00
|
|
|
extern char *lowmem_backup;
|
|
|
|
extern char *lowmem_backup_ptr;
|
|
|
|
extern int lowmem_backup_size;
|
2010-12-13 22:39:46 +01:00
|
|
|
#endif
|
2009-04-13 20:07:02 +02:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
#define WAKEUP_BASE 0x600
|
2009-11-10 23:17:15 +01:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
void (*acpi_do_wakeup)(u32 vector, u32 backup_source, u32 backup_target,
|
2012-12-06 22:54:29 +01:00
|
|
|
u32 backup_size) asmlinkage = (void *)WAKEUP_BASE;
|
2009-11-10 23:17:15 +01:00
|
|
|
|
2013-02-08 23:56:51 +01:00
|
|
|
extern unsigned char __wakeup;
|
|
|
|
extern unsigned int __wakeup_size;
|
2009-11-10 23:17:15 +01:00
|
|
|
|
2009-04-13 20:07:02 +02:00
|
|
|
void acpi_jump_to_wakeup(void *vector)
|
|
|
|
{
|
2013-02-09 00:28:04 +01:00
|
|
|
#if CONFIG_RELOCATABLE_RAMSTAGE
|
|
|
|
u32 acpi_backup_memory = 0;
|
|
|
|
#else
|
2010-11-19 16:14:42 +01:00
|
|
|
u32 acpi_backup_memory = (u32)cbmem_find(CBMEM_ID_RESUME);
|
2009-11-10 23:17:15 +01:00
|
|
|
|
|
|
|
if (!acpi_backup_memory) {
|
2010-11-19 16:14:42 +01:00
|
|
|
printk(BIOS_WARNING, "ACPI: Backup memory missing. "
|
|
|
|
"No S3 resume.\n");
|
2009-11-10 23:17:15 +01:00
|
|
|
return;
|
|
|
|
}
|
2013-02-09 00:28:04 +01:00
|
|
|
#endif
|
2009-11-10 23:17:15 +01:00
|
|
|
|
2010-12-13 22:39:46 +01:00
|
|
|
#if CONFIG_SMP
|
2010-11-19 16:14:42 +01:00
|
|
|
// FIXME: This should go into the ACPI backup memory, too. No pork saussages.
|
|
|
|
/*
|
|
|
|
* Just restore the SMP trampoline and continue with wakeup on
|
|
|
|
* assembly level.
|
|
|
|
*/
|
2009-04-13 20:07:02 +02:00
|
|
|
memcpy(lowmem_backup_ptr, lowmem_backup, lowmem_backup_size);
|
2010-12-13 22:39:46 +01:00
|
|
|
#endif
|
2009-11-10 23:17:15 +01:00
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
/* Copy wakeup trampoline in place. */
|
2013-02-08 23:56:51 +01:00
|
|
|
memcpy((void *)WAKEUP_BASE, &__wakeup, __wakeup_size);
|
2009-11-10 23:17:15 +01:00
|
|
|
|
2011-10-20 00:32:39 +02:00
|
|
|
#if CONFIG_COLLECT_TIMESTAMPS
|
|
|
|
timestamp_add_now(TS_ACPI_WAKE_JUMP);
|
|
|
|
#endif
|
|
|
|
|
2010-11-19 16:14:42 +01:00
|
|
|
acpi_do_wakeup((u32)vector, acpi_backup_memory, CONFIG_RAMBASE,
|
|
|
|
HIGH_MEMORY_SAVE);
|
2009-04-13 20:07:02 +02:00
|
|
|
}
|
|
|
|
#endif
|
2012-10-04 04:07:05 +02:00
|
|
|
|
|
|
|
void acpi_save_gnvs(u32 gnvs_address)
|
|
|
|
{
|
|
|
|
u32 *gnvs = cbmem_add(CBMEM_ID_ACPI_GNVS, sizeof(*gnvs));
|
|
|
|
if (gnvs)
|
|
|
|
*gnvs = gnvs_address;
|
|
|
|
}
|