Hi Len,
I am resending the following set of patches which support ACPI based physical
CPU hotplug for IA64 platform, after having including all the community
feedback(of course I got very thin feedback) which I got on
acpi-devel mailing list.
This set of patches has been tested on linux-2.6.9-rc2. Also this time I am
cc'ing ia64/lkml mailing lists as patch 3/6 and patch 4/6 touches arch specific files.
Details:(Applies cleanly onto linux-2.6.9-rc2)
Patch[1/6]- Core ACPI enhancement support
Patch[2/6]- ACPI hotplug eject interface support
Patch[3/6]- Arch specific support for mapping lsapic to cpu
Patch[4/6]- Dynamic cpu registration and unregistration support
Patch[5/6]- Extend ACPI processor driver to support Hotplug
Patch[6/6]- ACPI container driver(New driver)
Please consider applying this patch onto your test tree.
Thanks,
Anil S Keshavamurthy
---
Name:acpi_core.patch
Status: Tested on 2.6.9-rc2
Signed-off-by: Anil S Keshavamurthy <[email protected]>
Depends: None
Version: applies on 2.6.9-rc2
Description:
This patch provides core hotplug support in acpi by providing
acpi_bus_trim(), acpi_bus_remove() and acpi_pci_unbind()
which does exactly reverse of acpi_bus_scan(), acpi_bus_add()
and acpi_pci_bind().
---
linux-2.6.9-rc2-askeshav/drivers/acpi/acpi_ksyms.c | 3
linux-2.6.9-rc2-askeshav/drivers/acpi/bus.c | 4
linux-2.6.9-rc2-askeshav/drivers/acpi/pci_bind.c | 45 +++++++
linux-2.6.9-rc2-askeshav/drivers/acpi/pci_irq.c | 42 ++++++-
linux-2.6.9-rc2-askeshav/drivers/acpi/scan.c | 107 +++++++++++++++++--
linux-2.6.9-rc2-askeshav/include/acpi/acpi_bus.h | 9 +
linux-2.6.9-rc2-askeshav/include/acpi/acpi_drivers.h | 2
7 files changed, 194 insertions(+), 18 deletions(-)
diff -puN include/acpi/acpi_bus.h~acpi_core include/acpi/acpi_bus.h
--- linux-2.6.9-rc2/include/acpi/acpi_bus.h~acpi_core 2004-09-17 16:35:23.116378657 -0700
+++ linux-2.6.9-rc2-askeshav/include/acpi/acpi_bus.h 2004-09-17 16:35:23.233566156 -0700
@@ -104,6 +104,7 @@ typedef int (*acpi_op_suspend) (struct a
typedef int (*acpi_op_resume) (struct acpi_device *device, int state);
typedef int (*acpi_op_scan) (struct acpi_device *device);
typedef int (*acpi_op_bind) (struct acpi_device *device);
+typedef int (*acpi_op_unbind) (struct acpi_device *device);
struct acpi_device_ops {
acpi_op_add add;
@@ -115,6 +116,7 @@ struct acpi_device_ops {
acpi_op_resume resume;
acpi_op_scan scan;
acpi_op_bind bind;
+ acpi_op_unbind unbind;
};
struct acpi_driver {
@@ -313,7 +315,8 @@ extern struct subsystem acpi_subsys;
* External Functions
*/
-int acpi_bus_get_device(acpi_handle, struct acpi_device **device);
+int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device);
+void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context);
int acpi_bus_get_status (struct acpi_device *device);
int acpi_bus_get_power (acpi_handle handle, int *state);
int acpi_bus_set_power (acpi_handle handle, int state);
@@ -321,6 +324,10 @@ int acpi_bus_generate_event (struct acpi
int acpi_bus_receive_event (struct acpi_bus_event *event);
int acpi_bus_register_driver (struct acpi_driver *driver);
int acpi_bus_unregister_driver (struct acpi_driver *driver);
+int acpi_bus_scan (struct acpi_device *start);
+void acpi_bus_trim(struct acpi_device *start, int rmdevice);
+int acpi_bus_add (struct acpi_device **child, struct acpi_device *parent, acpi_handle handle, int type);
+
int acpi_create_dir(struct acpi_device *);
void acpi_remove_dir(struct acpi_device *);
diff -puN drivers/acpi/acpi_ksyms.c~acpi_core drivers/acpi/acpi_ksyms.c
--- linux-2.6.9-rc2/drivers/acpi/acpi_ksyms.c~acpi_core 2004-09-17 16:35:23.123214595 -0700
+++ linux-2.6.9-rc2-askeshav/drivers/acpi/acpi_ksyms.c 2004-09-17 16:35:23.233566156 -0700
@@ -135,6 +135,9 @@ EXPORT_SYMBOL(acpi_bus_generate_event);
EXPORT_SYMBOL(acpi_bus_receive_event);
EXPORT_SYMBOL(acpi_bus_register_driver);
EXPORT_SYMBOL(acpi_bus_unregister_driver);
+EXPORT_SYMBOL(acpi_bus_scan);
+EXPORT_SYMBOL(acpi_bus_trim);
+EXPORT_SYMBOL(acpi_bus_add);
#endif /*CONFIG_ACPI_BUS*/
diff -puN drivers/acpi/scan.c~acpi_core drivers/acpi/scan.c
--- linux-2.6.9-rc2/drivers/acpi/scan.c~acpi_core 2004-09-17 16:35:23.127120845 -0700
+++ linux-2.6.9-rc2-askeshav/drivers/acpi/scan.c 2004-09-17 16:35:23.235519281 -0700
@@ -57,6 +57,7 @@ static void acpi_device_register(struct
INIT_LIST_HEAD(&device->children);
INIT_LIST_HEAD(&device->node);
INIT_LIST_HEAD(&device->g_list);
+ INIT_LIST_HEAD(&device->wakeup_list);
spin_lock(&acpi_device_lock);
if (device->parent) {
@@ -64,6 +65,8 @@ static void acpi_device_register(struct
list_add_tail(&device->g_list,&device->parent->g_list);
} else
list_add_tail(&device->g_list,&acpi_device_list);
+ if (device->wakeup.flags.valid)
+ list_add_tail(&device->wakeup_list,&acpi_wakeup_device_list);
spin_unlock(&acpi_device_lock);
kobject_init(&device->kobj);
@@ -80,6 +83,18 @@ acpi_device_unregister (
struct acpi_device *device,
int type)
{
+ spin_lock(&acpi_device_lock);
+ if (device->parent) {
+ list_del(&device->node);
+ list_del(&device->g_list);
+ } else
+ list_del(&device->g_list);
+
+ list_del(&device->wakeup_list);
+
+ spin_unlock(&acpi_device_lock);
+
+ acpi_detach_data(device->handle, acpi_bus_data_handler);
kobject_unregister(&device->kobj);
return 0;
}
@@ -269,12 +284,6 @@ acpi_bus_get_wakeup_device_flags (
if (!acpi_match_ids(device, "PNP0C0D,PNP0C0C,PNP0C0E"))
device->wakeup.flags.run_wake = 1;
- /* TBD: lock */
- INIT_LIST_HEAD(&device->wakeup_list);
- spin_lock(&acpi_device_lock);
- list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list);
- spin_unlock(&acpi_device_lock);
-
end:
if (ACPI_FAILURE(status))
device->flags.wake_capable = 0;
@@ -315,7 +324,6 @@ acpi_bus_match (
return acpi_match_ids(device, driver->ids);
}
-
/**
* acpi_bus_driver_init
* --------------------
@@ -721,9 +729,10 @@ int acpi_device_set_context(struct acpi_
void acpi_device_get_debug_info(struct acpi_device * device, acpi_handle handle, int type)
{
#ifdef CONFIG_ACPI_DEBUG_OUTPUT
+
char *type_string = NULL;
char name[80] = {'?','\0'};
- acpi_buffer buffer = {sizeof(name), name};
+ struct acpi_buffer buffer = {sizeof(name), name};
switch (type) {
case ACPI_BUS_TYPE_DEVICE:
@@ -760,7 +769,56 @@ void acpi_device_get_debug_info(struct a
#endif /*CONFIG_ACPI_DEBUG_OUTPUT*/
}
-static int
+
+int
+acpi_bus_remove (
+ struct acpi_device *dev,
+ int rmdevice)
+{
+ int result = 0;
+ struct acpi_driver *driver;
+
+ ACPI_FUNCTION_TRACE("acpi_bus_remove");
+
+ if (!dev)
+ return_VALUE(-EINVAL);
+
+ driver = dev->driver;
+
+ if ((driver) && (driver->ops.remove)) {
+
+ if (driver->ops.stop) {
+ result = driver->ops.stop(dev, ACPI_BUS_REMOVAL_EJECT);
+ if (result)
+ return_VALUE(result);
+ }
+
+ result = dev->driver->ops.remove(dev, ACPI_BUS_REMOVAL_EJECT);
+ if (result) {
+ if (driver->ops.start)
+ driver->ops.start(dev);
+ return_VALUE(result);
+ }
+
+ atomic_dec(&dev->driver->references);
+ dev->driver = NULL;
+ acpi_driver_data(dev) = NULL;
+ }
+
+ if (!rmdevice)
+ return_VALUE(0);
+
+ if (dev->flags.bus_address) {
+ if ((dev->parent) && (dev->parent->ops.unbind))
+ dev->parent->ops.unbind(dev);
+ }
+
+ acpi_device_unregister(dev, ACPI_BUS_REMOVAL_EJECT);
+
+ return_VALUE(0);
+}
+
+int
acpi_bus_add (
struct acpi_device **child,
struct acpi_device *parent,
@@ -907,7 +965,7 @@ end:
-static int acpi_bus_scan (struct acpi_device *start)
+int acpi_bus_scan (struct acpi_device *start)
{
acpi_status status = AE_OK;
struct acpi_device *parent = NULL;
@@ -1009,6 +1067,35 @@ static int acpi_bus_scan (struct acpi_de
return_VALUE(0);
}
+void
+acpi_bus_trim(struct acpi_device *start,
+ int rmdevice)
+{
+ acpi_status status = AE_OK;
+ struct acpi_device *parent = NULL;
+ struct acpi_device *child = NULL;
+ acpi_handle phandle = 0;
+ acpi_handle chandle = 0;
+
+ parent = start;
+ phandle = start->handle;
+
+ /*
+ * NOTE: must be freed in a depth-first manner.
+ */
+ while (1) {
+ status = acpi_get_next_object(ACPI_TYPE_ANY, phandle,
+ chandle, &chandle);
+ if (ACPI_SUCCESS(status) && chandle != NULL) {
+ if (acpi_bus_get_device(chandle, &child) == 0)
+ acpi_bus_trim(child, 1);
+ } else {
+ /* this is a leaf */
+ acpi_bus_remove(parent, rmdevice);
+ break;
+ }
+ }
+}
static int
acpi_bus_scan_fixed (
diff -puN include/acpi/acpi_drivers.h~acpi_core include/acpi/acpi_drivers.h
--- linux-2.6.9-rc2/include/acpi/acpi_drivers.h~acpi_core 2004-09-17 16:35:23.132003657 -0700
+++ linux-2.6.9-rc2-askeshav/include/acpi/acpi_drivers.h 2004-09-17 16:35:23.236495844 -0700
@@ -61,12 +61,14 @@ int acpi_pci_link_get_irq (acpi_handle h
/* ACPI PCI Interrupt Routing (pci_irq.c) */
int acpi_pci_irq_add_prt (acpi_handle handle, int segment, int bus);
+void acpi_pci_irq_del_prt (int segment, int bus);
/* ACPI PCI Device Binding (pci_bind.c) */
struct pci_bus;
int acpi_pci_bind (struct acpi_device *device);
+int acpi_pci_unbind (struct acpi_device *device);
int acpi_pci_bind_root (struct acpi_device *device, struct acpi_pci_id *id, struct pci_bus *bus);
/* Arch-defined function to add a bus to the system */
diff -puN drivers/acpi/pci_irq.c~acpi_core drivers/acpi/pci_irq.c
--- linux-2.6.9-rc2/drivers/acpi/pci_irq.c~acpi_core 2004-09-17 16:35:23.135909907 -0700
+++ linux-2.6.9-rc2-askeshav/drivers/acpi/pci_irq.c 2004-09-17 16:35:23.237472406 -0700
@@ -43,7 +43,7 @@
ACPI_MODULE_NAME ("pci_irq")
struct acpi_prt_list acpi_prt;
-
+spinlock_t acpi_prt_lock = SPIN_LOCK_UNLOCKED;
/* --------------------------------------------------------------------------
PCI IRQ Routing Table (PRT) Support
@@ -68,18 +68,20 @@ acpi_pci_irq_find_prt_entry (
* Parse through all PRT entries looking for a match on the specified
* PCI device's segment, bus, device, and pin (don't care about func).
*
- * TBD: Acquire/release lock
*/
+ spin_lock(&acpi_prt_lock);
list_for_each(node, &acpi_prt.entries) {
entry = list_entry(node, struct acpi_prt_entry, node);
if ((segment == entry->id.segment)
&& (bus == entry->id.bus)
&& (device == entry->id.device)
&& (pin == entry->pin)) {
+ spin_unlock(&acpi_prt_lock);
return_PTR(entry);
}
}
+ spin_unlock(&acpi_prt_lock);
return_PTR(NULL);
}
@@ -141,14 +143,29 @@ acpi_pci_irq_add_entry (
entry->id.segment, entry->id.bus, entry->id.device,
('A' + entry->pin), prt->source, entry->link.index));
- /* TBD: Acquire/release lock */
+ spin_lock(&acpi_prt_lock);
list_add_tail(&entry->node, &acpi_prt.entries);
acpi_prt.count++;
+ spin_unlock(&acpi_prt_lock);
return_VALUE(0);
}
+static void
+acpi_pci_irq_del_entry (
+ int segment,
+ int bus,
+ struct acpi_prt_entry *entry)
+{
+ if (segment == entry->id.segment && bus == entry->id.bus){
+ acpi_prt.count--;
+ list_del(&entry->node);
+ kfree(entry);
+ }
+}
+
+
int
acpi_pci_irq_add_prt (
acpi_handle handle,
@@ -222,7 +239,26 @@ acpi_pci_irq_add_prt (
return_VALUE(0);
}
+void
+acpi_pci_irq_del_prt (int segment, int bus)
+{
+ struct list_head *node = NULL, *n = NULL;
+ struct acpi_prt_entry *entry = NULL;
+
+ if (!acpi_prt.count) {
+ return;
+ }
+ printk(KERN_DEBUG "ACPI: Delete PCI Interrupt Routing Table for %x:%x\n",
+ segment, bus);
+ spin_lock(&acpi_prt_lock);
+ list_for_each_safe(node, n, &acpi_prt.entries) {
+ entry = list_entry(node, struct acpi_prt_entry, node);
+
+ acpi_pci_irq_del_entry(segment, bus, entry);
+ }
+ spin_unlock(&acpi_prt_lock);
+}
/* --------------------------------------------------------------------------
PCI Interrupt Routing Support
-------------------------------------------------------------------------- */
diff -puN drivers/acpi/pci_bind.c~acpi_core drivers/acpi/pci_bind.c
--- linux-2.6.9-rc2/drivers/acpi/pci_bind.c~acpi_core 2004-09-17 16:35:23.140792720 -0700
+++ linux-2.6.9-rc2-askeshav/drivers/acpi/pci_bind.c 2004-09-17 16:35:23.238448968 -0700
@@ -214,6 +214,7 @@ acpi_pci_bind (
data->id.device, data->id.function));
data->bus = data->dev->subordinate;
device->ops.bind = acpi_pci_bind;
+ device->ops.unbind = acpi_pci_unbind;
}
/*
@@ -257,6 +258,49 @@ end:
return_VALUE(result);
}
+int acpi_pci_unbind(
+ struct acpi_device *device)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ struct acpi_pci_data *data = NULL;
+ char pathname[ACPI_PATHNAME_MAX] = {0};
+ struct acpi_buffer buffer = {ACPI_PATHNAME_MAX, pathname};
+
+ ACPI_FUNCTION_TRACE("acpi_pci_unbind");
+
+ if (!device || !device->parent)
+ return_VALUE(-EINVAL);
+
+ acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer);
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unbinding PCI device [%s]...\n",
+ pathname));
+
+ status = acpi_get_data(device->handle, acpi_pci_data_handler, (void**)&data);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to get data from device %s\n",
+ acpi_device_bid(device)));
+ result = -ENODEV;
+ goto end;
+ }
+
+ status = acpi_detach_data(device->handle, acpi_pci_data_handler);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to detach data from device %s\n",
+ acpi_device_bid(device)));
+ result = -ENODEV;
+ goto end;
+ }
+ if (data->dev->subordinate) {
+ acpi_pci_irq_del_prt(data->id.segment, data->bus->number);
+ }
+ kfree(data);
+
+end:
+ return_VALUE(result);
+}
int
acpi_pci_bind_root (
@@ -283,6 +327,7 @@ acpi_pci_bind_root (
data->id = *id;
data->bus = bus;
device->ops.bind = acpi_pci_bind;
+ device->ops.unbind = acpi_pci_unbind;
acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer);
diff -puN drivers/acpi/bus.c~acpi_core drivers/acpi/bus.c
--- linux-2.6.9-rc2/drivers/acpi/bus.c~acpi_core 2004-09-17 16:35:23.144698970 -0700
+++ linux-2.6.9-rc2-askeshav/drivers/acpi/bus.c 2004-09-17 16:35:23.239425531 -0700
@@ -53,10 +53,6 @@ struct proc_dir_entry *acpi_root_dir;
Device Management
-------------------------------------------------------------------------- */
-extern void acpi_bus_data_handler (
- acpi_handle handle,
- u32 function,
- void *context);
int
acpi_bus_get_device (
acpi_handle handle,
_
---
Name:acpi_core.patch
Status: Tested on 2.6.9-rc2
Signed-off-by: Anil S Keshavamurthy <[email protected]>
Depends: None
Version: applies on 2.6.9-rc2
Description:
This patch provides core hotplug support in acpi by providing
acpi_bus_trim(), acpi_bus_remove() and acpi_pci_unbind()
which does exactly reverse of acpi_bus_scan(), acpi_bus_add()
and acpi_pci_bind().
---
linux-2.6.9-rc2-askeshav/drivers/acpi/acpi_ksyms.c | 3
linux-2.6.9-rc2-askeshav/drivers/acpi/bus.c | 4
linux-2.6.9-rc2-askeshav/drivers/acpi/pci_bind.c | 45 +++++++
linux-2.6.9-rc2-askeshav/drivers/acpi/pci_irq.c | 42 ++++++-
linux-2.6.9-rc2-askeshav/drivers/acpi/scan.c | 107 +++++++++++++++++--
linux-2.6.9-rc2-askeshav/include/acpi/acpi_bus.h | 9 +
linux-2.6.9-rc2-askeshav/include/acpi/acpi_drivers.h | 2
7 files changed, 194 insertions(+), 18 deletions(-)
diff -puN include/acpi/acpi_bus.h~acpi_core include/acpi/acpi_bus.h
--- linux-2.6.9-rc2/include/acpi/acpi_bus.h~acpi_core 2004-09-17 16:35:23.116378657 -0700
+++ linux-2.6.9-rc2-askeshav/include/acpi/acpi_bus.h 2004-09-17 16:35:23.233566156 -0700
@@ -104,6 +104,7 @@ typedef int (*acpi_op_suspend) (struct a
typedef int (*acpi_op_resume) (struct acpi_device *device, int state);
typedef int (*acpi_op_scan) (struct acpi_device *device);
typedef int (*acpi_op_bind) (struct acpi_device *device);
+typedef int (*acpi_op_unbind) (struct acpi_device *device);
struct acpi_device_ops {
acpi_op_add add;
@@ -115,6 +116,7 @@ struct acpi_device_ops {
acpi_op_resume resume;
acpi_op_scan scan;
acpi_op_bind bind;
+ acpi_op_unbind unbind;
};
struct acpi_driver {
@@ -313,7 +315,8 @@ extern struct subsystem acpi_subsys;
* External Functions
*/
-int acpi_bus_get_device(acpi_handle, struct acpi_device **device);
+int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device);
+void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context);
int acpi_bus_get_status (struct acpi_device *device);
int acpi_bus_get_power (acpi_handle handle, int *state);
int acpi_bus_set_power (acpi_handle handle, int state);
@@ -321,6 +324,10 @@ int acpi_bus_generate_event (struct acpi
int acpi_bus_receive_event (struct acpi_bus_event *event);
int acpi_bus_register_driver (struct acpi_driver *driver);
int acpi_bus_unregister_driver (struct acpi_driver *driver);
+int acpi_bus_scan (struct acpi_device *start);
+void acpi_bus_trim(struct acpi_device *start, int rmdevice);
+int acpi_bus_add (struct acpi_device **child, struct acpi_device *parent, acpi_handle handle, int type);
+
int acpi_create_dir(struct acpi_device *);
void acpi_remove_dir(struct acpi_device *);
diff -puN drivers/acpi/acpi_ksyms.c~acpi_core drivers/acpi/acpi_ksyms.c
--- linux-2.6.9-rc2/drivers/acpi/acpi_ksyms.c~acpi_core 2004-09-17 16:35:23.123214595 -0700
+++ linux-2.6.9-rc2-askeshav/drivers/acpi/acpi_ksyms.c 2004-09-17 16:35:23.233566156 -0700
@@ -135,6 +135,9 @@ EXPORT_SYMBOL(acpi_bus_generate_event);
EXPORT_SYMBOL(acpi_bus_receive_event);
EXPORT_SYMBOL(acpi_bus_register_driver);
EXPORT_SYMBOL(acpi_bus_unregister_driver);
+EXPORT_SYMBOL(acpi_bus_scan);
+EXPORT_SYMBOL(acpi_bus_trim);
+EXPORT_SYMBOL(acpi_bus_add);
#endif /*CONFIG_ACPI_BUS*/
diff -puN drivers/acpi/scan.c~acpi_core drivers/acpi/scan.c
--- linux-2.6.9-rc2/drivers/acpi/scan.c~acpi_core 2004-09-17 16:35:23.127120845 -0700
+++ linux-2.6.9-rc2-askeshav/drivers/acpi/scan.c 2004-09-17 16:35:23.235519281 -0700
@@ -57,6 +57,7 @@ static void acpi_device_register(struct
INIT_LIST_HEAD(&device->children);
INIT_LIST_HEAD(&device->node);
INIT_LIST_HEAD(&device->g_list);
+ INIT_LIST_HEAD(&device->wakeup_list);
spin_lock(&acpi_device_lock);
if (device->parent) {
@@ -64,6 +65,8 @@ static void acpi_device_register(struct
list_add_tail(&device->g_list,&device->parent->g_list);
} else
list_add_tail(&device->g_list,&acpi_device_list);
+ if (device->wakeup.flags.valid)
+ list_add_tail(&device->wakeup_list,&acpi_wakeup_device_list);
spin_unlock(&acpi_device_lock);
kobject_init(&device->kobj);
@@ -80,6 +83,18 @@ acpi_device_unregister (
struct acpi_device *device,
int type)
{
+ spin_lock(&acpi_device_lock);
+ if (device->parent) {
+ list_del(&device->node);
+ list_del(&device->g_list);
+ } else
+ list_del(&device->g_list);
+
+ list_del(&device->wakeup_list);
+
+ spin_unlock(&acpi_device_lock);
+
+ acpi_detach_data(device->handle, acpi_bus_data_handler);
kobject_unregister(&device->kobj);
return 0;
}
@@ -269,12 +284,6 @@ acpi_bus_get_wakeup_device_flags (
if (!acpi_match_ids(device, "PNP0C0D,PNP0C0C,PNP0C0E"))
device->wakeup.flags.run_wake = 1;
- /* TBD: lock */
- INIT_LIST_HEAD(&device->wakeup_list);
- spin_lock(&acpi_device_lock);
- list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list);
- spin_unlock(&acpi_device_lock);
-
end:
if (ACPI_FAILURE(status))
device->flags.wake_capable = 0;
@@ -315,7 +324,6 @@ acpi_bus_match (
return acpi_match_ids(device, driver->ids);
}
-
/**
* acpi_bus_driver_init
* --------------------
@@ -721,9 +729,10 @@ int acpi_device_set_context(struct acpi_
void acpi_device_get_debug_info(struct acpi_device * device, acpi_handle handle, int type)
{
#ifdef CONFIG_ACPI_DEBUG_OUTPUT
+
char *type_string = NULL;
char name[80] = {'?','\0'};
- acpi_buffer buffer = {sizeof(name), name};
+ struct acpi_buffer buffer = {sizeof(name), name};
switch (type) {
case ACPI_BUS_TYPE_DEVICE:
@@ -760,7 +769,56 @@ void acpi_device_get_debug_info(struct a
#endif /*CONFIG_ACPI_DEBUG_OUTPUT*/
}
-static int
+
+int
+acpi_bus_remove (
+ struct acpi_device *dev,
+ int rmdevice)
+{
+ int result = 0;
+ struct acpi_driver *driver;
+
+ ACPI_FUNCTION_TRACE("acpi_bus_remove");
+
+ if (!dev)
+ return_VALUE(-EINVAL);
+
+ driver = dev->driver;
+
+ if ((driver) && (driver->ops.remove)) {
+
+ if (driver->ops.stop) {
+ result = driver->ops.stop(dev, ACPI_BUS_REMOVAL_EJECT);
+ if (result)
+ return_VALUE(result);
+ }
+
+ result = dev->driver->ops.remove(dev, ACPI_BUS_REMOVAL_EJECT);
+ if (result) {
+ if (driver->ops.start)
+ driver->ops.start(dev);
+ return_VALUE(result);
+ }
+
+ atomic_dec(&dev->driver->references);
+ dev->driver = NULL;
+ acpi_driver_data(dev) = NULL;
+ }
+
+ if (!rmdevice)
+ return_VALUE(0);
+
+ if (dev->flags.bus_address) {
+ if ((dev->parent) && (dev->parent->ops.unbind))
+ dev->parent->ops.unbind(dev);
+ }
+
+ acpi_device_unregister(dev, ACPI_BUS_REMOVAL_EJECT);
+
+ return_VALUE(0);
+}
+
+int
acpi_bus_add (
struct acpi_device **child,
struct acpi_device *parent,
@@ -907,7 +965,7 @@ end:
-static int acpi_bus_scan (struct acpi_device *start)
+int acpi_bus_scan (struct acpi_device *start)
{
acpi_status status = AE_OK;
struct acpi_device *parent = NULL;
@@ -1009,6 +1067,35 @@ static int acpi_bus_scan (struct acpi_de
return_VALUE(0);
}
+void
+acpi_bus_trim(struct acpi_device *start,
+ int rmdevice)
+{
+ acpi_status status = AE_OK;
+ struct acpi_device *parent = NULL;
+ struct acpi_device *child = NULL;
+ acpi_handle phandle = 0;
+ acpi_handle chandle = 0;
+
+ parent = start;
+ phandle = start->handle;
+
+ /*
+ * NOTE: must be freed in a depth-first manner.
+ */
+ while (1) {
+ status = acpi_get_next_object(ACPI_TYPE_ANY, phandle,
+ chandle, &chandle);
+ if (ACPI_SUCCESS(status) && chandle != NULL) {
+ if (acpi_bus_get_device(chandle, &child) == 0)
+ acpi_bus_trim(child, 1);
+ } else {
+ /* this is a leaf */
+ acpi_bus_remove(parent, rmdevice);
+ break;
+ }
+ }
+}
static int
acpi_bus_scan_fixed (
diff -puN include/acpi/acpi_drivers.h~acpi_core include/acpi/acpi_drivers.h
--- linux-2.6.9-rc2/include/acpi/acpi_drivers.h~acpi_core 2004-09-17 16:35:23.132003657 -0700
+++ linux-2.6.9-rc2-askeshav/include/acpi/acpi_drivers.h 2004-09-17 16:35:23.236495844 -0700
@@ -61,12 +61,14 @@ int acpi_pci_link_get_irq (acpi_handle h
/* ACPI PCI Interrupt Routing (pci_irq.c) */
int acpi_pci_irq_add_prt (acpi_handle handle, int segment, int bus);
+void acpi_pci_irq_del_prt (int segment, int bus);
/* ACPI PCI Device Binding (pci_bind.c) */
struct pci_bus;
int acpi_pci_bind (struct acpi_device *device);
+int acpi_pci_unbind (struct acpi_device *device);
int acpi_pci_bind_root (struct acpi_device *device, struct acpi_pci_id *id, struct pci_bus *bus);
/* Arch-defined function to add a bus to the system */
diff -puN drivers/acpi/pci_irq.c~acpi_core drivers/acpi/pci_irq.c
--- linux-2.6.9-rc2/drivers/acpi/pci_irq.c~acpi_core 2004-09-17 16:35:23.135909907 -0700
+++ linux-2.6.9-rc2-askeshav/drivers/acpi/pci_irq.c 2004-09-17 16:35:23.237472406 -0700
@@ -43,7 +43,7 @@
ACPI_MODULE_NAME ("pci_irq")
struct acpi_prt_list acpi_prt;
-
+spinlock_t acpi_prt_lock = SPIN_LOCK_UNLOCKED;
/* --------------------------------------------------------------------------
PCI IRQ Routing Table (PRT) Support
@@ -68,18 +68,20 @@ acpi_pci_irq_find_prt_entry (
* Parse through all PRT entries looking for a match on the specified
* PCI device's segment, bus, device, and pin (don't care about func).
*
- * TBD: Acquire/release lock
*/
+ spin_lock(&acpi_prt_lock);
list_for_each(node, &acpi_prt.entries) {
entry = list_entry(node, struct acpi_prt_entry, node);
if ((segment == entry->id.segment)
&& (bus == entry->id.bus)
&& (device == entry->id.device)
&& (pin == entry->pin)) {
+ spin_unlock(&acpi_prt_lock);
return_PTR(entry);
}
}
+ spin_unlock(&acpi_prt_lock);
return_PTR(NULL);
}
@@ -141,14 +143,29 @@ acpi_pci_irq_add_entry (
entry->id.segment, entry->id.bus, entry->id.device,
('A' + entry->pin), prt->source, entry->link.index));
- /* TBD: Acquire/release lock */
+ spin_lock(&acpi_prt_lock);
list_add_tail(&entry->node, &acpi_prt.entries);
acpi_prt.count++;
+ spin_unlock(&acpi_prt_lock);
return_VALUE(0);
}
+static void
+acpi_pci_irq_del_entry (
+ int segment,
+ int bus,
+ struct acpi_prt_entry *entry)
+{
+ if (segment == entry->id.segment && bus == entry->id.bus){
+ acpi_prt.count--;
+ list_del(&entry->node);
+ kfree(entry);
+ }
+}
+
+
int
acpi_pci_irq_add_prt (
acpi_handle handle,
@@ -222,7 +239,26 @@ acpi_pci_irq_add_prt (
return_VALUE(0);
}
+void
+acpi_pci_irq_del_prt (int segment, int bus)
+{
+ struct list_head *node = NULL, *n = NULL;
+ struct acpi_prt_entry *entry = NULL;
+
+ if (!acpi_prt.count) {
+ return;
+ }
+ printk(KERN_DEBUG "ACPI: Delete PCI Interrupt Routing Table for %x:%x\n",
+ segment, bus);
+ spin_lock(&acpi_prt_lock);
+ list_for_each_safe(node, n, &acpi_prt.entries) {
+ entry = list_entry(node, struct acpi_prt_entry, node);
+
+ acpi_pci_irq_del_entry(segment, bus, entry);
+ }
+ spin_unlock(&acpi_prt_lock);
+}
/* --------------------------------------------------------------------------
PCI Interrupt Routing Support
-------------------------------------------------------------------------- */
diff -puN drivers/acpi/pci_bind.c~acpi_core drivers/acpi/pci_bind.c
--- linux-2.6.9-rc2/drivers/acpi/pci_bind.c~acpi_core 2004-09-17 16:35:23.140792720 -0700
+++ linux-2.6.9-rc2-askeshav/drivers/acpi/pci_bind.c 2004-09-17 16:35:23.238448968 -0700
@@ -214,6 +214,7 @@ acpi_pci_bind (
data->id.device, data->id.function));
data->bus = data->dev->subordinate;
device->ops.bind = acpi_pci_bind;
+ device->ops.unbind = acpi_pci_unbind;
}
/*
@@ -257,6 +258,49 @@ end:
return_VALUE(result);
}
+int acpi_pci_unbind(
+ struct acpi_device *device)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ struct acpi_pci_data *data = NULL;
+ char pathname[ACPI_PATHNAME_MAX] = {0};
+ struct acpi_buffer buffer = {ACPI_PATHNAME_MAX, pathname};
+
+ ACPI_FUNCTION_TRACE("acpi_pci_unbind");
+
+ if (!device || !device->parent)
+ return_VALUE(-EINVAL);
+
+ acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer);
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unbinding PCI device [%s]...\n",
+ pathname));
+
+ status = acpi_get_data(device->handle, acpi_pci_data_handler, (void**)&data);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to get data from device %s\n",
+ acpi_device_bid(device)));
+ result = -ENODEV;
+ goto end;
+ }
+
+ status = acpi_detach_data(device->handle, acpi_pci_data_handler);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to detach data from device %s\n",
+ acpi_device_bid(device)));
+ result = -ENODEV;
+ goto end;
+ }
+ if (data->dev->subordinate) {
+ acpi_pci_irq_del_prt(data->id.segment, data->bus->number);
+ }
+ kfree(data);
+
+end:
+ return_VALUE(result);
+}
int
acpi_pci_bind_root (
@@ -283,6 +327,7 @@ acpi_pci_bind_root (
data->id = *id;
data->bus = bus;
device->ops.bind = acpi_pci_bind;
+ device->ops.unbind = acpi_pci_unbind;
acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer);
diff -puN drivers/acpi/bus.c~acpi_core drivers/acpi/bus.c
--- linux-2.6.9-rc2/drivers/acpi/bus.c~acpi_core 2004-09-17 16:35:23.144698970 -0700
+++ linux-2.6.9-rc2-askeshav/drivers/acpi/bus.c 2004-09-17 16:35:23.239425531 -0700
@@ -53,10 +53,6 @@ struct proc_dir_entry *acpi_root_dir;
Device Management
-------------------------------------------------------------------------- */
-extern void acpi_bus_data_handler (
- acpi_handle handle,
- u32 function,
- void *context);
int
acpi_bus_get_device (
acpi_handle handle,
_
---
Name:acpi_core_eject.patch
Status: Tested on 2.6.9-rc2
Signed-off-by: Anil S Keshavamurthy <[email protected]>
Depends:acpi_core
Version: applies on 2.6.9-rc2
This patch support /sys/firmware/acpi/eject interface where in
the ACPI device say "LSB0" can be ejected by echoing "\_SB.LSB0" >
/sys/firmware/acpi/eject
The kernel when it receives an hardware sci eject request it simply passes this
to user mode agent and the agent in turn will offline all the child devices and
then echo's the ACPI device name onto /sys/firware/acpi/eject file and then the
kernel will then actually remove the device.
---
linux-2.6.9-rc2-askeshav/drivers/acpi/scan.c | 141 +++++++++++++++++++++++++++
1 files changed, 141 insertions(+)
diff -puN drivers/acpi/scan.c~acpi_core_eject drivers/acpi/scan.c
--- linux-2.6.9-rc2/drivers/acpi/scan.c~acpi_core_eject 2004-09-17 17:56:46.027451654 -0700
+++ linux-2.6.9-rc2-askeshav/drivers/acpi/scan.c 2004-09-17 17:56:46.114365716 -0700
@@ -2,6 +2,7 @@
* scan.c - support for transforming the ACPI namespace into individual objects
*/
+#include <linux/module.h>
#include <linux/init.h>
#include <linux/acpi.h>
@@ -291,6 +292,141 @@ end:
}
/* --------------------------------------------------------------------------
+ ACPI hotplug Eject support
+ -------------------------------------------------------------------------- */
+static ssize_t acpi_eject_store(struct subsystem *subsys, const char *buf, size_t count);
+static struct subsys_attribute acpi_eject_attr =
+ __ATTR(eject,0200,NULL,acpi_eject_store);
+
+/*
+ * evaluate _EJ0, detach driver, and remove from ACPI bus
+ */
+static int
+eject_operation(acpi_handle handle, int lockable)
+{
+ struct acpi_object_list arg_list;
+ union acpi_object arg;
+ acpi_status status = AE_OK;
+
+ /*
+ * TBD: evaluate _PS3?
+ */
+
+ if (lockable) {
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+ arg.type = ACPI_TYPE_INTEGER;
+ arg.integer.value = 0;
+ acpi_evaluate_object(handle, "_LCK", &arg_list, NULL);
+ }
+
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+ arg.type = ACPI_TYPE_INTEGER;
+ arg.integer.value = 1;
+
+ /*
+ * TBD: _EJD support.
+ */
+
+ status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
+ if (ACPI_FAILURE(status)) {
+ return(-ENODEV);
+ }
+
+ return(0);
+}
+
+static ssize_t
+acpi_eject_store(struct subsystem *subsys, const char *buf, size_t count)
+{
+ acpi_status status;
+ acpi_handle hlsb;
+ struct acpi_device *device = NULL;
+ int result;
+ int ret = count;
+
+ char *acpi_name;
+ char *p;
+ int islockable;
+ acpi_object_type type = 0;
+
+ if (!count) {
+ return -EINVAL;
+ }
+
+ acpi_name = kmalloc(count+1, GFP_KERNEL);
+ if (!acpi_name) {
+ return -ENOMEM;
+ }
+
+ acpi_name[count] = '\0';
+ strncpy(acpi_name, buf, count);
+
+ for (p = acpi_name+(count-1); p >= acpi_name; --p) {
+ if (isspace(*p))
+ *p = '\0';
+ else
+ break;
+ }
+
+ status = acpi_get_handle(NULL, acpi_name, &hlsb);
+ if(ACPI_FAILURE(status)) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ status = acpi_get_type(hlsb, &type);
+ if (ACPI_FAILURE(status)) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ result = acpi_bus_get_device(hlsb, &device);
+ if (result) {
+ ret = -ENODEV;
+ goto err;
+ }
+#ifndef FORCE_EJECT
+ if (device->driver == NULL) {
+ ret = -ENODEV;
+ goto err;
+ }
+#endif
+ if (!device->flags.ejectable) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ islockable = device->flags.lockable;
+
+ /*
+ * remove from ACPI bus.
+ */
+ if (type == ACPI_BUS_TYPE_PROCESSOR)
+ acpi_bus_trim(device, 0);
+ else
+ acpi_bus_trim(device, 1);
+
+
+ result = eject_operation(hlsb, islockable);
+ if (result) {
+ ret = -EBUSY;
+ }
+err:
+ kfree(acpi_name);
+ return ret;
+}
+
+
+static int __init register_acpi_eject(void)
+{
+ subsys_create_file(&acpi_subsys, &acpi_eject_attr);
+ return 0;
+}
+
+
+/* --------------------------------------------------------------------------
Performance Management
-------------------------------------------------------------------------- */
@@ -1153,6 +1289,11 @@ static int __init acpi_scan_init(void)
if (result)
acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
+ /*
+ * Register hotplug eject interface
+ */
+ register_acpi_eject();
+
Done:
return_VALUE(result);
}
_
---
Name:acpi_hotplug_arch.patch
Status: Tested on 2.6.9-rc2
Signed-off-by: Anil S Keshavamurthy <[email protected]>
Depends:
Version: applies on 2.6.9-rc2
Description:
This patch provides the architecture specifice support for mapping lsapic to cpu array.
Currently this supports just IA64. Support for IA32 and x86_64 is in progress
---
linux-2.6.9-rc2-askeshav/arch/i386/kernel/acpi/boot.c | 22 +++
linux-2.6.9-rc2-askeshav/arch/ia64/kernel/acpi.c | 127 +++++++++++++++++-
linux-2.6.9-rc2-askeshav/include/linux/acpi.h | 6
3 files changed, 153 insertions(+), 2 deletions(-)
diff -puN include/linux/acpi.h~acpi_hotplug_arch include/linux/acpi.h
--- linux-2.6.9-rc2/include/linux/acpi.h~acpi_hotplug_arch 2004-09-17 17:56:49.136826616 -0700
+++ linux-2.6.9-rc2-askeshav/include/linux/acpi.h 2004-09-17 17:56:49.231553178 -0700
@@ -396,6 +396,12 @@ void acpi_numa_processor_affinity_init (
void acpi_numa_memory_affinity_init (struct acpi_table_memory_affinity *ma);
void acpi_numa_arch_fixup(void);
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+/* Arch dependent functions for cpu hotplug support */
+int acpi_map_lsapic(acpi_handle handle, int *pcpu);
+int acpi_unmap_lsapic(int cpu);
+#endif /* CONFIG_ACPI_HOTPLUG_CPU */
+
extern int acpi_mp_config;
extern u32 pci_mmcfg_base_addr;
diff -puN arch/ia64/kernel/acpi.c~acpi_hotplug_arch arch/ia64/kernel/acpi.c
--- linux-2.6.9-rc2/arch/ia64/kernel/acpi.c~acpi_hotplug_arch 2004-09-17 17:56:49.140732866 -0700
+++ linux-2.6.9-rc2-askeshav/arch/ia64/kernel/acpi.c 2004-09-17 17:56:49.232529740 -0700
@@ -354,11 +354,11 @@ acpi_parse_madt (unsigned long phys_addr
#define PXM_FLAG_LEN ((MAX_PXM_DOMAINS + 1)/32)
static int __initdata srat_num_cpus; /* number of cpus */
-static u32 __initdata pxm_flag[PXM_FLAG_LEN];
+static u32 __devinitdata pxm_flag[PXM_FLAG_LEN];
#define pxm_bit_set(bit) (set_bit(bit,(void *)pxm_flag))
#define pxm_bit_test(bit) (test_bit(bit,(void *)pxm_flag))
/* maps to convert between proximity domain and logical node ID */
-int __initdata pxm_to_nid_map[MAX_PXM_DOMAINS];
+int __devinitdata pxm_to_nid_map[MAX_PXM_DOMAINS];
int __initdata nid_to_pxm_map[MAX_NUMNODES];
static struct acpi_table_slit __initdata *slit_table;
@@ -650,4 +650,127 @@ acpi_gsi_to_irq (u32 gsi, unsigned int *
return 0;
}
+/*
+ * ACPI based hotplug support for CPU
+ */
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+static
+int
+acpi_map_cpu2node(acpi_handle handle, int cpu, long physid)
+{
+#ifdef CONFIG_ACPI_NUMA
+ int pxm_id = 0;
+ union acpi_object *obj;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+
+ if (ACPI_FAILURE(acpi_evaluate_object(handle, "_PXM", NULL, &buffer)))
+ goto pxm_id_0;
+
+ if ((!buffer.length) || (!buffer.pointer))
+ goto pxm_id_0;
+
+ obj = buffer.pointer;
+ if (obj->type != ACPI_TYPE_INTEGER) {
+ acpi_os_free(buffer.pointer);
+ goto pxm_id_0;
+ }
+
+ pxm_id = obj->integer.value;
+
+pxm_id_0:
+ /*
+ * Assuming that the container driver would have set the proximity
+ * domain and would have initialized pxm_to_nid_map[pxm_id] && pxm_flag
+ */
+
+ /* Return Error if proximity domain is not set */
+ if (!pxm_bit_test(pxm_id))
+ return -EINVAL;
+
+ node_cpuid[cpu].phys_id = physid;
+ node_cpuid[cpu].nid = pxm_to_nid_map[pxm_id];
+
+#endif
+ return(0);
+}
+
+
+int
+acpi_map_lsapic(acpi_handle handle, int *pcpu)
+{
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ union acpi_object *obj;
+ struct acpi_table_lsapic *lsapic;
+ cpumask_t tmp_map;
+ long physid;
+ int cpu;
+
+ if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
+ return -EINVAL;
+
+ if (!buffer.length || !buffer.pointer)
+ return -EINVAL;
+
+ obj = buffer.pointer;
+ if (obj->type != ACPI_TYPE_BUFFER ||
+ obj->buffer.length < sizeof(*lsapic)) {
+ acpi_os_free(buffer.pointer);
+ return -EINVAL;
+ }
+
+ lsapic = (struct acpi_table_lsapic *)obj->buffer.pointer;
+
+ if ((lsapic->header.type != ACPI_MADT_LSAPIC) ||
+ (!lsapic->flags.enabled)) {
+ acpi_os_free(buffer.pointer);
+ return -EINVAL;
+ }
+
+ physid = ((lsapic->id <<8) | (lsapic->eid));
+
+ acpi_os_free(buffer.pointer);
+ buffer.length = ACPI_ALLOCATE_BUFFER;
+ buffer.pointer = NULL;
+
+ cpus_complement(tmp_map, cpu_present_map);
+ cpu = first_cpu(tmp_map);
+ if(cpu >= NR_CPUS)
+ return -EINVAL;
+
+ if (ACPI_FAILURE(acpi_map_cpu2node(handle, cpu, physid)))
+ return -ENODEV;
+
+ cpu_set(cpu, cpu_present_map);
+ ia64_cpu_to_sapicid[cpu] = physid;
+ ia64_acpiid_to_sapicid[lsapic->acpi_id] = ia64_cpu_to_sapicid[cpu];
+
+ *pcpu = cpu;
+ return(0);
+}
+EXPORT_SYMBOL(acpi_map_lsapic);
+
+
+int
+acpi_unmap_lsapic(int cpu)
+{
+ int i;
+
+ for (i=0; i<MAX_SAPICS; i++) {
+ if (ia64_acpiid_to_sapicid[i] == ia64_cpu_to_sapicid[cpu]) {
+ ia64_acpiid_to_sapicid[i] = -1;
+ break;
+ }
+ }
+ ia64_cpu_to_sapicid[cpu] = -1;
+ cpu_clear(cpu,cpu_present_map);
+
+#ifdef CONFIG_ACPI_NUMA
+ /* NUMA specific cleanup's */
+#endif
+
+ return(0);
+}
+EXPORT_SYMBOL(acpi_unmap_lsapic);
+#endif /* CONFIG_ACPI_HOTPLUG_CPU */
+
#endif /* CONFIG_ACPI_BOOT */
diff -puN arch/i386/kernel/acpi/boot.c~acpi_hotplug_arch arch/i386/kernel/acpi/boot.c
--- linux-2.6.9-rc2/arch/i386/kernel/acpi/boot.c~acpi_hotplug_arch 2004-09-17 17:56:49.145615679 -0700
+++ linux-2.6.9-rc2-askeshav/arch/i386/kernel/acpi/boot.c 2004-09-17 17:56:49.233506303 -0700
@@ -478,6 +478,28 @@ unsigned int acpi_register_gsi(u32 gsi,
}
EXPORT_SYMBOL(acpi_register_gsi);
+/*
+ * ACPI based hotplug support for CPU
+ */
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+int
+acpi_map_lsapic(acpi_handle handle, int *pcpu)
+{
+ /* TBD */
+ return -EINVAL;
+}
+EXPORT_SYMBOL(acpi_map_lsapic);
+
+
+int
+acpi_unmap_lsapic(int cpu)
+{
+ /* TBD */
+ return -EINVAL;
+}
+EXPORT_SYMBOL(acpi_unmap_lsapic);
+#endif /* CONFIG_ACPI_HOTPLUG_CPU */
+
static unsigned long __init
acpi_scan_rsdp (
unsigned long start,
_
---
Name:topology.patch
Status:Tested on 2.6.9-rc2
Signed-off-by: Anil S Keshavamurthy <[email protected]>
Depends:
Version: applies on 2.6.9-rc2
Description:
Extends support for dynamic registration and unregistration of the cpu,
by implementing and exporting arch_register_cpu()/arch_unregister_cpu().
Also combines multiple implementation of topology_init() functions to
single topology_init() in case of ia64 architecture.
---
/dev/null | 43 ------
linux-2.6.9-rc2-askeshav/arch/i386/mach-default/topology.c | 31 ++++
linux-2.6.9-rc2-askeshav/arch/ia64/dig/Makefile | 5
linux-2.6.9-rc2-askeshav/arch/ia64/kernel/Makefile | 3
linux-2.6.9-rc2-askeshav/arch/ia64/kernel/topology.c | 91 +++++++++++++
linux-2.6.9-rc2-askeshav/arch/ia64/mm/numa.c | 35 -----
linux-2.6.9-rc2-askeshav/drivers/base/cpu.c | 20 ++
linux-2.6.9-rc2-askeshav/include/asm-i386/cpu.h | 17 --
linux-2.6.9-rc2-askeshav/include/asm-ia64/cpu.h | 5
linux-2.6.9-rc2-askeshav/include/linux/cpu.h | 3
10 files changed, 154 insertions(+), 99 deletions(-)
diff -L arch/ia64/dig/topology.c -puN arch/ia64/dig/topology.c~topology /dev/null
--- linux-2.6.9-rc2/arch/ia64/dig/topology.c
+++ /dev/null 2004-06-30 13:03:36.000000000 -0700
@@ -1,43 +0,0 @@
-/*
- * arch/ia64/dig/topology.c
- * Popuate driverfs with topology information.
- * Derived entirely from i386/mach-default.c
- * Intel Corporation - Ashok Raj
- */
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/cpumask.h>
-#include <linux/percpu.h>
-#include <linux/notifier.h>
-#include <linux/cpu.h>
-#include <asm/cpu.h>
-
-static DEFINE_PER_CPU(struct ia64_cpu, cpu_devices);
-
-/*
- * First Pass: simply borrowed code for now. Later should hook into
- * hotplug notification for node/cpu/memory as applicable
- */
-
-static int arch_register_cpu(int num)
-{
- struct node *parent = NULL;
-
-#ifdef CONFIG_NUMA
- //parent = &node_devices[cpu_to_node(num)].node;
-#endif
-
- return register_cpu(&per_cpu(cpu_devices,num).cpu, num, parent);
-}
-
-static int __init topology_init(void)
-{
- int i;
-
- for_each_cpu(i) {
- arch_register_cpu(i);
- }
- return 0;
-}
-
-subsys_initcall(topology_init);
diff -puN arch/ia64/dig/Makefile~topology arch/ia64/dig/Makefile
--- linux-2.6.9-rc2/arch/ia64/dig/Makefile~topology 2004-09-17 18:01:36.290143411 -0700
+++ linux-2.6.9-rc2-askeshav/arch/ia64/dig/Makefile 2004-09-17 18:01:36.429791847 -0700
@@ -6,9 +6,4 @@
#
obj-y := setup.o
-
-ifndef CONFIG_NUMA
-obj-$(CONFIG_IA64_DIG) += topology.o
-endif
-
obj-$(CONFIG_IA64_GENERIC) += machvec.o
diff -puN arch/ia64/mm/numa.c~topology arch/ia64/mm/numa.c
--- linux-2.6.9-rc2/arch/ia64/mm/numa.c~topology 2004-09-17 18:01:36.296979349 -0700
+++ linux-2.6.9-rc2-askeshav/arch/ia64/mm/numa.c 2004-09-17 18:01:36.429791847 -0700
@@ -20,8 +20,6 @@
#include <asm/mmzone.h>
#include <asm/numa.h>
-static struct node *sysfs_nodes;
-static struct cpu *sysfs_cpus;
/*
* The following structures are usually initialized by ACPI or
@@ -50,36 +48,3 @@ paddr_to_nid(unsigned long paddr)
return (i < num_node_memblks) ? node_memblk[i].nid : (num_node_memblks ? -1 : 0);
}
-static int __init topology_init(void)
-{
- int i, err = 0;
-
- sysfs_nodes = kmalloc(sizeof(struct node) * numnodes, GFP_KERNEL);
- if (!sysfs_nodes) {
- err = -ENOMEM;
- goto out;
- }
- memset(sysfs_nodes, 0, sizeof(struct node) * numnodes);
-
- sysfs_cpus = kmalloc(sizeof(struct cpu) * NR_CPUS, GFP_KERNEL);
- if (!sysfs_cpus) {
- kfree(sysfs_nodes);
- err = -ENOMEM;
- goto out;
- }
- memset(sysfs_cpus, 0, sizeof(struct cpu) * NR_CPUS);
-
- for (i = 0; i < numnodes; i++)
- if ((err = register_node(&sysfs_nodes[i], i, 0)))
- goto out;
-
- for (i = 0; i < NR_CPUS; i++)
- if (cpu_online(i))
- if((err = register_cpu(&sysfs_cpus[i], i,
- &sysfs_nodes[cpu_to_node(i)])))
- goto out;
- out:
- return err;
-}
-
-__initcall(topology_init);
diff -puN include/linux/cpu.h~topology include/linux/cpu.h
--- linux-2.6.9-rc2/include/linux/cpu.h~topology 2004-09-17 18:01:36.301862161 -0700
+++ linux-2.6.9-rc2-askeshav/include/linux/cpu.h 2004-09-17 18:01:36.430768409 -0700
@@ -32,6 +32,9 @@ struct cpu {
};
extern int register_cpu(struct cpu *, int, struct node *);
+#ifdef CONFIG_HOTPLUG_CPU
+extern void unregister_cpu(struct cpu *, struct node *);
+#endif
struct notifier_block;
#ifdef CONFIG_SMP
diff -puN include/asm-ia64/cpu.h~topology include/asm-ia64/cpu.h
--- linux-2.6.9-rc2/include/asm-ia64/cpu.h~topology 2004-09-17 18:01:36.308698098 -0700
+++ linux-2.6.9-rc2-askeshav/include/asm-ia64/cpu.h 2004-09-17 18:01:36.431744972 -0700
@@ -14,4 +14,9 @@ DECLARE_PER_CPU(struct ia64_cpu, cpu_dev
DECLARE_PER_CPU(int, cpu_state);
+extern int arch_register_cpu(int num);
+#ifdef CONFIG_HOTPLUG_CPU
+extern void arch_unregister_cpu(int);
+#endif
+
#endif /* _ASM_IA64_CPU_H_ */
diff -puN /dev/null arch/ia64/kernel/topology.c
--- /dev/null 2004-06-30 13:03:36.000000000 -0700
+++ linux-2.6.9-rc2-askeshav/arch/ia64/kernel/topology.c 2004-09-17 18:05:31.993265524 -0700
@@ -0,0 +1,91 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * This file contains NUMA specific variables and functions which can
+ * be split away from DISCONTIGMEM and are used on NUMA machines with
+ * contiguous memory.
+ * 2002/08/07 Erich Focht <[email protected]>
+ * Populate cpu entries in sysfs for non-numa systems as well
+ * Intel Corporation - Ashok Raj
+ */
+
+#include <linux/config.h>
+#include <linux/cpu.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/node.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <asm/mmzone.h>
+#include <asm/numa.h>
+#include <asm/cpu.h>
+
+#ifdef CONFIG_NUMA
+static struct node *sysfs_nodes;
+#endif
+static struct ia64_cpu *sysfs_cpus;
+
+int arch_register_cpu(int num)
+{
+ struct node *parent = NULL;
+
+#ifdef CONFIG_NUMA
+ parent = &sysfs_nodes[cpu_to_node(num)];
+#endif /* CONFIG_NUMA */
+
+ return register_cpu(&sysfs_cpus[num].cpu, num, parent);
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+
+void arch_unregister_cpu(int num)
+{
+ struct node *parent = NULL;
+
+#ifdef CONFIG_NUMA
+ int node = cpu_to_node(num);
+ if (node_online(node))
+ parent = &sysfs_nodes[node];
+#endif /* CONFIG_NUMA */
+
+ return unregister_cpu(&sysfs_cpus[num].cpu, parent);
+}
+EXPORT_SYMBOL(arch_register_cpu);
+EXPORT_SYMBOL(arch_unregister_cpu);
+#endif /*CONFIG_HOTPLUG_CPU*/
+
+
+static int __init topology_init(void)
+{
+ int i, err = 0;
+
+#ifdef CONFIG_NUMA
+ sysfs_nodes = kmalloc(sizeof(struct node) * MAX_NUMNODES, GFP_KERNEL);
+ if (!sysfs_nodes) {
+ err = -ENOMEM;
+ goto out;
+ }
+ memset(sysfs_nodes, 0, sizeof(struct node) * MAX_NUMNODES);
+
+ for (i = 0; i < numnodes; i++)
+ if ((err = register_node(&sysfs_nodes[i], i, 0)))
+ goto out;
+#endif
+
+ sysfs_cpus = kmalloc(sizeof(struct ia64_cpu) * NR_CPUS, GFP_KERNEL);
+ if (!sysfs_cpus) {
+ err = -ENOMEM;
+ goto out;
+ }
+ memset(sysfs_cpus, 0, sizeof(struct ia64_cpu) * NR_CPUS);
+
+ for_each_present_cpu(i)
+ if((err = arch_register_cpu(i)))
+ goto out;
+out:
+ return err;
+}
+
+__initcall(topology_init);
diff -puN arch/ia64/kernel/Makefile~topology arch/ia64/kernel/Makefile
--- linux-2.6.9-rc2/arch/ia64/kernel/Makefile~topology 2004-09-17 18:01:36.314557473 -0700
+++ linux-2.6.9-rc2-askeshav/arch/ia64/kernel/Makefile 2004-09-17 18:01:36.432721534 -0700
@@ -6,7 +6,8 @@ extra-y := head.o init_task.o vmlinux.ld
obj-y := acpi.o entry.o efi.o efi_stub.o gate-data.o fsys.o ia64_ksyms.o irq.o irq_ia64.o \
irq_lsapic.o ivt.o machvec.o pal.o patch.o process.o perfmon.o ptrace.o sal.o \
- salinfo.o semaphore.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o unwind.o mca.o mca_asm.o
+ salinfo.o semaphore.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o \
+ unwind.o mca.o mca_asm.o topology.o
obj-$(CONFIG_IA64_BRL_EMU) += brl_emu.o
obj-$(CONFIG_IA64_GENERIC) += acpi-ext.o
diff -puN include/asm-i386/cpu.h~topology include/asm-i386/cpu.h
--- linux-2.6.9-rc2/include/asm-i386/cpu.h~topology 2004-09-17 18:01:36.323346536 -0700
+++ linux-2.6.9-rc2-askeshav/include/asm-i386/cpu.h 2004-09-17 18:01:36.433698097 -0700
@@ -11,18 +11,9 @@ struct i386_cpu {
struct cpu cpu;
};
extern struct i386_cpu cpu_devices[NR_CPUS];
-
-
-static inline int arch_register_cpu(int num){
- struct node *parent = NULL;
-
-#ifdef CONFIG_NUMA
- int node = cpu_to_node(num);
- if (node_online(node))
- parent = &node_devices[node].node;
-#endif /* CONFIG_NUMA */
-
- return register_cpu(&cpu_devices[num].cpu, num, parent);
-}
+extern int arch_register_cpu(int num);
+#ifdef CONFIG_HOTPLUG_CPU
+extern void arch_unregister_cpu(int);
+#endif
#endif /* _ASM_I386_CPU_H_ */
diff -puN arch/i386/mach-default/topology.c~topology arch/i386/mach-default/topology.c
--- linux-2.6.9-rc2/arch/i386/mach-default/topology.c~topology 2004-09-17 18:01:36.330182473 -0700
+++ linux-2.6.9-rc2-askeshav/arch/i386/mach-default/topology.c 2004-09-17 18:01:36.434674659 -0700
@@ -31,6 +31,37 @@
struct i386_cpu cpu_devices[NR_CPUS];
+int arch_register_cpu(int num){
+ struct node *parent = NULL;
+
+#ifdef CONFIG_NUMA
+ int node = cpu_to_node(num);
+ if (node_online(node))
+ parent = &node_devices[node].node;
+#endif /* CONFIG_NUMA */
+
+ return register_cpu(&cpu_devices[num].cpu, num, parent);
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+
+void arch_unregister_cpu(int num) {
+ struct node *parent = NULL;
+
+#ifdef CONFIG_NUMA
+ int node = cpu_to_node(num);
+ if (node_online(node))
+ parent = &node_devices[node].node;
+#endif /* CONFIG_NUMA */
+
+ return unregister_cpu(&cpu_devices[num].cpu, parent);
+}
+EXPORT_SYMBOL(arch_register_cpu);
+EXPORT_SYMBOL(arch_unregister_cpu);
+#endif /*CONFIG_HOTPLUG_CPU*/
+
+
+
#ifdef CONFIG_NUMA
#include <linux/mmzone.h>
#include <asm/node.h>
diff -puN drivers/base/cpu.c~topology drivers/base/cpu.c
--- linux-2.6.9-rc2/drivers/base/cpu.c~topology 2004-09-17 18:01:36.335065286 -0700
+++ linux-2.6.9-rc2-askeshav/drivers/base/cpu.c 2004-09-17 18:01:36.435651222 -0700
@@ -46,10 +46,23 @@ static ssize_t store_online(struct sys_d
}
static SYSDEV_ATTR(online, 0600, show_online, store_online);
-static void __init register_cpu_control(struct cpu *cpu)
+static void __devinit register_cpu_control(struct cpu *cpu)
{
sysdev_create_file(&cpu->sysdev, &attr_online);
}
+void unregister_cpu(struct cpu *cpu, struct node *root)
+{
+
+ if (root)
+ sysfs_remove_link(&root->sysdev.kobj,
+ kobject_name(&cpu->sysdev.kobj));
+ sysdev_remove_file(&cpu->sysdev, &attr_online);
+
+ sysdev_unregister(&cpu->sysdev);
+
+ return;
+}
+EXPORT_SYMBOL(unregister_cpu);
#else /* ... !CONFIG_HOTPLUG_CPU */
static inline void register_cpu_control(struct cpu *cpu)
{
@@ -64,7 +77,7 @@ static inline void register_cpu_control(
*
* Initialize and register the CPU device.
*/
-int __init register_cpu(struct cpu *cpu, int num, struct node *root)
+int __devinit register_cpu(struct cpu *cpu, int num, struct node *root)
{
int error;
@@ -81,6 +94,9 @@ int __init register_cpu(struct cpu *cpu,
register_cpu_control(cpu);
return error;
}
+#ifdef CONFIG_HOTPLUG_CPU
+EXPORT_SYMBOL(register_cpu);
+#endif
_
Changes form previous version
1) Added depends on EXPERIMENTAL in kconfig file
---
Name:processor_drv.patch
Status:Tested on 2.6.9-rc2
Signed-off-by: Anil S Keshavamurthy <[email protected]>
Depends:
Version: applies on 2.6.9-rc2
Description:
Extends the processor driver to support ACPI based Physical CPU hotplug.
---
diff -puN drivers/acpi/Kconfig~processor_drv drivers/acpi/Kconfig
--- linux-2.6.9-rc2/drivers/acpi/Kconfig~processor_drv 2004-09-20 06:08:20.085257320 -0700
+++ linux-2.6.9-rc2-askeshav/drivers/acpi/Kconfig 2004-09-20 06:11:00.326896888 -0700
@@ -129,6 +129,14 @@ config ACPI_PROCESSOR
ACPI C2 and C3 processor states to save power, on systems that
support it.
+config ACPI_HOTPLUG_CPU
+ bool "Processor Hotplug (EXPERIMENTAL)"
+ depends on ACPI_PROCESSOR && HOTPLUG_CPU && EXPERIMENTAL
+ depends on !IA64_SGI_SN
+ default n
+ ---help---
+ Select this option if your platform support physical CPU hotplug.
+
config ACPI_THERMAL
tristate "Thermal Zone"
depends on ACPI_PROCESSOR
diff -puN include/linux/cpu.h~processor_drv include/linux/cpu.h
diff -puN kernel/cpu.c~processor_drv kernel/cpu.c
diff -puN drivers/acpi/processor.c~processor_drv drivers/acpi/processor.c
--- linux-2.6.9-rc2/drivers/acpi/processor.c~processor_drv 2004-09-20 06:08:20.102254736 -0700
+++ linux-2.6.9-rc2-askeshav/drivers/acpi/processor.c 2004-09-20 06:08:20.185242120 -0700
@@ -4,6 +4,8 @@
* Copyright (C) 2001, 2002 Andy Grover <[email protected]>
* Copyright (C) 2001, 2002 Paul Diefenbaugh <[email protected]>
* Copyright (C) 2004 Dominik Brodowski <[email protected]>
+ * Copyright (C) 2004 Anil S Keshavamurthy <[email protected]>
+ * - Added processor hotplug support
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
@@ -37,11 +39,13 @@
#include <linux/pci.h>
#include <linux/pm.h>
#include <linux/cpufreq.h>
+#include <linux/cpu.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <asm/io.h>
#include <asm/system.h>
+#include <asm/cpu.h>
#include <asm/delay.h>
#include <asm/uaccess.h>
#include <asm/processor.h>
@@ -69,10 +73,11 @@
#define C2_OVERHEAD 4 /* 1us (3.579 ticks per us) */
#define C3_OVERHEAD 4 /* 1us (3.579 ticks per us) */
-
#define ACPI_PROCESSOR_LIMIT_USER 0
#define ACPI_PROCESSOR_LIMIT_THERMAL 1
+#define ACPI_STA_PRESENT 0x00000001
+
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
ACPI_MODULE_NAME ("acpi_processor")
@@ -82,12 +87,15 @@ MODULE_LICENSE("GPL");
static int acpi_processor_add (struct acpi_device *device);
+static int acpi_processor_start (struct acpi_device *device);
static int acpi_processor_remove (struct acpi_device *device, int type);
static int acpi_processor_info_open_fs(struct inode *inode, struct file *file);
static int acpi_processor_throttling_open_fs(struct inode *inode, struct file *file);
static int acpi_processor_power_open_fs(struct inode *inode, struct file *file);
static int acpi_processor_limit_open_fs(struct inode *inode, struct file *file);
static int acpi_processor_get_limit_info(struct acpi_processor *pr);
+static void acpi_processor_notify ( acpi_handle handle, u32 event, void *data);
+static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu);
static struct acpi_driver acpi_processor_driver = {
.name = ACPI_PROCESSOR_DRIVER_NAME,
@@ -96,9 +104,12 @@ static struct acpi_driver acpi_processor
.ops = {
.add = acpi_processor_add,
.remove = acpi_processor_remove,
+ .start = acpi_processor_start,
},
};
+#define INSTALL_NOTIFY_HANDLER 1
+#define UNINSTALL_NOTIFY_HANDLER 2
struct acpi_processor_errata {
u8 smp;
@@ -2237,23 +2248,30 @@ acpi_processor_get_info (
cpu_index = convert_acpiid_to_cpu(pr->acpi_id);
- if ( !cpu0_initialized && (cpu_index == 0xff)) {
- /* Handle UP system running SMP kernel, with no LAPIC in MADT */
- cpu_index = 0;
- } else if (cpu_index > num_online_cpus()) {
- /*
- * Extra Processor objects may be enumerated on MP systems with
- * less than the max # of CPUs. They should be ignored.
- */
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error getting cpuindex for acpiid 0x%x\n",
- pr->acpi_id));
- return_VALUE(-ENODEV);
- }
- cpu0_initialized = 1;
-
- pr->id = cpu_index;
-
+ /* Handle UP system running SMP kernel, with no LAPIC in MADT */
+ if ( !cpu0_initialized && (cpu_index == 0xff) &&
+ (num_online_cpus() == 1)) {
+ cpu_index = 0;
+ }
+
+ cpu0_initialized = 1;
+
+ pr->id = cpu_index;
+
+ /*
+ * Extra Processor objects may be enumerated on MP systems with
+ * less than the max # of CPUs. They should be ignored _iff
+ * they are physically not present.
+ */
+ if (cpu_index >= NR_CPUS) {
+ if (ACPI_FAILURE(acpi_processor_hotadd_init(pr->handle, &pr->id))) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error getting cpuindex for acpiid 0x%x\n",
+ pr->acpi_id));
+ return_VALUE(-ENODEV);
+ }
+ }
+
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d:%d]\n", pr->id,
pr->acpi_id));
@@ -2292,6 +2310,65 @@ acpi_processor_get_info (
}
+static int
+acpi_processor_start(
+ struct acpi_device *device)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ u32 i = 0;
+ struct acpi_processor *pr;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_start");
+
+ pr = acpi_driver_data(device);
+
+ result = acpi_processor_get_info(pr);
+ if (result) {
+ /* Processor is physically not present */
+ return_VALUE(0);
+ }
+
+ BUG_ON((pr->id >= NR_CPUS) || (pr->id < 0));
+
+ processors[pr->id] = pr;
+
+ result = acpi_processor_add_fs(device);
+ if (result)
+ goto end;
+
+ status = acpi_install_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY,
+ acpi_processor_notify, pr);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error installing device notify handler\n"));
+ }
+
+ /*
+ * Install the idle handler if processor power management is supported.
+ * Note that the default idle handler (default_idle) will be used on
+ * platforms that only support C1.
+ */
+ if ((pr->id == 0) && (pr->flags.power)) {
+ pm_idle_save = pm_idle;
+ pm_idle = acpi_processor_idle;
+ }
+
+ printk(KERN_INFO PREFIX "%s [%s] (supports",
+ acpi_device_name(device), acpi_device_bid(device));
+ for (i=1; i<ACPI_C_STATE_COUNT; i++)
+ if (pr->power.states[i].valid)
+ printk(" C%d", i);
+ if (pr->flags.throttling)
+ printk(", %d throttling states", pr->throttling.state_count);
+ printk(")\n");
+end:
+
+ return_VALUE(result);
+}
+
+
+
static void
acpi_processor_notify (
acpi_handle handle,
@@ -2333,10 +2410,7 @@ static int
acpi_processor_add (
struct acpi_device *device)
{
- int result = 0;
- acpi_status status = AE_OK;
struct acpi_processor *pr = NULL;
- u32 i = 0;
ACPI_FUNCTION_TRACE("acpi_processor_add");
@@ -2353,51 +2427,7 @@ acpi_processor_add (
strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS);
acpi_driver_data(device) = pr;
- result = acpi_processor_get_info(pr);
- if (result)
- goto end;
-
- result = acpi_processor_add_fs(device);
- if (result)
- goto end;
-
- status = acpi_install_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY,
- acpi_processor_notify, pr);
- if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error installing notify handler\n"));
- result = -ENODEV;
- goto end;
- }
-
- processors[pr->id] = pr;
-
- /*
- * Install the idle handler if processor power management is supported.
- * Note that the default idle handler (default_idle) will be used on
- * platforms that only support C1.
- */
- if ((pr->id == 0) && (pr->flags.power)) {
- pm_idle_save = pm_idle;
- pm_idle = acpi_processor_idle;
- }
-
- printk(KERN_INFO PREFIX "%s [%s] (supports",
- acpi_device_name(device), acpi_device_bid(device));
- for (i=1; i<ACPI_C_STATE_COUNT; i++)
- if (pr->power.states[i].valid)
- printk(" C%d", i);
- if (pr->flags.throttling)
- printk(", %d throttling states", pr->throttling.state_count);
- printk(")\n");
-
-end:
- if (result) {
- acpi_processor_remove_fs(device);
- kfree(pr);
- }
-
- return_VALUE(result);
+ return_VALUE(0);
}
@@ -2416,6 +2446,21 @@ acpi_processor_remove (
pr = (struct acpi_processor *) acpi_driver_data(device);
+ if (pr->id >= NR_CPUS) {
+ kfree(pr);
+ return_VALUE(0);
+ }
+
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+ if (type == ACPI_BUS_REMOVAL_EJECT) {
+ if (cpu_online(pr->id)) {
+ return_VALUE(-EINVAL);
+ }
+ arch_unregister_cpu(pr->id);
+ acpi_unmap_lsapic(pr->id);
+ }
+#endif /* CONFIG_ACPI_HOTPLUG_CPU */
+
/* Unregister the idle handler when processor #0 is removed. */
if (pr->id == 0) {
pm_idle = pm_idle_save;
@@ -2426,7 +2471,7 @@ acpi_processor_remove (
acpi_processor_notify);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error removing notify handler\n"));
+ "Error removing device notify handler\n"));
}
acpi_processor_remove_fs(device);
@@ -2439,6 +2484,291 @@ acpi_processor_remove (
}
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+/****************************************************************************
+ * Acpi processor hotplug support *
+ ****************************************************************************/
+
+static int is_processor_present(acpi_handle handle);
+
+static int
+processor_run_sbin_hotplug(struct acpi_device *device,
+ int cpu, char *action)
+{
+ char *argv[3], *envp[7], action_str[32], cpu_str[15];
+ int i, ret;
+ int len;
+ char pathname[ACPI_PATHNAME_MAX] = {0};
+ acpi_status status;
+ char *processor_str;
+ struct acpi_buffer buffer = {ACPI_PATHNAME_MAX, pathname};
+
+ ACPI_FUNCTION_TRACE("processor_run_sbin_hotplug");
+
+
+ status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer);
+ if (ACPI_FAILURE(status)) {
+ return(-ENODEV);
+ }
+
+ len = strlen("PROCESSOR=") + strlen(pathname) + 1;
+ processor_str = kmalloc(len, GFP_KERNEL);
+ if (!processor_str)
+ return(-ENOMEM);
+
+ sprintf(processor_str, "PROCESSOR=%s",pathname);
+ sprintf(action_str, "ACTION=%s", action);
+ sprintf(cpu_str, "CPU=%d", cpu);
+
+ i = 0;
+ argv[i++] = hotplug_path;
+ argv[i++] = "cpu";
+ argv[i] = NULL;
+
+ i = 0;
+ envp[i++] = "HOME=/";
+ envp[i++] = "PATH=/sbin;/bin;/usr/sbin;/usr/bin";
+ envp[i++] = action_str;
+ envp[i++] = processor_str;
+ envp[i++] = cpu_str;
+ envp[i++] = "PLATFORM=ACPI";
+ envp[i] = NULL;
+
+ ret = call_usermodehelper(argv[0], argv, envp, 0);
+
+ kfree(processor_str);
+ return_VALUE(ret);
+}
+
+
+static int
+is_processor_present(
+ acpi_handle handle)
+{
+ acpi_status status;
+ unsigned long sta = 0;
+
+ ACPI_FUNCTION_TRACE("is_processor_present");
+
+ status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+ if (ACPI_FAILURE(status) || !(sta & ACPI_STA_PRESENT)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Processor Device is not present\n"));
+ return_VALUE(0);
+ }
+ return_VALUE(1);
+}
+
+
+static
+int acpi_processor_device_add(
+ acpi_handle handle,
+ struct acpi_device **device)
+{
+ acpi_handle phandle;
+ struct acpi_device *pdev;
+ struct acpi_processor *pr;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_device_add");
+
+ if (acpi_get_parent(handle, &phandle)) {
+ return_VALUE(-ENODEV);
+ }
+
+ if (acpi_bus_get_device(phandle, &pdev)) {
+ return_VALUE(-ENODEV);
+ }
+
+ if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_PROCESSOR)) {
+ return_VALUE(-ENODEV);
+ }
+
+ acpi_bus_scan(*device);
+
+ pr = acpi_driver_data(*device);
+ if (!pr)
+ return_VALUE(-ENODEV);
+
+ if ((pr->id >=0) && (pr->id < NR_CPUS)) {
+ processor_run_sbin_hotplug(*device, pr->id, "add");
+ }
+ return_VALUE(0);
+}
+
+
+static void
+acpi_processor_hotplug_notify (
+ acpi_handle handle,
+ u32 event,
+ void *data)
+{
+ struct acpi_processor *pr;
+ struct acpi_device *device = NULL;
+ int result;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_hotplug_notify");
+
+ switch (event) {
+ case ACPI_NOTIFY_BUS_CHECK:
+ case ACPI_NOTIFY_DEVICE_CHECK:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "received %s\n", (event==ACPI_NOTIFY_BUS_CHECK)?
+ "ACPI_NOTIFY_BUS_CHECK":"ACPI_NOTIFY_DEVICE_CHECK"));
+
+ if (!is_processor_present(handle))
+ break;
+
+ if (acpi_bus_get_device(handle, &device)) {
+ result = acpi_processor_device_add(handle, &device);
+ if (result)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to add the device\n"));
+ break;
+ }
+
+ pr = acpi_driver_data(device);
+ if (!pr) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Driver data is NULL\n"));
+ break;
+ }
+
+ if (pr->id >= 0 && (pr->id < NR_CPUS)) {
+ processor_run_sbin_hotplug(device, pr->id, "remove");
+ break;
+ }
+
+ result = acpi_processor_start(device);
+ if ((!result) && ((pr->id >=0) && (pr->id < NR_CPUS))) {
+ processor_run_sbin_hotplug(device, pr->id, "add");
+ } else {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Device [%s] failed to start\n",
+ acpi_device_bid(device)));
+ }
+ break;
+ case ACPI_NOTIFY_EJECT_REQUEST:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,"received ACPI_NOTIFY_EJECT_REQUEST\n"));
+
+ if (acpi_bus_get_device(handle, &device)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,"Device don't exist, dropping EJECT\n"));
+ break;
+ }
+ pr = acpi_driver_data(device);
+ if (!pr) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,"Driver data is NULL, dropping EJECT\n"));
+ return_VOID;
+ }
+
+ if ((pr->id < NR_CPUS) && (cpu_present(pr->id)))
+ processor_run_sbin_hotplug(device, pr->id, "remove");
+ break;
+ default:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Unsupported event [0x%x]\n", event));
+ break;
+ }
+
+ return_VOID;
+}
+
+static acpi_status
+processor_walk_namespace_cb(acpi_handle handle,
+ u32 lvl,
+ void *context,
+ void **rv)
+{
+ acpi_status status;
+ int *action = context;
+ acpi_object_type type = 0;
+
+ status = acpi_get_type(handle, &type);
+ if (ACPI_FAILURE(status))
+ return(AE_OK);
+
+ if (type != ACPI_TYPE_PROCESSOR)
+ return(AE_OK);
+
+ switch(*action) {
+ case INSTALL_NOTIFY_HANDLER:
+ acpi_install_notify_handler(handle,
+ ACPI_SYSTEM_NOTIFY,
+ acpi_processor_hotplug_notify,
+ NULL);
+ break;
+ case UNINSTALL_NOTIFY_HANDLER:
+ acpi_remove_notify_handler(handle,
+ ACPI_SYSTEM_NOTIFY,
+ acpi_processor_hotplug_notify);
+ break;
+ default:
+ break;
+ }
+
+ return(AE_OK);
+}
+
+
+static acpi_status
+acpi_processor_hotadd_init(
+ acpi_handle handle,
+ int *p_cpu)
+{
+ ACPI_FUNCTION_TRACE("acpi_processor_hotadd_init");
+
+ if (!is_processor_present(handle)) {
+ return_VALUE(AE_ERROR);
+ }
+
+ if (acpi_map_lsapic(handle, p_cpu))
+ return_VALUE(AE_ERROR);
+
+ if (arch_register_cpu(*p_cpu)) {
+ acpi_unmap_lsapic(*p_cpu);
+ return_VALUE(AE_ERROR);
+ }
+
+ return_VALUE(AE_OK);
+}
+#else
+static acpi_status
+acpi_processor_hotadd_init(
+ acpi_handle handle,
+ int *p_cpu)
+{
+ return AE_ERROR;
+}
+#endif
+
+
+static
+void acpi_processor_install_hotplug_notify(void)
+{
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+ int action = INSTALL_NOTIFY_HANDLER;
+ acpi_walk_namespace(ACPI_TYPE_PROCESSOR,
+ ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX,
+ processor_walk_namespace_cb,
+ &action, NULL);
+#endif
+}
+
+
+static
+void acpi_processor_uninstall_hotplug_notify(void)
+{
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+ int action = UNINSTALL_NOTIFY_HANDLER;
+ acpi_walk_namespace(ACPI_TYPE_PROCESSOR,
+ ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX,
+ processor_walk_namespace_cb,
+ &action, NULL);
+#endif
+}
+
+
static int __init
acpi_processor_init (void)
{
@@ -2460,6 +2790,8 @@ acpi_processor_init (void)
return_VALUE(-ENODEV);
}
+ acpi_processor_install_hotplug_notify();
+
acpi_thermal_cpufreq_init();
acpi_processor_ppc_init();
@@ -2477,6 +2809,8 @@ acpi_processor_exit (void)
acpi_thermal_cpufreq_exit();
+ acpi_processor_uninstall_hotplug_notify();
+
acpi_bus_unregister_driver(&acpi_processor_driver);
remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
_
Changes from previous release:
1) Typo fix- ACPI004 to ACPI0004
2) Added depends on EXPERIMENTAL in Kconfig file
---
Name:container_drv.patch
Status: Tested on 2.6.9-rc1
Signed-off-by: Anil S Keshavamurthy <[email protected]>
Depends:
Version: applies on 2.6.9-rc1
Description:
This is the very early version on the Container driver which supports
hotplug notifications on ACPI0004, PNP0A05 and PNP0A06 devices.
Changes from previous release:
1) Mergerd the typo fix patch which changes "ACPI004" to "ACPI0004"
---
diff -puN drivers/acpi/Kconfig~container_drv drivers/acpi/Kconfig
--- linux-2.6.9-rc2/drivers/acpi/Kconfig~container_drv 2004-09-20 06:12:12.485927048 -0700
+++ linux-2.6.9-rc2-askeshav/drivers/acpi/Kconfig 2004-09-20 06:15:25.020657320 -0700
@@ -133,6 +133,7 @@ config ACPI_HOTPLUG_CPU
bool "Processor Hotplug (EXPERIMENTAL)"
depends on ACPI_PROCESSOR && HOTPLUG_CPU && EXPERIMENTAL
depends on !IA64_SGI_SN
+ select ACPI_CONTAINER
default n
---help---
Select this option if your platform support physical CPU hotplug.
@@ -278,5 +279,12 @@ config X86_PM_TIMER
kernel logs, and/or you are using this on a notebook which
does not yet have an HPET, you should say "Y" here.
-endmenu
+config ACPI_CONTAINER
+ tristate "ACPI0004,PNP0A05 and PNP0A06 Container Driver (EXPERIMENTAL)"
+ depends on ACPI && EXPERIMENTAL
+ default (ACPI_HOTPLUG_MEMORY || ACPI_HOTPLUG_CPU || ACPI_HOTPLUG_IO)
+ ---help---
+ This is the ACPI generic container driver which supports
+ ACPI0004, PNP0A05 and PNP0A06 devices
+endmenu
diff -puN drivers/acpi/Makefile~container_drv drivers/acpi/Makefile
--- linux-2.6.9-rc2/drivers/acpi/Makefile~container_drv 2004-09-20 06:12:12.490926288 -0700
+++ linux-2.6.9-rc2-askeshav/drivers/acpi/Makefile 2004-09-20 06:12:12.570914128 -0700
@@ -41,6 +41,7 @@ obj-$(CONFIG_ACPI_FAN) += fan.o
obj-$(CONFIG_ACPI_PCI) += pci_root.o pci_link.o pci_irq.o pci_bind.o
obj-$(CONFIG_ACPI_POWER) += power.o
obj-$(CONFIG_ACPI_PROCESSOR) += processor.o
+obj-$(CONFIG_ACPI_CONTAINER) += container.o
obj-$(CONFIG_ACPI_THERMAL) += thermal.o
obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o
obj-$(CONFIG_ACPI_DEBUG) += debug.o
diff -puN /dev/null include/acpi/container.h
--- /dev/null 2004-04-06 06:27:52.000000000 -0700
+++ linux-2.6.9-rc2-askeshav/include/acpi/container.h 2004-09-20 06:12:12.571913976 -0700
@@ -0,0 +1,13 @@
+#ifndef __ACPI_CONTAINER_H
+#define __ACPI_CONTAINER_H
+
+#include <linux/kernel.h>
+
+struct acpi_container {
+ acpi_handle handle;
+ unsigned long sun;
+ int state;
+};
+
+#endif /* __ACPI_CONTAINER_H */
+
diff -puN /dev/null drivers/acpi/container.c
--- /dev/null 2004-04-06 06:27:52.000000000 -0700
+++ linux-2.6.9-rc2-askeshav/drivers/acpi/container.c 2004-09-20 06:12:12.573913672 -0700
@@ -0,0 +1,341 @@
+/*
+ * acpi_container.c - ACPI Generic Container Driver
+ * ($Revision: )
+ *
+ * Copyright (C) 2004 Anil S Keshavamurthy ([email protected])
+ * Copyright (C) 2004 Keiichiro Tokunaga ([email protected])
+ * Copyright (C) 2004 Motoyuki Ito ([email protected])
+ * Copyright (C) 2004 Intel Corp.
+ * Copyright (C) 2004 FUJITSU LIMITED
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/acpi.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/container.h>
+
+#define ACPI_CONTAINER_DRIVER_NAME "ACPI container driver"
+#define ACPI_CONTAINER_DEVICE_NAME "ACPI container device"
+#define ACPI_CONTAINER_CLASS "container"
+
+#define INSTALL_NOTIFY_HANDLER 1
+#define UNINSTALL_NOTIFY_HANDLER 2
+
+#define ACPI_CONTAINER_COMPONENT 0x01000000
+#define _COMPONENT ACPI_CONTAINER_COMPONENT
+ACPI_MODULE_NAME ("acpi_container")
+
+MODULE_AUTHOR("Anil S Keshavamurthy");
+MODULE_DESCRIPTION(ACPI_CONTAINER_DRIVER_NAME);
+MODULE_LICENSE("GPL");
+
+#define ACPI_STA_PRESENT (0x00000001)
+
+static int acpi_container_add(struct acpi_device *device);
+static int acpi_container_remove(struct acpi_device *device, int type);
+
+static struct acpi_driver acpi_container_driver = {
+ .name = ACPI_CONTAINER_DRIVER_NAME,
+ .class = ACPI_CONTAINER_CLASS,
+ .ids = "ACPI0004,PNP0A05,PNP0A06",
+ .ops = {
+ .add = acpi_container_add,
+ .remove = acpi_container_remove,
+ },
+};
+
+
+/*******************************************************************/
+
+static int
+is_device_present(acpi_handle handle)
+{
+ acpi_handle temp;
+ acpi_status status;
+ unsigned long sta;
+
+ ACPI_FUNCTION_TRACE("is_device_present");
+
+ status = acpi_get_handle(handle, "_STA", &temp);
+ if (ACPI_FAILURE(status))
+ return_VALUE(1); /* _STA not found, assmue device present */
+
+ status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+ if (ACPI_FAILURE(status))
+ return_VALUE(0); /* Firmware error */
+
+ return_VALUE((sta & ACPI_STA_PRESENT) == ACPI_STA_PRESENT);
+}
+
+/*******************************************************************/
+static int
+acpi_container_add(struct acpi_device *device)
+{
+ struct acpi_container *container;
+
+ ACPI_FUNCTION_TRACE("acpi_container_add");
+
+ if (!device) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "device is NULL\n"));
+ return_VALUE(-EINVAL);
+ }
+
+ container = kmalloc(sizeof(struct acpi_container), GFP_KERNEL);
+ if(!container)
+ return_VALUE(-ENOMEM);
+
+ memset(container, 0, sizeof(struct acpi_container));
+ container->handle = device->handle;
+ strcpy(acpi_device_name(device), ACPI_CONTAINER_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_CONTAINER_CLASS);
+ acpi_driver_data(device) = container;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device <%s> bid <%s>\n", \
+ acpi_device_name(device), acpi_device_bid(device)));
+
+
+ return_VALUE(0);
+}
+
+static int
+acpi_container_remove(struct acpi_device *device, int type)
+{
+ acpi_status status = AE_OK;
+ struct acpi_container *pc = NULL;
+ pc = (struct acpi_container*) acpi_driver_data(device);
+
+ if (pc)
+ kfree(pc);
+
+ return status;
+}
+
+
+static int
+container_run_sbin_hotplug(struct acpi_device *device, char *action)
+{
+ char *argv[3], *envp[6], action_str[32];
+ int i, ret;
+ int len;
+ char pathname[ACPI_PATHNAME_MAX] = {0};
+ acpi_status status;
+ char *container_str;
+ struct acpi_buffer buffer = {ACPI_PATHNAME_MAX, pathname};
+
+ ACPI_FUNCTION_TRACE("container_run_sbin_hotplug");
+
+
+ status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer);
+ if (ACPI_FAILURE(status)) {
+ return(-ENODEV);
+ }
+
+ len = strlen("CONTAINER=") + strlen(pathname) + 1;
+ container_str = kmalloc(len, GFP_KERNEL);
+ if (!container_str)
+ return(-ENOMEM);
+
+ sprintf(container_str, "CONTAINER=%s",pathname);
+ sprintf(action_str, "ACTION=%s", action);
+
+ i = 0;
+ argv[i++] = hotplug_path;
+ argv[i++] = "container";
+ argv[i] = NULL;
+
+ i = 0;
+ envp[i++] = "HOME=/";
+ envp[i++] = "PATH=/sbin;/bin;/usr/sbin;/usr/bin";
+ envp[i++] = action_str;
+ envp[i++] = container_str;
+ envp[i++] = "PLATFORM=ACPI";
+ envp[i] = NULL;
+
+ ret = call_usermodehelper(argv[0], argv, envp, 0);
+
+ kfree(container_str);
+ return_VALUE(ret);
+}
+
+static int
+container_device_add(struct acpi_device **device, acpi_handle handle)
+{
+ acpi_handle phandle;
+ struct acpi_device *pdev;
+ int result;
+
+ ACPI_FUNCTION_TRACE("container_device_add");
+
+ if (acpi_get_parent(handle, &phandle)) {
+ return_VALUE(-ENODEV);
+ }
+
+ if (acpi_bus_get_device(phandle, &pdev)) {
+ return_VALUE(-ENODEV);
+ }
+
+ if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_DEVICE)) {
+ return_VALUE(-ENODEV);
+ }
+
+ result = acpi_bus_scan(*device);
+
+ return_VALUE(result);
+}
+
+static void
+container_notify_cb(acpi_handle handle, u32 type, void *context)
+{
+ struct acpi_device *device = NULL;
+ int result;
+ int present;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE("container_notify_cb");
+
+ present = is_device_present(handle);
+
+ switch (type) {
+ case ACPI_NOTIFY_BUS_CHECK:
+ /* Fall through */
+ case ACPI_NOTIFY_DEVICE_CHECK:
+ if (present) {
+ status = acpi_bus_get_device(handle, &device);
+ if (ACPI_FAILURE(status) || !device) {
+ result = container_device_add(&device, handle);
+ if (!result)
+ container_run_sbin_hotplug(device, "add");
+ } else {
+ /* device exist and this is a remove request */
+ container_run_sbin_hotplug(device, "remove");
+ }
+ }
+ break;
+ case ACPI_NOTIFY_EJECT_REQUEST:
+ if (!acpi_bus_get_device(handle, &device) && device) {
+ container_run_sbin_hotplug(device, "remove");
+ }
+ break;
+ default:
+ break;
+ }
+ return_VOID;
+}
+
+static acpi_status
+container_walk_namespace_cb(acpi_handle handle,
+ u32 lvl,
+ void *context,
+ void **rv)
+{
+ char *hid = NULL;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ struct acpi_device_info *info;
+ acpi_status status;
+ int *action = context;
+
+ ACPI_FUNCTION_TRACE("container_walk_namespace_cb");
+
+ status = acpi_get_object_info(handle, &buffer);
+ if (ACPI_FAILURE(status) || !buffer.pointer) {
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ info = buffer.pointer;
+ if (info->valid & ACPI_VALID_HID)
+ hid = info->hardware_id.value;
+
+ if (hid == NULL) {
+ goto end;
+ }
+
+ if (strcmp(hid, "ACPI0004") && strcmp(hid, "PNP0A05") &&
+ strcmp(hid, "PNP0A06")) {
+ goto end;
+ }
+
+ switch(*action) {
+ case INSTALL_NOTIFY_HANDLER:
+ acpi_install_notify_handler(handle,
+ ACPI_SYSTEM_NOTIFY,
+ container_notify_cb,
+ NULL);
+ break;
+ case UNINSTALL_NOTIFY_HANDLER:
+ acpi_remove_notify_handler(handle,
+ ACPI_SYSTEM_NOTIFY,
+ container_notify_cb);
+ break;
+ default:
+ break;
+ }
+
+end:
+ acpi_os_free(buffer.pointer);
+
+ return_ACPI_STATUS(AE_OK);
+}
+
+
+int __init
+acpi_container_init(void)
+{
+ int result = 0;
+ int action = INSTALL_NOTIFY_HANDLER;
+
+ result = acpi_bus_register_driver(&acpi_container_driver);
+ if (result < 0) {
+ return(result);
+ }
+
+ /* register notify handler to every container device */
+ acpi_walk_namespace(ACPI_TYPE_DEVICE,
+ ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX,
+ container_walk_namespace_cb,
+ &action, NULL);
+
+ return(0);
+}
+
+void __exit
+acpi_container_exit(void)
+{
+ int action = UNINSTALL_NOTIFY_HANDLER;
+
+ ACPI_FUNCTION_TRACE("acpi_container_exit");
+
+ acpi_walk_namespace(ACPI_TYPE_DEVICE,
+ ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX,
+ container_walk_namespace_cb,
+ &action, NULL);
+
+ acpi_bus_unregister_driver(&acpi_container_driver);
+
+ return_VOID;
+}
+
+module_init(acpi_container_init);
+module_exit(acpi_container_exit);
_
On Monday 20 September 2004 11:35 am, Keshavamurthy Anil S wrote:
> This patch support /sys/firmware/acpi/eject interface where in
> the ACPI device say "LSB0" can be ejected by echoing "\_SB.LSB0" >
> /sys/firmware/acpi/eject
>
I wonder if eject should be an attribute of an individual device and visible
only when device can be ejected. Reading from it could show eject level
(_EJ0/_EJ3 etc).
--
Dmitry
On Mon, Sep 20, 2004 at 01:33:42PM -0500, Dmitry Torokhov wrote:
> On Monday 20 September 2004 11:35 am, Keshavamurthy Anil S wrote:
> > This patch support /sys/firmware/acpi/eject interface where in
> > the ACPI device say "LSB0" can be ejected by echoing "\_SB.LSB0" >
> > /sys/firmware/acpi/eject
> >
>
> I wonder if eject should be an attribute of an individual device and visible
> only when device can be ejected. Reading from it could show eject level
> (_EJ0/_EJ3 etc).
Hi Dmitry,
Today there is really no sysfs representation of acpi devices apart from
the acpi namespace representation. Evaluating acpi namespaces's _EJ0 method won't help,
as we need acpi device and all its child devices to be removed as part of the eject.
Also for there is no 1:1 maping of acpi devices to pci devices to consider eject to be
part of the pci devices.
Hence the best solution for now is to echo ACPI full path name of the device to be
ejected onto the eject file and the code will make sure that the device supports _EJx method before actuall removing the device.
thanks,
Anil
>
> --
> Dmitry
On Monday 20 September 2004 02:24 pm, Keshavamurthy Anil S wrote:
> On Mon, Sep 20, 2004 at 01:33:42PM -0500, Dmitry Torokhov wrote:
> > On Monday 20 September 2004 11:35 am, Keshavamurthy Anil S wrote:
> > > This patch support /sys/firmware/acpi/eject interface where in
> > > the ACPI device say "LSB0" can be ejected by echoing "\_SB.LSB0" >
> > > /sys/firmware/acpi/eject
> > >
> >
> > I wonder if eject should be an attribute of an individual device and visible
> > only when device can be ejected. Reading from it could show eject level
> > (_EJ0/_EJ3 etc).
> Hi Dmitry,
> Today there is really no sysfs representation of acpi devices apart from
> the acpi namespace representation. Evaluating acpi namespaces's _EJ0 method won't help,
> as we need acpi device and all its child devices to be removed as part of the eject.
>
> Also for there is no 1:1 maping of acpi devices to pci devices to consider eject to be
> part of the pci devices.
>
> Hence the best solution for now is to echo ACPI full path name of the device to be
> ejected onto the eject file and the code will make sure that the device supports _EJx method before actuall removing the device.
>
Hi Anil,
I obviously failed to deliver my idea :) I meant that I would like add eject
attribute (along with maybe status, hid and some others) to kobjects in
/sys/firmware/acpi tree.
I also wonder if userspace should traverse tree and emit eject requests for
children. While it is OK for user[space]-initiated removal what about surprise
removal. My concern that scripts will not be ready for all devices to be
suddently gone... Would not it be beter if generic handler for BUS_CHECK was
implemented in acpi/bus.c that would add/remove acpi devices and notify
userspace via hotplug?
--
Dmitry
On Mon, 2004-09-20 at 18:12 -0500, Dmitry Torokhov wrote:
>
> Hi Anil,
>
> I obviously failed to deliver my idea :) I meant that I would like add eject
> attribute (along with maybe status, hid and some others) to kobjects in
> /sys/firmware/acpi tree.
>
Dmitry,
See the patch I just posted to acpi-devel and lkml (Subject:
[PATCH/RFC] exposing ACPI objects in sysfs). It exposes acpi objects as
you describe. Something simple like:
# cat /sys/firmware/acpi/namespace/ACPI/_SB/LSB0/_EJ0
Will call the _EJ0 method on the ACPI device. You can evaluate eject
dependencies using the _EJD method.
Alex
On Monday 20 September 2004 07:52 pm, Alex Williamson wrote:
> On Mon, 2004-09-20 at 18:12 -0500, Dmitry Torokhov wrote:
> >
> > Hi Anil,
> >
> > I obviously failed to deliver my idea :) I meant that I would like add eject
> > attribute (along with maybe status, hid and some others) to kobjects in
> > /sys/firmware/acpi tree.
> >
>
> Dmitry,
>
> See the patch I just posted to acpi-devel and lkml (Subject:
> [PATCH/RFC] exposing ACPI objects in sysfs). It exposes acpi objects as
> you describe. Something simple like:
>
> # cat /sys/firmware/acpi/namespace/ACPI/_SB/LSB0/_EJ0
>
> Will call the _EJ0 method on the ACPI device. You can evaluate eject
> dependencies using the _EJD method.
>
> Alex
>
Alex,
While I think that your patch is very important and should be included (maybe
if not as is if somebody has some objections but in some other form) I see it
more like developer's tool. I imagined status, HID, eject etc. attributes to
be sanitized interface to kernel's data, not necessarily causing re-evaluation.
So it could be like this:
/sys/firmware/acpi/namespace/ACPI/_SB/LSB0/status
/sys/firmware/acpi/namespace/ACPI/_SB/LSB0/removable
/sys/firmware/acpi/namespace/ACPI/_SB/LSB0/lockable
..
/sys/firmware/acpi/namespace/ACPI/_SB/LSB0/eject
And your raw access to the ACPI methods could reside under raw:
/sys/firmware/acpi/namespace/ACPI/_SB/LSB0/raw/_STA
/sys/firmware/acpi/namespace/ACPI/_SB/LSB0/raw/_RNV
/sys/firmware/acpi/namespace/ACPI/_SB/LSB0/raw/_LCK
..
/sys/firmware/acpi/namespace/ACPI/_SB/LSB0/raw/_EJ0
--
Dmitry
On Mon, Sep 20, 2004 at 08:20:05PM -0500, Dmitry Torokhov wrote:
> On Monday 20 September 2004 07:52 pm, Alex Williamson wrote:
> > On Mon, 2004-09-20 at 18:12 -0500, Dmitry Torokhov wrote:
> > >
> > > Hi Anil,
> > >
> > > I obviously failed to deliver my idea :) I meant that I would like add eject
> > > attribute (along with maybe status, hid and some others) to kobjects in
> > > /sys/firmware/acpi tree.
> > >
> >
> > Dmitry,
> >
> > See the patch I just posted to acpi-devel and lkml (Subject:
> > [PATCH/RFC] exposing ACPI objects in sysfs). It exposes acpi objects as
> > you describe. Something simple like:
> >
> > # cat /sys/firmware/acpi/namespace/ACPI/_SB/LSB0/_EJ0
> >
> > Will call the _EJ0 method on the ACPI device. You can evaluate eject
> > dependencies using the _EJD method.
> >
> > Alex
> >
>
> Alex,
>
> While I think that your patch is very important and should be included (maybe
> if not as is if somebody has some objections but in some other form) I see it
> more like developer's tool. I imagined status, HID, eject etc. attributes to
> be sanitized interface to kernel's data, not necessarily causing re-evaluation.
>
> So it could be like this:
>
> /sys/firmware/acpi/namespace/ACPI/_SB/LSB0/status
> /sys/firmware/acpi/namespace/ACPI/_SB/LSB0/removable
> /sys/firmware/acpi/namespace/ACPI/_SB/LSB0/lockable
> ..
> /sys/firmware/acpi/namespace/ACPI/_SB/LSB0/eject
Ha..Now I got it and what you are saying sounds right
thing to do. I will invistigate more and will get back to
the mailing list hopefully with the patch:)
>
> And your raw access to the ACPI methods could reside under raw:
>
> /sys/firmware/acpi/namespace/ACPI/_SB/LSB0/raw/_STA
> /sys/firmware/acpi/namespace/ACPI/_SB/LSB0/raw/_RNV
> /sys/firmware/acpi/namespace/ACPI/_SB/LSB0/raw/_LCK
> ..
> /sys/firmware/acpi/namespace/ACPI/_SB/LSB0/raw/_EJ0
>
> --
> Dmitry
On Mon, Sep 20, 2004 at 06:12:45PM -0500, Dmitry Torokhov wrote:
> On Monday 20 September 2004 02:24 pm, Keshavamurthy Anil S wrote:
> > On Mon, Sep 20, 2004 at 01:33:42PM -0500, Dmitry Torokhov wrote:
> > > On Monday 20 September 2004 11:35 am, Keshavamurthy Anil S wrote:
> > > > This patch support /sys/firmware/acpi/eject interface where in
> > > > the ACPI device say "LSB0" can be ejected by echoing "\_SB.LSB0" >
> > > > /sys/firmware/acpi/eject
> > > >
> > >
> > > I wonder if eject should be an attribute of an individual device and visible
> > > only when device can be ejected. Reading from it could show eject level
> > > (_EJ0/_EJ3 etc).
> > Hi Dmitry,
> > Today there is really no sysfs representation of acpi devices apart from
> > the acpi namespace representation. Evaluating acpi namespaces's _EJ0 method won't help,
> > as we need acpi device and all its child devices to be removed as part of the eject.
> >
> > Also for there is no 1:1 maping of acpi devices to pci devices to consider eject to be
> > part of the pci devices.
> >
> > Hence the best solution for now is to echo ACPI full path name of the device to be
> > ejected onto the eject file and the code will make sure that the device supports _EJx method before actuall removing the device.
> >
>
> Hi Anil,
>
> I obviously failed to deliver my idea :) I meant that I would like add eject
> attribute (along with maybe status, hid and some others) to kobjects in
> /sys/firmware/acpi tree.
I got this one and as I have said I will come up with the path soon:)
>
> I also wonder if userspace should traverse tree and emit eject requests for
> children. While it is OK for user[space]-initiated removal what about surprise
> removal. My concern that scripts will not be ready for all devices to be
> suddently gone... Would not it be beter if generic handler for BUS_CHECK was
> implemented in acpi/bus.c that would add/remove acpi devices and notify
> userspace via hotplug?
Can you please clarify my concern here.
Currently I am handling both the surprise removal and the eject request in the same
way, i,e send the notification to the userland and the usermode agent scripts
is responsible for offlining of all the devices and then echoing onto eject file.
My worry is if we implement a generic handler for BUS_CHECK, then what would you
do if the device fails to remove, i.e what action to take if the device remove fails?
Thanks,
Anil
On Mon, 2004-09-20 at 20:20 -0500, Dmitry Torokhov wrote:
> On Monday 20 September 2004 07:52 pm, Alex Williamson wrote:
> > On Mon, 2004-09-20 at 18:12 -0500, Dmitry Torokhov wrote:
> > >
> > > Hi Anil,
> > >
> > > I obviously failed to deliver my idea :) I meant that I would like add eject
> > > attribute (along with maybe status, hid and some others) to kobjects in
> > > /sys/firmware/acpi tree.
> > >
> >
> > Dmitry,
> >
> > See the patch I just posted to acpi-devel and lkml (Subject:
> > [PATCH/RFC] exposing ACPI objects in sysfs). It exposes acpi objects as
> > you describe. Something simple like:
> >
> > # cat /sys/firmware/acpi/namespace/ACPI/_SB/LSB0/_EJ0
> >
> > Will call the _EJ0 method on the ACPI device. You can evaluate eject
> > dependencies using the _EJD method.
> >
> > Alex
> >
>
> Alex,
>
> While I think that your patch is very important and should be included (maybe
> if not as is if somebody has some objections but in some other form) I see it
> more like developer's tool. I imagined status, HID, eject etc. attributes to
> be sanitized interface to kernel's data, not necessarily causing re-evaluation.
>
Dmitry,
I imagined the sanitized interfaces would be provided via a userspace
library, similar to how lspci provides a clean interface to all of the
PCI data. An "lsacpi" tool could extract the information into something
more like you suggest. If you have objects exposed as human
readable/writable files, I think you'll quickly end up with a _STA
driver, _HID driver, _CID driver, _ADR driver, _UID driver, _EJx driver,
etc, etc, etc... I don't think we want that kind of bloat in the kernel
(that's what userspace is for ;^). Providing a solid, direct interface
to ACPI methods in the kernel seems like the most flexible, powerful
interface IMHO. Thanks,
Alex
> So it could be like this:
>
> /sys/firmware/acpi/namespace/ACPI/_SB/LSB0/status
> /sys/firmware/acpi/namespace/ACPI/_SB/LSB0/removable
> /sys/firmware/acpi/namespace/ACPI/_SB/LSB0/lockable
> ..
> /sys/firmware/acpi/namespace/ACPI/_SB/LSB0/eject
>
> And your raw access to the ACPI methods could reside under raw:
>
> /sys/firmware/acpi/namespace/ACPI/_SB/LSB0/raw/_STA
> /sys/firmware/acpi/namespace/ACPI/_SB/LSB0/raw/_RNV
> /sys/firmware/acpi/namespace/ACPI/_SB/LSB0/raw/_LCK
> ..
> /sys/firmware/acpi/namespace/ACPI/_SB/LSB0/raw/_EJ0
On Monday 20 September 2004 08:41 pm, Alex Williamson wrote:
> Dmitry,
>
> Â Â I imagined the sanitized interfaces would be provided via a userspace
> library, similar to how lspci provides a clean interface to all of the
> PCI data. Â An "lsacpi" tool could extract the information into something
> more like you suggest. Â If you have objects exposed as human
> readable/writable files, I think you'll quickly end up with a _STA
> driver, _HID driver, _CID driver, _ADR driver, _UID driver, _EJx driver,
> etc, etc, etc... Â I don't think we want that kind of bloat in the kernel
> (that's what userspace is for ;^). Â Providing a solid, direct interface
> to ACPI methods in the kernel seems like the most flexible, powerful
> interface IMHO.
Hmm, I do not quite agree. Except for "eject" being writeable to initiate
eject action the rest of the attributes would reflect kernel's view of the
device state and not re-evaluated when userspace references them. Monitoring
(or rather reacting to various events, like DEVICE_CHECK and BUS_CHECK) and
updating devices' statuses and other data is responsibility of the core ACPI
system. If system administrator is forced to manually (via libacpi or sysfs)
query device status to "kick" the device into working state I'd consider it
a bug, would'nt you agree?
I see that in your other mail you mention _CRS parsing and chipset discovery.
I think that if you had an ability to just retrieve raw ACPI data from the
system that would suffice. In other words during normal operations there
is no need for "active" ACPI methods (such as _WAK, _S4, etc) to be available
from userspace. And just exporting raw data solves problem of bloating kernel
with parsing of vendor-specific data. I wonder if any of these methods need
arguments to run - if not then we would not need any adjustments to sysfs
opeen/close methods.
I am not saying that we should chose one method or another. I think they both
can co-exist, as they can be used for diffectent purposes - the raw ACPI access
can affect state of the box while the sanitized attributes present kernel's
view and can be used to verify results of some action from kernel's POV.
--
Dmitry
On Monday 20 September 2004 08:38 pm, Keshavamurthy Anil S wrote:
> Currently I am handling both the surprise removal and the eject request in the same
> way, i,e send the notification to the userland and the usermode agent scripts
> is responsible for offlining of all the devices and then echoing onto eject file.
>
I actually think that on the highest level we should treat controlled and
surprise ejects differently. With controlled ejects the system (kernel +
userspace) can abort the sequence if something goes wrong while with surprise
eject the device is physically gone. Even if driver refuses to detach or we
have partition still mounted or something else if physical device is gone we
don't have any choice except for trimming the tree and doing whatever we need
to do.
> My worry is if we implement a generic handler for BUS_CHECK, then what would you
> do if the device fails to remove, i.e what action to take if the device remove fails?
>
It could depend on parent's status. If parent is gone (surprise removal) we will
trim. If it is controlled removal and driver does not let device go we could
abort eject.
Or we could always trim and offload the responsibility of having the system in
ready-to-eject state to the userspace. I.e. it should not write into "eject"
unless everything is unmounted/shut down/disconnected.
I am a bit light on implementation details though ;)
--
Dmitry
On Tue, Sep 21, 2004 at 12:51:36AM -0500, Dmitry Torokhov wrote:
> On Monday 20 September 2004 08:38 pm, Keshavamurthy Anil S wrote:
> > Currently I am handling both the surprise removal and the eject request in the same
> > way, i,e send the notification to the userland and the usermode agent scripts
> > is responsible for offlining of all the devices and then echoing onto eject file.
> >
>
> I actually think that on the highest level we should treat controlled and
> surprise ejects differently. With controlled ejects the system (kernel +
> userspace) can abort the sequence if something goes wrong while with surprise
> eject the device is physically gone. Even if driver refuses to detach or we
> have partition still mounted or something else if physical device is gone we
> don't have any choice except for trimming the tree and doing whatever we need
> to do.
I agree, but when dealing with devices like CPU and Memory, not sure how the
rest of the Operating System handles surprise removal. For now I will go ahead and
add a PRINTK saying that BUS_CHECK(surprise removal request) was received in the
ACPI Processor and in the container driver, and when we hit that printk on a
real hardware, I believe it would be the right time then to see how the OS behaves
and do the right code then. For Now I will just go ahead and add a PRINTK.
Let me know if this step by step approach is okay to you.
thanks,
Anil
Keshavamurthy Anil S wrote:
> On Tue, Sep 21, 2004 at 12:51:36AM -0500, Dmitry Torokhov wrote:
> > On Monday 20 September 2004 08:38 pm, Keshavamurthy Anil S wrote:
> >
> > I actually think that on the highest level we should treat controlled and
> > surprise ejects differently. With controlled ejects the system (kernel +
> > userspace) can abort the sequence if something goes wrong while with surprise
> > eject the device is physically gone. Even if driver refuses to detach or we
> > have partition still mounted or something else if physical device is gone we
> > don't have any choice except for trimming the tree and doing whatever we need
> > to do.
>
> I agree, but when dealing with devices like CPU and Memory, not sure how the
> rest of the Operating System handles surprise removal.
If by "surprise removal" you mean an Itanium CPU or Memory no longer are
accessable by the rest of the hardware, the result will be fatal MCA. For
example, if an Itanum CPU tried to load from Memory that no longer exists,
the load will time out and the CPU will generate a fatal MCA. It may (or may
not) be possible to enhance the MCA/linux error handling code to handle this
situation, but the current code does not.
> For now I will go ahead and
> add a PRINTK saying that BUS_CHECK(surprise removal request) was received in the
> ACPI Processor and in the container driver, and when we hit that printk on a
> real hardware, I believe it would be the right time then to see how the OS behaves
> and do the right code then. For Now I will just go ahead and add a PRINTK.
>
> Let me know if this step by step approach is okay to you.
>
> thanks,
> Anil
--
Russ Anderson, OS RAS/Partitioning Project Lead
SGI - Silicon Graphics Inc [email protected]
On Mon, 20 Sep 2004 09:38:19 -0700 Keshavamurthy Anil S wrote:
> ---
> Name:acpi_hotplug_arch.patch
> Status: Tested on 2.6.9-rc2
> Signed-off-by: Anil S Keshavamurthy <[email protected]>
> Depends:
> Version: applies on 2.6.9-rc2
> Description:
> This patch provides the architecture specifice support for mapping lsapic to cpu array.
> Currently this supports just IA64. Support for IA32 and x86_64 is in progress
> ---
Here is a small fix.
Thanks,
Keiichiro Tokunaga
Name: pxm_to_nid_map_fix.patch
Status: Tested on 2.6.9-rc2
Signed-off-by: Keiichiro Tokunaga <[email protected]>
Description:
Change an attribute of pxm_to_nid_map[] from __initdata to __devinitdata.
---
linux-2.6.9-rc2-fix-kei/include/asm-ia64/acpi.h | 2 +-
1 files changed, 1 insertion(+), 1 deletion(-)
diff -puN include/asm-ia64/acpi.h~pxm_to_nid_map_fix include/asm-ia64/acpi.h
--- linux-2.6.9-rc2-fix/include/asm-ia64/acpi.h~pxm_to_nid_map_fix 2004-09-22 09:30:17.692176696 +0900
+++ linux-2.6.9-rc2-fix-kei/include/asm-ia64/acpi.h 2004-09-22 09:30:17.694129834 +0900
@@ -101,7 +101,7 @@ int acpi_gsi_to_irq (u32 gsi, unsigned i
#ifdef CONFIG_ACPI_NUMA
/* Proximity bitmap length; _PXM is at most 255 (8 bit)*/
#define MAX_PXM_DOMAINS (256)
-extern int __initdata pxm_to_nid_map[MAX_PXM_DOMAINS];
+extern int __devinitdata pxm_to_nid_map[MAX_PXM_DOMAINS];
extern int __initdata nid_to_pxm_map[MAX_NUMNODES];
#endif
_
On Tuesday 21 September 2004 04:51 pm, Keshavamurthy Anil S wrote:
> On Tue, Sep 21, 2004 at 12:51:36AM -0500, Dmitry Torokhov wrote:
> > On Monday 20 September 2004 08:38 pm, Keshavamurthy Anil S wrote:
> > > Currently I am handling both the surprise removal and the eject request in the same
> > > way, i,e send the notification to the userland and the usermode agent scripts
> > > is responsible for offlining of all the devices and then echoing onto eject file.
> > >
> >
> > I actually think that on the highest level we should treat controlled and
> > surprise ejects differently. With controlled ejects the system (kernel +
> > userspace) can abort the sequence if something goes wrong while with surprise
> > eject the device is physically gone. Even if driver refuses to detach or we
> > have partition still mounted or something else if physical device is gone we
> > don't have any choice except for trimming the tree and doing whatever we need
> > to do.
>
> I agree, but when dealing with devices like CPU and Memory, not sure how the
> rest of the Operating System handles surprise removal. For now I will go ahead and
> add a PRINTK saying that BUS_CHECK(surprise removal request) was received in the
> ACPI Processor and in the container driver, and when we hit that printk on a
> real hardware, I believe it would be the right time then to see how the OS behaves
> and do the right code then. For Now I will just go ahead and add a PRINTK.
>
Heh, I really don't expect the kernel to survive if somebody just yanks out a
CPU without a warning, especially if the CPU is the last one :) I hand in mind
devices like my port replicator that only has an additional network card and
could survive surprise removal.
> Let me know if this step by step approach is okay to you.
It sure is, we can always adjust the process down the road.
Thank you for your work!
--
Dmitry
On Mon, 20 Sep 2004 09:35:33 -0700 Keshavamurthy Anil S wrote:
> ---
> Name:acpi_core_eject.patch
> Status: Tested on 2.6.9-rc2
> Signed-off-by: Anil S Keshavamurthy <[email protected]>
> Depends:acpi_core
> Version: applies on 2.6.9-rc2
>
> This patch support /sys/firmware/acpi/eject interface where in
> the ACPI device say "LSB0" can be ejected by echoing "\_SB.LSB0" >
> /sys/firmware/acpi/eject
>
> The kernel when it receives an hardware sci eject request it simply passes this
> to user mode agent and the agent in turn will offline all the child devices and
> then echo's the ACPI device name onto /sys/firware/acpi/eject file and then the
> kernel will then actually remove the device.
In acpi_eject_store(), eject_operation() is called regardless of the
result of acpi_bus_trim(). I think that eject_operation() should be
called only when acpi_bus_trim() returns success. Otherwise, a
device stil being online will be ejected forcibly.
Two steps might be needed to do this.
1. Modify acpi_bus_trim() to return success only when all the
acpi_bus_remove() are done successfully.
2. Modify acpi_eject_store() to see the result and call eject_operation()
only when the result is success.
Here is a patch just to show what I have in mind. It is still based on
the recursion, so please fix it as appropriate ;)
Thanks,
Keiichiro Tokunaga
Name: acpi_core_eject_fix.patch
Status: Tested on 2.6.9-rc2
---
linux-2.6.9-rc2-fix-kei/drivers/acpi/scan.c | 26 +++++++++++++++---------
linux-2.6.9-rc2-fix-kei/include/acpi/acpi_bus.h | 2 -
2 files changed, 18 insertions(+), 10 deletions(-)
diff -puN drivers/acpi/scan.c~acpi_core_eject_fix drivers/acpi/scan.c
--- linux-2.6.9-rc2-fix/drivers/acpi/scan.c~acpi_core_eject_fix 2004-09-22 08:42:49.402689136 +0900
+++ linux-2.6.9-rc2-fix-kei/drivers/acpi/scan.c 2004-09-22 09:29:51.056265232 +0900
@@ -404,11 +404,14 @@ acpi_eject_store(struct subsystem *subsy
* remove from ACPI bus.
*/
if (type == ACPI_BUS_TYPE_PROCESSOR)
- acpi_bus_trim(device, 0);
+ result = acpi_bus_trim(device, 0);
else
- acpi_bus_trim(device, 1);
+ result = acpi_bus_trim(device, 1);
-
+ if (result) {
+ ret = -EBUSY;
+ goto err;
+ }
result = eject_operation(hlsb, islockable);
if (result) {
ret = -EBUSY;
@@ -1203,7 +1206,7 @@ int acpi_bus_scan (struct acpi_device *s
return_VALUE(0);
}
-void
+int
acpi_bus_trim(struct acpi_device *start,
int rmdevice)
{
@@ -1212,25 +1215,30 @@ acpi_bus_trim(struct acpi_device *start,
struct acpi_device *child = NULL;
acpi_handle phandle = 0;
acpi_handle chandle = 0;
-
+ int err = 0;
parent = start;
phandle = start->handle;
/*
* NOTE: must be freed in a depth-first manner.
*/
- while (1) {
+ while (1) {
status = acpi_get_next_object(ACPI_TYPE_ANY, phandle,
chandle, &chandle);
- if (ACPI_SUCCESS(status) && chandle != NULL) {
+ if (ACPI_SUCCESS(status) && chandle != NULL) {
if (acpi_bus_get_device(chandle, &child) == 0)
- acpi_bus_trim(child, 1);
+ if (acpi_bus_trim(child, 1))
+ err = 1;
} else {
/* this is a leaf */
- acpi_bus_remove(parent, rmdevice);
+ if (!err) {
+ if (acpi_bus_remove(parent, rmdevice))
+ err = 1;
+ }
break;
}
}
+ return err;
}
static int
diff -puN include/acpi/acpi_bus.h~acpi_core_eject_fix include/acpi/acpi_bus.h
--- linux-2.6.9-rc2-fix/include/acpi/acpi_bus.h~acpi_core_eject_fix 2004-09-22 08:42:49.404642274 +0900
+++ linux-2.6.9-rc2-fix-kei/include/acpi/acpi_bus.h 2004-09-22 08:42:49.408548551 +0900
@@ -325,7 +325,7 @@ int acpi_bus_receive_event (struct acpi_
int acpi_bus_register_driver (struct acpi_driver *driver);
int acpi_bus_unregister_driver (struct acpi_driver *driver);
int acpi_bus_scan (struct acpi_device *start);
-void acpi_bus_trim(struct acpi_device *start, int rmdevice);
+int acpi_bus_trim(struct acpi_device *start, int rmdevice);
int acpi_bus_add (struct acpi_device **child, struct acpi_device *parent, acpi_handle handle, int type);
_
On Mon, 20 Sep 2004 09:41:07 -0700 Keshavamurthy Anil S wrote:
> ---
> Name:topology.patch
> Status:Tested on 2.6.9-rc2
> Signed-off-by: Anil S Keshavamurthy <[email protected]>
> Depends:
> Version: applies on 2.6.9-rc2
> Description:
> Extends support for dynamic registration and unregistration of the cpu,
> by implementing and exporting arch_register_cpu()/arch_unregister_cpu().
> Also combines multiple implementation of topology_init() functions to
> single topology_init() in case of ia64 architecture.
> ---
> +void arch_unregister_cpu(int num)
> +{
> + struct node *parent = NULL;
> +
> +#ifdef CONFIG_NUMA
> + int node = cpu_to_node(num);
> + if (node_online(node))
> + parent = &sysfs_nodes[node];
> +#endif /* CONFIG_NUMA */
> +
> + return unregister_cpu(&sysfs_cpus[num].cpu, parent);
> +}
I don't think that the check 'if (node_online(node))' is necessary
because sysfs_nodes[node] is there no matter if the node is online
or offline. sysfs_nodes[] is cleared only when unregister_node()
is called and it would be always called after unregister_cpu().
Thanks,
Keiichiro Tokunaga
Name: arch_register_cpu_fix.patch
Status: Tested on 2.6.9-rc2
Signed-off-by: Keiichiro Tokunaga <[email protected]>
---
linux-2.6.9-rc2-fix-kei/arch/ia64/kernel/topology.c | 3 +--
1 files changed, 1 insertion(+), 2 deletions(-)
diff -puN arch/ia64/kernel/topology.c~arch_register_cpu_fix arch/ia64/kernel/topology.c
--- linux-2.6.9-rc2-fix/arch/ia64/kernel/topology.c~arch_register_cpu_fix 2004-09-22 11:56:58.793274256 +0900
+++ linux-2.6.9-rc2-fix-kei/arch/ia64/kernel/topology.c 2004-09-22 11:56:58.795227390 +0900
@@ -46,8 +46,7 @@ void arch_unregister_cpu(int num)
#ifdef CONFIG_NUMA
int node = cpu_to_node(num);
- if (node_online(node))
- parent = &sysfs_nodes[node];
+ parent = &sysfs_nodes[node];
#endif /* CONFIG_NUMA */
return unregister_cpu(&sysfs_cpus[num].cpu, parent);
_
On Mon, 20 Sep 2004 09:43:52 -0700 Keshavamurthy Anil S wrote:
> Changes form previous version
> 1) Added depends on EXPERIMENTAL in kconfig file
>
> ---
> Name:processor_drv.patch
> Status:Tested on 2.6.9-rc2
> Signed-off-by: Anil S Keshavamurthy <[email protected]>
> Depends:
> Version: applies on 2.6.9-rc2
> Description:
> Extends the processor driver to support ACPI based Physical CPU hotplug.
> +static int
> +is_processor_present(
> + acpi_handle handle)
> +{
> + acpi_status status;
> + unsigned long sta = 0;
> +
> + ACPI_FUNCTION_TRACE("is_processor_present");
> +
> + status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
> + if (ACPI_FAILURE(status) || !(sta & ACPI_STA_PRESENT)) {
> + ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
> + "Processor Device is not present\n"));
> + return_VALUE(0);
> + }
> + return_VALUE(1);
> +}
This assumes that a device is not present if acpi_evaluate_integer()
returns failure. But, from the ACPI spec, I think we should assume
the device is present if the function fails due to a failure in finding
_STA method.
I am attaching a patch to fix this. Please see it below.
Thanks,
Keiichiro Tokunaga
Name: cpu_hp_sta_fix.patch
Status: Tested on 2.6.9-rc2
Signed-off-by: Keiichiro Tokunaga <[email protected]>
Description:
Fix the evaluation method of _STA in drivers/acpi/processor.c. If a processor
object does not have _STA, we should consider it as present.
---
linux-2.6.9-rc2-fix-kei/drivers/acpi/processor.c | 12 +++++++++++-
1 files changed, 11 insertions(+), 1 deletion(-)
diff -puN drivers/acpi/processor.c~cpu_hp_sta_fix drivers/acpi/processor.c
--- linux-2.6.9-rc2-fix/drivers/acpi/processor.c~cpu_hp_sta_fix 2004-09-22 11:56:58.000000000 +0900
+++ linux-2.6.9-rc2-fix-kei/drivers/acpi/processor.c 2004-09-22 18:36:34.000000000 +0900
@@ -2551,7 +2551,17 @@ is_processor_present(
ACPI_FUNCTION_TRACE("is_processor_present");
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
- if (ACPI_FAILURE(status) || !(sta & ACPI_STA_PRESENT)) {
+ if (ACPI_FAILURE(status)) {
+ /* Assume device is present if it does not have _STA. */
+ if (status == AE_NOT_FOUND)
+ return_VALUE(1);
+ else {
+ printk(KERN_WARNING "Failed to evaluate _STA.\n");
+ return_VALUE(0);
+ }
+ }
+
+ if (!(sta & ACPI_STA_PRESENT)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Processor Device is not present\n"));
return_VALUE(0);
_
On Mon, 20 Sep 2004 09:38:19 -0700 Keshavamurthy Anil S wrote:
> ---
> Name:acpi_hotplug_arch.patch
> Status: Tested on 2.6.9-rc2
> Signed-off-by: Anil S Keshavamurthy <[email protected]>
> Depends:
> Version: applies on 2.6.9-rc2
> Description:
> This patch provides the architecture specifice support for mapping lsapic to cpu array.
> Currently this supports just IA64. Support for IA32 and x86_64 is in progress
> ---
I would like to suggest introducing a new function 'acpi_get_pxm()'
since other drivers might need it in the future. Acutally, ACPI container
hotplug will be use it soon.
Here is a patch creating the function.
Thanks,
Keiichiro Tokunaga
Name: acpi_pxm_support.patch
Status: 2.6.9-rc2
Signed-off-by: Keiichiro Tokunaga <[email protected]>
Description:
Introduce acpi_get_pxm().
---
linux-2.6.9-rc2-fix-kei/drivers/acpi/numa.c | 22 +++++++++++++++++++++-
linux-2.6.9-rc2-fix-kei/include/linux/acpi.h | 8 ++++++++
2 files changed, 29 insertions(+), 1 deletion(-)
diff -puN drivers/acpi/numa.c~acpi_pxm_support drivers/acpi/numa.c
--- linux-2.6.9-rc2-fix/drivers/acpi/numa.c~acpi_pxm_support 2004-09-22 21:53:53.490202242 +0900
+++ linux-2.6.9-rc2-fix-kei/drivers/acpi/numa.c 2004-09-22 21:53:53.495085087 +0900
@@ -22,7 +22,7 @@
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
*/
-
+#include <linux/module.h>
#include <linux/config.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -195,3 +195,23 @@ acpi_numa_init()
acpi_numa_arch_fixup();
return 0;
}
+
+int
+acpi_get_pxm(acpi_handle h)
+{
+ unsigned long pxm=-1;
+ acpi_status status;
+ acpi_handle handle ;
+ acpi_handle phandle = h;
+
+ do {
+ handle = phandle;
+ status = acpi_evaluate_integer(handle,"_PXM",NULL,&pxm);
+ if (ACPI_SUCCESS(status)) {
+ return (int)pxm;
+ }
+ status = acpi_get_parent(handle,&phandle);
+ } while( ACPI_SUCCESS(status) );
+ return -1;
+}
+EXPORT_SYMBOL(acpi_get_pxm);
diff -puN include/linux/acpi.h~acpi_pxm_support include/linux/acpi.h
--- linux-2.6.9-rc2-fix/include/linux/acpi.h~acpi_pxm_support 2004-09-22 18:53:53.492155380 +0900
+++ linux-2.6.9-rc2-fix-kei/include/linux/acpi.h 2004-09-22 18:53:53.495085087 +0900
@@ -477,4 +477,12 @@ static inline int acpi_blacklisted(void)
#endif /*!CONFIG_ACPI_INTERPRETER*/
+#ifdef CONFIG_ACPI_NUMA
+int acpi_get_pxm(acpi_handle handle);
+#else
+static inline int acpi_get_pxm(acpi_handle hanle)
+{
+ return 0;
+}
+#endif
#endif /*_LINUX_ACPI_H*/
_
On Wed, 22 Sep 2004 22:15:38 +0900 Keiichiro Tokunaga wrote:
> On Mon, 20 Sep 2004 09:38:19 -0700 Keshavamurthy Anil S wrote:
> > ---
> > Name:acpi_hotplug_arch.patch
> > Status: Tested on 2.6.9-rc2
> > Signed-off-by: Anil S Keshavamurthy <[email protected]>
> > Depends:
> > Version: applies on 2.6.9-rc2
> > Description:
> > This patch provides the architecture specifice support for mapping lsapic to cpu array.
> > Currently this supports just IA64. Support for IA32 and x86_64 is in progress
> > ---
>
> I would like to suggest introducing a new function 'acpi_get_pxm()'
> since other drivers might need it in the future. Acutally, ACPI container
> hotplug will be use it soon.
I have made a patch to modify your code to use acpi_get_pxm()
that I just posted earlier. I hope it does not break your code:)
What do you think of it?
Thanks,
Keiichiro Tokunaga
Name: acpi_cpu_pxm_fix.patch
Status: Tested on 2.6.9-rc2
Signed-off-by: Keiichiro Tokunaga <[email protected]>
Description:
Modify acpi_map_cpu2node() to use acpi_get_pxm().
---
linux-2.6.9-rc2-fix-kei/arch/ia64/kernel/acpi.c | 31 +++++-------------------
1 files changed, 7 insertions(+), 24 deletions(-)
diff -puN arch/ia64/kernel/acpi.c~acpi_cpu_pxm_fix arch/ia64/kernel/acpi.c
--- linux-2.6.9-rc2-fix/arch/ia64/kernel/acpi.c~acpi_cpu_pxm_fix 2004-09-22 22:20:53.797821495 +0900
+++ linux-2.6.9-rc2-fix-kei/arch/ia64/kernel/acpi.c 2004-09-22 22:20:53.800751203 +0900
@@ -659,36 +659,20 @@ int
acpi_map_cpu2node(acpi_handle handle, int cpu, long physid)
{
#ifdef CONFIG_ACPI_NUMA
- int pxm_id = 0;
- union acpi_object *obj;
- struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ int pxm_id;
- if (ACPI_FAILURE(acpi_evaluate_object(handle, "_PXM", NULL, &buffer)))
- goto pxm_id_0;
+ pxm_id = acpi_get_pxm(handle);
- if ((!buffer.length) || (!buffer.pointer))
- goto pxm_id_0;
-
- obj = buffer.pointer;
- if (obj->type != ACPI_TYPE_INTEGER) {
- acpi_os_free(buffer.pointer);
- goto pxm_id_0;
- }
-
- pxm_id = obj->integer.value;
-
-pxm_id_0:
/*
* Assuming that the container driver would have set the proximity
* domain and would have initialized pxm_to_nid_map[pxm_id] && pxm_flag
*/
- /* Return Error if proximity domain is not set */
- if (!pxm_bit_test(pxm_id))
- return -EINVAL;
-
node_cpuid[cpu].phys_id = physid;
- node_cpuid[cpu].nid = pxm_to_nid_map[pxm_id];
+ if (pxm_id < 0)
+ node_cpuid[cpu].nid = 0;
+ else
+ node_cpuid[cpu].nid = pxm_to_nid_map[pxm_id];
#endif
return(0);
@@ -737,8 +721,7 @@ acpi_map_lsapic(acpi_handle handle, int
if(cpu >= NR_CPUS)
return -EINVAL;
- if (ACPI_FAILURE(acpi_map_cpu2node(handle, cpu, physid)))
- return -ENODEV;
+ acpi_map_cpu2node(handle, cpu, physid);
cpu_set(cpu, cpu_present_map);
ia64_cpu_to_sapicid[cpu] = physid;
_
On Wed, 2004-09-22 at 22:15 +0900, Keiichiro Tokunaga wrote:
>
> I would like to suggest introducing a new function 'acpi_get_pxm()'
> since other drivers might need it in the future. Acutally, ACPI container
> hotplug will be use it soon.
>
> Here is a patch creating the function.
>
Nice, I have a couple I/O locality patches that could be simplified
with this function.
> +#ifdef CONFIG_ACPI_NUMA
> +int acpi_get_pxm(acpi_handle handle);
> +#else
> +static inline int acpi_get_pxm(acpi_handle hanle)
Trivial typo here ---> ^^^^^ handle
Alex
--
Alex Williamson HP Linux & Open Source Lab
> In acpi_eject_store(), eject_operation() is called regardless of the
> result of acpi_bus_trim(). I think that eject_operation() should be
> called only when acpi_bus_trim() returns success. Otherwise, a
> device stil being online will be ejected forcibly.
>
> Two steps might be needed to do this.
>
> 1. Modify acpi_bus_trim() to return success only when all the
> acpi_bus_remove() are done successfully.
> 2. Modify acpi_eject_store() to see the result and call eject_operation()
> only when the result is success.
Hi Kei-san,
Your idea and the patch both looks good to me.
Thanks for eye balling the code and detecting the corner cases like this.
>
> Here is a patch just to show what I have in mind. It is still based on
> the recursion, so please fix it as appropriate ;)
I will merge this with my non-recursion version of the patch and post it ASAP.
thanks,
Anil
On Wed, Sep 22, 2004 at 05:34:00PM +0900, Keiichiro Tokunaga wrote:
> On Mon, 20 Sep 2004 09:41:07 -0700 Keshavamurthy Anil S wrote:
> > ---
> > Name:topology.patch
> > Status:Tested on 2.6.9-rc2
> > Signed-off-by: Anil S Keshavamurthy <[email protected]>
> > Depends:
> > Version: applies on 2.6.9-rc2
> > Description:
> > Extends support for dynamic registration and unregistration of the cpu,
> > by implementing and exporting arch_register_cpu()/arch_unregister_cpu().
> > Also combines multiple implementation of topology_init() functions to
> > single topology_init() in case of ia64 architecture.
> > ---
>
> > +void arch_unregister_cpu(int num)
> > +{
> > + struct node *parent = NULL;
> > +
> > +#ifdef CONFIG_NUMA
> > + int node = cpu_to_node(num);
> > + if (node_online(node))
> > + parent = &sysfs_nodes[node];
> > +#endif /* CONFIG_NUMA */
> > +
> > + return unregister_cpu(&sysfs_cpus[num].cpu, parent);
> > +}
>
> I don't think that the check 'if (node_online(node))' is necessary
> because sysfs_nodes[node] is there no matter if the node is online
> or offline. sysfs_nodes[] is cleared only when unregister_node()
> is called and it would be always called after unregister_cpu().
Yes, I agree with you. I will remove the check, or simply apply your patch:)
thanks,
Anil
On Wed, 22 Sep 2004 08:52:59 -0600, Alex Williamson wrote:
> On Wed, 2004-09-22 at 22:15 +0900, Keiichiro Tokunaga wrote:
> >
> > I would like to suggest introducing a new function 'acpi_get_pxm()'
> > since other drivers might need it in the future. Acutally, ACPI container
> > hotplug will be using it soon.
> >
> > Here is a patch creating the function.
> >
>
> Nice, I have a couple I/O locality patches that could be simplified
> with this function.
>
> > +#ifdef CONFIG_ACPI_NUMA
> > +int acpi_get_pxm(acpi_handle handle);
> > +#else
> > +static inline int acpi_get_pxm(acpi_handle hanle)
> Trivial typo here ---> ^^^^^ handle
Oh, good catch:)
Thanks!
Keiichiro Tokunaga
Name: acpi_pxm_support.patch
Status: 2.6.9-rc2
Signed-off-by: Keiichiro Tokunaga <[email protected]>
Description:
Introduce acpi_get_pxm(). The code has been refreshed a little bit
from the first version.
---
linux-2.6.9-rc2-fix-kei/drivers/acpi/numa.c | 21 ++++++++++++++++++++-
linux-2.6.9-rc2-fix-kei/include/linux/acpi.h | 8 ++++++++
2 files changed, 28 insertions(+), 1 deletion(-)
diff -puN drivers/acpi/numa.c~acpi_pxm_support drivers/acpi/numa.c
--- linux-2.6.9-rc2-fix/drivers/acpi/numa.c~acpi_pxm_support 2004-09-22 18:53:53.000000000 +0900
+++ linux-2.6.9-rc2-fix-kei/drivers/acpi/numa.c 2004-09-23 02:07:50.948628719 +0900
@@ -22,7 +22,7 @@
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
*/
-
+#include <linux/module.h>
#include <linux/config.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -195,3 +195,22 @@ acpi_numa_init()
acpi_numa_arch_fixup();
return 0;
}
+
+int
+acpi_get_pxm(acpi_handle h)
+{
+ unsigned long pxm = -1;
+ acpi_status status;
+ acpi_handle handle ;
+ acpi_handle phandle = h;
+
+ do {
+ handle = phandle;
+ status = acpi_evaluate_integer(handle, "_PXM", NULL, &pxm);
+ if (ACPI_SUCCESS(status))
+ return (int)pxm;
+ status = acpi_get_parent(handle, &phandle);
+ } while(ACPI_SUCCESS(status));
+ return -1;
+}
+EXPORT_SYMBOL(acpi_get_pxm);
diff -puN include/linux/acpi.h~acpi_pxm_support include/linux/acpi.h
--- linux-2.6.9-rc2-fix/include/linux/acpi.h~acpi_pxm_support 2004-09-22 18:53:53.000000000 +0900
+++ linux-2.6.9-rc2-fix-kei/include/linux/acpi.h 2004-09-23 02:08:18.792537695 +0900
@@ -477,4 +477,12 @@ static inline int acpi_blacklisted(void)
#endif /*!CONFIG_ACPI_INTERPRETER*/
+#ifdef CONFIG_ACPI_NUMA
+int acpi_get_pxm(acpi_handle handle);
+#else
+static inline int acpi_get_pxm(acpi_handle handle)
+{
+ return 0;
+}
+#endif
#endif /*_LINUX_ACPI_H*/
_
On Thu, Sep 23, 2004 at 02:10:31AM +0900, Keiichiro Tokunaga wrote:
> On Wed, 22 Sep 2004 08:52:59 -0600, Alex Williamson wrote:
> > On Wed, 2004-09-22 at 22:15 +0900, Keiichiro Tokunaga wrote:
> > >
> > > I would like to suggest introducing a new function 'acpi_get_pxm()'
> > > since other drivers might need it in the future. Acutally, ACPI container
> > > hotplug will be using it soon.
> > >
> > > Here is a patch creating the function.
> > >
> >
> > Nice, I have a couple I/O locality patches that could be simplified
> > with this function.
> >
> > > +#ifdef CONFIG_ACPI_NUMA
> > > +int acpi_get_pxm(acpi_handle handle);
> > > +#else
> > > +static inline int acpi_get_pxm(acpi_handle hanle)
> > Trivial typo here ---> ^^^^^ handle
>
> Oh, good catch:)
Merged your changes, thanks again.
-Anil
On Wed, Sep 22, 2004 at 11:10:56AM +0900, Keiichiro Tokunaga wrote:
> On Mon, 20 Sep 2004 09:38:19 -0700 Keshavamurthy Anil S wrote:
> > ---
> > Name:acpi_hotplug_arch.patch
> > Status: Tested on 2.6.9-rc2
> > Signed-off-by: Anil S Keshavamurthy <[email protected]>
> > Depends:
> > Version: applies on 2.6.9-rc2
> > Description:
> > This patch provides the architecture specifice support for mapping lsapic to cpu array.
> > Currently this supports just IA64. Support for IA32 and x86_64 is in progress
> > ---
>
> Here is a small fix.
>
> Thanks,
> Keiichiro Tokunaga
>
>
> Name: pxm_to_nid_map_fix.patch
> Status: Tested on 2.6.9-rc2
> Signed-off-by: Keiichiro Tokunaga <[email protected]>
> Description:
> Change an attribute of pxm_to_nid_map[] from __initdata to __devinitdata.
good catch:)
thanks,
Anil
On Mon, 20 Sep 2004 09:47:19 -0700, Keshavamurthy Anil S wrote:
> Changes from previous release:
> 1) Typo fix- ACPI004 to ACPI0004
> 2) Added depends on EXPERIMENTAL in Kconfig file
>
> ---
> Name:container_drv.patch
> Status: Tested on 2.6.9-rc1
> Signed-off-by: Anil S Keshavamurthy <[email protected]>
> Depends:
> Version: applies on 2.6.9-rc1
> Description:
> This is the very early version on the Container driver which supports
> hotplug notifications on ACPI0004, PNP0A05 and PNP0A06 devices.
> Changes from previous release:
> 1) Mergerd the typo fix patch which changes "ACPI004" to "ACPI0004"
> ---
I have made a patchset to add 'NUMA node handling support' to
your patchset. If a container that is identical to NUMA node is
hotplugged, this handles NUMA related stuffs. For instance,
creating/deleting sysfs directories and files of node, data structures,
and etc...
- numa_hp_base.patch
- numa_hp_ia64.patch
- acpi_numa_hp.patch
- container_for_numa.patch
Status: Tested on 2.6.9-rc2 including your patchset posted earlier.
Thanks,
Keiichiro Tokunaga
Name: numa_hp_ia64.patch
Status: Tested on 2.6.9-rc2
Signed-off-by: Keiichiro Tokunaga <[email protected]>
Description:
Add arch_register_node() to arch/ia64/kernel/topology.c. The
topology.c has been introduced by Anil (Intel).
Thanks,
Keiichiro Tokunaga
---
linux-2.6.9-rc2-fix-kei/arch/ia64/kernel/acpi.c | 1 +
linux-2.6.9-rc2-fix-kei/arch/ia64/kernel/topology.c | 18 +++++++++++++++---
linux-2.6.9-rc2-fix-kei/include/asm-ia64/numa.h | 3 ++-
3 files changed, 18 insertions(+), 4 deletions(-)
diff -puN arch/ia64/kernel/acpi.c~numa_hp_ia64 arch/ia64/kernel/acpi.c
--- linux-2.6.9-rc2-fix/arch/ia64/kernel/acpi.c~numa_hp_ia64 2004-09-24 00:14:56.062297005 +0900
+++ linux-2.6.9-rc2-fix-kei/arch/ia64/kernel/acpi.c 2004-09-24 00:14:56.069132982 +0900
@@ -362,6 +362,7 @@ int __devinitdata pxm_to_nid_map[MAX_PXM
int __initdata nid_to_pxm_map[MAX_NUMNODES];
static struct acpi_table_slit __initdata *slit_table;
+EXPORT_SYMBOL(pxm_to_nid_map);
/*
* ACPI 2.0 SLIT (System Locality Information Table)
* http://devresource.hp.com/devresource/Docs/TechPapers/IA64/slit.pdf
diff -puN arch/ia64/kernel/topology.c~numa_hp_ia64 arch/ia64/kernel/topology.c
--- linux-2.6.9-rc2-fix/arch/ia64/kernel/topology.c~numa_hp_ia64 2004-09-24 00:14:56.064250141 +0900
+++ linux-2.6.9-rc2-fix-kei/arch/ia64/kernel/topology.c 2004-09-24 00:14:56.070109550 +0900
@@ -21,8 +21,9 @@
#include <asm/mmzone.h>
#include <asm/numa.h>
#include <asm/cpu.h>
-
#ifdef CONFIG_NUMA
+#include <asm/numa.h>
+
static struct node *sysfs_nodes;
#endif
static struct ia64_cpu *sysfs_cpus;
@@ -37,6 +38,18 @@ int arch_register_cpu(int num)
return register_cpu(&sysfs_cpus[num].cpu, num, parent);
}
+#ifdef CONFIG_NUMA
+int arch_register_node(int num) {
+ return register_node(&sysfs_nodes[num],num,0);
+}
+int arch_unregister_node(int num) {
+ unregister_node(&sysfs_nodes[num],0);
+ return 0;
+}
+
+EXPORT_SYMBOL(arch_register_node);
+EXPORT_SYMBOL(arch_unregister_node);
+#endif /*CONFIG_NUMA*/
#ifdef CONFIG_HOTPLUG_CPU
@@ -69,7 +82,7 @@ static int __init topology_init(void)
memset(sysfs_nodes, 0, sizeof(struct node) * MAX_NUMNODES);
for (i = 0; i < numnodes; i++)
- if ((err = register_node(&sysfs_nodes[i], i, 0)))
+ if ((err = arch_register_node(i)))
goto out;
#endif
@@ -86,5 +99,4 @@ static int __init topology_init(void)
out:
return err;
}
-
__initcall(topology_init);
diff -puN include/asm-ia64/numa.h~numa_hp_ia64 include/asm-ia64/numa.h
--- linux-2.6.9-rc2-fix/include/asm-ia64/numa.h~numa_hp_ia64 2004-09-24 00:14:56.066203277 +0900
+++ linux-2.6.9-rc2-fix-kei/include/asm-ia64/numa.h 2004-09-24 00:14:56.070109550 +0900
@@ -65,8 +65,9 @@ extern int paddr_to_nid(unsigned long pa
#define local_nodeid (cpu_to_node_map[smp_processor_id()])
+extern int arch_register_node(int num);
+extern int arch_unregister_node(int num);
#else /* !CONFIG_NUMA */
-
#define paddr_to_nid(addr) 0
#endif /* CONFIG_NUMA */
_
Name: numa_hp_base.patch
Status: Tested on 2.6.9-rc2
Signed-off-by: Keiichiro Tokunaga <[email protected]>
Description:
Create unregister_node() that removes corresponding sysfs directory
and files from /sys/devices/system/node/ at hot-removal time.
Thanks,
Keiichiro Tokunaga
---
linux-2.6.9-rc2-fix-kei/drivers/base/node.c | 16 +++++++++++++++-
linux-2.6.9-rc2-fix-kei/include/linux/node.h | 1 +
linux-2.6.9-rc2-fix-kei/mm/page_alloc.c | 2 ++
3 files changed, 18 insertions(+), 1 deletion(-)
diff -puN drivers/base/node.c~numa_hp_base drivers/base/node.c
--- linux-2.6.9-rc2-fix/drivers/base/node.c~numa_hp_base 2004-09-24 00:14:55.659950914 +0900
+++ linux-2.6.9-rc2-fix-kei/drivers/base/node.c 2004-09-24 00:14:55.668740028 +0900
@@ -117,7 +117,7 @@ static SYSDEV_ATTR(numastat, S_IRUGO, no
*
* Initialize and register the node device.
*/
-int __init register_node(struct node *node, int num, struct node *parent)
+int register_node(struct node *node, int num, struct node *parent)
{
int error;
@@ -132,6 +132,16 @@ int __init register_node(struct node *no
}
return error;
}
+void unregister_node(struct node *node, struct node *parent)
+{
+ if (node == NULL) {
+ printk("unregister_node: node is null.");
+ return;
+ }
+ sysdev_remove_file(&node->sysdev, &attr_cpumap);
+ sysdev_remove_file(&node->sysdev, &attr_meminfo);
+ sysdev_unregister(&node->sysdev);
+}
int __init register_node_type(void)
@@ -139,3 +149,7 @@ int __init register_node_type(void)
return sysdev_class_register(&node_class);
}
postcore_initcall(register_node_type);
+
+
+EXPORT_SYMBOL(register_node);
+EXPORT_SYMBOL(unregister_node);
diff -puN include/linux/node.h~numa_hp_base include/linux/node.h
--- linux-2.6.9-rc2-fix/include/linux/node.h~numa_hp_base 2004-09-24 00:14:55.664833755 +0900
+++ linux-2.6.9-rc2-fix-kei/include/linux/node.h 2004-09-24 00:14:55.669716596 +0900
@@ -27,6 +27,7 @@ struct node {
};
extern int register_node(struct node *, int, struct node *);
+extern void unregister_node(struct node *node, struct node *parent);
#define to_node(sys_device) container_of(sys_device, struct node, sysdev)
diff -puN mm/page_alloc.c~numa_hp_base mm/page_alloc.c
--- linux-2.6.9-rc2-fix/mm/page_alloc.c~numa_hp_base 2004-09-24 00:14:55.666786892 +0900
+++ linux-2.6.9-rc2-fix-kei/mm/page_alloc.c 2004-09-24 00:14:55.670693164 +0900
@@ -14,6 +14,7 @@
* (lots of bits borrowed from Ingo Molnar & Andrew Morton)
*/
+#include <linux/module.h>
#include <linux/config.h>
#include <linux/stddef.h>
#include <linux/mm.h>
@@ -44,6 +45,7 @@ int sysctl_lower_zone_protection = 0;
EXPORT_SYMBOL(totalram_pages);
EXPORT_SYMBOL(nr_swap_pages);
+EXPORT_SYMBOL(node_online_map);
/*
* Used by page_zone() to look up the address of the struct zone whose
_
On Fri, Sep 24, 2004 at 01:23:01AM +0900, Keiichiro Tokunaga wrote:
> On Mon, 20 Sep 2004 09:47:19 -0700, Keshavamurthy Anil S wrote:
> > Changes from previous release:
> > 1) Typo fix- ACPI004 to ACPI0004
> > 2) Added depends on EXPERIMENTAL in Kconfig file
> >
> > ---
> > Name:container_drv.patch
> > Status: Tested on 2.6.9-rc1
> > Signed-off-by: Anil S Keshavamurthy <[email protected]>
> > Depends:
> > Version: applies on 2.6.9-rc1
> > Description:
> > This is the very early version on the Container driver which supports
> > hotplug notifications on ACPI0004, PNP0A05 and PNP0A06 devices.
> > Changes from previous release:
> > 1) Mergerd the typo fix patch which changes "ACPI004" to "ACPI0004"
> > ---
>
> I have made a patchset to add 'NUMA node handling support' to
> your patchset. If a container that is identical to NUMA node is
> hotplugged, this handles NUMA related stuffs. For instance,
> creating/deleting sysfs directories and files of node, data structures,
> and etc...
Great!!!
>
> - numa_hp_base.patch
> - numa_hp_ia64.patch
> - acpi_numa_hp.patch
> - container_for_numa.patch
I will take a look at all of the above patches and will get back to you soon.
>
> Status: Tested on 2.6.9-rc2 including your patchset posted earlier.
Sounds good.
thanks,
Anil Keshavamurthy
Name: acpi_numa_hp.patch
Status: Tested on 2.6.9-rc2
Signed-off-by: Keiichiro Tokunaga <[email protected]>
Description:
Add hotplug support to drivers/acpi/numa.c.
Thanks,
Keiichiro Tokunaga
---
linux-2.6.9-rc2-fix-kei/drivers/acpi/numa.c | 267 ++++++++++++++++++++++++++++
linux-2.6.9-rc2-fix-kei/include/acpi/numa.h | 30 +++
2 files changed, 297 insertions(+)
diff -puN drivers/acpi/numa.c~acpi_numa_hp drivers/acpi/numa.c
--- linux-2.6.9-rc2-fix/drivers/acpi/numa.c~acpi_numa_hp 2004-09-24 00:14:56.382611368 +0900
+++ linux-2.6.9-rc2-fix-kei/drivers/acpi/numa.c 2004-09-24 00:44:58.135989078 +0900
@@ -31,6 +31,7 @@
#include <linux/acpi.h>
#include <acpi/acpi_bus.h>
#include <acpi/acmacros.h>
+#include <acpi/numa.h>
#define ACPI_NUMA 0x80000000
#define _COMPONENT ACPI_NUMA
@@ -214,3 +215,269 @@ acpi_get_pxm(acpi_handle h)
return -1;
}
EXPORT_SYMBOL(acpi_get_pxm);
+
+
+#if ( defined(CONFIG_ACPI_CONTAINER_MODULE) || defined(CONFIG_ACPI_CONTAINER) ) && defined(CONFIG_HOTPLUG)
+
+static int nid2pxm(int nid)
+{
+ int i;
+
+ if ((nid < 0) || (nid >= MAX_NUMNODES))
+ return -1;
+
+ for(i=0; i < MAX_PXM_DOMAINS; i++) {
+ if ( pxm_to_nid_map[i] == nid )
+ return i;
+ }
+
+ return -1;
+}
+
+void
+acpi_numa_data_handler(acpi_handle handle, u32 function, void *context)
+{
+ return;
+}
+
+int is_numa_node_device(acpi_handle handle)
+{
+ acpi_status status;
+ struct acpi_numa_node *data=NULL;
+
+ status = acpi_get_data(handle, acpi_numa_data_handler, (void **)&data);
+ if (ACPI_FAILURE(status))
+ return 0;
+ else
+ return 1;
+}
+
+int acpi_get_numa_nodeid(int pxm)
+{
+ if (pxm < 0 || pxm >= MAX_PXM_DOMAINS)
+ return -EINVAL;
+
+ return pxm_to_nid_map[pxm];
+}
+EXPORT_SYMBOL(acpi_get_numa_nodeid);
+
+static void
+set_nodeid(int pxm, int nid)
+{
+ if (pxm_to_nid_map[pxm] >= 0) {
+ printk(KERN_INFO"PXM <%d> already has a nid <%d>.\n",
+ pxm_to_nid_map[pxm], pxm);
+ return ;
+ }
+
+ if (nid >= MAX_NUMNODES) {
+ printk(KERN_ERR"nid <%d> is too big. Range: 0-%d\n",
+ nid, MAX_NUMNODES-1);
+ return ;
+ }
+
+ pxm_to_nid_map[pxm] = nid;
+}
+
+static void unget_nodeid(int nid)
+{
+#ifdef PXM_FIX_NODEID
+ int pxm = nid2pxm(nid);
+ if (pxm < 0)
+ return;
+ pxm_to_nid_map[pxm] = -1;
+#endif
+}
+
+static int
+allocate_nodeid(int pxm)
+{
+ int i;
+
+#ifndef PXM_FIX_NODEID
+ if (pxm_to_nid_map[pxm] >= 0)
+ return pxm_to_nid_map[pxm];
+#endif
+ for(i=0 ;i < MAX_NUMNODES; i++) {
+ if (nid2pxm(i) < 0)
+ return i;
+ }
+
+ printk(KERN_ERR"Failed to allocate nid for PXM <%d>\n", pxm);
+ return -1;
+}
+
+static acpi_status
+find_processor(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+ int **cntp = (int **)rv;
+
+ ACPI_FUNCTION_TRACE("find_processor");
+
+ ++(**cntp);
+
+ return_ACPI_STATUS(AE_OK);
+}
+
+void acpi_numa_node_add(acpi_handle handle)
+{
+ acpi_status status;
+ struct acpi_numa_node *data=NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_numa_node_add");
+
+ status = acpi_get_data(handle, acpi_numa_data_handler, (void **)&data);
+ if (ACPI_FAILURE(status))
+ return_VOID;
+
+ if (data->pxm < 0) {
+ printk(KERN_ERR"Container does not have PXM.\n");
+ return_VOID;
+ }
+
+ arch_register_node(data->nid);
+
+ return_VOID;
+}
+
+void acpi_numa_node_remove(acpi_handle handle)
+{
+ acpi_status status;
+ struct acpi_numa_node *data=NULL;
+ int nid;
+
+ ACPI_FUNCTION_TRACE("acpi_numa_node_remove");
+
+ status = acpi_get_data(handle, acpi_numa_data_handler, (void **)&data);
+ if (ACPI_FAILURE(status) || !data)
+ return_VOID;
+
+ nid = data->nid;
+ if (nid < 0) {
+ printk(KERN_ERR"Invalid nid %d\n", nid);
+ return_VOID;
+ }
+
+ arch_unregister_node(nid);
+ unget_nodeid(nid);
+ acpi_numa_node_data_detach(handle);
+
+ return_VOID;
+}
+
+void acpi_numa_node_data_detach(acpi_handle handle)
+{
+ struct acpi_numa_node *data=NULL;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE("acpi_numa_node_data_detach");
+
+ status = acpi_get_data(handle, acpi_numa_data_handler, (void **)&data);
+ if (ACPI_FAILURE(status) || (data == NULL))
+ return_VOID;
+
+ status = acpi_detach_data(handle, acpi_numa_data_handler);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR"Failed to detach NUMA node data.\n");
+ return_VOID;
+ }
+
+ kfree(data);
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "NUMA node data is detached.\n"));
+ return_VOID;
+}
+
+void acpi_numa_node_init(acpi_handle handle)
+{
+ int pxm;
+ acpi_status status;
+ struct acpi_numa_node *data;
+ int _cnt=0;
+ int *cnt=&_cnt;
+ struct acpi_device *node_dev=NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_numa_node_init");
+
+ if (acpi_bus_get_device(handle, &node_dev)) {
+ printk(KERN_ERR"Unknown handle.\n");
+ return_VOID;
+ }
+
+ pxm = acpi_get_pxm(handle);
+ if (pxm < 0) {
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN, "PXM was not found.\n"));
+ return_VOID;
+ }
+
+ data = kmalloc(sizeof(struct acpi_numa_node), GFP_KERNEL);
+ if (!data) {
+ printk(KERN_ERR"Not enough memory.\n");
+ return_VOID;
+ }
+
+ data->handle = handle;
+ data->pxm = pxm;
+ data->nid = -1;
+
+ acpi_walk_namespace(ACPI_TYPE_PROCESSOR,
+ handle,
+ (u32) 1,
+ find_processor,
+ data,
+ (void **)&cnt);
+ /*
+ * TBD: Check nid of memory object
+ * paddr_to_node[] (include/asm-ia64/numa.h)
+ */
+ if (! _cnt) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "nid of <%s> is not detected.\n",
+ acpi_device_bid(node_dev)));
+ goto cancel;
+ }
+
+ if (pxm_to_nid_map[pxm] < 0) {
+ int nid = allocate_nodeid(pxm);
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "nid <%d> is allocated for PXM <%d>.\n",
+ nid, data->pxm));
+ if (nid < 1) {
+ /* "node 0" is a fixed ID. */
+ printk(KERN_ERR"Cannot get nid.\n");
+ return_VOID;
+ }
+ data->nid = nid;
+ set_nodeid(pxm, nid);
+ } else {
+ data->nid = pxm_to_nid_map[pxm];
+ }
+
+
+ status = acpi_attach_data(handle, acpi_numa_data_handler, data);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR"Failed to attach NUMA data for <%s>.\n",
+ acpi_device_bid(node_dev));
+ goto cancel;
+ }
+
+ printk(KERN_INFO"Container <%s> is NUMA node.\n",
+ acpi_device_bid(node_dev));
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Initialized: Container<%s> PXM=%d nid=%d\n",
+ acpi_device_bid(node_dev), pxm, data->nid));
+ return_VOID;
+
+cancel:
+ if (data)
+ kfree(data);
+ return_VOID;
+}
+
+EXPORT_SYMBOL(acpi_numa_node_init);
+EXPORT_SYMBOL(acpi_numa_node_add);
+EXPORT_SYMBOL(acpi_numa_node_remove);
+EXPORT_SYMBOL(acpi_numa_node_data_detach);
+EXPORT_SYMBOL(acpi_numa_data_handler);
+EXPORT_SYMBOL(is_numa_node_device);
+
+#endif /* defined(CONFIG_ACPI_CONTAINER) && defined(CONFIG_HOTPLUG) */
diff -puN /dev/null include/acpi/numa.h
--- /dev/null 2003-08-16 05:19:42.000000000 +0900
+++ linux-2.6.9-rc2-fix-kei/include/acpi/numa.h 2004-09-24 00:14:56.386517641 +0900
@@ -0,0 +1,30 @@
+#ifndef _ACPI_NUMA_H_
+#define _ACPI_NUMA_H_
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/acpi.h>
+#include <asm/acpi.h>
+#include <acpi/acpixf.h>
+
+#if defined(CONFIG_ACPI_CONTAINER) || defined(CONFIG_ACPI_CONTAINER_MODULE)
+#include <linux/numa.h>
+struct acpi_numa_node {
+ acpi_handle handle;
+ int pxm;
+ int nid;
+};
+
+#ifndef MAX_PXM_DOMAINS
+#define MAX_PXM_DOMAINS (256)
+#endif
+extern void acpi_numa_node_init(acpi_handle handle);
+extern void acpi_numa_node_add(acpi_handle handle);
+extern void acpi_numa_node_remove(acpi_handle handle);
+extern void acpi_numa_data_handler ( acpi_handle handle, u32 function, void *context);
+extern void acpi_numa_node_data_detach(acpi_handle handle);
+extern int is_numa_node_device(acpi_handle handle);
+extern int acpi_numa_node_add_post(acpi_handle handle);
+extern int acpi_numa_node_remove_request(acpi_handle handle);
+#endif /* CONFIG_ACPI_CONTAINER */
+#endif
_
Name: container_for_numa.patch
Status: Tested on 2.6.9-rc2
Signed-off-by: Keiichiro Tokunaga <[email protected]>
Description:
Add NUMA node handling to the container driver.
Thanks,
Keiichiro Tokunaga
---
linux-2.6.9-rc2-fix-kei/drivers/acpi/container.c | 11 +++++++++++
linux-2.6.9-rc2-fix-kei/include/acpi/container.h | 15 ++++++++++++++-
2 files changed, 25 insertions(+), 1 deletion(-)
diff -puN drivers/acpi/container.c~container_for_numa drivers/acpi/container.c
--- linux-2.6.9-rc2-fix/drivers/acpi/container.c~container_for_numa 2004-09-24 00:45:56.781826629 +0900
+++ linux-2.6.9-rc2-fix-kei/drivers/acpi/container.c 2004-09-24 01:38:09.774323452 +0900
@@ -104,6 +104,8 @@ acpi_container_add(struct acpi_device *d
container = kmalloc(sizeof(struct acpi_container), GFP_KERNEL);
if(!container)
return_VALUE(-ENOMEM);
+
+ container_numa_init(device->handle);
memset(container, 0, sizeof(struct acpi_container));
container->handle = device->handle;
@@ -123,6 +125,14 @@ acpi_container_remove(struct acpi_device
{
acpi_status status = AE_OK;
struct acpi_container *pc = NULL;
+ if (type == ACPI_BUS_REMOVAL_EJECT) {
+ if (!device->flags.ejectable)
+ return(-EINVAL);
+
+ container_numa_remove(device->handle);
+ }
+
+ container_numa_detach_data(device->handle);
pc = (struct acpi_container*) acpi_driver_data(device);
if (pc)
@@ -198,6 +208,7 @@ container_device_add(struct acpi_device
if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_DEVICE)) {
return_VALUE(-ENODEV);
}
+ container_numa_add((*device)->handle);
result = acpi_bus_scan(*device);
diff -puN include/acpi/container.h~container_for_numa include/acpi/container.h
--- linux-2.6.9-rc2-fix/include/acpi/container.h~container_for_numa 2004-09-24 00:45:56.783779765 +0900
+++ linux-2.6.9-rc2-fix-kei/include/acpi/container.h 2004-09-24 00:45:56.786709469 +0900
@@ -2,12 +2,25 @@
#define __ACPI_CONTAINER_H
#include <linux/kernel.h>
-
struct acpi_container {
acpi_handle handle;
unsigned long sun;
int state;
};
+#ifdef CONFIG_ACPI_NUMA
+#include <acpi/numa.h>
+#define container_numa_init(handle) acpi_numa_node_init(handle)
+#define container_numa_add(handle) acpi_numa_node_add(handle)
+#define container_numa_remove(handle) acpi_numa_node_remove(handle)
+#define container_numa_detach_data(handle) acpi_numa_node_data_detach(handle)
+#define is_numa_node(handle) is_numa_node_device(acpi_handle handle)
+#else
+#define container_numa_init(handle)
+#define container_numa_add(handle)
+#define container_numa_remove(handle)
+#define container_numa_detach_data(handle)
+#define is_numa_node(handle) (0)
+#endif
#endif /* __ACPI_CONTAINER_H */
_
On Thu, 2004-09-23 at 09:31, Keiichiro Tokunaga wrote:
> -int __init register_node(struct node *node, int num, struct node *parent)
> +int register_node(struct node *node, int num, struct node *parent)
__devinit, please.
-- Dave
Keiichiro Tokunaga wrote:
>Name: container_for_numa.patch
>Status: Tested on 2.6.9-rc2
>Signed-off-by: Keiichiro Tokunaga <[email protected]>
>Description:
>Add NUMA node handling to the container driver.
>
>Thanks,
>Keiichiro Tokunaga
>---
>
>
>@@ -198,6 +208,7 @@ container_device_add(struct acpi_device
> if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_DEVICE)) {
> return_VALUE(-ENODEV);
> }
>+ container_numa_add((*device)->handle);
>
>
Maybe that should be :
container_numa_add(phandle);
instead? Device is the child at this point.
--Mika
On Thu, 23 Sep 2004 09:43:16 -0700 Dave Hansen wrote:
> On Thu, 2004-09-23 at 09:31, Keiichiro Tokunaga wrote:
> > -int __init register_node(struct node *node, int num, struct node *parent)
> > +int register_node(struct node *node, int num, struct node *parent)
>
> __devinit, please.
Exactly. Thanks for looking.
I have refreshed the patch. Anil, please replace the old one with this.
Thanks,
Keiichiro Tokunaga
Name: numa_hp_base.patch
Status: Tested on 2.6.9-rc2
Signed-off-by: Keiichiro Tokunaga <[email protected]>
Description:
Create unregister_node() to remove corresponding sysfs directory and files
from /sys/devices/system/node/.
---
linux-2.6.9-rc2-fix-kei/drivers/base/node.c | 19 +++++++++++++++++--
linux-2.6.9-rc2-fix-kei/include/linux/node.h | 3 ++-
linux-2.6.9-rc2-fix-kei/mm/page_alloc.c | 2 ++
3 files changed, 21 insertions(+), 3 deletions(-)
diff -puN drivers/base/node.c~numa_hp_base drivers/base/node.c
--- linux-2.6.9-rc2-fix/drivers/base/node.c~numa_hp_base 2004-09-24 00:14:55.000000000 +0900
+++ linux-2.6.9-rc2-fix-kei/drivers/base/node.c 2004-09-24 10:03:38.898061522 +0900
@@ -117,7 +117,7 @@ static SYSDEV_ATTR(numastat, S_IRUGO, no
*
* Initialize and register the node device.
*/
-int __init register_node(struct node *node, int num, struct node *parent)
+int __devinit register_node(struct node *node, int num, struct node *parent)
{
int error;
@@ -133,9 +133,24 @@ int __init register_node(struct node *no
return error;
}
+void __devexit unregister_node(struct node *node, struct node *parent)
+{
+ if (node == NULL) {
+ printk("unregister_node: node is null.");
+ return;
+ }
+ sysdev_remove_file(&node->sysdev, &attr_cpumap);
+ sysdev_remove_file(&node->sysdev, &attr_meminfo);
+ sysdev_unregister(&node->sysdev);
+}
-int __init register_node_type(void)
+
+static int __init register_node_type(void)
{
return sysdev_class_register(&node_class);
}
postcore_initcall(register_node_type);
+
+
+EXPORT_SYMBOL(register_node);
+EXPORT_SYMBOL(unregister_node);
diff -puN include/linux/node.h~numa_hp_base include/linux/node.h
--- linux-2.6.9-rc2-fix/include/linux/node.h~numa_hp_base 2004-09-24 00:14:55.000000000 +0900
+++ linux-2.6.9-rc2-fix-kei/include/linux/node.h 2004-09-24 11:29:57.267562810 +0900
@@ -26,7 +26,8 @@ struct node {
struct sys_device sysdev;
};
-extern int register_node(struct node *, int, struct node *);
+extern int __devinit register_node(struct node *, int, struct node *);
+extern void __devexit unregister_node(struct node *node, struct node *parent);
#define to_node(sys_device) container_of(sys_device, struct node, sysdev)
diff -puN mm/page_alloc.c~numa_hp_base mm/page_alloc.c
--- linux-2.6.9-rc2-fix/mm/page_alloc.c~numa_hp_base 2004-09-24 00:14:55.000000000 +0900
+++ linux-2.6.9-rc2-fix-kei/mm/page_alloc.c 2004-09-24 00:14:55.000000000 +0900
@@ -14,6 +14,7 @@
* (lots of bits borrowed from Ingo Molnar & Andrew Morton)
*/
+#include <linux/module.h>
#include <linux/config.h>
#include <linux/stddef.h>
#include <linux/mm.h>
@@ -44,6 +45,7 @@ int sysctl_lower_zone_protection = 0;
EXPORT_SYMBOL(totalram_pages);
EXPORT_SYMBOL(nr_swap_pages);
+EXPORT_SYMBOL(node_online_map);
/*
* Used by page_zone() to look up the address of the struct zone whose
_
> Keiichiro Tokunaga wrote:
>
> >Name: container_for_numa.patch
> >Status: Tested on 2.6.9-rc2
> >Signed-off-by: Keiichiro Tokunaga <[email protected]>
> >Description:
> >Add NUMA node handling to the container driver.
> >
> >Thanks,
> >Keiichiro Tokunaga
> >---
> >@@ -198,6 +208,7 @@ container_device_add(struct acpi_device
> > if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_DEVICE)) {
> > return_VALUE(-ENODEV);
> > }
> >+ container_numa_add((*device)->handle);
> >
> >
> Maybe that should be :
>
> container_numa_add(phandle);
>
> instead? Device is the child at this point.
Thanks for looking!
A container's handle needs to be passed to the function here.
The (*device)->handle is the handle. So there is no problem.
The phandle is just used for acpi_bus_add().
Thanks,
Keiichiro Tokunaga
On Mon, Sep 20, 2004 at 06:12:45PM -0500, Dmitry Torokhov wrote:
> Hi Anil,
>
> I obviously failed to deliver my idea :) I meant that I would like add eject
> attribute (along with maybe status, hid and some others) to kobjects in
> /sys/firmware/acpi tree.
Here the modified patch based on the your feedback. Now I am creating eject attribute
to the acpi kobjects in /sys/firmware/acpi.
---
Name:acpi_core_eject.patch
Status: Tested on 2.6.9-rc2
Signed-off-by: Anil S Keshavamurthy <[email protected]>
Depends:acpi_core
Version: applies on 2.6.9-rc2
The kernel when it receives an hardware sci eject request it simply passes this
to user mode agent and the agent in turn will offline all the child devices and
then echo's 1 onto the eject file for that acpi device.
This patch provides the sysfs "eject" interface for the user mode agent
to notify the core acpi so that the core acpi can trim its bus which
causes .remove function to be called for all child devices.
For example for LSB0 which is an ejectable device, we will see
/sys/firmware/acpi/namespace/ACPI/_SB/LSB/eject.
---
linux-2.6.9-rc2-askeshav/drivers/acpi/scan.c | 153 +++++++++++++++++++++++++++
1 files changed, 153 insertions(+)
diff -puN drivers/acpi/scan.c~acpi_core_eject drivers/acpi/scan.c
--- linux-2.6.9-rc2/drivers/acpi/scan.c~acpi_core_eject 2004-09-24 15:26:20.348278419 -0700
+++ linux-2.6.9-rc2-askeshav/drivers/acpi/scan.c 2004-09-24 15:26:20.441051855 -0700
@@ -2,6 +2,7 @@
* scan.c - support for transforming the ACPI namespace into individual objects
*/
+#include <linux/module.h>
#include <linux/init.h>
#include <linux/acpi.h>
@@ -34,7 +35,49 @@ static void acpi_device_release(struct k
kfree(dev);
}
+struct acpi_device_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct acpi_device *, char *);
+ ssize_t (*store)(struct acpi_device *, const char *, size_t);
+};
+
+typedef void acpi_device_sysfs_files(struct kobject *,
+ const struct attribute *);
+
+static void setup_sys_fs_device_files(struct acpi_device *dev,
+ acpi_device_sysfs_files *func);
+
+#define create_sysfs_device_files(dev) \
+ setup_sys_fs_device_files(dev, (acpi_device_sysfs_files *)&sysfs_create_file)
+#define remove_sysfs_device_files(dev) \
+ setup_sys_fs_device_files(dev, (acpi_device_sysfs_files *)&sysfs_remove_file)
+
+
+#define to_acpi_device(n) container_of(n, struct acpi_device, kobj)
+#define to_handle_attr(n) container_of(n, struct acpi_device_attribute, attr);
+
+static ssize_t acpi_device_attr_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ struct acpi_device *device = to_acpi_device(kobj);
+ struct acpi_device_attribute *attribute = to_handle_attr(attr);
+ return attribute->show ? attribute->show(device, buf) : 0;
+}
+static ssize_t acpi_device_attr_store(struct kobject *kobj,
+ struct attribute *attr, const char *buf, size_t len)
+{
+ struct acpi_device *device = to_acpi_device(kobj);
+ struct acpi_device_attribute *attribute = to_handle_attr(attr);
+ return attribute->store ? attribute->store(device, buf, len) : len;
+}
+
+static struct sysfs_ops acpi_device_sysfs_ops = {
+ .show = acpi_device_attr_show,
+ .store = acpi_device_attr_store,
+};
+
static struct kobj_type ktype_acpi_ns = {
+ .sysfs_ops = &acpi_device_sysfs_ops,
.release = acpi_device_release,
};
@@ -76,6 +119,7 @@ static void acpi_device_register(struct
device->kobj.ktype = &ktype_acpi_ns;
device->kobj.kset = &acpi_namespace_kset;
kobject_add(&device->kobj);
+ create_sysfs_device_files(device);
}
static int
@@ -95,6 +139,7 @@ acpi_device_unregister (
spin_unlock(&acpi_device_lock);
acpi_detach_data(device->handle, acpi_bus_data_handler);
+ remove_sysfs_device_files(device);
kobject_unregister(&device->kobj);
return 0;
}
@@ -291,6 +336,114 @@ end:
}
/* --------------------------------------------------------------------------
+ ACPI hotplug sysfs device file support
+ -------------------------------------------------------------------------- */
+static ssize_t acpi_eject_store(struct acpi_device *device,
+ const char *buf, size_t count);
+
+#define ACPI_DEVICE_ATTR(_name,_mode,_show,_store) \
+static struct acpi_device_attribute acpi_device_attr_##_name = \
+ __ATTR(_name, _mode, _show, _store)
+
+ACPI_DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
+
+/**
+ * setup_sys_fs_device_files - sets up the device files under device namespace
+ * @@dev: acpi_device object
+ * @@func: function pointer to create or destroy the device file
+ */
+static void
+setup_sys_fs_device_files (
+ struct acpi_device *dev,
+ acpi_device_sysfs_files *func)
+{
+ if (dev->flags.ejectable == 1)
+ (*(func))(&dev->kobj,&acpi_device_attr_eject.attr);
+}
+
+static int
+acpi_eject_operation(acpi_handle handle, int lockable)
+{
+ struct acpi_object_list arg_list;
+ union acpi_object arg;
+ acpi_status status = AE_OK;
+
+ /*
+ * TBD: evaluate _PS3?
+ */
+
+ if (lockable) {
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+ arg.type = ACPI_TYPE_INTEGER;
+ arg.integer.value = 0;
+ acpi_evaluate_object(handle, "_LCK", &arg_list, NULL);
+ }
+
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+ arg.type = ACPI_TYPE_INTEGER;
+ arg.integer.value = 1;
+
+ /*
+ * TBD: _EJD support.
+ */
+
+ status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
+ if (ACPI_FAILURE(status)) {
+ return(-ENODEV);
+ }
+
+ return(0);
+}
+
+
+static ssize_t
+acpi_eject_store(struct acpi_device *device, const char *buf, size_t count)
+{
+ int result;
+ int ret = count;
+ int islockable;
+ acpi_status status;
+ acpi_handle handle;
+ acpi_object_type type = 0;
+
+ if ((!count) || (buf[0] != '1')) {
+ return -EINVAL;
+ }
+
+#ifndef FORCE_EJECT
+ if (device->driver == NULL) {
+ ret = -ENODEV;
+ goto err;
+ }
+#endif
+ status = acpi_get_type(device->handle, &type);
+ if (ACPI_FAILURE(status) || (!device->flags.ejectable) ) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ islockable = device->flags.lockable;
+ handle = device->handle;
+
+ if (type == ACPI_TYPE_PROCESSOR)
+ result = acpi_bus_trim(device, 0);
+ else
+ result = acpi_bus_trim(device, 1);
+
+ if (!result)
+ result = acpi_eject_operation(handle, islockable);
+
+ if (result) {
+ ret = -EBUSY;
+ }
+err:
+ return ret;
+}
+
+
+/* --------------------------------------------------------------------------
Performance Management
-------------------------------------------------------------------------- */
_
On Thu, Sep 23, 2004 at 02:10:31AM +0900, Keiichiro Tokunaga wrote:
> On Wed, 22 Sep 2004 08:52:59 -0600, Alex Williamson wrote:
> > On Wed, 2004-09-22 at 22:15 +0900, Keiichiro Tokunaga wrote:
> > >
> > > I would like to suggest introducing a new function 'acpi_get_pxm()'
> > > since other drivers might need it in the future. Acutally, ACPI container
> > > hotplug will be using it soon.
> > >
> > > Here is a patch creating the function.
> > >
> >
> > Nice, I have a couple I/O locality patches that could be simplified
Here is the revised patch which now fixes the all issues that were discussed.
- Now defines and uses acpi_get_pxm
- small bugfix "change __initdata to __devinitdata for pxm_to_nid_map varable
---
Name:acpi_hotplug_arch.patch
Status: Tested on 2.6.9-rc2
Signed-off-by: Anil S Keshavamurthy <[email protected]>
Depends:
Version: applies on 2.6.9-rc2
Description:
This patch provides the architecture specifice support for mapping lsapic to cpu array.
Currently this supports just IA64. Support for IA32 and x86_64 is in progress
changes from previous release:
- Now defines and uses acpi_get_pxm
- small bugfix "change __initdata to __devinitdata for pxm_to_nid_map varable
---
linux-2.6.9-rc2-askeshav/arch/i386/kernel/acpi/boot.c | 22 +++
linux-2.6.9-rc2-askeshav/arch/ia64/kernel/acpi.c | 107 +++++++++++++++++-
linux-2.6.9-rc2-askeshav/drivers/acpi/numa.c | 19 +++
linux-2.6.9-rc2-askeshav/include/linux/acpi.h | 14 ++
4 files changed, 159 insertions(+), 3 deletions(-)
diff -puN include/linux/acpi.h~acpi_hotplug_arch include/linux/acpi.h
--- linux-2.6.9-rc2/include/linux/acpi.h~acpi_hotplug_arch 2004-09-24 15:26:23.528942442 -0700
+++ linux-2.6.9-rc2-askeshav/include/linux/acpi.h 2004-09-24 15:26:23.637340879 -0700
@@ -396,6 +396,12 @@ void acpi_numa_processor_affinity_init (
void acpi_numa_memory_affinity_init (struct acpi_table_memory_affinity *ma);
void acpi_numa_arch_fixup(void);
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+/* Arch dependent functions for cpu hotplug support */
+int acpi_map_lsapic(acpi_handle handle, int *pcpu);
+int acpi_unmap_lsapic(int cpu);
+#endif /* CONFIG_ACPI_HOTPLUG_CPU */
+
extern int acpi_mp_config;
extern u32 pci_mmcfg_base_addr;
@@ -471,4 +477,12 @@ static inline int acpi_blacklisted(void)
#endif /*!CONFIG_ACPI_INTERPRETER*/
+#ifdef CONFIG_ACPI_NUMA
+int acpi_get_pxm(acpi_handle handle);
+#else
+static inline int acpi_get_pxm(acpi_handle handle)
+{
+ return 0;
+}
+#endif
#endif /*_LINUX_ACPI_H*/
diff -puN arch/ia64/kernel/acpi.c~acpi_hotplug_arch arch/ia64/kernel/acpi.c
--- linux-2.6.9-rc2/arch/ia64/kernel/acpi.c~acpi_hotplug_arch 2004-09-24 15:26:23.533825255 -0700
+++ linux-2.6.9-rc2-askeshav/arch/ia64/kernel/acpi.c 2004-09-24 15:26:23.639294003 -0700
@@ -354,11 +354,11 @@ acpi_parse_madt (unsigned long phys_addr
#define PXM_FLAG_LEN ((MAX_PXM_DOMAINS + 1)/32)
static int __initdata srat_num_cpus; /* number of cpus */
-static u32 __initdata pxm_flag[PXM_FLAG_LEN];
+static u32 __devinitdata pxm_flag[PXM_FLAG_LEN];
#define pxm_bit_set(bit) (set_bit(bit,(void *)pxm_flag))
#define pxm_bit_test(bit) (test_bit(bit,(void *)pxm_flag))
/* maps to convert between proximity domain and logical node ID */
-int __initdata pxm_to_nid_map[MAX_PXM_DOMAINS];
+int __devinitdata pxm_to_nid_map[MAX_PXM_DOMAINS];
int __initdata nid_to_pxm_map[MAX_NUMNODES];
static struct acpi_table_slit __initdata *slit_table;
@@ -650,4 +650,107 @@ acpi_gsi_to_irq (u32 gsi, unsigned int *
return 0;
}
+/*
+ * ACPI based hotplug CPU support
+ */
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+static
+int
+acpi_map_cpu2node(acpi_handle handle, int cpu, long physid)
+{
+#ifdef CONFIG_ACPI_NUMA
+ int pxm_id;
+
+ pxm_id = acpi_get_pxm(handle);
+
+ /*
+ * Assuming that the container driver would have set the proximity
+ * domain and would have initialized pxm_to_nid_map[pxm_id] && pxm_flag
+ */
+ node_cpuid[cpu].nid = (pxm_id < 0) ? 0:
+ pxm_to_nid_map[pxm_id];
+
+ node_cpuid[cpu].phys_id = physid;
+#endif
+ return(0);
+}
+
+
+int
+acpi_map_lsapic(acpi_handle handle, int *pcpu)
+{
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ union acpi_object *obj;
+ struct acpi_table_lsapic *lsapic;
+ cpumask_t tmp_map;
+ long physid;
+ int cpu;
+
+ if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
+ return -EINVAL;
+
+ if (!buffer.length || !buffer.pointer)
+ return -EINVAL;
+
+ obj = buffer.pointer;
+ if (obj->type != ACPI_TYPE_BUFFER ||
+ obj->buffer.length < sizeof(*lsapic)) {
+ acpi_os_free(buffer.pointer);
+ return -EINVAL;
+ }
+
+ lsapic = (struct acpi_table_lsapic *)obj->buffer.pointer;
+
+ if ((lsapic->header.type != ACPI_MADT_LSAPIC) ||
+ (!lsapic->flags.enabled)) {
+ acpi_os_free(buffer.pointer);
+ return -EINVAL;
+ }
+
+ physid = ((lsapic->id <<8) | (lsapic->eid));
+
+ acpi_os_free(buffer.pointer);
+ buffer.length = ACPI_ALLOCATE_BUFFER;
+ buffer.pointer = NULL;
+
+ cpus_complement(tmp_map, cpu_present_map);
+ cpu = first_cpu(tmp_map);
+ if(cpu >= NR_CPUS)
+ return -EINVAL;
+
+ acpi_map_cpu2node(handle, cpu, physid);
+
+ cpu_set(cpu, cpu_present_map);
+ ia64_cpu_to_sapicid[cpu] = physid;
+ ia64_acpiid_to_sapicid[lsapic->acpi_id] = ia64_cpu_to_sapicid[cpu];
+
+ *pcpu = cpu;
+ return(0);
+}
+EXPORT_SYMBOL(acpi_map_lsapic);
+
+
+int
+acpi_unmap_lsapic(int cpu)
+{
+ int i;
+
+ for (i=0; i<MAX_SAPICS; i++) {
+ if (ia64_acpiid_to_sapicid[i] == ia64_cpu_to_sapicid[cpu]) {
+ ia64_acpiid_to_sapicid[i] = -1;
+ break;
+ }
+ }
+ ia64_cpu_to_sapicid[cpu] = -1;
+ cpu_clear(cpu,cpu_present_map);
+
+#ifdef CONFIG_ACPI_NUMA
+ /* NUMA specific cleanup's */
+#endif
+
+ return(0);
+}
+EXPORT_SYMBOL(acpi_unmap_lsapic);
+#endif /* CONFIG_ACPI_HOTPLUG_CPU */
+
#endif /* CONFIG_ACPI_BOOT */
diff -puN arch/i386/kernel/acpi/boot.c~acpi_hotplug_arch arch/i386/kernel/acpi/boot.c
--- linux-2.6.9-rc2/arch/i386/kernel/acpi/boot.c~acpi_hotplug_arch 2004-09-24 15:26:23.540661192 -0700
+++ linux-2.6.9-rc2-askeshav/arch/i386/kernel/acpi/boot.c 2004-09-24 15:26:23.640270566 -0700
@@ -478,6 +478,28 @@ unsigned int acpi_register_gsi(u32 gsi,
}
EXPORT_SYMBOL(acpi_register_gsi);
+/*
+ * ACPI based hotplug support for CPU
+ */
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+int
+acpi_map_lsapic(acpi_handle handle, int *pcpu)
+{
+ /* TBD */
+ return -EINVAL;
+}
+EXPORT_SYMBOL(acpi_map_lsapic);
+
+
+int
+acpi_unmap_lsapic(int cpu)
+{
+ /* TBD */
+ return -EINVAL;
+}
+EXPORT_SYMBOL(acpi_unmap_lsapic);
+#endif /* CONFIG_ACPI_HOTPLUG_CPU */
+
static unsigned long __init
acpi_scan_rsdp (
unsigned long start,
diff -puN drivers/acpi/numa.c~acpi_hotplug_arch drivers/acpi/numa.c
--- linux-2.6.9-rc2/drivers/acpi/numa.c~acpi_hotplug_arch 2004-09-24 15:26:23.546520567 -0700
+++ linux-2.6.9-rc2-askeshav/drivers/acpi/numa.c 2004-09-24 15:26:23.640270566 -0700
@@ -22,7 +22,7 @@
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
*/
-
+#include <linux/module.h>
#include <linux/config.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -195,3 +195,20 @@ acpi_numa_init()
acpi_numa_arch_fixup();
return 0;
}
+
+int
+acpi_get_pxm(acpi_handle handle)
+{
+ unsigned long pxm;
+ acpi_status status;
+ acpi_handle phandle;
+
+ do {
+ status = acpi_evaluate_integer(handle, "_PXM", NULL, &pxm);
+ if (ACPI_SUCCESS(status))
+ return (int)pxm;
+ status = acpi_get_parent(handle, &phandle);
+ } while(ACPI_SUCCESS(status));
+ return -1;
+}
+EXPORT_SYMBOL(acpi_get_pxm);
_
On Wed, Sep 22, 2004 at 05:34:00PM +0900, Keiichiro Tokunaga wrote:
> On Mon, 20 Sep 2004 09:41:07 -0700 Keshavamurthy Anil S wrote:
> I don't think that the check 'if (node_online(node))' is necessary
> because sysfs_nodes[node] is there no matter if the node is online
> or offline. sysfs_nodes[] is cleared only when unregister_node()
> is called and it would be always called after unregister_cpu().
Refreshed this patch to address the above issues. Please let me know if you see
any other issue with this patch.
---
Name:topology.patch
Status:Tested on 2.6.9-rc2
Signed-off-by: Anil S Keshavamurthy <[email protected]>
Depends:
Version: applies on 2.6.9-rc2
Description:
Extends support for dynamic registration and unregistration of the cpu,
by implementing and exporting arch_register_cpu()/arch_unregister_cpu().
Also combines multiple implementation of topology_init() functions to
single topology_init() in case of ia64 architecture.
---
/dev/null | 43 ------
linux-2.6.9-rc2-askeshav/arch/i386/mach-default/topology.c | 31 ++++
linux-2.6.9-rc2-askeshav/arch/ia64/dig/Makefile | 5
linux-2.6.9-rc2-askeshav/arch/ia64/kernel/Makefile | 3
linux-2.6.9-rc2-askeshav/arch/ia64/kernel/topology.c | 90 +++++++++++++
linux-2.6.9-rc2-askeshav/arch/ia64/mm/numa.c | 35 -----
linux-2.6.9-rc2-askeshav/drivers/base/cpu.c | 20 ++
linux-2.6.9-rc2-askeshav/include/asm-i386/cpu.h | 17 --
linux-2.6.9-rc2-askeshav/include/asm-ia64/cpu.h | 5
linux-2.6.9-rc2-askeshav/include/linux/cpu.h | 3
10 files changed, 153 insertions(+), 99 deletions(-)
diff -L arch/ia64/dig/topology.c -puN arch/ia64/dig/topology.c~topology /dev/null
--- linux-2.6.9-rc2/arch/ia64/dig/topology.c
+++ /dev/null 2004-06-30 13:03:36.000000000 -0700
@@ -1,43 +0,0 @@
-/*
- * arch/ia64/dig/topology.c
- * Popuate driverfs with topology information.
- * Derived entirely from i386/mach-default.c
- * Intel Corporation - Ashok Raj
- */
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/cpumask.h>
-#include <linux/percpu.h>
-#include <linux/notifier.h>
-#include <linux/cpu.h>
-#include <asm/cpu.h>
-
-static DEFINE_PER_CPU(struct ia64_cpu, cpu_devices);
-
-/*
- * First Pass: simply borrowed code for now. Later should hook into
- * hotplug notification for node/cpu/memory as applicable
- */
-
-static int arch_register_cpu(int num)
-{
- struct node *parent = NULL;
-
-#ifdef CONFIG_NUMA
- //parent = &node_devices[cpu_to_node(num)].node;
-#endif
-
- return register_cpu(&per_cpu(cpu_devices,num).cpu, num, parent);
-}
-
-static int __init topology_init(void)
-{
- int i;
-
- for_each_cpu(i) {
- arch_register_cpu(i);
- }
- return 0;
-}
-
-subsys_initcall(topology_init);
diff -puN arch/ia64/dig/Makefile~topology arch/ia64/dig/Makefile
--- linux-2.6.9-rc2/arch/ia64/dig/Makefile~topology 2004-09-24 15:26:26.939098651 -0700
+++ linux-2.6.9-rc2-askeshav/arch/ia64/dig/Makefile 2004-09-24 15:26:27.062145524 -0700
@@ -6,9 +6,4 @@
#
obj-y := setup.o
-
-ifndef CONFIG_NUMA
-obj-$(CONFIG_IA64_DIG) += topology.o
-endif
-
obj-$(CONFIG_IA64_GENERIC) += machvec.o
diff -puN arch/ia64/mm/numa.c~topology arch/ia64/mm/numa.c
--- linux-2.6.9-rc2/arch/ia64/mm/numa.c~topology 2004-09-24 15:26:26.943004901 -0700
+++ linux-2.6.9-rc2-askeshav/arch/ia64/mm/numa.c 2004-09-24 15:26:27.063122087 -0700
@@ -20,8 +20,6 @@
#include <asm/mmzone.h>
#include <asm/numa.h>
-static struct node *sysfs_nodes;
-static struct cpu *sysfs_cpus;
/*
* The following structures are usually initialized by ACPI or
@@ -50,36 +48,3 @@ paddr_to_nid(unsigned long paddr)
return (i < num_node_memblks) ? node_memblk[i].nid : (num_node_memblks ? -1 : 0);
}
-static int __init topology_init(void)
-{
- int i, err = 0;
-
- sysfs_nodes = kmalloc(sizeof(struct node) * numnodes, GFP_KERNEL);
- if (!sysfs_nodes) {
- err = -ENOMEM;
- goto out;
- }
- memset(sysfs_nodes, 0, sizeof(struct node) * numnodes);
-
- sysfs_cpus = kmalloc(sizeof(struct cpu) * NR_CPUS, GFP_KERNEL);
- if (!sysfs_cpus) {
- kfree(sysfs_nodes);
- err = -ENOMEM;
- goto out;
- }
- memset(sysfs_cpus, 0, sizeof(struct cpu) * NR_CPUS);
-
- for (i = 0; i < numnodes; i++)
- if ((err = register_node(&sysfs_nodes[i], i, 0)))
- goto out;
-
- for (i = 0; i < NR_CPUS; i++)
- if (cpu_online(i))
- if((err = register_cpu(&sysfs_cpus[i], i,
- &sysfs_nodes[cpu_to_node(i)])))
- goto out;
- out:
- return err;
-}
-
-__initcall(topology_init);
diff -puN include/linux/cpu.h~topology include/linux/cpu.h
--- linux-2.6.9-rc2/include/linux/cpu.h~topology 2004-09-24 15:26:26.946911150 -0700
+++ linux-2.6.9-rc2-askeshav/include/linux/cpu.h 2004-09-24 15:26:27.063122087 -0700
@@ -32,6 +32,9 @@ struct cpu {
};
extern int register_cpu(struct cpu *, int, struct node *);
+#ifdef CONFIG_HOTPLUG_CPU
+extern void unregister_cpu(struct cpu *, struct node *);
+#endif
struct notifier_block;
#ifdef CONFIG_SMP
diff -puN include/asm-ia64/cpu.h~topology include/asm-ia64/cpu.h
--- linux-2.6.9-rc2/include/asm-ia64/cpu.h~topology 2004-09-24 15:26:26.951793963 -0700
+++ linux-2.6.9-rc2-askeshav/include/asm-ia64/cpu.h 2004-09-24 15:26:27.064098649 -0700
@@ -14,4 +14,9 @@ DECLARE_PER_CPU(struct ia64_cpu, cpu_dev
DECLARE_PER_CPU(int, cpu_state);
+extern int arch_register_cpu(int num);
+#ifdef CONFIG_HOTPLUG_CPU
+extern void arch_unregister_cpu(int);
+#endif
+
#endif /* _ASM_IA64_CPU_H_ */
diff -puN /dev/null arch/ia64/kernel/topology.c
--- /dev/null 2004-06-30 13:03:36.000000000 -0700
+++ linux-2.6.9-rc2-askeshav/arch/ia64/kernel/topology.c 2004-09-24 15:26:27.065075212 -0700
@@ -0,0 +1,90 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * This file contains NUMA specific variables and functions which can
+ * be split away from DISCONTIGMEM and are used on NUMA machines with
+ * contiguous memory.
+ * 2002/08/07 Erich Focht <[email protected]>
+ * Populate cpu entries in sysfs for non-numa systems as well
+ * Intel Corporation - Ashok Raj
+ */
+
+#include <linux/config.h>
+#include <linux/cpu.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/node.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <asm/mmzone.h>
+#include <asm/numa.h>
+#include <asm/cpu.h>
+
+#ifdef CONFIG_NUMA
+static struct node *sysfs_nodes;
+#endif
+static struct ia64_cpu *sysfs_cpus;
+
+int arch_register_cpu(int num)
+{
+ struct node *parent = NULL;
+
+#ifdef CONFIG_NUMA
+ parent = &sysfs_nodes[cpu_to_node(num)];
+#endif /* CONFIG_NUMA */
+
+ return register_cpu(&sysfs_cpus[num].cpu, num, parent);
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+
+void arch_unregister_cpu(int num)
+{
+ struct node *parent = NULL;
+
+#ifdef CONFIG_NUMA
+ int node = cpu_to_node(num);
+ parent = &sysfs_nodes[node];
+#endif /* CONFIG_NUMA */
+
+ return unregister_cpu(&sysfs_cpus[num].cpu, parent);
+}
+EXPORT_SYMBOL(arch_register_cpu);
+EXPORT_SYMBOL(arch_unregister_cpu);
+#endif /*CONFIG_HOTPLUG_CPU*/
+
+
+static int __init topology_init(void)
+{
+ int i, err = 0;
+
+#ifdef CONFIG_NUMA
+ sysfs_nodes = kmalloc(sizeof(struct node) * MAX_NUMNODES, GFP_KERNEL);
+ if (!sysfs_nodes) {
+ err = -ENOMEM;
+ goto out;
+ }
+ memset(sysfs_nodes, 0, sizeof(struct node) * MAX_NUMNODES);
+
+ for (i = 0; i < numnodes; i++)
+ if ((err = register_node(&sysfs_nodes[i], i, 0)))
+ goto out;
+#endif
+
+ sysfs_cpus = kmalloc(sizeof(struct ia64_cpu) * NR_CPUS, GFP_KERNEL);
+ if (!sysfs_cpus) {
+ err = -ENOMEM;
+ goto out;
+ }
+ memset(sysfs_cpus, 0, sizeof(struct ia64_cpu) * NR_CPUS);
+
+ for_each_present_cpu(i)
+ if((err = arch_register_cpu(i)))
+ goto out;
+out:
+ return err;
+}
+
+__initcall(topology_init);
diff -puN arch/ia64/kernel/Makefile~topology arch/ia64/kernel/Makefile
--- linux-2.6.9-rc2/arch/ia64/kernel/Makefile~topology 2004-09-24 15:26:26.956676775 -0700
+++ linux-2.6.9-rc2-askeshav/arch/ia64/kernel/Makefile 2004-09-24 15:26:27.065075212 -0700
@@ -6,7 +6,8 @@ extra-y := head.o init_task.o vmlinux.ld
obj-y := acpi.o entry.o efi.o efi_stub.o gate-data.o fsys.o ia64_ksyms.o irq.o irq_ia64.o \
irq_lsapic.o ivt.o machvec.o pal.o patch.o process.o perfmon.o ptrace.o sal.o \
- salinfo.o semaphore.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o unwind.o mca.o mca_asm.o
+ salinfo.o semaphore.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o \
+ unwind.o mca.o mca_asm.o topology.o
obj-$(CONFIG_IA64_BRL_EMU) += brl_emu.o
obj-$(CONFIG_IA64_GENERIC) += acpi-ext.o
diff -puN include/asm-i386/cpu.h~topology include/asm-i386/cpu.h
--- linux-2.6.9-rc2/include/asm-i386/cpu.h~topology 2004-09-24 15:26:26.960583025 -0700
+++ linux-2.6.9-rc2-askeshav/include/asm-i386/cpu.h 2004-09-24 15:26:27.066051774 -0700
@@ -11,18 +11,9 @@ struct i386_cpu {
struct cpu cpu;
};
extern struct i386_cpu cpu_devices[NR_CPUS];
-
-
-static inline int arch_register_cpu(int num){
- struct node *parent = NULL;
-
-#ifdef CONFIG_NUMA
- int node = cpu_to_node(num);
- if (node_online(node))
- parent = &node_devices[node].node;
-#endif /* CONFIG_NUMA */
-
- return register_cpu(&cpu_devices[num].cpu, num, parent);
-}
+extern int arch_register_cpu(int num);
+#ifdef CONFIG_HOTPLUG_CPU
+extern void arch_unregister_cpu(int);
+#endif
#endif /* _ASM_I386_CPU_H_ */
diff -puN arch/i386/mach-default/topology.c~topology arch/i386/mach-default/topology.c
--- linux-2.6.9-rc2/arch/i386/mach-default/topology.c~topology 2004-09-24 15:26:26.966442400 -0700
+++ linux-2.6.9-rc2-askeshav/arch/i386/mach-default/topology.c 2004-09-24 15:26:27.067028336 -0700
@@ -31,6 +31,37 @@
struct i386_cpu cpu_devices[NR_CPUS];
+int arch_register_cpu(int num){
+ struct node *parent = NULL;
+
+#ifdef CONFIG_NUMA
+ int node = cpu_to_node(num);
+ if (node_online(node))
+ parent = &node_devices[node].node;
+#endif /* CONFIG_NUMA */
+
+ return register_cpu(&cpu_devices[num].cpu, num, parent);
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+
+void arch_unregister_cpu(int num) {
+ struct node *parent = NULL;
+
+#ifdef CONFIG_NUMA
+ int node = cpu_to_node(num);
+ if (node_online(node))
+ parent = &node_devices[node].node;
+#endif /* CONFIG_NUMA */
+
+ return unregister_cpu(&cpu_devices[num].cpu, parent);
+}
+EXPORT_SYMBOL(arch_register_cpu);
+EXPORT_SYMBOL(arch_unregister_cpu);
+#endif /*CONFIG_HOTPLUG_CPU*/
+
+
+
#ifdef CONFIG_NUMA
#include <linux/mmzone.h>
#include <asm/node.h>
diff -puN drivers/base/cpu.c~topology drivers/base/cpu.c
--- linux-2.6.9-rc2/drivers/base/cpu.c~topology 2004-09-24 15:26:26.971325213 -0700
+++ linux-2.6.9-rc2-askeshav/drivers/base/cpu.c 2004-09-24 15:26:27.068004899 -0700
@@ -46,10 +46,23 @@ static ssize_t store_online(struct sys_d
}
static SYSDEV_ATTR(online, 0600, show_online, store_online);
-static void __init register_cpu_control(struct cpu *cpu)
+static void __devinit register_cpu_control(struct cpu *cpu)
{
sysdev_create_file(&cpu->sysdev, &attr_online);
}
+void unregister_cpu(struct cpu *cpu, struct node *root)
+{
+
+ if (root)
+ sysfs_remove_link(&root->sysdev.kobj,
+ kobject_name(&cpu->sysdev.kobj));
+ sysdev_remove_file(&cpu->sysdev, &attr_online);
+
+ sysdev_unregister(&cpu->sysdev);
+
+ return;
+}
+EXPORT_SYMBOL(unregister_cpu);
#else /* ... !CONFIG_HOTPLUG_CPU */
static inline void register_cpu_control(struct cpu *cpu)
{
@@ -64,7 +77,7 @@ static inline void register_cpu_control(
*
* Initialize and register the CPU device.
*/
-int __init register_cpu(struct cpu *cpu, int num, struct node *root)
+int __devinit register_cpu(struct cpu *cpu, int num, struct node *root)
{
int error;
@@ -81,6 +94,9 @@ int __init register_cpu(struct cpu *cpu,
register_cpu_control(cpu);
return error;
}
+#ifdef CONFIG_HOTPLUG_CPU
+EXPORT_SYMBOL(register_cpu);
+#endif
_
On Mon, Sep 20, 2004 at 09:43:52AM -0700, Keshavamurthy Anil S wrote:
> Changes form previous version
> 1) Added depends on EXPERIMENTAL in kconfig file
Changes from previous version
Added prink for ACPI_NOTIFY_BUS_CHECK and for ACPI_NOTIFY_DEVICE_CHECK based on
the community feedback.
---
Name:processor_drv.patch
Status:Tested on 2.6.9-rc2
Signed-off-by: Anil S Keshavamurthy <[email protected]>
Depends:
Version: applies on 2.6.9-rc2
Description:
Extends the processor driver to support ACPI based Physical CPU hotplug.
---
include/linux/cpu.h | 0
kernel/cpu.c | 0
linux-2.6.9-rc2-askeshav/drivers/acpi/Kconfig | 8
linux-2.6.9-rc2-askeshav/drivers/acpi/processor.c | 485 ++++++++++++++++++----
4 files changed, 424 insertions(+), 69 deletions(-)
diff -puN drivers/acpi/Kconfig~processor_drv drivers/acpi/Kconfig
--- linux-2.6.9-rc2/drivers/acpi/Kconfig~processor_drv 2004-09-24 15:26:30.480114232 -0700
+++ linux-2.6.9-rc2-askeshav/drivers/acpi/Kconfig 2004-09-24 15:26:30.587536106 -0700
@@ -129,6 +129,14 @@ config ACPI_PROCESSOR
ACPI C2 and C3 processor states to save power, on systems that
support it.
+config ACPI_HOTPLUG_CPU
+ bool "Processor Hotplug (EXPERIMENTAL)"
+ depends on ACPI_PROCESSOR && HOTPLUG_CPU && EXPERIMENTAL
+ depends on !IA64_SGI_SN
+ default n
+ ---help---
+ Select this option if your platform support physical CPU hotplug.
+
config ACPI_THERMAL
tristate "Thermal Zone"
depends on ACPI_PROCESSOR
diff -puN include/linux/cpu.h~processor_drv include/linux/cpu.h
diff -puN kernel/cpu.c~processor_drv kernel/cpu.c
diff -puN drivers/acpi/processor.c~processor_drv drivers/acpi/processor.c
--- linux-2.6.9-rc2/drivers/acpi/processor.c~processor_drv 2004-09-24 15:26:30.495739232 -0700
+++ linux-2.6.9-rc2-askeshav/drivers/acpi/processor.c 2004-09-24 15:26:30.591442356 -0700
@@ -4,6 +4,8 @@
* Copyright (C) 2001, 2002 Andy Grover <[email protected]>
* Copyright (C) 2001, 2002 Paul Diefenbaugh <[email protected]>
* Copyright (C) 2004 Dominik Brodowski <[email protected]>
+ * Copyright (C) 2004 Anil S Keshavamurthy <[email protected]>
+ * - Added processor hotplug support
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
@@ -37,11 +39,13 @@
#include <linux/pci.h>
#include <linux/pm.h>
#include <linux/cpufreq.h>
+#include <linux/cpu.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <asm/io.h>
#include <asm/system.h>
+#include <asm/cpu.h>
#include <asm/delay.h>
#include <asm/uaccess.h>
#include <asm/processor.h>
@@ -69,10 +73,11 @@
#define C2_OVERHEAD 4 /* 1us (3.579 ticks per us) */
#define C3_OVERHEAD 4 /* 1us (3.579 ticks per us) */
-
#define ACPI_PROCESSOR_LIMIT_USER 0
#define ACPI_PROCESSOR_LIMIT_THERMAL 1
+#define ACPI_STA_PRESENT 0x00000001
+
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
ACPI_MODULE_NAME ("acpi_processor")
@@ -82,12 +87,16 @@ MODULE_LICENSE("GPL");
static int acpi_processor_add (struct acpi_device *device);
+static int acpi_processor_start (struct acpi_device *device);
static int acpi_processor_remove (struct acpi_device *device, int type);
static int acpi_processor_info_open_fs(struct inode *inode, struct file *file);
static int acpi_processor_throttling_open_fs(struct inode *inode, struct file *file);
static int acpi_processor_power_open_fs(struct inode *inode, struct file *file);
static int acpi_processor_limit_open_fs(struct inode *inode, struct file *file);
static int acpi_processor_get_limit_info(struct acpi_processor *pr);
+static void acpi_processor_notify ( acpi_handle handle, u32 event, void *data);
+static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu);
+static int acpi_processor_handle_eject(struct acpi_processor *pr);
static struct acpi_driver acpi_processor_driver = {
.name = ACPI_PROCESSOR_DRIVER_NAME,
@@ -96,9 +105,12 @@ static struct acpi_driver acpi_processor
.ops = {
.add = acpi_processor_add,
.remove = acpi_processor_remove,
+ .start = acpi_processor_start,
},
};
+#define INSTALL_NOTIFY_HANDLER 1
+#define UNINSTALL_NOTIFY_HANDLER 2
struct acpi_processor_errata {
u8 smp;
@@ -2237,23 +2249,30 @@ acpi_processor_get_info (
cpu_index = convert_acpiid_to_cpu(pr->acpi_id);
- if ( !cpu0_initialized && (cpu_index == 0xff)) {
- /* Handle UP system running SMP kernel, with no LAPIC in MADT */
- cpu_index = 0;
- } else if (cpu_index > num_online_cpus()) {
- /*
- * Extra Processor objects may be enumerated on MP systems with
- * less than the max # of CPUs. They should be ignored.
- */
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error getting cpuindex for acpiid 0x%x\n",
- pr->acpi_id));
- return_VALUE(-ENODEV);
- }
- cpu0_initialized = 1;
-
- pr->id = cpu_index;
-
+ /* Handle UP system running SMP kernel, with no LAPIC in MADT */
+ if ( !cpu0_initialized && (cpu_index == 0xff) &&
+ (num_online_cpus() == 1)) {
+ cpu_index = 0;
+ }
+
+ cpu0_initialized = 1;
+
+ pr->id = cpu_index;
+
+ /*
+ * Extra Processor objects may be enumerated on MP systems with
+ * less than the max # of CPUs. They should be ignored _iff
+ * they are physically not present.
+ */
+ if (cpu_index >= NR_CPUS) {
+ if (ACPI_FAILURE(acpi_processor_hotadd_init(pr->handle, &pr->id))) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error getting cpuindex for acpiid 0x%x\n",
+ pr->acpi_id));
+ return_VALUE(-ENODEV);
+ }
+ }
+
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d:%d]\n", pr->id,
pr->acpi_id));
@@ -2292,6 +2311,65 @@ acpi_processor_get_info (
}
+static int
+acpi_processor_start(
+ struct acpi_device *device)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ u32 i = 0;
+ struct acpi_processor *pr;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_start");
+
+ pr = acpi_driver_data(device);
+
+ result = acpi_processor_get_info(pr);
+ if (result) {
+ /* Processor is physically not present */
+ return_VALUE(0);
+ }
+
+ BUG_ON((pr->id >= NR_CPUS) || (pr->id < 0));
+
+ processors[pr->id] = pr;
+
+ result = acpi_processor_add_fs(device);
+ if (result)
+ goto end;
+
+ status = acpi_install_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY,
+ acpi_processor_notify, pr);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error installing device notify handler\n"));
+ }
+
+ /*
+ * Install the idle handler if processor power management is supported.
+ * Note that the default idle handler (default_idle) will be used on
+ * platforms that only support C1.
+ */
+ if ((pr->id == 0) && (pr->flags.power)) {
+ pm_idle_save = pm_idle;
+ pm_idle = acpi_processor_idle;
+ }
+
+ printk(KERN_INFO PREFIX "%s [%s] (supports",
+ acpi_device_name(device), acpi_device_bid(device));
+ for (i=1; i<ACPI_C_STATE_COUNT; i++)
+ if (pr->power.states[i].valid)
+ printk(" C%d", i);
+ if (pr->flags.throttling)
+ printk(", %d throttling states", pr->throttling.state_count);
+ printk(")\n");
+end:
+
+ return_VALUE(result);
+}
+
+
+
static void
acpi_processor_notify (
acpi_handle handle,
@@ -2333,10 +2411,7 @@ static int
acpi_processor_add (
struct acpi_device *device)
{
- int result = 0;
- acpi_status status = AE_OK;
struct acpi_processor *pr = NULL;
- u32 i = 0;
ACPI_FUNCTION_TRACE("acpi_processor_add");
@@ -2353,51 +2428,7 @@ acpi_processor_add (
strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS);
acpi_driver_data(device) = pr;
- result = acpi_processor_get_info(pr);
- if (result)
- goto end;
-
- result = acpi_processor_add_fs(device);
- if (result)
- goto end;
-
- status = acpi_install_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY,
- acpi_processor_notify, pr);
- if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error installing notify handler\n"));
- result = -ENODEV;
- goto end;
- }
-
- processors[pr->id] = pr;
-
- /*
- * Install the idle handler if processor power management is supported.
- * Note that the default idle handler (default_idle) will be used on
- * platforms that only support C1.
- */
- if ((pr->id == 0) && (pr->flags.power)) {
- pm_idle_save = pm_idle;
- pm_idle = acpi_processor_idle;
- }
-
- printk(KERN_INFO PREFIX "%s [%s] (supports",
- acpi_device_name(device), acpi_device_bid(device));
- for (i=1; i<ACPI_C_STATE_COUNT; i++)
- if (pr->power.states[i].valid)
- printk(" C%d", i);
- if (pr->flags.throttling)
- printk(", %d throttling states", pr->throttling.state_count);
- printk(")\n");
-
-end:
- if (result) {
- acpi_processor_remove_fs(device);
- kfree(pr);
- }
-
- return_VALUE(result);
+ return_VALUE(0);
}
@@ -2416,17 +2447,27 @@ acpi_processor_remove (
pr = (struct acpi_processor *) acpi_driver_data(device);
+ if (pr->id >= NR_CPUS) {
+ kfree(pr);
+ return_VALUE(0);
+ }
+
+ if (type == ACPI_BUS_REMOVAL_EJECT) {
+ if (acpi_processor_handle_eject(pr))
+ return_VALUE(-EINVAL);
+ }
+
/* Unregister the idle handler when processor #0 is removed. */
if (pr->id == 0) {
pm_idle = pm_idle_save;
synchronize_kernel();
}
- status = acpi_remove_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY,
+ status = acpi_remove_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY,
acpi_processor_notify);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error removing notify handler\n"));
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error removing device notify handler\n"));
}
acpi_processor_remove_fs(device);
@@ -2439,6 +2480,308 @@ acpi_processor_remove (
}
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+/****************************************************************************
+ * Acpi processor hotplug support *
+ ****************************************************************************/
+
+static int is_processor_present(acpi_handle handle);
+
+static int
+processor_run_sbin_hotplug(struct acpi_device *device,
+ int cpu, char *action)
+{
+ char *argv[3], *envp[7], action_str[32], cpu_str[15];
+ int i, ret;
+ int len;
+ char pathname[ACPI_PATHNAME_MAX] = {0};
+ acpi_status status;
+ char *processor_str;
+ struct acpi_buffer buffer = {ACPI_PATHNAME_MAX, pathname};
+
+ ACPI_FUNCTION_TRACE("processor_run_sbin_hotplug");
+
+
+ status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer);
+ if (ACPI_FAILURE(status)) {
+ return(-ENODEV);
+ }
+
+ len = strlen("PROCESSOR=") + strlen(pathname) + 1;
+ processor_str = kmalloc(len, GFP_KERNEL);
+ if (!processor_str)
+ return(-ENOMEM);
+
+ sprintf(processor_str, "PROCESSOR=%s",pathname);
+ sprintf(action_str, "ACTION=%s", action);
+ sprintf(cpu_str, "CPU=%d", cpu);
+
+ i = 0;
+ argv[i++] = hotplug_path;
+ argv[i++] = "cpu";
+ argv[i] = NULL;
+
+ i = 0;
+ envp[i++] = "HOME=/";
+ envp[i++] = "PATH=/sbin;/bin;/usr/sbin;/usr/bin";
+ envp[i++] = action_str;
+ envp[i++] = processor_str;
+ envp[i++] = cpu_str;
+ envp[i++] = "PLATFORM=ACPI";
+ envp[i] = NULL;
+
+ ret = call_usermodehelper(argv[0], argv, envp, 0);
+
+ kfree(processor_str);
+ return_VALUE(ret);
+}
+
+
+static int
+is_processor_present(
+ acpi_handle handle)
+{
+ acpi_status status;
+ unsigned long sta = 0;
+
+ ACPI_FUNCTION_TRACE("is_processor_present");
+
+ status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+ if (ACPI_FAILURE(status) || !(sta & ACPI_STA_PRESENT)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Processor Device is not present\n"));
+ return_VALUE(0);
+ }
+ return_VALUE(1);
+}
+
+
+static
+int acpi_processor_device_add(
+ acpi_handle handle,
+ struct acpi_device **device)
+{
+ acpi_handle phandle;
+ struct acpi_device *pdev;
+ struct acpi_processor *pr;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_device_add");
+
+ if (acpi_get_parent(handle, &phandle)) {
+ return_VALUE(-ENODEV);
+ }
+
+ if (acpi_bus_get_device(phandle, &pdev)) {
+ return_VALUE(-ENODEV);
+ }
+
+ if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_PROCESSOR)) {
+ return_VALUE(-ENODEV);
+ }
+
+ acpi_bus_scan(*device);
+
+ pr = acpi_driver_data(*device);
+ if (!pr)
+ return_VALUE(-ENODEV);
+
+ if ((pr->id >=0) && (pr->id < NR_CPUS)) {
+ processor_run_sbin_hotplug(*device, pr->id, "add");
+ }
+ return_VALUE(0);
+}
+
+
+static void
+acpi_processor_hotplug_notify (
+ acpi_handle handle,
+ u32 event,
+ void *data)
+{
+ struct acpi_processor *pr;
+ struct acpi_device *device = NULL;
+ int result;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_hotplug_notify");
+
+ switch (event) {
+ case ACPI_NOTIFY_BUS_CHECK:
+ case ACPI_NOTIFY_DEVICE_CHECK:
+ printk("Processor driver received %s event\n",
+ (event==ACPI_NOTIFY_BUS_CHECK)?
+ "ACPI_NOTIFY_BUS_CHECK":"ACPI_NOTIFY_DEVICE_CHECK");
+
+ if (!is_processor_present(handle))
+ break;
+
+ if (acpi_bus_get_device(handle, &device)) {
+ result = acpi_processor_device_add(handle, &device);
+ if (result)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to add the device\n"));
+ break;
+ }
+
+ pr = acpi_driver_data(device);
+ if (!pr) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Driver data is NULL\n"));
+ break;
+ }
+
+ if (pr->id >= 0 && (pr->id < NR_CPUS)) {
+ processor_run_sbin_hotplug(device, pr->id, "remove");
+ break;
+ }
+
+ result = acpi_processor_start(device);
+ if ((!result) && ((pr->id >=0) && (pr->id < NR_CPUS))) {
+ processor_run_sbin_hotplug(device, pr->id, "add");
+ } else {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Device [%s] failed to start\n",
+ acpi_device_bid(device)));
+ }
+ break;
+ case ACPI_NOTIFY_EJECT_REQUEST:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,"received ACPI_NOTIFY_EJECT_REQUEST\n"));
+
+ if (acpi_bus_get_device(handle, &device)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,"Device don't exist, dropping EJECT\n"));
+ break;
+ }
+ pr = acpi_driver_data(device);
+ if (!pr) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,"Driver data is NULL, dropping EJECT\n"));
+ return_VOID;
+ }
+
+ if ((pr->id < NR_CPUS) && (cpu_present(pr->id)))
+ processor_run_sbin_hotplug(device, pr->id, "remove");
+ break;
+ default:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Unsupported event [0x%x]\n", event));
+ break;
+ }
+
+ return_VOID;
+}
+
+static acpi_status
+processor_walk_namespace_cb(acpi_handle handle,
+ u32 lvl,
+ void *context,
+ void **rv)
+{
+ acpi_status status;
+ int *action = context;
+ acpi_object_type type = 0;
+
+ status = acpi_get_type(handle, &type);
+ if (ACPI_FAILURE(status))
+ return(AE_OK);
+
+ if (type != ACPI_TYPE_PROCESSOR)
+ return(AE_OK);
+
+ switch(*action) {
+ case INSTALL_NOTIFY_HANDLER:
+ acpi_install_notify_handler(handle,
+ ACPI_SYSTEM_NOTIFY,
+ acpi_processor_hotplug_notify,
+ NULL);
+ break;
+ case UNINSTALL_NOTIFY_HANDLER:
+ acpi_remove_notify_handler(handle,
+ ACPI_SYSTEM_NOTIFY,
+ acpi_processor_hotplug_notify);
+ break;
+ default:
+ break;
+ }
+
+ return(AE_OK);
+}
+
+
+static acpi_status
+acpi_processor_hotadd_init(
+ acpi_handle handle,
+ int *p_cpu)
+{
+ ACPI_FUNCTION_TRACE("acpi_processor_hotadd_init");
+
+ if (!is_processor_present(handle)) {
+ return_VALUE(AE_ERROR);
+ }
+
+ if (acpi_map_lsapic(handle, p_cpu))
+ return_VALUE(AE_ERROR);
+
+ if (arch_register_cpu(*p_cpu)) {
+ acpi_unmap_lsapic(*p_cpu);
+ return_VALUE(AE_ERROR);
+ }
+
+ return_VALUE(AE_OK);
+}
+
+
+static int
+acpi_processor_handle_eject(struct acpi_processor *pr)
+{
+ if (cpu_online(pr->id)) {
+ return(-EINVAL);
+ }
+ arch_unregister_cpu(pr->id);
+ acpi_unmap_lsapic(pr->id);
+ return(0);
+}
+#else
+static acpi_status
+acpi_processor_hotadd_init(
+ acpi_handle handle,
+ int *p_cpu)
+{
+ return AE_ERROR;
+}
+static int
+acpi_processor_handle_eject(struct acpi_processor *pr)
+{
+ return(-EINVAL);
+}
+#endif
+
+
+static
+void acpi_processor_install_hotplug_notify(void)
+{
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+ int action = INSTALL_NOTIFY_HANDLER;
+ acpi_walk_namespace(ACPI_TYPE_PROCESSOR,
+ ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX,
+ processor_walk_namespace_cb,
+ &action, NULL);
+#endif
+}
+
+
+static
+void acpi_processor_uninstall_hotplug_notify(void)
+{
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+ int action = UNINSTALL_NOTIFY_HANDLER;
+ acpi_walk_namespace(ACPI_TYPE_PROCESSOR,
+ ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX,
+ processor_walk_namespace_cb,
+ &action, NULL);
+#endif
+}
+
+
static int __init
acpi_processor_init (void)
{
@@ -2460,6 +2803,8 @@ acpi_processor_init (void)
return_VALUE(-ENODEV);
}
+ acpi_processor_install_hotplug_notify();
+
acpi_thermal_cpufreq_init();
acpi_processor_ppc_init();
@@ -2477,6 +2822,8 @@ acpi_processor_exit (void)
acpi_thermal_cpufreq_exit();
+ acpi_processor_uninstall_hotplug_notify();
+
acpi_bus_unregister_driver(&acpi_processor_driver);
remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
_
On Mon, Sep 20, 2004 at 09:47:19AM -0700, Keshavamurthy Anil S wrote:
> Changes from previous release:
> 1) Typo fix- ACPI004 to ACPI0004
> 2) Added depends on EXPERIMENTAL in Kconfig file
Refreshed this patch and added printk for ACPI_NOTIFY_BUS_CHECK
and for ACPI_NOTIFY_DEVICE_CHECK as no major issues were identified with this patch.
---
Name:container_drv.patch
Status: Tested on 2.6.9-rc1
Signed-off-by: Anil S Keshavamurthy <[email protected]>
Depends:
Version: applies on 2.6.9-rc1
Description:
This is the very early version on the Container driver which supports
hotplug notifications on ACPI0004, PNP0A05 and PNP0A06 devices.
Changes from previous release:
1) Mergerd the typo fix patch which changes "ACPI004" to "ACPI0004"
---
linux-2.6.9-rc2-askeshav/drivers/acpi/Kconfig | 10
linux-2.6.9-rc2-askeshav/drivers/acpi/Makefile | 1
linux-2.6.9-rc2-askeshav/drivers/acpi/container.c | 344 ++++++++++++++++++++++
linux-2.6.9-rc2-askeshav/include/acpi/container.h | 13
4 files changed, 367 insertions(+), 1 deletion(-)
diff -puN drivers/acpi/Kconfig~container_drv drivers/acpi/Kconfig
--- linux-2.6.9-rc2/drivers/acpi/Kconfig~container_drv 2004-09-24 15:26:33.791637629 -0700
+++ linux-2.6.9-rc2-askeshav/drivers/acpi/Kconfig 2004-09-24 15:26:33.887340753 -0700
@@ -133,6 +133,7 @@ config ACPI_HOTPLUG_CPU
bool "Processor Hotplug (EXPERIMENTAL)"
depends on ACPI_PROCESSOR && HOTPLUG_CPU && EXPERIMENTAL
depends on !IA64_SGI_SN
+ select ACPI_CONTAINER
default n
---help---
Select this option if your platform support physical CPU hotplug.
@@ -278,5 +279,12 @@ config X86_PM_TIMER
kernel logs, and/or you are using this on a notebook which
does not yet have an HPET, you should say "Y" here.
-endmenu
+config ACPI_CONTAINER
+ tristate "ACPI0004,PNP0A05 and PNP0A06 Container Driver (EXPERIMENTAL)"
+ depends on ACPI && EXPERIMENTAL
+ default (ACPI_HOTPLUG_MEMORY || ACPI_HOTPLUG_CPU || ACPI_HOTPLUG_IO)
+ ---help---
+ This is the ACPI generic container driver which supports
+ ACPI0004, PNP0A05 and PNP0A06 devices
+endmenu
diff -puN drivers/acpi/Makefile~container_drv drivers/acpi/Makefile
--- linux-2.6.9-rc2/drivers/acpi/Makefile~container_drv 2004-09-24 15:26:33.796520442 -0700
+++ linux-2.6.9-rc2-askeshav/drivers/acpi/Makefile 2004-09-24 15:26:33.888317315 -0700
@@ -41,6 +41,7 @@ obj-$(CONFIG_ACPI_FAN) += fan.o
obj-$(CONFIG_ACPI_PCI) += pci_root.o pci_link.o pci_irq.o pci_bind.o
obj-$(CONFIG_ACPI_POWER) += power.o
obj-$(CONFIG_ACPI_PROCESSOR) += processor.o
+obj-$(CONFIG_ACPI_CONTAINER) += container.o
obj-$(CONFIG_ACPI_THERMAL) += thermal.o
obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o
obj-$(CONFIG_ACPI_DEBUG) += debug.o
diff -puN /dev/null include/acpi/container.h
--- /dev/null 2004-06-30 13:03:36.000000000 -0700
+++ linux-2.6.9-rc2-askeshav/include/acpi/container.h 2004-09-24 15:26:33.889293878 -0700
@@ -0,0 +1,13 @@
+#ifndef __ACPI_CONTAINER_H
+#define __ACPI_CONTAINER_H
+
+#include <linux/kernel.h>
+
+struct acpi_container {
+ acpi_handle handle;
+ unsigned long sun;
+ int state;
+};
+
+#endif /* __ACPI_CONTAINER_H */
+
diff -puN /dev/null drivers/acpi/container.c
--- /dev/null 2004-06-30 13:03:36.000000000 -0700
+++ linux-2.6.9-rc2-askeshav/drivers/acpi/container.c 2004-09-24 15:26:33.890270440 -0700
@@ -0,0 +1,344 @@
+/*
+ * acpi_container.c - ACPI Generic Container Driver
+ * ($Revision: )
+ *
+ * Copyright (C) 2004 Anil S Keshavamurthy ([email protected])
+ * Copyright (C) 2004 Keiichiro Tokunaga ([email protected])
+ * Copyright (C) 2004 Motoyuki Ito ([email protected])
+ * Copyright (C) 2004 Intel Corp.
+ * Copyright (C) 2004 FUJITSU LIMITED
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/acpi.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/container.h>
+
+#define ACPI_CONTAINER_DRIVER_NAME "ACPI container driver"
+#define ACPI_CONTAINER_DEVICE_NAME "ACPI container device"
+#define ACPI_CONTAINER_CLASS "container"
+
+#define INSTALL_NOTIFY_HANDLER 1
+#define UNINSTALL_NOTIFY_HANDLER 2
+
+#define ACPI_CONTAINER_COMPONENT 0x01000000
+#define _COMPONENT ACPI_CONTAINER_COMPONENT
+ACPI_MODULE_NAME ("acpi_container")
+
+MODULE_AUTHOR("Anil S Keshavamurthy");
+MODULE_DESCRIPTION(ACPI_CONTAINER_DRIVER_NAME);
+MODULE_LICENSE("GPL");
+
+#define ACPI_STA_PRESENT (0x00000001)
+
+static int acpi_container_add(struct acpi_device *device);
+static int acpi_container_remove(struct acpi_device *device, int type);
+
+static struct acpi_driver acpi_container_driver = {
+ .name = ACPI_CONTAINER_DRIVER_NAME,
+ .class = ACPI_CONTAINER_CLASS,
+ .ids = "ACPI0004,PNP0A05,PNP0A06",
+ .ops = {
+ .add = acpi_container_add,
+ .remove = acpi_container_remove,
+ },
+};
+
+
+/*******************************************************************/
+
+static int
+is_device_present(acpi_handle handle)
+{
+ acpi_handle temp;
+ acpi_status status;
+ unsigned long sta;
+
+ ACPI_FUNCTION_TRACE("is_device_present");
+
+ status = acpi_get_handle(handle, "_STA", &temp);
+ if (ACPI_FAILURE(status))
+ return_VALUE(1); /* _STA not found, assmue device present */
+
+ status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+ if (ACPI_FAILURE(status))
+ return_VALUE(0); /* Firmware error */
+
+ return_VALUE((sta & ACPI_STA_PRESENT) == ACPI_STA_PRESENT);
+}
+
+/*******************************************************************/
+static int
+acpi_container_add(struct acpi_device *device)
+{
+ struct acpi_container *container;
+
+ ACPI_FUNCTION_TRACE("acpi_container_add");
+
+ if (!device) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "device is NULL\n"));
+ return_VALUE(-EINVAL);
+ }
+
+ container = kmalloc(sizeof(struct acpi_container), GFP_KERNEL);
+ if(!container)
+ return_VALUE(-ENOMEM);
+
+ memset(container, 0, sizeof(struct acpi_container));
+ container->handle = device->handle;
+ strcpy(acpi_device_name(device), ACPI_CONTAINER_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_CONTAINER_CLASS);
+ acpi_driver_data(device) = container;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device <%s> bid <%s>\n", \
+ acpi_device_name(device), acpi_device_bid(device)));
+
+
+ return_VALUE(0);
+}
+
+static int
+acpi_container_remove(struct acpi_device *device, int type)
+{
+ acpi_status status = AE_OK;
+ struct acpi_container *pc = NULL;
+ pc = (struct acpi_container*) acpi_driver_data(device);
+
+ if (pc)
+ kfree(pc);
+
+ return status;
+}
+
+
+static int
+container_run_sbin_hotplug(struct acpi_device *device, char *action)
+{
+ char *argv[3], *envp[6], action_str[32];
+ int i, ret;
+ int len;
+ char pathname[ACPI_PATHNAME_MAX] = {0};
+ acpi_status status;
+ char *container_str;
+ struct acpi_buffer buffer = {ACPI_PATHNAME_MAX, pathname};
+
+ ACPI_FUNCTION_TRACE("container_run_sbin_hotplug");
+
+
+ status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer);
+ if (ACPI_FAILURE(status)) {
+ return(-ENODEV);
+ }
+
+ len = strlen("CONTAINER=") + strlen(pathname) + 1;
+ container_str = kmalloc(len, GFP_KERNEL);
+ if (!container_str)
+ return(-ENOMEM);
+
+ sprintf(container_str, "CONTAINER=%s",pathname);
+ sprintf(action_str, "ACTION=%s", action);
+
+ i = 0;
+ argv[i++] = hotplug_path;
+ argv[i++] = "container";
+ argv[i] = NULL;
+
+ i = 0;
+ envp[i++] = "HOME=/";
+ envp[i++] = "PATH=/sbin;/bin;/usr/sbin;/usr/bin";
+ envp[i++] = action_str;
+ envp[i++] = container_str;
+ envp[i++] = "PLATFORM=ACPI";
+ envp[i] = NULL;
+
+ ret = call_usermodehelper(argv[0], argv, envp, 0);
+
+ kfree(container_str);
+ return_VALUE(ret);
+}
+
+static int
+container_device_add(struct acpi_device **device, acpi_handle handle)
+{
+ acpi_handle phandle;
+ struct acpi_device *pdev;
+ int result;
+
+ ACPI_FUNCTION_TRACE("container_device_add");
+
+ if (acpi_get_parent(handle, &phandle)) {
+ return_VALUE(-ENODEV);
+ }
+
+ if (acpi_bus_get_device(phandle, &pdev)) {
+ return_VALUE(-ENODEV);
+ }
+
+ if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_DEVICE)) {
+ return_VALUE(-ENODEV);
+ }
+
+ result = acpi_bus_scan(*device);
+
+ return_VALUE(result);
+}
+
+static void
+container_notify_cb(acpi_handle handle, u32 type, void *context)
+{
+ struct acpi_device *device = NULL;
+ int result;
+ int present;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE("container_notify_cb");
+
+ present = is_device_present(handle);
+
+ switch (type) {
+ case ACPI_NOTIFY_BUS_CHECK:
+ /* Fall through */
+ case ACPI_NOTIFY_DEVICE_CHECK:
+ printk("Container driver received %s event\n",
+ (type == ACPI_NOTIFY_BUS_CHECK)?
+ "ACPI_NOTIFY_BUS_CHECK":"ACPI_NOTIFY_DEVICE_CHECK");
+ if (present) {
+ status = acpi_bus_get_device(handle, &device);
+ if (ACPI_FAILURE(status) || !device) {
+ result = container_device_add(&device, handle);
+ if (!result)
+ container_run_sbin_hotplug(device, "add");
+ } else {
+ /* device exist and this is a remove request */
+ container_run_sbin_hotplug(device, "remove");
+ }
+ }
+ break;
+ case ACPI_NOTIFY_EJECT_REQUEST:
+ if (!acpi_bus_get_device(handle, &device) && device) {
+ container_run_sbin_hotplug(device, "remove");
+ }
+ break;
+ default:
+ break;
+ }
+ return_VOID;
+}
+
+static acpi_status
+container_walk_namespace_cb(acpi_handle handle,
+ u32 lvl,
+ void *context,
+ void **rv)
+{
+ char *hid = NULL;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ struct acpi_device_info *info;
+ acpi_status status;
+ int *action = context;
+
+ ACPI_FUNCTION_TRACE("container_walk_namespace_cb");
+
+ status = acpi_get_object_info(handle, &buffer);
+ if (ACPI_FAILURE(status) || !buffer.pointer) {
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ info = buffer.pointer;
+ if (info->valid & ACPI_VALID_HID)
+ hid = info->hardware_id.value;
+
+ if (hid == NULL) {
+ goto end;
+ }
+
+ if (strcmp(hid, "ACPI0004") && strcmp(hid, "PNP0A05") &&
+ strcmp(hid, "PNP0A06")) {
+ goto end;
+ }
+
+ switch(*action) {
+ case INSTALL_NOTIFY_HANDLER:
+ acpi_install_notify_handler(handle,
+ ACPI_SYSTEM_NOTIFY,
+ container_notify_cb,
+ NULL);
+ break;
+ case UNINSTALL_NOTIFY_HANDLER:
+ acpi_remove_notify_handler(handle,
+ ACPI_SYSTEM_NOTIFY,
+ container_notify_cb);
+ break;
+ default:
+ break;
+ }
+
+end:
+ acpi_os_free(buffer.pointer);
+
+ return_ACPI_STATUS(AE_OK);
+}
+
+
+int __init
+acpi_container_init(void)
+{
+ int result = 0;
+ int action = INSTALL_NOTIFY_HANDLER;
+
+ result = acpi_bus_register_driver(&acpi_container_driver);
+ if (result < 0) {
+ return(result);
+ }
+
+ /* register notify handler to every container device */
+ acpi_walk_namespace(ACPI_TYPE_DEVICE,
+ ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX,
+ container_walk_namespace_cb,
+ &action, NULL);
+
+ return(0);
+}
+
+void __exit
+acpi_container_exit(void)
+{
+ int action = UNINSTALL_NOTIFY_HANDLER;
+
+ ACPI_FUNCTION_TRACE("acpi_container_exit");
+
+ acpi_walk_namespace(ACPI_TYPE_DEVICE,
+ ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX,
+ container_walk_namespace_cb,
+ &action, NULL);
+
+ acpi_bus_unregister_driver(&acpi_container_driver);
+
+ return_VOID;
+}
+
+module_init(acpi_container_init);
+module_exit(acpi_container_exit);
_
On Friday 24 September 2004 06:28 pm, Keshavamurthy Anil S wrote:
> +typedef void acpi_device_sysfs_files(struct kobject *,
> +???????????????????????????????const struct attribute *);
> +
> +static void setup_sys_fs_device_files(struct acpi_device *dev,
> +???????????????acpi_device_sysfs_files *func);
> +
> +#define create_sysfs_device_files(dev)?\
> +???????setup_sys_fs_device_files(dev, (acpi_device_sysfs_files *)&sysfs_create_file)
> +#define remove_sysfs_device_files(dev)?\
> +???????setup_sys_fs_device_files(dev, (acpi_device_sysfs_files *)&sysfs_remove_file)
Hi Anil,
It looks very nice except for the part above. I am really confused what the
purpose of this code is... It looks like it just complicates things?
--
Dmitry
On Fri, 24 Sep 2004 16:36:32 -0700 Keshavamurthy Anil S wrote:
> On Thu, Sep 23, 2004 at 02:10:31AM +0900, Keiichiro Tokunaga wrote:
> > On Wed, 22 Sep 2004 08:52:59 -0600, Alex Williamson wrote:
> > > On Wed, 2004-09-22 at 22:15 +0900, Keiichiro Tokunaga wrote:
> > > >
> > > > I would like to suggest introducing a new function 'acpi_get_pxm()'
> > > > since other drivers might need it in the future. Acutally, ACPI container
> > > > hotplug will be using it soon.
> > > >
> > > > Here is a patch creating the function.
> > > >
> > >
> > > Nice, I have a couple I/O locality patches that could be simplified
>
> Here is the revised patch which now fixes the all issues that were discussed.
> - Now defines and uses acpi_get_pxm
> - small bugfix "change __initdata to __devinitdata for pxm_to_nid_map varable
Thanks for your work! But, you might forget to merge the small bugfix
patch. See the diffstat below. The target file of small bugfix is
include/asm-ia64/acpi.h, but it didn't show up below:)
> linux-2.6.9-rc2-askeshav/arch/i386/kernel/acpi/boot.c | 22 +++
> linux-2.6.9-rc2-askeshav/arch/ia64/kernel/acpi.c | 107 +++++++++++++++++-
> linux-2.6.9-rc2-askeshav/drivers/acpi/numa.c | 19 +++
> linux-2.6.9-rc2-askeshav/include/linux/acpi.h | 14 ++
> 4 files changed, 159 insertions(+), 3 deletions(-)
Thanks,
Keiichiro Tokunaga
On Fri, 24 Sep 2004 16:36:32 -0700 Keshavamurthy Anil S wrote:
> On Thu, Sep 23, 2004 at 02:10:31AM +0900, Keiichiro Tokunaga wrote:
> > On Wed, 22 Sep 2004 08:52:59 -0600, Alex Williamson wrote:
> > > On Wed, 2004-09-22 at 22:15 +0900, Keiichiro Tokunaga wrote:
> > > >
> > > > I would like to suggest introducing a new function 'acpi_get_pxm()'
> > > > since other drivers might need it in the future. Acutally, ACPI container
> > > > hotplug will be using it soon.
> > > >
> > > > Here is a patch creating the function.
> > > >
> > >
> > > Nice, I have a couple I/O locality patches that could be simplified
>
> Here is the revised patch which now fixes the all issues that were discussed.
> - Now defines and uses acpi_get_pxm
> - small bugfix "change __initdata to __devinitdata for pxm_to_nid_map varable
One more thing. Did you modify my acpi_get_pxm.patch by hand?
That causes an infinite loop. Please apply my fix patch.
> +int
> +acpi_get_pxm(acpi_handle handle)
> +{
> + unsigned long pxm;
> + acpi_status status;
> + acpi_handle phandle;
> +
> + do {
> + status = acpi_evaluate_integer(handle, "_PXM", NULL, &pxm);
> + if (ACPI_SUCCESS(status))
> + return (int)pxm;
> + status = acpi_get_parent(handle, &phandle);
> + } while(ACPI_SUCCESS(status));
> + return -1;
> +}
> +EXPORT_SYMBOL(acpi_get_pxm);
> _
This do-loop never ends...
Thanks,
Keiichiro Tokunaga
Status: Tested on 2.6.9-rc2
Signed-off-by: Keiichiro Tokunaga <[email protected]>
---
linux-2.6.9-rc2-092704-kei/drivers/acpi/numa.c | 6 ++++--
1 files changed, 4 insertions(+), 2 deletions(-)
diff -puN drivers/acpi/numa.c~acpi_get_pxm-fix drivers/acpi/numa.c
--- linux-2.6.9-rc2-092704/drivers/acpi/numa.c~acpi_get_pxm-fix 2004-09-27 20:44:22.000000000 +0900
+++ linux-2.6.9-rc2-092704-kei/drivers/acpi/numa.c 2004-09-27 21:33:24.266377945 +0900
@@ -198,13 +198,15 @@ acpi_numa_init()
}
int
-acpi_get_pxm(acpi_handle handle)
+acpi_get_pxm(acpi_handle h)
{
unsigned long pxm;
acpi_status status;
- acpi_handle phandle;
+ acpi_handle handle;
+ acpi_handle phandle = h;
do {
+ handle = phandle;
status = acpi_evaluate_integer(handle, "_PXM", NULL, &pxm);
if (ACPI_SUCCESS(status))
return (int)pxm;
_
On Fri, 24 Sep 2004 01:32:55 +0900 Keiichiro Tokunaga wrote:
>
> Name: acpi_numa_hp.patch
> Status: Tested on 2.6.9-rc2
> Signed-off-by: Keiichiro Tokunaga <[email protected]>
> Description:
> Add hotplug support to drivers/acpi/numa.c.
Sorry, I found a bug in the printk's message.
> + if (pxm_to_nid_map[pxm] >= 0) {
> + printk(KERN_INFO"PXM <%d> already has a nid <%d>.\n",
> + pxm_to_nid_map[pxm], pxm);
> + return ;
> + }
The second and third arguments should change place with each
other like,
> + printk(KERN_INFO"PXM <%d> already has a nid <%d>.\n",
> + pxm, pxm_to_nid_map[pxm]);
I am attaching an updated patch. Anil, please include it instead of
the old one.
Thanks,
Keiichiro Tokunaga
Status: Tested on 2.6.9-rc2
Signed-off-by: Keiichiro Tokunaga <[email protected]>
---
linux-2.6.9-rc2-092704-kei/drivers/acpi/numa.c | 267 +++++++++++++++++++++++++
linux-2.6.9-rc2-092704-kei/include/acpi/numa.h | 30 ++
2 files changed, 297 insertions(+)
diff -puN drivers/acpi/numa.c~acpi_numa_hp drivers/acpi/numa.c
--- linux-2.6.9-rc2-092704/drivers/acpi/numa.c~acpi_numa_hp 2004-09-27 17:36:31.454783390 +0900
+++ linux-2.6.9-rc2-092704-kei/drivers/acpi/numa.c 2004-09-27 17:36:31.456736527 +0900
@@ -31,6 +31,7 @@
#include <linux/acpi.h>
#include <acpi/acpi_bus.h>
#include <acpi/acmacros.h>
+#include <acpi/numa.h>
#define ACPI_NUMA 0x80000000
#define _COMPONENT ACPI_NUMA
@@ -212,3 +213,269 @@ acpi_get_pxm(acpi_handle handle)
return -1;
}
EXPORT_SYMBOL(acpi_get_pxm);
+
+
+#if ( defined(CONFIG_ACPI_CONTAINER_MODULE) || defined(CONFIG_ACPI_CONTAINER) ) && defined(CONFIG_HOTPLUG)
+
+static int nid2pxm(int nid)
+{
+ int i;
+
+ if ((nid < 0) || (nid >= MAX_NUMNODES))
+ return -1;
+
+ for(i=0; i < MAX_PXM_DOMAINS; i++) {
+ if ( pxm_to_nid_map[i] == nid )
+ return i;
+ }
+
+ return -1;
+}
+
+void
+acpi_numa_data_handler(acpi_handle handle, u32 function, void *context)
+{
+ return;
+}
+
+int is_numa_node_device(acpi_handle handle)
+{
+ acpi_status status;
+ struct acpi_numa_node *data=NULL;
+
+ status = acpi_get_data(handle, acpi_numa_data_handler, (void **)&data);
+ if (ACPI_FAILURE(status))
+ return 0;
+ else
+ return 1;
+}
+
+int acpi_get_numa_nodeid(int pxm)
+{
+ if (pxm < 0 || pxm >= MAX_PXM_DOMAINS)
+ return -EINVAL;
+
+ return pxm_to_nid_map[pxm];
+}
+EXPORT_SYMBOL(acpi_get_numa_nodeid);
+
+static void
+set_nodeid(int pxm, int nid)
+{
+ if (pxm_to_nid_map[pxm] >= 0) {
+ printk(KERN_INFO"PXM <%d> already has a nid <%d>.\n",
+ pxm, pxm_to_nid_map[pxm]);
+ return ;
+ }
+
+ if (nid >= MAX_NUMNODES) {
+ printk(KERN_ERR"nid <%d> is too big. Range: 0-%d\n",
+ nid, MAX_NUMNODES-1);
+ return ;
+ }
+
+ pxm_to_nid_map[pxm] = nid;
+}
+
+static void unget_nodeid(int nid)
+{
+#ifdef PXM_FIX_NODEID
+ int pxm = nid2pxm(nid);
+ if (pxm < 0)
+ return;
+ pxm_to_nid_map[pxm] = -1;
+#endif
+}
+
+static int
+allocate_nodeid(int pxm)
+{
+ int i;
+
+#ifndef PXM_FIX_NODEID
+ if (pxm_to_nid_map[pxm] >= 0)
+ return pxm_to_nid_map[pxm];
+#endif
+ for(i=0 ;i < MAX_NUMNODES; i++) {
+ if (nid2pxm(i) < 0)
+ return i;
+ }
+
+ printk(KERN_ERR"Failed to allocate nid for PXM <%d>\n", pxm);
+ return -1;
+}
+
+static acpi_status
+find_processor(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+ int **cntp = (int **)rv;
+
+ ACPI_FUNCTION_TRACE("find_processor");
+
+ ++(**cntp);
+
+ return_ACPI_STATUS(AE_OK);
+}
+
+void acpi_numa_node_add(acpi_handle handle)
+{
+ acpi_status status;
+ struct acpi_numa_node *data=NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_numa_node_add");
+
+ status = acpi_get_data(handle, acpi_numa_data_handler, (void **)&data);
+ if (ACPI_FAILURE(status))
+ return_VOID;
+
+ if (data->pxm < 0) {
+ printk(KERN_ERR"Container does not have PXM.\n");
+ return_VOID;
+ }
+
+ arch_register_node(data->nid);
+
+ return_VOID;
+}
+
+void acpi_numa_node_remove(acpi_handle handle)
+{
+ acpi_status status;
+ struct acpi_numa_node *data=NULL;
+ int nid;
+
+ ACPI_FUNCTION_TRACE("acpi_numa_node_remove");
+
+ status = acpi_get_data(handle, acpi_numa_data_handler, (void **)&data);
+ if (ACPI_FAILURE(status) || !data)
+ return_VOID;
+
+ nid = data->nid;
+ if (nid < 0) {
+ printk(KERN_ERR"Invalid nid %d\n", nid);
+ return_VOID;
+ }
+
+ arch_unregister_node(nid);
+ unget_nodeid(nid);
+ acpi_numa_node_data_detach(handle);
+
+ return_VOID;
+}
+
+void acpi_numa_node_data_detach(acpi_handle handle)
+{
+ struct acpi_numa_node *data=NULL;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE("acpi_numa_node_data_detach");
+
+ status = acpi_get_data(handle, acpi_numa_data_handler, (void **)&data);
+ if (ACPI_FAILURE(status) || (data == NULL))
+ return_VOID;
+
+ status = acpi_detach_data(handle, acpi_numa_data_handler);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR"Failed to detach NUMA node data.\n");
+ return_VOID;
+ }
+
+ kfree(data);
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "NUMA node data is detached.\n"));
+ return_VOID;
+}
+
+void acpi_numa_node_init(acpi_handle handle)
+{
+ int pxm;
+ acpi_status status;
+ struct acpi_numa_node *data;
+ int _cnt=0;
+ int *cnt=&_cnt;
+ struct acpi_device *node_dev=NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_numa_node_init");
+
+ if (acpi_bus_get_device(handle, &node_dev)) {
+ printk(KERN_ERR"Unknown handle.\n");
+ return_VOID;
+ }
+
+ pxm = acpi_get_pxm(handle);
+ if (pxm < 0) {
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN, "PXM was not found.\n"));
+ return_VOID;
+ }
+
+ data = kmalloc(sizeof(struct acpi_numa_node), GFP_KERNEL);
+ if (!data) {
+ printk(KERN_ERR"Not enough memory.\n");
+ return_VOID;
+ }
+
+ data->handle = handle;
+ data->pxm = pxm;
+ data->nid = -1;
+
+ acpi_walk_namespace(ACPI_TYPE_PROCESSOR,
+ handle,
+ (u32) 1,
+ find_processor,
+ data,
+ (void **)&cnt);
+ /*
+ * TBD: Check nid of memory object
+ * paddr_to_node[] (include/asm-ia64/numa.h)
+ */
+ if (! _cnt) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "nid of <%s> is not detected.\n",
+ acpi_device_bid(node_dev)));
+ goto cancel;
+ }
+
+ if (pxm_to_nid_map[pxm] < 0) {
+ int nid = allocate_nodeid(pxm);
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "nid <%d> is allocated for PXM <%d>.\n",
+ nid, data->pxm));
+ if (nid < 1) {
+ /* "node 0" is a fixed ID. */
+ printk(KERN_ERR"Cannot get nid.\n");
+ return_VOID;
+ }
+ data->nid = nid;
+ set_nodeid(pxm, nid);
+ } else {
+ data->nid = pxm_to_nid_map[pxm];
+ }
+
+
+ status = acpi_attach_data(handle, acpi_numa_data_handler, data);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR"Failed to attach NUMA data for <%s>.\n",
+ acpi_device_bid(node_dev));
+ goto cancel;
+ }
+
+ printk(KERN_INFO"Container <%s> is NUMA node.\n",
+ acpi_device_bid(node_dev));
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Initialized: Container<%s> PXM=%d nid=%d\n",
+ acpi_device_bid(node_dev), pxm, data->nid));
+ return_VOID;
+
+cancel:
+ if (data)
+ kfree(data);
+ return_VOID;
+}
+
+EXPORT_SYMBOL(acpi_numa_node_init);
+EXPORT_SYMBOL(acpi_numa_node_add);
+EXPORT_SYMBOL(acpi_numa_node_remove);
+EXPORT_SYMBOL(acpi_numa_node_data_detach);
+EXPORT_SYMBOL(acpi_numa_data_handler);
+EXPORT_SYMBOL(is_numa_node_device);
+
+#endif /* defined(CONFIG_ACPI_CONTAINER) && defined(CONFIG_HOTPLUG) */
diff -puN /dev/null include/acpi/numa.h
--- /dev/null 2003-08-16 05:19:42.000000000 +0900
+++ linux-2.6.9-rc2-092704-kei/include/acpi/numa.h 2004-09-27 17:36:31.457713095 +0900
@@ -0,0 +1,30 @@
+#ifndef _ACPI_NUMA_H_
+#define _ACPI_NUMA_H_
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/acpi.h>
+#include <asm/acpi.h>
+#include <acpi/acpixf.h>
+
+#if defined(CONFIG_ACPI_CONTAINER) || defined(CONFIG_ACPI_CONTAINER_MODULE)
+#include <linux/numa.h>
+struct acpi_numa_node {
+ acpi_handle handle;
+ int pxm;
+ int nid;
+};
+
+#ifndef MAX_PXM_DOMAINS
+#define MAX_PXM_DOMAINS (256)
+#endif
+extern void acpi_numa_node_init(acpi_handle handle);
+extern void acpi_numa_node_add(acpi_handle handle);
+extern void acpi_numa_node_remove(acpi_handle handle);
+extern void acpi_numa_data_handler ( acpi_handle handle, u32 function, void *context);
+extern void acpi_numa_node_data_detach(acpi_handle handle);
+extern int is_numa_node_device(acpi_handle handle);
+extern int acpi_numa_node_add_post(acpi_handle handle);
+extern int acpi_numa_node_remove_request(acpi_handle handle);
+#endif /* CONFIG_ACPI_CONTAINER */
+#endif
_
On Mon, Sep 27, 2004 at 01:12:28AM -0500, Dmitry Torokhov wrote:
> On Friday 24 September 2004 06:28 pm, Keshavamurthy Anil S wrote:
> > +typedef void acpi_device_sysfs_files(struct kobject *,
> > +???????????????????????????????const struct attribute *);
> > +
> > +static void setup_sys_fs_device_files(struct acpi_device *dev,
> > +???????????????acpi_device_sysfs_files *func);
> > +
> > +#define create_sysfs_device_files(dev)?\
> > +???????setup_sys_fs_device_files(dev, (acpi_device_sysfs_files *)&sysfs_create_file)
> > +#define remove_sysfs_device_files(dev)?\
> > +???????setup_sys_fs_device_files(dev, (acpi_device_sysfs_files *)&sysfs_remove_file)
>
>
> Hi Anil,
>
> It looks very nice except for the part above. I am really confused what the
> purpose of this code is... It looks like it just complicates things?
Hi Dmitry,
I just wanted to have a single function i.e setup_sys_fs_device_files() for both
creating and removing sysfs files. So I have #defined create_sysfs_device_files() and
remove_sysfs_device_files() and one of the arguments to the setup_sys_fs_device_files()
is a function pointer, i.e for one it takes sysfs_create_file and for other it takes
sysfs_remove_file.
Having single function for creating and removing sysfs files make it easy
from the maintaince perspective, as oppose to remember to code for remove
as well when one adds the new file.
thanks,
Anil
On Monday 27 September 2004 11:53 am, Keshavamurthy Anil S wrote:
> ????????I just wanted to have a single function i.e setup_sys_fs_device_files() for both
> creating and removing sysfs files.
Ah, I see... Makes sense, especially when there is additional logic involved
in creating some of the attributes, which is the case with ACPI.
--
Dmitry
On Fri, Sep 24, 2004 at 01:31:23AM +0900, Keiichiro Tokunaga wrote:
>
> -int __init register_node(struct node *node, int num, struct node *parent)
> +int register_node(struct node *node, int num, struct node *parent)
__devinit please
> +void unregister_node(struct node *node, struct node *parent)
unregister_node is required only for hotplug case. Please hide this function
under suitable #ifdef's, say this is only required if CONFIG_HOTPLUG is enabled.
> + sysdev_remove_file(&node->sysdev, &attr_cpumap);
> + sysdev_remove_file(&node->sysdev, &attr_meminfo);
add sysdev_remove_file(&node->sysdev, &attr_numastat);
> +EXPORT_SYMBOL(node_online_map);
Why do you need this in this patch?
On Fri, Sep 24, 2004 at 01:32:55AM +0900, Keiichiro Tokunaga wrote:
> +void acpi_numa_node_init(acpi_handle handle)
Why is this function returning void? I expect
this to return int, what do you think?
> +
> + if (acpi_bus_get_device(handle, &node_dev)) {
> + printk(KERN_ERR"Unknown handle.\n");
> + return_VOID;
> + }
Why do you need to call acpi_bus_get_device?
> + acpi_walk_namespace(ACPI_TYPE_PROCESSOR,
> + handle,
> + (u32) 1,
> + find_processor,
> + data,
> + (void **)&cnt);
Why are you looking for processor device here?
Please remove this acpi_walk_namespace function.
> + /*
> diff -puN /dev/null include/acpi/numa.h
> +#ifndef MAX_PXM_DOMAINS
> +#define MAX_PXM_DOMAINS (256)
> +#endif
Why defining it again, It is already defined in asm-ia64/acpi.h file
>
> _
On Mon, Sep 27, 2004 at 09:50:27PM +0900, Keiichiro Tokunaga wrote:
> One more thing. Did you modify my acpi_get_pxm.patch by hand?
> That causes an infinite loop. Please apply my fix patch.
OOPS!! Now applying cleanly. Refreshing my patch again. Thanks.
Hi Len,
I hope all of my ACPI based CPU hotplug patches[1-6] have been reviewed
extensively and I have fixed all the issues that were raised. Do you think
it is reasonable now to have it in your test tree? Please let me know.
Once this goes to your test tree, I will work with the community to provide
ACPI based NUMA NODE hotplug support patches.
thanks,
Anil
---
Name:acpi_hotplug_arch.patch
Status: Tested on 2.6.9-rc2
Signed-off-by: Anil S Keshavamurthy <[email protected]>
Depends:
Version: applies on 2.6.9-rc2
Description:
This patch provides the architecture specifice support for mapping lsapic to cpu array.
Currently this supports just IA64. Support for IA32 and x86_64 is in progress
---
linux-2.6.9-rc2-askeshav/arch/i386/kernel/acpi/boot.c | 22 +++
linux-2.6.9-rc2-askeshav/arch/ia64/kernel/acpi.c | 107 +++++++++++++++++-
linux-2.6.9-rc2-askeshav/drivers/acpi/numa.c | 21 +++
linux-2.6.9-rc2-askeshav/include/asm-ia64/acpi.h | 2
linux-2.6.9-rc2-askeshav/include/linux/acpi.h | 14 ++
5 files changed, 162 insertions(+), 4 deletions(-)
diff -puN include/linux/acpi.h~acpi_hotplug_arch include/linux/acpi.h
--- linux-2.6.9-rc2/include/linux/acpi.h~acpi_hotplug_arch 2004-09-27 09:55:27.378549543 -0700
+++ linux-2.6.9-rc2-askeshav/include/linux/acpi.h 2004-09-27 09:55:27.488901104 -0700
@@ -396,6 +396,12 @@ void acpi_numa_processor_affinity_init (
void acpi_numa_memory_affinity_init (struct acpi_table_memory_affinity *ma);
void acpi_numa_arch_fixup(void);
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+/* Arch dependent functions for cpu hotplug support */
+int acpi_map_lsapic(acpi_handle handle, int *pcpu);
+int acpi_unmap_lsapic(int cpu);
+#endif /* CONFIG_ACPI_HOTPLUG_CPU */
+
extern int acpi_mp_config;
extern u32 pci_mmcfg_base_addr;
@@ -471,4 +477,12 @@ static inline int acpi_blacklisted(void)
#endif /*!CONFIG_ACPI_INTERPRETER*/
+#ifdef CONFIG_ACPI_NUMA
+int acpi_get_pxm(acpi_handle handle);
+#else
+static inline int acpi_get_pxm(acpi_handle handle)
+{
+ return 0;
+}
+#endif
#endif /*_LINUX_ACPI_H*/
diff -puN arch/ia64/kernel/acpi.c~acpi_hotplug_arch arch/ia64/kernel/acpi.c
--- linux-2.6.9-rc2/arch/ia64/kernel/acpi.c~acpi_hotplug_arch 2004-09-27 09:55:27.383432355 -0700
+++ linux-2.6.9-rc2-askeshav/arch/ia64/kernel/acpi.c 2004-09-27 09:55:27.489877666 -0700
@@ -354,11 +354,11 @@ acpi_parse_madt (unsigned long phys_addr
#define PXM_FLAG_LEN ((MAX_PXM_DOMAINS + 1)/32)
static int __initdata srat_num_cpus; /* number of cpus */
-static u32 __initdata pxm_flag[PXM_FLAG_LEN];
+static u32 __devinitdata pxm_flag[PXM_FLAG_LEN];
#define pxm_bit_set(bit) (set_bit(bit,(void *)pxm_flag))
#define pxm_bit_test(bit) (test_bit(bit,(void *)pxm_flag))
/* maps to convert between proximity domain and logical node ID */
-int __initdata pxm_to_nid_map[MAX_PXM_DOMAINS];
+int __devinitdata pxm_to_nid_map[MAX_PXM_DOMAINS];
int __initdata nid_to_pxm_map[MAX_NUMNODES];
static struct acpi_table_slit __initdata *slit_table;
@@ -650,4 +650,107 @@ acpi_gsi_to_irq (u32 gsi, unsigned int *
return 0;
}
+/*
+ * ACPI based hotplug CPU support
+ */
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+static
+int
+acpi_map_cpu2node(acpi_handle handle, int cpu, long physid)
+{
+#ifdef CONFIG_ACPI_NUMA
+ int pxm_id;
+
+ pxm_id = acpi_get_pxm(handle);
+
+ /*
+ * Assuming that the container driver would have set the proximity
+ * domain and would have initialized pxm_to_nid_map[pxm_id] && pxm_flag
+ */
+ node_cpuid[cpu].nid = (pxm_id < 0) ? 0:
+ pxm_to_nid_map[pxm_id];
+
+ node_cpuid[cpu].phys_id = physid;
+#endif
+ return(0);
+}
+
+
+int
+acpi_map_lsapic(acpi_handle handle, int *pcpu)
+{
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ union acpi_object *obj;
+ struct acpi_table_lsapic *lsapic;
+ cpumask_t tmp_map;
+ long physid;
+ int cpu;
+
+ if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
+ return -EINVAL;
+
+ if (!buffer.length || !buffer.pointer)
+ return -EINVAL;
+
+ obj = buffer.pointer;
+ if (obj->type != ACPI_TYPE_BUFFER ||
+ obj->buffer.length < sizeof(*lsapic)) {
+ acpi_os_free(buffer.pointer);
+ return -EINVAL;
+ }
+
+ lsapic = (struct acpi_table_lsapic *)obj->buffer.pointer;
+
+ if ((lsapic->header.type != ACPI_MADT_LSAPIC) ||
+ (!lsapic->flags.enabled)) {
+ acpi_os_free(buffer.pointer);
+ return -EINVAL;
+ }
+
+ physid = ((lsapic->id <<8) | (lsapic->eid));
+
+ acpi_os_free(buffer.pointer);
+ buffer.length = ACPI_ALLOCATE_BUFFER;
+ buffer.pointer = NULL;
+
+ cpus_complement(tmp_map, cpu_present_map);
+ cpu = first_cpu(tmp_map);
+ if(cpu >= NR_CPUS)
+ return -EINVAL;
+
+ acpi_map_cpu2node(handle, cpu, physid);
+
+ cpu_set(cpu, cpu_present_map);
+ ia64_cpu_to_sapicid[cpu] = physid;
+ ia64_acpiid_to_sapicid[lsapic->acpi_id] = ia64_cpu_to_sapicid[cpu];
+
+ *pcpu = cpu;
+ return(0);
+}
+EXPORT_SYMBOL(acpi_map_lsapic);
+
+
+int
+acpi_unmap_lsapic(int cpu)
+{
+ int i;
+
+ for (i=0; i<MAX_SAPICS; i++) {
+ if (ia64_acpiid_to_sapicid[i] == ia64_cpu_to_sapicid[cpu]) {
+ ia64_acpiid_to_sapicid[i] = -1;
+ break;
+ }
+ }
+ ia64_cpu_to_sapicid[cpu] = -1;
+ cpu_clear(cpu,cpu_present_map);
+
+#ifdef CONFIG_ACPI_NUMA
+ /* NUMA specific cleanup's */
+#endif
+
+ return(0);
+}
+EXPORT_SYMBOL(acpi_unmap_lsapic);
+#endif /* CONFIG_ACPI_HOTPLUG_CPU */
+
#endif /* CONFIG_ACPI_BOOT */
diff -puN arch/i386/kernel/acpi/boot.c~acpi_hotplug_arch arch/i386/kernel/acpi/boot.c
--- linux-2.6.9-rc2/arch/i386/kernel/acpi/boot.c~acpi_hotplug_arch 2004-09-27 09:55:27.390268292 -0700
+++ linux-2.6.9-rc2-askeshav/arch/i386/kernel/acpi/boot.c 2004-09-27 09:55:27.490854229 -0700
@@ -478,6 +478,28 @@ unsigned int acpi_register_gsi(u32 gsi,
}
EXPORT_SYMBOL(acpi_register_gsi);
+/*
+ * ACPI based hotplug support for CPU
+ */
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+int
+acpi_map_lsapic(acpi_handle handle, int *pcpu)
+{
+ /* TBD */
+ return -EINVAL;
+}
+EXPORT_SYMBOL(acpi_map_lsapic);
+
+
+int
+acpi_unmap_lsapic(int cpu)
+{
+ /* TBD */
+ return -EINVAL;
+}
+EXPORT_SYMBOL(acpi_unmap_lsapic);
+#endif /* CONFIG_ACPI_HOTPLUG_CPU */
+
static unsigned long __init
acpi_scan_rsdp (
unsigned long start,
diff -puN drivers/acpi/numa.c~acpi_hotplug_arch drivers/acpi/numa.c
--- linux-2.6.9-rc2/drivers/acpi/numa.c~acpi_hotplug_arch 2004-09-27 09:55:27.394174542 -0700
+++ linux-2.6.9-rc2-askeshav/drivers/acpi/numa.c 2004-09-27 10:04:23.009402356 -0700
@@ -22,7 +22,7 @@
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
*/
-
+#include <linux/module.h>
#include <linux/config.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -195,3 +195,22 @@ acpi_numa_init()
acpi_numa_arch_fixup();
return 0;
}
+
+int
+acpi_get_pxm(acpi_handle h)
+{
+ unsigned long pxm;
+ acpi_status status;
+ acpi_handle handle;
+ acpi_handle phandle = h;
+
+ do {
+ handle = phandle;
+ status = acpi_evaluate_integer(handle, "_PXM", NULL, &pxm);
+ if (ACPI_SUCCESS(status))
+ return (int)pxm;
+ status = acpi_get_parent(handle, &phandle);
+ } while(ACPI_SUCCESS(status));
+ return -1;
+}
+EXPORT_SYMBOL(acpi_get_pxm);
diff -puN include/asm-ia64/acpi.h~acpi_hotplug_arch include/asm-ia64/acpi.h
--- linux-2.6.9-rc2/include/asm-ia64/acpi.h~acpi_hotplug_arch 2004-09-27 09:59:44.901983888 -0700
+++ linux-2.6.9-rc2-askeshav/include/asm-ia64/acpi.h 2004-09-27 10:00:16.970342870 -0700
@@ -101,7 +101,7 @@ int acpi_gsi_to_irq (u32 gsi, unsigned i
#ifdef CONFIG_ACPI_NUMA
/* Proximity bitmap length; _PXM is at most 255 (8 bit)*/
#define MAX_PXM_DOMAINS (256)
-extern int __initdata pxm_to_nid_map[MAX_PXM_DOMAINS];
+extern int __devinitdata pxm_to_nid_map[MAX_PXM_DOMAINS];
extern int __initdata nid_to_pxm_map[MAX_NUMNODES];
#endif
_
On Mon, 27 Sep 2004 11:52:44 -0700 Keshavamurthy Anil S wrote:
> On Fri, Sep 24, 2004 at 01:31:23AM +0900, Keiichiro Tokunaga wrote:
Thanks for the comments!
> > -int __init register_node(struct node *node, int num, struct node *parent)
> > +int register_node(struct node *node, int num, struct node *parent)
>
> __devinit please
Oh, yes. I got the same comments from Dave and posted an updated
patch fixing the issue.
> > +void unregister_node(struct node *node, struct node *parent)
>
> unregister_node is required only for hotplug case. Please hide this function
> under suitable #ifdef's, say this is only required if CONFIG_HOTPLUG is enabled.
That's right. I enclosed the function with #ifdef CONFIG_HOTPLUG.
> > + sysdev_remove_file(&node->sysdev, &attr_cpumap);
> > + sysdev_remove_file(&node->sysdev, &attr_meminfo);
>
> add sysdev_remove_file(&node->sysdev, &attr_numastat);
I added.
> > +EXPORT_SYMBOL(node_online_map);
> Why do you need this in this patch?
Sorry, it's a stuff that I forgot to remove... so it's not needed.
I removed it.
I am attaching an updated patch. Please see it below.
Thanks!
Keiichiro Tokunaga
Name: numa_hp_base.patch
Status: Tested on 2.6.9-rc2
Signed-off-by: Keiichiro Tokunaga <[email protected]>
Description:
Create unregister_node() to remove corresponding sysfs directory and files
from /sys/devices/system/node/.
---
linux-2.6.9-rc2-092704-kei/drivers/base/node.c | 21 +++++++++++++++++++--
linux-2.6.9-rc2-092704-kei/include/linux/node.h | 4 +++-
2 files changed, 22 insertions(+), 3 deletions(-)
diff -puN drivers/base/node.c~numa_hp_base drivers/base/node.c
--- linux-2.6.9-rc2-092704/drivers/base/node.c~numa_hp_base 2004-09-28 18:57:21.225343043 +0900
+++ linux-2.6.9-rc2-092704-kei/drivers/base/node.c 2004-09-28 18:57:21.228272741 +0900
@@ -117,7 +117,7 @@ static SYSDEV_ATTR(numastat, S_IRUGO, no
*
* Initialize and register the node device.
*/
-int __init register_node(struct node *node, int num, struct node *parent)
+int __devinit register_node(struct node *node, int num, struct node *parent)
{
int error;
@@ -133,9 +133,26 @@ int __init register_node(struct node *no
return error;
}
+#ifdef CONFIG_HOTPLUG
+void __devexit unregister_node(struct node *node, struct node *parent)
+{
+ if (node == NULL) {
+ printk("unregister_node: node is null.");
+ return;
+ }
+ sysdev_remove_file(&node->sysdev, &attr_cpumap);
+ sysdev_remove_file(&node->sysdev, &attr_meminfo);
+ sysdev_remove_file(&node->sysdev, &attr_numastat);
+ sysdev_unregister(&node->sysdev);
+}
+#endif /* CONFIG_HOTPLUG */
-int __init register_node_type(void)
+static int __init register_node_type(void)
{
return sysdev_class_register(&node_class);
}
postcore_initcall(register_node_type);
+
+
+EXPORT_SYMBOL(register_node);
+EXPORT_SYMBOL(unregister_node);
diff -puN include/linux/node.h~numa_hp_base include/linux/node.h
--- linux-2.6.9-rc2-092704/include/linux/node.h~numa_hp_base 2004-09-28 18:57:21.226319609 +0900
+++ linux-2.6.9-rc2-092704-kei/include/linux/node.h 2004-09-28 18:57:21.228272741 +0900
@@ -21,12 +21,14 @@
#include <linux/sysdev.h>
#include <linux/cpumask.h>
+#include <linux/module.h>
struct node {
struct sys_device sysdev;
};
-extern int register_node(struct node *, int, struct node *);
+extern int __devinit register_node(struct node *, int, struct node *);
+extern void __devexit unregister_node(struct node *node, struct node *parent);
#define to_node(sys_device) container_of(sys_device, struct node, sysdev)
_
On Mon, 27 Sep 2004 13:06:16 -0700 Keshavamurthy Anil S wrote:
> On Fri, Sep 24, 2004 at 01:32:55AM +0900, Keiichiro Tokunaga wrote:
> > +void acpi_numa_node_init(acpi_handle handle)
> Why is this function returning void? I expect
> this to return int, what do you think?
> > +
> > + if (acpi_bus_get_device(handle, &node_dev)) {
> > + printk(KERN_ERR"Unknown handle.\n");
> > + return_VOID;
> > + }
> Why do you need to call acpi_bus_get_device?
I wrote it for printk()s and ACPI_DEBUG_PRINT() to log.
if (! _cnt) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"nid of <%s> is not detected.\n",
acpi_device_bid(node_dev)));
goto cancel;
}
...
status = acpi_attach_data(handle, acpi_numa_data_handler, data);
if (ACPI_FAILURE(status)) {
printk(KERN_ERR"Failed to attach NUMA data for <%s>.\n",
acpi_device_bid(node_dev));
goto cancel;
}
printk(KERN_INFO"Container <%s> is NUMA node.\n",
acpi_device_bid(node_dev));
> > + acpi_walk_namespace(ACPI_TYPE_PROCESSOR,
> > + handle,
> > + (u32) 1,
> > + find_processor,
> > + data,
> > + (void **)&cnt);
> Why are you looking for processor device here?
> Please remove this acpi_walk_namespace function.
The reason why the acpi_walk_namespace() is used here was to
find a container object which is identical to a NUMA node. My code
was assuming that a container having CPU and/or memory was
NUMA node sinece the current Linux seemed to assume so.
> > + /*
> > diff -puN /dev/null include/acpi/numa.h
> > +#ifndef MAX_PXM_DOMAINS
> > +#define MAX_PXM_DOMAINS (256)
> > +#endif
> Why defining it again, It is already defined in asm-ia64/acpi.h file
Sorry, that's a stuff that I forgot to remove. I will remove it.
Thanks,
Keiichiro Tokunaga