summaryrefslogtreecommitdiffstats
path: root/sys/amd64/acpica
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2009-09-23 15:42:35 +0000
committerjhb <jhb@FreeBSD.org>2009-09-23 15:42:35 +0000
commit3f9fa059d728aa84a279591b28ace3f492381d74 (patch)
tree819cd5a8387fa2c662b3e881f117275815b84f54 /sys/amd64/acpica
parentdb540265723b7c60fa06a887e9443e08f2bc2fc0 (diff)
downloadFreeBSD-src-3f9fa059d728aa84a279591b28ace3f492381d74.zip
FreeBSD-src-3f9fa059d728aa84a279591b28ace3f492381d74.tar.gz
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.
Diffstat (limited to 'sys/amd64/acpica')
-rw-r--r--sys/amd64/acpica/acpi_machdep.c244
-rw-r--r--sys/amd64/acpica/madt.c233
2 files changed, 254 insertions, 223 deletions
diff --git a/sys/amd64/acpica/acpi_machdep.c b/sys/amd64/acpica/acpi_machdep.c
index b902c12..0d866e8 100644
--- a/sys/amd64/acpica/acpi_machdep.c
+++ b/sys/amd64/acpica/acpi_machdep.c
@@ -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>
@@ -100,6 +104,246 @@ acpi_cpu_c1()
}
/*
+ * 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.
*/
static int
diff --git a/sys/amd64/acpica/madt.c b/sys/amd64/acpica/madt.c
index b27f8e4..a409682 100644
--- a/sys/amd64/acpica/madt.c
+++ b/sys/amd64/acpica/madt.c
@@ -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",
@@ -109,224 +96,30 @@ static struct apic_enumerator madt_enumerator = {
};
/*
- * 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.
*/
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
OpenPOWER on IntegriCloud