Skip to content

Commit

Permalink
ACPI: Add interfaces to parse IOAPIC ID for IOAPIC hotplug
Browse files Browse the repository at this point in the history
We need to parse APIC ID for IOAPIC registration for IOAPIC hotplug.
ACPI _MAT method and MADT table are used to figure out IOAPIC ID, just
like parsing CPU APIC ID for CPU hotplug.

[ tglx: Fixed docbook comment ]

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Len Brown <lenb@kernel.org>
Link: http://lkml.kernel.org/r/1414387308-27148-8-git-send-email-jiang.liu@linux.intel.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
  • Loading branch information
Yinghai Lu authored and Rafael J. Wysocki committed Feb 5, 2015
1 parent b4b55cd commit ecf5636
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 9 deletions.
123 changes: 114 additions & 9 deletions drivers/acpi/processor_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
*
* Alex Chiang <achiang@hp.com>
* - Unified x86/ia64 implementations
*
* I/O APIC hotplug support
* Yinghai Lu <yinghai@kernel.org>
* Jiang Liu <jiang.liu@intel.com>
*/
#include <linux/export.h>
#include <linux/acpi.h>
Expand All @@ -12,6 +16,21 @@
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
ACPI_MODULE_NAME("processor_core");

static struct acpi_table_madt *get_madt_table(void)
{
static struct acpi_table_madt *madt;
static int read_madt;

if (!read_madt) {
if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0,
(struct acpi_table_header **)&madt)))
madt = NULL;
read_madt++;
}

return madt;
}

static int map_lapic_id(struct acpi_subtable_header *entry,
u32 acpi_id, int *apic_id)
{
Expand Down Expand Up @@ -67,17 +86,10 @@ static int map_lsapic_id(struct acpi_subtable_header *entry,
static int map_madt_entry(int type, u32 acpi_id)
{
unsigned long madt_end, entry;
static struct acpi_table_madt *madt;
static int read_madt;
int phys_id = -1; /* CPU hardware ID */
struct acpi_table_madt *madt;

if (!read_madt) {
if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0,
(struct acpi_table_header **)&madt)))
madt = NULL;
read_madt++;
}

madt = get_madt_table();
if (!madt)
return phys_id;

Expand Down Expand Up @@ -203,3 +215,96 @@ int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)
return acpi_map_cpuid(phys_id, acpi_id);
}
EXPORT_SYMBOL_GPL(acpi_get_cpuid);

#ifdef CONFIG_ACPI_HOTPLUG_IOAPIC
static int get_ioapic_id(struct acpi_subtable_header *entry, u32 gsi_base,
u64 *phys_addr, int *ioapic_id)
{
struct acpi_madt_io_apic *ioapic = (struct acpi_madt_io_apic *)entry;

if (ioapic->global_irq_base != gsi_base)
return 0;

*phys_addr = ioapic->address;
*ioapic_id = ioapic->id;
return 1;
}

static int parse_madt_ioapic_entry(u32 gsi_base, u64 *phys_addr)
{
struct acpi_subtable_header *hdr;
unsigned long madt_end, entry;
struct acpi_table_madt *madt;
int apic_id = -1;

madt = get_madt_table();
if (!madt)
return apic_id;

entry = (unsigned long)madt;
madt_end = entry + madt->header.length;

/* Parse all entries looking for a match. */
entry += sizeof(struct acpi_table_madt);
while (entry + sizeof(struct acpi_subtable_header) < madt_end) {
hdr = (struct acpi_subtable_header *)entry;
if (hdr->type == ACPI_MADT_TYPE_IO_APIC &&
get_ioapic_id(hdr, gsi_base, phys_addr, &apic_id))
break;
else
entry += hdr->length;
}

return apic_id;
}

static int parse_mat_ioapic_entry(acpi_handle handle, u32 gsi_base,
u64 *phys_addr)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_subtable_header *header;
union acpi_object *obj;
int apic_id = -1;

if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
goto exit;

if (!buffer.length || !buffer.pointer)
goto exit;

obj = buffer.pointer;
if (obj->type != ACPI_TYPE_BUFFER ||
obj->buffer.length < sizeof(struct acpi_subtable_header))
goto exit;

header = (struct acpi_subtable_header *)obj->buffer.pointer;
if (header->type == ACPI_MADT_TYPE_IO_APIC)
get_ioapic_id(header, gsi_base, phys_addr, &apic_id);

exit:
kfree(buffer.pointer);
return apic_id;
}

/**
* acpi_get_ioapic_id - Get IOAPIC ID and physical address matching @gsi_base
* @handle: ACPI object for IOAPIC device
* @gsi_base: GSI base to match with
* @phys_addr: Pointer to store physical address of matching IOAPIC record
*
* Walk resources returned by ACPI_MAT method, then ACPI MADT table, to search
* for an ACPI IOAPIC record matching @gsi_base.
* Return IOAPIC id and store physical address in @phys_addr if found a match,
* otherwise return <0.
*/
int acpi_get_ioapic_id(acpi_handle handle, u32 gsi_base, u64 *phys_addr)
{
int apic_id;

apic_id = parse_mat_ioapic_entry(handle, gsi_base, phys_addr);
if (apic_id == -1)
apic_id = parse_madt_ioapic_entry(gsi_base, phys_addr);

return apic_id;
}
#endif /* CONFIG_ACPI_HOTPLUG_IOAPIC */
4 changes: 4 additions & 0 deletions include/linux/acpi.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ int acpi_map_cpu(acpi_handle handle, int physid, int *pcpu);
int acpi_unmap_cpu(int cpu);
#endif /* CONFIG_ACPI_HOTPLUG_CPU */

#ifdef CONFIG_ACPI_HOTPLUG_IOAPIC
int acpi_get_ioapic_id(acpi_handle handle, u32 gsi_base, u64 *phys_addr);
#endif

int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base);
int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base);
int acpi_ioapic_registered(acpi_handle handle, u32 gsi_base);
Expand Down

0 comments on commit ecf5636

Please sign in to comment.