[Note: Not for mainline inclusion, required only for testing purposes]
Emulate an ACPI SCI interrupt to emulate a hot-plug event. Useful
for testing ACPI based hot-plug on systems that don't have the
necessary firmware support.
Enable CONFIG_ACPI_SCI_EMULATE on kernel compile.
Now you will notice /proc/acpi/sci/notify when new kernel is booted.
echo "\_SB.CPU4 1" > /proc/acpi/sci/notify to trigger a hot-add of CPU4.
You will now notice an entry /sys/firmware/acpi/namespace/ACPI/_SB/CPU4
if the namespace had an entry CPU4 under _SB scope. If the entry had a
_EJ0 method, you will also notice a file "eject" under the CPU4 directory.
How to test physical cpu hotplug?
0. You need a ACPI based MP platform to perform tne test.
1. Get a dump of DSDT that you will modify to emulate CPU hotplug.
#acpidump -t DSDT -b -o DSDT
2. Disassemble it, so you can modify the output.
#iasl -d DSDT
This will create DSDT.dsl
3. Locate Scope _SB to add your new processor entries as below.
Processor (CPU4, 0x05, 0x00000, 0x00) {
Name(_HID,EISAID("INT0000"))
Name(_UID,5)
Name (L0st,0)
Method(_STA,0,NotSerialized) {
If ( LEqual(L0st,1) ) {
Return (0x0f)
} else {
Return (0x00)
}
}
Method(_PXM) {
Return(0)
}
Method(_PS0,0,NotSerialized) {
Store(1,L0st)
}
Method(_PS3,0,NotSerialized) {
Store(0,L0st)
}
Method(_EJ0,1,NotSerialized) {
Store(0,L0st)
}
Method (_MAT) {
Name(MAT,Buffer() {
0x00, //Local APIC
0x08, //Length
0x05, //ACPI Processor ID
0xC2, //Local APIC ID
0x01, //Enabled
0x00,
0x00,
0x00
})
Return (MAT)
}
4. Now compile and generate a hex file for inclusion
#iasl -tc DSDT.dsl
This will produce a file DSDT.hex which you will include in your kernel
kernel.
5. Rename it to some .h file for convenience.
You need to set CONFIG_STANDALONE=y
it will ask you custom dsdt file name, put that file in drivers/acpi
and provide that name when you do a
#make oldconfig.
6. Compile and boot your new kernel with limit_cpus=xxx
follow steps above to fake the notify for add, and remove cpu.
Signed-off-by: Anil Keshavamurthy <[email protected]>
Signed-off-by: Rajesh Shah <[email protected]>
Signed-off-by: Ashok Raj <[email protected]>
-----------------------------------------------------------------
drivers/acpi/Kconfig | 10 +++
drivers/acpi/bus.c | 138 ++++++++++++++++++++++++++++++++++++++++++
drivers/acpi/processor_core.c | 21 +++++-
drivers/acpi/scan.c | 35 ++++++++++
4 files changed, 199 insertions(+), 5 deletions(-)
Index: linux-2.6.16-rc4-mm1/drivers/acpi/Kconfig
===================================================================
--- linux-2.6.16-rc4-mm1.orig/drivers/acpi/Kconfig
+++ linux-2.6.16-rc4-mm1/drivers/acpi/Kconfig
@@ -333,4 +333,14 @@ config ACPI_HOTPLUG_MEMORY
$>modprobe acpi_memhotplug
endif # ACPI
+config ACPI_SCI_EMULATE
+ bool "ACPI SCI Event Emulation Support"
+ depends on ACPI
+ default n
+ help
+ This will enable your system to emulate sci hotplug event
+ notification through proc file system. For example user needs to
+ echo "XXX 0" > /proc/acpi/sci/notify (where, XXX is a target ACPI
+ device object name present under \_SB scope).
+
endmenu
Index: linux-2.6.16-rc4-mm1/drivers/acpi/bus.c
===================================================================
--- linux-2.6.16-rc4-mm1.orig/drivers/acpi/bus.c
+++ linux-2.6.16-rc4-mm1/drivers/acpi/bus.c
@@ -37,6 +37,22 @@
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
+#ifdef CONFIG_ACPI_SCI_EMULATE
+#include <acpi/acpi.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acevents.h>
+#include <acpi/acinterp.h>
+
+static int acpi_init_sci_emulate(void);
+static void acpi_sci_notify_client(char *acpi_name, u32 event);
+static int acpi_sci_notify_write_proc(struct file *file, const char *buffer, \
+ unsigned long count, void *data);
+struct proc_dir_entry *acpi_sci_dir;
+
+#else
+#define acpi_init_sci_emulate()
+#endif
+
#define _COMPONENT ACPI_BUS_COMPONENT
ACPI_MODULE_NAME("acpi_bus")
#ifdef CONFIG_X86
@@ -725,6 +741,8 @@ static int __init acpi_bus_init(void)
*/
acpi_root_dir = proc_mkdir(ACPI_BUS_FILE_ROOT, NULL);
+ acpi_init_sci_emulate();
+
return_VALUE(0);
/* Mimic structured exception handling */
@@ -770,3 +788,123 @@ static int __init acpi_init(void)
}
subsys_initcall(acpi_init);
+
+#ifdef CONFIG_ACPI_SCI_EMULATE
+/****** Code to emulate SCI interrupt for Hotplug node insertion/removal ******/
+
+static int acpi_sci_notify_write_proc(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ u32 event;
+ char *name1 = NULL;
+ char *name2 = NULL;
+ char *end_name = NULL;
+ const char *delim = " ";
+ char *temp_buf = NULL;
+ char *temp_buf_addr = NULL;
+
+ temp_buf = kmalloc(count+1, GFP_ATOMIC);
+ if (!temp_buf) {
+ printk(KERN_WARNING PREFIX "acpi_sci_notify_wire_proc: Memory allocation failed\n");
+ return count;
+ }
+ temp_buf[count] = '\0';
+ temp_buf_addr = temp_buf;
+ memcpy(temp_buf, buffer, count);
+ name1 = strsep(&temp_buf, delim);
+ name2 = strsep(&temp_buf, delim);
+
+ if(name1 && name2)
+ event = simple_strtoul(name2, &end_name, 10);
+ else {
+ printk(KERN_WARNING PREFIX "unknown device\n");
+ kfree(temp_buf_addr);
+ return count;
+ }
+
+ printk(KERN_INFO PREFIX "ACPI device name is <%s>, event code is <%d>\n",\
+ name1, event);
+
+ acpi_sci_notify_client(name1, event);
+
+ kfree(temp_buf_addr);
+
+ return count;
+}
+
+static void acpi_sci_notify_client(char *acpi_name, u32 event)
+{
+ struct acpi_namespace_node *node;
+ acpi_status status, status1;
+ acpi_handle hlsb, hsb;
+ union acpi_operand_object *obj_desc;
+
+ status = acpi_get_handle(NULL, "\\_SB", &hsb);
+ status1 = acpi_get_handle(hsb, acpi_name, &hlsb);
+ if(ACPI_FAILURE(status) || ACPI_FAILURE(status1)){
+ printk(KERN_ERR PREFIX "acpi getting handle to <\\_SB.%s> failed inside notify_client\n", \
+ acpi_name);
+ return;
+ }
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+ if(ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX "Acquiring acpi namespace mutext failed\n");
+ return;
+ }
+
+ node = acpi_ns_map_handle_to_node(hlsb);
+ if(!node) {
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ printk(KERN_ERR PREFIX "Mapping handle to node failed\n");
+ return;
+ }
+
+ /* Check for internal object and make sure there is a handler registered for this object */
+
+ obj_desc = acpi_ns_get_attached_object (node);
+ if(obj_desc) {
+ if(obj_desc->common_notify.system_notify){
+ /* Release the lock and queue the item for later exectuion */
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ status = acpi_ev_queue_notify_request(node, event);
+ if(ACPI_FAILURE(status)){
+ printk(KERN_ERR PREFIX "acpi_ev_queue_notify_request failed\n");
+ }else {
+ printk(KERN_INFO PREFIX "Notify event is queued\n");
+ }
+ return;
+ }
+ }else {
+ printk(KERN_INFO PREFIX "Notify handler not registered for this device\n");
+ }
+
+
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ return;
+}
+
+
+static int acpi_init_sci_emulate(void)
+{
+ struct proc_dir_entry *notify_entry = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_init_sci_emulate");
+
+ acpi_sci_dir = proc_mkdir("sci", acpi_root_dir);
+ if (!acpi_sci_dir)
+ return_VALUE(-ENODEV);
+
+ notify_entry = create_proc_entry("notify", \
+ S_IWUGO|S_IRUGO, acpi_sci_dir);
+ if (!notify_entry) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to create '%s' fs entry\n", "notify"));
+ } else {
+ notify_entry->write_proc = acpi_sci_notify_write_proc;
+ notify_entry->data = NULL;
+ }
+
+ return_VALUE(0);
+}
+#endif
Index: linux-2.6.16-rc4-mm1/drivers/acpi/processor_core.c
===================================================================
--- linux-2.6.16-rc4-mm1.orig/drivers/acpi/processor_core.c
+++ linux-2.6.16-rc4-mm1/drivers/acpi/processor_core.c
@@ -549,12 +549,14 @@ static int acpi_processor_start(struct a
* ACPI id of processors can be reported wrongly by the BIOS.
* Don't trust it blindly
*/
+#ifndef CONFIG_ACPI_SCI_EMULATE
if (processor_device_array[pr->id] != NULL &&
processor_device_array[pr->id] != (void *)device) {
ACPI_WARNING((AE_INFO, "BIOS reporting wrong ACPI id"
"for the processor"));
return_VALUE(-ENODEV);
}
+#endif
processor_device_array[pr->id] = (void *)device;
processors[pr->id] = pr;
@@ -678,9 +680,6 @@ static int acpi_processor_remove(struct
/****************************************************************************
* Acpi processor hotplug support *
****************************************************************************/
-
-static int is_processor_present(acpi_handle handle);
-
static int is_processor_present(acpi_handle handle)
{
acpi_status status;
@@ -734,7 +733,10 @@ acpi_processor_hotplug_notify(acpi_handl
{
struct acpi_processor *pr;
struct acpi_device *device = NULL;
- int result;
+ int result = 0;
+#ifdef CONFIG_ACPI_SCI_EMULATE
+ extern int is_PSX_present(acpi_handle handle, int number);
+#endif
ACPI_FUNCTION_TRACE("acpi_processor_hotplug_notify");
@@ -745,6 +747,16 @@ acpi_processor_hotplug_notify(acpi_handl
(event == ACPI_NOTIFY_BUS_CHECK) ?
"ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK");
+#ifdef CONFIG_ACPI_SCI_EMULATE
+ /*
+ * Evaluate _PS0 to make _STA return Present Status
+ */
+ if (is_PSX_present(handle, 0))
+ result = acpi_evaluate_object(handle, "_PS0", NULL, NULL);
+ if (ACPI_SUCCESS(result)) {
+ printk ("Called method _PS0, _STA should return Present\n");
+ }
+#endif
if (!is_processor_present(handle))
break;
@@ -865,6 +877,7 @@ static int acpi_processor_handle_eject(s
acpi_unmap_lsapic(pr->id);
return (0);
}
+
#else
static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu)
{
Index: linux-2.6.16-rc4-mm1/drivers/acpi/scan.c
===================================================================
--- linux-2.6.16-rc4-mm1.orig/drivers/acpi/scan.c
+++ linux-2.6.16-rc4-mm1/drivers/acpi/scan.c
@@ -371,15 +371,48 @@ setup_sys_fs_device_files(struct acpi_de
(*(func)) (&dev->kobj, &acpi_device_attr_eject.attr);
}
+#ifdef CONFIG_ACPI_SCI_EMULATE
+int is_PSX_present(acpi_handle handle, int number)
+{
+ acpi_status status = AE_OK;
+ acpi_handle temp = NULL;
+
+ ACPI_FUNCTION_TRACE("is_PSX_present");
+
+ switch (number) {
+ case 0:
+ status = acpi_get_handle(handle, "_PS0", &temp);
+ break;
+ case 3:
+ status = acpi_get_handle(handle, "_PS3", &temp);
+ break;
+ }
+
+ if (ACPI_SUCCESS(status)) {
+ printk ("Found _PS%d in Processor Scope\n", number);
+ return_VALUE(1);
+ }
+ else
+ return_VALUE(0);
+}
+#endif
+
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;
+#ifdef CONFIG_ACPI_SCI_EMULATE
/*
- * TBD: evaluate _PS3?
+ * evaluate _PS3 to make _STA return Not-Present.
*/
+ if (is_PSX_present(handle, 3))
+ status = acpi_evaluate_object(handle, "_PS3", NULL, NULL);
+ if (ACPI_SUCCESS(status)) {
+ printk ("Called method _PS3, _STA should return Not-Present\n");
+ }
+#endif
if (lockable) {
arg_list.count = 1;
--
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Stuff]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
[Linux Resources]