[RFC Patch V2 16/16] x86, irq, ACPI: implement ACPI driver to support IOAPIC hotplug
Enable support of IOAPIC hotplug by: 1) reintroducing ACPI based IOAPIC driver 2) enhance pci_root driver to hook hotplug events The ACPI IOAPIC driver is always enabled if system supports all of ACPI, PCI and IOAPIC. Signed-off-by: Jiang Liu --- drivers/acpi/Kconfig|6 ++ drivers/acpi/Makefile |1 + drivers/acpi/internal.h |7 ++ drivers/acpi/ioapic.c | 231 +++ drivers/acpi/pci_root.c |3 + 5 files changed, 248 insertions(+) create mode 100644 drivers/acpi/ioapic.c diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index ab686b310100..2d0ed9da6fea 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -292,6 +292,12 @@ config ACPI_HOTPLUG_MEMORY To compile this driver as a module, choose M here: the module will be called acpi_memhotplug. +config ACPI_HOTPLUG_IOAPIC + bool + depends on PCI + depends on X86_IO_APIC + default y + config ACPI_SBS tristate "Smart Battery System" depends on X86 diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index d922febd9164..b85b226a7f49 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -66,6 +66,7 @@ obj-$(CONFIG_ACPI_PROCESSOR) += processor.o obj-$(CONFIG_ACPI_CONTAINER) += container.o obj-$(CONFIG_ACPI_THERMAL) += thermal.o obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o +obj-$(CONFIG_ACPI_HOTPLUG_IOAPIC) += ioapic.o obj-$(CONFIG_ACPI_BATTERY) += battery.o obj-$(CONFIG_ACPI_SBS) += sbshc.o obj-$(CONFIG_ACPI_SBS) += sbs.o diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 957391306cbf..e8023cd81da3 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -52,6 +52,13 @@ void acpi_memory_hotplug_init(void); #else static inline void acpi_memory_hotplug_init(void) {} #endif +#ifdef CONFIG_ACPI_HOTPLUG_IOAPIC +int acpi_ioapic_add(struct acpi_pci_root *root); +int acpi_ioapic_remove(struct acpi_pci_root *root); +#else +static inline int acpi_ioapic_add(struct acpi_pci_root *root) { return 0; } +static inline int acpi_ioapic_remove(struct acpi_pci_root *root) { return 0; } +#endif #ifdef CONFIG_X86 void acpi_cmos_rtc_init(void); #else diff --git a/drivers/acpi/ioapic.c b/drivers/acpi/ioapic.c new file mode 100644 index ..3c9442899782 --- /dev/null +++ b/drivers/acpi/ioapic.c @@ -0,0 +1,231 @@ +/* + * IOAPIC/IOxAPIC/IOSAPIC driver + * + * Copyright (C) 2009 Fujitsu Limited. + * (c) Copyright 2009 Hewlett-Packard Development Company, L.P. + * + * Copyright (C) 2014 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Based on original drivers/pci/ioapic.c + * Yinghai Lu + * Jiang Liu + */ + +/* + * This driver manages I/O APICs added by hotplug after boot. + * We try to claim all I/O APIC devices, but those present at boot were + * registered when we parsed the ACPI MADT, so we'll fail when we try to + * re-register them. + */ + +#define pr_fmt(fmt) "ACPI : IOAPIC: " fmt + +#include +#include +#include +#include + +struct acpi_pci_ioapic { + acpi_handle root_handle; + acpi_handle handle; + u32 gsi_base; + struct resource res; + struct pci_dev *pdev; + struct list_head list; +}; + +static LIST_HEAD(ioapic_list); +static DEFINE_MUTEX(ioapic_list_lock); + +static acpi_status setup_res(struct acpi_resource *acpi_res, void *data) +{ + struct resource *res = data; + struct acpi_resource_address64 addr; + acpi_status status; + + status = acpi_mem_addr_resource_to_address64(acpi_res, ); + if (!ACPI_SUCCESS(status)) + return AE_OK; + + if (addr.resource_type != ACPI_MEMORY_RANGE || + addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY) + return AE_OK; + + res->flags = IORESOURCE_MEM; + res->start = addr.minimum + addr.translation_offset; + res->end = addr.maximum + addr.translation_offset; + + return AE_OK; +} + +static bool acpi_is_ioapic(acpi_handle handle, char **type) +{ + acpi_status status; + struct acpi_device_info *info; + char *hid = NULL; + bool match = false; + + if (!acpi_has_method(handle, "_GSB")) + return false; + + status = acpi_get_object_info(handle, ); + if (ACPI_SUCCESS(status)) { + if (info->valid & ACPI_VALID_HID) + hid = info->hardware_id.string; + if (hid) { + if (strcmp(hid, "ACPI0009") == 0) { + *type = "IOxAPIC"; + match = true; + } else if (strcmp(hid, "ACPI000A") == 0) { + *type = "IOAPIC"; + match =
[RFC Patch V2 16/16] x86, irq, ACPI: implement ACPI driver to support IOAPIC hotplug
Enable support of IOAPIC hotplug by: 1) reintroducing ACPI based IOAPIC driver 2) enhance pci_root driver to hook hotplug events The ACPI IOAPIC driver is always enabled if system supports all of ACPI, PCI and IOAPIC. Signed-off-by: Jiang Liu jiang@linux.intel.com --- drivers/acpi/Kconfig|6 ++ drivers/acpi/Makefile |1 + drivers/acpi/internal.h |7 ++ drivers/acpi/ioapic.c | 231 +++ drivers/acpi/pci_root.c |3 + 5 files changed, 248 insertions(+) create mode 100644 drivers/acpi/ioapic.c diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index ab686b310100..2d0ed9da6fea 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -292,6 +292,12 @@ config ACPI_HOTPLUG_MEMORY To compile this driver as a module, choose M here: the module will be called acpi_memhotplug. +config ACPI_HOTPLUG_IOAPIC + bool + depends on PCI + depends on X86_IO_APIC + default y + config ACPI_SBS tristate Smart Battery System depends on X86 diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index d922febd9164..b85b226a7f49 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -66,6 +66,7 @@ obj-$(CONFIG_ACPI_PROCESSOR) += processor.o obj-$(CONFIG_ACPI_CONTAINER) += container.o obj-$(CONFIG_ACPI_THERMAL) += thermal.o obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o +obj-$(CONFIG_ACPI_HOTPLUG_IOAPIC) += ioapic.o obj-$(CONFIG_ACPI_BATTERY) += battery.o obj-$(CONFIG_ACPI_SBS) += sbshc.o obj-$(CONFIG_ACPI_SBS) += sbs.o diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 957391306cbf..e8023cd81da3 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -52,6 +52,13 @@ void acpi_memory_hotplug_init(void); #else static inline void acpi_memory_hotplug_init(void) {} #endif +#ifdef CONFIG_ACPI_HOTPLUG_IOAPIC +int acpi_ioapic_add(struct acpi_pci_root *root); +int acpi_ioapic_remove(struct acpi_pci_root *root); +#else +static inline int acpi_ioapic_add(struct acpi_pci_root *root) { return 0; } +static inline int acpi_ioapic_remove(struct acpi_pci_root *root) { return 0; } +#endif #ifdef CONFIG_X86 void acpi_cmos_rtc_init(void); #else diff --git a/drivers/acpi/ioapic.c b/drivers/acpi/ioapic.c new file mode 100644 index ..3c9442899782 --- /dev/null +++ b/drivers/acpi/ioapic.c @@ -0,0 +1,231 @@ +/* + * IOAPIC/IOxAPIC/IOSAPIC driver + * + * Copyright (C) 2009 Fujitsu Limited. + * (c) Copyright 2009 Hewlett-Packard Development Company, L.P. + * + * Copyright (C) 2014 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Based on original drivers/pci/ioapic.c + * Yinghai Lu ying...@kernel.org + * Jiang Liu jiang@intel.com + */ + +/* + * This driver manages I/O APICs added by hotplug after boot. + * We try to claim all I/O APIC devices, but those present at boot were + * registered when we parsed the ACPI MADT, so we'll fail when we try to + * re-register them. + */ + +#define pr_fmt(fmt) ACPI : IOAPIC: fmt + +#include linux/slab.h +#include linux/acpi.h +#include linux/pci.h +#include acpi/acpi.h + +struct acpi_pci_ioapic { + acpi_handle root_handle; + acpi_handle handle; + u32 gsi_base; + struct resource res; + struct pci_dev *pdev; + struct list_head list; +}; + +static LIST_HEAD(ioapic_list); +static DEFINE_MUTEX(ioapic_list_lock); + +static acpi_status setup_res(struct acpi_resource *acpi_res, void *data) +{ + struct resource *res = data; + struct acpi_resource_address64 addr; + acpi_status status; + + status = acpi_mem_addr_resource_to_address64(acpi_res, addr); + if (!ACPI_SUCCESS(status)) + return AE_OK; + + if (addr.resource_type != ACPI_MEMORY_RANGE || + addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY) + return AE_OK; + + res-flags = IORESOURCE_MEM; + res-start = addr.minimum + addr.translation_offset; + res-end = addr.maximum + addr.translation_offset; + + return AE_OK; +} + +static bool acpi_is_ioapic(acpi_handle handle, char **type) +{ + acpi_status status; + struct acpi_device_info *info; + char *hid = NULL; + bool match = false; + + if (!acpi_has_method(handle, _GSB)) + return false; + + status = acpi_get_object_info(handle, info); + if (ACPI_SUCCESS(status)) { + if (info-valid ACPI_VALID_HID) + hid = info-hardware_id.string; + if (hid) { + if (strcmp(hid, ACPI0009) == 0) { + *type = IOxAPIC; + match = true; + } else if (strcmp(hid, ACPI000A) ==