[PATCH 3/5][RFT] ACPI / hotplug / PCI: Consolidate ACPIPHP with ACPI core hotplug

From: Rafael J. Wysocki
Date: Tue Jan 28 2014 - 17:06:22 EST


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

Use the same ACPI notify handler, acpi_hotplug_notify_cb() for both
ACPI-based PCI hotplug (ACPIPHP) and the generic ACPI-based hotplug
of devices. For PCI devices use the .hp.event() callback from
their ACPI companions that points to acpiphp_hotplug_event().
For other devices (CPU, memory, containers, PCI host bridges) the
generic ACPI-based device hotplug code is used.

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

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx>
---
drivers/acpi/scan.c | 85 ++++++++++++++++++----------
drivers/pci/hotplug/acpiphp_glue.c | 110 +++----------------------------------
include/acpi/acpi_bus.h | 1
3 files changed, 66 insertions(+), 130 deletions(-)

Index: linux-pm/include/acpi/acpi_bus.h
===================================================================
--- linux-pm.orig/include/acpi/acpi_bus.h
+++ linux-pm/include/acpi/acpi_bus.h
@@ -145,6 +145,7 @@ struct acpi_scan_handler {

struct acpi_hotplug_context {
struct acpi_device *self;
+ int (*event)(struct acpi_device *, u32);
void (*release)(struct acpi_hotplug_context *);
};

Index: linux-pm/drivers/acpi/scan.c
===================================================================
--- linux-pm.orig/drivers/acpi/scan.c
+++ linux-pm/drivers/acpi/scan.c
@@ -439,40 +439,44 @@ 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;
+ u32 ost_code = ACPI_OST_SC_SUCCESS;
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;

- 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 (!error)
- ost_code = ACPI_OST_SC_SUCCESS;
+ if (adev->handler)
+ error = acpi_generic_hotplug_event(adev, src);
+ else if (adev->hp && adev->hp->event)
+ error = adev->hp->event(adev, src);
+
+ if (error)
+ ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;

out:
acpi_evaluate_hotplug_ost(adev->handle, src, ost_code, NULL);
@@ -483,35 +487,58 @@ 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;

- if (acpi_bus_get_device(handle, &adev))
- goto err_out;
-
switch (type) {
case ACPI_NOTIFY_BUS_CHECK:
acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
break;
+
case ACPI_NOTIFY_DEVICE_CHECK:
acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
break;
+
case ACPI_NOTIFY_EJECT_REQUEST:
acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
- if (!handler->hotplug.enabled) {
+ if (handler && !handler->hotplug.enabled) {
acpi_handle_err(handle, "Eject disabled\n");
ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
- goto err_out;
+ goto out;
}
acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
break;
- default:
- /* non-hotplug event; possibly handled by other handler */
+
+ case ACPI_NOTIFY_DEVICE_WAKE:
return;
+
+ case ACPI_NOTIFY_FREQUENCY_MISMATCH:
+ acpi_handle_err(handle, "Device cannot be configured due "
+ "to a frequency mismatch\n");
+ goto out;
+
+ case ACPI_NOTIFY_BUS_MODE_MISMATCH:
+ acpi_handle_err(handle, "Device cannot be configured due "
+ "to a bus mode mismatch\n");
+ goto out;
+
+ case ACPI_NOTIFY_POWER_FAULT:
+ acpi_handle_err(handle, "Device has suffered a power fault\n");
+ goto out;
+
+ default:
+ acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type);
+ ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY;
+ goto out;
}
+
+ ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
+ if (acpi_bus_get_device(handle, &adev))
+ goto out;
+
get_device(&adev->dev);
status = acpi_hotplug_execute(acpi_device_hotplug, adev, type);
if (ACPI_SUCCESS(status))
@@ -519,7 +546,7 @@ static void acpi_hotplug_notify_cb(acpi_

put_device(&adev->dev);

- err_out:
+ out:
acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
}

Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c
+++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c
@@ -53,18 +53,14 @@
#include <linux/slab.h>
#include <linux/acpi.h>

-#include <asm/pgtable.h>
-
#include "../pci.h"
#include "acpiphp.h"

-#define INVALID_ACPI_HANDLE ((acpi_handle)empty_zero_page)
-
static LIST_HEAD(bridge_list);
static DEFINE_MUTEX(bridge_mutex);
static DEFINE_MUTEX(acpiphp_context_lock);

-static void handle_hotplug_event(acpi_handle handle, u32 type, void *data);
+static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type);
static void acpiphp_sanitize_bus(struct pci_bus *bus);
static void acpiphp_set_hpp_values(struct pci_bus *bus);
static void hotplug_event(u32 type, void *data);
@@ -91,6 +87,7 @@ static struct acpiphp_context *acpiphp_i

context->hp.self = adev;
context->hp.release = acpiphp_free_context;
+ context->hp.event = acpiphp_hotplug_event;
context->refcount = 1;
adev->hp = &context->hp;
return context;
@@ -373,14 +370,8 @@ static acpi_status register_slot(acpi_ha
}

/* install notify handler */
- if (!(newfunc->flags & FUNC_HAS_DCK)) {
- status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
- handle_hotplug_event,
- context);
- if (ACPI_FAILURE(status))
- acpi_handle_err(handle,
- "failed to install notify handler\n");
- }
+ if (!(newfunc->flags & FUNC_HAS_DCK))
+ acpi_install_hotplug_notify_handler(handle, NULL);

return AE_OK;
}
@@ -411,7 +402,6 @@ static void cleanup_bridge(struct acpiph
{
struct acpiphp_slot *slot;
struct acpiphp_func *func;
- acpi_status status;

list_for_each_entry(slot, &bridge->slots, node) {
list_for_each_entry(func, &slot->funcs, sibling) {
@@ -420,13 +410,8 @@ static void cleanup_bridge(struct acpiph
if (is_dock_device(handle))
unregister_hotplug_dock_device(handle);

- if (!(func->flags & FUNC_HAS_DCK)) {
- status = acpi_remove_notify_handler(handle,
- ACPI_SYSTEM_NOTIFY,
- handle_hotplug_event);
- if (ACPI_FAILURE(status))
- pr_err("failed to remove notify handler\n");
- }
+ if (!(func->flags & FUNC_HAS_DCK))
+ acpi_remove_hotplug_notify_handler(handle);
}
slot->flags |= SLOT_IS_GOING_AWAY;
if (slot->slot)
@@ -838,26 +823,15 @@ static void hotplug_event(u32 type, void
put_bridge(bridge);
}

-static void hotplug_event_work(void *data, u32 type)
+static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type)
{
- struct acpi_device *adev = data;
struct acpiphp_context *context;
- u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
-
- acpi_scan_lock_acquire();
- /*
- * The device object's ACPI handle cannot become invalid as long as we
- * are holding acpi_scan_lock, but it might have become invalid before
- * that lock was acquired.
- */
- if (adev->handle == INVALID_ACPI_HANDLE)
- goto out;

mutex_lock(&acpiphp_context_lock);
context = acpiphp_get_context(adev);
if (!context) {
mutex_unlock(&acpiphp_context_lock);
- goto out;
+ return -ENODATA;
}
get_bridge(context->func.parent);
acpiphp_put_context(context);
@@ -867,73 +841,7 @@ static void hotplug_event_work(void *dat
hotplug_event(type, context);
pci_unlock_rescan_remove();
put_bridge(context->func.parent);
- ost_code = ACPI_OST_SC_SUCCESS;
-
- out:
- acpi_evaluate_hotplug_ost(adev->handle, type, ost_code, NULL);
- put_device(&adev->dev);
- acpi_scan_lock_release();
-}
-
-/**
- * handle_hotplug_event - handle ACPI hotplug event
- * @handle: Notify()'ed acpi_handle
- * @type: Notify code
- * @data: pointer to acpiphp_context structure
- *
- * Handles ACPI event notification on slots.
- */
-static void handle_hotplug_event(acpi_handle handle, u32 type, void *data)
-{
- struct acpi_device *adev;
- acpi_status status;
- u32 ost_code = ACPI_OST_SC_SUCCESS;
-
- switch (type) {
- case ACPI_NOTIFY_BUS_CHECK:
- case ACPI_NOTIFY_DEVICE_CHECK:
- break;
- case ACPI_NOTIFY_EJECT_REQUEST:
- ost_code = ACPI_OST_SC_EJECT_IN_PROGRESS;
- acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
- break;
-
- case ACPI_NOTIFY_DEVICE_WAKE:
- return;
-
- case ACPI_NOTIFY_FREQUENCY_MISMATCH:
- acpi_handle_err(handle, "Device cannot be configured due "
- "to a frequency mismatch\n");
- goto out;
-
- case ACPI_NOTIFY_BUS_MODE_MISMATCH:
- acpi_handle_err(handle, "Device cannot be configured due "
- "to a bus mode mismatch\n");
- goto out;
-
- case ACPI_NOTIFY_POWER_FAULT:
- acpi_handle_err(handle, "Device has suffered a power fault\n");
- goto out;
-
- default:
- acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type);
- ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY;
- goto out;
- }
-
- ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
- if (acpi_bus_get_device(handle, &adev))
- goto out;
-
- get_device(&adev->dev);
- status = acpi_hotplug_execute(hotplug_event_work, adev, type);
- if (ACPI_SUCCESS(status))
- return;
-
- put_device(&adev->dev);
-
- out:
- acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
+ return 0;
}

/**

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/