All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/7] ACPI / hotplug: Common code for ACPI-based hotplug
@ 2013-02-17 15:18 Rafael J. Wysocki
  2013-02-17 15:20 ` [PATCH 1/7] ACPI / scan: Introduce acpi_scan_match_handler() Rafael J. Wysocki
                   ` (7 more replies)
  0 siblings, 8 replies; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-17 15:18 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Yinghai Lu, Toshi Kani, Yasuaki Ishimatsu,
	Jiang Liu

Hi All,

The following patches introduce common code for ACPI-based hotplug for non-PCI
devices and modify the container and memory hotplug ACPI drivers to use the new
code.

This is based on linux-pm.git/master and regarded as v3.10 material.

[1/7] Introduce acpi_scan_match_handler() that will be useful going forward.
[2/7] Introduce common code for ACPI-base device hotplug.
[3/7] Use the new commot hotplug code in the container driver.
[4/7] Introduce acpi_scan_handler_matching() that will be useful subsequently.
[5/7] Introduce user space interface for hotplug profiles.
[6/7] Make the container driver use the hotplug profiles user space interface.
[7/7] Make the memory hotplug driver use struct acpi_scan_handler along with
      the hotplug profiles user space interface.

Thanks,
Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH 1/7] ACPI / scan: Introduce acpi_scan_match_handler()
  2013-02-17 15:18 [PATCH 0/7] ACPI / hotplug: Common code for ACPI-based hotplug Rafael J. Wysocki
@ 2013-02-17 15:20 ` Rafael J. Wysocki
  2013-02-19  6:48   ` Yasuaki Ishimatsu
  2013-02-17 15:21 ` [PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug Rafael J. Wysocki
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-17 15:20 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Yinghai Lu, Toshi Kani, Yasuaki Ishimatsu,
	Jiang Liu

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Introduce helper routine acpi_scan_match_handler() that will find the
ACPI scan handler matching a given device ID, if there is one, and
rework acpi_scan_attach_handler() to use the new routine (that
routine will also be useful for other purposes going forward).

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/acpi/scan.c |   53 +++++++++++++++++++++++++++-------------------------
 1 file changed, 28 insertions(+), 25 deletions(-)

Index: test/drivers/acpi/scan.c
===================================================================
--- test.orig/drivers/acpi/scan.c
+++ test/drivers/acpi/scan.c
@@ -1529,6 +1529,25 @@ static int acpi_bus_type_and_status(acpi
 	return 0;
 }
 
+static struct acpi_scan_handler *acpi_scan_match_handler(char *idstr,
+					const struct acpi_device_id **matchid)
+{
+	struct acpi_scan_handler *handler;
+
+	list_for_each_entry(handler, &acpi_scan_handlers_list, list_node) {
+		const struct acpi_device_id *devid;
+
+		for (devid = handler->ids; devid->id[0]; devid++)
+			if (!strcmp((char *)devid->id, idstr)) {
+				if (matchid)
+					*matchid = devid;
+
+				return handler;
+			}
+	}
+	return NULL;
+}
+
 static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
 				      void *not_used, void **return_value)
 {
@@ -1576,42 +1595,26 @@ static acpi_status acpi_bus_check_add(ac
 	return AE_OK;
 }
 
-static int acpi_scan_do_attach_handler(struct acpi_device *device, char *id)
+static int acpi_scan_attach_handler(struct acpi_device *device)
 {
-	struct acpi_scan_handler *handler;
+	struct acpi_hardware_id *hwid;
+	int ret = 0;
 
-	list_for_each_entry(handler, &acpi_scan_handlers_list, list_node) {
+	list_for_each_entry(hwid, &device->pnp.ids, list) {
 		const struct acpi_device_id *devid;
+		struct acpi_scan_handler *handler;
 
-		for (devid = handler->ids; devid->id[0]; devid++) {
-			int ret;
-
-			if (strcmp((char *)devid->id, id))
-				continue;
-
+		handler = acpi_scan_match_handler(hwid->id, &devid);
+		if (handler) {
 			ret = handler->attach(device, devid);
 			if (ret > 0) {
 				device->handler = handler;
-				return ret;
+				break;
 			} else if (ret < 0) {
-				return ret;
+				break;
 			}
 		}
 	}
-	return 0;
-}
-
-static int acpi_scan_attach_handler(struct acpi_device *device)
-{
-	struct acpi_hardware_id *hwid;
-	int ret = 0;
-
-	list_for_each_entry(hwid, &device->pnp.ids, list) {
-		ret = acpi_scan_do_attach_handler(device, hwid->id);
-		if (ret)
-			break;
-
-	}
 	return ret;
 }
 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-17 15:18 [PATCH 0/7] ACPI / hotplug: Common code for ACPI-based hotplug Rafael J. Wysocki
  2013-02-17 15:20 ` [PATCH 1/7] ACPI / scan: Introduce acpi_scan_match_handler() Rafael J. Wysocki
@ 2013-02-17 15:21 ` Rafael J. Wysocki
  2013-02-19  6:43   ` Yasuaki Ishimatsu
  2013-02-20 22:49   ` [Update][PATCH " Rafael J. Wysocki
  2013-02-17 15:22 ` [PATCH 3/7] ACPI / container: Use common hotplug code Rafael J. Wysocki
                   ` (5 subsequent siblings)
  7 siblings, 2 replies; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-17 15:21 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Yinghai Lu, Toshi Kani, Yasuaki Ishimatsu,
	Jiang Liu

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Multiple drivers handling hotplug-capable ACPI device nodes install
notify handlers covering the same types of events in a very similar
way.  Moreover, those handlers are installed in separate namespace
walks, although that really should be done during namespace scans
carried out by acpi_bus_scan().  This leads to substantial code
duplication, unnecessary overhead and behavior that is hard to
follow.

For this reason, introduce common code in drivers/acpi/scan.c for
handling hotplug-related notification and carrying out device
insertion and eject operations in a generic fashion, such that it
may be used by all of the relevant drivers in the future.  To cover
the existing differences between those drivers introduce struct
acpi_hotplug_profile for representing collections of hotplug
settings associated with different ACPI scan handlers that can be
used by the drivers to make the common code reflect their current
behavior.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/acpi/scan.c     |  271 +++++++++++++++++++++++++++++++++++++-----------
 include/acpi/acpi_bus.h |    7 +
 2 files changed, 220 insertions(+), 58 deletions(-)

Index: test/include/acpi/acpi_bus.h
===================================================================
--- test.orig/include/acpi/acpi_bus.h
+++ test/include/acpi/acpi_bus.h
@@ -88,11 +88,18 @@ struct acpi_device;
  * -----------------
  */
 
+struct acpi_hotplug_profile {
+	bool enabled:1;
+	bool uevents:1;
+	bool autoeject:1;
+};
+
 struct acpi_scan_handler {
 	const struct acpi_device_id *ids;
 	struct list_head list_node;
 	int (*attach)(struct acpi_device *dev, const struct acpi_device_id *id);
 	void (*detach)(struct acpi_device *dev);
+	struct acpi_hotplug_profile hotplug;
 };
 
 /*
Index: test/drivers/acpi/scan.c
===================================================================
--- test.orig/drivers/acpi/scan.c
+++ test/drivers/acpi/scan.c
@@ -107,32 +107,19 @@ acpi_device_modalias_show(struct device
 }
 static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
 
-/**
- * acpi_bus_hot_remove_device: hot-remove a device and its children
- * @context: struct acpi_eject_event pointer (freed in this func)
- *
- * Hot-remove a device and its children. This function frees up the
- * memory space passed by arg context, so that the caller may call
- * this function asynchronously through acpi_os_hotplug_execute().
- */
-void acpi_bus_hot_remove_device(void *context)
+static int acpi_scan_hot_remove(struct acpi_device *device)
 {
-	struct acpi_eject_event *ej_event = context;
-	struct acpi_device *device = ej_event->device;
 	acpi_handle handle = device->handle;
-	acpi_handle temp;
+	acpi_handle not_used;
 	struct acpi_object_list arg_list;
 	union acpi_object arg;
-	acpi_status status = AE_OK;
-	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
-
-	mutex_lock(&acpi_scan_lock);
+	acpi_status status;
 
 	/* If there is no handle, the device node has been unregistered. */
-	if (!device->handle) {
+	if (!handle) {
 		dev_dbg(&device->dev, "ACPI handle missing\n");
 		put_device(&device->dev);
-		goto out;
+		return -EINVAL;
 	}
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -143,7 +130,7 @@ void acpi_bus_hot_remove_device(void *co
 	put_device(&device->dev);
 	device = NULL;
 
-	if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &temp))) {
+	if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &not_used))) {
 		arg_list.count = 1;
 		arg_list.pointer = &arg;
 		arg.type = ACPI_TYPE_INTEGER;
@@ -161,18 +148,162 @@ void acpi_bus_hot_remove_device(void *co
 	 */
 	status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
 	if (ACPI_FAILURE(status)) {
-		if (status != AE_NOT_FOUND)
+		if (status == AE_NOT_FOUND) {
+			return -ENODEV;
+		} else {
 			acpi_handle_warn(handle, "Eject failed\n");
+			return -EIO;
+		}
+	}
+	return 0;
+}
+
+static void acpi_bus_device_eject(void *context)
+{
+	acpi_handle handle = context;
+	struct acpi_device *device = NULL;
+	struct acpi_scan_handler *handler;
+	u32 ost_source = ACPI_NOTIFY_EJECT_REQUEST;
+	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
+
+	mutex_lock(&acpi_scan_lock);
 
-		/* Tell the firmware the hot-remove operation has failed. */
-		acpi_evaluate_hotplug_ost(handle, ej_event->event,
-					  ost_code, NULL);
+	acpi_bus_get_device(handle, &device);
+	if (!device)
+		goto out;
+
+	handler = device->handler;
+	if (!handler || !handler->hotplug.enabled) {
+		ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
+		goto out;
 	}
+	acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
+				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+	if (handler->hotplug.uevents)
+		kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
+
+	if (handler->hotplug.autoeject) {
+		int error;
+
+		ost_source = ACPI_OST_EC_OSPM_EJECT;
+		get_device(&device->dev);
+		error = acpi_scan_hot_remove(device);
+		if (!error)
+			ost_code = ACPI_OST_SC_SUCCESS;
+	} else {
+		device->flags.eject_pending = true;
+		goto out_unlock;
+	}
+
+ out:
+	acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL);
+
+ out_unlock:
+	mutex_unlock(&acpi_scan_lock);
+}
+
+static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
+{
+	struct acpi_device *device = NULL;
+	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
+	int error;
+
+	mutex_lock(&acpi_scan_lock);
+
+	acpi_bus_get_device(handle, &device);
+	if (device) {
+		dev_warn(&device->dev, "Attempt to re-insert\n");
+		goto out;
+	}
+	acpi_evaluate_hotplug_ost(handle, ost_source,
+				  ACPI_OST_SC_INSERT_IN_PROGRESS, NULL);
+	ost_source = ACPI_OST_EC_OSPM_INSERTION;
+	error = acpi_bus_scan(handle);
+	if (error) {
+		acpi_handle_warn(handle, "Namespace scan failure\n");
+		goto out;
+	}
+	error = acpi_bus_get_device(handle, &device);
+	if (error) {
+		acpi_handle_warn(handle, "Missing device node object\n");
+		goto out;
+	}
+	ost_code = ACPI_OST_SC_SUCCESS;
+	if (device->handler && device->handler->hotplug.uevents)
+		kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
 
  out:
+	acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL);
+	mutex_unlock(&acpi_scan_lock);
+}
+
+static void acpi_scan_bus_check(void *context)
+{
+	acpi_scan_bus_device_check((acpi_handle)context,
+				   ACPI_NOTIFY_BUS_CHECK);
+}
+
+static void acpi_scan_device_check(void *context)
+{
+	acpi_scan_bus_device_check((acpi_handle)context,
+				   ACPI_NOTIFY_DEVICE_CHECK);
+}
+
+static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *not_used)
+{
+	acpi_osd_exec_callback callback;
+	acpi_status status;
+
+	switch (type) {
+	case ACPI_NOTIFY_BUS_CHECK:
+		acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
+		callback = acpi_scan_bus_check;
+		break;
+	case ACPI_NOTIFY_DEVICE_CHECK:
+		acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
+		callback = acpi_scan_device_check;
+		break;
+	case ACPI_NOTIFY_EJECT_REQUEST:
+		acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
+		callback = acpi_bus_device_eject;
+		break;
+	default:
+		/* non-hotplug event; possibly handled by other handler */
+		return;
+	}
+	status = acpi_os_hotplug_execute(callback, handle);
+	if (ACPI_FAILURE(status))
+		acpi_evaluate_hotplug_ost(handle, type,
+					  ACPI_OST_SC_NON_SPECIFIC_FAILURE,
+					  NULL);
+}
+
+/**
+ * acpi_bus_hot_remove_device: hot-remove a device and its children
+ * @context: struct acpi_eject_event pointer (freed in this func)
+ *
+ * Hot-remove a device and its children. This function frees up the
+ * memory space passed by arg context, so that the caller may call
+ * this function asynchronously through acpi_os_hotplug_execute().
+ */
+void acpi_bus_hot_remove_device(void *context)
+{
+	struct acpi_eject_event *ej_event = context;
+	struct acpi_device *device = ej_event->device;
+	acpi_handle handle = device->handle;
+	u32 ost_code = ACPI_OST_SC_SUCCESS;
+	int error;
+
+	mutex_lock(&acpi_scan_lock);
+
+	error = acpi_scan_hot_remove(device);
+	if (error)
+		ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
+
+	acpi_evaluate_hotplug_ost(handle, ej_event->event, ost_code, NULL);
+
 	mutex_unlock(&acpi_scan_lock);
 	kfree(context);
-	return;
 }
 EXPORT_SYMBOL(acpi_bus_hot_remove_device);
 
@@ -206,50 +337,48 @@ static ssize_t
 acpi_eject_store(struct device *d, struct device_attribute *attr,
 		const char *buf, size_t count)
 {
-	int ret = count;
-	acpi_status status;
-	acpi_object_type type = 0;
 	struct acpi_device *acpi_device = to_acpi_device(d);
-	struct acpi_eject_event *ej_event;
+	acpi_object_type not_used;
+	acpi_status status;
+	u32 ost_source;
+	u32 ost_code;
+	int ret;
 
-	if ((!count) || (buf[0] != '1')) {
+	if (!count || buf[0] != '1')
 		return -EINVAL;
-	}
-	if (!acpi_device->driver && !acpi_device->handler) {
-		ret = -ENODEV;
-		goto err;
-	}
-	status = acpi_get_type(acpi_device->handle, &type);
-	if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) {
-		ret = -ENODEV;
-		goto err;
-	}
 
-	ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
-	if (!ej_event) {
-		ret = -ENOMEM;
-		goto err;
-	}
+	if ((!acpi_device->handler || !acpi_device->handler->hotplug.enabled)
+	    && !acpi_device->driver)
+		return -ENODEV;
+
+	status = acpi_get_type(acpi_device->handle, &not_used);
+	if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable)
+		return -ENODEV;
+
+	mutex_lock(&acpi_scan_lock);
 
-	get_device(&acpi_device->dev);
-	ej_event->device = acpi_device;
 	if (acpi_device->flags.eject_pending) {
-		/* event originated from ACPI eject notification */
-		ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
+		/* ACPI eject notification event. */
+		ost_source = ACPI_NOTIFY_EJECT_REQUEST;
 		acpi_device->flags.eject_pending = 0;
 	} else {
-		/* event originated from user */
-		ej_event->event = ACPI_OST_EC_OSPM_EJECT;
-		(void) acpi_evaluate_hotplug_ost(acpi_device->handle,
-			ej_event->event, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+		/* Eject initiated by user space. */
+		ost_source = ACPI_OST_EC_OSPM_EJECT;
 	}
-
-	status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event);
-	if (ACPI_FAILURE(status)) {
-		put_device(&acpi_device->dev);
-		kfree(ej_event);
+	acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source,
+				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+	get_device(&acpi_device->dev);
+	ret = acpi_scan_hot_remove(acpi_device);
+	if (ret) {
+		ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
+	} else {
+		ost_code = ACPI_OST_SC_SUCCESS;
+		ret = count;
 	}
-err:
+	acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT,
+				  ost_code, NULL);
+
+	mutex_unlock(&acpi_scan_lock);
 	return ret;
 }
 
@@ -1548,6 +1677,30 @@ static struct acpi_scan_handler *acpi_sc
 	return NULL;
 }
 
+static void acpi_scan_init_hotplug(acpi_handle handle)
+{
+	struct acpi_device_info *info;
+	struct acpi_scan_handler *handler;
+
+	if (ACPI_FAILURE(acpi_get_object_info(handle, &info)))
+		return;
+
+	if (!(info->valid & ACPI_VALID_HID)) {
+		kfree(info);
+		return;
+	}
+
+	/*
+	 * This relies on the fact that acpi_install_notify_handler() will not
+	 * install the same notify handler routine twice for the same handle.
+	 */
+	handler = acpi_scan_match_handler(info->hardware_id.string, NULL);
+	kfree(info);
+	if (handler && handler->hotplug.enabled)
+		acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+					    acpi_hotplug_notify_cb, NULL);
+}
+
 static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
 				      void *not_used, void **return_value)
 {
@@ -1570,6 +1723,8 @@ static acpi_status acpi_bus_check_add(ac
 		return AE_OK;
 	}
 
+	acpi_scan_init_hotplug(handle);
+
 	if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
 	    !(sta & ACPI_STA_DEVICE_FUNCTIONING)) {
 		struct acpi_device_wakeup wakeup;

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH 3/7] ACPI / container: Use common hotplug code
  2013-02-17 15:18 [PATCH 0/7] ACPI / hotplug: Common code for ACPI-based hotplug Rafael J. Wysocki
  2013-02-17 15:20 ` [PATCH 1/7] ACPI / scan: Introduce acpi_scan_match_handler() Rafael J. Wysocki
  2013-02-17 15:21 ` [PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug Rafael J. Wysocki
@ 2013-02-17 15:22 ` Rafael J. Wysocki
  2013-02-17 15:23 ` [PATCH 4/7] ACPI / scan: Introduce acpi_scan_handler_matching() Rafael J. Wysocki
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-17 15:22 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Yinghai Lu, Toshi Kani, Yasuaki Ishimatsu,
	Jiang Liu

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Switch the ACPI container driver to using common device hotplug code
introduced previously.  This reduces the driver down to a trivial
definition and registration of a struct acpi_scan_handler object.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/acpi/container.c |  146 +++--------------------------------------------
 1 file changed, 10 insertions(+), 136 deletions(-)

Index: test/drivers/acpi/container.c
===================================================================
--- test.orig/drivers/acpi/container.c
+++ test/drivers/acpi/container.c
@@ -1,12 +1,12 @@
 /*
- * acpi_container.c  - ACPI Generic Container Driver
- * ($Revision: )
+ * container.c  - ACPI Generic Container Driver
  *
  * Copyright (C) 2004 Anil S Keshavamurthy (anil.s.keshavamurthy@intel.com)
  * Copyright (C) 2004 Keiichiro Tokunaga (tokunaga.keiich@jp.fujitsu.com)
  * Copyright (C) 2004 Motoyuki Ito (motoyuki@soft.fujitsu.com)
- * Copyright (C) 2004 Intel Corp.
  * Copyright (C) 2004 FUJITSU LIMITED
+ * Copyright (C) 2004, 2013 Intel Corp.
+ * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  *
@@ -26,14 +26,9 @@
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/types.h>
 #include <linux/acpi.h>
-#include <acpi/acpi_bus.h>
-#include <acpi/acpi_drivers.h>
+
+#include "internal.h"
 
 #define PREFIX "ACPI: "
 
@@ -50,141 +45,20 @@ static const struct acpi_device_id conta
 static int container_device_attach(struct acpi_device *device,
 				   const struct acpi_device_id *not_used)
 {
-	/*
-	 * FIXME: This is necessary, so that acpi_eject_store() doesn't return
-	 * -ENODEV for containers.
-	 */
+	/* This is necessary for container hotplug to work. */
 	return 1;
 }
 
 static struct acpi_scan_handler container_device_handler = {
 	.ids = container_device_ids,
 	.attach = container_device_attach,
+	.hotplug = {
+		.enabled = true,
+		.uevents = true,
+	},
 };
 
-static int is_device_present(acpi_handle handle)
-{
-	acpi_handle temp;
-	acpi_status status;
-	unsigned long long sta;
-
-
-	status = acpi_get_handle(handle, "_STA", &temp);
-	if (ACPI_FAILURE(status))
-		return 1;	/* _STA not found, assume device present */
-
-	status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
-	if (ACPI_FAILURE(status))
-		return 0;	/* Firmware error */
-
-	return ((sta & ACPI_STA_DEVICE_PRESENT) == ACPI_STA_DEVICE_PRESENT);
-}
-
-static void container_notify_cb(acpi_handle handle, u32 type, void *context)
-{
-	struct acpi_device *device = NULL;
-	int result;
-	int present;
-	acpi_status status;
-	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
-
-	acpi_scan_lock_acquire();
-
-	switch (type) {
-	case ACPI_NOTIFY_BUS_CHECK:
-		/* Fall through */
-	case ACPI_NOTIFY_DEVICE_CHECK:
-		pr_debug("Container driver received %s event\n",
-		       (type == ACPI_NOTIFY_BUS_CHECK) ?
-		       "ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK");
-
-		present = is_device_present(handle);
-		status = acpi_bus_get_device(handle, &device);
-		if (!present) {
-			if (ACPI_SUCCESS(status)) {
-				/* device exist and this is a remove request */
-				device->flags.eject_pending = 1;
-				kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
-				goto out;
-			}
-			break;
-		}
-
-		if (!ACPI_FAILURE(status) || device)
-			break;
-
-		result = acpi_bus_scan(handle);
-		if (result) {
-			acpi_handle_warn(handle, "Failed to add container\n");
-			break;
-		}
-		result = acpi_bus_get_device(handle, &device);
-		if (result) {
-			acpi_handle_warn(handle, "Missing device object\n");
-			break;
-		}
-
-		kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
-		ost_code = ACPI_OST_SC_SUCCESS;
-		break;
-
-	case ACPI_NOTIFY_EJECT_REQUEST:
-		if (!acpi_bus_get_device(handle, &device) && device) {
-			device->flags.eject_pending = 1;
-			kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
-			goto out;
-		}
-		break;
-
-	default:
-		/* non-hotplug event; possibly handled by other handler */
-		goto out;
-	}
-
-	/* Inform firmware that the hotplug operation has completed */
-	(void) acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
-
- out:
-	acpi_scan_lock_release();
-}
-
-static bool is_container(acpi_handle handle)
-{
-	struct acpi_device_info *info;
-	bool ret = false;
-
-	if (ACPI_FAILURE(acpi_get_object_info(handle, &info)))
-		return false;
-
-	if (info->valid & ACPI_VALID_HID) {
-		const struct acpi_device_id *id;
-
-		for (id = container_device_ids; id->id[0]; id++) {
-			ret = !strcmp((char *)id->id, info->hardware_id.string);
-			if (ret)
-				break;
-		}
-	}
-	kfree(info);
-	return ret;
-}
-
-static acpi_status acpi_container_register_notify_handler(acpi_handle handle,
-							  u32 lvl, void *ctxt,
-							  void **retv)
-{
-	if (is_container(handle))
-		acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
-					    container_notify_cb, NULL);
-
-	return AE_OK;
-}
-
 void __init acpi_container_init(void)
 {
-	acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
-			    acpi_container_register_notify_handler, NULL,
-			    NULL, NULL);
-
 	acpi_scan_add_handler(&container_device_handler);
 }

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH 4/7] ACPI / scan: Introduce acpi_scan_handler_matching()
  2013-02-17 15:18 [PATCH 0/7] ACPI / hotplug: Common code for ACPI-based hotplug Rafael J. Wysocki
                   ` (2 preceding siblings ...)
  2013-02-17 15:22 ` [PATCH 3/7] ACPI / container: Use common hotplug code Rafael J. Wysocki
@ 2013-02-17 15:23 ` Rafael J. Wysocki
  2013-02-19  8:05   ` Yasuaki Ishimatsu
  2013-02-17 15:24 ` [PATCH 5/7] ACPI / hotplug: Introduce user space interface for hotplug profiles Rafael J. Wysocki
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-17 15:23 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Yinghai Lu, Toshi Kani, Yasuaki Ishimatsu,
	Jiang Liu

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Introduce new helper routine acpi_scan_handler_matching() for
checking if the given ACPI scan handler matches a given device ID
and rework acpi_scan_match_handler() to use the new routine (that
routine will also be useful for other purposes in the future).

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/acpi/scan.c |   30 ++++++++++++++++++++----------
 1 file changed, 20 insertions(+), 10 deletions(-)

Index: test/drivers/acpi/scan.c
===================================================================
--- test.orig/drivers/acpi/scan.c
+++ test/drivers/acpi/scan.c
@@ -1658,22 +1658,32 @@ static int acpi_bus_type_and_status(acpi
 	return 0;
 }
 
+static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler,
+				       char *idstr,
+				       const struct acpi_device_id **matchid)
+{
+	const struct acpi_device_id *devid;
+
+	for (devid = handler->ids; devid->id[0]; devid++)
+		if (!strcmp((char *)devid->id, idstr)) {
+			if (matchid)
+				*matchid = devid;
+
+			return true;
+		}
+
+	return false;
+}
+
 static struct acpi_scan_handler *acpi_scan_match_handler(char *idstr,
 					const struct acpi_device_id **matchid)
 {
 	struct acpi_scan_handler *handler;
 
-	list_for_each_entry(handler, &acpi_scan_handlers_list, list_node) {
-		const struct acpi_device_id *devid;
+	list_for_each_entry(handler, &acpi_scan_handlers_list, list_node)
+		if (acpi_scan_handler_matching(handler, idstr, matchid))
+			return handler;
 
-		for (devid = handler->ids; devid->id[0]; devid++)
-			if (!strcmp((char *)devid->id, idstr)) {
-				if (matchid)
-					*matchid = devid;
-
-				return handler;
-			}
-	}
 	return NULL;
 }
 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH 5/7] ACPI / hotplug: Introduce user space interface for hotplug profiles
  2013-02-17 15:18 [PATCH 0/7] ACPI / hotplug: Common code for ACPI-based hotplug Rafael J. Wysocki
                   ` (3 preceding siblings ...)
  2013-02-17 15:23 ` [PATCH 4/7] ACPI / scan: Introduce acpi_scan_handler_matching() Rafael J. Wysocki
@ 2013-02-17 15:24 ` Rafael J. Wysocki
  2013-02-25 18:13   ` Toshi Kani
  2013-02-17 15:25 ` [PATCH 6/7] ACPI / container: Use hotplug profile user space interface Rafael J. Wysocki
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-17 15:24 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Yinghai Lu, Toshi Kani, Yasuaki Ishimatsu,
	Jiang Liu

From: Rafael J. Wysocki <rafael.j.wysocki@inel.com>

Introduce user space interface for manipulating hotplug profiles
associated with ACPI scan handlers.

The interface consists of sysfs directories under
/sys/firmware/acpi/hotplug/, one for each hotplug profile, containing
attributes allowing user space to manipulate the enabled, uevents,
and autoeject fields of the corresponding profile.  In particular,
switching the enabled attribute from 'unset' to 'set' will cause
the common hotplug notify handler to be installed for all ACPI
namespace objects representing devices matching the scan handler
associated with the given hotplug profile (and analogously for the
converse switch).

Drivers willing to use the new user space interface should add their
ACPI scan handlers with the help of new funtion
acpi_scan_add_handler_with_hotplug().

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@inel.com>
---
 Documentation/ABI/testing/sysfs-firmware-acpi |   42 +++++++++
 drivers/acpi/internal.h                       |    9 +
 drivers/acpi/scan.c                           |   73 +++++++++++++++
 drivers/acpi/sysfs.c                          |  120 ++++++++++++++++++++++++++
 include/acpi/acpi_bus.h                       |    7 +
 5 files changed, 251 insertions(+)

Index: test/drivers/acpi/sysfs.c
===================================================================
--- test.orig/drivers/acpi/sysfs.c
+++ test/drivers/acpi/sysfs.c
@@ -7,6 +7,8 @@
 #include <linux/moduleparam.h>
 #include <acpi/acpi_drivers.h>
 
+#include "internal.h"
+
 #define _COMPONENT		ACPI_SYSTEM_COMPONENT
 ACPI_MODULE_NAME("sysfs");
 
@@ -249,6 +251,7 @@ module_param_call(acpica_version, NULL,
 static LIST_HEAD(acpi_table_attr_list);
 static struct kobject *tables_kobj;
 static struct kobject *dynamic_tables_kobj;
+static struct kobject *hotplug_kobj;
 
 struct acpi_table_attr {
 	struct bin_attribute attr;
@@ -716,6 +719,121 @@ acpi_show_profile(struct device *dev, st
 static const struct device_attribute pm_profile_attr =
 	__ATTR(pm_profile, S_IRUGO, acpi_show_profile, NULL);
 
+static ssize_t hotplug_enabled_show(struct kobject *kobj,
+				    struct kobj_attribute *attr, char *buf)
+{
+	struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj);
+
+	return sprintf(buf, "%d\n", hotplug->enabled);
+}
+
+static ssize_t hotplug_enabled_store(struct kobject *kobj,
+				     struct kobj_attribute *attr,
+				     const char *buf, size_t size)
+{
+	struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj);
+	unsigned int val;
+
+	if (kstrtouint(buf, 10, &val) || val > 1)
+		return -EINVAL;
+
+	acpi_scan_hotplug_enabled(hotplug, val);
+	return size;
+}
+
+static struct kobj_attribute hotplug_enabled_attr =
+	__ATTR(enabled, S_IRUGO | S_IWUSR, hotplug_enabled_show,
+		hotplug_enabled_store);
+
+static ssize_t hotplug_uevents_show(struct kobject *kobj,
+				    struct kobj_attribute *attr, char *buf)
+{
+	struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj);
+
+	return sprintf(buf, "%d\n", hotplug->uevents);
+}
+
+static ssize_t hotplug_uevents_store(struct kobject *kobj,
+				     struct kobj_attribute *attr,
+				     const char *buf, size_t size)
+{
+	struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj);
+	unsigned int val;
+
+	if (kstrtouint(buf, 10, &val) || val > 1)
+		return -EINVAL;
+
+	acpi_scan_hotplug_uevents(hotplug, val);
+	return size;
+}
+
+static struct kobj_attribute hotplug_uevents_attr =
+	__ATTR(uevents, S_IRUGO | S_IWUSR, hotplug_uevents_show,
+		hotplug_uevents_store);
+
+static ssize_t hotplug_autoeject_show(struct kobject *kobj,
+				      struct kobj_attribute *attr, char *buf)
+{
+	struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj);
+
+	return sprintf(buf, "%d\n", hotplug->autoeject);
+}
+
+static ssize_t hotplug_autoeject_store(struct kobject *kobj,
+				       struct kobj_attribute *attr,
+				       const char *buf, size_t size)
+{
+	struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj);
+	unsigned int val;
+
+	if (kstrtouint(buf, 10, &val) || val > 1)
+		return -EINVAL;
+
+	acpi_scan_hotplug_autoeject(hotplug, val);
+	return size;
+}
+
+static struct kobj_attribute hotplug_autoeject_attr =
+	__ATTR(autoeject, S_IRUGO | S_IWUSR, hotplug_autoeject_show,
+		hotplug_autoeject_store);
+
+static struct attribute *hotplug_profile_attrs[] = {
+	&hotplug_enabled_attr.attr,
+	&hotplug_uevents_attr.attr,
+	&hotplug_autoeject_attr.attr,
+	NULL
+};
+
+struct kobj_type acpi_hotplug_profile_ktype = {
+	.sysfs_ops = &kobj_sysfs_ops,
+	.default_attrs = hotplug_profile_attrs,
+};
+
+void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug,
+				    const char *name)
+{
+	int error;
+
+	if (!hotplug_kobj)
+		goto err_out;
+
+	kobject_init(&hotplug->kobj, &acpi_hotplug_profile_ktype);
+	error = kobject_set_name(&hotplug->kobj, "%s", name);
+	if (error)
+		goto err_out;
+
+	hotplug->kobj.parent = hotplug_kobj;
+	error = kobject_add(&hotplug->kobj, hotplug_kobj, NULL);
+	if (error)
+		goto err_out;
+
+	kobject_uevent(&hotplug->kobj, KOBJ_ADD);
+	return;
+
+ err_out:
+	pr_err(PREFIX "Unable to add hotplug profile '%s'\n", name);
+}
+
 int __init acpi_sysfs_init(void)
 {
 	int result;
@@ -723,6 +841,8 @@ int __init acpi_sysfs_init(void)
 	result = acpi_tables_sysfs_init();
 	if (result)
 		return result;
+
+	hotplug_kobj = kobject_create_and_add("hotplug", acpi_kobj);
 	result = sysfs_create_file(acpi_kobj, &pm_profile_attr.attr);
 	return result;
 }
Index: test/include/acpi/acpi_bus.h
===================================================================
--- test.orig/include/acpi/acpi_bus.h
+++ test/include/acpi/acpi_bus.h
@@ -89,11 +89,18 @@ struct acpi_device;
  */
 
 struct acpi_hotplug_profile {
+	struct kobject kobj;
 	bool enabled:1;
 	bool uevents:1;
 	bool autoeject:1;
 };
 
+static inline struct acpi_hotplug_profile *to_acpi_hotplug_profile(
+						struct kobject *kobj)
+{
+	return container_of(kobj, struct acpi_hotplug_profile, kobj);
+}
+
 struct acpi_scan_handler {
 	const struct acpi_device_id *ids;
 	struct list_head list_node;
Index: test/drivers/acpi/internal.h
===================================================================
--- test.orig/drivers/acpi/internal.h
+++ test/drivers/acpi/internal.h
@@ -36,6 +36,15 @@ void acpi_container_init(void);
 static inline void acpi_container_init(void) {}
 #endif
 
+void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug,
+				    const char *name);
+int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler,
+				       const char *hotplug_profile_name);
+void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val);
+void acpi_scan_hotplug_uevents(struct acpi_hotplug_profile *hotplug, bool val);
+void acpi_scan_hotplug_autoeject(struct acpi_hotplug_profile *hotplug,
+				 bool val);
+
 #ifdef CONFIG_DEBUG_FS
 extern struct dentry *acpi_debugfs_dir;
 int acpi_debugfs_init(void);
Index: test/drivers/acpi/scan.c
===================================================================
--- test.orig/drivers/acpi/scan.c
+++ test/drivers/acpi/scan.c
@@ -63,6 +63,19 @@ int acpi_scan_add_handler(struct acpi_sc
 	return 0;
 }
 
+int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler,
+				       const char *hotplug_profile_name)
+{
+	int error;
+
+	error = acpi_scan_add_handler(handler);
+	if (error)
+		return error;
+
+	acpi_sysfs_add_hotplug_profile(&handler->hotplug, hotplug_profile_name);
+	return 0;
+}
+
 /*
  * Creates hid/cid(s) string needed for modalias and uevent
  * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get:
@@ -1675,6 +1688,66 @@ static bool acpi_scan_handler_matching(s
 	return false;
 }
 
+static acpi_status acpi_scan_hotplug_modify(acpi_handle handle,
+					    u32 lvl_not_used, void *data,
+					    void **ret_not_used)
+{
+	struct acpi_scan_handler *handler = data;
+	struct acpi_device_info *info;
+	bool match = false;
+
+	if (ACPI_FAILURE(acpi_get_object_info(handle, &info)))
+		return AE_OK;
+
+	if (info->valid & ACPI_VALID_HID) {
+		char *idstr = info->hardware_id.string;
+		match = acpi_scan_handler_matching(handler, idstr, NULL);
+	}
+	kfree(info);
+	if (!match)
+		return AE_OK;
+
+	if (handler->hotplug.enabled)
+		acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+					   acpi_hotplug_notify_cb);
+	else
+		acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+					    acpi_hotplug_notify_cb, NULL);
+
+	return AE_OK;
+}
+
+void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val)
+{
+	struct acpi_scan_handler *handler;
+
+	if (!!hotplug->enabled == !!val)
+		return;
+
+	mutex_lock(&acpi_scan_lock);
+
+	hotplug->enabled = val;
+	handler = container_of(hotplug, struct acpi_scan_handler, hotplug);
+	acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
+			    acpi_scan_hotplug_modify, NULL, handler, NULL);
+
+	mutex_unlock(&acpi_scan_lock);
+}
+
+void acpi_scan_hotplug_uevents(struct acpi_hotplug_profile *hotplug, bool val)
+{
+	mutex_lock(&acpi_scan_lock);
+	hotplug->uevents = val;
+	mutex_unlock(&acpi_scan_lock);
+}
+
+void acpi_scan_hotplug_autoeject(struct acpi_hotplug_profile *hotplug, bool val)
+{
+	mutex_lock(&acpi_scan_lock);
+	hotplug->autoeject = val;
+	mutex_unlock(&acpi_scan_lock);
+}
+
 static struct acpi_scan_handler *acpi_scan_match_handler(char *idstr,
 					const struct acpi_device_id **matchid)
 {
Index: test/Documentation/ABI/testing/sysfs-firmware-acpi
===================================================================
--- test.orig/Documentation/ABI/testing/sysfs-firmware-acpi
+++ test/Documentation/ABI/testing/sysfs-firmware-acpi
@@ -18,6 +18,48 @@ Description:
 		yoffset: The number of pixels between the top of the screen
 			 and the top edge of the image.
 
+What:		/sys/firmware/acpi/hotplug/
+Date:		February 2013
+Contact:	Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Description:
+		There are separate hotplug profiles for different classes of
+		devices supported by ACPI, such as containers, memory modules,
+		processors, PCI root bridges etc.  A hotplug profile for a given
+		class of devices is a collection of settings defining the way
+		that class of devices will be handled by the ACPI core hotplug
+		code.  Those profiles are represented in sysfs as subdirectories
+		of /sys/firmware/acpi/hotplug/.
+
+		The following settings are available for each hotplug profile:
+
+		enabled: If set, the ACPI core will handle notifications of
+			hotplug events associated with the given class of
+			devices and will allow those devices to be ejected with
+			the help of the _EJ0 control method.  Unsetting it
+			effectively disables hotplug for the correspoinding
+			class of devices.
+
+		uevents: If set, the ACPI core will emit a KOBJ_ONLINE uevent
+			after a successful namespace scan for a device of the
+			given class resulting from a "bus check" or "device
+			check" firmware notification.  It also will emit a
+			KOBJ_OFFLINE uevent upon receiving an eject request from
+			the platform firmware for a device node of the given
+			class.  If unset, no uevents related to hotplug will be
+			emitted for devices of the given class.
+
+		autoeject: If set, the ACPI core will automatically carry out
+			a namespace trim operation and will attempt to execute
+			_EJ0 after receiving an eject request from the platform
+			firmware for a device node of the given class.  If
+			unset, user space will have to trigger ejects directly
+			using the 'eject' attributes of the device nodes to be
+			ejected.
+
+		The values of all of the above attributes are integer numbers:
+		1 (set) or 0 (unset).  Attempts to write any other values to
+		them will cause -EINVAL to be returned.
+
 What:		/sys/firmware/acpi/interrupts/
 Date:		February 2008
 Contact:	Len Brown <lenb@kernel.org>

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH 6/7] ACPI / container: Use hotplug profile user space interface
  2013-02-17 15:18 [PATCH 0/7] ACPI / hotplug: Common code for ACPI-based hotplug Rafael J. Wysocki
                   ` (4 preceding siblings ...)
  2013-02-17 15:24 ` [PATCH 5/7] ACPI / hotplug: Introduce user space interface for hotplug profiles Rafael J. Wysocki
@ 2013-02-17 15:25 ` Rafael J. Wysocki
  2013-02-17 15:27 ` [PATCH 7/7] ACPI / scan: Make memory hotplug driver use struct acpi_scan_handler Rafael J. Wysocki
  2013-02-26 22:41 ` [PATCH v2, 0/7] ACPI / hotplug: Common code for ACPI-based hotplug Rafael J. Wysocki
  7 siblings, 0 replies; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-17 15:25 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Yinghai Lu, Toshi Kani, Yasuaki Ishimatsu,
	Jiang Liu

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Make the ACPI container driver register its ACPI scan handler object
using acpi_scan_add_handler_with_hotplug() to allow user space to
manipulate its hotplug profile attributes.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/acpi/container.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

Index: test/drivers/acpi/container.c
===================================================================
--- test.orig/drivers/acpi/container.c
+++ test/drivers/acpi/container.c
@@ -49,7 +49,7 @@ static int container_device_attach(struc
 	return 1;
 }
 
-static struct acpi_scan_handler container_device_handler = {
+static struct acpi_scan_handler container_handler = {
 	.ids = container_device_ids,
 	.attach = container_device_attach,
 	.hotplug = {
@@ -60,5 +60,5 @@ static struct acpi_scan_handler containe
 
 void __init acpi_container_init(void)
 {
-	acpi_scan_add_handler(&container_device_handler);
+	acpi_scan_add_handler_with_hotplug(&container_handler, "container");
 }

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH 7/7] ACPI / scan: Make memory hotplug driver use struct acpi_scan_handler
  2013-02-17 15:18 [PATCH 0/7] ACPI / hotplug: Common code for ACPI-based hotplug Rafael J. Wysocki
                   ` (5 preceding siblings ...)
  2013-02-17 15:25 ` [PATCH 6/7] ACPI / container: Use hotplug profile user space interface Rafael J. Wysocki
@ 2013-02-17 15:27 ` Rafael J. Wysocki
  2013-02-19 18:11   ` Vasilis Liaskovitis
  2013-02-26 22:41 ` [PATCH v2, 0/7] ACPI / hotplug: Common code for ACPI-based hotplug Rafael J. Wysocki
  7 siblings, 1 reply; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-17 15:27 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Yinghai Lu, Toshi Kani, Yasuaki Ishimatsu,
	Jiang Liu

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Make the ACPI memory hotplug driver use struct acpi_scan_handler
for representing the object used to set up ACPI memory hotplug
functionality and to remove hotplug memory ranges and data
structures used by the driver before unregistering ACPI device
nodes representing memory.  Register the new struct acpi_scan_handler
object with the help of acpi_scan_add_handler_with_hotplug() to allow
user space to manipulate the attributes of the memory hotplug
profile.

This results in a significant reduction of the drvier's code size
and removes some ACPI hotplug code duplication.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/acpi/Kconfig           |    3 
 drivers/acpi/acpi_memhotplug.c |  310 +++++------------------------------------
 drivers/acpi/internal.h        |    5 
 drivers/acpi/scan.c            |    1 
 4 files changed, 46 insertions(+), 273 deletions(-)

Index: test/drivers/acpi/Kconfig
===================================================================
--- test.orig/drivers/acpi/Kconfig
+++ test/drivers/acpi/Kconfig
@@ -350,9 +350,8 @@ config ACPI_CONTAINER
 	  the module will be called container.
 
 config ACPI_HOTPLUG_MEMORY
-	tristate "Memory Hotplug"
+	bool "Memory Hotplug"
 	depends on MEMORY_HOTPLUG
-	default n
 	help
 	  This driver supports ACPI memory hotplug.  The driver
 	  fields notifications on ACPI memory devices (PNP0C80),
Index: test/drivers/acpi/acpi_memhotplug.c
===================================================================
--- test.orig/drivers/acpi/acpi_memhotplug.c
+++ test/drivers/acpi/acpi_memhotplug.c
@@ -1,5 +1,7 @@
 /*
- * Copyright (C) 2004 Intel Corporation <naveen.b.s@intel.com>
+ * Copyright (C) 2004, 2013 Intel Corporation
+ * Author: Naveen B S <naveen.b.s@intel.com>
+ * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
  *
  * All rights reserved.
  *
@@ -25,14 +27,10 @@
  * ranges.
  */
 
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/memory_hotplug.h>
-#include <linux/slab.h>
 #include <linux/acpi.h>
-#include <acpi/acpi_drivers.h>
+#include <linux/memory_hotplug.h>
+
+#include "internal.h"
 
 #define ACPI_MEMORY_DEVICE_CLASS		"memory"
 #define ACPI_MEMORY_DEVICE_HID			"PNP0C80"
@@ -44,32 +42,29 @@
 #define 	PREFIX		"ACPI:memory_hp:"
 
 ACPI_MODULE_NAME("acpi_memhotplug");
-MODULE_AUTHOR("Naveen B S <naveen.b.s@intel.com>");
-MODULE_DESCRIPTION("Hotplug Mem Driver");
-MODULE_LICENSE("GPL");
 
 /* Memory Device States */
 #define MEMORY_INVALID_STATE	0
 #define MEMORY_POWER_ON_STATE	1
 #define MEMORY_POWER_OFF_STATE	2
 
-static int acpi_memory_device_add(struct acpi_device *device);
-static int acpi_memory_device_remove(struct acpi_device *device);
+static int acpi_memory_device_add(struct acpi_device *device,
+				  const struct acpi_device_id *not_used);
+static void acpi_memory_device_remove(struct acpi_device *device);
 
 static const struct acpi_device_id memory_device_ids[] = {
 	{ACPI_MEMORY_DEVICE_HID, 0},
 	{"", 0},
 };
-MODULE_DEVICE_TABLE(acpi, memory_device_ids);
 
-static struct acpi_driver acpi_memory_device_driver = {
-	.name = "acpi_memhotplug",
-	.class = ACPI_MEMORY_DEVICE_CLASS,
+static struct acpi_scan_handler memory_device_handler = {
 	.ids = memory_device_ids,
-	.ops = {
-		.add = acpi_memory_device_add,
-		.remove = acpi_memory_device_remove,
-		},
+	.attach = acpi_memory_device_add,
+	.detach = acpi_memory_device_remove,
+	.hotplug = {
+		.enabled = true,
+		.autoeject = true,
+	},
 };
 
 struct acpi_memory_info {
@@ -153,48 +148,6 @@ acpi_memory_get_device_resources(struct
 	return 0;
 }
 
-static int acpi_memory_get_device(acpi_handle handle,
-				  struct acpi_memory_device **mem_device)
-{
-	struct acpi_device *device = NULL;
-	int result = 0;
-
-	acpi_scan_lock_acquire();
-
-	acpi_bus_get_device(handle, &device);
-	if (device)
-		goto end;
-
-	/*
-	 * Now add the notified device.  This creates the acpi_device
-	 * and invokes .add function
-	 */
-	result = acpi_bus_scan(handle);
-	if (result) {
-		acpi_handle_warn(handle, "ACPI namespace scan failed\n");
-		result = -EINVAL;
-		goto out;
-	}
-	result = acpi_bus_get_device(handle, &device);
-	if (result) {
-		acpi_handle_warn(handle, "Missing device object\n");
-		result = -EINVAL;
-		goto out;
-	}
-
- end:
-	*mem_device = acpi_driver_data(device);
-	if (!(*mem_device)) {
-		dev_err(&device->dev, "driver data not found\n");
-		result = -ENODEV;
-		goto out;
-	}
-
- out:
-	acpi_scan_lock_release();
-	return result;
-}
-
 static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
 {
 	unsigned long long current_status;
@@ -306,95 +259,21 @@ static int acpi_memory_remove_memory(str
 	return result;
 }
 
-static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
-{
-	struct acpi_memory_device *mem_device;
-	struct acpi_device *device;
-	struct acpi_eject_event *ej_event = NULL;
-	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
-	acpi_status status;
-
-	switch (event) {
-	case ACPI_NOTIFY_BUS_CHECK:
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-				  "\nReceived BUS CHECK notification for device\n"));
-		/* Fall Through */
-	case ACPI_NOTIFY_DEVICE_CHECK:
-		if (event == ACPI_NOTIFY_DEVICE_CHECK)
-			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-					  "\nReceived DEVICE CHECK notification for device\n"));
-		if (acpi_memory_get_device(handle, &mem_device)) {
-			acpi_handle_err(handle, "Cannot find driver data\n");
-			break;
-		}
-
-		ost_code = ACPI_OST_SC_SUCCESS;
-		break;
-
-	case ACPI_NOTIFY_EJECT_REQUEST:
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-				  "\nReceived EJECT REQUEST notification for device\n"));
-
-		status = AE_ERROR;
-		acpi_scan_lock_acquire();
-
-		if (acpi_bus_get_device(handle, &device)) {
-			acpi_handle_err(handle, "Device doesn't exist\n");
-			goto unlock;
-		}
-		mem_device = acpi_driver_data(device);
-		if (!mem_device) {
-			acpi_handle_err(handle, "Driver Data is NULL\n");
-			goto unlock;
-		}
-
-		ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
-		if (!ej_event) {
-			pr_err(PREFIX "No memory, dropping EJECT\n");
-			goto unlock;
-		}
-
-		get_device(&device->dev);
-		ej_event->device = device;
-		ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
-		/* The eject is carried out asynchronously. */
-		status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
-						 ej_event);
-		if (ACPI_FAILURE(status)) {
-			put_device(&device->dev);
-			kfree(ej_event);
-		}
-
- unlock:
-		acpi_scan_lock_release();
-		if (ACPI_SUCCESS(status))
-			return;
-	default:
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-				  "Unsupported event [0x%x]\n", event));
-
-		/* non-hotplug event; possibly handled by other handler */
-		return;
-	}
-
-	/* Inform firmware that the hotplug operation has completed */
-	(void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL);
-}
-
 static void acpi_memory_device_free(struct acpi_memory_device *mem_device)
 {
 	if (!mem_device)
 		return;
 
 	acpi_memory_free_device_resources(mem_device);
+	mem_device->device->driver_data = NULL;
 	kfree(mem_device);
 }
 
-static int acpi_memory_device_add(struct acpi_device *device)
+static int acpi_memory_device_add(struct acpi_device *device,
+				  const struct acpi_device_id *not_used)
 {
+	struct acpi_memory_device *mem_device;
 	int result;
-	struct acpi_memory_device *mem_device = NULL;
-
 
 	if (!device)
 		return -EINVAL;
@@ -419,147 +298,36 @@ static int acpi_memory_device_add(struct
 	/* Set the device state */
 	mem_device->state = MEMORY_POWER_ON_STATE;
 
-	pr_debug("%s\n", acpi_device_name(device));
+	result = acpi_memory_check_device(mem_device);
+	if (result) {
+		acpi_memory_device_free(mem_device);
+		return 0;
+	}
 
-	if (!acpi_memory_check_device(mem_device)) {
-		/* call add_memory func */
-		result = acpi_memory_enable_device(mem_device);
-		if (result) {
-			dev_err(&device->dev,
-				"Error in acpi_memory_enable_device\n");
-			acpi_memory_device_free(mem_device);
-		}
+	result = acpi_memory_enable_device(mem_device);
+	if (result) {
+		dev_err(&device->dev, "acpi_memory_enable_device() error\n");
+		acpi_memory_device_free(mem_device);
+		return -ENODEV;
 	}
-	return result;
+
+	dev_dbg(&device->dev, "Memory device configured by ACPI\n");
+	return 1;
 }
 
-static int acpi_memory_device_remove(struct acpi_device *device)
+static void acpi_memory_device_remove(struct acpi_device *device)
 {
-	struct acpi_memory_device *mem_device = NULL;
-	int result;
+	struct acpi_memory_device *mem_device;
 
 	if (!device || !acpi_driver_data(device))
-		return -EINVAL;
+		return;
 
 	mem_device = acpi_driver_data(device);
-
-	result = acpi_memory_remove_memory(mem_device);
-	if (result)
-		return result;
-
+	acpi_memory_remove_memory(mem_device);
 	acpi_memory_device_free(mem_device);
-
-	return 0;
-}
-
-/*
- * Helper function to check for memory device
- */
-static acpi_status is_memory_device(acpi_handle handle)
-{
-	char *hardware_id;
-	acpi_status status;
-	struct acpi_device_info *info;
-
-	status = acpi_get_object_info(handle, &info);
-	if (ACPI_FAILURE(status))
-		return status;
-
-	if (!(info->valid & ACPI_VALID_HID)) {
-		kfree(info);
-		return AE_ERROR;
-	}
-
-	hardware_id = info->hardware_id.string;
-	if ((hardware_id == NULL) ||
-	    (strcmp(hardware_id, ACPI_MEMORY_DEVICE_HID)))
-		status = AE_ERROR;
-
-	kfree(info);
-	return status;
-}
-
-static acpi_status
-acpi_memory_register_notify_handler(acpi_handle handle,
-				    u32 level, void *ctxt, void **retv)
-{
-	acpi_status status;
-
-
-	status = is_memory_device(handle);
-	if (ACPI_FAILURE(status))
-		return AE_OK;	/* continue */
-
-	status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
-					     acpi_memory_device_notify, NULL);
-	/* continue */
-	return AE_OK;
-}
-
-static acpi_status
-acpi_memory_deregister_notify_handler(acpi_handle handle,
-				      u32 level, void *ctxt, void **retv)
-{
-	acpi_status status;
-
-
-	status = is_memory_device(handle);
-	if (ACPI_FAILURE(status))
-		return AE_OK;	/* continue */
-
-	status = acpi_remove_notify_handler(handle,
-					    ACPI_SYSTEM_NOTIFY,
-					    acpi_memory_device_notify);
-
-	return AE_OK;	/* continue */
-}
-
-static int __init acpi_memory_device_init(void)
-{
-	int result;
-	acpi_status status;
-
-
-	result = acpi_bus_register_driver(&acpi_memory_device_driver);
-
-	if (result < 0)
-		return -ENODEV;
-
-	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
-				     ACPI_UINT32_MAX,
-				     acpi_memory_register_notify_handler, NULL,
-				     NULL, NULL);
-
-	if (ACPI_FAILURE(status)) {
-		ACPI_EXCEPTION((AE_INFO, status, "walk_namespace failed"));
-		acpi_bus_unregister_driver(&acpi_memory_device_driver);
-		return -ENODEV;
-	}
-
-	return 0;
 }
 
-static void __exit acpi_memory_device_exit(void)
+void __init acpi_memory_hotplug_init(void)
 {
-	acpi_status status;
-
-
-	/*
-	 * Adding this to un-install notification handlers for all the device
-	 * handles.
-	 */
-	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
-				     ACPI_UINT32_MAX,
-				     acpi_memory_deregister_notify_handler, NULL,
-				     NULL, NULL);
-
-	if (ACPI_FAILURE(status))
-		ACPI_EXCEPTION((AE_INFO, status, "walk_namespace failed"));
-
-	acpi_bus_unregister_driver(&acpi_memory_device_driver);
-
-	return;
+	acpi_scan_add_handler_with_hotplug(&memory_device_handler, "memory");
 }
-
-module_init(acpi_memory_device_init);
-module_exit(acpi_memory_device_exit);
Index: test/drivers/acpi/internal.h
===================================================================
--- test.orig/drivers/acpi/internal.h
+++ test/drivers/acpi/internal.h
@@ -35,6 +35,11 @@ void acpi_container_init(void);
 #else
 static inline void acpi_container_init(void) {}
 #endif
+#ifdef CONFIG_ACPI_HOTPLUG_MEMORY
+void acpi_memory_hotplug_init(void);
+#else
+static inline void acpi_memory_hotplug_init(void) {}
+#endif
 
 void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug,
 				    const char *name);
Index: test/drivers/acpi/scan.c
===================================================================
--- test.orig/drivers/acpi/scan.c
+++ test/drivers/acpi/scan.c
@@ -2024,6 +2024,7 @@ int __init acpi_scan_init(void)
 	acpi_platform_init();
 	acpi_csrt_init();
 	acpi_container_init();
+	acpi_memory_hotplug_init();
 
 	mutex_lock(&acpi_scan_lock);
 	/*


^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-17 15:21 ` [PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug Rafael J. Wysocki
@ 2013-02-19  6:43   ` Yasuaki Ishimatsu
  2013-02-19  7:10     ` Yasuaki Ishimatsu
  2013-02-20 13:23     ` Rafael J. Wysocki
  2013-02-20 22:49   ` [Update][PATCH " Rafael J. Wysocki
  1 sibling, 2 replies; 69+ messages in thread
From: Yasuaki Ishimatsu @ 2013-02-19  6:43 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Yinghai Lu,
	Toshi Kani, Jiang Liu

Hi Rafael,

I have comments. Please see below.

2013/02/18 0:21, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>
> Multiple drivers handling hotplug-capable ACPI device nodes install
> notify handlers covering the same types of events in a very similar
> way.  Moreover, those handlers are installed in separate namespace
> walks, although that really should be done during namespace scans
> carried out by acpi_bus_scan().  This leads to substantial code
> duplication, unnecessary overhead and behavior that is hard to
> follow.
>
> For this reason, introduce common code in drivers/acpi/scan.c for
> handling hotplug-related notification and carrying out device
> insertion and eject operations in a generic fashion, such that it
> may be used by all of the relevant drivers in the future.  To cover
> the existing differences between those drivers introduce struct
> acpi_hotplug_profile for representing collections of hotplug
> settings associated with different ACPI scan handlers that can be
> used by the drivers to make the common code reflect their current
> behavior.
>
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> ---
>   drivers/acpi/scan.c     |  271 +++++++++++++++++++++++++++++++++++++-----------
>   include/acpi/acpi_bus.h |    7 +
>   2 files changed, 220 insertions(+), 58 deletions(-)
>
> Index: test/include/acpi/acpi_bus.h
> ===================================================================
> --- test.orig/include/acpi/acpi_bus.h
> +++ test/include/acpi/acpi_bus.h
> @@ -88,11 +88,18 @@ struct acpi_device;
>    * -----------------
>    */
>
> +struct acpi_hotplug_profile {
> +	bool enabled:1;
> +	bool uevents:1;
> +	bool autoeject:1;
> +};
> +
>   struct acpi_scan_handler {
>   	const struct acpi_device_id *ids;
>   	struct list_head list_node;
>   	int (*attach)(struct acpi_device *dev, const struct acpi_device_id *id);
>   	void (*detach)(struct acpi_device *dev);
> +	struct acpi_hotplug_profile hotplug;
>   };
>
>   /*
> Index: test/drivers/acpi/scan.c
> ===================================================================
> --- test.orig/drivers/acpi/scan.c
> +++ test/drivers/acpi/scan.c
> @@ -107,32 +107,19 @@ acpi_device_modalias_show(struct device
>   }
>   static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
>
> -/**
> - * acpi_bus_hot_remove_device: hot-remove a device and its children
> - * @context: struct acpi_eject_event pointer (freed in this func)
> - *
> - * Hot-remove a device and its children. This function frees up the
> - * memory space passed by arg context, so that the caller may call
> - * this function asynchronously through acpi_os_hotplug_execute().
> - */
> -void acpi_bus_hot_remove_device(void *context)
> +static int acpi_scan_hot_remove(struct acpi_device *device)
>   {
> -	struct acpi_eject_event *ej_event = context;
> -	struct acpi_device *device = ej_event->device;
>   	acpi_handle handle = device->handle;
> -	acpi_handle temp;
> +	acpi_handle not_used;
>   	struct acpi_object_list arg_list;
>   	union acpi_object arg;
> -	acpi_status status = AE_OK;
> -	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
> -
> -	mutex_lock(&acpi_scan_lock);
> +	acpi_status status;
>
>   	/* If there is no handle, the device node has been unregistered. */
> -	if (!device->handle) {
> +	if (!handle) {
>   		dev_dbg(&device->dev, "ACPI handle missing\n");
>   		put_device(&device->dev);
> -		goto out;
> +		return -EINVAL;
>   	}
>
>   	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
> @@ -143,7 +130,7 @@ void acpi_bus_hot_remove_device(void *co
>   	put_device(&device->dev);
>   	device = NULL;
>
> -	if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &temp))) {
> +	if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &not_used))) {
>   		arg_list.count = 1;
>   		arg_list.pointer = &arg;
>   		arg.type = ACPI_TYPE_INTEGER;
> @@ -161,18 +148,162 @@ void acpi_bus_hot_remove_device(void *co
>   	 */
>   	status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
>   	if (ACPI_FAILURE(status)) {
> -		if (status != AE_NOT_FOUND)
> +		if (status == AE_NOT_FOUND) {
> +			return -ENODEV;
> +		} else {
>   			acpi_handle_warn(handle, "Eject failed\n");
> +			return -EIO;
> +		}
> +	}
> +	return 0;
> +}
> +
> +static void acpi_bus_device_eject(void *context)
> +{
> +	acpi_handle handle = context;
> +	struct acpi_device *device = NULL;
> +	struct acpi_scan_handler *handler;
> +	u32 ost_source = ACPI_NOTIFY_EJECT_REQUEST;
> +	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
> +
> +	mutex_lock(&acpi_scan_lock);
>
> -		/* Tell the firmware the hot-remove operation has failed. */
> -		acpi_evaluate_hotplug_ost(handle, ej_event->event,
> -					  ost_code, NULL);
> +	acpi_bus_get_device(handle, &device);
> +	if (!device)
> +		goto out;
> +
> +	handler = device->handler;
> +	if (!handler || !handler->hotplug.enabled) {
> +		ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
> +		goto out;
>   	}
> +	acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
> +				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);

> +	if (handler->hotplug.uevents)
> +		kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
> +
> +	if (handler->hotplug.autoeject) {
> +		int error;
> +
> +		ost_source = ACPI_OST_EC_OSPM_EJECT;
> +		get_device(&device->dev);
> +		error = acpi_scan_hot_remove(device);
> +		if (!error)
> +			ost_code = ACPI_OST_SC_SUCCESS;
> +	} else {
> +		device->flags.eject_pending = true;
> +		goto out_unlock;
> +	}

I want you to change the order of uevents and autoeject.
When user caught OFFLINE event, user thinks devices were removed.
But it is not guaranteed in this code since acpi_scan_hot_remove() may
be running.

> +
> + out:
> +	acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL);
> +
> + out_unlock:
> +	mutex_unlock(&acpi_scan_lock);
> +}
> +
> +static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
> +{
> +	struct acpi_device *device = NULL;
> +	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
> +	int error;
> +
> +	mutex_lock(&acpi_scan_lock);
> +
> +	acpi_bus_get_device(handle, &device);
> +	if (device) {
> +		dev_warn(&device->dev, "Attempt to re-insert\n");
> +		goto out;
> +	}
> +	acpi_evaluate_hotplug_ost(handle, ost_source,
> +				  ACPI_OST_SC_INSERT_IN_PROGRESS, NULL);
> +	ost_source = ACPI_OST_EC_OSPM_INSERTION;
> +	error = acpi_bus_scan(handle);
> +	if (error) {
> +		acpi_handle_warn(handle, "Namespace scan failure\n");
> +		goto out;
> +	}
> +	error = acpi_bus_get_device(handle, &device);
> +	if (error) {
> +		acpi_handle_warn(handle, "Missing device node object\n");
> +		goto out;
> +	}
> +	ost_code = ACPI_OST_SC_SUCCESS;
> +	if (device->handler && device->handler->hotplug.uevents)
> +		kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
>
>    out:
> +	acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL);
> +	mutex_unlock(&acpi_scan_lock);
> +}
> +
> +static void acpi_scan_bus_check(void *context)
> +{
> +	acpi_scan_bus_device_check((acpi_handle)context,
> +				   ACPI_NOTIFY_BUS_CHECK);
> +}
> +
> +static void acpi_scan_device_check(void *context)
> +{
> +	acpi_scan_bus_device_check((acpi_handle)context,
> +				   ACPI_NOTIFY_DEVICE_CHECK);
> +}
> +
> +static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *not_used)
> +{
> +	acpi_osd_exec_callback callback;
> +	acpi_status status;
> +
> +	switch (type) {
> +	case ACPI_NOTIFY_BUS_CHECK:
> +		acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
> +		callback = acpi_scan_bus_check;
> +		break;
> +	case ACPI_NOTIFY_DEVICE_CHECK:
> +		acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
> +		callback = acpi_scan_device_check;
> +		break;
> +	case ACPI_NOTIFY_EJECT_REQUEST:
> +		acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
> +		callback = acpi_bus_device_eject;
> +		break;
> +	default:
> +		/* non-hotplug event; possibly handled by other handler */
> +		return;
> +	}
> +	status = acpi_os_hotplug_execute(callback, handle);
> +	if (ACPI_FAILURE(status))
> +		acpi_evaluate_hotplug_ost(handle, type,
> +					  ACPI_OST_SC_NON_SPECIFIC_FAILURE,
> +					  NULL);
> +}
> +
> +/**
> + * acpi_bus_hot_remove_device: hot-remove a device and its children
> + * @context: struct acpi_eject_event pointer (freed in this func)
> + *
> + * Hot-remove a device and its children. This function frees up the
> + * memory space passed by arg context, so that the caller may call
> + * this function asynchronously through acpi_os_hotplug_execute().
> + */
> +void acpi_bus_hot_remove_device(void *context)
> +{
> +	struct acpi_eject_event *ej_event = context;
> +	struct acpi_device *device = ej_event->device;
> +	acpi_handle handle = device->handle;
> +	u32 ost_code = ACPI_OST_SC_SUCCESS;
> +	int error;
> +
> +	mutex_lock(&acpi_scan_lock);
> +
> +	error = acpi_scan_hot_remove(device);
> +	if (error)
> +		ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
> +
> +	acpi_evaluate_hotplug_ost(handle, ej_event->event, ost_code, NULL);
> +
>   	mutex_unlock(&acpi_scan_lock);
>   	kfree(context);
> -	return;
>   }
>   EXPORT_SYMBOL(acpi_bus_hot_remove_device);
>
> @@ -206,50 +337,48 @@ static ssize_t
>   acpi_eject_store(struct device *d, struct device_attribute *attr,
>   		const char *buf, size_t count)
>   {
> -	int ret = count;
> -	acpi_status status;
> -	acpi_object_type type = 0;
>   	struct acpi_device *acpi_device = to_acpi_device(d);
> -	struct acpi_eject_event *ej_event;
> +	acpi_object_type not_used;
> +	acpi_status status;
> +	u32 ost_source;
> +	u32 ost_code;
> +	int ret;
>
> -	if ((!count) || (buf[0] != '1')) {
> +	if (!count || buf[0] != '1')
>   		return -EINVAL;
> -	}
> -	if (!acpi_device->driver && !acpi_device->handler) {
> -		ret = -ENODEV;
> -		goto err;
> -	}
> -	status = acpi_get_type(acpi_device->handle, &type);
> -	if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) {
> -		ret = -ENODEV;
> -		goto err;
> -	}
>
> -	ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
> -	if (!ej_event) {
> -		ret = -ENOMEM;
> -		goto err;
> -	}
> +	if ((!acpi_device->handler || !acpi_device->handler->hotplug.enabled)
> +	    && !acpi_device->driver)
> +		return -ENODEV;
> +
> +	status = acpi_get_type(acpi_device->handle, &not_used);
> +	if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable)
> +		return -ENODEV;
> +
> +	mutex_lock(&acpi_scan_lock);
>
> -	get_device(&acpi_device->dev);
> -	ej_event->device = acpi_device;
>   	if (acpi_device->flags.eject_pending) {
> -		/* event originated from ACPI eject notification */
> -		ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
> +		/* ACPI eject notification event. */
> +		ost_source = ACPI_NOTIFY_EJECT_REQUEST;
>   		acpi_device->flags.eject_pending = 0;
>   	} else {
> -		/* event originated from user */
> -		ej_event->event = ACPI_OST_EC_OSPM_EJECT;
> -		(void) acpi_evaluate_hotplug_ost(acpi_device->handle,
> -			ej_event->event, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
> +		/* Eject initiated by user space. */
> +		ost_source = ACPI_OST_EC_OSPM_EJECT;
>   	}
> -

> -	status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event);
> -	if (ACPI_FAILURE(status)) {
> -		put_device(&acpi_device->dev);
> -		kfree(ej_event);
> +	acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source,
> +				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
> +	get_device(&acpi_device->dev);
> +	ret = acpi_scan_hot_remove(acpi_device);

Why don't you use acpi_os_hotplug_execute()? Do you have some reason?

Thanks,
Yasuaki Ishimatsu

> +	if (ret) {
> +		ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
> +	} else {
> +		ost_code = ACPI_OST_SC_SUCCESS;
> +		ret = count;
>   	}
> -err:
> +	acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT,
> +				  ost_code, NULL);
> +
> +	mutex_unlock(&acpi_scan_lock);
>   	return ret;
>   }
>
> @@ -1548,6 +1677,30 @@ static struct acpi_scan_handler *acpi_sc
>   	return NULL;
>   }
>
> +static void acpi_scan_init_hotplug(acpi_handle handle)
> +{
> +	struct acpi_device_info *info;
> +	struct acpi_scan_handler *handler;
> +
> +	if (ACPI_FAILURE(acpi_get_object_info(handle, &info)))
> +		return;
> +
> +	if (!(info->valid & ACPI_VALID_HID)) {
> +		kfree(info);
> +		return;
> +	}
> +
> +	/*
> +	 * This relies on the fact that acpi_install_notify_handler() will not
> +	 * install the same notify handler routine twice for the same handle.
> +	 */
> +	handler = acpi_scan_match_handler(info->hardware_id.string, NULL);
> +	kfree(info);
> +	if (handler && handler->hotplug.enabled)
> +		acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
> +					    acpi_hotplug_notify_cb, NULL);
> +}
> +
>   static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
>   				      void *not_used, void **return_value)
>   {
> @@ -1570,6 +1723,8 @@ static acpi_status acpi_bus_check_add(ac
>   		return AE_OK;
>   	}
>
> +	acpi_scan_init_hotplug(handle);
> +
>   	if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
>   	    !(sta & ACPI_STA_DEVICE_FUNCTIONING)) {
>   		struct acpi_device_wakeup wakeup;
>



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH 1/7] ACPI / scan: Introduce acpi_scan_match_handler()
  2013-02-17 15:20 ` [PATCH 1/7] ACPI / scan: Introduce acpi_scan_match_handler() Rafael J. Wysocki
@ 2013-02-19  6:48   ` Yasuaki Ishimatsu
  0 siblings, 0 replies; 69+ messages in thread
From: Yasuaki Ishimatsu @ 2013-02-19  6:48 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Yinghai Lu,
	Toshi Kani, Jiang Liu

2013/02/18 0:20, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>
> Introduce helper routine acpi_scan_match_handler() that will find the
> ACPI scan handler matching a given device ID, if there is one, and
> rework acpi_scan_attach_handler() to use the new routine (that
> routine will also be useful for other purposes going forward).
>
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> ---

Acked-by: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>

Thanks,
Yasuaki Ishimatsu

>   drivers/acpi/scan.c |   53 +++++++++++++++++++++++++++-------------------------
>   1 file changed, 28 insertions(+), 25 deletions(-)
>
> Index: test/drivers/acpi/scan.c
> ===================================================================
> --- test.orig/drivers/acpi/scan.c
> +++ test/drivers/acpi/scan.c
> @@ -1529,6 +1529,25 @@ static int acpi_bus_type_and_status(acpi
>   	return 0;
>   }
>
> +static struct acpi_scan_handler *acpi_scan_match_handler(char *idstr,
> +					const struct acpi_device_id **matchid)
> +{
> +	struct acpi_scan_handler *handler;
> +
> +	list_for_each_entry(handler, &acpi_scan_handlers_list, list_node) {
> +		const struct acpi_device_id *devid;
> +
> +		for (devid = handler->ids; devid->id[0]; devid++)
> +			if (!strcmp((char *)devid->id, idstr)) {
> +				if (matchid)
> +					*matchid = devid;
> +
> +				return handler;
> +			}
> +	}
> +	return NULL;
> +}
> +
>   static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
>   				      void *not_used, void **return_value)
>   {
> @@ -1576,42 +1595,26 @@ static acpi_status acpi_bus_check_add(ac
>   	return AE_OK;
>   }
>
> -static int acpi_scan_do_attach_handler(struct acpi_device *device, char *id)
> +static int acpi_scan_attach_handler(struct acpi_device *device)
>   {
> -	struct acpi_scan_handler *handler;
> +	struct acpi_hardware_id *hwid;
> +	int ret = 0;
>
> -	list_for_each_entry(handler, &acpi_scan_handlers_list, list_node) {
> +	list_for_each_entry(hwid, &device->pnp.ids, list) {
>   		const struct acpi_device_id *devid;
> +		struct acpi_scan_handler *handler;
>
> -		for (devid = handler->ids; devid->id[0]; devid++) {
> -			int ret;
> -
> -			if (strcmp((char *)devid->id, id))
> -				continue;
> -
> +		handler = acpi_scan_match_handler(hwid->id, &devid);
> +		if (handler) {
>   			ret = handler->attach(device, devid);
>   			if (ret > 0) {
>   				device->handler = handler;
> -				return ret;
> +				break;
>   			} else if (ret < 0) {
> -				return ret;
> +				break;
>   			}
>   		}
>   	}
> -	return 0;
> -}
> -
> -static int acpi_scan_attach_handler(struct acpi_device *device)
> -{
> -	struct acpi_hardware_id *hwid;
> -	int ret = 0;
> -
> -	list_for_each_entry(hwid, &device->pnp.ids, list) {
> -		ret = acpi_scan_do_attach_handler(device, hwid->id);
> -		if (ret)
> -			break;
> -
> -	}
>   	return ret;
>   }
>
>



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-19  6:43   ` Yasuaki Ishimatsu
@ 2013-02-19  7:10     ` Yasuaki Ishimatsu
  2013-02-20 13:27       ` Rafael J. Wysocki
  2013-02-20 13:23     ` Rafael J. Wysocki
  1 sibling, 1 reply; 69+ messages in thread
From: Yasuaki Ishimatsu @ 2013-02-19  7:10 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Yinghai Lu,
	Toshi Kani, Jiang Liu

2013/02/19 15:43, Yasuaki Ishimatsu wrote:
> Hi Rafael,
>
> I have comments. Please see below.
>
> 2013/02/18 0:21, Rafael J. Wysocki wrote:
>> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>>
>> Multiple drivers handling hotplug-capable ACPI device nodes install
>> notify handlers covering the same types of events in a very similar
>> way.  Moreover, those handlers are installed in separate namespace
>> walks, although that really should be done during namespace scans
>> carried out by acpi_bus_scan().  This leads to substantial code
>> duplication, unnecessary overhead and behavior that is hard to
>> follow.
>>
>> For this reason, introduce common code in drivers/acpi/scan.c for
>> handling hotplug-related notification and carrying out device
>> insertion and eject operations in a generic fashion, such that it
>> may be used by all of the relevant drivers in the future.  To cover
>> the existing differences between those drivers introduce struct
>> acpi_hotplug_profile for representing collections of hotplug
>> settings associated with different ACPI scan handlers that can be
>> used by the drivers to make the common code reflect their current
>> behavior.
>>
>> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>> ---
>>   drivers/acpi/scan.c     |  271 +++++++++++++++++++++++++++++++++++++-----------
>>   include/acpi/acpi_bus.h |    7 +
>>   2 files changed, 220 insertions(+), 58 deletions(-)
>>
>> Index: test/include/acpi/acpi_bus.h
>> ===================================================================
>> --- test.orig/include/acpi/acpi_bus.h
>> +++ test/include/acpi/acpi_bus.h
>> @@ -88,11 +88,18 @@ struct acpi_device;
>>    * -----------------
>>    */
>>
>> +struct acpi_hotplug_profile {
>> +    bool enabled:1;
>> +    bool uevents:1;
>> +    bool autoeject:1;
>> +};
>> +
>>   struct acpi_scan_handler {
>>       const struct acpi_device_id *ids;
>>       struct list_head list_node;
>>       int (*attach)(struct acpi_device *dev, const struct acpi_device_id *id);
>>       void (*detach)(struct acpi_device *dev);
>> +    struct acpi_hotplug_profile hotplug;
>>   };
>>
>>   /*
>> Index: test/drivers/acpi/scan.c
>> ===================================================================
>> --- test.orig/drivers/acpi/scan.c
>> +++ test/drivers/acpi/scan.c
>> @@ -107,32 +107,19 @@ acpi_device_modalias_show(struct device
>>   }
>>   static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
>>
>> -/**
>> - * acpi_bus_hot_remove_device: hot-remove a device and its children
>> - * @context: struct acpi_eject_event pointer (freed in this func)
>> - *
>> - * Hot-remove a device and its children. This function frees up the
>> - * memory space passed by arg context, so that the caller may call
>> - * this function asynchronously through acpi_os_hotplug_execute().
>> - */
>> -void acpi_bus_hot_remove_device(void *context)
>> +static int acpi_scan_hot_remove(struct acpi_device *device)
>>   {
>> -    struct acpi_eject_event *ej_event = context;
>> -    struct acpi_device *device = ej_event->device;
>>       acpi_handle handle = device->handle;
>> -    acpi_handle temp;
>> +    acpi_handle not_used;
>>       struct acpi_object_list arg_list;
>>       union acpi_object arg;
>> -    acpi_status status = AE_OK;
>> -    u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
>> -
>> -    mutex_lock(&acpi_scan_lock);
>> +    acpi_status status;
>>
>>       /* If there is no handle, the device node has been unregistered. */
>> -    if (!device->handle) {
>> +    if (!handle) {
>>           dev_dbg(&device->dev, "ACPI handle missing\n");
>>           put_device(&device->dev);
>> -        goto out;
>> +        return -EINVAL;
>>       }
>>
>>       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
>> @@ -143,7 +130,7 @@ void acpi_bus_hot_remove_device(void *co
>>       put_device(&device->dev);
>>       device = NULL;
>>
>> -    if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &temp))) {
>> +    if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &not_used))) {
>>           arg_list.count = 1;
>>           arg_list.pointer = &arg;
>>           arg.type = ACPI_TYPE_INTEGER;
>> @@ -161,18 +148,162 @@ void acpi_bus_hot_remove_device(void *co
>>        */
>>       status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
>>       if (ACPI_FAILURE(status)) {
>> -        if (status != AE_NOT_FOUND)
>> +        if (status == AE_NOT_FOUND) {
>> +            return -ENODEV;
>> +        } else {
>>               acpi_handle_warn(handle, "Eject failed\n");
>> +            return -EIO;
>> +        }
>> +    }
>> +    return 0;
>> +}
>> +
>> +static void acpi_bus_device_eject(void *context)
>> +{
>> +    acpi_handle handle = context;
>> +    struct acpi_device *device = NULL;
>> +    struct acpi_scan_handler *handler;
>> +    u32 ost_source = ACPI_NOTIFY_EJECT_REQUEST;
>> +    u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
>> +
>> +    mutex_lock(&acpi_scan_lock);
>>
>> -        /* Tell the firmware the hot-remove operation has failed. */
>> -        acpi_evaluate_hotplug_ost(handle, ej_event->event,
>> -                      ost_code, NULL);
>> +    acpi_bus_get_device(handle, &device);
>> +    if (!device)
>> +        goto out;
>> +
>> +    handler = device->handler;
>> +    if (!handler || !handler->hotplug.enabled) {
>> +        ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
>> +        goto out;
>>       }
>> +    acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
>> +                  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
>
>> +    if (handler->hotplug.uevents)
>> +        kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
>> +
>> +    if (handler->hotplug.autoeject) {
>> +        int error;
>> +
>> +        ost_source = ACPI_OST_EC_OSPM_EJECT;
>> +        get_device(&device->dev);
>> +        error = acpi_scan_hot_remove(device);
>> +        if (!error)
>> +            ost_code = ACPI_OST_SC_SUCCESS;
>> +    } else {
>> +        device->flags.eject_pending = true;
>> +        goto out_unlock;
>> +    }
>
> I want you to change the order of uevents and autoeject.
> When user caught OFFLINE event, user thinks devices were removed.
> But it is not guaranteed in this code since acpi_scan_hot_remove() may
> be running.
>
>> +
>> + out:
>> +    acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL);
>> +
>> + out_unlock:
>> +    mutex_unlock(&acpi_scan_lock);
>> +}
>> +

>> +static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
>> +{
>> +    struct acpi_device *device = NULL;
>> +    u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
>> +    int error;
>> +
>> +    mutex_lock(&acpi_scan_lock);
>> +
>> +    acpi_bus_get_device(handle, &device);
>> +    if (device) {
>> +        dev_warn(&device->dev, "Attempt to re-insert\n");
>> +        goto out;
>> +    }
>> +    acpi_evaluate_hotplug_ost(handle, ost_source,
>> +                  ACPI_OST_SC_INSERT_IN_PROGRESS, NULL);
>> +    ost_source = ACPI_OST_EC_OSPM_INSERTION;
>> +    error = acpi_bus_scan(handle);
>> +    if (error) {
>> +        acpi_handle_warn(handle, "Namespace scan failure\n");
>> +        goto out;
>> +    }
>> +    error = acpi_bus_get_device(handle, &device);
>> +    if (error) {
>> +        acpi_handle_warn(handle, "Missing device node object\n");
>> +        goto out;
>> +    }
>> +    ost_code = ACPI_OST_SC_SUCCESS;
>> +    if (device->handler && device->handler->hotplug.uevents)
>> +        kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
>>
>>    out:
>> +    acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL);
>> +    mutex_unlock(&acpi_scan_lock);
>> +}

Why don't you check _STA method in acpi_scan_bus_device_check()?
When hot adding new device, we must check _STA method of the device.

Thanks,
Yasuaki Ishimatsu

>> +
>> +static void acpi_scan_bus_check(void *context)
>> +{
>> +    acpi_scan_bus_device_check((acpi_handle)context,
>> +                   ACPI_NOTIFY_BUS_CHECK);
>> +}
>> +
>> +static void acpi_scan_device_check(void *context)
>> +{
>> +    acpi_scan_bus_device_check((acpi_handle)context,
>> +                   ACPI_NOTIFY_DEVICE_CHECK);
>> +}
>> +
>> +static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *not_used)
>> +{
>> +    acpi_osd_exec_callback callback;
>> +    acpi_status status;
>> +
>> +    switch (type) {
>> +    case ACPI_NOTIFY_BUS_CHECK:
>> +        acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
>> +        callback = acpi_scan_bus_check;
>> +        break;
>> +    case ACPI_NOTIFY_DEVICE_CHECK:
>> +        acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
>> +        callback = acpi_scan_device_check;
>> +        break;
>> +    case ACPI_NOTIFY_EJECT_REQUEST:
>> +        acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
>> +        callback = acpi_bus_device_eject;
>> +        break;
>> +    default:
>> +        /* non-hotplug event; possibly handled by other handler */
>> +        return;
>> +    }
>> +    status = acpi_os_hotplug_execute(callback, handle);
>> +    if (ACPI_FAILURE(status))
>> +        acpi_evaluate_hotplug_ost(handle, type,
>> +                      ACPI_OST_SC_NON_SPECIFIC_FAILURE,
>> +                      NULL);
>> +}
>> +
>> +/**
>> + * acpi_bus_hot_remove_device: hot-remove a device and its children
>> + * @context: struct acpi_eject_event pointer (freed in this func)
>> + *
>> + * Hot-remove a device and its children. This function frees up the
>> + * memory space passed by arg context, so that the caller may call
>> + * this function asynchronously through acpi_os_hotplug_execute().
>> + */
>> +void acpi_bus_hot_remove_device(void *context)
>> +{
>> +    struct acpi_eject_event *ej_event = context;
>> +    struct acpi_device *device = ej_event->device;
>> +    acpi_handle handle = device->handle;
>> +    u32 ost_code = ACPI_OST_SC_SUCCESS;
>> +    int error;
>> +
>> +    mutex_lock(&acpi_scan_lock);
>> +
>> +    error = acpi_scan_hot_remove(device);
>> +    if (error)
>> +        ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
>> +
>> +    acpi_evaluate_hotplug_ost(handle, ej_event->event, ost_code, NULL);
>> +
>>       mutex_unlock(&acpi_scan_lock);
>>       kfree(context);
>> -    return;
>>   }
>>   EXPORT_SYMBOL(acpi_bus_hot_remove_device);
>>
>> @@ -206,50 +337,48 @@ static ssize_t
>>   acpi_eject_store(struct device *d, struct device_attribute *attr,
>>           const char *buf, size_t count)
>>   {
>> -    int ret = count;
>> -    acpi_status status;
>> -    acpi_object_type type = 0;
>>       struct acpi_device *acpi_device = to_acpi_device(d);
>> -    struct acpi_eject_event *ej_event;
>> +    acpi_object_type not_used;
>> +    acpi_status status;
>> +    u32 ost_source;
>> +    u32 ost_code;
>> +    int ret;
>>
>> -    if ((!count) || (buf[0] != '1')) {
>> +    if (!count || buf[0] != '1')
>>           return -EINVAL;
>> -    }
>> -    if (!acpi_device->driver && !acpi_device->handler) {
>> -        ret = -ENODEV;
>> -        goto err;
>> -    }
>> -    status = acpi_get_type(acpi_device->handle, &type);
>> -    if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) {
>> -        ret = -ENODEV;
>> -        goto err;
>> -    }
>>
>> -    ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
>> -    if (!ej_event) {
>> -        ret = -ENOMEM;
>> -        goto err;
>> -    }
>> +    if ((!acpi_device->handler || !acpi_device->handler->hotplug.enabled)
>> +        && !acpi_device->driver)
>> +        return -ENODEV;
>> +
>> +    status = acpi_get_type(acpi_device->handle, &not_used);
>> +    if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable)
>> +        return -ENODEV;
>> +
>> +    mutex_lock(&acpi_scan_lock);
>>
>> -    get_device(&acpi_device->dev);
>> -    ej_event->device = acpi_device;
>>       if (acpi_device->flags.eject_pending) {
>> -        /* event originated from ACPI eject notification */
>> -        ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
>> +        /* ACPI eject notification event. */
>> +        ost_source = ACPI_NOTIFY_EJECT_REQUEST;
>>           acpi_device->flags.eject_pending = 0;
>>       } else {
>> -        /* event originated from user */
>> -        ej_event->event = ACPI_OST_EC_OSPM_EJECT;
>> -        (void) acpi_evaluate_hotplug_ost(acpi_device->handle,
>> -            ej_event->event, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
>> +        /* Eject initiated by user space. */
>> +        ost_source = ACPI_OST_EC_OSPM_EJECT;
>>       }
>> -
>
>> -    status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event);
>> -    if (ACPI_FAILURE(status)) {
>> -        put_device(&acpi_device->dev);
>> -        kfree(ej_event);
>> +    acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source,
>> +                  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
>> +    get_device(&acpi_device->dev);
>> +    ret = acpi_scan_hot_remove(acpi_device);
>
> Why don't you use acpi_os_hotplug_execute()? Do you have some reason?
>
> Thanks,
> Yasuaki Ishimatsu
>
>> +    if (ret) {
>> +        ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
>> +    } else {
>> +        ost_code = ACPI_OST_SC_SUCCESS;
>> +        ret = count;
>>       }
>> -err:
>> +    acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT,
>> +                  ost_code, NULL);
>> +
>> +    mutex_unlock(&acpi_scan_lock);
>>       return ret;
>>   }
>>
>> @@ -1548,6 +1677,30 @@ static struct acpi_scan_handler *acpi_sc
>>       return NULL;
>>   }
>>
>> +static void acpi_scan_init_hotplug(acpi_handle handle)
>> +{
>> +    struct acpi_device_info *info;
>> +    struct acpi_scan_handler *handler;
>> +
>> +    if (ACPI_FAILURE(acpi_get_object_info(handle, &info)))
>> +        return;
>> +
>> +    if (!(info->valid & ACPI_VALID_HID)) {
>> +        kfree(info);
>> +        return;
>> +    }
>> +
>> +    /*
>> +     * This relies on the fact that acpi_install_notify_handler() will not
>> +     * install the same notify handler routine twice for the same handle.
>> +     */
>> +    handler = acpi_scan_match_handler(info->hardware_id.string, NULL);
>> +    kfree(info);
>> +    if (handler && handler->hotplug.enabled)
>> +        acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
>> +                        acpi_hotplug_notify_cb, NULL);
>> +}
>> +
>>   static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
>>                         void *not_used, void **return_value)
>>   {
>> @@ -1570,6 +1723,8 @@ static acpi_status acpi_bus_check_add(ac
>>           return AE_OK;
>>       }
>>
>> +    acpi_scan_init_hotplug(handle);
>> +
>>       if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
>>           !(sta & ACPI_STA_DEVICE_FUNCTIONING)) {
>>           struct acpi_device_wakeup wakeup;
>>
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH 4/7] ACPI / scan: Introduce acpi_scan_handler_matching()
  2013-02-17 15:23 ` [PATCH 4/7] ACPI / scan: Introduce acpi_scan_handler_matching() Rafael J. Wysocki
@ 2013-02-19  8:05   ` Yasuaki Ishimatsu
  0 siblings, 0 replies; 69+ messages in thread
From: Yasuaki Ishimatsu @ 2013-02-19  8:05 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Yinghai Lu,
	Toshi Kani, Jiang Liu

2013/02/18 0:23, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>
> Introduce new helper routine acpi_scan_handler_matching() for
> checking if the given ACPI scan handler matches a given device ID
> and rework acpi_scan_match_handler() to use the new routine (that
> routine will also be useful for other purposes in the future).
>
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> ---

Acked-by: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>

Thanks,
Yasuaki Ishimatsu

>   drivers/acpi/scan.c |   30 ++++++++++++++++++++----------
>   1 file changed, 20 insertions(+), 10 deletions(-)
>
> Index: test/drivers/acpi/scan.c
> ===================================================================
> --- test.orig/drivers/acpi/scan.c
> +++ test/drivers/acpi/scan.c
> @@ -1658,22 +1658,32 @@ static int acpi_bus_type_and_status(acpi
>   	return 0;
>   }
>
> +static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler,
> +				       char *idstr,
> +				       const struct acpi_device_id **matchid)
> +{
> +	const struct acpi_device_id *devid;
> +
> +	for (devid = handler->ids; devid->id[0]; devid++)
> +		if (!strcmp((char *)devid->id, idstr)) {
> +			if (matchid)
> +				*matchid = devid;
> +
> +			return true;
> +		}
> +
> +	return false;
> +}
> +
>   static struct acpi_scan_handler *acpi_scan_match_handler(char *idstr,
>   					const struct acpi_device_id **matchid)
>   {
>   	struct acpi_scan_handler *handler;
>
> -	list_for_each_entry(handler, &acpi_scan_handlers_list, list_node) {
> -		const struct acpi_device_id *devid;
> +	list_for_each_entry(handler, &acpi_scan_handlers_list, list_node)
> +		if (acpi_scan_handler_matching(handler, idstr, matchid))
> +			return handler;
>
> -		for (devid = handler->ids; devid->id[0]; devid++)
> -			if (!strcmp((char *)devid->id, idstr)) {
> -				if (matchid)
> -					*matchid = devid;
> -
> -				return handler;
> -			}
> -	}
>   	return NULL;
>   }
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH 7/7] ACPI / scan: Make memory hotplug driver use struct acpi_scan_handler
  2013-02-17 15:27 ` [PATCH 7/7] ACPI / scan: Make memory hotplug driver use struct acpi_scan_handler Rafael J. Wysocki
@ 2013-02-19 18:11   ` Vasilis Liaskovitis
  2013-02-20  3:35     ` Yasuaki Ishimatsu
  0 siblings, 1 reply; 69+ messages in thread
From: Vasilis Liaskovitis @ 2013-02-19 18:11 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Yinghai Lu,
	Toshi Kani, Yasuaki Ishimatsu, Jiang Liu

Hi,

On Sun, Feb 17, 2013 at 04:27:18PM +0100, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> 
> Make the ACPI memory hotplug driver use struct acpi_scan_handler
> for representing the object used to set up ACPI memory hotplug
> functionality and to remove hotplug memory ranges and data
> structures used by the driver before unregistering ACPI device
> nodes representing memory.  Register the new struct acpi_scan_handler
> object with the help of acpi_scan_add_handler_with_hotplug() to allow
> user space to manipulate the attributes of the memory hotplug
> profile.

Let's consider an example where we want acpi memory device ejection to be safely
handled by userspace. We do the following:

echo 0 > /sys/firmware/acpi/hotplug/memory/autoeject
echo 1 > /sys/firmware/acpi/hotplug/memory/uevents

We succesfully hotplug acpi device:
/sys/devices/LNXSYSTM:00/LNXSYSBUS:00/PNP0C80:00
and its corresponding memblocks /sys/devices/system/memory/memoryXX are
also successfully onlined.

On an eject request, since uevents == 1, the kernel will emit KOBJ_OFFLINE for:
/sys/devices/LNXSYSTM:00/LNXSYSBUS:00/PNP0C80:00

Can userspace know which memblocks in /sys/devices/system/memory/memoryXX/
correspond to the acpi device /sys/devices/LNXSYSTM:00/LNXSYSBUS:00/PNP0C80:00 ?
This will be needed so that userspace tries to offline the memblocks (and only
if successful, issue the eject operation on the acpi device). As far as I see,
we don't create any sysfs links or files for this scenario - can userspace get
this info somehow?

/sys/devices/system/memory/memoryXX/phys_device needs to be properly implemented
for this to work I think, see Documentation/ABI/testing/sysfs-memory

The following test patch works toward that direction. Let me know if it's of
interest or if there are better ideas /comments.

From: Vasilis Liaskovitis <vasilis.liaskovitis@profitbricks.com>
Date: Tue, 19 Feb 2013 18:36:25 +0100
Subject: [RFC PATCH] acpi / memory-hotplug: implement phys_device

In order for userspace to know which memblocks in:
/sys/devices/system/memory/memoryXX correspond to which acpi memory devices in:
/sys/devices/LNXSYSTM:00/LNXSYSBUS:00/PNP0C80:YY,
/sys/devices/system/memory/memoryXX/phys_device should return a name (or index
YY) of the memory device each memblock XX belongs to.

WIth this patch, the acpi mem_hotplug driver keeps a global list of acpi memory
devices (inserted in hotplug_order). The base memory driver checks against this
list in arch_get_memory_phys_device to determine the zero-based index of the
physical memory device each new memblock belongs to.

For initial memory or for non-acpi/hotplug enabled systems, phys_device is
always -1.

Signed-off-by: Vasilis Liaskovitis <vasilis.liaskovitis@profitbricks.com>
---
 Documentation/ABI/testing/sysfs-devices-memory |    8 ++++++-
 drivers/acpi/acpi_memhotplug.c                 |   27 ++++++++++++++++++++++++
 drivers/base/memory.c                          |    7 +++++-
 include/linux/acpi.h                           |    2 +
 4 files changed, 42 insertions(+), 2 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-devices-memory b/Documentation/ABI/testing/sysfs-devices-memory
index 7405de2..290c62a 100644
--- a/Documentation/ABI/testing/sysfs-devices-memory
+++ b/Documentation/ABI/testing/sysfs-devices-memory
@@ -27,7 +27,13 @@ Contact:	Badari Pulavarty <pbadari@us.ibm.com>
 Description:
 		The file /sys/devices/system/memory/memoryX/phys_device
 		is read-only and is designed to show the name of physical
-		memory device.  Implementation is currently incomplete.
+		memory device.  Implementation is currently incomplete. In a
+		system with CONFIG_ACPI_HOTPLUG_MEMORY=n, phys_device is always
+	     	-1. In a system with CONFIG_ACPI_HOTPLUG_MEMORY=y, phys_device
+		is -1 for all initial / non-hot-removable memory. For
+	       	memory that has been hot-plugged, phys_device will return the
+	       	zero-based index of the physical device that this memory block
+	       	belongs to. Indices are determined by hotplug order.
 
 What:		/sys/devices/system/memory/memoryX/phys_index
 Date:		September 2008
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index 3be9501..4154dc5 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -48,6 +48,7 @@ ACPI_MODULE_NAME("acpi_memhotplug");
 #define MEMORY_POWER_ON_STATE	1
 #define MEMORY_POWER_OFF_STATE	2
 
+static LIST_HEAD(acpi_mem_device_list);
 static int acpi_memory_device_add(struct acpi_device *device,
 				  const struct acpi_device_id *not_used);
 static void acpi_memory_device_remove(struct acpi_device *device);
@@ -81,6 +82,7 @@ struct acpi_memory_device {
 	struct acpi_device * device;
 	unsigned int state;	/* State of the memory device */
 	struct list_head res_list;
+	struct list_head mem_device_list;
 };
 
 static acpi_status
@@ -287,6 +289,7 @@ static int acpi_memory_device_add(struct acpi_device *device,
 		return -ENOMEM;
 
 	INIT_LIST_HEAD(&mem_device->res_list);
+	INIT_LIST_HEAD(&mem_device->mem_device_list);
 	mem_device->device = device;
 	sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME);
 	sprintf(acpi_device_class(device), "%s", ACPI_MEMORY_DEVICE_CLASS);
@@ -308,9 +311,11 @@ static int acpi_memory_device_add(struct acpi_device *device,
 		return 0;
 	}
 
+	list_add_tail(&mem_device->mem_device_list, &acpi_mem_device_list);
 	result = acpi_memory_enable_device(mem_device);
 	if (result) {
 		dev_err(&device->dev, "acpi_memory_enable_device() error\n");
+		list_del(&mem_device->mem_device_list);
 		acpi_memory_device_free(mem_device);
 		return -ENODEV;
 	}
@@ -328,9 +333,31 @@ static void acpi_memory_device_remove(struct acpi_device *device)
 
 	mem_device = acpi_driver_data(device);
 	acpi_memory_remove_memory(mem_device);
+	list_del(&mem_device->mem_device_list);
 	acpi_memory_device_free(mem_device);
 }
 
+int acpi_memory_phys_device(unsigned long start_pfn)
+{
+	struct acpi_memory_device *mem_dev;
+	struct acpi_memory_info *info;
+	unsigned long start_addr = start_pfn << PAGE_SHIFT;
+	int id = 0;
+
+	list_for_each_entry(mem_dev, &acpi_mem_device_list, mem_device_list) {
+		list_for_each_entry(info, &mem_dev->res_list, list) {
+			if ((info->start_addr <= start_addr) &&
+				(info->start_addr + info->length > start_addr))
+				return id;
+		}
+		id++;
+	}
+
+	/* Memory not associated with a hot-pluggable device gets -1. For
+	 * example, initial memory. */
+	return -1;
+}
+
 void __init acpi_memory_hotplug_init(void)
 {
 	acpi_scan_add_handler_with_hotplug(&memory_device_handler, "memory");
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 8300a18..2cc98df 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -22,6 +22,7 @@
 #include <linux/mutex.h>
 #include <linux/stat.h>
 #include <linux/slab.h>
+#include <linux/acpi.h>
 
 #include <linux/atomic.h>
 #include <asm/uaccess.h>
@@ -522,7 +523,11 @@ static inline int memory_fail_init(void)
  */
 int __weak arch_get_memory_phys_device(unsigned long start_pfn)
 {
-	return 0;
+#ifdef CONFIG_ACPI_HOTPLUG_MEMORY
+	return acpi_memory_phys_device(start_pfn);
+#else
+	return -1;
+#endif
 }
 
 /*
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index f46cfd7..00302fc 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -562,6 +562,8 @@ static inline __printf(3, 4) void
 acpi_handle_printk(const char *level, void *handle, const char *fmt, ...) {}
 #endif	/* !CONFIG_ACPI */
 
+int acpi_memory_phys_device(unsigned long start_pfn);
+
 /*
  * acpi_handle_<level>: Print message with ACPI prefix and object path
  *
-- 
1.7.9


^ permalink raw reply related	[flat|nested] 69+ messages in thread

* Re: [PATCH 7/7] ACPI / scan: Make memory hotplug driver use struct acpi_scan_handler
  2013-02-19 18:11   ` Vasilis Liaskovitis
@ 2013-02-20  3:35     ` Yasuaki Ishimatsu
  2013-02-20 10:42       ` Vasilis Liaskovitis
  0 siblings, 1 reply; 69+ messages in thread
From: Yasuaki Ishimatsu @ 2013-02-20  3:35 UTC (permalink / raw)
  To: Vasilis Liaskovitis
  Cc: Rafael J. Wysocki, ACPI Devel Maling List, Bjorn Helgaas, LKML,
	Yinghai Lu, Toshi Kani, Jiang Liu

Hi Vasilis,

2013/02/20 3:11, Vasilis Liaskovitis wrote:
> Hi,
>
> On Sun, Feb 17, 2013 at 04:27:18PM +0100, Rafael J. Wysocki wrote:
>> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>>
>> Make the ACPI memory hotplug driver use struct acpi_scan_handler
>> for representing the object used to set up ACPI memory hotplug
>> functionality and to remove hotplug memory ranges and data
>> structures used by the driver before unregistering ACPI device
>> nodes representing memory.  Register the new struct acpi_scan_handler
>> object with the help of acpi_scan_add_handler_with_hotplug() to allow
>> user space to manipulate the attributes of the memory hotplug
>> profile.
>
> Let's consider an example where we want acpi memory device ejection to be safely
> handled by userspace. We do the following:
>
> echo 0 > /sys/firmware/acpi/hotplug/memory/autoeject
> echo 1 > /sys/firmware/acpi/hotplug/memory/uevents
>
> We succesfully hotplug acpi device:
> /sys/devices/LNXSYSTM:00/LNXSYSBUS:00/PNP0C80:00
> and its corresponding memblocks /sys/devices/system/memory/memoryXX are
> also successfully onlined.
>
> On an eject request, since uevents == 1, the kernel will emit KOBJ_OFFLINE for:
> /sys/devices/LNXSYSTM:00/LNXSYSBUS:00/PNP0C80:00
>
> Can userspace know which memblocks in /sys/devices/system/memory/memoryXX/
> correspond to the acpi device /sys/devices/LNXSYSTM:00/LNXSYSBUS:00/PNP0C80:00 ?
> This will be needed so that userspace tries to offline the memblocks (and only
> if successful, issue the eject operation on the acpi device). As far as I see,
> we don't create any sysfs links or files for this scenario - can userspace get
> this info somehow?

>
> /sys/devices/system/memory/memoryXX/phys_device needs to be properly implemented
> for this to work I think, see Documentation/ABI/testing/sysfs-memory
>
> The following test patch works toward that direction. Let me know if it's of
> interest or if there are better ideas /comments.

How about use ../PNP0C80:00/physical_node/resources file?
In my system, the file shows following information.

$ cat /sys/bus/acpi/devices/PNP0C80\:00/physical_node/resources
state = active
mem 0x0-0x80000000
mem 0x100000000-0x800000000

It means PNP0C80:00's memory ranges are "0x0-0x7fffffff" and
"0x100000000-0x7ffffffff". In x86 architecture, memory section size is
128MiB. So, if these memory range is divided by 128MiB, you can
calculate memory section number as follow:

0x0-0x7fffffff => 0x0-0x10
0x100000000-0x7ffffffff => 0x20-0xff

But there is one problem. The problem is that resources file of added memory
is not created. If the problem is fixed, I think you can use the way.

>
> From: Vasilis Liaskovitis <vasilis.liaskovitis@profitbricks.com>
> Date: Tue, 19 Feb 2013 18:36:25 +0100
> Subject: [RFC PATCH] acpi / memory-hotplug: implement phys_device
>
> In order for userspace to know which memblocks in:
> /sys/devices/system/memory/memoryXX correspond to which acpi memory devices in:
> /sys/devices/LNXSYSTM:00/LNXSYSBUS:00/PNP0C80:YY,
> /sys/devices/system/memory/memoryXX/phys_device should return a name (or index
> YY) of the memory device each memblock XX belongs to.
>
> WIth this patch, the acpi mem_hotplug driver keeps a global list of acpi memory
> devices (inserted in hotplug_order). The base memory driver checks against this
> list in arch_get_memory_phys_device to determine the zero-based index of the
> physical memory device each new memblock belongs to.
>
> For initial memory or for non-acpi/hotplug enabled systems, phys_device is
> always -1.
>
> Signed-off-by: Vasilis Liaskovitis <vasilis.liaskovitis@profitbricks.com>
> ---
>   Documentation/ABI/testing/sysfs-devices-memory |    8 ++++++-
>   drivers/acpi/acpi_memhotplug.c                 |   27 ++++++++++++++++++++++++
>   drivers/base/memory.c                          |    7 +++++-
>   include/linux/acpi.h                           |    2 +
>   4 files changed, 42 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/ABI/testing/sysfs-devices-memory b/Documentation/ABI/testing/sysfs-devices-memory
> index 7405de2..290c62a 100644
> --- a/Documentation/ABI/testing/sysfs-devices-memory
> +++ b/Documentation/ABI/testing/sysfs-devices-memory
> @@ -27,7 +27,13 @@ Contact:	Badari Pulavarty <pbadari@us.ibm.com>
>   Description:
>   		The file /sys/devices/system/memory/memoryX/phys_device
>   		is read-only and is designed to show the name of physical
> -		memory device.  Implementation is currently incomplete.
> +		memory device.  Implementation is currently incomplete. In a
> +		system with CONFIG_ACPI_HOTPLUG_MEMORY=n, phys_device is always
> +	     	-1. In a system with CONFIG_ACPI_HOTPLUG_MEMORY=y, phys_device
> +		is -1 for all initial / non-hot-removable memory. For
> +	       	memory that has been hot-plugged, phys_device will return the
> +	       	zero-based index of the physical device that this memory block
> +	       	belongs to. Indices are determined by hotplug order.
>
>   What:		/sys/devices/system/memory/memoryX/phys_index
>   Date:		September 2008
> diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
> index 3be9501..4154dc5 100644
> --- a/drivers/acpi/acpi_memhotplug.c
> +++ b/drivers/acpi/acpi_memhotplug.c
> @@ -48,6 +48,7 @@ ACPI_MODULE_NAME("acpi_memhotplug");
>   #define MEMORY_POWER_ON_STATE	1
>   #define MEMORY_POWER_OFF_STATE	2
>
> +static LIST_HEAD(acpi_mem_device_list);
>   static int acpi_memory_device_add(struct acpi_device *device,
>   				  const struct acpi_device_id *not_used);
>   static void acpi_memory_device_remove(struct acpi_device *device);
> @@ -81,6 +82,7 @@ struct acpi_memory_device {
>   	struct acpi_device * device;
>   	unsigned int state;	/* State of the memory device */
>   	struct list_head res_list;
> +	struct list_head mem_device_list;
>   };
>
>   static acpi_status
> @@ -287,6 +289,7 @@ static int acpi_memory_device_add(struct acpi_device *device,
>   		return -ENOMEM;
>
>   	INIT_LIST_HEAD(&mem_device->res_list);
> +	INIT_LIST_HEAD(&mem_device->mem_device_list);
>   	mem_device->device = device;
>   	sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME);
>   	sprintf(acpi_device_class(device), "%s", ACPI_MEMORY_DEVICE_CLASS);
> @@ -308,9 +311,11 @@ static int acpi_memory_device_add(struct acpi_device *device,
>   		return 0;
>   	}
>
> +	list_add_tail(&mem_device->mem_device_list, &acpi_mem_device_list);
>   	result = acpi_memory_enable_device(mem_device);
>   	if (result) {
>   		dev_err(&device->dev, "acpi_memory_enable_device() error\n");
> +		list_del(&mem_device->mem_device_list);
>   		acpi_memory_device_free(mem_device);
>   		return -ENODEV;
>   	}
> @@ -328,9 +333,31 @@ static void acpi_memory_device_remove(struct acpi_device *device)
>
>   	mem_device = acpi_driver_data(device);
>   	acpi_memory_remove_memory(mem_device);
> +	list_del(&mem_device->mem_device_list);
>   	acpi_memory_device_free(mem_device);
>   }
>

> +int acpi_memory_phys_device(unsigned long start_pfn)
> +{
> +	struct acpi_memory_device *mem_dev;
> +	struct acpi_memory_info *info;
> +	unsigned long start_addr = start_pfn << PAGE_SHIFT;
> +	int id = 0;
> +
> +	list_for_each_entry(mem_dev, &acpi_mem_device_list, mem_device_list) {
> +		list_for_each_entry(info, &mem_dev->res_list, list) {
> +			if ((info->start_addr <= start_addr) &&
> +				(info->start_addr + info->length > start_addr))
> +				return id;
> +		}
> +		id++;
> +	}

I don't think this solve your problem.

When hot adding memory device in my system, consecutive index number is
applied to PNP0C80 as follows:

$ ls /sys/bus/acpi/devices/ |grep PNP0C80
PNP0C80:00
PNP0C80:01  => hot added memory device
PNP0C80:02  => hot added memory device

In this case, we can know PNP0C80:YY by memoryXX/phys_device file.
But if hot removing and adding the same device, index number is changed
as follows:

$ ls /sys/bus/acpi/devices/
PNP0C80:00
PNP0C80:03  => hot added memory device
PNP0C80:04  => hot added memory device

In this case, we cannot know PNP0C80:YY by memoryXX/phys_device file.

Thanks,
Yasuaki Ishimatsu

> +
> +	/* Memory not associated with a hot-pluggable device gets -1. For
> +	 * example, initial memory. */
> +	return -1;
> +}
> +
>   void __init acpi_memory_hotplug_init(void)
>   {
>   	acpi_scan_add_handler_with_hotplug(&memory_device_handler, "memory");
> diff --git a/drivers/base/memory.c b/drivers/base/memory.c
> index 8300a18..2cc98df 100644
> --- a/drivers/base/memory.c
> +++ b/drivers/base/memory.c
> @@ -22,6 +22,7 @@
>   #include <linux/mutex.h>
>   #include <linux/stat.h>
>   #include <linux/slab.h>
> +#include <linux/acpi.h>
>
>   #include <linux/atomic.h>
>   #include <asm/uaccess.h>
> @@ -522,7 +523,11 @@ static inline int memory_fail_init(void)
>    */
>   int __weak arch_get_memory_phys_device(unsigned long start_pfn)
>   {
> -	return 0;
> +#ifdef CONFIG_ACPI_HOTPLUG_MEMORY
> +	return acpi_memory_phys_device(start_pfn);
> +#else
> +	return -1;
> +#endif
>   }
>
>   /*
> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
> index f46cfd7..00302fc 100644
> --- a/include/linux/acpi.h
> +++ b/include/linux/acpi.h
> @@ -562,6 +562,8 @@ static inline __printf(3, 4) void
>   acpi_handle_printk(const char *level, void *handle, const char *fmt, ...) {}
>   #endif	/* !CONFIG_ACPI */
>
> +int acpi_memory_phys_device(unsigned long start_pfn);
> +
>   /*
>    * acpi_handle_<level>: Print message with ACPI prefix and object path
>    *
>



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH 7/7] ACPI / scan: Make memory hotplug driver use struct acpi_scan_handler
  2013-02-20  3:35     ` Yasuaki Ishimatsu
@ 2013-02-20 10:42       ` Vasilis Liaskovitis
  2013-02-20 21:50         ` Toshi Kani
  2013-02-21  6:58         ` Yasuaki Ishimatsu
  0 siblings, 2 replies; 69+ messages in thread
From: Vasilis Liaskovitis @ 2013-02-20 10:42 UTC (permalink / raw)
  To: Yasuaki Ishimatsu
  Cc: Rafael J. Wysocki, ACPI Devel Maling List, Bjorn Helgaas, LKML,
	Yinghai Lu, Toshi Kani, Jiang Liu

Hi Yasuaki,

On Wed, Feb 20, 2013 at 12:35:48PM +0900, Yasuaki Ishimatsu wrote:
> Hi Vasilis,
> 
> 2013/02/20 3:11, Vasilis Liaskovitis wrote:
> >Hi,
> >
> >On Sun, Feb 17, 2013 at 04:27:18PM +0100, Rafael J. Wysocki wrote:
> >>From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> >>
> >>Make the ACPI memory hotplug driver use struct acpi_scan_handler
> >>for representing the object used to set up ACPI memory hotplug
> >>functionality and to remove hotplug memory ranges and data
> >>structures used by the driver before unregistering ACPI device
> >>nodes representing memory.  Register the new struct acpi_scan_handler
> >>object with the help of acpi_scan_add_handler_with_hotplug() to allow
> >>user space to manipulate the attributes of the memory hotplug
> >>profile.
> >
> >Let's consider an example where we want acpi memory device ejection to be safely
> >handled by userspace. We do the following:
> >
> >echo 0 > /sys/firmware/acpi/hotplug/memory/autoeject
> >echo 1 > /sys/firmware/acpi/hotplug/memory/uevents
> >
> >We succesfully hotplug acpi device:
> >/sys/devices/LNXSYSTM:00/LNXSYSBUS:00/PNP0C80:00
> >and its corresponding memblocks /sys/devices/system/memory/memoryXX are
> >also successfully onlined.
> >
> >On an eject request, since uevents == 1, the kernel will emit KOBJ_OFFLINE for:
> >/sys/devices/LNXSYSTM:00/LNXSYSBUS:00/PNP0C80:00
> >
> >Can userspace know which memblocks in /sys/devices/system/memory/memoryXX/
> >correspond to the acpi device /sys/devices/LNXSYSTM:00/LNXSYSBUS:00/PNP0C80:00 ?
> >This will be needed so that userspace tries to offline the memblocks (and only
> >if successful, issue the eject operation on the acpi device). As far as I see,
> >we don't create any sysfs links or files for this scenario - can userspace get
> >this info somehow?
> 
> >
> >/sys/devices/system/memory/memoryXX/phys_device needs to be properly implemented
> >for this to work I think, see Documentation/ABI/testing/sysfs-memory
> >
> >The following test patch works toward that direction. Let me know if it's of
> >interest or if there are better ideas /comments.
> 
> How about use ../PNP0C80:00/physical_node/resources file?
> In my system, the file shows following information.
> 
> $ cat /sys/bus/acpi/devices/PNP0C80\:00/physical_node/resources
> state = active
> mem 0x0-0x80000000
> mem 0x100000000-0x800000000
> 
> It means PNP0C80:00's memory ranges are "0x0-0x7fffffff" and
> "0x100000000-0x7ffffffff". In x86 architecture, memory section size is
> 128MiB. So, if these memory range is divided by 128MiB, you can
> calculate memory section number as follow:
> 
> 0x0-0x7fffffff => 0x0-0x10
> 0x100000000-0x7ffffffff => 0x20-0xff
> 
> But there is one problem. The problem is that resources file of added memory
> is not created. If the problem is fixed, I think you can use the way.

thanks for your suggestion. Is this resources file a property of the
physical_node or of each acpi devices? 

If it's a node specific file could there be a chance that adjacent memory
ranges get merged? We 'd like these to not get merged.

I will look more into this property. I don't see it currently in my system
(probably because initial memory is not backed by acpi devices in my
 seabios/virtual machine).

> 
[...] 
> >+int acpi_memory_phys_device(unsigned long start_pfn)
> >+{
> >+	struct acpi_memory_device *mem_dev;
> >+	struct acpi_memory_info *info;
> >+	unsigned long start_addr = start_pfn << PAGE_SHIFT;
> >+	int id = 0;
> >+
> >+	list_for_each_entry(mem_dev, &acpi_mem_device_list, mem_device_list) {
> >+		list_for_each_entry(info, &mem_dev->res_list, list) {
> >+			if ((info->start_addr <= start_addr) &&
> >+				(info->start_addr + info->length > start_addr))
> >+				return id;
> >+		}
> >+		id++;
> >+	}
> 
> I don't think this solve your problem.
> 
> When hot adding memory device in my system, consecutive index number is
> applied to PNP0C80 as follows:
> 
> $ ls /sys/bus/acpi/devices/ |grep PNP0C80
> PNP0C80:00
> PNP0C80:01  => hot added memory device
> PNP0C80:02  => hot added memory device
> 
> In this case, we can know PNP0C80:YY by memoryXX/phys_device file.
> But if hot removing and adding the same device, index number is changed
> as follows:
> 
> $ ls /sys/bus/acpi/devices/
> PNP0C80:00
> PNP0C80:03  => hot added memory device
> PNP0C80:04  => hot added memory device
> 
> In this case, we cannot know PNP0C80:YY by memoryXX/phys_device file.
>

thanks, yes you are right. I forgot each new hotplug event will create a new
PNP0C80:XX device where XX always increases. So the hot-add/hot-remove/hot-add
scenario would have a problem.
Then it would be enough to be able to return this monotonically increasing
counter from phys_device instead of the current list iterator. Is this counter
available somehwere in drivers/acpi/scan.c or bus.c? I 'll take a look.

thanks,

- Vasilis

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-19  6:43   ` Yasuaki Ishimatsu
  2013-02-19  7:10     ` Yasuaki Ishimatsu
@ 2013-02-20 13:23     ` Rafael J. Wysocki
  2013-02-20 20:23       ` Toshi Kani
  1 sibling, 1 reply; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-20 13:23 UTC (permalink / raw)
  To: Yasuaki Ishimatsu
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Yinghai Lu,
	Toshi Kani, Jiang Liu

On Tuesday, February 19, 2013 03:43:08 PM Yasuaki Ishimatsu wrote:
> Hi Rafael,
> 
> I have comments. Please see below.
> 
> 2013/02/18 0:21, Rafael J. Wysocki wrote:
> > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> >
> > Multiple drivers handling hotplug-capable ACPI device nodes install
> > notify handlers covering the same types of events in a very similar
> > way.  Moreover, those handlers are installed in separate namespace
> > walks, although that really should be done during namespace scans
> > carried out by acpi_bus_scan().  This leads to substantial code
> > duplication, unnecessary overhead and behavior that is hard to
> > follow.
> >
> > For this reason, introduce common code in drivers/acpi/scan.c for
> > handling hotplug-related notification and carrying out device
> > insertion and eject operations in a generic fashion, such that it
> > may be used by all of the relevant drivers in the future.  To cover
> > the existing differences between those drivers introduce struct
> > acpi_hotplug_profile for representing collections of hotplug
> > settings associated with different ACPI scan handlers that can be
> > used by the drivers to make the common code reflect their current
> > behavior.
> >
> > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > ---
> >   drivers/acpi/scan.c     |  271 +++++++++++++++++++++++++++++++++++++-----------
> >   include/acpi/acpi_bus.h |    7 +
> >   2 files changed, 220 insertions(+), 58 deletions(-)
> >
> > Index: test/include/acpi/acpi_bus.h
> > ===================================================================
> > --- test.orig/include/acpi/acpi_bus.h
> > +++ test/include/acpi/acpi_bus.h
> > @@ -88,11 +88,18 @@ struct acpi_device;
> >    * -----------------
> >    */
> >
> > +struct acpi_hotplug_profile {
> > +	bool enabled:1;
> > +	bool uevents:1;
> > +	bool autoeject:1;
> > +};
> > +
> >   struct acpi_scan_handler {
> >   	const struct acpi_device_id *ids;
> >   	struct list_head list_node;
> >   	int (*attach)(struct acpi_device *dev, const struct acpi_device_id *id);
> >   	void (*detach)(struct acpi_device *dev);
> > +	struct acpi_hotplug_profile hotplug;
> >   };
> >
> >   /*
> > Index: test/drivers/acpi/scan.c
> > ===================================================================
> > --- test.orig/drivers/acpi/scan.c
> > +++ test/drivers/acpi/scan.c
> > @@ -107,32 +107,19 @@ acpi_device_modalias_show(struct device
> >   }
> >   static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
> >
> > -/**
> > - * acpi_bus_hot_remove_device: hot-remove a device and its children
> > - * @context: struct acpi_eject_event pointer (freed in this func)
> > - *
> > - * Hot-remove a device and its children. This function frees up the
> > - * memory space passed by arg context, so that the caller may call
> > - * this function asynchronously through acpi_os_hotplug_execute().
> > - */
> > -void acpi_bus_hot_remove_device(void *context)
> > +static int acpi_scan_hot_remove(struct acpi_device *device)
> >   {
> > -	struct acpi_eject_event *ej_event = context;
> > -	struct acpi_device *device = ej_event->device;
> >   	acpi_handle handle = device->handle;
> > -	acpi_handle temp;
> > +	acpi_handle not_used;
> >   	struct acpi_object_list arg_list;
> >   	union acpi_object arg;
> > -	acpi_status status = AE_OK;
> > -	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
> > -
> > -	mutex_lock(&acpi_scan_lock);
> > +	acpi_status status;
> >
> >   	/* If there is no handle, the device node has been unregistered. */
> > -	if (!device->handle) {
> > +	if (!handle) {
> >   		dev_dbg(&device->dev, "ACPI handle missing\n");
> >   		put_device(&device->dev);
> > -		goto out;
> > +		return -EINVAL;
> >   	}
> >
> >   	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
> > @@ -143,7 +130,7 @@ void acpi_bus_hot_remove_device(void *co
> >   	put_device(&device->dev);
> >   	device = NULL;
> >
> > -	if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &temp))) {
> > +	if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &not_used))) {
> >   		arg_list.count = 1;
> >   		arg_list.pointer = &arg;
> >   		arg.type = ACPI_TYPE_INTEGER;
> > @@ -161,18 +148,162 @@ void acpi_bus_hot_remove_device(void *co
> >   	 */
> >   	status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
> >   	if (ACPI_FAILURE(status)) {
> > -		if (status != AE_NOT_FOUND)
> > +		if (status == AE_NOT_FOUND) {
> > +			return -ENODEV;
> > +		} else {
> >   			acpi_handle_warn(handle, "Eject failed\n");
> > +			return -EIO;
> > +		}
> > +	}
> > +	return 0;
> > +}
> > +
> > +static void acpi_bus_device_eject(void *context)
> > +{
> > +	acpi_handle handle = context;
> > +	struct acpi_device *device = NULL;
> > +	struct acpi_scan_handler *handler;
> > +	u32 ost_source = ACPI_NOTIFY_EJECT_REQUEST;
> > +	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
> > +
> > +	mutex_lock(&acpi_scan_lock);
> >
> > -		/* Tell the firmware the hot-remove operation has failed. */
> > -		acpi_evaluate_hotplug_ost(handle, ej_event->event,
> > -					  ost_code, NULL);
> > +	acpi_bus_get_device(handle, &device);
> > +	if (!device)
> > +		goto out;
> > +
> > +	handler = device->handler;
> > +	if (!handler || !handler->hotplug.enabled) {
> > +		ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
> > +		goto out;
> >   	}
> > +	acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
> > +				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
> 
> > +	if (handler->hotplug.uevents)
> > +		kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
> > +
> > +	if (handler->hotplug.autoeject) {
> > +		int error;
> > +
> > +		ost_source = ACPI_OST_EC_OSPM_EJECT;
> > +		get_device(&device->dev);
> > +		error = acpi_scan_hot_remove(device);
> > +		if (!error)
> > +			ost_code = ACPI_OST_SC_SUCCESS;
> > +	} else {
> > +		device->flags.eject_pending = true;
> > +		goto out_unlock;
> > +	}
> 
> I want you to change the order of uevents and autoeject.
> When user caught OFFLINE event, user thinks devices were removed.
> But it is not guaranteed in this code since acpi_scan_hot_remove() may
> be running.

Sure, I can do that.

> > +
> > + out:
> > +	acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL);
> > +
> > + out_unlock:
> > +	mutex_unlock(&acpi_scan_lock);
> > +}
> > +
> > +static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
> > +{
> > +	struct acpi_device *device = NULL;
> > +	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
> > +	int error;
> > +
> > +	mutex_lock(&acpi_scan_lock);
> > +
> > +	acpi_bus_get_device(handle, &device);
> > +	if (device) {
> > +		dev_warn(&device->dev, "Attempt to re-insert\n");
> > +		goto out;
> > +	}
> > +	acpi_evaluate_hotplug_ost(handle, ost_source,
> > +				  ACPI_OST_SC_INSERT_IN_PROGRESS, NULL);
> > +	ost_source = ACPI_OST_EC_OSPM_INSERTION;
> > +	error = acpi_bus_scan(handle);
> > +	if (error) {
> > +		acpi_handle_warn(handle, "Namespace scan failure\n");
> > +		goto out;
> > +	}
> > +	error = acpi_bus_get_device(handle, &device);
> > +	if (error) {
> > +		acpi_handle_warn(handle, "Missing device node object\n");
> > +		goto out;
> > +	}
> > +	ost_code = ACPI_OST_SC_SUCCESS;
> > +	if (device->handler && device->handler->hotplug.uevents)
> > +		kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
> >
> >    out:
> > +	acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL);
> > +	mutex_unlock(&acpi_scan_lock);
> > +}
> > +
> > +static void acpi_scan_bus_check(void *context)
> > +{
> > +	acpi_scan_bus_device_check((acpi_handle)context,
> > +				   ACPI_NOTIFY_BUS_CHECK);
> > +}
> > +
> > +static void acpi_scan_device_check(void *context)
> > +{
> > +	acpi_scan_bus_device_check((acpi_handle)context,
> > +				   ACPI_NOTIFY_DEVICE_CHECK);
> > +}
> > +
> > +static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *not_used)
> > +{
> > +	acpi_osd_exec_callback callback;
> > +	acpi_status status;
> > +
> > +	switch (type) {
> > +	case ACPI_NOTIFY_BUS_CHECK:
> > +		acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
> > +		callback = acpi_scan_bus_check;
> > +		break;
> > +	case ACPI_NOTIFY_DEVICE_CHECK:
> > +		acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
> > +		callback = acpi_scan_device_check;
> > +		break;
> > +	case ACPI_NOTIFY_EJECT_REQUEST:
> > +		acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
> > +		callback = acpi_bus_device_eject;
> > +		break;
> > +	default:
> > +		/* non-hotplug event; possibly handled by other handler */
> > +		return;
> > +	}
> > +	status = acpi_os_hotplug_execute(callback, handle);
> > +	if (ACPI_FAILURE(status))
> > +		acpi_evaluate_hotplug_ost(handle, type,
> > +					  ACPI_OST_SC_NON_SPECIFIC_FAILURE,
> > +					  NULL);
> > +}
> > +
> > +/**
> > + * acpi_bus_hot_remove_device: hot-remove a device and its children
> > + * @context: struct acpi_eject_event pointer (freed in this func)
> > + *
> > + * Hot-remove a device and its children. This function frees up the
> > + * memory space passed by arg context, so that the caller may call
> > + * this function asynchronously through acpi_os_hotplug_execute().
> > + */
> > +void acpi_bus_hot_remove_device(void *context)
> > +{
> > +	struct acpi_eject_event *ej_event = context;
> > +	struct acpi_device *device = ej_event->device;
> > +	acpi_handle handle = device->handle;
> > +	u32 ost_code = ACPI_OST_SC_SUCCESS;
> > +	int error;
> > +
> > +	mutex_lock(&acpi_scan_lock);
> > +
> > +	error = acpi_scan_hot_remove(device);
> > +	if (error)
> > +		ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
> > +
> > +	acpi_evaluate_hotplug_ost(handle, ej_event->event, ost_code, NULL);
> > +
> >   	mutex_unlock(&acpi_scan_lock);
> >   	kfree(context);
> > -	return;
> >   }
> >   EXPORT_SYMBOL(acpi_bus_hot_remove_device);
> >
> > @@ -206,50 +337,48 @@ static ssize_t
> >   acpi_eject_store(struct device *d, struct device_attribute *attr,
> >   		const char *buf, size_t count)
> >   {
> > -	int ret = count;
> > -	acpi_status status;
> > -	acpi_object_type type = 0;
> >   	struct acpi_device *acpi_device = to_acpi_device(d);
> > -	struct acpi_eject_event *ej_event;
> > +	acpi_object_type not_used;
> > +	acpi_status status;
> > +	u32 ost_source;
> > +	u32 ost_code;
> > +	int ret;
> >
> > -	if ((!count) || (buf[0] != '1')) {
> > +	if (!count || buf[0] != '1')
> >   		return -EINVAL;
> > -	}
> > -	if (!acpi_device->driver && !acpi_device->handler) {
> > -		ret = -ENODEV;
> > -		goto err;
> > -	}
> > -	status = acpi_get_type(acpi_device->handle, &type);
> > -	if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) {
> > -		ret = -ENODEV;
> > -		goto err;
> > -	}
> >
> > -	ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
> > -	if (!ej_event) {
> > -		ret = -ENOMEM;
> > -		goto err;
> > -	}
> > +	if ((!acpi_device->handler || !acpi_device->handler->hotplug.enabled)
> > +	    && !acpi_device->driver)
> > +		return -ENODEV;
> > +
> > +	status = acpi_get_type(acpi_device->handle, &not_used);
> > +	if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable)
> > +		return -ENODEV;
> > +
> > +	mutex_lock(&acpi_scan_lock);
> >
> > -	get_device(&acpi_device->dev);
> > -	ej_event->device = acpi_device;
> >   	if (acpi_device->flags.eject_pending) {
> > -		/* event originated from ACPI eject notification */
> > -		ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
> > +		/* ACPI eject notification event. */
> > +		ost_source = ACPI_NOTIFY_EJECT_REQUEST;
> >   		acpi_device->flags.eject_pending = 0;
> >   	} else {
> > -		/* event originated from user */
> > -		ej_event->event = ACPI_OST_EC_OSPM_EJECT;
> > -		(void) acpi_evaluate_hotplug_ost(acpi_device->handle,
> > -			ej_event->event, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
> > +		/* Eject initiated by user space. */
> > +		ost_source = ACPI_OST_EC_OSPM_EJECT;
> >   	}
> > -
> 
> > -	status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event);
> > -	if (ACPI_FAILURE(status)) {
> > -		put_device(&acpi_device->dev);
> > -		kfree(ej_event);
> > +	acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source,
> > +				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
> > +	get_device(&acpi_device->dev);
> > +	ret = acpi_scan_hot_remove(acpi_device);
> 
> Why don't you use acpi_os_hotplug_execute()? Do you have some reason?

Yes, I do.  acpi_eject_store() is run in a separate thread anyway (started by
user space), so there's no need to use the workqueue for delayed execution here
and we are under acpi_scan_lock anyway, so there shouldn't be any concurrency
issues.

Thanks,
Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-19  7:10     ` Yasuaki Ishimatsu
@ 2013-02-20 13:27       ` Rafael J. Wysocki
  0 siblings, 0 replies; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-20 13:27 UTC (permalink / raw)
  To: Yasuaki Ishimatsu
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Yinghai Lu,
	Toshi Kani, Jiang Liu

On Tuesday, February 19, 2013 04:10:15 PM Yasuaki Ishimatsu wrote:
> 2013/02/19 15:43, Yasuaki Ishimatsu wrote:
> > Hi Rafael,
> >
> > I have comments. Please see below.
> >
> > 2013/02/18 0:21, Rafael J. Wysocki wrote:
> >> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> >>
> >> Multiple drivers handling hotplug-capable ACPI device nodes install
> >> notify handlers covering the same types of events in a very similar
> >> way.  Moreover, those handlers are installed in separate namespace
> >> walks, although that really should be done during namespace scans
> >> carried out by acpi_bus_scan().  This leads to substantial code
> >> duplication, unnecessary overhead and behavior that is hard to
> >> follow.
> >>
> >> For this reason, introduce common code in drivers/acpi/scan.c for
> >> handling hotplug-related notification and carrying out device
> >> insertion and eject operations in a generic fashion, such that it
> >> may be used by all of the relevant drivers in the future.  To cover
> >> the existing differences between those drivers introduce struct
> >> acpi_hotplug_profile for representing collections of hotplug
> >> settings associated with different ACPI scan handlers that can be
> >> used by the drivers to make the common code reflect their current
> >> behavior.
> >>
> >> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> >> ---
> >>   drivers/acpi/scan.c     |  271 +++++++++++++++++++++++++++++++++++++-----------
> >>   include/acpi/acpi_bus.h |    7 +
> >>   2 files changed, 220 insertions(+), 58 deletions(-)
> >>
[...]
> 
> >> +static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
> >> +{
> >> +    struct acpi_device *device = NULL;
> >> +    u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
> >> +    int error;
> >> +
> >> +    mutex_lock(&acpi_scan_lock);
> >> +
> >> +    acpi_bus_get_device(handle, &device);
> >> +    if (device) {
> >> +        dev_warn(&device->dev, "Attempt to re-insert\n");
> >> +        goto out;
> >> +    }
> >> +    acpi_evaluate_hotplug_ost(handle, ost_source,
> >> +                  ACPI_OST_SC_INSERT_IN_PROGRESS, NULL);
> >> +    ost_source = ACPI_OST_EC_OSPM_INSERTION;
> >> +    error = acpi_bus_scan(handle);
> >> +    if (error) {
> >> +        acpi_handle_warn(handle, "Namespace scan failure\n");
> >> +        goto out;
> >> +    }
> >> +    error = acpi_bus_get_device(handle, &device);
> >> +    if (error) {
> >> +        acpi_handle_warn(handle, "Missing device node object\n");
> >> +        goto out;
> >> +    }
> >> +    ost_code = ACPI_OST_SC_SUCCESS;
> >> +    if (device->handler && device->handler->hotplug.uevents)
> >> +        kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
> >>
> >>    out:
> >> +    acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL);
> >> +    mutex_unlock(&acpi_scan_lock);
> >> +}
> 
> Why don't you check _STA method in acpi_scan_bus_device_check()?
> When hot adding new device, we must check _STA method of the device.

Yes, which is going to happen in acpi_bus_scan().

Thanks,
Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-20 13:23     ` Rafael J. Wysocki
@ 2013-02-20 20:23       ` Toshi Kani
  2013-02-20 21:17         ` Rafael J. Wysocki
  0 siblings, 1 reply; 69+ messages in thread
From: Toshi Kani @ 2013-02-20 20:23 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Yasuaki Ishimatsu, ACPI Devel Maling List, Bjorn Helgaas, LKML,
	Yinghai Lu, Jiang Liu

On Wed, 2013-02-20 at 14:23 +0100, Rafael J. Wysocki wrote:
> On Tuesday, February 19, 2013 03:43:08 PM Yasuaki Ishimatsu wrote:
 :
> > 
> > > -	status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event);
> > > -	if (ACPI_FAILURE(status)) {
> > > -		put_device(&acpi_device->dev);
> > > -		kfree(ej_event);
> > > +	acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source,
> > > +				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
> > > +	get_device(&acpi_device->dev);
> > > +	ret = acpi_scan_hot_remove(acpi_device);
> > 
> > Why don't you use acpi_os_hotplug_execute()? Do you have some reason?
> 
> Yes, I do.  acpi_eject_store() is run in a separate thread anyway (started by
> user space), so there's no need to use the workqueue for delayed execution here
> and we are under acpi_scan_lock anyway, so there shouldn't be any concurrency
> issues.

Well, there is an issue...  I just tested your patchset and hit the
following hang when I tried to delete a container through its sysfs
eject.  This thread got stuck in trying to delete the sysfs eject file
of the container.  I believe this is because the shell is still opening
this sysfs eject file.

PID: 1518   TASK: ffff88005f09c950  CPU: 1   COMMAND: "bash"
 #0 [ffff88003392baf8] __schedule at ffffffff8151ba75
 #1 [ffff88003392bb70] schedule at ffffffff8151bdc7
 #2 [ffff88003392bb80] schedule_timeout at ffffffff8151aa55
 #3 [ffff88003392bc00] wait_for_common at ffffffff8151bc43
 #4 [ffff88003392bc70] wait_for_completion at ffffffff8151bd60
 #5 [ffff88003392bc80] sysfs_addrm_finish at ffffffff811984ad
 #6 [ffff88003392bcd0] sysfs_hash_and_remove at ffffffff81196deb
 #7 [ffff88003392bd10] sysfs_remove_file at ffffffff81197051
 #8 [ffff88003392bd40] device_remove_file at ffffffff81332950
 #9 [ffff88003392bd50] acpi_device_unregister at ffffffff812a0556
#10 [ffff88003392bd80] acpi_bus_remove at ffffffff812a0658
#11 [ffff88003392bda0] acpi_bus_trim at ffffffff812a090e
#12 [ffff88003392bdd0] acpi_scan_hot_remove at ffffffff812a09c9
#13 [ffff88003392be30] acpi_eject_store at ffffffff812a0b45
#14 [ffff88003392be70] dev_attr_store at ffffffff81332038
#15 [ffff88003392be80] sysfs_write_file at ffffffff81197212
#16 [ffff88003392bee0] vfs_write at ffffffff8113a3cb
#17 [ffff88003392bf20] sys_write at ffffffff8113a5fd
#18 [ffff88003392bf80] system_call_fastpath at ffffffff81523759
    RIP: 00000033a16e4950  RSP: 00007fff4a5f5368  RFLAGS: 00000206
    RAX: 0000000000000001  RBX: ffffffff81523759  RCX: ffffffffffffffff
    RDX: 0000000000000002  RSI: 00007f2f8a3d8000  RDI: 0000000000000001
    RBP: 00007f2f8a3d8000   R8: 000000000000000a   R9: 00007f2f8a3c4740
    R10: 00007f2f8a3c4740  R11: 0000000000000246  R12: 00000033a19b1260
    R13: 0000000000000002  R14: ffff880000000000  R15: ffff88003395d680
    ORIG_RAX: 0000000000000001  CS: 0033  SS: 002b

Thanks,
-Toshi



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-20 20:23       ` Toshi Kani
@ 2013-02-20 21:17         ` Rafael J. Wysocki
  0 siblings, 0 replies; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-20 21:17 UTC (permalink / raw)
  To: Toshi Kani
  Cc: Yasuaki Ishimatsu, ACPI Devel Maling List, Bjorn Helgaas, LKML,
	Yinghai Lu, Jiang Liu

On Wednesday, February 20, 2013 01:23:34 PM Toshi Kani wrote:
> On Wed, 2013-02-20 at 14:23 +0100, Rafael J. Wysocki wrote:
> > On Tuesday, February 19, 2013 03:43:08 PM Yasuaki Ishimatsu wrote:
>  :
> > > 
> > > > -	status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event);
> > > > -	if (ACPI_FAILURE(status)) {
> > > > -		put_device(&acpi_device->dev);
> > > > -		kfree(ej_event);
> > > > +	acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source,
> > > > +				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
> > > > +	get_device(&acpi_device->dev);
> > > > +	ret = acpi_scan_hot_remove(acpi_device);
> > > 
> > > Why don't you use acpi_os_hotplug_execute()? Do you have some reason?
> > 
> > Yes, I do.  acpi_eject_store() is run in a separate thread anyway (started by
> > user space), so there's no need to use the workqueue for delayed execution here
> > and we are under acpi_scan_lock anyway, so there shouldn't be any concurrency
> > issues.
> 
> Well, there is an issue...  I just tested your patchset and hit the
> following hang when I tried to delete a container through its sysfs
> eject.  This thread got stuck in trying to delete the sysfs eject file
> of the container.  I believe this is because the shell is still opening
> this sysfs eject file.

You're right.

> PID: 1518   TASK: ffff88005f09c950  CPU: 1   COMMAND: "bash"
>  #0 [ffff88003392baf8] __schedule at ffffffff8151ba75
>  #1 [ffff88003392bb70] schedule at ffffffff8151bdc7
>  #2 [ffff88003392bb80] schedule_timeout at ffffffff8151aa55
>  #3 [ffff88003392bc00] wait_for_common at ffffffff8151bc43
>  #4 [ffff88003392bc70] wait_for_completion at ffffffff8151bd60
>  #5 [ffff88003392bc80] sysfs_addrm_finish at ffffffff811984ad
>  #6 [ffff88003392bcd0] sysfs_hash_and_remove at ffffffff81196deb
>  #7 [ffff88003392bd10] sysfs_remove_file at ffffffff81197051
>  #8 [ffff88003392bd40] device_remove_file at ffffffff81332950
>  #9 [ffff88003392bd50] acpi_device_unregister at ffffffff812a0556
> #10 [ffff88003392bd80] acpi_bus_remove at ffffffff812a0658
> #11 [ffff88003392bda0] acpi_bus_trim at ffffffff812a090e
> #12 [ffff88003392bdd0] acpi_scan_hot_remove at ffffffff812a09c9
> #13 [ffff88003392be30] acpi_eject_store at ffffffff812a0b45
> #14 [ffff88003392be70] dev_attr_store at ffffffff81332038
> #15 [ffff88003392be80] sysfs_write_file at ffffffff81197212
> #16 [ffff88003392bee0] vfs_write at ffffffff8113a3cb
> #17 [ffff88003392bf20] sys_write at ffffffff8113a5fd
> #18 [ffff88003392bf80] system_call_fastpath at ffffffff81523759
>     RIP: 00000033a16e4950  RSP: 00007fff4a5f5368  RFLAGS: 00000206
>     RAX: 0000000000000001  RBX: ffffffff81523759  RCX: ffffffffffffffff
>     RDX: 0000000000000002  RSI: 00007f2f8a3d8000  RDI: 0000000000000001
>     RBP: 00007f2f8a3d8000   R8: 000000000000000a   R9: 00007f2f8a3c4740
>     R10: 00007f2f8a3c4740  R11: 0000000000000246  R12: 00000033a19b1260
>     R13: 0000000000000002  R14: ffff880000000000  R15: ffff88003395d680
>     ORIG_RAX: 0000000000000001  CS: 0033  SS: 002b

Well, admittedly, I didn't think about this situation.

Since the eject attribute is under the device we're going to remove, the
removal has to be done from a different thread (e.g. workqueue).

OK, I'll fix up the patch.

Thanks,
Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH 7/7] ACPI / scan: Make memory hotplug driver use struct acpi_scan_handler
  2013-02-20 10:42       ` Vasilis Liaskovitis
@ 2013-02-20 21:50         ` Toshi Kani
  2013-02-20 22:29           ` Rafael J. Wysocki
  2013-02-21  6:58         ` Yasuaki Ishimatsu
  1 sibling, 1 reply; 69+ messages in thread
From: Toshi Kani @ 2013-02-20 21:50 UTC (permalink / raw)
  To: Vasilis Liaskovitis
  Cc: Yasuaki Ishimatsu, Rafael J. Wysocki, ACPI Devel Maling List,
	Bjorn Helgaas, LKML, Yinghai Lu, Jiang Liu

On Wed, 2013-02-20 at 11:42 +0100, Vasilis Liaskovitis wrote:
> Hi Yasuaki,
> 
> On Wed, Feb 20, 2013 at 12:35:48PM +0900, Yasuaki Ishimatsu wrote:
> > Hi Vasilis,
> > 
> > 2013/02/20 3:11, Vasilis Liaskovitis wrote:
> > >Hi,
> > >
> > >On Sun, Feb 17, 2013 at 04:27:18PM +0100, Rafael J. Wysocki wrote:
> > >>From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > >>
> > >>Make the ACPI memory hotplug driver use struct acpi_scan_handler
> > >>for representing the object used to set up ACPI memory hotplug
> > >>functionality and to remove hotplug memory ranges and data
> > >>structures used by the driver before unregistering ACPI device
> > >>nodes representing memory.  Register the new struct acpi_scan_handler
> > >>object with the help of acpi_scan_add_handler_with_hotplug() to allow
> > >>user space to manipulate the attributes of the memory hotplug
> > >>profile.
> > >
> > >Let's consider an example where we want acpi memory device ejection to be safely
> > >handled by userspace. We do the following:
> > >
> > >echo 0 > /sys/firmware/acpi/hotplug/memory/autoeject
> > >echo 1 > /sys/firmware/acpi/hotplug/memory/uevents
> > >
> > >We succesfully hotplug acpi device:
> > >/sys/devices/LNXSYSTM:00/LNXSYSBUS:00/PNP0C80:00
> > >and its corresponding memblocks /sys/devices/system/memory/memoryXX are
> > >also successfully onlined.
> > >
> > >On an eject request, since uevents == 1, the kernel will emit KOBJ_OFFLINE for:
> > >/sys/devices/LNXSYSTM:00/LNXSYSBUS:00/PNP0C80:00
> > >
> > >Can userspace know which memblocks in /sys/devices/system/memory/memoryXX/
> > >correspond to the acpi device /sys/devices/LNXSYSTM:00/LNXSYSBUS:00/PNP0C80:00 ?
> > >This will be needed so that userspace tries to offline the memblocks (and only
> > >if successful, issue the eject operation on the acpi device). As far as I see,
> > >we don't create any sysfs links or files for this scenario - can userspace get
> > >this info somehow?
> > 
> > >
> > >/sys/devices/system/memory/memoryXX/phys_device needs to be properly implemented
> > >for this to work I think, see Documentation/ABI/testing/sysfs-memory
> > >
> > >The following test patch works toward that direction. Let me know if it's of
> > >interest or if there are better ideas /comments.
> > 
> > How about use ../PNP0C80:00/physical_node/resources file?
> > In my system, the file shows following information.
> > 
> > $ cat /sys/bus/acpi/devices/PNP0C80\:00/physical_node/resources
> > state = active
> > mem 0x0-0x80000000
> > mem 0x100000000-0x800000000
> > 
> > It means PNP0C80:00's memory ranges are "0x0-0x7fffffff" and
> > "0x100000000-0x7ffffffff". In x86 architecture, memory section size is
> > 128MiB. So, if these memory range is divided by 128MiB, you can
> > calculate memory section number as follow:
> > 
> > 0x0-0x7fffffff => 0x0-0x10
> > 0x100000000-0x7ffffffff => 0x20-0xff
> > 
> > But there is one problem. The problem is that resources file of added memory
> > is not created. If the problem is fixed, I think you can use the way.
> 
> thanks for your suggestion. Is this resources file a property of the
> physical_node or of each acpi devices? 
> 
> If it's a node specific file could there be a chance that adjacent memory
> ranges get merged? We 'd like these to not get merged.
> 
> I will look more into this property. I don't see it currently in my system
> (probably because initial memory is not backed by acpi devices in my
>  seabios/virtual machine).

I have been thinking about this issue as well.  In case of CPUs, we have
a sysdev link that links LNXCPU:%d to its system/cpu/cpu%d file.

/sys/bus/acpi/devices/LNXCPU:02 > ll sysdev
lrwxrwxrwx. 1 root root 0 Feb  8 13:52 sysdev -> ../../system/cpu/cpu2

So, one possible approach is to create a sysdev directory under
PNP0C080:%d, and then create links to associated system/cpu/memory%d
files underneath.  What do you think?

Thanks,
-Toshi



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH 7/7] ACPI / scan: Make memory hotplug driver use struct acpi_scan_handler
  2013-02-20 21:50         ` Toshi Kani
@ 2013-02-20 22:29           ` Rafael J. Wysocki
  2013-02-20 22:39             ` Toshi Kani
  0 siblings, 1 reply; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-20 22:29 UTC (permalink / raw)
  To: Toshi Kani
  Cc: Vasilis Liaskovitis, Yasuaki Ishimatsu, ACPI Devel Maling List,
	Bjorn Helgaas, LKML, Yinghai Lu, Jiang Liu

On Wednesday, February 20, 2013 02:50:12 PM Toshi Kani wrote:
> On Wed, 2013-02-20 at 11:42 +0100, Vasilis Liaskovitis wrote:
> > Hi Yasuaki,
> > 
> > On Wed, Feb 20, 2013 at 12:35:48PM +0900, Yasuaki Ishimatsu wrote:
> > > Hi Vasilis,
> > > 
> > > 2013/02/20 3:11, Vasilis Liaskovitis wrote:
> > > >Hi,
> > > >
> > > >On Sun, Feb 17, 2013 at 04:27:18PM +0100, Rafael J. Wysocki wrote:
> > > >>From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > > >>
> > > >>Make the ACPI memory hotplug driver use struct acpi_scan_handler
> > > >>for representing the object used to set up ACPI memory hotplug
> > > >>functionality and to remove hotplug memory ranges and data
> > > >>structures used by the driver before unregistering ACPI device
> > > >>nodes representing memory.  Register the new struct acpi_scan_handler
> > > >>object with the help of acpi_scan_add_handler_with_hotplug() to allow
> > > >>user space to manipulate the attributes of the memory hotplug
> > > >>profile.
> > > >
> > > >Let's consider an example where we want acpi memory device ejection to be safely
> > > >handled by userspace. We do the following:
> > > >
> > > >echo 0 > /sys/firmware/acpi/hotplug/memory/autoeject
> > > >echo 1 > /sys/firmware/acpi/hotplug/memory/uevents
> > > >
> > > >We succesfully hotplug acpi device:
> > > >/sys/devices/LNXSYSTM:00/LNXSYSBUS:00/PNP0C80:00
> > > >and its corresponding memblocks /sys/devices/system/memory/memoryXX are
> > > >also successfully onlined.
> > > >
> > > >On an eject request, since uevents == 1, the kernel will emit KOBJ_OFFLINE for:
> > > >/sys/devices/LNXSYSTM:00/LNXSYSBUS:00/PNP0C80:00
> > > >
> > > >Can userspace know which memblocks in /sys/devices/system/memory/memoryXX/
> > > >correspond to the acpi device /sys/devices/LNXSYSTM:00/LNXSYSBUS:00/PNP0C80:00 ?
> > > >This will be needed so that userspace tries to offline the memblocks (and only
> > > >if successful, issue the eject operation on the acpi device). As far as I see,
> > > >we don't create any sysfs links or files for this scenario - can userspace get
> > > >this info somehow?
> > > 
> > > >
> > > >/sys/devices/system/memory/memoryXX/phys_device needs to be properly implemented
> > > >for this to work I think, see Documentation/ABI/testing/sysfs-memory
> > > >
> > > >The following test patch works toward that direction. Let me know if it's of
> > > >interest or if there are better ideas /comments.
> > > 
> > > How about use ../PNP0C80:00/physical_node/resources file?
> > > In my system, the file shows following information.
> > > 
> > > $ cat /sys/bus/acpi/devices/PNP0C80\:00/physical_node/resources
> > > state = active
> > > mem 0x0-0x80000000
> > > mem 0x100000000-0x800000000
> > > 
> > > It means PNP0C80:00's memory ranges are "0x0-0x7fffffff" and
> > > "0x100000000-0x7ffffffff". In x86 architecture, memory section size is
> > > 128MiB. So, if these memory range is divided by 128MiB, you can
> > > calculate memory section number as follow:
> > > 
> > > 0x0-0x7fffffff => 0x0-0x10
> > > 0x100000000-0x7ffffffff => 0x20-0xff
> > > 
> > > But there is one problem. The problem is that resources file of added memory
> > > is not created. If the problem is fixed, I think you can use the way.
> > 
> > thanks for your suggestion. Is this resources file a property of the
> > physical_node or of each acpi devices? 
> > 
> > If it's a node specific file could there be a chance that adjacent memory
> > ranges get merged? We 'd like these to not get merged.
> > 
> > I will look more into this property. I don't see it currently in my system
> > (probably because initial memory is not backed by acpi devices in my
> >  seabios/virtual machine).
> 
> I have been thinking about this issue as well.  In case of CPUs, we have
> a sysdev link that links LNXCPU:%d to its system/cpu/cpu%d file.
> 
> /sys/bus/acpi/devices/LNXCPU:02 > ll sysdev
> lrwxrwxrwx. 1 root root 0 Feb  8 13:52 sysdev -> ../../system/cpu/cpu2
> 
> So, one possible approach is to create a sysdev directory under
> PNP0C080:%d, and then create links to associated system/cpu/memory%d
> files underneath.  What do you think?

I need to think about that a bit more, quite frankly.

I probably would prefer links to be created directly from under PNP0C080:%d
to system/cpu/memory%d (in analogy with PCI and other devices having ACPI
companions).

One of the problems here is that the whole /sys/bus/acpi/ stuff is kind of
confusing, because it makes people think that there's an "ACPI bus", while
there's no such thing.  For this reason, it should go away and the
/sys/devices/LNXSYSTM:00/ directory should be moved somewhere under
/sys/firmware/acpi/.  Of course, that's long-term, but this means I'd prefer
not to add more stuff under /sys/devices/LNXSYSTM:00/ that may potentially
cause that to be more difficult to do in the future.

Thanks,
Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH 7/7] ACPI / scan: Make memory hotplug driver use struct acpi_scan_handler
  2013-02-20 22:29           ` Rafael J. Wysocki
@ 2013-02-20 22:39             ` Toshi Kani
  0 siblings, 0 replies; 69+ messages in thread
From: Toshi Kani @ 2013-02-20 22:39 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Vasilis Liaskovitis, Yasuaki Ishimatsu, ACPI Devel Maling List,
	Bjorn Helgaas, LKML, Yinghai Lu, Jiang Liu

On Wed, 2013-02-20 at 23:29 +0100, Rafael J. Wysocki wrote:
> On Wednesday, February 20, 2013 02:50:12 PM Toshi Kani wrote:
> > On Wed, 2013-02-20 at 11:42 +0100, Vasilis Liaskovitis wrote:
> > > Hi Yasuaki,
> > > 
> > > On Wed, Feb 20, 2013 at 12:35:48PM +0900, Yasuaki Ishimatsu wrote:
> > > > Hi Vasilis,
> > > > 
> > > > 2013/02/20 3:11, Vasilis Liaskovitis wrote:
> > > > >Hi,
> > > > >
> > > > >On Sun, Feb 17, 2013 at 04:27:18PM +0100, Rafael J. Wysocki wrote:
> > > > >>From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > > > >>
> > > > >>Make the ACPI memory hotplug driver use struct acpi_scan_handler
> > > > >>for representing the object used to set up ACPI memory hotplug
> > > > >>functionality and to remove hotplug memory ranges and data
> > > > >>structures used by the driver before unregistering ACPI device
> > > > >>nodes representing memory.  Register the new struct acpi_scan_handler
> > > > >>object with the help of acpi_scan_add_handler_with_hotplug() to allow
> > > > >>user space to manipulate the attributes of the memory hotplug
> > > > >>profile.
> > > > >
> > > > >Let's consider an example where we want acpi memory device ejection to be safely
> > > > >handled by userspace. We do the following:
> > > > >
> > > > >echo 0 > /sys/firmware/acpi/hotplug/memory/autoeject
> > > > >echo 1 > /sys/firmware/acpi/hotplug/memory/uevents
> > > > >
> > > > >We succesfully hotplug acpi device:
> > > > >/sys/devices/LNXSYSTM:00/LNXSYSBUS:00/PNP0C80:00
> > > > >and its corresponding memblocks /sys/devices/system/memory/memoryXX are
> > > > >also successfully onlined.
> > > > >
> > > > >On an eject request, since uevents == 1, the kernel will emit KOBJ_OFFLINE for:
> > > > >/sys/devices/LNXSYSTM:00/LNXSYSBUS:00/PNP0C80:00
> > > > >
> > > > >Can userspace know which memblocks in /sys/devices/system/memory/memoryXX/
> > > > >correspond to the acpi device /sys/devices/LNXSYSTM:00/LNXSYSBUS:00/PNP0C80:00 ?
> > > > >This will be needed so that userspace tries to offline the memblocks (and only
> > > > >if successful, issue the eject operation on the acpi device). As far as I see,
> > > > >we don't create any sysfs links or files for this scenario - can userspace get
> > > > >this info somehow?
> > > > 
> > > > >
> > > > >/sys/devices/system/memory/memoryXX/phys_device needs to be properly implemented
> > > > >for this to work I think, see Documentation/ABI/testing/sysfs-memory
> > > > >
> > > > >The following test patch works toward that direction. Let me know if it's of
> > > > >interest or if there are better ideas /comments.
> > > > 
> > > > How about use ../PNP0C80:00/physical_node/resources file?
> > > > In my system, the file shows following information.
> > > > 
> > > > $ cat /sys/bus/acpi/devices/PNP0C80\:00/physical_node/resources
> > > > state = active
> > > > mem 0x0-0x80000000
> > > > mem 0x100000000-0x800000000
> > > > 
> > > > It means PNP0C80:00's memory ranges are "0x0-0x7fffffff" and
> > > > "0x100000000-0x7ffffffff". In x86 architecture, memory section size is
> > > > 128MiB. So, if these memory range is divided by 128MiB, you can
> > > > calculate memory section number as follow:
> > > > 
> > > > 0x0-0x7fffffff => 0x0-0x10
> > > > 0x100000000-0x7ffffffff => 0x20-0xff
> > > > 
> > > > But there is one problem. The problem is that resources file of added memory
> > > > is not created. If the problem is fixed, I think you can use the way.
> > > 
> > > thanks for your suggestion. Is this resources file a property of the
> > > physical_node or of each acpi devices? 
> > > 
> > > If it's a node specific file could there be a chance that adjacent memory
> > > ranges get merged? We 'd like these to not get merged.
> > > 
> > > I will look more into this property. I don't see it currently in my system
> > > (probably because initial memory is not backed by acpi devices in my
> > >  seabios/virtual machine).
> > 
> > I have been thinking about this issue as well.  In case of CPUs, we have
> > a sysdev link that links LNXCPU:%d to its system/cpu/cpu%d file.
> > 
> > /sys/bus/acpi/devices/LNXCPU:02 > ll sysdev
> > lrwxrwxrwx. 1 root root 0 Feb  8 13:52 sysdev -> ../../system/cpu/cpu2
> > 
> > So, one possible approach is to create a sysdev directory under
> > PNP0C080:%d, and then create links to associated system/cpu/memory%d
> > files underneath.  What do you think?
> 
> I need to think about that a bit more, quite frankly.
> 
> I probably would prefer links to be created directly from under PNP0C080:%d
> to system/cpu/memory%d (in analogy with PCI and other devices having ACPI
> companions).
> 
> One of the problems here is that the whole /sys/bus/acpi/ stuff is kind of
> confusing, because it makes people think that there's an "ACPI bus", while
> there's no such thing.  For this reason, it should go away and the
> /sys/devices/LNXSYSTM:00/ directory should be moved somewhere under
> /sys/firmware/acpi/.  Of course, that's long-term, but this means I'd prefer
> not to add more stuff under /sys/devices/LNXSYSTM:00/ that may potentially
> cause that to be more difficult to do in the future.

I see.  I think PCI creates files under PNP0A08:%d/physical_node.
Either way, we need to do something in this space.  I will think about a
bit more as well.

Thanks,
-Toshi


^ permalink raw reply	[flat|nested] 69+ messages in thread

* [Update][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-17 15:21 ` [PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug Rafael J. Wysocki
  2013-02-19  6:43   ` Yasuaki Ishimatsu
@ 2013-02-20 22:49   ` Rafael J. Wysocki
  2013-02-21  1:17     ` Toshi Kani
  2013-02-21 15:52     ` [Update 2][PATCH " Rafael J. Wysocki
  1 sibling, 2 replies; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-20 22:49 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Yinghai Lu, Toshi Kani, Yasuaki Ishimatsu,
	Jiang Liu

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Multiple drivers handling hotplug-capable ACPI device nodes install
notify handlers covering the same types of events in a very similar
way.  Moreover, those handlers are installed in separate namespace
walks, although that really should be done during namespace scans
carried out by acpi_bus_scan().  This leads to substantial code
duplication, unnecessary overhead and behavior that is hard to
follow.

For this reason, introduce common code in drivers/acpi/scan.c for
handling hotplug-related notification and carrying out device
insertion and eject operations in a generic fashion, such that it
may be used by all of the relevant drivers in the future.  To cover
the existing differences between those drivers introduce struct
acpi_hotplug_profile for representing collections of hotplug
settings associated with different ACPI scan handlers that can be
used by the drivers to make the common code reflect their current
behavior.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---

This version addresses issues pointed out by Yasuaki Ishimatsu (ordering of
the uevent vs acpi_scan_hot_remove() in acpi_bus_device_eject()) and Toshi
Kani (deadlock in acpi_eject_store caused by attmepting to remove the
"eject" attribute while executing its store callback).

Thanks,
Rafael

---
 drivers/acpi/scan.c     |  278 ++++++++++++++++++++++++++++++++++++++----------
 include/acpi/acpi_bus.h |    7 +
 2 files changed, 231 insertions(+), 54 deletions(-)

Index: test/include/acpi/acpi_bus.h
===================================================================
--- test.orig/include/acpi/acpi_bus.h
+++ test/include/acpi/acpi_bus.h
@@ -88,11 +88,18 @@ struct acpi_device;
  * -----------------
  */
 
+struct acpi_hotplug_profile {
+	bool enabled:1;
+	bool uevents:1;
+	bool autoeject:1;
+};
+
 struct acpi_scan_handler {
 	const struct acpi_device_id *ids;
 	struct list_head list_node;
 	int (*attach)(struct acpi_device *dev, const struct acpi_device_id *id);
 	void (*detach)(struct acpi_device *dev);
+	struct acpi_hotplug_profile hotplug;
 };
 
 /*
Index: test/drivers/acpi/scan.c
===================================================================
--- test.orig/drivers/acpi/scan.c
+++ test/drivers/acpi/scan.c
@@ -107,32 +107,19 @@ acpi_device_modalias_show(struct device
 }
 static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
 
-/**
- * acpi_bus_hot_remove_device: hot-remove a device and its children
- * @context: struct acpi_eject_event pointer (freed in this func)
- *
- * Hot-remove a device and its children. This function frees up the
- * memory space passed by arg context, so that the caller may call
- * this function asynchronously through acpi_os_hotplug_execute().
- */
-void acpi_bus_hot_remove_device(void *context)
+static int acpi_scan_hot_remove(struct acpi_device *device)
 {
-	struct acpi_eject_event *ej_event = context;
-	struct acpi_device *device = ej_event->device;
 	acpi_handle handle = device->handle;
-	acpi_handle temp;
+	acpi_handle not_used;
 	struct acpi_object_list arg_list;
 	union acpi_object arg;
-	acpi_status status = AE_OK;
-	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
-
-	mutex_lock(&acpi_scan_lock);
+	acpi_status status;
 
 	/* If there is no handle, the device node has been unregistered. */
-	if (!device->handle) {
+	if (!handle) {
 		dev_dbg(&device->dev, "ACPI handle missing\n");
 		put_device(&device->dev);
-		goto out;
+		return -EINVAL;
 	}
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -143,7 +130,7 @@ void acpi_bus_hot_remove_device(void *co
 	put_device(&device->dev);
 	device = NULL;
 
-	if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &temp))) {
+	if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &not_used))) {
 		arg_list.count = 1;
 		arg_list.pointer = &arg;
 		arg.type = ACPI_TYPE_INTEGER;
@@ -161,18 +148,165 @@ void acpi_bus_hot_remove_device(void *co
 	 */
 	status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
 	if (ACPI_FAILURE(status)) {
-		if (status != AE_NOT_FOUND)
+		if (status == AE_NOT_FOUND) {
+			return -ENODEV;
+		} else {
 			acpi_handle_warn(handle, "Eject failed\n");
+			return -EIO;
+		}
+	}
+	return 0;
+}
+
+static void acpi_bus_device_eject(void *context)
+{
+	acpi_handle handle = context;
+	struct acpi_device *device = NULL;
+	struct acpi_scan_handler *handler;
+	u32 ost_source = ACPI_NOTIFY_EJECT_REQUEST;
+	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
+
+	mutex_lock(&acpi_scan_lock);
+
+	acpi_bus_get_device(handle, &device);
+	if (!device)
+		goto out;
+
+	handler = device->handler;
+	if (!handler || !handler->hotplug.enabled) {
+		ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
+		goto out;
+	}
+	acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
+				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+	if (handler->hotplug.autoeject) {
+		int error;
+
+		ost_source = ACPI_OST_EC_OSPM_EJECT;
+		get_device(&device->dev);
+		error = acpi_scan_hot_remove(device);
+		if (!error) {
+			ost_code = ACPI_OST_SC_SUCCESS;
+			if (handler->hotplug.uevents)
+				kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
+		}
+	} else {
+		device->flags.eject_pending = true;
+		if (handler->hotplug.uevents)
+			kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
 
-		/* Tell the firmware the hot-remove operation has failed. */
-		acpi_evaluate_hotplug_ost(handle, ej_event->event,
-					  ost_code, NULL);
+		goto out_unlock;
 	}
 
  out:
+	acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL);
+
+ out_unlock:
+	mutex_unlock(&acpi_scan_lock);
+}
+
+static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
+{
+	struct acpi_device *device = NULL;
+	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
+	int error;
+
+	mutex_lock(&acpi_scan_lock);
+
+	acpi_bus_get_device(handle, &device);
+	if (device) {
+		dev_warn(&device->dev, "Attempt to re-insert\n");
+		goto out;
+	}
+	acpi_evaluate_hotplug_ost(handle, ost_source,
+				  ACPI_OST_SC_INSERT_IN_PROGRESS, NULL);
+	ost_source = ACPI_OST_EC_OSPM_INSERTION;
+	error = acpi_bus_scan(handle);
+	if (error) {
+		acpi_handle_warn(handle, "Namespace scan failure\n");
+		goto out;
+	}
+	error = acpi_bus_get_device(handle, &device);
+	if (error) {
+		acpi_handle_warn(handle, "Missing device node object\n");
+		goto out;
+	}
+	ost_code = ACPI_OST_SC_SUCCESS;
+	if (device->handler && device->handler->hotplug.uevents)
+		kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
+
+ out:
+	acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL);
+	mutex_unlock(&acpi_scan_lock);
+}
+
+static void acpi_scan_bus_check(void *context)
+{
+	acpi_scan_bus_device_check((acpi_handle)context,
+				   ACPI_NOTIFY_BUS_CHECK);
+}
+
+static void acpi_scan_device_check(void *context)
+{
+	acpi_scan_bus_device_check((acpi_handle)context,
+				   ACPI_NOTIFY_DEVICE_CHECK);
+}
+
+static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *not_used)
+{
+	acpi_osd_exec_callback callback;
+	acpi_status status;
+
+	switch (type) {
+	case ACPI_NOTIFY_BUS_CHECK:
+		acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
+		callback = acpi_scan_bus_check;
+		break;
+	case ACPI_NOTIFY_DEVICE_CHECK:
+		acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
+		callback = acpi_scan_device_check;
+		break;
+	case ACPI_NOTIFY_EJECT_REQUEST:
+		acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
+		callback = acpi_bus_device_eject;
+		break;
+	default:
+		/* non-hotplug event; possibly handled by other handler */
+		return;
+	}
+	status = acpi_os_hotplug_execute(callback, handle);
+	if (ACPI_FAILURE(status))
+		acpi_evaluate_hotplug_ost(handle, type,
+					  ACPI_OST_SC_NON_SPECIFIC_FAILURE,
+					  NULL);
+}
+
+/**
+ * acpi_bus_hot_remove_device: hot-remove a device and its children
+ * @context: struct acpi_eject_event pointer (freed in this func)
+ *
+ * Hot-remove a device and its children. This function frees up the
+ * memory space passed by arg context, so that the caller may call
+ * this function asynchronously through acpi_os_hotplug_execute().
+ */
+void acpi_bus_hot_remove_device(void *context)
+{
+	struct acpi_eject_event *ej_event = context;
+	struct acpi_device *device = ej_event->device;
+	acpi_handle handle = device->handle;
+	u32 ost_code = ACPI_OST_SC_SUCCESS;
+	int error;
+
+	mutex_lock(&acpi_scan_lock);
+
+	error = acpi_scan_hot_remove(device);
+	if (error)
+		ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
+
+	acpi_evaluate_hotplug_ost(handle, ej_event->event, ost_code, NULL);
+
 	mutex_unlock(&acpi_scan_lock);
 	kfree(context);
-	return;
 }
 EXPORT_SYMBOL(acpi_bus_hot_remove_device);
 
@@ -206,50 +340,60 @@ static ssize_t
 acpi_eject_store(struct device *d, struct device_attribute *attr,
 		const char *buf, size_t count)
 {
-	int ret = count;
-	acpi_status status;
-	acpi_object_type type = 0;
 	struct acpi_device *acpi_device = to_acpi_device(d);
 	struct acpi_eject_event *ej_event;
+	acpi_object_type not_used;
+	acpi_status status;
+	u32 ost_source;
+	int ret;
 
-	if ((!count) || (buf[0] != '1')) {
+	if (!count || buf[0] != '1')
 		return -EINVAL;
-	}
-	if (!acpi_device->driver && !acpi_device->handler) {
-		ret = -ENODEV;
-		goto err;
-	}
-	status = acpi_get_type(acpi_device->handle, &type);
-	if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) {
-		ret = -ENODEV;
-		goto err;
-	}
 
-	ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
-	if (!ej_event) {
-		ret = -ENOMEM;
-		goto err;
-	}
+	if ((!acpi_device->handler || !acpi_device->handler->hotplug.enabled)
+	    && !acpi_device->driver)
+		return -ENODEV;
+
+	status = acpi_get_type(acpi_device->handle, &not_used);
+	if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable)
+		return -ENODEV;
+
+	mutex_lock(&acpi_scan_lock);
 
-	get_device(&acpi_device->dev);
-	ej_event->device = acpi_device;
 	if (acpi_device->flags.eject_pending) {
-		/* event originated from ACPI eject notification */
-		ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
+		/* ACPI eject notification event. */
+		ost_source = ACPI_NOTIFY_EJECT_REQUEST;
 		acpi_device->flags.eject_pending = 0;
 	} else {
-		/* event originated from user */
-		ej_event->event = ACPI_OST_EC_OSPM_EJECT;
-		(void) acpi_evaluate_hotplug_ost(acpi_device->handle,
-			ej_event->event, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+		/* Eject initiated by user space. */
+		ost_source = ACPI_OST_EC_OSPM_EJECT;
 	}
-
+	ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
+	if (!ej_event) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source,
+				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+	ej_event->device = acpi_device;
+	ej_event->event = ost_source;
+	get_device(&acpi_device->dev);
 	status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event);
-	if (ACPI_FAILURE(status)) {
+	if (ACPI_SUCCESS(status)) {
+		ret = count;
+		goto out_unlock;
+	} else {
 		put_device(&acpi_device->dev);
 		kfree(ej_event);
+		ret = status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN;
 	}
-err:
+
+ out:
+	acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source,
+				  ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
+
+ out_unlock:
+	mutex_unlock(&acpi_scan_lock);
 	return ret;
 }
 
@@ -1548,6 +1692,30 @@ static struct acpi_scan_handler *acpi_sc
 	return NULL;
 }
 
+static void acpi_scan_init_hotplug(acpi_handle handle)
+{
+	struct acpi_device_info *info;
+	struct acpi_scan_handler *handler;
+
+	if (ACPI_FAILURE(acpi_get_object_info(handle, &info)))
+		return;
+
+	if (!(info->valid & ACPI_VALID_HID)) {
+		kfree(info);
+		return;
+	}
+
+	/*
+	 * This relies on the fact that acpi_install_notify_handler() will not
+	 * install the same notify handler routine twice for the same handle.
+	 */
+	handler = acpi_scan_match_handler(info->hardware_id.string, NULL);
+	kfree(info);
+	if (handler && handler->hotplug.enabled)
+		acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+					    acpi_hotplug_notify_cb, NULL);
+}
+
 static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
 				      void *not_used, void **return_value)
 {
@@ -1570,6 +1738,8 @@ static acpi_status acpi_bus_check_add(ac
 		return AE_OK;
 	}
 
+	acpi_scan_init_hotplug(handle);
+
 	if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
 	    !(sta & ACPI_STA_DEVICE_FUNCTIONING)) {
 		struct acpi_device_wakeup wakeup;

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Update][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-20 22:49   ` [Update][PATCH " Rafael J. Wysocki
@ 2013-02-21  1:17     ` Toshi Kani
  2013-02-21 15:44       ` Rafael J. Wysocki
  2013-02-21 15:52     ` [Update 2][PATCH " Rafael J. Wysocki
  1 sibling, 1 reply; 69+ messages in thread
From: Toshi Kani @ 2013-02-21  1:17 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Yinghai Lu,
	Yasuaki Ishimatsu, Jiang Liu

On Wed, 2013-02-20 at 23:49 +0100, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
 :
> +
> +/**
> + * acpi_bus_hot_remove_device: hot-remove a device and its children
> + * @context: struct acpi_eject_event pointer (freed in this func)
> + *
> + * Hot-remove a device and its children. This function frees up the
> + * memory space passed by arg context, so that the caller may call
> + * this function asynchronously through acpi_os_hotplug_execute().
> + */
> +void acpi_bus_hot_remove_device(void *context)
> +{
> +	struct acpi_eject_event *ej_event = context;
> +	struct acpi_device *device = ej_event->device;
> +	acpi_handle handle = device->handle;
> +	u32 ost_code = ACPI_OST_SC_SUCCESS;
> +	int error;
> +
> +	mutex_lock(&acpi_scan_lock);
> +
> +	error = acpi_scan_hot_remove(device);
> +	if (error)
> +		ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
> +
> +	acpi_evaluate_hotplug_ost(handle, ej_event->event, ost_code, NULL);

Thanks for the quick update.  It fixed the deadlock issue. :-)  As it
now completes an eject operation, I found a new issue.  When the OS
called _EJ0, it is not supposed to call _OST since FW has already
received the completion status from _EJ0.  That is, the OS calls either
_EJ0 (success case) or _OST (failure case) for hot-delete. 

-Toshi



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH 7/7] ACPI / scan: Make memory hotplug driver use struct acpi_scan_handler
  2013-02-20 10:42       ` Vasilis Liaskovitis
  2013-02-20 21:50         ` Toshi Kani
@ 2013-02-21  6:58         ` Yasuaki Ishimatsu
  1 sibling, 0 replies; 69+ messages in thread
From: Yasuaki Ishimatsu @ 2013-02-21  6:58 UTC (permalink / raw)
  To: Vasilis Liaskovitis
  Cc: Rafael J. Wysocki, ACPI Devel Maling List, Bjorn Helgaas, LKML,
	Yinghai Lu, Toshi Kani, Jiang Liu

Hi Vasilis,

2013/02/20 19:42, Vasilis Liaskovitis wrote:
> Hi Yasuaki,
>
> On Wed, Feb 20, 2013 at 12:35:48PM +0900, Yasuaki Ishimatsu wrote:
>> Hi Vasilis,
>>
>> 2013/02/20 3:11, Vasilis Liaskovitis wrote:
>>> Hi,
>>>
>>> On Sun, Feb 17, 2013 at 04:27:18PM +0100, Rafael J. Wysocki wrote:
>>>> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>>>>
>>>> Make the ACPI memory hotplug driver use struct acpi_scan_handler
>>>> for representing the object used to set up ACPI memory hotplug
>>>> functionality and to remove hotplug memory ranges and data
>>>> structures used by the driver before unregistering ACPI device
>>>> nodes representing memory.  Register the new struct acpi_scan_handler
>>>> object with the help of acpi_scan_add_handler_with_hotplug() to allow
>>>> user space to manipulate the attributes of the memory hotplug
>>>> profile.
>>>
>>> Let's consider an example where we want acpi memory device ejection to be safely
>>> handled by userspace. We do the following:
>>>
>>> echo 0 > /sys/firmware/acpi/hotplug/memory/autoeject
>>> echo 1 > /sys/firmware/acpi/hotplug/memory/uevents
>>>
>>> We succesfully hotplug acpi device:
>>> /sys/devices/LNXSYSTM:00/LNXSYSBUS:00/PNP0C80:00
>>> and its corresponding memblocks /sys/devices/system/memory/memoryXX are
>>> also successfully onlined.
>>>
>>> On an eject request, since uevents == 1, the kernel will emit KOBJ_OFFLINE for:
>>> /sys/devices/LNXSYSTM:00/LNXSYSBUS:00/PNP0C80:00
>>>
>>> Can userspace know which memblocks in /sys/devices/system/memory/memoryXX/
>>> correspond to the acpi device /sys/devices/LNXSYSTM:00/LNXSYSBUS:00/PNP0C80:00 ?
>>> This will be needed so that userspace tries to offline the memblocks (and only
>>> if successful, issue the eject operation on the acpi device). As far as I see,
>>> we don't create any sysfs links or files for this scenario - can userspace get
>>> this info somehow?
>>
>>>
>>> /sys/devices/system/memory/memoryXX/phys_device needs to be properly implemented
>>> for this to work I think, see Documentation/ABI/testing/sysfs-memory
>>>
>>> The following test patch works toward that direction. Let me know if it's of
>>> interest or if there are better ideas /comments.
>>
>> How about use ../PNP0C80:00/physical_node/resources file?
>> In my system, the file shows following information.
>>
>> $ cat /sys/bus/acpi/devices/PNP0C80\:00/physical_node/resources
>> state = active
>> mem 0x0-0x80000000
>> mem 0x100000000-0x800000000
>>
>> It means PNP0C80:00's memory ranges are "0x0-0x7fffffff" and
>> "0x100000000-0x7ffffffff". In x86 architecture, memory section size is
>> 128MiB. So, if these memory range is divided by 128MiB, you can
>> calculate memory section number as follow:
>>
>> 0x0-0x7fffffff => 0x0-0x10
>> 0x100000000-0x7ffffffff => 0x20-0xff
>>
>> But there is one problem. The problem is that resources file of added memory
>> is not created. If the problem is fixed, I think you can use the way.
>

> thanks for your suggestion. Is this resources file a property of the
> physical_node or of each acpi devices?
>
> If it's a node specific file could there be a chance that adjacent memory
> ranges get merged? We 'd like these to not get merged.

This information is created by pnppacpi_init().
It seems that:
   - resources file is created to each acpi_devices.
   - the memory range does not get merged.

Thanks,
Yasuaki Ishimatsu
>
> I will look more into this property. I don't see it currently in my system
> (probably because initial memory is not backed by acpi devices in my
>   seabios/virtual machine).
>
>>
> [...]
>>> +int acpi_memory_phys_device(unsigned long start_pfn)
>>> +{
>>> +	struct acpi_memory_device *mem_dev;
>>> +	struct acpi_memory_info *info;
>>> +	unsigned long start_addr = start_pfn << PAGE_SHIFT;
>>> +	int id = 0;
>>> +
>>> +	list_for_each_entry(mem_dev, &acpi_mem_device_list, mem_device_list) {
>>> +		list_for_each_entry(info, &mem_dev->res_list, list) {
>>> +			if ((info->start_addr <= start_addr) &&
>>> +				(info->start_addr + info->length > start_addr))
>>> +				return id;
>>> +		}
>>> +		id++;
>>> +	}
>>
>> I don't think this solve your problem.
>>
>> When hot adding memory device in my system, consecutive index number is
>> applied to PNP0C80 as follows:
>>
>> $ ls /sys/bus/acpi/devices/ |grep PNP0C80
>> PNP0C80:00
>> PNP0C80:01  => hot added memory device
>> PNP0C80:02  => hot added memory device
>>
>> In this case, we can know PNP0C80:YY by memoryXX/phys_device file.
>> But if hot removing and adding the same device, index number is changed
>> as follows:
>>
>> $ ls /sys/bus/acpi/devices/
>> PNP0C80:00
>> PNP0C80:03  => hot added memory device
>> PNP0C80:04  => hot added memory device
>>
>> In this case, we cannot know PNP0C80:YY by memoryXX/phys_device file.
>>
>
> thanks, yes you are right. I forgot each new hotplug event will create a new
> PNP0C80:XX device where XX always increases. So the hot-add/hot-remove/hot-add
> scenario would have a problem.
> Then it would be enough to be able to return this monotonically increasing
> counter from phys_device instead of the current list iterator. Is this counter
> available somehwere in drivers/acpi/scan.c or bus.c? I 'll take a look.
>
> thanks,
>
> - Vasilis
>



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Update][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-21  1:17     ` Toshi Kani
@ 2013-02-21 15:44       ` Rafael J. Wysocki
  0 siblings, 0 replies; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-21 15:44 UTC (permalink / raw)
  To: Toshi Kani
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Yinghai Lu,
	Yasuaki Ishimatsu, Jiang Liu

On Wednesday, February 20, 2013 06:17:48 PM Toshi Kani wrote:
> On Wed, 2013-02-20 at 23:49 +0100, Rafael J. Wysocki wrote:
> > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>  :
> > +
> > +/**
> > + * acpi_bus_hot_remove_device: hot-remove a device and its children
> > + * @context: struct acpi_eject_event pointer (freed in this func)
> > + *
> > + * Hot-remove a device and its children. This function frees up the
> > + * memory space passed by arg context, so that the caller may call
> > + * this function asynchronously through acpi_os_hotplug_execute().
> > + */
> > +void acpi_bus_hot_remove_device(void *context)
> > +{
> > +	struct acpi_eject_event *ej_event = context;
> > +	struct acpi_device *device = ej_event->device;
> > +	acpi_handle handle = device->handle;
> > +	u32 ost_code = ACPI_OST_SC_SUCCESS;
> > +	int error;
> > +
> > +	mutex_lock(&acpi_scan_lock);
> > +
> > +	error = acpi_scan_hot_remove(device);
> > +	if (error)
> > +		ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
> > +
> > +	acpi_evaluate_hotplug_ost(handle, ej_event->event, ost_code, NULL);
> 
> Thanks for the quick update.  It fixed the deadlock issue. :-)  As it
> now completes an eject operation, I found a new issue.  When the OS
> called _EJ0, it is not supposed to call _OST since FW has already
> received the completion status from _EJ0.  That is, the OS calls either
> _EJ0 (success case) or _OST (failure case) for hot-delete. 

In fact, I wasn't quite sure about that, so thanks a lot for the clarification.

That makes life a bit easier, actually. :-)

I'll send a second update in a little while.

Thanks,
Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [Update 2][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-20 22:49   ` [Update][PATCH " Rafael J. Wysocki
  2013-02-21  1:17     ` Toshi Kani
@ 2013-02-21 15:52     ` Rafael J. Wysocki
  2013-02-21 17:39       ` Toshi Kani
  2013-02-21 23:06       ` [Update 3][PATCH " Rafael J. Wysocki
  1 sibling, 2 replies; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-21 15:52 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Yinghai Lu, Toshi Kani, Yasuaki Ishimatsu,
	Jiang Liu

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Multiple drivers handling hotplug-capable ACPI device nodes install
notify handlers covering the same types of events in a very similar
way.  Moreover, those handlers are installed in separate namespace
walks, although that really should be done during namespace scans
carried out by acpi_bus_scan().  This leads to substantial code
duplication, unnecessary overhead and behavior that is hard to
follow.

For this reason, introduce common code in drivers/acpi/scan.c for
handling hotplug-related notification and carrying out device
insertion and eject operations in a generic fashion, such that it
may be used by all of the relevant drivers in the future.  To cover
the existing differences between those drivers introduce struct
acpi_hotplug_profile for representing collections of hotplug
settings associated with different ACPI scan handlers that can be
used by the drivers to make the common code reflect their current
behavior.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---

This update fixes an issue pointed out by Toshi Kani (_OST shouldn't be
evaluated after successful _EJ0).

Thanks,
Rafael

---
 drivers/acpi/scan.c     |  272 ++++++++++++++++++++++++++++++++++++++----------
 include/acpi/acpi_bus.h |    7 +
 2 files changed, 226 insertions(+), 53 deletions(-)

Index: test/include/acpi/acpi_bus.h
===================================================================
--- test.orig/include/acpi/acpi_bus.h
+++ test/include/acpi/acpi_bus.h
@@ -88,11 +88,18 @@ struct acpi_device;
  * -----------------
  */
 
+struct acpi_hotplug_profile {
+	bool enabled:1;
+	bool uevents:1;
+	bool autoeject:1;
+};
+
 struct acpi_scan_handler {
 	const struct acpi_device_id *ids;
 	struct list_head list_node;
 	int (*attach)(struct acpi_device *dev, const struct acpi_device_id *id);
 	void (*detach)(struct acpi_device *dev);
+	struct acpi_hotplug_profile hotplug;
 };
 
 /*
Index: test/drivers/acpi/scan.c
===================================================================
--- test.orig/drivers/acpi/scan.c
+++ test/drivers/acpi/scan.c
@@ -107,32 +107,19 @@ acpi_device_modalias_show(struct device
 }
 static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
 
-/**
- * acpi_bus_hot_remove_device: hot-remove a device and its children
- * @context: struct acpi_eject_event pointer (freed in this func)
- *
- * Hot-remove a device and its children. This function frees up the
- * memory space passed by arg context, so that the caller may call
- * this function asynchronously through acpi_os_hotplug_execute().
- */
-void acpi_bus_hot_remove_device(void *context)
+static int acpi_scan_hot_remove(struct acpi_device *device)
 {
-	struct acpi_eject_event *ej_event = context;
-	struct acpi_device *device = ej_event->device;
 	acpi_handle handle = device->handle;
-	acpi_handle temp;
+	acpi_handle not_used;
 	struct acpi_object_list arg_list;
 	union acpi_object arg;
-	acpi_status status = AE_OK;
-	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
-
-	mutex_lock(&acpi_scan_lock);
+	acpi_status status;
 
 	/* If there is no handle, the device node has been unregistered. */
-	if (!device->handle) {
+	if (!handle) {
 		dev_dbg(&device->dev, "ACPI handle missing\n");
 		put_device(&device->dev);
-		goto out;
+		return -EINVAL;
 	}
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -143,7 +130,7 @@ void acpi_bus_hot_remove_device(void *co
 	put_device(&device->dev);
 	device = NULL;
 
-	if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &temp))) {
+	if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &not_used))) {
 		arg_list.count = 1;
 		arg_list.pointer = &arg;
 		arg.type = ACPI_TYPE_INTEGER;
@@ -161,18 +148,161 @@ void acpi_bus_hot_remove_device(void *co
 	 */
 	status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
 	if (ACPI_FAILURE(status)) {
-		if (status != AE_NOT_FOUND)
+		if (status == AE_NOT_FOUND) {
+			return -ENODEV;
+		} else {
 			acpi_handle_warn(handle, "Eject failed\n");
+			return -EIO;
+		}
+	}
+	return 0;
+}
 
-		/* Tell the firmware the hot-remove operation has failed. */
-		acpi_evaluate_hotplug_ost(handle, ej_event->event,
-					  ost_code, NULL);
+static void acpi_bus_device_eject(void *context)
+{
+	acpi_handle handle = context;
+	struct acpi_device *device = NULL;
+	struct acpi_scan_handler *handler;
+	u32 ost_source = ACPI_NOTIFY_EJECT_REQUEST;
+	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
+
+	mutex_lock(&acpi_scan_lock);
+
+	acpi_bus_get_device(handle, &device);
+	if (!device)
+		goto err_out;
+
+	handler = device->handler;
+	if (!handler || !handler->hotplug.enabled) {
+		ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
+		goto err_out;
+	}
+	acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
+				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+	if (handler->hotplug.autoeject) {
+		int error;
+
+		ost_source = ACPI_OST_EC_OSPM_EJECT;
+		get_device(&device->dev);
+		error = acpi_scan_hot_remove(device);
+		if (error)
+			goto err_out;
+	} else {
+		device->flags.eject_pending = true;
 	}
+	if (handler->hotplug.uevents)
+		kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
 
  out:
 	mutex_unlock(&acpi_scan_lock);
-	kfree(context);
 	return;
+
+ err_out:
+	acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL);
+	goto out;
+}
+
+static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
+{
+	struct acpi_device *device = NULL;
+	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
+	int error;
+
+	mutex_lock(&acpi_scan_lock);
+
+	acpi_bus_get_device(handle, &device);
+	if (device) {
+		dev_warn(&device->dev, "Attempt to re-insert\n");
+		goto out;
+	}
+	acpi_evaluate_hotplug_ost(handle, ost_source,
+				  ACPI_OST_SC_INSERT_IN_PROGRESS, NULL);
+	ost_source = ACPI_OST_EC_OSPM_INSERTION;
+	error = acpi_bus_scan(handle);
+	if (error) {
+		acpi_handle_warn(handle, "Namespace scan failure\n");
+		goto out;
+	}
+	error = acpi_bus_get_device(handle, &device);
+	if (error) {
+		acpi_handle_warn(handle, "Missing device node object\n");
+		goto out;
+	}
+	ost_code = ACPI_OST_SC_SUCCESS;
+	if (device->handler && device->handler->hotplug.uevents)
+		kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
+
+ out:
+	acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL);
+	mutex_unlock(&acpi_scan_lock);
+}
+
+static void acpi_scan_bus_check(void *context)
+{
+	acpi_scan_bus_device_check((acpi_handle)context,
+				   ACPI_NOTIFY_BUS_CHECK);
+}
+
+static void acpi_scan_device_check(void *context)
+{
+	acpi_scan_bus_device_check((acpi_handle)context,
+				   ACPI_NOTIFY_DEVICE_CHECK);
+}
+
+static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *not_used)
+{
+	acpi_osd_exec_callback callback;
+	acpi_status status;
+
+	switch (type) {
+	case ACPI_NOTIFY_BUS_CHECK:
+		acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
+		callback = acpi_scan_bus_check;
+		break;
+	case ACPI_NOTIFY_DEVICE_CHECK:
+		acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
+		callback = acpi_scan_device_check;
+		break;
+	case ACPI_NOTIFY_EJECT_REQUEST:
+		acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
+		callback = acpi_bus_device_eject;
+		break;
+	default:
+		/* non-hotplug event; possibly handled by other handler */
+		return;
+	}
+	status = acpi_os_hotplug_execute(callback, handle);
+	if (ACPI_FAILURE(status))
+		acpi_evaluate_hotplug_ost(handle, type,
+					  ACPI_OST_SC_NON_SPECIFIC_FAILURE,
+					  NULL);
+}
+
+/**
+ * acpi_bus_hot_remove_device: hot-remove a device and its children
+ * @context: struct acpi_eject_event pointer (freed in this func)
+ *
+ * Hot-remove a device and its children. This function frees up the
+ * memory space passed by arg context, so that the caller may call
+ * this function asynchronously through acpi_os_hotplug_execute().
+ */
+void acpi_bus_hot_remove_device(void *context)
+{
+	struct acpi_eject_event *ej_event = context;
+	struct acpi_device *device = ej_event->device;
+	acpi_handle handle = device->handle;
+	int error;
+
+	mutex_lock(&acpi_scan_lock);
+
+	error = acpi_scan_hot_remove(device);
+	if (error && handle)
+		acpi_evaluate_hotplug_ost(handle, ej_event->event,
+					  ACPI_OST_SC_NON_SPECIFIC_FAILURE,
+					  NULL);
+
+	mutex_unlock(&acpi_scan_lock);
+	kfree(context);
 }
 EXPORT_SYMBOL(acpi_bus_hot_remove_device);
 
@@ -206,51 +336,61 @@ static ssize_t
 acpi_eject_store(struct device *d, struct device_attribute *attr,
 		const char *buf, size_t count)
 {
-	int ret = count;
-	acpi_status status;
-	acpi_object_type type = 0;
 	struct acpi_device *acpi_device = to_acpi_device(d);
 	struct acpi_eject_event *ej_event;
+	acpi_object_type not_used;
+	acpi_status status;
+	u32 ost_source;
+	int ret;
 
-	if ((!count) || (buf[0] != '1')) {
+	if (!count || buf[0] != '1')
 		return -EINVAL;
-	}
-	if (!acpi_device->driver && !acpi_device->handler) {
-		ret = -ENODEV;
-		goto err;
-	}
-	status = acpi_get_type(acpi_device->handle, &type);
-	if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) {
-		ret = -ENODEV;
-		goto err;
-	}
 
-	ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
-	if (!ej_event) {
-		ret = -ENOMEM;
-		goto err;
-	}
+	if ((!acpi_device->handler || !acpi_device->handler->hotplug.enabled)
+	    && !acpi_device->driver)
+		return -ENODEV;
+
+	status = acpi_get_type(acpi_device->handle, &not_used);
+	if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable)
+		return -ENODEV;
+
+	mutex_lock(&acpi_scan_lock);
 
-	get_device(&acpi_device->dev);
-	ej_event->device = acpi_device;
 	if (acpi_device->flags.eject_pending) {
-		/* event originated from ACPI eject notification */
-		ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
+		/* ACPI eject notification event. */
+		ost_source = ACPI_NOTIFY_EJECT_REQUEST;
 		acpi_device->flags.eject_pending = 0;
 	} else {
-		/* event originated from user */
-		ej_event->event = ACPI_OST_EC_OSPM_EJECT;
-		(void) acpi_evaluate_hotplug_ost(acpi_device->handle,
-			ej_event->event, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+		/* Eject initiated by user space. */
+		ost_source = ACPI_OST_EC_OSPM_EJECT;
 	}
-
+	ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
+	if (!ej_event) {
+		ret = -ENOMEM;
+		goto err_out;
+	}
+	acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source,
+				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+	ej_event->device = acpi_device;
+	ej_event->event = ost_source;
+	get_device(&acpi_device->dev);
 	status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event);
 	if (ACPI_FAILURE(status)) {
 		put_device(&acpi_device->dev);
 		kfree(ej_event);
+		ret = status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN;
+		goto err_out;
 	}
-err:
+	ret = count;
+
+ out:
+	mutex_unlock(&acpi_scan_lock);
 	return ret;
+
+ err_out:
+	acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source,
+				  ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
+	goto out;
 }
 
 static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
@@ -1548,6 +1688,30 @@ static struct acpi_scan_handler *acpi_sc
 	return NULL;
 }
 
+static void acpi_scan_init_hotplug(acpi_handle handle)
+{
+	struct acpi_device_info *info;
+	struct acpi_scan_handler *handler;
+
+	if (ACPI_FAILURE(acpi_get_object_info(handle, &info)))
+		return;
+
+	if (!(info->valid & ACPI_VALID_HID)) {
+		kfree(info);
+		return;
+	}
+
+	/*
+	 * This relies on the fact that acpi_install_notify_handler() will not
+	 * install the same notify handler routine twice for the same handle.
+	 */
+	handler = acpi_scan_match_handler(info->hardware_id.string, NULL);
+	kfree(info);
+	if (handler && handler->hotplug.enabled)
+		acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+					    acpi_hotplug_notify_cb, NULL);
+}
+
 static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
 				      void *not_used, void **return_value)
 {
@@ -1570,6 +1734,8 @@ static acpi_status acpi_bus_check_add(ac
 		return AE_OK;
 	}
 
+	acpi_scan_init_hotplug(handle);
+
 	if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
 	    !(sta & ACPI_STA_DEVICE_FUNCTIONING)) {
 		struct acpi_device_wakeup wakeup;

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Update 2][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-21 15:52     ` [Update 2][PATCH " Rafael J. Wysocki
@ 2013-02-21 17:39       ` Toshi Kani
  2013-02-21 22:57         ` Rafael J. Wysocki
  2013-02-21 23:06       ` [Update 3][PATCH " Rafael J. Wysocki
  1 sibling, 1 reply; 69+ messages in thread
From: Toshi Kani @ 2013-02-21 17:39 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Yinghai Lu,
	Yasuaki Ishimatsu, Jiang Liu

On Thu, 2013-02-21 at 16:52 +0100, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
 :
> 
> This update fixes an issue pointed out by Toshi Kani (_OST shouldn't be
> evaluated after successful _EJ0).
> 
> Thanks,
> Rafael
> 
> ---
>  drivers/acpi/scan.c     |  272 ++++++++++++++++++++++++++++++++++++++----------
>  include/acpi/acpi_bus.h |    7 +
>  2 files changed, 226 insertions(+), 53 deletions(-)
 :
> +static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
> +{
> +	struct acpi_device *device = NULL;
> +	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
> +	int error;
> +
> +	mutex_lock(&acpi_scan_lock);
> +
> +	acpi_bus_get_device(handle, &device);
> +	if (device) {
> +		dev_warn(&device->dev, "Attempt to re-insert\n");
> +		goto out;
> +	}
> +	acpi_evaluate_hotplug_ost(handle, ost_source,
> +				  ACPI_OST_SC_INSERT_IN_PROGRESS, NULL);
> +	ost_source = ACPI_OST_EC_OSPM_INSERTION;

Thanks for the update.  I confirmed that _OST was handled correctly for
hot-delete.  However, I found there is an issue for hot-add too.
ACPI_OST_EC_OSPM_INSERTION is used for _OST when the OS initiated a
hot-add event (which may not happen today).  This case, however, is that
hot-add is initiated by FW through an ACPI notification.  So, ost_source
must have the ACPI notification event value.

Thanks,
-Toshi

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Update 2][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-21 17:39       ` Toshi Kani
@ 2013-02-21 22:57         ` Rafael J. Wysocki
  0 siblings, 0 replies; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-21 22:57 UTC (permalink / raw)
  To: Toshi Kani
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Yinghai Lu,
	Yasuaki Ishimatsu, Jiang Liu

On Thursday, February 21, 2013 10:39:40 AM Toshi Kani wrote:
> On Thu, 2013-02-21 at 16:52 +0100, Rafael J. Wysocki wrote:
> > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>  :
> > 
> > This update fixes an issue pointed out by Toshi Kani (_OST shouldn't be
> > evaluated after successful _EJ0).
> > 
> > Thanks,
> > Rafael
> > 
> > ---
> >  drivers/acpi/scan.c     |  272 ++++++++++++++++++++++++++++++++++++++----------
> >  include/acpi/acpi_bus.h |    7 +
> >  2 files changed, 226 insertions(+), 53 deletions(-)
>  :
> > +static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
> > +{
> > +	struct acpi_device *device = NULL;
> > +	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
> > +	int error;
> > +
> > +	mutex_lock(&acpi_scan_lock);
> > +
> > +	acpi_bus_get_device(handle, &device);
> > +	if (device) {
> > +		dev_warn(&device->dev, "Attempt to re-insert\n");
> > +		goto out;
> > +	}
> > +	acpi_evaluate_hotplug_ost(handle, ost_source,
> > +				  ACPI_OST_SC_INSERT_IN_PROGRESS, NULL);
> > +	ost_source = ACPI_OST_EC_OSPM_INSERTION;
> 
> Thanks for the update.  I confirmed that _OST was handled correctly for
> hot-delete.  However, I found there is an issue for hot-add too.
> ACPI_OST_EC_OSPM_INSERTION is used for _OST when the OS initiated a
> hot-add event (which may not happen today).  This case, however, is that
> hot-add is initiated by FW through an ACPI notification.  So, ost_source
> must have the ACPI notification event value.

OK

So I think acpi_bus_device_eject() should be changed analogously.

I'll send another update in a while. :-)

Thanks,
Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [Update 3][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-21 15:52     ` [Update 2][PATCH " Rafael J. Wysocki
  2013-02-21 17:39       ` Toshi Kani
@ 2013-02-21 23:06       ` Rafael J. Wysocki
  2013-02-22  1:12         ` Toshi Kani
  2013-02-23 22:38         ` [Update 4][PATCH " Rafael J. Wysocki
  1 sibling, 2 replies; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-21 23:06 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Yinghai Lu, Toshi Kani, Yasuaki Ishimatsu,
	Jiang Liu

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Multiple drivers handling hotplug-capable ACPI device nodes install
notify handlers covering the same types of events in a very similar
way.  Moreover, those handlers are installed in separate namespace
walks, although that really should be done during namespace scans
carried out by acpi_bus_scan().  This leads to substantial code
duplication, unnecessary overhead and behavior that is hard to
follow.

For this reason, introduce common code in drivers/acpi/scan.c for
handling hotplug-related notification and carrying out device
insertion and eject operations in a generic fashion, such that it
may be used by all of the relevant drivers in the future.  To cover
the existing differences between those drivers introduce struct
acpi_hotplug_profile for representing collections of hotplug
settings associated with different ACPI scan handlers that can be
used by the drivers to make the common code reflect their current
behavior.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---

This update fixes an issue pointed out by Toshi Kani (that
ACPI_OST_EC_OSPM_* event source codes should not be used with _OST for events
that we received a notification for from the platform firmware).

Thanks,
Rafael

---
 drivers/acpi/scan.c     |  270 ++++++++++++++++++++++++++++++++++++++----------
 include/acpi/acpi_bus.h |    7 +
 2 files changed, 224 insertions(+), 53 deletions(-)

Index: test/include/acpi/acpi_bus.h
===================================================================
--- test.orig/include/acpi/acpi_bus.h
+++ test/include/acpi/acpi_bus.h
@@ -88,11 +88,18 @@ struct acpi_device;
  * -----------------
  */
 
+struct acpi_hotplug_profile {
+	bool enabled:1;
+	bool uevents:1;
+	bool autoeject:1;
+};
+
 struct acpi_scan_handler {
 	const struct acpi_device_id *ids;
 	struct list_head list_node;
 	int (*attach)(struct acpi_device *dev, const struct acpi_device_id *id);
 	void (*detach)(struct acpi_device *dev);
+	struct acpi_hotplug_profile hotplug;
 };
 
 /*
Index: test/drivers/acpi/scan.c
===================================================================
--- test.orig/drivers/acpi/scan.c
+++ test/drivers/acpi/scan.c
@@ -107,32 +107,19 @@ acpi_device_modalias_show(struct device
 }
 static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
 
-/**
- * acpi_bus_hot_remove_device: hot-remove a device and its children
- * @context: struct acpi_eject_event pointer (freed in this func)
- *
- * Hot-remove a device and its children. This function frees up the
- * memory space passed by arg context, so that the caller may call
- * this function asynchronously through acpi_os_hotplug_execute().
- */
-void acpi_bus_hot_remove_device(void *context)
+static int acpi_scan_hot_remove(struct acpi_device *device)
 {
-	struct acpi_eject_event *ej_event = context;
-	struct acpi_device *device = ej_event->device;
 	acpi_handle handle = device->handle;
-	acpi_handle temp;
+	acpi_handle not_used;
 	struct acpi_object_list arg_list;
 	union acpi_object arg;
-	acpi_status status = AE_OK;
-	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
-
-	mutex_lock(&acpi_scan_lock);
+	acpi_status status;
 
 	/* If there is no handle, the device node has been unregistered. */
-	if (!device->handle) {
+	if (!handle) {
 		dev_dbg(&device->dev, "ACPI handle missing\n");
 		put_device(&device->dev);
-		goto out;
+		return -EINVAL;
 	}
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -143,7 +130,7 @@ void acpi_bus_hot_remove_device(void *co
 	put_device(&device->dev);
 	device = NULL;
 
-	if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &temp))) {
+	if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &not_used))) {
 		arg_list.count = 1;
 		arg_list.pointer = &arg;
 		arg.type = ACPI_TYPE_INTEGER;
@@ -161,18 +148,159 @@ void acpi_bus_hot_remove_device(void *co
 	 */
 	status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
 	if (ACPI_FAILURE(status)) {
-		if (status != AE_NOT_FOUND)
+		if (status == AE_NOT_FOUND) {
+			return -ENODEV;
+		} else {
 			acpi_handle_warn(handle, "Eject failed\n");
+			return -EIO;
+		}
+	}
+	return 0;
+}
 
-		/* Tell the firmware the hot-remove operation has failed. */
-		acpi_evaluate_hotplug_ost(handle, ej_event->event,
-					  ost_code, NULL);
+static void acpi_bus_device_eject(void *context)
+{
+	acpi_handle handle = context;
+	struct acpi_device *device = NULL;
+	struct acpi_scan_handler *handler;
+	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
+
+	mutex_lock(&acpi_scan_lock);
+
+	acpi_bus_get_device(handle, &device);
+	if (!device)
+		goto err_out;
+
+	handler = device->handler;
+	if (!handler || !handler->hotplug.enabled) {
+		ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
+		goto err_out;
+	}
+	acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
+				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+	if (handler->hotplug.autoeject) {
+		int error;
+
+		get_device(&device->dev);
+		error = acpi_scan_hot_remove(device);
+		if (error)
+			goto err_out;
+	} else {
+		device->flags.eject_pending = true;
 	}
+	if (handler->hotplug.uevents)
+		kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
 
  out:
 	mutex_unlock(&acpi_scan_lock);
-	kfree(context);
 	return;
+
+ err_out:
+	acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, ost_code,
+				  NULL);
+	goto out;
+}
+
+static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
+{
+	struct acpi_device *device = NULL;
+	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
+	int error;
+
+	mutex_lock(&acpi_scan_lock);
+
+	acpi_bus_get_device(handle, &device);
+	if (device) {
+		dev_warn(&device->dev, "Attempt to re-insert\n");
+		goto out;
+	}
+	acpi_evaluate_hotplug_ost(handle, ost_source,
+				  ACPI_OST_SC_INSERT_IN_PROGRESS, NULL);
+	error = acpi_bus_scan(handle);
+	if (error) {
+		acpi_handle_warn(handle, "Namespace scan failure\n");
+		goto out;
+	}
+	error = acpi_bus_get_device(handle, &device);
+	if (error) {
+		acpi_handle_warn(handle, "Missing device node object\n");
+		goto out;
+	}
+	ost_code = ACPI_OST_SC_SUCCESS;
+	if (device->handler && device->handler->hotplug.uevents)
+		kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
+
+ out:
+	acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL);
+	mutex_unlock(&acpi_scan_lock);
+}
+
+static void acpi_scan_bus_check(void *context)
+{
+	acpi_scan_bus_device_check((acpi_handle)context,
+				   ACPI_NOTIFY_BUS_CHECK);
+}
+
+static void acpi_scan_device_check(void *context)
+{
+	acpi_scan_bus_device_check((acpi_handle)context,
+				   ACPI_NOTIFY_DEVICE_CHECK);
+}
+
+static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *not_used)
+{
+	acpi_osd_exec_callback callback;
+	acpi_status status;
+
+	switch (type) {
+	case ACPI_NOTIFY_BUS_CHECK:
+		acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
+		callback = acpi_scan_bus_check;
+		break;
+	case ACPI_NOTIFY_DEVICE_CHECK:
+		acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
+		callback = acpi_scan_device_check;
+		break;
+	case ACPI_NOTIFY_EJECT_REQUEST:
+		acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
+		callback = acpi_bus_device_eject;
+		break;
+	default:
+		/* non-hotplug event; possibly handled by other handler */
+		return;
+	}
+	status = acpi_os_hotplug_execute(callback, handle);
+	if (ACPI_FAILURE(status))
+		acpi_evaluate_hotplug_ost(handle, type,
+					  ACPI_OST_SC_NON_SPECIFIC_FAILURE,
+					  NULL);
+}
+
+/**
+ * acpi_bus_hot_remove_device: hot-remove a device and its children
+ * @context: struct acpi_eject_event pointer (freed in this func)
+ *
+ * Hot-remove a device and its children. This function frees up the
+ * memory space passed by arg context, so that the caller may call
+ * this function asynchronously through acpi_os_hotplug_execute().
+ */
+void acpi_bus_hot_remove_device(void *context)
+{
+	struct acpi_eject_event *ej_event = context;
+	struct acpi_device *device = ej_event->device;
+	acpi_handle handle = device->handle;
+	int error;
+
+	mutex_lock(&acpi_scan_lock);
+
+	error = acpi_scan_hot_remove(device);
+	if (error && handle)
+		acpi_evaluate_hotplug_ost(handle, ej_event->event,
+					  ACPI_OST_SC_NON_SPECIFIC_FAILURE,
+					  NULL);
+
+	mutex_unlock(&acpi_scan_lock);
+	kfree(context);
 }
 EXPORT_SYMBOL(acpi_bus_hot_remove_device);
 
@@ -206,51 +334,61 @@ static ssize_t
 acpi_eject_store(struct device *d, struct device_attribute *attr,
 		const char *buf, size_t count)
 {
-	int ret = count;
-	acpi_status status;
-	acpi_object_type type = 0;
 	struct acpi_device *acpi_device = to_acpi_device(d);
 	struct acpi_eject_event *ej_event;
+	acpi_object_type not_used;
+	acpi_status status;
+	u32 ost_source;
+	int ret;
 
-	if ((!count) || (buf[0] != '1')) {
+	if (!count || buf[0] != '1')
 		return -EINVAL;
-	}
-	if (!acpi_device->driver && !acpi_device->handler) {
-		ret = -ENODEV;
-		goto err;
-	}
-	status = acpi_get_type(acpi_device->handle, &type);
-	if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) {
-		ret = -ENODEV;
-		goto err;
-	}
 
-	ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
-	if (!ej_event) {
-		ret = -ENOMEM;
-		goto err;
-	}
+	if ((!acpi_device->handler || !acpi_device->handler->hotplug.enabled)
+	    && !acpi_device->driver)
+		return -ENODEV;
+
+	status = acpi_get_type(acpi_device->handle, &not_used);
+	if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable)
+		return -ENODEV;
+
+	mutex_lock(&acpi_scan_lock);
 
-	get_device(&acpi_device->dev);
-	ej_event->device = acpi_device;
 	if (acpi_device->flags.eject_pending) {
-		/* event originated from ACPI eject notification */
-		ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
+		/* ACPI eject notification event. */
+		ost_source = ACPI_NOTIFY_EJECT_REQUEST;
 		acpi_device->flags.eject_pending = 0;
 	} else {
-		/* event originated from user */
-		ej_event->event = ACPI_OST_EC_OSPM_EJECT;
-		(void) acpi_evaluate_hotplug_ost(acpi_device->handle,
-			ej_event->event, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+		/* Eject initiated by user space. */
+		ost_source = ACPI_OST_EC_OSPM_EJECT;
 	}
-
+	ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
+	if (!ej_event) {
+		ret = -ENOMEM;
+		goto err_out;
+	}
+	acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source,
+				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+	ej_event->device = acpi_device;
+	ej_event->event = ost_source;
+	get_device(&acpi_device->dev);
 	status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event);
 	if (ACPI_FAILURE(status)) {
 		put_device(&acpi_device->dev);
 		kfree(ej_event);
+		ret = status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN;
+		goto err_out;
 	}
-err:
+	ret = count;
+
+ out:
+	mutex_unlock(&acpi_scan_lock);
 	return ret;
+
+ err_out:
+	acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source,
+				  ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
+	goto out;
 }
 
 static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
@@ -1548,6 +1686,30 @@ static struct acpi_scan_handler *acpi_sc
 	return NULL;
 }
 
+static void acpi_scan_init_hotplug(acpi_handle handle)
+{
+	struct acpi_device_info *info;
+	struct acpi_scan_handler *handler;
+
+	if (ACPI_FAILURE(acpi_get_object_info(handle, &info)))
+		return;
+
+	if (!(info->valid & ACPI_VALID_HID)) {
+		kfree(info);
+		return;
+	}
+
+	/*
+	 * This relies on the fact that acpi_install_notify_handler() will not
+	 * install the same notify handler routine twice for the same handle.
+	 */
+	handler = acpi_scan_match_handler(info->hardware_id.string, NULL);
+	kfree(info);
+	if (handler && handler->hotplug.enabled)
+		acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+					    acpi_hotplug_notify_cb, NULL);
+}
+
 static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
 				      void *not_used, void **return_value)
 {
@@ -1570,6 +1732,8 @@ static acpi_status acpi_bus_check_add(ac
 		return AE_OK;
 	}
 
+	acpi_scan_init_hotplug(handle);
+
 	if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
 	    !(sta & ACPI_STA_DEVICE_FUNCTIONING)) {
 		struct acpi_device_wakeup wakeup;


^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Update 3][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-21 23:06       ` [Update 3][PATCH " Rafael J. Wysocki
@ 2013-02-22  1:12         ` Toshi Kani
  2013-02-22  1:50           ` Rafael J. Wysocki
  2013-02-23 22:38         ` [Update 4][PATCH " Rafael J. Wysocki
  1 sibling, 1 reply; 69+ messages in thread
From: Toshi Kani @ 2013-02-22  1:12 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Yinghai Lu,
	Yasuaki Ishimatsu, Jiang Liu

On Fri, 2013-02-22 at 00:06 +0100, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> 
> Multiple drivers handling hotplug-capable ACPI device nodes install
> notify handlers covering the same types of events in a very similar
> way.  Moreover, those handlers are installed in separate namespace
> walks, although that really should be done during namespace scans
> carried out by acpi_bus_scan().  This leads to substantial code
> duplication, unnecessary overhead and behavior that is hard to
> follow.
> 
> For this reason, introduce common code in drivers/acpi/scan.c for
> handling hotplug-related notification and carrying out device
> insertion and eject operations in a generic fashion, such that it
> may be used by all of the relevant drivers in the future.  To cover
> the existing differences between those drivers introduce struct
> acpi_hotplug_profile for representing collections of hotplug
> settings associated with different ACPI scan handlers that can be
> used by the drivers to make the common code reflect their current
> behavior.
> 
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> ---
> 
> This update fixes an issue pointed out by Toshi Kani (that
> ACPI_OST_EC_OSPM_* event source codes should not be used with _OST for events
> that we received a notification for from the platform firmware).
> 
> Thanks,
> Rafael
> 
> ---
>  drivers/acpi/scan.c     |  270 ++++++++++++++++++++++++++++++++++++++----------
>  include/acpi/acpi_bus.h |    7 +
>  2 files changed, 224 insertions(+), 53 deletions(-)
 :
> +static void acpi_bus_device_eject(void *context)
> +{
> +	acpi_handle handle = context;
> +	struct acpi_device *device = NULL;
> +	struct acpi_scan_handler *handler;
> +	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
> +
> +	mutex_lock(&acpi_scan_lock);
> +
> +	acpi_bus_get_device(handle, &device);
> +	if (!device)
> +		goto err_out;
> +
> +	handler = device->handler;
> +	if (!handler || !handler->hotplug.enabled) {
> +		ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
> +		goto err_out;
> +	}
> +	acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
> +				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
> +	if (handler->hotplug.autoeject) {
> +		int error;
> +
> +		get_device(&device->dev);
> +		error = acpi_scan_hot_remove(device);
> +		if (error)
> +			goto err_out;
> +	} else {
> +		device->flags.eject_pending = true;
>  	}
> +	if (handler->hotplug.uevents)
> +		kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);

I confirmed that the _OST issue with hot-add is fixed.  Here is a new
one.  When autoeject is enabled, it crashes in kobject_uevent() since
the device is no longer valid. 

Thanks,
-Toshi



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Update 3][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-22  1:12         ` Toshi Kani
@ 2013-02-22  1:50           ` Rafael J. Wysocki
  2013-02-22  8:51             ` Yasuaki Ishimatsu
  0 siblings, 1 reply; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-22  1:50 UTC (permalink / raw)
  To: Toshi Kani
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Yinghai Lu,
	Yasuaki Ishimatsu, Jiang Liu

On Thursday, February 21, 2013 06:12:21 PM Toshi Kani wrote:
> On Fri, 2013-02-22 at 00:06 +0100, Rafael J. Wysocki wrote:
> > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > 
> > Multiple drivers handling hotplug-capable ACPI device nodes install
> > notify handlers covering the same types of events in a very similar
> > way.  Moreover, those handlers are installed in separate namespace
> > walks, although that really should be done during namespace scans
> > carried out by acpi_bus_scan().  This leads to substantial code
> > duplication, unnecessary overhead and behavior that is hard to
> > follow.
> > 
> > For this reason, introduce common code in drivers/acpi/scan.c for
> > handling hotplug-related notification and carrying out device
> > insertion and eject operations in a generic fashion, such that it
> > may be used by all of the relevant drivers in the future.  To cover
> > the existing differences between those drivers introduce struct
> > acpi_hotplug_profile for representing collections of hotplug
> > settings associated with different ACPI scan handlers that can be
> > used by the drivers to make the common code reflect their current
> > behavior.
> > 
> > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > ---
> > 
> > This update fixes an issue pointed out by Toshi Kani (that
> > ACPI_OST_EC_OSPM_* event source codes should not be used with _OST for events
> > that we received a notification for from the platform firmware).
> > 
> > Thanks,
> > Rafael
> > 
> > ---
> >  drivers/acpi/scan.c     |  270 ++++++++++++++++++++++++++++++++++++++----------
> >  include/acpi/acpi_bus.h |    7 +
> >  2 files changed, 224 insertions(+), 53 deletions(-)
>  :
> > +static void acpi_bus_device_eject(void *context)
> > +{
> > +	acpi_handle handle = context;
> > +	struct acpi_device *device = NULL;
> > +	struct acpi_scan_handler *handler;
> > +	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
> > +
> > +	mutex_lock(&acpi_scan_lock);
> > +
> > +	acpi_bus_get_device(handle, &device);
> > +	if (!device)
> > +		goto err_out;
> > +
> > +	handler = device->handler;
> > +	if (!handler || !handler->hotplug.enabled) {
> > +		ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
> > +		goto err_out;
> > +	}
> > +	acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
> > +				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
> > +	if (handler->hotplug.autoeject) {
> > +		int error;
> > +
> > +		get_device(&device->dev);
> > +		error = acpi_scan_hot_remove(device);
> > +		if (error)
> > +			goto err_out;
> > +	} else {
> > +		device->flags.eject_pending = true;
> >  	}
> > +	if (handler->hotplug.uevents)
> > +		kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
> 
> I confirmed that the _OST issue with hot-add is fixed.  Here is a new
> one.  When autoeject is enabled, it crashes in kobject_uevent() since
> the device is no longer valid. 

Well, this one is more difficult.

I can change the ordering so that kobject_uevent() is called before
acpi_scan_hot_remove(), but then user space may not know that the device is
being removed at the moment (which still may fail).  Still, maybe this is
OK, because user space will get KOBJ_REMOVE when the device actually goes
away anyway.

Or perhaps we can emit KOBJ_OFFLINE before acpi_scan_hot_remove() and if
it fails, emit KOBJ_ONLINE?

I'm not sure.

Thanks,
Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Update 3][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-22  1:50           ` Rafael J. Wysocki
@ 2013-02-22  8:51             ` Yasuaki Ishimatsu
  2013-02-22 12:37               ` Rafael J. Wysocki
  0 siblings, 1 reply; 69+ messages in thread
From: Yasuaki Ishimatsu @ 2013-02-22  8:51 UTC (permalink / raw)
  To: Rafael J. Wysocki, Toshi Kani
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Yinghai Lu, Jiang Liu

[-- Attachment #1: Type: text/plain, Size: 5350 bytes --]

2013/02/22 10:50, Rafael J. Wysocki wrote:
> On Thursday, February 21, 2013 06:12:21 PM Toshi Kani wrote:
>> On Fri, 2013-02-22 at 00:06 +0100, Rafael J. Wysocki wrote:
>>> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>>>
>>> Multiple drivers handling hotplug-capable ACPI device nodes install
>>> notify handlers covering the same types of events in a very similar
>>> way.  Moreover, those handlers are installed in separate namespace
>>> walks, although that really should be done during namespace scans
>>> carried out by acpi_bus_scan().  This leads to substantial code
>>> duplication, unnecessary overhead and behavior that is hard to
>>> follow.
>>>
>>> For this reason, introduce common code in drivers/acpi/scan.c for
>>> handling hotplug-related notification and carrying out device
>>> insertion and eject operations in a generic fashion, such that it
>>> may be used by all of the relevant drivers in the future.  To cover
>>> the existing differences between those drivers introduce struct
>>> acpi_hotplug_profile for representing collections of hotplug
>>> settings associated with different ACPI scan handlers that can be
>>> used by the drivers to make the common code reflect their current
>>> behavior.
>>>
>>> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>>> ---
>>>
>>> This update fixes an issue pointed out by Toshi Kani (that
>>> ACPI_OST_EC_OSPM_* event source codes should not be used with _OST for events
>>> that we received a notification for from the platform firmware).
>>>
>>> Thanks,
>>> Rafael
>>>
>>> ---
>>>   drivers/acpi/scan.c     |  270 ++++++++++++++++++++++++++++++++++++++----------
>>>   include/acpi/acpi_bus.h |    7 +
>>>   2 files changed, 224 insertions(+), 53 deletions(-)
>>   :
>>> +static void acpi_bus_device_eject(void *context)
>>> +{
>>> +	acpi_handle handle = context;
>>> +	struct acpi_device *device = NULL;
>>> +	struct acpi_scan_handler *handler;
>>> +	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
>>> +
>>> +	mutex_lock(&acpi_scan_lock);
>>> +
>>> +	acpi_bus_get_device(handle, &device);
>>> +	if (!device)
>>> +		goto err_out;
>>> +
>>> +	handler = device->handler;
>>> +	if (!handler || !handler->hotplug.enabled) {
>>> +		ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
>>> +		goto err_out;
>>> +	}
>>> +	acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
>>> +				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
>>> +	if (handler->hotplug.autoeject) {
>>> +		int error;
>>> +
>>> +		get_device(&device->dev);
>>> +		error = acpi_scan_hot_remove(device);
>>> +		if (error)
>>> +			goto err_out;
>>> +	} else {
>>> +		device->flags.eject_pending = true;
>>>   	}
>>> +	if (handler->hotplug.uevents)
>>> +		kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
>>
>> I confirmed that the _OST issue with hot-add is fixed.  Here is a new
>> one.  When autoeject is enabled, it crashes in kobject_uevent() since
>> the device is no longer valid.
>
> Well, this one is more difficult.
>
> I can change the ordering so that kobject_uevent() is called before
> acpi_scan_hot_remove(), but then user space may not know that the device is
> being removed at the moment (which still may fail).  Still, maybe this is
> OK, because user space will get KOBJ_REMOVE when the device actually goes
> away anyway.
>
> Or perhaps we can emit KOBJ_OFFLINE before acpi_scan_hot_remove() and if
> it fails, emit KOBJ_ONLINE?

How about following patch? My system cannot send EJECT notification.
So I have not tested this patch.

# Recently when I send a patch, tabs of the patch is changed to spaces often.
# So I attached the patch.

---

When hotplug.autoeject and uevents are enabled, it crashes in
kobject_uevent() since the device is no longer valid.

This patch fixes the problem.

Reported-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>

---
  drivers/acpi/scan.c |    7 +++----
  1 file changed, 3 insertions(+), 4 deletions(-)

Index: linux-pm/drivers/acpi/scan.c
===================================================================
--- linux-pm.orig/drivers/acpi/scan.c	2013-02-22 16:02:07.000000000 +0900
+++ linux-pm/drivers/acpi/scan.c	2013-02-22 16:06:36.792816699 +0900
@@ -139,9 +139,6 @@ static int acpi_scan_hot_remove(struct a
  		"Hot-removing device %s...\n", dev_name(&device->dev)));
  
  	acpi_bus_trim(device);
-	/* Device node has been unregistered. */
-	put_device(&device->dev);
-	device = NULL;
  
  	if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &not_used))) {
  		arg_list.count = 1;
@@ -191,10 +188,10 @@ static void acpi_bus_device_eject(void *
  	}
  	acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
  				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+	get_device(&device->dev);
  	if (handler->hotplug.autoeject) {
  		int error;
  
-		get_device(&device->dev);
  		error = acpi_scan_hot_remove(device);
  		if (error)
  			goto err_out;
@@ -204,6 +201,7 @@ static void acpi_bus_device_eject(void *
  	if (handler->hotplug.uevents)
  		kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
  
+	put_device(&device->dev);
   out:
  	mutex_unlock(&acpi_scan_lock);
  	return;
@@ -312,6 +310,7 @@ void acpi_bus_hot_remove_device(void *co
  					  ACPI_OST_SC_NON_SPECIFIC_FAILURE,
  					  NULL);
  
+	put_device(&acpi_device->dev);
  	mutex_unlock(&acpi_scan_lock);
  	kfree(context);
  }


[-- Attachment #2: fix-panic-in-kobject_uevent.patch --]
[-- Type: text/x-patch, Size: 1712 bytes --]

When hotplug.autoeject and uevents are enabled, it crashes in
kobject_uevent() since the device is no longer valid.

This patch fixes the problem.

Reported-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>

---
 drivers/acpi/scan.c |    7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

Index: linux-pm/drivers/acpi/scan.c
===================================================================
--- linux-pm.orig/drivers/acpi/scan.c	2013-02-22 16:02:07.000000000 +0900
+++ linux-pm/drivers/acpi/scan.c	2013-02-22 16:06:36.792816699 +0900
@@ -139,9 +139,6 @@ static int acpi_scan_hot_remove(struct a
 		"Hot-removing device %s...\n", dev_name(&device->dev)));
 
 	acpi_bus_trim(device);
-	/* Device node has been unregistered. */
-	put_device(&device->dev);
-	device = NULL;
 
 	if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &not_used))) {
 		arg_list.count = 1;
@@ -191,10 +188,10 @@ static void acpi_bus_device_eject(void *
 	}
 	acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
 				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+	get_device(&device->dev);
 	if (handler->hotplug.autoeject) {
 		int error;
 
-		get_device(&device->dev);
 		error = acpi_scan_hot_remove(device);
 		if (error)
 			goto err_out;
@@ -204,6 +201,7 @@ static void acpi_bus_device_eject(void *
 	if (handler->hotplug.uevents)
 		kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
 
+	put_device(&device->dev);
  out:
 	mutex_unlock(&acpi_scan_lock);
 	return;
@@ -312,6 +310,7 @@ void acpi_bus_hot_remove_device(void *co
 					  ACPI_OST_SC_NON_SPECIFIC_FAILURE,
 					  NULL);
 
+	put_device(&acpi_device->dev);
 	mutex_unlock(&acpi_scan_lock);
 	kfree(context);
 }

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Update 3][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-22  8:51             ` Yasuaki Ishimatsu
@ 2013-02-22 12:37               ` Rafael J. Wysocki
  2013-02-22 15:54                 ` Toshi Kani
  0 siblings, 1 reply; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-22 12:37 UTC (permalink / raw)
  To: Yasuaki Ishimatsu
  Cc: Toshi Kani, ACPI Devel Maling List, Bjorn Helgaas, LKML,
	Yinghai Lu, Jiang Liu

On Friday, February 22, 2013 05:51:28 PM Yasuaki Ishimatsu wrote:
> 2013/02/22 10:50, Rafael J. Wysocki wrote:
> > On Thursday, February 21, 2013 06:12:21 PM Toshi Kani wrote:
> >> On Fri, 2013-02-22 at 00:06 +0100, Rafael J. Wysocki wrote:
> >>> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> >>>
> >>> Multiple drivers handling hotplug-capable ACPI device nodes install
> >>> notify handlers covering the same types of events in a very similar
> >>> way.  Moreover, those handlers are installed in separate namespace
> >>> walks, although that really should be done during namespace scans
> >>> carried out by acpi_bus_scan().  This leads to substantial code
> >>> duplication, unnecessary overhead and behavior that is hard to
> >>> follow.
> >>>
> >>> For this reason, introduce common code in drivers/acpi/scan.c for
> >>> handling hotplug-related notification and carrying out device
> >>> insertion and eject operations in a generic fashion, such that it
> >>> may be used by all of the relevant drivers in the future.  To cover
> >>> the existing differences between those drivers introduce struct
> >>> acpi_hotplug_profile for representing collections of hotplug
> >>> settings associated with different ACPI scan handlers that can be
> >>> used by the drivers to make the common code reflect their current
> >>> behavior.
> >>>
> >>> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> >>> ---
> >>>
> >>> This update fixes an issue pointed out by Toshi Kani (that
> >>> ACPI_OST_EC_OSPM_* event source codes should not be used with _OST for events
> >>> that we received a notification for from the platform firmware).
> >>>
> >>> Thanks,
> >>> Rafael
> >>>
> >>> ---
> >>>   drivers/acpi/scan.c     |  270 ++++++++++++++++++++++++++++++++++++++----------
> >>>   include/acpi/acpi_bus.h |    7 +
> >>>   2 files changed, 224 insertions(+), 53 deletions(-)
> >>   :
> >>> +static void acpi_bus_device_eject(void *context)
> >>> +{
> >>> +	acpi_handle handle = context;
> >>> +	struct acpi_device *device = NULL;
> >>> +	struct acpi_scan_handler *handler;
> >>> +	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
> >>> +
> >>> +	mutex_lock(&acpi_scan_lock);
> >>> +
> >>> +	acpi_bus_get_device(handle, &device);
> >>> +	if (!device)
> >>> +		goto err_out;
> >>> +
> >>> +	handler = device->handler;
> >>> +	if (!handler || !handler->hotplug.enabled) {
> >>> +		ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
> >>> +		goto err_out;
> >>> +	}
> >>> +	acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
> >>> +				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
> >>> +	if (handler->hotplug.autoeject) {
> >>> +		int error;
> >>> +
> >>> +		get_device(&device->dev);
> >>> +		error = acpi_scan_hot_remove(device);
> >>> +		if (error)
> >>> +			goto err_out;
> >>> +	} else {
> >>> +		device->flags.eject_pending = true;
> >>>   	}
> >>> +	if (handler->hotplug.uevents)
> >>> +		kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
> >>
> >> I confirmed that the _OST issue with hot-add is fixed.  Here is a new
> >> one.  When autoeject is enabled, it crashes in kobject_uevent() since
> >> the device is no longer valid.
> >
> > Well, this one is more difficult.
> >
> > I can change the ordering so that kobject_uevent() is called before
> > acpi_scan_hot_remove(), but then user space may not know that the device is
> > being removed at the moment (which still may fail).  Still, maybe this is
> > OK, because user space will get KOBJ_REMOVE when the device actually goes
> > away anyway.
> >
> > Or perhaps we can emit KOBJ_OFFLINE before acpi_scan_hot_remove() and if
> > it fails, emit KOBJ_ONLINE?
> 
> How about following patch? My system cannot send EJECT notification.
> So I have not tested this patch.

No, that's not correct, acpi_scan_hot_remove(device) will remove the device
from sysfs, if successful, among other things.

We can't emit uevents for a device that has been, even though the data
structure is still around.

The following are the choices we have, in my opinion:
- Emit KOBJ_OFFLINE before removal.
- Emit KOBJ_OFFLINE before removal and KOBJ_ONLINE afterwards if it fails.
- Do not emit KOBJ_OFFLINE at all with autoeject.

Each of them has some disadvantages, so I'm not sure.  The last one is the
easiest, so I'll probably send another update implementing it.

Thanks,
Rafael


> # Recently when I send a patch, tabs of the patch is changed to spaces often.
> # So I attached the patch.
> 
> ---
> 
> When hotplug.autoeject and uevents are enabled, it crashes in
> kobject_uevent() since the device is no longer valid.
> 
> This patch fixes the problem.
> 
> Reported-by: Toshi Kani <toshi.kani@hp.com>
> Signed-off-by: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
> 
> ---
>   drivers/acpi/scan.c |    7 +++----
>   1 file changed, 3 insertions(+), 4 deletions(-)
> 
> Index: linux-pm/drivers/acpi/scan.c
> ===================================================================
> --- linux-pm.orig/drivers/acpi/scan.c	2013-02-22 16:02:07.000000000 +0900
> +++ linux-pm/drivers/acpi/scan.c	2013-02-22 16:06:36.792816699 +0900
> @@ -139,9 +139,6 @@ static int acpi_scan_hot_remove(struct a
>   		"Hot-removing device %s...\n", dev_name(&device->dev)));
>   
>   	acpi_bus_trim(device);
> -	/* Device node has been unregistered. */
> -	put_device(&device->dev);
> -	device = NULL;
>   
>   	if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &not_used))) {
>   		arg_list.count = 1;
> @@ -191,10 +188,10 @@ static void acpi_bus_device_eject(void *
>   	}
>   	acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
>   				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
> +	get_device(&device->dev);
>   	if (handler->hotplug.autoeject) {
>   		int error;
>   
> -		get_device(&device->dev);
>   		error = acpi_scan_hot_remove(device);
>   		if (error)
>   			goto err_out;
> @@ -204,6 +201,7 @@ static void acpi_bus_device_eject(void *
>   	if (handler->hotplug.uevents)
>   		kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
>   
> +	put_device(&device->dev);
>    out:
>   	mutex_unlock(&acpi_scan_lock);
>   	return;
> @@ -312,6 +310,7 @@ void acpi_bus_hot_remove_device(void *co
>   					  ACPI_OST_SC_NON_SPECIFIC_FAILURE,
>   					  NULL);
>   
> +	put_device(&acpi_device->dev);
>   	mutex_unlock(&acpi_scan_lock);
>   	kfree(context);
>   }
> 
-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Update 3][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-22 12:37               ` Rafael J. Wysocki
@ 2013-02-22 15:54                 ` Toshi Kani
  2013-02-22 20:59                   ` Rafael J. Wysocki
  0 siblings, 1 reply; 69+ messages in thread
From: Toshi Kani @ 2013-02-22 15:54 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Yasuaki Ishimatsu, ACPI Devel Maling List, Bjorn Helgaas, LKML,
	Yinghai Lu, Jiang Liu

On Fri, 2013-02-22 at 13:37 +0100, Rafael J. Wysocki wrote:
> On Friday, February 22, 2013 05:51:28 PM Yasuaki Ishimatsu wrote:
> > 2013/02/22 10:50, Rafael J. Wysocki wrote:
> > > On Thursday, February 21, 2013 06:12:21 PM Toshi Kani wrote:
> > >> On Fri, 2013-02-22 at 00:06 +0100, Rafael J. Wysocki wrote:
> > >>> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > >>>
> > >>> Multiple drivers handling hotplug-capable ACPI device nodes install
> > >>> notify handlers covering the same types of events in a very similar
> > >>> way.  Moreover, those handlers are installed in separate namespace
> > >>> walks, although that really should be done during namespace scans
> > >>> carried out by acpi_bus_scan().  This leads to substantial code
> > >>> duplication, unnecessary overhead and behavior that is hard to
> > >>> follow.
> > >>>
> > >>> For this reason, introduce common code in drivers/acpi/scan.c for
> > >>> handling hotplug-related notification and carrying out device
> > >>> insertion and eject operations in a generic fashion, such that it
> > >>> may be used by all of the relevant drivers in the future.  To cover
> > >>> the existing differences between those drivers introduce struct
> > >>> acpi_hotplug_profile for representing collections of hotplug
> > >>> settings associated with different ACPI scan handlers that can be
> > >>> used by the drivers to make the common code reflect their current
> > >>> behavior.
> > >>>
> > >>> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > >>> ---
> > >>>
> > >>> This update fixes an issue pointed out by Toshi Kani (that
> > >>> ACPI_OST_EC_OSPM_* event source codes should not be used with _OST for events
> > >>> that we received a notification for from the platform firmware).
> > >>>
> > >>> Thanks,
> > >>> Rafael
> > >>>
> > >>> ---
> > >>>   drivers/acpi/scan.c     |  270 ++++++++++++++++++++++++++++++++++++++----------
> > >>>   include/acpi/acpi_bus.h |    7 +
> > >>>   2 files changed, 224 insertions(+), 53 deletions(-)
> > >>   :
> > >>> +static void acpi_bus_device_eject(void *context)
> > >>> +{
> > >>> +	acpi_handle handle = context;
> > >>> +	struct acpi_device *device = NULL;
> > >>> +	struct acpi_scan_handler *handler;
> > >>> +	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
> > >>> +
> > >>> +	mutex_lock(&acpi_scan_lock);
> > >>> +
> > >>> +	acpi_bus_get_device(handle, &device);
> > >>> +	if (!device)
> > >>> +		goto err_out;
> > >>> +
> > >>> +	handler = device->handler;
> > >>> +	if (!handler || !handler->hotplug.enabled) {
> > >>> +		ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
> > >>> +		goto err_out;
> > >>> +	}
> > >>> +	acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
> > >>> +				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
> > >>> +	if (handler->hotplug.autoeject) {
> > >>> +		int error;
> > >>> +
> > >>> +		get_device(&device->dev);
> > >>> +		error = acpi_scan_hot_remove(device);
> > >>> +		if (error)
> > >>> +			goto err_out;
> > >>> +	} else {
> > >>> +		device->flags.eject_pending = true;
> > >>>   	}
> > >>> +	if (handler->hotplug.uevents)
> > >>> +		kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
> > >>
> > >> I confirmed that the _OST issue with hot-add is fixed.  Here is a new
> > >> one.  When autoeject is enabled, it crashes in kobject_uevent() since
> > >> the device is no longer valid.
> > >
> > > Well, this one is more difficult.
> > >
> > > I can change the ordering so that kobject_uevent() is called before
> > > acpi_scan_hot_remove(), but then user space may not know that the device is
> > > being removed at the moment (which still may fail).  Still, maybe this is
> > > OK, because user space will get KOBJ_REMOVE when the device actually goes
> > > away anyway.
> > >
> > > Or perhaps we can emit KOBJ_OFFLINE before acpi_scan_hot_remove() and if
> > > it fails, emit KOBJ_ONLINE?
> > 
> > How about following patch? My system cannot send EJECT notification.
> > So I have not tested this patch.
> 
> No, that's not correct, acpi_scan_hot_remove(device) will remove the device
> from sysfs, if successful, among other things.
> 
> We can't emit uevents for a device that has been, even though the data
> structure is still around.
> 
> The following are the choices we have, in my opinion:
> - Emit KOBJ_OFFLINE before removal.
> - Emit KOBJ_OFFLINE before removal and KOBJ_ONLINE afterwards if it fails.
> - Do not emit KOBJ_OFFLINE at all with autoeject.
> 
> Each of them has some disadvantages, so I'm not sure.  The last one is the
> easiest, so I'll probably send another update implementing it.

I agree with the 3rd option.  KOBJ_REMOVE is emitted when a device is
removed, so it should be OK to not emitting KOBJ_OFFLINE here.  Besides,
we are going to rely on a target offlined beforehand, so this code path
won't have to do it anyway. 

BTW, it appears that KOBJ_OFFLINE is used for two different purposes
today.  sysfs cpu/memory emits KOBJ_OFFLINE when a target has been
offlined.  The container driver (or autoeject is not set with this
patch) emits KOBJ_OFFLINE to request a user to offline a target.
Expected action from user space is different from these cases. 

Thanks,
-Toshi



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Update 3][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-22 15:54                 ` Toshi Kani
@ 2013-02-22 20:59                   ` Rafael J. Wysocki
  0 siblings, 0 replies; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-22 20:59 UTC (permalink / raw)
  To: Toshi Kani
  Cc: Yasuaki Ishimatsu, ACPI Devel Maling List, Bjorn Helgaas, LKML,
	Yinghai Lu, Jiang Liu

On Friday, February 22, 2013 08:54:14 AM Toshi Kani wrote:
> On Fri, 2013-02-22 at 13:37 +0100, Rafael J. Wysocki wrote:
> > On Friday, February 22, 2013 05:51:28 PM Yasuaki Ishimatsu wrote:
> > > 2013/02/22 10:50, Rafael J. Wysocki wrote:
> > > > On Thursday, February 21, 2013 06:12:21 PM Toshi Kani wrote:
> > > >> On Fri, 2013-02-22 at 00:06 +0100, Rafael J. Wysocki wrote:
> > > >>> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > > >>>
> > > >>> Multiple drivers handling hotplug-capable ACPI device nodes install
> > > >>> notify handlers covering the same types of events in a very similar
> > > >>> way.  Moreover, those handlers are installed in separate namespace
> > > >>> walks, although that really should be done during namespace scans
> > > >>> carried out by acpi_bus_scan().  This leads to substantial code
> > > >>> duplication, unnecessary overhead and behavior that is hard to
> > > >>> follow.
> > > >>>
> > > >>> For this reason, introduce common code in drivers/acpi/scan.c for
> > > >>> handling hotplug-related notification and carrying out device
> > > >>> insertion and eject operations in a generic fashion, such that it
> > > >>> may be used by all of the relevant drivers in the future.  To cover
> > > >>> the existing differences between those drivers introduce struct
> > > >>> acpi_hotplug_profile for representing collections of hotplug
> > > >>> settings associated with different ACPI scan handlers that can be
> > > >>> used by the drivers to make the common code reflect their current
> > > >>> behavior.
> > > >>>
> > > >>> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > > >>> ---
> > > >>>
> > > >>> This update fixes an issue pointed out by Toshi Kani (that
> > > >>> ACPI_OST_EC_OSPM_* event source codes should not be used with _OST for events
> > > >>> that we received a notification for from the platform firmware).
> > > >>>
> > > >>> Thanks,
> > > >>> Rafael
> > > >>>
> > > >>> ---
> > > >>>   drivers/acpi/scan.c     |  270 ++++++++++++++++++++++++++++++++++++++----------
> > > >>>   include/acpi/acpi_bus.h |    7 +
> > > >>>   2 files changed, 224 insertions(+), 53 deletions(-)
> > > >>   :
> > > >>> +static void acpi_bus_device_eject(void *context)
> > > >>> +{
> > > >>> +	acpi_handle handle = context;
> > > >>> +	struct acpi_device *device = NULL;
> > > >>> +	struct acpi_scan_handler *handler;
> > > >>> +	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
> > > >>> +
> > > >>> +	mutex_lock(&acpi_scan_lock);
> > > >>> +
> > > >>> +	acpi_bus_get_device(handle, &device);
> > > >>> +	if (!device)
> > > >>> +		goto err_out;
> > > >>> +
> > > >>> +	handler = device->handler;
> > > >>> +	if (!handler || !handler->hotplug.enabled) {
> > > >>> +		ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
> > > >>> +		goto err_out;
> > > >>> +	}
> > > >>> +	acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
> > > >>> +				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
> > > >>> +	if (handler->hotplug.autoeject) {
> > > >>> +		int error;
> > > >>> +
> > > >>> +		get_device(&device->dev);
> > > >>> +		error = acpi_scan_hot_remove(device);
> > > >>> +		if (error)
> > > >>> +			goto err_out;
> > > >>> +	} else {
> > > >>> +		device->flags.eject_pending = true;
> > > >>>   	}
> > > >>> +	if (handler->hotplug.uevents)
> > > >>> +		kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
> > > >>
> > > >> I confirmed that the _OST issue with hot-add is fixed.  Here is a new
> > > >> one.  When autoeject is enabled, it crashes in kobject_uevent() since
> > > >> the device is no longer valid.
> > > >
> > > > Well, this one is more difficult.
> > > >
> > > > I can change the ordering so that kobject_uevent() is called before
> > > > acpi_scan_hot_remove(), but then user space may not know that the device is
> > > > being removed at the moment (which still may fail).  Still, maybe this is
> > > > OK, because user space will get KOBJ_REMOVE when the device actually goes
> > > > away anyway.
> > > >
> > > > Or perhaps we can emit KOBJ_OFFLINE before acpi_scan_hot_remove() and if
> > > > it fails, emit KOBJ_ONLINE?
> > > 
> > > How about following patch? My system cannot send EJECT notification.
> > > So I have not tested this patch.
> > 
> > No, that's not correct, acpi_scan_hot_remove(device) will remove the device
> > from sysfs, if successful, among other things.
> > 
> > We can't emit uevents for a device that has been, even though the data
> > structure is still around.
> > 
> > The following are the choices we have, in my opinion:
> > - Emit KOBJ_OFFLINE before removal.
> > - Emit KOBJ_OFFLINE before removal and KOBJ_ONLINE afterwards if it fails.
> > - Do not emit KOBJ_OFFLINE at all with autoeject.
> > 
> > Each of them has some disadvantages, so I'm not sure.  The last one is the
> > easiest, so I'll probably send another update implementing it.
> 
> I agree with the 3rd option.  KOBJ_REMOVE is emitted when a device is
> removed, so it should be OK to not emitting KOBJ_OFFLINE here.  Besides,
> we are going to rely on a target offlined beforehand, so this code path
> won't have to do it anyway. 

Yeah.

OK, I'll update the patch this way, thanks!

> BTW, it appears that KOBJ_OFFLINE is used for two different purposes
> today.  sysfs cpu/memory emits KOBJ_OFFLINE when a target has been
> offlined.  The container driver (or autoeject is not set with this
> patch) emits KOBJ_OFFLINE to request a user to offline a target.
> Expected action from user space is different from these cases. 

What a mess.  Well, we'll need to resolve it somehow, probably by special
casing the processor driver, but let's do that later.

Thanks,
Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [Update 4][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-21 23:06       ` [Update 3][PATCH " Rafael J. Wysocki
  2013-02-22  1:12         ` Toshi Kani
@ 2013-02-23 22:38         ` Rafael J. Wysocki
  2013-02-25 18:07           ` Toshi Kani
  1 sibling, 1 reply; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-23 22:38 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Yinghai Lu, Toshi Kani, Yasuaki Ishimatsu,
	Jiang Liu

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Multiple drivers handling hotplug-capable ACPI device nodes install
notify handlers covering the same types of events in a very similar
way.  Moreover, those handlers are installed in separate namespace
walks, although that really should be done during namespace scans
carried out by acpi_bus_scan().  This leads to substantial code
duplication, unnecessary overhead and behavior that is hard to
follow.

For this reason, introduce common code in drivers/acpi/scan.c for
handling hotplug-related notification and carrying out device
insertion and eject operations in a generic fashion, such that it
may be used by all of the relevant drivers in the future.  To cover
the existing differences between those drivers introduce struct
acpi_hotplug_profile for representing collections of hotplug
settings associated with different ACPI scan handlers that can be
used by the drivers to make the common code reflect their current
behavior.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---

This update causes acpi_bus_device_eject() to only emit KOBJ_OFFLINE uevent if
autoexec is unset for the given scan handler.

This will require the doc in patch [5/7] to be updated which I'm going to do if
everyone is OK with the $subject patch.

Thanks,
Rafael

---
 drivers/acpi/scan.c     |  270 ++++++++++++++++++++++++++++++++++++++----------
 include/acpi/acpi_bus.h |    7 +
 2 files changed, 224 insertions(+), 53 deletions(-)

Index: test/include/acpi/acpi_bus.h
===================================================================
--- test.orig/include/acpi/acpi_bus.h
+++ test/include/acpi/acpi_bus.h
@@ -88,11 +88,18 @@ struct acpi_device;
  * -----------------
  */
 
+struct acpi_hotplug_profile {
+	bool enabled:1;
+	bool uevents:1;
+	bool autoeject:1;
+};
+
 struct acpi_scan_handler {
 	const struct acpi_device_id *ids;
 	struct list_head list_node;
 	int (*attach)(struct acpi_device *dev, const struct acpi_device_id *id);
 	void (*detach)(struct acpi_device *dev);
+	struct acpi_hotplug_profile hotplug;
 };
 
 /*
Index: test/drivers/acpi/scan.c
===================================================================
--- test.orig/drivers/acpi/scan.c
+++ test/drivers/acpi/scan.c
@@ -107,32 +107,19 @@ acpi_device_modalias_show(struct device
 }
 static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
 
-/**
- * acpi_bus_hot_remove_device: hot-remove a device and its children
- * @context: struct acpi_eject_event pointer (freed in this func)
- *
- * Hot-remove a device and its children. This function frees up the
- * memory space passed by arg context, so that the caller may call
- * this function asynchronously through acpi_os_hotplug_execute().
- */
-void acpi_bus_hot_remove_device(void *context)
+static int acpi_scan_hot_remove(struct acpi_device *device)
 {
-	struct acpi_eject_event *ej_event = context;
-	struct acpi_device *device = ej_event->device;
 	acpi_handle handle = device->handle;
-	acpi_handle temp;
+	acpi_handle not_used;
 	struct acpi_object_list arg_list;
 	union acpi_object arg;
-	acpi_status status = AE_OK;
-	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
-
-	mutex_lock(&acpi_scan_lock);
+	acpi_status status;
 
 	/* If there is no handle, the device node has been unregistered. */
-	if (!device->handle) {
+	if (!handle) {
 		dev_dbg(&device->dev, "ACPI handle missing\n");
 		put_device(&device->dev);
-		goto out;
+		return -EINVAL;
 	}
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -143,7 +130,7 @@ void acpi_bus_hot_remove_device(void *co
 	put_device(&device->dev);
 	device = NULL;
 
-	if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &temp))) {
+	if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &not_used))) {
 		arg_list.count = 1;
 		arg_list.pointer = &arg;
 		arg.type = ACPI_TYPE_INTEGER;
@@ -161,18 +148,159 @@ void acpi_bus_hot_remove_device(void *co
 	 */
 	status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
 	if (ACPI_FAILURE(status)) {
-		if (status != AE_NOT_FOUND)
+		if (status == AE_NOT_FOUND) {
+			return -ENODEV;
+		} else {
 			acpi_handle_warn(handle, "Eject failed\n");
+			return -EIO;
+		}
+	}
+	return 0;
+}
 
-		/* Tell the firmware the hot-remove operation has failed. */
-		acpi_evaluate_hotplug_ost(handle, ej_event->event,
-					  ost_code, NULL);
+static void acpi_bus_device_eject(void *context)
+{
+	acpi_handle handle = context;
+	struct acpi_device *device = NULL;
+	struct acpi_scan_handler *handler;
+	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
+
+	mutex_lock(&acpi_scan_lock);
+
+	acpi_bus_get_device(handle, &device);
+	if (!device)
+		goto err_out;
+
+	handler = device->handler;
+	if (!handler || !handler->hotplug.enabled) {
+		ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
+		goto err_out;
+	}
+	acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
+				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+	if (handler->hotplug.autoeject) {
+		int error;
+
+		get_device(&device->dev);
+		error = acpi_scan_hot_remove(device);
+		if (error)
+			goto err_out;
+	} else {
+		device->flags.eject_pending = true;
+		if (handler->hotplug.uevents)
+			kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
 	}
 
  out:
 	mutex_unlock(&acpi_scan_lock);
-	kfree(context);
 	return;
+
+ err_out:
+	acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, ost_code,
+				  NULL);
+	goto out;
+}
+
+static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
+{
+	struct acpi_device *device = NULL;
+	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
+	int error;
+
+	mutex_lock(&acpi_scan_lock);
+
+	acpi_bus_get_device(handle, &device);
+	if (device) {
+		dev_warn(&device->dev, "Attempt to re-insert\n");
+		goto out;
+	}
+	acpi_evaluate_hotplug_ost(handle, ost_source,
+				  ACPI_OST_SC_INSERT_IN_PROGRESS, NULL);
+	error = acpi_bus_scan(handle);
+	if (error) {
+		acpi_handle_warn(handle, "Namespace scan failure\n");
+		goto out;
+	}
+	error = acpi_bus_get_device(handle, &device);
+	if (error) {
+		acpi_handle_warn(handle, "Missing device node object\n");
+		goto out;
+	}
+	ost_code = ACPI_OST_SC_SUCCESS;
+	if (device->handler && device->handler->hotplug.uevents)
+		kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
+
+ out:
+	acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL);
+	mutex_unlock(&acpi_scan_lock);
+}
+
+static void acpi_scan_bus_check(void *context)
+{
+	acpi_scan_bus_device_check((acpi_handle)context,
+				   ACPI_NOTIFY_BUS_CHECK);
+}
+
+static void acpi_scan_device_check(void *context)
+{
+	acpi_scan_bus_device_check((acpi_handle)context,
+				   ACPI_NOTIFY_DEVICE_CHECK);
+}
+
+static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *not_used)
+{
+	acpi_osd_exec_callback callback;
+	acpi_status status;
+
+	switch (type) {
+	case ACPI_NOTIFY_BUS_CHECK:
+		acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
+		callback = acpi_scan_bus_check;
+		break;
+	case ACPI_NOTIFY_DEVICE_CHECK:
+		acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
+		callback = acpi_scan_device_check;
+		break;
+	case ACPI_NOTIFY_EJECT_REQUEST:
+		acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
+		callback = acpi_bus_device_eject;
+		break;
+	default:
+		/* non-hotplug event; possibly handled by other handler */
+		return;
+	}
+	status = acpi_os_hotplug_execute(callback, handle);
+	if (ACPI_FAILURE(status))
+		acpi_evaluate_hotplug_ost(handle, type,
+					  ACPI_OST_SC_NON_SPECIFIC_FAILURE,
+					  NULL);
+}
+
+/**
+ * acpi_bus_hot_remove_device: hot-remove a device and its children
+ * @context: struct acpi_eject_event pointer (freed in this func)
+ *
+ * Hot-remove a device and its children. This function frees up the
+ * memory space passed by arg context, so that the caller may call
+ * this function asynchronously through acpi_os_hotplug_execute().
+ */
+void acpi_bus_hot_remove_device(void *context)
+{
+	struct acpi_eject_event *ej_event = context;
+	struct acpi_device *device = ej_event->device;
+	acpi_handle handle = device->handle;
+	int error;
+
+	mutex_lock(&acpi_scan_lock);
+
+	error = acpi_scan_hot_remove(device);
+	if (error && handle)
+		acpi_evaluate_hotplug_ost(handle, ej_event->event,
+					  ACPI_OST_SC_NON_SPECIFIC_FAILURE,
+					  NULL);
+
+	mutex_unlock(&acpi_scan_lock);
+	kfree(context);
 }
 EXPORT_SYMBOL(acpi_bus_hot_remove_device);
 
@@ -206,51 +334,61 @@ static ssize_t
 acpi_eject_store(struct device *d, struct device_attribute *attr,
 		const char *buf, size_t count)
 {
-	int ret = count;
-	acpi_status status;
-	acpi_object_type type = 0;
 	struct acpi_device *acpi_device = to_acpi_device(d);
 	struct acpi_eject_event *ej_event;
+	acpi_object_type not_used;
+	acpi_status status;
+	u32 ost_source;
+	int ret;
 
-	if ((!count) || (buf[0] != '1')) {
+	if (!count || buf[0] != '1')
 		return -EINVAL;
-	}
-	if (!acpi_device->driver && !acpi_device->handler) {
-		ret = -ENODEV;
-		goto err;
-	}
-	status = acpi_get_type(acpi_device->handle, &type);
-	if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) {
-		ret = -ENODEV;
-		goto err;
-	}
 
-	ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
-	if (!ej_event) {
-		ret = -ENOMEM;
-		goto err;
-	}
+	if ((!acpi_device->handler || !acpi_device->handler->hotplug.enabled)
+	    && !acpi_device->driver)
+		return -ENODEV;
+
+	status = acpi_get_type(acpi_device->handle, &not_used);
+	if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable)
+		return -ENODEV;
+
+	mutex_lock(&acpi_scan_lock);
 
-	get_device(&acpi_device->dev);
-	ej_event->device = acpi_device;
 	if (acpi_device->flags.eject_pending) {
-		/* event originated from ACPI eject notification */
-		ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
+		/* ACPI eject notification event. */
+		ost_source = ACPI_NOTIFY_EJECT_REQUEST;
 		acpi_device->flags.eject_pending = 0;
 	} else {
-		/* event originated from user */
-		ej_event->event = ACPI_OST_EC_OSPM_EJECT;
-		(void) acpi_evaluate_hotplug_ost(acpi_device->handle,
-			ej_event->event, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+		/* Eject initiated by user space. */
+		ost_source = ACPI_OST_EC_OSPM_EJECT;
 	}
-
+	ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
+	if (!ej_event) {
+		ret = -ENOMEM;
+		goto err_out;
+	}
+	acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source,
+				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+	ej_event->device = acpi_device;
+	ej_event->event = ost_source;
+	get_device(&acpi_device->dev);
 	status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event);
 	if (ACPI_FAILURE(status)) {
 		put_device(&acpi_device->dev);
 		kfree(ej_event);
+		ret = status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN;
+		goto err_out;
 	}
-err:
+	ret = count;
+
+ out:
+	mutex_unlock(&acpi_scan_lock);
 	return ret;
+
+ err_out:
+	acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source,
+				  ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
+	goto out;
 }
 
 static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
@@ -1548,6 +1686,30 @@ static struct acpi_scan_handler *acpi_sc
 	return NULL;
 }
 
+static void acpi_scan_init_hotplug(acpi_handle handle)
+{
+	struct acpi_device_info *info;
+	struct acpi_scan_handler *handler;
+
+	if (ACPI_FAILURE(acpi_get_object_info(handle, &info)))
+		return;
+
+	if (!(info->valid & ACPI_VALID_HID)) {
+		kfree(info);
+		return;
+	}
+
+	/*
+	 * This relies on the fact that acpi_install_notify_handler() will not
+	 * install the same notify handler routine twice for the same handle.
+	 */
+	handler = acpi_scan_match_handler(info->hardware_id.string, NULL);
+	kfree(info);
+	if (handler && handler->hotplug.enabled)
+		acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+					    acpi_hotplug_notify_cb, NULL);
+}
+
 static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
 				      void *not_used, void **return_value)
 {
@@ -1570,6 +1732,8 @@ static acpi_status acpi_bus_check_add(ac
 		return AE_OK;
 	}
 
+	acpi_scan_init_hotplug(handle);
+
 	if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
 	    !(sta & ACPI_STA_DEVICE_FUNCTIONING)) {
 		struct acpi_device_wakeup wakeup;


^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Update 4][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-23 22:38         ` [Update 4][PATCH " Rafael J. Wysocki
@ 2013-02-25 18:07           ` Toshi Kani
  2013-02-25 23:39             ` Rafael J. Wysocki
  0 siblings, 1 reply; 69+ messages in thread
From: Toshi Kani @ 2013-02-25 18:07 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Yinghai Lu,
	Yasuaki Ishimatsu, Jiang Liu

On Sat, 2013-02-23 at 22:38 +0000, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> 
> Multiple drivers handling hotplug-capable ACPI device nodes install
> notify handlers covering the same types of events in a very similar
> way.  Moreover, those handlers are installed in separate namespace
> walks, although that really should be done during namespace scans
> carried out by acpi_bus_scan().  This leads to substantial code
> duplication, unnecessary overhead and behavior that is hard to
> follow.
> 
> For this reason, introduce common code in drivers/acpi/scan.c for
> handling hotplug-related notification and carrying out device
> insertion and eject operations in a generic fashion, such that it
> may be used by all of the relevant drivers in the future.  To cover
> the existing differences between those drivers introduce struct
> acpi_hotplug_profile for representing collections of hotplug
> settings associated with different ACPI scan handlers that can be
> used by the drivers to make the common code reflect their current
> behavior.
> 
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> ---
> 
> This update causes acpi_bus_device_eject() to only emit KOBJ_OFFLINE uevent if
> autoexec is unset for the given scan handler.
> 
> This will require the doc in patch [5/7] to be updated which I'm going to do if
> everyone is OK with the $subject patch.
> 
> Thanks,
> Rafael
 :
> +
> +static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
> +{
> +	struct acpi_device *device = NULL;
> +	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
> +	int error;
> +
> +	mutex_lock(&acpi_scan_lock);
> +
> +	acpi_bus_get_device(handle, &device);
> +	if (device) {
> +		dev_warn(&device->dev, "Attempt to re-insert\n");
> +		goto out;
> +	}
> +	acpi_evaluate_hotplug_ost(handle, ost_source,
> +				  ACPI_OST_SC_INSERT_IN_PROGRESS, NULL);
> +	error = acpi_bus_scan(handle);
> +	if (error) {
> +		acpi_handle_warn(handle, "Namespace scan failure\n");
> +		goto out;
> +	}
> +	error = acpi_bus_get_device(handle, &device);
> +	if (error) {
> +		acpi_handle_warn(handle, "Missing device node object\n");
> +		goto out;
> +	}
> +	ost_code = ACPI_OST_SC_SUCCESS;
> +	if (device->handler && device->handler->hotplug.uevents)
> +		kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);

I confirmed that the uevent crash issue was solved.  Thinking further, I
wonder if we need to emit KOBJ_ONLINE here.  This behavior is asymmetric
since we do not emit KOBJ_OFFLINE when autoeject is set.  The definition
of ONLINE/OFFLINE event to an ACPI device object seems also bogus since
there is no online/offline operation to the ACPI device object itself.
Online/offline operation is only possible to actual device, such as
system/cpu/cpu% and system/memory/memory%.

So, I'd suggest the following changes.
 - Remove the "uevents" attribute.  KOBJ_ONLINE/OFFLINE are not used for
ACPI device objects.
 - Make the !autoeject case as an exception for now, and emit
KOBJ_OFFLINE as a way to request off-lining to user.  This uevent is
tied with the !autoeject case.  We can then revisit if this use-case
needs to be supported going forward.  If so, we may want to consider a
different event type.

Thanks,
-Toshi


^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH 5/7] ACPI / hotplug: Introduce user space interface for hotplug profiles
  2013-02-17 15:24 ` [PATCH 5/7] ACPI / hotplug: Introduce user space interface for hotplug profiles Rafael J. Wysocki
@ 2013-02-25 18:13   ` Toshi Kani
  2013-02-25 23:25     ` Rafael J. Wysocki
  0 siblings, 1 reply; 69+ messages in thread
From: Toshi Kani @ 2013-02-25 18:13 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Yinghai Lu,
	Yasuaki Ishimatsu, Jiang Liu

On Sun, 2013-02-17 at 16:24 +0100, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@inel.com>
> 
> Introduce user space interface for manipulating hotplug profiles
> associated with ACPI scan handlers.
> 
> The interface consists of sysfs directories under
> /sys/firmware/acpi/hotplug/, one for each hotplug profile, containing
> attributes allowing user space to manipulate the enabled, uevents,
> and autoeject fields of the corresponding profile.  In particular,
> switching the enabled attribute from 'unset' to 'set' will cause
> the common hotplug notify handler to be installed for all ACPI
> namespace objects representing devices matching the scan handler
> associated with the given hotplug profile (and analogously for the
> converse switch).
> 
> Drivers willing to use the new user space interface should add their
> ACPI scan handlers with the help of new funtion
> acpi_scan_add_handler_with_hotplug().
> 
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@inel.com>
> ---
>  Documentation/ABI/testing/sysfs-firmware-acpi |   42 +++++++++
>  drivers/acpi/internal.h                       |    9 +
>  drivers/acpi/scan.c                           |   73 +++++++++++++++
>  drivers/acpi/sysfs.c                          |  120 ++++++++++++++++++++++++++
>  include/acpi/acpi_bus.h                       |    7 +
>  5 files changed, 251 insertions(+)
 :
> Index: test/drivers/acpi/scan.c
> ===================================================================
> --- test.orig/drivers/acpi/scan.c
> +++ test/drivers/acpi/scan.c
> @@ -63,6 +63,19 @@ int acpi_scan_add_handler(struct acpi_sc
>  	return 0;
>  }
>  
> +int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler,
> +				       const char *hotplug_profile_name)
> +{
> +	int error;
> +
> +	error = acpi_scan_add_handler(handler);
> +	if (error)
> +		return error;
> +
> +	acpi_sysfs_add_hotplug_profile(&handler->hotplug, hotplug_profile_name);
> +	return 0;
> +}
> +
>  /*
>   * Creates hid/cid(s) string needed for modalias and uevent
>   * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get:
> @@ -1675,6 +1688,66 @@ static bool acpi_scan_handler_matching(s
>  	return false;
>  }
>  
> +static acpi_status acpi_scan_hotplug_modify(acpi_handle handle,
> +					    u32 lvl_not_used, void *data,
> +					    void **ret_not_used)
> +{
> +	struct acpi_scan_handler *handler = data;
> +	struct acpi_device_info *info;
> +	bool match = false;
> +
> +	if (ACPI_FAILURE(acpi_get_object_info(handle, &info)))
> +		return AE_OK;
> +
> +	if (info->valid & ACPI_VALID_HID) {
> +		char *idstr = info->hardware_id.string;
> +		match = acpi_scan_handler_matching(handler, idstr, NULL);
> +	}
> +	kfree(info);
> +	if (!match)
> +		return AE_OK;
> +
> +	if (handler->hotplug.enabled)
> +		acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
> +					   acpi_hotplug_notify_cb);
> +	else
> +		acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
> +					    acpi_hotplug_notify_cb, NULL);

I found that the action for "enabled" attribute is incorrect.  When
enabled, it should install the notify handler, and remove otherwise.

Thanks,
-Toshi





^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH 5/7] ACPI / hotplug: Introduce user space interface for hotplug profiles
  2013-02-25 18:13   ` Toshi Kani
@ 2013-02-25 23:25     ` Rafael J. Wysocki
  0 siblings, 0 replies; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-25 23:25 UTC (permalink / raw)
  To: Toshi Kani
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Yinghai Lu,
	Yasuaki Ishimatsu, Jiang Liu

On Monday, February 25, 2013 11:13:59 AM Toshi Kani wrote:
> On Sun, 2013-02-17 at 16:24 +0100, Rafael J. Wysocki wrote:
> > From: Rafael J. Wysocki <rafael.j.wysocki@inel.com>
> > 
> > Introduce user space interface for manipulating hotplug profiles
> > associated with ACPI scan handlers.
> > 
> > The interface consists of sysfs directories under
> > /sys/firmware/acpi/hotplug/, one for each hotplug profile, containing
> > attributes allowing user space to manipulate the enabled, uevents,
> > and autoeject fields of the corresponding profile.  In particular,
> > switching the enabled attribute from 'unset' to 'set' will cause
> > the common hotplug notify handler to be installed for all ACPI
> > namespace objects representing devices matching the scan handler
> > associated with the given hotplug profile (and analogously for the
> > converse switch).
> > 
> > Drivers willing to use the new user space interface should add their
> > ACPI scan handlers with the help of new funtion
> > acpi_scan_add_handler_with_hotplug().
> > 
> > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@inel.com>
> > ---
> >  Documentation/ABI/testing/sysfs-firmware-acpi |   42 +++++++++
> >  drivers/acpi/internal.h                       |    9 +
> >  drivers/acpi/scan.c                           |   73 +++++++++++++++
> >  drivers/acpi/sysfs.c                          |  120 ++++++++++++++++++++++++++
> >  include/acpi/acpi_bus.h                       |    7 +
> >  5 files changed, 251 insertions(+)
>  :
> > Index: test/drivers/acpi/scan.c
> > ===================================================================
> > --- test.orig/drivers/acpi/scan.c
> > +++ test/drivers/acpi/scan.c
> > @@ -63,6 +63,19 @@ int acpi_scan_add_handler(struct acpi_sc
> >  	return 0;
> >  }
> >  
> > +int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler,
> > +				       const char *hotplug_profile_name)
> > +{
> > +	int error;
> > +
> > +	error = acpi_scan_add_handler(handler);
> > +	if (error)
> > +		return error;
> > +
> > +	acpi_sysfs_add_hotplug_profile(&handler->hotplug, hotplug_profile_name);
> > +	return 0;
> > +}
> > +
> >  /*
> >   * Creates hid/cid(s) string needed for modalias and uevent
> >   * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get:
> > @@ -1675,6 +1688,66 @@ static bool acpi_scan_handler_matching(s
> >  	return false;
> >  }
> >  
> > +static acpi_status acpi_scan_hotplug_modify(acpi_handle handle,
> > +					    u32 lvl_not_used, void *data,
> > +					    void **ret_not_used)
> > +{
> > +	struct acpi_scan_handler *handler = data;
> > +	struct acpi_device_info *info;
> > +	bool match = false;
> > +
> > +	if (ACPI_FAILURE(acpi_get_object_info(handle, &info)))
> > +		return AE_OK;
> > +
> > +	if (info->valid & ACPI_VALID_HID) {
> > +		char *idstr = info->hardware_id.string;
> > +		match = acpi_scan_handler_matching(handler, idstr, NULL);
> > +	}
> > +	kfree(info);
> > +	if (!match)
> > +		return AE_OK;
> > +
> > +	if (handler->hotplug.enabled)
> > +		acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
> > +					   acpi_hotplug_notify_cb);
> > +	else
> > +		acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
> > +					    acpi_hotplug_notify_cb, NULL);
> 
> I found that the action for "enabled" attribute is incorrect.  When
> enabled, it should install the notify handler, and remove otherwise.

Well, thanks for spotting this!

Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Update 4][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-25 23:39             ` Rafael J. Wysocki
@ 2013-02-25 23:32               ` Toshi Kani
  2013-02-26  0:40               ` Yasuaki Ishimatsu
  2013-03-04 13:10               ` Vasilis Liaskovitis
  2 siblings, 0 replies; 69+ messages in thread
From: Toshi Kani @ 2013-02-25 23:32 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Yinghai Lu,
	Yasuaki Ishimatsu, Jiang Liu

On Tue, 2013-02-26 at 00:39 +0100, Rafael J. Wysocki wrote:
> On Monday, February 25, 2013 11:07:52 AM Toshi Kani wrote:
> > On Sat, 2013-02-23 at 22:38 +0000, Rafael J. Wysocki wrote:
> > > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > > 
> > > Multiple drivers handling hotplug-capable ACPI device nodes install
> > > notify handlers covering the same types of events in a very similar
> > > way.  Moreover, those handlers are installed in separate namespace
> > > walks, although that really should be done during namespace scans
> > > carried out by acpi_bus_scan().  This leads to substantial code
> > > duplication, unnecessary overhead and behavior that is hard to
> > > follow.
> > > 
> > > For this reason, introduce common code in drivers/acpi/scan.c for
> > > handling hotplug-related notification and carrying out device
> > > insertion and eject operations in a generic fashion, such that it
> > > may be used by all of the relevant drivers in the future.  To cover
> > > the existing differences between those drivers introduce struct
> > > acpi_hotplug_profile for representing collections of hotplug
> > > settings associated with different ACPI scan handlers that can be
> > > used by the drivers to make the common code reflect their current
> > > behavior.
> > > 
> > > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > > ---
> > > 
> > > This update causes acpi_bus_device_eject() to only emit KOBJ_OFFLINE uevent if
> > > autoexec is unset for the given scan handler.
> > > 
> > > This will require the doc in patch [5/7] to be updated which I'm going to do if
> > > everyone is OK with the $subject patch.
> > > 
> > > Thanks,
> > > Rafael
> >  :
> > > +
> > > +static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
> > > +{
> > > +	struct acpi_device *device = NULL;
> > > +	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
> > > +	int error;
> > > +
> > > +	mutex_lock(&acpi_scan_lock);
> > > +
> > > +	acpi_bus_get_device(handle, &device);
> > > +	if (device) {
> > > +		dev_warn(&device->dev, "Attempt to re-insert\n");
> > > +		goto out;
> > > +	}
> > > +	acpi_evaluate_hotplug_ost(handle, ost_source,
> > > +				  ACPI_OST_SC_INSERT_IN_PROGRESS, NULL);
> > > +	error = acpi_bus_scan(handle);
> > > +	if (error) {
> > > +		acpi_handle_warn(handle, "Namespace scan failure\n");
> > > +		goto out;
> > > +	}
> > > +	error = acpi_bus_get_device(handle, &device);
> > > +	if (error) {
> > > +		acpi_handle_warn(handle, "Missing device node object\n");
> > > +		goto out;
> > > +	}
> > > +	ost_code = ACPI_OST_SC_SUCCESS;
> > > +	if (device->handler && device->handler->hotplug.uevents)
> > > +		kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
> > 
> > I confirmed that the uevent crash issue was solved.  Thinking further, I
> > wonder if we need to emit KOBJ_ONLINE here.  This behavior is asymmetric
> > since we do not emit KOBJ_OFFLINE when autoeject is set.
> 
> Well, I put that in there only to be able to make the container driver behave
> in a backwards compatible way (which is to emit KOBJ_ONLINE at this point).
> 
> If the container driver doesn't need to emit KOBJ_ONLINE at all, I agree with
> your suggestion.
> 
> > The definition of ONLINE/OFFLINE event to an ACPI device object seems also
> > bogus since there is no online/offline operation to the ACPI device object
> > itself.
> > Online/offline operation is only possible to actual device, such as
> > system/cpu/cpu% and system/memory/memory%.
> 
> That's correct, but I don't know what the user space expectations are
> currently.

I see.  I agree that we should keep backward compatibility with this
patchset.

> > So, I'd suggest the following changes.
> >  - Remove the "uevents" attribute.  KOBJ_ONLINE/OFFLINE are not used for
> > ACPI device objects.
> >  - Make the !autoeject case as an exception for now, and emit
> > KOBJ_OFFLINE as a way to request off-lining to user.  This uevent is
> > tied with the !autoeject case.  We can then revisit if this use-case
> > needs to be supported going forward.  If so, we may want to consider a
> > different event type.
> 
> Well, what about avoiding to expose uevents and autoeject for now and
> exposing enabled only?  Drivers would still be able to set the other flags on
> init on init to enforce the backwards-compatible behavior.
> 
> I agree that it would be sufficient to use one additional flag then, to start
> with, but its meaning would be something like "keep backwards compatibility
> with the old container driver", so perhaps "autoeject" is not a good name.
> 
> What about "user_eject" (that won't be exposed to user space) instead?  Where,
> if set, it would meand "do not autoeject and emit KOBJ_OFFLINE/ONLINE uevents
> like the old container driver did"?

Good idea!

Thanks,
-Toshi



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Update 4][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-25 18:07           ` Toshi Kani
@ 2013-02-25 23:39             ` Rafael J. Wysocki
  2013-02-25 23:32               ` Toshi Kani
                                 ` (2 more replies)
  0 siblings, 3 replies; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-25 23:39 UTC (permalink / raw)
  To: Toshi Kani
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Yinghai Lu,
	Yasuaki Ishimatsu, Jiang Liu

On Monday, February 25, 2013 11:07:52 AM Toshi Kani wrote:
> On Sat, 2013-02-23 at 22:38 +0000, Rafael J. Wysocki wrote:
> > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > 
> > Multiple drivers handling hotplug-capable ACPI device nodes install
> > notify handlers covering the same types of events in a very similar
> > way.  Moreover, those handlers are installed in separate namespace
> > walks, although that really should be done during namespace scans
> > carried out by acpi_bus_scan().  This leads to substantial code
> > duplication, unnecessary overhead and behavior that is hard to
> > follow.
> > 
> > For this reason, introduce common code in drivers/acpi/scan.c for
> > handling hotplug-related notification and carrying out device
> > insertion and eject operations in a generic fashion, such that it
> > may be used by all of the relevant drivers in the future.  To cover
> > the existing differences between those drivers introduce struct
> > acpi_hotplug_profile for representing collections of hotplug
> > settings associated with different ACPI scan handlers that can be
> > used by the drivers to make the common code reflect their current
> > behavior.
> > 
> > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > ---
> > 
> > This update causes acpi_bus_device_eject() to only emit KOBJ_OFFLINE uevent if
> > autoexec is unset for the given scan handler.
> > 
> > This will require the doc in patch [5/7] to be updated which I'm going to do if
> > everyone is OK with the $subject patch.
> > 
> > Thanks,
> > Rafael
>  :
> > +
> > +static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
> > +{
> > +	struct acpi_device *device = NULL;
> > +	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
> > +	int error;
> > +
> > +	mutex_lock(&acpi_scan_lock);
> > +
> > +	acpi_bus_get_device(handle, &device);
> > +	if (device) {
> > +		dev_warn(&device->dev, "Attempt to re-insert\n");
> > +		goto out;
> > +	}
> > +	acpi_evaluate_hotplug_ost(handle, ost_source,
> > +				  ACPI_OST_SC_INSERT_IN_PROGRESS, NULL);
> > +	error = acpi_bus_scan(handle);
> > +	if (error) {
> > +		acpi_handle_warn(handle, "Namespace scan failure\n");
> > +		goto out;
> > +	}
> > +	error = acpi_bus_get_device(handle, &device);
> > +	if (error) {
> > +		acpi_handle_warn(handle, "Missing device node object\n");
> > +		goto out;
> > +	}
> > +	ost_code = ACPI_OST_SC_SUCCESS;
> > +	if (device->handler && device->handler->hotplug.uevents)
> > +		kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
> 
> I confirmed that the uevent crash issue was solved.  Thinking further, I
> wonder if we need to emit KOBJ_ONLINE here.  This behavior is asymmetric
> since we do not emit KOBJ_OFFLINE when autoeject is set.

Well, I put that in there only to be able to make the container driver behave
in a backwards compatible way (which is to emit KOBJ_ONLINE at this point).

If the container driver doesn't need to emit KOBJ_ONLINE at all, I agree with
your suggestion.

> The definition of ONLINE/OFFLINE event to an ACPI device object seems also
> bogus since there is no online/offline operation to the ACPI device object
> itself.
> Online/offline operation is only possible to actual device, such as
> system/cpu/cpu% and system/memory/memory%.

That's correct, but I don't know what the user space expectations are
currently.

> So, I'd suggest the following changes.
>  - Remove the "uevents" attribute.  KOBJ_ONLINE/OFFLINE are not used for
> ACPI device objects.
>  - Make the !autoeject case as an exception for now, and emit
> KOBJ_OFFLINE as a way to request off-lining to user.  This uevent is
> tied with the !autoeject case.  We can then revisit if this use-case
> needs to be supported going forward.  If so, we may want to consider a
> different event type.

Well, what about avoiding to expose uevents and autoeject for now and
exposing enabled only?  Drivers would still be able to set the other flags on
init on init to enforce the backwards-compatible behavior.

I agree that it would be sufficient to use one additional flag then, to start
with, but its meaning would be something like "keep backwards compatibility
with the old container driver", so perhaps "autoeject" is not a good name.

What about "user_eject" (that won't be exposed to user space) instead?  Where,
if set, it would meand "do not autoeject and emit KOBJ_OFFLINE/ONLINE uevents
like the old container driver did"?

Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Update 4][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-25 23:39             ` Rafael J. Wysocki
  2013-02-25 23:32               ` Toshi Kani
@ 2013-02-26  0:40               ` Yasuaki Ishimatsu
  2013-02-26  1:09                 ` Toshi Kani
  2013-03-04 13:10               ` Vasilis Liaskovitis
  2 siblings, 1 reply; 69+ messages in thread
From: Yasuaki Ishimatsu @ 2013-02-26  0:40 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Toshi Kani, ACPI Devel Maling List, Bjorn Helgaas, LKML,
	Yinghai Lu, Jiang Liu

2013/02/26 8:39, Rafael J. Wysocki wrote:
> On Monday, February 25, 2013 11:07:52 AM Toshi Kani wrote:
>> On Sat, 2013-02-23 at 22:38 +0000, Rafael J. Wysocki wrote:
>>> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>>>
>>> Multiple drivers handling hotplug-capable ACPI device nodes install
>>> notify handlers covering the same types of events in a very similar
>>> way.  Moreover, those handlers are installed in separate namespace
>>> walks, although that really should be done during namespace scans
>>> carried out by acpi_bus_scan().  This leads to substantial code
>>> duplication, unnecessary overhead and behavior that is hard to
>>> follow.
>>>
>>> For this reason, introduce common code in drivers/acpi/scan.c for
>>> handling hotplug-related notification and carrying out device
>>> insertion and eject operations in a generic fashion, such that it
>>> may be used by all of the relevant drivers in the future.  To cover
>>> the existing differences between those drivers introduce struct
>>> acpi_hotplug_profile for representing collections of hotplug
>>> settings associated with different ACPI scan handlers that can be
>>> used by the drivers to make the common code reflect their current
>>> behavior.
>>>
>>> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>>> ---
>>>
>>> This update causes acpi_bus_device_eject() to only emit KOBJ_OFFLINE uevent if
>>> autoexec is unset for the given scan handler.
>>>
>>> This will require the doc in patch [5/7] to be updated which I'm going to do if
>>> everyone is OK with the $subject patch.
>>>
>>> Thanks,
>>> Rafael
>>   :
>>> +
>>> +static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
>>> +{
>>> +	struct acpi_device *device = NULL;
>>> +	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
>>> +	int error;
>>> +
>>> +	mutex_lock(&acpi_scan_lock);
>>> +
>>> +	acpi_bus_get_device(handle, &device);
>>> +	if (device) {
>>> +		dev_warn(&device->dev, "Attempt to re-insert\n");
>>> +		goto out;
>>> +	}
>>> +	acpi_evaluate_hotplug_ost(handle, ost_source,
>>> +				  ACPI_OST_SC_INSERT_IN_PROGRESS, NULL);
>>> +	error = acpi_bus_scan(handle);
>>> +	if (error) {
>>> +		acpi_handle_warn(handle, "Namespace scan failure\n");
>>> +		goto out;
>>> +	}
>>> +	error = acpi_bus_get_device(handle, &device);
>>> +	if (error) {
>>> +		acpi_handle_warn(handle, "Missing device node object\n");
>>> +		goto out;
>>> +	}
>>> +	ost_code = ACPI_OST_SC_SUCCESS;
>>> +	if (device->handler && device->handler->hotplug.uevents)
>>> +		kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
>>

>> I confirmed that the uevent crash issue was solved.  Thinking further, I
>> wonder if we need to emit KOBJ_ONLINE here.  This behavior is asymmetric
>> since we do not emit KOBJ_OFFLINE when autoeject is set.
>
> Well, I put that in there only to be able to make the container driver behave
> in a backwards compatible way (which is to emit KOBJ_ONLINE at this point).
>
> If the container driver doesn't need to emit KOBJ_ONLINE at all, I agree with
> your suggestion.
>
>> The definition of ONLINE/OFFLINE event to an ACPI device object seems also
>> bogus since there is no online/offline operation to the ACPI device object
>> itself.
>> Online/offline operation is only possible to actual device, such as
>> system/cpu/cpu% and system/memory/memory%.
>
> That's correct, but I don't know what the user space expectations are
> currently.

My system expects this event to be notified when hot adding container device.
My container device has cpu and memory. As Toshi said, these devices are
offline when hot adding container device. So in my system, when notifying
container device's KOBJ_ONLINE event, my application runs for onlining these
devices. If this event is not notified to user land, we cannot online these
devices  automatically.

>
>> So, I'd suggest the following changes.
>>   - Remove the "uevents" attribute.  KOBJ_ONLINE/OFFLINE are not used for
>> ACPI device objects.
>>   - Make the !autoeject case as an exception for now, and emit
>> KOBJ_OFFLINE as a way to request off-lining to user.  This uevent is
>> tied with the !autoeject case.  We can then revisit if this use-case
>> needs to be supported going forward.  If so, we may want to consider a
>> different event type.
>
> Well, what about avoiding to expose uevents and autoeject for now and
> exposing enabled only?  Drivers would still be able to set the other flags on
> init on init to enforce the backwards-compatible behavior.
>
> I agree that it would be sufficient to use one additional flag then, to start
> with, but its meaning would be something like "keep backwards compatibility
> with the old container driver", so perhaps "autoeject" is not a good name.
>

> What about "user_eject" (that won't be exposed to user space) instead?  Where,
> if set, it would meand "do not autoeject and emit KOBJ_OFFLINE/ONLINE uevents
> like the old container driver did"?

It's good idea.

Thanks,
Yasuaki Ishimatsu

>
> Rafael
>
>



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Update 4][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-26  0:40               ` Yasuaki Ishimatsu
@ 2013-02-26  1:09                 ` Toshi Kani
  2013-02-26  2:02                   ` Yasuaki Ishimatsu
  0 siblings, 1 reply; 69+ messages in thread
From: Toshi Kani @ 2013-02-26  1:09 UTC (permalink / raw)
  To: Yasuaki Ishimatsu
  Cc: Rafael J. Wysocki, ACPI Devel Maling List, Bjorn Helgaas, LKML,
	Yinghai Lu, Jiang Liu

On Tue, 2013-02-26 at 09:40 +0900, Yasuaki Ishimatsu wrote:
> 2013/02/26 8:39, Rafael J. Wysocki wrote:
> > On Monday, February 25, 2013 11:07:52 AM Toshi Kani wrote:
> >> On Sat, 2013-02-23 at 22:38 +0000, Rafael J. Wysocki wrote:
> >>> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> >>>
> >>> Multiple drivers handling hotplug-capable ACPI device nodes install
> >>> notify handlers covering the same types of events in a very similar
> >>> way.  Moreover, those handlers are installed in separate namespace
> >>> walks, although that really should be done during namespace scans
> >>> carried out by acpi_bus_scan().  This leads to substantial code
> >>> duplication, unnecessary overhead and behavior that is hard to
> >>> follow.
> >>>
> >>> For this reason, introduce common code in drivers/acpi/scan.c for
> >>> handling hotplug-related notification and carrying out device
> >>> insertion and eject operations in a generic fashion, such that it
> >>> may be used by all of the relevant drivers in the future.  To cover
> >>> the existing differences between those drivers introduce struct
> >>> acpi_hotplug_profile for representing collections of hotplug
> >>> settings associated with different ACPI scan handlers that can be
> >>> used by the drivers to make the common code reflect their current
> >>> behavior.
> >>>
> >>> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> >>> ---
> >>>
> >>> This update causes acpi_bus_device_eject() to only emit KOBJ_OFFLINE uevent if
> >>> autoexec is unset for the given scan handler.
> >>>
> >>> This will require the doc in patch [5/7] to be updated which I'm going to do if
> >>> everyone is OK with the $subject patch.
> >>>
> >>> Thanks,
> >>> Rafael
> >>   :
> >>> +
> >>> +static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
> >>> +{
> >>> +	struct acpi_device *device = NULL;
> >>> +	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
> >>> +	int error;
> >>> +
> >>> +	mutex_lock(&acpi_scan_lock);
> >>> +
> >>> +	acpi_bus_get_device(handle, &device);
> >>> +	if (device) {
> >>> +		dev_warn(&device->dev, "Attempt to re-insert\n");
> >>> +		goto out;
> >>> +	}
> >>> +	acpi_evaluate_hotplug_ost(handle, ost_source,
> >>> +				  ACPI_OST_SC_INSERT_IN_PROGRESS, NULL);
> >>> +	error = acpi_bus_scan(handle);
> >>> +	if (error) {
> >>> +		acpi_handle_warn(handle, "Namespace scan failure\n");
> >>> +		goto out;
> >>> +	}
> >>> +	error = acpi_bus_get_device(handle, &device);
> >>> +	if (error) {
> >>> +		acpi_handle_warn(handle, "Missing device node object\n");
> >>> +		goto out;
> >>> +	}
> >>> +	ost_code = ACPI_OST_SC_SUCCESS;
> >>> +	if (device->handler && device->handler->hotplug.uevents)
> >>> +		kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
> >>
> 
> >> I confirmed that the uevent crash issue was solved.  Thinking further, I
> >> wonder if we need to emit KOBJ_ONLINE here.  This behavior is asymmetric
> >> since we do not emit KOBJ_OFFLINE when autoeject is set.
> >
> > Well, I put that in there only to be able to make the container driver behave
> > in a backwards compatible way (which is to emit KOBJ_ONLINE at this point).
> >
> > If the container driver doesn't need to emit KOBJ_ONLINE at all, I agree with
> > your suggestion.
> >
> >> The definition of ONLINE/OFFLINE event to an ACPI device object seems also
> >> bogus since there is no online/offline operation to the ACPI device object
> >> itself.
> >> Online/offline operation is only possible to actual device, such as
> >> system/cpu/cpu% and system/memory/memory%.
> >
> > That's correct, but I don't know what the user space expectations are
> > currently.
> 
> My system expects this event to be notified when hot adding container device.
> My container device has cpu and memory. As Toshi said, these devices are
> offline when hot adding container device. So in my system, when notifying
> container device's KOBJ_ONLINE event, my application runs for onlining these
> devices. If this event is not notified to user land, we cannot online these
> devices  automatically.

Thanks for the info.  Can your application listen KOBJ_ADD to a
container device, instead of KOBJ_ONLINE?  IOW, does it distinguish
between ADD and ONLINE events to a container device?

-Toshi



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Update 4][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-26  1:09                 ` Toshi Kani
@ 2013-02-26  2:02                   ` Yasuaki Ishimatsu
  2013-02-26  3:11                     ` Rafael J. Wysocki
  0 siblings, 1 reply; 69+ messages in thread
From: Yasuaki Ishimatsu @ 2013-02-26  2:02 UTC (permalink / raw)
  To: Toshi Kani
  Cc: Rafael J. Wysocki, ACPI Devel Maling List, Bjorn Helgaas, LKML,
	Yinghai Lu, Jiang Liu

2013/02/26 10:09, Toshi Kani wrote:
> On Tue, 2013-02-26 at 09:40 +0900, Yasuaki Ishimatsu wrote:
>> 2013/02/26 8:39, Rafael J. Wysocki wrote:
>>> On Monday, February 25, 2013 11:07:52 AM Toshi Kani wrote:
>>>> On Sat, 2013-02-23 at 22:38 +0000, Rafael J. Wysocki wrote:
>>>>> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>>>>>
>>>>> Multiple drivers handling hotplug-capable ACPI device nodes install
>>>>> notify handlers covering the same types of events in a very similar
>>>>> way.  Moreover, those handlers are installed in separate namespace
>>>>> walks, although that really should be done during namespace scans
>>>>> carried out by acpi_bus_scan().  This leads to substantial code
>>>>> duplication, unnecessary overhead and behavior that is hard to
>>>>> follow.
>>>>>
>>>>> For this reason, introduce common code in drivers/acpi/scan.c for
>>>>> handling hotplug-related notification and carrying out device
>>>>> insertion and eject operations in a generic fashion, such that it
>>>>> may be used by all of the relevant drivers in the future.  To cover
>>>>> the existing differences between those drivers introduce struct
>>>>> acpi_hotplug_profile for representing collections of hotplug
>>>>> settings associated with different ACPI scan handlers that can be
>>>>> used by the drivers to make the common code reflect their current
>>>>> behavior.
>>>>>
>>>>> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>>>>> ---
>>>>>
>>>>> This update causes acpi_bus_device_eject() to only emit KOBJ_OFFLINE uevent if
>>>>> autoexec is unset for the given scan handler.
>>>>>
>>>>> This will require the doc in patch [5/7] to be updated which I'm going to do if
>>>>> everyone is OK with the $subject patch.
>>>>>
>>>>> Thanks,
>>>>> Rafael
>>>>    :
>>>>> +
>>>>> +static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
>>>>> +{
>>>>> +	struct acpi_device *device = NULL;
>>>>> +	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
>>>>> +	int error;
>>>>> +
>>>>> +	mutex_lock(&acpi_scan_lock);
>>>>> +
>>>>> +	acpi_bus_get_device(handle, &device);
>>>>> +	if (device) {
>>>>> +		dev_warn(&device->dev, "Attempt to re-insert\n");
>>>>> +		goto out;
>>>>> +	}
>>>>> +	acpi_evaluate_hotplug_ost(handle, ost_source,
>>>>> +				  ACPI_OST_SC_INSERT_IN_PROGRESS, NULL);
>>>>> +	error = acpi_bus_scan(handle);
>>>>> +	if (error) {
>>>>> +		acpi_handle_warn(handle, "Namespace scan failure\n");
>>>>> +		goto out;
>>>>> +	}
>>>>> +	error = acpi_bus_get_device(handle, &device);
>>>>> +	if (error) {
>>>>> +		acpi_handle_warn(handle, "Missing device node object\n");
>>>>> +		goto out;
>>>>> +	}
>>>>> +	ost_code = ACPI_OST_SC_SUCCESS;
>>>>> +	if (device->handler && device->handler->hotplug.uevents)
>>>>> +		kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
>>>>
>>
>>>> I confirmed that the uevent crash issue was solved.  Thinking further, I
>>>> wonder if we need to emit KOBJ_ONLINE here.  This behavior is asymmetric
>>>> since we do not emit KOBJ_OFFLINE when autoeject is set.
>>>
>>> Well, I put that in there only to be able to make the container driver behave
>>> in a backwards compatible way (which is to emit KOBJ_ONLINE at this point).
>>>
>>> If the container driver doesn't need to emit KOBJ_ONLINE at all, I agree with
>>> your suggestion.
>>>
>>>> The definition of ONLINE/OFFLINE event to an ACPI device object seems also
>>>> bogus since there is no online/offline operation to the ACPI device object
>>>> itself.
>>>> Online/offline operation is only possible to actual device, such as
>>>> system/cpu/cpu% and system/memory/memory%.
>>>
>>> That's correct, but I don't know what the user space expectations are
>>> currently.
>>
>> My system expects this event to be notified when hot adding container device.
>> My container device has cpu and memory. As Toshi said, these devices are
>> offline when hot adding container device. So in my system, when notifying
>> container device's KOBJ_ONLINE event, my application runs for onlining these
>> devices. If this event is not notified to user land, we cannot online these
>> devices  automatically.
>

> Thanks for the info.  Can your application listen KOBJ_ADD to a
> container device, instead of KOBJ_ONLINE?  IOW, does it distinguish
> between ADD and ONLINE events to a container device?

My application does not distinguish between ADD and ONLINE events
currently. But if the event is changed from ONLINE to ADD, I will
change my application.

Thanks,
Yasuaki Ishimatsu

>
> -Toshi
>
>



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Update 4][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-26  2:02                   ` Yasuaki Ishimatsu
@ 2013-02-26  3:11                     ` Rafael J. Wysocki
  2013-02-26  3:40                       ` Yasuaki Ishimatsu
  0 siblings, 1 reply; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-26  3:11 UTC (permalink / raw)
  To: Yasuaki Ishimatsu
  Cc: Toshi Kani, ACPI Devel Maling List, Bjorn Helgaas, LKML,
	Yinghai Lu, Jiang Liu

On Tuesday, February 26, 2013 11:02:56 AM Yasuaki Ishimatsu wrote:
> 2013/02/26 10:09, Toshi Kani wrote:
> > On Tue, 2013-02-26 at 09:40 +0900, Yasuaki Ishimatsu wrote:
> >> 2013/02/26 8:39, Rafael J. Wysocki wrote:
> >>> On Monday, February 25, 2013 11:07:52 AM Toshi Kani wrote:
> >>>> On Sat, 2013-02-23 at 22:38 +0000, Rafael J. Wysocki wrote:
> >>>>> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> >>>>>
> >>>>> Multiple drivers handling hotplug-capable ACPI device nodes install
> >>>>> notify handlers covering the same types of events in a very similar
> >>>>> way.  Moreover, those handlers are installed in separate namespace
> >>>>> walks, although that really should be done during namespace scans
> >>>>> carried out by acpi_bus_scan().  This leads to substantial code
> >>>>> duplication, unnecessary overhead and behavior that is hard to
> >>>>> follow.
> >>>>>
> >>>>> For this reason, introduce common code in drivers/acpi/scan.c for
> >>>>> handling hotplug-related notification and carrying out device
> >>>>> insertion and eject operations in a generic fashion, such that it
> >>>>> may be used by all of the relevant drivers in the future.  To cover
> >>>>> the existing differences between those drivers introduce struct
> >>>>> acpi_hotplug_profile for representing collections of hotplug
> >>>>> settings associated with different ACPI scan handlers that can be
> >>>>> used by the drivers to make the common code reflect their current
> >>>>> behavior.
> >>>>>
> >>>>> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> >>>>> ---
> >>>>>
> >>>>> This update causes acpi_bus_device_eject() to only emit KOBJ_OFFLINE uevent if
> >>>>> autoexec is unset for the given scan handler.
> >>>>>
> >>>>> This will require the doc in patch [5/7] to be updated which I'm going to do if
> >>>>> everyone is OK with the $subject patch.
> >>>>>
> >>>>> Thanks,
> >>>>> Rafael
> >>>>    :
> >>>>> +
> >>>>> +static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
> >>>>> +{
> >>>>> +	struct acpi_device *device = NULL;
> >>>>> +	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
> >>>>> +	int error;
> >>>>> +
> >>>>> +	mutex_lock(&acpi_scan_lock);
> >>>>> +
> >>>>> +	acpi_bus_get_device(handle, &device);
> >>>>> +	if (device) {
> >>>>> +		dev_warn(&device->dev, "Attempt to re-insert\n");
> >>>>> +		goto out;
> >>>>> +	}
> >>>>> +	acpi_evaluate_hotplug_ost(handle, ost_source,
> >>>>> +				  ACPI_OST_SC_INSERT_IN_PROGRESS, NULL);
> >>>>> +	error = acpi_bus_scan(handle);
> >>>>> +	if (error) {
> >>>>> +		acpi_handle_warn(handle, "Namespace scan failure\n");
> >>>>> +		goto out;
> >>>>> +	}
> >>>>> +	error = acpi_bus_get_device(handle, &device);
> >>>>> +	if (error) {
> >>>>> +		acpi_handle_warn(handle, "Missing device node object\n");
> >>>>> +		goto out;
> >>>>> +	}
> >>>>> +	ost_code = ACPI_OST_SC_SUCCESS;
> >>>>> +	if (device->handler && device->handler->hotplug.uevents)
> >>>>> +		kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
> >>>>
> >>
> >>>> I confirmed that the uevent crash issue was solved.  Thinking further, I
> >>>> wonder if we need to emit KOBJ_ONLINE here.  This behavior is asymmetric
> >>>> since we do not emit KOBJ_OFFLINE when autoeject is set.
> >>>
> >>> Well, I put that in there only to be able to make the container driver behave
> >>> in a backwards compatible way (which is to emit KOBJ_ONLINE at this point).
> >>>
> >>> If the container driver doesn't need to emit KOBJ_ONLINE at all, I agree with
> >>> your suggestion.
> >>>
> >>>> The definition of ONLINE/OFFLINE event to an ACPI device object seems also
> >>>> bogus since there is no online/offline operation to the ACPI device object
> >>>> itself.
> >>>> Online/offline operation is only possible to actual device, such as
> >>>> system/cpu/cpu% and system/memory/memory%.
> >>>
> >>> That's correct, but I don't know what the user space expectations are
> >>> currently.
> >>
> >> My system expects this event to be notified when hot adding container device.
> >> My container device has cpu and memory. As Toshi said, these devices are
> >> offline when hot adding container device. So in my system, when notifying
> >> container device's KOBJ_ONLINE event, my application runs for onlining these
> >> devices. If this event is not notified to user land, we cannot online these
> >> devices  automatically.
> >
> 
> > Thanks for the info.  Can your application listen KOBJ_ADD to a
> > container device, instead of KOBJ_ONLINE?  IOW, does it distinguish
> > between ADD and ONLINE events to a container device?
> 
> My application does not distinguish between ADD and ONLINE events
> currently. But if the event is changed from ONLINE to ADD, I will
> change my application.

KOBJ_ADD is emitted for every struct acpi_device being registered, including
container devices, by acpi_device_add_finalize().  Can your application listen
to those events?

Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Update 4][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-26  3:11                     ` Rafael J. Wysocki
@ 2013-02-26  3:40                       ` Yasuaki Ishimatsu
  2013-02-26  3:50                         ` Rafael J. Wysocki
  0 siblings, 1 reply; 69+ messages in thread
From: Yasuaki Ishimatsu @ 2013-02-26  3:40 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Toshi Kani, ACPI Devel Maling List, Bjorn Helgaas, LKML,
	Yinghai Lu, Jiang Liu

2013/02/26 12:11, Rafael J. Wysocki wrote:
> On Tuesday, February 26, 2013 11:02:56 AM Yasuaki Ishimatsu wrote:
>> 2013/02/26 10:09, Toshi Kani wrote:
>>> On Tue, 2013-02-26 at 09:40 +0900, Yasuaki Ishimatsu wrote:
>>>> 2013/02/26 8:39, Rafael J. Wysocki wrote:
>>>>> On Monday, February 25, 2013 11:07:52 AM Toshi Kani wrote:
>>>>>> On Sat, 2013-02-23 at 22:38 +0000, Rafael J. Wysocki wrote:
>>>>>>> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>>>>>>>
>>>>>>> Multiple drivers handling hotplug-capable ACPI device nodes install
>>>>>>> notify handlers covering the same types of events in a very similar
>>>>>>> way.  Moreover, those handlers are installed in separate namespace
>>>>>>> walks, although that really should be done during namespace scans
>>>>>>> carried out by acpi_bus_scan().  This leads to substantial code
>>>>>>> duplication, unnecessary overhead and behavior that is hard to
>>>>>>> follow.
>>>>>>>
>>>>>>> For this reason, introduce common code in drivers/acpi/scan.c for
>>>>>>> handling hotplug-related notification and carrying out device
>>>>>>> insertion and eject operations in a generic fashion, such that it
>>>>>>> may be used by all of the relevant drivers in the future.  To cover
>>>>>>> the existing differences between those drivers introduce struct
>>>>>>> acpi_hotplug_profile for representing collections of hotplug
>>>>>>> settings associated with different ACPI scan handlers that can be
>>>>>>> used by the drivers to make the common code reflect their current
>>>>>>> behavior.
>>>>>>>
>>>>>>> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>>>>>>> ---
>>>>>>>
>>>>>>> This update causes acpi_bus_device_eject() to only emit KOBJ_OFFLINE uevent if
>>>>>>> autoexec is unset for the given scan handler.
>>>>>>>
>>>>>>> This will require the doc in patch [5/7] to be updated which I'm going to do if
>>>>>>> everyone is OK with the $subject patch.
>>>>>>>
>>>>>>> Thanks,
>>>>>>> Rafael
>>>>>>     :
>>>>>>> +
>>>>>>> +static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
>>>>>>> +{
>>>>>>> +	struct acpi_device *device = NULL;
>>>>>>> +	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
>>>>>>> +	int error;
>>>>>>> +
>>>>>>> +	mutex_lock(&acpi_scan_lock);
>>>>>>> +
>>>>>>> +	acpi_bus_get_device(handle, &device);
>>>>>>> +	if (device) {
>>>>>>> +		dev_warn(&device->dev, "Attempt to re-insert\n");
>>>>>>> +		goto out;
>>>>>>> +	}
>>>>>>> +	acpi_evaluate_hotplug_ost(handle, ost_source,
>>>>>>> +				  ACPI_OST_SC_INSERT_IN_PROGRESS, NULL);
>>>>>>> +	error = acpi_bus_scan(handle);
>>>>>>> +	if (error) {
>>>>>>> +		acpi_handle_warn(handle, "Namespace scan failure\n");
>>>>>>> +		goto out;
>>>>>>> +	}
>>>>>>> +	error = acpi_bus_get_device(handle, &device);
>>>>>>> +	if (error) {
>>>>>>> +		acpi_handle_warn(handle, "Missing device node object\n");
>>>>>>> +		goto out;
>>>>>>> +	}
>>>>>>> +	ost_code = ACPI_OST_SC_SUCCESS;
>>>>>>> +	if (device->handler && device->handler->hotplug.uevents)
>>>>>>> +		kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
>>>>>>
>>>>
>>>>>> I confirmed that the uevent crash issue was solved.  Thinking further, I
>>>>>> wonder if we need to emit KOBJ_ONLINE here.  This behavior is asymmetric
>>>>>> since we do not emit KOBJ_OFFLINE when autoeject is set.
>>>>>
>>>>> Well, I put that in there only to be able to make the container driver behave
>>>>> in a backwards compatible way (which is to emit KOBJ_ONLINE at this point).
>>>>>
>>>>> If the container driver doesn't need to emit KOBJ_ONLINE at all, I agree with
>>>>> your suggestion.
>>>>>
>>>>>> The definition of ONLINE/OFFLINE event to an ACPI device object seems also
>>>>>> bogus since there is no online/offline operation to the ACPI device object
>>>>>> itself.
>>>>>> Online/offline operation is only possible to actual device, such as
>>>>>> system/cpu/cpu% and system/memory/memory%.
>>>>>
>>>>> That's correct, but I don't know what the user space expectations are
>>>>> currently.
>>>>
>>>> My system expects this event to be notified when hot adding container device.
>>>> My container device has cpu and memory. As Toshi said, these devices are
>>>> offline when hot adding container device. So in my system, when notifying
>>>> container device's KOBJ_ONLINE event, my application runs for onlining these
>>>> devices. If this event is not notified to user land, we cannot online these
>>>> devices  automatically.
>>>
>>
>>> Thanks for the info.  Can your application listen KOBJ_ADD to a
>>> container device, instead of KOBJ_ONLINE?  IOW, does it distinguish
>>> between ADD and ONLINE events to a container device?
>>
>> My application does not distinguish between ADD and ONLINE events
>> currently. But if the event is changed from ONLINE to ADD, I will
>> change my application.
>
> KOBJ_ADD is emitted for every struct acpi_device being registered, including
> container devices, by acpi_device_add_finalize().  Can your application listen
> to those events?

Ah O.K. I understood. Even if the ONLINE event disappers, my application can get
ADD event from acpi_device_add_finalize(). Of course, I need to change my
application.
If the ADD event of container device is notified after hot adding devices which
are contained into container device, there is no reason to leave ONLINE event.

Thanks,
Yasuaki Ishimatsu

>
> Rafael
>
>



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Update 4][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-26  3:40                       ` Yasuaki Ishimatsu
@ 2013-02-26  3:50                         ` Rafael J. Wysocki
  0 siblings, 0 replies; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-26  3:50 UTC (permalink / raw)
  To: Yasuaki Ishimatsu
  Cc: Toshi Kani, ACPI Devel Maling List, Bjorn Helgaas, LKML,
	Yinghai Lu, Jiang Liu

On Tuesday, February 26, 2013 12:40:22 PM Yasuaki Ishimatsu wrote:
> 2013/02/26 12:11, Rafael J. Wysocki wrote:
> > On Tuesday, February 26, 2013 11:02:56 AM Yasuaki Ishimatsu wrote:
> >> 2013/02/26 10:09, Toshi Kani wrote:
> >>> On Tue, 2013-02-26 at 09:40 +0900, Yasuaki Ishimatsu wrote:
> >>>> 2013/02/26 8:39, Rafael J. Wysocki wrote:
> >>>>> On Monday, February 25, 2013 11:07:52 AM Toshi Kani wrote:
> >>>>>> On Sat, 2013-02-23 at 22:38 +0000, Rafael J. Wysocki wrote:
> >>>>>>> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> >>>>>>>
> >>>>>>> Multiple drivers handling hotplug-capable ACPI device nodes install
> >>>>>>> notify handlers covering the same types of events in a very similar
> >>>>>>> way.  Moreover, those handlers are installed in separate namespace
> >>>>>>> walks, although that really should be done during namespace scans
> >>>>>>> carried out by acpi_bus_scan().  This leads to substantial code
> >>>>>>> duplication, unnecessary overhead and behavior that is hard to
> >>>>>>> follow.
> >>>>>>>
> >>>>>>> For this reason, introduce common code in drivers/acpi/scan.c for
> >>>>>>> handling hotplug-related notification and carrying out device
> >>>>>>> insertion and eject operations in a generic fashion, such that it
> >>>>>>> may be used by all of the relevant drivers in the future.  To cover
> >>>>>>> the existing differences between those drivers introduce struct
> >>>>>>> acpi_hotplug_profile for representing collections of hotplug
> >>>>>>> settings associated with different ACPI scan handlers that can be
> >>>>>>> used by the drivers to make the common code reflect their current
> >>>>>>> behavior.
> >>>>>>>
> >>>>>>> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> >>>>>>> ---
> >>>>>>>
> >>>>>>> This update causes acpi_bus_device_eject() to only emit KOBJ_OFFLINE uevent if
> >>>>>>> autoexec is unset for the given scan handler.
> >>>>>>>
> >>>>>>> This will require the doc in patch [5/7] to be updated which I'm going to do if
> >>>>>>> everyone is OK with the $subject patch.
> >>>>>>>
> >>>>>>> Thanks,
> >>>>>>> Rafael
> >>>>>>     :
> >>>>>>> +
> >>>>>>> +static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
> >>>>>>> +{
> >>>>>>> +	struct acpi_device *device = NULL;
> >>>>>>> +	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
> >>>>>>> +	int error;
> >>>>>>> +
> >>>>>>> +	mutex_lock(&acpi_scan_lock);
> >>>>>>> +
> >>>>>>> +	acpi_bus_get_device(handle, &device);
> >>>>>>> +	if (device) {
> >>>>>>> +		dev_warn(&device->dev, "Attempt to re-insert\n");
> >>>>>>> +		goto out;
> >>>>>>> +	}
> >>>>>>> +	acpi_evaluate_hotplug_ost(handle, ost_source,
> >>>>>>> +				  ACPI_OST_SC_INSERT_IN_PROGRESS, NULL);
> >>>>>>> +	error = acpi_bus_scan(handle);
> >>>>>>> +	if (error) {
> >>>>>>> +		acpi_handle_warn(handle, "Namespace scan failure\n");
> >>>>>>> +		goto out;
> >>>>>>> +	}
> >>>>>>> +	error = acpi_bus_get_device(handle, &device);
> >>>>>>> +	if (error) {
> >>>>>>> +		acpi_handle_warn(handle, "Missing device node object\n");
> >>>>>>> +		goto out;
> >>>>>>> +	}
> >>>>>>> +	ost_code = ACPI_OST_SC_SUCCESS;
> >>>>>>> +	if (device->handler && device->handler->hotplug.uevents)
> >>>>>>> +		kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
> >>>>>>
> >>>>
> >>>>>> I confirmed that the uevent crash issue was solved.  Thinking further, I
> >>>>>> wonder if we need to emit KOBJ_ONLINE here.  This behavior is asymmetric
> >>>>>> since we do not emit KOBJ_OFFLINE when autoeject is set.
> >>>>>
> >>>>> Well, I put that in there only to be able to make the container driver behave
> >>>>> in a backwards compatible way (which is to emit KOBJ_ONLINE at this point).
> >>>>>
> >>>>> If the container driver doesn't need to emit KOBJ_ONLINE at all, I agree with
> >>>>> your suggestion.
> >>>>>
> >>>>>> The definition of ONLINE/OFFLINE event to an ACPI device object seems also
> >>>>>> bogus since there is no online/offline operation to the ACPI device object
> >>>>>> itself.
> >>>>>> Online/offline operation is only possible to actual device, such as
> >>>>>> system/cpu/cpu% and system/memory/memory%.
> >>>>>
> >>>>> That's correct, but I don't know what the user space expectations are
> >>>>> currently.
> >>>>
> >>>> My system expects this event to be notified when hot adding container device.
> >>>> My container device has cpu and memory. As Toshi said, these devices are
> >>>> offline when hot adding container device. So in my system, when notifying
> >>>> container device's KOBJ_ONLINE event, my application runs for onlining these
> >>>> devices. If this event is not notified to user land, we cannot online these
> >>>> devices  automatically.
> >>>
> >>
> >>> Thanks for the info.  Can your application listen KOBJ_ADD to a
> >>> container device, instead of KOBJ_ONLINE?  IOW, does it distinguish
> >>> between ADD and ONLINE events to a container device?
> >>
> >> My application does not distinguish between ADD and ONLINE events
> >> currently. But if the event is changed from ONLINE to ADD, I will
> >> change my application.
> >
> > KOBJ_ADD is emitted for every struct acpi_device being registered, including
> > container devices, by acpi_device_add_finalize().  Can your application listen
> > to those events?
> 
> Ah O.K. I understood. Even if the ONLINE event disappers, my application can get
> ADD event from acpi_device_add_finalize(). Of course, I need to change my
> application.
> If the ADD event of container device is notified after hot adding devices which
> are contained into container device, there is no reason to leave ONLINE event.

If they are located below the container device in the namespace, then the
container's ADD will happen before they are added, so if the ONLINE event is
supposed to mean that all devices under the container have been added, we need
to keep it as is.

Thanks,
Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2, 0/7] ACPI / hotplug: Common code for ACPI-based hotplug
  2013-02-17 15:18 [PATCH 0/7] ACPI / hotplug: Common code for ACPI-based hotplug Rafael J. Wysocki
                   ` (6 preceding siblings ...)
  2013-02-17 15:27 ` [PATCH 7/7] ACPI / scan: Make memory hotplug driver use struct acpi_scan_handler Rafael J. Wysocki
@ 2013-02-26 22:41 ` Rafael J. Wysocki
  2013-02-26 22:44   ` [PATCH v2, 1/7] ACPI / scan: Introduce acpi_scan_match_handler() Rafael J. Wysocki
                     ` (7 more replies)
  7 siblings, 8 replies; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-26 22:41 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Yinghai Lu, Toshi Kani, Yasuaki Ishimatsu,
	Jiang Liu

On Sunday, February 17, 2013 04:18:31 PM Rafael J. Wysocki wrote:
> Hi All,
> 
> The following patches introduce common code for ACPI-based hotplug for non-PCI
> devices and modify the container and memory hotplug ACPI drivers to use the new
> code.
> 
> This is based on linux-pm.git/master and regarded as v3.10 material.
> 
> [1/7] Introduce acpi_scan_match_handler() that will be useful going forward.
> [2/7] Introduce common code for ACPI-base device hotplug.
> [3/7] Use the new commot hotplug code in the container driver.
> [4/7] Introduce acpi_scan_handler_matching() that will be useful subsequently.
> [5/7] Introduce user space interface for hotplug profiles.
> [6/7] Make the container driver use the hotplug profiles user space interface.
> [7/7] Make the memory hotplug driver use struct acpi_scan_handler along with
>       the hotplug profiles user space interface.

Following is the second iteration.  It takes all of the updates of patch [2/7]
and the discussion of them into account and fixes the issue with 'enabled'
working inversely in [5/7] spotted by Toshi Kani.

Thanks,
Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2, 1/7] ACPI / scan: Introduce acpi_scan_match_handler()
  2013-02-26 22:41 ` [PATCH v2, 0/7] ACPI / hotplug: Common code for ACPI-based hotplug Rafael J. Wysocki
@ 2013-02-26 22:44   ` Rafael J. Wysocki
  2013-02-26 22:46   ` [PATCH v2, 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug Rafael J. Wysocki
                     ` (6 subsequent siblings)
  7 siblings, 0 replies; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-26 22:44 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Yinghai Lu, Toshi Kani, Yasuaki Ishimatsu,
	Jiang Liu

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Introduce helper routine acpi_scan_match_handler() that will find the
ACPI scan handler matching a given device ID, if there is one, and
rework acpi_scan_attach_handler() to use the new routine (that
routine will also be useful for other purposes going forward).

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
---
 drivers/acpi/scan.c |   53 +++++++++++++++++++++++++++-------------------------
 1 file changed, 28 insertions(+), 25 deletions(-)

Index: test/drivers/acpi/scan.c
===================================================================
--- test.orig/drivers/acpi/scan.c
+++ test/drivers/acpi/scan.c
@@ -1536,6 +1536,25 @@ static int acpi_bus_type_and_status(acpi
 	return 0;
 }
 
+static struct acpi_scan_handler *acpi_scan_match_handler(char *idstr,
+					const struct acpi_device_id **matchid)
+{
+	struct acpi_scan_handler *handler;
+
+	list_for_each_entry(handler, &acpi_scan_handlers_list, list_node) {
+		const struct acpi_device_id *devid;
+
+		for (devid = handler->ids; devid->id[0]; devid++)
+			if (!strcmp((char *)devid->id, idstr)) {
+				if (matchid)
+					*matchid = devid;
+
+				return handler;
+			}
+	}
+	return NULL;
+}
+
 static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
 				      void *not_used, void **return_value)
 {
@@ -1583,42 +1602,26 @@ static acpi_status acpi_bus_check_add(ac
 	return AE_OK;
 }
 
-static int acpi_scan_do_attach_handler(struct acpi_device *device, char *id)
+static int acpi_scan_attach_handler(struct acpi_device *device)
 {
-	struct acpi_scan_handler *handler;
+	struct acpi_hardware_id *hwid;
+	int ret = 0;
 
-	list_for_each_entry(handler, &acpi_scan_handlers_list, list_node) {
+	list_for_each_entry(hwid, &device->pnp.ids, list) {
 		const struct acpi_device_id *devid;
+		struct acpi_scan_handler *handler;
 
-		for (devid = handler->ids; devid->id[0]; devid++) {
-			int ret;
-
-			if (strcmp((char *)devid->id, id))
-				continue;
-
+		handler = acpi_scan_match_handler(hwid->id, &devid);
+		if (handler) {
 			ret = handler->attach(device, devid);
 			if (ret > 0) {
 				device->handler = handler;
-				return ret;
+				break;
 			} else if (ret < 0) {
-				return ret;
+				break;
 			}
 		}
 	}
-	return 0;
-}
-
-static int acpi_scan_attach_handler(struct acpi_device *device)
-{
-	struct acpi_hardware_id *hwid;
-	int ret = 0;
-
-	list_for_each_entry(hwid, &device->pnp.ids, list) {
-		ret = acpi_scan_do_attach_handler(device, hwid->id);
-		if (ret)
-			break;
-
-	}
 	return ret;
 }
 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2, 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-26 22:41 ` [PATCH v2, 0/7] ACPI / hotplug: Common code for ACPI-based hotplug Rafael J. Wysocki
  2013-02-26 22:44   ` [PATCH v2, 1/7] ACPI / scan: Introduce acpi_scan_match_handler() Rafael J. Wysocki
@ 2013-02-26 22:46   ` Rafael J. Wysocki
  2013-02-26 22:46   ` [PATCH v2, 3/7] ACPI / container: Use common hotplug code Rafael J. Wysocki
                     ` (5 subsequent siblings)
  7 siblings, 0 replies; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-26 22:46 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Yinghai Lu, Toshi Kani, Yasuaki Ishimatsu,
	Jiang Liu

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Multiple drivers handling hotplug-capable ACPI device nodes install
notify handlers covering the same types of events in a very similar
way.  Moreover, those handlers are installed in separate namespace
walks, although that really should be done during namespace scans
carried out by acpi_bus_scan().  This leads to substantial code
duplication, unnecessary overhead and behavior that is hard to
follow.

For this reason, introduce common code in drivers/acpi/scan.c for
handling hotplug-related notification and carrying out device
insertion and eject operations in a generic fashion, such that it
may be used by all of the relevant drivers in the future.  To cover
the existing differences between those drivers introduce struct
acpi_hotplug_profile for representing collections of hotplug
settings associated with different ACPI scan handlers that can be
used by the drivers to make the common code reflect their current
behavior.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/acpi/scan.c     |  269 ++++++++++++++++++++++++++++++++++++++----------
 include/acpi/acpi_bus.h |   12 ++
 2 files changed, 228 insertions(+), 53 deletions(-)

Index: test/include/acpi/acpi_bus.h
===================================================================
--- test.orig/include/acpi/acpi_bus.h
+++ test/include/acpi/acpi_bus.h
@@ -88,11 +88,23 @@ struct acpi_device;
  * -----------------
  */
 
+enum acpi_hotplug_mode {
+	AHM_GENERIC = 0,
+	AHM_CONTAINER,
+	AHM_COUNT
+};
+
+struct acpi_hotplug_profile {
+	bool enabled:1;
+	enum acpi_hotplug_mode mode;
+};
+
 struct acpi_scan_handler {
 	const struct acpi_device_id *ids;
 	struct list_head list_node;
 	int (*attach)(struct acpi_device *dev, const struct acpi_device_id *id);
 	void (*detach)(struct acpi_device *dev);
+	struct acpi_hotplug_profile hotplug;
 };
 
 /*
Index: test/drivers/acpi/scan.c
===================================================================
--- test.orig/drivers/acpi/scan.c
+++ test/drivers/acpi/scan.c
@@ -107,32 +107,19 @@ acpi_device_modalias_show(struct device
 }
 static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
 
-/**
- * acpi_bus_hot_remove_device: hot-remove a device and its children
- * @context: struct acpi_eject_event pointer (freed in this func)
- *
- * Hot-remove a device and its children. This function frees up the
- * memory space passed by arg context, so that the caller may call
- * this function asynchronously through acpi_os_hotplug_execute().
- */
-void acpi_bus_hot_remove_device(void *context)
+static int acpi_scan_hot_remove(struct acpi_device *device)
 {
-	struct acpi_eject_event *ej_event = context;
-	struct acpi_device *device = ej_event->device;
 	acpi_handle handle = device->handle;
-	acpi_handle temp;
+	acpi_handle not_used;
 	struct acpi_object_list arg_list;
 	union acpi_object arg;
-	acpi_status status = AE_OK;
-	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
-
-	mutex_lock(&acpi_scan_lock);
+	acpi_status status;
 
 	/* If there is no handle, the device node has been unregistered. */
-	if (!device->handle) {
+	if (!handle) {
 		dev_dbg(&device->dev, "ACPI handle missing\n");
 		put_device(&device->dev);
-		goto out;
+		return -EINVAL;
 	}
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -143,7 +130,7 @@ void acpi_bus_hot_remove_device(void *co
 	put_device(&device->dev);
 	device = NULL;
 
-	if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &temp))) {
+	if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &not_used))) {
 		arg_list.count = 1;
 		arg_list.pointer = &arg;
 		arg.type = ACPI_TYPE_INTEGER;
@@ -161,18 +148,158 @@ void acpi_bus_hot_remove_device(void *co
 	 */
 	status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
 	if (ACPI_FAILURE(status)) {
-		if (status != AE_NOT_FOUND)
+		if (status == AE_NOT_FOUND) {
+			return -ENODEV;
+		} else {
 			acpi_handle_warn(handle, "Eject failed\n");
+			return -EIO;
+		}
+	}
+	return 0;
+}
 
-		/* Tell the firmware the hot-remove operation has failed. */
-		acpi_evaluate_hotplug_ost(handle, ej_event->event,
-					  ost_code, NULL);
+static void acpi_bus_device_eject(void *context)
+{
+	acpi_handle handle = context;
+	struct acpi_device *device = NULL;
+	struct acpi_scan_handler *handler;
+	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
+
+	mutex_lock(&acpi_scan_lock);
+
+	acpi_bus_get_device(handle, &device);
+	if (!device)
+		goto err_out;
+
+	handler = device->handler;
+	if (!handler || !handler->hotplug.enabled) {
+		ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
+		goto err_out;
+	}
+	acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
+				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+	if (handler->hotplug.mode == AHM_CONTAINER) {
+		device->flags.eject_pending = true;
+		kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
+	} else {
+		int error;
+
+		get_device(&device->dev);
+		error = acpi_scan_hot_remove(device);
+		if (error)
+			goto err_out;
 	}
 
  out:
 	mutex_unlock(&acpi_scan_lock);
-	kfree(context);
 	return;
+
+ err_out:
+	acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, ost_code,
+				  NULL);
+	goto out;
+}
+
+static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
+{
+	struct acpi_device *device = NULL;
+	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
+	int error;
+
+	mutex_lock(&acpi_scan_lock);
+
+	acpi_bus_get_device(handle, &device);
+	if (device) {
+		dev_warn(&device->dev, "Attempt to re-insert\n");
+		goto out;
+	}
+	acpi_evaluate_hotplug_ost(handle, ost_source,
+				  ACPI_OST_SC_INSERT_IN_PROGRESS, NULL);
+	error = acpi_bus_scan(handle);
+	if (error) {
+		acpi_handle_warn(handle, "Namespace scan failure\n");
+		goto out;
+	}
+	error = acpi_bus_get_device(handle, &device);
+	if (error) {
+		acpi_handle_warn(handle, "Missing device node object\n");
+		goto out;
+	}
+	ost_code = ACPI_OST_SC_SUCCESS;
+	if (device->handler && device->handler->hotplug.mode == AHM_CONTAINER)
+		kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
+
+ out:
+	acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL);
+	mutex_unlock(&acpi_scan_lock);
+}
+
+static void acpi_scan_bus_check(void *context)
+{
+	acpi_scan_bus_device_check((acpi_handle)context,
+				   ACPI_NOTIFY_BUS_CHECK);
+}
+
+static void acpi_scan_device_check(void *context)
+{
+	acpi_scan_bus_device_check((acpi_handle)context,
+				   ACPI_NOTIFY_DEVICE_CHECK);
+}
+
+static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *not_used)
+{
+	acpi_osd_exec_callback callback;
+	acpi_status status;
+
+	switch (type) {
+	case ACPI_NOTIFY_BUS_CHECK:
+		acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
+		callback = acpi_scan_bus_check;
+		break;
+	case ACPI_NOTIFY_DEVICE_CHECK:
+		acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
+		callback = acpi_scan_device_check;
+		break;
+	case ACPI_NOTIFY_EJECT_REQUEST:
+		acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
+		callback = acpi_bus_device_eject;
+		break;
+	default:
+		/* non-hotplug event; possibly handled by other handler */
+		return;
+	}
+	status = acpi_os_hotplug_execute(callback, handle);
+	if (ACPI_FAILURE(status))
+		acpi_evaluate_hotplug_ost(handle, type,
+					  ACPI_OST_SC_NON_SPECIFIC_FAILURE,
+					  NULL);
+}
+
+/**
+ * acpi_bus_hot_remove_device: hot-remove a device and its children
+ * @context: struct acpi_eject_event pointer (freed in this func)
+ *
+ * Hot-remove a device and its children. This function frees up the
+ * memory space passed by arg context, so that the caller may call
+ * this function asynchronously through acpi_os_hotplug_execute().
+ */
+void acpi_bus_hot_remove_device(void *context)
+{
+	struct acpi_eject_event *ej_event = context;
+	struct acpi_device *device = ej_event->device;
+	acpi_handle handle = device->handle;
+	int error;
+
+	mutex_lock(&acpi_scan_lock);
+
+	error = acpi_scan_hot_remove(device);
+	if (error && handle)
+		acpi_evaluate_hotplug_ost(handle, ej_event->event,
+					  ACPI_OST_SC_NON_SPECIFIC_FAILURE,
+					  NULL);
+
+	mutex_unlock(&acpi_scan_lock);
+	kfree(context);
 }
 EXPORT_SYMBOL(acpi_bus_hot_remove_device);
 
@@ -206,51 +333,61 @@ static ssize_t
 acpi_eject_store(struct device *d, struct device_attribute *attr,
 		const char *buf, size_t count)
 {
-	int ret = count;
-	acpi_status status;
-	acpi_object_type type = 0;
 	struct acpi_device *acpi_device = to_acpi_device(d);
 	struct acpi_eject_event *ej_event;
+	acpi_object_type not_used;
+	acpi_status status;
+	u32 ost_source;
+	int ret;
 
-	if ((!count) || (buf[0] != '1')) {
+	if (!count || buf[0] != '1')
 		return -EINVAL;
-	}
-	if (!acpi_device->driver && !acpi_device->handler) {
-		ret = -ENODEV;
-		goto err;
-	}
-	status = acpi_get_type(acpi_device->handle, &type);
-	if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) {
-		ret = -ENODEV;
-		goto err;
-	}
 
-	ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
-	if (!ej_event) {
-		ret = -ENOMEM;
-		goto err;
-	}
+	if ((!acpi_device->handler || !acpi_device->handler->hotplug.enabled)
+	    && !acpi_device->driver)
+		return -ENODEV;
+
+	status = acpi_get_type(acpi_device->handle, &not_used);
+	if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable)
+		return -ENODEV;
+
+	mutex_lock(&acpi_scan_lock);
 
-	get_device(&acpi_device->dev);
-	ej_event->device = acpi_device;
 	if (acpi_device->flags.eject_pending) {
-		/* event originated from ACPI eject notification */
-		ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
+		/* ACPI eject notification event. */
+		ost_source = ACPI_NOTIFY_EJECT_REQUEST;
 		acpi_device->flags.eject_pending = 0;
 	} else {
-		/* event originated from user */
-		ej_event->event = ACPI_OST_EC_OSPM_EJECT;
-		(void) acpi_evaluate_hotplug_ost(acpi_device->handle,
-			ej_event->event, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+		/* Eject initiated by user space. */
+		ost_source = ACPI_OST_EC_OSPM_EJECT;
 	}
-
+	ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
+	if (!ej_event) {
+		ret = -ENOMEM;
+		goto err_out;
+	}
+	acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source,
+				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+	ej_event->device = acpi_device;
+	ej_event->event = ost_source;
+	get_device(&acpi_device->dev);
 	status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event);
 	if (ACPI_FAILURE(status)) {
 		put_device(&acpi_device->dev);
 		kfree(ej_event);
+		ret = status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN;
+		goto err_out;
 	}
-err:
+	ret = count;
+
+ out:
+	mutex_unlock(&acpi_scan_lock);
 	return ret;
+
+ err_out:
+	acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source,
+				  ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
+	goto out;
 }
 
 static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
@@ -1555,6 +1692,30 @@ static struct acpi_scan_handler *acpi_sc
 	return NULL;
 }
 
+static void acpi_scan_init_hotplug(acpi_handle handle)
+{
+	struct acpi_device_info *info;
+	struct acpi_scan_handler *handler;
+
+	if (ACPI_FAILURE(acpi_get_object_info(handle, &info)))
+		return;
+
+	if (!(info->valid & ACPI_VALID_HID)) {
+		kfree(info);
+		return;
+	}
+
+	/*
+	 * This relies on the fact that acpi_install_notify_handler() will not
+	 * install the same notify handler routine twice for the same handle.
+	 */
+	handler = acpi_scan_match_handler(info->hardware_id.string, NULL);
+	kfree(info);
+	if (handler && handler->hotplug.enabled)
+		acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+					    acpi_hotplug_notify_cb, NULL);
+}
+
 static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
 				      void *not_used, void **return_value)
 {
@@ -1577,6 +1738,8 @@ static acpi_status acpi_bus_check_add(ac
 		return AE_OK;
 	}
 
+	acpi_scan_init_hotplug(handle);
+
 	if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
 	    !(sta & ACPI_STA_DEVICE_FUNCTIONING)) {
 		struct acpi_device_wakeup wakeup;

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2, 3/7] ACPI / container: Use common hotplug code
  2013-02-26 22:41 ` [PATCH v2, 0/7] ACPI / hotplug: Common code for ACPI-based hotplug Rafael J. Wysocki
  2013-02-26 22:44   ` [PATCH v2, 1/7] ACPI / scan: Introduce acpi_scan_match_handler() Rafael J. Wysocki
  2013-02-26 22:46   ` [PATCH v2, 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug Rafael J. Wysocki
@ 2013-02-26 22:46   ` Rafael J. Wysocki
  2013-02-26 23:13       ` Toshi Kani
  2013-02-27  0:09     ` [Update][PATCH " Rafael J. Wysocki
  2013-02-26 22:47   ` [PATCH v2, 4/7] ACPI / scan: Introduce acpi_scan_handler_matching() Rafael J. Wysocki
                     ` (4 subsequent siblings)
  7 siblings, 2 replies; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-26 22:46 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Yinghai Lu, Toshi Kani, Yasuaki Ishimatsu,
	Jiang Liu

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Switch the ACPI container driver to using common device hotplug code
introduced previously.  This reduces the driver down to a trivial
definition and registration of a struct acpi_scan_handler object.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/acpi/container.c |  146 +++--------------------------------------------
 1 file changed, 10 insertions(+), 136 deletions(-)

Index: test/drivers/acpi/container.c
===================================================================
--- test.orig/drivers/acpi/container.c
+++ test/drivers/acpi/container.c
@@ -1,12 +1,12 @@
 /*
- * acpi_container.c  - ACPI Generic Container Driver
- * ($Revision: )
+ * container.c  - ACPI Generic Container Driver
  *
  * Copyright (C) 2004 Anil S Keshavamurthy (anil.s.keshavamurthy@intel.com)
  * Copyright (C) 2004 Keiichiro Tokunaga (tokunaga.keiich@jp.fujitsu.com)
  * Copyright (C) 2004 Motoyuki Ito (motoyuki@soft.fujitsu.com)
- * Copyright (C) 2004 Intel Corp.
  * Copyright (C) 2004 FUJITSU LIMITED
+ * Copyright (C) 2004, 2013 Intel Corp.
+ * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  *
@@ -26,14 +26,9 @@
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/types.h>
 #include <linux/acpi.h>
-#include <acpi/acpi_bus.h>
-#include <acpi/acpi_drivers.h>
+
+#include "internal.h"
 
 #define PREFIX "ACPI: "
 
@@ -50,141 +45,20 @@ static const struct acpi_device_id conta
 static int container_device_attach(struct acpi_device *device,
 				   const struct acpi_device_id *not_used)
 {
-	/*
-	 * FIXME: This is necessary, so that acpi_eject_store() doesn't return
-	 * -ENODEV for containers.
-	 */
+	/* This is necessary for container hotplug to work. */
 	return 1;
 }
 
 static struct acpi_scan_handler container_device_handler = {
 	.ids = container_device_ids,
 	.attach = container_device_attach,
+	.hotplug = {
+		.enabled = true,
+		.user_eject = true,
+	},
 };
 
-static int is_device_present(acpi_handle handle)
-{
-	acpi_handle temp;
-	acpi_status status;
-	unsigned long long sta;
-
-
-	status = acpi_get_handle(handle, "_STA", &temp);
-	if (ACPI_FAILURE(status))
-		return 1;	/* _STA not found, assume device present */
-
-	status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
-	if (ACPI_FAILURE(status))
-		return 0;	/* Firmware error */
-
-	return ((sta & ACPI_STA_DEVICE_PRESENT) == ACPI_STA_DEVICE_PRESENT);
-}
-
-static void container_notify_cb(acpi_handle handle, u32 type, void *context)
-{
-	struct acpi_device *device = NULL;
-	int result;
-	int present;
-	acpi_status status;
-	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
-
-	acpi_scan_lock_acquire();
-
-	switch (type) {
-	case ACPI_NOTIFY_BUS_CHECK:
-		/* Fall through */
-	case ACPI_NOTIFY_DEVICE_CHECK:
-		pr_debug("Container driver received %s event\n",
-		       (type == ACPI_NOTIFY_BUS_CHECK) ?
-		       "ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK");
-
-		present = is_device_present(handle);
-		status = acpi_bus_get_device(handle, &device);
-		if (!present) {
-			if (ACPI_SUCCESS(status)) {
-				/* device exist and this is a remove request */
-				device->flags.eject_pending = 1;
-				kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
-				goto out;
-			}
-			break;
-		}
-
-		if (!ACPI_FAILURE(status) || device)
-			break;
-
-		result = acpi_bus_scan(handle);
-		if (result) {
-			acpi_handle_warn(handle, "Failed to add container\n");
-			break;
-		}
-		result = acpi_bus_get_device(handle, &device);
-		if (result) {
-			acpi_handle_warn(handle, "Missing device object\n");
-			break;
-		}
-
-		kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
-		ost_code = ACPI_OST_SC_SUCCESS;
-		break;
-
-	case ACPI_NOTIFY_EJECT_REQUEST:
-		if (!acpi_bus_get_device(handle, &device) && device) {
-			device->flags.eject_pending = 1;
-			kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
-			goto out;
-		}
-		break;
-
-	default:
-		/* non-hotplug event; possibly handled by other handler */
-		goto out;
-	}
-
-	/* Inform firmware that the hotplug operation has completed */
-	(void) acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
-
- out:
-	acpi_scan_lock_release();
-}
-
-static bool is_container(acpi_handle handle)
-{
-	struct acpi_device_info *info;
-	bool ret = false;
-
-	if (ACPI_FAILURE(acpi_get_object_info(handle, &info)))
-		return false;
-
-	if (info->valid & ACPI_VALID_HID) {
-		const struct acpi_device_id *id;
-
-		for (id = container_device_ids; id->id[0]; id++) {
-			ret = !strcmp((char *)id->id, info->hardware_id.string);
-			if (ret)
-				break;
-		}
-	}
-	kfree(info);
-	return ret;
-}
-
-static acpi_status acpi_container_register_notify_handler(acpi_handle handle,
-							  u32 lvl, void *ctxt,
-							  void **retv)
-{
-	if (is_container(handle))
-		acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
-					    container_notify_cb, NULL);
-
-	return AE_OK;
-}
-
 void __init acpi_container_init(void)
 {
-	acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
-			    acpi_container_register_notify_handler, NULL,
-			    NULL, NULL);
-
 	acpi_scan_add_handler(&container_device_handler);
 }

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2, 4/7] ACPI / scan: Introduce acpi_scan_handler_matching()
  2013-02-26 22:41 ` [PATCH v2, 0/7] ACPI / hotplug: Common code for ACPI-based hotplug Rafael J. Wysocki
                     ` (2 preceding siblings ...)
  2013-02-26 22:46   ` [PATCH v2, 3/7] ACPI / container: Use common hotplug code Rafael J. Wysocki
@ 2013-02-26 22:47   ` Rafael J. Wysocki
  2013-02-26 22:48   ` [PATCH v2, 5/7] ACPI / hotplug: Introduce user space interface for hotplug profiles Rafael J. Wysocki
                     ` (3 subsequent siblings)
  7 siblings, 0 replies; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-26 22:47 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Yinghai Lu, Toshi Kani, Yasuaki Ishimatsu,
	Jiang Liu

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Introduce new helper routine acpi_scan_handler_matching() for
checking if the given ACPI scan handler matches a given device ID
and rework acpi_scan_match_handler() to use the new routine (that
routine will also be useful for other purposes in the future).

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
---
 drivers/acpi/scan.c |   30 ++++++++++++++++++++----------
 1 file changed, 20 insertions(+), 10 deletions(-)

Index: test/drivers/acpi/scan.c
===================================================================
--- test.orig/drivers/acpi/scan.c
+++ test/drivers/acpi/scan.c
@@ -1673,22 +1673,32 @@ static int acpi_bus_type_and_status(acpi
 	return 0;
 }
 
+static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler,
+				       char *idstr,
+				       const struct acpi_device_id **matchid)
+{
+	const struct acpi_device_id *devid;
+
+	for (devid = handler->ids; devid->id[0]; devid++)
+		if (!strcmp((char *)devid->id, idstr)) {
+			if (matchid)
+				*matchid = devid;
+
+			return true;
+		}
+
+	return false;
+}
+
 static struct acpi_scan_handler *acpi_scan_match_handler(char *idstr,
 					const struct acpi_device_id **matchid)
 {
 	struct acpi_scan_handler *handler;
 
-	list_for_each_entry(handler, &acpi_scan_handlers_list, list_node) {
-		const struct acpi_device_id *devid;
+	list_for_each_entry(handler, &acpi_scan_handlers_list, list_node)
+		if (acpi_scan_handler_matching(handler, idstr, matchid))
+			return handler;
 
-		for (devid = handler->ids; devid->id[0]; devid++)
-			if (!strcmp((char *)devid->id, idstr)) {
-				if (matchid)
-					*matchid = devid;
-
-				return handler;
-			}
-	}
 	return NULL;
 }
 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2, 5/7] ACPI / hotplug: Introduce user space interface for hotplug profiles
  2013-02-26 22:41 ` [PATCH v2, 0/7] ACPI / hotplug: Common code for ACPI-based hotplug Rafael J. Wysocki
                     ` (3 preceding siblings ...)
  2013-02-26 22:47   ` [PATCH v2, 4/7] ACPI / scan: Introduce acpi_scan_handler_matching() Rafael J. Wysocki
@ 2013-02-26 22:48   ` Rafael J. Wysocki
  2013-02-26 22:49   ` [PATCH v2, 6/7] ACPI / container: Use hotplug profile user space interface Rafael J. Wysocki
                     ` (2 subsequent siblings)
  7 siblings, 0 replies; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-26 22:48 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Yinghai Lu, Toshi Kani, Yasuaki Ishimatsu,
	Jiang Liu

From: Rafael J. Wysocki <rafael.j.wysocki@inel.com>

Introduce user space interface for manipulating hotplug profiles
associated with ACPI scan handlers.

The interface consists of sysfs directories under
/sys/firmware/acpi/hotplug/, one for each hotplug profile, containing
an attribute allowing user space to manipulate the enabled field of
the corresponding profile.  Namely, switching the enabled attribute
from '0' to '1' will cause the common hotplug notify handler to be
installed for all ACPI namespace objects representing devices matching
the scan handler associated with the given hotplug profile (and
analogously for the converse switch).

Drivers willing to use the new user space interface should add their
ACPI scan handlers with the help of new funtion
acpi_scan_add_handler_with_hotplug().

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@inel.com>
---
 Documentation/ABI/testing/sysfs-firmware-acpi |   26 ++++++++++
 drivers/acpi/internal.h                       |    6 ++
 drivers/acpi/scan.c                           |   59 +++++++++++++++++++++++
 drivers/acpi/sysfs.c                          |   66 ++++++++++++++++++++++++++
 include/acpi/acpi_bus.h                       |    7 ++
 5 files changed, 164 insertions(+)

Index: test/drivers/acpi/sysfs.c
===================================================================
--- test.orig/drivers/acpi/sysfs.c
+++ test/drivers/acpi/sysfs.c
@@ -7,6 +7,8 @@
 #include <linux/moduleparam.h>
 #include <acpi/acpi_drivers.h>
 
+#include "internal.h"
+
 #define _COMPONENT		ACPI_SYSTEM_COMPONENT
 ACPI_MODULE_NAME("sysfs");
 
@@ -249,6 +251,7 @@ module_param_call(acpica_version, NULL,
 static LIST_HEAD(acpi_table_attr_list);
 static struct kobject *tables_kobj;
 static struct kobject *dynamic_tables_kobj;
+static struct kobject *hotplug_kobj;
 
 struct acpi_table_attr {
 	struct bin_attribute attr;
@@ -716,6 +719,67 @@ acpi_show_profile(struct device *dev, st
 static const struct device_attribute pm_profile_attr =
 	__ATTR(pm_profile, S_IRUGO, acpi_show_profile, NULL);
 
+static ssize_t hotplug_enabled_show(struct kobject *kobj,
+				    struct kobj_attribute *attr, char *buf)
+{
+	struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj);
+
+	return sprintf(buf, "%d\n", hotplug->enabled);
+}
+
+static ssize_t hotplug_enabled_store(struct kobject *kobj,
+				     struct kobj_attribute *attr,
+				     const char *buf, size_t size)
+{
+	struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj);
+	unsigned int val;
+
+	if (kstrtouint(buf, 10, &val) || val > 1)
+		return -EINVAL;
+
+	acpi_scan_hotplug_enabled(hotplug, val);
+	return size;
+}
+
+static struct kobj_attribute hotplug_enabled_attr =
+	__ATTR(enabled, S_IRUGO | S_IWUSR, hotplug_enabled_show,
+		hotplug_enabled_store);
+
+static struct attribute *hotplug_profile_attrs[] = {
+	&hotplug_enabled_attr.attr,
+	NULL
+};
+
+struct kobj_type acpi_hotplug_profile_ktype = {
+	.sysfs_ops = &kobj_sysfs_ops,
+	.default_attrs = hotplug_profile_attrs,
+};
+
+void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug,
+				    const char *name)
+{
+	int error;
+
+	if (!hotplug_kobj)
+		goto err_out;
+
+	kobject_init(&hotplug->kobj, &acpi_hotplug_profile_ktype);
+	error = kobject_set_name(&hotplug->kobj, "%s", name);
+	if (error)
+		goto err_out;
+
+	hotplug->kobj.parent = hotplug_kobj;
+	error = kobject_add(&hotplug->kobj, hotplug_kobj, NULL);
+	if (error)
+		goto err_out;
+
+	kobject_uevent(&hotplug->kobj, KOBJ_ADD);
+	return;
+
+ err_out:
+	pr_err(PREFIX "Unable to add hotplug profile '%s'\n", name);
+}
+
 int __init acpi_sysfs_init(void)
 {
 	int result;
@@ -723,6 +787,8 @@ int __init acpi_sysfs_init(void)
 	result = acpi_tables_sysfs_init();
 	if (result)
 		return result;
+
+	hotplug_kobj = kobject_create_and_add("hotplug", acpi_kobj);
 	result = sysfs_create_file(acpi_kobj, &pm_profile_attr.attr);
 	return result;
 }
Index: test/include/acpi/acpi_bus.h
===================================================================
--- test.orig/include/acpi/acpi_bus.h
+++ test/include/acpi/acpi_bus.h
@@ -95,10 +95,17 @@ enum acpi_hotplug_mode {
 };
 
 struct acpi_hotplug_profile {
+	struct kobject kobj;
 	bool enabled:1;
 	enum acpi_hotplug_mode mode;
 };
 
+static inline struct acpi_hotplug_profile *to_acpi_hotplug_profile(
+						struct kobject *kobj)
+{
+	return container_of(kobj, struct acpi_hotplug_profile, kobj);
+}
+
 struct acpi_scan_handler {
 	const struct acpi_device_id *ids;
 	struct list_head list_node;
Index: test/drivers/acpi/internal.h
===================================================================
--- test.orig/drivers/acpi/internal.h
+++ test/drivers/acpi/internal.h
@@ -36,6 +36,12 @@ void acpi_container_init(void);
 static inline void acpi_container_init(void) {}
 #endif
 
+void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug,
+				    const char *name);
+int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler,
+				       const char *hotplug_profile_name);
+void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val);
+
 #ifdef CONFIG_DEBUG_FS
 extern struct dentry *acpi_debugfs_dir;
 int acpi_debugfs_init(void);
Index: test/drivers/acpi/scan.c
===================================================================
--- test.orig/drivers/acpi/scan.c
+++ test/drivers/acpi/scan.c
@@ -63,6 +63,19 @@ int acpi_scan_add_handler(struct acpi_sc
 	return 0;
 }
 
+int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler,
+				       const char *hotplug_profile_name)
+{
+	int error;
+
+	error = acpi_scan_add_handler(handler);
+	if (error)
+		return error;
+
+	acpi_sysfs_add_hotplug_profile(&handler->hotplug, hotplug_profile_name);
+	return 0;
+}
+
 /*
  * Creates hid/cid(s) string needed for modalias and uevent
  * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get:
@@ -1690,6 +1703,52 @@ static bool acpi_scan_handler_matching(s
 	return false;
 }
 
+static acpi_status acpi_scan_hotplug_modify(acpi_handle handle,
+					    u32 lvl_not_used, void *data,
+					    void **ret_not_used)
+{
+	struct acpi_scan_handler *handler = data;
+	struct acpi_device_info *info;
+	bool match = false;
+
+	if (ACPI_FAILURE(acpi_get_object_info(handle, &info)))
+		return AE_OK;
+
+	if (info->valid & ACPI_VALID_HID) {
+		char *idstr = info->hardware_id.string;
+		match = acpi_scan_handler_matching(handler, idstr, NULL);
+	}
+	kfree(info);
+	if (!match)
+		return AE_OK;
+
+	if (handler->hotplug.enabled)
+		acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+					    acpi_hotplug_notify_cb, NULL);
+	else
+		acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+					   acpi_hotplug_notify_cb);
+
+	return AE_OK;
+}
+
+void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val)
+{
+	struct acpi_scan_handler *handler;
+
+	if (!!hotplug->enabled == !!val)
+		return;
+
+	mutex_lock(&acpi_scan_lock);
+
+	hotplug->enabled = val;
+	handler = container_of(hotplug, struct acpi_scan_handler, hotplug);
+	acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
+			    acpi_scan_hotplug_modify, NULL, handler, NULL);
+
+	mutex_unlock(&acpi_scan_lock);
+}
+
 static struct acpi_scan_handler *acpi_scan_match_handler(char *idstr,
 					const struct acpi_device_id **matchid)
 {
Index: test/Documentation/ABI/testing/sysfs-firmware-acpi
===================================================================
--- test.orig/Documentation/ABI/testing/sysfs-firmware-acpi
+++ test/Documentation/ABI/testing/sysfs-firmware-acpi
@@ -18,6 +18,32 @@ Description:
 		yoffset: The number of pixels between the top of the screen
 			 and the top edge of the image.
 
+What:		/sys/firmware/acpi/hotplug/
+Date:		February 2013
+Contact:	Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Description:
+		There are separate hotplug profiles for different classes of
+		devices supported by ACPI, such as containers, memory modules,
+		processors, PCI root bridges etc.  A hotplug profile for a given
+		class of devices is a collection of settings defining the way
+		that class of devices will be handled by the ACPI core hotplug
+		code.  Those profiles are represented in sysfs as subdirectories
+		of /sys/firmware/acpi/hotplug/.
+
+		The following setting is available to user space for each
+		hotplug profile:
+
+		enabled: If set, the ACPI core will handle notifications of
+			hotplug events associated with the given class of
+			devices and will allow those devices to be ejected with
+			the help of the _EJ0 control method.  Unsetting it
+			effectively disables hotplug for the correspoinding
+			class of devices.
+
+		The value of the above attribute is an integer number: 1 (set)
+		or 0 (unset).  Attempts to write any other values to it will
+		cause -EINVAL to be returned.
+
 What:		/sys/firmware/acpi/interrupts/
 Date:		February 2008
 Contact:	Len Brown <lenb@kernel.org>


^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2, 6/7] ACPI / container: Use hotplug profile user space interface
  2013-02-26 22:41 ` [PATCH v2, 0/7] ACPI / hotplug: Common code for ACPI-based hotplug Rafael J. Wysocki
                     ` (4 preceding siblings ...)
  2013-02-26 22:48   ` [PATCH v2, 5/7] ACPI / hotplug: Introduce user space interface for hotplug profiles Rafael J. Wysocki
@ 2013-02-26 22:49   ` Rafael J. Wysocki
  2013-02-26 22:50   ` [PATCH v2, 7/7] ACPI / scan: Make memory hotplug driver use struct acpi_scan_handler Rafael J. Wysocki
  2013-02-27  0:51   ` [PATCH v2, 0/7] ACPI / hotplug: Common code for ACPI-based hotplug Toshi Kani
  7 siblings, 0 replies; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-26 22:49 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Yinghai Lu, Toshi Kani, Yasuaki Ishimatsu,
	Jiang Liu

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Make the ACPI container driver register its ACPI scan handler object
using acpi_scan_add_handler_with_hotplug() to allow user space to
manipulate its hotplug profile 'enabled' attribute.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/acpi/container.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

Index: test/drivers/acpi/container.c
===================================================================
--- test.orig/drivers/acpi/container.c
+++ test/drivers/acpi/container.c
@@ -49,7 +49,7 @@ static int container_device_attach(struc
 	return 1;
 }
 
-static struct acpi_scan_handler container_device_handler = {
+static struct acpi_scan_handler container_handler = {
 	.ids = container_device_ids,
 	.attach = container_device_attach,
 	.hotplug = {
@@ -60,5 +60,5 @@ static struct acpi_scan_handler containe
 
 void __init acpi_container_init(void)
 {
-	acpi_scan_add_handler(&container_device_handler);
+	acpi_scan_add_handler_with_hotplug(&container_handler, "container");
 }

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [PATCH v2, 7/7] ACPI / scan: Make memory hotplug driver use struct acpi_scan_handler
  2013-02-26 22:41 ` [PATCH v2, 0/7] ACPI / hotplug: Common code for ACPI-based hotplug Rafael J. Wysocki
                     ` (5 preceding siblings ...)
  2013-02-26 22:49   ` [PATCH v2, 6/7] ACPI / container: Use hotplug profile user space interface Rafael J. Wysocki
@ 2013-02-26 22:50   ` Rafael J. Wysocki
  2013-02-27  0:51   ` [PATCH v2, 0/7] ACPI / hotplug: Common code for ACPI-based hotplug Toshi Kani
  7 siblings, 0 replies; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-26 22:50 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Yinghai Lu, Toshi Kani, Yasuaki Ishimatsu,
	Jiang Liu

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

Make the ACPI memory hotplug driver use struct acpi_scan_handler
for representing the object used to set up ACPI memory hotplug
functionality and to remove hotplug memory ranges and data
structures used by the driver before unregistering ACPI device
nodes representing memory.  Register the new struct acpi_scan_handler
object with the help of acpi_scan_add_handler_with_hotplug() to allow
user space to manipulate the 'enabled' attribute of the memory hotplug
profile.

This results in a significant reduction of the drvier's code size
and removes some ACPI hotplug code duplication.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/acpi/Kconfig           |    3 
 drivers/acpi/acpi_memhotplug.c |  309 +++++------------------------------------
 drivers/acpi/internal.h        |    5 
 drivers/acpi/scan.c            |    1 
 4 files changed, 45 insertions(+), 273 deletions(-)

Index: test/drivers/acpi/Kconfig
===================================================================
--- test.orig/drivers/acpi/Kconfig
+++ test/drivers/acpi/Kconfig
@@ -350,9 +350,8 @@ config ACPI_CONTAINER
 	  the module will be called container.
 
 config ACPI_HOTPLUG_MEMORY
-	tristate "Memory Hotplug"
+	bool "Memory Hotplug"
 	depends on MEMORY_HOTPLUG
-	default n
 	help
 	  This driver supports ACPI memory hotplug.  The driver
 	  fields notifications on ACPI memory devices (PNP0C80),
Index: test/drivers/acpi/acpi_memhotplug.c
===================================================================
--- test.orig/drivers/acpi/acpi_memhotplug.c
+++ test/drivers/acpi/acpi_memhotplug.c
@@ -1,5 +1,7 @@
 /*
- * Copyright (C) 2004 Intel Corporation <naveen.b.s@intel.com>
+ * Copyright (C) 2004, 2013 Intel Corporation
+ * Author: Naveen B S <naveen.b.s@intel.com>
+ * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
  *
  * All rights reserved.
  *
@@ -25,14 +27,10 @@
  * ranges.
  */
 
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/memory_hotplug.h>
-#include <linux/slab.h>
 #include <linux/acpi.h>
-#include <acpi/acpi_drivers.h>
+#include <linux/memory_hotplug.h>
+
+#include "internal.h"
 
 #define ACPI_MEMORY_DEVICE_CLASS		"memory"
 #define ACPI_MEMORY_DEVICE_HID			"PNP0C80"
@@ -44,32 +42,28 @@
 #define 	PREFIX		"ACPI:memory_hp:"
 
 ACPI_MODULE_NAME("acpi_memhotplug");
-MODULE_AUTHOR("Naveen B S <naveen.b.s@intel.com>");
-MODULE_DESCRIPTION("Hotplug Mem Driver");
-MODULE_LICENSE("GPL");
 
 /* Memory Device States */
 #define MEMORY_INVALID_STATE	0
 #define MEMORY_POWER_ON_STATE	1
 #define MEMORY_POWER_OFF_STATE	2
 
-static int acpi_memory_device_add(struct acpi_device *device);
-static int acpi_memory_device_remove(struct acpi_device *device);
+static int acpi_memory_device_add(struct acpi_device *device,
+				  const struct acpi_device_id *not_used);
+static void acpi_memory_device_remove(struct acpi_device *device);
 
 static const struct acpi_device_id memory_device_ids[] = {
 	{ACPI_MEMORY_DEVICE_HID, 0},
 	{"", 0},
 };
-MODULE_DEVICE_TABLE(acpi, memory_device_ids);
 
-static struct acpi_driver acpi_memory_device_driver = {
-	.name = "acpi_memhotplug",
-	.class = ACPI_MEMORY_DEVICE_CLASS,
+static struct acpi_scan_handler memory_device_handler = {
 	.ids = memory_device_ids,
-	.ops = {
-		.add = acpi_memory_device_add,
-		.remove = acpi_memory_device_remove,
-		},
+	.attach = acpi_memory_device_add,
+	.detach = acpi_memory_device_remove,
+	.hotplug = {
+		.enabled = true,
+	},
 };
 
 struct acpi_memory_info {
@@ -153,48 +147,6 @@ acpi_memory_get_device_resources(struct
 	return 0;
 }
 
-static int acpi_memory_get_device(acpi_handle handle,
-				  struct acpi_memory_device **mem_device)
-{
-	struct acpi_device *device = NULL;
-	int result = 0;
-
-	acpi_scan_lock_acquire();
-
-	acpi_bus_get_device(handle, &device);
-	if (device)
-		goto end;
-
-	/*
-	 * Now add the notified device.  This creates the acpi_device
-	 * and invokes .add function
-	 */
-	result = acpi_bus_scan(handle);
-	if (result) {
-		acpi_handle_warn(handle, "ACPI namespace scan failed\n");
-		result = -EINVAL;
-		goto out;
-	}
-	result = acpi_bus_get_device(handle, &device);
-	if (result) {
-		acpi_handle_warn(handle, "Missing device object\n");
-		result = -EINVAL;
-		goto out;
-	}
-
- end:
-	*mem_device = acpi_driver_data(device);
-	if (!(*mem_device)) {
-		dev_err(&device->dev, "driver data not found\n");
-		result = -ENODEV;
-		goto out;
-	}
-
- out:
-	acpi_scan_lock_release();
-	return result;
-}
-
 static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
 {
 	unsigned long long current_status;
@@ -306,95 +258,21 @@ static int acpi_memory_remove_memory(str
 	return result;
 }
 
-static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
-{
-	struct acpi_memory_device *mem_device;
-	struct acpi_device *device;
-	struct acpi_eject_event *ej_event = NULL;
-	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
-	acpi_status status;
-
-	switch (event) {
-	case ACPI_NOTIFY_BUS_CHECK:
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-				  "\nReceived BUS CHECK notification for device\n"));
-		/* Fall Through */
-	case ACPI_NOTIFY_DEVICE_CHECK:
-		if (event == ACPI_NOTIFY_DEVICE_CHECK)
-			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-					  "\nReceived DEVICE CHECK notification for device\n"));
-		if (acpi_memory_get_device(handle, &mem_device)) {
-			acpi_handle_err(handle, "Cannot find driver data\n");
-			break;
-		}
-
-		ost_code = ACPI_OST_SC_SUCCESS;
-		break;
-
-	case ACPI_NOTIFY_EJECT_REQUEST:
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-				  "\nReceived EJECT REQUEST notification for device\n"));
-
-		status = AE_ERROR;
-		acpi_scan_lock_acquire();
-
-		if (acpi_bus_get_device(handle, &device)) {
-			acpi_handle_err(handle, "Device doesn't exist\n");
-			goto unlock;
-		}
-		mem_device = acpi_driver_data(device);
-		if (!mem_device) {
-			acpi_handle_err(handle, "Driver Data is NULL\n");
-			goto unlock;
-		}
-
-		ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
-		if (!ej_event) {
-			pr_err(PREFIX "No memory, dropping EJECT\n");
-			goto unlock;
-		}
-
-		get_device(&device->dev);
-		ej_event->device = device;
-		ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
-		/* The eject is carried out asynchronously. */
-		status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
-						 ej_event);
-		if (ACPI_FAILURE(status)) {
-			put_device(&device->dev);
-			kfree(ej_event);
-		}
-
- unlock:
-		acpi_scan_lock_release();
-		if (ACPI_SUCCESS(status))
-			return;
-	default:
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-				  "Unsupported event [0x%x]\n", event));
-
-		/* non-hotplug event; possibly handled by other handler */
-		return;
-	}
-
-	/* Inform firmware that the hotplug operation has completed */
-	(void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL);
-}
-
 static void acpi_memory_device_free(struct acpi_memory_device *mem_device)
 {
 	if (!mem_device)
 		return;
 
 	acpi_memory_free_device_resources(mem_device);
+	mem_device->device->driver_data = NULL;
 	kfree(mem_device);
 }
 
-static int acpi_memory_device_add(struct acpi_device *device)
+static int acpi_memory_device_add(struct acpi_device *device,
+				  const struct acpi_device_id *not_used)
 {
+	struct acpi_memory_device *mem_device;
 	int result;
-	struct acpi_memory_device *mem_device = NULL;
-
 
 	if (!device)
 		return -EINVAL;
@@ -419,147 +297,36 @@ static int acpi_memory_device_add(struct
 	/* Set the device state */
 	mem_device->state = MEMORY_POWER_ON_STATE;
 
-	pr_debug("%s\n", acpi_device_name(device));
+	result = acpi_memory_check_device(mem_device);
+	if (result) {
+		acpi_memory_device_free(mem_device);
+		return 0;
+	}
 
-	if (!acpi_memory_check_device(mem_device)) {
-		/* call add_memory func */
-		result = acpi_memory_enable_device(mem_device);
-		if (result) {
-			dev_err(&device->dev,
-				"Error in acpi_memory_enable_device\n");
-			acpi_memory_device_free(mem_device);
-		}
+	result = acpi_memory_enable_device(mem_device);
+	if (result) {
+		dev_err(&device->dev, "acpi_memory_enable_device() error\n");
+		acpi_memory_device_free(mem_device);
+		return -ENODEV;
 	}
-	return result;
+
+	dev_dbg(&device->dev, "Memory device configured by ACPI\n");
+	return 1;
 }
 
-static int acpi_memory_device_remove(struct acpi_device *device)
+static void acpi_memory_device_remove(struct acpi_device *device)
 {
-	struct acpi_memory_device *mem_device = NULL;
-	int result;
+	struct acpi_memory_device *mem_device;
 
 	if (!device || !acpi_driver_data(device))
-		return -EINVAL;
+		return;
 
 	mem_device = acpi_driver_data(device);
-
-	result = acpi_memory_remove_memory(mem_device);
-	if (result)
-		return result;
-
+	acpi_memory_remove_memory(mem_device);
 	acpi_memory_device_free(mem_device);
-
-	return 0;
-}
-
-/*
- * Helper function to check for memory device
- */
-static acpi_status is_memory_device(acpi_handle handle)
-{
-	char *hardware_id;
-	acpi_status status;
-	struct acpi_device_info *info;
-
-	status = acpi_get_object_info(handle, &info);
-	if (ACPI_FAILURE(status))
-		return status;
-
-	if (!(info->valid & ACPI_VALID_HID)) {
-		kfree(info);
-		return AE_ERROR;
-	}
-
-	hardware_id = info->hardware_id.string;
-	if ((hardware_id == NULL) ||
-	    (strcmp(hardware_id, ACPI_MEMORY_DEVICE_HID)))
-		status = AE_ERROR;
-
-	kfree(info);
-	return status;
-}
-
-static acpi_status
-acpi_memory_register_notify_handler(acpi_handle handle,
-				    u32 level, void *ctxt, void **retv)
-{
-	acpi_status status;
-
-
-	status = is_memory_device(handle);
-	if (ACPI_FAILURE(status))
-		return AE_OK;	/* continue */
-
-	status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
-					     acpi_memory_device_notify, NULL);
-	/* continue */
-	return AE_OK;
-}
-
-static acpi_status
-acpi_memory_deregister_notify_handler(acpi_handle handle,
-				      u32 level, void *ctxt, void **retv)
-{
-	acpi_status status;
-
-
-	status = is_memory_device(handle);
-	if (ACPI_FAILURE(status))
-		return AE_OK;	/* continue */
-
-	status = acpi_remove_notify_handler(handle,
-					    ACPI_SYSTEM_NOTIFY,
-					    acpi_memory_device_notify);
-
-	return AE_OK;	/* continue */
-}
-
-static int __init acpi_memory_device_init(void)
-{
-	int result;
-	acpi_status status;
-
-
-	result = acpi_bus_register_driver(&acpi_memory_device_driver);
-
-	if (result < 0)
-		return -ENODEV;
-
-	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
-				     ACPI_UINT32_MAX,
-				     acpi_memory_register_notify_handler, NULL,
-				     NULL, NULL);
-
-	if (ACPI_FAILURE(status)) {
-		ACPI_EXCEPTION((AE_INFO, status, "walk_namespace failed"));
-		acpi_bus_unregister_driver(&acpi_memory_device_driver);
-		return -ENODEV;
-	}
-
-	return 0;
 }
 
-static void __exit acpi_memory_device_exit(void)
+void __init acpi_memory_hotplug_init(void)
 {
-	acpi_status status;
-
-
-	/*
-	 * Adding this to un-install notification handlers for all the device
-	 * handles.
-	 */
-	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
-				     ACPI_UINT32_MAX,
-				     acpi_memory_deregister_notify_handler, NULL,
-				     NULL, NULL);
-
-	if (ACPI_FAILURE(status))
-		ACPI_EXCEPTION((AE_INFO, status, "walk_namespace failed"));
-
-	acpi_bus_unregister_driver(&acpi_memory_device_driver);
-
-	return;
+	acpi_scan_add_handler_with_hotplug(&memory_device_handler, "memory");
 }
-
-module_init(acpi_memory_device_init);
-module_exit(acpi_memory_device_exit);
Index: test/drivers/acpi/internal.h
===================================================================
--- test.orig/drivers/acpi/internal.h
+++ test/drivers/acpi/internal.h
@@ -35,6 +35,11 @@ void acpi_container_init(void);
 #else
 static inline void acpi_container_init(void) {}
 #endif
+#ifdef CONFIG_ACPI_HOTPLUG_MEMORY
+void acpi_memory_hotplug_init(void);
+#else
+static inline void acpi_memory_hotplug_init(void) {}
+#endif
 
 void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug,
 				    const char *name);
Index: test/drivers/acpi/scan.c
===================================================================
--- test.orig/drivers/acpi/scan.c
+++ test/drivers/acpi/scan.c
@@ -2025,6 +2025,7 @@ int __init acpi_scan_init(void)
 	acpi_platform_init();
 	acpi_csrt_init();
 	acpi_container_init();
+	acpi_memory_hotplug_init();
 
 	mutex_lock(&acpi_scan_lock);
 	/*


^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH v2, 3/7] ACPI / container: Use common hotplug code
  2013-02-26 22:46   ` [PATCH v2, 3/7] ACPI / container: Use common hotplug code Rafael J. Wysocki
@ 2013-02-26 23:13       ` Toshi Kani
  2013-02-27  0:09     ` [Update][PATCH " Rafael J. Wysocki
  1 sibling, 0 replies; 69+ messages in thread
From: Toshi Kani @ 2013-02-26 23:13 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Yinghai Lu,
	Yasuaki Ishimatsu, Jiang Liu

On Tue, 2013-02-26 at 23:46 +0100, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> 
> Switch the ACPI container driver to using common device hotplug code
> introduced previously.  This reduces the driver down to a trivial
> definition and registration of a struct acpi_scan_handler object.
> 
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> ---
>  drivers/acpi/container.c |  146 +++--------------------------------------------
>  1 file changed, 10 insertions(+), 136 deletions(-)
> 
> Index: test/drivers/acpi/container.c
> ===================================================================
> --- test.orig/drivers/acpi/container.c
> +++ test/drivers/acpi/container.c
> @@ -1,12 +1,12 @@
>  /*
> - * acpi_container.c  - ACPI Generic Container Driver
> - * ($Revision: )
> + * container.c  - ACPI Generic Container Driver
>   *
>   * Copyright (C) 2004 Anil S Keshavamurthy (anil.s.keshavamurthy@intel.com)
>   * Copyright (C) 2004 Keiichiro Tokunaga (tokunaga.keiich@jp.fujitsu.com)
>   * Copyright (C) 2004 Motoyuki Ito (motoyuki@soft.fujitsu.com)
> - * Copyright (C) 2004 Intel Corp.
>   * Copyright (C) 2004 FUJITSU LIMITED
> + * Copyright (C) 2004, 2013 Intel Corp.
> + * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>   *
>   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>   *
> @@ -26,14 +26,9 @@
>   *
>   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>   */
> -#include <linux/kernel.h>
> -#include <linux/module.h>
> -#include <linux/init.h>
> -#include <linux/slab.h>
> -#include <linux/types.h>
>  #include <linux/acpi.h>
> -#include <acpi/acpi_bus.h>
> -#include <acpi/acpi_drivers.h>
> +
> +#include "internal.h"
>  
>  #define PREFIX "ACPI: "
>  
> @@ -50,141 +45,20 @@ static const struct acpi_device_id conta
>  static int container_device_attach(struct acpi_device *device,
>  				   const struct acpi_device_id *not_used)
>  {
> -	/*
> -	 * FIXME: This is necessary, so that acpi_eject_store() doesn't return
> -	 * -ENODEV for containers.
> -	 */
> +	/* This is necessary for container hotplug to work. */
>  	return 1;
>  }
>  
>  static struct acpi_scan_handler container_device_handler = {
>  	.ids = container_device_ids,
>  	.attach = container_device_attach,
> +	.hotplug = {
> +		.enabled = true,
> +		.user_eject = true,

I am not able to compile this patch 3/7...  user_eject is not defined in
patch 2/7.

  CC      drivers/acpi/container.o
drivers/acpi/container.c:57:3: error: unknown field ‘user_eject’
specified in initializer

-Toshi

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH v2, 3/7] ACPI / container: Use common hotplug code
@ 2013-02-26 23:13       ` Toshi Kani
  0 siblings, 0 replies; 69+ messages in thread
From: Toshi Kani @ 2013-02-26 23:13 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Yinghai Lu,
	Yasuaki Ishimatsu, Jiang Liu

On Tue, 2013-02-26 at 23:46 +0100, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> 
> Switch the ACPI container driver to using common device hotplug code
> introduced previously.  This reduces the driver down to a trivial
> definition and registration of a struct acpi_scan_handler object.
> 
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> ---
>  drivers/acpi/container.c |  146 +++--------------------------------------------
>  1 file changed, 10 insertions(+), 136 deletions(-)
> 
> Index: test/drivers/acpi/container.c
> ===================================================================
> --- test.orig/drivers/acpi/container.c
> +++ test/drivers/acpi/container.c
> @@ -1,12 +1,12 @@
>  /*
> - * acpi_container.c  - ACPI Generic Container Driver
> - * ($Revision: )
> + * container.c  - ACPI Generic Container Driver
>   *
>   * Copyright (C) 2004 Anil S Keshavamurthy (anil.s.keshavamurthy@intel.com)
>   * Copyright (C) 2004 Keiichiro Tokunaga (tokunaga.keiich@jp.fujitsu.com)
>   * Copyright (C) 2004 Motoyuki Ito (motoyuki@soft.fujitsu.com)
> - * Copyright (C) 2004 Intel Corp.
>   * Copyright (C) 2004 FUJITSU LIMITED
> + * Copyright (C) 2004, 2013 Intel Corp.
> + * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>   *
>   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>   *
> @@ -26,14 +26,9 @@
>   *
>   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>   */
> -#include <linux/kernel.h>
> -#include <linux/module.h>
> -#include <linux/init.h>
> -#include <linux/slab.h>
> -#include <linux/types.h>
>  #include <linux/acpi.h>
> -#include <acpi/acpi_bus.h>
> -#include <acpi/acpi_drivers.h>
> +
> +#include "internal.h"
>  
>  #define PREFIX "ACPI: "
>  
> @@ -50,141 +45,20 @@ static const struct acpi_device_id conta
>  static int container_device_attach(struct acpi_device *device,
>  				   const struct acpi_device_id *not_used)
>  {
> -	/*
> -	 * FIXME: This is necessary, so that acpi_eject_store() doesn't return
> -	 * -ENODEV for containers.
> -	 */
> +	/* This is necessary for container hotplug to work. */
>  	return 1;
>  }
>  
>  static struct acpi_scan_handler container_device_handler = {
>  	.ids = container_device_ids,
>  	.attach = container_device_attach,
> +	.hotplug = {
> +		.enabled = true,
> +		.user_eject = true,

I am not able to compile this patch 3/7...  user_eject is not defined in
patch 2/7.

  CC      drivers/acpi/container.o
drivers/acpi/container.c:57:3: error: unknown field ‘user_eject’
specified in initializer

-Toshi


^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH v2, 3/7] ACPI / container: Use common hotplug code
  2013-02-26 23:13       ` Toshi Kani
  (?)
@ 2013-02-27  0:06       ` Rafael J. Wysocki
  -1 siblings, 0 replies; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-27  0:06 UTC (permalink / raw)
  To: Toshi Kani
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Yinghai Lu,
	Yasuaki Ishimatsu, Jiang Liu

On Tuesday, February 26, 2013 04:13:06 PM Toshi Kani wrote:
> On Tue, 2013-02-26 at 23:46 +0100, Rafael J. Wysocki wrote:
> > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > 
> > Switch the ACPI container driver to using common device hotplug code
> > introduced previously.  This reduces the driver down to a trivial
> > definition and registration of a struct acpi_scan_handler object.
> > 
> > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > ---
> >  drivers/acpi/container.c |  146 +++--------------------------------------------
> >  1 file changed, 10 insertions(+), 136 deletions(-)
> > 
> > Index: test/drivers/acpi/container.c
> > ===================================================================
> > --- test.orig/drivers/acpi/container.c
> > +++ test/drivers/acpi/container.c
> > @@ -1,12 +1,12 @@
> >  /*
> > - * acpi_container.c  - ACPI Generic Container Driver
> > - * ($Revision: )
> > + * container.c  - ACPI Generic Container Driver
> >   *
> >   * Copyright (C) 2004 Anil S Keshavamurthy (anil.s.keshavamurthy@intel.com)
> >   * Copyright (C) 2004 Keiichiro Tokunaga (tokunaga.keiich@jp.fujitsu.com)
> >   * Copyright (C) 2004 Motoyuki Ito (motoyuki@soft.fujitsu.com)
> > - * Copyright (C) 2004 Intel Corp.
> >   * Copyright (C) 2004 FUJITSU LIMITED
> > + * Copyright (C) 2004, 2013 Intel Corp.
> > + * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> >   *
> >   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> >   *
> > @@ -26,14 +26,9 @@
> >   *
> >   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> >   */
> > -#include <linux/kernel.h>
> > -#include <linux/module.h>
> > -#include <linux/init.h>
> > -#include <linux/slab.h>
> > -#include <linux/types.h>
> >  #include <linux/acpi.h>
> > -#include <acpi/acpi_bus.h>
> > -#include <acpi/acpi_drivers.h>
> > +
> > +#include "internal.h"
> >  
> >  #define PREFIX "ACPI: "
> >  
> > @@ -50,141 +45,20 @@ static const struct acpi_device_id conta
> >  static int container_device_attach(struct acpi_device *device,
> >  				   const struct acpi_device_id *not_used)
> >  {
> > -	/*
> > -	 * FIXME: This is necessary, so that acpi_eject_store() doesn't return
> > -	 * -ENODEV for containers.
> > -	 */
> > +	/* This is necessary for container hotplug to work. */
> >  	return 1;
> >  }
> >  
> >  static struct acpi_scan_handler container_device_handler = {
> >  	.ids = container_device_ids,
> >  	.attach = container_device_attach,
> > +	.hotplug = {
> > +		.enabled = true,
> > +		.user_eject = true,
> 
> I am not able to compile this patch 3/7...  user_eject is not defined in
> patch 2/7.
> 
>   CC      drivers/acpi/container.o
> drivers/acpi/container.c:57:3: error: unknown field ‘user_eject’
> specified in initializer

I forgot the refresh the patch, sorry.  Will send an update shortly.

Thanks,
Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* [Update][PATCH v2, 3/7] ACPI / container: Use common hotplug code
  2013-02-26 22:46   ` [PATCH v2, 3/7] ACPI / container: Use common hotplug code Rafael J. Wysocki
  2013-02-26 23:13       ` Toshi Kani
@ 2013-02-27  0:09     ` Rafael J. Wysocki
  1 sibling, 0 replies; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-02-27  0:09 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Yinghai Lu, Toshi Kani, Yasuaki Ishimatsu,
	Jiang Liu

From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Subject: ACPI / container: Use common hotplug code

Switch the ACPI container driver to using common device hotplug code
introduced previously.  This reduces the driver down to a trivial
definition and registration of a struct acpi_scan_handler object.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---

I sent an old version of the patch before, sorry about that.

Thanks,
Rafael

---
 drivers/acpi/container.c |  146 +++--------------------------------------------
 1 file changed, 10 insertions(+), 136 deletions(-)

Index: test/drivers/acpi/container.c
===================================================================
--- test.orig/drivers/acpi/container.c
+++ test/drivers/acpi/container.c
@@ -1,12 +1,12 @@
 /*
- * acpi_container.c  - ACPI Generic Container Driver
- * ($Revision: )
+ * container.c  - ACPI Generic Container Driver
  *
  * Copyright (C) 2004 Anil S Keshavamurthy (anil.s.keshavamurthy@intel.com)
  * Copyright (C) 2004 Keiichiro Tokunaga (tokunaga.keiich@jp.fujitsu.com)
  * Copyright (C) 2004 Motoyuki Ito (motoyuki@soft.fujitsu.com)
- * Copyright (C) 2004 Intel Corp.
  * Copyright (C) 2004 FUJITSU LIMITED
+ * Copyright (C) 2004, 2013 Intel Corp.
+ * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  *
@@ -26,14 +26,9 @@
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/types.h>
 #include <linux/acpi.h>
-#include <acpi/acpi_bus.h>
-#include <acpi/acpi_drivers.h>
+
+#include "internal.h"
 
 #define PREFIX "ACPI: "
 
@@ -50,141 +45,20 @@ static const struct acpi_device_id conta
 static int container_device_attach(struct acpi_device *device,
 				   const struct acpi_device_id *not_used)
 {
-	/*
-	 * FIXME: This is necessary, so that acpi_eject_store() doesn't return
-	 * -ENODEV for containers.
-	 */
+	/* This is necessary for container hotplug to work. */
 	return 1;
 }
 
 static struct acpi_scan_handler container_device_handler = {
 	.ids = container_device_ids,
 	.attach = container_device_attach,
+	.hotplug = {
+		.enabled = true,
+		.mode = AHM_CONTAINER,
+	},
 };
 
-static int is_device_present(acpi_handle handle)
-{
-	acpi_handle temp;
-	acpi_status status;
-	unsigned long long sta;
-
-
-	status = acpi_get_handle(handle, "_STA", &temp);
-	if (ACPI_FAILURE(status))
-		return 1;	/* _STA not found, assume device present */
-
-	status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
-	if (ACPI_FAILURE(status))
-		return 0;	/* Firmware error */
-
-	return ((sta & ACPI_STA_DEVICE_PRESENT) == ACPI_STA_DEVICE_PRESENT);
-}
-
-static void container_notify_cb(acpi_handle handle, u32 type, void *context)
-{
-	struct acpi_device *device = NULL;
-	int result;
-	int present;
-	acpi_status status;
-	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
-
-	acpi_scan_lock_acquire();
-
-	switch (type) {
-	case ACPI_NOTIFY_BUS_CHECK:
-		/* Fall through */
-	case ACPI_NOTIFY_DEVICE_CHECK:
-		pr_debug("Container driver received %s event\n",
-		       (type == ACPI_NOTIFY_BUS_CHECK) ?
-		       "ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK");
-
-		present = is_device_present(handle);
-		status = acpi_bus_get_device(handle, &device);
-		if (!present) {
-			if (ACPI_SUCCESS(status)) {
-				/* device exist and this is a remove request */
-				device->flags.eject_pending = 1;
-				kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
-				goto out;
-			}
-			break;
-		}
-
-		if (!ACPI_FAILURE(status) || device)
-			break;
-
-		result = acpi_bus_scan(handle);
-		if (result) {
-			acpi_handle_warn(handle, "Failed to add container\n");
-			break;
-		}
-		result = acpi_bus_get_device(handle, &device);
-		if (result) {
-			acpi_handle_warn(handle, "Missing device object\n");
-			break;
-		}
-
-		kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
-		ost_code = ACPI_OST_SC_SUCCESS;
-		break;
-
-	case ACPI_NOTIFY_EJECT_REQUEST:
-		if (!acpi_bus_get_device(handle, &device) && device) {
-			device->flags.eject_pending = 1;
-			kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
-			goto out;
-		}
-		break;
-
-	default:
-		/* non-hotplug event; possibly handled by other handler */
-		goto out;
-	}
-
-	/* Inform firmware that the hotplug operation has completed */
-	(void) acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
-
- out:
-	acpi_scan_lock_release();
-}
-
-static bool is_container(acpi_handle handle)
-{
-	struct acpi_device_info *info;
-	bool ret = false;
-
-	if (ACPI_FAILURE(acpi_get_object_info(handle, &info)))
-		return false;
-
-	if (info->valid & ACPI_VALID_HID) {
-		const struct acpi_device_id *id;
-
-		for (id = container_device_ids; id->id[0]; id++) {
-			ret = !strcmp((char *)id->id, info->hardware_id.string);
-			if (ret)
-				break;
-		}
-	}
-	kfree(info);
-	return ret;
-}
-
-static acpi_status acpi_container_register_notify_handler(acpi_handle handle,
-							  u32 lvl, void *ctxt,
-							  void **retv)
-{
-	if (is_container(handle))
-		acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
-					    container_notify_cb, NULL);
-
-	return AE_OK;
-}
-
 void __init acpi_container_init(void)
 {
-	acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
-			    acpi_container_register_notify_handler, NULL,
-			    NULL, NULL);
-
 	acpi_scan_add_handler(&container_device_handler);
 }

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [PATCH v2, 0/7] ACPI / hotplug: Common code for ACPI-based hotplug
  2013-02-26 22:41 ` [PATCH v2, 0/7] ACPI / hotplug: Common code for ACPI-based hotplug Rafael J. Wysocki
                     ` (6 preceding siblings ...)
  2013-02-26 22:50   ` [PATCH v2, 7/7] ACPI / scan: Make memory hotplug driver use struct acpi_scan_handler Rafael J. Wysocki
@ 2013-02-27  0:51   ` Toshi Kani
  7 siblings, 0 replies; 69+ messages in thread
From: Toshi Kani @ 2013-02-27  0:51 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Yinghai Lu,
	Yasuaki Ishimatsu, Jiang Liu

On Tue, 2013-02-26 at 23:41 +0100, Rafael J. Wysocki wrote:
> On Sunday, February 17, 2013 04:18:31 PM Rafael J. Wysocki wrote:
> > Hi All,
> > 
> > The following patches introduce common code for ACPI-based hotplug for non-PCI
> > devices and modify the container and memory hotplug ACPI drivers to use the new
> > code.
> > 
> > This is based on linux-pm.git/master and regarded as v3.10 material.
> > 
> > [1/7] Introduce acpi_scan_match_handler() that will be useful going forward.
> > [2/7] Introduce common code for ACPI-base device hotplug.
> > [3/7] Use the new commot hotplug code in the container driver.
> > [4/7] Introduce acpi_scan_handler_matching() that will be useful subsequently.
> > [5/7] Introduce user space interface for hotplug profiles.
> > [6/7] Make the container driver use the hotplug profiles user space interface.
> > [7/7] Make the memory hotplug driver use struct acpi_scan_handler along with
> >       the hotplug profiles user space interface.
> 
> Following is the second iteration.  It takes all of the updates of patch [2/7]
> and the discussion of them into account and fixes the issue with 'enabled'
> working inversely in [5/7] spotted by Toshi Kani.

Thanks for all the updates.  Things look good now.  For the series:

Acked-by: Toshi Kani <toshi.kani@hp.com>
Tested-by: Toshi Kani <toshi.kani@hp.com>

-Toshi

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Update 4][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-02-25 23:39             ` Rafael J. Wysocki
  2013-02-25 23:32               ` Toshi Kani
  2013-02-26  0:40               ` Yasuaki Ishimatsu
@ 2013-03-04 13:10               ` Vasilis Liaskovitis
  2013-03-14 17:16                 ` Rafael J. Wysocki
  2 siblings, 1 reply; 69+ messages in thread
From: Vasilis Liaskovitis @ 2013-03-04 13:10 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Toshi Kani, ACPI Devel Maling List, Bjorn Helgaas, LKML,
	Yinghai Lu, Yasuaki Ishimatsu, Jiang Liu

Hi,

On Tue, Feb 26, 2013 at 12:39:50AM +0100, Rafael J. Wysocki wrote:
> On Monday, February 25, 2013 11:07:52 AM Toshi Kani wrote:
> > On Sat, 2013-02-23 at 22:38 +0000, Rafael J. Wysocki wrote:
> > > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > > 
> > > Multiple drivers handling hotplug-capable ACPI device nodes install
> > > notify handlers covering the same types of events in a very similar
> > > way.  Moreover, those handlers are installed in separate namespace
> > > walks, although that really should be done during namespace scans
> > > carried out by acpi_bus_scan().  This leads to substantial code
> > > duplication, unnecessary overhead and behavior that is hard to
> > > follow.
> > > 
> > > For this reason, introduce common code in drivers/acpi/scan.c for
> > > handling hotplug-related notification and carrying out device
> > > insertion and eject operations in a generic fashion, such that it
> > > may be used by all of the relevant drivers in the future.  To cover
> > > the existing differences between those drivers introduce struct
> > > acpi_hotplug_profile for representing collections of hotplug
> > > settings associated with different ACPI scan handlers that can be
> > > used by the drivers to make the common code reflect their current
> > > behavior.
[...]
> That's correct, but I don't know what the user space expectations are
> currently.
> 
> > So, I'd suggest the following changes.
> >  - Remove the "uevents" attribute.  KOBJ_ONLINE/OFFLINE are not used for
> > ACPI device objects.
> >  - Make the !autoeject case as an exception for now, and emit
> > KOBJ_OFFLINE as a way to request off-lining to user.  This uevent is
> > tied with the !autoeject case.  We can then revisit if this use-case
> > needs to be supported going forward.  If so, we may want to consider a
> > different event type.
> 
> Well, what about avoiding to expose uevents and autoeject for now and
> exposing enabled only?  Drivers would still be able to set the other flags on
> init on init to enforce the backwards-compatible behavior.

Now that we don't define uevents and autoeject in v2 of this series, could you
explain how we get safe ejection from userspace e.g. for memory hot-remove? What
are the other flags drivers can use (on init?) to avoid autoeject and only issue
KOBJ_OFFLINE?

> 
> I agree that it would be sufficient to use one additional flag then, to start
> with, but its meaning would be something like "keep backwards compatibility
> with the old container driver", so perhaps "autoeject" is not a good name.
> 
> What about "user_eject" (that won't be exposed to user space) instead?  Where,
> if set, it would meand "do not autoeject and emit KOBJ_OFFLINE/ONLINE uevents
> like the old container driver did"?

I don't see user_eject in v2. Is it unnecessary for userspace ejection control
or planned for later? Also why shouldn't it be exposed to userpace?

thanks,

- Vasilis

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Update 4][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-03-04 13:10               ` Vasilis Liaskovitis
@ 2013-03-14 17:16                 ` Rafael J. Wysocki
  2013-03-15 10:47                   ` Vasilis Liaskovitis
  0 siblings, 1 reply; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-03-14 17:16 UTC (permalink / raw)
  To: Vasilis Liaskovitis
  Cc: Toshi Kani, ACPI Devel Maling List, Bjorn Helgaas, LKML,
	Yinghai Lu, Yasuaki Ishimatsu, Jiang Liu

Sorry for the sluggish response, I've been travelling recently. ->

On Monday, March 04, 2013 02:10:23 PM Vasilis Liaskovitis wrote:
> Hi,
> 
> On Tue, Feb 26, 2013 at 12:39:50AM +0100, Rafael J. Wysocki wrote:
> > On Monday, February 25, 2013 11:07:52 AM Toshi Kani wrote:
> > > On Sat, 2013-02-23 at 22:38 +0000, Rafael J. Wysocki wrote:
> > > > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > > > 
> > > > Multiple drivers handling hotplug-capable ACPI device nodes install
> > > > notify handlers covering the same types of events in a very similar
> > > > way.  Moreover, those handlers are installed in separate namespace
> > > > walks, although that really should be done during namespace scans
> > > > carried out by acpi_bus_scan().  This leads to substantial code
> > > > duplication, unnecessary overhead and behavior that is hard to
> > > > follow.
> > > > 
> > > > For this reason, introduce common code in drivers/acpi/scan.c for
> > > > handling hotplug-related notification and carrying out device
> > > > insertion and eject operations in a generic fashion, such that it
> > > > may be used by all of the relevant drivers in the future.  To cover
> > > > the existing differences between those drivers introduce struct
> > > > acpi_hotplug_profile for representing collections of hotplug
> > > > settings associated with different ACPI scan handlers that can be
> > > > used by the drivers to make the common code reflect their current
> > > > behavior.
> [...]
> > That's correct, but I don't know what the user space expectations are
> > currently.
> > 
> > > So, I'd suggest the following changes.
> > >  - Remove the "uevents" attribute.  KOBJ_ONLINE/OFFLINE are not used for
> > > ACPI device objects.
> > >  - Make the !autoeject case as an exception for now, and emit
> > > KOBJ_OFFLINE as a way to request off-lining to user.  This uevent is
> > > tied with the !autoeject case.  We can then revisit if this use-case
> > > needs to be supported going forward.  If so, we may want to consider a
> > > different event type.
> > 
> > Well, what about avoiding to expose uevents and autoeject for now and
> > exposing enabled only?  Drivers would still be able to set the other flags on
> > init on init to enforce the backwards-compatible behavior.
> 
> Now that we don't define uevents and autoeject in v2 of this series, could you
> explain how we get safe ejection from userspace e.g. for memory hot-remove? What
> are the other flags drivers can use (on init?) to avoid autoeject and only issue
> KOBJ_OFFLINE?
> 
> > 
> > I agree that it would be sufficient to use one additional flag then, to start
> > with, but its meaning would be something like "keep backwards compatibility
> > with the old container driver", so perhaps "autoeject" is not a good name.
> > 
> > What about "user_eject" (that won't be exposed to user space) instead?  Where,
> > if set, it would meand "do not autoeject and emit KOBJ_OFFLINE/ONLINE uevents
> > like the old container driver did"?
> 
> I don't see user_eject in v2. Is it unnecessary for userspace ejection control
> or planned for later? Also why shouldn't it be exposed to userpace?

-> At this point we are not sure if it is necessary to have an attribute for
direct ejection control.  Since the plan is to have a separate offline/online
attribute anyway (and a check preventing us from ejecting things that haven't
been put offline), it is not clear how useful it is going to be to control
ejection directly from user space.

Thanks,
Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Update 4][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-03-14 17:16                 ` Rafael J. Wysocki
@ 2013-03-15 10:47                   ` Vasilis Liaskovitis
  2013-03-25 20:45                     ` Toshi Kani
  0 siblings, 1 reply; 69+ messages in thread
From: Vasilis Liaskovitis @ 2013-03-15 10:47 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Toshi Kani, ACPI Devel Maling List, Bjorn Helgaas, LKML,
	Yinghai Lu, Yasuaki Ishimatsu, Jiang Liu

Hi,

On Thu, Mar 14, 2013 at 06:16:30PM +0100, Rafael J. Wysocki wrote:
> Sorry for the sluggish response, I've been travelling recently. ->
[...]
> > > > So, I'd suggest the following changes.
> > > >  - Remove the "uevents" attribute.  KOBJ_ONLINE/OFFLINE are not used for
> > > > ACPI device objects.
> > > >  - Make the !autoeject case as an exception for now, and emit
> > > > KOBJ_OFFLINE as a way to request off-lining to user.  This uevent is
> > > > tied with the !autoeject case.  We can then revisit if this use-case
> > > > needs to be supported going forward.  If so, we may want to consider a
> > > > different event type.
> > > 
> > > Well, what about avoiding to expose uevents and autoeject for now and
> > > exposing enabled only?  Drivers would still be able to set the other flags on
> > > init on init to enforce the backwards-compatible behavior.
> > 
> > Now that we don't define uevents and autoeject in v2 of this series, could you
> > explain how we get safe ejection from userspace e.g. for memory hot-remove? What
> > are the other flags drivers can use (on init?) to avoid autoeject and only issue
> > KOBJ_OFFLINE?
> > 
> > > 
> > > I agree that it would be sufficient to use one additional flag then, to start
> > > with, but its meaning would be something like "keep backwards compatibility
> > > with the old container driver", so perhaps "autoeject" is not a good name.
> > > 
> > > What about "user_eject" (that won't be exposed to user space) instead?  Where,
> > > if set, it would meand "do not autoeject and emit KOBJ_OFFLINE/ONLINE uevents
> > > like the old container driver did"?
> > 
> > I don't see user_eject in v2. Is it unnecessary for userspace ejection control
> > or planned for later? Also why shouldn't it be exposed to userpace?
> 
> -> At this point we are not sure if it is necessary to have an attribute for
> direct ejection control.  Since the plan is to have a separate offline/online
> attribute anyway (and a check preventing us from ejecting things that haven't
> been put offline), it is not clear how useful it is going to be to control
> ejection directly from user space.

ok.
Regarding the offline/online attribute and ejection prevention checking, do you
mean the offline/online framework from Toshi:
http://thread.gmane.org/gmane.linux.kernel/1420262
or something else? I assume this is the long-term plan.

Is there any other short-term solution planned? If i understand correctly, until
this framework is accepted, memory hot-remove is broken (=unsafe). 

thanks,

- Vasilis

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Update 4][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-03-15 10:47                   ` Vasilis Liaskovitis
@ 2013-03-25 20:45                     ` Toshi Kani
  2013-03-25 22:29                       ` Rafael J. Wysocki
  0 siblings, 1 reply; 69+ messages in thread
From: Toshi Kani @ 2013-03-25 20:45 UTC (permalink / raw)
  To: Vasilis Liaskovitis
  Cc: Rafael J. Wysocki, ACPI Devel Maling List, Bjorn Helgaas, LKML,
	Yinghai Lu, Yasuaki Ishimatsu, Jiang Liu

On Fri, 2013-03-15 at 11:47 +0100, Vasilis Liaskovitis wrote:
> Hi,
> 
> On Thu, Mar 14, 2013 at 06:16:30PM +0100, Rafael J. Wysocki wrote:
> > Sorry for the sluggish response, I've been travelling recently. ->
> [...]
> > > > > So, I'd suggest the following changes.
> > > > >  - Remove the "uevents" attribute.  KOBJ_ONLINE/OFFLINE are not used for
> > > > > ACPI device objects.
> > > > >  - Make the !autoeject case as an exception for now, and emit
> > > > > KOBJ_OFFLINE as a way to request off-lining to user.  This uevent is
> > > > > tied with the !autoeject case.  We can then revisit if this use-case
> > > > > needs to be supported going forward.  If so, we may want to consider a
> > > > > different event type.
> > > > 
> > > > Well, what about avoiding to expose uevents and autoeject for now and
> > > > exposing enabled only?  Drivers would still be able to set the other flags on
> > > > init on init to enforce the backwards-compatible behavior.
> > > 
> > > Now that we don't define uevents and autoeject in v2 of this series, could you
> > > explain how we get safe ejection from userspace e.g. for memory hot-remove? What
> > > are the other flags drivers can use (on init?) to avoid autoeject and only issue
> > > KOBJ_OFFLINE?
> > > 
> > > > 
> > > > I agree that it would be sufficient to use one additional flag then, to start
> > > > with, but its meaning would be something like "keep backwards compatibility
> > > > with the old container driver", so perhaps "autoeject" is not a good name.
> > > > 
> > > > What about "user_eject" (that won't be exposed to user space) instead?  Where,
> > > > if set, it would meand "do not autoeject and emit KOBJ_OFFLINE/ONLINE uevents
> > > > like the old container driver did"?
> > > 
> > > I don't see user_eject in v2. Is it unnecessary for userspace ejection control
> > > or planned for later? Also why shouldn't it be exposed to userpace?
> > 
> > -> At this point we are not sure if it is necessary to have an attribute for
> > direct ejection control.  Since the plan is to have a separate offline/online
> > attribute anyway (and a check preventing us from ejecting things that haven't
> > been put offline), it is not clear how useful it is going to be to control
> > ejection directly from user space.
> 
> ok.
> Regarding the offline/online attribute and ejection prevention checking, do you
> mean the offline/online framework from Toshi:
> http://thread.gmane.org/gmane.linux.kernel/1420262
> or something else? I assume this is the long-term plan.

Unfortunately, the idea of adding a new set of common hotplug framework
was not well-received.  Since the driver-core does not allow any eject
failure case, integrating into the driver-core framework seems also
impractical.

> Is there any other short-term solution planned? If i understand correctly, until
> this framework is accepted, memory hot-remove is broken (=unsafe). 

That is correct.  The alternative plan is to go with an ACPI-specific
approach that user has to off-line a target device and its children
beforehand from sysfs before initiating a hot-delete request.  This
hot-delete request will fail if any of the devices are still on-line.
The sysfs online/offline interfaces may fail, and user (or user tool)
has to take care of the rollback as necessary.  It would move all the
error handling & rollback stuff into the user space, and make the kernel
part very simple & straightforward -- just delete target device
objects.  

After looking further, however, I think this isn't the case...  In case
of memory hot-delete, for example, off-lining is only a part of the job
done in remove_memory().  So, ACPI-core still needs to call
device-specific handlers to perform device-specific hot-delete
operations, such as calling remove_memory() or its sub-set function,
which can fail when a device is online.  In order to make sure all
devices stay off-line, we need to delete their sysfs interfaces.  Since
we do not have a way to serialize all online/offline & hot-plug
operations (the above patchset had such serialization, but did not get
thru), we cannot change all devices at once but delete sysfs interface
for each device one by one.  If it failed on one of the devices, we need
to rollback to put them back into the original state.  Other implication
is that this approach is not backward compatible.

Given this, I am inclined to other alternative -- rework on my patchset
and make it as ACPI device hotplug framework.  All changes are within
ACPI.  This actually requires less work and provides backward
compatibility as well.  I have finished prototyping and is working well.
I will send it out for review after all testing is done.

Thanks,
-Toshi


^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Update 4][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-03-25 20:45                     ` Toshi Kani
@ 2013-03-25 22:29                       ` Rafael J. Wysocki
  2013-03-25 22:57                         ` Toshi Kani
  0 siblings, 1 reply; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-03-25 22:29 UTC (permalink / raw)
  To: Toshi Kani
  Cc: Vasilis Liaskovitis, ACPI Devel Maling List, Bjorn Helgaas, LKML,
	Yinghai Lu, Yasuaki Ishimatsu, Jiang Liu

On Monday, March 25, 2013 02:45:36 PM Toshi Kani wrote:
> On Fri, 2013-03-15 at 11:47 +0100, Vasilis Liaskovitis wrote:
> > Hi,
> > 
> > On Thu, Mar 14, 2013 at 06:16:30PM +0100, Rafael J. Wysocki wrote:
> > > Sorry for the sluggish response, I've been travelling recently. ->
> > [...]
> > > > > > So, I'd suggest the following changes.
> > > > > >  - Remove the "uevents" attribute.  KOBJ_ONLINE/OFFLINE are not used for
> > > > > > ACPI device objects.
> > > > > >  - Make the !autoeject case as an exception for now, and emit
> > > > > > KOBJ_OFFLINE as a way to request off-lining to user.  This uevent is
> > > > > > tied with the !autoeject case.  We can then revisit if this use-case
> > > > > > needs to be supported going forward.  If so, we may want to consider a
> > > > > > different event type.
> > > > > 
> > > > > Well, what about avoiding to expose uevents and autoeject for now and
> > > > > exposing enabled only?  Drivers would still be able to set the other flags on
> > > > > init on init to enforce the backwards-compatible behavior.
> > > > 
> > > > Now that we don't define uevents and autoeject in v2 of this series, could you
> > > > explain how we get safe ejection from userspace e.g. for memory hot-remove? What
> > > > are the other flags drivers can use (on init?) to avoid autoeject and only issue
> > > > KOBJ_OFFLINE?
> > > > 
> > > > > 
> > > > > I agree that it would be sufficient to use one additional flag then, to start
> > > > > with, but its meaning would be something like "keep backwards compatibility
> > > > > with the old container driver", so perhaps "autoeject" is not a good name.
> > > > > 
> > > > > What about "user_eject" (that won't be exposed to user space) instead?  Where,
> > > > > if set, it would meand "do not autoeject and emit KOBJ_OFFLINE/ONLINE uevents
> > > > > like the old container driver did"?
> > > > 
> > > > I don't see user_eject in v2. Is it unnecessary for userspace ejection control
> > > > or planned for later? Also why shouldn't it be exposed to userpace?
> > > 
> > > -> At this point we are not sure if it is necessary to have an attribute for
> > > direct ejection control.  Since the plan is to have a separate offline/online
> > > attribute anyway (and a check preventing us from ejecting things that haven't
> > > been put offline), it is not clear how useful it is going to be to control
> > > ejection directly from user space.
> > 
> > ok.
> > Regarding the offline/online attribute and ejection prevention checking, do you
> > mean the offline/online framework from Toshi:
> > http://thread.gmane.org/gmane.linux.kernel/1420262
> > or something else? I assume this is the long-term plan.
> 
> Unfortunately, the idea of adding a new set of common hotplug framework
> was not well-received.  Since the driver-core does not allow any eject
> failure case, integrating into the driver-core framework seems also
> impractical.
> 
> > Is there any other short-term solution planned? If i understand correctly, until
> > this framework is accepted, memory hot-remove is broken (=unsafe). 
> 
> That is correct.  The alternative plan is to go with an ACPI-specific
> approach that user has to off-line a target device and its children
> beforehand from sysfs before initiating a hot-delete request.  This
> hot-delete request will fail if any of the devices are still on-line.
> The sysfs online/offline interfaces may fail, and user (or user tool)
> has to take care of the rollback as necessary.  It would move all the
> error handling & rollback stuff into the user space, and make the kernel
> part very simple & straightforward -- just delete target device
> objects.  
> 
> After looking further, however, I think this isn't the case...  In case
> of memory hot-delete, for example, off-lining is only a part of the job
> done in remove_memory().  So, ACPI-core still needs to call
> device-specific handlers to perform device-specific hot-delete
> operations, such as calling remove_memory() or its sub-set function,
> which can fail when a device is online.  In order to make sure all
> devices stay off-line, we need to delete their sysfs interfaces.

No, we don't need to.

> Since we do not have a way to serialize all online/offline & hot-plug
> operations (the above patchset had such serialization, but did not get
> thru), we cannot change all devices at once but delete sysfs interface
> for each device one by one.  If it failed on one of the devices, we need
> to rollback to put them back into the original state.  Other implication
> is that this approach is not backward compatible.

No.  No rollbacks, please.

There are three things that are needed: (1) online/offline, (2) a flag in
struct acpi_device indicating whether or not the "physical" device represented
by that struct acpi_device has been offlined, and (3) a synchronization
mechanism that will make the manipulation of the flag and device eject mutually
exclusive (it actually would need to tie the manipulation of the flag to
the online/offline).

Then, acpi_scan_hot_remove() will only need to check, before it calls
acpi_bus_trim(), if all of the devices that correspond to the struct device
objects to be removed have been offlined.  Of course, it will have to ensure
that the "online/offline" status of any of those devices won't change while
it is running (hence, the synchronization mechanism).

And once everything has been offlined, there's no reason why the removal should
fail, right?

> Given this, I am inclined to other alternative -- rework on my patchset
> and make it as ACPI device hotplug framework.

Please don't.

Thanks,
Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Update 4][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-03-25 22:29                       ` Rafael J. Wysocki
@ 2013-03-25 22:57                         ` Toshi Kani
  2013-03-26 12:22                           ` Rafael J. Wysocki
  0 siblings, 1 reply; 69+ messages in thread
From: Toshi Kani @ 2013-03-25 22:57 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Vasilis Liaskovitis, ACPI Devel Maling List, Bjorn Helgaas, LKML,
	Yinghai Lu, Yasuaki Ishimatsu, Jiang Liu

On Mon, 2013-03-25 at 23:29 +0100, Rafael J. Wysocki wrote:
> On Monday, March 25, 2013 02:45:36 PM Toshi Kani wrote:
> > On Fri, 2013-03-15 at 11:47 +0100, Vasilis Liaskovitis wrote:
> > > Hi,
> > > 
> > > On Thu, Mar 14, 2013 at 06:16:30PM +0100, Rafael J. Wysocki wrote:
> > > > Sorry for the sluggish response, I've been travelling recently. ->
> > > [...]
> > > > > > > So, I'd suggest the following changes.
> > > > > > >  - Remove the "uevents" attribute.  KOBJ_ONLINE/OFFLINE are not used for
> > > > > > > ACPI device objects.
> > > > > > >  - Make the !autoeject case as an exception for now, and emit
> > > > > > > KOBJ_OFFLINE as a way to request off-lining to user.  This uevent is
> > > > > > > tied with the !autoeject case.  We can then revisit if this use-case
> > > > > > > needs to be supported going forward.  If so, we may want to consider a
> > > > > > > different event type.
> > > > > > 
> > > > > > Well, what about avoiding to expose uevents and autoeject for now and
> > > > > > exposing enabled only?  Drivers would still be able to set the other flags on
> > > > > > init on init to enforce the backwards-compatible behavior.
> > > > > 
> > > > > Now that we don't define uevents and autoeject in v2 of this series, could you
> > > > > explain how we get safe ejection from userspace e.g. for memory hot-remove? What
> > > > > are the other flags drivers can use (on init?) to avoid autoeject and only issue
> > > > > KOBJ_OFFLINE?
> > > > > 
> > > > > > 
> > > > > > I agree that it would be sufficient to use one additional flag then, to start
> > > > > > with, but its meaning would be something like "keep backwards compatibility
> > > > > > with the old container driver", so perhaps "autoeject" is not a good name.
> > > > > > 
> > > > > > What about "user_eject" (that won't be exposed to user space) instead?  Where,
> > > > > > if set, it would meand "do not autoeject and emit KOBJ_OFFLINE/ONLINE uevents
> > > > > > like the old container driver did"?
> > > > > 
> > > > > I don't see user_eject in v2. Is it unnecessary for userspace ejection control
> > > > > or planned for later? Also why shouldn't it be exposed to userpace?
> > > > 
> > > > -> At this point we are not sure if it is necessary to have an attribute for
> > > > direct ejection control.  Since the plan is to have a separate offline/online
> > > > attribute anyway (and a check preventing us from ejecting things that haven't
> > > > been put offline), it is not clear how useful it is going to be to control
> > > > ejection directly from user space.
> > > 
> > > ok.
> > > Regarding the offline/online attribute and ejection prevention checking, do you
> > > mean the offline/online framework from Toshi:
> > > http://thread.gmane.org/gmane.linux.kernel/1420262
> > > or something else? I assume this is the long-term plan.
> > 
> > Unfortunately, the idea of adding a new set of common hotplug framework
> > was not well-received.  Since the driver-core does not allow any eject
> > failure case, integrating into the driver-core framework seems also
> > impractical.
> > 
> > > Is there any other short-term solution planned? If i understand correctly, until
> > > this framework is accepted, memory hot-remove is broken (=unsafe). 
> > 
> > That is correct.  The alternative plan is to go with an ACPI-specific
> > approach that user has to off-line a target device and its children
> > beforehand from sysfs before initiating a hot-delete request.  This
> > hot-delete request will fail if any of the devices are still on-line.
> > The sysfs online/offline interfaces may fail, and user (or user tool)
> > has to take care of the rollback as necessary.  It would move all the
> > error handling & rollback stuff into the user space, and make the kernel
> > part very simple & straightforward -- just delete target device
> > objects.  
> > 
> > After looking further, however, I think this isn't the case...  In case
> > of memory hot-delete, for example, off-lining is only a part of the job
> > done in remove_memory().  So, ACPI-core still needs to call
> > device-specific handlers to perform device-specific hot-delete
> > operations, such as calling remove_memory() or its sub-set function,
> > which can fail when a device is online.  In order to make sure all
> > devices stay off-line, we need to delete their sysfs interfaces.
> 
> No, we don't need to.
> 
> > Since we do not have a way to serialize all online/offline & hot-plug
> > operations (the above patchset had such serialization, but did not get
> > thru), we cannot change all devices at once but delete sysfs interface
> > for each device one by one.  If it failed on one of the devices, we need
> > to rollback to put them back into the original state.  Other implication
> > is that this approach is not backward compatible.
> 
> No.  No rollbacks, please.
> 
> There are three things that are needed: (1) online/offline, (2) a flag in
> struct acpi_device indicating whether or not the "physical" device represented
> by that struct acpi_device has been offlined, 

acpi_device and its associated device(s) do not match 1 to 1.  For
instance, a memory acpi_device usually associates with multiple memblks
sysfs files, which can be individually on-lined / off-lined.  This
association can be M:N matching.  I am not sure if the flag can be
implemented easily.

> and (3) a synchronization
> mechanism that will make the manipulation of the flag and device eject mutually
> exclusive (it actually would need to tie the manipulation of the flag to
> the online/offline).

This needs to be a global lock that can serialize online/offline
operations of all system devices.

> Then, acpi_scan_hot_remove() will only need to check, before it calls
> acpi_bus_trim(), if all of the devices that correspond to the struct device
> objects to be removed have been offlined.  Of course, it will have to ensure
> that the "online/offline" status of any of those devices won't change while
> it is running (hence, the synchronization mechanism).
> 
> And once everything has been offlined, there's no reason why the removal should
> fail, right?

Yes, if we can introduce such global lock, we can prevent rollbacks.  I
was under an assumption that we cannot make such changes to the common
code.  

> > Given this, I am inclined to other alternative -- rework on my patchset
> > and make it as ACPI device hotplug framework.
> 
> Please don't.

OK, I will keep it myself for now.  Are you going to make the code
changes which you summarized?  I am hoping that we can make some
improvement for 3.10.

Thanks,
-Toshi


^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Update 4][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-03-25 22:57                         ` Toshi Kani
@ 2013-03-26 12:22                           ` Rafael J. Wysocki
  2013-03-26 20:10                             ` Toshi Kani
  0 siblings, 1 reply; 69+ messages in thread
From: Rafael J. Wysocki @ 2013-03-26 12:22 UTC (permalink / raw)
  To: Toshi Kani
  Cc: Vasilis Liaskovitis, ACPI Devel Maling List, Bjorn Helgaas, LKML,
	Yinghai Lu, Yasuaki Ishimatsu, Jiang Liu

On Monday, March 25, 2013 04:57:11 PM Toshi Kani wrote:
> On Mon, 2013-03-25 at 23:29 +0100, Rafael J. Wysocki wrote:
> > On Monday, March 25, 2013 02:45:36 PM Toshi Kani wrote:
> > > On Fri, 2013-03-15 at 11:47 +0100, Vasilis Liaskovitis wrote:
> > > > Hi,
> > > > 
> > > > On Thu, Mar 14, 2013 at 06:16:30PM +0100, Rafael J. Wysocki wrote:
> > > > > Sorry for the sluggish response, I've been travelling recently. ->
> > > > [...]
> > > > > > > > So, I'd suggest the following changes.
> > > > > > > >  - Remove the "uevents" attribute.  KOBJ_ONLINE/OFFLINE are not used for
> > > > > > > > ACPI device objects.
> > > > > > > >  - Make the !autoeject case as an exception for now, and emit
> > > > > > > > KOBJ_OFFLINE as a way to request off-lining to user.  This uevent is
> > > > > > > > tied with the !autoeject case.  We can then revisit if this use-case
> > > > > > > > needs to be supported going forward.  If so, we may want to consider a
> > > > > > > > different event type.
> > > > > > > 
> > > > > > > Well, what about avoiding to expose uevents and autoeject for now and
> > > > > > > exposing enabled only?  Drivers would still be able to set the other flags on
> > > > > > > init on init to enforce the backwards-compatible behavior.
> > > > > > 
> > > > > > Now that we don't define uevents and autoeject in v2 of this series, could you
> > > > > > explain how we get safe ejection from userspace e.g. for memory hot-remove? What
> > > > > > are the other flags drivers can use (on init?) to avoid autoeject and only issue
> > > > > > KOBJ_OFFLINE?
> > > > > > 
> > > > > > > 
> > > > > > > I agree that it would be sufficient to use one additional flag then, to start
> > > > > > > with, but its meaning would be something like "keep backwards compatibility
> > > > > > > with the old container driver", so perhaps "autoeject" is not a good name.
> > > > > > > 
> > > > > > > What about "user_eject" (that won't be exposed to user space) instead?  Where,
> > > > > > > if set, it would meand "do not autoeject and emit KOBJ_OFFLINE/ONLINE uevents
> > > > > > > like the old container driver did"?
> > > > > > 
> > > > > > I don't see user_eject in v2. Is it unnecessary for userspace ejection control
> > > > > > or planned for later? Also why shouldn't it be exposed to userpace?
> > > > > 
> > > > > -> At this point we are not sure if it is necessary to have an attribute for
> > > > > direct ejection control.  Since the plan is to have a separate offline/online
> > > > > attribute anyway (and a check preventing us from ejecting things that haven't
> > > > > been put offline), it is not clear how useful it is going to be to control
> > > > > ejection directly from user space.
> > > > 
> > > > ok.
> > > > Regarding the offline/online attribute and ejection prevention checking, do you
> > > > mean the offline/online framework from Toshi:
> > > > http://thread.gmane.org/gmane.linux.kernel/1420262
> > > > or something else? I assume this is the long-term plan.
> > > 
> > > Unfortunately, the idea of adding a new set of common hotplug framework
> > > was not well-received.  Since the driver-core does not allow any eject
> > > failure case, integrating into the driver-core framework seems also
> > > impractical.
> > > 
> > > > Is there any other short-term solution planned? If i understand correctly, until
> > > > this framework is accepted, memory hot-remove is broken (=unsafe). 
> > > 
> > > That is correct.  The alternative plan is to go with an ACPI-specific
> > > approach that user has to off-line a target device and its children
> > > beforehand from sysfs before initiating a hot-delete request.  This
> > > hot-delete request will fail if any of the devices are still on-line.
> > > The sysfs online/offline interfaces may fail, and user (or user tool)
> > > has to take care of the rollback as necessary.  It would move all the
> > > error handling & rollback stuff into the user space, and make the kernel
> > > part very simple & straightforward -- just delete target device
> > > objects.  
> > > 
> > > After looking further, however, I think this isn't the case...  In case
> > > of memory hot-delete, for example, off-lining is only a part of the job
> > > done in remove_memory().  So, ACPI-core still needs to call
> > > device-specific handlers to perform device-specific hot-delete
> > > operations, such as calling remove_memory() or its sub-set function,
> > > which can fail when a device is online.  In order to make sure all
> > > devices stay off-line, we need to delete their sysfs interfaces.
> > 
> > No, we don't need to.
> > 
> > > Since we do not have a way to serialize all online/offline & hot-plug
> > > operations (the above patchset had such serialization, but did not get
> > > thru), we cannot change all devices at once but delete sysfs interface
> > > for each device one by one.  If it failed on one of the devices, we need
> > > to rollback to put them back into the original state.  Other implication
> > > is that this approach is not backward compatible.
> > 
> > No.  No rollbacks, please.
> > 
> > There are three things that are needed: (1) online/offline, (2) a flag in
> > struct acpi_device indicating whether or not the "physical" device represented
> > by that struct acpi_device has been offlined, 
> 
> acpi_device and its associated device(s) do not match 1 to 1.  For
> instance, a memory acpi_device usually associates with multiple memblks
> sysfs files, which can be individually on-lined / off-lined.  This
> association can be M:N matching.  I am not sure if the flag can be
> implemented easily.

If there are more "physical devices" associated with a single struct
acpi_device (which is entirely possible), then that needs to be a counter
rather than a flag.

> > and (3) a synchronization
> > mechanism that will make the manipulation of the flag and device eject mutually
> > exclusive (it actually would need to tie the manipulation of the flag to
> > the online/offline).
> 
> This needs to be a global lock that can serialize online/offline
> operations of all system devices.

Yes, it does, but we already have acpi_scan_lock that serializes all hotplug
operations on the ACPI level, so it won't add much overhead.  And as far as
memory is concerned, I really think it would be better not to offline two
things at a time anyway.

> > Then, acpi_scan_hot_remove() will only need to check, before it calls
> > acpi_bus_trim(), if all of the devices that correspond to the struct device
> > objects to be removed have been offlined.  Of course, it will have to ensure
> > that the "online/offline" status of any of those devices won't change while
> > it is running (hence, the synchronization mechanism).
> > 
> > And once everything has been offlined, there's no reason why the removal should
> > fail, right?
> 
> Yes, if we can introduce such global lock, we can prevent rollbacks.  I
> was under an assumption that we cannot make such changes to the common
> code.  

I believe we can add such a lock of online/offline operations.

> > > Given this, I am inclined to other alternative -- rework on my patchset
> > > and make it as ACPI device hotplug framework.
> > 
> > Please don't.
> 
> OK, I will keep it myself for now.  Are you going to make the code
> changes which you summarized?  I am hoping that we can make some
> improvement for 3.10.

Well, for now memory offline/online is missing and that's needed in the first
place regardless.  I'm not sure if I have the time to add it on time for the
v3.10 merge window, however, because I have two conferences to attend in the
meantime (where I'm going to speak) and some power management work to do.

Thanks,
Rafael


-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Update 4][PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug
  2013-03-26 12:22                           ` Rafael J. Wysocki
@ 2013-03-26 20:10                             ` Toshi Kani
  0 siblings, 0 replies; 69+ messages in thread
From: Toshi Kani @ 2013-03-26 20:10 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Vasilis Liaskovitis, ACPI Devel Maling List, Bjorn Helgaas, LKML,
	Yinghai Lu, Yasuaki Ishimatsu, Jiang Liu

On Tue, 2013-03-26 at 13:22 +0100, Rafael J. Wysocki wrote:
> On Monday, March 25, 2013 04:57:11 PM Toshi Kani wrote:
> > On Mon, 2013-03-25 at 23:29 +0100, Rafael J. Wysocki wrote:
> > > On Monday, March 25, 2013 02:45:36 PM Toshi Kani wrote:
> > > > On Fri, 2013-03-15 at 11:47 +0100, Vasilis Liaskovitis wrote:
> > > > > Hi,
> > > > > 
> > > > > On Thu, Mar 14, 2013 at 06:16:30PM +0100, Rafael J. Wysocki wrote:
> > > > > > Sorry for the sluggish response, I've been travelling recently. ->
> > > > > [...]
> > > > > > > > > So, I'd suggest the following changes.
> > > > > > > > >  - Remove the "uevents" attribute.  KOBJ_ONLINE/OFFLINE are not used for
> > > > > > > > > ACPI device objects.
> > > > > > > > >  - Make the !autoeject case as an exception for now, and emit
> > > > > > > > > KOBJ_OFFLINE as a way to request off-lining to user.  This uevent is
> > > > > > > > > tied with the !autoeject case.  We can then revisit if this use-case
> > > > > > > > > needs to be supported going forward.  If so, we may want to consider a
> > > > > > > > > different event type.
> > > > > > > > 
> > > > > > > > Well, what about avoiding to expose uevents and autoeject for now and
> > > > > > > > exposing enabled only?  Drivers would still be able to set the other flags on
> > > > > > > > init on init to enforce the backwards-compatible behavior.
> > > > > > > 
> > > > > > > Now that we don't define uevents and autoeject in v2 of this series, could you
> > > > > > > explain how we get safe ejection from userspace e.g. for memory hot-remove? What
> > > > > > > are the other flags drivers can use (on init?) to avoid autoeject and only issue
> > > > > > > KOBJ_OFFLINE?
> > > > > > > 
> > > > > > > > 
> > > > > > > > I agree that it would be sufficient to use one additional flag then, to start
> > > > > > > > with, but its meaning would be something like "keep backwards compatibility
> > > > > > > > with the old container driver", so perhaps "autoeject" is not a good name.
> > > > > > > > 
> > > > > > > > What about "user_eject" (that won't be exposed to user space) instead?  Where,
> > > > > > > > if set, it would meand "do not autoeject and emit KOBJ_OFFLINE/ONLINE uevents
> > > > > > > > like the old container driver did"?
> > > > > > > 
> > > > > > > I don't see user_eject in v2. Is it unnecessary for userspace ejection control
> > > > > > > or planned for later? Also why shouldn't it be exposed to userpace?
> > > > > > 
> > > > > > -> At this point we are not sure if it is necessary to have an attribute for
> > > > > > direct ejection control.  Since the plan is to have a separate offline/online
> > > > > > attribute anyway (and a check preventing us from ejecting things that haven't
> > > > > > been put offline), it is not clear how useful it is going to be to control
> > > > > > ejection directly from user space.
> > > > > 
> > > > > ok.
> > > > > Regarding the offline/online attribute and ejection prevention checking, do you
> > > > > mean the offline/online framework from Toshi:
> > > > > http://thread.gmane.org/gmane.linux.kernel/1420262
> > > > > or something else? I assume this is the long-term plan.
> > > > 
> > > > Unfortunately, the idea of adding a new set of common hotplug framework
> > > > was not well-received.  Since the driver-core does not allow any eject
> > > > failure case, integrating into the driver-core framework seems also
> > > > impractical.
> > > > 
> > > > > Is there any other short-term solution planned? If i understand correctly, until
> > > > > this framework is accepted, memory hot-remove is broken (=unsafe). 
> > > > 
> > > > That is correct.  The alternative plan is to go with an ACPI-specific
> > > > approach that user has to off-line a target device and its children
> > > > beforehand from sysfs before initiating a hot-delete request.  This
> > > > hot-delete request will fail if any of the devices are still on-line.
> > > > The sysfs online/offline interfaces may fail, and user (or user tool)
> > > > has to take care of the rollback as necessary.  It would move all the
> > > > error handling & rollback stuff into the user space, and make the kernel
> > > > part very simple & straightforward -- just delete target device
> > > > objects.  
> > > > 
> > > > After looking further, however, I think this isn't the case...  In case
> > > > of memory hot-delete, for example, off-lining is only a part of the job
> > > > done in remove_memory().  So, ACPI-core still needs to call
> > > > device-specific handlers to perform device-specific hot-delete
> > > > operations, such as calling remove_memory() or its sub-set function,
> > > > which can fail when a device is online.  In order to make sure all
> > > > devices stay off-line, we need to delete their sysfs interfaces.
> > > 
> > > No, we don't need to.
> > > 
> > > > Since we do not have a way to serialize all online/offline & hot-plug
> > > > operations (the above patchset had such serialization, but did not get
> > > > thru), we cannot change all devices at once but delete sysfs interface
> > > > for each device one by one.  If it failed on one of the devices, we need
> > > > to rollback to put them back into the original state.  Other implication
> > > > is that this approach is not backward compatible.
> > > 
> > > No.  No rollbacks, please.
> > > 
> > > There are three things that are needed: (1) online/offline, (2) a flag in
> > > struct acpi_device indicating whether or not the "physical" device represented
> > > by that struct acpi_device has been offlined, 
> > 
> > acpi_device and its associated device(s) do not match 1 to 1.  For
> > instance, a memory acpi_device usually associates with multiple memblks
> > sysfs files, which can be individually on-lined / off-lined.  This
> > association can be M:N matching.  I am not sure if the flag can be
> > implemented easily.
> 
> If there are more "physical devices" associated with a single struct
> acpi_device (which is entirely possible), then that needs to be a counter
> rather than a flag.

Right.

> > > and (3) a synchronization
> > > mechanism that will make the manipulation of the flag and device eject mutually
> > > exclusive (it actually would need to tie the manipulation of the flag to
> > > the online/offline).
> > 
> > This needs to be a global lock that can serialize online/offline
> > operations of all system devices.
> 
> Yes, it does, but we already have acpi_scan_lock that serializes all hotplug
> operations on the ACPI level, so it won't add much overhead.  And as far as
> memory is concerned, I really think it would be better not to offline two
> things at a time anyway.

I agree.  I actually tried to introduce such serialization in my former
patchset.

> > > Then, acpi_scan_hot_remove() will only need to check, before it calls
> > > acpi_bus_trim(), if all of the devices that correspond to the struct device
> > > objects to be removed have been offlined.  Of course, it will have to ensure
> > > that the "online/offline" status of any of those devices won't change while
> > > it is running (hence, the synchronization mechanism).
> > > 
> > > And once everything has been offlined, there's no reason why the removal should
> > > fail, right?
> > 
> > Yes, if we can introduce such global lock, we can prevent rollbacks.  I
> > was under an assumption that we cannot make such changes to the common
> > code.  
> 
> I believe we can add such a lock of online/offline operations.

That's great.

> > > > Given this, I am inclined to other alternative -- rework on my patchset
> > > > and make it as ACPI device hotplug framework.
> > > 
> > > Please don't.
> > 
> > OK, I will keep it myself for now.  Are you going to make the code
> > changes which you summarized?  I am hoping that we can make some
> > improvement for 3.10.
> 
> Well, for now memory offline/online is missing and that's needed in the first
> place regardless.  

Memory offline/online is already in-place through the memblk interface,
i.e. /sys/devices/system/memory/memoryN.  This is the one my other patch
created symbolic links to.

> I'm not sure if I have the time to add it on time for the
> v3.10 merge window, however, because I have two conferences to attend in the
> meantime (where I'm going to speak) and some power management work to do.

Understood.  I was just checking if you had already planed to do so.  I
will look further to see if I can be any help.

Thanks,
-Toshi



^ permalink raw reply	[flat|nested] 69+ messages in thread

end of thread, other threads:[~2013-03-26 20:22 UTC | newest]

Thread overview: 69+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-02-17 15:18 [PATCH 0/7] ACPI / hotplug: Common code for ACPI-based hotplug Rafael J. Wysocki
2013-02-17 15:20 ` [PATCH 1/7] ACPI / scan: Introduce acpi_scan_match_handler() Rafael J. Wysocki
2013-02-19  6:48   ` Yasuaki Ishimatsu
2013-02-17 15:21 ` [PATCH 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug Rafael J. Wysocki
2013-02-19  6:43   ` Yasuaki Ishimatsu
2013-02-19  7:10     ` Yasuaki Ishimatsu
2013-02-20 13:27       ` Rafael J. Wysocki
2013-02-20 13:23     ` Rafael J. Wysocki
2013-02-20 20:23       ` Toshi Kani
2013-02-20 21:17         ` Rafael J. Wysocki
2013-02-20 22:49   ` [Update][PATCH " Rafael J. Wysocki
2013-02-21  1:17     ` Toshi Kani
2013-02-21 15:44       ` Rafael J. Wysocki
2013-02-21 15:52     ` [Update 2][PATCH " Rafael J. Wysocki
2013-02-21 17:39       ` Toshi Kani
2013-02-21 22:57         ` Rafael J. Wysocki
2013-02-21 23:06       ` [Update 3][PATCH " Rafael J. Wysocki
2013-02-22  1:12         ` Toshi Kani
2013-02-22  1:50           ` Rafael J. Wysocki
2013-02-22  8:51             ` Yasuaki Ishimatsu
2013-02-22 12:37               ` Rafael J. Wysocki
2013-02-22 15:54                 ` Toshi Kani
2013-02-22 20:59                   ` Rafael J. Wysocki
2013-02-23 22:38         ` [Update 4][PATCH " Rafael J. Wysocki
2013-02-25 18:07           ` Toshi Kani
2013-02-25 23:39             ` Rafael J. Wysocki
2013-02-25 23:32               ` Toshi Kani
2013-02-26  0:40               ` Yasuaki Ishimatsu
2013-02-26  1:09                 ` Toshi Kani
2013-02-26  2:02                   ` Yasuaki Ishimatsu
2013-02-26  3:11                     ` Rafael J. Wysocki
2013-02-26  3:40                       ` Yasuaki Ishimatsu
2013-02-26  3:50                         ` Rafael J. Wysocki
2013-03-04 13:10               ` Vasilis Liaskovitis
2013-03-14 17:16                 ` Rafael J. Wysocki
2013-03-15 10:47                   ` Vasilis Liaskovitis
2013-03-25 20:45                     ` Toshi Kani
2013-03-25 22:29                       ` Rafael J. Wysocki
2013-03-25 22:57                         ` Toshi Kani
2013-03-26 12:22                           ` Rafael J. Wysocki
2013-03-26 20:10                             ` Toshi Kani
2013-02-17 15:22 ` [PATCH 3/7] ACPI / container: Use common hotplug code Rafael J. Wysocki
2013-02-17 15:23 ` [PATCH 4/7] ACPI / scan: Introduce acpi_scan_handler_matching() Rafael J. Wysocki
2013-02-19  8:05   ` Yasuaki Ishimatsu
2013-02-17 15:24 ` [PATCH 5/7] ACPI / hotplug: Introduce user space interface for hotplug profiles Rafael J. Wysocki
2013-02-25 18:13   ` Toshi Kani
2013-02-25 23:25     ` Rafael J. Wysocki
2013-02-17 15:25 ` [PATCH 6/7] ACPI / container: Use hotplug profile user space interface Rafael J. Wysocki
2013-02-17 15:27 ` [PATCH 7/7] ACPI / scan: Make memory hotplug driver use struct acpi_scan_handler Rafael J. Wysocki
2013-02-19 18:11   ` Vasilis Liaskovitis
2013-02-20  3:35     ` Yasuaki Ishimatsu
2013-02-20 10:42       ` Vasilis Liaskovitis
2013-02-20 21:50         ` Toshi Kani
2013-02-20 22:29           ` Rafael J. Wysocki
2013-02-20 22:39             ` Toshi Kani
2013-02-21  6:58         ` Yasuaki Ishimatsu
2013-02-26 22:41 ` [PATCH v2, 0/7] ACPI / hotplug: Common code for ACPI-based hotplug Rafael J. Wysocki
2013-02-26 22:44   ` [PATCH v2, 1/7] ACPI / scan: Introduce acpi_scan_match_handler() Rafael J. Wysocki
2013-02-26 22:46   ` [PATCH v2, 2/7] ACPI / scan: Introduce common code for ACPI-based device hotplug Rafael J. Wysocki
2013-02-26 22:46   ` [PATCH v2, 3/7] ACPI / container: Use common hotplug code Rafael J. Wysocki
2013-02-26 23:13     ` Toshi Kani
2013-02-26 23:13       ` Toshi Kani
2013-02-27  0:06       ` Rafael J. Wysocki
2013-02-27  0:09     ` [Update][PATCH " Rafael J. Wysocki
2013-02-26 22:47   ` [PATCH v2, 4/7] ACPI / scan: Introduce acpi_scan_handler_matching() Rafael J. Wysocki
2013-02-26 22:48   ` [PATCH v2, 5/7] ACPI / hotplug: Introduce user space interface for hotplug profiles Rafael J. Wysocki
2013-02-26 22:49   ` [PATCH v2, 6/7] ACPI / container: Use hotplug profile user space interface Rafael J. Wysocki
2013-02-26 22:50   ` [PATCH v2, 7/7] ACPI / scan: Make memory hotplug driver use struct acpi_scan_handler Rafael J. Wysocki
2013-02-27  0:51   ` [PATCH v2, 0/7] ACPI / hotplug: Common code for ACPI-based hotplug Toshi Kani

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.