int __init acpi_table_parse_entries(char *id, unsigned long table_size, int entry_id, acpi_table_entry_handler handler, unsigned int max_entries) { struct acpi_table_header *table_header = NULL; struct acpi_subtable_header *entry; unsigned int count = 0; unsigned long table_end; acpi_size tbl_size; if (acpi_disabled && !acpi_ht) return -ENODEV; if (!handler) return -EINVAL; if (strncmp(id, ACPI_SIG_MADT, 4) == 0) acpi_get_table_with_size(id, acpi_apic_instance, &table_header, &tbl_size); else acpi_get_table_with_size(id, 0, &table_header, &tbl_size); if (!table_header) { printk(KERN_WARNING PREFIX "%4.4s not present\n", id); return -ENODEV; } table_end = (unsigned long)table_header + table_header->length; /* Parse all entries looking for a match. */ entry = (struct acpi_subtable_header *) ((unsigned long)table_header + table_size); while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) < table_end) { if (entry->type == entry_id && (!max_entries || count++ < max_entries)) if (handler(entry, table_end)) { early_acpi_os_unmap_memory((char *)table_header, tbl_size); return -EINVAL; } entry = (struct acpi_subtable_header *) ((unsigned long)entry + entry->length); } if (max_entries && count > max_entries) { printk(KERN_WARNING PREFIX "[%4.4s:0x%02x] ignored %i entries of " "%i found\n", id, entry_id, count - max_entries, count); } early_acpi_os_unmap_memory((char *)table_header, tbl_size); return count; }
int __init acpi_table_parse_entries(char *id, unsigned long table_size, int entry_id, acpi_tbl_entry_handler handler, unsigned int max_entries) { struct acpi_table_header *table_header = NULL; acpi_size tbl_size; int count; u32 instance = 0; if (acpi_disabled) return -ENODEV; if (!id || !handler) return -EINVAL; if (!strncmp(id, ACPI_SIG_MADT, 4)) instance = acpi_apic_instance; acpi_get_table_with_size(id, instance, &table_header, &tbl_size); if (!table_header) { pr_warn("%4.4s not present\n", id); return -ENODEV; } count = acpi_parse_entries(id, table_size, handler, table_header, entry_id, max_entries); early_acpi_os_unmap_memory((char *)table_header, tbl_size); return count; }
/** * acpi_table_parse - find table with @id, run @handler on it * * @id: table id to find * @handler: handler to run * * Scan the ACPI System Descriptor Table (STD) for a table matching @id, * run @handler on it. Return 0 if table found, return on if not. */ int acpi_table_parse (char *id, acpi_table_handler handler, void * arg) { struct acpi_table_header *table = NULL; acpi_size tbl_size; if (acpi_disabled) { //printk("[ACPI DISABLED]\n"); return -ENODEV; } if (!handler) { return -EINVAL; } acpi_get_table_with_size(id, 0, &table, &tbl_size); if (table) { handler(table, arg); //early_acpi_os_unmap_memory(table, tbl_size); return 0; } else { return 1; } }
static int __init find_unisys_acpi_oem_table(unsigned long *oem_addr) { struct acpi_table_header *header = NULL; struct es7000_oem_table *table; acpi_size tbl_size; acpi_status ret; int i = 0; for (;;) { ret = acpi_get_table_with_size("OEM1", i++, &header, &tbl_size); if (!ACPI_SUCCESS(ret)) return -1; if (!memcmp((char *) &header->oem_id, "UNISYS", 6)) break; early_acpi_os_unmap_memory(header, tbl_size); } table = (void *)header; oem_addrX = table->OEMTableAddr; oem_size = table->OEMTableSize; early_acpi_os_unmap_memory(header, tbl_size); *oem_addr = (unsigned long)__acpi_map_table(oem_addrX, oem_size); return 0; }
static bool radeon_acpi_vfct_bios(struct radeon_device *rdev) { bool ret = false; struct acpi_table_header *hdr; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)) acpi_size tbl_size; #else /* acpi_get_table_with_size() not exported on kernels < 3.6 */ acpi_size tbl_size = 0x7fffffff; #endif UEFI_ACPI_VFCT *vfct; GOP_VBIOS_CONTENT *vbios; VFCT_IMAGE_HEADER *vhdr; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)) if (!ACPI_SUCCESS(acpi_get_table_with_size("VFCT", 1, &hdr, &tbl_size))) #else if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr))) #endif return false; if (tbl_size < sizeof(UEFI_ACPI_VFCT)) { DRM_ERROR("ACPI VFCT table present but broken (too short #1)\n"); goto out_unmap; } vfct = (UEFI_ACPI_VFCT *)hdr; if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) > tbl_size) { DRM_ERROR("ACPI VFCT table present but broken (too short #2)\n"); goto out_unmap; } vbios = (GOP_VBIOS_CONTENT *)((char *)hdr + vfct->VBIOSImageOffset); vhdr = &vbios->VbiosHeader; DRM_INFO("ACPI VFCT contains a BIOS for %02x:%02x.%d %04x:%04x, size %d\n", vhdr->PCIBus, vhdr->PCIDevice, vhdr->PCIFunction, vhdr->VendorID, vhdr->DeviceID, vhdr->ImageLength); if (vhdr->PCIBus != rdev->pdev->bus->number || vhdr->PCIDevice != PCI_SLOT(rdev->pdev->devfn) || vhdr->PCIFunction != PCI_FUNC(rdev->pdev->devfn) || vhdr->VendorID != rdev->pdev->vendor || vhdr->DeviceID != rdev->pdev->device) { DRM_INFO("ACPI VFCT table is not for this card\n"); goto out_unmap; }; if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) + vhdr->ImageLength > tbl_size) { DRM_ERROR("ACPI VFCT image truncated\n"); goto out_unmap; } rdev->bios = kmemdup(&vbios->VbiosContent, vhdr->ImageLength, GFP_KERNEL); ret = !!rdev->bios; out_unmap: return ret; }
acpi_status acpi_get_table(char *signature, u32 instance, struct acpi_table_header **out_table) { acpi_size tbl_size; return acpi_get_table_with_size(signature, instance, out_table, &tbl_size); }
/** * acpi_table_parse - find table with @id, run @handler on it * * @id: table id to find * @handler: handler to run * * Scan the ACPI System Descriptor Table (STD) for a table matching @id, * run @handler on it. Return 0 if table found, return on if not. */ int __init acpi_table_parse(char *id, acpi_table_handler handler) { struct acpi_table_header *table = NULL; acpi_size tbl_size; if (!handler) return -EINVAL; if (strncmp(id, ACPI_SIG_MADT, 4) == 0) acpi_get_table_with_size(id, acpi_apic_instance, &table, &tbl_size); else acpi_get_table_with_size(id, 0, &table, &tbl_size); if (table) { handler(table); early_acpi_os_unmap_memory(table, tbl_size); return 0; } else return 1; }
/** * acpi_pcc_probe - Parse the ACPI tree for the PCCT. * * Return: 0 for Success, else errno. */ static int __init acpi_pcc_probe(void) { acpi_size pcct_tbl_header_size; struct acpi_table_header *pcct_tbl; struct acpi_subtable_header *pcct_entry; int count, i; acpi_status status = AE_OK; /* Search for PCCT */ status = acpi_get_table_with_size(ACPI_SIG_PCCT, 0, &pcct_tbl, &pcct_tbl_header_size); if (ACPI_FAILURE(status) || !pcct_tbl) { pr_warn("PCCT header not found.\n"); return -ENODEV; } count = acpi_table_parse_entries(ACPI_SIG_PCCT, sizeof(struct acpi_table_pcct), ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE, parse_pcc_subspace, MAX_PCC_SUBSPACES); if (count <= 0) { pr_err("Error parsing PCC subspaces from PCCT\n"); return -EINVAL; } pcc_mbox_channels = kzalloc(sizeof(struct mbox_chan) * count, GFP_KERNEL); if (!pcc_mbox_channels) { pr_err("Could not allocate space for PCC mbox channels\n"); return -ENOMEM; } /* Point to the first PCC subspace entry */ pcct_entry = (struct acpi_subtable_header *) ( (unsigned long) pcct_tbl + sizeof(struct acpi_table_pcct)); for (i = 0; i < count; i++) { pcc_mbox_channels[i].con_priv = pcct_entry; pcct_entry = (struct acpi_subtable_header *) ((unsigned long) pcct_entry + pcct_entry->length); } pcc_mbox_ctrl.num_chans = count; pr_info("Detected %d PCC Subspaces\n", pcc_mbox_ctrl.num_chans); return 0; }
phys_cpuid_t __init acpi_map_madt_entry(u32 acpi_id) { struct acpi_table_madt *madt = NULL; acpi_size tbl_size; phys_cpuid_t rv; acpi_get_table_with_size(ACPI_SIG_MADT, 0, (struct acpi_table_header **)&madt, &tbl_size); if (!madt) return PHYS_CPUID_INVALID; rv = map_madt_
/* * acpi_fadt_sanity_check() - Check FADT presence and carry out sanity * checks on it * * Return 0 on success, <0 on failure */ static int __init acpi_fadt_sanity_check(void) { struct acpi_table_header *table; struct acpi_table_fadt *fadt; acpi_status status; acpi_size tbl_size; int ret = 0; /* * FADT is required on arm64; retrieve it to check its presence * and carry out revision and ACPI HW reduced compliancy tests */ status = acpi_get_table_with_size(ACPI_SIG_FADT, 0, &table, &tbl_size); if (ACPI_FAILURE(status)) { const char *msg = acpi_format_exception(status); pr_err("Failed to get FADT table, %s\n", msg); return -ENODEV; } fadt = (struct acpi_table_fadt *)table; /* * Revision in table header is the FADT Major revision, and there * is a minor revision of FADT which was introduced by ACPI 5.1, * we only deal with ACPI 5.1 or newer revision to get GIC and SMP * boot protocol configuration data. */ if (table->revision < 5 || (table->revision == 5 && fadt->minor_revision < 1)) { pr_err("Unsupported FADT revision %d.%d, should be 5.1+\n", table->revision, fadt->minor_revision); ret = -EINVAL; goto out; } if (!(fadt->flags & ACPI_FADT_HW_REDUCED)) { pr_err("FADT not ACPI hardware reduced compliant\n"); ret = -EINVAL; } out: /* * acpi_get_table_with_size() creates FADT table mapping that * should be released after parsing and before resuming boot */ early_acpi_os_unmap_memory(table, tbl_size); return ret; }
static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev) { bool ret = false; struct acpi_table_header *hdr; acpi_size tbl_size; UEFI_ACPI_VFCT *vfct; GOP_VBIOS_CONTENT *vbios; VFCT_IMAGE_HEADER *vhdr; if (!ACPI_SUCCESS(acpi_get_table_with_size("VFCT", 1, &hdr, &tbl_size))) return false; if (tbl_size < sizeof(UEFI_ACPI_VFCT)) { DRM_ERROR("ACPI VFCT table present but broken (too short #1)\n"); goto out_unmap; } vfct = (UEFI_ACPI_VFCT *)hdr; if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) > tbl_size) { DRM_ERROR("ACPI VFCT table present but broken (too short #2)\n"); goto out_unmap; } vbios = (GOP_VBIOS_CONTENT *)((char *)hdr + vfct->VBIOSImageOffset); vhdr = &vbios->VbiosHeader; DRM_INFO("ACPI VFCT contains a BIOS for %02x:%02x.%d %04x:%04x, size %d\n", vhdr->PCIBus, vhdr->PCIDevice, vhdr->PCIFunction, vhdr->VendorID, vhdr->DeviceID, vhdr->ImageLength); if (vhdr->PCIBus != adev->pdev->bus->number || vhdr->PCIDevice != PCI_SLOT(adev->pdev->devfn) || vhdr->PCIFunction != PCI_FUNC(adev->pdev->devfn) || vhdr->VendorID != adev->pdev->vendor || vhdr->DeviceID != adev->pdev->device) { DRM_INFO("ACPI VFCT table is not for this card\n"); goto out_unmap; } if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) + vhdr->ImageLength > tbl_size) { DRM_ERROR("ACPI VFCT image truncated\n"); goto out_unmap; } adev->bios = kmemdup(&vbios->VbiosContent, vhdr->ImageLength, GFP_KERNEL); adev->bios_size = vhdr->ImageLength; ret = !!adev->bios; out_unmap: return ret; }
void* KCL_ACPI_GetVfctBios(unsigned long *size) { struct acpi_table_header *hdr; acpi_size tbl_size ; #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,3) if (!ACPI_SUCCESS(acpi_get_table_with_size("VFCT", 1, &hdr, &tbl_size))) #else tbl_size = 0x7fffffff; if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr))) #endif { return NULL; } *size = tbl_size; return hdr; }
/* * The BIOS is supposed to supply a single APIC/MADT, * but some report two. Provide a knob to use either. * (don't you wish instance 0 and 1 were not the same?) */ static void __init check_multiple_madt(void) { struct acpi_table_header *table = NULL; acpi_size tbl_size; acpi_get_table_with_size(ACPI_SIG_MADT, 2, &table, &tbl_size); if (table) { pr_warn("BIOS bug: multiple APIC/MADT found, using %d\n", acpi_apic_instance); pr_warn("If \"acpi_apic_instance=%d\" works better, " "notify [email protected]\n", acpi_apic_instance ? 0 : 2); early_acpi_os_unmap_memory(table, tbl_size); } else acpi_apic_instance = 0; return; }
void __init acpi_gic_init(void) { struct acpi_table_header *table; acpi_status status; acpi_size tbl_size; int err; if (acpi_disabled) return; status = acpi_get_table_with_size(ACPI_SIG_MADT, 0, &table, &tbl_size); if (ACPI_FAILURE(status)) { const char *msg = acpi_format_exception(status); pr_err("Failed to get MADT table, %s\n", msg); return; } err = gic_v2_acpi_init(table); if (err) pr_err("Failed to initialize GIC IRQ controller"); early_acpi_os_unmap_memory((char *)table, tbl_size); }
/** * acpi_pcc_probe - Parse the ACPI tree for the PCCT. * * Return: 0 for Success, else errno. */ static int __init acpi_pcc_probe(void) { acpi_size pcct_tbl_header_size; struct acpi_table_header *pcct_tbl; struct acpi_subtable_header *pcct_entry; int count, i; acpi_status status = AE_OK; /* Search for PCCT */ status = acpi_get_table_with_size(ACPI_SIG_PCCT, 0, &pcct_tbl, &pcct_tbl_header_size); if (ACPI_FAILURE(status) || !pcct_tbl) { pr_warn("PCCT header not found.\n"); return -ENODEV; } count = acpi_table_parse_entries(ACPI_SIG_PCCT, sizeof(struct acpi_table_pcct), ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE, parse_pcc_subspace, MAX_PCC_SUBSPACES); if (count <= 0) { pr_err("Error parsing PCC subspaces from PCCT\n"); return -EINVAL; } pcc_mbox_channels = kzalloc(sizeof(struct mbox_chan) * count, GFP_KERNEL); if (!pcc_mbox_channels) { pr_err("Could not allocate space for PCC mbox channels\n"); return -ENOMEM; } pcc_doorbell_vaddr = kcalloc(count, sizeof(void *), GFP_KERNEL); if (!pcc_doorbell_vaddr) { kfree(pcc_mbox_channels); return -ENOMEM; } /* Point to the first PCC subspace entry */ pcct_entry = (struct acpi_subtable_header *) ( (unsigned long) pcct_tbl + sizeof(struct acpi_table_pcct)); for (i = 0; i < count; i++) { struct acpi_generic_address *db_reg; struct acpi_pcct_hw_reduced *pcct_ss; pcc_mbox_channels[i].con_priv = pcct_entry; pcct_entry = (struct acpi_subtable_header *) ((unsigned long) pcct_entry + pcct_entry->length); /* If doorbell is in system memory cache the virt address */ pcct_ss = (struct acpi_pcct_hw_reduced *)pcct_entry; db_reg = &pcct_ss->doorbell_register; if (db_reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) pcc_doorbell_vaddr[i] = acpi_os_ioremap(db_reg->address, db_reg->bit_width/8); } pcc_mbox_ctrl.num_chans = count; pr_info("Detected %d PCC Subspaces\n", pcc_mbox_ctrl.num_chans); return 0; }
/** * parse_spcr() - parse ACPI SPCR table and add preferred console * * @earlycon: set up earlycon for the console specified by the table * * For the architectures with support for ACPI, CONFIG_ACPI_SPCR_TABLE may be * defined to parse ACPI SPCR table. As a result of the parsing preferred * console is registered and if @earlycon is true, earlycon is set up. * * When CONFIG_ACPI_SPCR_TABLE is defined, this function should should be called * from arch inintialization code as soon as the DT/ACPI decision is made. * */ int __init parse_spcr(bool earlycon) { static char opts[64]; struct acpi_table_spcr *table; acpi_size table_size; acpi_status status; char *uart; char *iotype; int baud_rate; int err; if (acpi_disabled) return -ENODEV; status = acpi_get_table_with_size(ACPI_SIG_SPCR, 0, (struct acpi_table_header **)&table, &table_size); if (ACPI_FAILURE(status)) return -ENOENT; if (table->header.revision < 2) { err = -ENOENT; pr_err("wrong table version\n"); goto done; } iotype = table->serial_port.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY ? "mmio" : "io"; switch (table->interface_type) { case ACPI_DBG2_ARM_SBSA_32BIT: iotype = "mmio32"; /* fall through */ case ACPI_DBG2_ARM_PL011: case ACPI_DBG2_ARM_SBSA_GENERIC: case ACPI_DBG2_BCM2835: uart = "pl011"; break; case ACPI_DBG2_16550_COMPATIBLE: case ACPI_DBG2_16550_SUBSET: if (table->serial_port.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY && table->serial_port.bit_width == 32) iotype = "mmio32"; uart = "uart"; break; default: err = -ENOENT; goto done; } switch (table->baud_rate) { case 3: baud_rate = 9600; break; case 4: baud_rate = 19200; break; case 6: baud_rate = 57600; break; case 7: baud_rate = 115200; break; default: err = -ENOENT; goto done; } snprintf(opts, sizeof(opts), "%s,%s,0x%llx", uart, iotype, table->serial_port.address); pr_info("console: %s", opts); if (earlycon) setup_earlycon(opts); err = add_preferred_console(uart, 0, opts + strlen(uart) + 1); done: early_acpi_os_unmap_memory((void __iomem *)table, table_size); return err; }