* [PATCH 0/2] PCI / ACPI cleanups
@ 2013-07-07 23:15 Rafael J. Wysocki
2013-07-07 23:17 ` [PATCH 1/2] ACPI / PCI: Make bus registration and unregistration symmetric Rafael J. Wysocki
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Rafael J. Wysocki @ 2013-07-07 23:15 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: LKML, Linux PCI, ACPI Devel Maling List, Yinghai Lu, Jiang Liu
Hi,
These two patches clean up the ACPI part of the PCI core and ACPIPHP.
[1/2] Make bus registration and unregistration symmetric.
[2/2] Consolidate acpiphp_enumerate_slots().
They are on top of 3.10 plus my 3.11 queue (should apply on plain 3.10),
but if they look good, I'll add them to the previous ACPI dock cleanups.
Thanks,
Rafael
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/2] ACPI / PCI: Make bus registration and unregistration symmetric
2013-07-07 23:15 [PATCH 0/2] PCI / ACPI cleanups Rafael J. Wysocki
@ 2013-07-07 23:17 ` Rafael J. Wysocki
2013-07-07 23:19 ` [PATCH 2/2] ACPI / PCI: Consolidate acpiphp_enumerate_slots() Rafael J. Wysocki
2013-07-08 13:27 ` [PATCH 0/3] ACPI / hotplug / PCI: Rework of events handling Rafael J. Wysocki
2 siblings, 0 replies; 8+ messages in thread
From: Rafael J. Wysocki @ 2013-07-07 23:17 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: LKML, Linux PCI, ACPI Devel Maling List, Yinghai Lu, Jiang Liu
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Since acpi_pci_slot_enumerate() and acpiphp_enumerate_slots() can get
the ACPI device handle they need from bus->bridge, it is not
necessary to pass that handle to them as an argument.
Drop the second argument of acpi_pci_slot_enumerate() and
acpiphp_enumerate_slots(), rework them to obtain the ACPI handle
from bus->bridge and make acpi_pci_add_bus() and
acpi_pci_remove_bus() entirely symmetrical.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/acpi/pci_slot.c | 14 +++++++++-----
drivers/pci/hotplug/acpiphp_glue.c | 7 ++++---
drivers/pci/pci-acpi.c | 16 ++++------------
include/linux/pci-acpi.h | 10 ++++------
4 files changed, 21 insertions(+), 26 deletions(-)
Index: linux-pm/drivers/acpi/pci_slot.c
===================================================================
--- linux-pm.orig/drivers/acpi/pci_slot.c
+++ linux-pm/drivers/acpi/pci_slot.c
@@ -159,12 +159,16 @@ register_slot(acpi_handle handle, u32 lv
return AE_OK;
}
-void acpi_pci_slot_enumerate(struct pci_bus *bus, acpi_handle handle)
+void acpi_pci_slot_enumerate(struct pci_bus *bus)
{
- mutex_lock(&slot_list_lock);
- acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
- register_slot, NULL, bus, NULL);
- mutex_unlock(&slot_list_lock);
+ acpi_handle handle = ACPI_HANDLE(bus->bridge);
+
+ if (handle) {
+ mutex_lock(&slot_list_lock);
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
+ register_slot, NULL, bus, NULL);
+ mutex_unlock(&slot_list_lock);
+ }
}
void acpi_pci_slot_remove(struct pci_bus *bus)
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
@@ -1169,15 +1169,16 @@ static void handle_hotplug_event_func(ac
* Create hotplug slots for the PCI bus.
* It should always return 0 to avoid skipping following notifiers.
*/
-void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle)
+void acpiphp_enumerate_slots(struct pci_bus *bus)
{
- acpi_handle dummy_handle;
+ acpi_handle handle, dummy_handle;
struct acpiphp_bridge *bridge;
if (acpiphp_disabled)
return;
- if (detect_ejectable_slots(handle) <= 0)
+ handle = ACPI_HANDLE(bus->bridge);
+ if (!handle || detect_ejectable_slots(handle) <= 0)
return;
bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
Index: linux-pm/drivers/pci/pci-acpi.c
===================================================================
--- linux-pm.orig/drivers/pci/pci-acpi.c
+++ linux-pm/drivers/pci/pci-acpi.c
@@ -290,24 +290,16 @@ static struct pci_platform_pm_ops acpi_p
void acpi_pci_add_bus(struct pci_bus *bus)
{
- acpi_handle handle = NULL;
-
- if (bus->bridge)
- handle = ACPI_HANDLE(bus->bridge);
- if (acpi_pci_disabled || handle == NULL)
+ if (acpi_pci_disabled || !bus->bridge)
return;
- acpi_pci_slot_enumerate(bus, handle);
- acpiphp_enumerate_slots(bus, handle);
+ acpi_pci_slot_enumerate(bus);
+ acpiphp_enumerate_slots(bus);
}
void acpi_pci_remove_bus(struct pci_bus *bus)
{
- /*
- * bus->bridge->acpi_node.handle has already been reset to NULL
- * when acpi_pci_remove_bus() is called, so don't check ACPI handle.
- */
- if (acpi_pci_disabled)
+ if (acpi_pci_disabled || !bus->bridge)
return;
acpiphp_remove_slots(bus);
Index: linux-pm/include/linux/pci-acpi.h
===================================================================
--- linux-pm.orig/include/linux/pci-acpi.h
+++ linux-pm/include/linux/pci-acpi.h
@@ -47,24 +47,22 @@ void acpi_pci_remove_bus(struct pci_bus
#ifdef CONFIG_ACPI_PCI_SLOT
void acpi_pci_slot_init(void);
-void acpi_pci_slot_enumerate(struct pci_bus *bus, acpi_handle handle);
+void acpi_pci_slot_enumerate(struct pci_bus *bus);
void acpi_pci_slot_remove(struct pci_bus *bus);
#else
static inline void acpi_pci_slot_init(void) { }
-static inline void acpi_pci_slot_enumerate(struct pci_bus *bus,
- acpi_handle handle) { }
+static inline void acpi_pci_slot_enumerate(struct pci_bus *bus) { }
static inline void acpi_pci_slot_remove(struct pci_bus *bus) { }
#endif
#ifdef CONFIG_HOTPLUG_PCI_ACPI
void acpiphp_init(void);
-void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle);
+void acpiphp_enumerate_slots(struct pci_bus *bus);
void acpiphp_remove_slots(struct pci_bus *bus);
void acpiphp_check_host_bridge(acpi_handle handle);
#else
static inline void acpiphp_init(void) { }
-static inline void acpiphp_enumerate_slots(struct pci_bus *bus,
- acpi_handle handle) { }
+static inline void acpiphp_enumerate_slots(struct pci_bus *bus) { }
static inline void acpiphp_remove_slots(struct pci_bus *bus) { }
static inline void acpiphp_check_host_bridge(acpi_handle handle) { }
#endif
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/2] ACPI / PCI: Consolidate acpiphp_enumerate_slots()
2013-07-07 23:15 [PATCH 0/2] PCI / ACPI cleanups Rafael J. Wysocki
2013-07-07 23:17 ` [PATCH 1/2] ACPI / PCI: Make bus registration and unregistration symmetric Rafael J. Wysocki
@ 2013-07-07 23:19 ` Rafael J. Wysocki
2013-07-08 13:27 ` [PATCH 0/3] ACPI / hotplug / PCI: Rework of events handling Rafael J. Wysocki
2 siblings, 0 replies; 8+ messages in thread
From: Rafael J. Wysocki @ 2013-07-07 23:19 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: LKML, Linux PCI, ACPI Devel Maling List, Yinghai Lu, Jiang Liu
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
The acpiphp_enumerate_slots() function is now split into two parts,
acpiphp_enumerate_slots() proper and init_bridge_misc() which is
only called by the former. If these functions are combined,
it is possible to make the code easier to follow and to clean up
the error handling (to prevent memory leaks on error from
happening in particular), so do that.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/pci/hotplug/acpiphp_glue.c | 94 ++++++++++++++++++-------------------
1 file changed, 46 insertions(+), 48 deletions(-)
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
@@ -363,46 +363,6 @@ static int detect_ejectable_slots(acpi_h
return found;
}
-/* initialize miscellaneous stuff for both root and PCI-to-PCI bridge */
-static void init_bridge_misc(struct acpiphp_bridge *bridge)
-{
- acpi_status status;
-
- /* must be added to the list prior to calling register_slot */
- mutex_lock(&bridge_mutex);
- list_add(&bridge->list, &bridge_list);
- mutex_unlock(&bridge_mutex);
-
- /* register all slot objects under this bridge */
- status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1,
- register_slot, NULL, bridge, NULL);
- if (ACPI_FAILURE(status)) {
- mutex_lock(&bridge_mutex);
- list_del(&bridge->list);
- mutex_unlock(&bridge_mutex);
- return;
- }
-
- /* install notify handler for P2P bridges */
- if (!pci_is_root_bus(bridge->pci_bus)) {
- if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) {
- status = acpi_remove_notify_handler(bridge->func->handle,
- ACPI_SYSTEM_NOTIFY,
- handle_hotplug_event_func);
- if (ACPI_FAILURE(status))
- err("failed to remove notify handler\n");
- }
- status = acpi_install_notify_handler(bridge->handle,
- ACPI_SYSTEM_NOTIFY,
- handle_hotplug_event_bridge,
- bridge);
-
- if (ACPI_FAILURE(status)) {
- err("failed to register interrupt notify handler\n");
- }
- }
-}
-
/* find acpiphp_func from acpiphp_bridge */
static struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle)
@@ -1171,8 +1131,9 @@ static void handle_hotplug_event_func(ac
*/
void acpiphp_enumerate_slots(struct pci_bus *bus)
{
- acpi_handle handle, dummy_handle;
struct acpiphp_bridge *bridge;
+ acpi_handle handle;
+ acpi_status status;
if (acpiphp_disabled)
return;
@@ -1200,15 +1161,52 @@ void acpiphp_enumerate_slots(struct pci_
*/
get_device(&bus->dev);
- if (!pci_is_root_bus(bridge->pci_bus) &&
- ACPI_SUCCESS(acpi_get_handle(bridge->handle,
- "_EJ0", &dummy_handle))) {
- dbg("found ejectable p2p bridge\n");
- bridge->flags |= BRIDGE_HAS_EJ0;
- bridge->func = acpiphp_bridge_handle_to_function(handle);
+ /* must be added to the list prior to calling register_slot */
+ mutex_lock(&bridge_mutex);
+ list_add(&bridge->list, &bridge_list);
+ mutex_unlock(&bridge_mutex);
+
+ /* register all slot objects under this bridge */
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, 1,
+ register_slot, NULL, bridge, NULL);
+ if (ACPI_FAILURE(status)) {
+ acpi_handle_err(bridge->handle, "failed to register slots\n");
+ goto err;
}
- init_bridge_misc(bridge);
+ if (pci_is_root_bus(bridge->pci_bus))
+ return;
+
+ /* install notify handler for P2P bridges */
+ status = acpi_install_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY,
+ handle_hotplug_event_bridge,
+ bridge);
+ if (ACPI_FAILURE(status)) {
+ acpi_handle_err(bridge->handle,
+ "failed to register notify handler\n");
+ goto err;
+ }
+
+ status = acpi_get_handle(bridge->handle, "_EJ0", &handle);
+ if (ACPI_FAILURE(status))
+ return;
+
+ dbg("found ejectable p2p bridge\n");
+ bridge->flags |= BRIDGE_HAS_EJ0;
+ bridge->func = acpiphp_bridge_handle_to_function(bridge->handle);
+ if (bridge->func) {
+ status = acpi_remove_notify_handler(bridge->func->handle,
+ ACPI_SYSTEM_NOTIFY,
+ handle_hotplug_event_func);
+ if (ACPI_FAILURE(status))
+ acpi_handle_err(bridge->func->handle,
+ "failed to remove notify handler\n");
+ }
+ return;
+
+ err:
+ cleanup_bridge(bridge);
+ put_bridge(bridge);
}
/* Destroy hotplug slots associated with the PCI bus */
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 0/3] ACPI / hotplug / PCI: Rework of events handling
2013-07-07 23:15 [PATCH 0/2] PCI / ACPI cleanups Rafael J. Wysocki
2013-07-07 23:17 ` [PATCH 1/2] ACPI / PCI: Make bus registration and unregistration symmetric Rafael J. Wysocki
2013-07-07 23:19 ` [PATCH 2/2] ACPI / PCI: Consolidate acpiphp_enumerate_slots() Rafael J. Wysocki
@ 2013-07-08 13:27 ` Rafael J. Wysocki
2013-07-08 13:28 ` [PATCH 1/3] ACPI / hotplug / PCI: Always return success after adding a function Rafael J. Wysocki
` (2 more replies)
2 siblings, 3 replies; 8+ messages in thread
From: Rafael J. Wysocki @ 2013-07-08 13:27 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: LKML, Linux PCI, ACPI Devel Maling List, Yinghai Lu, Jiang Liu,
Mika Westerberg
Hi,
Yesterday I started looking into reworking acpiphp and the following is what
I have at the moment, on top of 3.10 with my 3.11 material merged and the
cleanups I posted yesterday:
https://patchwork.kernel.org/patch/2824650/
https://patchwork.kernel.org/patch/2824649/
Eventually, I'm going to rebase all that on top of the bleeding-edge branch
of my tree.
[1/3] Fix error code path in register_slot().
[2/3] Introduce hotplug context objects for ACPI device objects corresponding
to PCI hotplug devices.
[3/3] Unified notify handler for hotplug events.
This hasn't been tested yet and I'm sending it just to let you know what
direction it is going into and to get some early feedback, if any.
Thanks,
Rafael
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/3] ACPI / hotplug / PCI: Always return success after adding a function
2013-07-08 13:27 ` [PATCH 0/3] ACPI / hotplug / PCI: Rework of events handling Rafael J. Wysocki
@ 2013-07-08 13:28 ` Rafael J. Wysocki
2013-07-08 13:30 ` [PATCH 2/3] ACPI / hotplug / PCI: Hotplug context objects for bridges and functions Rafael J. Wysocki
2013-07-08 13:34 ` [PATCH 3/3] ACPI / hotplug / PCI: Unified notify handler for hotplug events Rafael J. Wysocki
2 siblings, 0 replies; 8+ messages in thread
From: Rafael J. Wysocki @ 2013-07-08 13:28 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: LKML, Linux PCI, ACPI Devel Maling List, Yinghai Lu, Jiang Liu,
Mika Westerberg
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
When a new ACPIPHP function is added by register_slot() and the
notify handler cannot be installed for it, register_slot() returns an
error status without cleaning up, which causes the entire namespace
walk in acpiphp_enumerate_slots() to be aborted, although it still
may be possible to successfully install the function notify handler
for other device objects under the given brigde.
To address this issue make register_slot() return success after
a new function has been added, even if the addition of the notify
handler for it has failed.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/pci/hotplug/acpiphp_glue.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
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
@@ -335,10 +335,9 @@ register_slot(acpi_handle handle, u32 lv
if (ACPI_FAILURE(status))
err("failed to register interrupt notify handler\n");
- } else
- status = AE_OK;
+ }
- return status;
+ return AE_OK;
err_exit:
bridge->nr_slots--;
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/3] ACPI / hotplug / PCI: Hotplug context objects for bridges and functions
2013-07-08 13:27 ` [PATCH 0/3] ACPI / hotplug / PCI: Rework of events handling Rafael J. Wysocki
2013-07-08 13:28 ` [PATCH 1/3] ACPI / hotplug / PCI: Always return success after adding a function Rafael J. Wysocki
@ 2013-07-08 13:30 ` Rafael J. Wysocki
2013-07-08 23:44 ` Rafael J. Wysocki
2013-07-08 13:34 ` [PATCH 3/3] ACPI / hotplug / PCI: Unified notify handler for hotplug events Rafael J. Wysocki
2 siblings, 1 reply; 8+ messages in thread
From: Rafael J. Wysocki @ 2013-07-08 13:30 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: LKML, Linux PCI, ACPI Devel Maling List, Yinghai Lu, Jiang Liu,
Mika Westerberg
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
When either a new hotplug brigde or a new hotplug function is added
by the ACPI-based PCI hotplug (acpiphp) code, attach a context object
to its ACPI handle to store hotplug-related information in it. To
start with, put the handle's bridge and function pointers into that
object. Count references to the context objects and drop them when
they are not needed any more.
First of all, this makes it possible to find out if the given bridge
has been registered as a function already in a much more
straightforward way and acpiphp_bridge_handle_to_function() can be
dropped (Yay!).
This also will allow some more simplifications to be made going
forward.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/pci/hotplug/acpiphp.h | 10 ++
drivers/pci/hotplug/acpiphp_glue.c | 149 ++++++++++++++++++++++++++-----------
2 files changed, 116 insertions(+), 43 deletions(-)
Index: linux-pm/drivers/pci/hotplug/acpiphp.h
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
+++ linux-pm/drivers/pci/hotplug/acpiphp.h
@@ -49,6 +49,7 @@
#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
+struct acpiphp_context;
struct acpiphp_bridge;
struct acpiphp_slot;
@@ -77,6 +78,7 @@ struct acpiphp_bridge {
struct kref ref;
acpi_handle handle;
+ struct acpiphp_context *context;
/* Ejectable PCI-to-PCI bridge (PCI bridge and PCI function) */
struct acpiphp_func *func;
@@ -119,6 +121,7 @@ struct acpiphp_slot {
* typically 8 objects per slot (i.e. for each PCI function)
*/
struct acpiphp_func {
+ struct acpiphp_context *context;
struct acpiphp_slot *slot; /* parent */
struct list_head sibling;
@@ -129,6 +132,13 @@ struct acpiphp_func {
u32 flags; /* see below */
};
+struct acpiphp_context {
+ struct kref kref;
+ acpi_handle handle;
+ struct acpiphp_func *func;
+ struct acpiphp_bridge *bridge;
+};
+
/*
* struct acpiphp_attention_info - device specific attention registration
*
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
@@ -79,6 +79,61 @@ is_pci_dock_device(acpi_handle handle, u
}
}
+static void acpiphp_context_handler(acpi_handle handle, void *context)
+{
+ /* Intentionally empty. */
+}
+
+static struct acpiphp_context *acpiphp_init_context(acpi_handle handle)
+{
+ struct acpiphp_context *context;
+ acpi_status status;
+
+ context = kzalloc(sizeof(*context), GFP_KERNEL);
+ if (!context)
+ return NULL;
+
+ context->handle = handle;
+ kref_init(&context->kref);
+ status = acpi_attach_data(handle, acpiphp_context_handler, context);
+ if (ACPI_FAILURE(status)) {
+ kfree(context);
+ return NULL;
+ }
+ return context;
+}
+
+static struct acpiphp_context *acpiphp_get_context(acpi_handle handle)
+{
+ struct acpiphp_context *context = NULL;
+ acpi_status status;
+ void *data;
+
+ status = acpi_get_data(handle, acpiphp_context_handler, &data);
+ if (ACPI_SUCCESS(status)) {
+ context = data;
+ kref_get(&context->kref);
+ } else if (status == AE_NOT_FOUND) {
+ context = acpiphp_init_context(handle);
+ }
+ return context;
+}
+
+static void acpiphp_release_context(struct kref *kref)
+{
+ struct acpiphp_context *context;
+
+ context = container_of(kref, struct acpiphp_context, kref);
+ WARN_ON(context->func || context->bridge);
+ acpi_detach_data(context->handle, acpiphp_context_handler);
+ kfree(context);
+}
+
+static void acpiphp_put_context(struct acpiphp_context *context)
+{
+ kref_put(&context->kref, acpiphp_release_context);
+}
+
static inline void get_bridge(struct acpiphp_bridge *bridge)
{
kref_get(&bridge->ref);
@@ -91,6 +146,7 @@ static inline void put_bridge(struct acp
static void free_bridge(struct kref *kref)
{
+ struct acpiphp_context *context;
struct acpiphp_bridge *bridge;
struct acpiphp_slot *slot, *next;
struct acpiphp_func *func, *tmp;
@@ -99,17 +155,24 @@ static void free_bridge(struct kref *kre
list_for_each_entry_safe(slot, next, &bridge->slots, node) {
list_for_each_entry_safe(func, tmp, &slot->funcs, sibling) {
+ context = func->context;
+ context->func = NULL;
kfree(func);
+ acpiphp_put_context(context);
}
kfree(slot);
}
- /* Release reference acquired by acpiphp_bridge_handle_to_function() */
+ /* Release reference acquired by acpiphp_enumerate_slots(). */
if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func)
put_bridge(bridge->func->slot->bridge);
+
put_device(&bridge->pci_bus->dev);
pci_dev_put(bridge->pci_dev);
+ context = bridge->context;
+ context->bridge = NULL;
kfree(bridge);
+ acpiphp_put_context(context);
}
/*
@@ -195,10 +258,11 @@ static void acpiphp_dock_release(void *d
}
/* callback routine to register each ACPI PCI slot object */
-static acpi_status
-register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
+static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
+ void **rv)
{
- struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context;
+ struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)data;
+ struct acpiphp_context *context;
struct acpiphp_slot *slot;
struct acpiphp_func *newfunc;
acpi_handle tmp;
@@ -229,8 +293,18 @@ register_slot(acpi_handle handle, u32 lv
if (!newfunc)
return AE_NO_MEMORY;
+ context = acpiphp_get_context(newfunc->handle);
+ if (!context) {
+ acpi_handle_err(newfunc->handle,
+ "Unable to get hotplug context\n");
+ kfree(newfunc);
+ return AE_NOT_EXIST;
+ }
+
newfunc->handle = handle;
newfunc->function = function;
+ newfunc->context = context;
+ context->func = newfunc;
if (ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp)))
newfunc->flags = FUNC_HAS_EJ0;
@@ -268,8 +342,8 @@ register_slot(acpi_handle handle, u32 lv
if (!found) {
slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL);
if (!slot) {
- kfree(newfunc);
- return AE_NO_MEMORY;
+ status = AE_NO_MEMORY;
+ goto err_out;
}
slot->bridge = bridge;
@@ -293,7 +367,9 @@ register_slot(acpi_handle handle, u32 lv
else
warn("acpiphp_register_hotplug_slot failed "
"(err code = 0x%x)\n", retval);
- goto err_exit;
+
+ status = AE_OK;
+ goto err;
}
}
@@ -339,15 +415,17 @@ register_slot(acpi_handle handle, u32 lv
return AE_OK;
- err_exit:
+ err:
bridge->nr_slots--;
mutex_lock(&bridge_mutex);
list_del(&slot->node);
mutex_unlock(&bridge_mutex);
kfree(slot);
+ err_out:
+ context->func = NULL;
kfree(newfunc);
-
- return AE_OK;
+ acpiphp_put_context(context);
+ return status;
}
@@ -362,32 +440,6 @@ static int detect_ejectable_slots(acpi_h
return found;
}
-
-/* find acpiphp_func from acpiphp_bridge */
-static struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle)
-{
- struct acpiphp_bridge *bridge;
- struct acpiphp_slot *slot;
- struct acpiphp_func *func = NULL;
-
- mutex_lock(&bridge_mutex);
- list_for_each_entry(bridge, &bridge_list, list) {
- list_for_each_entry(slot, &bridge->slots, node) {
- list_for_each_entry(func, &slot->funcs, sibling) {
- if (func->handle == handle) {
- get_bridge(func->slot->bridge);
- mutex_unlock(&bridge_mutex);
- return func;
- }
- }
- }
- }
- mutex_unlock(&bridge_mutex);
-
- return NULL;
-}
-
-
static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle)
{
struct acpiphp_bridge *bridge;
@@ -1130,6 +1182,7 @@ static void handle_hotplug_event_func(ac
*/
void acpiphp_enumerate_slots(struct pci_bus *bus)
{
+ struct acpiphp_context *context;
struct acpiphp_bridge *bridge;
acpi_handle handle;
acpi_status status;
@@ -1141,9 +1194,16 @@ void acpiphp_enumerate_slots(struct pci_
if (!handle || detect_ejectable_slots(handle) <= 0)
return;
+ context = acpiphp_get_context(handle);
+ if (!context) {
+ acpi_handle_err(handle, "Unable to get hotplug context\n");
+ return;
+ }
+
bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
if (bridge == NULL) {
- err("out of memory\n");
+ acpi_handle_err(handle, "No memory for bridge object\n");
+ acpiphp_put_context(context);
return;
}
@@ -1152,6 +1212,8 @@ void acpiphp_enumerate_slots(struct pci_
bridge->handle = handle;
bridge->pci_dev = pci_dev_get(bus->self);
bridge->pci_bus = bus;
+ bridge->context = context;
+ context->bridge = bridge;
/*
* Grab a ref to the subordinate PCI bus in case the bus is
@@ -1185,20 +1247,21 @@ void acpiphp_enumerate_slots(struct pci_
"failed to register notify handler\n");
goto err;
}
-
status = acpi_get_handle(bridge->handle, "_EJ0", &handle);
if (ACPI_FAILURE(status))
return;
dbg("found ejectable p2p bridge\n");
bridge->flags |= BRIDGE_HAS_EJ0;
- bridge->func = acpiphp_bridge_handle_to_function(bridge->handle);
- if (bridge->func) {
- status = acpi_remove_notify_handler(bridge->func->handle,
- ACPI_SYSTEM_NOTIFY,
+ if (context->func) {
+ get_bridge(context->func->slot->bridge);
+ bridge->func = context->func;
+ handle = context->handle;
+ WARN_ON(bridge->handle != handle);
+ status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
handle_hotplug_event_func);
if (ACPI_FAILURE(status))
- acpi_handle_err(bridge->func->handle,
+ acpi_handle_err(handle,
"failed to remove notify handler\n");
}
return;
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 3/3] ACPI / hotplug / PCI: Unified notify handler for hotplug events
2013-07-08 13:27 ` [PATCH 0/3] ACPI / hotplug / PCI: Rework of events handling Rafael J. Wysocki
2013-07-08 13:28 ` [PATCH 1/3] ACPI / hotplug / PCI: Always return success after adding a function Rafael J. Wysocki
2013-07-08 13:30 ` [PATCH 2/3] ACPI / hotplug / PCI: Hotplug context objects for bridges and functions Rafael J. Wysocki
@ 2013-07-08 13:34 ` Rafael J. Wysocki
2 siblings, 0 replies; 8+ messages in thread
From: Rafael J. Wysocki @ 2013-07-08 13:34 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: LKML, Linux PCI, ACPI Devel Maling List, Yinghai Lu, Jiang Liu,
Mika Westerberg
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Using the hotplug context objects introduced previously rework the
ACPI-based PCI hotplug (acpiphp) core code so that all notifications
for ACPI device objects corresponding to the hotplug PCI devices are
handled by one function, handle_hotplug_event(), which recognizes
whether it has to handle a bridge or a function.
In addition to code size reduction it allows some ugly pieces of code
where notify handlers have to be uninstalled and installed again to
go away.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
The future direction would be to merge _handle_hotplug_event_bridge()
and _handle_hotplug_event_func() into one function taking acpiphp_context
as the "context" argument and possibly simplify the addition/removal
code paths going from there.
Eventually, I'd like to install handle_hotplug_event() as a universal
hotplug event handler for all ACPI device objects corresponding to PCI
devices (regardless of whether or not they have any "hotplugish" methods
etc.).
Thanks,
Rafael
---
drivers/pci/hotplug/acpiphp.h | 1
drivers/pci/hotplug/acpiphp_glue.c | 127 +++++++++++++------------------------
2 files changed, 48 insertions(+), 80 deletions(-)
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
@@ -58,11 +58,10 @@ static DEFINE_MUTEX(bridge_mutex);
#define MY_NAME "acpiphp_glue"
-static void handle_hotplug_event_bridge (acpi_handle, u32, void *);
+static void handle_hotplug_event(acpi_handle handle, u32 type, void *data);
static void acpiphp_sanitize_bus(struct pci_bus *bus);
static void acpiphp_set_hpp_values(struct pci_bus *bus);
static void hotplug_event_func(acpi_handle handle, u32 type, void *context);
-static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context);
static void free_bridge(struct kref *kref);
/* callback routine to check for the existence of a pci dock device */
@@ -163,13 +162,13 @@ static void free_bridge(struct kref *kre
kfree(slot);
}
+ context = bridge->context;
/* Release reference acquired by acpiphp_enumerate_slots(). */
- if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func)
+ if (context->handler_for_func)
put_bridge(bridge->func->slot->bridge);
put_device(&bridge->pci_bus->dev);
pci_dev_put(bridge->pci_dev);
- context = bridge->context;
context->bridge = NULL;
kfree(bridge);
acpiphp_put_context(context);
@@ -404,12 +403,12 @@ 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_func,
- newfunc);
-
- if (ACPI_FAILURE(status))
+ status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+ handle_hotplug_event,
+ context);
+ if (ACPI_SUCCESS(status))
+ context->handler_for_func = true;
+ else
err("failed to register interrupt notify handler\n");
}
@@ -463,23 +462,13 @@ static void cleanup_bridge(struct acpiph
acpi_status status;
acpi_handle handle = bridge->handle;
- if (!pci_is_root_bus(bridge->pci_bus)) {
- status = acpi_remove_notify_handler(handle,
- ACPI_SYSTEM_NOTIFY,
- handle_hotplug_event_bridge);
+ if (!bridge->context->handler_for_func) {
+ status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+ handle_hotplug_event);
if (ACPI_FAILURE(status))
err("failed to remove notify handler\n");
}
- if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) {
- status = acpi_install_notify_handler(bridge->func->handle,
- ACPI_SYSTEM_NOTIFY,
- handle_hotplug_event_func,
- bridge->func);
- if (ACPI_FAILURE(status))
- err("failed to install interrupt notify handler\n");
- }
-
list_for_each_entry(slot, &bridge->slots, node) {
list_for_each_entry(func, &slot->funcs, sibling) {
if (is_dock_device(func->handle)) {
@@ -487,9 +476,10 @@ static void cleanup_bridge(struct acpiph
unregister_dock_notifier(&func->nb);
}
if (!(func->flags & FUNC_HAS_DCK)) {
+ func->context->handler_for_func = false;
status = acpi_remove_notify_handler(func->handle,
- ACPI_SYSTEM_NOTIFY,
- handle_hotplug_event_func);
+ ACPI_SYSTEM_NOTIFY,
+ handle_hotplug_event);
if (ACPI_FAILURE(status))
err("failed to remove notify handler\n");
}
@@ -1070,31 +1060,6 @@ static void _handle_hotplug_event_bridge
put_bridge(bridge);
}
-/**
- * handle_hotplug_event_bridge - handle ACPI event on bridges
- * @handle: Notify()'ed acpi_handle
- * @type: Notify code
- * @context: pointer to acpiphp_bridge structure
- *
- * Handles ACPI event notification on {host,p2p} bridges.
- */
-static void handle_hotplug_event_bridge(acpi_handle handle, u32 type,
- void *context)
-{
- struct acpiphp_bridge *bridge = context;
-
- /*
- * Currently the code adds all hotplug events to the kacpid_wq
- * queue when it should add hotplug events to the kacpi_hotplug_wq.
- * The proper way to fix this is to reorganize the code so that
- * drivers (dock, etc.) do not call acpi_os_execute(), etc.
- * For now just re-add this work to the kacpi_hotplug_wq so we
- * don't deadlock on hotplug actions.
- */
- get_bridge(bridge);
- alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_bridge);
-}
-
static void hotplug_event_func(acpi_handle handle, u32 type, void *context)
{
struct acpiphp_func *func = context;
@@ -1152,18 +1117,29 @@ static void _handle_hotplug_event_func(s
}
/**
- * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots)
+ * handle_hotplug_event - handle ACPI hotplug event
* @handle: Notify()'ed acpi_handle
* @type: Notify code
- * @context: pointer to acpiphp_func structure
+ * @data: pointer to acpiphp_context structure
*
* Handles ACPI event notification on slots.
*/
-static void handle_hotplug_event_func(acpi_handle handle, u32 type,
- void *context)
+static void handle_hotplug_event(acpi_handle handle, u32 type, void *data)
{
- struct acpiphp_func *func = context;
+ struct acpiphp_context *context = data;
+ void (*work_func)(struct work_struct *work);
+ if (context->bridge) {
+ get_bridge(context->bridge);
+ data = context->bridge;
+ work_func = _handle_hotplug_event_bridge;
+ } else if (context->func) {
+ get_bridge(context->func->slot->bridge);
+ data = context->func;
+ work_func = _handle_hotplug_event_func;
+ } else {
+ return;
+ }
/*
* Currently the code adds all hotplug events to the kacpid_wq
* queue when it should add hotplug events to the kacpi_hotplug_wq.
@@ -1172,8 +1148,7 @@ static void handle_hotplug_event_func(ac
* For now just re-add this work to the kacpi_hotplug_wq so we
* don't deadlock on hotplug actions.
*/
- get_bridge(func->slot->bridge);
- alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_func);
+ alloc_acpi_hp_work(handle, type, data, work_func);
}
/*
@@ -1238,33 +1213,25 @@ void acpiphp_enumerate_slots(struct pci_
if (pci_is_root_bus(bridge->pci_bus))
return;
+ status = acpi_get_handle(bridge->handle, "_EJ0", &handle);
+ if (ACPI_SUCCESS(status)) {
+ dbg("found ejectable p2p bridge\n");
+ bridge->flags |= BRIDGE_HAS_EJ0;
+ }
+ if (context->handler_for_func) {
+ /* Notify handler already installed. */
+ bridge->func = context->func;
+ get_bridge(context->func->slot->bridge);
+ return;
+ }
+
/* install notify handler for P2P bridges */
status = acpi_install_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY,
- handle_hotplug_event_bridge,
- bridge);
- if (ACPI_FAILURE(status)) {
- acpi_handle_err(bridge->handle,
- "failed to register notify handler\n");
- goto err;
- }
- status = acpi_get_handle(bridge->handle, "_EJ0", &handle);
- if (ACPI_FAILURE(status))
+ handle_hotplug_event, context);
+ if (ACPI_SUCCESS(status))
return;
- dbg("found ejectable p2p bridge\n");
- bridge->flags |= BRIDGE_HAS_EJ0;
- if (context->func) {
- get_bridge(context->func->slot->bridge);
- bridge->func = context->func;
- handle = context->handle;
- WARN_ON(bridge->handle != handle);
- status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
- handle_hotplug_event_func);
- if (ACPI_FAILURE(status))
- acpi_handle_err(handle,
- "failed to remove notify handler\n");
- }
- return;
+ acpi_handle_err(bridge->handle, "failed to register notify handler\n");
err:
cleanup_bridge(bridge);
Index: linux-pm/drivers/pci/hotplug/acpiphp.h
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
+++ linux-pm/drivers/pci/hotplug/acpiphp.h
@@ -137,6 +137,7 @@ struct acpiphp_context {
acpi_handle handle;
struct acpiphp_func *func;
struct acpiphp_bridge *bridge;
+ bool handler_for_func:1;
};
/*
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/3] ACPI / hotplug / PCI: Hotplug context objects for bridges and functions
2013-07-08 13:30 ` [PATCH 2/3] ACPI / hotplug / PCI: Hotplug context objects for bridges and functions Rafael J. Wysocki
@ 2013-07-08 23:44 ` Rafael J. Wysocki
0 siblings, 0 replies; 8+ messages in thread
From: Rafael J. Wysocki @ 2013-07-08 23:44 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: LKML, Linux PCI, ACPI Devel Maling List, Yinghai Lu, Jiang Liu,
Mika Westerberg
On Monday, July 08, 2013 03:30:16 PM Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>
> When either a new hotplug brigde or a new hotplug function is added
> by the ACPI-based PCI hotplug (acpiphp) code, attach a context object
> to its ACPI handle to store hotplug-related information in it. To
> start with, put the handle's bridge and function pointers into that
> object. Count references to the context objects and drop them when
> they are not needed any more.
>
> First of all, this makes it possible to find out if the given bridge
> has been registered as a function already in a much more
> straightforward way and acpiphp_bridge_handle_to_function() can be
> dropped (Yay!).
>
> This also will allow some more simplifications to be made going
> forward.
Unfortunately, this one is buggy. ->
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> ---
> drivers/pci/hotplug/acpiphp.h | 10 ++
> drivers/pci/hotplug/acpiphp_glue.c | 149 ++++++++++++++++++++++++++-----------
> 2 files changed, 116 insertions(+), 43 deletions(-)
>
> Index: linux-pm/drivers/pci/hotplug/acpiphp.h
> ===================================================================
> --- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
> +++ linux-pm/drivers/pci/hotplug/acpiphp.h
> @@ -49,6 +49,7 @@
> #define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
> #define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
>
> +struct acpiphp_context;
> struct acpiphp_bridge;
> struct acpiphp_slot;
>
> @@ -77,6 +78,7 @@ struct acpiphp_bridge {
> struct kref ref;
> acpi_handle handle;
>
> + struct acpiphp_context *context;
> /* Ejectable PCI-to-PCI bridge (PCI bridge and PCI function) */
> struct acpiphp_func *func;
>
> @@ -119,6 +121,7 @@ struct acpiphp_slot {
> * typically 8 objects per slot (i.e. for each PCI function)
> */
> struct acpiphp_func {
> + struct acpiphp_context *context;
> struct acpiphp_slot *slot; /* parent */
>
> struct list_head sibling;
> @@ -129,6 +132,13 @@ struct acpiphp_func {
> u32 flags; /* see below */
> };
>
> +struct acpiphp_context {
> + struct kref kref;
> + acpi_handle handle;
> + struct acpiphp_func *func;
> + struct acpiphp_bridge *bridge;
> +};
> +
> /*
> * struct acpiphp_attention_info - device specific attention registration
> *
> 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
> @@ -79,6 +79,61 @@ is_pci_dock_device(acpi_handle handle, u
> }
> }
>
> +static void acpiphp_context_handler(acpi_handle handle, void *context)
> +{
> + /* Intentionally empty. */
> +}
> +
> +static struct acpiphp_context *acpiphp_init_context(acpi_handle handle)
> +{
> + struct acpiphp_context *context;
> + acpi_status status;
> +
> + context = kzalloc(sizeof(*context), GFP_KERNEL);
> + if (!context)
> + return NULL;
> +
> + context->handle = handle;
> + kref_init(&context->kref);
> + status = acpi_attach_data(handle, acpiphp_context_handler, context);
> + if (ACPI_FAILURE(status)) {
> + kfree(context);
> + return NULL;
> + }
> + return context;
> +}
> +
> +static struct acpiphp_context *acpiphp_get_context(acpi_handle handle)
> +{
> + struct acpiphp_context *context = NULL;
> + acpi_status status;
> + void *data;
> +
> + status = acpi_get_data(handle, acpiphp_context_handler, &data);
> + if (ACPI_SUCCESS(status)) {
> + context = data;
> + kref_get(&context->kref);
> + } else if (status == AE_NOT_FOUND) {
> + context = acpiphp_init_context(handle);
> + }
> + return context;
> +}
> +
> +static void acpiphp_release_context(struct kref *kref)
> +{
> + struct acpiphp_context *context;
> +
> + context = container_of(kref, struct acpiphp_context, kref);
> + WARN_ON(context->func || context->bridge);
> + acpi_detach_data(context->handle, acpiphp_context_handler);
> + kfree(context);
> +}
> +
> +static void acpiphp_put_context(struct acpiphp_context *context)
> +{
> + kref_put(&context->kref, acpiphp_release_context);
> +}
> +
> static inline void get_bridge(struct acpiphp_bridge *bridge)
> {
> kref_get(&bridge->ref);
> @@ -91,6 +146,7 @@ static inline void put_bridge(struct acp
>
> static void free_bridge(struct kref *kref)
> {
> + struct acpiphp_context *context;
> struct acpiphp_bridge *bridge;
> struct acpiphp_slot *slot, *next;
> struct acpiphp_func *func, *tmp;
> @@ -99,17 +155,24 @@ static void free_bridge(struct kref *kre
>
> list_for_each_entry_safe(slot, next, &bridge->slots, node) {
> list_for_each_entry_safe(func, tmp, &slot->funcs, sibling) {
> + context = func->context;
> + context->func = NULL;
> kfree(func);
> + acpiphp_put_context(context);
> }
> kfree(slot);
> }
>
> - /* Release reference acquired by acpiphp_bridge_handle_to_function() */
> + /* Release reference acquired by acpiphp_enumerate_slots(). */
> if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func)
> put_bridge(bridge->func->slot->bridge);
> +
> put_device(&bridge->pci_bus->dev);
> pci_dev_put(bridge->pci_dev);
> + context = bridge->context;
> + context->bridge = NULL;
> kfree(bridge);
> + acpiphp_put_context(context);
> }
>
> /*
> @@ -195,10 +258,11 @@ static void acpiphp_dock_release(void *d
> }
>
> /* callback routine to register each ACPI PCI slot object */
> -static acpi_status
> -register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
> +static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
> + void **rv)
> {
> - struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context;
> + struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)data;
> + struct acpiphp_context *context;
> struct acpiphp_slot *slot;
> struct acpiphp_func *newfunc;
> acpi_handle tmp;
> @@ -229,8 +293,18 @@ register_slot(acpi_handle handle, u32 lv
> if (!newfunc)
> return AE_NO_MEMORY;
>
> + context = acpiphp_get_context(newfunc->handle);
-> Because newfunc->handle is still NULL here. Sorry about that.
I'll send an update shortly along with some more stuff on top.
> + if (!context) {
> + acpi_handle_err(newfunc->handle,
> + "Unable to get hotplug context\n");
> + kfree(newfunc);
> + return AE_NOT_EXIST;
> + }
> +
> newfunc->handle = handle;
> newfunc->function = function;
> + newfunc->context = context;
> + context->func = newfunc;
>
> if (ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp)))
> newfunc->flags = FUNC_HAS_EJ0;
> @@ -268,8 +342,8 @@ register_slot(acpi_handle handle, u32 lv
> if (!found) {
> slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL);
> if (!slot) {
> - kfree(newfunc);
> - return AE_NO_MEMORY;
> + status = AE_NO_MEMORY;
> + goto err_out;
> }
>
> slot->bridge = bridge;
> @@ -293,7 +367,9 @@ register_slot(acpi_handle handle, u32 lv
> else
> warn("acpiphp_register_hotplug_slot failed "
> "(err code = 0x%x)\n", retval);
> - goto err_exit;
> +
> + status = AE_OK;
> + goto err;
> }
> }
>
> @@ -339,15 +415,17 @@ register_slot(acpi_handle handle, u32 lv
>
> return AE_OK;
>
> - err_exit:
> + err:
> bridge->nr_slots--;
> mutex_lock(&bridge_mutex);
> list_del(&slot->node);
> mutex_unlock(&bridge_mutex);
> kfree(slot);
> + err_out:
> + context->func = NULL;
> kfree(newfunc);
> -
> - return AE_OK;
> + acpiphp_put_context(context);
> + return status;
> }
>
>
> @@ -362,32 +440,6 @@ static int detect_ejectable_slots(acpi_h
> return found;
> }
>
> -
> -/* find acpiphp_func from acpiphp_bridge */
> -static struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle)
> -{
> - struct acpiphp_bridge *bridge;
> - struct acpiphp_slot *slot;
> - struct acpiphp_func *func = NULL;
> -
> - mutex_lock(&bridge_mutex);
> - list_for_each_entry(bridge, &bridge_list, list) {
> - list_for_each_entry(slot, &bridge->slots, node) {
> - list_for_each_entry(func, &slot->funcs, sibling) {
> - if (func->handle == handle) {
> - get_bridge(func->slot->bridge);
> - mutex_unlock(&bridge_mutex);
> - return func;
> - }
> - }
> - }
> - }
> - mutex_unlock(&bridge_mutex);
> -
> - return NULL;
> -}
> -
> -
> static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle)
> {
> struct acpiphp_bridge *bridge;
> @@ -1130,6 +1182,7 @@ static void handle_hotplug_event_func(ac
> */
> void acpiphp_enumerate_slots(struct pci_bus *bus)
> {
> + struct acpiphp_context *context;
> struct acpiphp_bridge *bridge;
> acpi_handle handle;
> acpi_status status;
> @@ -1141,9 +1194,16 @@ void acpiphp_enumerate_slots(struct pci_
> if (!handle || detect_ejectable_slots(handle) <= 0)
> return;
>
> + context = acpiphp_get_context(handle);
> + if (!context) {
> + acpi_handle_err(handle, "Unable to get hotplug context\n");
> + return;
> + }
> +
> bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
> if (bridge == NULL) {
> - err("out of memory\n");
> + acpi_handle_err(handle, "No memory for bridge object\n");
> + acpiphp_put_context(context);
> return;
> }
>
> @@ -1152,6 +1212,8 @@ void acpiphp_enumerate_slots(struct pci_
> bridge->handle = handle;
> bridge->pci_dev = pci_dev_get(bus->self);
> bridge->pci_bus = bus;
> + bridge->context = context;
> + context->bridge = bridge;
>
> /*
> * Grab a ref to the subordinate PCI bus in case the bus is
> @@ -1185,20 +1247,21 @@ void acpiphp_enumerate_slots(struct pci_
> "failed to register notify handler\n");
> goto err;
> }
> -
> status = acpi_get_handle(bridge->handle, "_EJ0", &handle);
> if (ACPI_FAILURE(status))
> return;
>
> dbg("found ejectable p2p bridge\n");
> bridge->flags |= BRIDGE_HAS_EJ0;
> - bridge->func = acpiphp_bridge_handle_to_function(bridge->handle);
> - if (bridge->func) {
> - status = acpi_remove_notify_handler(bridge->func->handle,
> - ACPI_SYSTEM_NOTIFY,
> + if (context->func) {
> + get_bridge(context->func->slot->bridge);
> + bridge->func = context->func;
> + handle = context->handle;
> + WARN_ON(bridge->handle != handle);
> + status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
> handle_hotplug_event_func);
> if (ACPI_FAILURE(status))
> - acpi_handle_err(bridge->func->handle,
> + acpi_handle_err(handle,
> "failed to remove notify handler\n");
> }
> return;
>
> --
> 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
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2013-07-08 23:34 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-07-07 23:15 [PATCH 0/2] PCI / ACPI cleanups Rafael J. Wysocki
2013-07-07 23:17 ` [PATCH 1/2] ACPI / PCI: Make bus registration and unregistration symmetric Rafael J. Wysocki
2013-07-07 23:19 ` [PATCH 2/2] ACPI / PCI: Consolidate acpiphp_enumerate_slots() Rafael J. Wysocki
2013-07-08 13:27 ` [PATCH 0/3] ACPI / hotplug / PCI: Rework of events handling Rafael J. Wysocki
2013-07-08 13:28 ` [PATCH 1/3] ACPI / hotplug / PCI: Always return success after adding a function Rafael J. Wysocki
2013-07-08 13:30 ` [PATCH 2/3] ACPI / hotplug / PCI: Hotplug context objects for bridges and functions Rafael J. Wysocki
2013-07-08 23:44 ` Rafael J. Wysocki
2013-07-08 13:34 ` [PATCH 3/3] ACPI / hotplug / PCI: Unified notify handler for hotplug events Rafael J. Wysocki
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox