[PATCH v2 3/6] ACPI / hotplug / PCI: Consolidate ACPIPHP with ACPI core hotplug

2014-02-01 Thread Rafael J. Wysocki
From: Rafael J. Wysocki 

The ACPI-based PCI hotplug (ACPIPHP) code currently attaches its
hotplug context objects directly to ACPI namespace nodes representing
hotplug devices.  However, after recent changes causing struct
acpi_device to be created for every namespace node representing a
device (regardless of its status), that is not necessary any more.
Moreover, it's vulnerable to a theoretical issue that the ACPI
handle passed in the context between handle_hotplug_event() and
hotplug_event_work() may become invalid in the meantime (as a
result of a concurrent table unload).

In principle, this issue might be addressed by adding a non-empty
release handler for ACPIPHP hotplug context objects analogous to
acpi_scan_drop_device(), but that would duplicate the code in that
function and in acpi_device_del_work_fn().  For this reason, it's
better to modify ACPIPHP to attach its device hotplug contexts to
struct device objects representing hotplug devices and make it
use acpi_hotplug_notify_cb() as its notify handler.  At the same
time, acpi_device_hotplug() can be modified to dispatch the new
.hp.event() callback pointing to acpiphp_hotplug_event() from ACPI
device objects associated with PCI devices and use the generic
ACPI device hotplug code for device objects with scan handlers
attached to them.

This allows the existing code duplication between ACPIPHP and the
ACPI core to be reduced too and makes further ACPI-based device
hotplug consolidation possible.

Signed-off-by: Rafael J. Wysocki 
---
 drivers/acpi/scan.c|  106 +---
 drivers/pci/hotplug/acpiphp.h  |9 +-
 drivers/pci/hotplug/acpiphp_glue.c |  136 +++--
 include/acpi/acpi_bus.h|   22 +
 4 files changed, 136 insertions(+), 137 deletions(-)

Index: linux-pm/drivers/acpi/scan.c
===
--- linux-pm.orig/drivers/acpi/scan.c
+++ linux-pm/drivers/acpi/scan.c
@@ -452,43 +452,61 @@ static int acpi_scan_bus_check(struct ac
return 0;
 }
 
+static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type)
+{
+   switch (type) {
+   case ACPI_NOTIFY_BUS_CHECK:
+   return acpi_scan_bus_check(adev);
+   case ACPI_NOTIFY_DEVICE_CHECK:
+   return acpi_scan_device_check(adev);
+   case ACPI_NOTIFY_EJECT_REQUEST:
+   case ACPI_OST_EC_OSPM_EJECT:
+   return acpi_scan_hot_remove(adev);
+   }
+   return -EINVAL;
+}
+
 static void acpi_device_hotplug(void *data, u32 src)
 {
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
struct acpi_device *adev = data;
-   int error;
+   int error = -ENODEV;
 
lock_device_hotplug();
mutex_lock(_scan_lock);
 
/*
 * The device object's ACPI handle cannot become invalid as long as we
-* are holding acpi_scan_lock, but it may have become invalid before
+* are holding acpi_scan_lock, but it might have become invalid before
 * that lock was acquired.
 */
if (adev->handle == INVALID_ACPI_HANDLE)
-   goto out;
+   goto err_out;
 
-   switch (src) {
-   case ACPI_NOTIFY_BUS_CHECK:
-   error = acpi_scan_bus_check(adev);
-   break;
-   case ACPI_NOTIFY_DEVICE_CHECK:
-   error = acpi_scan_device_check(adev);
-   break;
-   case ACPI_NOTIFY_EJECT_REQUEST:
-   case ACPI_OST_EC_OSPM_EJECT:
-   error = acpi_scan_hot_remove(adev);
-   break;
-   default:
-   error = -EINVAL;
-   break;
+   if (adev->handler) {
+   error = acpi_generic_hotplug_event(adev, src);
+   } else {
+   int (*event)(struct acpi_device *, u32);
+
+   acpi_lock_hp_context();
+   event = adev->hp ? adev->hp->event : NULL;
+   acpi_unlock_hp_context();
+   /*
+* There may be additional notify handlers for device objects
+* without the .event() callback, so ignore them here.
+*/
+   if (event)
+   error = event(adev, src);
+   else
+   goto out;
}
if (!error)
ost_code = ACPI_OST_SC_SUCCESS;
 
- out:
+ err_out:
acpi_evaluate_hotplug_ost(adev->handle, src, ost_code, NULL);
+
+ out:
put_device(>dev);
mutex_unlock(_scan_lock);
unlock_device_hotplug();
@@ -496,8 +514,8 @@ static void acpi_device_hotplug(void *da
 
 static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data)
 {
-   u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
struct acpi_scan_handler *handler = data;
+   u32 ost_code = ACPI_OST_SC_SUCCESS;
struct acpi_device *adev;
acpi_status status;
 
@@ -505,27 +523,50 @@ static void acpi_hotplug_notify_cb(acpi_
   

[PATCH v2 3/6] ACPI / hotplug / PCI: Consolidate ACPIPHP with ACPI core hotplug

2014-02-01 Thread Rafael J. Wysocki
From: Rafael J. Wysocki rafael.j.wyso...@intel.com

The ACPI-based PCI hotplug (ACPIPHP) code currently attaches its
hotplug context objects directly to ACPI namespace nodes representing
hotplug devices.  However, after recent changes causing struct
acpi_device to be created for every namespace node representing a
device (regardless of its status), that is not necessary any more.
Moreover, it's vulnerable to a theoretical issue that the ACPI
handle passed in the context between handle_hotplug_event() and
hotplug_event_work() may become invalid in the meantime (as a
result of a concurrent table unload).

In principle, this issue might be addressed by adding a non-empty
release handler for ACPIPHP hotplug context objects analogous to
acpi_scan_drop_device(), but that would duplicate the code in that
function and in acpi_device_del_work_fn().  For this reason, it's
better to modify ACPIPHP to attach its device hotplug contexts to
struct device objects representing hotplug devices and make it
use acpi_hotplug_notify_cb() as its notify handler.  At the same
time, acpi_device_hotplug() can be modified to dispatch the new
.hp.event() callback pointing to acpiphp_hotplug_event() from ACPI
device objects associated with PCI devices and use the generic
ACPI device hotplug code for device objects with scan handlers
attached to them.

This allows the existing code duplication between ACPIPHP and the
ACPI core to be reduced too and makes further ACPI-based device
hotplug consolidation possible.

Signed-off-by: Rafael J. Wysocki rafael.j.wyso...@intel.com
---
 drivers/acpi/scan.c|  106 +---
 drivers/pci/hotplug/acpiphp.h  |9 +-
 drivers/pci/hotplug/acpiphp_glue.c |  136 +++--
 include/acpi/acpi_bus.h|   22 +
 4 files changed, 136 insertions(+), 137 deletions(-)

Index: linux-pm/drivers/acpi/scan.c
===
--- linux-pm.orig/drivers/acpi/scan.c
+++ linux-pm/drivers/acpi/scan.c
@@ -452,43 +452,61 @@ static int acpi_scan_bus_check(struct ac
return 0;
 }
 
+static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type)
+{
+   switch (type) {
+   case ACPI_NOTIFY_BUS_CHECK:
+   return acpi_scan_bus_check(adev);
+   case ACPI_NOTIFY_DEVICE_CHECK:
+   return acpi_scan_device_check(adev);
+   case ACPI_NOTIFY_EJECT_REQUEST:
+   case ACPI_OST_EC_OSPM_EJECT:
+   return acpi_scan_hot_remove(adev);
+   }
+   return -EINVAL;
+}
+
 static void acpi_device_hotplug(void *data, u32 src)
 {
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
struct acpi_device *adev = data;
-   int error;
+   int error = -ENODEV;
 
lock_device_hotplug();
mutex_lock(acpi_scan_lock);
 
/*
 * The device object's ACPI handle cannot become invalid as long as we
-* are holding acpi_scan_lock, but it may have become invalid before
+* are holding acpi_scan_lock, but it might have become invalid before
 * that lock was acquired.
 */
if (adev-handle == INVALID_ACPI_HANDLE)
-   goto out;
+   goto err_out;
 
-   switch (src) {
-   case ACPI_NOTIFY_BUS_CHECK:
-   error = acpi_scan_bus_check(adev);
-   break;
-   case ACPI_NOTIFY_DEVICE_CHECK:
-   error = acpi_scan_device_check(adev);
-   break;
-   case ACPI_NOTIFY_EJECT_REQUEST:
-   case ACPI_OST_EC_OSPM_EJECT:
-   error = acpi_scan_hot_remove(adev);
-   break;
-   default:
-   error = -EINVAL;
-   break;
+   if (adev-handler) {
+   error = acpi_generic_hotplug_event(adev, src);
+   } else {
+   int (*event)(struct acpi_device *, u32);
+
+   acpi_lock_hp_context();
+   event = adev-hp ? adev-hp-event : NULL;
+   acpi_unlock_hp_context();
+   /*
+* There may be additional notify handlers for device objects
+* without the .event() callback, so ignore them here.
+*/
+   if (event)
+   error = event(adev, src);
+   else
+   goto out;
}
if (!error)
ost_code = ACPI_OST_SC_SUCCESS;
 
- out:
+ err_out:
acpi_evaluate_hotplug_ost(adev-handle, src, ost_code, NULL);
+
+ out:
put_device(adev-dev);
mutex_unlock(acpi_scan_lock);
unlock_device_hotplug();
@@ -496,8 +514,8 @@ static void acpi_device_hotplug(void *da
 
 static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data)
 {
-   u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
struct acpi_scan_handler *handler = data;
+   u32 ost_code = ACPI_OST_SC_SUCCESS;
struct acpi_device *adev;
acpi_status status;
 
@@