MFC 197439:
Extract the code to find and map the MADT ACPI table during early kernel startup and genericize it so it can be reused to map other tables as well: - Add a routine to walk a list of ACPI subtables such as those used in the APIC and SRAT tables in the MI acpi(4) driver. - Move the routines for mapping and unmapping an ACPI table as well as mapping the RSDT or XSDT and searching for a table with a given signature out into acpica_machdep.c for both amd64 and i386.
This commit is contained in:
parent
a74a662b74
commit
ff5bfa3ef6
@ -32,8 +32,12 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
#include <contrib/dev/acpica/include/acpi.h>
|
||||
#include <contrib/dev/acpica/include/accommon.h>
|
||||
#include <contrib/dev/acpica/include/actables.h>
|
||||
|
||||
#include <dev/acpica/acpivar.h>
|
||||
|
||||
@ -99,6 +103,246 @@ acpi_cpu_c1()
|
||||
__asm __volatile("sti; hlt");
|
||||
}
|
||||
|
||||
/*
|
||||
* Support for mapping ACPI tables during early boot. Currently this
|
||||
* uses the crashdump map to map each table. However, the crashdump
|
||||
* map is created in pmap_bootstrap() right after the direct map, so
|
||||
* we should be able to just use pmap_mapbios() here instead.
|
||||
*
|
||||
* This makes the following assumptions about how we use this KVA:
|
||||
* pages 0 and 1 are used to map in the header of each table found via
|
||||
* the RSDT or XSDT and pages 2 to n are used to map in the RSDT or
|
||||
* XSDT. This has to use 2 pages for the table headers in case a
|
||||
* header spans a page boundary.
|
||||
*
|
||||
* XXX: We don't ensure the table fits in the available address space
|
||||
* in the crashdump map.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Map some memory using the crashdump map. 'offset' is an offset in
|
||||
* pages into the crashdump map to use for the start of the mapping.
|
||||
*/
|
||||
static void *
|
||||
table_map(vm_paddr_t pa, int offset, vm_offset_t length)
|
||||
{
|
||||
vm_offset_t va, off;
|
||||
void *data;
|
||||
|
||||
off = pa & PAGE_MASK;
|
||||
length = roundup(length + off, PAGE_SIZE);
|
||||
pa = pa & PG_FRAME;
|
||||
va = (vm_offset_t)pmap_kenter_temporary(pa, offset) +
|
||||
(offset * PAGE_SIZE);
|
||||
data = (void *)(va + off);
|
||||
length -= PAGE_SIZE;
|
||||
while (length > 0) {
|
||||
va += PAGE_SIZE;
|
||||
pa += PAGE_SIZE;
|
||||
length -= PAGE_SIZE;
|
||||
pmap_kenter(va, pa);
|
||||
invlpg(va);
|
||||
}
|
||||
return (data);
|
||||
}
|
||||
|
||||
/* Unmap memory previously mapped with table_map(). */
|
||||
static void
|
||||
table_unmap(void *data, vm_offset_t length)
|
||||
{
|
||||
vm_offset_t va, off;
|
||||
|
||||
va = (vm_offset_t)data;
|
||||
off = va & PAGE_MASK;
|
||||
length = roundup(length + off, PAGE_SIZE);
|
||||
va &= ~PAGE_MASK;
|
||||
while (length > 0) {
|
||||
pmap_kremove(va);
|
||||
invlpg(va);
|
||||
va += PAGE_SIZE;
|
||||
length -= PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Map a table at a given offset into the crashdump map. It first
|
||||
* maps the header to determine the table length and then maps the
|
||||
* entire table.
|
||||
*/
|
||||
static void *
|
||||
map_table(vm_paddr_t pa, int offset, const char *sig)
|
||||
{
|
||||
ACPI_TABLE_HEADER *header;
|
||||
vm_offset_t length;
|
||||
void *table;
|
||||
|
||||
header = table_map(pa, offset, sizeof(ACPI_TABLE_HEADER));
|
||||
if (strncmp(header->Signature, sig, ACPI_NAME_SIZE) != 0) {
|
||||
table_unmap(header, sizeof(ACPI_TABLE_HEADER));
|
||||
return (NULL);
|
||||
}
|
||||
length = header->Length;
|
||||
table_unmap(header, sizeof(ACPI_TABLE_HEADER));
|
||||
table = table_map(pa, offset, length);
|
||||
if (ACPI_FAILURE(AcpiTbChecksum(table, length))) {
|
||||
if (bootverbose)
|
||||
printf("ACPI: Failed checksum for table %s\n", sig);
|
||||
table_unmap(table, length);
|
||||
return (NULL);
|
||||
}
|
||||
return (table);
|
||||
}
|
||||
|
||||
/*
|
||||
* See if a given ACPI table is the requested table. Returns the
|
||||
* length of the able if it matches or zero on failure.
|
||||
*/
|
||||
static int
|
||||
probe_table(vm_paddr_t address, const char *sig)
|
||||
{
|
||||
ACPI_TABLE_HEADER *table;
|
||||
|
||||
table = table_map(address, 0, sizeof(ACPI_TABLE_HEADER));
|
||||
if (table == NULL) {
|
||||
if (bootverbose)
|
||||
printf("ACPI: Failed to map table at 0x%jx\n",
|
||||
(uintmax_t)address);
|
||||
return (0);
|
||||
}
|
||||
if (bootverbose)
|
||||
printf("Table '%.4s' at 0x%jx\n", table->Signature,
|
||||
(uintmax_t)address);
|
||||
|
||||
if (strncmp(table->Signature, sig, ACPI_NAME_SIZE) != 0) {
|
||||
table_unmap(table, sizeof(ACPI_TABLE_HEADER));
|
||||
return (0);
|
||||
}
|
||||
table_unmap(table, sizeof(ACPI_TABLE_HEADER));
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to map a table at a given physical address previously returned
|
||||
* by acpi_find_table().
|
||||
*/
|
||||
void *
|
||||
acpi_map_table(vm_paddr_t pa, const char *sig)
|
||||
{
|
||||
|
||||
return (map_table(pa, 0, sig));
|
||||
}
|
||||
|
||||
/* Unmap a table previously mapped via acpi_map_table(). */
|
||||
void
|
||||
acpi_unmap_table(void *table)
|
||||
{
|
||||
ACPI_TABLE_HEADER *header;
|
||||
|
||||
header = (ACPI_TABLE_HEADER *)table;
|
||||
table_unmap(table, header->Length);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the physical address of the requested table or zero if one
|
||||
* is not found.
|
||||
*/
|
||||
vm_paddr_t
|
||||
acpi_find_table(const char *sig)
|
||||
{
|
||||
ACPI_PHYSICAL_ADDRESS rsdp_ptr;
|
||||
ACPI_TABLE_RSDP *rsdp;
|
||||
ACPI_TABLE_RSDT *rsdt;
|
||||
ACPI_TABLE_XSDT *xsdt;
|
||||
ACPI_TABLE_HEADER *table;
|
||||
vm_paddr_t addr;
|
||||
int i, count;
|
||||
|
||||
if (resource_disabled("acpi", 0))
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* Map in the RSDP. Since ACPI uses AcpiOsMapMemory() which in turn
|
||||
* calls pmap_mapbios() to find the RSDP, we assume that we can use
|
||||
* pmap_mapbios() to map the RSDP.
|
||||
*/
|
||||
if ((rsdp_ptr = AcpiOsGetRootPointer()) == 0)
|
||||
return (0);
|
||||
rsdp = pmap_mapbios(rsdp_ptr, sizeof(ACPI_TABLE_RSDP));
|
||||
if (rsdp == NULL) {
|
||||
if (bootverbose)
|
||||
printf("ACPI: Failed to map RSDP\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* For ACPI >= 2.0, use the XSDT if it is available.
|
||||
* Otherwise, use the RSDT. We map the XSDT or RSDT at page 2
|
||||
* in the crashdump area. Pages 0 and 1 are used to map in the
|
||||
* headers of candidate ACPI tables.
|
||||
*/
|
||||
addr = 0;
|
||||
if (rsdp->Revision >= 2 && rsdp->XsdtPhysicalAddress != 0) {
|
||||
/*
|
||||
* AcpiOsGetRootPointer only verifies the checksum for
|
||||
* the version 1.0 portion of the RSDP. Version 2.0 has
|
||||
* an additional checksum that we verify first.
|
||||
*/
|
||||
if (AcpiTbChecksum((UINT8 *)rsdp, ACPI_RSDP_XCHECKSUM_LENGTH)) {
|
||||
if (bootverbose)
|
||||
printf("ACPI: RSDP failed extended checksum\n");
|
||||
return (0);
|
||||
}
|
||||
xsdt = map_table(rsdp->XsdtPhysicalAddress, 2, ACPI_SIG_XSDT);
|
||||
if (xsdt == NULL) {
|
||||
if (bootverbose)
|
||||
printf("ACPI: Failed to map XSDT\n");
|
||||
return (0);
|
||||
}
|
||||
count = (xsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) /
|
||||
sizeof(UINT64);
|
||||
for (i = 0; i < count; i++)
|
||||
if (probe_table(xsdt->TableOffsetEntry[i], sig)) {
|
||||
addr = xsdt->TableOffsetEntry[i];
|
||||
break;
|
||||
}
|
||||
acpi_unmap_table(xsdt);
|
||||
} else {
|
||||
rsdt = map_table(rsdp->RsdtPhysicalAddress, 2, ACPI_SIG_RSDT);
|
||||
if (rsdt == NULL) {
|
||||
if (bootverbose)
|
||||
printf("ACPI: Failed to map RSDT\n");
|
||||
return (0);
|
||||
}
|
||||
count = (rsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) /
|
||||
sizeof(UINT32);
|
||||
for (i = 0; i < count; i++)
|
||||
if (probe_table(rsdt->TableOffsetEntry[i], sig)) {
|
||||
addr = rsdt->TableOffsetEntry[i];
|
||||
break;
|
||||
}
|
||||
acpi_unmap_table(rsdt);
|
||||
}
|
||||
pmap_unmapbios((vm_offset_t)rsdp, sizeof(ACPI_TABLE_RSDP));
|
||||
if (addr == 0) {
|
||||
if (bootverbose)
|
||||
printf("ACPI: No %s table found\n", sig);
|
||||
return (0);
|
||||
}
|
||||
if (bootverbose)
|
||||
printf("%s: Found table at 0x%jx\n", sig, (uintmax_t)addr);
|
||||
|
||||
/*
|
||||
* Verify that we can map the full table and that its checksum is
|
||||
* correct, etc.
|
||||
*/
|
||||
table = map_table(addr, 0, sig);
|
||||
if (table == NULL)
|
||||
return (0);
|
||||
acpi_unmap_table(table);
|
||||
|
||||
return (addr);
|
||||
}
|
||||
|
||||
/*
|
||||
* ACPI nexus(4) driver.
|
||||
*/
|
||||
|
@ -36,27 +36,19 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/smp.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_param.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
#include <machine/apicreg.h>
|
||||
#include <machine/frame.h>
|
||||
#include <machine/intr_machdep.h>
|
||||
#include <machine/apicvar.h>
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/specialreg.h>
|
||||
|
||||
#include <contrib/dev/acpica/include/acpi.h>
|
||||
#include <contrib/dev/acpica/include/accommon.h>
|
||||
#include <contrib/dev/acpica/include/actables.h>
|
||||
|
||||
#include <dev/acpica/acpivar.h>
|
||||
#include <dev/pci/pcivar.h>
|
||||
|
||||
typedef void madt_entry_handler(ACPI_SUBTABLE_HEADER *entry, void *arg);
|
||||
|
||||
/* These two arrays are indexed by APIC IDs. */
|
||||
struct ioapic_info {
|
||||
void *io_apic;
|
||||
@ -79,8 +71,6 @@ static enum intr_polarity interrupt_polarity(UINT16 IntiFlags, UINT8 Source);
|
||||
static enum intr_trigger interrupt_trigger(UINT16 IntiFlags, UINT8 Source);
|
||||
static int madt_find_cpu(u_int acpi_id, u_int *apic_id);
|
||||
static int madt_find_interrupt(int intr, void **apic, u_int *pin);
|
||||
static void *madt_map(vm_paddr_t pa, int offset, vm_offset_t length);
|
||||
static void *madt_map_table(vm_paddr_t pa, int offset, const char *sig);
|
||||
static void madt_parse_apics(ACPI_SUBTABLE_HEADER *entry, void *arg);
|
||||
static void madt_parse_interrupt_override(
|
||||
ACPI_MADT_INTERRUPT_OVERRIDE *intr);
|
||||
@ -92,13 +82,10 @@ static int madt_probe(void);
|
||||
static int madt_probe_cpus(void);
|
||||
static void madt_probe_cpus_handler(ACPI_SUBTABLE_HEADER *entry,
|
||||
void *arg __unused);
|
||||
static int madt_probe_table(vm_paddr_t address);
|
||||
static void madt_register(void *dummy);
|
||||
static int madt_setup_local(void);
|
||||
static int madt_setup_io(void);
|
||||
static void madt_unmap(void *data, vm_offset_t length);
|
||||
static void madt_unmap_table(void *table);
|
||||
static void madt_walk_table(madt_entry_handler *handler, void *arg);
|
||||
static void madt_walk_table(acpi_subtable_handler *handler, void *arg);
|
||||
|
||||
static struct apic_enumerator madt_enumerator = {
|
||||
"MADT",
|
||||
@ -108,214 +95,19 @@ static struct apic_enumerator madt_enumerator = {
|
||||
madt_setup_io
|
||||
};
|
||||
|
||||
/*
|
||||
* Code to abuse the crashdump map to map in the tables for the early
|
||||
* probe. We cheat and make the following assumptions about how we
|
||||
* use this KVA: pages 0 and 1 are used to map in the header of each
|
||||
* table found via the RSDT or XSDT and pages 2 to n are used to map
|
||||
* in the RSDT or XSDT. We have to use 2 pages for the table headers
|
||||
* in case a header spans a page boundary. The offset is in pages;
|
||||
* the length is in bytes.
|
||||
*/
|
||||
static void *
|
||||
madt_map(vm_paddr_t pa, int offset, vm_offset_t length)
|
||||
{
|
||||
vm_offset_t va, off;
|
||||
void *data;
|
||||
|
||||
off = pa & PAGE_MASK;
|
||||
length = roundup(length + off, PAGE_SIZE);
|
||||
pa = pa & PG_FRAME;
|
||||
va = (vm_offset_t)pmap_kenter_temporary(pa, offset) +
|
||||
(offset * PAGE_SIZE);
|
||||
data = (void *)(va + off);
|
||||
length -= PAGE_SIZE;
|
||||
while (length > 0) {
|
||||
va += PAGE_SIZE;
|
||||
pa += PAGE_SIZE;
|
||||
length -= PAGE_SIZE;
|
||||
pmap_kenter(va, pa);
|
||||
invlpg(va);
|
||||
}
|
||||
return (data);
|
||||
}
|
||||
|
||||
static void
|
||||
madt_unmap(void *data, vm_offset_t length)
|
||||
{
|
||||
vm_offset_t va, off;
|
||||
|
||||
va = (vm_offset_t)data;
|
||||
off = va & PAGE_MASK;
|
||||
length = roundup(length + off, PAGE_SIZE);
|
||||
va &= ~PAGE_MASK;
|
||||
while (length > 0) {
|
||||
pmap_kremove(va);
|
||||
invlpg(va);
|
||||
va += PAGE_SIZE;
|
||||
length -= PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static void *
|
||||
madt_map_table(vm_paddr_t pa, int offset, const char *sig)
|
||||
{
|
||||
ACPI_TABLE_HEADER *header;
|
||||
vm_offset_t length;
|
||||
void *table;
|
||||
|
||||
header = madt_map(pa, offset, sizeof(ACPI_TABLE_HEADER));
|
||||
if (strncmp(header->Signature, sig, ACPI_NAME_SIZE) != 0) {
|
||||
madt_unmap(header, sizeof(ACPI_TABLE_HEADER));
|
||||
return (NULL);
|
||||
}
|
||||
length = header->Length;
|
||||
madt_unmap(header, sizeof(ACPI_TABLE_HEADER));
|
||||
table = madt_map(pa, offset, length);
|
||||
if (ACPI_FAILURE(AcpiTbChecksum(table, length))) {
|
||||
if (bootverbose)
|
||||
printf("MADT: Failed checksum for table %s\n", sig);
|
||||
madt_unmap(table, length);
|
||||
return (NULL);
|
||||
}
|
||||
return (table);
|
||||
}
|
||||
|
||||
static void
|
||||
madt_unmap_table(void *table)
|
||||
{
|
||||
ACPI_TABLE_HEADER *header;
|
||||
|
||||
header = (ACPI_TABLE_HEADER *)table;
|
||||
madt_unmap(table, header->Length);
|
||||
}
|
||||
|
||||
/*
|
||||
* Look for an ACPI Multiple APIC Description Table ("APIC")
|
||||
*/
|
||||
static int
|
||||
madt_probe(void)
|
||||
{
|
||||
ACPI_PHYSICAL_ADDRESS rsdp_ptr;
|
||||
ACPI_TABLE_RSDP *rsdp;
|
||||
ACPI_TABLE_RSDT *rsdt;
|
||||
ACPI_TABLE_XSDT *xsdt;
|
||||
int i, count;
|
||||
|
||||
if (resource_disabled("acpi", 0))
|
||||
madt_physaddr = acpi_find_table(ACPI_SIG_MADT);
|
||||
if (madt_physaddr == 0)
|
||||
return (ENXIO);
|
||||
|
||||
/*
|
||||
* Map in the RSDP. Since ACPI uses AcpiOsMapMemory() which in turn
|
||||
* calls pmap_mapbios() to find the RSDP, we assume that we can use
|
||||
* pmap_mapbios() to map the RSDP.
|
||||
*/
|
||||
if ((rsdp_ptr = AcpiOsGetRootPointer()) == 0)
|
||||
return (ENXIO);
|
||||
rsdp = pmap_mapbios(rsdp_ptr, sizeof(ACPI_TABLE_RSDP));
|
||||
if (rsdp == NULL) {
|
||||
if (bootverbose)
|
||||
printf("MADT: Failed to map RSDP\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/*
|
||||
* For ACPI >= 2.0, use the XSDT if it is available.
|
||||
* Otherwise, use the RSDT. We map the XSDT or RSDT at page 1
|
||||
* in the crashdump area. Page 0 is used to map in the
|
||||
* headers of candidate ACPI tables.
|
||||
*/
|
||||
if (rsdp->Revision >= 2 && rsdp->XsdtPhysicalAddress != 0) {
|
||||
/*
|
||||
* AcpiOsGetRootPointer only verifies the checksum for
|
||||
* the version 1.0 portion of the RSDP. Version 2.0 has
|
||||
* an additional checksum that we verify first.
|
||||
*/
|
||||
if (AcpiTbChecksum((UINT8 *)rsdp, ACPI_RSDP_XCHECKSUM_LENGTH)) {
|
||||
if (bootverbose)
|
||||
printf("MADT: RSDP failed extended checksum\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
xsdt = madt_map_table(rsdp->XsdtPhysicalAddress, 2,
|
||||
ACPI_SIG_XSDT);
|
||||
if (xsdt == NULL) {
|
||||
if (bootverbose)
|
||||
printf("MADT: Failed to map XSDT\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
count = (xsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) /
|
||||
sizeof(UINT64);
|
||||
for (i = 0; i < count; i++)
|
||||
if (madt_probe_table(xsdt->TableOffsetEntry[i]))
|
||||
break;
|
||||
madt_unmap_table(xsdt);
|
||||
} else {
|
||||
rsdt = madt_map_table(rsdp->RsdtPhysicalAddress, 2,
|
||||
ACPI_SIG_RSDT);
|
||||
if (rsdt == NULL) {
|
||||
if (bootverbose)
|
||||
printf("MADT: Failed to map RSDT\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
count = (rsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) /
|
||||
sizeof(UINT32);
|
||||
for (i = 0; i < count; i++)
|
||||
if (madt_probe_table(rsdt->TableOffsetEntry[i]))
|
||||
break;
|
||||
madt_unmap_table(rsdt);
|
||||
}
|
||||
pmap_unmapbios((vm_offset_t)rsdp, sizeof(ACPI_TABLE_RSDP));
|
||||
if (madt_physaddr == 0) {
|
||||
if (bootverbose)
|
||||
printf("MADT: No MADT table found\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
if (bootverbose)
|
||||
printf("MADT: Found table at 0x%jx\n",
|
||||
(uintmax_t)madt_physaddr);
|
||||
|
||||
/*
|
||||
* Verify that we can map the full table and that its checksum is
|
||||
* correct, etc.
|
||||
*/
|
||||
madt = madt_map_table(madt_physaddr, 0, ACPI_SIG_MADT);
|
||||
if (madt == NULL)
|
||||
return (ENXIO);
|
||||
madt_unmap_table(madt);
|
||||
madt = NULL;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* See if a given ACPI table is the MADT.
|
||||
*/
|
||||
static int
|
||||
madt_probe_table(vm_paddr_t address)
|
||||
{
|
||||
ACPI_TABLE_HEADER *table;
|
||||
|
||||
table = madt_map(address, 0, sizeof(ACPI_TABLE_HEADER));
|
||||
if (table == NULL) {
|
||||
if (bootverbose)
|
||||
printf("MADT: Failed to map table at 0x%jx\n",
|
||||
(uintmax_t)address);
|
||||
return (0);
|
||||
}
|
||||
if (bootverbose)
|
||||
printf("Table '%.4s' at 0x%jx\n", table->Signature,
|
||||
(uintmax_t)address);
|
||||
|
||||
if (strncmp(table->Signature, ACPI_SIG_MADT, ACPI_NAME_SIZE) != 0) {
|
||||
madt_unmap(table, sizeof(ACPI_TABLE_HEADER));
|
||||
return (0);
|
||||
}
|
||||
madt_physaddr = address;
|
||||
madt_length = table->Length;
|
||||
madt_unmap(table, sizeof(ACPI_TABLE_HEADER));
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Run through the MP table enumerating CPUs.
|
||||
*/
|
||||
@ -323,10 +115,11 @@ static int
|
||||
madt_probe_cpus(void)
|
||||
{
|
||||
|
||||
madt = madt_map_table(madt_physaddr, 0, ACPI_SIG_MADT);
|
||||
madt = acpi_map_table(madt_physaddr, ACPI_SIG_MADT);
|
||||
madt_length = madt->Header.Length;
|
||||
KASSERT(madt != NULL, ("Unable to re-map MADT"));
|
||||
madt_walk_table(madt_probe_cpus_handler, NULL);
|
||||
madt_unmap_table(madt);
|
||||
acpi_unmap_table(madt);
|
||||
madt = NULL;
|
||||
return (0);
|
||||
}
|
||||
@ -417,17 +210,11 @@ SYSINIT(madt_register, SI_SUB_TUNABLES - 1, SI_ORDER_FIRST,
|
||||
* Call the handler routine for each entry in the MADT table.
|
||||
*/
|
||||
static void
|
||||
madt_walk_table(madt_entry_handler *handler, void *arg)
|
||||
madt_walk_table(acpi_subtable_handler *handler, void *arg)
|
||||
{
|
||||
ACPI_SUBTABLE_HEADER *entry;
|
||||
u_char *p, *end;
|
||||
|
||||
end = (u_char *)(madt) + madt->Header.Length;
|
||||
for (p = (u_char *)(madt + 1); p < end; ) {
|
||||
entry = (ACPI_SUBTABLE_HEADER *)p;
|
||||
handler(entry, arg);
|
||||
p += entry->Length;
|
||||
}
|
||||
acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
|
||||
handler, arg);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -77,5 +77,8 @@ extern int acpi_release_global_lock(uint32_t *lock);
|
||||
|
||||
void acpi_SetDefaultIntrModel(int model);
|
||||
void acpi_cpu_c1(void);
|
||||
void *acpi_map_table(vm_paddr_t pa, const char *sig);
|
||||
void acpi_unmap_table(void *table);
|
||||
vm_paddr_t acpi_find_table(const char *sig);
|
||||
|
||||
#endif /* __ACPICA_MACHDEP_H__ */
|
||||
|
@ -2289,6 +2289,28 @@ acpi_SetIntrModel(int model)
|
||||
return (acpi_SetInteger(ACPI_ROOT_OBJECT, "_PIC", model));
|
||||
}
|
||||
|
||||
/*
|
||||
* Walk subtables of a table and call a callback routine for each
|
||||
* subtable. The caller should provide the first subtable and a
|
||||
* pointer to the end of the table. This can be used to walk tables
|
||||
* such as MADT and SRAT that use subtable entries.
|
||||
*/
|
||||
void
|
||||
acpi_walk_subtables(void *first, void *end, acpi_subtable_handler *handler,
|
||||
void *arg)
|
||||
{
|
||||
ACPI_SUBTABLE_HEADER *entry;
|
||||
|
||||
for (entry = first; (void *)entry < end; ) {
|
||||
/* Avoid an infinite loop if we hit a bogus entry. */
|
||||
if (entry->Length < sizeof(ACPI_SUBTABLE_HEADER))
|
||||
return;
|
||||
|
||||
handler(entry, arg);
|
||||
entry = ACPI_ADD_PTR(ACPI_SUBTABLE_HEADER, entry, entry->Length);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* DEPRECATED. This interface has serious deficiencies and will be
|
||||
* removed.
|
||||
|
@ -307,6 +307,9 @@ void acpi_EnterDebugger(void);
|
||||
ACPI_DEVINFO_PRESENT(x, ACPI_STA_PRESENT | ACPI_STA_FUNCTIONAL | \
|
||||
ACPI_STA_BATT_PRESENT)
|
||||
|
||||
/* Callback function type for walking subtables within a table. */
|
||||
typedef void acpi_subtable_handler(ACPI_SUBTABLE_HEADER *, void *);
|
||||
|
||||
BOOLEAN acpi_DeviceIsPresent(device_t dev);
|
||||
BOOLEAN acpi_BatteryIsPresent(device_t dev);
|
||||
ACPI_STATUS acpi_GetHandleInScope(ACPI_HANDLE parent, char *path,
|
||||
@ -340,6 +343,8 @@ void acpi_UserNotify(const char *subsystem, ACPI_HANDLE h,
|
||||
int acpi_bus_alloc_gas(device_t dev, int *type, int *rid,
|
||||
ACPI_GENERIC_ADDRESS *gas, struct resource **res,
|
||||
u_int flags);
|
||||
void acpi_walk_subtables(void *first, void *end,
|
||||
acpi_subtable_handler *handler, void *arg);
|
||||
|
||||
struct acpi_parse_resource_set {
|
||||
void (*set_init)(device_t dev, void *arg, void **context);
|
||||
|
@ -42,6 +42,8 @@ __FBSDID("$FreeBSD$");
|
||||
#include <vm/pmap.h>
|
||||
|
||||
#include <contrib/dev/acpica/include/acpi.h>
|
||||
#include <contrib/dev/acpica/include/accommon.h>
|
||||
#include <contrib/dev/acpica/include/actables.h>
|
||||
|
||||
#include <dev/acpica/acpivar.h>
|
||||
#include <dev/acpica/acpiio.h>
|
||||
@ -554,6 +556,244 @@ acpi_cpu_c1()
|
||||
__asm __volatile("sti; hlt");
|
||||
}
|
||||
|
||||
/*
|
||||
* Support for mapping ACPI tables during early boot. This abuses the
|
||||
* crashdump map because the kernel cannot allocate KVA in
|
||||
* pmap_mapbios() when this is used. This makes the following
|
||||
* assumptions about how we use this KVA: pages 0 and 1 are used to
|
||||
* map in the header of each table found via the RSDT or XSDT and
|
||||
* pages 2 to n are used to map in the RSDT or XSDT. This has to use
|
||||
* 2 pages for the table headers in case a header spans a page
|
||||
* boundary.
|
||||
*
|
||||
* XXX: We don't ensure the table fits in the available address space
|
||||
* in the crashdump map.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Map some memory using the crashdump map. 'offset' is an offset in
|
||||
* pages into the crashdump map to use for the start of the mapping.
|
||||
*/
|
||||
static void *
|
||||
table_map(vm_paddr_t pa, int offset, vm_offset_t length)
|
||||
{
|
||||
vm_offset_t va, off;
|
||||
void *data;
|
||||
|
||||
off = pa & PAGE_MASK;
|
||||
length = roundup(length + off, PAGE_SIZE);
|
||||
pa = pa & PG_FRAME;
|
||||
va = (vm_offset_t)pmap_kenter_temporary(pa, offset) +
|
||||
(offset * PAGE_SIZE);
|
||||
data = (void *)(va + off);
|
||||
length -= PAGE_SIZE;
|
||||
while (length > 0) {
|
||||
va += PAGE_SIZE;
|
||||
pa += PAGE_SIZE;
|
||||
length -= PAGE_SIZE;
|
||||
pmap_kenter(va, pa);
|
||||
invlpg(va);
|
||||
}
|
||||
return (data);
|
||||
}
|
||||
|
||||
/* Unmap memory previously mapped with table_map(). */
|
||||
static void
|
||||
table_unmap(void *data, vm_offset_t length)
|
||||
{
|
||||
vm_offset_t va, off;
|
||||
|
||||
va = (vm_offset_t)data;
|
||||
off = va & PAGE_MASK;
|
||||
length = roundup(length + off, PAGE_SIZE);
|
||||
va &= ~PAGE_MASK;
|
||||
while (length > 0) {
|
||||
pmap_kremove(va);
|
||||
invlpg(va);
|
||||
va += PAGE_SIZE;
|
||||
length -= PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Map a table at a given offset into the crashdump map. It first
|
||||
* maps the header to determine the table length and then maps the
|
||||
* entire table.
|
||||
*/
|
||||
static void *
|
||||
map_table(vm_paddr_t pa, int offset, const char *sig)
|
||||
{
|
||||
ACPI_TABLE_HEADER *header;
|
||||
vm_offset_t length;
|
||||
void *table;
|
||||
|
||||
header = table_map(pa, offset, sizeof(ACPI_TABLE_HEADER));
|
||||
if (strncmp(header->Signature, sig, ACPI_NAME_SIZE) != 0) {
|
||||
table_unmap(header, sizeof(ACPI_TABLE_HEADER));
|
||||
return (NULL);
|
||||
}
|
||||
length = header->Length;
|
||||
table_unmap(header, sizeof(ACPI_TABLE_HEADER));
|
||||
table = table_map(pa, offset, length);
|
||||
if (ACPI_FAILURE(AcpiTbChecksum(table, length))) {
|
||||
if (bootverbose)
|
||||
printf("ACPI: Failed checksum for table %s\n", sig);
|
||||
table_unmap(table, length);
|
||||
return (NULL);
|
||||
}
|
||||
return (table);
|
||||
}
|
||||
|
||||
/*
|
||||
* See if a given ACPI table is the requested table. Returns the
|
||||
* length of the able if it matches or zero on failure.
|
||||
*/
|
||||
static int
|
||||
probe_table(vm_paddr_t address, const char *sig)
|
||||
{
|
||||
ACPI_TABLE_HEADER *table;
|
||||
|
||||
table = table_map(address, 0, sizeof(ACPI_TABLE_HEADER));
|
||||
if (table == NULL) {
|
||||
if (bootverbose)
|
||||
printf("ACPI: Failed to map table at 0x%jx\n",
|
||||
(uintmax_t)address);
|
||||
return (0);
|
||||
}
|
||||
if (bootverbose)
|
||||
printf("Table '%.4s' at 0x%jx\n", table->Signature,
|
||||
(uintmax_t)address);
|
||||
|
||||
if (strncmp(table->Signature, sig, ACPI_NAME_SIZE) != 0) {
|
||||
table_unmap(table, sizeof(ACPI_TABLE_HEADER));
|
||||
return (0);
|
||||
}
|
||||
table_unmap(table, sizeof(ACPI_TABLE_HEADER));
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to map a table at a given physical address previously returned
|
||||
* by acpi_find_table().
|
||||
*/
|
||||
void *
|
||||
acpi_map_table(vm_paddr_t pa, const char *sig)
|
||||
{
|
||||
|
||||
return (map_table(pa, 0, sig));
|
||||
}
|
||||
|
||||
/* Unmap a table previously mapped via acpi_map_table(). */
|
||||
void
|
||||
acpi_unmap_table(void *table)
|
||||
{
|
||||
ACPI_TABLE_HEADER *header;
|
||||
|
||||
header = (ACPI_TABLE_HEADER *)table;
|
||||
table_unmap(table, header->Length);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the physical address of the requested table or zero if one
|
||||
* is not found.
|
||||
*/
|
||||
vm_paddr_t
|
||||
acpi_find_table(const char *sig)
|
||||
{
|
||||
ACPI_PHYSICAL_ADDRESS rsdp_ptr;
|
||||
ACPI_TABLE_RSDP *rsdp;
|
||||
ACPI_TABLE_RSDT *rsdt;
|
||||
ACPI_TABLE_XSDT *xsdt;
|
||||
ACPI_TABLE_HEADER *table;
|
||||
vm_paddr_t addr;
|
||||
int i, count;
|
||||
|
||||
if (resource_disabled("acpi", 0))
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* Map in the RSDP. Since ACPI uses AcpiOsMapMemory() which in turn
|
||||
* calls pmap_mapbios() to find the RSDP, we assume that we can use
|
||||
* pmap_mapbios() to map the RSDP.
|
||||
*/
|
||||
if ((rsdp_ptr = AcpiOsGetRootPointer()) == 0)
|
||||
return (0);
|
||||
rsdp = pmap_mapbios(rsdp_ptr, sizeof(ACPI_TABLE_RSDP));
|
||||
if (rsdp == NULL) {
|
||||
if (bootverbose)
|
||||
printf("ACPI: Failed to map RSDP\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* For ACPI >= 2.0, use the XSDT if it is available.
|
||||
* Otherwise, use the RSDT. We map the XSDT or RSDT at page 2
|
||||
* in the crashdump area. Pages 0 and 1 are used to map in the
|
||||
* headers of candidate ACPI tables.
|
||||
*/
|
||||
addr = 0;
|
||||
if (rsdp->Revision >= 2 && rsdp->XsdtPhysicalAddress != 0) {
|
||||
/*
|
||||
* AcpiOsGetRootPointer only verifies the checksum for
|
||||
* the version 1.0 portion of the RSDP. Version 2.0 has
|
||||
* an additional checksum that we verify first.
|
||||
*/
|
||||
if (AcpiTbChecksum((UINT8 *)rsdp, ACPI_RSDP_XCHECKSUM_LENGTH)) {
|
||||
if (bootverbose)
|
||||
printf("ACPI: RSDP failed extended checksum\n");
|
||||
return (0);
|
||||
}
|
||||
xsdt = map_table(rsdp->XsdtPhysicalAddress, 2, ACPI_SIG_XSDT);
|
||||
if (xsdt == NULL) {
|
||||
if (bootverbose)
|
||||
printf("ACPI: Failed to map XSDT\n");
|
||||
return (0);
|
||||
}
|
||||
count = (xsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) /
|
||||
sizeof(UINT64);
|
||||
for (i = 0; i < count; i++)
|
||||
if (probe_table(xsdt->TableOffsetEntry[i], sig)) {
|
||||
addr = xsdt->TableOffsetEntry[i];
|
||||
break;
|
||||
}
|
||||
acpi_unmap_table(xsdt);
|
||||
} else {
|
||||
rsdt = map_table(rsdp->RsdtPhysicalAddress, 2, ACPI_SIG_RSDT);
|
||||
if (rsdt == NULL) {
|
||||
if (bootverbose)
|
||||
printf("ACPI: Failed to map RSDT\n");
|
||||
return (0);
|
||||
}
|
||||
count = (rsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) /
|
||||
sizeof(UINT32);
|
||||
for (i = 0; i < count; i++)
|
||||
if (probe_table(rsdt->TableOffsetEntry[i], sig)) {
|
||||
addr = rsdt->TableOffsetEntry[i];
|
||||
break;
|
||||
}
|
||||
acpi_unmap_table(rsdt);
|
||||
}
|
||||
pmap_unmapbios((vm_offset_t)rsdp, sizeof(ACPI_TABLE_RSDP));
|
||||
if (addr == 0) {
|
||||
if (bootverbose)
|
||||
printf("ACPI: No %s table found\n", sig);
|
||||
return (0);
|
||||
}
|
||||
if (bootverbose)
|
||||
printf("%s: Found table at 0x%jx\n", sig, (uintmax_t)addr);
|
||||
|
||||
/*
|
||||
* Verify that we can map the full table and that its checksum is
|
||||
* correct, etc.
|
||||
*/
|
||||
table = map_table(addr, 0, sig);
|
||||
if (table == NULL)
|
||||
return (0);
|
||||
acpi_unmap_table(table);
|
||||
|
||||
return (addr);
|
||||
}
|
||||
|
||||
/*
|
||||
* ACPI nexus(4) driver.
|
||||
*/
|
||||
|
@ -36,27 +36,19 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/smp.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_param.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
#include <machine/apicreg.h>
|
||||
#include <machine/frame.h>
|
||||
#include <machine/intr_machdep.h>
|
||||
#include <machine/apicvar.h>
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/specialreg.h>
|
||||
|
||||
#include <contrib/dev/acpica/include/acpi.h>
|
||||
#include <contrib/dev/acpica/include/accommon.h>
|
||||
#include <contrib/dev/acpica/include/actables.h>
|
||||
|
||||
#include <dev/acpica/acpivar.h>
|
||||
#include <dev/pci/pcivar.h>
|
||||
|
||||
typedef void madt_entry_handler(ACPI_SUBTABLE_HEADER *entry, void *arg);
|
||||
|
||||
/* These two arrays are indexed by APIC IDs. */
|
||||
struct ioapic_info {
|
||||
void *io_apic;
|
||||
@ -79,8 +71,6 @@ static enum intr_polarity interrupt_polarity(UINT16 IntiFlags, UINT8 Source);
|
||||
static enum intr_trigger interrupt_trigger(UINT16 IntiFlags, UINT8 Source);
|
||||
static int madt_find_cpu(u_int acpi_id, u_int *apic_id);
|
||||
static int madt_find_interrupt(int intr, void **apic, u_int *pin);
|
||||
static void *madt_map(vm_paddr_t pa, int offset, vm_offset_t length);
|
||||
static void *madt_map_table(vm_paddr_t pa, int offset, const char *sig);
|
||||
static void madt_parse_apics(ACPI_SUBTABLE_HEADER *entry, void *arg);
|
||||
static void madt_parse_interrupt_override(
|
||||
ACPI_MADT_INTERRUPT_OVERRIDE *intr);
|
||||
@ -92,13 +82,10 @@ static int madt_probe(void);
|
||||
static int madt_probe_cpus(void);
|
||||
static void madt_probe_cpus_handler(ACPI_SUBTABLE_HEADER *entry,
|
||||
void *arg __unused);
|
||||
static int madt_probe_table(vm_paddr_t address);
|
||||
static void madt_register(void *dummy);
|
||||
static int madt_setup_local(void);
|
||||
static int madt_setup_io(void);
|
||||
static void madt_unmap(void *data, vm_offset_t length);
|
||||
static void madt_unmap_table(void *table);
|
||||
static void madt_walk_table(madt_entry_handler *handler, void *arg);
|
||||
static void madt_walk_table(acpi_subtable_handler *handler, void *arg);
|
||||
|
||||
static struct apic_enumerator madt_enumerator = {
|
||||
"MADT",
|
||||
@ -108,87 +95,6 @@ static struct apic_enumerator madt_enumerator = {
|
||||
madt_setup_io
|
||||
};
|
||||
|
||||
/*
|
||||
* Code to abuse the crashdump map to map in the tables for the early
|
||||
* probe. We cheat and make the following assumptions about how we
|
||||
* use this KVA: pages 0 and 1 are used to map in the header of each
|
||||
* table found via the RSDT or XSDT and pages 2 to n are used to map
|
||||
* in the RSDT or XSDT. We have to use 2 pages for the table headers
|
||||
* in case a header spans a page boundary. The offset is in pages;
|
||||
* the length is in bytes.
|
||||
*/
|
||||
static void *
|
||||
madt_map(vm_paddr_t pa, int offset, vm_offset_t length)
|
||||
{
|
||||
vm_offset_t va, off;
|
||||
void *data;
|
||||
|
||||
off = pa & PAGE_MASK;
|
||||
length = roundup(length + off, PAGE_SIZE);
|
||||
pa = pa & PG_FRAME;
|
||||
va = (vm_offset_t)pmap_kenter_temporary(pa, offset) +
|
||||
(offset * PAGE_SIZE);
|
||||
data = (void *)(va + off);
|
||||
length -= PAGE_SIZE;
|
||||
while (length > 0) {
|
||||
va += PAGE_SIZE;
|
||||
pa += PAGE_SIZE;
|
||||
length -= PAGE_SIZE;
|
||||
pmap_kenter(va, pa);
|
||||
invlpg(va);
|
||||
}
|
||||
return (data);
|
||||
}
|
||||
|
||||
static void
|
||||
madt_unmap(void *data, vm_offset_t length)
|
||||
{
|
||||
vm_offset_t va, off;
|
||||
|
||||
va = (vm_offset_t)data;
|
||||
off = va & PAGE_MASK;
|
||||
length = roundup(length + off, PAGE_SIZE);
|
||||
va &= ~PAGE_MASK;
|
||||
while (length > 0) {
|
||||
pmap_kremove(va);
|
||||
invlpg(va);
|
||||
va += PAGE_SIZE;
|
||||
length -= PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static void *
|
||||
madt_map_table(vm_paddr_t pa, int offset, const char *sig)
|
||||
{
|
||||
ACPI_TABLE_HEADER *header;
|
||||
vm_offset_t length;
|
||||
void *table;
|
||||
|
||||
header = madt_map(pa, offset, sizeof(ACPI_TABLE_HEADER));
|
||||
if (strncmp(header->Signature, sig, ACPI_NAME_SIZE) != 0) {
|
||||
madt_unmap(header, sizeof(ACPI_TABLE_HEADER));
|
||||
return (NULL);
|
||||
}
|
||||
length = header->Length;
|
||||
madt_unmap(header, sizeof(ACPI_TABLE_HEADER));
|
||||
table = madt_map(pa, offset, length);
|
||||
if (ACPI_FAILURE(AcpiTbChecksum(table, length))) {
|
||||
if (bootverbose)
|
||||
printf("MADT: Failed checksum for table %s\n", sig);
|
||||
madt_unmap(table, length);
|
||||
return (NULL);
|
||||
}
|
||||
return (table);
|
||||
}
|
||||
|
||||
static void
|
||||
madt_unmap_table(void *table)
|
||||
{
|
||||
ACPI_TABLE_HEADER *header;
|
||||
|
||||
header = (ACPI_TABLE_HEADER *)table;
|
||||
madt_unmap(table, header->Length);
|
||||
}
|
||||
|
||||
/*
|
||||
* Look for an ACPI Multiple APIC Description Table ("APIC")
|
||||
@ -196,126 +102,13 @@ madt_unmap_table(void *table)
|
||||
static int
|
||||
madt_probe(void)
|
||||
{
|
||||
ACPI_PHYSICAL_ADDRESS rsdp_ptr;
|
||||
ACPI_TABLE_RSDP *rsdp;
|
||||
ACPI_TABLE_RSDT *rsdt;
|
||||
ACPI_TABLE_XSDT *xsdt;
|
||||
int i, count;
|
||||
|
||||
if (resource_disabled("acpi", 0))
|
||||
madt_physaddr = acpi_find_table(ACPI_SIG_MADT);
|
||||
if (madt_physaddr == 0)
|
||||
return (ENXIO);
|
||||
|
||||
/*
|
||||
* Map in the RSDP. Since ACPI uses AcpiOsMapMemory() which in turn
|
||||
* calls pmap_mapbios() to find the RSDP, we assume that we can use
|
||||
* pmap_mapbios() to map the RSDP.
|
||||
*/
|
||||
if ((rsdp_ptr = AcpiOsGetRootPointer()) == 0)
|
||||
return (ENXIO);
|
||||
rsdp = pmap_mapbios(rsdp_ptr, sizeof(ACPI_TABLE_RSDP));
|
||||
if (rsdp == NULL) {
|
||||
if (bootverbose)
|
||||
printf("MADT: Failed to map RSDP\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/*
|
||||
* For ACPI >= 2.0, use the XSDT if it is available.
|
||||
* Otherwise, use the RSDT. We map the XSDT or RSDT at page 1
|
||||
* in the crashdump area. Page 0 is used to map in the
|
||||
* headers of candidate ACPI tables.
|
||||
*/
|
||||
if (rsdp->Revision >= 2 && rsdp->XsdtPhysicalAddress != 0) {
|
||||
/*
|
||||
* AcpiOsGetRootPointer only verifies the checksum for
|
||||
* the version 1.0 portion of the RSDP. Version 2.0 has
|
||||
* an additional checksum that we verify first.
|
||||
*/
|
||||
if (AcpiTbChecksum((UINT8 *)rsdp, ACPI_RSDP_XCHECKSUM_LENGTH)) {
|
||||
if (bootverbose)
|
||||
printf("MADT: RSDP failed extended checksum\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
xsdt = madt_map_table(rsdp->XsdtPhysicalAddress, 2,
|
||||
ACPI_SIG_XSDT);
|
||||
if (xsdt == NULL) {
|
||||
if (bootverbose)
|
||||
printf("MADT: Failed to map XSDT\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
count = (xsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) /
|
||||
sizeof(UINT64);
|
||||
for (i = 0; i < count; i++)
|
||||
if (madt_probe_table(xsdt->TableOffsetEntry[i]))
|
||||
break;
|
||||
madt_unmap_table(xsdt);
|
||||
} else {
|
||||
rsdt = madt_map_table(rsdp->RsdtPhysicalAddress, 2,
|
||||
ACPI_SIG_RSDT);
|
||||
if (rsdt == NULL) {
|
||||
if (bootverbose)
|
||||
printf("MADT: Failed to map RSDT\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
count = (rsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) /
|
||||
sizeof(UINT32);
|
||||
for (i = 0; i < count; i++)
|
||||
if (madt_probe_table(rsdt->TableOffsetEntry[i]))
|
||||
break;
|
||||
madt_unmap_table(rsdt);
|
||||
}
|
||||
pmap_unmapbios((vm_offset_t)rsdp, sizeof(ACPI_TABLE_RSDP));
|
||||
if (madt_physaddr == 0) {
|
||||
if (bootverbose)
|
||||
printf("MADT: No MADT table found\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
if (bootverbose)
|
||||
printf("MADT: Found table at 0x%jx\n",
|
||||
(uintmax_t)madt_physaddr);
|
||||
|
||||
/*
|
||||
* Verify that we can map the full table and that its checksum is
|
||||
* correct, etc.
|
||||
*/
|
||||
madt = madt_map_table(madt_physaddr, 0, ACPI_SIG_MADT);
|
||||
if (madt == NULL)
|
||||
return (ENXIO);
|
||||
madt_unmap_table(madt);
|
||||
madt = NULL;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* See if a given ACPI table is the MADT.
|
||||
*/
|
||||
static int
|
||||
madt_probe_table(vm_paddr_t address)
|
||||
{
|
||||
ACPI_TABLE_HEADER *table;
|
||||
|
||||
table = madt_map(address, 0, sizeof(ACPI_TABLE_HEADER));
|
||||
if (table == NULL) {
|
||||
if (bootverbose)
|
||||
printf("MADT: Failed to map table at 0x%jx\n",
|
||||
(uintmax_t)address);
|
||||
return (0);
|
||||
}
|
||||
if (bootverbose)
|
||||
printf("Table '%.4s' at 0x%jx\n", table->Signature,
|
||||
(uintmax_t)address);
|
||||
|
||||
if (strncmp(table->Signature, ACPI_SIG_MADT, ACPI_NAME_SIZE) != 0) {
|
||||
madt_unmap(table, sizeof(ACPI_TABLE_HEADER));
|
||||
return (0);
|
||||
}
|
||||
madt_physaddr = address;
|
||||
madt_length = table->Length;
|
||||
madt_unmap(table, sizeof(ACPI_TABLE_HEADER));
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Run through the MP table enumerating CPUs.
|
||||
*/
|
||||
@ -323,10 +116,11 @@ static int
|
||||
madt_probe_cpus(void)
|
||||
{
|
||||
|
||||
madt = madt_map_table(madt_physaddr, 0, ACPI_SIG_MADT);
|
||||
madt = acpi_map_table(madt_physaddr, ACPI_SIG_MADT);
|
||||
madt_length = madt->Header.Length;
|
||||
KASSERT(madt != NULL, ("Unable to re-map MADT"));
|
||||
madt_walk_table(madt_probe_cpus_handler, NULL);
|
||||
madt_unmap_table(madt);
|
||||
acpi_unmap_table(madt);
|
||||
madt = NULL;
|
||||
return (0);
|
||||
}
|
||||
@ -416,17 +210,11 @@ SYSINIT(madt_register, SI_SUB_CPU - 1, SI_ORDER_SECOND, madt_register, NULL);
|
||||
* Call the handler routine for each entry in the MADT table.
|
||||
*/
|
||||
static void
|
||||
madt_walk_table(madt_entry_handler *handler, void *arg)
|
||||
madt_walk_table(acpi_subtable_handler *handler, void *arg)
|
||||
{
|
||||
ACPI_SUBTABLE_HEADER *entry;
|
||||
u_char *p, *end;
|
||||
|
||||
end = (u_char *)(madt) + madt->Header.Length;
|
||||
for (p = (u_char *)(madt + 1); p < end; ) {
|
||||
entry = (ACPI_SUBTABLE_HEADER *)p;
|
||||
handler(entry, arg);
|
||||
p += entry->Length;
|
||||
}
|
||||
acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
|
||||
handler, arg);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -97,5 +97,8 @@ extern int acpi_release_global_lock(uint32_t *lock);
|
||||
|
||||
void acpi_SetDefaultIntrModel(int model);
|
||||
void acpi_cpu_c1(void);
|
||||
void *acpi_map_table(vm_paddr_t pa, const char *sig);
|
||||
void acpi_unmap_table(void *table);
|
||||
vm_paddr_t acpi_find_table(const char *sig);
|
||||
|
||||
#endif /* __ACPICA_MACHDEP_H__ */
|
||||
|
Loading…
x
Reference in New Issue
Block a user