All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC][PATCH 0/8] ACPI / hotplug / PCI: Consolidation of handling notifications (in progress)
@ 2013-07-09  0:01 Rafael J. Wysocki
  2013-07-09  0:14 ` [RFC][PATCH 1/8] ACPI / PCI: Make bus registration and unregistration symmetric Rafael J. Wysocki
                   ` (8 more replies)
  0 siblings, 9 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-09  0:01 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

Hi,

Following is the current set of acpiphp updates targeted at the consolidation
of device notifications handling and removal of suprefluous infrastructure.
Still on top of 3.10 with ACPI+PM 3.11 material merged on top (I'll rebase it
on top of linux-pm.git/bleeding-edge eventually).

[1/8] Make bus registration and unregistration symmetric.  [Resend]
[2/8] Consolidate acpiphp_enumerate_slots().  [Resend]
[3/8] Fix error code path in register_slot().  [Resend]
[4/8] Introduce hotplug context objects for ACPI device objects corresponding
      to PCI hotplug devices.  [Update]
[5/8] Unified notify handler for hotplug events.  [Resend]
[6/8] Drop acpiphp_handle_to_bridge() and use context objects instead of it.
[7/8] Pass entire hotplug context objects (instead of their fields
      individually) to event handling work functions.
[8/8] Merge hotplug event handling functions.

Comments welcome.

Thanks,
Rafael


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


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

* [RFC][PATCH 1/8] ACPI / PCI: Make bus registration and unregistration symmetric
  2013-07-09  0:01 [RFC][PATCH 0/8] ACPI / hotplug / PCI: Consolidation of handling notifications (in progress) Rafael J. Wysocki
@ 2013-07-09  0:14 ` Rafael J. Wysocki
  2013-07-09  0:16 ` [RFC][PATCH 2/8] ACPI / hotplug / PCI: Consolidate acpiphp_enumerate_slots() Rafael J. Wysocki
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-09  0:14 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

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] 135+ messages in thread

* [RFC][PATCH 2/8] ACPI / hotplug / PCI: Consolidate acpiphp_enumerate_slots()
  2013-07-09  0:01 [RFC][PATCH 0/8] ACPI / hotplug / PCI: Consolidation of handling notifications (in progress) Rafael J. Wysocki
  2013-07-09  0:14 ` [RFC][PATCH 1/8] ACPI / PCI: Make bus registration and unregistration symmetric Rafael J. Wysocki
@ 2013-07-09  0:16 ` Rafael J. Wysocki
  2013-07-09  0:17 ` [RFC][PATCH 3/8] ACPI / hotplug / PCI: Always return success after adding a function Rafael J. Wysocki
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-09  0:16 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

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] 135+ messages in thread

* [RFC][PATCH 3/8] ACPI / hotplug / PCI: Always return success after adding a function
  2013-07-09  0:01 [RFC][PATCH 0/8] ACPI / hotplug / PCI: Consolidation of handling notifications (in progress) Rafael J. Wysocki
  2013-07-09  0:14 ` [RFC][PATCH 1/8] ACPI / PCI: Make bus registration and unregistration symmetric Rafael J. Wysocki
  2013-07-09  0:16 ` [RFC][PATCH 2/8] ACPI / hotplug / PCI: Consolidate acpiphp_enumerate_slots() Rafael J. Wysocki
@ 2013-07-09  0:17 ` Rafael J. Wysocki
  2013-07-09  0:18 ` [RFC][PATCH 4/8] ACPI / hotplug / PCI: Hotplug context objects for bridges and functions Rafael J. Wysocki
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-09  0:17 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, 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] 135+ messages in thread

* [RFC][PATCH 4/8] ACPI / hotplug / PCI: Hotplug context objects for bridges and functions
  2013-07-09  0:01 [RFC][PATCH 0/8] ACPI / hotplug / PCI: Consolidation of handling notifications (in progress) Rafael J. Wysocki
                   ` (2 preceding siblings ...)
  2013-07-09  0:17 ` [RFC][PATCH 3/8] ACPI / hotplug / PCI: Always return success after adding a function Rafael J. Wysocki
@ 2013-07-09  0:18 ` Rafael J. Wysocki
  2013-07-09  9:23   ` Mika Westerberg
  2013-07-09  0:19 ` [RFC][PATCH 5/8] ACPI / hotplug / PCI: Unified notify handler for hotplug events Rafael J. Wysocki
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-09  0:18 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, 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 |  154 ++++++++++++++++++++++++++-----------
 2 files changed, 121 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,20 @@ register_slot(acpi_handle handle, u32 lv
 	if (!newfunc)
 		return AE_NO_MEMORY;
 
+	context = acpiphp_get_context(handle);
+	if (!context) {
+		context = acpiphp_init_context(handle);
+		if (!context) {
+			acpi_handle_err(handle, "No 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 +344,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 +369,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 +417,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 +442,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 +1184,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 +1196,19 @@ void acpiphp_enumerate_slots(struct pci_
 	if (!handle || detect_ejectable_slots(handle) <= 0)
 		return;
 
+	context = acpiphp_get_context(handle);
+	if (!context) {
+		context = acpiphp_init_context(handle);
+		if (!context) {
+			acpi_handle_err(handle, "No 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 +1217,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 +1252,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] 135+ messages in thread

* [RFC][PATCH 5/8] ACPI / hotplug / PCI: Unified notify handler for hotplug events
  2013-07-09  0:01 [RFC][PATCH 0/8] ACPI / hotplug / PCI: Consolidation of handling notifications (in progress) Rafael J. Wysocki
                   ` (3 preceding siblings ...)
  2013-07-09  0:18 ` [RFC][PATCH 4/8] ACPI / hotplug / PCI: Hotplug context objects for bridges and functions Rafael J. Wysocki
@ 2013-07-09  0:19 ` Rafael J. Wysocki
  2013-07-09  9:30   ` Mika Westerberg
  2013-07-09  0:20 ` [RFC][PATCH 6/8] ACPI / hotplug / PCI: Drop acpiphp_handle_to_bridge() Rafael J. Wysocki
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-09  0:19 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, 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>
---
 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);
@@ -406,12 +405,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");
 	}
 
@@ -465,23 +464,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)) {
@@ -489,9 +478,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");
 			}
@@ -1072,31 +1062,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;
@@ -1154,18 +1119,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.
@@ -1174,8 +1150,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);
 }
 
 /*
@@ -1243,33 +1218,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] 135+ messages in thread

* [RFC][PATCH 6/8] ACPI / hotplug / PCI: Drop acpiphp_handle_to_bridge()
  2013-07-09  0:01 [RFC][PATCH 0/8] ACPI / hotplug / PCI: Consolidation of handling notifications (in progress) Rafael J. Wysocki
                   ` (4 preceding siblings ...)
  2013-07-09  0:19 ` [RFC][PATCH 5/8] ACPI / hotplug / PCI: Unified notify handler for hotplug events Rafael J. Wysocki
@ 2013-07-09  0:20 ` Rafael J. Wysocki
  2013-07-09  9:37   ` Mika Westerberg
  2013-07-09  0:21 ` [RFC][PATCH 7/8] ACPI / hotplug / PCI: Pass hotplug context object to event handlers Rafael J. Wysocki
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-09  0:20 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, 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 to get to acpiphp_bridge
objects associated with hotplug bridges from those context objects
rather than from the global list of hotplug bridges.

After that the acpiphp_handle_to_bridge() is not necessary any more,
so drop it.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp_glue.c |   54 +++++++++++++++++--------------------
 1 file changed, 25 insertions(+), 29 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
@@ -441,22 +441,6 @@ static int detect_ejectable_slots(acpi_h
 	return found;
 }
 
-static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle)
-{
-	struct acpiphp_bridge *bridge;
-
-	mutex_lock(&bridge_mutex);
-	list_for_each_entry(bridge, &bridge_list, list)
-		if (bridge->handle == handle) {
-			get_bridge(bridge);
-			mutex_unlock(&bridge_mutex);
-			return bridge;
-		}
-	mutex_unlock(&bridge_mutex);
-
-	return NULL;
-}
-
 static void cleanup_bridge(struct acpiphp_bridge *bridge)
 {
 	struct acpiphp_slot *slot;
@@ -953,37 +937,49 @@ static void acpiphp_sanitize_bus(struct
  * ACPI event handlers
  */
 
-static acpi_status
-check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
+static acpi_status check_sub_bridges(acpi_handle handle, u32 lvl, void *data,
+				     void **rv)
 {
-	struct acpiphp_bridge *bridge;
-	char objname[64];
-	struct acpi_buffer buffer = { .length = sizeof(objname),
-				      .pointer = objname };
+	struct acpiphp_context *context = acpiphp_get_context(handle);
+
+	if (!context)
+		return AE_OK;
 
-	bridge = acpiphp_handle_to_bridge(handle);
-	if (bridge) {
+	if (context->bridge) {
+		struct acpiphp_bridge *bridge = context->bridge;
+		char objname[64];
+		struct acpi_buffer buffer = { .length = sizeof(objname),
+					      .pointer = objname };
+
+		get_bridge(bridge);
 		acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-		dbg("%s: re-enumerating slots under %s\n",
-			__func__, objname);
+		dbg("%s: re-enumerating slots under %s\n", __func__, objname);
 		acpiphp_check_bridge(bridge);
 		put_bridge(bridge);
 	}
+	acpiphp_put_context(context);
 	return AE_OK ;
 }
 
 void acpiphp_check_host_bridge(acpi_handle handle)
 {
-	struct acpiphp_bridge *bridge;
+	struct acpiphp_context *context = acpiphp_get_context(handle);
 
-	bridge = acpiphp_handle_to_bridge(handle);
-	if (bridge) {
+	if (!context)
+		return;
+
+	if (context->bridge) {
+		struct acpiphp_bridge *bridge = context->bridge;
+
+		get_bridge(bridge);
 		acpiphp_check_bridge(bridge);
 		put_bridge(bridge);
 	}
 
 	acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
 		ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL);
+
+	acpiphp_put_context(context);
 }
 
 static void _handle_hotplug_event_bridge(struct work_struct *work)


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

* [RFC][PATCH 7/8] ACPI / hotplug / PCI: Pass hotplug context object to event handlers
  2013-07-09  0:01 [RFC][PATCH 0/8] ACPI / hotplug / PCI: Consolidation of handling notifications (in progress) Rafael J. Wysocki
                   ` (5 preceding siblings ...)
  2013-07-09  0:20 ` [RFC][PATCH 6/8] ACPI / hotplug / PCI: Drop acpiphp_handle_to_bridge() Rafael J. Wysocki
@ 2013-07-09  0:21 ` Rafael J. Wysocki
  2013-07-09  0:22 ` [RFC][PATCH 8/8] ACPI / hotplug / PCI: Merge hotplug event handling functions Rafael J. Wysocki
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
  8 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-09  0:21 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

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

Modify handle_hotplug_event() to pass the entire context object
(instead of its fields individually) to work functions started by it.

This change makes the subsequent consolidation of the event handling
work functions a bit more straightforward.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp_glue.c |   16 ++++++++--------
 1 file changed, 8 insertions(+), 8 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
@@ -984,6 +984,7 @@ void acpiphp_check_host_bridge(acpi_hand
 
 static void _handle_hotplug_event_bridge(struct work_struct *work)
 {
+	struct acpiphp_context *context;
 	struct acpiphp_bridge *bridge;
 	char objname[64];
 	struct acpi_buffer buffer = { .length = sizeof(objname),
@@ -995,7 +996,8 @@ static void _handle_hotplug_event_bridge
 	hp_work = container_of(work, struct acpi_hp_work, work);
 	handle = hp_work->handle;
 	type = hp_work->type;
-	bridge = (struct acpiphp_bridge *)hp_work->context;
+	context = hp_work->context;
+	bridge = context->bridge;
 
 	acpi_scan_lock_acquire();
 
@@ -1100,18 +1102,18 @@ static void hotplug_event_func(acpi_hand
 
 static void _handle_hotplug_event_func(struct work_struct *work)
 {
+	struct acpiphp_context *context;
 	struct acpi_hp_work *hp_work;
-	struct acpiphp_func *func;
 
 	hp_work = container_of(work, struct acpi_hp_work, work);
-	func = hp_work->context;
+	context = hp_work->context;
 	acpi_scan_lock_acquire();
 
-	hotplug_event_func(hp_work->handle, hp_work->type, func);
+	hotplug_event_func(hp_work->handle, hp_work->type, context->func);
 
 	acpi_scan_lock_release();
 	kfree(hp_work); /* allocated in handle_hotplug_event_func */
-	put_bridge(func->slot->bridge);
+	put_bridge(context->func->slot->bridge);
 }
 
 /**
@@ -1129,11 +1131,9 @@ static void handle_hotplug_event(acpi_ha
 
 	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;
@@ -1146,7 +1146,7 @@ static void handle_hotplug_event(acpi_ha
 	 * For now just re-add this work to the kacpi_hotplug_wq so we
 	 * don't deadlock on hotplug actions.
 	 */
-	alloc_acpi_hp_work(handle, type, data, work_func);
+	alloc_acpi_hp_work(handle, type, context, work_func);
 }
 
 /*


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

* [RFC][PATCH 8/8] ACPI / hotplug / PCI: Merge hotplug event handling functions
  2013-07-09  0:01 [RFC][PATCH 0/8] ACPI / hotplug / PCI: Consolidation of handling notifications (in progress) Rafael J. Wysocki
                   ` (6 preceding siblings ...)
  2013-07-09  0:21 ` [RFC][PATCH 7/8] ACPI / hotplug / PCI: Pass hotplug context object to event handlers Rafael J. Wysocki
@ 2013-07-09  0:22 ` Rafael J. Wysocki
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
  8 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-09  0:22 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

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

There are separate handling event functions for hotplug bridges and
for hotplug functions, but they may be combined into one common
hotplug event handling function which simplifies the code slightly.

That also allows a theoretical bug to be dealt with which in
principle may occur if a hotplug bridge is a docking station
device, because in that case the bridge-specific notification should
be used instead of the device-specific one.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp_glue.c |  156 +++++++++++++++----------------------
 1 file changed, 66 insertions(+), 90 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
@@ -61,7 +61,7 @@ static DEFINE_MUTEX(bridge_mutex);
 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 hotplug_event(acpi_handle handle, u32 type, void *data);
 static void free_bridge(struct kref *kref);
 
 /* callback routine to check for the existence of a pci dock device */
@@ -210,7 +210,7 @@ static int post_dock_fixups(struct notif
 
 
 static const struct acpi_dock_ops acpiphp_dock_ops = {
-	.handler = hotplug_event_func,
+	.handler = hotplug_event,
 };
 
 /* Check whether the PCI device is managed by native PCIe hotplug driver */
@@ -244,16 +244,24 @@ static bool device_is_managed_by_native_
 
 static void acpiphp_dock_init(void *data)
 {
-	struct acpiphp_func *func = data;
+	struct acpiphp_context *context = data;
+
+	if (context->func)
+		get_bridge(context->func->slot->bridge);
 
-	get_bridge(func->slot->bridge);
+	if (context->bridge)
+		get_bridge(context->bridge);
 }
 
 static void acpiphp_dock_release(void *data)
 {
-	struct acpiphp_func *func = data;
+	struct acpiphp_context *context = data;
+
+	if (context->bridge)
+		put_bridge(context->bridge);
 
-	put_bridge(func->slot->bridge);
+	if (context->func)
+		put_bridge(context->func->slot->bridge);
 }
 
 /* callback routine to register each ACPI PCI slot object */
@@ -390,7 +398,7 @@ static acpi_status register_slot(acpi_ha
 		 */
 		newfunc->flags &= ~FUNC_HAS_EJ0;
 		if (register_hotplug_dock_device(handle,
-			&acpiphp_dock_ops, newfunc,
+			&acpiphp_dock_ops, context,
 			acpiphp_dock_init, acpiphp_dock_release))
 			dbg("failed to register dock device\n");
 
@@ -982,24 +990,14 @@ void acpiphp_check_host_bridge(acpi_hand
 	acpiphp_put_context(context);
 }
 
-static void _handle_hotplug_event_bridge(struct work_struct *work)
+static void hotplug_event(acpi_handle handle, u32 type, void *data)
 {
-	struct acpiphp_context *context;
-	struct acpiphp_bridge *bridge;
+	struct acpiphp_context *context = data;
+	struct acpiphp_bridge *bridge = context->bridge;
+	struct acpiphp_func *func = context->func;
 	char objname[64];
 	struct acpi_buffer buffer = { .length = sizeof(objname),
 				      .pointer = objname };
-	struct acpi_hp_work *hp_work;
-	acpi_handle handle;
-	u32 type;
-
-	hp_work = container_of(work, struct acpi_hp_work, work);
-	handle = hp_work->handle;
-	type = hp_work->type;
-	context = hp_work->context;
-	bridge = context->bridge;
-
-	acpi_scan_lock_acquire();
 
 	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
 
@@ -1008,15 +1006,24 @@ static void _handle_hotplug_event_bridge
 		/* bus re-enumerate */
 		dbg("%s: Bus check notify on %s\n", __func__, objname);
 		dbg("%s: re-enumerating slots under %s\n", __func__, objname);
-		acpiphp_check_bridge(bridge);
-		acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
-			ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL);
+		if (bridge) {
+			acpiphp_check_bridge(bridge);
+			acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
+					    ACPI_UINT32_MAX, check_sub_bridges,
+					    NULL, NULL, NULL);
+		} else {
+			acpiphp_enable_slot(func->slot);
+		}
 		break;
 
 	case ACPI_NOTIFY_DEVICE_CHECK:
 		/* device check */
 		dbg("%s: Device check notify on %s\n", __func__, objname);
-		acpiphp_check_bridge(bridge);
+		if (bridge)
+			acpiphp_check_bridge(bridge);
+		else
+			acpiphp_check_bridge(func->slot->bridge);
+
 		break;
 
 	case ACPI_NOTIFY_DEVICE_WAKE:
@@ -1027,12 +1034,15 @@ static void _handle_hotplug_event_bridge
 	case ACPI_NOTIFY_EJECT_REQUEST:
 		/* request device eject */
 		dbg("%s: Device eject notify on %s\n", __func__, objname);
-		if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) {
-			struct acpiphp_slot *slot;
-			slot = bridge->func->slot;
-			if (!acpiphp_disable_slot(slot))
-				acpiphp_eject_slot(slot);
-		}
+		if (!func)
+			break;
+
+		if (bridge && !(bridge->flags & BRIDGE_HAS_EJ0))
+			break;
+
+		if (!(acpiphp_disable_slot(func->slot)))
+			acpiphp_eject_slot(func->slot);
+
 		break;
 
 	case ACPI_NOTIFY_FREQUENCY_MISMATCH:
@@ -1051,56 +1061,13 @@ static void _handle_hotplug_event_bridge
 		break;
 
 	default:
-		warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
+		warn("notify_handler: unknown event type 0x%x for %s\n", type,
+		     objname);
 		break;
 	}
-
-	acpi_scan_lock_release();
-	kfree(hp_work); /* allocated in handle_hotplug_event_bridge */
-	put_bridge(bridge);
 }
 
-static void hotplug_event_func(acpi_handle handle, u32 type, void *context)
-{
-	struct acpiphp_func *func = context;
-	char objname[64];
-	struct acpi_buffer buffer = { .length = sizeof(objname),
-				      .pointer = objname };
-
-	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-
-	switch (type) {
-	case ACPI_NOTIFY_BUS_CHECK:
-		/* bus re-enumerate */
-		dbg("%s: Bus check notify on %s\n", __func__, objname);
-		acpiphp_enable_slot(func->slot);
-		break;
-
-	case ACPI_NOTIFY_DEVICE_CHECK:
-		/* device check : re-enumerate from parent bus */
-		dbg("%s: Device check notify on %s\n", __func__, objname);
-		acpiphp_check_bridge(func->slot->bridge);
-		break;
-
-	case ACPI_NOTIFY_DEVICE_WAKE:
-		/* wake event */
-		dbg("%s: Device wake notify on %s\n", __func__, objname);
-		break;
-
-	case ACPI_NOTIFY_EJECT_REQUEST:
-		/* request device eject */
-		dbg("%s: Device eject notify on %s\n", __func__, objname);
-		if (!(acpiphp_disable_slot(func->slot)))
-			acpiphp_eject_slot(func->slot);
-		break;
-
-	default:
-		warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
-		break;
-	}
-}
-
-static void _handle_hotplug_event_func(struct work_struct *work)
+static void handle_hotplug_event_work_fn(struct work_struct *work)
 {
 	struct acpiphp_context *context;
 	struct acpi_hp_work *hp_work;
@@ -1109,11 +1076,16 @@ static void _handle_hotplug_event_func(s
 	context = hp_work->context;
 	acpi_scan_lock_acquire();
 
-	hotplug_event_func(hp_work->handle, hp_work->type, context->func);
+	hotplug_event(hp_work->handle, hp_work->type, context);
 
 	acpi_scan_lock_release();
-	kfree(hp_work); /* allocated in handle_hotplug_event_func */
-	put_bridge(context->func->slot->bridge);
+	kfree(hp_work); /* allocated in handle_hotplug_event() */
+	if (context->bridge)
+		put_bridge(context->bridge);
+
+	if (context->func)
+		put_bridge(context->func->slot->bridge);
+
 }
 
 /**
@@ -1127,17 +1099,16 @@ static void _handle_hotplug_event_func(s
 static void handle_hotplug_event(acpi_handle handle, u32 type, void *data)
 {
 	struct acpiphp_context *context = data;
-	void (*work_func)(struct work_struct *work);
 
-	if (context->bridge) {
-		get_bridge(context->bridge);
-		work_func = _handle_hotplug_event_bridge;
-	} else if (context->func) {
-		get_bridge(context->func->slot->bridge);
-		work_func = _handle_hotplug_event_func;
-	} else {
+	if (WARN_ON(!context->bridge && !context->func))
 		return;
-	}
+
+	if (context->func)
+		get_bridge(context->func->slot->bridge);
+
+	if (context->bridge)
+		get_bridge(context->bridge);
+
 	/*
 	 * Currently the code adds all hotplug events to the kacpid_wq
 	 * queue when it should add hotplug events to the kacpi_hotplug_wq.
@@ -1146,7 +1117,7 @@ static void handle_hotplug_event(acpi_ha
 	 * For now just re-add this work to the kacpi_hotplug_wq so we
 	 * don't deadlock on hotplug actions.
 	 */
-	alloc_acpi_hp_work(handle, type, context, work_func);
+	alloc_acpi_hp_work(handle, type, context, handle_hotplug_event_work_fn);
 }
 
 /*
@@ -1226,6 +1197,11 @@ void acpiphp_enumerate_slots(struct pci_
 		return;
 	}
 
+	/* If it has _DCK, there is a notify handler for it already. */
+	status = acpi_get_handle(bridge->handle, "_DCK", &handle);
+	if (ACPI_SUCCESS(status))
+		return;
+
 	/* install notify handler for P2P bridges */
 	status = acpi_install_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY,
 					     handle_hotplug_event, context);


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

* Re: [RFC][PATCH 4/8] ACPI / hotplug / PCI: Hotplug context objects for bridges and functions
  2013-07-09  0:18 ` [RFC][PATCH 4/8] ACPI / hotplug / PCI: Hotplug context objects for bridges and functions Rafael J. Wysocki
@ 2013-07-09  9:23   ` Mika Westerberg
  2013-07-09 23:54     ` [Update][RFC][PATCH " Rafael J. Wysocki
  0 siblings, 1 reply; 135+ messages in thread
From: Mika Westerberg @ 2013-07-09  9:23 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu

On Tue, Jul 09, 2013 at 02:18:12AM +0200, 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
                            ^^^^^^
                            typo

> 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 |  154 ++++++++++++++++++++++++++-----------
>  2 files changed, 121 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,20 @@ register_slot(acpi_handle handle, u32 lv
>  	if (!newfunc)
>  		return AE_NO_MEMORY;
>  
> +	context = acpiphp_get_context(handle);
> +	if (!context) {
> +		context = acpiphp_init_context(handle);

Since acpiphp_get_context() already does acpiphp_init_context() is the
above really necessary?

> +		if (!context) {
> +			acpi_handle_err(handle, "No 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 +344,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 +369,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 +417,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 +442,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 +1184,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 +1196,19 @@ void acpiphp_enumerate_slots(struct pci_
>  	if (!handle || detect_ejectable_slots(handle) <= 0)
>  		return;
>  
> +	context = acpiphp_get_context(handle);
> +	if (!context) {
> +		context = acpiphp_init_context(handle);

Ditto.

> +		if (!context) {
> +			acpi_handle_err(handle, "No 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;
>  	}

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

* Re: [RFC][PATCH 5/8] ACPI / hotplug / PCI: Unified notify handler for hotplug events
  2013-07-09  0:19 ` [RFC][PATCH 5/8] ACPI / hotplug / PCI: Unified notify handler for hotplug events Rafael J. Wysocki
@ 2013-07-09  9:30   ` Mika Westerberg
  2013-07-09 23:49     ` Rafael J. Wysocki
  0 siblings, 1 reply; 135+ messages in thread
From: Mika Westerberg @ 2013-07-09  9:30 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu

On Tue, Jul 09, 2013 at 02:19:04AM +0200, Rafael J. Wysocki wrote:
> 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;

Hmm, should it be just plain:

	bool handler_for_func;

? What's the reason using bitfields for bool?

>  };

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

* Re: [RFC][PATCH 6/8] ACPI / hotplug / PCI: Drop acpiphp_handle_to_bridge()
  2013-07-09  0:20 ` [RFC][PATCH 6/8] ACPI / hotplug / PCI: Drop acpiphp_handle_to_bridge() Rafael J. Wysocki
@ 2013-07-09  9:37   ` Mika Westerberg
  2013-07-09 23:46     ` Rafael J. Wysocki
  0 siblings, 1 reply; 135+ messages in thread
From: Mika Westerberg @ 2013-07-09  9:37 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu

On Tue, Jul 09, 2013 at 02:20:31AM +0200, Rafael J. Wysocki wrote:
> @@ -953,37 +937,49 @@ static void acpiphp_sanitize_bus(struct
>   * ACPI event handlers
>   */
>  
> -static acpi_status
> -check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
> +static acpi_status check_sub_bridges(acpi_handle handle, u32 lvl, void *data,
> +				     void **rv)
>  {
> -	struct acpiphp_bridge *bridge;
> -	char objname[64];
> -	struct acpi_buffer buffer = { .length = sizeof(objname),
> -				      .pointer = objname };
> +	struct acpiphp_context *context = acpiphp_get_context(handle);
> +
> +	if (!context)
> +		return AE_OK;
>  
> -	bridge = acpiphp_handle_to_bridge(handle);
> -	if (bridge) {
> +	if (context->bridge) {
> +		struct acpiphp_bridge *bridge = context->bridge;
> +		char objname[64];
> +		struct acpi_buffer buffer = { .length = sizeof(objname),
> +					      .pointer = objname };
> +
> +		get_bridge(bridge);
>  		acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
> -		dbg("%s: re-enumerating slots under %s\n",
> -			__func__, objname);
> +		dbg("%s: re-enumerating slots under %s\n", __func__, objname);

Although not related to this patch directly, how about using
acpi_handle_debug() or similar here?

>  		acpiphp_check_bridge(bridge);
>  		put_bridge(bridge);
>  	}
> +	acpiphp_put_context(context);
>  	return AE_OK ;
>  }

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

* Re: [RFC][PATCH 6/8] ACPI / hotplug / PCI: Drop acpiphp_handle_to_bridge()
  2013-07-09  9:37   ` Mika Westerberg
@ 2013-07-09 23:46     ` Rafael J. Wysocki
  0 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-09 23:46 UTC (permalink / raw)
  To: Mika Westerberg
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu

On Tuesday, July 09, 2013 12:37:26 PM Mika Westerberg wrote:
> On Tue, Jul 09, 2013 at 02:20:31AM +0200, Rafael J. Wysocki wrote:
> > @@ -953,37 +937,49 @@ static void acpiphp_sanitize_bus(struct
> >   * ACPI event handlers
> >   */
> >  
> > -static acpi_status
> > -check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
> > +static acpi_status check_sub_bridges(acpi_handle handle, u32 lvl, void *data,
> > +				     void **rv)
> >  {
> > -	struct acpiphp_bridge *bridge;
> > -	char objname[64];
> > -	struct acpi_buffer buffer = { .length = sizeof(objname),
> > -				      .pointer = objname };
> > +	struct acpiphp_context *context = acpiphp_get_context(handle);
> > +
> > +	if (!context)
> > +		return AE_OK;
> >  
> > -	bridge = acpiphp_handle_to_bridge(handle);
> > -	if (bridge) {
> > +	if (context->bridge) {
> > +		struct acpiphp_bridge *bridge = context->bridge;
> > +		char objname[64];
> > +		struct acpi_buffer buffer = { .length = sizeof(objname),
> > +					      .pointer = objname };
> > +
> > +		get_bridge(bridge);
> >  		acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
> > -		dbg("%s: re-enumerating slots under %s\n",
> > -			__func__, objname);
> > +		dbg("%s: re-enumerating slots under %s\n", __func__, objname);
> 
> Although not related to this patch directly, how about using
> acpi_handle_debug() or similar here?

Well, we don't have acpi_handle_debug() and I remember there was a reason why,
but I can't recall what the reason was at the moment. :-)

> >  		acpiphp_check_bridge(bridge);
> >  		put_bridge(bridge);
> >  	}
> > +	acpiphp_put_context(context);
> >  	return AE_OK ;
> >  }
-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

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

* Re: [RFC][PATCH 5/8] ACPI / hotplug / PCI: Unified notify handler for hotplug events
  2013-07-09  9:30   ` Mika Westerberg
@ 2013-07-09 23:49     ` Rafael J. Wysocki
  0 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-09 23:49 UTC (permalink / raw)
  To: Mika Westerberg
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu

On Tuesday, July 09, 2013 12:30:45 PM Mika Westerberg wrote:
> On Tue, Jul 09, 2013 at 02:19:04AM +0200, Rafael J. Wysocki wrote:
> > 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;
> 
> Hmm, should it be just plain:
> 
> 	bool handler_for_func;
> 
> ? What's the reason using bitfields for bool?

If there are more of them, they can be stored together in one int (they are
unsigned int under the hood).

I this particular case it doesn't matter and one of subsequent patches will
remove that field anyway. :-)

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

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

* [Update][RFC][PATCH 4/8] ACPI / hotplug / PCI: Hotplug context objects for bridges and functions
  2013-07-09  9:23   ` Mika Westerberg
@ 2013-07-09 23:54     ` Rafael J. Wysocki
  0 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-09 23:54 UTC (permalink / raw)
  To: Mika Westerberg
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu

On Tuesday, July 09, 2013 12:23:53 PM Mika Westerberg wrote:
> On Tue, Jul 09, 2013 at 02:18:12AM +0200, 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
>                             ^^^^^^
>                             typo
> 

Yup, thanks!

> > 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>
> > ---

[...]

> >  /* 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,20 @@ register_slot(acpi_handle handle, u32 lv
> >  	if (!newfunc)
> >  		return AE_NO_MEMORY;
> >  
> > +	context = acpiphp_get_context(handle);
> > +	if (!context) {
> > +		context = acpiphp_init_context(handle);
> 
> Since acpiphp_get_context() already does acpiphp_init_context() is the
> above really necessary?

Hmm, acpiphp_get_context() wasn't supposed to be doing that.

Well, I guess I just forgot to remove that part.  Updated patch is appended.

Thanks,
Rafael

---
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Subject: ACPI / hotplug / PCI: Hotplug context objects for bridges and functions

When either a new hotplug bridge 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 |  152 ++++++++++++++++++++++++++-----------
 2 files changed, 119 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,59 @@ 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);
+	}
+	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 +144,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 +153,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 +256,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 +291,20 @@ register_slot(acpi_handle handle, u32 lv
 	if (!newfunc)
 		return AE_NO_MEMORY;
 
+	context = acpiphp_get_context(handle);
+	if (!context) {
+		context = acpiphp_init_context(handle);
+		if (!context) {
+			acpi_handle_err(handle, "No 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,19 @@ void acpiphp_enumerate_slots(struct pci_
 	if (!handle || detect_ejectable_slots(handle) <= 0)
 		return;
 
+	context = acpiphp_get_context(handle);
+	if (!context) {
+		context = acpiphp_init_context(handle);
+		if (!context) {
+			acpi_handle_err(handle, "No 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 +1215,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 +1250,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] 135+ messages in thread

* [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds
  2013-07-09  0:01 [RFC][PATCH 0/8] ACPI / hotplug / PCI: Consolidation of handling notifications (in progress) Rafael J. Wysocki
                   ` (7 preceding siblings ...)
  2013-07-09  0:22 ` [RFC][PATCH 8/8] ACPI / hotplug / PCI: Merge hotplug event handling functions Rafael J. Wysocki
@ 2013-07-11 23:34 ` Rafael J. Wysocki
  2013-07-11 23:36   ` [RFC][PATCH 1/30] ACPI / PCI: Make bus registration and unregistration symmetric Rafael J. Wysocki
                     ` (31 more replies)
  8 siblings, 32 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-11 23:34 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

Hi,

I've made some progress with my ACPIPHP rework since I posted the series last
time and here goes an update.

First off, the previous series was somewhat racy, which should be fixed now.
Apart from this there's quite some new material on top of the patches I posted
last time (or rather on top of their new versions) and I integrated the
Thunderbolt series from Mika with that.  As a result,

https://patchwork.kernel.org/patch/2817341/

is required to be applied.

Still untested, still based on 3.10 with ACPI+PM 3.11 material merged on top,
but this time I don't have any plans to add more patches to the series for the
time being.  Also 3.11-rc1 should be out in a couple of days, so I'll be able
to integrate this work with the previous cleanups series from Gerry and myself
on top of it.

I did my best not to change too much at a time and some steps add stuff that
is removed by the subsequent ones, so hopefully it is bisectable.

If anyone finds something questionable or outright bogus in these patches,
please let me know before it's too late. ;-)

[ 1/30] Make bus registration and unregistration symmetric.  [Resend]
[ 2/30] Consolidate acpiphp_enumerate_slots().  [Resend]
[ 3/30] Fix error code path in register_slot().  [Resend]
[ 4/30] Introduce hotplug context objects for ACPI device objects corresponding
        to PCI hotplug devices.  [Update]
[ 5/30] Unified notify handler for hotplug events.  [Update]
[ 6/30] Drop acpiphp_handle_to_bridge() and use context objects instead of it.  [Update]
[ 7/30] Pass entire hotplug context objects (instead of their fields
        individually) to event handling work functions.  [Update]
[ 8/30] Merge hotplug event handling functions.  [Update]
[ 9/30] Drop func field from struct acpiphp_bridge.
[10/30] Refactor slot allocation code in register_slot().
[11/30] Make acpiphp_enumerate_slots() to register all devices on the given bus
        and install the notification handler for all of them.
[12/30] Drop sun field from struct acpiphp_slot.
[13/30] Use common slot count variable in register_slot().
[14/30] Drop flags field from struct acpiphp_bridge.
[15/30] Embed function structure into struct acpiphp_context.
[16/30] Drop handle field from struct acpiphp_func.
[17/30] Drop handle field from struct acpiphp_bridge.
[18/30] Store parent bridge pointer in function objects and bus pointer in slot
        objects.
[19/30] Rework ACPI namespace scanning and trimming routines.
[20/30] Drop redundant checks from check_hotplug_bridge().
[21/30] Consolidate slot disabling and ejecting
[22/30] Do not queue up event handling work items for non-hotplug events.
[23/30] Do not execute _PS0 and _PS3 directly.
[24/30] Do not check SLOT_ENABLED in enable_device().  [Thunderbolt series]
[25/30] Allow slots without new devices to be rescanned.  [Thunderbolt series]
[26/30] Check for new devices on enabled slots.  [Thunderbolt series, TBD]
[27/30] Get rid of unused constands in acpiphp.h.  [Thunderbolt series]
[28/30] Sanitize acpiphp_get_(latch)|(adapter)_status().  [Thunderbolt series]
[29/30] Redefine enable_device() and disable_device() (rename and change to void).
[30/30] Clean up the usage of bridge_mutex.

Patch [26/30] seems to go over the top with dropping the non-responsive devices
and it probaby needs some more thought.  Also the algorithm of bus checks and
device checks may need to be improved in the future, but for the time being I
think it is good enough.

Comments welcome!

Rafael


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

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

* [RFC][PATCH 1/30] ACPI / PCI: Make bus registration and unregistration symmetric
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
@ 2013-07-11 23:36   ` Rafael J. Wysocki
  2013-07-11 23:37   ` [RFC][PATCH 2/30] ACPI / hotplug / PCI: Consolidate acpiphp_enumerate_slots() Rafael J. Wysocki
                     ` (30 subsequent siblings)
  31 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-11 23:36 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

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] 135+ messages in thread

* [RFC][PATCH 2/30] ACPI / hotplug / PCI: Consolidate acpiphp_enumerate_slots()
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
  2013-07-11 23:36   ` [RFC][PATCH 1/30] ACPI / PCI: Make bus registration and unregistration symmetric Rafael J. Wysocki
@ 2013-07-11 23:37   ` Rafael J. Wysocki
  2013-07-11 23:38   ` [RFC][PATCH 3/30] ACPI / hotplug / PCI: Always return success after adding a function Rafael J. Wysocki
                     ` (29 subsequent siblings)
  31 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-11 23:37 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

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] 135+ messages in thread

* [RFC][PATCH 3/30] ACPI / hotplug / PCI: Always return success after adding a function
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
  2013-07-11 23:36   ` [RFC][PATCH 1/30] ACPI / PCI: Make bus registration and unregistration symmetric Rafael J. Wysocki
  2013-07-11 23:37   ` [RFC][PATCH 2/30] ACPI / hotplug / PCI: Consolidate acpiphp_enumerate_slots() Rafael J. Wysocki
@ 2013-07-11 23:38   ` Rafael J. Wysocki
  2013-07-11 23:39   ` [RFC][PATCH 4/30] ACPI / hotplug / PCI: Hotplug context objects for bridges and functions Rafael J. Wysocki
                     ` (28 subsequent siblings)
  31 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-11 23:38 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, 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] 135+ messages in thread

* [RFC][PATCH 4/30] ACPI / hotplug / PCI: Hotplug context objects for bridges and functions
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
                     ` (2 preceding siblings ...)
  2013-07-11 23:38   ` [RFC][PATCH 3/30] ACPI / hotplug / PCI: Always return success after adding a function Rafael J. Wysocki
@ 2013-07-11 23:39   ` Rafael J. Wysocki
  2013-07-11 23:40   ` [RFC][PATCH 5/30] ACPI / hotplug / PCI: Unified notify handler for hotplug events Rafael J. Wysocki
                     ` (27 subsequent siblings)
  31 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-11 23:39 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

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

When either a new hotplug bridge 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 |  180 +++++++++++++++++++++++++++----------
 2 files changed, 146 insertions(+), 44 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 {
+	acpi_handle handle;
+	struct acpiphp_func *func;
+	struct acpiphp_bridge *bridge;
+	unsigned int refcount;
+};
+
 /*
  * 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
@@ -55,6 +55,7 @@
 
 static LIST_HEAD(bridge_list);
 static DEFINE_MUTEX(bridge_mutex);
+static DEFINE_MUTEX(acpiphp_context_lock);
 
 #define MY_NAME "acpiphp_glue"
 
@@ -79,6 +80,74 @@ is_pci_dock_device(acpi_handle handle, u
 	}
 }
 
+static void acpiphp_context_handler(acpi_handle handle, void *context)
+{
+	/* Intentionally empty. */
+}
+
+/**
+ * acpiphp_init_context - Create hotplug context and grab a reference to it.
+ * @handle: ACPI object handle to create the context for.
+ *
+ * Call under acpiphp_context_lock.
+ */
+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;
+	context->refcount = 1;
+	status = acpi_attach_data(handle, acpiphp_context_handler, context);
+	if (ACPI_FAILURE(status)) {
+		kfree(context);
+		return NULL;
+	}
+	return context;
+}
+
+/**
+ * acpiphp_get_context - Get hotplug context and grab a reference to it.
+ * @handle: ACPI object handle to get the context for.
+ *
+ * Call under acpiphp_context_lock.
+ */
+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;
+		context->refcount++;
+	}
+	return context;
+}
+
+/**
+ * acpiphp_put_context - Drop a reference to ACPI hotplug context.
+ * @handle: ACPI object handle to put the context for.
+ *
+ * The context object is removed if there are no more references to it.
+ *
+ * Call under acpiphp_context_lock.
+ */
+static void acpiphp_put_context(struct acpiphp_context *context)
+{
+	if (--context->refcount)
+		return;
+
+	WARN_ON(context->func || context->bridge);
+	acpi_detach_data(context->handle, acpiphp_context_handler);
+	kfree(context);
+}
+
 static inline void get_bridge(struct acpiphp_bridge *bridge)
 {
 	kref_get(&bridge->ref);
@@ -91,25 +160,37 @@ 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;
 
+	mutex_lock(&acpiphp_context_lock);
+
 	bridge = container_of(kref, struct acpiphp_bridge, ref);
 
 	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;
+			acpiphp_put_context(context);
 			kfree(func);
 		}
 		kfree(slot);
 	}
 
-	/* Release reference acquired by acpiphp_bridge_handle_to_function() */
+	/* Release the 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;
+	acpiphp_put_context(context);
 	kfree(bridge);
+
+	mutex_unlock(&acpiphp_context_lock);
 }
 
 /*
@@ -195,10 +276,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 = data;
+	struct acpiphp_context *context;
 	struct acpiphp_slot *slot;
 	struct acpiphp_func *newfunc;
 	acpi_handle tmp;
@@ -232,6 +314,18 @@ register_slot(acpi_handle handle, u32 lv
 	newfunc->handle = handle;
 	newfunc->function = function;
 
+	mutex_lock(&acpiphp_context_lock);
+	context = acpiphp_init_context(handle);
+	if (!context) {
+		mutex_unlock(&acpiphp_context_lock);
+		acpi_handle_err(handle, "No hotplug context\n");
+		kfree(newfunc);
+		return AE_NOT_EXIST;
+	}
+	newfunc->context = context;
+	context->func = newfunc;
+	mutex_unlock(&acpiphp_context_lock);
+
 	if (ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp)))
 		newfunc->flags = FUNC_HAS_EJ0;
 
@@ -268,8 +362,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 +387,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 +435,20 @@ 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);
-	kfree(newfunc);
 
-	return AE_OK;
+ err_out:
+	mutex_lock(&acpiphp_context_lock);
+	context->func = NULL;
+	acpiphp_put_context(context);
+	mutex_unlock(&acpiphp_context_lock);
+	kfree(newfunc);
+	return status;
 }
 
 
@@ -362,32 +463,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 +1205,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;
@@ -1142,8 +1218,8 @@ void acpiphp_enumerate_slots(struct pci_
 		return;
 
 	bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
-	if (bridge == NULL) {
-		err("out of memory\n");
+	if (!bridge) {
+		acpi_handle_err(handle, "No memory for bridge object\n");
 		return;
 	}
 
@@ -1153,6 +1229,21 @@ void acpiphp_enumerate_slots(struct pci_
 	bridge->pci_dev = pci_dev_get(bus->self);
 	bridge->pci_bus = bus;
 
+	mutex_lock(&acpiphp_context_lock);
+	context = acpiphp_get_context(handle);
+	if (!context) {
+		context = acpiphp_init_context(handle);
+		if (!context) {
+			mutex_unlock(&acpiphp_context_lock);
+			acpi_handle_err(handle, "No hotplug context\n");
+			kfree(bridge);
+			return;
+		}
+	}
+	bridge->context = context;
+	context->bridge = bridge;
+	mutex_unlock(&acpiphp_context_lock);
+
 	/*
 	 * Grab a ref to the subordinate PCI bus in case the bus is
 	 * removed via PCI core logical hotplug. The ref pins the bus
@@ -1185,20 +1276,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] 135+ messages in thread

* [RFC][PATCH 5/30] ACPI / hotplug / PCI: Unified notify handler for hotplug events
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
                     ` (3 preceding siblings ...)
  2013-07-11 23:39   ` [RFC][PATCH 4/30] ACPI / hotplug / PCI: Hotplug context objects for bridges and functions Rafael J. Wysocki
@ 2013-07-11 23:40   ` Rafael J. Wysocki
  2013-07-11 23:44   ` [RFC][PATCH 6/30] ACPI / hotplug / PCI: Rework acpiphp_handle_to_bridge() Rafael J. Wysocki
                     ` (26 subsequent siblings)
  31 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-11 23:40 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, 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.  Moreover, it fixes a theoretically possible race between
handle_hotplug_event() and free_bridge() tearing down data structures
for the same handle.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp.h      |    1 
 drivers/pci/hotplug/acpiphp_glue.c |  133 ++++++++++++++-----------------------
 2 files changed, 54 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
@@ -59,11 +59,10 @@ static DEFINE_MUTEX(acpiphp_context_lock
 
 #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 */
@@ -179,13 +178,13 @@ static void free_bridge(struct kref *kre
 		kfree(slot);
 	}
 
+	context = bridge->context;
 	/* Release the 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;
 	acpiphp_put_context(context);
 	kfree(bridge);
@@ -424,12 +423,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");
 	}
 
@@ -486,23 +485,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)) {
@@ -510,9 +499,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");
 			}
@@ -1093,31 +1083,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;
@@ -1175,17 +1140,33 @@ 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;
+	void (*work_func)(struct work_struct *work) = NULL;
+
+	mutex_lock(&acpiphp_context_lock);
+	context = acpiphp_get_context(handle);
+	if (context) {
+		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;
+		}
+		acpiphp_put_context(context);
+	}
+	mutex_unlock(&acpiphp_context_lock);
 
 	/*
 	 * Currently the code adds all hotplug events to the kacpid_wq
@@ -1195,8 +1176,8 @@ 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);
+	if (work_func)
+		alloc_acpi_hp_work(handle, type, data, work_func);
 }
 
 /*
@@ -1267,33 +1248,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, NULL);
+	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 {
 	struct acpiphp_func *func;
 	struct acpiphp_bridge *bridge;
 	unsigned int refcount;
+	bool handler_for_func;
 };
 
 /*

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

* [RFC][PATCH 6/30] ACPI / hotplug / PCI: Rework acpiphp_handle_to_bridge()
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
                     ` (4 preceding siblings ...)
  2013-07-11 23:40   ` [RFC][PATCH 5/30] ACPI / hotplug / PCI: Unified notify handler for hotplug events Rafael J. Wysocki
@ 2013-07-11 23:44   ` Rafael J. Wysocki
  2013-07-11 23:45   ` [RFC][PATCH 7/30] ACPI / hotplug / PCI: Pass hotplug context objects to event handlers Rafael J. Wysocki
                     ` (25 subsequent siblings)
  31 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-11 23:44 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

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

Using the hotplug context objects introduced previously rework the
ACPI-based PCI hotplug (ACPIPHP) core code to get to acpiphp_bridge
objects associated with hotplug bridges from those context objects
rather than from the global list of hotplug bridges.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp_glue.c |   20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 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
@@ -464,18 +464,20 @@ static int detect_ejectable_slots(acpi_h
 
 static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle)
 {
-	struct acpiphp_bridge *bridge;
+	struct acpiphp_context *context;
+	struct acpiphp_bridge *bridge = NULL;
 
-	mutex_lock(&bridge_mutex);
-	list_for_each_entry(bridge, &bridge_list, list)
-		if (bridge->handle == handle) {
+	mutex_lock(&acpiphp_context_lock);
+	context = acpiphp_get_context(handle);
+	if (context) {
+		bridge = context->bridge;
+		if (bridge)
 			get_bridge(bridge);
-			mutex_unlock(&bridge_mutex);
-			return bridge;
-		}
-	mutex_unlock(&bridge_mutex);
 
-	return NULL;
+		acpiphp_put_context(context);
+	}
+	mutex_unlock(&acpiphp_context_lock);
+	return bridge;
 }
 
 static void cleanup_bridge(struct acpiphp_bridge *bridge)

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

* [RFC][PATCH 7/30] ACPI / hotplug / PCI: Pass hotplug context objects to event handlers
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
                     ` (5 preceding siblings ...)
  2013-07-11 23:44   ` [RFC][PATCH 6/30] ACPI / hotplug / PCI: Rework acpiphp_handle_to_bridge() Rafael J. Wysocki
@ 2013-07-11 23:45   ` Rafael J. Wysocki
  2013-07-11 23:47   ` [RFC][PATCH 8/30] ACPI / hotplug / PCI: Merge hotplug event handling functions Rafael J. Wysocki
                     ` (24 subsequent siblings)
  31 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-11 23:45 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

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

Modify handle_hotplug_event() to pass the entire context object
(instead of its fields individually) to work functions started by it.

This change makes the subsequent consolidation of the event handling
work functions a bit more straightforward.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp_glue.c |   16 ++++++++--------
 1 file changed, 8 insertions(+), 8 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
@@ -1011,6 +1011,7 @@ void acpiphp_check_host_bridge(acpi_hand
 
 static void _handle_hotplug_event_bridge(struct work_struct *work)
 {
+	struct acpiphp_context *context;
 	struct acpiphp_bridge *bridge;
 	char objname[64];
 	struct acpi_buffer buffer = { .length = sizeof(objname),
@@ -1022,7 +1023,8 @@ static void _handle_hotplug_event_bridge
 	hp_work = container_of(work, struct acpi_hp_work, work);
 	handle = hp_work->handle;
 	type = hp_work->type;
-	bridge = (struct acpiphp_bridge *)hp_work->context;
+	context = hp_work->context;
+	bridge = context->bridge;
 
 	acpi_scan_lock_acquire();
 
@@ -1127,18 +1129,18 @@ static void hotplug_event_func(acpi_hand
 
 static void _handle_hotplug_event_func(struct work_struct *work)
 {
+	struct acpiphp_context *context;
 	struct acpi_hp_work *hp_work;
-	struct acpiphp_func *func;
 
 	hp_work = container_of(work, struct acpi_hp_work, work);
-	func = hp_work->context;
+	context = hp_work->context;
 	acpi_scan_lock_acquire();
 
-	hotplug_event_func(hp_work->handle, hp_work->type, func);
+	hotplug_event_func(hp_work->handle, hp_work->type, context->func);
 
 	acpi_scan_lock_release();
 	kfree(hp_work); /* allocated in handle_hotplug_event_func */
-	put_bridge(func->slot->bridge);
+	put_bridge(context->func->slot->bridge);
 }
 
 /**
@@ -1159,11 +1161,9 @@ static void handle_hotplug_event(acpi_ha
 	if (context) {
 		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;
 		}
 		acpiphp_put_context(context);
@@ -1179,7 +1179,7 @@ static void handle_hotplug_event(acpi_ha
 	 * don't deadlock on hotplug actions.
 	 */
 	if (work_func)
-		alloc_acpi_hp_work(handle, type, data, work_func);
+		alloc_acpi_hp_work(handle, type, context, work_func);
 }
 
 /*


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

* [RFC][PATCH 8/30] ACPI / hotplug / PCI: Merge hotplug event handling functions
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
                     ` (6 preceding siblings ...)
  2013-07-11 23:45   ` [RFC][PATCH 7/30] ACPI / hotplug / PCI: Pass hotplug context objects to event handlers Rafael J. Wysocki
@ 2013-07-11 23:47   ` Rafael J. Wysocki
  2013-07-11 23:48   ` [RFC][PATCH 9/30] ACPI / hotplug / PCI: Drop func field from struct acpiphp_bridge Rafael J. Wysocki
                     ` (23 subsequent siblings)
  31 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-11 23:47 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

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

There are separate handling event functions for hotplug bridges and
for hotplug functions, but they may be combined into one common
hotplug event handling function which simplifies the code slightly.

That also allows a theoretical bug to be dealt with which in
principle may occur if a hotplug bridge is on a dock station, because
in that case the bridge-specific notification should be used instead
of the function-specific one, but the dock station always uses the
latter.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp_glue.c |  148 +++++++++++++++----------------------
 1 file changed, 63 insertions(+), 85 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
@@ -62,7 +62,7 @@ static DEFINE_MUTEX(acpiphp_context_lock
 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 hotplug_event(acpi_handle handle, u32 type, void *data);
 static void free_bridge(struct kref *kref);
 
 /* callback routine to check for the existence of a pci dock device */
@@ -228,7 +228,7 @@ static int post_dock_fixups(struct notif
 
 
 static const struct acpi_dock_ops acpiphp_dock_ops = {
-	.handler = hotplug_event_func,
+	.handler = hotplug_event,
 };
 
 /* Check whether the PCI device is managed by native PCIe hotplug driver */
@@ -262,16 +262,16 @@ static bool device_is_managed_by_native_
 
 static void acpiphp_dock_init(void *data)
 {
-	struct acpiphp_func *func = data;
+	struct acpiphp_context *context = data;
 
-	get_bridge(func->slot->bridge);
+	get_bridge(context->func->slot->bridge);
 }
 
 static void acpiphp_dock_release(void *data)
 {
-	struct acpiphp_func *func = data;
+	struct acpiphp_context *context = data;
 
-	put_bridge(func->slot->bridge);
+	put_bridge(context->func->slot->bridge);
 }
 
 /* callback routine to register each ACPI PCI slot object */
@@ -408,7 +408,7 @@ static acpi_status register_slot(acpi_ha
 		 */
 		newfunc->flags &= ~FUNC_HAS_EJ0;
 		if (register_hotplug_dock_device(handle,
-			&acpiphp_dock_ops, newfunc,
+			&acpiphp_dock_ops, context,
 			acpiphp_dock_init, acpiphp_dock_release))
 			dbg("failed to register dock device\n");
 
@@ -1009,24 +1009,26 @@ void acpiphp_check_host_bridge(acpi_hand
 		ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL);
 }
 
-static void _handle_hotplug_event_bridge(struct work_struct *work)
+static void hotplug_event(acpi_handle handle, u32 type, void *data)
 {
-	struct acpiphp_context *context;
+	struct acpiphp_context *context = data;
 	struct acpiphp_bridge *bridge;
+	struct acpiphp_func *func;
 	char objname[64];
 	struct acpi_buffer buffer = { .length = sizeof(objname),
 				      .pointer = objname };
-	struct acpi_hp_work *hp_work;
-	acpi_handle handle;
-	u32 type;
 
-	hp_work = container_of(work, struct acpi_hp_work, work);
-	handle = hp_work->handle;
-	type = hp_work->type;
-	context = hp_work->context;
+	mutex_lock(&acpiphp_context_lock);
 	bridge = context->bridge;
+	if (bridge)
+		get_bridge(bridge);
 
-	acpi_scan_lock_acquire();
+	/*
+	 * If context->func is not NULL, we are holding a reference to its
+	 * parent bridge, so it won't go away until we drop that reference.
+	 */
+	func = context->func;
+	mutex_unlock(&acpiphp_context_lock);
 
 	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
 
@@ -1035,15 +1037,24 @@ static void _handle_hotplug_event_bridge
 		/* bus re-enumerate */
 		dbg("%s: Bus check notify on %s\n", __func__, objname);
 		dbg("%s: re-enumerating slots under %s\n", __func__, objname);
-		acpiphp_check_bridge(bridge);
-		acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
-			ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL);
+		if (bridge) {
+			acpiphp_check_bridge(bridge);
+			acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
+					    ACPI_UINT32_MAX, check_sub_bridges,
+					    NULL, NULL, NULL);
+		} else {
+			acpiphp_enable_slot(func->slot);
+		}
 		break;
 
 	case ACPI_NOTIFY_DEVICE_CHECK:
 		/* device check */
 		dbg("%s: Device check notify on %s\n", __func__, objname);
-		acpiphp_check_bridge(bridge);
+		if (bridge)
+			acpiphp_check_bridge(bridge);
+		else
+			acpiphp_check_bridge(func->slot->bridge);
+
 		break;
 
 	case ACPI_NOTIFY_DEVICE_WAKE:
@@ -1054,12 +1065,15 @@ static void _handle_hotplug_event_bridge
 	case ACPI_NOTIFY_EJECT_REQUEST:
 		/* request device eject */
 		dbg("%s: Device eject notify on %s\n", __func__, objname);
-		if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) {
-			struct acpiphp_slot *slot;
-			slot = bridge->func->slot;
-			if (!acpiphp_disable_slot(slot))
-				acpiphp_eject_slot(slot);
-		}
+		if (!func)
+			break;
+
+		if (bridge && !(bridge->flags & BRIDGE_HAS_EJ0))
+			break;
+
+		if (!(acpiphp_disable_slot(func->slot)))
+			acpiphp_eject_slot(func->slot);
+
 		break;
 
 	case ACPI_NOTIFY_FREQUENCY_MISMATCH:
@@ -1078,56 +1092,16 @@ static void _handle_hotplug_event_bridge
 		break;
 
 	default:
-		warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
+		warn("notify_handler: unknown event type 0x%x for %s\n", type,
+		     objname);
 		break;
 	}
 
-	acpi_scan_lock_release();
-	kfree(hp_work); /* allocated in handle_hotplug_event_bridge */
-	put_bridge(bridge);
-}
-
-static void hotplug_event_func(acpi_handle handle, u32 type, void *context)
-{
-	struct acpiphp_func *func = context;
-	char objname[64];
-	struct acpi_buffer buffer = { .length = sizeof(objname),
-				      .pointer = objname };
-
-	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-
-	switch (type) {
-	case ACPI_NOTIFY_BUS_CHECK:
-		/* bus re-enumerate */
-		dbg("%s: Bus check notify on %s\n", __func__, objname);
-		acpiphp_enable_slot(func->slot);
-		break;
-
-	case ACPI_NOTIFY_DEVICE_CHECK:
-		/* device check : re-enumerate from parent bus */
-		dbg("%s: Device check notify on %s\n", __func__, objname);
-		acpiphp_check_bridge(func->slot->bridge);
-		break;
-
-	case ACPI_NOTIFY_DEVICE_WAKE:
-		/* wake event */
-		dbg("%s: Device wake notify on %s\n", __func__, objname);
-		break;
-
-	case ACPI_NOTIFY_EJECT_REQUEST:
-		/* request device eject */
-		dbg("%s: Device eject notify on %s\n", __func__, objname);
-		if (!(acpiphp_disable_slot(func->slot)))
-			acpiphp_eject_slot(func->slot);
-		break;
-
-	default:
-		warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
-		break;
-	}
+	if (bridge)
+		put_bridge(bridge);
 }
 
-static void _handle_hotplug_event_func(struct work_struct *work)
+static void hotplug_event_work(struct work_struct *work)
 {
 	struct acpiphp_context *context;
 	struct acpi_hp_work *hp_work;
@@ -1136,11 +1110,18 @@ static void _handle_hotplug_event_func(s
 	context = hp_work->context;
 	acpi_scan_lock_acquire();
 
-	hotplug_event_func(hp_work->handle, hp_work->type, context->func);
+	hotplug_event(hp_work->handle, hp_work->type, context);
 
 	acpi_scan_lock_release();
-	kfree(hp_work); /* allocated in handle_hotplug_event_func */
-	put_bridge(context->func->slot->bridge);
+	kfree(hp_work); /* allocated in handle_hotplug_event() */
+
+	mutex_lock(&acpiphp_context_lock);
+	if (context->func)
+		put_bridge(context->func->slot->bridge);
+	else
+		acpiphp_put_context(context);
+
+	mutex_unlock(&acpiphp_context_lock);
 }
 
 /**
@@ -1154,22 +1135,19 @@ static void _handle_hotplug_event_func(s
 static void handle_hotplug_event(acpi_handle handle, u32 type, void *data)
 {
 	struct acpiphp_context *context;
-	void (*work_func)(struct work_struct *work) = NULL;
 
 	mutex_lock(&acpiphp_context_lock);
 	context = acpiphp_get_context(handle);
 	if (context) {
-		if (context->bridge) {
-			get_bridge(context->bridge);
-			work_func = _handle_hotplug_event_bridge;
-		} else if (context->func) {
+		if (context->func) {
 			get_bridge(context->func->slot->bridge);
-			work_func = _handle_hotplug_event_func;
+			acpiphp_put_context(context);
+		} else if (!context->bridge) {
+			acpiphp_put_context(context);
+			context = NULL;
 		}
-		acpiphp_put_context(context);
 	}
 	mutex_unlock(&acpiphp_context_lock);
-
 	/*
 	 * Currently the code adds all hotplug events to the kacpid_wq
 	 * queue when it should add hotplug events to the kacpi_hotplug_wq.
@@ -1178,8 +1156,8 @@ static void handle_hotplug_event(acpi_ha
 	 * For now just re-add this work to the kacpi_hotplug_wq so we
 	 * don't deadlock on hotplug actions.
 	 */
-	if (work_func)
-		alloc_acpi_hp_work(handle, type, context, work_func);
+	if (context)
+		alloc_acpi_hp_work(handle, type, context, hotplug_event_work);
 }
 
 /*

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

* [RFC][PATCH 9/30] ACPI / hotplug / PCI: Drop func field from struct acpiphp_bridge
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
                     ` (7 preceding siblings ...)
  2013-07-11 23:47   ` [RFC][PATCH 8/30] ACPI / hotplug / PCI: Merge hotplug event handling functions Rafael J. Wysocki
@ 2013-07-11 23:48   ` Rafael J. Wysocki
  2013-07-11 23:49   ` [RFC][PATCH 10/30] ACPI / hotplug / PCI: Refactor slot allocation code in register_slot() Rafael J. Wysocki
                     ` (22 subsequent siblings)
  31 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-11 23:48 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

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

Since the func pointer in struct acpiphp_context can always be used
instead of the func pointer in struct acpiphp_bridge, drop the
latter.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp.h      |    2 --
 drivers/pci/hotplug/acpiphp_glue.c |    3 +--
 2 files changed, 1 insertion(+), 4 deletions(-)

Index: linux-pm/drivers/pci/hotplug/acpiphp.h
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
+++ linux-pm/drivers/pci/hotplug/acpiphp.h
@@ -79,8 +79,6 @@ struct acpiphp_bridge {
 	acpi_handle handle;
 
 	struct acpiphp_context *context;
-	/* Ejectable PCI-to-PCI bridge (PCI bridge and PCI function) */
-	struct acpiphp_func *func;
 
 	int nr_slots;
 
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
@@ -181,7 +181,7 @@ static void free_bridge(struct kref *kre
 	context = bridge->context;
 	/* Release the reference acquired by acpiphp_enumerate_slots(). */
 	if (context->handler_for_func)
-		put_bridge(bridge->func->slot->bridge);
+		put_bridge(context->func->slot->bridge);
 
 	put_device(&bridge->pci_bus->dev);
 	pci_dev_put(bridge->pci_dev);
@@ -1235,7 +1235,6 @@ void acpiphp_enumerate_slots(struct pci_
 	}
 	if (context->handler_for_func) {
 		/* Notify handler already installed. */
-		bridge->func = context->func;
 		get_bridge(context->func->slot->bridge);
 		return;
 	}


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

* [RFC][PATCH 10/30] ACPI / hotplug / PCI: Refactor slot allocation code in register_slot()
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
                     ` (8 preceding siblings ...)
  2013-07-11 23:48   ` [RFC][PATCH 9/30] ACPI / hotplug / PCI: Drop func field from struct acpiphp_bridge Rafael J. Wysocki
@ 2013-07-11 23:49   ` Rafael J. Wysocki
  2013-07-11 23:50   ` [RFC][PATCH 11/30] ACPI / hotplug / PCI: Register all devices under the given bridge Rafael J. Wysocki
                     ` (21 subsequent siblings)
  31 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-11 23:49 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

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

To make the code in register_slot() a bit easier to follow, change
the way the slot allocation part is organized.  Drop one local
variable that's not used any more after that modification.

This code change should not lead to any changes in behavior.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp_glue.c |   74 ++++++++++++++++++-------------------
 1 file changed, 36 insertions(+), 38 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
@@ -285,7 +285,7 @@ static acpi_status register_slot(acpi_ha
 	acpi_handle tmp;
 	acpi_status status = AE_OK;
 	unsigned long long adr, sun;
-	int device, function, retval, found = 0;
+	int device, function, retval;
 	struct pci_bus *pbus = bridge->pci_bus;
 	struct pci_dev *pdev;
 	u32 val;
@@ -354,44 +354,49 @@ static acpi_status register_slot(acpi_ha
 		if (slot->device == device) {
 			if (slot->sun != sun)
 				warn("sibling found, but _SUN doesn't match!\n");
-			found = 1;
-			break;
-		}
 
-	if (!found) {
-		slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL);
-		if (!slot) {
-			status = AE_NO_MEMORY;
-			goto err_out;
+			goto slot_found;
 		}
 
-		slot->bridge = bridge;
-		slot->device = device;
-		slot->sun = sun;
-		INIT_LIST_HEAD(&slot->funcs);
-		mutex_init(&slot->crit_sect);
+	slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL);
+	if (!slot) {
+		status = AE_NO_MEMORY;
+		goto err;
+	}
 
-		mutex_lock(&bridge_mutex);
-		list_add_tail(&slot->node, &bridge->slots);
-		mutex_unlock(&bridge_mutex);
-		bridge->nr_slots++;
+	slot->bridge = bridge;
+	slot->device = device;
+	slot->sun = sun;
+	INIT_LIST_HEAD(&slot->funcs);
+	mutex_init(&slot->crit_sect);
 
-		dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n",
-		    slot->sun, pci_domain_nr(pbus), pbus->number, device);
-		retval = acpiphp_register_hotplug_slot(slot);
-		if (retval) {
-			if (retval == -EBUSY)
-				warn("Slot %llu already registered by another "
-					"hotplug driver\n", slot->sun);
-			else
-				warn("acpiphp_register_hotplug_slot failed "
-					"(err code = 0x%x)\n", retval);
+	mutex_lock(&bridge_mutex);
+	list_add_tail(&slot->node, &bridge->slots);
+	mutex_unlock(&bridge_mutex);
+	bridge->nr_slots++;
 
-			status = AE_OK;
-			goto err;
-		}
+	dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n",
+	    slot->sun, pci_domain_nr(pbus), pbus->number, device);
+
+	retval = acpiphp_register_hotplug_slot(slot);
+	if (retval) {
+		if (retval == -EBUSY)
+			warn("Slot %llu already registered by another "
+				"hotplug driver\n", slot->sun);
+		else
+			warn("acpiphp_register_hotplug_slot failed "
+				"(err code = 0x%x)\n", retval);
+
+		bridge->nr_slots--;
+		mutex_lock(&bridge_mutex);
+		list_del(&slot->node);
+		mutex_unlock(&bridge_mutex);
+		kfree(slot);
+		status = AE_OK;
+		goto err;
 	}
 
+ slot_found:
 	newfunc->slot = slot;
 	mutex_lock(&bridge_mutex);
 	list_add_tail(&newfunc->sibling, &slot->funcs);
@@ -435,13 +440,6 @@ static acpi_status register_slot(acpi_ha
 	return AE_OK;
 
  err:
-	bridge->nr_slots--;
-	mutex_lock(&bridge_mutex);
-	list_del(&slot->node);
-	mutex_unlock(&bridge_mutex);
-	kfree(slot);
-
- err_out:
 	mutex_lock(&acpiphp_context_lock);
 	context->func = NULL;
 	acpiphp_put_context(context);

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

* [RFC][PATCH 11/30] ACPI / hotplug / PCI: Register all devices under the given bridge
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
                     ` (9 preceding siblings ...)
  2013-07-11 23:49   ` [RFC][PATCH 10/30] ACPI / hotplug / PCI: Refactor slot allocation code in register_slot() Rafael J. Wysocki
@ 2013-07-11 23:50   ` Rafael J. Wysocki
  2013-07-12 11:54     ` Mika Westerberg
  2013-07-11 23:51   ` [RFC][PATCH 12/30] ACPI / hotplug / PCI: Drop sun field from struct acpiphp_slot Rafael J. Wysocki
                     ` (20 subsequent siblings)
  31 siblings, 1 reply; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-11 23:50 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

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

Rework register_slot() to create a struct acpiphp_func object for
every function it is called for and to create acpiphp slots for all
of them.  Although acpiphp_register_hotplug_slot() is only called for
the slots whose functions are identified as "ejectable", so that user
space can manipulate them, the ACPIPHP notify handler,
handle_hotplug_event(), is now installed for all of the registered
functions (that aren't dock stations) and hotplug events may be
handled for all of them.

As a result, essentially, all PCI bridges represented by objects in
the ACPI namespace are now going to be "hotplug" bridges and that may
affect resources allocation in general, although it shouldn't lead to
problems.

This allows the code to be simplified substantially and addresses
the problem where bus check or device check notifications for some
PCI bridges or devices are not handled, because those devices are
not recognized as "ejectable" or there appear to be no "ejectable"
devices under those bridges.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp.h      |    1 
 drivers/pci/hotplug/acpiphp_glue.c |  231 ++++++++++++-------------------------
 2 files changed, 75 insertions(+), 157 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
@@ -65,20 +65,6 @@ static void acpiphp_set_hpp_values(struc
 static void hotplug_event(acpi_handle handle, u32 type, void *data);
 static void free_bridge(struct kref *kref);
 
-/* callback routine to check for the existence of a pci dock device */
-static acpi_status
-is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
-	int *count = (int *)context;
-
-	if (is_dock_device(handle)) {
-		(*count)++;
-		return AE_CTRL_TERMINATE;
-	} else {
-		return AE_OK;
-	}
-}
-
 static void acpiphp_context_handler(acpi_handle handle, void *context)
 {
 	/* Intentionally empty. */
@@ -179,14 +165,16 @@ static void free_bridge(struct kref *kre
 	}
 
 	context = bridge->context;
-	/* Release the reference acquired by acpiphp_enumerate_slots(). */
-	if (context->handler_for_func)
+	/* Root bridges will not have hotplug context. */
+	if (context) {
+		/* Release the reference taken by acpiphp_enumerate_slots(). */
 		put_bridge(context->func->slot->bridge);
+		context->bridge = NULL;
+		acpiphp_put_context(context);
+	}
 
 	put_device(&bridge->pci_bus->dev);
 	pci_dev_put(bridge->pci_dev);
-	context->bridge = NULL;
-	acpiphp_put_context(context);
 	kfree(bridge);
 
 	mutex_unlock(&acpiphp_context_lock);
@@ -284,28 +272,24 @@ static acpi_status register_slot(acpi_ha
 	struct acpiphp_func *newfunc;
 	acpi_handle tmp;
 	acpi_status status = AE_OK;
-	unsigned long long adr, sun;
-	int device, function, retval;
+	unsigned long long adr;
+	int device, function;
 	struct pci_bus *pbus = bridge->pci_bus;
-	struct pci_dev *pdev;
+	struct pci_dev *pdev = bridge->pci_dev;
 	u32 val;
 
-	if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle))
+	if (pdev && device_is_managed_by_native_pciehp(pdev))
 		return AE_OK;
 
 	status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
 	if (ACPI_FAILURE(status)) {
-		warn("can't evaluate _ADR (%#x)\n", status);
+		acpi_handle_warn(handle, "can't evaluate _ADR (%#x)\n", status);
 		return AE_OK;
 	}
 
 	device = (adr >> 16) & 0xffff;
 	function = adr & 0xffff;
 
-	pdev = bridge->pci_dev;
-	if (pdev && device_is_managed_by_native_pciehp(pdev))
-		return AE_OK;
-
 	newfunc = kzalloc(sizeof(struct acpiphp_func), GFP_KERNEL);
 	if (!newfunc)
 		return AE_NO_MEMORY;
@@ -340,23 +324,10 @@ static acpi_status register_slot(acpi_ha
 	if (ACPI_SUCCESS(acpi_get_handle(handle, "_DCK", &tmp)))
 		newfunc->flags |= FUNC_HAS_DCK;
 
-	status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun);
-	if (ACPI_FAILURE(status)) {
-		/*
-		 * use the count of the number of slots we've found
-		 * for the number of the slot
-		 */
-		sun = bridge->nr_slots+1;
-	}
-
 	/* search for objects that share the same slot */
 	list_for_each_entry(slot, &bridge->slots, node)
-		if (slot->device == device) {
-			if (slot->sun != sun)
-				warn("sibling found, but _SUN doesn't match!\n");
-
+		if (slot->device == device)
 			goto slot_found;
-		}
 
 	slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL);
 	if (!slot) {
@@ -366,34 +337,38 @@ static acpi_status register_slot(acpi_ha
 
 	slot->bridge = bridge;
 	slot->device = device;
-	slot->sun = sun;
 	INIT_LIST_HEAD(&slot->funcs);
 	mutex_init(&slot->crit_sect);
 
 	mutex_lock(&bridge_mutex);
 	list_add_tail(&slot->node, &bridge->slots);
 	mutex_unlock(&bridge_mutex);
-	bridge->nr_slots++;
 
-	dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n",
-	    slot->sun, pci_domain_nr(pbus), pbus->number, device);
+	/* Register slots for ejectable funtions only. */
+	if (acpi_pci_check_ejectable(pbus, handle)  || is_dock_device(handle)) {
+		unsigned long long sun;
+		int retval;
 
-	retval = acpiphp_register_hotplug_slot(slot);
-	if (retval) {
-		if (retval == -EBUSY)
-			warn("Slot %llu already registered by another "
-				"hotplug driver\n", slot->sun);
-		else
-			warn("acpiphp_register_hotplug_slot failed "
-				"(err code = 0x%x)\n", retval);
+		bridge->nr_slots++;
+		status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun);
+		if (ACPI_FAILURE(status))
+			sun = bridge->nr_slots;
 
-		bridge->nr_slots--;
-		mutex_lock(&bridge_mutex);
-		list_del(&slot->node);
-		mutex_unlock(&bridge_mutex);
-		kfree(slot);
-		status = AE_OK;
-		goto err;
+		slot->sun = sun;
+		dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n",
+		    slot->sun, pci_domain_nr(pbus), pbus->number, device);
+
+		retval = acpiphp_register_hotplug_slot(slot);
+		if (retval) {
+			bridge->nr_slots--;
+			if (retval == -EBUSY)
+				warn("Slot %llu already registered by another "
+					"hotplug driver\n", slot->sun);
+			else
+				warn("acpiphp_register_hotplug_slot failed "
+					"(err code = 0x%x)\n", retval);
+		}
+		/* Even if the slot registration fails, we can still use it. */
 	}
 
  slot_found:
@@ -431,10 +406,9 @@ static acpi_status register_slot(acpi_ha
 		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");
+		if (ACPI_FAILURE(status))
+			acpi_handle_err(handle,
+					"failed to install notify handler\n");
 	}
 
 	return AE_OK;
@@ -448,18 +422,6 @@ static acpi_status register_slot(acpi_ha
 	return status;
 }
 
-
-/* see if it's worth looking at this bridge */
-static int detect_ejectable_slots(acpi_handle handle)
-{
-	int found = acpi_pci_detect_ejectable(handle);
-	if (!found) {
-		acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
-				    is_pci_dock_device, NULL, (void *)&found, NULL);
-	}
-	return found;
-}
-
 static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle)
 {
 	struct acpiphp_context *context;
@@ -483,14 +445,6 @@ static void cleanup_bridge(struct acpiph
 	struct acpiphp_slot *slot;
 	struct acpiphp_func *func;
 	acpi_status status;
-	acpi_handle handle = bridge->handle;
-
-	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");
-	}
 
 	list_for_each_entry(slot, &bridge->slots, node) {
 		list_for_each_entry(func, &slot->funcs, sibling) {
@@ -499,7 +453,6 @@ 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);
@@ -689,9 +642,7 @@ static void check_hotplug_bridge(struct
 
 	list_for_each_entry(func, &slot->funcs, sibling) {
 		if (PCI_FUNC(dev->devfn) == func->function) {
-			/* check if this bridge has ejectable slots */
-			if ((detect_ejectable_slots(func->handle) > 0))
-				dev->is_hotplug_bridge = 1;
+			dev->is_hotplug_bridge = 1;
 			break;
 		}
 	}
@@ -1010,8 +961,8 @@ void acpiphp_check_host_bridge(acpi_hand
 static void hotplug_event(acpi_handle handle, u32 type, void *data)
 {
 	struct acpiphp_context *context = data;
+	struct acpiphp_func *func = context->func;
 	struct acpiphp_bridge *bridge;
-	struct acpiphp_func *func;
 	char objname[64];
 	struct acpi_buffer buffer = { .length = sizeof(objname),
 				      .pointer = objname };
@@ -1021,11 +972,6 @@ static void hotplug_event(acpi_handle ha
 	if (bridge)
 		get_bridge(bridge);
 
-	/*
-	 * If context->func is not NULL, we are holding a reference to its
-	 * parent bridge, so it won't go away until we drop that reference.
-	 */
-	func = context->func;
 	mutex_unlock(&acpiphp_context_lock);
 
 	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
@@ -1063,9 +1009,6 @@ static void hotplug_event(acpi_handle ha
 	case ACPI_NOTIFY_EJECT_REQUEST:
 		/* request device eject */
 		dbg("%s: Device eject notify on %s\n", __func__, objname);
-		if (!func)
-			break;
-
 		if (bridge && !(bridge->flags & BRIDGE_HAS_EJ0))
 			break;
 
@@ -1112,14 +1055,7 @@ static void hotplug_event_work(struct wo
 
 	acpi_scan_lock_release();
 	kfree(hp_work); /* allocated in handle_hotplug_event() */
-
-	mutex_lock(&acpiphp_context_lock);
-	if (context->func)
-		put_bridge(context->func->slot->bridge);
-	else
-		acpiphp_put_context(context);
-
-	mutex_unlock(&acpiphp_context_lock);
+	put_bridge(context->func->slot->bridge);
 }
 
 /**
@@ -1137,13 +1073,8 @@ static void handle_hotplug_event(acpi_ha
 	mutex_lock(&acpiphp_context_lock);
 	context = acpiphp_get_context(handle);
 	if (context) {
-		if (context->func) {
-			get_bridge(context->func->slot->bridge);
-			acpiphp_put_context(context);
-		} else if (!context->bridge) {
-			acpiphp_put_context(context);
-			context = NULL;
-		}
+		get_bridge(context->func->slot->bridge);
+		acpiphp_put_context(context);
 	}
 	mutex_unlock(&acpiphp_context_lock);
 	/*
@@ -1164,7 +1095,6 @@ static void handle_hotplug_event(acpi_ha
  */
 void acpiphp_enumerate_slots(struct pci_bus *bus)
 {
-	struct acpiphp_context *context;
 	struct acpiphp_bridge *bridge;
 	acpi_handle handle;
 	acpi_status status;
@@ -1173,7 +1103,7 @@ void acpiphp_enumerate_slots(struct pci_
 		return;
 
 	handle = ACPI_HANDLE(bus->bridge);
-	if (!handle || detect_ejectable_slots(handle) <= 0)
+	if (!handle)
 		return;
 
 	bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
@@ -1188,21 +1118,6 @@ void acpiphp_enumerate_slots(struct pci_
 	bridge->pci_dev = pci_dev_get(bus->self);
 	bridge->pci_bus = bus;
 
-	mutex_lock(&acpiphp_context_lock);
-	context = acpiphp_get_context(handle);
-	if (!context) {
-		context = acpiphp_init_context(handle);
-		if (!context) {
-			mutex_unlock(&acpiphp_context_lock);
-			acpi_handle_err(handle, "No hotplug context\n");
-			kfree(bridge);
-			return;
-		}
-	}
-	bridge->context = context;
-	context->bridge = bridge;
-	mutex_unlock(&acpiphp_context_lock);
-
 	/*
 	 * Grab a ref to the subordinate PCI bus in case the bus is
 	 * removed via PCI core logical hotplug. The ref pins the bus
@@ -1210,6 +1125,35 @@ void acpiphp_enumerate_slots(struct pci_
 	 */
 	get_device(&bus->dev);
 
+	if (!pci_is_root_bus(bridge->pci_bus)) {
+		struct acpiphp_context *context;
+
+		/*
+		 * This bridge should have been registered as a hotplug function
+		 * under its parent, so the context has to be there.  If not, we
+		 * are in deep goo.
+		 */
+		mutex_lock(&acpiphp_context_lock);
+		context = acpiphp_get_context(handle);
+		if (WARN_ON(!context || !context->func)) {
+			mutex_unlock(&acpiphp_context_lock);
+			put_device(&bus->dev);
+			kfree(bridge);
+			return;
+		}
+		bridge->context = context;
+		context->bridge = bridge;
+		/* Get a reference to the parent bridge. */
+		get_bridge(context->func->slot->bridge);
+		mutex_unlock(&acpiphp_context_lock);
+	}
+
+	status = acpi_get_handle(bridge->handle, "_EJ0", &handle);
+	if (ACPI_SUCCESS(status)) {
+		dbg("found ejectable p2p bridge\n");
+		bridge->flags |= BRIDGE_HAS_EJ0;
+	}
+
 	/* must be added to the list prior to calling register_slot */
 	mutex_lock(&bridge_mutex);
 	list_add(&bridge->list, &bridge_list);
@@ -1220,34 +1164,9 @@ void acpiphp_enumerate_slots(struct pci_
 				     register_slot, NULL, bridge, NULL);
 	if (ACPI_FAILURE(status)) {
 		acpi_handle_err(bridge->handle, "failed to register slots\n");
-		goto err;
-	}
-
-	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. */
-		get_bridge(context->func->slot->bridge);
-		return;
+		cleanup_bridge(bridge);
+		put_bridge(bridge);
 	}
-
-	/* install notify handler for P2P bridges */
-	status = acpi_install_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY,
-					     handle_hotplug_event, NULL);
-	if (ACPI_SUCCESS(status))
-		return;
-
-	acpi_handle_err(bridge->handle, "failed to register notify handler\n");
-
- err:
-	cleanup_bridge(bridge);
-	put_bridge(bridge);
 }
 
 /* Destroy hotplug slots associated with the PCI bus */
Index: linux-pm/drivers/pci/hotplug/acpiphp.h
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
+++ linux-pm/drivers/pci/hotplug/acpiphp.h
@@ -135,7 +135,6 @@ struct acpiphp_context {
 	struct acpiphp_func *func;
 	struct acpiphp_bridge *bridge;
 	unsigned int refcount;
-	bool handler_for_func;
 };
 
 /*

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

* [RFC][PATCH 12/30] ACPI / hotplug / PCI: Drop sun field from struct acpiphp_slot
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
                     ` (10 preceding siblings ...)
  2013-07-11 23:50   ` [RFC][PATCH 11/30] ACPI / hotplug / PCI: Register all devices under the given bridge Rafael J. Wysocki
@ 2013-07-11 23:51   ` Rafael J. Wysocki
  2013-07-11 23:52   ` [RFC][PATCH 13/30] ACPI / hotplug / PCI: Use common slot count variable in register_slot() Rafael J. Wysocki
                     ` (19 subsequent siblings)
  31 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-11 23:51 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

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

If the slot unique number is passed as an additional argument to
acpiphp_register_hotplug_slot(), the slot field in struct
acpiphp_slot is not necessary and may be dropped, so make that
happen.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp.h      |    4 +---
 drivers/pci/hotplug/acpiphp_core.c |    5 +++--
 drivers/pci/hotplug/acpiphp_glue.c |    7 +++----
 3 files changed, 7 insertions(+), 9 deletions(-)

Index: linux-pm/drivers/pci/hotplug/acpiphp.h
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
+++ linux-pm/drivers/pci/hotplug/acpiphp.h
@@ -106,8 +106,6 @@ struct acpiphp_slot {
 	struct mutex crit_sect;
 
 	u8		device;		/* pci device# */
-
-	unsigned long long sun;		/* ACPI _SUN (slot unique number) */
 	u32		flags;		/* see below */
 };
 
@@ -180,7 +178,7 @@ struct acpiphp_attention_info
 /* acpiphp_core.c */
 int acpiphp_register_attention(struct acpiphp_attention_info*info);
 int acpiphp_unregister_attention(struct acpiphp_attention_info *info);
-int acpiphp_register_hotplug_slot(struct acpiphp_slot *slot);
+int acpiphp_register_hotplug_slot(struct acpiphp_slot *slot, unsigned int sun);
 void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot);
 
 /* acpiphp_glue.c */
Index: linux-pm/drivers/pci/hotplug/acpiphp_core.c
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp_core.c
+++ linux-pm/drivers/pci/hotplug/acpiphp_core.c
@@ -290,7 +290,8 @@ static void release_slot(struct hotplug_
 }
 
 /* callback routine to initialize 'struct slot' for each slot */
-int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
+int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot,
+				  unsigned int sun)
 {
 	struct slot *slot;
 	int retval = -ENOMEM;
@@ -317,7 +318,7 @@ int acpiphp_register_hotplug_slot(struct
 	slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot);
 
 	acpiphp_slot->slot = slot;
-	snprintf(name, SLOT_NAME_SIZE, "%llu", slot->acpi_slot->sun);
+	snprintf(name, SLOT_NAME_SIZE, "%u", sun);
 
 	retval = pci_hp_register(slot->hotplug_slot,
 					acpiphp_slot->bridge->pci_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
@@ -354,16 +354,15 @@ static acpi_status register_slot(acpi_ha
 		if (ACPI_FAILURE(status))
 			sun = bridge->nr_slots;
 
-		slot->sun = sun;
 		dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n",
-		    slot->sun, pci_domain_nr(pbus), pbus->number, device);
+		    sun, pci_domain_nr(pbus), pbus->number, device);
 
-		retval = acpiphp_register_hotplug_slot(slot);
+		retval = acpiphp_register_hotplug_slot(slot, sun);
 		if (retval) {
 			bridge->nr_slots--;
 			if (retval == -EBUSY)
 				warn("Slot %llu already registered by another "
-					"hotplug driver\n", slot->sun);
+					"hotplug driver\n", sun);
 			else
 				warn("acpiphp_register_hotplug_slot failed "
 					"(err code = 0x%x)\n", retval);

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

* [RFC][PATCH 13/30] ACPI / hotplug / PCI: Use common slot count variable in register_slot()
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
                     ` (11 preceding siblings ...)
  2013-07-11 23:51   ` [RFC][PATCH 12/30] ACPI / hotplug / PCI: Drop sun field from struct acpiphp_slot Rafael J. Wysocki
@ 2013-07-11 23:52   ` Rafael J. Wysocki
  2013-07-11 23:54   ` [RFC][PATCH 14/30] ACPI / hotplug / PCI: Drop flags field from struct acpiphp_bridge Rafael J. Wysocki
                     ` (18 subsequent siblings)
  31 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-11 23:52 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

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

It is not necessary to use per-bridge slot count fields just in
order to label slots for devices without _SUN, so use a common
static slot_count variable for this purpose and drop the nr_slots
field from struct acpiphp_bridge.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp.h      |    2 --
 drivers/pci/hotplug/acpiphp_glue.c |    7 ++++---
 2 files changed, 4 insertions(+), 5 deletions(-)

Index: linux-pm/drivers/pci/hotplug/acpiphp.h
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
+++ linux-pm/drivers/pci/hotplug/acpiphp.h
@@ -80,8 +80,6 @@ struct acpiphp_bridge {
 
 	struct acpiphp_context *context;
 
-	int nr_slots;
-
 	u32 flags;
 
 	/* This bus (host bridge) or Secondary bus (PCI-to-PCI bridge) */
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
@@ -346,20 +346,21 @@ static acpi_status register_slot(acpi_ha
 
 	/* Register slots for ejectable funtions only. */
 	if (acpi_pci_check_ejectable(pbus, handle)  || is_dock_device(handle)) {
+		static unsigned int slot_count;
 		unsigned long long sun;
 		int retval;
 
-		bridge->nr_slots++;
+		slot_count++;
 		status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun);
 		if (ACPI_FAILURE(status))
-			sun = bridge->nr_slots;
+			sun = slot_count;
 
 		dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n",
 		    sun, pci_domain_nr(pbus), pbus->number, device);
 
 		retval = acpiphp_register_hotplug_slot(slot, sun);
 		if (retval) {
-			bridge->nr_slots--;
+			slot_count--;
 			if (retval == -EBUSY)
 				warn("Slot %llu already registered by another "
 					"hotplug driver\n", sun);

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

* [RFC][PATCH 14/30] ACPI / hotplug / PCI: Drop flags field from struct acpiphp_bridge
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
                     ` (12 preceding siblings ...)
  2013-07-11 23:52   ` [RFC][PATCH 13/30] ACPI / hotplug / PCI: Use common slot count variable in register_slot() Rafael J. Wysocki
@ 2013-07-11 23:54   ` Rafael J. Wysocki
  2013-07-11 23:54   ` [RFC][PATCH 15/30] ACPI / hotplug / PCI: Embed function struct into struct acpiphp_context Rafael J. Wysocki
                     ` (17 subsequent siblings)
  31 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-11 23:54 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

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

The only bridge flag used by the ACPI-based PCI hotplug (ACPIPHP)
code is BRIDGE_HAS_EJ0, but it is only used by the event handling
function hotplug_event() and if that flag is set, the corresponding
function flag FUNC_HAS_EJ0 is set as well, so that bridge flag is
redundant.

For this reason, drop BRIDGE_HAS_EJ0 and all code referring to it
and since it is the only bridge flag defined, drop the flags field
from struct acpiphp_bridge entirely.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp.h      |    5 -----
 drivers/pci/hotplug/acpiphp_glue.c |    9 ---------
 2 files changed, 14 deletions(-)

Index: linux-pm/drivers/pci/hotplug/acpiphp.h
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
+++ linux-pm/drivers/pci/hotplug/acpiphp.h
@@ -80,8 +80,6 @@ struct acpiphp_bridge {
 
 	struct acpiphp_context *context;
 
-	u32 flags;
-
 	/* This bus (host bridge) or Secondary bus (PCI-to-PCI bridge) */
 	struct pci_bus *pci_bus;
 
@@ -152,9 +150,6 @@ struct acpiphp_attention_info
 /* ACPI _STA method value (ignore bit 4; battery present) */
 #define ACPI_STA_ALL			(0x0000000f)
 
-/* bridge flags */
-#define BRIDGE_HAS_EJ0		(0x00000001)
-
 /* slot flags */
 
 #define SLOT_POWEREDON		(0x00000001)
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
@@ -1009,9 +1009,6 @@ static void hotplug_event(acpi_handle ha
 	case ACPI_NOTIFY_EJECT_REQUEST:
 		/* request device eject */
 		dbg("%s: Device eject notify on %s\n", __func__, objname);
-		if (bridge && !(bridge->flags & BRIDGE_HAS_EJ0))
-			break;
-
 		if (!(acpiphp_disable_slot(func->slot)))
 			acpiphp_eject_slot(func->slot);
 
@@ -1148,12 +1145,6 @@ void acpiphp_enumerate_slots(struct pci_
 		mutex_unlock(&acpiphp_context_lock);
 	}
 
-	status = acpi_get_handle(bridge->handle, "_EJ0", &handle);
-	if (ACPI_SUCCESS(status)) {
-		dbg("found ejectable p2p bridge\n");
-		bridge->flags |= BRIDGE_HAS_EJ0;
-	}
-
 	/* must be added to the list prior to calling register_slot */
 	mutex_lock(&bridge_mutex);
 	list_add(&bridge->list, &bridge_list);

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

* [RFC][PATCH 15/30] ACPI / hotplug / PCI: Embed function struct into struct acpiphp_context
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
                     ` (13 preceding siblings ...)
  2013-07-11 23:54   ` [RFC][PATCH 14/30] ACPI / hotplug / PCI: Drop flags field from struct acpiphp_bridge Rafael J. Wysocki
@ 2013-07-11 23:54   ` Rafael J. Wysocki
  2013-07-11 23:55   ` [RFC][PATCH 16/30] ACPI / hotplug / PCI: Drop handle field from struct acpiphp_func Rafael J. Wysocki
                     ` (16 subsequent siblings)
  31 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-11 23:54 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

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

Since there has to be a struct acpiphp_func object for every struct
acpiphp_context created by register_slot(), the struct acpiphp_func
one can be embedded into the struct acpiphp_context one, which allows
some code simplifications to be made.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp.h      |    8 +++++--
 drivers/pci/hotplug/acpiphp_glue.c |   42 +++++++++++++------------------------
 2 files changed, 21 insertions(+), 29 deletions(-)

Index: linux-pm/drivers/pci/hotplug/acpiphp.h
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
+++ linux-pm/drivers/pci/hotplug/acpiphp.h
@@ -113,7 +113,6 @@ 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;
@@ -126,11 +125,16 @@ struct acpiphp_func {
 
 struct acpiphp_context {
 	acpi_handle handle;
-	struct acpiphp_func *func;
+	struct acpiphp_func func;
 	struct acpiphp_bridge *bridge;
 	unsigned int refcount;
 };
 
+static inline struct acpiphp_context *func_to_context(struct acpiphp_func *func)
+{
+	return container_of(func, struct acpiphp_context, func);
+}
+
 /*
  * 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
@@ -128,7 +128,7 @@ static void acpiphp_put_context(struct a
 	if (--context->refcount)
 		return;
 
-	WARN_ON(context->func || context->bridge);
+	WARN_ON(context->bridge);
 	acpi_detach_data(context->handle, acpiphp_context_handler);
 	kfree(context);
 }
@@ -155,12 +155,9 @@ static void free_bridge(struct kref *kre
 	bridge = container_of(kref, struct acpiphp_bridge, ref);
 
 	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;
-			acpiphp_put_context(context);
-			kfree(func);
-		}
+		list_for_each_entry_safe(func, tmp, &slot->funcs, sibling)
+			acpiphp_put_context(func_to_context(func));
+
 		kfree(slot);
 	}
 
@@ -168,7 +165,7 @@ static void free_bridge(struct kref *kre
 	/* Root bridges will not have hotplug context. */
 	if (context) {
 		/* Release the reference taken by acpiphp_enumerate_slots(). */
-		put_bridge(context->func->slot->bridge);
+		put_bridge(context->func.slot->bridge);
 		context->bridge = NULL;
 		acpiphp_put_context(context);
 	}
@@ -252,14 +249,14 @@ static void acpiphp_dock_init(void *data
 {
 	struct acpiphp_context *context = data;
 
-	get_bridge(context->func->slot->bridge);
+	get_bridge(context->func.slot->bridge);
 }
 
 static void acpiphp_dock_release(void *data)
 {
 	struct acpiphp_context *context = data;
 
-	put_bridge(context->func->slot->bridge);
+	put_bridge(context->func.slot->bridge);
 }
 
 /* callback routine to register each ACPI PCI slot object */
@@ -290,23 +287,16 @@ static acpi_status register_slot(acpi_ha
 	device = (adr >> 16) & 0xffff;
 	function = adr & 0xffff;
 
-	newfunc = kzalloc(sizeof(struct acpiphp_func), GFP_KERNEL);
-	if (!newfunc)
-		return AE_NO_MEMORY;
-
-	newfunc->handle = handle;
-	newfunc->function = function;
-
 	mutex_lock(&acpiphp_context_lock);
 	context = acpiphp_init_context(handle);
 	if (!context) {
 		mutex_unlock(&acpiphp_context_lock);
 		acpi_handle_err(handle, "No hotplug context\n");
-		kfree(newfunc);
 		return AE_NOT_EXIST;
 	}
-	newfunc->context = context;
-	context->func = newfunc;
+	newfunc = &context->func;
+	newfunc->handle = handle;
+	newfunc->function = function;
 	mutex_unlock(&acpiphp_context_lock);
 
 	if (ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp)))
@@ -415,10 +405,8 @@ static acpi_status register_slot(acpi_ha
 
  err:
 	mutex_lock(&acpiphp_context_lock);
-	context->func = NULL;
 	acpiphp_put_context(context);
 	mutex_unlock(&acpiphp_context_lock);
-	kfree(newfunc);
 	return status;
 }
 
@@ -961,7 +949,7 @@ void acpiphp_check_host_bridge(acpi_hand
 static void hotplug_event(acpi_handle handle, u32 type, void *data)
 {
 	struct acpiphp_context *context = data;
-	struct acpiphp_func *func = context->func;
+	struct acpiphp_func *func = &context->func;
 	struct acpiphp_bridge *bridge;
 	char objname[64];
 	struct acpi_buffer buffer = { .length = sizeof(objname),
@@ -1052,7 +1040,7 @@ static void hotplug_event_work(struct wo
 
 	acpi_scan_lock_release();
 	kfree(hp_work); /* allocated in handle_hotplug_event() */
-	put_bridge(context->func->slot->bridge);
+	put_bridge(context->func.slot->bridge);
 }
 
 /**
@@ -1070,7 +1058,7 @@ static void handle_hotplug_event(acpi_ha
 	mutex_lock(&acpiphp_context_lock);
 	context = acpiphp_get_context(handle);
 	if (context) {
-		get_bridge(context->func->slot->bridge);
+		get_bridge(context->func.slot->bridge);
 		acpiphp_put_context(context);
 	}
 	mutex_unlock(&acpiphp_context_lock);
@@ -1132,7 +1120,7 @@ void acpiphp_enumerate_slots(struct pci_
 		 */
 		mutex_lock(&acpiphp_context_lock);
 		context = acpiphp_get_context(handle);
-		if (WARN_ON(!context || !context->func)) {
+		if (WARN_ON(!context)) {
 			mutex_unlock(&acpiphp_context_lock);
 			put_device(&bus->dev);
 			kfree(bridge);
@@ -1141,7 +1129,7 @@ void acpiphp_enumerate_slots(struct pci_
 		bridge->context = context;
 		context->bridge = bridge;
 		/* Get a reference to the parent bridge. */
-		get_bridge(context->func->slot->bridge);
+		get_bridge(context->func.slot->bridge);
 		mutex_unlock(&acpiphp_context_lock);
 	}
 

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

* [RFC][PATCH 16/30] ACPI / hotplug / PCI: Drop handle field from struct acpiphp_func
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
                     ` (14 preceding siblings ...)
  2013-07-11 23:54   ` [RFC][PATCH 15/30] ACPI / hotplug / PCI: Embed function struct into struct acpiphp_context Rafael J. Wysocki
@ 2013-07-11 23:55   ` Rafael J. Wysocki
  2013-07-11 23:56   ` [RFC][PATCH 17/30] ACPI / hotplug / PCI: Drop handle field from struct acpiphp_bridge Rafael J. Wysocki
                     ` (15 subsequent siblings)
  31 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-11 23:55 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

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

The ACPI handle stored in struct acpiphp_func is also stored in the
struct acpiphp_context object containing it and it is trivial to get
from a struct acpiphp_func pointer to the handle field of the outer
struct acpiphp_context.

Hence, the handle field of struct acpiphp_func is redundant, so drop
it and provide a helper function, func_to_handle(), allowing it
users to get the ACPI handle for the given struct acpiphp_func
pointer.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp.h      |    6 ++++-
 drivers/pci/hotplug/acpiphp_glue.c |   42 ++++++++++++++++++++++---------------
 2 files changed, 30 insertions(+), 18 deletions(-)

Index: linux-pm/drivers/pci/hotplug/acpiphp.h
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
+++ linux-pm/drivers/pci/hotplug/acpiphp.h
@@ -117,7 +117,6 @@ struct acpiphp_func {
 
 	struct list_head sibling;
 	struct notifier_block nb;
-	acpi_handle	handle;
 
 	u8		function;	/* pci function# */
 	u32		flags;		/* see below */
@@ -135,6 +134,11 @@ static inline struct acpiphp_context *fu
 	return container_of(func, struct acpiphp_context, func);
 }
 
+static inline acpi_handle func_to_handle(struct acpiphp_func *func)
+{
+	return func_to_context(func)->handle;
+}
+
 /*
  * 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
@@ -295,7 +295,6 @@ static acpi_status register_slot(acpi_ha
 		return AE_NOT_EXIST;
 	}
 	newfunc = &context->func;
-	newfunc->handle = handle;
 	newfunc->function = function;
 	mutex_unlock(&acpiphp_context_lock);
 
@@ -436,12 +435,14 @@ static void cleanup_bridge(struct acpiph
 
 	list_for_each_entry(slot, &bridge->slots, node) {
 		list_for_each_entry(func, &slot->funcs, sibling) {
-			if (is_dock_device(func->handle)) {
-				unregister_hotplug_dock_device(func->handle);
+			acpi_handle handle = func_to_handle(func);
+
+			if (is_dock_device(handle)) {
+				unregister_hotplug_dock_device(handle);
 				unregister_dock_notifier(&func->nb);
 			}
 			if (!(func->flags & FUNC_HAS_DCK)) {
-				status = acpi_remove_notify_handler(func->handle,
+				status = acpi_remove_notify_handler(handle,
 							ACPI_SYSTEM_NOTIFY,
 							handle_hotplug_event);
 				if (ACPI_FAILURE(status))
@@ -469,7 +470,8 @@ static int power_on_slot(struct acpiphp_
 	list_for_each_entry(func, &slot->funcs, sibling) {
 		if (func->flags & FUNC_HAS_PS0) {
 			dbg("%s: executing _PS0\n", __func__);
-			status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL);
+			status = acpi_evaluate_object(func_to_handle(func),
+						      "_PS0", NULL, NULL);
 			if (ACPI_FAILURE(status)) {
 				warn("%s: _PS0 failed\n", __func__);
 				retval = -1;
@@ -501,7 +503,8 @@ static int power_off_slot(struct acpiphp
 
 	list_for_each_entry(func, &slot->funcs, sibling) {
 		if (func->flags & FUNC_HAS_PS3) {
-			status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL);
+			status = acpi_evaluate_object(func_to_handle(func),
+						      "_PS3", NULL, NULL);
 			if (ACPI_FAILURE(status)) {
 				warn("%s: _PS3 failed\n", __func__);
 				retval = -1;
@@ -555,10 +558,11 @@ static unsigned char acpiphp_max_busnr(s
  */
 static int acpiphp_bus_add(struct acpiphp_func *func)
 {
+	acpi_handle handle = func_to_handle(func);
 	struct acpi_device *device;
 	int ret_val;
 
-	if (!acpi_bus_get_device(func->handle, &device)) {
+	if (!acpi_bus_get_device(handle, &device)) {
 		dbg("bus exists... trim\n");
 		/* this shouldn't be in here, so remove
 		 * the bus then re-add it...
@@ -566,9 +570,9 @@ static int acpiphp_bus_add(struct acpiph
 		acpi_bus_trim(device);
 	}
 
-	ret_val = acpi_bus_scan(func->handle);
+	ret_val = acpi_bus_scan(handle);
 	if (!ret_val)
-		ret_val = acpi_bus_get_device(func->handle, &device);
+		ret_val = acpi_bus_get_device(handle, &device);
 
 	if (ret_val)
 		dbg("error adding bus, %x\n", -ret_val);
@@ -610,7 +614,8 @@ static void acpiphp_set_acpi_region(stru
 		params[1].type = ACPI_TYPE_INTEGER;
 		params[1].integer.value = 1;
 		/* _REG is optional, we don't care about if there is failure */
-		acpi_evaluate_object(func->handle, "_REG", &arg_list, NULL);
+		acpi_evaluate_object(func_to_handle(func), "_REG", &arg_list,
+				     NULL);
 	}
 }
 
@@ -751,9 +756,8 @@ static int disable_device(struct acpiphp
 		pci_dev_put(pdev);
 	}
 
-	list_for_each_entry(func, &slot->funcs, sibling) {
-		acpiphp_bus_trim(func->handle);
-	}
+	list_for_each_entry(func, &slot->funcs, sibling)
+		acpiphp_bus_trim(func_to_handle(func));
 
 	slot->flags &= (~SLOT_ENABLED);
 
@@ -775,17 +779,20 @@ static int disable_device(struct acpiphp
  */
 static unsigned int get_slot_status(struct acpiphp_slot *slot)
 {
-	acpi_status status;
 	unsigned long long sta = 0;
-	u32 dvid;
 	struct acpiphp_func *func;
 
 	list_for_each_entry(func, &slot->funcs, sibling) {
 		if (func->flags & FUNC_HAS_STA) {
-			status = acpi_evaluate_integer(func->handle, "_STA", NULL, &sta);
+			acpi_status status;
+
+			status = acpi_evaluate_integer(func_to_handle(func),
+						       "_STA", NULL, &sta);
 			if (ACPI_SUCCESS(status) && sta)
 				break;
 		} else {
+			u32 dvid;
+
 			pci_bus_read_config_dword(slot->bridge->pci_bus,
 						  PCI_DEVFN(slot->device,
 							    func->function),
@@ -820,7 +827,8 @@ int acpiphp_eject_slot(struct acpiphp_sl
 			arg.type = ACPI_TYPE_INTEGER;
 			arg.integer.value = 1;
 
-			status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL);
+			status = acpi_evaluate_object(func_to_handle(func),
+						      "_EJ0", &arg_list, NULL);
 			if (ACPI_FAILURE(status)) {
 				warn("%s: _EJ0 failed\n", __func__);
 				return -1;

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

* [RFC][PATCH 17/30] ACPI / hotplug / PCI: Drop handle field from struct acpiphp_bridge
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
                     ` (15 preceding siblings ...)
  2013-07-11 23:55   ` [RFC][PATCH 16/30] ACPI / hotplug / PCI: Drop handle field from struct acpiphp_func Rafael J. Wysocki
@ 2013-07-11 23:56   ` Rafael J. Wysocki
  2013-07-11 23:56   ` [RFC][PATCH 18/30] ACPI / hotplug / PCI: Store parent in functions and bus in slots Rafael J. Wysocki
                     ` (14 subsequent siblings)
  31 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-11 23:56 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

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

The handle field in struct acpiphp_bridge is only used by
acpiphp_enumerate_slots(), but in that function the local handle
variable can be used instead, so make that happen and drop handle
from struct acpiphp_bridge.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp.h      |    1 -
 drivers/pci/hotplug/acpiphp_glue.c |    5 ++---
 2 files changed, 2 insertions(+), 4 deletions(-)

Index: linux-pm/drivers/pci/hotplug/acpiphp.h
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
+++ linux-pm/drivers/pci/hotplug/acpiphp.h
@@ -76,7 +76,6 @@ struct acpiphp_bridge {
 	struct list_head list;
 	struct list_head slots;
 	struct kref ref;
-	acpi_handle handle;
 
 	struct acpiphp_context *context;
 
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
@@ -1107,7 +1107,6 @@ void acpiphp_enumerate_slots(struct pci_
 
 	INIT_LIST_HEAD(&bridge->slots);
 	kref_init(&bridge->ref);
-	bridge->handle = handle;
 	bridge->pci_dev = pci_dev_get(bus->self);
 	bridge->pci_bus = bus;
 
@@ -1147,10 +1146,10 @@ void acpiphp_enumerate_slots(struct pci_
 	mutex_unlock(&bridge_mutex);
 
 	/* register all slot objects under this bridge */
-	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, 1,
+	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
 				     register_slot, NULL, bridge, NULL);
 	if (ACPI_FAILURE(status)) {
-		acpi_handle_err(bridge->handle, "failed to register slots\n");
+		acpi_handle_err(handle, "failed to register slots\n");
 		cleanup_bridge(bridge);
 		put_bridge(bridge);
 	}

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

* [RFC][PATCH 18/30] ACPI / hotplug / PCI: Store parent in functions and bus in slots
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
                     ` (16 preceding siblings ...)
  2013-07-11 23:56   ` [RFC][PATCH 17/30] ACPI / hotplug / PCI: Drop handle field from struct acpiphp_bridge Rafael J. Wysocki
@ 2013-07-11 23:56   ` Rafael J. Wysocki
  2013-07-11 23:57   ` [RFC][PATCH 19/30] ACPI / hotplug / PCI: Rework namespace scanning and trimming routines Rafael J. Wysocki
                     ` (13 subsequent siblings)
  31 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-11 23:56 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

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

To avoid chasing more pointers than necessary in some situations,
move the bridge pointer from struct acpiphp_slot to struct
acpiphp_func (and call it 'parent') and add a bus pointer to
struct acpiphp_slot.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp.h      |    5 +++--
 drivers/pci/hotplug/acpiphp_core.c |    6 ++----
 drivers/pci/hotplug/acpiphp_glue.c |   25 +++++++++++++------------
 3 files changed, 18 insertions(+), 18 deletions(-)

Index: linux-pm/drivers/pci/hotplug/acpiphp.h
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
+++ linux-pm/drivers/pci/hotplug/acpiphp.h
@@ -94,7 +94,7 @@ struct acpiphp_bridge {
  */
 struct acpiphp_slot {
 	struct list_head node;
-	struct acpiphp_bridge *bridge;	/* parent */
+	struct pci_bus *bus;
 	struct list_head funcs;		/* one slot may have different
 					   objects (i.e. for each function) */
 	struct slot *slot;
@@ -112,7 +112,8 @@ struct acpiphp_slot {
  * typically 8 objects per slot (i.e. for each PCI function)
  */
 struct acpiphp_func {
-	struct acpiphp_slot *slot;	/* parent */
+	struct acpiphp_bridge *parent;
+	struct acpiphp_slot *slot;
 
 	struct list_head sibling;
 	struct notifier_block nb;
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
@@ -165,7 +165,7 @@ static void free_bridge(struct kref *kre
 	/* Root bridges will not have hotplug context. */
 	if (context) {
 		/* Release the reference taken by acpiphp_enumerate_slots(). */
-		put_bridge(context->func.slot->bridge);
+		put_bridge(context->func.parent);
 		context->bridge = NULL;
 		acpiphp_put_context(context);
 	}
@@ -188,7 +188,7 @@ static int post_dock_fixups(struct notif
 	void *v)
 {
 	struct acpiphp_func *func = container_of(nb, struct acpiphp_func, nb);
-	struct pci_bus *bus = func->slot->bridge->pci_bus;
+	struct pci_bus *bus = func->slot->bus;
 	u32 buses;
 
 	if (!bus->self)
@@ -249,14 +249,14 @@ static void acpiphp_dock_init(void *data
 {
 	struct acpiphp_context *context = data;
 
-	get_bridge(context->func.slot->bridge);
+	get_bridge(context->func.parent);
 }
 
 static void acpiphp_dock_release(void *data)
 {
 	struct acpiphp_context *context = data;
 
-	put_bridge(context->func.slot->bridge);
+	put_bridge(context->func.parent);
 }
 
 /* callback routine to register each ACPI PCI slot object */
@@ -296,6 +296,7 @@ static acpi_status register_slot(acpi_ha
 	}
 	newfunc = &context->func;
 	newfunc->function = function;
+	newfunc->parent = bridge;
 	mutex_unlock(&acpiphp_context_lock);
 
 	if (ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp)))
@@ -324,7 +325,7 @@ static acpi_status register_slot(acpi_ha
 		goto err;
 	}
 
-	slot->bridge = bridge;
+	slot->bus = bridge->pci_bus;
 	slot->device = device;
 	INIT_LIST_HEAD(&slot->funcs);
 	mutex_init(&slot->crit_sect);
@@ -651,7 +652,7 @@ static void check_hotplug_bridge(struct
 static int __ref enable_device(struct acpiphp_slot *slot)
 {
 	struct pci_dev *dev;
-	struct pci_bus *bus = slot->bridge->pci_bus;
+	struct pci_bus *bus = slot->bus;
 	struct acpiphp_func *func;
 	int num, max, pass;
 	LIST_HEAD(add_list);
@@ -721,7 +722,7 @@ static int __ref enable_device(struct ac
 /* return first device in slot, acquiring a reference on it */
 static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot)
 {
-	struct pci_bus *bus = slot->bridge->pci_bus;
+	struct pci_bus *bus = slot->bus;
 	struct pci_dev *dev;
 	struct pci_dev *ret = NULL;
 
@@ -793,7 +794,7 @@ static unsigned int get_slot_status(stru
 		} else {
 			u32 dvid;
 
-			pci_bus_read_config_dword(slot->bridge->pci_bus,
+			pci_bus_read_config_dword(slot->bus,
 						  PCI_DEVFN(slot->device,
 							    func->function),
 						  PCI_VENDOR_ID, &dvid);
@@ -993,7 +994,7 @@ static void hotplug_event(acpi_handle ha
 		if (bridge)
 			acpiphp_check_bridge(bridge);
 		else
-			acpiphp_check_bridge(func->slot->bridge);
+			acpiphp_check_bridge(func->parent);
 
 		break;
 
@@ -1048,7 +1049,7 @@ static void hotplug_event_work(struct wo
 
 	acpi_scan_lock_release();
 	kfree(hp_work); /* allocated in handle_hotplug_event() */
-	put_bridge(context->func.slot->bridge);
+	put_bridge(context->func.parent);
 }
 
 /**
@@ -1066,7 +1067,7 @@ static void handle_hotplug_event(acpi_ha
 	mutex_lock(&acpiphp_context_lock);
 	context = acpiphp_get_context(handle);
 	if (context) {
-		get_bridge(context->func.slot->bridge);
+		get_bridge(context->func.parent);
 		acpiphp_put_context(context);
 	}
 	mutex_unlock(&acpiphp_context_lock);
@@ -1136,7 +1137,7 @@ void acpiphp_enumerate_slots(struct pci_
 		bridge->context = context;
 		context->bridge = bridge;
 		/* Get a reference to the parent bridge. */
-		get_bridge(context->func.slot->bridge);
+		get_bridge(context->func.parent);
 		mutex_unlock(&acpiphp_context_lock);
 	}
 
Index: linux-pm/drivers/pci/hotplug/acpiphp_core.c
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp_core.c
+++ linux-pm/drivers/pci/hotplug/acpiphp_core.c
@@ -320,10 +320,8 @@ int acpiphp_register_hotplug_slot(struct
 	acpiphp_slot->slot = slot;
 	snprintf(name, SLOT_NAME_SIZE, "%u", sun);
 
-	retval = pci_hp_register(slot->hotplug_slot,
-					acpiphp_slot->bridge->pci_bus,
-					acpiphp_slot->device,
-					name);
+	retval = pci_hp_register(slot->hotplug_slot, acpiphp_slot->bus,
+				 acpiphp_slot->device, name);
 	if (retval == -EBUSY)
 		goto error_hpslot;
 	if (retval) {

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

* [RFC][PATCH 19/30] ACPI / hotplug / PCI: Rework namespace scanning and trimming routines
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
                     ` (17 preceding siblings ...)
  2013-07-11 23:56   ` [RFC][PATCH 18/30] ACPI / hotplug / PCI: Store parent in functions and bus in slots Rafael J. Wysocki
@ 2013-07-11 23:57   ` Rafael J. Wysocki
  2013-07-11 23:58   ` [RFC][PATCH 20/30] ACPI / hotplug / PCI: Drop redundant checks from check_hotplug_bridge() Rafael J. Wysocki
                     ` (12 subsequent siblings)
  31 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-11 23:57 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

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

The acpiphp_bus_trim() and acpiphp_bus_add() functions need not
return error codes that are never checked, so redefine them and
simplify them a bit.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp_glue.c |   52 +++++++++----------------------------
 1 file changed, 13 insertions(+), 39 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
@@ -552,53 +552,27 @@ static unsigned char acpiphp_max_busnr(s
 	return max;
 }
 
-
 /**
- * acpiphp_bus_add - add a new bus to acpi subsystem
- * @func: acpiphp_func of the bridge
+ * acpiphp_bus_trim - Trim device objects in an ACPI namespace subtree.
+ * @handle: ACPI device object handle to start from.
  */
-static int acpiphp_bus_add(struct acpiphp_func *func)
+static void acpiphp_bus_trim(acpi_handle handle)
 {
-	acpi_handle handle = func_to_handle(func);
-	struct acpi_device *device;
-	int ret_val;
-
-	if (!acpi_bus_get_device(handle, &device)) {
-		dbg("bus exists... trim\n");
-		/* this shouldn't be in here, so remove
-		 * the bus then re-add it...
-		 */
-		acpi_bus_trim(device);
-	}
-
-	ret_val = acpi_bus_scan(handle);
-	if (!ret_val)
-		ret_val = acpi_bus_get_device(handle, &device);
-
-	if (ret_val)
-		dbg("error adding bus, %x\n", -ret_val);
+	struct acpi_device *adev = NULL;
 
-	return ret_val;
+	acpi_bus_get_device(handle, &adev);
+	if (adev)
+		acpi_bus_trim(adev);
 }
 
-
 /**
- * acpiphp_bus_trim - trim a bus from acpi subsystem
- * @handle: handle to acpi namespace
+ * acpiphp_bus_add - Scan ACPI namespace subtree.
+ * @handle: ACPI object handle to start the scan from.
  */
-static int acpiphp_bus_trim(acpi_handle handle)
+static void acpiphp_bus_add(acpi_handle handle)
 {
-	struct acpi_device *device;
-	int retval;
-
-	retval = acpi_bus_get_device(handle, &device);
-	if (retval) {
-		dbg("acpi_device not found\n");
-		return retval;
-	}
-
-	acpi_bus_trim(device);
-	return 0;
+	acpiphp_bus_trim(handle);
+	acpi_bus_scan(handle);
 }
 
 static void acpiphp_set_acpi_region(struct acpiphp_slot *slot)
@@ -661,7 +635,7 @@ static int __ref enable_device(struct ac
 		goto err_exit;
 
 	list_for_each_entry(func, &slot->funcs, sibling)
-		acpiphp_bus_add(func);
+		acpiphp_bus_add(func_to_handle(func));
 
 	num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
 	if (num == 0) {

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

* [RFC][PATCH 20/30] ACPI / hotplug / PCI: Drop redundant checks from check_hotplug_bridge()
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
                     ` (18 preceding siblings ...)
  2013-07-11 23:57   ` [RFC][PATCH 19/30] ACPI / hotplug / PCI: Rework namespace scanning and trimming routines Rafael J. Wysocki
@ 2013-07-11 23:58   ` Rafael J. Wysocki
  2013-07-11 23:59   ` [RFC][PATCH 21/30] ACPI / hotplug / PCI: Consolidate slot disabling and ejecting Rafael J. Wysocki
                     ` (11 subsequent siblings)
  31 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-11 23:58 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

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

Two checks in check_hotplug_bridge() are redundant (they have been
done by the caller already), so drop them.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp_glue.c |    6 ------
 1 file changed, 6 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
@@ -598,16 +598,10 @@ static void check_hotplug_bridge(struct
 {
 	struct acpiphp_func *func;
 
-	if (!dev->subordinate)
-		return;
-
 	/* quirk, or pcie could set it already */
 	if (dev->is_hotplug_bridge)
 		return;
 
-	if (PCI_SLOT(dev->devfn) != slot->device)
-		return;
-
 	list_for_each_entry(func, &slot->funcs, sibling) {
 		if (PCI_FUNC(dev->devfn) == func->function) {
 			dev->is_hotplug_bridge = 1;

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

* [RFC][PATCH 21/30] ACPI / hotplug / PCI: Consolidate slot disabling and ejecting
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
                     ` (19 preceding siblings ...)
  2013-07-11 23:58   ` [RFC][PATCH 20/30] ACPI / hotplug / PCI: Drop redundant checks from check_hotplug_bridge() Rafael J. Wysocki
@ 2013-07-11 23:59   ` Rafael J. Wysocki
  2013-07-12  0:00   ` [RFC][PATCH 22/30] ACPI / hotplug / PCI: Do not queue up event handling work items in vain Rafael J. Wysocki
                     ` (10 subsequent siblings)
  31 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-11 23:59 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

From: Mika Westerberg <mika.westerberg@linux.intel.com>

Both acpiphp_disable_slot() and acpiphp_eject_slot() are always
called together so instead of calling each separately we can
consolidate them into one function acpiphp_disable_and_eject_slot()
that does both (but it will return success on _EJ0 failures that
were ignored in the majority of call sites anyway).

[rjw: Rebased plus minor tweaks]
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp.h      |    3 -
 drivers/pci/hotplug/acpiphp_core.c |    6 ---
 drivers/pci/hotplug/acpiphp_glue.c |   74 +++++++++++++++----------------------
 3 files changed, 33 insertions(+), 50 deletions(-)

Index: linux-pm/drivers/pci/hotplug/acpiphp.h
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
+++ linux-pm/drivers/pci/hotplug/acpiphp.h
@@ -186,8 +186,7 @@ void acpiphp_unregister_hotplug_slot(str
 typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data);
 
 int acpiphp_enable_slot(struct acpiphp_slot *slot);
-int acpiphp_disable_slot(struct acpiphp_slot *slot);
-int acpiphp_eject_slot(struct acpiphp_slot *slot);
+int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot);
 u8 acpiphp_get_power_status(struct acpiphp_slot *slot);
 u8 acpiphp_get_attention_status(struct acpiphp_slot *slot);
 u8 acpiphp_get_latch_status(struct acpiphp_slot *slot);
Index: linux-pm/drivers/pci/hotplug/acpiphp_core.c
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp_core.c
+++ linux-pm/drivers/pci/hotplug/acpiphp_core.c
@@ -155,15 +155,11 @@ static int enable_slot(struct hotplug_sl
 static int disable_slot(struct hotplug_slot *hotplug_slot)
 {
 	struct slot *slot = hotplug_slot->private;
-	int retval;
 
 	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
 
 	/* disable the specified slot */
-	retval = acpiphp_disable_slot(slot->acpi_slot);
-	if (!retval)
-		retval = acpiphp_eject_slot(slot->acpi_slot);
-	return retval;
+	return acpiphp_disable_and_eject_slot(slot->acpi_slot);
 }
 
 
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
@@ -777,38 +777,6 @@ static unsigned int get_slot_status(stru
 }
 
 /**
- * acpiphp_eject_slot - physically eject the slot
- * @slot: ACPI PHP slot
- */
-int acpiphp_eject_slot(struct acpiphp_slot *slot)
-{
-	acpi_status status;
-	struct acpiphp_func *func;
-	struct acpi_object_list arg_list;
-	union acpi_object arg;
-
-	list_for_each_entry(func, &slot->funcs, sibling) {
-		/* We don't want to call _EJ0 on non-existing functions. */
-		if ((func->flags & FUNC_HAS_EJ0)) {
-			/* _EJ0 method take one argument */
-			arg_list.count = 1;
-			arg_list.pointer = &arg;
-			arg.type = ACPI_TYPE_INTEGER;
-			arg.integer.value = 1;
-
-			status = acpi_evaluate_object(func_to_handle(func),
-						      "_EJ0", &arg_list, NULL);
-			if (ACPI_FAILURE(status)) {
-				warn("%s: _EJ0 failed\n", __func__);
-				return -1;
-			} else
-				break;
-		}
-	}
-	return 0;
-}
-
-/**
  * acpiphp_check_bridge - re-enumerate devices
  * @bridge: where to begin re-enumeration
  *
@@ -828,13 +796,11 @@ static int acpiphp_check_bridge(struct a
 		if (slot->flags & SLOT_ENABLED) {
 			if (status == ACPI_STA_ALL)
 				continue;
-			retval = acpiphp_disable_slot(slot);
-			if (retval) {
-				err("Error occurred in disabling\n");
+
+			retval = acpiphp_disable_and_eject_slot(slot);
+			if (retval)
 				goto err_exit;
-			} else {
-				acpiphp_eject_slot(slot);
-			}
+
 			disabled++;
 		} else {
 			if (status != ACPI_STA_ALL)
@@ -974,9 +940,7 @@ static void hotplug_event(acpi_handle ha
 	case ACPI_NOTIFY_EJECT_REQUEST:
 		/* request device eject */
 		dbg("%s: Device eject notify on %s\n", __func__, objname);
-		if (!(acpiphp_disable_slot(func->slot)))
-			acpiphp_eject_slot(func->slot);
-
+		acpiphp_disable_and_eject_slot(func->slot);
 		break;
 
 	case ACPI_NOTIFY_FREQUENCY_MISMATCH:
@@ -1171,11 +1135,14 @@ int acpiphp_enable_slot(struct acpiphp_s
 }
 
 /**
- * acpiphp_disable_slot - power off slot
+ * acpiphp_disable_and_eject_slot - power off and eject slot
  * @slot: ACPI PHP slot
  */
-int acpiphp_disable_slot(struct acpiphp_slot *slot)
+int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot)
 {
+	struct acpiphp_func *func;
+	struct acpi_object_list arg_list;
+	union acpi_object arg;
 	int retval = 0;
 
 	mutex_lock(&slot->crit_sect);
@@ -1190,6 +1157,27 @@ int acpiphp_disable_slot(struct acpiphp_
 	if (retval)
 		goto err_exit;
 
+	list_for_each_entry(func, &slot->funcs, sibling) {
+		/* We don't want to call _EJ0 on non-existing functions. */
+		if (func->flags & FUNC_HAS_EJ0) {
+			acpi_handle handle = func_to_handle(func);
+			acpi_status status;
+
+			/* _EJ0 method take one argument */
+			arg_list.count = 1;
+			arg_list.pointer = &arg;
+			arg.type = ACPI_TYPE_INTEGER;
+			arg.integer.value = 1;
+
+			status = acpi_evaluate_object(handle, "_EJ0", &arg_list,
+						      NULL);
+			if (ACPI_FAILURE(status))
+				acpi_handle_err(handle, "_EJ0 failed\n");
+
+			break;
+		}
+	}
+
  err_exit:
 	mutex_unlock(&slot->crit_sect);
 	return retval;

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

* [RFC][PATCH 22/30] ACPI / hotplug / PCI: Do not queue up event handling work items in vain
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
                     ` (20 preceding siblings ...)
  2013-07-11 23:59   ` [RFC][PATCH 21/30] ACPI / hotplug / PCI: Consolidate slot disabling and ejecting Rafael J. Wysocki
@ 2013-07-12  0:00   ` Rafael J. Wysocki
  2013-07-12  0:01   ` [RFC][PATCH 23/30] ACPI / hotplug / PCI: Do not exectute _PS0 and _PS3 directly Rafael J. Wysocki
                     ` (9 subsequent siblings)
  31 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-12  0:00 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

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

Modify handle_hotplug_event() to avoid queing up the execution of
handle_hotplug_event_work_fn() as a work item on kacpi_hotplug_wq
for non-hotplug events, such as ACPI_NOTIFY_DEVICE_WAKE.  Move
the code printing diagnostic messages for those events into
handle_hotplug_event().

In addition to that, remove the bogus comment about how the core
should distinguish between hotplug and non-hotplug events and
queue them up on different workqueues.  The core clearly cannot
know in advance what events will be interesting to the given
caller of acpi_install_notify_handler().

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp_glue.c |   64 ++++++++++++++++---------------------
 1 file changed, 29 insertions(+), 35 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
@@ -932,36 +932,11 @@ static void hotplug_event(acpi_handle ha
 
 		break;
 
-	case ACPI_NOTIFY_DEVICE_WAKE:
-		/* wake event */
-		dbg("%s: Device wake notify on %s\n", __func__, objname);
-		break;
-
 	case ACPI_NOTIFY_EJECT_REQUEST:
 		/* request device eject */
 		dbg("%s: Device eject notify on %s\n", __func__, objname);
 		acpiphp_disable_and_eject_slot(func->slot);
 		break;
-
-	case ACPI_NOTIFY_FREQUENCY_MISMATCH:
-		printk(KERN_ERR "Device %s cannot be configured due"
-				" to a frequency mismatch\n", objname);
-		break;
-
-	case ACPI_NOTIFY_BUS_MODE_MISMATCH:
-		printk(KERN_ERR "Device %s cannot be configured due"
-				" to a bus mode mismatch\n", objname);
-		break;
-
-	case ACPI_NOTIFY_POWER_FAULT:
-		printk(KERN_ERR "Device %s has suffered a power fault\n",
-				objname);
-		break;
-
-	default:
-		warn("notify_handler: unknown event type 0x%x for %s\n", type,
-		     objname);
-		break;
 	}
 
 	if (bridge)
@@ -996,23 +971,42 @@ static void handle_hotplug_event(acpi_ha
 {
 	struct acpiphp_context *context;
 
+	switch (type) {
+	case ACPI_NOTIFY_BUS_CHECK:
+	case ACPI_NOTIFY_DEVICE_CHECK:
+	case ACPI_NOTIFY_EJECT_REQUEST:
+		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");
+		return;
+
+	case ACPI_NOTIFY_BUS_MODE_MISMATCH:
+		acpi_handle_err(handle, "Device cannot be configured due "
+				"to a bus mode mismatch\n");
+		return;
+
+	case ACPI_NOTIFY_POWER_FAULT:
+		acpi_handle_err(handle, "Device has suffered a power fault\n");
+		return;
+
+	default:
+		acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type);
+		return;
+	}
+
 	mutex_lock(&acpiphp_context_lock);
 	context = acpiphp_get_context(handle);
 	if (context) {
 		get_bridge(context->func.parent);
 		acpiphp_put_context(context);
+		alloc_acpi_hp_work(handle, type, context, hotplug_event_work);
 	}
 	mutex_unlock(&acpiphp_context_lock);
-	/*
-	 * 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.
-	 */
-	if (context)
-		alloc_acpi_hp_work(handle, type, context, hotplug_event_work);
 }
 
 /*

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

* [RFC][PATCH 23/30] ACPI / hotplug / PCI: Do not exectute _PS0 and _PS3 directly
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
                     ` (21 preceding siblings ...)
  2013-07-12  0:00   ` [RFC][PATCH 22/30] ACPI / hotplug / PCI: Do not queue up event handling work items in vain Rafael J. Wysocki
@ 2013-07-12  0:01   ` Rafael J. Wysocki
  2013-07-12 13:05     ` Mika Westerberg
  2013-07-12  0:02   ` [RFC][PATCH 24/30] ACPI / hotplug / PCI: Do not check SLOT_ENABLED in enable_device() Rafael J. Wysocki
                     ` (8 subsequent siblings)
  31 siblings, 1 reply; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-12  0:01 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

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

The ACPI-based PCI hotplug (acpiphp) core code need not and really
should not execute _PS0 and _PS3 directly for devices it handles.

First of all, it is not necessary to put devices into D3 after
acpi_bus_trim() has walked through them, because
acpi_device_unregister() invoked by it puts each device into D3cold
before returning.  Thus after disable_device() the slot should be
powered down already.

Second, calling _PS0 directly on ACPI device objects may not be
appropriate, because it may require power resources to be set up in
a specific way in advance and that must be taken care of by the ACPI
core.  Thus modify acpiphp_bus_add() to power up the device using
the appropriate interface after it has run acpi_bus_scan() on its
handle.

After that, the functions executing _PS0 and _PS3, power_on_slot()
and power_off_slot(), are not necessary any more, so drop them
and update the code calling them accordingly.  Also drop the
function flags related to device power states, since they aren't
useful any more too.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp.h      |    7 --
 drivers/pci/hotplug/acpiphp_glue.c |  106 +++----------------------------------
 2 files changed, 10 insertions(+), 103 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
@@ -305,12 +305,6 @@ static acpi_status register_slot(acpi_ha
 	if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp)))
 		newfunc->flags |= FUNC_HAS_STA;
 
-	if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS0", &tmp)))
-		newfunc->flags |= FUNC_HAS_PS0;
-
-	if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp)))
-		newfunc->flags |= FUNC_HAS_PS3;
-
 	if (ACPI_SUCCESS(acpi_get_handle(handle, "_DCK", &tmp)))
 		newfunc->flags |= FUNC_HAS_DCK;
 
@@ -369,7 +363,7 @@ static acpi_status register_slot(acpi_ha
 
 	if (pci_bus_read_dev_vendor_id(pbus, PCI_DEVFN(device, function),
 				       &val, 60*1000))
-		slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON);
+		slot->flags |= SLOT_ENABLED;
 
 	if (is_dock_device(handle)) {
 		/* we don't want to call this device's _EJ0
@@ -458,73 +452,6 @@ static void cleanup_bridge(struct acpiph
 	mutex_unlock(&bridge_mutex);
 }
 
-static int power_on_slot(struct acpiphp_slot *slot)
-{
-	acpi_status status;
-	struct acpiphp_func *func;
-	int retval = 0;
-
-	/* if already enabled, just skip */
-	if (slot->flags & SLOT_POWEREDON)
-		goto err_exit;
-
-	list_for_each_entry(func, &slot->funcs, sibling) {
-		if (func->flags & FUNC_HAS_PS0) {
-			dbg("%s: executing _PS0\n", __func__);
-			status = acpi_evaluate_object(func_to_handle(func),
-						      "_PS0", NULL, NULL);
-			if (ACPI_FAILURE(status)) {
-				warn("%s: _PS0 failed\n", __func__);
-				retval = -1;
-				goto err_exit;
-			} else
-				break;
-		}
-	}
-
-	/* TBD: evaluate _STA to check if the slot is enabled */
-
-	slot->flags |= SLOT_POWEREDON;
-
- err_exit:
-	return retval;
-}
-
-
-static int power_off_slot(struct acpiphp_slot *slot)
-{
-	acpi_status status;
-	struct acpiphp_func *func;
-
-	int retval = 0;
-
-	/* if already disabled, just skip */
-	if ((slot->flags & SLOT_POWEREDON) == 0)
-		goto err_exit;
-
-	list_for_each_entry(func, &slot->funcs, sibling) {
-		if (func->flags & FUNC_HAS_PS3) {
-			status = acpi_evaluate_object(func_to_handle(func),
-						      "_PS3", NULL, NULL);
-			if (ACPI_FAILURE(status)) {
-				warn("%s: _PS3 failed\n", __func__);
-				retval = -1;
-				goto err_exit;
-			} else
-				break;
-		}
-	}
-
-	/* TBD: evaluate _STA to check if the slot is disabled */
-
-	slot->flags &= (~SLOT_POWEREDON);
-
- err_exit:
-	return retval;
-}
-
-
-
 /**
  * acpiphp_max_busnr - return the highest reserved bus number under the given bus.
  * @bus: bus to start search with
@@ -571,8 +498,13 @@ static void acpiphp_bus_trim(acpi_handle
  */
 static void acpiphp_bus_add(acpi_handle handle)
 {
+	struct acpi_device *adev = NULL;
+
 	acpiphp_bus_trim(handle);
 	acpi_bus_scan(handle);
+	acpi_bus_get_device(handle, &adev);
+	if (adev)
+		acpi_device_set_power(adev, ACPI_STATE_D0);
 }
 
 static void acpiphp_set_acpi_region(struct acpiphp_slot *slot)
@@ -1107,23 +1039,8 @@ int acpiphp_enable_slot(struct acpiphp_s
 	int retval;
 
 	mutex_lock(&slot->crit_sect);
-
-	/* wake up all functions */
-	retval = power_on_slot(slot);
-	if (retval)
-		goto err_exit;
-
-	if (get_slot_status(slot) == ACPI_STA_ALL) {
-		/* configure all functions */
-		retval = enable_device(slot);
-		if (retval)
-			power_off_slot(slot);
-	} else {
-		dbg("%s: Slot status is not ACPI_STA_ALL\n", __func__);
-		power_off_slot(slot);
-	}
-
- err_exit:
+	/* configure all functions */
+	retval = enable_device(slot);
 	mutex_unlock(&slot->crit_sect);
 	return retval;
 }
@@ -1146,11 +1063,6 @@ int acpiphp_disable_and_eject_slot(struc
 	if (retval)
 		goto err_exit;
 
-	/* power off all functions */
-	retval = power_off_slot(slot);
-	if (retval)
-		goto err_exit;
-
 	list_for_each_entry(func, &slot->funcs, sibling) {
 		/* We don't want to call _EJ0 on non-existing functions. */
 		if (func->flags & FUNC_HAS_EJ0) {
@@ -1184,7 +1096,7 @@ int acpiphp_disable_and_eject_slot(struc
  */
 u8 acpiphp_get_power_status(struct acpiphp_slot *slot)
 {
-	return (slot->flags & SLOT_POWEREDON);
+	return (slot->flags & SLOT_ENABLED);
 }
 
 
Index: linux-pm/drivers/pci/hotplug/acpiphp.h
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
+++ linux-pm/drivers/pci/hotplug/acpiphp.h
@@ -160,7 +160,6 @@ struct acpiphp_attention_info
 
 /* slot flags */
 
-#define SLOT_POWEREDON		(0x00000001)
 #define SLOT_ENABLED		(0x00000002)
 #define SLOT_MULTIFUNCTION	(0x00000004)
 
@@ -168,11 +167,7 @@ struct acpiphp_attention_info
 
 #define FUNC_HAS_STA		(0x00000001)
 #define FUNC_HAS_EJ0		(0x00000002)
-#define FUNC_HAS_PS0		(0x00000010)
-#define FUNC_HAS_PS1		(0x00000020)
-#define FUNC_HAS_PS2		(0x00000040)
-#define FUNC_HAS_PS3		(0x00000080)
-#define FUNC_HAS_DCK            (0x00000100)
+#define FUNC_HAS_DCK            (0x00000003)
 
 /* function prototypes */
 

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

* [RFC][PATCH 24/30] ACPI / hotplug / PCI: Do not check SLOT_ENABLED in enable_device()
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
                     ` (22 preceding siblings ...)
  2013-07-12  0:01   ` [RFC][PATCH 23/30] ACPI / hotplug / PCI: Do not exectute _PS0 and _PS3 directly Rafael J. Wysocki
@ 2013-07-12  0:02   ` Rafael J. Wysocki
  2013-07-12  0:03   ` [RFC][PATCH 25/30] ACPI / hotplug / PCI: Allow slots without new devices to be rescanned Rafael J. Wysocki
                     ` (7 subsequent siblings)
  31 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-12  0:02 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

From: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>

With Thunderbolt you can daisy chain devices: connect new devices to
an already plugged one.  In that case the "hotplug slot" is already
enabled, but we still want to look for new PCI devices behind it.

Reuse enable_device() to scan for new PCI devices on enabled slots
and push the SLOT_ENABLED check up into acpiphp_enable_slot().

[rjw: Rebased, modified the changelog]
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/pci/hotplug/acpiphp_glue.c | 5 ++---
 drivers/pci/hotplug/acpiphp_glue.c |   10 +++++-----
 1 file changed, 5 insertions(+), 5 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
@@ -557,9 +557,6 @@ static int __ref enable_device(struct ac
 	int num, max, pass;
 	LIST_HEAD(add_list);
 
-	if (slot->flags & SLOT_ENABLED)
-		goto err_exit;
-
 	list_for_each_entry(func, &slot->funcs, sibling)
 		acpiphp_bus_add(func_to_handle(func));
 
@@ -1036,11 +1033,14 @@ void acpiphp_remove_slots(struct pci_bus
  */
 int acpiphp_enable_slot(struct acpiphp_slot *slot)
 {
-	int retval;
+	int retval = 0;
 
 	mutex_lock(&slot->crit_sect);
+
 	/* configure all functions */
-	retval = enable_device(slot);
+	if (!(slot->flags & SLOT_ENABLED))
+		retval = enable_device(slot);
+
 	mutex_unlock(&slot->crit_sect);
 	return retval;
 }

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

* [RFC][PATCH 25/30] ACPI / hotplug / PCI: Allow slots without new devices to be rescanned
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
                     ` (23 preceding siblings ...)
  2013-07-12  0:02   ` [RFC][PATCH 24/30] ACPI / hotplug / PCI: Do not check SLOT_ENABLED in enable_device() Rafael J. Wysocki
@ 2013-07-12  0:03   ` Rafael J. Wysocki
  2013-07-12  0:04   ` [RFC][PATCH 26/30] ACPI / hotplug / PCI: Check for new devices on enabled slots Rafael J. Wysocki
                     ` (6 subsequent siblings)
  31 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-12  0:03 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

From: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>

Currently, enable_device() checks the return value of pci_scan_slot()
and returns immediately if that's 0 (meaning that no new functions
have been found in the slot).  However, if one of the functions in
the slot is a bridge, some new devices may appear below it even if
the bridge itself is present continuously, so it generally is
necessary to do the rescan anyway just in case.  [In particular,
that's necessary with the Thunderbolt daisy chaining in which case
new devices may be connected to the existing ones down the chain.]

The correctness of this change relies on the ability of
pcibios_resource_survey_bus() to detect if it has already been called
for the given bus and to skip it if so.  Failure to do that will lead
to resource allocation conflicts.

[rjw: Changelog]
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/pci/hotplug/acpiphp_glue.c | 11 ++---------
 drivers/pci/hotplug/acpiphp_glue.c |   11 ++---------
 1 file changed, 2 insertions(+), 9 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
@@ -554,18 +554,13 @@ static int __ref enable_device(struct ac
 	struct pci_dev *dev;
 	struct pci_bus *bus = slot->bus;
 	struct acpiphp_func *func;
-	int num, max, pass;
+	int max, pass;
 	LIST_HEAD(add_list);
 
 	list_for_each_entry(func, &slot->funcs, sibling)
 		acpiphp_bus_add(func_to_handle(func));
 
-	num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
-	if (num == 0) {
-		/* Maybe only part of funcs are added. */
-		dbg("No new device found\n");
-		goto err_exit;
-	}
+	pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
 
 	max = acpiphp_max_busnr(bus);
 	for (pass = 0; pass < 2; pass++) {
@@ -611,8 +606,6 @@ static int __ref enable_device(struct ac
 		}
 	}
 
-
- err_exit:
 	return 0;
 }
 


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

* [RFC][PATCH 26/30] ACPI / hotplug / PCI: Check for new devices on enabled slots
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
                     ` (24 preceding siblings ...)
  2013-07-12  0:03   ` [RFC][PATCH 25/30] ACPI / hotplug / PCI: Allow slots without new devices to be rescanned Rafael J. Wysocki
@ 2013-07-12  0:04   ` Rafael J. Wysocki
  2013-07-12  0:05   ` [RFC][PATCH 27/30] ACPI / hotplug / PCI: Get rid of unused constants in acpiphp.h Rafael J. Wysocki
                     ` (5 subsequent siblings)
  31 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-12  0:04 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

From: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Subject: 

The current implementation of acpiphp_check_bridge() is pretty dumb:
 - It enables a slot if it's not enabled and the slot status is
   ACPI_STA_ALL.
 - It disables a slot if it's enabled and the slot status is not
   ACPI_STA_ALL.

This behavior is not sufficient to handle the Thunderbolt daisy
chaining case properly, however, because in that case the bus
behind the already enabled slot needs to be rescanned for new
devices.

For this reason, modify acpiphp_check_bridge() so that slots are
disabled and stopped if they are not in the ACPI_STA_ALL state.

For slots in the ACPI_STA_ALL state devices that don't respond
are trimmed using a new function, pci_trim_stale_devices(),
introduced specifically for this purpose.  That function walks
the given bus and checks each device on it.  If the device doesn't
respond, it is assumed to be gone and removed.

Once all of the stale device objects on the bus have been removed,
we start looking for new devices that might have appeared on that
bus.  We do that even if the slot is already enabled (SLOT_ENABLED).

Moreover, make the bus check notification ignore SLOT_ENABLED and
go for enable_device() directly if bridge is NULL, so that devices
behind the slot are re-enumerated in that case too.

[rjw: Rebased, modified the changelog]
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp_glue.c |   49 +++++++++++++++----------------------
 drivers/pci/remove.c               |   20 +++++++++++++++
 include/linux/pci.h                |    1 
 3 files changed, 42 insertions(+), 28 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
@@ -705,41 +705,30 @@ static unsigned int get_slot_status(stru
  * Iterate over all slots under this bridge and make sure that if a
  * card is present they are enabled, and if not they are disabled.
  */
-static int acpiphp_check_bridge(struct acpiphp_bridge *bridge)
+static void acpiphp_check_bridge(struct acpiphp_bridge *bridge)
 {
 	struct acpiphp_slot *slot;
-	int retval = 0;
-	int enabled, disabled;
-
-	enabled = disabled = 0;
 
 	list_for_each_entry(slot, &bridge->slots, node) {
-		unsigned int status = get_slot_status(slot);
-		if (slot->flags & SLOT_ENABLED) {
-			if (status == ACPI_STA_ALL)
-				continue;
-
-			retval = acpiphp_disable_and_eject_slot(slot);
-			if (retval)
-				goto err_exit;
+		struct pci_bus *bus = slot->bus;
+		struct pci_dev *dev, *tmp;
+
+		mutex_lock(&slot->crit_sect);
+		/* wake up all functions */
+		if (get_slot_status(slot) == ACPI_STA_ALL) {
+			/* remove stale devices if any */
+			list_for_each_entry_safe(dev, tmp, &bus->devices,
+						 bus_list)
+				if (PCI_SLOT(dev->devfn) == slot->device)
+					pci_trim_stale_devices(dev);
 
-			disabled++;
+			/* configure all functions */
+			enable_device(slot);
 		} else {
-			if (status != ACPI_STA_ALL)
-				continue;
-			retval = acpiphp_enable_slot(slot);
-			if (retval) {
-				err("Error occurred in enabling\n");
-				goto err_exit;
-			}
-			enabled++;
+			disable_device(slot);
 		}
+		mutex_unlock(&slot->crit_sect);
 	}
-
-	dbg("%s: %d enabled, %d disabled\n", __func__, enabled, disabled);
-
- err_exit:
-	return retval;
 }
 
 static void acpiphp_set_hpp_values(struct pci_bus *bus)
@@ -840,7 +829,11 @@ static void hotplug_event(acpi_handle ha
 					    ACPI_UINT32_MAX, check_sub_bridges,
 					    NULL, NULL, NULL);
 		} else {
-			acpiphp_enable_slot(func->slot);
+			struct acpiphp_slot *slot = func->slot;
+
+			mutex_lock(&slot->crit_sect);
+			enable_device(slot);
+			mutex_unlock(&slot->crit_sect);
 		}
 		break;
 
Index: linux-pm/drivers/pci/remove.c
===================================================================
--- linux-pm.orig/drivers/pci/remove.c
+++ linux-pm/drivers/pci/remove.c
@@ -112,6 +112,26 @@ void pci_stop_and_remove_bus_device(stru
 }
 EXPORT_SYMBOL(pci_stop_and_remove_bus_device);
 
+/**
+ * pci_trim_stale_devices - remove stale device or any stale child
+ */
+void pci_trim_stale_devices(struct pci_dev *dev)
+{
+	struct pci_bus *bus = dev->subordinate;
+	struct pci_dev *child, *tmp;
+	bool alive;
+	u32 l;
+
+	/* check if the device responds */
+	alive = pci_bus_read_dev_vendor_id(dev->bus, dev->devfn, &l, 0);
+	if (!alive)
+		pci_stop_and_remove_bus_device(dev);
+
+	if (alive && bus)
+		list_for_each_entry_safe(child, tmp, &bus->devices, bus_list)
+			pci_trim_stale_devices(child);
+}
+
 void pci_stop_root_bus(struct pci_bus *bus)
 {
 	struct pci_dev *child, *tmp;
Index: linux-pm/include/linux/pci.h
===================================================================
--- linux-pm.orig/include/linux/pci.h
+++ linux-pm/include/linux/pci.h
@@ -754,6 +754,7 @@ struct pci_dev *pci_dev_get(struct pci_d
 void pci_dev_put(struct pci_dev *dev);
 void pci_remove_bus(struct pci_bus *b);
 void pci_stop_and_remove_bus_device(struct pci_dev *dev);
+void pci_trim_stale_devices(struct pci_dev *dev);
 void pci_stop_root_bus(struct pci_bus *bus);
 void pci_remove_root_bus(struct pci_bus *bus);
 void pci_setup_cardbus(struct pci_bus *bus);

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

* [RFC][PATCH 27/30] ACPI / hotplug / PCI: Get rid of unused constants in acpiphp.h
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
                     ` (25 preceding siblings ...)
  2013-07-12  0:04   ` [RFC][PATCH 26/30] ACPI / hotplug / PCI: Check for new devices on enabled slots Rafael J. Wysocki
@ 2013-07-12  0:05   ` Rafael J. Wysocki
  2013-07-12  0:06   ` [RFC][PATCH 28/30] ACPI / hotplug / PCI: Sanitize acpiphp_get_(latch)|(adapter)_status() Rafael J. Wysocki
                     ` (4 subsequent siblings)
  31 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-12  0:05 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

From: Mika Westerberg <mika.westerberg@linux.intel.com>

Drop some unused symbols from acpiphp.h and redefine SLOT_ENABLED
(which is the only slot flag now) as 1.

[rjw: Redefinition of SLOT_ENABLED, changelog]
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/pci/hotplug/acpiphp.h | 4 ----
 drivers/pci/hotplug/acpiphp.h |    6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

Index: linux-pm/drivers/pci/hotplug/acpiphp.h
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
+++ linux-pm/drivers/pci/hotplug/acpiphp.h
@@ -152,16 +152,12 @@ struct acpiphp_attention_info
 	struct module *owner;
 };
 
-/* PCI bus bridge HID */
-#define ACPI_PCI_HOST_HID		"PNP0A03"
-
 /* ACPI _STA method value (ignore bit 4; battery present) */
 #define ACPI_STA_ALL			(0x0000000f)
 
 /* slot flags */
 
-#define SLOT_ENABLED		(0x00000002)
-#define SLOT_MULTIFUNCTION	(0x00000004)
+#define SLOT_ENABLED		(0x00000001)
 
 /* function flags */
 

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

* [RFC][PATCH 28/30] ACPI / hotplug / PCI: Sanitize acpiphp_get_(latch)|(adapter)_status()
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
                     ` (26 preceding siblings ...)
  2013-07-12  0:05   ` [RFC][PATCH 27/30] ACPI / hotplug / PCI: Get rid of unused constants in acpiphp.h Rafael J. Wysocki
@ 2013-07-12  0:06   ` Rafael J. Wysocki
  2013-07-12  0:07   ` [RFC][PATCH 29/30] ACPI / hotplug / PCI: Redefine enable_device() and disable_device() Rafael J. Wysocki
                     ` (3 subsequent siblings)
  31 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-12  0:06 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

From: Mika Westerberg <mika.westerberg@linux.intel.com>

There is no need for a temporary variable and all the tricks with
ternary operators in acpiphp_get_(latch)|(adapter)_status(). Change
those functions to be a bit more straightforward.

[rjw: Changelog]
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/pci/hotplug/acpiphp_glue.c | 12 ++----------
 drivers/pci/hotplug/acpiphp_glue.c |   12 ++----------
 1 file changed, 2 insertions(+), 10 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
@@ -1092,11 +1092,7 @@ u8 acpiphp_get_power_status(struct acpip
  */
 u8 acpiphp_get_latch_status(struct acpiphp_slot *slot)
 {
-	unsigned int sta;
-
-	sta = get_slot_status(slot);
-
-	return (sta & ACPI_STA_DEVICE_UI) ? 0 : 1;
+	return !(get_slot_status(slot) & ACPI_STA_DEVICE_UI);
 }
 
 
@@ -1106,9 +1102,5 @@ u8 acpiphp_get_latch_status(struct acpip
  */
 u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot)
 {
-	unsigned int sta;
-
-	sta = get_slot_status(slot);
-
-	return (sta == 0) ? 0 : 1;
+	return !!get_slot_status(slot);
 }

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

* [RFC][PATCH 29/30] ACPI / hotplug / PCI: Redefine enable_device() and disable_device()
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
                     ` (27 preceding siblings ...)
  2013-07-12  0:06   ` [RFC][PATCH 28/30] ACPI / hotplug / PCI: Sanitize acpiphp_get_(latch)|(adapter)_status() Rafael J. Wysocki
@ 2013-07-12  0:07   ` Rafael J. Wysocki
  2013-07-12  0:07   ` [RFC][PATCH 30/30] ACPI / hotplug / PCI: Clean up bridge_mutex usage Rafael J. Wysocki
                     ` (2 subsequent siblings)
  31 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-12  0:07 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

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

Notice that functions enable_device() and disable_device() cannot
fail and their return values are ignored in the majority of places,
so redefine them as void and use the opportunity to change their
names to enable_slot() and disable_slot(), respectively, which much
better reflects what they do.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp_glue.c |   33 ++++++++++++---------------------
 1 file changed, 12 insertions(+), 21 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
@@ -543,13 +543,13 @@ static void check_hotplug_bridge(struct
 }
 
 /**
- * enable_device - enable, configure a slot
+ * enable_slot - enable, configure a slot
  * @slot: slot to be enabled
  *
  * This function should be called per *physical slot*,
  * not per each slot object in ACPI namespace.
  */
-static int __ref enable_device(struct acpiphp_slot *slot)
+static void __ref enable_slot(struct acpiphp_slot *slot)
 {
 	struct pci_dev *dev;
 	struct pci_bus *bus = slot->bus;
@@ -567,6 +567,7 @@ static int __ref enable_device(struct ac
 		list_for_each_entry(dev, &bus->devices, bus_list) {
 			if (PCI_SLOT(dev->devfn) != slot->device)
 				continue;
+
 			if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
 			    dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
 				max = pci_scan_bridge(bus, dev, max, pass);
@@ -605,8 +606,6 @@ static int __ref enable_device(struct ac
 			continue;
 		}
 	}
-
-	return 0;
 }
 
 /* return first device in slot, acquiring a reference on it */
@@ -628,16 +627,16 @@ static struct pci_dev *dev_in_slot(struc
 }
 
 /**
- * disable_device - disable a slot
+ * disable_slot - disable a slot
  * @slot: ACPI PHP slot
  */
-static int disable_device(struct acpiphp_slot *slot)
+static void disable_slot(struct acpiphp_slot *slot)
 {
 	struct acpiphp_func *func;
 	struct pci_dev *pdev;
 
 	/*
-	 * enable_device() enumerates all functions in this device via
+	 * enable_slot() enumerates all functions in this device via
 	 * pci_scan_slot(), whether they have associated ACPI hotplug
 	 * methods (_EJ0, etc.) or not.  Therefore, we remove all functions
 	 * here.
@@ -651,8 +650,6 @@ static int disable_device(struct acpiphp
 		acpiphp_bus_trim(func_to_handle(func));
 
 	slot->flags &= (~SLOT_ENABLED);
-
-	return 0;
 }
 
 
@@ -723,9 +720,9 @@ static void acpiphp_check_bridge(struct
 					pci_trim_stale_devices(dev);
 
 			/* configure all functions */
-			enable_device(slot);
+			enable_slot(slot);
 		} else {
-			disable_device(slot);
+			disable_slot(slot);
 		}
 		mutex_unlock(&slot->crit_sect);
 	}
@@ -832,7 +829,7 @@ static void hotplug_event(acpi_handle ha
 			struct acpiphp_slot *slot = func->slot;
 
 			mutex_lock(&slot->crit_sect);
-			enable_device(slot);
+			enable_slot(slot);
 			mutex_unlock(&slot->crit_sect);
 		}
 		break;
@@ -1019,16 +1016,13 @@ void acpiphp_remove_slots(struct pci_bus
  */
 int acpiphp_enable_slot(struct acpiphp_slot *slot)
 {
-	int retval = 0;
-
 	mutex_lock(&slot->crit_sect);
-
 	/* configure all functions */
 	if (!(slot->flags & SLOT_ENABLED))
-		retval = enable_device(slot);
+		enable_slot(slot);
 
 	mutex_unlock(&slot->crit_sect);
-	return retval;
+	return 0;
 }
 
 /**
@@ -1045,9 +1039,7 @@ int acpiphp_disable_and_eject_slot(struc
 	mutex_lock(&slot->crit_sect);
 
 	/* unconfigure all functions */
-	retval = disable_device(slot);
-	if (retval)
-		goto err_exit;
+	disable_slot(slot);
 
 	list_for_each_entry(func, &slot->funcs, sibling) {
 		/* We don't want to call _EJ0 on non-existing functions. */
@@ -1070,7 +1062,6 @@ int acpiphp_disable_and_eject_slot(struc
 		}
 	}
 
- err_exit:
 	mutex_unlock(&slot->crit_sect);
 	return retval;
 }

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

* [RFC][PATCH 30/30] ACPI / hotplug / PCI: Clean up bridge_mutex usage
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
                     ` (28 preceding siblings ...)
  2013-07-12  0:07   ` [RFC][PATCH 29/30] ACPI / hotplug / PCI: Redefine enable_device() and disable_device() Rafael J. Wysocki
@ 2013-07-12  0:07   ` Rafael J. Wysocki
  2013-07-12 13:18   ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Mika Westerberg
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
  31 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-12  0:07 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg

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

Do not acquire bridge_mutex around the addition of a slot to its
bridge's list of slots and arount the addition of a function to
its slot's list of functions, because that doesn't help anything
right now (those lists are walked without any locking anyway).

However, acquire bridge_mutex around the list walk in
acpiphp_remove_slots() and use list_for_each_entry() there,
because we terminate the walk as soon as we find the first matching
entry.  This prevents that list walk from colliding with bridge
addition and removal.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp_glue.c |   14 +++++++-------
 1 file changed, 7 insertions(+), 7 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
@@ -324,9 +324,7 @@ static acpi_status register_slot(acpi_ha
 	INIT_LIST_HEAD(&slot->funcs);
 	mutex_init(&slot->crit_sect);
 
-	mutex_lock(&bridge_mutex);
 	list_add_tail(&slot->node, &bridge->slots);
-	mutex_unlock(&bridge_mutex);
 
 	/* Register slots for ejectable funtions only. */
 	if (acpi_pci_check_ejectable(pbus, handle)  || is_dock_device(handle)) {
@@ -357,9 +355,7 @@ static acpi_status register_slot(acpi_ha
 
  slot_found:
 	newfunc->slot = slot;
-	mutex_lock(&bridge_mutex);
 	list_add_tail(&newfunc->sibling, &slot->funcs);
-	mutex_unlock(&bridge_mutex);
 
 	if (pci_bus_read_dev_vendor_id(pbus, PCI_DEVFN(device, function),
 				       &val, 60*1000))
@@ -997,17 +993,21 @@ void acpiphp_enumerate_slots(struct pci_
 /* Destroy hotplug slots associated with the PCI bus */
 void acpiphp_remove_slots(struct pci_bus *bus)
 {
-	struct acpiphp_bridge *bridge, *tmp;
+	struct acpiphp_bridge *bridge;
 
 	if (acpiphp_disabled)
 		return;
 
-	list_for_each_entry_safe(bridge, tmp, &bridge_list, list)
+	mutex_lock(&bridge_mutex);
+	list_for_each_entry(bridge, &bridge_list, list)
 		if (bridge->pci_bus == bus) {
+			mutex_unlock(&bridge_mutex);
 			cleanup_bridge(bridge);
 			put_bridge(bridge);
-			break;
+			return;
 		}
+
+	mutex_unlock(&bridge_mutex);
 }
 
 /**

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

* Re: [RFC][PATCH 11/30] ACPI / hotplug / PCI: Register all devices under the given bridge
  2013-07-11 23:50   ` [RFC][PATCH 11/30] ACPI / hotplug / PCI: Register all devices under the given bridge Rafael J. Wysocki
@ 2013-07-12 11:54     ` Mika Westerberg
  2013-07-12 13:01       ` Mika Westerberg
  0 siblings, 1 reply; 135+ messages in thread
From: Mika Westerberg @ 2013-07-12 11:54 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu

On Fri, Jul 12, 2013 at 01:50:29AM +0200, Rafael J. Wysocki wrote:
> @@ -1210,6 +1125,35 @@ void acpiphp_enumerate_slots(struct pci_
>  	 */
>  	get_device(&bus->dev);
>  
> +	if (!pci_is_root_bus(bridge->pci_bus)) {
> +		struct acpiphp_context *context;
> +
> +		/*
> +		 * This bridge should have been registered as a hotplug function
> +		 * under its parent, so the context has to be there.  If not, we
> +		 * are in deep goo.
> +		 */
> +		mutex_lock(&acpiphp_context_lock);
> +		context = acpiphp_get_context(handle);
> +		if (WARN_ON(!context || !context->func)) {
> +			mutex_unlock(&acpiphp_context_lock);
> +			put_device(&bus->dev);
> +			kfree(bridge);
> +			return;
> +		}
> +		bridge->context = context;
> +		context->bridge = bridge;
> +		/* Get a reference to the parent bridge. */
> +		get_bridge(context->func->slot->bridge);
> +		mutex_unlock(&acpiphp_context_lock);
> +	}
> +
> +	status = acpi_get_handle(bridge->handle, "_EJ0", &handle);
> +	if (ACPI_SUCCESS(status)) {
> +		dbg("found ejectable p2p bridge\n");
> +		bridge->flags |= BRIDGE_HAS_EJ0;
> +	}
> +
>  	/* must be added to the list prior to calling register_slot */
>  	mutex_lock(&bridge_mutex);
>  	list_add(&bridge->list, &bridge_list);
> @@ -1220,34 +1164,9 @@ void acpiphp_enumerate_slots(struct pci_
>  				     register_slot, NULL, bridge, NULL);
>  	if (ACPI_FAILURE(status)) {
>  		acpi_handle_err(bridge->handle, "failed to register slots\n");
> -		goto err;
> -	}
> -
> -	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. */
> -		get_bridge(context->func->slot->bridge);
> -		return;
> +		cleanup_bridge(bridge);
> +		put_bridge(bridge);
>  	}
> -
> -	/* install notify handler for P2P bridges */
> -	status = acpi_install_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY,
> -					     handle_hotplug_event, NULL);

With this removed we now install notify handlers for the slot objects under
this bridge but not for the bridge itself.

In case of Thunderbolt the BIOS will send the event for the root port ACPI
device \_SB_.PCI0.RP05 and with the above change we don't handle it
anymore.

> -	if (ACPI_SUCCESS(status))
> -		return;
> -
> -	acpi_handle_err(bridge->handle, "failed to register notify handler\n");
> -
> - err:
> -	cleanup_bridge(bridge);
> -	put_bridge(bridge);
>  }

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

* Re: [RFC][PATCH 11/30] ACPI / hotplug / PCI: Register all devices under the given bridge
  2013-07-12 11:54     ` Mika Westerberg
@ 2013-07-12 13:01       ` Mika Westerberg
  0 siblings, 0 replies; 135+ messages in thread
From: Mika Westerberg @ 2013-07-12 13:01 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu

On Fri, Jul 12, 2013 at 02:54:20PM +0300, Mika Westerberg wrote:
> On Fri, Jul 12, 2013 at 01:50:29AM +0200, Rafael J. Wysocki wrote:
> > @@ -1210,6 +1125,35 @@ void acpiphp_enumerate_slots(struct pci_
> >  	 */
> >  	get_device(&bus->dev);
> >  
> > +	if (!pci_is_root_bus(bridge->pci_bus)) {
> > +		struct acpiphp_context *context;
> > +
> > +		/*
> > +		 * This bridge should have been registered as a hotplug function
> > +		 * under its parent, so the context has to be there.  If not, we
> > +		 * are in deep goo.
> > +		 */
> > +		mutex_lock(&acpiphp_context_lock);
> > +		context = acpiphp_get_context(handle);
> > +		if (WARN_ON(!context || !context->func)) {
> > +			mutex_unlock(&acpiphp_context_lock);
> > +			put_device(&bus->dev);
> > +			kfree(bridge);
> > +			return;
> > +		}
> > +		bridge->context = context;
> > +		context->bridge = bridge;
> > +		/* Get a reference to the parent bridge. */
> > +		get_bridge(context->func->slot->bridge);
> > +		mutex_unlock(&acpiphp_context_lock);
> > +	}
> > +
> > +	status = acpi_get_handle(bridge->handle, "_EJ0", &handle);
> > +	if (ACPI_SUCCESS(status)) {
> > +		dbg("found ejectable p2p bridge\n");
> > +		bridge->flags |= BRIDGE_HAS_EJ0;
> > +	}
> > +
> >  	/* must be added to the list prior to calling register_slot */
> >  	mutex_lock(&bridge_mutex);
> >  	list_add(&bridge->list, &bridge_list);
> > @@ -1220,34 +1164,9 @@ void acpiphp_enumerate_slots(struct pci_
> >  				     register_slot, NULL, bridge, NULL);
> >  	if (ACPI_FAILURE(status)) {
> >  		acpi_handle_err(bridge->handle, "failed to register slots\n");
> > -		goto err;
> > -	}
> > -
> > -	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. */
> > -		get_bridge(context->func->slot->bridge);
> > -		return;
> > +		cleanup_bridge(bridge);
> > +		put_bridge(bridge);
> >  	}
> > -
> > -	/* install notify handler for P2P bridges */
> > -	status = acpi_install_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY,
> > -					     handle_hotplug_event, NULL);
> 
> With this removed we now install notify handlers for the slot objects under
> this bridge but not for the bridge itself.
> 
> In case of Thunderbolt the BIOS will send the event for the root port ACPI
> device \_SB_.PCI0.RP05 and with the above change we don't handle it
> anymore.

Actually there was a bug in patch [23/30] that caused this. Once that is
fixed I can see that the notify handlers get correctly installed. I'll
comment on that patch.

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

* Re: [RFC][PATCH 23/30] ACPI / hotplug / PCI: Do not exectute _PS0 and _PS3 directly
  2013-07-12  0:01   ` [RFC][PATCH 23/30] ACPI / hotplug / PCI: Do not exectute _PS0 and _PS3 directly Rafael J. Wysocki
@ 2013-07-12 13:05     ` Mika Westerberg
  2013-07-12 21:09       ` Rafael J. Wysocki
  0 siblings, 1 reply; 135+ messages in thread
From: Mika Westerberg @ 2013-07-12 13:05 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu

On Fri, Jul 12, 2013 at 02:01:30AM +0200, Rafael J. Wysocki wrote:
> Index: linux-pm/drivers/pci/hotplug/acpiphp.h
> ===================================================================
> --- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
> +++ linux-pm/drivers/pci/hotplug/acpiphp.h
> @@ -160,7 +160,6 @@ struct acpiphp_attention_info
>  
>  /* slot flags */
>  
> -#define SLOT_POWEREDON		(0x00000001)
>  #define SLOT_ENABLED		(0x00000002)
>  #define SLOT_MULTIFUNCTION	(0x00000004)
>  
> @@ -168,11 +167,7 @@ struct acpiphp_attention_info
>  
>  #define FUNC_HAS_STA		(0x00000001)
>  #define FUNC_HAS_EJ0		(0x00000002)
> -#define FUNC_HAS_PS0		(0x00000010)
> -#define FUNC_HAS_PS1		(0x00000020)
> -#define FUNC_HAS_PS2		(0x00000040)
> -#define FUNC_HAS_PS3		(0x00000080)
> -#define FUNC_HAS_DCK            (0x00000100)
> +#define FUNC_HAS_DCK            (0x00000003)

These are flags not enum so the above wants to be

	#define FUNC_HAS_DCK            (0x00000004)

otherwise we accidentally match checks like:

	/* install notify handler */
	if (!(newfunc->flags & FUNC_HAS_DCK)) {
		...

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

* Re: [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
                     ` (29 preceding siblings ...)
  2013-07-12  0:07   ` [RFC][PATCH 30/30] ACPI / hotplug / PCI: Clean up bridge_mutex usage Rafael J. Wysocki
@ 2013-07-12 13:18   ` Mika Westerberg
  2013-07-12 21:04     ` Rafael J. Wysocki
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
  31 siblings, 1 reply; 135+ messages in thread
From: Mika Westerberg @ 2013-07-12 13:18 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu

On Fri, Jul 12, 2013 at 01:34:20AM +0200, Rafael J. Wysocki wrote:
> Hi,
> 
> I've made some progress with my ACPIPHP rework since I posted the series last
> time and here goes an update.
> 
> First off, the previous series was somewhat racy, which should be fixed now.
> Apart from this there's quite some new material on top of the patches I posted
> last time (or rather on top of their new versions) and I integrated the
> Thunderbolt series from Mika with that.  As a result,
> 
> https://patchwork.kernel.org/patch/2817341/
> 
> is required to be applied.

With the above mentioned patch applied + fix for patch [23/30], I tested
this series on Acer Aspire S5 and Intel DZ77RE-75K desktop and Thunderbolt
works just fine :-)

You can add

Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>

to the series.

Nice cleanup!

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

* Re: [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds
  2013-07-12 13:18   ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Mika Westerberg
@ 2013-07-12 21:04     ` Rafael J. Wysocki
  0 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-12 21:04 UTC (permalink / raw)
  To: Mika Westerberg
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu

On Friday, July 12, 2013 04:18:50 PM Mika Westerberg wrote:
> On Fri, Jul 12, 2013 at 01:34:20AM +0200, Rafael J. Wysocki wrote:
> > Hi,
> > 
> > I've made some progress with my ACPIPHP rework since I posted the series last
> > time and here goes an update.
> > 
> > First off, the previous series was somewhat racy, which should be fixed now.
> > Apart from this there's quite some new material on top of the patches I posted
> > last time (or rather on top of their new versions) and I integrated the
> > Thunderbolt series from Mika with that.  As a result,
> > 
> > https://patchwork.kernel.org/patch/2817341/
> > 
> > is required to be applied.
> 
> With the above mentioned patch applied + fix for patch [23/30], I tested
> this series on Acer Aspire S5 and Intel DZ77RE-75K desktop and Thunderbolt
> works just fine :-)
> 
> You can add
> 
> Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
> 
> to the series.

Thanks a lot, that's really helpful!

Now I can rebase it on the previous cleanups and we'll see how that all
together works on top of the Linus' current. :-)

> Nice cleanup!

Thanks!

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

* Re: [RFC][PATCH 23/30] ACPI / hotplug / PCI: Do not exectute _PS0 and _PS3 directly
  2013-07-12 13:05     ` Mika Westerberg
@ 2013-07-12 21:09       ` Rafael J. Wysocki
  0 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-12 21:09 UTC (permalink / raw)
  To: Mika Westerberg
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu

On Friday, July 12, 2013 04:05:08 PM Mika Westerberg wrote:
> On Fri, Jul 12, 2013 at 02:01:30AM +0200, Rafael J. Wysocki wrote:
> > Index: linux-pm/drivers/pci/hotplug/acpiphp.h
> > ===================================================================
> > --- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
> > +++ linux-pm/drivers/pci/hotplug/acpiphp.h
> > @@ -160,7 +160,6 @@ struct acpiphp_attention_info
> >  
> >  /* slot flags */
> >  
> > -#define SLOT_POWEREDON		(0x00000001)
> >  #define SLOT_ENABLED		(0x00000002)
> >  #define SLOT_MULTIFUNCTION	(0x00000004)
> >  
> > @@ -168,11 +167,7 @@ struct acpiphp_attention_info
> >  
> >  #define FUNC_HAS_STA		(0x00000001)
> >  #define FUNC_HAS_EJ0		(0x00000002)
> > -#define FUNC_HAS_PS0		(0x00000010)
> > -#define FUNC_HAS_PS1		(0x00000020)
> > -#define FUNC_HAS_PS2		(0x00000040)
> > -#define FUNC_HAS_PS3		(0x00000080)
> > -#define FUNC_HAS_DCK            (0x00000100)
> > +#define FUNC_HAS_DCK            (0x00000003)
> 
> These are flags not enum so the above wants to be
> 
> 	#define FUNC_HAS_DCK            (0x00000004)

Yeah, obviously.

I guess it goes against the natural tendency to assign numbers to things
sequentially, so I generally prefer the (1U << n) notation. :-)

> otherwise we accidentally match checks like:
> 
> 	/* install notify handler */
> 	if (!(newfunc->flags & FUNC_HAS_DCK)) {
> 		...

Yup.  Thanks for spotting that!

Rafael


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

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

* [PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds
  2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
                     ` (30 preceding siblings ...)
  2013-07-12 13:18   ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Mika Westerberg
@ 2013-07-17 23:05   ` Rafael J. Wysocki
  2013-07-17 23:15     ` [PATCH 1/30] ACPI / PCI: Make bus registration and unregistration symmetric Rafael J. Wysocki
                       ` (30 more replies)
  31 siblings, 31 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:05 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

Hi All,

Now the series has been rebased on top of current linux-pm.git/linux-next
and tested on two systems with Thunderbolt.  Some changes have been made too. ->

On Friday, July 12, 2013 01:34:20 AM Rafael J. Wysocki wrote:
> Hi,
> 
> I've made some progress with my ACPIPHP rework since I posted the series last
> time and here goes an update.
> 
> First off, the previous series was somewhat racy, which should be fixed now.
> Apart from this there's quite some new material on top of the patches I posted
> last time (or rather on top of their new versions) and I integrated the
> Thunderbolt series from Mika with that.  As a result,
> 
> https://patchwork.kernel.org/patch/2817341/
> 
> is required to be applied.
> 
> Still untested, still based on 3.10 with ACPI+PM 3.11 material merged on top,
> but this time I don't have any plans to add more patches to the series for the
> time being.  Also 3.11-rc1 should be out in a couple of days, so I'll be able
> to integrate this work with the previous cleanups series from Gerry and myself
> on top of it.
> 
> I did my best not to change too much at a time and some steps add stuff that
> is removed by the subsequent ones, so hopefully it is bisectable.
> 
> If anyone finds something questionable or outright bogus in these patches,
> please let me know before it's too late. ;-)
> 
> [ 1/30] Make bus registration and unregistration symmetric.  [Resend]
> [ 2/30] Consolidate acpiphp_enumerate_slots().  [Resend]
> [ 3/30] Fix error code path in register_slot().  [Resend]
> [ 4/30] Introduce hotplug context objects for ACPI device objects corresponding
>         to PCI hotplug devices.  [Update]
> [ 5/30] Unified notify handler for hotplug events.  [Update]
> [ 6/30] Drop acpiphp_handle_to_bridge() and use context objects instead of it.  [Update]
> [ 7/30] Pass entire hotplug context objects (instead of their fields
>         individually) to event handling work functions.  [Update]
> [ 8/30] Merge hotplug event handling functions.  [Update]
> [ 9/30] Drop func field from struct acpiphp_bridge.
> [10/30] Refactor slot allocation code in register_slot().
> [11/30] Make acpiphp_enumerate_slots() to register all devices on the given bus
>         and install the notification handler for all of them.
> [12/30] Drop sun field from struct acpiphp_slot.
> [13/30] Use common slot count variable in register_slot().

-> The one above has been dropped, because it might cause regressions to appear
on some systems, but that's not a big deal.

The numbering of the patches below has changed as a result, so the next one is
[13/30] now and so on.

> [14/30] Drop flags field from struct acpiphp_bridge.
> [15/30] Embed function structure into struct acpiphp_context.
> [16/30] Drop handle field from struct acpiphp_func.
> [17/30] Drop handle field from struct acpiphp_bridge.
> [18/30] Store parent bridge pointer in function objects and bus pointer in slot
>         objects.
> [19/30] Rework ACPI namespace scanning and trimming routines.
> [20/30] Drop redundant checks from check_hotplug_bridge().
> [21/30] Consolidate slot disabling and ejecting
> [22/30] Do not queue up event handling work items for non-hotplug events.
> [23/30] Do not execute _PS0 and _PS3 directly.

This one was fixed after Mika had reported a problem with it.

> [24/30] Do not check SLOT_ENABLED in enable_device().  [Thunderbolt series]
> [25/30] Allow slots without new devices to be rescanned.  [Thunderbolt series]
> [26/30] Check for new devices on enabled slots.  [Thunderbolt series, TBD]

This one was reworked to use acpi_bus_trim() on ACPI device objects
corresponding to PCI devices being removed (it also uses _STA to check the
status of those devices if available).

> [27/30] Get rid of unused constands in acpiphp.h.  [Thunderbolt series]
> [28/30] Sanitize acpiphp_get_(latch)|(adapter)_status().  [Thunderbolt series]
> [29/30] Redefine enable_device() and disable_device() (rename and change to void).
> [30/30] Clean up the usage of bridge_mutex.

The one above is [29/30] now and we have added one more patch:

[30/30] Drop check_sub_bridges() which isn't necessary any more.

The updated patches follow.

If you don't hate this stuff, I'll put it into linux-next over the weekend for
further testing.

Thanks,
Rafael


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

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

* [PATCH 1/30] ACPI / PCI: Make bus registration and unregistration symmetric
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
@ 2013-07-17 23:15     ` Rafael J. Wysocki
  2013-07-18  1:00       ` Yinghai Lu
  2013-07-17 23:16     ` [PATCH 2/30] ACPI / hotplug / PCI: Consolidate acpiphp_enumerate_slots() Rafael J. Wysocki
                       ` (29 subsequent siblings)
  30 siblings, 1 reply; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:15 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

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 |    6 ++++--
 drivers/pci/pci-acpi.c             |   16 ++++------------
 include/linux/pci-acpi.h           |   10 ++++------
 4 files changed, 21 insertions(+), 25 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
@@ -1147,14 +1147,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 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] 135+ messages in thread

* [PATCH 2/30] ACPI / hotplug / PCI: Consolidate acpiphp_enumerate_slots()
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
  2013-07-17 23:15     ` [PATCH 1/30] ACPI / PCI: Make bus registration and unregistration symmetric Rafael J. Wysocki
@ 2013-07-17 23:16     ` Rafael J. Wysocki
  2013-07-18  1:40       ` Yinghai Lu
  2013-07-17 23:17     ` [PATCH 3/30] ACPI / hotplug / PCI: Always return success after adding a function Rafael J. Wysocki
                       ` (28 subsequent siblings)
  30 siblings, 1 reply; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:16 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

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 |   92 ++++++++++++++++++-------------------
 1 file changed, 45 insertions(+), 47 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
@@ -353,46 +353,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)
@@ -1149,8 +1109,9 @@ static void handle_hotplug_event_func(ac
  */
 void acpiphp_enumerate_slots(struct pci_bus *bus)
 {
-	acpi_handle handle;
 	struct acpiphp_bridge *bridge;
+	acpi_handle handle;
+	acpi_status status;
 
 	if (acpiphp_disabled)
 		return;
@@ -1178,14 +1139,51 @@ void acpiphp_enumerate_slots(struct pci_
 	 */
 	get_device(&bus->dev);
 
-	if (!pci_is_root_bus(bridge->pci_bus) &&
-	    acpi_has_method(bridge->handle, "_EJ0")) {
-		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;
+	}
+
+	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;
 	}
 
-	init_bridge_misc(bridge);
+	if (!acpi_has_method(bridge->handle, "_EJ0"))
+		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] 135+ messages in thread

* [PATCH 3/30] ACPI / hotplug / PCI: Always return success after adding a function
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
  2013-07-17 23:15     ` [PATCH 1/30] ACPI / PCI: Make bus registration and unregistration symmetric Rafael J. Wysocki
  2013-07-17 23:16     ` [PATCH 2/30] ACPI / hotplug / PCI: Consolidate acpiphp_enumerate_slots() Rafael J. Wysocki
@ 2013-07-17 23:17     ` Rafael J. Wysocki
  2013-07-17 23:17     ` [PATCH 4/30] ACPI / hotplug / PCI: Hotplug context objects for bridges and functions Rafael J. Wysocki
                       ` (27 subsequent siblings)
  30 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:17 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

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
@@ -325,10 +325,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] 135+ messages in thread

* [PATCH 4/30] ACPI / hotplug / PCI: Hotplug context objects for bridges and functions
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
                       ` (2 preceding siblings ...)
  2013-07-17 23:17     ` [PATCH 3/30] ACPI / hotplug / PCI: Always return success after adding a function Rafael J. Wysocki
@ 2013-07-17 23:17     ` Rafael J. Wysocki
  2013-07-18  2:00       ` Yinghai Lu
  2013-07-17 23:18     ` [PATCH 5/30] ACPI / hotplug / PCI: Unified notify handler for hotplug events Rafael J. Wysocki
                       ` (26 subsequent siblings)
  30 siblings, 1 reply; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:17 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

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

When either a new hotplug bridge 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 |  179 ++++++++++++++++++++++++++++---------
 2 files changed, 146 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;
@@ -128,6 +131,13 @@ struct acpiphp_func {
 	u32		flags;		/* see below */
 };
 
+struct acpiphp_context {
+	acpi_handle handle;
+	struct acpiphp_func *func;
+	struct acpiphp_bridge *bridge;
+	unsigned int refcount;
+};
+
 /*
  * 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
@@ -55,6 +55,7 @@
 
 static LIST_HEAD(bridge_list);
 static DEFINE_MUTEX(bridge_mutex);
+static DEFINE_MUTEX(acpiphp_context_lock);
 
 #define MY_NAME "acpiphp_glue"
 
@@ -79,6 +80,74 @@ is_pci_dock_device(acpi_handle handle, u
 	}
 }
 
+static void acpiphp_context_handler(acpi_handle handle, void *context)
+{
+	/* Intentionally empty. */
+}
+
+/**
+ * acpiphp_init_context - Create hotplug context and grab a reference to it.
+ * @handle: ACPI object handle to create the context for.
+ *
+ * Call under acpiphp_context_lock.
+ */
+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;
+	context->refcount = 1;
+	status = acpi_attach_data(handle, acpiphp_context_handler, context);
+	if (ACPI_FAILURE(status)) {
+		kfree(context);
+		return NULL;
+	}
+	return context;
+}
+
+/**
+ * acpiphp_get_context - Get hotplug context and grab a reference to it.
+ * @handle: ACPI object handle to get the context for.
+ *
+ * Call under acpiphp_context_lock.
+ */
+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;
+		context->refcount++;
+	}
+	return context;
+}
+
+/**
+ * acpiphp_put_context - Drop a reference to ACPI hotplug context.
+ * @handle: ACPI object handle to put the context for.
+ *
+ * The context object is removed if there are no more references to it.
+ *
+ * Call under acpiphp_context_lock.
+ */
+static void acpiphp_put_context(struct acpiphp_context *context)
+{
+	if (--context->refcount)
+		return;
+
+	WARN_ON(context->func || context->bridge);
+	acpi_detach_data(context->handle, acpiphp_context_handler);
+	kfree(context);
+}
+
 static inline void get_bridge(struct acpiphp_bridge *bridge)
 {
 	kref_get(&bridge->ref);
@@ -91,25 +160,37 @@ 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;
 
+	mutex_lock(&acpiphp_context_lock);
+
 	bridge = container_of(kref, struct acpiphp_bridge, ref);
 
 	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;
+			acpiphp_put_context(context);
 			kfree(func);
 		}
 		kfree(slot);
 	}
 
-	/* Release reference acquired by acpiphp_bridge_handle_to_function() */
+	/* Release the 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;
+	acpiphp_put_context(context);
 	kfree(bridge);
+
+	mutex_unlock(&acpiphp_context_lock);
 }
 
 /*
@@ -194,10 +275,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 = data;
+	struct acpiphp_context *context;
 	struct acpiphp_slot *slot;
 	struct acpiphp_func *newfunc;
 	acpi_status status = AE_OK;
@@ -230,6 +312,18 @@ register_slot(acpi_handle handle, u32 lv
 	newfunc->handle = handle;
 	newfunc->function = function;
 
+	mutex_lock(&acpiphp_context_lock);
+	context = acpiphp_init_context(handle);
+	if (!context) {
+		mutex_unlock(&acpiphp_context_lock);
+		acpi_handle_err(handle, "No hotplug context\n");
+		kfree(newfunc);
+		return AE_NOT_EXIST;
+	}
+	newfunc->context = context;
+	context->func = newfunc;
+	mutex_unlock(&acpiphp_context_lock);
+
 	if (acpi_has_method(handle, "_EJ0"))
 		newfunc->flags = FUNC_HAS_EJ0;
 
@@ -266,8 +360,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;
@@ -291,7 +385,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;
 		}
 	}
 
@@ -329,15 +425,20 @@ 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);
-	kfree(newfunc);
 
-	return AE_OK;
+ err_out:
+	mutex_lock(&acpiphp_context_lock);
+	context->func = NULL;
+	acpiphp_put_context(context);
+	mutex_unlock(&acpiphp_context_lock);
+	kfree(newfunc);
+	return status;
 }
 
 
@@ -352,32 +453,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;
@@ -1108,6 +1183,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;
@@ -1120,8 +1196,8 @@ void acpiphp_enumerate_slots(struct pci_
 		return;
 
 	bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
-	if (bridge == NULL) {
-		err("out of memory\n");
+	if (!bridge) {
+		acpi_handle_err(handle, "No memory for bridge object\n");
 		return;
 	}
 
@@ -1131,6 +1207,21 @@ void acpiphp_enumerate_slots(struct pci_
 	bridge->pci_dev = pci_dev_get(bus->self);
 	bridge->pci_bus = bus;
 
+	mutex_lock(&acpiphp_context_lock);
+	context = acpiphp_get_context(handle);
+	if (!context) {
+		context = acpiphp_init_context(handle);
+		if (!context) {
+			mutex_unlock(&acpiphp_context_lock);
+			acpi_handle_err(handle, "No hotplug context\n");
+			kfree(bridge);
+			return;
+		}
+	}
+	bridge->context = context;
+	context->bridge = bridge;
+	mutex_unlock(&acpiphp_context_lock);
+
 	/*
 	 * Grab a ref to the subordinate PCI bus in case the bus is
 	 * removed via PCI core logical hotplug. The ref pins the bus
@@ -1169,13 +1260,15 @@ void acpiphp_enumerate_slots(struct pci_
 
 	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] 135+ messages in thread

* [PATCH 5/30] ACPI / hotplug / PCI: Unified notify handler for hotplug events
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
                       ` (3 preceding siblings ...)
  2013-07-17 23:17     ` [PATCH 4/30] ACPI / hotplug / PCI: Hotplug context objects for bridges and functions Rafael J. Wysocki
@ 2013-07-17 23:18     ` Rafael J. Wysocki
  2013-07-18  2:07       ` Yinghai Lu
  2013-07-17 23:19     ` [PATCH 6/30] ACPI / hotplug / PCI: Rework acpiphp_handle_to_bridge() Rafael J. Wysocki
                       ` (25 subsequent siblings)
  30 siblings, 1 reply; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:18 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

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.  Moreover, it fixes a theoretically possible race between
handle_hotplug_event() and free_bridge() tearing down data structures
for the same handle.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp.h      |    1 
 drivers/pci/hotplug/acpiphp_glue.c |  132 ++++++++++++++-----------------------
 2 files changed, 53 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
@@ -59,11 +59,10 @@ static DEFINE_MUTEX(acpiphp_context_lock
 
 #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 */
@@ -179,13 +178,13 @@ static void free_bridge(struct kref *kre
 		kfree(slot);
 	}
 
+	context = bridge->context;
 	/* Release the 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;
 	acpiphp_put_context(context);
 	kfree(bridge);
@@ -414,12 +413,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");
 	}
 
@@ -476,32 +475,23 @@ 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)) {
 				unregister_hotplug_dock_device(func->handle);
 			}
 			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");
 			}
@@ -1071,31 +1061,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;
@@ -1153,17 +1118,33 @@ 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;
+	void (*work_func)(struct work_struct *work) = NULL;
+
+	mutex_lock(&acpiphp_context_lock);
+	context = acpiphp_get_context(handle);
+	if (context) {
+		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;
+		}
+		acpiphp_put_context(context);
+	}
+	mutex_unlock(&acpiphp_context_lock);
 
 	/*
 	 * Currently the code adds all hotplug events to the kacpid_wq
@@ -1173,8 +1154,8 @@ 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);
+	if (work_func)
+		alloc_acpi_hp_work(handle, type, data, work_func);
 }
 
 /*
@@ -1245,33 +1226,24 @@ void acpiphp_enumerate_slots(struct pci_
 	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;
+	if (acpi_has_method(bridge->handle, "_EJ0")) {
+		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;
 	}
 
-	if (!acpi_has_method(bridge->handle, "_EJ0"))
+	/* install notify handler for P2P bridges */
+	status = acpi_install_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY,
+					     handle_hotplug_event, NULL);
+	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
@@ -136,6 +136,7 @@ struct acpiphp_context {
 	struct acpiphp_func *func;
 	struct acpiphp_bridge *bridge;
 	unsigned int refcount;
+	bool handler_for_func;
 };
 
 /*

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

* [PATCH 6/30] ACPI / hotplug / PCI: Rework acpiphp_handle_to_bridge()
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
                       ` (4 preceding siblings ...)
  2013-07-17 23:18     ` [PATCH 5/30] ACPI / hotplug / PCI: Unified notify handler for hotplug events Rafael J. Wysocki
@ 2013-07-17 23:19     ` Rafael J. Wysocki
  2013-07-17 23:19     ` [PATCH 7/30] ACPI / hotplug / PCI: Pass hotplug context objects to event handlers Rafael J. Wysocki
                       ` (24 subsequent siblings)
  30 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:19 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

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 to get to acpiphp_bridge
objects associated with hotplug bridges from those context objects
rather than from the global list of hotplug bridges.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp_glue.c |   20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 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
@@ -454,18 +454,20 @@ static int detect_ejectable_slots(acpi_h
 
 static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle)
 {
-	struct acpiphp_bridge *bridge;
+	struct acpiphp_context *context;
+	struct acpiphp_bridge *bridge = NULL;
 
-	mutex_lock(&bridge_mutex);
-	list_for_each_entry(bridge, &bridge_list, list)
-		if (bridge->handle == handle) {
+	mutex_lock(&acpiphp_context_lock);
+	context = acpiphp_get_context(handle);
+	if (context) {
+		bridge = context->bridge;
+		if (bridge)
 			get_bridge(bridge);
-			mutex_unlock(&bridge_mutex);
-			return bridge;
-		}
-	mutex_unlock(&bridge_mutex);
 
-	return NULL;
+		acpiphp_put_context(context);
+	}
+	mutex_unlock(&acpiphp_context_lock);
+	return bridge;
 }
 
 static void cleanup_bridge(struct acpiphp_bridge *bridge)

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

* [PATCH 7/30] ACPI / hotplug / PCI: Pass hotplug context objects to event handlers
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
                       ` (5 preceding siblings ...)
  2013-07-17 23:19     ` [PATCH 6/30] ACPI / hotplug / PCI: Rework acpiphp_handle_to_bridge() Rafael J. Wysocki
@ 2013-07-17 23:19     ` Rafael J. Wysocki
  2013-07-17 23:20     ` [PATCH 8/30] ACPI / hotplug / PCI: Merge hotplug event handling functions Rafael J. Wysocki
                       ` (23 subsequent siblings)
  30 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:19 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

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

Modify handle_hotplug_event() to pass the entire context object
(instead of its fields individually) to work functions started by it.

This change makes the subsequent consolidation of the event handling
work functions a bit more straightforward.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp_glue.c |   16 ++++++++--------
 1 file changed, 8 insertions(+), 8 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
@@ -989,6 +989,7 @@ void acpiphp_check_host_bridge(acpi_hand
 
 static void _handle_hotplug_event_bridge(struct work_struct *work)
 {
+	struct acpiphp_context *context;
 	struct acpiphp_bridge *bridge;
 	char objname[64];
 	struct acpi_buffer buffer = { .length = sizeof(objname),
@@ -1000,7 +1001,8 @@ static void _handle_hotplug_event_bridge
 	hp_work = container_of(work, struct acpi_hp_work, work);
 	handle = hp_work->handle;
 	type = hp_work->type;
-	bridge = (struct acpiphp_bridge *)hp_work->context;
+	context = hp_work->context;
+	bridge = context->bridge;
 
 	acpi_scan_lock_acquire();
 
@@ -1105,18 +1107,18 @@ static void hotplug_event_func(acpi_hand
 
 static void _handle_hotplug_event_func(struct work_struct *work)
 {
+	struct acpiphp_context *context;
 	struct acpi_hp_work *hp_work;
-	struct acpiphp_func *func;
 
 	hp_work = container_of(work, struct acpi_hp_work, work);
-	func = hp_work->context;
+	context = hp_work->context;
 	acpi_scan_lock_acquire();
 
-	hotplug_event_func(hp_work->handle, hp_work->type, func);
+	hotplug_event_func(hp_work->handle, hp_work->type, context->func);
 
 	acpi_scan_lock_release();
 	kfree(hp_work); /* allocated in handle_hotplug_event_func */
-	put_bridge(func->slot->bridge);
+	put_bridge(context->func->slot->bridge);
 }
 
 /**
@@ -1137,11 +1139,9 @@ static void handle_hotplug_event(acpi_ha
 	if (context) {
 		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;
 		}
 		acpiphp_put_context(context);
@@ -1157,7 +1157,7 @@ static void handle_hotplug_event(acpi_ha
 	 * don't deadlock on hotplug actions.
 	 */
 	if (work_func)
-		alloc_acpi_hp_work(handle, type, data, work_func);
+		alloc_acpi_hp_work(handle, type, context, work_func);
 }
 
 /*


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

* [PATCH 8/30] ACPI / hotplug / PCI: Merge hotplug event handling functions
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
                       ` (6 preceding siblings ...)
  2013-07-17 23:19     ` [PATCH 7/30] ACPI / hotplug / PCI: Pass hotplug context objects to event handlers Rafael J. Wysocki
@ 2013-07-17 23:20     ` Rafael J. Wysocki
  2013-07-17 23:21     ` [PATCH 9/30] ACPI / hotplug / PCI: Drop func field from struct acpiphp_bridge Rafael J. Wysocki
                       ` (22 subsequent siblings)
  30 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:20 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

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

There are separate handling event functions for hotplug bridges and
for hotplug functions, but they may be combined into one common
hotplug event handling function which simplifies the code slightly.

That also allows a theoretical bug to be dealt with which in
principle may occur if a hotplug bridge is on a dock station, because
in that case the bridge-specific notification should be used instead
of the function-specific one, but the dock station always uses the
latter.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp_glue.c |  152 +++++++++++++++----------------------
 1 file changed, 65 insertions(+), 87 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
@@ -62,7 +62,7 @@ static DEFINE_MUTEX(acpiphp_context_lock
 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 hotplug_event(acpi_handle handle, u32 type, void *data);
 static void free_bridge(struct kref *kref);
 
 /* callback routine to check for the existence of a pci dock device */
@@ -201,8 +201,8 @@ static void free_bridge(struct kref *kre
  */
 static void post_dock_fixups(acpi_handle not_used, u32 event, void *data)
 {
-	struct acpiphp_func *func = data;
-	struct pci_bus *bus = func->slot->bridge->pci_bus;
+	struct acpiphp_context *context = data;
+	struct pci_bus *bus = context->func->slot->bridge->pci_bus;
 	u32 buses;
 
 	if (!bus->self)
@@ -227,7 +227,7 @@ static void post_dock_fixups(acpi_handle
 
 static const struct acpi_dock_ops acpiphp_dock_ops = {
 	.fixup = post_dock_fixups,
-	.handler = hotplug_event_func,
+	.handler = hotplug_event,
 };
 
 /* Check whether the PCI device is managed by native PCIe hotplug driver */
@@ -261,16 +261,16 @@ static bool device_is_managed_by_native_
 
 static void acpiphp_dock_init(void *data)
 {
-	struct acpiphp_func *func = data;
+	struct acpiphp_context *context = data;
 
-	get_bridge(func->slot->bridge);
+	get_bridge(context->func->slot->bridge);
 }
 
 static void acpiphp_dock_release(void *data)
 {
-	struct acpiphp_func *func = data;
+	struct acpiphp_context *context = data;
 
-	put_bridge(func->slot->bridge);
+	put_bridge(context->func->slot->bridge);
 }
 
 /* callback routine to register each ACPI PCI slot object */
@@ -406,7 +406,7 @@ static acpi_status register_slot(acpi_ha
 		 */
 		newfunc->flags &= ~FUNC_HAS_EJ0;
 		if (register_hotplug_dock_device(handle,
-			&acpiphp_dock_ops, newfunc,
+			&acpiphp_dock_ops, context,
 			acpiphp_dock_init, acpiphp_dock_release))
 			dbg("failed to register dock device\n");
 	}
@@ -987,24 +987,26 @@ void acpiphp_check_host_bridge(acpi_hand
 		ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL);
 }
 
-static void _handle_hotplug_event_bridge(struct work_struct *work)
+static void hotplug_event(acpi_handle handle, u32 type, void *data)
 {
-	struct acpiphp_context *context;
+	struct acpiphp_context *context = data;
 	struct acpiphp_bridge *bridge;
+	struct acpiphp_func *func;
 	char objname[64];
 	struct acpi_buffer buffer = { .length = sizeof(objname),
 				      .pointer = objname };
-	struct acpi_hp_work *hp_work;
-	acpi_handle handle;
-	u32 type;
 
-	hp_work = container_of(work, struct acpi_hp_work, work);
-	handle = hp_work->handle;
-	type = hp_work->type;
-	context = hp_work->context;
+	mutex_lock(&acpiphp_context_lock);
 	bridge = context->bridge;
+	if (bridge)
+		get_bridge(bridge);
 
-	acpi_scan_lock_acquire();
+	/*
+	 * If context->func is not NULL, we are holding a reference to its
+	 * parent bridge, so it won't go away until we drop that reference.
+	 */
+	func = context->func;
+	mutex_unlock(&acpiphp_context_lock);
 
 	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
 
@@ -1013,15 +1015,24 @@ static void _handle_hotplug_event_bridge
 		/* bus re-enumerate */
 		dbg("%s: Bus check notify on %s\n", __func__, objname);
 		dbg("%s: re-enumerating slots under %s\n", __func__, objname);
-		acpiphp_check_bridge(bridge);
-		acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
-			ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL);
+		if (bridge) {
+			acpiphp_check_bridge(bridge);
+			acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
+					    ACPI_UINT32_MAX, check_sub_bridges,
+					    NULL, NULL, NULL);
+		} else {
+			acpiphp_enable_slot(func->slot);
+		}
 		break;
 
 	case ACPI_NOTIFY_DEVICE_CHECK:
 		/* device check */
 		dbg("%s: Device check notify on %s\n", __func__, objname);
-		acpiphp_check_bridge(bridge);
+		if (bridge)
+			acpiphp_check_bridge(bridge);
+		else
+			acpiphp_check_bridge(func->slot->bridge);
+
 		break;
 
 	case ACPI_NOTIFY_DEVICE_WAKE:
@@ -1032,12 +1043,15 @@ static void _handle_hotplug_event_bridge
 	case ACPI_NOTIFY_EJECT_REQUEST:
 		/* request device eject */
 		dbg("%s: Device eject notify on %s\n", __func__, objname);
-		if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) {
-			struct acpiphp_slot *slot;
-			slot = bridge->func->slot;
-			if (!acpiphp_disable_slot(slot))
-				acpiphp_eject_slot(slot);
-		}
+		if (!func)
+			break;
+
+		if (bridge && !(bridge->flags & BRIDGE_HAS_EJ0))
+			break;
+
+		if (!(acpiphp_disable_slot(func->slot)))
+			acpiphp_eject_slot(func->slot);
+
 		break;
 
 	case ACPI_NOTIFY_FREQUENCY_MISMATCH:
@@ -1056,56 +1070,16 @@ static void _handle_hotplug_event_bridge
 		break;
 
 	default:
-		warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
+		warn("notify_handler: unknown event type 0x%x for %s\n", type,
+		     objname);
 		break;
 	}
 
-	acpi_scan_lock_release();
-	kfree(hp_work); /* allocated in handle_hotplug_event_bridge */
-	put_bridge(bridge);
-}
-
-static void hotplug_event_func(acpi_handle handle, u32 type, void *context)
-{
-	struct acpiphp_func *func = context;
-	char objname[64];
-	struct acpi_buffer buffer = { .length = sizeof(objname),
-				      .pointer = objname };
-
-	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-
-	switch (type) {
-	case ACPI_NOTIFY_BUS_CHECK:
-		/* bus re-enumerate */
-		dbg("%s: Bus check notify on %s\n", __func__, objname);
-		acpiphp_enable_slot(func->slot);
-		break;
-
-	case ACPI_NOTIFY_DEVICE_CHECK:
-		/* device check : re-enumerate from parent bus */
-		dbg("%s: Device check notify on %s\n", __func__, objname);
-		acpiphp_check_bridge(func->slot->bridge);
-		break;
-
-	case ACPI_NOTIFY_DEVICE_WAKE:
-		/* wake event */
-		dbg("%s: Device wake notify on %s\n", __func__, objname);
-		break;
-
-	case ACPI_NOTIFY_EJECT_REQUEST:
-		/* request device eject */
-		dbg("%s: Device eject notify on %s\n", __func__, objname);
-		if (!(acpiphp_disable_slot(func->slot)))
-			acpiphp_eject_slot(func->slot);
-		break;
-
-	default:
-		warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
-		break;
-	}
+	if (bridge)
+		put_bridge(bridge);
 }
 
-static void _handle_hotplug_event_func(struct work_struct *work)
+static void hotplug_event_work(struct work_struct *work)
 {
 	struct acpiphp_context *context;
 	struct acpi_hp_work *hp_work;
@@ -1114,11 +1088,18 @@ static void _handle_hotplug_event_func(s
 	context = hp_work->context;
 	acpi_scan_lock_acquire();
 
-	hotplug_event_func(hp_work->handle, hp_work->type, context->func);
+	hotplug_event(hp_work->handle, hp_work->type, context);
 
 	acpi_scan_lock_release();
-	kfree(hp_work); /* allocated in handle_hotplug_event_func */
-	put_bridge(context->func->slot->bridge);
+	kfree(hp_work); /* allocated in handle_hotplug_event() */
+
+	mutex_lock(&acpiphp_context_lock);
+	if (context->func)
+		put_bridge(context->func->slot->bridge);
+	else
+		acpiphp_put_context(context);
+
+	mutex_unlock(&acpiphp_context_lock);
 }
 
 /**
@@ -1132,22 +1113,19 @@ static void _handle_hotplug_event_func(s
 static void handle_hotplug_event(acpi_handle handle, u32 type, void *data)
 {
 	struct acpiphp_context *context;
-	void (*work_func)(struct work_struct *work) = NULL;
 
 	mutex_lock(&acpiphp_context_lock);
 	context = acpiphp_get_context(handle);
 	if (context) {
-		if (context->bridge) {
-			get_bridge(context->bridge);
-			work_func = _handle_hotplug_event_bridge;
-		} else if (context->func) {
+		if (context->func) {
 			get_bridge(context->func->slot->bridge);
-			work_func = _handle_hotplug_event_func;
+			acpiphp_put_context(context);
+		} else if (!context->bridge) {
+			acpiphp_put_context(context);
+			context = NULL;
 		}
-		acpiphp_put_context(context);
 	}
 	mutex_unlock(&acpiphp_context_lock);
-
 	/*
 	 * Currently the code adds all hotplug events to the kacpid_wq
 	 * queue when it should add hotplug events to the kacpi_hotplug_wq.
@@ -1156,8 +1134,8 @@ static void handle_hotplug_event(acpi_ha
 	 * For now just re-add this work to the kacpi_hotplug_wq so we
 	 * don't deadlock on hotplug actions.
 	 */
-	if (work_func)
-		alloc_acpi_hp_work(handle, type, context, work_func);
+	if (context)
+		alloc_acpi_hp_work(handle, type, context, hotplug_event_work);
 }
 
 /*

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

* [PATCH 9/30] ACPI / hotplug / PCI: Drop func field from struct acpiphp_bridge
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
                       ` (7 preceding siblings ...)
  2013-07-17 23:20     ` [PATCH 8/30] ACPI / hotplug / PCI: Merge hotplug event handling functions Rafael J. Wysocki
@ 2013-07-17 23:21     ` Rafael J. Wysocki
  2013-07-17 23:22     ` [PATCH 10/30] ACPI / hotplug / PCI: Refactor slot allocation code in register_slot() Rafael J. Wysocki
                       ` (21 subsequent siblings)
  30 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:21 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

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

Since the func pointer in struct acpiphp_context can always be used
instead of the func pointer in struct acpiphp_bridge, drop the
latter.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp.h      |    2 --
 drivers/pci/hotplug/acpiphp_glue.c |    3 +--
 2 files changed, 1 insertion(+), 4 deletions(-)

Index: linux-pm/drivers/pci/hotplug/acpiphp.h
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
+++ linux-pm/drivers/pci/hotplug/acpiphp.h
@@ -79,8 +79,6 @@ struct acpiphp_bridge {
 	acpi_handle handle;
 
 	struct acpiphp_context *context;
-	/* Ejectable PCI-to-PCI bridge (PCI bridge and PCI function) */
-	struct acpiphp_func *func;
 
 	int nr_slots;
 
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
@@ -181,7 +181,7 @@ static void free_bridge(struct kref *kre
 	context = bridge->context;
 	/* Release the reference acquired by acpiphp_enumerate_slots(). */
 	if (context->handler_for_func)
-		put_bridge(bridge->func->slot->bridge);
+		put_bridge(context->func->slot->bridge);
 
 	put_device(&bridge->pci_bus->dev);
 	pci_dev_put(bridge->pci_dev);
@@ -1212,7 +1212,6 @@ void acpiphp_enumerate_slots(struct pci_
 	}
 	if (context->handler_for_func) {
 		/* Notify handler already installed. */
-		bridge->func = context->func;
 		get_bridge(context->func->slot->bridge);
 		return;
 	}

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

* [PATCH 10/30] ACPI / hotplug / PCI: Refactor slot allocation code in register_slot()
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
                       ` (8 preceding siblings ...)
  2013-07-17 23:21     ` [PATCH 9/30] ACPI / hotplug / PCI: Drop func field from struct acpiphp_bridge Rafael J. Wysocki
@ 2013-07-17 23:22     ` Rafael J. Wysocki
  2013-07-17 23:22     ` [PATCH 11/30] ACPI / hotplug / PCI: Register all devices under the given bridge Rafael J. Wysocki
                       ` (20 subsequent siblings)
  30 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:22 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

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

To make the code in register_slot() a bit easier to follow, change
the way the slot allocation part is organized.  Drop one local
variable that's not used any more after that modification.

This code change should not lead to any changes in behavior.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp_glue.c |   74 ++++++++++++++++++-------------------
 1 file changed, 36 insertions(+), 38 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
@@ -283,7 +283,7 @@ static acpi_status register_slot(acpi_ha
 	struct acpiphp_func *newfunc;
 	acpi_status status = AE_OK;
 	unsigned long long adr, sun;
-	int device, function, retval, found = 0;
+	int device, function, retval;
 	struct pci_bus *pbus = bridge->pci_bus;
 	struct pci_dev *pdev;
 	u32 val;
@@ -352,44 +352,49 @@ static acpi_status register_slot(acpi_ha
 		if (slot->device == device) {
 			if (slot->sun != sun)
 				warn("sibling found, but _SUN doesn't match!\n");
-			found = 1;
-			break;
-		}
 
-	if (!found) {
-		slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL);
-		if (!slot) {
-			status = AE_NO_MEMORY;
-			goto err_out;
+			goto slot_found;
 		}
 
-		slot->bridge = bridge;
-		slot->device = device;
-		slot->sun = sun;
-		INIT_LIST_HEAD(&slot->funcs);
-		mutex_init(&slot->crit_sect);
+	slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL);
+	if (!slot) {
+		status = AE_NO_MEMORY;
+		goto err;
+	}
 
-		mutex_lock(&bridge_mutex);
-		list_add_tail(&slot->node, &bridge->slots);
-		mutex_unlock(&bridge_mutex);
-		bridge->nr_slots++;
+	slot->bridge = bridge;
+	slot->device = device;
+	slot->sun = sun;
+	INIT_LIST_HEAD(&slot->funcs);
+	mutex_init(&slot->crit_sect);
 
-		dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n",
-		    slot->sun, pci_domain_nr(pbus), pbus->number, device);
-		retval = acpiphp_register_hotplug_slot(slot);
-		if (retval) {
-			if (retval == -EBUSY)
-				warn("Slot %llu already registered by another "
-					"hotplug driver\n", slot->sun);
-			else
-				warn("acpiphp_register_hotplug_slot failed "
-					"(err code = 0x%x)\n", retval);
+	mutex_lock(&bridge_mutex);
+	list_add_tail(&slot->node, &bridge->slots);
+	mutex_unlock(&bridge_mutex);
+	bridge->nr_slots++;
 
-			status = AE_OK;
-			goto err;
-		}
+	dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n",
+	    slot->sun, pci_domain_nr(pbus), pbus->number, device);
+
+	retval = acpiphp_register_hotplug_slot(slot);
+	if (retval) {
+		if (retval == -EBUSY)
+			warn("Slot %llu already registered by another "
+				"hotplug driver\n", slot->sun);
+		else
+			warn("acpiphp_register_hotplug_slot failed "
+				"(err code = 0x%x)\n", retval);
+
+		bridge->nr_slots--;
+		mutex_lock(&bridge_mutex);
+		list_del(&slot->node);
+		mutex_unlock(&bridge_mutex);
+		kfree(slot);
+		status = AE_OK;
+		goto err;
 	}
 
+ slot_found:
 	newfunc->slot = slot;
 	mutex_lock(&bridge_mutex);
 	list_add_tail(&newfunc->sibling, &slot->funcs);
@@ -425,13 +430,6 @@ static acpi_status register_slot(acpi_ha
 	return AE_OK;
 
  err:
-	bridge->nr_slots--;
-	mutex_lock(&bridge_mutex);
-	list_del(&slot->node);
-	mutex_unlock(&bridge_mutex);
-	kfree(slot);
-
- err_out:
 	mutex_lock(&acpiphp_context_lock);
 	context->func = NULL;
 	acpiphp_put_context(context);

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

* [PATCH 11/30] ACPI / hotplug / PCI: Register all devices under the given bridge
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
                       ` (9 preceding siblings ...)
  2013-07-17 23:22     ` [PATCH 10/30] ACPI / hotplug / PCI: Refactor slot allocation code in register_slot() Rafael J. Wysocki
@ 2013-07-17 23:22     ` Rafael J. Wysocki
  2013-07-17 23:23     ` [PATCH 12/30] ACPI / hotplug / PCI: Drop sun field from struct acpiphp_slot Rafael J. Wysocki
                       ` (19 subsequent siblings)
  30 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:22 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

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

Rework register_slot() to create a struct acpiphp_func object for
every function it is called for and to create acpiphp slots for all
of them.  Although acpiphp_register_hotplug_slot() is only called for
the slots whose functions are identified as "ejectable", so that user
space can manipulate them, the ACPIPHP notify handler,
handle_hotplug_event(), is now installed for all of the registered
functions (that aren't dock stations) and hotplug events may be
handled for all of them.

As a result, essentially, all PCI bridges represented by objects in
the ACPI namespace are now going to be "hotplug" bridges and that may
affect resources allocation in general, although it shouldn't lead to
problems.

This allows the code to be simplified substantially and addresses
the problem where bus check or device check notifications for some
PCI bridges or devices are not handled, because those devices are
not recognized as "ejectable" or there appear to be no "ejectable"
devices under those bridges.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp.h      |    1 
 drivers/pci/hotplug/acpiphp_glue.c |  230 ++++++++++++-------------------------
 2 files changed, 75 insertions(+), 156 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
@@ -65,20 +65,6 @@ static void acpiphp_set_hpp_values(struc
 static void hotplug_event(acpi_handle handle, u32 type, void *data);
 static void free_bridge(struct kref *kref);
 
-/* callback routine to check for the existence of a pci dock device */
-static acpi_status
-is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
-	int *count = (int *)context;
-
-	if (is_dock_device(handle)) {
-		(*count)++;
-		return AE_CTRL_TERMINATE;
-	} else {
-		return AE_OK;
-	}
-}
-
 static void acpiphp_context_handler(acpi_handle handle, void *context)
 {
 	/* Intentionally empty. */
@@ -179,14 +165,16 @@ static void free_bridge(struct kref *kre
 	}
 
 	context = bridge->context;
-	/* Release the reference acquired by acpiphp_enumerate_slots(). */
-	if (context->handler_for_func)
+	/* Root bridges will not have hotplug context. */
+	if (context) {
+		/* Release the reference taken by acpiphp_enumerate_slots(). */
 		put_bridge(context->func->slot->bridge);
+		context->bridge = NULL;
+		acpiphp_put_context(context);
+	}
 
 	put_device(&bridge->pci_bus->dev);
 	pci_dev_put(bridge->pci_dev);
-	context->bridge = NULL;
-	acpiphp_put_context(context);
 	kfree(bridge);
 
 	mutex_unlock(&acpiphp_context_lock);
@@ -282,28 +270,24 @@ static acpi_status register_slot(acpi_ha
 	struct acpiphp_slot *slot;
 	struct acpiphp_func *newfunc;
 	acpi_status status = AE_OK;
-	unsigned long long adr, sun;
-	int device, function, retval;
+	unsigned long long adr;
+	int device, function;
 	struct pci_bus *pbus = bridge->pci_bus;
-	struct pci_dev *pdev;
+	struct pci_dev *pdev = bridge->pci_dev;
 	u32 val;
 
-	if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle))
+	if (pdev && device_is_managed_by_native_pciehp(pdev))
 		return AE_OK;
 
 	status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
 	if (ACPI_FAILURE(status)) {
-		warn("can't evaluate _ADR (%#x)\n", status);
+		acpi_handle_warn(handle, "can't evaluate _ADR (%#x)\n", status);
 		return AE_OK;
 	}
 
 	device = (adr >> 16) & 0xffff;
 	function = adr & 0xffff;
 
-	pdev = bridge->pci_dev;
-	if (pdev && device_is_managed_by_native_pciehp(pdev))
-		return AE_OK;
-
 	newfunc = kzalloc(sizeof(struct acpiphp_func), GFP_KERNEL);
 	if (!newfunc)
 		return AE_NO_MEMORY;
@@ -338,23 +322,10 @@ static acpi_status register_slot(acpi_ha
 	if (acpi_has_method(handle, "_DCK"))
 		newfunc->flags |= FUNC_HAS_DCK;
 
-	status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun);
-	if (ACPI_FAILURE(status)) {
-		/*
-		 * use the count of the number of slots we've found
-		 * for the number of the slot
-		 */
-		sun = bridge->nr_slots+1;
-	}
-
 	/* search for objects that share the same slot */
 	list_for_each_entry(slot, &bridge->slots, node)
-		if (slot->device == device) {
-			if (slot->sun != sun)
-				warn("sibling found, but _SUN doesn't match!\n");
-
+		if (slot->device == device)
 			goto slot_found;
-		}
 
 	slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL);
 	if (!slot) {
@@ -364,34 +335,38 @@ static acpi_status register_slot(acpi_ha
 
 	slot->bridge = bridge;
 	slot->device = device;
-	slot->sun = sun;
 	INIT_LIST_HEAD(&slot->funcs);
 	mutex_init(&slot->crit_sect);
 
 	mutex_lock(&bridge_mutex);
 	list_add_tail(&slot->node, &bridge->slots);
 	mutex_unlock(&bridge_mutex);
-	bridge->nr_slots++;
 
-	dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n",
-	    slot->sun, pci_domain_nr(pbus), pbus->number, device);
+	/* Register slots for ejectable funtions only. */
+	if (acpi_pci_check_ejectable(pbus, handle)  || is_dock_device(handle)) {
+		unsigned long long sun;
+		int retval;
 
-	retval = acpiphp_register_hotplug_slot(slot);
-	if (retval) {
-		if (retval == -EBUSY)
-			warn("Slot %llu already registered by another "
-				"hotplug driver\n", slot->sun);
-		else
-			warn("acpiphp_register_hotplug_slot failed "
-				"(err code = 0x%x)\n", retval);
+		bridge->nr_slots++;
+		status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun);
+		if (ACPI_FAILURE(status))
+			sun = bridge->nr_slots;
 
-		bridge->nr_slots--;
-		mutex_lock(&bridge_mutex);
-		list_del(&slot->node);
-		mutex_unlock(&bridge_mutex);
-		kfree(slot);
-		status = AE_OK;
-		goto err;
+		slot->sun = sun;
+		dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n",
+		    slot->sun, pci_domain_nr(pbus), pbus->number, device);
+
+		retval = acpiphp_register_hotplug_slot(slot);
+		if (retval) {
+			bridge->nr_slots--;
+			if (retval == -EBUSY)
+				warn("Slot %llu already registered by another "
+					"hotplug driver\n", slot->sun);
+			else
+				warn("acpiphp_register_hotplug_slot failed "
+					"(err code = 0x%x)\n", retval);
+		}
+		/* Even if the slot registration fails, we can still use it. */
 	}
 
  slot_found:
@@ -421,10 +396,9 @@ static acpi_status register_slot(acpi_ha
 		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");
+		if (ACPI_FAILURE(status))
+			acpi_handle_err(handle,
+					"failed to install notify handler\n");
 	}
 
 	return AE_OK;
@@ -438,18 +412,6 @@ static acpi_status register_slot(acpi_ha
 	return status;
 }
 
-
-/* see if it's worth looking at this bridge */
-static int detect_ejectable_slots(acpi_handle handle)
-{
-	int found = acpi_pci_detect_ejectable(handle);
-	if (!found) {
-		acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
-				    is_pci_dock_device, NULL, (void *)&found, NULL);
-	}
-	return found;
-}
-
 static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle)
 {
 	struct acpiphp_context *context;
@@ -473,14 +435,6 @@ static void cleanup_bridge(struct acpiph
 	struct acpiphp_slot *slot;
 	struct acpiphp_func *func;
 	acpi_status status;
-	acpi_handle handle = bridge->handle;
-
-	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");
-	}
 
 	list_for_each_entry(slot, &bridge->slots, node) {
 		list_for_each_entry(func, &slot->funcs, sibling) {
@@ -488,7 +442,6 @@ static void cleanup_bridge(struct acpiph
 				unregister_hotplug_dock_device(func->handle);
 			}
 			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);
@@ -678,9 +631,7 @@ static void check_hotplug_bridge(struct
 
 	list_for_each_entry(func, &slot->funcs, sibling) {
 		if (PCI_FUNC(dev->devfn) == func->function) {
-			/* check if this bridge has ejectable slots */
-			if ((detect_ejectable_slots(func->handle) > 0))
-				dev->is_hotplug_bridge = 1;
+			dev->is_hotplug_bridge = 1;
 			break;
 		}
 	}
@@ -988,8 +939,8 @@ void acpiphp_check_host_bridge(acpi_hand
 static void hotplug_event(acpi_handle handle, u32 type, void *data)
 {
 	struct acpiphp_context *context = data;
+	struct acpiphp_func *func = context->func;
 	struct acpiphp_bridge *bridge;
-	struct acpiphp_func *func;
 	char objname[64];
 	struct acpi_buffer buffer = { .length = sizeof(objname),
 				      .pointer = objname };
@@ -999,11 +950,6 @@ static void hotplug_event(acpi_handle ha
 	if (bridge)
 		get_bridge(bridge);
 
-	/*
-	 * If context->func is not NULL, we are holding a reference to its
-	 * parent bridge, so it won't go away until we drop that reference.
-	 */
-	func = context->func;
 	mutex_unlock(&acpiphp_context_lock);
 
 	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
@@ -1041,9 +987,6 @@ static void hotplug_event(acpi_handle ha
 	case ACPI_NOTIFY_EJECT_REQUEST:
 		/* request device eject */
 		dbg("%s: Device eject notify on %s\n", __func__, objname);
-		if (!func)
-			break;
-
 		if (bridge && !(bridge->flags & BRIDGE_HAS_EJ0))
 			break;
 
@@ -1090,14 +1033,7 @@ static void hotplug_event_work(struct wo
 
 	acpi_scan_lock_release();
 	kfree(hp_work); /* allocated in handle_hotplug_event() */
-
-	mutex_lock(&acpiphp_context_lock);
-	if (context->func)
-		put_bridge(context->func->slot->bridge);
-	else
-		acpiphp_put_context(context);
-
-	mutex_unlock(&acpiphp_context_lock);
+	put_bridge(context->func->slot->bridge);
 }
 
 /**
@@ -1115,13 +1051,8 @@ static void handle_hotplug_event(acpi_ha
 	mutex_lock(&acpiphp_context_lock);
 	context = acpiphp_get_context(handle);
 	if (context) {
-		if (context->func) {
-			get_bridge(context->func->slot->bridge);
-			acpiphp_put_context(context);
-		} else if (!context->bridge) {
-			acpiphp_put_context(context);
-			context = NULL;
-		}
+		get_bridge(context->func->slot->bridge);
+		acpiphp_put_context(context);
 	}
 	mutex_unlock(&acpiphp_context_lock);
 	/*
@@ -1142,7 +1073,6 @@ static void handle_hotplug_event(acpi_ha
  */
 void acpiphp_enumerate_slots(struct pci_bus *bus)
 {
-	struct acpiphp_context *context;
 	struct acpiphp_bridge *bridge;
 	acpi_handle handle;
 	acpi_status status;
@@ -1151,7 +1081,7 @@ void acpiphp_enumerate_slots(struct pci_
 		return;
 
 	handle = ACPI_HANDLE(bus->bridge);
-	if (!handle || detect_ejectable_slots(handle) <= 0)
+	if (!handle)
 		return;
 
 	bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
@@ -1166,21 +1096,6 @@ void acpiphp_enumerate_slots(struct pci_
 	bridge->pci_dev = pci_dev_get(bus->self);
 	bridge->pci_bus = bus;
 
-	mutex_lock(&acpiphp_context_lock);
-	context = acpiphp_get_context(handle);
-	if (!context) {
-		context = acpiphp_init_context(handle);
-		if (!context) {
-			mutex_unlock(&acpiphp_context_lock);
-			acpi_handle_err(handle, "No hotplug context\n");
-			kfree(bridge);
-			return;
-		}
-	}
-	bridge->context = context;
-	context->bridge = bridge;
-	mutex_unlock(&acpiphp_context_lock);
-
 	/*
 	 * Grab a ref to the subordinate PCI bus in case the bus is
 	 * removed via PCI core logical hotplug. The ref pins the bus
@@ -1188,6 +1103,35 @@ void acpiphp_enumerate_slots(struct pci_
 	 */
 	get_device(&bus->dev);
 
+	if (!pci_is_root_bus(bridge->pci_bus)) {
+		struct acpiphp_context *context;
+
+		/*
+		 * This bridge should have been registered as a hotplug function
+		 * under its parent, so the context has to be there.  If not, we
+		 * are in deep goo.
+		 */
+		mutex_lock(&acpiphp_context_lock);
+		context = acpiphp_get_context(handle);
+		if (WARN_ON(!context || !context->func)) {
+			mutex_unlock(&acpiphp_context_lock);
+			put_device(&bus->dev);
+			kfree(bridge);
+			return;
+		}
+		bridge->context = context;
+		context->bridge = bridge;
+		/* Get a reference to the parent bridge. */
+		get_bridge(context->func->slot->bridge);
+		mutex_unlock(&acpiphp_context_lock);
+	}
+
+	status = acpi_get_handle(bridge->handle, "_EJ0", &handle);
+	if (ACPI_SUCCESS(status)) {
+		dbg("found ejectable p2p bridge\n");
+		bridge->flags |= BRIDGE_HAS_EJ0;
+	}
+
 	/* must be added to the list prior to calling register_slot */
 	mutex_lock(&bridge_mutex);
 	list_add(&bridge->list, &bridge_list);
@@ -1198,33 +1142,9 @@ void acpiphp_enumerate_slots(struct pci_
 				     register_slot, NULL, bridge, NULL);
 	if (ACPI_FAILURE(status)) {
 		acpi_handle_err(bridge->handle, "failed to register slots\n");
-		goto err;
-	}
-
-	if (pci_is_root_bus(bridge->pci_bus))
-		return;
-
-	if (acpi_has_method(bridge->handle, "_EJ0")) {
-		dbg("found ejectable p2p bridge\n");
-		bridge->flags |= BRIDGE_HAS_EJ0;
-	}
-	if (context->handler_for_func) {
-		/* Notify handler already installed. */
-		get_bridge(context->func->slot->bridge);
-		return;
+		cleanup_bridge(bridge);
+		put_bridge(bridge);
 	}
-
-	/* install notify handler for P2P bridges */
-	status = acpi_install_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY,
-					     handle_hotplug_event, NULL);
-	if (ACPI_SUCCESS(status))
-		return;
-
-	acpi_handle_err(bridge->handle, "failed to register notify handler\n");
-
- err:
-	cleanup_bridge(bridge);
-	put_bridge(bridge);
 }
 
 /* Destroy hotplug slots associated with the PCI bus */
Index: linux-pm/drivers/pci/hotplug/acpiphp.h
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
+++ linux-pm/drivers/pci/hotplug/acpiphp.h
@@ -134,7 +134,6 @@ struct acpiphp_context {
 	struct acpiphp_func *func;
 	struct acpiphp_bridge *bridge;
 	unsigned int refcount;
-	bool handler_for_func;
 };
 
 /*

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

* [PATCH 12/30] ACPI / hotplug / PCI: Drop sun field from struct acpiphp_slot
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
                       ` (10 preceding siblings ...)
  2013-07-17 23:22     ` [PATCH 11/30] ACPI / hotplug / PCI: Register all devices under the given bridge Rafael J. Wysocki
@ 2013-07-17 23:23     ` Rafael J. Wysocki
  2013-07-17 23:24     ` [PATCH 13/30] ACPI / hotplug / PCI: Drop flags field from struct acpiphp_bridge Rafael J. Wysocki
                       ` (18 subsequent siblings)
  30 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:23 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

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

If the slot unique number is passed as an additional argument to
acpiphp_register_hotplug_slot(), the 'sun' field in struct
acpiphp_slot is only used by ibm_[s|g]et_attention_status(),
but then it's more efficient to store it in struct slot.

Thus move the 'sun' field from struct acpiphp_slot to struct slot
changing its data type to unsigned int in the process, and redefine
acpiphp_register_hotplug_slot() to take the slot number as separate
argument.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp.h      |    5 ++---
 drivers/pci/hotplug/acpiphp_core.c |    6 ++++--
 drivers/pci/hotplug/acpiphp_glue.c |    7 +++----
 drivers/pci/hotplug/acpiphp_ibm.c  |    2 +-
 4 files changed, 10 insertions(+), 10 deletions(-)

Index: linux-pm/drivers/pci/hotplug/acpiphp.h
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
+++ linux-pm/drivers/pci/hotplug/acpiphp.h
@@ -60,6 +60,7 @@ struct slot {
 	struct hotplug_slot	*hotplug_slot;
 	struct acpiphp_slot	*acpi_slot;
 	struct hotplug_slot_info info;
+	unsigned int sun;	/* ACPI _SUN (Slot User Number) value */
 };
 
 static inline const char *slot_name(struct slot *slot)
@@ -106,8 +107,6 @@ struct acpiphp_slot {
 	struct mutex crit_sect;
 
 	u8		device;		/* pci device# */
-
-	unsigned long long sun;		/* ACPI _SUN (slot unique number) */
 	u32		flags;		/* see below */
 };
 
@@ -179,7 +178,7 @@ struct acpiphp_attention_info
 /* acpiphp_core.c */
 int acpiphp_register_attention(struct acpiphp_attention_info*info);
 int acpiphp_unregister_attention(struct acpiphp_attention_info *info);
-int acpiphp_register_hotplug_slot(struct acpiphp_slot *slot);
+int acpiphp_register_hotplug_slot(struct acpiphp_slot *slot, unsigned int sun);
 void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot);
 
 /* acpiphp_glue.c */
Index: linux-pm/drivers/pci/hotplug/acpiphp_core.c
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp_core.c
+++ linux-pm/drivers/pci/hotplug/acpiphp_core.c
@@ -290,7 +290,8 @@ static void release_slot(struct hotplug_
 }
 
 /* callback routine to initialize 'struct slot' for each slot */
-int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
+int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot,
+				  unsigned int sun)
 {
 	struct slot *slot;
 	int retval = -ENOMEM;
@@ -317,7 +318,8 @@ int acpiphp_register_hotplug_slot(struct
 	slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot);
 
 	acpiphp_slot->slot = slot;
-	snprintf(name, SLOT_NAME_SIZE, "%llu", slot->acpi_slot->sun);
+	slot->sun = sun;
+	snprintf(name, SLOT_NAME_SIZE, "%u", sun);
 
 	retval = pci_hp_register(slot->hotplug_slot,
 					acpiphp_slot->bridge->pci_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
@@ -352,16 +352,15 @@ static acpi_status register_slot(acpi_ha
 		if (ACPI_FAILURE(status))
 			sun = bridge->nr_slots;
 
-		slot->sun = sun;
 		dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n",
-		    slot->sun, pci_domain_nr(pbus), pbus->number, device);
+		    sun, pci_domain_nr(pbus), pbus->number, device);
 
-		retval = acpiphp_register_hotplug_slot(slot);
+		retval = acpiphp_register_hotplug_slot(slot, sun);
 		if (retval) {
 			bridge->nr_slots--;
 			if (retval == -EBUSY)
 				warn("Slot %llu already registered by another "
-					"hotplug driver\n", slot->sun);
+					"hotplug driver\n", sun);
 			else
 				warn("acpiphp_register_hotplug_slot failed "
 					"(err code = 0x%x)\n", retval);
Index: linux-pm/drivers/pci/hotplug/acpiphp_ibm.c
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp_ibm.c
+++ linux-pm/drivers/pci/hotplug/acpiphp_ibm.c
@@ -66,7 +66,7 @@ do {							\
 #define IBM_HARDWARE_ID1 "IBM37D0"
 #define IBM_HARDWARE_ID2 "IBM37D4"
 
-#define hpslot_to_sun(A) (((struct slot *)((A)->private))->acpi_slot->sun)
+#define hpslot_to_sun(A) (((struct slot *)((A)->private))->sun)
 
 /* union apci_descriptor - allows access to the
  * various device descriptors that are embedded in the

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

* [PATCH 13/30] ACPI / hotplug / PCI: Drop flags field from struct acpiphp_bridge
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
                       ` (11 preceding siblings ...)
  2013-07-17 23:23     ` [PATCH 12/30] ACPI / hotplug / PCI: Drop sun field from struct acpiphp_slot Rafael J. Wysocki
@ 2013-07-17 23:24     ` Rafael J. Wysocki
  2013-07-17 23:24     ` [PATCH 14/30] ACPI / hotplug / PCI: Embed function struct into struct acpiphp_context Rafael J. Wysocki
                       ` (17 subsequent siblings)
  30 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:24 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

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

The only bridge flag used by the ACPI-based PCI hotplug (ACPIPHP)
code is BRIDGE_HAS_EJ0, but it is only used by the event handling
function hotplug_event() and if that flag is set, the corresponding
function flag FUNC_HAS_EJ0 is set as well, so that bridge flag is
redundant.

For this reason, drop BRIDGE_HAS_EJ0 and all code referring to it
and since it is the only bridge flag defined, drop the flags field
from struct acpiphp_bridge entirely.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp.h      |    5 -----
 drivers/pci/hotplug/acpiphp_glue.c |    9 ---------
 2 files changed, 14 deletions(-)

Index: linux-pm/drivers/pci/hotplug/acpiphp.h
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
+++ linux-pm/drivers/pci/hotplug/acpiphp.h
@@ -83,8 +83,6 @@ struct acpiphp_bridge {
 
 	int nr_slots;
 
-	u32 flags;
-
 	/* This bus (host bridge) or Secondary bus (PCI-to-PCI bridge) */
 	struct pci_bus *pci_bus;
 
@@ -154,9 +152,6 @@ struct acpiphp_attention_info
 /* ACPI _STA method value (ignore bit 4; battery present) */
 #define ACPI_STA_ALL			(0x0000000f)
 
-/* bridge flags */
-#define BRIDGE_HAS_EJ0		(0x00000001)
-
 /* slot flags */
 
 #define SLOT_POWEREDON		(0x00000001)
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
@@ -986,9 +986,6 @@ static void hotplug_event(acpi_handle ha
 	case ACPI_NOTIFY_EJECT_REQUEST:
 		/* request device eject */
 		dbg("%s: Device eject notify on %s\n", __func__, objname);
-		if (bridge && !(bridge->flags & BRIDGE_HAS_EJ0))
-			break;
-
 		if (!(acpiphp_disable_slot(func->slot)))
 			acpiphp_eject_slot(func->slot);
 
@@ -1125,12 +1122,6 @@ void acpiphp_enumerate_slots(struct pci_
 		mutex_unlock(&acpiphp_context_lock);
 	}
 
-	status = acpi_get_handle(bridge->handle, "_EJ0", &handle);
-	if (ACPI_SUCCESS(status)) {
-		dbg("found ejectable p2p bridge\n");
-		bridge->flags |= BRIDGE_HAS_EJ0;
-	}
-
 	/* must be added to the list prior to calling register_slot */
 	mutex_lock(&bridge_mutex);
 	list_add(&bridge->list, &bridge_list);

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

* [PATCH 14/30] ACPI / hotplug / PCI: Embed function struct into struct acpiphp_context
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
                       ` (12 preceding siblings ...)
  2013-07-17 23:24     ` [PATCH 13/30] ACPI / hotplug / PCI: Drop flags field from struct acpiphp_bridge Rafael J. Wysocki
@ 2013-07-17 23:24     ` Rafael J. Wysocki
  2013-07-17 23:25     ` [PATCH 15/30] ACPI / hotplug / PCI: Drop handle field from struct acpiphp_func Rafael J. Wysocki
                       ` (16 subsequent siblings)
  30 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:24 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

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

Since there has to be a struct acpiphp_func object for every struct
acpiphp_context created by register_slot(), the struct acpiphp_func
one can be embedded into the struct acpiphp_context one, which allows
some code simplifications to be made.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp.h      |    8 +++++-
 drivers/pci/hotplug/acpiphp_glue.c |   44 +++++++++++++------------------------
 2 files changed, 22 insertions(+), 30 deletions(-)

Index: linux-pm/drivers/pci/hotplug/acpiphp.h
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
+++ linux-pm/drivers/pci/hotplug/acpiphp.h
@@ -116,7 +116,6 @@ 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;
@@ -128,11 +127,16 @@ struct acpiphp_func {
 
 struct acpiphp_context {
 	acpi_handle handle;
-	struct acpiphp_func *func;
+	struct acpiphp_func func;
 	struct acpiphp_bridge *bridge;
 	unsigned int refcount;
 };
 
+static inline struct acpiphp_context *func_to_context(struct acpiphp_func *func)
+{
+	return container_of(func, struct acpiphp_context, func);
+}
+
 /*
  * 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
@@ -128,7 +128,7 @@ static void acpiphp_put_context(struct a
 	if (--context->refcount)
 		return;
 
-	WARN_ON(context->func || context->bridge);
+	WARN_ON(context->bridge);
 	acpi_detach_data(context->handle, acpiphp_context_handler);
 	kfree(context);
 }
@@ -155,12 +155,9 @@ static void free_bridge(struct kref *kre
 	bridge = container_of(kref, struct acpiphp_bridge, ref);
 
 	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;
-			acpiphp_put_context(context);
-			kfree(func);
-		}
+		list_for_each_entry_safe(func, tmp, &slot->funcs, sibling)
+			acpiphp_put_context(func_to_context(func));
+
 		kfree(slot);
 	}
 
@@ -168,7 +165,7 @@ static void free_bridge(struct kref *kre
 	/* Root bridges will not have hotplug context. */
 	if (context) {
 		/* Release the reference taken by acpiphp_enumerate_slots(). */
-		put_bridge(context->func->slot->bridge);
+		put_bridge(context->func.slot->bridge);
 		context->bridge = NULL;
 		acpiphp_put_context(context);
 	}
@@ -190,7 +187,7 @@ static void free_bridge(struct kref *kre
 static void post_dock_fixups(acpi_handle not_used, u32 event, void *data)
 {
 	struct acpiphp_context *context = data;
-	struct pci_bus *bus = context->func->slot->bridge->pci_bus;
+	struct pci_bus *bus = context->func.slot->bridge->pci_bus;
 	u32 buses;
 
 	if (!bus->self)
@@ -251,14 +248,14 @@ static void acpiphp_dock_init(void *data
 {
 	struct acpiphp_context *context = data;
 
-	get_bridge(context->func->slot->bridge);
+	get_bridge(context->func.slot->bridge);
 }
 
 static void acpiphp_dock_release(void *data)
 {
 	struct acpiphp_context *context = data;
 
-	put_bridge(context->func->slot->bridge);
+	put_bridge(context->func.slot->bridge);
 }
 
 /* callback routine to register each ACPI PCI slot object */
@@ -288,23 +285,16 @@ static acpi_status register_slot(acpi_ha
 	device = (adr >> 16) & 0xffff;
 	function = adr & 0xffff;
 
-	newfunc = kzalloc(sizeof(struct acpiphp_func), GFP_KERNEL);
-	if (!newfunc)
-		return AE_NO_MEMORY;
-
-	newfunc->handle = handle;
-	newfunc->function = function;
-
 	mutex_lock(&acpiphp_context_lock);
 	context = acpiphp_init_context(handle);
 	if (!context) {
 		mutex_unlock(&acpiphp_context_lock);
 		acpi_handle_err(handle, "No hotplug context\n");
-		kfree(newfunc);
 		return AE_NOT_EXIST;
 	}
-	newfunc->context = context;
-	context->func = newfunc;
+	newfunc = &context->func;
+	newfunc->handle = handle;
+	newfunc->function = function;
 	mutex_unlock(&acpiphp_context_lock);
 
 	if (acpi_has_method(handle, "_EJ0"))
@@ -404,10 +394,8 @@ static acpi_status register_slot(acpi_ha
 
  err:
 	mutex_lock(&acpiphp_context_lock);
-	context->func = NULL;
 	acpiphp_put_context(context);
 	mutex_unlock(&acpiphp_context_lock);
-	kfree(newfunc);
 	return status;
 }
 
@@ -938,7 +926,7 @@ void acpiphp_check_host_bridge(acpi_hand
 static void hotplug_event(acpi_handle handle, u32 type, void *data)
 {
 	struct acpiphp_context *context = data;
-	struct acpiphp_func *func = context->func;
+	struct acpiphp_func *func = &context->func;
 	struct acpiphp_bridge *bridge;
 	char objname[64];
 	struct acpi_buffer buffer = { .length = sizeof(objname),
@@ -1029,7 +1017,7 @@ static void hotplug_event_work(struct wo
 
 	acpi_scan_lock_release();
 	kfree(hp_work); /* allocated in handle_hotplug_event() */
-	put_bridge(context->func->slot->bridge);
+	put_bridge(context->func.slot->bridge);
 }
 
 /**
@@ -1047,7 +1035,7 @@ static void handle_hotplug_event(acpi_ha
 	mutex_lock(&acpiphp_context_lock);
 	context = acpiphp_get_context(handle);
 	if (context) {
-		get_bridge(context->func->slot->bridge);
+		get_bridge(context->func.slot->bridge);
 		acpiphp_put_context(context);
 	}
 	mutex_unlock(&acpiphp_context_lock);
@@ -1109,7 +1097,7 @@ void acpiphp_enumerate_slots(struct pci_
 		 */
 		mutex_lock(&acpiphp_context_lock);
 		context = acpiphp_get_context(handle);
-		if (WARN_ON(!context || !context->func)) {
+		if (WARN_ON(!context)) {
 			mutex_unlock(&acpiphp_context_lock);
 			put_device(&bus->dev);
 			kfree(bridge);
@@ -1118,7 +1106,7 @@ void acpiphp_enumerate_slots(struct pci_
 		bridge->context = context;
 		context->bridge = bridge;
 		/* Get a reference to the parent bridge. */
-		get_bridge(context->func->slot->bridge);
+		get_bridge(context->func.slot->bridge);
 		mutex_unlock(&acpiphp_context_lock);
 	}
 

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

* [PATCH 15/30] ACPI / hotplug / PCI: Drop handle field from struct acpiphp_func
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
                       ` (13 preceding siblings ...)
  2013-07-17 23:24     ` [PATCH 14/30] ACPI / hotplug / PCI: Embed function struct into struct acpiphp_context Rafael J. Wysocki
@ 2013-07-17 23:25     ` Rafael J. Wysocki
  2013-07-17 23:26     ` [PATCH 16/30] ACPI / hotplug / PCI: Drop handle field from struct acpiphp_bridge Rafael J. Wysocki
                       ` (15 subsequent siblings)
  30 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:25 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

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

The ACPI handle stored in struct acpiphp_func is also stored in the
struct acpiphp_context object containing it and it is trivial to get
from a struct acpiphp_func pointer to the handle field of the outer
struct acpiphp_context.

Hence, the handle field of struct acpiphp_func is redundant, so drop
it and provide a helper function, func_to_handle(), allowing it
users to get the ACPI handle for the given struct acpiphp_func
pointer.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp.h      |    6 +++-
 drivers/pci/hotplug/acpiphp_glue.c |   54 +++++++++++++++++++++----------------
 2 files changed, 36 insertions(+), 24 deletions(-)

Index: linux-pm/drivers/pci/hotplug/acpiphp.h
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
+++ linux-pm/drivers/pci/hotplug/acpiphp.h
@@ -119,7 +119,6 @@ struct acpiphp_func {
 	struct acpiphp_slot *slot;	/* parent */
 
 	struct list_head sibling;
-	acpi_handle	handle;
 
 	u8		function;	/* pci function# */
 	u32		flags;		/* see below */
@@ -137,6 +136,11 @@ static inline struct acpiphp_context *fu
 	return container_of(func, struct acpiphp_context, func);
 }
 
+static inline acpi_handle func_to_handle(struct acpiphp_func *func)
+{
+	return func_to_context(func)->handle;
+}
+
 /*
  * 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
@@ -293,7 +293,6 @@ static acpi_status register_slot(acpi_ha
 		return AE_NOT_EXIST;
 	}
 	newfunc = &context->func;
-	newfunc->handle = handle;
 	newfunc->function = function;
 	mutex_unlock(&acpiphp_context_lock);
 
@@ -425,11 +424,13 @@ static void cleanup_bridge(struct acpiph
 
 	list_for_each_entry(slot, &bridge->slots, node) {
 		list_for_each_entry(func, &slot->funcs, sibling) {
-			if (is_dock_device(func->handle)) {
-				unregister_hotplug_dock_device(func->handle);
-			}
+			acpi_handle handle = func_to_handle(func);
+
+			if (is_dock_device(handle))
+				unregister_hotplug_dock_device(handle);
+
 			if (!(func->flags & FUNC_HAS_DCK)) {
-				status = acpi_remove_notify_handler(func->handle,
+				status = acpi_remove_notify_handler(handle,
 							ACPI_SYSTEM_NOTIFY,
 							handle_hotplug_event);
 				if (ACPI_FAILURE(status))
@@ -457,7 +458,8 @@ static int power_on_slot(struct acpiphp_
 	list_for_each_entry(func, &slot->funcs, sibling) {
 		if (func->flags & FUNC_HAS_PS0) {
 			dbg("%s: executing _PS0\n", __func__);
-			status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL);
+			status = acpi_evaluate_object(func_to_handle(func),
+						      "_PS0", NULL, NULL);
 			if (ACPI_FAILURE(status)) {
 				warn("%s: _PS0 failed\n", __func__);
 				retval = -1;
@@ -489,7 +491,8 @@ static int power_off_slot(struct acpiphp
 
 	list_for_each_entry(func, &slot->funcs, sibling) {
 		if (func->flags & FUNC_HAS_PS3) {
-			status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL);
+			status = acpi_evaluate_object(func_to_handle(func),
+						      "_PS3", NULL, NULL);
 			if (ACPI_FAILURE(status)) {
 				warn("%s: _PS3 failed\n", __func__);
 				retval = -1;
@@ -543,10 +546,11 @@ static unsigned char acpiphp_max_busnr(s
  */
 static int acpiphp_bus_add(struct acpiphp_func *func)
 {
+	acpi_handle handle = func_to_handle(func);
 	struct acpi_device *device;
 	int ret_val;
 
-	if (!acpi_bus_get_device(func->handle, &device)) {
+	if (!acpi_bus_get_device(handle, &device)) {
 		dbg("bus exists... trim\n");
 		/* this shouldn't be in here, so remove
 		 * the bus then re-add it...
@@ -554,9 +558,9 @@ static int acpiphp_bus_add(struct acpiph
 		acpi_bus_trim(device);
 	}
 
-	ret_val = acpi_bus_scan(func->handle);
+	ret_val = acpi_bus_scan(handle);
 	if (!ret_val)
-		ret_val = acpi_bus_get_device(func->handle, &device);
+		ret_val = acpi_bus_get_device(handle, &device);
 
 	if (ret_val)
 		dbg("error adding bus, %x\n", -ret_val);
@@ -598,7 +602,8 @@ static void acpiphp_set_acpi_region(stru
 		params[1].type = ACPI_TYPE_INTEGER;
 		params[1].integer.value = 1;
 		/* _REG is optional, we don't care about if there is failure */
-		acpi_evaluate_object(func->handle, "_REG", &arg_list, NULL);
+		acpi_evaluate_object(func_to_handle(func), "_REG", &arg_list,
+				     NULL);
 	}
 }
 
@@ -739,9 +744,8 @@ static int disable_device(struct acpiphp
 		pci_dev_put(pdev);
 	}
 
-	list_for_each_entry(func, &slot->funcs, sibling) {
-		acpiphp_bus_trim(func->handle);
-	}
+	list_for_each_entry(func, &slot->funcs, sibling)
+		acpiphp_bus_trim(func_to_handle(func));
 
 	slot->flags &= (~SLOT_ENABLED);
 
@@ -763,17 +767,20 @@ static int disable_device(struct acpiphp
  */
 static unsigned int get_slot_status(struct acpiphp_slot *slot)
 {
-	acpi_status status;
 	unsigned long long sta = 0;
-	u32 dvid;
 	struct acpiphp_func *func;
 
 	list_for_each_entry(func, &slot->funcs, sibling) {
 		if (func->flags & FUNC_HAS_STA) {
-			status = acpi_evaluate_integer(func->handle, "_STA", NULL, &sta);
+			acpi_status status;
+
+			status = acpi_evaluate_integer(func_to_handle(func),
+						       "_STA", NULL, &sta);
 			if (ACPI_SUCCESS(status) && sta)
 				break;
 		} else {
+			u32 dvid;
+
 			pci_bus_read_config_dword(slot->bridge->pci_bus,
 						  PCI_DEVFN(slot->device,
 							    func->function),
@@ -798,12 +805,13 @@ int acpiphp_eject_slot(struct acpiphp_sl
 
 	list_for_each_entry(func, &slot->funcs, sibling) {
 		/* We don't want to call _EJ0 on non-existing functions. */
-		if ((func->flags & FUNC_HAS_EJ0)) {
-			if (ACPI_FAILURE(acpi_evaluate_ej0(func->handle)))
-				return -1;
-			else
-				break;
-		}
+		if (!(func->flags & FUNC_HAS_EJ0))
+			continue;
+
+		if (ACPI_FAILURE(acpi_evaluate_ej0(func_to_handle(func))))
+			return -1;
+		else
+			break;
 	}
 	return 0;
 }

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

* [PATCH 16/30] ACPI / hotplug / PCI: Drop handle field from struct acpiphp_bridge
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
                       ` (14 preceding siblings ...)
  2013-07-17 23:25     ` [PATCH 15/30] ACPI / hotplug / PCI: Drop handle field from struct acpiphp_func Rafael J. Wysocki
@ 2013-07-17 23:26     ` Rafael J. Wysocki
  2013-07-17 23:26     ` [PATCH 17/30] ACPI / hotplug / PCI: Store parent in functions and bus in slots Rafael J. Wysocki
                       ` (14 subsequent siblings)
  30 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:26 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

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

The handle field in struct acpiphp_bridge is only used by
acpiphp_enumerate_slots(), but in that function the local handle
variable can be used instead, so make that happen and drop handle
from struct acpiphp_bridge.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp.h      |    1 -
 drivers/pci/hotplug/acpiphp_glue.c |    5 ++---
 2 files changed, 2 insertions(+), 4 deletions(-)

Index: linux-pm/drivers/pci/hotplug/acpiphp.h
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
+++ linux-pm/drivers/pci/hotplug/acpiphp.h
@@ -77,7 +77,6 @@ struct acpiphp_bridge {
 	struct list_head list;
 	struct list_head slots;
 	struct kref ref;
-	acpi_handle handle;
 
 	struct acpiphp_context *context;
 
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
@@ -1084,7 +1084,6 @@ void acpiphp_enumerate_slots(struct pci_
 
 	INIT_LIST_HEAD(&bridge->slots);
 	kref_init(&bridge->ref);
-	bridge->handle = handle;
 	bridge->pci_dev = pci_dev_get(bus->self);
 	bridge->pci_bus = bus;
 
@@ -1124,10 +1123,10 @@ void acpiphp_enumerate_slots(struct pci_
 	mutex_unlock(&bridge_mutex);
 
 	/* register all slot objects under this bridge */
-	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, 1,
+	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
 				     register_slot, NULL, bridge, NULL);
 	if (ACPI_FAILURE(status)) {
-		acpi_handle_err(bridge->handle, "failed to register slots\n");
+		acpi_handle_err(handle, "failed to register slots\n");
 		cleanup_bridge(bridge);
 		put_bridge(bridge);
 	}

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

* [PATCH 17/30] ACPI / hotplug / PCI: Store parent in functions and bus in slots
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
                       ` (15 preceding siblings ...)
  2013-07-17 23:26     ` [PATCH 16/30] ACPI / hotplug / PCI: Drop handle field from struct acpiphp_bridge Rafael J. Wysocki
@ 2013-07-17 23:26     ` Rafael J. Wysocki
  2013-07-17 23:27     ` [PATCH 18/30] ACPI / hotplug / PCI: Rework namespace scanning and trimming routines Rafael J. Wysocki
                       ` (13 subsequent siblings)
  30 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:26 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

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

To avoid chasing more pointers than necessary in some situations,
move the bridge pointer from struct acpiphp_slot to struct
acpiphp_func (and call it 'parent') and add a bus pointer to
struct acpiphp_slot.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp.h      |    5 +++--
 drivers/pci/hotplug/acpiphp_core.c |    6 ++----
 drivers/pci/hotplug/acpiphp_glue.c |   25 +++++++++++++------------
 3 files changed, 18 insertions(+), 18 deletions(-)

Index: linux-pm/drivers/pci/hotplug/acpiphp.h
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
+++ linux-pm/drivers/pci/hotplug/acpiphp.h
@@ -97,7 +97,7 @@ struct acpiphp_bridge {
  */
 struct acpiphp_slot {
 	struct list_head node;
-	struct acpiphp_bridge *bridge;	/* parent */
+	struct pci_bus *bus;
 	struct list_head funcs;		/* one slot may have different
 					   objects (i.e. for each function) */
 	struct slot *slot;
@@ -115,7 +115,8 @@ struct acpiphp_slot {
  * typically 8 objects per slot (i.e. for each PCI function)
  */
 struct acpiphp_func {
-	struct acpiphp_slot *slot;	/* parent */
+	struct acpiphp_bridge *parent;
+	struct acpiphp_slot *slot;
 
 	struct list_head sibling;
 
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
@@ -165,7 +165,7 @@ static void free_bridge(struct kref *kre
 	/* Root bridges will not have hotplug context. */
 	if (context) {
 		/* Release the reference taken by acpiphp_enumerate_slots(). */
-		put_bridge(context->func.slot->bridge);
+		put_bridge(context->func.parent);
 		context->bridge = NULL;
 		acpiphp_put_context(context);
 	}
@@ -187,7 +187,7 @@ static void free_bridge(struct kref *kre
 static void post_dock_fixups(acpi_handle not_used, u32 event, void *data)
 {
 	struct acpiphp_context *context = data;
-	struct pci_bus *bus = context->func.slot->bridge->pci_bus;
+	struct pci_bus *bus = context->func.slot->bus;
 	u32 buses;
 
 	if (!bus->self)
@@ -248,14 +248,14 @@ static void acpiphp_dock_init(void *data
 {
 	struct acpiphp_context *context = data;
 
-	get_bridge(context->func.slot->bridge);
+	get_bridge(context->func.parent);
 }
 
 static void acpiphp_dock_release(void *data)
 {
 	struct acpiphp_context *context = data;
 
-	put_bridge(context->func.slot->bridge);
+	put_bridge(context->func.parent);
 }
 
 /* callback routine to register each ACPI PCI slot object */
@@ -294,6 +294,7 @@ static acpi_status register_slot(acpi_ha
 	}
 	newfunc = &context->func;
 	newfunc->function = function;
+	newfunc->parent = bridge;
 	mutex_unlock(&acpiphp_context_lock);
 
 	if (acpi_has_method(handle, "_EJ0"))
@@ -322,7 +323,7 @@ static acpi_status register_slot(acpi_ha
 		goto err;
 	}
 
-	slot->bridge = bridge;
+	slot->bus = bridge->pci_bus;
 	slot->device = device;
 	INIT_LIST_HEAD(&slot->funcs);
 	mutex_init(&slot->crit_sect);
@@ -639,7 +640,7 @@ static void check_hotplug_bridge(struct
 static int __ref enable_device(struct acpiphp_slot *slot)
 {
 	struct pci_dev *dev;
-	struct pci_bus *bus = slot->bridge->pci_bus;
+	struct pci_bus *bus = slot->bus;
 	struct acpiphp_func *func;
 	int num, max, pass;
 	LIST_HEAD(add_list);
@@ -709,7 +710,7 @@ static int __ref enable_device(struct ac
 /* return first device in slot, acquiring a reference on it */
 static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot)
 {
-	struct pci_bus *bus = slot->bridge->pci_bus;
+	struct pci_bus *bus = slot->bus;
 	struct pci_dev *dev;
 	struct pci_dev *ret = NULL;
 
@@ -781,7 +782,7 @@ static unsigned int get_slot_status(stru
 		} else {
 			u32 dvid;
 
-			pci_bus_read_config_dword(slot->bridge->pci_bus,
+			pci_bus_read_config_dword(slot->bus,
 						  PCI_DEVFN(slot->device,
 							    func->function),
 						  PCI_VENDOR_ID, &dvid);
@@ -970,7 +971,7 @@ static void hotplug_event(acpi_handle ha
 		if (bridge)
 			acpiphp_check_bridge(bridge);
 		else
-			acpiphp_check_bridge(func->slot->bridge);
+			acpiphp_check_bridge(func->parent);
 
 		break;
 
@@ -1025,7 +1026,7 @@ static void hotplug_event_work(struct wo
 
 	acpi_scan_lock_release();
 	kfree(hp_work); /* allocated in handle_hotplug_event() */
-	put_bridge(context->func.slot->bridge);
+	put_bridge(context->func.parent);
 }
 
 /**
@@ -1043,7 +1044,7 @@ static void handle_hotplug_event(acpi_ha
 	mutex_lock(&acpiphp_context_lock);
 	context = acpiphp_get_context(handle);
 	if (context) {
-		get_bridge(context->func.slot->bridge);
+		get_bridge(context->func.parent);
 		acpiphp_put_context(context);
 	}
 	mutex_unlock(&acpiphp_context_lock);
@@ -1113,7 +1114,7 @@ void acpiphp_enumerate_slots(struct pci_
 		bridge->context = context;
 		context->bridge = bridge;
 		/* Get a reference to the parent bridge. */
-		get_bridge(context->func.slot->bridge);
+		get_bridge(context->func.parent);
 		mutex_unlock(&acpiphp_context_lock);
 	}
 
Index: linux-pm/drivers/pci/hotplug/acpiphp_core.c
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp_core.c
+++ linux-pm/drivers/pci/hotplug/acpiphp_core.c
@@ -321,10 +321,8 @@ int acpiphp_register_hotplug_slot(struct
 	slot->sun = sun;
 	snprintf(name, SLOT_NAME_SIZE, "%u", sun);
 
-	retval = pci_hp_register(slot->hotplug_slot,
-					acpiphp_slot->bridge->pci_bus,
-					acpiphp_slot->device,
-					name);
+	retval = pci_hp_register(slot->hotplug_slot, acpiphp_slot->bus,
+				 acpiphp_slot->device, name);
 	if (retval == -EBUSY)
 		goto error_hpslot;
 	if (retval) {

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

* [PATCH 18/30] ACPI / hotplug / PCI: Rework namespace scanning and trimming routines
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
                       ` (16 preceding siblings ...)
  2013-07-17 23:26     ` [PATCH 17/30] ACPI / hotplug / PCI: Store parent in functions and bus in slots Rafael J. Wysocki
@ 2013-07-17 23:27     ` Rafael J. Wysocki
  2013-07-17 23:27     ` [PATCH 19/30] ACPI / hotplug / PCI: Drop redundant checks from check_hotplug_bridge() Rafael J. Wysocki
                       ` (12 subsequent siblings)
  30 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:27 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

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

The acpiphp_bus_trim() and acpiphp_bus_add() functions need not
return error codes that are never checked, so redefine them and
simplify them a bit.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp_glue.c |   52 +++++++++----------------------------
 1 file changed, 13 insertions(+), 39 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
@@ -540,53 +540,27 @@ static unsigned char acpiphp_max_busnr(s
 	return max;
 }
 
-
 /**
- * acpiphp_bus_add - add a new bus to acpi subsystem
- * @func: acpiphp_func of the bridge
+ * acpiphp_bus_trim - Trim device objects in an ACPI namespace subtree.
+ * @handle: ACPI device object handle to start from.
  */
-static int acpiphp_bus_add(struct acpiphp_func *func)
+static void acpiphp_bus_trim(acpi_handle handle)
 {
-	acpi_handle handle = func_to_handle(func);
-	struct acpi_device *device;
-	int ret_val;
-
-	if (!acpi_bus_get_device(handle, &device)) {
-		dbg("bus exists... trim\n");
-		/* this shouldn't be in here, so remove
-		 * the bus then re-add it...
-		 */
-		acpi_bus_trim(device);
-	}
-
-	ret_val = acpi_bus_scan(handle);
-	if (!ret_val)
-		ret_val = acpi_bus_get_device(handle, &device);
-
-	if (ret_val)
-		dbg("error adding bus, %x\n", -ret_val);
+	struct acpi_device *adev = NULL;
 
-	return ret_val;
+	acpi_bus_get_device(handle, &adev);
+	if (adev)
+		acpi_bus_trim(adev);
 }
 
-
 /**
- * acpiphp_bus_trim - trim a bus from acpi subsystem
- * @handle: handle to acpi namespace
+ * acpiphp_bus_add - Scan ACPI namespace subtree.
+ * @handle: ACPI object handle to start the scan from.
  */
-static int acpiphp_bus_trim(acpi_handle handle)
+static void acpiphp_bus_add(acpi_handle handle)
 {
-	struct acpi_device *device;
-	int retval;
-
-	retval = acpi_bus_get_device(handle, &device);
-	if (retval) {
-		dbg("acpi_device not found\n");
-		return retval;
-	}
-
-	acpi_bus_trim(device);
-	return 0;
+	acpiphp_bus_trim(handle);
+	acpi_bus_scan(handle);
 }
 
 static void acpiphp_set_acpi_region(struct acpiphp_slot *slot)
@@ -649,7 +623,7 @@ static int __ref enable_device(struct ac
 		goto err_exit;
 
 	list_for_each_entry(func, &slot->funcs, sibling)
-		acpiphp_bus_add(func);
+		acpiphp_bus_add(func_to_handle(func));
 
 	num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
 	if (num == 0) {


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

* [PATCH 19/30] ACPI / hotplug / PCI: Drop redundant checks from check_hotplug_bridge()
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
                       ` (17 preceding siblings ...)
  2013-07-17 23:27     ` [PATCH 18/30] ACPI / hotplug / PCI: Rework namespace scanning and trimming routines Rafael J. Wysocki
@ 2013-07-17 23:27     ` Rafael J. Wysocki
  2013-07-17 23:28     ` [PATCH 20/30] ACPI / hotplug / PCI: Consolidate slot disabling and ejecting Rafael J. Wysocki
                       ` (11 subsequent siblings)
  30 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:27 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

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

Two checks in check_hotplug_bridge() are redundant (they have been
done by the caller already), so drop them.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp_glue.c |    6 ------
 1 file changed, 6 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
@@ -586,16 +586,10 @@ static void check_hotplug_bridge(struct
 {
 	struct acpiphp_func *func;
 
-	if (!dev->subordinate)
-		return;
-
 	/* quirk, or pcie could set it already */
 	if (dev->is_hotplug_bridge)
 		return;
 
-	if (PCI_SLOT(dev->devfn) != slot->device)
-		return;
-
 	list_for_each_entry(func, &slot->funcs, sibling) {
 		if (PCI_FUNC(dev->devfn) == func->function) {
 			dev->is_hotplug_bridge = 1;

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

* [PATCH 20/30] ACPI / hotplug / PCI: Consolidate slot disabling and ejecting
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
                       ` (18 preceding siblings ...)
  2013-07-17 23:27     ` [PATCH 19/30] ACPI / hotplug / PCI: Drop redundant checks from check_hotplug_bridge() Rafael J. Wysocki
@ 2013-07-17 23:28     ` Rafael J. Wysocki
  2013-07-17 23:29     ` [PATCH 21/30] ACPI / hotplug / PCI: Do not queue up event handling work items in vain Rafael J. Wysocki
                       ` (10 subsequent siblings)
  30 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:28 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

From: Mika Westerberg <mika.westerberg@linux.intel.com>

Both acpiphp_disable_slot() and acpiphp_eject_slot() are always
called together so instead of calling each separately we can
consolidate them into one function acpiphp_disable_and_eject_slot()
that does both (but it will return success on _EJ0 failures that
were ignored in the majority of call sites anyway).

[rjw: Rebased plus minor tweaks]
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp.h      |    3 --
 drivers/pci/hotplug/acpiphp_core.c |    6 ----
 drivers/pci/hotplug/acpiphp_glue.c |   50 +++++++++++++------------------------
 3 files changed, 20 insertions(+), 39 deletions(-)

Index: linux-pm/drivers/pci/hotplug/acpiphp.h
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
+++ linux-pm/drivers/pci/hotplug/acpiphp.h
@@ -188,8 +188,7 @@ void acpiphp_unregister_hotplug_slot(str
 typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data);
 
 int acpiphp_enable_slot(struct acpiphp_slot *slot);
-int acpiphp_disable_slot(struct acpiphp_slot *slot);
-int acpiphp_eject_slot(struct acpiphp_slot *slot);
+int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot);
 u8 acpiphp_get_power_status(struct acpiphp_slot *slot);
 u8 acpiphp_get_attention_status(struct acpiphp_slot *slot);
 u8 acpiphp_get_latch_status(struct acpiphp_slot *slot);
Index: linux-pm/drivers/pci/hotplug/acpiphp_core.c
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp_core.c
+++ linux-pm/drivers/pci/hotplug/acpiphp_core.c
@@ -155,15 +155,11 @@ static int enable_slot(struct hotplug_sl
 static int disable_slot(struct hotplug_slot *hotplug_slot)
 {
 	struct slot *slot = hotplug_slot->private;
-	int retval;
 
 	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
 
 	/* disable the specified slot */
-	retval = acpiphp_disable_slot(slot->acpi_slot);
-	if (!retval)
-		retval = acpiphp_eject_slot(slot->acpi_slot);
-	return retval;
+	return acpiphp_disable_and_eject_slot(slot->acpi_slot);
 }
 
 
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
@@ -765,27 +765,6 @@ static unsigned int get_slot_status(stru
 }
 
 /**
- * acpiphp_eject_slot - physically eject the slot
- * @slot: ACPI PHP slot
- */
-int acpiphp_eject_slot(struct acpiphp_slot *slot)
-{
-	struct acpiphp_func *func;
-
-	list_for_each_entry(func, &slot->funcs, sibling) {
-		/* We don't want to call _EJ0 on non-existing functions. */
-		if (!(func->flags & FUNC_HAS_EJ0))
-			continue;
-
-		if (ACPI_FAILURE(acpi_evaluate_ej0(func_to_handle(func))))
-			return -1;
-		else
-			break;
-	}
-	return 0;
-}
-
-/**
  * acpiphp_check_bridge - re-enumerate devices
  * @bridge: where to begin re-enumeration
  *
@@ -805,13 +784,11 @@ static int acpiphp_check_bridge(struct a
 		if (slot->flags & SLOT_ENABLED) {
 			if (status == ACPI_STA_ALL)
 				continue;
-			retval = acpiphp_disable_slot(slot);
-			if (retval) {
-				err("Error occurred in disabling\n");
+
+			retval = acpiphp_disable_and_eject_slot(slot);
+			if (retval)
 				goto err_exit;
-			} else {
-				acpiphp_eject_slot(slot);
-			}
+
 			disabled++;
 		} else {
 			if (status != ACPI_STA_ALL)
@@ -951,9 +928,7 @@ static void hotplug_event(acpi_handle ha
 	case ACPI_NOTIFY_EJECT_REQUEST:
 		/* request device eject */
 		dbg("%s: Device eject notify on %s\n", __func__, objname);
-		if (!(acpiphp_disable_slot(func->slot)))
-			acpiphp_eject_slot(func->slot);
-
+		acpiphp_disable_and_eject_slot(func->slot);
 		break;
 
 	case ACPI_NOTIFY_FREQUENCY_MISMATCH:
@@ -1148,11 +1123,12 @@ int acpiphp_enable_slot(struct acpiphp_s
 }
 
 /**
- * acpiphp_disable_slot - power off slot
+ * acpiphp_disable_and_eject_slot - power off and eject slot
  * @slot: ACPI PHP slot
  */
-int acpiphp_disable_slot(struct acpiphp_slot *slot)
+int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot)
 {
+	struct acpiphp_func *func;
 	int retval = 0;
 
 	mutex_lock(&slot->crit_sect);
@@ -1167,6 +1143,16 @@ int acpiphp_disable_slot(struct acpiphp_
 	if (retval)
 		goto err_exit;
 
+	list_for_each_entry(func, &slot->funcs, sibling)
+		if (func->flags & FUNC_HAS_EJ0) {
+			acpi_handle handle = func_to_handle(func);
+
+			if (ACPI_FAILURE(acpi_evaluate_ej0(handle)))
+				acpi_handle_err(handle, "_EJ0 failed\n");
+
+			break;
+		}
+
  err_exit:
 	mutex_unlock(&slot->crit_sect);
 	return retval;


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

* [PATCH 21/30] ACPI / hotplug / PCI: Do not queue up event handling work items in vain
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
                       ` (19 preceding siblings ...)
  2013-07-17 23:28     ` [PATCH 20/30] ACPI / hotplug / PCI: Consolidate slot disabling and ejecting Rafael J. Wysocki
@ 2013-07-17 23:29     ` Rafael J. Wysocki
  2013-07-17 23:30     ` [PATCH 22/30] ACPI / hotplug / PCI: Do not exectute _PS0 and _PS3 directly Rafael J. Wysocki
                       ` (9 subsequent siblings)
  30 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:29 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

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

Modify handle_hotplug_event() to avoid queing up the execution of
handle_hotplug_event_work_fn() as a work item on kacpi_hotplug_wq
for non-hotplug events, such as ACPI_NOTIFY_DEVICE_WAKE.  Move
the code printing diagnostic messages for those events into
handle_hotplug_event().

In addition to that, remove the bogus comment about how the core
should distinguish between hotplug and non-hotplug events and
queue them up on different workqueues.  The core clearly cannot
know in advance what events will be interesting to the given
caller of acpi_install_notify_handler().

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp_glue.c |   64 ++++++++++++++++---------------------
 1 file changed, 29 insertions(+), 35 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
@@ -920,36 +920,11 @@ static void hotplug_event(acpi_handle ha
 
 		break;
 
-	case ACPI_NOTIFY_DEVICE_WAKE:
-		/* wake event */
-		dbg("%s: Device wake notify on %s\n", __func__, objname);
-		break;
-
 	case ACPI_NOTIFY_EJECT_REQUEST:
 		/* request device eject */
 		dbg("%s: Device eject notify on %s\n", __func__, objname);
 		acpiphp_disable_and_eject_slot(func->slot);
 		break;
-
-	case ACPI_NOTIFY_FREQUENCY_MISMATCH:
-		printk(KERN_ERR "Device %s cannot be configured due"
-				" to a frequency mismatch\n", objname);
-		break;
-
-	case ACPI_NOTIFY_BUS_MODE_MISMATCH:
-		printk(KERN_ERR "Device %s cannot be configured due"
-				" to a bus mode mismatch\n", objname);
-		break;
-
-	case ACPI_NOTIFY_POWER_FAULT:
-		printk(KERN_ERR "Device %s has suffered a power fault\n",
-				objname);
-		break;
-
-	default:
-		warn("notify_handler: unknown event type 0x%x for %s\n", type,
-		     objname);
-		break;
 	}
 
 	if (bridge)
@@ -984,23 +959,42 @@ static void handle_hotplug_event(acpi_ha
 {
 	struct acpiphp_context *context;
 
+	switch (type) {
+	case ACPI_NOTIFY_BUS_CHECK:
+	case ACPI_NOTIFY_DEVICE_CHECK:
+	case ACPI_NOTIFY_EJECT_REQUEST:
+		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");
+		return;
+
+	case ACPI_NOTIFY_BUS_MODE_MISMATCH:
+		acpi_handle_err(handle, "Device cannot be configured due "
+				"to a bus mode mismatch\n");
+		return;
+
+	case ACPI_NOTIFY_POWER_FAULT:
+		acpi_handle_err(handle, "Device has suffered a power fault\n");
+		return;
+
+	default:
+		acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type);
+		return;
+	}
+
 	mutex_lock(&acpiphp_context_lock);
 	context = acpiphp_get_context(handle);
 	if (context) {
 		get_bridge(context->func.parent);
 		acpiphp_put_context(context);
+		alloc_acpi_hp_work(handle, type, context, hotplug_event_work);
 	}
 	mutex_unlock(&acpiphp_context_lock);
-	/*
-	 * 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.
-	 */
-	if (context)
-		alloc_acpi_hp_work(handle, type, context, hotplug_event_work);
 }
 
 /*

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

* [PATCH 22/30] ACPI / hotplug / PCI: Do not exectute _PS0 and _PS3 directly
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
                       ` (20 preceding siblings ...)
  2013-07-17 23:29     ` [PATCH 21/30] ACPI / hotplug / PCI: Do not queue up event handling work items in vain Rafael J. Wysocki
@ 2013-07-17 23:30     ` Rafael J. Wysocki
  2013-07-17 23:31     ` [PATCH 23/30] ACPI / hotplug / PCI: Do not check SLOT_ENABLED in enable_device() Rafael J. Wysocki
                       ` (8 subsequent siblings)
  30 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:30 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

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

The ACPI-based PCI hotplug (acpiphp) core code need not and really
should not execute _PS0 and _PS3 directly for devices it handles.

First of all, it is not necessary to put devices into D3 after
acpi_bus_trim() has walked through them, because
acpi_device_unregister() invoked by it puts each device into D3cold
before returning.  Thus after disable_device() the slot should be
powered down already.

Second, calling _PS0 directly on ACPI device objects may not be
appropriate, because it may require power resources to be set up in
a specific way in advance and that must be taken care of by the ACPI
core.  Thus modify acpiphp_bus_add() to power up the device using
the appropriate interface after it has run acpi_bus_scan() on its
handle.

After that, the functions executing _PS0 and _PS3, power_on_slot()
and power_off_slot(), are not necessary any more, so drop them
and update the code calling them accordingly.  Also drop the
function flags related to device power states, since they aren't
useful any more too.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp.h      |    7 --
 drivers/pci/hotplug/acpiphp_glue.c |  106 +++----------------------------------
 2 files changed, 10 insertions(+), 103 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
@@ -303,12 +303,6 @@ static acpi_status register_slot(acpi_ha
 	if (acpi_has_method(handle, "_STA"))
 		newfunc->flags |= FUNC_HAS_STA;
 
-	if (acpi_has_method(handle, "_PS0"))
-		newfunc->flags |= FUNC_HAS_PS0;
-
-	if (acpi_has_method(handle, "_PS3"))
-		newfunc->flags |= FUNC_HAS_PS3;
-
 	if (acpi_has_method(handle, "_DCK"))
 		newfunc->flags |= FUNC_HAS_DCK;
 
@@ -366,7 +360,7 @@ static acpi_status register_slot(acpi_ha
 
 	if (pci_bus_read_dev_vendor_id(pbus, PCI_DEVFN(device, function),
 				       &val, 60*1000))
-		slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON);
+		slot->flags |= SLOT_ENABLED;
 
 	if (is_dock_device(handle)) {
 		/* we don't want to call this device's _EJ0
@@ -446,73 +440,6 @@ static void cleanup_bridge(struct acpiph
 	mutex_unlock(&bridge_mutex);
 }
 
-static int power_on_slot(struct acpiphp_slot *slot)
-{
-	acpi_status status;
-	struct acpiphp_func *func;
-	int retval = 0;
-
-	/* if already enabled, just skip */
-	if (slot->flags & SLOT_POWEREDON)
-		goto err_exit;
-
-	list_for_each_entry(func, &slot->funcs, sibling) {
-		if (func->flags & FUNC_HAS_PS0) {
-			dbg("%s: executing _PS0\n", __func__);
-			status = acpi_evaluate_object(func_to_handle(func),
-						      "_PS0", NULL, NULL);
-			if (ACPI_FAILURE(status)) {
-				warn("%s: _PS0 failed\n", __func__);
-				retval = -1;
-				goto err_exit;
-			} else
-				break;
-		}
-	}
-
-	/* TBD: evaluate _STA to check if the slot is enabled */
-
-	slot->flags |= SLOT_POWEREDON;
-
- err_exit:
-	return retval;
-}
-
-
-static int power_off_slot(struct acpiphp_slot *slot)
-{
-	acpi_status status;
-	struct acpiphp_func *func;
-
-	int retval = 0;
-
-	/* if already disabled, just skip */
-	if ((slot->flags & SLOT_POWEREDON) == 0)
-		goto err_exit;
-
-	list_for_each_entry(func, &slot->funcs, sibling) {
-		if (func->flags & FUNC_HAS_PS3) {
-			status = acpi_evaluate_object(func_to_handle(func),
-						      "_PS3", NULL, NULL);
-			if (ACPI_FAILURE(status)) {
-				warn("%s: _PS3 failed\n", __func__);
-				retval = -1;
-				goto err_exit;
-			} else
-				break;
-		}
-	}
-
-	/* TBD: evaluate _STA to check if the slot is disabled */
-
-	slot->flags &= (~SLOT_POWEREDON);
-
- err_exit:
-	return retval;
-}
-
-
-
 /**
  * acpiphp_max_busnr - return the highest reserved bus number under the given bus.
  * @bus: bus to start search with
@@ -559,8 +486,13 @@ static void acpiphp_bus_trim(acpi_handle
  */
 static void acpiphp_bus_add(acpi_handle handle)
 {
+	struct acpi_device *adev = NULL;
+
 	acpiphp_bus_trim(handle);
 	acpi_bus_scan(handle);
+	acpi_bus_get_device(handle, &adev);
+	if (adev)
+		acpi_device_set_power(adev, ACPI_STATE_D0);
 }
 
 static void acpiphp_set_acpi_region(struct acpiphp_slot *slot)
@@ -1095,23 +1027,8 @@ int acpiphp_enable_slot(struct acpiphp_s
 	int retval;
 
 	mutex_lock(&slot->crit_sect);
-
-	/* wake up all functions */
-	retval = power_on_slot(slot);
-	if (retval)
-		goto err_exit;
-
-	if (get_slot_status(slot) == ACPI_STA_ALL) {
-		/* configure all functions */
-		retval = enable_device(slot);
-		if (retval)
-			power_off_slot(slot);
-	} else {
-		dbg("%s: Slot status is not ACPI_STA_ALL\n", __func__);
-		power_off_slot(slot);
-	}
-
- err_exit:
+	/* configure all functions */
+	retval = enable_device(slot);
 	mutex_unlock(&slot->crit_sect);
 	return retval;
 }
@@ -1132,11 +1049,6 @@ int acpiphp_disable_and_eject_slot(struc
 	if (retval)
 		goto err_exit;
 
-	/* power off all functions */
-	retval = power_off_slot(slot);
-	if (retval)
-		goto err_exit;
-
 	list_for_each_entry(func, &slot->funcs, sibling)
 		if (func->flags & FUNC_HAS_EJ0) {
 			acpi_handle handle = func_to_handle(func);
@@ -1159,7 +1071,7 @@ int acpiphp_disable_and_eject_slot(struc
  */
 u8 acpiphp_get_power_status(struct acpiphp_slot *slot)
 {
-	return (slot->flags & SLOT_POWEREDON);
+	return (slot->flags & SLOT_ENABLED);
 }
 
 
Index: linux-pm/drivers/pci/hotplug/acpiphp.h
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
+++ linux-pm/drivers/pci/hotplug/acpiphp.h
@@ -162,7 +162,6 @@ struct acpiphp_attention_info
 
 /* slot flags */
 
-#define SLOT_POWEREDON		(0x00000001)
 #define SLOT_ENABLED		(0x00000002)
 #define SLOT_MULTIFUNCTION	(0x00000004)
 
@@ -170,11 +169,7 @@ struct acpiphp_attention_info
 
 #define FUNC_HAS_STA		(0x00000001)
 #define FUNC_HAS_EJ0		(0x00000002)
-#define FUNC_HAS_PS0		(0x00000010)
-#define FUNC_HAS_PS1		(0x00000020)
-#define FUNC_HAS_PS2		(0x00000040)
-#define FUNC_HAS_PS3		(0x00000080)
-#define FUNC_HAS_DCK            (0x00000100)
+#define FUNC_HAS_DCK            (0x00000004)
 
 /* function prototypes */
 

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

* [PATCH 23/30] ACPI / hotplug / PCI: Do not check SLOT_ENABLED in enable_device()
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
                       ` (21 preceding siblings ...)
  2013-07-17 23:30     ` [PATCH 22/30] ACPI / hotplug / PCI: Do not exectute _PS0 and _PS3 directly Rafael J. Wysocki
@ 2013-07-17 23:31     ` Rafael J. Wysocki
  2013-07-17 23:31     ` [PATCH 24/30] ACPI / hotplug / PCI: Allow slots without new devices to be rescanned Rafael J. Wysocki
                       ` (7 subsequent siblings)
  30 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:31 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

From: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>

With Thunderbolt you can daisy chain devices: connect new devices to
an already plugged one.  In that case the "hotplug slot" is already
enabled, but we still want to look for new PCI devices behind it.

Reuse enable_device() to scan for new PCI devices on enabled slots
and push the SLOT_ENABLED check up into acpiphp_enable_slot().

[rjw: Rebased, modified the changelog]
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/pci/hotplug/acpiphp_glue.c | 5 ++---
 drivers/pci/hotplug/acpiphp_glue.c |   10 +++++-----
 1 file changed, 5 insertions(+), 5 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
@@ -545,9 +545,6 @@ static int __ref enable_device(struct ac
 	int num, max, pass;
 	LIST_HEAD(add_list);
 
-	if (slot->flags & SLOT_ENABLED)
-		goto err_exit;
-
 	list_for_each_entry(func, &slot->funcs, sibling)
 		acpiphp_bus_add(func_to_handle(func));
 
@@ -1024,11 +1021,14 @@ void acpiphp_remove_slots(struct pci_bus
  */
 int acpiphp_enable_slot(struct acpiphp_slot *slot)
 {
-	int retval;
+	int retval = 0;
 
 	mutex_lock(&slot->crit_sect);
+
 	/* configure all functions */
-	retval = enable_device(slot);
+	if (!(slot->flags & SLOT_ENABLED))
+		retval = enable_device(slot);
+
 	mutex_unlock(&slot->crit_sect);
 	return retval;
 }


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

* [PATCH 24/30] ACPI / hotplug / PCI: Allow slots without new devices to be rescanned
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
                       ` (22 preceding siblings ...)
  2013-07-17 23:31     ` [PATCH 23/30] ACPI / hotplug / PCI: Do not check SLOT_ENABLED in enable_device() Rafael J. Wysocki
@ 2013-07-17 23:31     ` Rafael J. Wysocki
  2013-07-17 23:32     ` [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots Rafael J. Wysocki
                       ` (6 subsequent siblings)
  30 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:31 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

From: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>

Currently, enable_device() checks the return value of pci_scan_slot()
and returns immediately if that's 0 (meaning that no new functions
have been found in the slot).  However, if one of the functions in
the slot is a bridge, some new devices may appear below it even if
the bridge itself is present continuously, so it generally is
necessary to do the rescan anyway just in case.  [In particular,
that's necessary with the Thunderbolt daisy chaining in which case
new devices may be connected to the existing ones down the chain.]

The correctness of this change relies on the ability of
pcibios_resource_survey_bus() to detect if it has already been called
for the given bus and to skip it if so.  Failure to do that will lead
to resource allocation conflicts.

[rjw: Changelog]
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/pci/hotplug/acpiphp_glue.c | 11 ++---------
 drivers/pci/hotplug/acpiphp_glue.c |   11 ++---------
 1 file changed, 2 insertions(+), 9 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
@@ -542,18 +542,13 @@ static int __ref enable_device(struct ac
 	struct pci_dev *dev;
 	struct pci_bus *bus = slot->bus;
 	struct acpiphp_func *func;
-	int num, max, pass;
+	int max, pass;
 	LIST_HEAD(add_list);
 
 	list_for_each_entry(func, &slot->funcs, sibling)
 		acpiphp_bus_add(func_to_handle(func));
 
-	num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
-	if (num == 0) {
-		/* Maybe only part of funcs are added. */
-		dbg("No new device found\n");
-		goto err_exit;
-	}
+	pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
 
 	max = acpiphp_max_busnr(bus);
 	for (pass = 0; pass < 2; pass++) {
@@ -599,8 +594,6 @@ static int __ref enable_device(struct ac
 		}
 	}
 
-
- err_exit:
 	return 0;
 }
 

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

* [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
                       ` (23 preceding siblings ...)
  2013-07-17 23:31     ` [PATCH 24/30] ACPI / hotplug / PCI: Allow slots without new devices to be rescanned Rafael J. Wysocki
@ 2013-07-17 23:32     ` Rafael J. Wysocki
  2013-09-04 20:36       ` Alex Williamson
  2013-07-17 23:33     ` [PATCH 26/30] ACPI / hotplug / PCI: Get rid of unused constants in acpiphp.h Rafael J. Wysocki
                       ` (5 subsequent siblings)
  30 siblings, 1 reply; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:32 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

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

The current implementation of acpiphp_check_bridge() is pretty dumb:
 - It enables a slot if it's not enabled and the slot status is
   ACPI_STA_ALL.
 - It disables a slot if it's enabled and the slot status is not
   ACPI_STA_ALL.

This behavior is not sufficient to handle the Thunderbolt daisy
chaining case properly, however, because in that case the bus
behind the already enabled slot needs to be rescanned for new
devices.

For this reason, modify acpiphp_check_bridge() so that slots are
disabled and stopped if they are not in the ACPI_STA_ALL state.

For slots in the ACPI_STA_ALL state, devices behind them that don't
respond are trimmed using a new function, trim_stale_devices(),
introduced specifically for this purpose.  That function walks
the given bus and checks each device on it.  If the device doesn't
respond, it is assumed to be gone and is removed.

Once all of the stale devices directy behind the slot have been
removed, acpiphp_check_bridge() will start looking for new devices
that might have appeared on the given bus.  It will do that even if
the slot is already enabled (SLOT_ENABLED is set for it).

In addition to that, make the bus check notification ignore
SLOT_ENABLED and go for enable_device() directly if bridge is NULL,
so that devices behind the slot are re-enumerated in that case too.

This change is based on earlier patches from Kirill A Shutemov
and Mika Westerberg.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
---
 drivers/pci/hotplug/acpiphp_glue.c |   87 +++++++++++++++++++++++++------------
 1 file changed, 60 insertions(+), 27 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
@@ -46,6 +46,7 @@
 #include <linux/pci.h>
 #include <linux/pci_hotplug.h>
 #include <linux/pci-acpi.h>
+#include <linux/pm_runtime.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
 #include <linux/acpi.h>
@@ -687,47 +688,75 @@ static unsigned int get_slot_status(stru
 }
 
 /**
+ * trim_stale_devices - remove PCI devices that are not responding.
+ * @dev: PCI device to start walking the hierarchy from.
+ */
+static void trim_stale_devices(struct pci_dev *dev)
+{
+	acpi_handle handle = ACPI_HANDLE(&dev->dev);
+	struct pci_bus *bus = dev->subordinate;
+	bool alive = false;
+
+	if (handle) {
+		acpi_status status;
+		unsigned long long sta;
+
+		status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+		alive = ACPI_SUCCESS(status) && sta == ACPI_STA_ALL;
+	}
+	if (!alive) {
+		u32 v;
+
+		/* Check if the device responds. */
+		alive = pci_bus_read_dev_vendor_id(dev->bus, dev->devfn, &v, 0);
+	}
+	if (!alive) {
+		pci_stop_and_remove_bus_device(dev);
+		if (handle)
+			acpiphp_bus_trim(handle);
+	} else if (bus) {
+		struct pci_dev *child, *tmp;
+
+		/* The device is a bridge. so check the bus below it. */
+		pm_runtime_get_sync(&dev->dev);
+		list_for_each_entry_safe(child, tmp, &bus->devices, bus_list)
+			trim_stale_devices(child);
+
+		pm_runtime_put(&dev->dev);
+	}
+}
+
+/**
  * acpiphp_check_bridge - re-enumerate devices
  * @bridge: where to begin re-enumeration
  *
  * Iterate over all slots under this bridge and make sure that if a
  * card is present they are enabled, and if not they are disabled.
  */
-static int acpiphp_check_bridge(struct acpiphp_bridge *bridge)
+static void acpiphp_check_bridge(struct acpiphp_bridge *bridge)
 {
 	struct acpiphp_slot *slot;
-	int retval = 0;
-	int enabled, disabled;
-
-	enabled = disabled = 0;
 
 	list_for_each_entry(slot, &bridge->slots, node) {
-		unsigned int status = get_slot_status(slot);
-		if (slot->flags & SLOT_ENABLED) {
-			if (status == ACPI_STA_ALL)
-				continue;
+		struct pci_bus *bus = slot->bus;
+		struct pci_dev *dev, *tmp;
 
-			retval = acpiphp_disable_and_eject_slot(slot);
-			if (retval)
-				goto err_exit;
+		mutex_lock(&slot->crit_sect);
+		/* wake up all functions */
+		if (get_slot_status(slot) == ACPI_STA_ALL) {
+			/* remove stale devices if any */
+			list_for_each_entry_safe(dev, tmp, &bus->devices,
+						 bus_list)
+				if (PCI_SLOT(dev->devfn) == slot->device)
+					trim_stale_devices(dev);
 
-			disabled++;
+			/* configure all functions */
+			enable_device(slot);
 		} else {
-			if (status != ACPI_STA_ALL)
-				continue;
-			retval = acpiphp_enable_slot(slot);
-			if (retval) {
-				err("Error occurred in enabling\n");
-				goto err_exit;
-			}
-			enabled++;
+			disable_device(slot);
 		}
+		mutex_unlock(&slot->crit_sect);
 	}
-
-	dbg("%s: %d enabled, %d disabled\n", __func__, enabled, disabled);
-
- err_exit:
-	return retval;
 }
 
 static void acpiphp_set_hpp_values(struct pci_bus *bus)
@@ -828,7 +857,11 @@ static void hotplug_event(acpi_handle ha
 					    ACPI_UINT32_MAX, check_sub_bridges,
 					    NULL, NULL, NULL);
 		} else {
-			acpiphp_enable_slot(func->slot);
+			struct acpiphp_slot *slot = func->slot;
+
+			mutex_lock(&slot->crit_sect);
+			enable_device(slot);
+			mutex_unlock(&slot->crit_sect);
 		}
 		break;
 

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

* [PATCH 26/30] ACPI / hotplug / PCI: Get rid of unused constants in acpiphp.h
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
                       ` (24 preceding siblings ...)
  2013-07-17 23:32     ` [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots Rafael J. Wysocki
@ 2013-07-17 23:33     ` Rafael J. Wysocki
  2013-07-17 23:34     ` [PATCH 27/30] ACPI / hotplug / PCI: Sanitize acpiphp_get_(latch)|(adapter)_status() Rafael J. Wysocki
                       ` (4 subsequent siblings)
  30 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:33 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

From: Mika Westerberg <mika.westerberg@linux.intel.com>

Drop some unused symbols from acpiphp.h and redefine SLOT_ENABLED
(which is the only slot flag now) as 1.

[rjw: Redefinition of SLOT_ENABLED, changelog]
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/pci/hotplug/acpiphp.h | 4 ----
 drivers/pci/hotplug/acpiphp.h |    6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

Index: linux-pm/drivers/pci/hotplug/acpiphp.h
===================================================================
--- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
+++ linux-pm/drivers/pci/hotplug/acpiphp.h
@@ -154,16 +154,12 @@ struct acpiphp_attention_info
 	struct module *owner;
 };
 
-/* PCI bus bridge HID */
-#define ACPI_PCI_HOST_HID		"PNP0A03"
-
 /* ACPI _STA method value (ignore bit 4; battery present) */
 #define ACPI_STA_ALL			(0x0000000f)
 
 /* slot flags */
 
-#define SLOT_ENABLED		(0x00000002)
-#define SLOT_MULTIFUNCTION	(0x00000004)
+#define SLOT_ENABLED		(0x00000001)
 
 /* function flags */
 

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

* [PATCH 27/30] ACPI / hotplug / PCI: Sanitize acpiphp_get_(latch)|(adapter)_status()
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
                       ` (25 preceding siblings ...)
  2013-07-17 23:33     ` [PATCH 26/30] ACPI / hotplug / PCI: Get rid of unused constants in acpiphp.h Rafael J. Wysocki
@ 2013-07-17 23:34     ` Rafael J. Wysocki
  2013-07-17 23:35     ` [PATCH 28/30] ACPI / hotplug / PCI: Redefine enable_device() and disable_device() Rafael J. Wysocki
                       ` (3 subsequent siblings)
  30 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:34 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

From: Mika Westerberg <mika.westerberg@linux.intel.com>

There is no need for a temporary variable and all the tricks with
ternary operators in acpiphp_get_(latch)|(adapter)_status(). Change
those functions to be a bit more straightforward.

[rjw: Changelog]
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp_glue.c |   12 ++----------
 1 file changed, 2 insertions(+), 10 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
@@ -1107,11 +1107,7 @@ u8 acpiphp_get_power_status(struct acpip
  */
 u8 acpiphp_get_latch_status(struct acpiphp_slot *slot)
 {
-	unsigned int sta;
-
-	sta = get_slot_status(slot);
-
-	return (sta & ACPI_STA_DEVICE_UI) ? 0 : 1;
+	return !(get_slot_status(slot) & ACPI_STA_DEVICE_UI);
 }
 
 
@@ -1121,9 +1117,5 @@ u8 acpiphp_get_latch_status(struct acpip
  */
 u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot)
 {
-	unsigned int sta;
-
-	sta = get_slot_status(slot);
-
-	return (sta == 0) ? 0 : 1;
+	return !!get_slot_status(slot);
 }

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

* [PATCH 28/30] ACPI / hotplug / PCI: Redefine enable_device() and disable_device()
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
                       ` (26 preceding siblings ...)
  2013-07-17 23:34     ` [PATCH 27/30] ACPI / hotplug / PCI: Sanitize acpiphp_get_(latch)|(adapter)_status() Rafael J. Wysocki
@ 2013-07-17 23:35     ` Rafael J. Wysocki
  2013-07-17 23:35     ` [PATCH 29/30] ACPI / hotplug / PCI: Clean up bridge_mutex usage Rafael J. Wysocki
                       ` (2 subsequent siblings)
  30 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:35 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

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

Notice that functions enable_device() and disable_device() cannot
fail and their return values are ignored in the majority of places,
so redefine them as void and use the opportunity to change their
names to enable_slot() and disable_slot(), respectively, which much
better reflects what they do.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp_glue.c |   33 ++++++++++++---------------------
 1 file changed, 12 insertions(+), 21 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
@@ -532,13 +532,13 @@ static void check_hotplug_bridge(struct
 }
 
 /**
- * enable_device - enable, configure a slot
+ * enable_slot - enable, configure a slot
  * @slot: slot to be enabled
  *
  * This function should be called per *physical slot*,
  * not per each slot object in ACPI namespace.
  */
-static int __ref enable_device(struct acpiphp_slot *slot)
+static void __ref enable_slot(struct acpiphp_slot *slot)
 {
 	struct pci_dev *dev;
 	struct pci_bus *bus = slot->bus;
@@ -556,6 +556,7 @@ static int __ref enable_device(struct ac
 		list_for_each_entry(dev, &bus->devices, bus_list) {
 			if (PCI_SLOT(dev->devfn) != slot->device)
 				continue;
+
 			if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
 			    dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
 				max = pci_scan_bridge(bus, dev, max, pass);
@@ -594,8 +595,6 @@ static int __ref enable_device(struct ac
 			continue;
 		}
 	}
-
-	return 0;
 }
 
 /* return first device in slot, acquiring a reference on it */
@@ -617,16 +616,16 @@ static struct pci_dev *dev_in_slot(struc
 }
 
 /**
- * disable_device - disable a slot
+ * disable_slot - disable a slot
  * @slot: ACPI PHP slot
  */
-static int disable_device(struct acpiphp_slot *slot)
+static void disable_slot(struct acpiphp_slot *slot)
 {
 	struct acpiphp_func *func;
 	struct pci_dev *pdev;
 
 	/*
-	 * enable_device() enumerates all functions in this device via
+	 * enable_slot() enumerates all functions in this device via
 	 * pci_scan_slot(), whether they have associated ACPI hotplug
 	 * methods (_EJ0, etc.) or not.  Therefore, we remove all functions
 	 * here.
@@ -640,8 +639,6 @@ static int disable_device(struct acpiphp
 		acpiphp_bus_trim(func_to_handle(func));
 
 	slot->flags &= (~SLOT_ENABLED);
-
-	return 0;
 }
 
 
@@ -751,9 +748,9 @@ static void acpiphp_check_bridge(struct
 					trim_stale_devices(dev);
 
 			/* configure all functions */
-			enable_device(slot);
+			enable_slot(slot);
 		} else {
-			disable_device(slot);
+			disable_slot(slot);
 		}
 		mutex_unlock(&slot->crit_sect);
 	}
@@ -860,7 +857,7 @@ static void hotplug_event(acpi_handle ha
 			struct acpiphp_slot *slot = func->slot;
 
 			mutex_lock(&slot->crit_sect);
-			enable_device(slot);
+			enable_slot(slot);
 			mutex_unlock(&slot->crit_sect);
 		}
 		break;
@@ -1047,16 +1044,13 @@ void acpiphp_remove_slots(struct pci_bus
  */
 int acpiphp_enable_slot(struct acpiphp_slot *slot)
 {
-	int retval = 0;
-
 	mutex_lock(&slot->crit_sect);
-
 	/* configure all functions */
 	if (!(slot->flags & SLOT_ENABLED))
-		retval = enable_device(slot);
+		enable_slot(slot);
 
 	mutex_unlock(&slot->crit_sect);
-	return retval;
+	return 0;
 }
 
 /**
@@ -1071,9 +1065,7 @@ int acpiphp_disable_and_eject_slot(struc
 	mutex_lock(&slot->crit_sect);
 
 	/* unconfigure all functions */
-	retval = disable_device(slot);
-	if (retval)
-		goto err_exit;
+	disable_slot(slot);
 
 	list_for_each_entry(func, &slot->funcs, sibling)
 		if (func->flags & FUNC_HAS_EJ0) {
@@ -1085,7 +1077,6 @@ int acpiphp_disable_and_eject_slot(struc
 			break;
 		}
 
- err_exit:
 	mutex_unlock(&slot->crit_sect);
 	return retval;
 }

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

* [PATCH 29/30] ACPI / hotplug / PCI: Clean up bridge_mutex usage
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
                       ` (27 preceding siblings ...)
  2013-07-17 23:35     ` [PATCH 28/30] ACPI / hotplug / PCI: Redefine enable_device() and disable_device() Rafael J. Wysocki
@ 2013-07-17 23:35     ` Rafael J. Wysocki
  2013-07-17 23:36     ` [PATCH 30/30] ACPI / hotplug / PCI: Get rid of check_sub_bridges() Rafael J. Wysocki
  2013-07-23  6:49     ` [PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Yinghai Lu
  30 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:35 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

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

Do not acquire bridge_mutex around the addition of a slot to its
bridge's list of slots and arount the addition of a function to
its slot's list of functions, because that doesn't help anything
right now (those lists are walked without any locking anyway).

However, acquire bridge_mutex around the list walk in
acpiphp_remove_slots() and use list_for_each_entry() there,
because we terminate the walk as soon as we find the first matching
entry.  This prevents that list walk from colliding with bridge
addition and removal.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp_glue.c |   14 +++++++-------
 1 file changed, 7 insertions(+), 7 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
@@ -323,9 +323,7 @@ static acpi_status register_slot(acpi_ha
 	INIT_LIST_HEAD(&slot->funcs);
 	mutex_init(&slot->crit_sect);
 
-	mutex_lock(&bridge_mutex);
 	list_add_tail(&slot->node, &bridge->slots);
-	mutex_unlock(&bridge_mutex);
 
 	/* Register slots for ejectable funtions only. */
 	if (acpi_pci_check_ejectable(pbus, handle)  || is_dock_device(handle)) {
@@ -355,9 +353,7 @@ static acpi_status register_slot(acpi_ha
 
  slot_found:
 	newfunc->slot = slot;
-	mutex_lock(&bridge_mutex);
 	list_add_tail(&newfunc->sibling, &slot->funcs);
-	mutex_unlock(&bridge_mutex);
 
 	if (pci_bus_read_dev_vendor_id(pbus, PCI_DEVFN(device, function),
 				       &val, 60*1000))
@@ -1025,17 +1021,21 @@ void acpiphp_enumerate_slots(struct pci_
 /* Destroy hotplug slots associated with the PCI bus */
 void acpiphp_remove_slots(struct pci_bus *bus)
 {
-	struct acpiphp_bridge *bridge, *tmp;
+	struct acpiphp_bridge *bridge;
 
 	if (acpiphp_disabled)
 		return;
 
-	list_for_each_entry_safe(bridge, tmp, &bridge_list, list)
+	mutex_lock(&bridge_mutex);
+	list_for_each_entry(bridge, &bridge_list, list)
 		if (bridge->pci_bus == bus) {
+			mutex_unlock(&bridge_mutex);
 			cleanup_bridge(bridge);
 			put_bridge(bridge);
-			break;
+			return;
 		}
+
+	mutex_unlock(&bridge_mutex);
 }
 
 /**


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

* [PATCH 30/30] ACPI / hotplug / PCI: Get rid of check_sub_bridges()
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
                       ` (28 preceding siblings ...)
  2013-07-17 23:35     ` [PATCH 29/30] ACPI / hotplug / PCI: Clean up bridge_mutex usage Rafael J. Wysocki
@ 2013-07-17 23:36     ` Rafael J. Wysocki
  2013-07-23  6:49     ` [PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Yinghai Lu
  30 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-17 23:36 UTC (permalink / raw)
  To: ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

From: Mika Westerberg <mika.westerberg@linux.intel.com>

Now that acpiphp_check_bridge() always enumerates devices behind the
bridge, there is no need to do that for each sub-bridge anymore like
it is done in the current ACPI-based PCI hotplug (ACPIPHP) code.

Given this we don't need check_sub_bridges() anymore, so drop that
function completely.

This also simplifies the ACPIPHP code a bit.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp_glue.c |   25 -------------------------
 1 file changed, 25 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
@@ -788,25 +788,6 @@ static void acpiphp_sanitize_bus(struct
  * ACPI event handlers
  */
 
-static acpi_status
-check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
-	struct acpiphp_bridge *bridge;
-	char objname[64];
-	struct acpi_buffer buffer = { .length = sizeof(objname),
-				      .pointer = objname };
-
-	bridge = acpiphp_handle_to_bridge(handle);
-	if (bridge) {
-		acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-		dbg("%s: re-enumerating slots under %s\n",
-			__func__, objname);
-		acpiphp_check_bridge(bridge);
-		put_bridge(bridge);
-	}
-	return AE_OK ;
-}
-
 void acpiphp_check_host_bridge(acpi_handle handle)
 {
 	struct acpiphp_bridge *bridge;
@@ -816,9 +797,6 @@ void acpiphp_check_host_bridge(acpi_hand
 		acpiphp_check_bridge(bridge);
 		put_bridge(bridge);
 	}
-
-	acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
-		ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL);
 }
 
 static void hotplug_event(acpi_handle handle, u32 type, void *data)
@@ -846,9 +824,6 @@ static void hotplug_event(acpi_handle ha
 		dbg("%s: re-enumerating slots under %s\n", __func__, objname);
 		if (bridge) {
 			acpiphp_check_bridge(bridge);
-			acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
-					    ACPI_UINT32_MAX, check_sub_bridges,
-					    NULL, NULL, NULL);
 		} else {
 			struct acpiphp_slot *slot = func->slot;
 

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

* Re: [PATCH 1/30] ACPI / PCI: Make bus registration and unregistration symmetric
  2013-07-17 23:15     ` [PATCH 1/30] ACPI / PCI: Make bus registration and unregistration symmetric Rafael J. Wysocki
@ 2013-07-18  1:00       ` Yinghai Lu
  0 siblings, 0 replies; 135+ messages in thread
From: Yinghai Lu @ 2013-07-18  1:00 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Wed, Jul 17, 2013 at 4:15 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> 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 |    6 ++++--
>  drivers/pci/pci-acpi.c             |   16 ++++------------
>  include/linux/pci-acpi.h           |   10 ++++------
>  4 files changed, 21 insertions(+), 25 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
> @@ -1147,14 +1147,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 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;

Acked-by: Yinghai Lu <yinghai@kernel.org>

>
>         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] 135+ messages in thread

* Re: [PATCH 2/30] ACPI / hotplug / PCI: Consolidate acpiphp_enumerate_slots()
  2013-07-17 23:16     ` [PATCH 2/30] ACPI / hotplug / PCI: Consolidate acpiphp_enumerate_slots() Rafael J. Wysocki
@ 2013-07-18  1:40       ` Yinghai Lu
  2013-07-18 19:09         ` Rafael J. Wysocki
  0 siblings, 1 reply; 135+ messages in thread
From: Yinghai Lu @ 2013-07-18  1:40 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Wed, Jul 17, 2013 at 4:16 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> 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 |   92 ++++++++++++++++++-------------------
>  1 file changed, 45 insertions(+), 47 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
> @@ -353,46 +353,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)
> @@ -1149,8 +1109,9 @@ static void handle_hotplug_event_func(ac
>   */
>  void acpiphp_enumerate_slots(struct pci_bus *bus)
>  {
> -       acpi_handle handle;
>         struct acpiphp_bridge *bridge;
> +       acpi_handle handle;
> +       acpi_status status;
>
>         if (acpiphp_disabled)
>                 return;
> @@ -1178,14 +1139,51 @@ void acpiphp_enumerate_slots(struct pci_
>          */
>         get_device(&bus->dev);
>
> -       if (!pci_is_root_bus(bridge->pci_bus) &&
> -           acpi_has_method(bridge->handle, "_EJ0")) {
> -               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;
> +       }
> +
> +       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;
>         }
>
> -       init_bridge_misc(bridge);
> +       if (!acpi_has_method(bridge->handle, "_EJ0"))
> +               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");
> +       }

looks little weird that you change to install bridge notifier handler and remove
bridge func notifier handler.
actually these two handles is the same one.

I would prefer to keeping the old sequence.

Yinghai

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

* Re: [PATCH 4/30] ACPI / hotplug / PCI: Hotplug context objects for bridges and functions
  2013-07-17 23:17     ` [PATCH 4/30] ACPI / hotplug / PCI: Hotplug context objects for bridges and functions Rafael J. Wysocki
@ 2013-07-18  2:00       ` Yinghai Lu
  2013-07-18 19:04         ` Rafael J. Wysocki
  0 siblings, 1 reply; 135+ messages in thread
From: Yinghai Lu @ 2013-07-18  2:00 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Wed, Jul 17, 2013 at 4:17 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>
> When either a new hotplug bridge 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 |  179 ++++++++++++++++++++++++++++---------
>  2 files changed, 146 insertions(+), 43 deletions(-)

no, more lines are added.

>
> 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;
> @@ -128,6 +131,13 @@ struct acpiphp_func {
>         u32             flags;          /* see below */
>  };
>
> +struct acpiphp_context {
> +       acpi_handle handle;
> +       struct acpiphp_func *func;
> +       struct acpiphp_bridge *bridge;
> +       unsigned int refcount;
> +};
> +
>  /*
>   * 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
> @@ -55,6 +55,7 @@
>
>  static LIST_HEAD(bridge_list);
>  static DEFINE_MUTEX(bridge_mutex);
> +static DEFINE_MUTEX(acpiphp_context_lock);
>
>  #define MY_NAME "acpiphp_glue"
>
> @@ -79,6 +80,74 @@ is_pci_dock_device(acpi_handle handle, u
>         }
>  }
>
> +static void acpiphp_context_handler(acpi_handle handle, void *context)
> +{
> +       /* Intentionally empty. */
> +}
> +
> +/**
> + * acpiphp_init_context - Create hotplug context and grab a reference to it.
> + * @handle: ACPI object handle to create the context for.
> + *
> + * Call under acpiphp_context_lock.
> + */
> +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;
> +       context->refcount = 1;
> +       status = acpi_attach_data(handle, acpiphp_context_handler, context);
> +       if (ACPI_FAILURE(status)) {
> +               kfree(context);
> +               return NULL;
> +       }
> +       return context;
> +}
> +
> +/**
> + * acpiphp_get_context - Get hotplug context and grab a reference to it.
> + * @handle: ACPI object handle to get the context for.
> + *
> + * Call under acpiphp_context_lock.
> + */
> +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;
> +               context->refcount++;
> +       }
> +       return context;
> +}
> +
> +/**
> + * acpiphp_put_context - Drop a reference to ACPI hotplug context.
> + * @handle: ACPI object handle to put the context for.
> + *
> + * The context object is removed if there are no more references to it.
> + *
> + * Call under acpiphp_context_lock.
> + */
> +static void acpiphp_put_context(struct acpiphp_context *context)
> +{
> +       if (--context->refcount)
> +               return;
> +
> +       WARN_ON(context->func || context->bridge);
> +       acpi_detach_data(context->handle, acpiphp_context_handler);
> +       kfree(context);
> +}
> +
>  static inline void get_bridge(struct acpiphp_bridge *bridge)
>  {
>         kref_get(&bridge->ref);
> @@ -91,25 +160,37 @@ 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;
>
> +       mutex_lock(&acpiphp_context_lock);
> +
>         bridge = container_of(kref, struct acpiphp_bridge, ref);
>
>         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;
> +                       acpiphp_put_context(context);
>                         kfree(func);
>                 }
>                 kfree(slot);
>         }
>
> -       /* Release reference acquired by acpiphp_bridge_handle_to_function() */
> +       /* Release the 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;
> +       acpiphp_put_context(context);
>         kfree(bridge);
> +
> +       mutex_unlock(&acpiphp_context_lock);
>  }
>
>  /*
> @@ -194,10 +275,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 = data;
> +       struct acpiphp_context *context;
>         struct acpiphp_slot *slot;
>         struct acpiphp_func *newfunc;
>         acpi_status status = AE_OK;
> @@ -230,6 +312,18 @@ register_slot(acpi_handle handle, u32 lv
>         newfunc->handle = handle;
>         newfunc->function = function;
>
> +       mutex_lock(&acpiphp_context_lock);
> +       context = acpiphp_init_context(handle);
> +       if (!context) {
> +               mutex_unlock(&acpiphp_context_lock);
> +               acpi_handle_err(handle, "No hotplug context\n");
> +               kfree(newfunc);
> +               return AE_NOT_EXIST;
> +       }
> +       newfunc->context = context;
> +       context->func = newfunc;
> +       mutex_unlock(&acpiphp_context_lock);
> +
>         if (acpi_has_method(handle, "_EJ0"))
>                 newfunc->flags = FUNC_HAS_EJ0;
>
> @@ -266,8 +360,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;
> @@ -291,7 +385,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;
>                 }
>         }
>
> @@ -329,15 +425,20 @@ 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);
> -       kfree(newfunc);
>
> -       return AE_OK;
> + err_out:
> +       mutex_lock(&acpiphp_context_lock);
> +       context->func = NULL;
> +       acpiphp_put_context(context);
> +       mutex_unlock(&acpiphp_context_lock);
> +       kfree(newfunc);
> +       return status;
>  }
>
>
> @@ -352,32 +453,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;
> @@ -1108,6 +1183,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;
> @@ -1120,8 +1196,8 @@ void acpiphp_enumerate_slots(struct pci_
>                 return;
>
>         bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
> -       if (bridge == NULL) {
> -               err("out of memory\n");
> +       if (!bridge) {
> +               acpi_handle_err(handle, "No memory for bridge object\n");
>                 return;
>         }
>

can you put this change in another patch?

> @@ -1131,6 +1207,21 @@ void acpiphp_enumerate_slots(struct pci_
>         bridge->pci_dev = pci_dev_get(bus->self);
>         bridge->pci_bus = bus;
>
> +       mutex_lock(&acpiphp_context_lock);
> +       context = acpiphp_get_context(handle);
> +       if (!context) {
> +               context = acpiphp_init_context(handle);
> +               if (!context) {
> +                       mutex_unlock(&acpiphp_context_lock);
> +                       acpi_handle_err(handle, "No hotplug context\n");
> +                       kfree(bridge);
> +                       return;
> +               }
> +       }
> +       bridge->context = context;
> +       context->bridge = bridge;
> +       mutex_unlock(&acpiphp_context_lock);
> +
>         /*
>          * Grab a ref to the subordinate PCI bus in case the bus is
>          * removed via PCI core logical hotplug. The ref pins the bus
> @@ -1169,13 +1260,15 @@ void acpiphp_enumerate_slots(struct pci_
>
>         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] 135+ messages in thread

* Re: [PATCH 5/30] ACPI / hotplug / PCI: Unified notify handler for hotplug events
  2013-07-17 23:18     ` [PATCH 5/30] ACPI / hotplug / PCI: Unified notify handler for hotplug events Rafael J. Wysocki
@ 2013-07-18  2:07       ` Yinghai Lu
  2013-07-18 18:59         ` Rafael J. Wysocki
  0 siblings, 1 reply; 135+ messages in thread
From: Yinghai Lu @ 2013-07-18  2:07 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Wed, Jul 17, 2013 at 4:18 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> 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.  Moreover, it fixes a theoretically possible race between
> handle_hotplug_event() and free_bridge() tearing down data structures
> for the same handle.
>
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> ---
>  drivers/pci/hotplug/acpiphp.h      |    1
>  drivers/pci/hotplug/acpiphp_glue.c |  132 ++++++++++++++-----------------------
>  2 files changed, 53 insertions(+), 80 deletions(-)

Can you put this patches in one temp branch ?

Like to check final bits.

Thanks

Yinghai

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

* Re: [PATCH 5/30] ACPI / hotplug / PCI: Unified notify handler for hotplug events
  2013-07-18  2:07       ` Yinghai Lu
@ 2013-07-18 18:59         ` Rafael J. Wysocki
  0 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-18 18:59 UTC (permalink / raw)
  To: Yinghai Lu
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Wednesday, July 17, 2013 07:07:02 PM Yinghai Lu wrote:
> On Wed, Jul 17, 2013 at 4:18 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> > 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.  Moreover, it fixes a theoretically possible race between
> > handle_hotplug_event() and free_bridge() tearing down data structures
> > for the same handle.
> >
> > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > ---
> >  drivers/pci/hotplug/acpiphp.h      |    1
> >  drivers/pci/hotplug/acpiphp_glue.c |  132 ++++++++++++++-----------------------
> >  2 files changed, 53 insertions(+), 80 deletions(-)
> 
> Can you put this patches in one temp branch ?

They are in linux-pm.git/bleeding-edge.

> 
> Like to check final bits.

Sure.

Thanks,
Rafael


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

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

* Re: [PATCH 4/30] ACPI / hotplug / PCI: Hotplug context objects for bridges and functions
  2013-07-18  2:00       ` Yinghai Lu
@ 2013-07-18 19:04         ` Rafael J. Wysocki
  2013-07-18 20:06           ` Rafael J. Wysocki
  0 siblings, 1 reply; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-18 19:04 UTC (permalink / raw)
  To: Yinghai Lu
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Wednesday, July 17, 2013 07:00:33 PM Yinghai Lu wrote:
> On Wed, Jul 17, 2013 at 4:17 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> >
> > When either a new hotplug bridge 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 |  179 ++++++++++++++++++++++++++++---------
> >  2 files changed, 146 insertions(+), 43 deletions(-)
> 
> no, more lines are added.

Well, that's what 'quilt refresh --diffstat' tells me, quite consistently.

Have you actually counted them?

> > 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;
> > @@ -128,6 +131,13 @@ struct acpiphp_func {
> >         u32             flags;          /* see below */
> >  };
> >
> > +struct acpiphp_context {
> > +       acpi_handle handle;
> > +       struct acpiphp_func *func;
> > +       struct acpiphp_bridge *bridge;
> > +       unsigned int refcount;
> > +};
> > +
> >  /*
> >   * 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
> > @@ -55,6 +55,7 @@
> >
> >  static LIST_HEAD(bridge_list);
> >  static DEFINE_MUTEX(bridge_mutex);
> > +static DEFINE_MUTEX(acpiphp_context_lock);
> >
> >  #define MY_NAME "acpiphp_glue"
> >
> > @@ -79,6 +80,74 @@ is_pci_dock_device(acpi_handle handle, u
> >         }
> >  }
> >
> > +static void acpiphp_context_handler(acpi_handle handle, void *context)
> > +{
> > +       /* Intentionally empty. */
> > +}
> > +
> > +/**
> > + * acpiphp_init_context - Create hotplug context and grab a reference to it.
> > + * @handle: ACPI object handle to create the context for.
> > + *
> > + * Call under acpiphp_context_lock.
> > + */
> > +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;
> > +       context->refcount = 1;
> > +       status = acpi_attach_data(handle, acpiphp_context_handler, context);
> > +       if (ACPI_FAILURE(status)) {
> > +               kfree(context);
> > +               return NULL;
> > +       }
> > +       return context;
> > +}
> > +
> > +/**
> > + * acpiphp_get_context - Get hotplug context and grab a reference to it.
> > + * @handle: ACPI object handle to get the context for.
> > + *
> > + * Call under acpiphp_context_lock.
> > + */
> > +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;
> > +               context->refcount++;
> > +       }
> > +       return context;
> > +}
> > +
> > +/**
> > + * acpiphp_put_context - Drop a reference to ACPI hotplug context.
> > + * @handle: ACPI object handle to put the context for.
> > + *
> > + * The context object is removed if there are no more references to it.
> > + *
> > + * Call under acpiphp_context_lock.
> > + */
> > +static void acpiphp_put_context(struct acpiphp_context *context)
> > +{
> > +       if (--context->refcount)
> > +               return;
> > +
> > +       WARN_ON(context->func || context->bridge);
> > +       acpi_detach_data(context->handle, acpiphp_context_handler);
> > +       kfree(context);
> > +}
> > +
> >  static inline void get_bridge(struct acpiphp_bridge *bridge)
> >  {
> >         kref_get(&bridge->ref);
> > @@ -91,25 +160,37 @@ 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;
> >
> > +       mutex_lock(&acpiphp_context_lock);
> > +
> >         bridge = container_of(kref, struct acpiphp_bridge, ref);
> >
> >         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;
> > +                       acpiphp_put_context(context);
> >                         kfree(func);
> >                 }
> >                 kfree(slot);
> >         }
> >
> > -       /* Release reference acquired by acpiphp_bridge_handle_to_function() */
> > +       /* Release the 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;
> > +       acpiphp_put_context(context);
> >         kfree(bridge);
> > +
> > +       mutex_unlock(&acpiphp_context_lock);
> >  }
> >
> >  /*
> > @@ -194,10 +275,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 = data;
> > +       struct acpiphp_context *context;
> >         struct acpiphp_slot *slot;
> >         struct acpiphp_func *newfunc;
> >         acpi_status status = AE_OK;
> > @@ -230,6 +312,18 @@ register_slot(acpi_handle handle, u32 lv
> >         newfunc->handle = handle;
> >         newfunc->function = function;
> >
> > +       mutex_lock(&acpiphp_context_lock);
> > +       context = acpiphp_init_context(handle);
> > +       if (!context) {
> > +               mutex_unlock(&acpiphp_context_lock);
> > +               acpi_handle_err(handle, "No hotplug context\n");
> > +               kfree(newfunc);
> > +               return AE_NOT_EXIST;
> > +       }
> > +       newfunc->context = context;
> > +       context->func = newfunc;
> > +       mutex_unlock(&acpiphp_context_lock);
> > +
> >         if (acpi_has_method(handle, "_EJ0"))
> >                 newfunc->flags = FUNC_HAS_EJ0;
> >
> > @@ -266,8 +360,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;
> > @@ -291,7 +385,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;
> >                 }
> >         }
> >
> > @@ -329,15 +425,20 @@ 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);
> > -       kfree(newfunc);
> >
> > -       return AE_OK;
> > + err_out:
> > +       mutex_lock(&acpiphp_context_lock);
> > +       context->func = NULL;
> > +       acpiphp_put_context(context);
> > +       mutex_unlock(&acpiphp_context_lock);
> > +       kfree(newfunc);
> > +       return status;
> >  }
> >
> >
> > @@ -352,32 +453,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;
> > @@ -1108,6 +1183,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;
> > @@ -1120,8 +1196,8 @@ void acpiphp_enumerate_slots(struct pci_
> >                 return;
> >
> >         bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
> > -       if (bridge == NULL) {
> > -               err("out of memory\n");
> > +       if (!bridge) {
> > +               acpi_handle_err(handle, "No memory for bridge object\n");
> >                 return;
> >         }
> >
> 
> can you put this change in another patch?

Yes, I can, but is it worth it?

> > @@ -1131,6 +1207,21 @@ void acpiphp_enumerate_slots(struct pci_
> >         bridge->pci_dev = pci_dev_get(bus->self);
> >         bridge->pci_bus = bus;
> >
> > +       mutex_lock(&acpiphp_context_lock);
> > +       context = acpiphp_get_context(handle);
> > +       if (!context) {
> > +               context = acpiphp_init_context(handle);
> > +               if (!context) {
> > +                       mutex_unlock(&acpiphp_context_lock);
> > +                       acpi_handle_err(handle, "No hotplug context\n");
> > +                       kfree(bridge);
> > +                       return;
> > +               }
> > +       }
> > +       bridge->context = context;
> > +       context->bridge = bridge;
> > +       mutex_unlock(&acpiphp_context_lock);
> > +
> >         /*
> >          * Grab a ref to the subordinate PCI bus in case the bus is
> >          * removed via PCI core logical hotplug. The ref pins the bus
> > @@ -1169,13 +1260,15 @@ void acpiphp_enumerate_slots(struct pci_
> >
> >         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;
> >
-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

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

* Re: [PATCH 2/30] ACPI / hotplug / PCI: Consolidate acpiphp_enumerate_slots()
  2013-07-18  1:40       ` Yinghai Lu
@ 2013-07-18 19:09         ` Rafael J. Wysocki
  0 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-18 19:09 UTC (permalink / raw)
  To: Yinghai Lu
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Wednesday, July 17, 2013 06:40:10 PM Yinghai Lu wrote:
> On Wed, Jul 17, 2013 at 4:16 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> > 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 |   92 ++++++++++++++++++-------------------
> >  1 file changed, 45 insertions(+), 47 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
> > @@ -353,46 +353,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)
> > @@ -1149,8 +1109,9 @@ static void handle_hotplug_event_func(ac
> >   */
> >  void acpiphp_enumerate_slots(struct pci_bus *bus)
> >  {
> > -       acpi_handle handle;
> >         struct acpiphp_bridge *bridge;
> > +       acpi_handle handle;
> > +       acpi_status status;
> >
> >         if (acpiphp_disabled)
> >                 return;
> > @@ -1178,14 +1139,51 @@ void acpiphp_enumerate_slots(struct pci_
> >          */
> >         get_device(&bus->dev);
> >
> > -       if (!pci_is_root_bus(bridge->pci_bus) &&
> > -           acpi_has_method(bridge->handle, "_EJ0")) {
> > -               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;
> > +       }
> > +
> > +       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;
> >         }
> >
> > -       init_bridge_misc(bridge);
> > +       if (!acpi_has_method(bridge->handle, "_EJ0"))
> > +               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");
> > +       }
> 
> looks little weird that you change to install bridge notifier handler and remove
> bridge func notifier handler.
> actually these two handles is the same one.
> 
> I would prefer to keeping the old sequence.

First, it doesn't matter because one of the notifiers goes away in the
subsequent patches and it would complicate those patches without any real
reason if I did that.

Second, it doesn't matter because there can be multiple notify handlers for the
same handle and if one of the above two triggers, the second one won't really
do anything.

So no, I'm not going to do that, sorry.

Thanks,
Rafael


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

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

* Re: [PATCH 4/30] ACPI / hotplug / PCI: Hotplug context objects for bridges and functions
  2013-07-18 19:04         ` Rafael J. Wysocki
@ 2013-07-18 20:06           ` Rafael J. Wysocki
  0 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-18 20:06 UTC (permalink / raw)
  To: Yinghai Lu
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Thursday, July 18, 2013 09:04:11 PM Rafael J. Wysocki wrote:
> On Wednesday, July 17, 2013 07:00:33 PM Yinghai Lu wrote:
> > On Wed, Jul 17, 2013 at 4:17 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> > > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > >
> > > When either a new hotplug bridge 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 |  179 ++++++++++++++++++++++++++++---------
> > >  2 files changed, 146 insertions(+), 43 deletions(-)
> > 
> > no, more lines are added.
> 
> Well, that's what 'quilt refresh --diffstat' tells me, quite consistently.
> 
> Have you actually counted them?

Now I have done that (using "grep '^+' | wc -l") and that indeed turns out ot
the right number.

What gives?

Rafael


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

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

* Re: [PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds
  2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
                       ` (29 preceding siblings ...)
  2013-07-17 23:36     ` [PATCH 30/30] ACPI / hotplug / PCI: Get rid of check_sub_bridges() Rafael J. Wysocki
@ 2013-07-23  6:49     ` Yinghai Lu
  2013-07-23 21:39       ` Rafael J. Wysocki
  30 siblings, 1 reply; 135+ messages in thread
From: Yinghai Lu @ 2013-07-23  6:49 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Wed, Jul 17, 2013 at 4:05 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> Hi All,
>
> Now the series has been rebased on top of current linux-pm.git/linux-next
> and tested on two systems with Thunderbolt.  Some changes have been made too. ->
>
> On Friday, July 12, 2013 01:34:20 AM Rafael J. Wysocki wrote:
>> Hi,
>>
>> I've made some progress with my ACPIPHP rework since I posted the series last
>> time and here goes an update.
>>
>> First off, the previous series was somewhat racy, which should be fixed now.
>> Apart from this there's quite some new material on top of the patches I posted
>> last time (or rather on top of their new versions) and I integrated the
>> Thunderbolt series from Mika with that.  As a result,
>>
>> https://patchwork.kernel.org/patch/2817341/
>>
>> is required to be applied.
>>
>> Still untested, still based on 3.10 with ACPI+PM 3.11 material merged on top,
>> but this time I don't have any plans to add more patches to the series for the
>> time being.  Also 3.11-rc1 should be out in a couple of days, so I'll be able
>> to integrate this work with the previous cleanups series from Gerry and myself
>> on top of it.
>>
>> I did my best not to change too much at a time and some steps add stuff that
>> is removed by the subsequent ones, so hopefully it is bisectable.
>>
>> If anyone finds something questionable or outright bogus in these patches,
>> please let me know before it's too late. ;-)
>>
>> [ 1/30] Make bus registration and unregistration symmetric.  [Resend]
>> [ 2/30] Consolidate acpiphp_enumerate_slots().  [Resend]
>> [ 3/30] Fix error code path in register_slot().  [Resend]
>> [ 4/30] Introduce hotplug context objects for ACPI device objects corresponding
>>         to PCI hotplug devices.  [Update]
>> [ 5/30] Unified notify handler for hotplug events.  [Update]
>> [ 6/30] Drop acpiphp_handle_to_bridge() and use context objects instead of it.  [Update]
>> [ 7/30] Pass entire hotplug context objects (instead of their fields
>>         individually) to event handling work functions.  [Update]
>> [ 8/30] Merge hotplug event handling functions.  [Update]
>> [ 9/30] Drop func field from struct acpiphp_bridge.
>> [10/30] Refactor slot allocation code in register_slot().
>> [11/30] Make acpiphp_enumerate_slots() to register all devices on the given bus
>>         and install the notification handler for all of them.
>> [12/30] Drop sun field from struct acpiphp_slot.
>> [13/30] Use common slot count variable in register_slot().
>
> -> The one above has been dropped, because it might cause regressions to appear
> on some systems, but that's not a big deal.
>
> The numbering of the patches below has changed as a result, so the next one is
> [13/30] now and so on.
>
>> [14/30] Drop flags field from struct acpiphp_bridge.
>> [15/30] Embed function structure into struct acpiphp_context.
>> [16/30] Drop handle field from struct acpiphp_func.
>> [17/30] Drop handle field from struct acpiphp_bridge.
>> [18/30] Store parent bridge pointer in function objects and bus pointer in slot
>>         objects.
>> [19/30] Rework ACPI namespace scanning and trimming routines.
>> [20/30] Drop redundant checks from check_hotplug_bridge().
>> [21/30] Consolidate slot disabling and ejecting
>> [22/30] Do not queue up event handling work items for non-hotplug events.
>> [23/30] Do not execute _PS0 and _PS3 directly.
>
> This one was fixed after Mika had reported a problem with it.
>
>> [24/30] Do not check SLOT_ENABLED in enable_device().  [Thunderbolt series]
>> [25/30] Allow slots without new devices to be rescanned.  [Thunderbolt series]
>> [26/30] Check for new devices on enabled slots.  [Thunderbolt series, TBD]
>
> This one was reworked to use acpi_bus_trim() on ACPI device objects
> corresponding to PCI devices being removed (it also uses _STA to check the
> status of those devices if available).
>
>> [27/30] Get rid of unused constands in acpiphp.h.  [Thunderbolt series]
>> [28/30] Sanitize acpiphp_get_(latch)|(adapter)_status().  [Thunderbolt series]
>> [29/30] Redefine enable_device() and disable_device() (rename and change to void).
>> [30/30] Clean up the usage of bridge_mutex.
>
> The one above is [29/30] now and we have added one more patch:
>
> [30/30] Drop check_sub_bridges() which isn't necessary any more.
>
> The updated patches follow.
>
> If you don't hate this stuff, I'll put it into linux-next over the weekend for
> further testing.

pm/linux-next with those patches breaks acpi root bus hotplug.
it is kvm guest:

10:~ # echo "PCI0 3" > /sys/kernel/debug/acpi/sci_notify
[   92.549508] ACPI: ACPI device name is <PCI0>, event code is <3>
[   92.552433] ACPI: Notify event is queued
10:~ # [   92.554279] ACPI: \_SB_.PCI0: Device eject notify on
_handle_hotplug_event_root
[   92.677696] ACPI: Device 0000:00:03.0 -x-> \_SB_.PCI0.S03_
[   92.679229] ACPI: Device 0000:00:02.0 -x-> \_SB_.PCI0.VGA_
[   92.680684] ACPI: Device 0000:00:01.3 -x-> \_SB_.PCI0.PX13
[   92.682235] ata1.00: disabled
[   92.689000] sd 0:0:0:0: [sda] Synchronizing SCSI cache
[   92.690399] sd 0:0:0:0: [sda]
[   92.691133] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK
[   92.693151] sd 0:0:0:0: [sda] Stopping disk
[   92.694682] sd 0:0:0:0: [sda] START_STOP FAILED
[   92.696749] sd 0:0:0:0: [sda]
[   92.698157] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK
[   92.702852] ata2.00: disabled
[   92.711550] ACPI: Device 0000:00:01.0 -x-> \_SB_.PCI0.ISA_
[   92.713208] ACPI: Device pci0000:00 -x-> \_SB_.PCI0
[   92.713226]   acpi_pci_iommu_remove is called for \_SB_.PCI0 ffff88007ab3f1e0
[   92.713274]   acpi_pci_ioapic_remove is called for \_SB_.PCI0
ffff88007ab3f1e0
[   92.713345] pci 0000:00:00.0: freeing pci_dev info
[   92.713363] pci 0000:00:01.0: freeing pci_dev info
[   92.713366] pci 0000:00:01.1: freeing pci_dev info
[   92.713376] pci 0000:00:01.3: freeing pci_dev info
[   92.713380] pci 0000:00:02.0: freeing pci_dev info
[   92.713384] pci 0000:00:03.0: freeing pci_dev info
[   92.713396] pci_bus 0000:00: busn_res: [bus 00-ff] is released
[   92.713441] BUG: unable to handle kernel NULL pointer dereference
at           (null)
[   92.713446] IP: [<ffffffff81557910>]
acpiphp_unregister_hotplug_slot+0x20/0x60
[   92.713448] PGD 0
[   92.713449] Oops: 0000 [#1] SMP
[   92.713451] Modules linked in:
[   92.713453] CPU: 0 PID: 1042 Comm: kworker/0:1 Not tainted
3.11.0-rc2-yh-00277-gaaf9c19-dirty #1818
[   92.713454] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011
[   92.713458] Workqueue: kacpi_hotplug acpi_os_execute_deferred
[   92.713459] task: ffff88007a0ecb40 ti: ffff88007a72a000 task.ti:
ffff88007a72a000
[   92.713461] RIP: 0010:[<ffffffff81557910>]  [<ffffffff81557910>]
acpiphp_unregister_hotplug_slot+0x20/0x60
[   92.713462] RSP: 0018:ffff88007a72bb28  EFLAGS: 00010296
[   92.713463] RAX: ffff88007a774e18 RBX: 0000000000000000 RCX: 0000000000000004
[   92.713463] RDX: ffffffff822ab080 RSI: ffffffff8284eaef RDI: ffffffff8284eb13
[   92.713464] RBP: ffff88007a72bb38 R08: 0000000000000000 R09: 0000000000000000
[   92.713465] R10: 0000000000000000 R11: 0000000000000001 R12: ffff88007a774e18
[   92.713465] R13: ffff88007a774e00 R14: ffff88007a148f70 R15: ffff88007a774e08
[   92.713466] FS:  0000000000000000(0000) GS:ffff88007b800000(0000)
knlGS:0000000000000000
[   92.713467] CS:  0010 DS: 0000 ES: 0000 CR0: 000000008005003b
[   92.713470] CR2: 0000000000000000 CR3: 00000000794fc000 CR4: 00000000000006f0
[   92.713474] Stack:
[   92.713476]  ffff88007a148f70 ffff88007ab43cd0 ffff88007a72bb88
ffffffff81557ae0
[   92.713478]  ffff88007a72bb78 ffff88007a148f60 ffffffff8153574e
ffff88007a148f60
[   92.713479]  ffff88007a07d000 ffff88007a07d028 ffff88007a07d800
ffff88007a325298
[   92.713480] Call Trace:
[   92.713482]  [<ffffffff81557ae0>] cleanup_bridge+0x80/0xf0
[   92.713485]  [<ffffffff8153574e>] ? pci_remove_bus+0x3e/0x60
[   92.713487]  [<ffffffff81558b1d>] acpiphp_remove_slots+0x5d/0xa0
[   92.713489]  [<ffffffff8155d48a>] acpi_pci_remove_bus+0x2a/0x40
[   92.713493]  [<ffffffff81f7bf9e>] pcibios_remove_bus+0xe/0x10
[   92.713494]  [<ffffffff81535756>] pci_remove_bus+0x46/0x60
[   92.713496]  [<ffffffff81535900>] pci_remove_root_bus+0x50/0xa0
[   92.713499]  [<ffffffff81595596>] acpi_pci_root_remove+0x52/0x5f
[   92.713501]  [<ffffffff81590a0f>] acpi_bus_device_detach+0x3d/0x5e
[   92.713503]  [<ffffffff81590a72>] acpi_bus_trim+0x42/0x7a
[   92.713505]  [<ffffffff8159104e>] acpi_scan_hot_remove+0x194/0x23b
[   92.713507]  [<ffffffff815911f4>] acpi_bus_hot_remove_device+0x2f/0x66
[   92.713509]  [<ffffffff8158b60b>] acpi_os_execute_deferred+0x25/0x32
[   92.713513]  [<ffffffff810b7ffb>] process_one_work+0x28b/0x490
[   92.713515]  [<ffffffff810b7f72>] ? process_one_work+0x202/0x490
[   92.713517]  [<ffffffff810b94ce>] worker_thread+0x21e/0x370
[   92.713521]  [<ffffffff810fdafd>] ? trace_hardirqs_on+0xd/0x10
[   92.713523]  [<ffffffff810b92b0>] ? manage_workers.isra.18+0x330/0x330
[   92.713526]  [<ffffffff810c0aa8>] kthread+0xe8/0xf0
[   92.713528]  [<ffffffff810c09c0>] ? __init_kthread_worker+0x70/0x70
[   92.713531]  [<ffffffff820d991c>] ret_from_fork+0x7c/0xb0
[   92.713533]  [<ffffffff810c09c0>] ? __init_kthread_worker+0x70/0x70
[   92.713549] Code: 66 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00
55 48 c7 c6 ef ea 84 82 48 89 e5 53 48 83 ec 08 48 8b 5f 28 48 c7 c7
13 eb 84 82 <48> 8b 03 48 8b 40 30 48 8b 50 28 31 c0 e8 f7 dd b5 00 48
8b 3b
[   92.713551] RIP  [<ffffffff81557910>]
acpiphp_unregister_hotplug_slot+0x20/0x60
[   92.713552]  RSP <ffff88007a72bb28>
[   92.713552] CR2: 0000000000000000
[   92.713554] ---[ end trace 9e3bba504fb5e5d4 ]---
[   92.713589] BUG: unable to handle kernel paging request at ffffffffffffff98
[   92.713591] IP: [<ffffffff810c0e30>] kthread_data+0x10/0x20
[   92.713593] PGD 2a15067 PUD 2a17067 PMD 0
[   92.713594] Oops: 0000 [#2] SMP
[   92.713595] Modules linked in:
[   92.713596] CPU: 0 PID: 1042 Comm: kworker/0:1 Tainted: G      D
  3.11.0-rc2-yh-00277-gaaf9c19-dirty #1818
[   92.713597] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011
[   92.713604] task: ffff88007a0ecb40 ti: ffff88007a72a000 task.ti:
ffff88007a72a000
[   92.713606] RIP: 0010:[<ffffffff810c0e30>]  [<ffffffff810c0e30>]
kthread_data+0x10/0x20
[   92.713607] RSP: 0018:ffff88007a72b648  EFLAGS: 00010092
[   92.713607] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000008
[   92.713608] RDX: 0000000000000006 RSI: 0000000000000000 RDI: ffff88007a0ecb40
[   92.713608] RBP: ffff88007a72b648 R08: ffff88007a0ecbb0 R09: 0000000000000000
[   92.713609] R10: 0000000000000000 R11: 000000159620c258 R12: ffff88007b9d3e80
[   92.713610] R13: 0000000000000000 R14: 0000000000000001 R15: ffff88007a0ecb40
[   92.713611] FS:  0000000000000000(0000) GS:ffff88007b800000(0000)
knlGS:0000000000000000
[   92.713612] CS:  0010 DS: 0000 ES: 0000 CR0: 000000008005003b
[   92.713615] CR2: 0000000000000028 CR3: 00000000794fc000 CR4: 00000000000006f0
[   92.713618] Stack:
[   92.713620]  ffff88007a72b668 ffffffff810b9a15 ffff88007a72b668
ffff88007a0ed168
[   92.713621]  ffff88007a72b788 ffffffff820ce2f4 ffff88007a72b6c8
ffff88007a72bfd8
[   92.713623]  ffff88007a72bfd8 0000000000004000 ffff88007a0ecb40
ffff88007a0ecb40
[   92.713623] Call Trace:
[   92.713625]  [<ffffffff810b9a15>] wq_worker_sleeping+0x15/0xa0
[   92.713627]  [<ffffffff820ce2f4>] __schedule+0x154/0xa60
[   92.713629]  [<ffffffff810fdafd>] ? trace_hardirqs_on+0xd/0x10
[   92.713632]  [<ffffffff814e540a>] ? put_io_context+0x9a/0xb0
[   92.713633]  [<ffffffff814e547b>] ? put_io_context_active+0x5b/0xd0
[   92.713635]  [<ffffffff820cecfd>] schedule+0x5d/0x60
[   92.713638]  [<ffffffff8109def5>] do_exit+0x935/0x990
[   92.713640]  [<ffffffff820d20e8>] oops_end+0xc8/0xe0
[   92.713643]  [<ffffffff820b4fbc>] no_context+0x261/0x28c
[   92.713645]  [<ffffffff820b51ac>] __bad_area_nosemaphore+0x1c5/0x1e4
[   92.713646]  [<ffffffff820b51de>] bad_area_nosemaphore+0x13/0x15
[   92.713649]  [<ffffffff820d505e>] __do_page_fault+0x4be/0x550
[   92.713651]  [<ffffffff810d41e5>] ? sched_clock_local+0x25/0xa0
[   92.713653]  [<ffffffff810f9fc8>] ? trace_hardirqs_off_caller+0x28/0x160
[   92.713655]  [<ffffffff810fd876>] ? mark_held_locks+0x136/0x150
[   92.713657]  [<ffffffff810c673b>] ? up+0x4b/0x60
[   92.713659]  [<ffffffff820d5127>] do_page_fault+0x37/0x60
[   92.713660]  [<ffffffff820d128c>] ? restore_args+0x30/0x30
[   92.713662]  [<ffffffff820d1462>] page_fault+0x22/0x30
[   92.713664]  [<ffffffff81557910>] ? acpiphp_unregister_hotplug_slot+0x20/0x60
[   92.713667]  [<ffffffff81557ae0>] cleanup_bridge+0x80/0xf0
[   92.713669]  [<ffffffff8153574e>] ? pci_remove_bus+0x3e/0x60
[   92.713671]  [<ffffffff81558b1d>] acpiphp_remove_slots+0x5d/0xa0
[   92.713673]  [<ffffffff8155d48a>] acpi_pci_remove_bus+0x2a/0x40
[   92.713676]  [<ffffffff81f7bf9e>] pcibios_remove_bus+0xe/0x10
[   92.713678]  [<ffffffff81535756>] pci_remove_bus+0x46/0x60
[   92.713681]  [<ffffffff81535900>] pci_remove_root_bus+0x50/0xa0
[   92.713683]  [<ffffffff81595596>] acpi_pci_root_remove+0x52/0x5f
[   92.713685]  [<ffffffff81590a0f>] acpi_bus_device_detach+0x3d/0x5e
[   92.713687]  [<ffffffff81590a72>] acpi_bus_trim+0x42/0x7a
[   92.713690]  [<ffffffff8159104e>] acpi_scan_hot_remove+0x194/0x23b
[   92.713692]  [<ffffffff815911f4>] acpi_bus_hot_remove_device+0x2f/0x66
[   92.713695]  [<ffffffff8158b60b>] acpi_os_execute_deferred+0x25/0x32
[   92.713697]  [<ffffffff810b7ffb>] process_one_work+0x28b/0x490
[   92.713699]  [<ffffffff810b7f72>] ? process_one_work+0x202/0x490
[   92.713701]  [<ffffffff810b94ce>] worker_thread+0x21e/0x370
[   92.713704]  [<ffffffff810fdafd>] ? trace_hardirqs_on+0xd/0x10
[   92.713706]  [<ffffffff810b92b0>] ? manage_workers.isra.18+0x330/0x330
[   92.713708]  [<ffffffff810c0aa8>] kthread+0xe8/0xf0
[   92.713710]  [<ffffffff810c09c0>] ? __init_kthread_worker+0x70/0x70
[   92.713712]  [<ffffffff820d991c>] ret_from_fork+0x7c/0xb0
[   92.713713]  [<ffffffff810c09c0>] ? __init_kthread_worker+0x70/0x70
[   92.713728] Code: 00 48 89 e5 5d 48 8b 40 88 48 c1 e8 02 83 e0 01
c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 8b 87 70 05 00 00
55 48 89 e5 <48> 8b 40 98 5d c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44
00 00
[   92.713730] RIP  [<ffffffff810c0e30>] kthread_data+0x10/0x20
[   92.713730]  RSP <ffff88007a72b648>
[   92.713731] CR2: ffffffffffffff98
[   92.713732] ---[ end trace 9e3bba504fb5e5d5 ]---
[   92.713732] Fixing recursive fault but reboot is needed!

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

* Re: [PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds
  2013-07-23  6:49     ` [PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Yinghai Lu
@ 2013-07-23 21:39       ` Rafael J. Wysocki
  2013-07-24  2:20         ` Yinghai Lu
  0 siblings, 1 reply; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-23 21:39 UTC (permalink / raw)
  To: Yinghai Lu
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Monday, July 22, 2013 11:49:45 PM Yinghai Lu wrote:
> On Wed, Jul 17, 2013 at 4:05 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> > Hi All,
> >
> > Now the series has been rebased on top of current linux-pm.git/linux-next
> > and tested on two systems with Thunderbolt.  Some changes have been made too. ->
> >
> > On Friday, July 12, 2013 01:34:20 AM Rafael J. Wysocki wrote:
> >> Hi,
> >>
> >> I've made some progress with my ACPIPHP rework since I posted the series last
> >> time and here goes an update.
> >>
> >> First off, the previous series was somewhat racy, which should be fixed now.
> >> Apart from this there's quite some new material on top of the patches I posted
> >> last time (or rather on top of their new versions) and I integrated the
> >> Thunderbolt series from Mika with that.  As a result,
> >>
> >> https://patchwork.kernel.org/patch/2817341/
> >>
> >> is required to be applied.
> >>
> >> Still untested, still based on 3.10 with ACPI+PM 3.11 material merged on top,
> >> but this time I don't have any plans to add more patches to the series for the
> >> time being.  Also 3.11-rc1 should be out in a couple of days, so I'll be able
> >> to integrate this work with the previous cleanups series from Gerry and myself
> >> on top of it.
> >>
> >> I did my best not to change too much at a time and some steps add stuff that
> >> is removed by the subsequent ones, so hopefully it is bisectable.
> >>
> >> If anyone finds something questionable or outright bogus in these patches,
> >> please let me know before it's too late. ;-)
> >>
> >> [ 1/30] Make bus registration and unregistration symmetric.  [Resend]
> >> [ 2/30] Consolidate acpiphp_enumerate_slots().  [Resend]
> >> [ 3/30] Fix error code path in register_slot().  [Resend]
> >> [ 4/30] Introduce hotplug context objects for ACPI device objects corresponding
> >>         to PCI hotplug devices.  [Update]
> >> [ 5/30] Unified notify handler for hotplug events.  [Update]
> >> [ 6/30] Drop acpiphp_handle_to_bridge() and use context objects instead of it.  [Update]
> >> [ 7/30] Pass entire hotplug context objects (instead of their fields
> >>         individually) to event handling work functions.  [Update]
> >> [ 8/30] Merge hotplug event handling functions.  [Update]
> >> [ 9/30] Drop func field from struct acpiphp_bridge.
> >> [10/30] Refactor slot allocation code in register_slot().
> >> [11/30] Make acpiphp_enumerate_slots() to register all devices on the given bus
> >>         and install the notification handler for all of them.
> >> [12/30] Drop sun field from struct acpiphp_slot.
> >> [13/30] Use common slot count variable in register_slot().
> >
> > -> The one above has been dropped, because it might cause regressions to appear
> > on some systems, but that's not a big deal.
> >
> > The numbering of the patches below has changed as a result, so the next one is
> > [13/30] now and so on.
> >
> >> [14/30] Drop flags field from struct acpiphp_bridge.
> >> [15/30] Embed function structure into struct acpiphp_context.
> >> [16/30] Drop handle field from struct acpiphp_func.
> >> [17/30] Drop handle field from struct acpiphp_bridge.
> >> [18/30] Store parent bridge pointer in function objects and bus pointer in slot
> >>         objects.
> >> [19/30] Rework ACPI namespace scanning and trimming routines.
> >> [20/30] Drop redundant checks from check_hotplug_bridge().
> >> [21/30] Consolidate slot disabling and ejecting
> >> [22/30] Do not queue up event handling work items for non-hotplug events.
> >> [23/30] Do not execute _PS0 and _PS3 directly.
> >
> > This one was fixed after Mika had reported a problem with it.
> >
> >> [24/30] Do not check SLOT_ENABLED in enable_device().  [Thunderbolt series]
> >> [25/30] Allow slots without new devices to be rescanned.  [Thunderbolt series]
> >> [26/30] Check for new devices on enabled slots.  [Thunderbolt series, TBD]
> >
> > This one was reworked to use acpi_bus_trim() on ACPI device objects
> > corresponding to PCI devices being removed (it also uses _STA to check the
> > status of those devices if available).
> >
> >> [27/30] Get rid of unused constands in acpiphp.h.  [Thunderbolt series]
> >> [28/30] Sanitize acpiphp_get_(latch)|(adapter)_status().  [Thunderbolt series]
> >> [29/30] Redefine enable_device() and disable_device() (rename and change to void).
> >> [30/30] Clean up the usage of bridge_mutex.
> >
> > The one above is [29/30] now and we have added one more patch:
> >
> > [30/30] Drop check_sub_bridges() which isn't necessary any more.
> >
> > The updated patches follow.
> >
> > If you don't hate this stuff, I'll put it into linux-next over the weekend for
> > further testing.
> 
> pm/linux-next with those patches breaks acpi root bus hotplug.
> it is kvm guest:
> 
> 10:~ # echo "PCI0 3" > /sys/kernel/debug/acpi/sci_notify
> [   92.549508] ACPI: ACPI device name is <PCI0>, event code is <3>
> [   92.552433] ACPI: Notify event is queued
> 10:~ # [   92.554279] ACPI: \_SB_.PCI0: Device eject notify on
> _handle_hotplug_event_root
> [   92.677696] ACPI: Device 0000:00:03.0 -x-> \_SB_.PCI0.S03_
> [   92.679229] ACPI: Device 0000:00:02.0 -x-> \_SB_.PCI0.VGA_
> [   92.680684] ACPI: Device 0000:00:01.3 -x-> \_SB_.PCI0.PX13
> [   92.682235] ata1.00: disabled
> [   92.689000] sd 0:0:0:0: [sda] Synchronizing SCSI cache
> [   92.690399] sd 0:0:0:0: [sda]
> [   92.691133] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK
> [   92.693151] sd 0:0:0:0: [sda] Stopping disk
> [   92.694682] sd 0:0:0:0: [sda] START_STOP FAILED
> [   92.696749] sd 0:0:0:0: [sda]
> [   92.698157] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK
> [   92.702852] ata2.00: disabled
> [   92.711550] ACPI: Device 0000:00:01.0 -x-> \_SB_.PCI0.ISA_
> [   92.713208] ACPI: Device pci0000:00 -x-> \_SB_.PCI0
> [   92.713226]   acpi_pci_iommu_remove is called for \_SB_.PCI0 ffff88007ab3f1e0
> [   92.713274]   acpi_pci_ioapic_remove is called for \_SB_.PCI0
> ffff88007ab3f1e0
> [   92.713345] pci 0000:00:00.0: freeing pci_dev info
> [   92.713363] pci 0000:00:01.0: freeing pci_dev info
> [   92.713366] pci 0000:00:01.1: freeing pci_dev info
> [   92.713376] pci 0000:00:01.3: freeing pci_dev info
> [   92.713380] pci 0000:00:02.0: freeing pci_dev info
> [   92.713384] pci 0000:00:03.0: freeing pci_dev info
> [   92.713396] pci_bus 0000:00: busn_res: [bus 00-ff] is released
> [   92.713441] BUG: unable to handle kernel NULL pointer dereference
> at           (null)
> [   92.713446] IP: [<ffffffff81557910>]
> acpiphp_unregister_hotplug_slot+0x20/0x60

Ugh, stupid bug, sorry about it.  We try to unregister something that may have
not been registered.

Can you please check if the appended patch helps (on top of
linux-pm.git/linux-next)?

Rafael


---
 drivers/pci/hotplug/acpiphp_glue.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

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
@@ -340,6 +340,7 @@ static acpi_status register_slot(acpi_ha
 
 		retval = acpiphp_register_hotplug_slot(slot, sun);
 		if (retval) {
+			slot->slot = NULL;
 			bridge->nr_slots--;
 			if (retval == -EBUSY)
 				warn("Slot %llu already registered by another "
@@ -429,7 +430,8 @@ static void cleanup_bridge(struct acpiph
 					err("failed to remove notify handler\n");
 			}
 		}
-		acpiphp_unregister_hotplug_slot(slot);
+		if (slot->slot)
+			acpiphp_unregister_hotplug_slot(slot);
 	}
 
 	mutex_lock(&bridge_mutex);


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

* Re: [PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds
  2013-07-23 21:39       ` Rafael J. Wysocki
@ 2013-07-24  2:20         ` Yinghai Lu
  2013-07-24 12:22           ` Rafael J. Wysocki
  2013-07-24 12:58           ` Rafael J. Wysocki
  0 siblings, 2 replies; 135+ messages in thread
From: Yinghai Lu @ 2013-07-24  2:20 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Tue, Jul 23, 2013 at 2:39 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
>
> Ugh, stupid bug, sorry about it.  We try to unregister something that may have
> not been registered.
>
> Can you please check if the appended patch helps (on top of
> linux-pm.git/linux-next)?
>
> Rafael
>
>
> ---
>  drivers/pci/hotplug/acpiphp_glue.c |    4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
>
> 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
> @@ -340,6 +340,7 @@ static acpi_status register_slot(acpi_ha
>
>                 retval = acpiphp_register_hotplug_slot(slot, sun);
>                 if (retval) {
> +                       slot->slot = NULL;
>                         bridge->nr_slots--;
>                         if (retval == -EBUSY)
>                                 warn("Slot %llu already registered by another "
> @@ -429,7 +430,8 @@ static void cleanup_bridge(struct acpiph
>                                         err("failed to remove notify handler\n");
>                         }
>                 }
> -               acpiphp_unregister_hotplug_slot(slot);
> +               if (slot->slot)
> +                       acpiphp_unregister_hotplug_slot(slot);
>         }
>
>         mutex_lock(&bridge_mutex);
>

yes, that fixes the problem. Thanks

10:~ # echo "PCI0 3" > /sys/kernel/debug/acpi/sci_notify
[  102.231645] ACPI: ACPI device name is <PCI0>, event code is <3>
[  102.233189] ACPI: Notify event is queued
[  102.234326] ACPI: \_SB_.PCI0: Device eject notify on
_handle_hotplug_event_root
10:~ # [  102.357749] ACPI: Device 0000:00:03.0 -x-> \_SB_.PCI0.S03_
[  102.359902] ACPI: Device 0000:00:02.0 -x-> \_SB_.PCI0.VGA_
[  102.362188] ACPI: Device 0000:00:01.3 -x-> \_SB_.PCI0.PX13
[  102.364752] ata1.00: disabled
[  102.372154] sd 0:0:0:0: [sda] Synchronizing SCSI cache
[  102.374523] sd 0:0:0:0: [sda]
[  102.375759] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK
[  102.378173] sd 0:0:0:0: [sda] Stopping disk
[  102.380248] sd 0:0:0:0: [sda] START_STOP FAILED
[  102.381983] sd 0:0:0:0: [sda]
[  102.383167] Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK
[  102.387588] ata2.00: disabled
[  102.395254] ACPI: Device 0000:00:01.0 -x-> \_SB_.PCI0.ISA_
[  102.396943] ACPI: Device pci0000:00 -x-> \_SB_.PCI0
[  102.398162]   acpi_pci_iommu_remove is called for \_SB_.PCI0 ffff88007ab3f1e0
[  102.400253]   acpi_pci_ioapic_remove is called for \_SB_.PCI0
ffff88007ab3f1e0
[  102.402176] pci 0000:00:00.0: freeing pci_dev info
[  102.404247] pci 0000:00:01.0: freeing pci_dev info
[  102.406611] pci 0000:00:01.1: freeing pci_dev info
[  102.408401] pci 0000:00:01.3: freeing pci_dev info
[  102.410276] pci 0000:00:02.0: freeing pci_dev info
[  102.411378] pci 0000:00:03.0: freeing pci_dev info
[  102.412485] pci_bus 0000:00: busn_res: [bus 00-ff] is released
[  102.413945] acpiphp: Slot [3] unregistered
[  102.415189] pci_hotplug: pci_hp_deregister: Removed slot 3 from the list
[  102.418224] acpiphp: release_slot - physical_slot = 3
[  102.420439] pci_bus 0000:00: dev 03, dec refcount to 1
[  102.422689] acpiphp: Slot [4] unregistered
[  102.424592] pci_hotplug: pci_hp_deregister: Removed slot 4 from the list
[  102.427484] acpiphp: release_slot - physical_slot = 4
[  102.429679] pci_bus 0000:00: dev 04, dec refcount to 1
[  102.431492] acpiphp: Slot [5] unregistered
[  102.433169] pci_hotplug: pci_hp_deregister: Removed slot 5 from the list
[  102.435486] acpiphp: release_slot - physical_slot = 5
[  102.436963] pci_bus 0000:00: dev 05, dec refcount to 1
[  102.438140] acpiphp: Slot [6] unregistered
[  102.439116] pci_hotplug: pci_hp_deregister: Removed slot 6 from the list
[  102.440922] acpiphp: release_slot - physical_slot = 6
[  102.442079] pci_bus 0000:00: dev 06, dec refcount to 1
[  102.443280] acpiphp: Slot [7] unregistered
[  102.444286] pci_hotplug: pci_hp_deregister: Removed slot 7 from the list
[  102.445840] acpiphp: release_slot - physical_slot = 7
[  102.447024] pci_bus 0000:00: dev 07, dec refcount to 1
[  102.448272] acpiphp: Slot [8] unregistered
[  102.449236] pci_hotplug: pci_hp_deregister: Removed slot 8 from the list
[  102.450770] acpiphp: release_slot - physical_slot = 8
[  102.451632] pci_bus 0000:00: dev 08, dec refcount to 1
[  102.452870] acpiphp: Slot [9] unregistered
[  102.453848] pci_hotplug: pci_hp_deregister: Removed slot 9 from the list
[  102.455400] acpiphp: release_slot - physical_slot = 9
[  102.456594] pci_bus 0000:00: dev 09, dec refcount to 1
[  102.457557] acpiphp: Slot [10] unregistered
[  102.458542] pci_hotplug: pci_hp_deregister: Removed slot 10 from the list
[  102.460124] acpiphp: release_slot - physical_slot = 10
[  102.461295] pci_bus 0000:00: dev 0a, dec refcount to 1
[  102.462482] acpiphp: Slot [11] unregistered
[  102.463464] pci_hotplug: pci_hp_deregister: Removed slot 11 from the list
[  102.465046] acpiphp: release_slot - physical_slot = 11
[  102.467024] pci_bus 0000:00: dev 0b, dec refcount to 1
[  102.468199] acpiphp: Slot [12] unregistered
[  102.469210] pci_hotplug: pci_hp_deregister: Removed slot 12 from the list
[  102.470798] acpiphp: release_slot - physical_slot = 12
[  102.471992] pci_bus 0000:00: dev 0c, dec refcount to 1
[  102.473239] acpiphp: Slot [13] unregistered
[  102.473959] pci_hotplug: pci_hp_deregister: Removed slot 13 from the list
[  102.475545] acpiphp: release_slot - physical_slot = 13
[  102.476516] pci_bus 0000:00: dev 0d, dec refcount to 1
[  102.477740] acpiphp: Slot [14] unregistered
[  102.478733] pci_hotplug: pci_hp_deregister: Removed slot 14 from the list
[  102.480319] acpiphp: release_slot - physical_slot = 14
[  102.481296] pci_bus 0000:00: dev 0e, dec refcount to 1
[  102.481947] acpiphp: Slot [15] unregistered
[  102.482888] pci_hotplug: pci_hp_deregister: Removed slot 15 from the list
[  102.484555] acpiphp: release_slot - physical_slot = 15
[  102.485806] pci_bus 0000:00: dev 0f, dec refcount to 1
[  102.486808] acpiphp: Slot [16] unregistered
[  102.487652] pci_hotplug: pci_hp_deregister: Removed slot 16 from the list
[  102.488986] acpiphp: release_slot - physical_slot = 16
[  102.489996] pci_bus 0000:00: dev 10, dec refcount to 1
[  102.491100] acpiphp: Slot [17] unregistered
[  102.492054] pci_hotplug: pci_hp_deregister: Removed slot 17 from the list
[  102.493572] acpiphp: release_slot - physical_slot = 17
[  102.494444] pci_bus 0000:00: dev 11, dec refcount to 1
[  102.495266] acpiphp: Slot [18] unregistered
[  102.495966] pci_hotplug: pci_hp_deregister: Removed slot 18 from the list
[  102.497083] acpiphp: release_slot - physical_slot = 18
[  102.497921] pci_bus 0000:00: dev 12, dec refcount to 1
[  102.498770] acpiphp: Slot [19] unregistered
[  102.499474] pci_hotplug: pci_hp_deregister: Removed slot 19 from the list
[  102.500764] acpiphp: release_slot - physical_slot = 19
[  102.501873] pci_bus 0000:00: dev 13, dec refcount to 1
[  102.502966] acpiphp: Slot [20] unregistered
[  102.503824] pci_hotplug: pci_hp_deregister: Removed slot 20 from the list
[  102.504770] acpiphp: release_slot - physical_slot = 20
[  102.505608] pci_bus 0000:00: dev 14, dec refcount to 1
[  102.506456] acpiphp: Slot [21] unregistered
[  102.507146] pci_hotplug: pci_hp_deregister: Removed slot 21 from the list
[  102.508269] acpiphp: release_slot - physical_slot = 21
[  102.508981] pci_bus 0000:00: dev 15, dec refcount to 1
[  102.509815] acpiphp: Slot [22] unregistered
[  102.510668] pci_hotplug: pci_hp_deregister: Removed slot 22 from the list
[  102.511955] acpiphp: release_slot - physical_slot = 22
[  102.512980] pci_bus 0000:00: dev 16, dec refcount to 1
[  102.514040] acpiphp: Slot [23] unregistered
[  102.514621] pci_hotplug: pci_hp_deregister: Removed slot 23 from the list
[  102.515446] acpiphp: release_slot - physical_slot = 23
[  102.516101] pci_bus 0000:00: dev 17, dec refcount to 1
[  102.516752] acpiphp: Slot [24] unregistered
[  102.517370] pci_hotplug: pci_hp_deregister: Removed slot 24 from the list
[  102.518210] acpiphp: release_slot - physical_slot = 24
[  102.518841] pci_bus 0000:00: dev 18, dec refcount to 1
[  102.519500] acpiphp: Slot [25] unregistered
[  102.520146] pci_hotplug: pci_hp_deregister: Removed slot 25 from the list
[  102.520995] acpiphp: release_slot - physical_slot = 25
[  102.522445] pci_bus 0000:00: dev 19, dec refcount to 1
[  102.523463] acpiphp: Slot [26] unregistered
[  102.524335] pci_hotplug: pci_hp_deregister: Removed slot 26 from the list
[  102.525597] acpiphp: release_slot - physical_slot = 26
[  102.526599] pci_bus 0000:00: dev 1a, dec refcount to 1
[  102.527636] acpiphp: Slot [27] unregistered
[  102.528483] pci_hotplug: pci_hp_deregister: Removed slot 27 from the list
[  102.529812] acpiphp: release_slot - physical_slot = 27
[  102.530872] pci_bus 0000:00: dev 1b, dec refcount to 1
[  102.531988] acpiphp: Slot [28] unregistered
[  102.532775] pci_hotplug: pci_hp_deregister: Removed slot 28 from the list
[  102.534200] acpiphp: release_slot - physical_slot = 28
[  102.535038] pci_bus 0000:00: dev 1c, dec refcount to 1
[  102.535727] acpiphp: Slot [29] unregistered
[  102.536328] pci_hotplug: pci_hp_deregister: Removed slot 29 from the list
[  102.537213] acpiphp: release_slot - physical_slot = 29
[  102.537886] pci_bus 0000:00: dev 1d, dec refcount to 1
[  102.539560] acpiphp: Slot [30] unregistered
[  102.541427] pci_hotplug: pci_hp_deregister: Removed slot 30 from the list
[  102.544245] acpiphp: release_slot - physical_slot = 30
[  102.545431] pci_bus 0000:00: dev 1e, dec refcount to 1
[  102.546647] acpiphp: Slot [31] unregistered
[  102.547643] pci_hotplug: pci_hp_deregister: Removed slot 31 from the list
[  102.549290] acpiphp: release_slot - physical_slot = 31
[  102.550510] pci_bus 0000:00: dev 1f, dec refcount to 1
[  102.551810] pci_bus 0000:00: dev 1f, dec refcount to 0
[  102.552861] pci_bus 0000:00: dev 1f, released physical slot 31
[  102.554226] pci_bus 0000:00: dev 1e, dec refcount to 0
[  102.555448] pci_bus 0000:00: dev 1e, released physical slot 30
[  102.556836] pci_bus 0000:00: dev 1d, dec refcount to 0
[  102.558061] pci_bus 0000:00: dev 1d, released physical slot 29
[  102.559420] pci_bus 0000:00: dev 1c, dec refcount to 0
[  102.560662] pci_bus 0000:00: dev 1c, released physical slot 28
[  102.562016] pci_bus 0000:00: dev 1b, dec refcount to 0
[  102.563218] pci_bus 0000:00: dev 1b, released physical slot 27
[  102.564556] pci_bus 0000:00: dev 1a, dec refcount to 0
[  102.565767] pci_bus 0000:00: dev 1a, released physical slot 26
[  102.567132] pci_bus 0000:00: dev 19, dec refcount to 0
[  102.568366] pci_bus 0000:00: dev 19, released physical slot 25
[  102.569631] pci_bus 0000:00: dev 18, dec refcount to 0
[  102.570826] pci_bus 0000:00: dev 18, released physical slot 24
[  102.572194] pci_bus 0000:00: dev 17, dec refcount to 0
[  102.573407] pci_bus 0000:00: dev 17, released physical slot 23
[  102.574741] pci_bus 0000:00: dev 16, dec refcount to 0
[  102.575960] pci_bus 0000:00: dev 16, released physical slot 22
[  102.577334] pci_bus 0000:00: dev 15, dec refcount to 0
[  102.578548] pci_bus 0000:00: dev 15, released physical slot 21
[  102.579894] pci_bus 0000:00: dev 14, dec refcount to 0
[  102.581141] pci_bus 0000:00: dev 14, released physical slot 20
[  102.582506] pci_bus 0000:00: dev 13, dec refcount to 0
[  102.583722] pci_bus 0000:00: dev 13, released physical slot 19
[  102.585111] pci_bus 0000:00: dev 12, dec refcount to 0
[  102.586328] pci_bus 0000:00: dev 12, released physical slot 18
[  102.587688] pci_bus 0000:00: dev 11, dec refcount to 0
[  102.588915] pci_bus 0000:00: dev 11, released physical slot 17
[  102.590281] pci_bus 0000:00: dev 10, dec refcount to 0
[  102.591485] pci_bus 0000:00: dev 10, released physical slot 16
[  102.592854] pci_bus 0000:00: dev 0f, dec refcount to 0
[  102.594066] pci_bus 0000:00: dev 0f, released physical slot 15
[  102.595417] pci_bus 0000:00: dev 0e, dec refcount to 0
[  102.596635] pci_bus 0000:00: dev 0e, released physical slot 14
[  102.598010] pci_bus 0000:00: dev 0d, dec refcount to 0
[  102.599210] pci_bus 0000:00: dev 0d, released physical slot 13
[  102.600595] pci_bus 0000:00: dev 0c, dec refcount to 0
[  102.601794] pci_bus 0000:00: dev 0c, released physical slot 12
[  102.603143] pci_bus 0000:00: dev 0b, dec refcount to 0
[  102.604362] pci_bus 0000:00: dev 0b, released physical slot 11
[  102.605700] pci_bus 0000:00: dev 0a, dec refcount to 0
[  102.606904] pci_bus 0000:00: dev 0a, released physical slot 10
[  102.608313] pci_bus 0000:00: dev 09, dec refcount to 0
[  102.609539] pci_bus 0000:00: dev 09, released physical slot 9
[  102.610879] pci_bus 0000:00: dev 08, dec refcount to 0
[  102.612117] pci_bus 0000:00: dev 08, released physical slot 8
[  102.613452] pci_bus 0000:00: dev 07, dec refcount to 0
[  102.614664] pci_bus 0000:00: dev 07, released physical slot 7
[  102.615992] pci_bus 0000:00: dev 06, dec refcount to 0
[  102.617221] pci_bus 0000:00: dev 06, released physical slot 6
[  102.618554] pci_bus 0000:00: dev 05, dec refcount to 0
[  102.619758] pci_bus 0000:00: dev 05, released physical slot 5
[  102.621116] pci_bus 0000:00: dev 04, dec refcount to 0
[  102.622320] pci_bus 0000:00: dev 04, released physical slot 4
[  102.623656] pci_bus 0000:00: dev 03, dec refcount to 0
[  102.624887] pci_bus 0000:00: dev 03, released physical slot 3
[  102.626239] pci_bus 0000:00: dev 02, dec refcount to 0
[  102.627445] pci_bus 0000:00: dev 02, released physical slot 2
[  102.628805] pci_bus 0000:00: dev 01, dec refcount to 0
[  102.629589] pci_bus 0000:00: dev 01, released physical slot 1
[  102.630631] pci_bus 0000:00: freeing pci_bus info
[  102.631369] pci_host_bridge pci0000:00: freeing pci_host_bridge info
[  102.633091] ACPI: Device does not support D3cold
[  102.633915] ACPI: Device does not support D3cold
[  102.635221] ACPI: Device does not support D3cold
[  102.636103] ACPI: Device does not support D3cold
[  102.636902] ACPI: Device does not support D3cold
[  102.637685] ACPI: Device does not support D3cold
[  102.638467] ACPI: Device does not support D3cold
[  102.639631] ACPI: Device does not support D3cold
[  102.640472] ACPI: Device does not support D3cold
[  102.641310] ACPI: Device does not support D3cold
[  102.642105] ACPI: Device does not support D3cold
[  102.642928] ACPI: Device does not support D3cold
[  102.643725] ACPI: Device does not support D3cold
[  102.644544] ACPI: Device does not support D3cold
[  102.645344] ACPI: Device does not support D3cold
[  102.646126] ACPI: Device does not support D3cold
[  102.646902] ACPI: Device does not support D3cold
[  102.647677] ACPI: Device does not support D3cold
[  102.648485] ACPI: Device does not support D3cold
[  102.649269] ACPI: Device does not support D3cold
[  102.650065] ACPI: Device does not support D3cold
[  102.650822] ACPI: Device does not support D3cold
[  102.652483] ACPI: Device does not support D3cold
[  102.654157] ACPI: Device does not support D3cold
[  102.655803] ACPI: Device does not support D3cold
[  102.657419] ACPI: Device does not support D3cold
[  102.658528] ACPI: Device does not support D3cold
[  102.659255] ACPI: Device does not support D3cold
[  102.659973] ACPI: Device does not support D3cold
[  102.661807] ACPI: Device does not support D3cold
[  102.661925] ACPI: Device does not support D3cold
[  102.662047] ACPI: Device does not support D3cold
[  102.662148] ACPI: Device does not support D3cold
[  102.662258] ACPI: Device does not support D3cold
[  102.662374] ACPI: Device does not support D3cold
[  102.662486] ACPI: Device does not support D3cold
[  102.662597] ACPI: Device does not support D3cold
[  102.662711] ACPI: Device does not support D3cold
[  102.662814] ACPI: Device does not support D3cold
[  102.662918] ACPI: Device does not support D3cold
[  102.663019] ACPI: Device does not support D3cold
[  102.663039] ACPI: \_SB_.PCI0: No _EJ0 support for device

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

* Re: [PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds
  2013-07-24  2:20         ` Yinghai Lu
@ 2013-07-24 12:22           ` Rafael J. Wysocki
  2013-07-24 12:58           ` Rafael J. Wysocki
  1 sibling, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-24 12:22 UTC (permalink / raw)
  To: Yinghai Lu
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Tuesday, July 23, 2013 07:20:53 PM Yinghai Lu wrote:
> On Tue, Jul 23, 2013 at 2:39 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> >
> > Ugh, stupid bug, sorry about it.  We try to unregister something that may have
> > not been registered.
> >
> > Can you please check if the appended patch helps (on top of
> > linux-pm.git/linux-next)?
> >
> > Rafael
> >
> >
> > ---
> >  drivers/pci/hotplug/acpiphp_glue.c |    4 +++-
> >  1 file changed, 3 insertions(+), 1 deletion(-)
> >
> > 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
> > @@ -340,6 +340,7 @@ static acpi_status register_slot(acpi_ha
> >
> >                 retval = acpiphp_register_hotplug_slot(slot, sun);
> >                 if (retval) {
> > +                       slot->slot = NULL;
> >                         bridge->nr_slots--;
> >                         if (retval == -EBUSY)
> >                                 warn("Slot %llu already registered by another "
> > @@ -429,7 +430,8 @@ static void cleanup_bridge(struct acpiph
> >                                         err("failed to remove notify handler\n");
> >                         }
> >                 }
> > -               acpiphp_unregister_hotplug_slot(slot);
> > +               if (slot->slot)
> > +                       acpiphp_unregister_hotplug_slot(slot);
> >         }
> >
> >         mutex_lock(&bridge_mutex);
> >
> 
> yes, that fixes the problem. Thanks

Great, thanks for testing!

I'm adding this to the series (after commit 7342798):

---
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Subject: ACPI / hotplug / PCI: Fix NULL pointer dereference in cleanup_bridge()

After commit bbd34fc (ACPI / hotplug / PCI: Register all devices
under the given bridge) register_slot() is called for all PCI
devices under a given bridge that have corresponding objects in
the ACPI namespace, but it calls acpiphp_register_hotplug_slot()
only for devices satisfying specific criteria.  Still,
cleanup_bridge() calls acpiphp_unregister_hotplug_slot() for all
objects created by register_slot(), although it should only call it
for the ones that acpiphp_register_hotplug_slot() has been called
for (successfully).  This causes a NULL pointer to be dereferenced
by the acpiphp_unregister_hotplug_slot() executed by cleanup_bridge()
if the object it is called for has not been passed to
acpiphp_register_hotplug_slot().

To fix this problem, check if the 'slot' field of the object passed
to acpiphp_unregister_hotplug_slot() in cleanup_bridge() is not NULL,
which only is the case if acpiphp_register_hotplug_slot() has been
executed for that object.  In addition to that, make register_slot()
reset the 'slot' field to NULL if acpiphp_register_hotplug_slot() has
failed for the given object to prevent stale pointers from being
used by acpiphp_unregister_hotplug_slot().

Reported-and-tested-by: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp_glue.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

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
@@ -340,6 +340,7 @@ static acpi_status register_slot(acpi_ha
 
 		retval = acpiphp_register_hotplug_slot(slot, sun);
 		if (retval) {
+			slot->slot = NULL;
 			bridge->nr_slots--;
 			if (retval == -EBUSY)
 				warn("Slot %llu already registered by another "
@@ -429,7 +430,8 @@ static void cleanup_bridge(struct acpiph
 					err("failed to remove notify handler\n");
 			}
 		}
-		acpiphp_unregister_hotplug_slot(slot);
+		if (slot->slot)
+			acpiphp_unregister_hotplug_slot(slot);
 	}
 
 	mutex_lock(&bridge_mutex);


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

* Re: [PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds
  2013-07-24  2:20         ` Yinghai Lu
  2013-07-24 12:22           ` Rafael J. Wysocki
@ 2013-07-24 12:58           ` Rafael J. Wysocki
  2013-07-24 16:06             ` Bjorn Helgaas
  2013-07-25 13:25             ` Yinghai Lu
  1 sibling, 2 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-24 12:58 UTC (permalink / raw)
  To: Yinghai Lu
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Tuesday, July 23, 2013 07:20:53 PM Yinghai Lu wrote:
> On Tue, Jul 23, 2013 at 2:39 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:

[...]

> [  102.631369] pci_host_bridge pci0000:00: freeing pci_host_bridge info

By the way this looks fishy:

> [  102.633091] ACPI: Device does not support D3cold
> [  102.633915] ACPI: Device does not support D3cold
> [  102.635221] ACPI: Device does not support D3cold
> [  102.636103] ACPI: Device does not support D3cold
> [  102.636902] ACPI: Device does not support D3cold
> [  102.637685] ACPI: Device does not support D3cold
> [  102.638467] ACPI: Device does not support D3cold
> [  102.639631] ACPI: Device does not support D3cold
> [  102.640472] ACPI: Device does not support D3cold
> [  102.641310] ACPI: Device does not support D3cold
> [  102.642105] ACPI: Device does not support D3cold
> [  102.642928] ACPI: Device does not support D3cold
> [  102.643725] ACPI: Device does not support D3cold
> [  102.644544] ACPI: Device does not support D3cold
> [  102.645344] ACPI: Device does not support D3cold
> [  102.646126] ACPI: Device does not support D3cold
> [  102.646902] ACPI: Device does not support D3cold
> [  102.647677] ACPI: Device does not support D3cold
> [  102.648485] ACPI: Device does not support D3cold
> [  102.649269] ACPI: Device does not support D3cold
> [  102.650065] ACPI: Device does not support D3cold
> [  102.650822] ACPI: Device does not support D3cold
> [  102.652483] ACPI: Device does not support D3cold
> [  102.654157] ACPI: Device does not support D3cold
> [  102.655803] ACPI: Device does not support D3cold
> [  102.657419] ACPI: Device does not support D3cold
> [  102.658528] ACPI: Device does not support D3cold
> [  102.659255] ACPI: Device does not support D3cold
> [  102.659973] ACPI: Device does not support D3cold
> [  102.661807] ACPI: Device does not support D3cold
> [  102.661925] ACPI: Device does not support D3cold
> [  102.662047] ACPI: Device does not support D3cold
> [  102.662148] ACPI: Device does not support D3cold
> [  102.662258] ACPI: Device does not support D3cold
> [  102.662374] ACPI: Device does not support D3cold
> [  102.662486] ACPI: Device does not support D3cold
> [  102.662597] ACPI: Device does not support D3cold
> [  102.662711] ACPI: Device does not support D3cold
> [  102.662814] ACPI: Device does not support D3cold
> [  102.662918] ACPI: Device does not support D3cold
> [  102.663019] ACPI: Device does not support D3cold

Can you please check if it goes away with the patch below applied?

> [  102.663039] ACPI: \_SB_.PCI0: No _EJ0 support for device


---
 drivers/acpi/device_pm.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

Index: linux-pm/drivers/acpi/device_pm.c
===================================================================
--- linux-pm.orig/drivers/acpi/device_pm.c
+++ linux-pm/drivers/acpi/device_pm.c
@@ -159,7 +159,8 @@ int acpi_device_set_power(struct acpi_de
 	int result = 0;
 	bool cut_power = false;
 
-	if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
+	if (!device || !device->flags.power_manageable
+	    || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
 		return -EINVAL;
 
 	/* Make sure this is a valid target state */

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

* Re: [PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds
  2013-07-24 12:58           ` Rafael J. Wysocki
@ 2013-07-24 16:06             ` Bjorn Helgaas
  2013-07-24 20:02               ` Rafael J. Wysocki
  2013-07-25 13:25             ` Yinghai Lu
  1 sibling, 1 reply; 135+ messages in thread
From: Bjorn Helgaas @ 2013-07-24 16:06 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Yinghai Lu, ACPI Devel Maling List, LKML, Linux PCI, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

On Wed, Jul 24, 2013 at 6:58 AM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> On Tuesday, July 23, 2013 07:20:53 PM Yinghai Lu wrote:
>> On Tue, Jul 23, 2013 at 2:39 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
>
> [...]
>
>> [  102.631369] pci_host_bridge pci0000:00: freeing pci_host_bridge info
>
> By the way this looks fishy:
>
>> [  102.633091] ACPI: Device does not support D3cold

This and other printks in that function don't give any clue what
device is involved, even though we have an acpi_device pointer.  It'd
be nice to fix that, too.

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

* Re: [PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds
  2013-07-24 16:06             ` Bjorn Helgaas
@ 2013-07-24 20:02               ` Rafael J. Wysocki
  0 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-24 20:02 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: Yinghai Lu, ACPI Devel Maling List, LKML, Linux PCI, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

On Wednesday, July 24, 2013 10:06:01 AM Bjorn Helgaas wrote:
> On Wed, Jul 24, 2013 at 6:58 AM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> > On Tuesday, July 23, 2013 07:20:53 PM Yinghai Lu wrote:
> >> On Tue, Jul 23, 2013 at 2:39 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> >
> > [...]
> >
> >> [  102.631369] pci_host_bridge pci0000:00: freeing pci_host_bridge info
> >
> > By the way this looks fishy:
> >
> >> [  102.633091] ACPI: Device does not support D3cold
> 
> This and other printks in that function don't give any clue what
> device is involved, even though we have an acpi_device pointer.  It'd
> be nice to fix that, too.

As it turns out, I have that patch ready as well.  Appended for completeness.

Thanks,
Rafael


---
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Subject: ACPI / PM: Make messages in acpi_device_set_power() print device name

Modify acpi_device_set_power() so that diagnostic messages printed by
it to the kernel log always contain the name of the device to make it
possible to identify the device if need be.  Also replace
printk(KERN_WARNING ) with dev_warn() everywhere in that function.

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

Index: linux-pm/drivers/acpi/device_pm.c
===================================================================
--- linux-pm.orig/drivers/acpi/device_pm.c
+++ linux-pm/drivers/acpi/device_pm.c
@@ -166,20 +166,20 @@ int acpi_device_set_power(struct acpi_de
 	/* Make sure this is a valid target state */
 
 	if (state == device->power.state) {
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at %s\n",
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] already in %s\n",
+				  device->pnp.bus_id,
 				  acpi_power_state_string(state)));
 		return 0;
 	}
 
 	if (!device->power.states[state].flags.valid) {
-		printk(KERN_WARNING PREFIX "Device does not support %s\n",
-		       acpi_power_state_string(state));
+		dev_warn(&device->dev, "Power state %s not supported\n",
+			 acpi_power_state_string(state));
 		return -ENODEV;
 	}
 	if (device->parent && (state < device->parent->power.state)) {
-		printk(KERN_WARNING PREFIX
-			      "Cannot set device to a higher-powered"
-			      " state than parent\n");
+		dev_warn(&device->dev, "Cannot transition to a higher-powered "
+			 "state than parent\n");
 		return -ENODEV;
 	}
 
@@ -192,8 +192,8 @@ int acpi_device_set_power(struct acpi_de
 
 	if (state < device->power.state && state != ACPI_STATE_D0
 	    && device->power.state >= ACPI_STATE_D3_HOT) {
-		printk(KERN_WARNING PREFIX
-			"Cannot transition to non-D0 state from D3\n");
+		dev_warn(&device->dev,
+			 "Cannot transition to non-D0 state from D3\n");
 		return -ENODEV;
 	}
 
@@ -220,10 +220,8 @@ int acpi_device_set_power(struct acpi_de
 
  end:
 	if (result) {
-		printk(KERN_WARNING PREFIX
-			      "Device [%s] failed to transition to %s\n",
-			      device->pnp.bus_id,
-			      acpi_power_state_string(state));
+		dev_warn(&device->dev, "Failed to change power state to %s\n",
+			 acpi_power_state_string(state));
 	} else {
 		device->power.state = state;
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,


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

* Re: [PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds
  2013-07-24 12:58           ` Rafael J. Wysocki
  2013-07-24 16:06             ` Bjorn Helgaas
@ 2013-07-25 13:25             ` Yinghai Lu
  2013-07-25 19:57               ` Rafael J. Wysocki
  1 sibling, 1 reply; 135+ messages in thread
From: Yinghai Lu @ 2013-07-25 13:25 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Wed, Jul 24, 2013 at 5:58 AM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> On Tuesday, July 23, 2013 07:20:53 PM Yinghai Lu wrote:
>> On Tue, Jul 23, 2013 at 2:39 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
>
> [...]
>
>> [  102.631369] pci_host_bridge pci0000:00: freeing pci_host_bridge info
>
> By the way this looks fishy:
>
>> [  102.633091] ACPI: Device does not support D3cold
>> [  102.633915] ACPI: Device does not support D3cold
>> [  102.635221] ACPI: Device does not support D3cold
>> [  102.636103] ACPI: Device does not support D3cold
>> [  102.636902] ACPI: Device does not support D3cold
>> [  102.637685] ACPI: Device does not support D3cold
>> [  102.638467] ACPI: Device does not support D3cold
>> [  102.639631] ACPI: Device does not support D3cold
>> [  102.640472] ACPI: Device does not support D3cold
>> [  102.641310] ACPI: Device does not support D3cold
>> [  102.642105] ACPI: Device does not support D3cold
>> [  102.642928] ACPI: Device does not support D3cold
>> [  102.643725] ACPI: Device does not support D3cold
>> [  102.644544] ACPI: Device does not support D3cold
>> [  102.645344] ACPI: Device does not support D3cold
>> [  102.646126] ACPI: Device does not support D3cold
>> [  102.646902] ACPI: Device does not support D3cold
>> [  102.647677] ACPI: Device does not support D3cold
>> [  102.648485] ACPI: Device does not support D3cold
>> [  102.649269] ACPI: Device does not support D3cold
>> [  102.650065] ACPI: Device does not support D3cold
>> [  102.650822] ACPI: Device does not support D3cold
>> [  102.652483] ACPI: Device does not support D3cold
>> [  102.654157] ACPI: Device does not support D3cold
>> [  102.655803] ACPI: Device does not support D3cold
>> [  102.657419] ACPI: Device does not support D3cold
>> [  102.658528] ACPI: Device does not support D3cold
>> [  102.659255] ACPI: Device does not support D3cold
>> [  102.659973] ACPI: Device does not support D3cold
>> [  102.661807] ACPI: Device does not support D3cold
>> [  102.661925] ACPI: Device does not support D3cold
>> [  102.662047] ACPI: Device does not support D3cold
>> [  102.662148] ACPI: Device does not support D3cold
>> [  102.662258] ACPI: Device does not support D3cold
>> [  102.662374] ACPI: Device does not support D3cold
>> [  102.662486] ACPI: Device does not support D3cold
>> [  102.662597] ACPI: Device does not support D3cold
>> [  102.662711] ACPI: Device does not support D3cold
>> [  102.662814] ACPI: Device does not support D3cold
>> [  102.662918] ACPI: Device does not support D3cold
>> [  102.663019] ACPI: Device does not support D3cold
>
> Can you please check if it goes away with the patch below applied?
>
>> [  102.663039] ACPI: \_SB_.PCI0: No _EJ0 support for device
>
>
> ---
>  drivers/acpi/device_pm.c |    3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
>
> Index: linux-pm/drivers/acpi/device_pm.c
> ===================================================================
> --- linux-pm.orig/drivers/acpi/device_pm.c
> +++ linux-pm/drivers/acpi/device_pm.c
> @@ -159,7 +159,8 @@ int acpi_device_set_power(struct acpi_de
>         int result = 0;
>         bool cut_power = false;
>
> -       if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
> +       if (!device || !device->flags.power_manageable
> +           || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
>                 return -EINVAL;
>
>         /* Make sure this is a valid target state */
>

yes, with this change, those print out are gone.

Thanks

Yinghai

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

* Re: [PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds
  2013-07-25 13:25             ` Yinghai Lu
@ 2013-07-25 19:57               ` Rafael J. Wysocki
  0 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-07-25 19:57 UTC (permalink / raw)
  To: Yinghai Lu
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Thursday, July 25, 2013 06:25:06 AM Yinghai Lu wrote:
> On Wed, Jul 24, 2013 at 5:58 AM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> > On Tuesday, July 23, 2013 07:20:53 PM Yinghai Lu wrote:
> >> On Tue, Jul 23, 2013 at 2:39 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> >
> > [...]
> >
> >> [  102.631369] pci_host_bridge pci0000:00: freeing pci_host_bridge info
> >
> > By the way this looks fishy:
> >
> >> [  102.633091] ACPI: Device does not support D3cold
> >> [  102.633915] ACPI: Device does not support D3cold
> >> [  102.635221] ACPI: Device does not support D3cold
> >> [  102.636103] ACPI: Device does not support D3cold
> >> [  102.636902] ACPI: Device does not support D3cold
> >> [  102.637685] ACPI: Device does not support D3cold
> >> [  102.638467] ACPI: Device does not support D3cold
> >> [  102.639631] ACPI: Device does not support D3cold
> >> [  102.640472] ACPI: Device does not support D3cold
> >> [  102.641310] ACPI: Device does not support D3cold
> >> [  102.642105] ACPI: Device does not support D3cold
> >> [  102.642928] ACPI: Device does not support D3cold
> >> [  102.643725] ACPI: Device does not support D3cold
> >> [  102.644544] ACPI: Device does not support D3cold
> >> [  102.645344] ACPI: Device does not support D3cold
> >> [  102.646126] ACPI: Device does not support D3cold
> >> [  102.646902] ACPI: Device does not support D3cold
> >> [  102.647677] ACPI: Device does not support D3cold
> >> [  102.648485] ACPI: Device does not support D3cold
> >> [  102.649269] ACPI: Device does not support D3cold
> >> [  102.650065] ACPI: Device does not support D3cold
> >> [  102.650822] ACPI: Device does not support D3cold
> >> [  102.652483] ACPI: Device does not support D3cold
> >> [  102.654157] ACPI: Device does not support D3cold
> >> [  102.655803] ACPI: Device does not support D3cold
> >> [  102.657419] ACPI: Device does not support D3cold
> >> [  102.658528] ACPI: Device does not support D3cold
> >> [  102.659255] ACPI: Device does not support D3cold
> >> [  102.659973] ACPI: Device does not support D3cold
> >> [  102.661807] ACPI: Device does not support D3cold
> >> [  102.661925] ACPI: Device does not support D3cold
> >> [  102.662047] ACPI: Device does not support D3cold
> >> [  102.662148] ACPI: Device does not support D3cold
> >> [  102.662258] ACPI: Device does not support D3cold
> >> [  102.662374] ACPI: Device does not support D3cold
> >> [  102.662486] ACPI: Device does not support D3cold
> >> [  102.662597] ACPI: Device does not support D3cold
> >> [  102.662711] ACPI: Device does not support D3cold
> >> [  102.662814] ACPI: Device does not support D3cold
> >> [  102.662918] ACPI: Device does not support D3cold
> >> [  102.663019] ACPI: Device does not support D3cold
> >
> > Can you please check if it goes away with the patch below applied?
> >
> >> [  102.663039] ACPI: \_SB_.PCI0: No _EJ0 support for device
> >
> >
> > ---
> >  drivers/acpi/device_pm.c |    3 ++-
> >  1 file changed, 2 insertions(+), 1 deletion(-)
> >
> > Index: linux-pm/drivers/acpi/device_pm.c
> > ===================================================================
> > --- linux-pm.orig/drivers/acpi/device_pm.c
> > +++ linux-pm/drivers/acpi/device_pm.c
> > @@ -159,7 +159,8 @@ int acpi_device_set_power(struct acpi_de
> >         int result = 0;
> >         bool cut_power = false;
> >
> > -       if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
> > +       if (!device || !device->flags.power_manageable
> > +           || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
> >                 return -EINVAL;
> >
> >         /* Make sure this is a valid target state */
> >
> 
> yes, with this change, those print out are gone.

Cool, thanks!

Rafael

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

* Re: [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots
  2013-07-17 23:32     ` [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots Rafael J. Wysocki
@ 2013-09-04 20:36       ` Alex Williamson
  2013-09-04 22:54         ` Rafael J. Wysocki
  0 siblings, 1 reply; 135+ messages in thread
From: Alex Williamson @ 2013-09-04 20:36 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Thu, 2013-07-18 at 01:32 +0200, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> 
> The current implementation of acpiphp_check_bridge() is pretty dumb:
>  - It enables a slot if it's not enabled and the slot status is
>    ACPI_STA_ALL.
>  - It disables a slot if it's enabled and the slot status is not
>    ACPI_STA_ALL.
> 
> This behavior is not sufficient to handle the Thunderbolt daisy
> chaining case properly, however, because in that case the bus
> behind the already enabled slot needs to be rescanned for new
> devices.
> 
> For this reason, modify acpiphp_check_bridge() so that slots are
> disabled and stopped if they are not in the ACPI_STA_ALL state.
> 
> For slots in the ACPI_STA_ALL state, devices behind them that don't
> respond are trimmed using a new function, trim_stale_devices(),
> introduced specifically for this purpose.  That function walks
> the given bus and checks each device on it.  If the device doesn't
> respond, it is assumed to be gone and is removed.
> 
> Once all of the stale devices directy behind the slot have been
> removed, acpiphp_check_bridge() will start looking for new devices
> that might have appeared on the given bus.  It will do that even if
> the slot is already enabled (SLOT_ENABLED is set for it).
> 
> In addition to that, make the bus check notification ignore
> SLOT_ENABLED and go for enable_device() directly if bridge is NULL,
> so that devices behind the slot are re-enumerated in that case too.
> 
> This change is based on earlier patches from Kirill A Shutemov
> and Mika Westerberg.
> 
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
> ---

FYI, git bisect landed on this patch as the cause of my serial console
dying on current upstream.  Further debugging to come...  Thanks,

Alex


>  drivers/pci/hotplug/acpiphp_glue.c |   87 +++++++++++++++++++++++++------------
>  1 file changed, 60 insertions(+), 27 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
> @@ -46,6 +46,7 @@
>  #include <linux/pci.h>
>  #include <linux/pci_hotplug.h>
>  #include <linux/pci-acpi.h>
> +#include <linux/pm_runtime.h>
>  #include <linux/mutex.h>
>  #include <linux/slab.h>
>  #include <linux/acpi.h>
> @@ -687,47 +688,75 @@ static unsigned int get_slot_status(stru
>  }
>  
>  /**
> + * trim_stale_devices - remove PCI devices that are not responding.
> + * @dev: PCI device to start walking the hierarchy from.
> + */
> +static void trim_stale_devices(struct pci_dev *dev)
> +{
> +	acpi_handle handle = ACPI_HANDLE(&dev->dev);
> +	struct pci_bus *bus = dev->subordinate;
> +	bool alive = false;
> +
> +	if (handle) {
> +		acpi_status status;
> +		unsigned long long sta;
> +
> +		status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
> +		alive = ACPI_SUCCESS(status) && sta == ACPI_STA_ALL;
> +	}
> +	if (!alive) {
> +		u32 v;
> +
> +		/* Check if the device responds. */
> +		alive = pci_bus_read_dev_vendor_id(dev->bus, dev->devfn, &v, 0);
> +	}
> +	if (!alive) {
> +		pci_stop_and_remove_bus_device(dev);
> +		if (handle)
> +			acpiphp_bus_trim(handle);
> +	} else if (bus) {
> +		struct pci_dev *child, *tmp;
> +
> +		/* The device is a bridge. so check the bus below it. */
> +		pm_runtime_get_sync(&dev->dev);
> +		list_for_each_entry_safe(child, tmp, &bus->devices, bus_list)
> +			trim_stale_devices(child);
> +
> +		pm_runtime_put(&dev->dev);
> +	}
> +}
> +
> +/**
>   * acpiphp_check_bridge - re-enumerate devices
>   * @bridge: where to begin re-enumeration
>   *
>   * Iterate over all slots under this bridge and make sure that if a
>   * card is present they are enabled, and if not they are disabled.
>   */
> -static int acpiphp_check_bridge(struct acpiphp_bridge *bridge)
> +static void acpiphp_check_bridge(struct acpiphp_bridge *bridge)
>  {
>  	struct acpiphp_slot *slot;
> -	int retval = 0;
> -	int enabled, disabled;
> -
> -	enabled = disabled = 0;
>  
>  	list_for_each_entry(slot, &bridge->slots, node) {
> -		unsigned int status = get_slot_status(slot);
> -		if (slot->flags & SLOT_ENABLED) {
> -			if (status == ACPI_STA_ALL)
> -				continue;
> +		struct pci_bus *bus = slot->bus;
> +		struct pci_dev *dev, *tmp;
>  
> -			retval = acpiphp_disable_and_eject_slot(slot);
> -			if (retval)
> -				goto err_exit;
> +		mutex_lock(&slot->crit_sect);
> +		/* wake up all functions */
> +		if (get_slot_status(slot) == ACPI_STA_ALL) {
> +			/* remove stale devices if any */
> +			list_for_each_entry_safe(dev, tmp, &bus->devices,
> +						 bus_list)
> +				if (PCI_SLOT(dev->devfn) == slot->device)
> +					trim_stale_devices(dev);
>  
> -			disabled++;
> +			/* configure all functions */
> +			enable_device(slot);
>  		} else {
> -			if (status != ACPI_STA_ALL)
> -				continue;
> -			retval = acpiphp_enable_slot(slot);
> -			if (retval) {
> -				err("Error occurred in enabling\n");
> -				goto err_exit;
> -			}
> -			enabled++;
> +			disable_device(slot);
>  		}
> +		mutex_unlock(&slot->crit_sect);
>  	}
> -
> -	dbg("%s: %d enabled, %d disabled\n", __func__, enabled, disabled);
> -
> - err_exit:
> -	return retval;
>  }
>  
>  static void acpiphp_set_hpp_values(struct pci_bus *bus)
> @@ -828,7 +857,11 @@ static void hotplug_event(acpi_handle ha
>  					    ACPI_UINT32_MAX, check_sub_bridges,
>  					    NULL, NULL, NULL);
>  		} else {
> -			acpiphp_enable_slot(func->slot);
> +			struct acpiphp_slot *slot = func->slot;
> +
> +			mutex_lock(&slot->crit_sect);
> +			enable_device(slot);
> +			mutex_unlock(&slot->crit_sect);
>  		}
>  		break;
>  
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pci" 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] 135+ messages in thread

* Re: [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots
  2013-09-04 20:36       ` Alex Williamson
@ 2013-09-04 22:54         ` Rafael J. Wysocki
  2013-09-04 23:12           ` Alex Williamson
  0 siblings, 1 reply; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-09-04 22:54 UTC (permalink / raw)
  To: Alex Williamson
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Wednesday, September 04, 2013 02:36:34 PM Alex Williamson wrote:
> On Thu, 2013-07-18 at 01:32 +0200, Rafael J. Wysocki wrote:
> > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > 
> > The current implementation of acpiphp_check_bridge() is pretty dumb:
> >  - It enables a slot if it's not enabled and the slot status is
> >    ACPI_STA_ALL.
> >  - It disables a slot if it's enabled and the slot status is not
> >    ACPI_STA_ALL.
> > 
> > This behavior is not sufficient to handle the Thunderbolt daisy
> > chaining case properly, however, because in that case the bus
> > behind the already enabled slot needs to be rescanned for new
> > devices.
> > 
> > For this reason, modify acpiphp_check_bridge() so that slots are
> > disabled and stopped if they are not in the ACPI_STA_ALL state.
> > 
> > For slots in the ACPI_STA_ALL state, devices behind them that don't
> > respond are trimmed using a new function, trim_stale_devices(),
> > introduced specifically for this purpose.  That function walks
> > the given bus and checks each device on it.  If the device doesn't
> > respond, it is assumed to be gone and is removed.
> > 
> > Once all of the stale devices directy behind the slot have been
> > removed, acpiphp_check_bridge() will start looking for new devices
> > that might have appeared on the given bus.  It will do that even if
> > the slot is already enabled (SLOT_ENABLED is set for it).
> > 
> > In addition to that, make the bus check notification ignore
> > SLOT_ENABLED and go for enable_device() directly if bridge is NULL,
> > so that devices behind the slot are re-enumerated in that case too.
> > 
> > This change is based on earlier patches from Kirill A Shutemov
> > and Mika Westerberg.
> > 
> > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
> > ---
> 
> FYI, git bisect landed on this patch as the cause of my serial console
> dying on current upstream.  Further debugging to come...  Thanks,

Well, sorry about that.

What exactly do you mean by "dying"?

Rafael


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

* Re: [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots
  2013-09-04 22:54         ` Rafael J. Wysocki
@ 2013-09-04 23:12           ` Alex Williamson
  2013-09-04 23:35             ` Rafael J. Wysocki
  0 siblings, 1 reply; 135+ messages in thread
From: Alex Williamson @ 2013-09-04 23:12 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Thu, 2013-09-05 at 00:54 +0200, Rafael J. Wysocki wrote:
> On Wednesday, September 04, 2013 02:36:34 PM Alex Williamson wrote:
> > On Thu, 2013-07-18 at 01:32 +0200, Rafael J. Wysocki wrote:
> > > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > > 
> > > The current implementation of acpiphp_check_bridge() is pretty dumb:
> > >  - It enables a slot if it's not enabled and the slot status is
> > >    ACPI_STA_ALL.
> > >  - It disables a slot if it's enabled and the slot status is not
> > >    ACPI_STA_ALL.
> > > 
> > > This behavior is not sufficient to handle the Thunderbolt daisy
> > > chaining case properly, however, because in that case the bus
> > > behind the already enabled slot needs to be rescanned for new
> > > devices.
> > > 
> > > For this reason, modify acpiphp_check_bridge() so that slots are
> > > disabled and stopped if they are not in the ACPI_STA_ALL state.
> > > 
> > > For slots in the ACPI_STA_ALL state, devices behind them that don't
> > > respond are trimmed using a new function, trim_stale_devices(),
> > > introduced specifically for this purpose.  That function walks
> > > the given bus and checks each device on it.  If the device doesn't
> > > respond, it is assumed to be gone and is removed.
> > > 
> > > Once all of the stale devices directy behind the slot have been
> > > removed, acpiphp_check_bridge() will start looking for new devices
> > > that might have appeared on the given bus.  It will do that even if
> > > the slot is already enabled (SLOT_ENABLED is set for it).
> > > 
> > > In addition to that, make the bus check notification ignore
> > > SLOT_ENABLED and go for enable_device() directly if bridge is NULL,
> > > so that devices behind the slot are re-enumerated in that case too.
> > > 
> > > This change is based on earlier patches from Kirill A Shutemov
> > > and Mika Westerberg.
> > > 
> > > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > > Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
> > > ---
> > 
> > FYI, git bisect landed on this patch as the cause of my serial console
> > dying on current upstream.  Further debugging to come...  Thanks,
> 
> Well, sorry about that.
> 
> What exactly do you mean by "dying"?

Sorry, I was hoping to have more details quickly, but it's been a pain
to debug.  By dying I mean serial console output suddenly stops during
kernel boot and nothing more comes out of it until after the system is
rebooted.  The problem happens when acpiphp_check_bridge() calls
enable_slot().  The serial console dies somewhere down in
acpiphp_bus_trim().  I think this is happening on the 00:1f ISA bridge,
so there's a good chance the serial ports are described as somewhere
under there.  Thanks,

Alex


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

* Re: [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots
  2013-09-04 23:12           ` Alex Williamson
@ 2013-09-04 23:35             ` Rafael J. Wysocki
  2013-09-05  3:37               ` Alex Williamson
  0 siblings, 1 reply; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-09-04 23:35 UTC (permalink / raw)
  To: Alex Williamson
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Wednesday, September 04, 2013 05:12:14 PM Alex Williamson wrote:
> On Thu, 2013-09-05 at 00:54 +0200, Rafael J. Wysocki wrote:
> > On Wednesday, September 04, 2013 02:36:34 PM Alex Williamson wrote:
> > > On Thu, 2013-07-18 at 01:32 +0200, Rafael J. Wysocki wrote:
> > > > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > > > 
> > > > The current implementation of acpiphp_check_bridge() is pretty dumb:
> > > >  - It enables a slot if it's not enabled and the slot status is
> > > >    ACPI_STA_ALL.
> > > >  - It disables a slot if it's enabled and the slot status is not
> > > >    ACPI_STA_ALL.
> > > > 
> > > > This behavior is not sufficient to handle the Thunderbolt daisy
> > > > chaining case properly, however, because in that case the bus
> > > > behind the already enabled slot needs to be rescanned for new
> > > > devices.
> > > > 
> > > > For this reason, modify acpiphp_check_bridge() so that slots are
> > > > disabled and stopped if they are not in the ACPI_STA_ALL state.
> > > > 
> > > > For slots in the ACPI_STA_ALL state, devices behind them that don't
> > > > respond are trimmed using a new function, trim_stale_devices(),
> > > > introduced specifically for this purpose.  That function walks
> > > > the given bus and checks each device on it.  If the device doesn't
> > > > respond, it is assumed to be gone and is removed.
> > > > 
> > > > Once all of the stale devices directy behind the slot have been
> > > > removed, acpiphp_check_bridge() will start looking for new devices
> > > > that might have appeared on the given bus.  It will do that even if
> > > > the slot is already enabled (SLOT_ENABLED is set for it).
> > > > 
> > > > In addition to that, make the bus check notification ignore
> > > > SLOT_ENABLED and go for enable_device() directly if bridge is NULL,
> > > > so that devices behind the slot are re-enumerated in that case too.
> > > > 
> > > > This change is based on earlier patches from Kirill A Shutemov
> > > > and Mika Westerberg.
> > > > 
> > > > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > > > Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
> > > > ---
> > > 
> > > FYI, git bisect landed on this patch as the cause of my serial console
> > > dying on current upstream.  Further debugging to come...  Thanks,
> > 
> > Well, sorry about that.
> > 
> > What exactly do you mean by "dying"?
> 
> Sorry, I was hoping to have more details quickly, but it's been a pain
> to debug.  By dying I mean serial console output suddenly stops during
> kernel boot and nothing more comes out of it until after the system is
> rebooted.  The problem happens when acpiphp_check_bridge() calls
> enable_slot().  The serial console dies somewhere down in
> acpiphp_bus_trim().  I think this is happening on the 00:1f ISA bridge,
> so there's a good chance the serial ports are described as somewhere
> under there.

Can you please check if that is the acpiphp_bus_trim() called by
acpiphp_bus_add() or the other one called from trim_stale_devices()?

Just add a dump_stack() or WARN_ON(1) to trim_stale_devices() next to
the acpiphp_bus_trim() call and see if that triggers.  I *think* it's the one
in acpiphp_bus_add(), but it won't hurt to verify that.

Thanks,
Rafael


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

* Re: [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots
  2013-09-04 23:35             ` Rafael J. Wysocki
@ 2013-09-05  3:37               ` Alex Williamson
  2013-09-05  4:06                 ` Alex Williamson
  2013-09-05  6:17                 ` [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots Lan Tianyu
  0 siblings, 2 replies; 135+ messages in thread
From: Alex Williamson @ 2013-09-05  3:37 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Thu, 2013-09-05 at 01:35 +0200, Rafael J. Wysocki wrote:
> On Wednesday, September 04, 2013 05:12:14 PM Alex Williamson wrote:
> > On Thu, 2013-09-05 at 00:54 +0200, Rafael J. Wysocki wrote:
> > > On Wednesday, September 04, 2013 02:36:34 PM Alex Williamson wrote:
> > > > On Thu, 2013-07-18 at 01:32 +0200, Rafael J. Wysocki wrote:
> > > > > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > > > > 
> > > > > The current implementation of acpiphp_check_bridge() is pretty dumb:
> > > > >  - It enables a slot if it's not enabled and the slot status is
> > > > >    ACPI_STA_ALL.
> > > > >  - It disables a slot if it's enabled and the slot status is not
> > > > >    ACPI_STA_ALL.
> > > > > 
> > > > > This behavior is not sufficient to handle the Thunderbolt daisy
> > > > > chaining case properly, however, because in that case the bus
> > > > > behind the already enabled slot needs to be rescanned for new
> > > > > devices.
> > > > > 
> > > > > For this reason, modify acpiphp_check_bridge() so that slots are
> > > > > disabled and stopped if they are not in the ACPI_STA_ALL state.
> > > > > 
> > > > > For slots in the ACPI_STA_ALL state, devices behind them that don't
> > > > > respond are trimmed using a new function, trim_stale_devices(),
> > > > > introduced specifically for this purpose.  That function walks
> > > > > the given bus and checks each device on it.  If the device doesn't
> > > > > respond, it is assumed to be gone and is removed.
> > > > > 
> > > > > Once all of the stale devices directy behind the slot have been
> > > > > removed, acpiphp_check_bridge() will start looking for new devices
> > > > > that might have appeared on the given bus.  It will do that even if
> > > > > the slot is already enabled (SLOT_ENABLED is set for it).
> > > > > 
> > > > > In addition to that, make the bus check notification ignore
> > > > > SLOT_ENABLED and go for enable_device() directly if bridge is NULL,
> > > > > so that devices behind the slot are re-enumerated in that case too.
> > > > > 
> > > > > This change is based on earlier patches from Kirill A Shutemov
> > > > > and Mika Westerberg.
> > > > > 
> > > > > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > > > > Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
> > > > > ---
> > > > 
> > > > FYI, git bisect landed on this patch as the cause of my serial console
> > > > dying on current upstream.  Further debugging to come...  Thanks,
> > > 
> > > Well, sorry about that.
> > > 
> > > What exactly do you mean by "dying"?
> > 
> > Sorry, I was hoping to have more details quickly, but it's been a pain
> > to debug.  By dying I mean serial console output suddenly stops during
> > kernel boot and nothing more comes out of it until after the system is
> > rebooted.  The problem happens when acpiphp_check_bridge() calls
> > enable_slot().  The serial console dies somewhere down in
> > acpiphp_bus_trim().  I think this is happening on the 00:1f ISA bridge,
> > so there's a good chance the serial ports are described as somewhere
> > under there.
> 
> Can you please check if that is the acpiphp_bus_trim() called by
> acpiphp_bus_add() or the other one called from trim_stale_devices()?
> 
> Just add a dump_stack() or WARN_ON(1) to trim_stale_devices() next to
> the acpiphp_bus_trim() call and see if that triggers.  I *think* it's the one
> in acpiphp_bus_add(), but it won't hurt to verify that.

Here's the call path:

[   16.120824]  [<ffffffff81627e6c>] dump_stack+0x55/0x76
[   16.125979]  [<ffffffff8162132e>] enable_slot+0x4ee/0x5e0
[   16.131396]  [<ffffffff813418fb>] ? trim_stale_devices+0x5b/0xf0
[   16.137420]  [<ffffffff81341b35>] acpiphp_check_bridge+0xd5/0x110
[   16.143531]  [<ffffffff81342acb>] hotplug_event+0x16b/0x260
[   16.149115]  [<ffffffff81072cd9>] ? process_one_work+0x189/0x540
[   16.155136]  [<ffffffff81342bf0>] hotplug_event_work+0x30/0x70
[   16.160978]  [<ffffffff81072d3b>] process_one_work+0x1eb/0x540
[   16.166819]  [<ffffffff81072cd9>] ? process_one_work+0x189/0x540
[   16.172836]  [<ffffffff8107353c>] worker_thread+0x11c/0x370
[   16.178426]  [<ffffffff81073420>] ? rescuer_thread+0x350/0x350
[   16.184276]  [<ffffffff8107b0ea>] kthread+0xea/0xf0
[   16.189165]  [<ffffffff8107b000>] ? kthread_create_on_node+0x160/0x160
[   16.195700]  [<ffffffff816395dc>] ret_from_fork+0x7c/0xb0
[   16.201109]  [<ffffffff8107b000>] ? kthread_create_on_node+0x160/0x160

The actual death of the serial console occurs in acpi_device_set_power()
called from:

enable_slot()
 acpiphp_bus_add()
  acpiphp_bus_trim()
   acpi_bus_trim()
    acpi_walk_namespace()
     acpi_bus_remove()
      acpi_device_unregister()
       acpi_device_set_power()

I can't seem to get a path from the acpi devices in question there, so I
have no idea what's getting trimmed here.  It worries me quite a bit by
introducing this trimming that apparently wasn't happening before
though.  Thanks,

Alex


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

* Re: [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots
  2013-09-05  3:37               ` Alex Williamson
@ 2013-09-05  4:06                 ` Alex Williamson
  2013-09-05 11:54                   ` Rafael J. Wysocki
  2013-09-05  6:17                 ` [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots Lan Tianyu
  1 sibling, 1 reply; 135+ messages in thread
From: Alex Williamson @ 2013-09-05  4:06 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Wed, 2013-09-04 at 21:37 -0600, Alex Williamson wrote:
> On Thu, 2013-09-05 at 01:35 +0200, Rafael J. Wysocki wrote:
> > On Wednesday, September 04, 2013 05:12:14 PM Alex Williamson wrote:
> > > On Thu, 2013-09-05 at 00:54 +0200, Rafael J. Wysocki wrote:
> > > > On Wednesday, September 04, 2013 02:36:34 PM Alex Williamson wrote:
> > > > > On Thu, 2013-07-18 at 01:32 +0200, Rafael J. Wysocki wrote:
> > > > > > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > > > > > 
> > > > > > The current implementation of acpiphp_check_bridge() is pretty dumb:
> > > > > >  - It enables a slot if it's not enabled and the slot status is
> > > > > >    ACPI_STA_ALL.
> > > > > >  - It disables a slot if it's enabled and the slot status is not
> > > > > >    ACPI_STA_ALL.
> > > > > > 
> > > > > > This behavior is not sufficient to handle the Thunderbolt daisy
> > > > > > chaining case properly, however, because in that case the bus
> > > > > > behind the already enabled slot needs to be rescanned for new
> > > > > > devices.
> > > > > > 
> > > > > > For this reason, modify acpiphp_check_bridge() so that slots are
> > > > > > disabled and stopped if they are not in the ACPI_STA_ALL state.
> > > > > > 
> > > > > > For slots in the ACPI_STA_ALL state, devices behind them that don't
> > > > > > respond are trimmed using a new function, trim_stale_devices(),
> > > > > > introduced specifically for this purpose.  That function walks
> > > > > > the given bus and checks each device on it.  If the device doesn't
> > > > > > respond, it is assumed to be gone and is removed.
> > > > > > 
> > > > > > Once all of the stale devices directy behind the slot have been
> > > > > > removed, acpiphp_check_bridge() will start looking for new devices
> > > > > > that might have appeared on the given bus.  It will do that even if
> > > > > > the slot is already enabled (SLOT_ENABLED is set for it).
> > > > > > 
> > > > > > In addition to that, make the bus check notification ignore
> > > > > > SLOT_ENABLED and go for enable_device() directly if bridge is NULL,
> > > > > > so that devices behind the slot are re-enumerated in that case too.
> > > > > > 
> > > > > > This change is based on earlier patches from Kirill A Shutemov
> > > > > > and Mika Westerberg.
> > > > > > 
> > > > > > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > > > > > Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
> > > > > > ---
> > > > > 
> > > > > FYI, git bisect landed on this patch as the cause of my serial console
> > > > > dying on current upstream.  Further debugging to come...  Thanks,
> > > > 
> > > > Well, sorry about that.
> > > > 
> > > > What exactly do you mean by "dying"?
> > > 
> > > Sorry, I was hoping to have more details quickly, but it's been a pain
> > > to debug.  By dying I mean serial console output suddenly stops during
> > > kernel boot and nothing more comes out of it until after the system is
> > > rebooted.  The problem happens when acpiphp_check_bridge() calls
> > > enable_slot().  The serial console dies somewhere down in
> > > acpiphp_bus_trim().  I think this is happening on the 00:1f ISA bridge,
> > > so there's a good chance the serial ports are described as somewhere
> > > under there.
> > 
> > Can you please check if that is the acpiphp_bus_trim() called by
> > acpiphp_bus_add() or the other one called from trim_stale_devices()?
> > 
> > Just add a dump_stack() or WARN_ON(1) to trim_stale_devices() next to
> > the acpiphp_bus_trim() call and see if that triggers.  I *think* it's the one
> > in acpiphp_bus_add(), but it won't hurt to verify that.
> 
> Here's the call path:
> 
> [   16.120824]  [<ffffffff81627e6c>] dump_stack+0x55/0x76
> [   16.125979]  [<ffffffff8162132e>] enable_slot+0x4ee/0x5e0
> [   16.131396]  [<ffffffff813418fb>] ? trim_stale_devices+0x5b/0xf0
> [   16.137420]  [<ffffffff81341b35>] acpiphp_check_bridge+0xd5/0x110
> [   16.143531]  [<ffffffff81342acb>] hotplug_event+0x16b/0x260
> [   16.149115]  [<ffffffff81072cd9>] ? process_one_work+0x189/0x540
> [   16.155136]  [<ffffffff81342bf0>] hotplug_event_work+0x30/0x70
> [   16.160978]  [<ffffffff81072d3b>] process_one_work+0x1eb/0x540
> [   16.166819]  [<ffffffff81072cd9>] ? process_one_work+0x189/0x540
> [   16.172836]  [<ffffffff8107353c>] worker_thread+0x11c/0x370
> [   16.178426]  [<ffffffff81073420>] ? rescuer_thread+0x350/0x350
> [   16.184276]  [<ffffffff8107b0ea>] kthread+0xea/0xf0
> [   16.189165]  [<ffffffff8107b000>] ? kthread_create_on_node+0x160/0x160
> [   16.195700]  [<ffffffff816395dc>] ret_from_fork+0x7c/0xb0
> [   16.201109]  [<ffffffff8107b000>] ? kthread_create_on_node+0x160/0x160
> 
> The actual death of the serial console occurs in acpi_device_set_power()
> called from:
> 
> enable_slot()
>  acpiphp_bus_add()
>   acpiphp_bus_trim()
>    acpi_bus_trim()
>     acpi_walk_namespace()
>      acpi_bus_remove()
>       acpi_device_unregister()
>        acpi_device_set_power()
> 
> I can't seem to get a path from the acpi devices in question there, so I
> have no idea what's getting trimmed here.  It worries me quite a bit by
> introducing this trimming that apparently wasn't happening before
> though.  Thanks,

As suspected, the pnp.bus_id/id of the last device before the serial
console dies is COM1/PNP0501.  I also see all of these being trimmed
out:

 MBRD/PNP0C02
 DMAC/PNP0200
 MATH/PNP0C04
 PIC/PNP0000
 HPET/PNP0103
 RTC/PNP0B00
 SPKR/PNP0800
 TIME/PNP0100
 LNK{A-H}/PNP0C0F

This seems like a bad idea.  I forgot to mention, the original
hotplug_event is called with a device check on \_SB_.PCI0.PEX2.  The box
where I'm seeing this is a pretty generic X58 based Nehalem workstation
(Lenovo S20).  Thanks,

Alex

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

* Re: [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots
  2013-09-05  3:37               ` Alex Williamson
  2013-09-05  4:06                 ` Alex Williamson
@ 2013-09-05  6:17                 ` Lan Tianyu
  2013-09-05 11:57                   ` Rafael J. Wysocki
  1 sibling, 1 reply; 135+ messages in thread
From: Lan Tianyu @ 2013-09-05  6:17 UTC (permalink / raw)
  To: Alex Williamson
  Cc: Rafael J. Wysocki, ACPI Devel Maling List, Bjorn Helgaas, LKML,
	Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg,
	Kirill A. Shutemov

2013/9/5 Alex Williamson <alex.williamson@redhat.com>:
> On Thu, 2013-09-05 at 01:35 +0200, Rafael J. Wysocki wrote:
>> On Wednesday, September 04, 2013 05:12:14 PM Alex Williamson wrote:
>> > On Thu, 2013-09-05 at 00:54 +0200, Rafael J. Wysocki wrote:
>> > > On Wednesday, September 04, 2013 02:36:34 PM Alex Williamson wrote:
>> > > > On Thu, 2013-07-18 at 01:32 +0200, Rafael J. Wysocki wrote:
>> > > > > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>> > > > >
>> > > > > The current implementation of acpiphp_check_bridge() is pretty dumb:
>> > > > >  - It enables a slot if it's not enabled and the slot status is
>> > > > >    ACPI_STA_ALL.
>> > > > >  - It disables a slot if it's enabled and the slot status is not
>> > > > >    ACPI_STA_ALL.
>> > > > >
>> > > > > This behavior is not sufficient to handle the Thunderbolt daisy
>> > > > > chaining case properly, however, because in that case the bus
>> > > > > behind the already enabled slot needs to be rescanned for new
>> > > > > devices.
>> > > > >
>> > > > > For this reason, modify acpiphp_check_bridge() so that slots are
>> > > > > disabled and stopped if they are not in the ACPI_STA_ALL state.
>> > > > >
>> > > > > For slots in the ACPI_STA_ALL state, devices behind them that don't
>> > > > > respond are trimmed using a new function, trim_stale_devices(),
>> > > > > introduced specifically for this purpose.  That function walks
>> > > > > the given bus and checks each device on it.  If the device doesn't
>> > > > > respond, it is assumed to be gone and is removed.
>> > > > >
>> > > > > Once all of the stale devices directy behind the slot have been
>> > > > > removed, acpiphp_check_bridge() will start looking for new devices
>> > > > > that might have appeared on the given bus.  It will do that even if
>> > > > > the slot is already enabled (SLOT_ENABLED is set for it).
>> > > > >
>> > > > > In addition to that, make the bus check notification ignore
>> > > > > SLOT_ENABLED and go for enable_device() directly if bridge is NULL,
>> > > > > so that devices behind the slot are re-enumerated in that case too.
>> > > > >
>> > > > > This change is based on earlier patches from Kirill A Shutemov
>> > > > > and Mika Westerberg.
>> > > > >
>> > > > > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>> > > > > Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
>> > > > > ---
>> > > >
>> > > > FYI, git bisect landed on this patch as the cause of my serial console
>> > > > dying on current upstream.  Further debugging to come...  Thanks,
>> > >
>> > > Well, sorry about that.
>> > >
>> > > What exactly do you mean by "dying"?
>> >
>> > Sorry, I was hoping to have more details quickly, but it's been a pain
>> > to debug.  By dying I mean serial console output suddenly stops during
>> > kernel boot and nothing more comes out of it until after the system is
>> > rebooted.  The problem happens when acpiphp_check_bridge() calls
>> > enable_slot().  The serial console dies somewhere down in
>> > acpiphp_bus_trim().  I think this is happening on the 00:1f ISA bridge,
>> > so there's a good chance the serial ports are described as somewhere
>> > under there.
>>
>> Can you please check if that is the acpiphp_bus_trim() called by
>> acpiphp_bus_add() or the other one called from trim_stale_devices()?
>>
>> Just add a dump_stack() or WARN_ON(1) to trim_stale_devices() next to
>> the acpiphp_bus_trim() call and see if that triggers.  I *think* it's the one
>> in acpiphp_bus_add(), but it won't hurt to verify that.
>
> Here's the call path:
>
> [   16.120824]  [<ffffffff81627e6c>] dump_stack+0x55/0x76
> [   16.125979]  [<ffffffff8162132e>] enable_slot+0x4ee/0x5e0
> [   16.131396]  [<ffffffff813418fb>] ? trim_stale_devices+0x5b/0xf0
> [   16.137420]  [<ffffffff81341b35>] acpiphp_check_bridge+0xd5/0x110
> [   16.143531]  [<ffffffff81342acb>] hotplug_event+0x16b/0x260
> [   16.149115]  [<ffffffff81072cd9>] ? process_one_work+0x189/0x540
> [   16.155136]  [<ffffffff81342bf0>] hotplug_event_work+0x30/0x70
> [   16.160978]  [<ffffffff81072d3b>] process_one_work+0x1eb/0x540
> [   16.166819]  [<ffffffff81072cd9>] ? process_one_work+0x189/0x540
> [   16.172836]  [<ffffffff8107353c>] worker_thread+0x11c/0x370
> [   16.178426]  [<ffffffff81073420>] ? rescuer_thread+0x350/0x350
> [   16.184276]  [<ffffffff8107b0ea>] kthread+0xea/0xf0
> [   16.189165]  [<ffffffff8107b000>] ? kthread_create_on_node+0x160/0x160
> [   16.195700]  [<ffffffff816395dc>] ret_from_fork+0x7c/0xb0
> [   16.201109]  [<ffffffff8107b000>] ? kthread_create_on_node+0x160/0x160
>
> The actual death of the serial console occurs in acpi_device_set_power()
> called from:
>
> enable_slot()
>  acpiphp_bus_add()
>   acpiphp_bus_trim()
>    acpi_bus_trim()
>     acpi_walk_namespace()
>      acpi_bus_remove()
>       acpi_device_unregister()
>        acpi_device_set_power()
>
> I can't seem to get a path from the acpi devices in question there, so I
> have no idea what's getting trimmed here.  It worries me quite a bit by
> introducing this trimming that apparently wasn't happening before
> though.  Thanks,

Hi Alex:
           Could you apply the following patch and bootup with kernel param
"acpiphp.acpiphp_debug=1"?
           I guess the patch can make serial port alive. It will not
be put into D3cold
during trimming. But I don't know why it doesn't work after being put
back to D0.
So please attach output of acpidump and the dmesg if it can work. Thanks.

diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index e763651..359b23d 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1110,7 +1110,7 @@ static void acpi_device_unregister(struct
acpi_device *device)
         * power resources the device depends on and turn off the ones that have
         * no more references.
         */
-       acpi_device_set_power(device, ACPI_STATE_D3_COLD);
+       //acpi_device_set_power(device, ACPI_STATE_D3_COLD);
        device->handle = NULL;
        put_device(&device->dev);
 }



>
> Alex
>
> --
> 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



-- 
Best regards
Tianyu Lan

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

* Re: [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots
  2013-09-05  4:06                 ` Alex Williamson
@ 2013-09-05 11:54                   ` Rafael J. Wysocki
  2013-09-05 13:19                     ` Alex Williamson
  0 siblings, 1 reply; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-09-05 11:54 UTC (permalink / raw)
  To: Alex Williamson
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Wednesday, September 04, 2013 10:06:02 PM Alex Williamson wrote:
> On Wed, 2013-09-04 at 21:37 -0600, Alex Williamson wrote:
> > On Thu, 2013-09-05 at 01:35 +0200, Rafael J. Wysocki wrote:
> > > On Wednesday, September 04, 2013 05:12:14 PM Alex Williamson wrote:
> > > > On Thu, 2013-09-05 at 00:54 +0200, Rafael J. Wysocki wrote:
> > > > > On Wednesday, September 04, 2013 02:36:34 PM Alex Williamson wrote:
> > > > > > On Thu, 2013-07-18 at 01:32 +0200, Rafael J. Wysocki wrote:
> > > > > > > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > > > > > > 
> > > > > > > The current implementation of acpiphp_check_bridge() is pretty dumb:
> > > > > > >  - It enables a slot if it's not enabled and the slot status is
> > > > > > >    ACPI_STA_ALL.
> > > > > > >  - It disables a slot if it's enabled and the slot status is not
> > > > > > >    ACPI_STA_ALL.
> > > > > > > 
> > > > > > > This behavior is not sufficient to handle the Thunderbolt daisy
> > > > > > > chaining case properly, however, because in that case the bus
> > > > > > > behind the already enabled slot needs to be rescanned for new
> > > > > > > devices.
> > > > > > > 
> > > > > > > For this reason, modify acpiphp_check_bridge() so that slots are
> > > > > > > disabled and stopped if they are not in the ACPI_STA_ALL state.
> > > > > > > 
> > > > > > > For slots in the ACPI_STA_ALL state, devices behind them that don't
> > > > > > > respond are trimmed using a new function, trim_stale_devices(),
> > > > > > > introduced specifically for this purpose.  That function walks
> > > > > > > the given bus and checks each device on it.  If the device doesn't
> > > > > > > respond, it is assumed to be gone and is removed.
> > > > > > > 
> > > > > > > Once all of the stale devices directy behind the slot have been
> > > > > > > removed, acpiphp_check_bridge() will start looking for new devices
> > > > > > > that might have appeared on the given bus.  It will do that even if
> > > > > > > the slot is already enabled (SLOT_ENABLED is set for it).
> > > > > > > 
> > > > > > > In addition to that, make the bus check notification ignore
> > > > > > > SLOT_ENABLED and go for enable_device() directly if bridge is NULL,
> > > > > > > so that devices behind the slot are re-enumerated in that case too.
> > > > > > > 
> > > > > > > This change is based on earlier patches from Kirill A Shutemov
> > > > > > > and Mika Westerberg.
> > > > > > > 
> > > > > > > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > > > > > > Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
> > > > > > > ---
> > > > > > 
> > > > > > FYI, git bisect landed on this patch as the cause of my serial console
> > > > > > dying on current upstream.  Further debugging to come...  Thanks,
> > > > > 
> > > > > Well, sorry about that.
> > > > > 
> > > > > What exactly do you mean by "dying"?
> > > > 
> > > > Sorry, I was hoping to have more details quickly, but it's been a pain
> > > > to debug.  By dying I mean serial console output suddenly stops during
> > > > kernel boot and nothing more comes out of it until after the system is
> > > > rebooted.  The problem happens when acpiphp_check_bridge() calls
> > > > enable_slot().  The serial console dies somewhere down in
> > > > acpiphp_bus_trim().  I think this is happening on the 00:1f ISA bridge,
> > > > so there's a good chance the serial ports are described as somewhere
> > > > under there.
> > > 
> > > Can you please check if that is the acpiphp_bus_trim() called by
> > > acpiphp_bus_add() or the other one called from trim_stale_devices()?
> > > 
> > > Just add a dump_stack() or WARN_ON(1) to trim_stale_devices() next to
> > > the acpiphp_bus_trim() call and see if that triggers.  I *think* it's the one
> > > in acpiphp_bus_add(), but it won't hurt to verify that.
> > 
> > Here's the call path:
> > 
> > [   16.120824]  [<ffffffff81627e6c>] dump_stack+0x55/0x76
> > [   16.125979]  [<ffffffff8162132e>] enable_slot+0x4ee/0x5e0
> > [   16.131396]  [<ffffffff813418fb>] ? trim_stale_devices+0x5b/0xf0
> > [   16.137420]  [<ffffffff81341b35>] acpiphp_check_bridge+0xd5/0x110
> > [   16.143531]  [<ffffffff81342acb>] hotplug_event+0x16b/0x260
> > [   16.149115]  [<ffffffff81072cd9>] ? process_one_work+0x189/0x540
> > [   16.155136]  [<ffffffff81342bf0>] hotplug_event_work+0x30/0x70
> > [   16.160978]  [<ffffffff81072d3b>] process_one_work+0x1eb/0x540
> > [   16.166819]  [<ffffffff81072cd9>] ? process_one_work+0x189/0x540
> > [   16.172836]  [<ffffffff8107353c>] worker_thread+0x11c/0x370
> > [   16.178426]  [<ffffffff81073420>] ? rescuer_thread+0x350/0x350
> > [   16.184276]  [<ffffffff8107b0ea>] kthread+0xea/0xf0
> > [   16.189165]  [<ffffffff8107b000>] ? kthread_create_on_node+0x160/0x160
> > [   16.195700]  [<ffffffff816395dc>] ret_from_fork+0x7c/0xb0
> > [   16.201109]  [<ffffffff8107b000>] ? kthread_create_on_node+0x160/0x160
> > 
> > The actual death of the serial console occurs in acpi_device_set_power()
> > called from:
> > 
> > enable_slot()
> >  acpiphp_bus_add()
> >   acpiphp_bus_trim()
> >    acpi_bus_trim()
> >     acpi_walk_namespace()
> >      acpi_bus_remove()
> >       acpi_device_unregister()
> >        acpi_device_set_power()
> > 
> > I can't seem to get a path from the acpi devices in question there, so I
> > have no idea what's getting trimmed here.  It worries me quite a bit by
> > introducing this trimming that apparently wasn't happening before
> > though.  Thanks,
> 
> As suspected, the pnp.bus_id/id of the last device before the serial
> console dies is COM1/PNP0501.  I also see all of these being trimmed
> out:
> 
>  MBRD/PNP0C02
>  DMAC/PNP0200
>  MATH/PNP0C04
>  PIC/PNP0000
>  HPET/PNP0103
>  RTC/PNP0B00
>  SPKR/PNP0800
>  TIME/PNP0100
>  LNK{A-H}/PNP0C0F
> 
> This seems like a bad idea.  I forgot to mention, the original
> hotplug_event is called with a device check on \_SB_.PCI0.PEX2.  The box
> where I'm seeing this is a pretty generic X58 based Nehalem workstation
> (Lenovo S20).

Thanks for the info!

The acpiphp_bus_trim() in acpiphp_bus_add() is a leftover and a bad one.
I don't think it's actually necessary, at least Thunderbolt works without
it just fine on my Aspire S5.

The patch below should help, can you please test it?

Rafael

---
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Subject: ACPI / hotplug / PCI: Don't trim devices before scanning the namespace

In acpiphp_bus_add() we first remove device objects corresponding to
the given handle and the ACPI namespace branch below it which are
then re-created by acpi_bus_scan().  This used to be done to clean
up after surprise removals, but now we do the cleanup through
trim_stale_devices() which checks if the devices in question are
actually gone before removing them, so the device hierarchy trimming
in acpiphp_bus_add() is not necessary any more and, moreover, it may
lead to problems if it removes device objects corresponding to
devices that are actually present.

Reported-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp_glue.c |    1 -
 1 file changed, 1 deletion(-)

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
@@ -487,7 +487,6 @@ static void acpiphp_bus_add(acpi_handle
 {
 	struct acpi_device *adev = NULL;
 
-	acpiphp_bus_trim(handle);
 	acpi_bus_scan(handle);
 	acpi_bus_get_device(handle, &adev);
 	if (adev)

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

* Re: [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots
  2013-09-05  6:17                 ` [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots Lan Tianyu
@ 2013-09-05 11:57                   ` Rafael J. Wysocki
  2013-09-05 13:11                     ` Lan Tianyu
  0 siblings, 1 reply; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-09-05 11:57 UTC (permalink / raw)
  To: Lan Tianyu
  Cc: Alex Williamson, ACPI Devel Maling List, Bjorn Helgaas, LKML,
	Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg,
	Kirill A. Shutemov

On Thursday, September 05, 2013 02:17:06 PM Lan Tianyu wrote:
> 2013/9/5 Alex Williamson <alex.williamson@redhat.com>:
> > On Thu, 2013-09-05 at 01:35 +0200, Rafael J. Wysocki wrote:
> >> On Wednesday, September 04, 2013 05:12:14 PM Alex Williamson wrote:
> >> > On Thu, 2013-09-05 at 00:54 +0200, Rafael J. Wysocki wrote:
> >> > > On Wednesday, September 04, 2013 02:36:34 PM Alex Williamson wrote:
> >> > > > On Thu, 2013-07-18 at 01:32 +0200, Rafael J. Wysocki wrote:
> >> > > > > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> >> > > > >
> >> > > > > The current implementation of acpiphp_check_bridge() is pretty dumb:
> >> > > > >  - It enables a slot if it's not enabled and the slot status is
> >> > > > >    ACPI_STA_ALL.
> >> > > > >  - It disables a slot if it's enabled and the slot status is not
> >> > > > >    ACPI_STA_ALL.
> >> > > > >
> >> > > > > This behavior is not sufficient to handle the Thunderbolt daisy
> >> > > > > chaining case properly, however, because in that case the bus
> >> > > > > behind the already enabled slot needs to be rescanned for new
> >> > > > > devices.
> >> > > > >
> >> > > > > For this reason, modify acpiphp_check_bridge() so that slots are
> >> > > > > disabled and stopped if they are not in the ACPI_STA_ALL state.
> >> > > > >
> >> > > > > For slots in the ACPI_STA_ALL state, devices behind them that don't
> >> > > > > respond are trimmed using a new function, trim_stale_devices(),
> >> > > > > introduced specifically for this purpose.  That function walks
> >> > > > > the given bus and checks each device on it.  If the device doesn't
> >> > > > > respond, it is assumed to be gone and is removed.
> >> > > > >
> >> > > > > Once all of the stale devices directy behind the slot have been
> >> > > > > removed, acpiphp_check_bridge() will start looking for new devices
> >> > > > > that might have appeared on the given bus.  It will do that even if
> >> > > > > the slot is already enabled (SLOT_ENABLED is set for it).
> >> > > > >
> >> > > > > In addition to that, make the bus check notification ignore
> >> > > > > SLOT_ENABLED and go for enable_device() directly if bridge is NULL,
> >> > > > > so that devices behind the slot are re-enumerated in that case too.
> >> > > > >
> >> > > > > This change is based on earlier patches from Kirill A Shutemov
> >> > > > > and Mika Westerberg.
> >> > > > >
> >> > > > > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> >> > > > > Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
> >> > > > > ---
> >> > > >
> >> > > > FYI, git bisect landed on this patch as the cause of my serial console
> >> > > > dying on current upstream.  Further debugging to come...  Thanks,
> >> > >
> >> > > Well, sorry about that.
> >> > >
> >> > > What exactly do you mean by "dying"?
> >> >
> >> > Sorry, I was hoping to have more details quickly, but it's been a pain
> >> > to debug.  By dying I mean serial console output suddenly stops during
> >> > kernel boot and nothing more comes out of it until after the system is
> >> > rebooted.  The problem happens when acpiphp_check_bridge() calls
> >> > enable_slot().  The serial console dies somewhere down in
> >> > acpiphp_bus_trim().  I think this is happening on the 00:1f ISA bridge,
> >> > so there's a good chance the serial ports are described as somewhere
> >> > under there.
> >>
> >> Can you please check if that is the acpiphp_bus_trim() called by
> >> acpiphp_bus_add() or the other one called from trim_stale_devices()?
> >>
> >> Just add a dump_stack() or WARN_ON(1) to trim_stale_devices() next to
> >> the acpiphp_bus_trim() call and see if that triggers.  I *think* it's the one
> >> in acpiphp_bus_add(), but it won't hurt to verify that.
> >
> > Here's the call path:
> >
> > [   16.120824]  [<ffffffff81627e6c>] dump_stack+0x55/0x76
> > [   16.125979]  [<ffffffff8162132e>] enable_slot+0x4ee/0x5e0
> > [   16.131396]  [<ffffffff813418fb>] ? trim_stale_devices+0x5b/0xf0
> > [   16.137420]  [<ffffffff81341b35>] acpiphp_check_bridge+0xd5/0x110
> > [   16.143531]  [<ffffffff81342acb>] hotplug_event+0x16b/0x260
> > [   16.149115]  [<ffffffff81072cd9>] ? process_one_work+0x189/0x540
> > [   16.155136]  [<ffffffff81342bf0>] hotplug_event_work+0x30/0x70
> > [   16.160978]  [<ffffffff81072d3b>] process_one_work+0x1eb/0x540
> > [   16.166819]  [<ffffffff81072cd9>] ? process_one_work+0x189/0x540
> > [   16.172836]  [<ffffffff8107353c>] worker_thread+0x11c/0x370
> > [   16.178426]  [<ffffffff81073420>] ? rescuer_thread+0x350/0x350
> > [   16.184276]  [<ffffffff8107b0ea>] kthread+0xea/0xf0
> > [   16.189165]  [<ffffffff8107b000>] ? kthread_create_on_node+0x160/0x160
> > [   16.195700]  [<ffffffff816395dc>] ret_from_fork+0x7c/0xb0
> > [   16.201109]  [<ffffffff8107b000>] ? kthread_create_on_node+0x160/0x160
> >
> > The actual death of the serial console occurs in acpi_device_set_power()
> > called from:
> >
> > enable_slot()
> >  acpiphp_bus_add()
> >   acpiphp_bus_trim()
> >    acpi_bus_trim()
> >     acpi_walk_namespace()
> >      acpi_bus_remove()
> >       acpi_device_unregister()
> >        acpi_device_set_power()
> >
> > I can't seem to get a path from the acpi devices in question there, so I
> > have no idea what's getting trimmed here.  It worries me quite a bit by
> > introducing this trimming that apparently wasn't happening before
> > though.  Thanks,
> 
> Hi Alex:
>            Could you apply the following patch and bootup with kernel param
> "acpiphp.acpiphp_debug=1"?
>            I guess the patch can make serial port alive. It will not
> be put into D3cold
> during trimming. But I don't know why it doesn't work after being put
> back to D0.

Do we actually put it into D0 in acpi_bus_scan()?  I don't think so.

> So please attach output of acpidump and the dmesg if it can work. Thanks.
> 
> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
> index e763651..359b23d 100644
> --- a/drivers/acpi/scan.c
> +++ b/drivers/acpi/scan.c
> @@ -1110,7 +1110,7 @@ static void acpi_device_unregister(struct
> acpi_device *device)
>          * power resources the device depends on and turn off the ones that have
>          * no more references.
>          */
> -       acpi_device_set_power(device, ACPI_STATE_D3_COLD);
> +       //acpi_device_set_power(device, ACPI_STATE_D3_COLD);
>         device->handle = NULL;
>         put_device(&device->dev);
>  }

I don't think we should do the trimming in acpiphp_bus_add() at all.

Thanks,
Rafael

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

* Re: [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots
  2013-09-05 11:57                   ` Rafael J. Wysocki
@ 2013-09-05 13:11                     ` Lan Tianyu
  2013-09-05 21:43                       ` Rafael J. Wysocki
  0 siblings, 1 reply; 135+ messages in thread
From: Lan Tianyu @ 2013-09-05 13:11 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Alex Williamson, ACPI Devel Maling List, Bjorn Helgaas, LKML,
	Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg,
	Kirill A. Shutemov

2013/9/5 Rafael J. Wysocki <rjw@sisk.pl>:
> On Thursday, September 05, 2013 02:17:06 PM Lan Tianyu wrote:
>> 2013/9/5 Alex Williamson <alex.williamson@redhat.com>:
>> > On Thu, 2013-09-05 at 01:35 +0200, Rafael J. Wysocki wrote:
>> >> On Wednesday, September 04, 2013 05:12:14 PM Alex Williamson wrote:
>> >> > On Thu, 2013-09-05 at 00:54 +0200, Rafael J. Wysocki wrote:
>> >> > > On Wednesday, September 04, 2013 02:36:34 PM Alex Williamson wrote:
>> >> > > > On Thu, 2013-07-18 at 01:32 +0200, Rafael J. Wysocki wrote:
>> >> > > > > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>> >> > > > >
>> >> > > > > The current implementation of acpiphp_check_bridge() is pretty dumb:
>> >> > > > >  - It enables a slot if it's not enabled and the slot status is
>> >> > > > >    ACPI_STA_ALL.
>> >> > > > >  - It disables a slot if it's enabled and the slot status is not
>> >> > > > >    ACPI_STA_ALL.
>> >> > > > >
>> >> > > > > This behavior is not sufficient to handle the Thunderbolt daisy
>> >> > > > > chaining case properly, however, because in that case the bus
>> >> > > > > behind the already enabled slot needs to be rescanned for new
>> >> > > > > devices.
>> >> > > > >
>> >> > > > > For this reason, modify acpiphp_check_bridge() so that slots are
>> >> > > > > disabled and stopped if they are not in the ACPI_STA_ALL state.
>> >> > > > >
>> >> > > > > For slots in the ACPI_STA_ALL state, devices behind them that don't
>> >> > > > > respond are trimmed using a new function, trim_stale_devices(),
>> >> > > > > introduced specifically for this purpose.  That function walks
>> >> > > > > the given bus and checks each device on it.  If the device doesn't
>> >> > > > > respond, it is assumed to be gone and is removed.
>> >> > > > >
>> >> > > > > Once all of the stale devices directy behind the slot have been
>> >> > > > > removed, acpiphp_check_bridge() will start looking for new devices
>> >> > > > > that might have appeared on the given bus.  It will do that even if
>> >> > > > > the slot is already enabled (SLOT_ENABLED is set for it).
>> >> > > > >
>> >> > > > > In addition to that, make the bus check notification ignore
>> >> > > > > SLOT_ENABLED and go for enable_device() directly if bridge is NULL,
>> >> > > > > so that devices behind the slot are re-enumerated in that case too.
>> >> > > > >
>> >> > > > > This change is based on earlier patches from Kirill A Shutemov
>> >> > > > > and Mika Westerberg.
>> >> > > > >
>> >> > > > > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>> >> > > > > Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
>> >> > > > > ---
>> >> > > >
>> >> > > > FYI, git bisect landed on this patch as the cause of my serial console
>> >> > > > dying on current upstream.  Further debugging to come...  Thanks,
>> >> > >
>> >> > > Well, sorry about that.
>> >> > >
>> >> > > What exactly do you mean by "dying"?
>> >> >
>> >> > Sorry, I was hoping to have more details quickly, but it's been a pain
>> >> > to debug.  By dying I mean serial console output suddenly stops during
>> >> > kernel boot and nothing more comes out of it until after the system is
>> >> > rebooted.  The problem happens when acpiphp_check_bridge() calls
>> >> > enable_slot().  The serial console dies somewhere down in
>> >> > acpiphp_bus_trim().  I think this is happening on the 00:1f ISA bridge,
>> >> > so there's a good chance the serial ports are described as somewhere
>> >> > under there.
>> >>
>> >> Can you please check if that is the acpiphp_bus_trim() called by
>> >> acpiphp_bus_add() or the other one called from trim_stale_devices()?
>> >>
>> >> Just add a dump_stack() or WARN_ON(1) to trim_stale_devices() next to
>> >> the acpiphp_bus_trim() call and see if that triggers.  I *think* it's the one
>> >> in acpiphp_bus_add(), but it won't hurt to verify that.
>> >
>> > Here's the call path:
>> >
>> > [   16.120824]  [<ffffffff81627e6c>] dump_stack+0x55/0x76
>> > [   16.125979]  [<ffffffff8162132e>] enable_slot+0x4ee/0x5e0
>> > [   16.131396]  [<ffffffff813418fb>] ? trim_stale_devices+0x5b/0xf0
>> > [   16.137420]  [<ffffffff81341b35>] acpiphp_check_bridge+0xd5/0x110
>> > [   16.143531]  [<ffffffff81342acb>] hotplug_event+0x16b/0x260
>> > [   16.149115]  [<ffffffff81072cd9>] ? process_one_work+0x189/0x540
>> > [   16.155136]  [<ffffffff81342bf0>] hotplug_event_work+0x30/0x70
>> > [   16.160978]  [<ffffffff81072d3b>] process_one_work+0x1eb/0x540
>> > [   16.166819]  [<ffffffff81072cd9>] ? process_one_work+0x189/0x540
>> > [   16.172836]  [<ffffffff8107353c>] worker_thread+0x11c/0x370
>> > [   16.178426]  [<ffffffff81073420>] ? rescuer_thread+0x350/0x350
>> > [   16.184276]  [<ffffffff8107b0ea>] kthread+0xea/0xf0
>> > [   16.189165]  [<ffffffff8107b000>] ? kthread_create_on_node+0x160/0x160
>> > [   16.195700]  [<ffffffff816395dc>] ret_from_fork+0x7c/0xb0
>> > [   16.201109]  [<ffffffff8107b000>] ? kthread_create_on_node+0x160/0x160
>> >
>> > The actual death of the serial console occurs in acpi_device_set_power()
>> > called from:
>> >
>> > enable_slot()
>> >  acpiphp_bus_add()
>> >   acpiphp_bus_trim()
>> >    acpi_bus_trim()
>> >     acpi_walk_namespace()
>> >      acpi_bus_remove()
>> >       acpi_device_unregister()
>> >        acpi_device_set_power()
>> >
>> > I can't seem to get a path from the acpi devices in question there, so I
>> > have no idea what's getting trimmed here.  It worries me quite a bit by
>> > introducing this trimming that apparently wasn't happening before
>> > though.  Thanks,
>>
>> Hi Alex:
>>            Could you apply the following patch and bootup with kernel param
>> "acpiphp.acpiphp_debug=1"?
>>            I guess the patch can make serial port alive. It will not
>> be put into D3cold
>> during trimming. But I don't know why it doesn't work after being put
>> back to D0.
>
> Do we actually put it into D0 in acpi_bus_scan()?  I don't think so.
>

Hi Rafael:
         I mean the code in the acpiphp_bus_add(). After trimming and acpi
bus scan handle, the device will be put back to D0 if acpi_bus_get_device()
return acpi device. So I thought the serial port is put back to D0.

>> So please attach output of acpidump and the dmesg if it can work. Thanks.
>>
>> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
>> index e763651..359b23d 100644
>> --- a/drivers/acpi/scan.c
>> +++ b/drivers/acpi/scan.c
>> @@ -1110,7 +1110,7 @@ static void acpi_device_unregister(struct
>> acpi_device *device)
>>          * power resources the device depends on and turn off the ones that have
>>          * no more references.
>>          */
>> -       acpi_device_set_power(device, ACPI_STATE_D3_COLD);
>> +       //acpi_device_set_power(device, ACPI_STATE_D3_COLD);
>>         device->handle = NULL;
>>         put_device(&device->dev);
>>  }
>
> I don't think we should do the trimming in acpiphp_bus_add() at all.

Yes,  I agree.

>
> Thanks,
> Rafael
>



-- 
Best regards
Tianyu Lan

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

* Re: [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots
  2013-09-05 11:54                   ` Rafael J. Wysocki
@ 2013-09-05 13:19                     ` Alex Williamson
  2013-09-05 14:21                       ` Alex Williamson
  0 siblings, 1 reply; 135+ messages in thread
From: Alex Williamson @ 2013-09-05 13:19 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Thu, 2013-09-05 at 13:54 +0200, Rafael J. Wysocki wrote:
> On Wednesday, September 04, 2013 10:06:02 PM Alex Williamson wrote:
> > On Wed, 2013-09-04 at 21:37 -0600, Alex Williamson wrote:
> > > On Thu, 2013-09-05 at 01:35 +0200, Rafael J. Wysocki wrote:
> > > > On Wednesday, September 04, 2013 05:12:14 PM Alex Williamson wrote:
> > > > > On Thu, 2013-09-05 at 00:54 +0200, Rafael J. Wysocki wrote:
> > > > > > On Wednesday, September 04, 2013 02:36:34 PM Alex Williamson wrote:
> > > > > > > On Thu, 2013-07-18 at 01:32 +0200, Rafael J. Wysocki wrote:
> > > > > > > > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > > > > > > > 
> > > > > > > > The current implementation of acpiphp_check_bridge() is pretty dumb:
> > > > > > > >  - It enables a slot if it's not enabled and the slot status is
> > > > > > > >    ACPI_STA_ALL.
> > > > > > > >  - It disables a slot if it's enabled and the slot status is not
> > > > > > > >    ACPI_STA_ALL.
> > > > > > > > 
> > > > > > > > This behavior is not sufficient to handle the Thunderbolt daisy
> > > > > > > > chaining case properly, however, because in that case the bus
> > > > > > > > behind the already enabled slot needs to be rescanned for new
> > > > > > > > devices.
> > > > > > > > 
> > > > > > > > For this reason, modify acpiphp_check_bridge() so that slots are
> > > > > > > > disabled and stopped if they are not in the ACPI_STA_ALL state.
> > > > > > > > 
> > > > > > > > For slots in the ACPI_STA_ALL state, devices behind them that don't
> > > > > > > > respond are trimmed using a new function, trim_stale_devices(),
> > > > > > > > introduced specifically for this purpose.  That function walks
> > > > > > > > the given bus and checks each device on it.  If the device doesn't
> > > > > > > > respond, it is assumed to be gone and is removed.
> > > > > > > > 
> > > > > > > > Once all of the stale devices directy behind the slot have been
> > > > > > > > removed, acpiphp_check_bridge() will start looking for new devices
> > > > > > > > that might have appeared on the given bus.  It will do that even if
> > > > > > > > the slot is already enabled (SLOT_ENABLED is set for it).
> > > > > > > > 
> > > > > > > > In addition to that, make the bus check notification ignore
> > > > > > > > SLOT_ENABLED and go for enable_device() directly if bridge is NULL,
> > > > > > > > so that devices behind the slot are re-enumerated in that case too.
> > > > > > > > 
> > > > > > > > This change is based on earlier patches from Kirill A Shutemov
> > > > > > > > and Mika Westerberg.
> > > > > > > > 
> > > > > > > > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > > > > > > > Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
> > > > > > > > ---
> > > > > > > 
> > > > > > > FYI, git bisect landed on this patch as the cause of my serial console
> > > > > > > dying on current upstream.  Further debugging to come...  Thanks,
> > > > > > 
> > > > > > Well, sorry about that.
> > > > > > 
> > > > > > What exactly do you mean by "dying"?
> > > > > 
> > > > > Sorry, I was hoping to have more details quickly, but it's been a pain
> > > > > to debug.  By dying I mean serial console output suddenly stops during
> > > > > kernel boot and nothing more comes out of it until after the system is
> > > > > rebooted.  The problem happens when acpiphp_check_bridge() calls
> > > > > enable_slot().  The serial console dies somewhere down in
> > > > > acpiphp_bus_trim().  I think this is happening on the 00:1f ISA bridge,
> > > > > so there's a good chance the serial ports are described as somewhere
> > > > > under there.
> > > > 
> > > > Can you please check if that is the acpiphp_bus_trim() called by
> > > > acpiphp_bus_add() or the other one called from trim_stale_devices()?
> > > > 
> > > > Just add a dump_stack() or WARN_ON(1) to trim_stale_devices() next to
> > > > the acpiphp_bus_trim() call and see if that triggers.  I *think* it's the one
> > > > in acpiphp_bus_add(), but it won't hurt to verify that.
> > > 
> > > Here's the call path:
> > > 
> > > [   16.120824]  [<ffffffff81627e6c>] dump_stack+0x55/0x76
> > > [   16.125979]  [<ffffffff8162132e>] enable_slot+0x4ee/0x5e0
> > > [   16.131396]  [<ffffffff813418fb>] ? trim_stale_devices+0x5b/0xf0
> > > [   16.137420]  [<ffffffff81341b35>] acpiphp_check_bridge+0xd5/0x110
> > > [   16.143531]  [<ffffffff81342acb>] hotplug_event+0x16b/0x260
> > > [   16.149115]  [<ffffffff81072cd9>] ? process_one_work+0x189/0x540
> > > [   16.155136]  [<ffffffff81342bf0>] hotplug_event_work+0x30/0x70
> > > [   16.160978]  [<ffffffff81072d3b>] process_one_work+0x1eb/0x540
> > > [   16.166819]  [<ffffffff81072cd9>] ? process_one_work+0x189/0x540
> > > [   16.172836]  [<ffffffff8107353c>] worker_thread+0x11c/0x370
> > > [   16.178426]  [<ffffffff81073420>] ? rescuer_thread+0x350/0x350
> > > [   16.184276]  [<ffffffff8107b0ea>] kthread+0xea/0xf0
> > > [   16.189165]  [<ffffffff8107b000>] ? kthread_create_on_node+0x160/0x160
> > > [   16.195700]  [<ffffffff816395dc>] ret_from_fork+0x7c/0xb0
> > > [   16.201109]  [<ffffffff8107b000>] ? kthread_create_on_node+0x160/0x160
> > > 
> > > The actual death of the serial console occurs in acpi_device_set_power()
> > > called from:
> > > 
> > > enable_slot()
> > >  acpiphp_bus_add()
> > >   acpiphp_bus_trim()
> > >    acpi_bus_trim()
> > >     acpi_walk_namespace()
> > >      acpi_bus_remove()
> > >       acpi_device_unregister()
> > >        acpi_device_set_power()
> > > 
> > > I can't seem to get a path from the acpi devices in question there, so I
> > > have no idea what's getting trimmed here.  It worries me quite a bit by
> > > introducing this trimming that apparently wasn't happening before
> > > though.  Thanks,
> > 
> > As suspected, the pnp.bus_id/id of the last device before the serial
> > console dies is COM1/PNP0501.  I also see all of these being trimmed
> > out:
> > 
> >  MBRD/PNP0C02
> >  DMAC/PNP0200
> >  MATH/PNP0C04
> >  PIC/PNP0000
> >  HPET/PNP0103
> >  RTC/PNP0B00
> >  SPKR/PNP0800
> >  TIME/PNP0100
> >  LNK{A-H}/PNP0C0F
> > 
> > This seems like a bad idea.  I forgot to mention, the original
> > hotplug_event is called with a device check on \_SB_.PCI0.PEX2.  The box
> > where I'm seeing this is a pretty generic X58 based Nehalem workstation
> > (Lenovo S20).
> 
> Thanks for the info!
> 
> The acpiphp_bus_trim() in acpiphp_bus_add() is a leftover and a bad one.
> I don't think it's actually necessary, at least Thunderbolt works without
> it just fine on my Aspire S5.
> 
> The patch below should help, can you please test it?
> 
> Rafael
> 
> ---
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> Subject: ACPI / hotplug / PCI: Don't trim devices before scanning the namespace
> 
> In acpiphp_bus_add() we first remove device objects corresponding to
> the given handle and the ACPI namespace branch below it which are
> then re-created by acpi_bus_scan().  This used to be done to clean
> up after surprise removals, but now we do the cleanup through
> trim_stale_devices() which checks if the devices in question are
> actually gone before removing them, so the device hierarchy trimming
> in acpiphp_bus_add() is not necessary any more and, moreover, it may
> lead to problems if it removes device objects corresponding to
> devices that are actually present.
> 
> Reported-by: Alex Williamson <alex.williamson@redhat.com>
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> ---
>  drivers/pci/hotplug/acpiphp_glue.c |    1 -
>  1 file changed, 1 deletion(-)
> 
> 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
> @@ -487,7 +487,6 @@ static void acpiphp_bus_add(acpi_handle
>  {
>  	struct acpi_device *adev = NULL;
>  
> -	acpiphp_bus_trim(handle);
>  	acpi_bus_scan(handle);
>  	acpi_bus_get_device(handle, &adev);
>  	if (adev)
> 
> 

It boots again and the console works, but I see screens and screens of
messages like this:

[   18.288122] pci 0000:00:00.0: no hotplug settings from platform
[   18.288127] pcieport 0000:00:01.0: no hotplug settings from platform
[   18.288142] pci 0000:01:00.0: no hotplug settings from platform
[   18.288157] pci 0000:01:00.1: no hotplug settings from platform
[   18.288162] pcieport 0000:00:03.0: no hotplug settings from platform
[   18.288176] pci 0000:02:00.0: no hotplug settings from platform
[   18.288190] pci 0000:02:00.1: no hotplug settings from platform
[   18.288195] pcieport 0000:00:07.0: no hotplug settings from platform
[   18.288209] pci 0000:03:00.0: no hotplug settings from platform
[   18.288224] pci 0000:03:00.1: no hotplug settings from platform
[   18.288228] pci 0000:00:14.0: no hotplug settings from platform
[   18.288233] pci 0000:00:14.1: no hotplug settings from platform
[   18.288237] pci 0000:00:14.2: no hotplug settings from platform
[   18.288242] pci 0000:00:16.0: no hotplug settings from platform
[   18.288247] pci 0000:00:16.1: no hotplug settings from platform
[   18.288251] pci 0000:00:16.2: no hotplug settings from platform
[   18.288256] pci 0000:00:16.3: no hotplug settings from platform
[   18.288260] pci 0000:00:16.4: no hotplug settings from platform
[   18.288265] pci 0000:00:16.5: no hotplug settings from platform
[   18.288269] pci 0000:00:16.6: no hotplug settings from platform
[   18.288274] pci 0000:00:16.7: no hotplug settings from platform
[   18.288278] pci 0000:00:1a.0: no hotplug settings from platform
[   18.288279] pci 0000:00:1a.0: using default PCI settings
[   18.288292] pci 0000:00:1a.1: no hotplug settings from platform
[   18.288293] pci 0000:00:1a.1: using default PCI settings
[   18.288307] ehci-pci 0000:00:1a.7: no hotplug settings from platform
[   18.288308] ehci-pci 0000:00:1a.7: using default PCI settings
[   18.288322] pci 0000:00:1b.0: no hotplug settings from platform
[   18.288327] pcieport 0000:00:1c.0: no hotplug settings from platform
[   18.288332] pcieport 0000:00:1c.4: no hotplug settings from platform
[   18.288344] pci 0000:05:00.0: no hotplug settings from platform
[   18.288349] pci 0000:00:1d.0: no hotplug settings from platform
[   18.288350] pci 0000:00:1d.0: using default PCI settings
[   18.288360] pci 0000:00:1d.1: no hotplug settings from platform
[   18.288361] pci 0000:00:1d.1: using default PCI settings
[   18.288374] pci 0000:00:1d.2: no hotplug settings from platform
[   18.288374] pci 0000:00:1d.2: using default PCI settings
[   18.288387] pci 0000:00:1d.3: no hotplug settings from platform
[   18.288387] pci 0000:00:1d.3: using default PCI settings

The boot is noticeably slower.  What's going to happen on systems that
actually have a significant I/O topology vs my little workstation?
Thanks,

Alex

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

* Re: [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots
  2013-09-05 13:19                     ` Alex Williamson
@ 2013-09-05 14:21                       ` Alex Williamson
  2013-09-05 19:44                         ` Excess dmesg output from ACPIPHP on boot (was: Re: [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots) Rafael J. Wysocki
  0 siblings, 1 reply; 135+ messages in thread
From: Alex Williamson @ 2013-09-05 14:21 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Thu, 2013-09-05 at 07:19 -0600, Alex Williamson wrote:
> On Thu, 2013-09-05 at 13:54 +0200, Rafael J. Wysocki wrote:
> > On Wednesday, September 04, 2013 10:06:02 PM Alex Williamson wrote:
> > > On Wed, 2013-09-04 at 21:37 -0600, Alex Williamson wrote:
> > > > On Thu, 2013-09-05 at 01:35 +0200, Rafael J. Wysocki wrote:
> > > > > On Wednesday, September 04, 2013 05:12:14 PM Alex Williamson wrote:
> > > > > > On Thu, 2013-09-05 at 00:54 +0200, Rafael J. Wysocki wrote:
> > > > > > > On Wednesday, September 04, 2013 02:36:34 PM Alex Williamson wrote:
> > > > > > > > On Thu, 2013-07-18 at 01:32 +0200, Rafael J. Wysocki wrote:
> > > > > > > > > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > > > > > > > > 
> > > > > > > > > The current implementation of acpiphp_check_bridge() is pretty dumb:
> > > > > > > > >  - It enables a slot if it's not enabled and the slot status is
> > > > > > > > >    ACPI_STA_ALL.
> > > > > > > > >  - It disables a slot if it's enabled and the slot status is not
> > > > > > > > >    ACPI_STA_ALL.
> > > > > > > > > 
> > > > > > > > > This behavior is not sufficient to handle the Thunderbolt daisy
> > > > > > > > > chaining case properly, however, because in that case the bus
> > > > > > > > > behind the already enabled slot needs to be rescanned for new
> > > > > > > > > devices.
> > > > > > > > > 
> > > > > > > > > For this reason, modify acpiphp_check_bridge() so that slots are
> > > > > > > > > disabled and stopped if they are not in the ACPI_STA_ALL state.
> > > > > > > > > 
> > > > > > > > > For slots in the ACPI_STA_ALL state, devices behind them that don't
> > > > > > > > > respond are trimmed using a new function, trim_stale_devices(),
> > > > > > > > > introduced specifically for this purpose.  That function walks
> > > > > > > > > the given bus and checks each device on it.  If the device doesn't
> > > > > > > > > respond, it is assumed to be gone and is removed.
> > > > > > > > > 
> > > > > > > > > Once all of the stale devices directy behind the slot have been
> > > > > > > > > removed, acpiphp_check_bridge() will start looking for new devices
> > > > > > > > > that might have appeared on the given bus.  It will do that even if
> > > > > > > > > the slot is already enabled (SLOT_ENABLED is set for it).
> > > > > > > > > 
> > > > > > > > > In addition to that, make the bus check notification ignore
> > > > > > > > > SLOT_ENABLED and go for enable_device() directly if bridge is NULL,
> > > > > > > > > so that devices behind the slot are re-enumerated in that case too.
> > > > > > > > > 
> > > > > > > > > This change is based on earlier patches from Kirill A Shutemov
> > > > > > > > > and Mika Westerberg.
> > > > > > > > > 
> > > > > > > > > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > > > > > > > > Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
> > > > > > > > > ---
> > > > > > > > 
> > > > > > > > FYI, git bisect landed on this patch as the cause of my serial console
> > > > > > > > dying on current upstream.  Further debugging to come...  Thanks,
> > > > > > > 
> > > > > > > Well, sorry about that.
> > > > > > > 
> > > > > > > What exactly do you mean by "dying"?
> > > > > > 
> > > > > > Sorry, I was hoping to have more details quickly, but it's been a pain
> > > > > > to debug.  By dying I mean serial console output suddenly stops during
> > > > > > kernel boot and nothing more comes out of it until after the system is
> > > > > > rebooted.  The problem happens when acpiphp_check_bridge() calls
> > > > > > enable_slot().  The serial console dies somewhere down in
> > > > > > acpiphp_bus_trim().  I think this is happening on the 00:1f ISA bridge,
> > > > > > so there's a good chance the serial ports are described as somewhere
> > > > > > under there.
> > > > > 
> > > > > Can you please check if that is the acpiphp_bus_trim() called by
> > > > > acpiphp_bus_add() or the other one called from trim_stale_devices()?
> > > > > 
> > > > > Just add a dump_stack() or WARN_ON(1) to trim_stale_devices() next to
> > > > > the acpiphp_bus_trim() call and see if that triggers.  I *think* it's the one
> > > > > in acpiphp_bus_add(), but it won't hurt to verify that.
> > > > 
> > > > Here's the call path:
> > > > 
> > > > [   16.120824]  [<ffffffff81627e6c>] dump_stack+0x55/0x76
> > > > [   16.125979]  [<ffffffff8162132e>] enable_slot+0x4ee/0x5e0
> > > > [   16.131396]  [<ffffffff813418fb>] ? trim_stale_devices+0x5b/0xf0
> > > > [   16.137420]  [<ffffffff81341b35>] acpiphp_check_bridge+0xd5/0x110
> > > > [   16.143531]  [<ffffffff81342acb>] hotplug_event+0x16b/0x260
> > > > [   16.149115]  [<ffffffff81072cd9>] ? process_one_work+0x189/0x540
> > > > [   16.155136]  [<ffffffff81342bf0>] hotplug_event_work+0x30/0x70
> > > > [   16.160978]  [<ffffffff81072d3b>] process_one_work+0x1eb/0x540
> > > > [   16.166819]  [<ffffffff81072cd9>] ? process_one_work+0x189/0x540
> > > > [   16.172836]  [<ffffffff8107353c>] worker_thread+0x11c/0x370
> > > > [   16.178426]  [<ffffffff81073420>] ? rescuer_thread+0x350/0x350
> > > > [   16.184276]  [<ffffffff8107b0ea>] kthread+0xea/0xf0
> > > > [   16.189165]  [<ffffffff8107b000>] ? kthread_create_on_node+0x160/0x160
> > > > [   16.195700]  [<ffffffff816395dc>] ret_from_fork+0x7c/0xb0
> > > > [   16.201109]  [<ffffffff8107b000>] ? kthread_create_on_node+0x160/0x160
> > > > 
> > > > The actual death of the serial console occurs in acpi_device_set_power()
> > > > called from:
> > > > 
> > > > enable_slot()
> > > >  acpiphp_bus_add()
> > > >   acpiphp_bus_trim()
> > > >    acpi_bus_trim()
> > > >     acpi_walk_namespace()
> > > >      acpi_bus_remove()
> > > >       acpi_device_unregister()
> > > >        acpi_device_set_power()
> > > > 
> > > > I can't seem to get a path from the acpi devices in question there, so I
> > > > have no idea what's getting trimmed here.  It worries me quite a bit by
> > > > introducing this trimming that apparently wasn't happening before
> > > > though.  Thanks,
> > > 
> > > As suspected, the pnp.bus_id/id of the last device before the serial
> > > console dies is COM1/PNP0501.  I also see all of these being trimmed
> > > out:
> > > 
> > >  MBRD/PNP0C02
> > >  DMAC/PNP0200
> > >  MATH/PNP0C04
> > >  PIC/PNP0000
> > >  HPET/PNP0103
> > >  RTC/PNP0B00
> > >  SPKR/PNP0800
> > >  TIME/PNP0100
> > >  LNK{A-H}/PNP0C0F
> > > 
> > > This seems like a bad idea.  I forgot to mention, the original
> > > hotplug_event is called with a device check on \_SB_.PCI0.PEX2.  The box
> > > where I'm seeing this is a pretty generic X58 based Nehalem workstation
> > > (Lenovo S20).
> > 
> > Thanks for the info!
> > 
> > The acpiphp_bus_trim() in acpiphp_bus_add() is a leftover and a bad one.
> > I don't think it's actually necessary, at least Thunderbolt works without
> > it just fine on my Aspire S5.
> > 
> > The patch below should help, can you please test it?
> > 
> > Rafael
> > 
> > ---
> > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > Subject: ACPI / hotplug / PCI: Don't trim devices before scanning the namespace
> > 
> > In acpiphp_bus_add() we first remove device objects corresponding to
> > the given handle and the ACPI namespace branch below it which are
> > then re-created by acpi_bus_scan().  This used to be done to clean
> > up after surprise removals, but now we do the cleanup through
> > trim_stale_devices() which checks if the devices in question are
> > actually gone before removing them, so the device hierarchy trimming
> > in acpiphp_bus_add() is not necessary any more and, moreover, it may
> > lead to problems if it removes device objects corresponding to
> > devices that are actually present.
> > 
> > Reported-by: Alex Williamson <alex.williamson@redhat.com>
> > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > ---
> >  drivers/pci/hotplug/acpiphp_glue.c |    1 -
> >  1 file changed, 1 deletion(-)
> > 
> > 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
> > @@ -487,7 +487,6 @@ static void acpiphp_bus_add(acpi_handle
> >  {
> >  	struct acpi_device *adev = NULL;
> >  
> > -	acpiphp_bus_trim(handle);
> >  	acpi_bus_scan(handle);
> >  	acpi_bus_get_device(handle, &adev);
> >  	if (adev)
> > 
> > 
> 
> It boots again and the console works, but I see screens and screens of
> messages like this:
> 
> [   18.288122] pci 0000:00:00.0: no hotplug settings from platform
> [   18.288127] pcieport 0000:00:01.0: no hotplug settings from platform
> [   18.288142] pci 0000:01:00.0: no hotplug settings from platform
> [   18.288157] pci 0000:01:00.1: no hotplug settings from platform
> [   18.288162] pcieport 0000:00:03.0: no hotplug settings from platform
> [   18.288176] pci 0000:02:00.0: no hotplug settings from platform
> [   18.288190] pci 0000:02:00.1: no hotplug settings from platform
> [   18.288195] pcieport 0000:00:07.0: no hotplug settings from platform
> [   18.288209] pci 0000:03:00.0: no hotplug settings from platform
> [   18.288224] pci 0000:03:00.1: no hotplug settings from platform
> [   18.288228] pci 0000:00:14.0: no hotplug settings from platform
> [   18.288233] pci 0000:00:14.1: no hotplug settings from platform
> [   18.288237] pci 0000:00:14.2: no hotplug settings from platform
> [   18.288242] pci 0000:00:16.0: no hotplug settings from platform
> [   18.288247] pci 0000:00:16.1: no hotplug settings from platform
> [   18.288251] pci 0000:00:16.2: no hotplug settings from platform
> [   18.288256] pci 0000:00:16.3: no hotplug settings from platform
> [   18.288260] pci 0000:00:16.4: no hotplug settings from platform
> [   18.288265] pci 0000:00:16.5: no hotplug settings from platform
> [   18.288269] pci 0000:00:16.6: no hotplug settings from platform
> [   18.288274] pci 0000:00:16.7: no hotplug settings from platform
> [   18.288278] pci 0000:00:1a.0: no hotplug settings from platform
> [   18.288279] pci 0000:00:1a.0: using default PCI settings
> [   18.288292] pci 0000:00:1a.1: no hotplug settings from platform
> [   18.288293] pci 0000:00:1a.1: using default PCI settings
> [   18.288307] ehci-pci 0000:00:1a.7: no hotplug settings from platform
> [   18.288308] ehci-pci 0000:00:1a.7: using default PCI settings
> [   18.288322] pci 0000:00:1b.0: no hotplug settings from platform
> [   18.288327] pcieport 0000:00:1c.0: no hotplug settings from platform
> [   18.288332] pcieport 0000:00:1c.4: no hotplug settings from platform
> [   18.288344] pci 0000:05:00.0: no hotplug settings from platform
> [   18.288349] pci 0000:00:1d.0: no hotplug settings from platform
> [   18.288350] pci 0000:00:1d.0: using default PCI settings
> [   18.288360] pci 0000:00:1d.1: no hotplug settings from platform
> [   18.288361] pci 0000:00:1d.1: using default PCI settings
> [   18.288374] pci 0000:00:1d.2: no hotplug settings from platform
> [   18.288374] pci 0000:00:1d.2: using default PCI settings
> [   18.288387] pci 0000:00:1d.3: no hotplug settings from platform
> [   18.288387] pci 0000:00:1d.3: using default PCI settings
> 
> The boot is noticeably slower.  What's going to happen on systems that
> actually have a significant I/O topology vs my little workstation?

Just to give you an idea:

CONFIG_HOTPLUG_PCI_ACPI=y

$ dmesg | wc
  5697  49935 384368

$ dmesg | tail --lines=1
[   53.137123] Ebtables v2.0 registered

-- vs --

# CONFIG_HOTPLUG_PCI_ACPI is not set

$ dmesg | wc
 1053  9176 71652

$dmesg | tail --lines=1
[   28.917220] Ebtables v2.0 registered

So it spews out 5x more output with acpiphp enabled and takes and extra
24s to boot (nearly 2x).  Not good.  Thanks,

Alex



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

* Excess dmesg output from ACPIPHP on boot (was: Re: [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots)
  2013-09-05 14:21                       ` Alex Williamson
@ 2013-09-05 19:44                         ` Rafael J. Wysocki
  2013-09-05 21:39                           ` Rafael J. Wysocki
  0 siblings, 1 reply; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-09-05 19:44 UTC (permalink / raw)
  To: Alex Williamson
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Thursday, September 05, 2013 08:21:41 AM Alex Williamson wrote:
> On Thu, 2013-09-05 at 07:19 -0600, Alex Williamson wrote:
> > On Thu, 2013-09-05 at 13:54 +0200, Rafael J. Wysocki wrote:
> > > On Wednesday, September 04, 2013 10:06:02 PM Alex Williamson wrote:
> > > > On Wed, 2013-09-04 at 21:37 -0600, Alex Williamson wrote:
> > > > > On Thu, 2013-09-05 at 01:35 +0200, Rafael J. Wysocki wrote:
> > > > > > On Wednesday, September 04, 2013 05:12:14 PM Alex Williamson wrote:
> > > > > > > On Thu, 2013-09-05 at 00:54 +0200, Rafael J. Wysocki wrote:
> > > > > > > > On Wednesday, September 04, 2013 02:36:34 PM Alex Williamson wrote:
> > > > > > > > > On Thu, 2013-07-18 at 01:32 +0200, Rafael J. Wysocki wrote:
> > > > > > > > > > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > > > > > > > > > 
> > > > > > > > > > The current implementation of acpiphp_check_bridge() is pretty dumb:
> > > > > > > > > >  - It enables a slot if it's not enabled and the slot status is
> > > > > > > > > >    ACPI_STA_ALL.
> > > > > > > > > >  - It disables a slot if it's enabled and the slot status is not
> > > > > > > > > >    ACPI_STA_ALL.
> > > > > > > > > > 
> > > > > > > > > > This behavior is not sufficient to handle the Thunderbolt daisy
> > > > > > > > > > chaining case properly, however, because in that case the bus
> > > > > > > > > > behind the already enabled slot needs to be rescanned for new
> > > > > > > > > > devices.
> > > > > > > > > > 
> > > > > > > > > > For this reason, modify acpiphp_check_bridge() so that slots are
> > > > > > > > > > disabled and stopped if they are not in the ACPI_STA_ALL state.
> > > > > > > > > > 
> > > > > > > > > > For slots in the ACPI_STA_ALL state, devices behind them that don't
> > > > > > > > > > respond are trimmed using a new function, trim_stale_devices(),
> > > > > > > > > > introduced specifically for this purpose.  That function walks
> > > > > > > > > > the given bus and checks each device on it.  If the device doesn't
> > > > > > > > > > respond, it is assumed to be gone and is removed.
> > > > > > > > > > 
> > > > > > > > > > Once all of the stale devices directy behind the slot have been
> > > > > > > > > > removed, acpiphp_check_bridge() will start looking for new devices
> > > > > > > > > > that might have appeared on the given bus.  It will do that even if
> > > > > > > > > > the slot is already enabled (SLOT_ENABLED is set for it).
> > > > > > > > > > 
> > > > > > > > > > In addition to that, make the bus check notification ignore
> > > > > > > > > > SLOT_ENABLED and go for enable_device() directly if bridge is NULL,
> > > > > > > > > > so that devices behind the slot are re-enumerated in that case too.
> > > > > > > > > > 
> > > > > > > > > > This change is based on earlier patches from Kirill A Shutemov
> > > > > > > > > > and Mika Westerberg.
> > > > > > > > > > 
> > > > > > > > > > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > > > > > > > > > Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
> > > > > > > > > > ---
> > > > > > > > > 
> > > > > > > > > FYI, git bisect landed on this patch as the cause of my serial console
> > > > > > > > > dying on current upstream.  Further debugging to come...  Thanks,
> > > > > > > > 
> > > > > > > > Well, sorry about that.
> > > > > > > > 
> > > > > > > > What exactly do you mean by "dying"?
> > > > > > > 
> > > > > > > Sorry, I was hoping to have more details quickly, but it's been a pain
> > > > > > > to debug.  By dying I mean serial console output suddenly stops during
> > > > > > > kernel boot and nothing more comes out of it until after the system is
> > > > > > > rebooted.  The problem happens when acpiphp_check_bridge() calls
> > > > > > > enable_slot().  The serial console dies somewhere down in
> > > > > > > acpiphp_bus_trim().  I think this is happening on the 00:1f ISA bridge,
> > > > > > > so there's a good chance the serial ports are described as somewhere
> > > > > > > under there.
> > > > > > 
> > > > > > Can you please check if that is the acpiphp_bus_trim() called by
> > > > > > acpiphp_bus_add() or the other one called from trim_stale_devices()?
> > > > > > 
> > > > > > Just add a dump_stack() or WARN_ON(1) to trim_stale_devices() next to
> > > > > > the acpiphp_bus_trim() call and see if that triggers.  I *think* it's the one
> > > > > > in acpiphp_bus_add(), but it won't hurt to verify that.
> > > > > 
> > > > > Here's the call path:
> > > > > 
> > > > > [   16.120824]  [<ffffffff81627e6c>] dump_stack+0x55/0x76
> > > > > [   16.125979]  [<ffffffff8162132e>] enable_slot+0x4ee/0x5e0
> > > > > [   16.131396]  [<ffffffff813418fb>] ? trim_stale_devices+0x5b/0xf0
> > > > > [   16.137420]  [<ffffffff81341b35>] acpiphp_check_bridge+0xd5/0x110
> > > > > [   16.143531]  [<ffffffff81342acb>] hotplug_event+0x16b/0x260
> > > > > [   16.149115]  [<ffffffff81072cd9>] ? process_one_work+0x189/0x540
> > > > > [   16.155136]  [<ffffffff81342bf0>] hotplug_event_work+0x30/0x70
> > > > > [   16.160978]  [<ffffffff81072d3b>] process_one_work+0x1eb/0x540
> > > > > [   16.166819]  [<ffffffff81072cd9>] ? process_one_work+0x189/0x540
> > > > > [   16.172836]  [<ffffffff8107353c>] worker_thread+0x11c/0x370
> > > > > [   16.178426]  [<ffffffff81073420>] ? rescuer_thread+0x350/0x350
> > > > > [   16.184276]  [<ffffffff8107b0ea>] kthread+0xea/0xf0
> > > > > [   16.189165]  [<ffffffff8107b000>] ? kthread_create_on_node+0x160/0x160
> > > > > [   16.195700]  [<ffffffff816395dc>] ret_from_fork+0x7c/0xb0
> > > > > [   16.201109]  [<ffffffff8107b000>] ? kthread_create_on_node+0x160/0x160
> > > > > 
> > > > > The actual death of the serial console occurs in acpi_device_set_power()
> > > > > called from:
> > > > > 
> > > > > enable_slot()
> > > > >  acpiphp_bus_add()
> > > > >   acpiphp_bus_trim()
> > > > >    acpi_bus_trim()
> > > > >     acpi_walk_namespace()
> > > > >      acpi_bus_remove()
> > > > >       acpi_device_unregister()
> > > > >        acpi_device_set_power()
> > > > > 
> > > > > I can't seem to get a path from the acpi devices in question there, so I
> > > > > have no idea what's getting trimmed here.  It worries me quite a bit by
> > > > > introducing this trimming that apparently wasn't happening before
> > > > > though.  Thanks,
> > > > 
> > > > As suspected, the pnp.bus_id/id of the last device before the serial
> > > > console dies is COM1/PNP0501.  I also see all of these being trimmed
> > > > out:
> > > > 
> > > >  MBRD/PNP0C02
> > > >  DMAC/PNP0200
> > > >  MATH/PNP0C04
> > > >  PIC/PNP0000
> > > >  HPET/PNP0103
> > > >  RTC/PNP0B00
> > > >  SPKR/PNP0800
> > > >  TIME/PNP0100
> > > >  LNK{A-H}/PNP0C0F
> > > > 
> > > > This seems like a bad idea.  I forgot to mention, the original
> > > > hotplug_event is called with a device check on \_SB_.PCI0.PEX2.  The box
> > > > where I'm seeing this is a pretty generic X58 based Nehalem workstation
> > > > (Lenovo S20).
> > > 
> > > Thanks for the info!
> > > 
> > > The acpiphp_bus_trim() in acpiphp_bus_add() is a leftover and a bad one.
> > > I don't think it's actually necessary, at least Thunderbolt works without
> > > it just fine on my Aspire S5.
> > > 
> > > The patch below should help, can you please test it?
> > > 
> > > Rafael
> > > 
> > > ---
> > > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > > Subject: ACPI / hotplug / PCI: Don't trim devices before scanning the namespace
> > > 
> > > In acpiphp_bus_add() we first remove device objects corresponding to
> > > the given handle and the ACPI namespace branch below it which are
> > > then re-created by acpi_bus_scan().  This used to be done to clean
> > > up after surprise removals, but now we do the cleanup through
> > > trim_stale_devices() which checks if the devices in question are
> > > actually gone before removing them, so the device hierarchy trimming
> > > in acpiphp_bus_add() is not necessary any more and, moreover, it may
> > > lead to problems if it removes device objects corresponding to
> > > devices that are actually present.
> > > 
> > > Reported-by: Alex Williamson <alex.williamson@redhat.com>
> > > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > > ---
> > >  drivers/pci/hotplug/acpiphp_glue.c |    1 -
> > >  1 file changed, 1 deletion(-)
> > > 
> > > 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
> > > @@ -487,7 +487,6 @@ static void acpiphp_bus_add(acpi_handle
> > >  {
> > >  	struct acpi_device *adev = NULL;
> > >  
> > > -	acpiphp_bus_trim(handle);
> > >  	acpi_bus_scan(handle);
> > >  	acpi_bus_get_device(handle, &adev);
> > >  	if (adev)
> > > 
> > > 
> > 
> > It boots again and the console works,

OK, so I'll queue up the patch above as a 3.12 fix and let's regard the
dying serial console problem as fixed.

Now ->

> > but I see screens and screens of messages like this:

-> this is a separate issue that we need to take care of (so I've changed the
subject to reflect that).

> > 
> > [   18.288122] pci 0000:00:00.0: no hotplug settings from platform
> > [   18.288127] pcieport 0000:00:01.0: no hotplug settings from platform
> > [   18.288142] pci 0000:01:00.0: no hotplug settings from platform
> > [   18.288157] pci 0000:01:00.1: no hotplug settings from platform
> > [   18.288162] pcieport 0000:00:03.0: no hotplug settings from platform
> > [   18.288176] pci 0000:02:00.0: no hotplug settings from platform
> > [   18.288190] pci 0000:02:00.1: no hotplug settings from platform
> > [   18.288195] pcieport 0000:00:07.0: no hotplug settings from platform
> > [   18.288209] pci 0000:03:00.0: no hotplug settings from platform
> > [   18.288224] pci 0000:03:00.1: no hotplug settings from platform
> > [   18.288228] pci 0000:00:14.0: no hotplug settings from platform
> > [   18.288233] pci 0000:00:14.1: no hotplug settings from platform
> > [   18.288237] pci 0000:00:14.2: no hotplug settings from platform
> > [   18.288242] pci 0000:00:16.0: no hotplug settings from platform
> > [   18.288247] pci 0000:00:16.1: no hotplug settings from platform
> > [   18.288251] pci 0000:00:16.2: no hotplug settings from platform
> > [   18.288256] pci 0000:00:16.3: no hotplug settings from platform
> > [   18.288260] pci 0000:00:16.4: no hotplug settings from platform
> > [   18.288265] pci 0000:00:16.5: no hotplug settings from platform
> > [   18.288269] pci 0000:00:16.6: no hotplug settings from platform
> > [   18.288274] pci 0000:00:16.7: no hotplug settings from platform
> > [   18.288278] pci 0000:00:1a.0: no hotplug settings from platform
> > [   18.288279] pci 0000:00:1a.0: using default PCI settings
> > [   18.288292] pci 0000:00:1a.1: no hotplug settings from platform
> > [   18.288293] pci 0000:00:1a.1: using default PCI settings
> > [   18.288307] ehci-pci 0000:00:1a.7: no hotplug settings from platform
> > [   18.288308] ehci-pci 0000:00:1a.7: using default PCI settings
> > [   18.288322] pci 0000:00:1b.0: no hotplug settings from platform
> > [   18.288327] pcieport 0000:00:1c.0: no hotplug settings from platform
> > [   18.288332] pcieport 0000:00:1c.4: no hotplug settings from platform
> > [   18.288344] pci 0000:05:00.0: no hotplug settings from platform
> > [   18.288349] pci 0000:00:1d.0: no hotplug settings from platform
> > [   18.288350] pci 0000:00:1d.0: using default PCI settings
> > [   18.288360] pci 0000:00:1d.1: no hotplug settings from platform
> > [   18.288361] pci 0000:00:1d.1: using default PCI settings
> > [   18.288374] pci 0000:00:1d.2: no hotplug settings from platform
> > [   18.288374] pci 0000:00:1d.2: using default PCI settings
> > [   18.288387] pci 0000:00:1d.3: no hotplug settings from platform
> > [   18.288387] pci 0000:00:1d.3: using default PCI settings
> > 
> > The boot is noticeably slower.  What's going to happen on systems that
> > actually have a significant I/O topology vs my little workstation?

That depends on how many bus check/device check events they generate on boot.

My test machines don't generate them during boot at all (even the one with
a Thunderbolt connector), so I don't see the messages in question during boot
on any of them.  Mika doesn't see them either I suppose, or he would have told
me about that before.

And let's just make it clear that it is not usual or even OK to generate bus
checks or device checks during boot like this.  And since the changes in
question have been in linux-next since right after the 3.11 merge window, I
think that someone would have complained already had that been a common issue.

Of course, we need to deal with that somehow nevertheless. :-)

> Just to give you an idea:
> 
> CONFIG_HOTPLUG_PCI_ACPI=y
> 
> $ dmesg | wc
>   5697  49935 384368
> 
> $ dmesg | tail --lines=1
> [   53.137123] Ebtables v2.0 registered
> 
> -- vs --
> 
> # CONFIG_HOTPLUG_PCI_ACPI is not set
> 
> $ dmesg | wc
>  1053  9176 71652
> 
> $dmesg | tail --lines=1
> [   28.917220] Ebtables v2.0 registered
> 
> So it spews out 5x more output with acpiphp enabled and takes and extra
> 24s to boot (nearly 2x).  Not good.

The "no hotplug settings from platform" message is from pci_configure_slot().
I think the messages you're seeing are from the call to it in
acpiphp_set_hpp_values() which is called by enable_slot().

There, I think, we can simply check the return value of pci_scan_slot() and
if that is 0 (no new devices), we can just skip everything under the call to
__pci_bus_assign_resources().

However, we can't skip the scanning of bridges, if any, because there may be
new devices below them and I guess that's what takes so much time on your
machine.

Thanks,
Rafael


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

* Re: Excess dmesg output from ACPIPHP on boot (was: Re: [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots)
  2013-09-05 19:44                         ` Excess dmesg output from ACPIPHP on boot (was: Re: [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots) Rafael J. Wysocki
@ 2013-09-05 21:39                           ` Rafael J. Wysocki
  2013-09-05 21:45                             ` Rafael J. Wysocki
  2013-09-05 22:17                             ` Alex Williamson
  0 siblings, 2 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-09-05 21:39 UTC (permalink / raw)
  To: Alex Williamson
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Thursday, September 05, 2013 09:44:26 PM Rafael J. Wysocki wrote:
> On Thursday, September 05, 2013 08:21:41 AM Alex Williamson wrote:

[...]

> > > 
> > > [   18.288122] pci 0000:00:00.0: no hotplug settings from platform
> > > [   18.288127] pcieport 0000:00:01.0: no hotplug settings from platform
> > > [   18.288142] pci 0000:01:00.0: no hotplug settings from platform
> > > [   18.288157] pci 0000:01:00.1: no hotplug settings from platform
> > > [   18.288162] pcieport 0000:00:03.0: no hotplug settings from platform
> > > [   18.288176] pci 0000:02:00.0: no hotplug settings from platform
> > > [   18.288190] pci 0000:02:00.1: no hotplug settings from platform
> > > [   18.288195] pcieport 0000:00:07.0: no hotplug settings from platform
> > > [   18.288209] pci 0000:03:00.0: no hotplug settings from platform
> > > [   18.288224] pci 0000:03:00.1: no hotplug settings from platform
> > > [   18.288228] pci 0000:00:14.0: no hotplug settings from platform
> > > [   18.288233] pci 0000:00:14.1: no hotplug settings from platform
> > > [   18.288237] pci 0000:00:14.2: no hotplug settings from platform
> > > [   18.288242] pci 0000:00:16.0: no hotplug settings from platform
> > > [   18.288247] pci 0000:00:16.1: no hotplug settings from platform
> > > [   18.288251] pci 0000:00:16.2: no hotplug settings from platform
> > > [   18.288256] pci 0000:00:16.3: no hotplug settings from platform
> > > [   18.288260] pci 0000:00:16.4: no hotplug settings from platform
> > > [   18.288265] pci 0000:00:16.5: no hotplug settings from platform
> > > [   18.288269] pci 0000:00:16.6: no hotplug settings from platform
> > > [   18.288274] pci 0000:00:16.7: no hotplug settings from platform
> > > [   18.288278] pci 0000:00:1a.0: no hotplug settings from platform
> > > [   18.288279] pci 0000:00:1a.0: using default PCI settings
> > > [   18.288292] pci 0000:00:1a.1: no hotplug settings from platform
> > > [   18.288293] pci 0000:00:1a.1: using default PCI settings
> > > [   18.288307] ehci-pci 0000:00:1a.7: no hotplug settings from platform
> > > [   18.288308] ehci-pci 0000:00:1a.7: using default PCI settings
> > > [   18.288322] pci 0000:00:1b.0: no hotplug settings from platform
> > > [   18.288327] pcieport 0000:00:1c.0: no hotplug settings from platform
> > > [   18.288332] pcieport 0000:00:1c.4: no hotplug settings from platform
> > > [   18.288344] pci 0000:05:00.0: no hotplug settings from platform
> > > [   18.288349] pci 0000:00:1d.0: no hotplug settings from platform
> > > [   18.288350] pci 0000:00:1d.0: using default PCI settings
> > > [   18.288360] pci 0000:00:1d.1: no hotplug settings from platform
> > > [   18.288361] pci 0000:00:1d.1: using default PCI settings
> > > [   18.288374] pci 0000:00:1d.2: no hotplug settings from platform
> > > [   18.288374] pci 0000:00:1d.2: using default PCI settings
> > > [   18.288387] pci 0000:00:1d.3: no hotplug settings from platform
> > > [   18.288387] pci 0000:00:1d.3: using default PCI settings
> > > 
> > > The boot is noticeably slower.  What's going to happen on systems that
> > > actually have a significant I/O topology vs my little workstation?
> 
> That depends on how many bus check/device check events they generate on boot.
> 
> My test machines don't generate them during boot at all (even the one with
> a Thunderbolt connector), so I don't see the messages in question during boot
> on any of them.  Mika doesn't see them either I suppose, or he would have told
> me about that before.
> 
> And let's just make it clear that it is not usual or even OK to generate bus
> checks or device checks during boot like this.  And since the changes in
> question have been in linux-next since right after the 3.11 merge window, I
> think that someone would have complained already had that been a common issue.
> 
> Of course, we need to deal with that somehow nevertheless. :-)
> 
> > Just to give you an idea:
> > 
> > CONFIG_HOTPLUG_PCI_ACPI=y
> > 
> > $ dmesg | wc
> >   5697  49935 384368
> > 
> > $ dmesg | tail --lines=1
> > [   53.137123] Ebtables v2.0 registered
> > 
> > -- vs --
> > 
> > # CONFIG_HOTPLUG_PCI_ACPI is not set
> > 
> > $ dmesg | wc
> >  1053  9176 71652
> > 
> > $dmesg | tail --lines=1
> > [   28.917220] Ebtables v2.0 registered
> > 
> > So it spews out 5x more output with acpiphp enabled and takes and extra
> > 24s to boot (nearly 2x).  Not good.
> 
> The "no hotplug settings from platform" message is from pci_configure_slot().
> I think the messages you're seeing are from the call to it in
> acpiphp_set_hpp_values() which is called by enable_slot().
> 
> There, I think, we can simply check the return value of pci_scan_slot() and
> if that is 0 (no new devices), we can just skip everything under the call to
> __pci_bus_assign_resources().
> 
> However, we can't skip the scanning of bridges, if any, because there may be
> new devices below them and I guess that's what takes so much time on your
> machine.

OK, one piece is missing.  We may need to evaluate _OSC after handling each
event to let the platform know the status.

Can you please check if the appended patch makes any difference (with the
previous fix applied, of course)?

If fact, it is two patches combined.  One of them optimizes enable_slot()
slightly and the other adds the missing _OSC evaluation.

Thanks,
Rafael


---
 drivers/pci/hotplug/acpiphp_glue.c |   35 +++++++++++++++++++++++++++--------
 1 file changed, 27 insertions(+), 8 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
@@ -542,12 +542,12 @@ static void __ref enable_slot(struct acp
 	struct acpiphp_func *func;
 	int max, pass;
 	LIST_HEAD(add_list);
+	int nr_found;
 
 	list_for_each_entry(func, &slot->funcs, sibling)
 		acpiphp_bus_add(func_to_handle(func));
 
-	pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
-
+	nr_found = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
 	max = acpiphp_max_busnr(bus);
 	for (pass = 0; pass < 2; pass++) {
 		list_for_each_entry(dev, &bus->devices, bus_list) {
@@ -566,8 +566,11 @@ static void __ref enable_slot(struct acp
 			}
 		}
 	}
-
 	__pci_bus_assign_resources(bus, &add_list, NULL);
+	/* Nothing more to do here if there are no new devices on this bus. */
+	if (!nr_found && (slot->flags & SLOT_ENABLED))
+		return;
+
 	acpiphp_sanitize_bus(bus);
 	acpiphp_set_hpp_values(bus);
 	acpiphp_set_acpi_region(slot);
@@ -867,6 +870,8 @@ static void hotplug_event_work(struct wo
 	hotplug_event(hp_work->handle, hp_work->type, context);
 
 	acpi_scan_lock_release();
+	acpi_evaluate_hotplug_ost(hp_work->handle, hp_work->type,
+				  ACPI_OST_SC_SUCCESS, NULL);
 	kfree(hp_work); /* allocated in handle_hotplug_event() */
 	put_bridge(context->func.parent);
 }
@@ -882,12 +887,16 @@ static void hotplug_event_work(struct wo
 static void handle_hotplug_event(acpi_handle handle, u32 type, void *data)
 {
 	struct acpiphp_context *context;
+	u32 ost_code;
 
 	switch (type) {
 	case ACPI_NOTIFY_BUS_CHECK:
 	case ACPI_NOTIFY_DEVICE_CHECK:
+		ost_code = ACPI_OST_SC_INSERT_IN_PROGRESS;
+		goto work;
 	case ACPI_NOTIFY_EJECT_REQUEST:
-		break;
+		ost_code = ACPI_OST_SC_EJECT_IN_PROGRESS;
+		goto work;
 
 	case ACPI_NOTIFY_DEVICE_WAKE:
 		return;
@@ -895,30 +904,40 @@ static void handle_hotplug_event(acpi_ha
 	case ACPI_NOTIFY_FREQUENCY_MISMATCH:
 		acpi_handle_err(handle, "Device cannot be configured due "
 				"to a frequency mismatch\n");
-		return;
+		break;
 
 	case ACPI_NOTIFY_BUS_MODE_MISMATCH:
 		acpi_handle_err(handle, "Device cannot be configured due "
 				"to a bus mode mismatch\n");
-		return;
+		break;
 
 	case ACPI_NOTIFY_POWER_FAULT:
 		acpi_handle_err(handle, "Device has suffered a power fault\n");
-		return;
+		break;
 
 	default:
 		acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type);
-		return;
+		break;
 	}
 
+ err:
+	ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
+	acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
+	return;
+
+ work:
 	mutex_lock(&acpiphp_context_lock);
 	context = acpiphp_get_context(handle);
 	if (context) {
 		get_bridge(context->func.parent);
 		acpiphp_put_context(context);
+		acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
 		alloc_acpi_hp_work(handle, type, context, hotplug_event_work);
+		mutex_unlock(&acpiphp_context_lock);
+		return;
 	}
 	mutex_unlock(&acpiphp_context_lock);
+	goto err;
 }
 
 /*


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

* Re: [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots
  2013-09-05 13:11                     ` Lan Tianyu
@ 2013-09-05 21:43                       ` Rafael J. Wysocki
  0 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-09-05 21:43 UTC (permalink / raw)
  To: Lan Tianyu
  Cc: Alex Williamson, ACPI Devel Maling List, Bjorn Helgaas, LKML,
	Linux PCI, Yinghai Lu, Jiang Liu, Mika Westerberg,
	Kirill A. Shutemov

On Thursday, September 05, 2013 09:11:51 AM Lan Tianyu wrote:
> 2013/9/5 Rafael J. Wysocki <rjw@sisk.pl>:
> > On Thursday, September 05, 2013 02:17:06 PM Lan Tianyu wrote:
> >> 2013/9/5 Alex Williamson <alex.williamson@redhat.com>:
> >> > On Thu, 2013-09-05 at 01:35 +0200, Rafael J. Wysocki wrote:
> >> >> On Wednesday, September 04, 2013 05:12:14 PM Alex Williamson wrote:
> >> >> > On Thu, 2013-09-05 at 00:54 +0200, Rafael J. Wysocki wrote:
> >> >> > > On Wednesday, September 04, 2013 02:36:34 PM Alex Williamson wrote:
> >> >> > > > On Thu, 2013-07-18 at 01:32 +0200, Rafael J. Wysocki wrote:
> >> >> > > > > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> >> >> > > > >
> >> >> > > > > The current implementation of acpiphp_check_bridge() is pretty dumb:
> >> >> > > > >  - It enables a slot if it's not enabled and the slot status is
> >> >> > > > >    ACPI_STA_ALL.
> >> >> > > > >  - It disables a slot if it's enabled and the slot status is not
> >> >> > > > >    ACPI_STA_ALL.
> >> >> > > > >
> >> >> > > > > This behavior is not sufficient to handle the Thunderbolt daisy
> >> >> > > > > chaining case properly, however, because in that case the bus
> >> >> > > > > behind the already enabled slot needs to be rescanned for new
> >> >> > > > > devices.
> >> >> > > > >
> >> >> > > > > For this reason, modify acpiphp_check_bridge() so that slots are
> >> >> > > > > disabled and stopped if they are not in the ACPI_STA_ALL state.
> >> >> > > > >
> >> >> > > > > For slots in the ACPI_STA_ALL state, devices behind them that don't
> >> >> > > > > respond are trimmed using a new function, trim_stale_devices(),
> >> >> > > > > introduced specifically for this purpose.  That function walks
> >> >> > > > > the given bus and checks each device on it.  If the device doesn't
> >> >> > > > > respond, it is assumed to be gone and is removed.
> >> >> > > > >
> >> >> > > > > Once all of the stale devices directy behind the slot have been
> >> >> > > > > removed, acpiphp_check_bridge() will start looking for new devices
> >> >> > > > > that might have appeared on the given bus.  It will do that even if
> >> >> > > > > the slot is already enabled (SLOT_ENABLED is set for it).
> >> >> > > > >
> >> >> > > > > In addition to that, make the bus check notification ignore
> >> >> > > > > SLOT_ENABLED and go for enable_device() directly if bridge is NULL,
> >> >> > > > > so that devices behind the slot are re-enumerated in that case too.
> >> >> > > > >
> >> >> > > > > This change is based on earlier patches from Kirill A Shutemov
> >> >> > > > > and Mika Westerberg.
> >> >> > > > >
> >> >> > > > > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> >> >> > > > > Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
> >> >> > > > > ---
> >> >> > > >
> >> >> > > > FYI, git bisect landed on this patch as the cause of my serial console
> >> >> > > > dying on current upstream.  Further debugging to come...  Thanks,
> >> >> > >
> >> >> > > Well, sorry about that.
> >> >> > >
> >> >> > > What exactly do you mean by "dying"?
> >> >> >
> >> >> > Sorry, I was hoping to have more details quickly, but it's been a pain
> >> >> > to debug.  By dying I mean serial console output suddenly stops during
> >> >> > kernel boot and nothing more comes out of it until after the system is
> >> >> > rebooted.  The problem happens when acpiphp_check_bridge() calls
> >> >> > enable_slot().  The serial console dies somewhere down in
> >> >> > acpiphp_bus_trim().  I think this is happening on the 00:1f ISA bridge,
> >> >> > so there's a good chance the serial ports are described as somewhere
> >> >> > under there.
> >> >>
> >> >> Can you please check if that is the acpiphp_bus_trim() called by
> >> >> acpiphp_bus_add() or the other one called from trim_stale_devices()?
> >> >>
> >> >> Just add a dump_stack() or WARN_ON(1) to trim_stale_devices() next to
> >> >> the acpiphp_bus_trim() call and see if that triggers.  I *think* it's the one
> >> >> in acpiphp_bus_add(), but it won't hurt to verify that.
> >> >
> >> > Here's the call path:
> >> >
> >> > [   16.120824]  [<ffffffff81627e6c>] dump_stack+0x55/0x76
> >> > [   16.125979]  [<ffffffff8162132e>] enable_slot+0x4ee/0x5e0
> >> > [   16.131396]  [<ffffffff813418fb>] ? trim_stale_devices+0x5b/0xf0
> >> > [   16.137420]  [<ffffffff81341b35>] acpiphp_check_bridge+0xd5/0x110
> >> > [   16.143531]  [<ffffffff81342acb>] hotplug_event+0x16b/0x260
> >> > [   16.149115]  [<ffffffff81072cd9>] ? process_one_work+0x189/0x540
> >> > [   16.155136]  [<ffffffff81342bf0>] hotplug_event_work+0x30/0x70
> >> > [   16.160978]  [<ffffffff81072d3b>] process_one_work+0x1eb/0x540
> >> > [   16.166819]  [<ffffffff81072cd9>] ? process_one_work+0x189/0x540
> >> > [   16.172836]  [<ffffffff8107353c>] worker_thread+0x11c/0x370
> >> > [   16.178426]  [<ffffffff81073420>] ? rescuer_thread+0x350/0x350
> >> > [   16.184276]  [<ffffffff8107b0ea>] kthread+0xea/0xf0
> >> > [   16.189165]  [<ffffffff8107b000>] ? kthread_create_on_node+0x160/0x160
> >> > [   16.195700]  [<ffffffff816395dc>] ret_from_fork+0x7c/0xb0
> >> > [   16.201109]  [<ffffffff8107b000>] ? kthread_create_on_node+0x160/0x160
> >> >
> >> > The actual death of the serial console occurs in acpi_device_set_power()
> >> > called from:
> >> >
> >> > enable_slot()
> >> >  acpiphp_bus_add()
> >> >   acpiphp_bus_trim()
> >> >    acpi_bus_trim()
> >> >     acpi_walk_namespace()
> >> >      acpi_bus_remove()
> >> >       acpi_device_unregister()
> >> >        acpi_device_set_power()
> >> >
> >> > I can't seem to get a path from the acpi devices in question there, so I
> >> > have no idea what's getting trimmed here.  It worries me quite a bit by
> >> > introducing this trimming that apparently wasn't happening before
> >> > though.  Thanks,
> >>
> >> Hi Alex:
> >>            Could you apply the following patch and bootup with kernel param
> >> "acpiphp.acpiphp_debug=1"?
> >>            I guess the patch can make serial port alive. It will not
> >> be put into D3cold
> >> during trimming. But I don't know why it doesn't work after being put
> >> back to D0.
> >
> > Do we actually put it into D0 in acpi_bus_scan()?  I don't think so.
> >
> 
> Hi Rafael:
>          I mean the code in the acpiphp_bus_add(). After trimming and acpi
> bus scan handle, the device will be put back to D0 if acpi_bus_get_device()
> return acpi device. So I thought the serial port is put back to D0.

*The* device corresponding to handle will be put into D0.  Any devices below it
whose ACPI device objects may also be added by acpi_bus_scan() - not necessarily.

Thanks,
Rafael

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

* Re: Excess dmesg output from ACPIPHP on boot (was: Re: [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots)
  2013-09-05 21:39                           ` Rafael J. Wysocki
@ 2013-09-05 21:45                             ` Rafael J. Wysocki
  2013-09-05 22:17                             ` Alex Williamson
  1 sibling, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-09-05 21:45 UTC (permalink / raw)
  To: Alex Williamson
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Thursday, September 05, 2013 11:39:07 PM Rafael J. Wysocki wrote:
> On Thursday, September 05, 2013 09:44:26 PM Rafael J. Wysocki wrote:
> > On Thursday, September 05, 2013 08:21:41 AM Alex Williamson wrote:
> 
> [...]
> 
> > > > 
> > > > [   18.288122] pci 0000:00:00.0: no hotplug settings from platform
> > > > [   18.288127] pcieport 0000:00:01.0: no hotplug settings from platform
> > > > [   18.288142] pci 0000:01:00.0: no hotplug settings from platform
> > > > [   18.288157] pci 0000:01:00.1: no hotplug settings from platform
> > > > [   18.288162] pcieport 0000:00:03.0: no hotplug settings from platform
> > > > [   18.288176] pci 0000:02:00.0: no hotplug settings from platform
> > > > [   18.288190] pci 0000:02:00.1: no hotplug settings from platform
> > > > [   18.288195] pcieport 0000:00:07.0: no hotplug settings from platform
> > > > [   18.288209] pci 0000:03:00.0: no hotplug settings from platform
> > > > [   18.288224] pci 0000:03:00.1: no hotplug settings from platform
> > > > [   18.288228] pci 0000:00:14.0: no hotplug settings from platform
> > > > [   18.288233] pci 0000:00:14.1: no hotplug settings from platform
> > > > [   18.288237] pci 0000:00:14.2: no hotplug settings from platform
> > > > [   18.288242] pci 0000:00:16.0: no hotplug settings from platform
> > > > [   18.288247] pci 0000:00:16.1: no hotplug settings from platform
> > > > [   18.288251] pci 0000:00:16.2: no hotplug settings from platform
> > > > [   18.288256] pci 0000:00:16.3: no hotplug settings from platform
> > > > [   18.288260] pci 0000:00:16.4: no hotplug settings from platform
> > > > [   18.288265] pci 0000:00:16.5: no hotplug settings from platform
> > > > [   18.288269] pci 0000:00:16.6: no hotplug settings from platform
> > > > [   18.288274] pci 0000:00:16.7: no hotplug settings from platform
> > > > [   18.288278] pci 0000:00:1a.0: no hotplug settings from platform
> > > > [   18.288279] pci 0000:00:1a.0: using default PCI settings
> > > > [   18.288292] pci 0000:00:1a.1: no hotplug settings from platform
> > > > [   18.288293] pci 0000:00:1a.1: using default PCI settings
> > > > [   18.288307] ehci-pci 0000:00:1a.7: no hotplug settings from platform
> > > > [   18.288308] ehci-pci 0000:00:1a.7: using default PCI settings
> > > > [   18.288322] pci 0000:00:1b.0: no hotplug settings from platform
> > > > [   18.288327] pcieport 0000:00:1c.0: no hotplug settings from platform
> > > > [   18.288332] pcieport 0000:00:1c.4: no hotplug settings from platform
> > > > [   18.288344] pci 0000:05:00.0: no hotplug settings from platform
> > > > [   18.288349] pci 0000:00:1d.0: no hotplug settings from platform
> > > > [   18.288350] pci 0000:00:1d.0: using default PCI settings
> > > > [   18.288360] pci 0000:00:1d.1: no hotplug settings from platform
> > > > [   18.288361] pci 0000:00:1d.1: using default PCI settings
> > > > [   18.288374] pci 0000:00:1d.2: no hotplug settings from platform
> > > > [   18.288374] pci 0000:00:1d.2: using default PCI settings
> > > > [   18.288387] pci 0000:00:1d.3: no hotplug settings from platform
> > > > [   18.288387] pci 0000:00:1d.3: using default PCI settings
> > > > 
> > > > The boot is noticeably slower.  What's going to happen on systems that
> > > > actually have a significant I/O topology vs my little workstation?
> > 
> > That depends on how many bus check/device check events they generate on boot.
> > 
> > My test machines don't generate them during boot at all (even the one with
> > a Thunderbolt connector), so I don't see the messages in question during boot
> > on any of them.  Mika doesn't see them either I suppose, or he would have told
> > me about that before.
> > 
> > And let's just make it clear that it is not usual or even OK to generate bus
> > checks or device checks during boot like this.  And since the changes in
> > question have been in linux-next since right after the 3.11 merge window, I
> > think that someone would have complained already had that been a common issue.
> > 
> > Of course, we need to deal with that somehow nevertheless. :-)
> > 
> > > Just to give you an idea:
> > > 
> > > CONFIG_HOTPLUG_PCI_ACPI=y
> > > 
> > > $ dmesg | wc
> > >   5697  49935 384368
> > > 
> > > $ dmesg | tail --lines=1
> > > [   53.137123] Ebtables v2.0 registered
> > > 
> > > -- vs --
> > > 
> > > # CONFIG_HOTPLUG_PCI_ACPI is not set
> > > 
> > > $ dmesg | wc
> > >  1053  9176 71652
> > > 
> > > $dmesg | tail --lines=1
> > > [   28.917220] Ebtables v2.0 registered
> > > 
> > > So it spews out 5x more output with acpiphp enabled and takes and extra
> > > 24s to boot (nearly 2x).  Not good.
> > 
> > The "no hotplug settings from platform" message is from pci_configure_slot().
> > I think the messages you're seeing are from the call to it in
> > acpiphp_set_hpp_values() which is called by enable_slot().
> > 
> > There, I think, we can simply check the return value of pci_scan_slot() and
> > if that is 0 (no new devices), we can just skip everything under the call to
> > __pci_bus_assign_resources().
> > 
> > However, we can't skip the scanning of bridges, if any, because there may be
> > new devices below them and I guess that's what takes so much time on your
> > machine.
> 
> OK, one piece is missing.  We may need to evaluate _OSC after handling each
> event to let the platform know the status.

s/_OSC/_OST/

> Can you please check if the appended patch makes any difference (with the
> previous fix applied, of course)?
> 
> If fact, it is two patches combined.  One of them optimizes enable_slot()
> slightly and the other adds the missing _OSC evaluation.

s/_OSC/_OST/ (What the heck?)

But the patch should be OK. :-)

Thanks,
Rafael


> ---
>  drivers/pci/hotplug/acpiphp_glue.c |   35 +++++++++++++++++++++++++++--------
>  1 file changed, 27 insertions(+), 8 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
> @@ -542,12 +542,12 @@ static void __ref enable_slot(struct acp
>  	struct acpiphp_func *func;
>  	int max, pass;
>  	LIST_HEAD(add_list);
> +	int nr_found;
>  
>  	list_for_each_entry(func, &slot->funcs, sibling)
>  		acpiphp_bus_add(func_to_handle(func));
>  
> -	pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
> -
> +	nr_found = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
>  	max = acpiphp_max_busnr(bus);
>  	for (pass = 0; pass < 2; pass++) {
>  		list_for_each_entry(dev, &bus->devices, bus_list) {
> @@ -566,8 +566,11 @@ static void __ref enable_slot(struct acp
>  			}
>  		}
>  	}
> -
>  	__pci_bus_assign_resources(bus, &add_list, NULL);
> +	/* Nothing more to do here if there are no new devices on this bus. */
> +	if (!nr_found && (slot->flags & SLOT_ENABLED))
> +		return;
> +
>  	acpiphp_sanitize_bus(bus);
>  	acpiphp_set_hpp_values(bus);
>  	acpiphp_set_acpi_region(slot);
> @@ -867,6 +870,8 @@ static void hotplug_event_work(struct wo
>  	hotplug_event(hp_work->handle, hp_work->type, context);
>  
>  	acpi_scan_lock_release();
> +	acpi_evaluate_hotplug_ost(hp_work->handle, hp_work->type,
> +				  ACPI_OST_SC_SUCCESS, NULL);
>  	kfree(hp_work); /* allocated in handle_hotplug_event() */
>  	put_bridge(context->func.parent);
>  }
> @@ -882,12 +887,16 @@ static void hotplug_event_work(struct wo
>  static void handle_hotplug_event(acpi_handle handle, u32 type, void *data)
>  {
>  	struct acpiphp_context *context;
> +	u32 ost_code;
>  
>  	switch (type) {
>  	case ACPI_NOTIFY_BUS_CHECK:
>  	case ACPI_NOTIFY_DEVICE_CHECK:
> +		ost_code = ACPI_OST_SC_INSERT_IN_PROGRESS;
> +		goto work;
>  	case ACPI_NOTIFY_EJECT_REQUEST:
> -		break;
> +		ost_code = ACPI_OST_SC_EJECT_IN_PROGRESS;
> +		goto work;
>  
>  	case ACPI_NOTIFY_DEVICE_WAKE:
>  		return;
> @@ -895,30 +904,40 @@ static void handle_hotplug_event(acpi_ha
>  	case ACPI_NOTIFY_FREQUENCY_MISMATCH:
>  		acpi_handle_err(handle, "Device cannot be configured due "
>  				"to a frequency mismatch\n");
> -		return;
> +		break;
>  
>  	case ACPI_NOTIFY_BUS_MODE_MISMATCH:
>  		acpi_handle_err(handle, "Device cannot be configured due "
>  				"to a bus mode mismatch\n");
> -		return;
> +		break;
>  
>  	case ACPI_NOTIFY_POWER_FAULT:
>  		acpi_handle_err(handle, "Device has suffered a power fault\n");
> -		return;
> +		break;
>  
>  	default:
>  		acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type);
> -		return;
> +		break;
>  	}
>  
> + err:
> +	ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
> +	acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
> +	return;
> +
> + work:
>  	mutex_lock(&acpiphp_context_lock);
>  	context = acpiphp_get_context(handle);
>  	if (context) {
>  		get_bridge(context->func.parent);
>  		acpiphp_put_context(context);
> +		acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
>  		alloc_acpi_hp_work(handle, type, context, hotplug_event_work);
> +		mutex_unlock(&acpiphp_context_lock);
> +		return;
>  	}
>  	mutex_unlock(&acpiphp_context_lock);
> +	goto err;
>  }
>  
>  /*
> 
> --
> 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] 135+ messages in thread

* Re: Excess dmesg output from ACPIPHP on boot (was: Re: [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots)
  2013-09-05 21:39                           ` Rafael J. Wysocki
  2013-09-05 21:45                             ` Rafael J. Wysocki
@ 2013-09-05 22:17                             ` Alex Williamson
  2013-09-05 22:40                               ` Rafael J. Wysocki
  1 sibling, 1 reply; 135+ messages in thread
From: Alex Williamson @ 2013-09-05 22:17 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Thu, 2013-09-05 at 23:39 +0200, Rafael J. Wysocki wrote:
> On Thursday, September 05, 2013 09:44:26 PM Rafael J. Wysocki wrote:
> > On Thursday, September 05, 2013 08:21:41 AM Alex Williamson wrote:
> 
> [...]
> 
> > > > 
> > > > [   18.288122] pci 0000:00:00.0: no hotplug settings from platform
> > > > [   18.288127] pcieport 0000:00:01.0: no hotplug settings from platform
> > > > [   18.288142] pci 0000:01:00.0: no hotplug settings from platform
> > > > [   18.288157] pci 0000:01:00.1: no hotplug settings from platform
> > > > [   18.288162] pcieport 0000:00:03.0: no hotplug settings from platform
> > > > [   18.288176] pci 0000:02:00.0: no hotplug settings from platform
> > > > [   18.288190] pci 0000:02:00.1: no hotplug settings from platform
> > > > [   18.288195] pcieport 0000:00:07.0: no hotplug settings from platform
> > > > [   18.288209] pci 0000:03:00.0: no hotplug settings from platform
> > > > [   18.288224] pci 0000:03:00.1: no hotplug settings from platform
> > > > [   18.288228] pci 0000:00:14.0: no hotplug settings from platform
> > > > [   18.288233] pci 0000:00:14.1: no hotplug settings from platform
> > > > [   18.288237] pci 0000:00:14.2: no hotplug settings from platform
> > > > [   18.288242] pci 0000:00:16.0: no hotplug settings from platform
> > > > [   18.288247] pci 0000:00:16.1: no hotplug settings from platform
> > > > [   18.288251] pci 0000:00:16.2: no hotplug settings from platform
> > > > [   18.288256] pci 0000:00:16.3: no hotplug settings from platform
> > > > [   18.288260] pci 0000:00:16.4: no hotplug settings from platform
> > > > [   18.288265] pci 0000:00:16.5: no hotplug settings from platform
> > > > [   18.288269] pci 0000:00:16.6: no hotplug settings from platform
> > > > [   18.288274] pci 0000:00:16.7: no hotplug settings from platform
> > > > [   18.288278] pci 0000:00:1a.0: no hotplug settings from platform
> > > > [   18.288279] pci 0000:00:1a.0: using default PCI settings
> > > > [   18.288292] pci 0000:00:1a.1: no hotplug settings from platform
> > > > [   18.288293] pci 0000:00:1a.1: using default PCI settings
> > > > [   18.288307] ehci-pci 0000:00:1a.7: no hotplug settings from platform
> > > > [   18.288308] ehci-pci 0000:00:1a.7: using default PCI settings
> > > > [   18.288322] pci 0000:00:1b.0: no hotplug settings from platform
> > > > [   18.288327] pcieport 0000:00:1c.0: no hotplug settings from platform
> > > > [   18.288332] pcieport 0000:00:1c.4: no hotplug settings from platform
> > > > [   18.288344] pci 0000:05:00.0: no hotplug settings from platform
> > > > [   18.288349] pci 0000:00:1d.0: no hotplug settings from platform
> > > > [   18.288350] pci 0000:00:1d.0: using default PCI settings
> > > > [   18.288360] pci 0000:00:1d.1: no hotplug settings from platform
> > > > [   18.288361] pci 0000:00:1d.1: using default PCI settings
> > > > [   18.288374] pci 0000:00:1d.2: no hotplug settings from platform
> > > > [   18.288374] pci 0000:00:1d.2: using default PCI settings
> > > > [   18.288387] pci 0000:00:1d.3: no hotplug settings from platform
> > > > [   18.288387] pci 0000:00:1d.3: using default PCI settings
> > > > 
> > > > The boot is noticeably slower.  What's going to happen on systems that
> > > > actually have a significant I/O topology vs my little workstation?
> > 
> > That depends on how many bus check/device check events they generate on boot.
> > 
> > My test machines don't generate them during boot at all (even the one with
> > a Thunderbolt connector), so I don't see the messages in question during boot
> > on any of them.  Mika doesn't see them either I suppose, or he would have told
> > me about that before.
> > 
> > And let's just make it clear that it is not usual or even OK to generate bus
> > checks or device checks during boot like this.  And since the changes in
> > question have been in linux-next since right after the 3.11 merge window, I
> > think that someone would have complained already had that been a common issue.
> > 
> > Of course, we need to deal with that somehow nevertheless. :-)
> > 
> > > Just to give you an idea:
> > > 
> > > CONFIG_HOTPLUG_PCI_ACPI=y
> > > 
> > > $ dmesg | wc
> > >   5697  49935 384368
> > > 
> > > $ dmesg | tail --lines=1
> > > [   53.137123] Ebtables v2.0 registered
> > > 
> > > -- vs --
> > > 
> > > # CONFIG_HOTPLUG_PCI_ACPI is not set
> > > 
> > > $ dmesg | wc
> > >  1053  9176 71652
> > > 
> > > $dmesg | tail --lines=1
> > > [   28.917220] Ebtables v2.0 registered
> > > 
> > > So it spews out 5x more output with acpiphp enabled and takes and extra
> > > 24s to boot (nearly 2x).  Not good.
> > 
> > The "no hotplug settings from platform" message is from pci_configure_slot().
> > I think the messages you're seeing are from the call to it in
> > acpiphp_set_hpp_values() which is called by enable_slot().
> > 
> > There, I think, we can simply check the return value of pci_scan_slot() and
> > if that is 0 (no new devices), we can just skip everything under the call to
> > __pci_bus_assign_resources().
> > 
> > However, we can't skip the scanning of bridges, if any, because there may be
> > new devices below them and I guess that's what takes so much time on your
> > machine.
> 
> OK, one piece is missing.  We may need to evaluate _OSC after handling each
> event to let the platform know the status.
> 
> Can you please check if the appended patch makes any difference (with the
> previous fix applied, of course)?
> 
> If fact, it is two patches combined.  One of them optimizes enable_slot()
> slightly and the other adds the missing _OSC evaluation.

Better, still double the output:

$ dmesg | wc
   2169   19047  152710

$ dmesg | tail --lines=1
[   39.980918] Ebtables v2.0 registered

Here's another interesting stat:

$ dmesg | colrm 1 15 | sort | uniq -c | sort -nr | head --lines=25
     73 pci 0000:00:1f.0: BAR 13: [io  0x1000-0x107f] has bogus alignment
     73 pci 0000:00:1e.0: PCI bridge to [bus 06]
     64 pci 0000:00:1e.0:   bridge window [mem 0x81100000-0x812fffff 64bit pref]
     64 pci 0000:00:1e.0:   bridge window [mem 0x80f00000-0x810fffff]
     64 pci 0000:00:1e.0:   bridge window [io  0x7000-0x7fff]
     38 pci 0000:00:1c.4: PCI bridge to [bus 05]
     38 pci 0000:00:1c.4:   bridge window [mem 0xf4f00000-0xf4ffffff]
     38 pci 0000:00:1c.0: PCI bridge to [bus 04]
     38 pci 0000:00:07.0: PCI bridge to [bus 03]
     38 pci 0000:00:07.0:   bridge window [mem 0xf2000000-0xf40fffff]
     38 pci 0000:00:07.0:   bridge window [mem 0xe0000000-0xf1ffffff 64bit pref]
     38 pci 0000:00:07.0:   bridge window [io  0x4000-0x4fff]
     38 pci 0000:00:03.0: PCI bridge to [bus 02]
     38 pci 0000:00:03.0:   bridge window [mem 0xf4e00000-0xf4efffff]
     38 pci 0000:00:03.0:   bridge window [mem 0xd0000000-0xdfffffff 64bit pref]
     38 pci 0000:00:03.0:   bridge window [io  0x3000-0x3fff]
     38 pci 0000:00:01.0: PCI bridge to [bus 01]
     38 pci 0000:00:01.0:   bridge window [mem 0xf4100000-0xf4bfffff]
     38 pci 0000:00:01.0:   bridge window [io  0x2000-0x2fff]
     37 pci 0000:00:1c.4:   bridge window [mem 0x80c00000-0x80dfffff 64bit pref]
     37 pci 0000:00:1c.4:   bridge window [io  0x6000-0x6fff]
     37 pci 0000:00:1c.0:   bridge window [mem 0x80a00000-0x80bfffff 64bit pref]
     37 pci 0000:00:1c.0:   bridge window [mem 0x80800000-0x809fffff]
     37 pci 0000:00:1c.0:   bridge window [io  0x5000-0x5fff]
     36 pci 0000:00:01.0:   bridge window [mem 0x80000000-0x807fffff 64bit pref]

This is nearly the entire difference, just 25 lines repeated over and
over.  Thanks,

Alex


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

* Re: Excess dmesg output from ACPIPHP on boot (was: Re: [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots)
  2013-09-05 22:17                             ` Alex Williamson
@ 2013-09-05 22:40                               ` Rafael J. Wysocki
  2013-09-05 23:08                                 ` Alex Williamson
  0 siblings, 1 reply; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-09-05 22:40 UTC (permalink / raw)
  To: Alex Williamson
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Thursday, September 05, 2013 04:17:25 PM Alex Williamson wrote:
> On Thu, 2013-09-05 at 23:39 +0200, Rafael J. Wysocki wrote:
> > On Thursday, September 05, 2013 09:44:26 PM Rafael J. Wysocki wrote:
> > > On Thursday, September 05, 2013 08:21:41 AM Alex Williamson wrote:
> > 
> > [...]
> > 
> > > > > 
> > > > > [   18.288122] pci 0000:00:00.0: no hotplug settings from platform
> > > > > [   18.288127] pcieport 0000:00:01.0: no hotplug settings from platform
> > > > > [   18.288142] pci 0000:01:00.0: no hotplug settings from platform
> > > > > [   18.288157] pci 0000:01:00.1: no hotplug settings from platform
> > > > > [   18.288162] pcieport 0000:00:03.0: no hotplug settings from platform
> > > > > [   18.288176] pci 0000:02:00.0: no hotplug settings from platform
> > > > > [   18.288190] pci 0000:02:00.1: no hotplug settings from platform
> > > > > [   18.288195] pcieport 0000:00:07.0: no hotplug settings from platform
> > > > > [   18.288209] pci 0000:03:00.0: no hotplug settings from platform
> > > > > [   18.288224] pci 0000:03:00.1: no hotplug settings from platform
> > > > > [   18.288228] pci 0000:00:14.0: no hotplug settings from platform
> > > > > [   18.288233] pci 0000:00:14.1: no hotplug settings from platform
> > > > > [   18.288237] pci 0000:00:14.2: no hotplug settings from platform
> > > > > [   18.288242] pci 0000:00:16.0: no hotplug settings from platform
> > > > > [   18.288247] pci 0000:00:16.1: no hotplug settings from platform
> > > > > [   18.288251] pci 0000:00:16.2: no hotplug settings from platform
> > > > > [   18.288256] pci 0000:00:16.3: no hotplug settings from platform
> > > > > [   18.288260] pci 0000:00:16.4: no hotplug settings from platform
> > > > > [   18.288265] pci 0000:00:16.5: no hotplug settings from platform
> > > > > [   18.288269] pci 0000:00:16.6: no hotplug settings from platform
> > > > > [   18.288274] pci 0000:00:16.7: no hotplug settings from platform
> > > > > [   18.288278] pci 0000:00:1a.0: no hotplug settings from platform
> > > > > [   18.288279] pci 0000:00:1a.0: using default PCI settings
> > > > > [   18.288292] pci 0000:00:1a.1: no hotplug settings from platform
> > > > > [   18.288293] pci 0000:00:1a.1: using default PCI settings
> > > > > [   18.288307] ehci-pci 0000:00:1a.7: no hotplug settings from platform
> > > > > [   18.288308] ehci-pci 0000:00:1a.7: using default PCI settings
> > > > > [   18.288322] pci 0000:00:1b.0: no hotplug settings from platform
> > > > > [   18.288327] pcieport 0000:00:1c.0: no hotplug settings from platform
> > > > > [   18.288332] pcieport 0000:00:1c.4: no hotplug settings from platform
> > > > > [   18.288344] pci 0000:05:00.0: no hotplug settings from platform
> > > > > [   18.288349] pci 0000:00:1d.0: no hotplug settings from platform
> > > > > [   18.288350] pci 0000:00:1d.0: using default PCI settings
> > > > > [   18.288360] pci 0000:00:1d.1: no hotplug settings from platform
> > > > > [   18.288361] pci 0000:00:1d.1: using default PCI settings
> > > > > [   18.288374] pci 0000:00:1d.2: no hotplug settings from platform
> > > > > [   18.288374] pci 0000:00:1d.2: using default PCI settings
> > > > > [   18.288387] pci 0000:00:1d.3: no hotplug settings from platform
> > > > > [   18.288387] pci 0000:00:1d.3: using default PCI settings
> > > > > 
> > > > > The boot is noticeably slower.  What's going to happen on systems that
> > > > > actually have a significant I/O topology vs my little workstation?
> > > 
> > > That depends on how many bus check/device check events they generate on boot.
> > > 
> > > My test machines don't generate them during boot at all (even the one with
> > > a Thunderbolt connector), so I don't see the messages in question during boot
> > > on any of them.  Mika doesn't see them either I suppose, or he would have told
> > > me about that before.
> > > 
> > > And let's just make it clear that it is not usual or even OK to generate bus
> > > checks or device checks during boot like this.  And since the changes in
> > > question have been in linux-next since right after the 3.11 merge window, I
> > > think that someone would have complained already had that been a common issue.
> > > 
> > > Of course, we need to deal with that somehow nevertheless. :-)
> > > 
> > > > Just to give you an idea:
> > > > 
> > > > CONFIG_HOTPLUG_PCI_ACPI=y
> > > > 
> > > > $ dmesg | wc
> > > >   5697  49935 384368
> > > > 
> > > > $ dmesg | tail --lines=1
> > > > [   53.137123] Ebtables v2.0 registered
> > > > 
> > > > -- vs --
> > > > 
> > > > # CONFIG_HOTPLUG_PCI_ACPI is not set
> > > > 
> > > > $ dmesg | wc
> > > >  1053  9176 71652
> > > > 
> > > > $dmesg | tail --lines=1
> > > > [   28.917220] Ebtables v2.0 registered
> > > > 
> > > > So it spews out 5x more output with acpiphp enabled and takes and extra
> > > > 24s to boot (nearly 2x).  Not good.
> > > 
> > > The "no hotplug settings from platform" message is from pci_configure_slot().
> > > I think the messages you're seeing are from the call to it in
> > > acpiphp_set_hpp_values() which is called by enable_slot().
> > > 
> > > There, I think, we can simply check the return value of pci_scan_slot() and
> > > if that is 0 (no new devices), we can just skip everything under the call to
> > > __pci_bus_assign_resources().
> > > 
> > > However, we can't skip the scanning of bridges, if any, because there may be
> > > new devices below them and I guess that's what takes so much time on your
> > > machine.
> > 
> > OK, one piece is missing.  We may need to evaluate _OSC after handling each
> > event to let the platform know the status.
> > 
> > Can you please check if the appended patch makes any difference (with the
> > previous fix applied, of course)?
> > 
> > If fact, it is two patches combined.  One of them optimizes enable_slot()
> > slightly and the other adds the missing _OSC evaluation.
> 
> Better, still double the output:
> 
> $ dmesg | wc
>    2169   19047  152710

I see.

What about the timing?

> $ dmesg | tail --lines=1
> [   39.980918] Ebtables v2.0 registered
> 
> Here's another interesting stat:
> 
> $ dmesg | colrm 1 15 | sort | uniq -c | sort -nr | head --lines=25
>      73 pci 0000:00:1f.0: BAR 13: [io  0x1000-0x107f] has bogus alignment
>      73 pci 0000:00:1e.0: PCI bridge to [bus 06]
>      64 pci 0000:00:1e.0:   bridge window [mem 0x81100000-0x812fffff 64bit pref]
>      64 pci 0000:00:1e.0:   bridge window [mem 0x80f00000-0x810fffff]
>      64 pci 0000:00:1e.0:   bridge window [io  0x7000-0x7fff]
>      38 pci 0000:00:1c.4: PCI bridge to [bus 05]
>      38 pci 0000:00:1c.4:   bridge window [mem 0xf4f00000-0xf4ffffff]
>      38 pci 0000:00:1c.0: PCI bridge to [bus 04]
>      38 pci 0000:00:07.0: PCI bridge to [bus 03]
>      38 pci 0000:00:07.0:   bridge window [mem 0xf2000000-0xf40fffff]
>      38 pci 0000:00:07.0:   bridge window [mem 0xe0000000-0xf1ffffff 64bit pref]
>      38 pci 0000:00:07.0:   bridge window [io  0x4000-0x4fff]
>      38 pci 0000:00:03.0: PCI bridge to [bus 02]
>      38 pci 0000:00:03.0:   bridge window [mem 0xf4e00000-0xf4efffff]
>      38 pci 0000:00:03.0:   bridge window [mem 0xd0000000-0xdfffffff 64bit pref]
>      38 pci 0000:00:03.0:   bridge window [io  0x3000-0x3fff]
>      38 pci 0000:00:01.0: PCI bridge to [bus 01]
>      38 pci 0000:00:01.0:   bridge window [mem 0xf4100000-0xf4bfffff]
>      38 pci 0000:00:01.0:   bridge window [io  0x2000-0x2fff]
>      37 pci 0000:00:1c.4:   bridge window [mem 0x80c00000-0x80dfffff 64bit pref]
>      37 pci 0000:00:1c.4:   bridge window [io  0x6000-0x6fff]
>      37 pci 0000:00:1c.0:   bridge window [mem 0x80a00000-0x80bfffff 64bit pref]
>      37 pci 0000:00:1c.0:   bridge window [mem 0x80800000-0x809fffff]
>      37 pci 0000:00:1c.0:   bridge window [io  0x5000-0x5fff]
>      36 pci 0000:00:01.0:   bridge window [mem 0x80000000-0x807fffff 64bit pref]
> 
> This is nearly the entire difference, just 25 lines repeated over and
> over.

Well, this is the bridge sizing I talked about previously.  We still get
apparently spurious bus check/device check events and they trigger bridge
scans.

I'm not sure what to do about that and I wonder whether or not this is
reproducible on any other machines you can test.

Can you please change dbg() to pr_info() under ACPI_NOTIFY_BUS_CHECK and
ACPI_NOTIFY_DEVICE_CHECK in hotplug_event() (acpiphp_glue.c), grep the boot
dmesg log for "check notify" and send the result?  I'm wondering what's
going on there.

Thanks,
Rafael


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

* Re: Excess dmesg output from ACPIPHP on boot (was: Re: [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots)
  2013-09-05 22:40                               ` Rafael J. Wysocki
@ 2013-09-05 23:08                                 ` Alex Williamson
  2013-09-05 23:36                                   ` Rafael J. Wysocki
  0 siblings, 1 reply; 135+ messages in thread
From: Alex Williamson @ 2013-09-05 23:08 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Fri, 2013-09-06 at 00:40 +0200, Rafael J. Wysocki wrote:
> On Thursday, September 05, 2013 04:17:25 PM Alex Williamson wrote:
> > On Thu, 2013-09-05 at 23:39 +0200, Rafael J. Wysocki wrote:
> > > On Thursday, September 05, 2013 09:44:26 PM Rafael J. Wysocki wrote:
> > > > On Thursday, September 05, 2013 08:21:41 AM Alex Williamson wrote:
> > > 
> > > [...]
> > > 
> > > > > > 
> > > > > > [   18.288122] pci 0000:00:00.0: no hotplug settings from platform
> > > > > > [   18.288127] pcieport 0000:00:01.0: no hotplug settings from platform
> > > > > > [   18.288142] pci 0000:01:00.0: no hotplug settings from platform
> > > > > > [   18.288157] pci 0000:01:00.1: no hotplug settings from platform
> > > > > > [   18.288162] pcieport 0000:00:03.0: no hotplug settings from platform
> > > > > > [   18.288176] pci 0000:02:00.0: no hotplug settings from platform
> > > > > > [   18.288190] pci 0000:02:00.1: no hotplug settings from platform
> > > > > > [   18.288195] pcieport 0000:00:07.0: no hotplug settings from platform
> > > > > > [   18.288209] pci 0000:03:00.0: no hotplug settings from platform
> > > > > > [   18.288224] pci 0000:03:00.1: no hotplug settings from platform
> > > > > > [   18.288228] pci 0000:00:14.0: no hotplug settings from platform
> > > > > > [   18.288233] pci 0000:00:14.1: no hotplug settings from platform
> > > > > > [   18.288237] pci 0000:00:14.2: no hotplug settings from platform
> > > > > > [   18.288242] pci 0000:00:16.0: no hotplug settings from platform
> > > > > > [   18.288247] pci 0000:00:16.1: no hotplug settings from platform
> > > > > > [   18.288251] pci 0000:00:16.2: no hotplug settings from platform
> > > > > > [   18.288256] pci 0000:00:16.3: no hotplug settings from platform
> > > > > > [   18.288260] pci 0000:00:16.4: no hotplug settings from platform
> > > > > > [   18.288265] pci 0000:00:16.5: no hotplug settings from platform
> > > > > > [   18.288269] pci 0000:00:16.6: no hotplug settings from platform
> > > > > > [   18.288274] pci 0000:00:16.7: no hotplug settings from platform
> > > > > > [   18.288278] pci 0000:00:1a.0: no hotplug settings from platform
> > > > > > [   18.288279] pci 0000:00:1a.0: using default PCI settings
> > > > > > [   18.288292] pci 0000:00:1a.1: no hotplug settings from platform
> > > > > > [   18.288293] pci 0000:00:1a.1: using default PCI settings
> > > > > > [   18.288307] ehci-pci 0000:00:1a.7: no hotplug settings from platform
> > > > > > [   18.288308] ehci-pci 0000:00:1a.7: using default PCI settings
> > > > > > [   18.288322] pci 0000:00:1b.0: no hotplug settings from platform
> > > > > > [   18.288327] pcieport 0000:00:1c.0: no hotplug settings from platform
> > > > > > [   18.288332] pcieport 0000:00:1c.4: no hotplug settings from platform
> > > > > > [   18.288344] pci 0000:05:00.0: no hotplug settings from platform
> > > > > > [   18.288349] pci 0000:00:1d.0: no hotplug settings from platform
> > > > > > [   18.288350] pci 0000:00:1d.0: using default PCI settings
> > > > > > [   18.288360] pci 0000:00:1d.1: no hotplug settings from platform
> > > > > > [   18.288361] pci 0000:00:1d.1: using default PCI settings
> > > > > > [   18.288374] pci 0000:00:1d.2: no hotplug settings from platform
> > > > > > [   18.288374] pci 0000:00:1d.2: using default PCI settings
> > > > > > [   18.288387] pci 0000:00:1d.3: no hotplug settings from platform
> > > > > > [   18.288387] pci 0000:00:1d.3: using default PCI settings
> > > > > > 
> > > > > > The boot is noticeably slower.  What's going to happen on systems that
> > > > > > actually have a significant I/O topology vs my little workstation?
> > > > 
> > > > That depends on how many bus check/device check events they generate on boot.
> > > > 
> > > > My test machines don't generate them during boot at all (even the one with
> > > > a Thunderbolt connector), so I don't see the messages in question during boot
> > > > on any of them.  Mika doesn't see them either I suppose, or he would have told
> > > > me about that before.
> > > > 
> > > > And let's just make it clear that it is not usual or even OK to generate bus
> > > > checks or device checks during boot like this.  And since the changes in
> > > > question have been in linux-next since right after the 3.11 merge window, I
> > > > think that someone would have complained already had that been a common issue.
> > > > 
> > > > Of course, we need to deal with that somehow nevertheless. :-)
> > > > 
> > > > > Just to give you an idea:
> > > > > 
> > > > > CONFIG_HOTPLUG_PCI_ACPI=y
> > > > > 
> > > > > $ dmesg | wc
> > > > >   5697  49935 384368
> > > > > 
> > > > > $ dmesg | tail --lines=1
> > > > > [   53.137123] Ebtables v2.0 registered
> > > > > 
> > > > > -- vs --
> > > > > 
> > > > > # CONFIG_HOTPLUG_PCI_ACPI is not set
> > > > > 
> > > > > $ dmesg | wc
> > > > >  1053  9176 71652
> > > > > 
> > > > > $dmesg | tail --lines=1
> > > > > [   28.917220] Ebtables v2.0 registered
> > > > > 
> > > > > So it spews out 5x more output with acpiphp enabled and takes and extra
> > > > > 24s to boot (nearly 2x).  Not good.
> > > > 
> > > > The "no hotplug settings from platform" message is from pci_configure_slot().
> > > > I think the messages you're seeing are from the call to it in
> > > > acpiphp_set_hpp_values() which is called by enable_slot().
> > > > 
> > > > There, I think, we can simply check the return value of pci_scan_slot() and
> > > > if that is 0 (no new devices), we can just skip everything under the call to
> > > > __pci_bus_assign_resources().
> > > > 
> > > > However, we can't skip the scanning of bridges, if any, because there may be
> > > > new devices below them and I guess that's what takes so much time on your
> > > > machine.
> > > 
> > > OK, one piece is missing.  We may need to evaluate _OSC after handling each
> > > event to let the platform know the status.
> > > 
> > > Can you please check if the appended patch makes any difference (with the
> > > previous fix applied, of course)?
> > > 
> > > If fact, it is two patches combined.  One of them optimizes enable_slot()
> > > slightly and the other adds the missing _OSC evaluation.
> > 
> > Better, still double the output:
> > 
> > $ dmesg | wc
> >    2169   19047  152710
> 
> I see.
> 
> What about the timing?

~40s below vs ~29s for acpiphp config'd out above.

> > $ dmesg | tail --lines=1
> > [   39.980918] Ebtables v2.0 registered
> > 
> > Here's another interesting stat:
> > 
> > $ dmesg | colrm 1 15 | sort | uniq -c | sort -nr | head --lines=25
> >      73 pci 0000:00:1f.0: BAR 13: [io  0x1000-0x107f] has bogus alignment
> >      73 pci 0000:00:1e.0: PCI bridge to [bus 06]
> >      64 pci 0000:00:1e.0:   bridge window [mem 0x81100000-0x812fffff 64bit pref]
> >      64 pci 0000:00:1e.0:   bridge window [mem 0x80f00000-0x810fffff]
> >      64 pci 0000:00:1e.0:   bridge window [io  0x7000-0x7fff]
> >      38 pci 0000:00:1c.4: PCI bridge to [bus 05]
> >      38 pci 0000:00:1c.4:   bridge window [mem 0xf4f00000-0xf4ffffff]
> >      38 pci 0000:00:1c.0: PCI bridge to [bus 04]
> >      38 pci 0000:00:07.0: PCI bridge to [bus 03]
> >      38 pci 0000:00:07.0:   bridge window [mem 0xf2000000-0xf40fffff]
> >      38 pci 0000:00:07.0:   bridge window [mem 0xe0000000-0xf1ffffff 64bit pref]
> >      38 pci 0000:00:07.0:   bridge window [io  0x4000-0x4fff]
> >      38 pci 0000:00:03.0: PCI bridge to [bus 02]
> >      38 pci 0000:00:03.0:   bridge window [mem 0xf4e00000-0xf4efffff]
> >      38 pci 0000:00:03.0:   bridge window [mem 0xd0000000-0xdfffffff 64bit pref]
> >      38 pci 0000:00:03.0:   bridge window [io  0x3000-0x3fff]
> >      38 pci 0000:00:01.0: PCI bridge to [bus 01]
> >      38 pci 0000:00:01.0:   bridge window [mem 0xf4100000-0xf4bfffff]
> >      38 pci 0000:00:01.0:   bridge window [io  0x2000-0x2fff]
> >      37 pci 0000:00:1c.4:   bridge window [mem 0x80c00000-0x80dfffff 64bit pref]
> >      37 pci 0000:00:1c.4:   bridge window [io  0x6000-0x6fff]
> >      37 pci 0000:00:1c.0:   bridge window [mem 0x80a00000-0x80bfffff 64bit pref]
> >      37 pci 0000:00:1c.0:   bridge window [mem 0x80800000-0x809fffff]
> >      37 pci 0000:00:1c.0:   bridge window [io  0x5000-0x5fff]
> >      36 pci 0000:00:01.0:   bridge window [mem 0x80000000-0x807fffff 64bit pref]
> > 
> > This is nearly the entire difference, just 25 lines repeated over and
> > over.
> 
> Well, this is the bridge sizing I talked about previously.  We still get
> apparently spurious bus check/device check events and they trigger bridge
> scans.
> 
> I'm not sure what to do about that and I wonder whether or not this is
> reproducible on any other machines you can test.

I can try it on a couple other systems, but probably not until tomorrow.

> Can you please change dbg() to pr_info() under ACPI_NOTIFY_BUS_CHECK and
> ACPI_NOTIFY_DEVICE_CHECK in hotplug_event() (acpiphp_glue.c), grep the boot
> dmesg log for "check notify" and send the result?  I'm wondering what's
> going on there.

$ dmesg | grep "check notify"
[    1.633228] hotplug_event: Device check notify on \_SB_.PCI0.PEX2
[    2.472004] hotplug_event: Device check notify on \_SB_.PCI0.PEX3
[    2.477288] hotplug_event: Device check notify on \_SB_.PCI0.PEX4
[    2.482571] hotplug_event: Device check notify on \_SB_.PCI0.PEX5
[    2.482579] hotplug_event: Device check notify on \_SB_.PCI0.PEX6
[    8.204953] hotplug_event: Device check notify on \_SB_.PCI0.PEX2
[    8.209632] hotplug_event: Device check notify on \_SB_.PCI0.PEX3
[    8.214272] hotplug_event: Device check notify on \_SB_.PCI0.PEX4
[    8.218894] hotplug_event: Device check notify on \_SB_.PCI0.PEX5
[    8.218901] hotplug_event: Device check notify on \_SB_.PCI0.PEX6

Thanks,
Alex


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

* Re: Excess dmesg output from ACPIPHP on boot (was: Re: [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots)
  2013-09-05 23:36                                   ` Rafael J. Wysocki
@ 2013-09-05 23:31                                     ` Alex Williamson
  2013-09-05 23:48                                       ` Rafael J. Wysocki
  2013-09-06 12:19                                     ` Bjorn Helgaas
  2013-09-06 13:42                                     ` [PATCH 0/2] Re: Excess dmesg output from ACPIPHP on boot Rafael J. Wysocki
  2 siblings, 1 reply; 135+ messages in thread
From: Alex Williamson @ 2013-09-05 23:31 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Fri, 2013-09-06 at 01:36 +0200, Rafael J. Wysocki wrote:
> On Thursday, September 05, 2013 05:08:03 PM Alex Williamson wrote:
> > On Fri, 2013-09-06 at 00:40 +0200, Rafael J. Wysocki wrote:
> > > On Thursday, September 05, 2013 04:17:25 PM Alex Williamson wrote:
> > > > On Thu, 2013-09-05 at 23:39 +0200, Rafael J. Wysocki wrote:
> > > > > On Thursday, September 05, 2013 09:44:26 PM Rafael J. Wysocki wrote:
> > > > > > On Thursday, September 05, 2013 08:21:41 AM Alex Williamson wrote:
> > > > > 
> > > > > [...]
> > > > > 
> > > > > > > > 
> > > > > > > > [   18.288122] pci 0000:00:00.0: no hotplug settings from platform
> > > > > > > > [   18.288127] pcieport 0000:00:01.0: no hotplug settings from platform
> > > > > > > > [   18.288142] pci 0000:01:00.0: no hotplug settings from platform
> > > > > > > > [   18.288157] pci 0000:01:00.1: no hotplug settings from platform
> > > > > > > > [   18.288162] pcieport 0000:00:03.0: no hotplug settings from platform
> > > > > > > > [   18.288176] pci 0000:02:00.0: no hotplug settings from platform
> > > > > > > > [   18.288190] pci 0000:02:00.1: no hotplug settings from platform
> > > > > > > > [   18.288195] pcieport 0000:00:07.0: no hotplug settings from platform
> > > > > > > > [   18.288209] pci 0000:03:00.0: no hotplug settings from platform
> > > > > > > > [   18.288224] pci 0000:03:00.1: no hotplug settings from platform
> > > > > > > > [   18.288228] pci 0000:00:14.0: no hotplug settings from platform
> > > > > > > > [   18.288233] pci 0000:00:14.1: no hotplug settings from platform
> > > > > > > > [   18.288237] pci 0000:00:14.2: no hotplug settings from platform
> > > > > > > > [   18.288242] pci 0000:00:16.0: no hotplug settings from platform
> > > > > > > > [   18.288247] pci 0000:00:16.1: no hotplug settings from platform
> > > > > > > > [   18.288251] pci 0000:00:16.2: no hotplug settings from platform
> > > > > > > > [   18.288256] pci 0000:00:16.3: no hotplug settings from platform
> > > > > > > > [   18.288260] pci 0000:00:16.4: no hotplug settings from platform
> > > > > > > > [   18.288265] pci 0000:00:16.5: no hotplug settings from platform
> > > > > > > > [   18.288269] pci 0000:00:16.6: no hotplug settings from platform
> > > > > > > > [   18.288274] pci 0000:00:16.7: no hotplug settings from platform
> > > > > > > > [   18.288278] pci 0000:00:1a.0: no hotplug settings from platform
> > > > > > > > [   18.288279] pci 0000:00:1a.0: using default PCI settings
> > > > > > > > [   18.288292] pci 0000:00:1a.1: no hotplug settings from platform
> > > > > > > > [   18.288293] pci 0000:00:1a.1: using default PCI settings
> > > > > > > > [   18.288307] ehci-pci 0000:00:1a.7: no hotplug settings from platform
> > > > > > > > [   18.288308] ehci-pci 0000:00:1a.7: using default PCI settings
> > > > > > > > [   18.288322] pci 0000:00:1b.0: no hotplug settings from platform
> > > > > > > > [   18.288327] pcieport 0000:00:1c.0: no hotplug settings from platform
> > > > > > > > [   18.288332] pcieport 0000:00:1c.4: no hotplug settings from platform
> > > > > > > > [   18.288344] pci 0000:05:00.0: no hotplug settings from platform
> > > > > > > > [   18.288349] pci 0000:00:1d.0: no hotplug settings from platform
> > > > > > > > [   18.288350] pci 0000:00:1d.0: using default PCI settings
> > > > > > > > [   18.288360] pci 0000:00:1d.1: no hotplug settings from platform
> > > > > > > > [   18.288361] pci 0000:00:1d.1: using default PCI settings
> > > > > > > > [   18.288374] pci 0000:00:1d.2: no hotplug settings from platform
> > > > > > > > [   18.288374] pci 0000:00:1d.2: using default PCI settings
> > > > > > > > [   18.288387] pci 0000:00:1d.3: no hotplug settings from platform
> > > > > > > > [   18.288387] pci 0000:00:1d.3: using default PCI settings
> > > > > > > > 
> > > > > > > > The boot is noticeably slower.  What's going to happen on systems that
> > > > > > > > actually have a significant I/O topology vs my little workstation?
> > > > > > 
> > > > > > That depends on how many bus check/device check events they generate on boot.
> > > > > > 
> > > > > > My test machines don't generate them during boot at all (even the one with
> > > > > > a Thunderbolt connector), so I don't see the messages in question during boot
> > > > > > on any of them.  Mika doesn't see them either I suppose, or he would have told
> > > > > > me about that before.
> > > > > > 
> > > > > > And let's just make it clear that it is not usual or even OK to generate bus
> > > > > > checks or device checks during boot like this.  And since the changes in
> > > > > > question have been in linux-next since right after the 3.11 merge window, I
> > > > > > think that someone would have complained already had that been a common issue.
> > > > > > 
> > > > > > Of course, we need to deal with that somehow nevertheless. :-)
> > > > > > 
> > > > > > > Just to give you an idea:
> > > > > > > 
> > > > > > > CONFIG_HOTPLUG_PCI_ACPI=y
> > > > > > > 
> > > > > > > $ dmesg | wc
> > > > > > >   5697  49935 384368
> > > > > > > 
> > > > > > > $ dmesg | tail --lines=1
> > > > > > > [   53.137123] Ebtables v2.0 registered
> > > > > > > 
> > > > > > > -- vs --
> > > > > > > 
> > > > > > > # CONFIG_HOTPLUG_PCI_ACPI is not set
> > > > > > > 
> > > > > > > $ dmesg | wc
> > > > > > >  1053  9176 71652
> > > > > > > 
> > > > > > > $dmesg | tail --lines=1
> > > > > > > [   28.917220] Ebtables v2.0 registered
> > > > > > > 
> > > > > > > So it spews out 5x more output with acpiphp enabled and takes and extra
> > > > > > > 24s to boot (nearly 2x).  Not good.
> > > > > > 
> > > > > > The "no hotplug settings from platform" message is from pci_configure_slot().
> > > > > > I think the messages you're seeing are from the call to it in
> > > > > > acpiphp_set_hpp_values() which is called by enable_slot().
> > > > > > 
> > > > > > There, I think, we can simply check the return value of pci_scan_slot() and
> > > > > > if that is 0 (no new devices), we can just skip everything under the call to
> > > > > > __pci_bus_assign_resources().
> > > > > > 
> > > > > > However, we can't skip the scanning of bridges, if any, because there may be
> > > > > > new devices below them and I guess that's what takes so much time on your
> > > > > > machine.
> > > > > 
> > > > > OK, one piece is missing.  We may need to evaluate _OSC after handling each
> > > > > event to let the platform know the status.
> > > > > 
> > > > > Can you please check if the appended patch makes any difference (with the
> > > > > previous fix applied, of course)?
> > > > > 
> > > > > If fact, it is two patches combined.  One of them optimizes enable_slot()
> > > > > slightly and the other adds the missing _OSC evaluation.
> > > > 
> > > > Better, still double the output:
> > > > 
> > > > $ dmesg | wc
> > > >    2169   19047  152710
> > > 
> > > I see.
> > > 
> > > What about the timing?
> > 
> > ~40s below vs ~29s for acpiphp config'd out above.
> 
> Well, that's better than before.
> 
> I'll prepare "official" patches with the last changes then too.
> 
> > > > $ dmesg | tail --lines=1
> > > > [   39.980918] Ebtables v2.0 registered
> > > > 
> > > > Here's another interesting stat:
> > > > 
> > > > $ dmesg | colrm 1 15 | sort | uniq -c | sort -nr | head --lines=25
> > > >      73 pci 0000:00:1f.0: BAR 13: [io  0x1000-0x107f] has bogus alignment
> > > >      73 pci 0000:00:1e.0: PCI bridge to [bus 06]
> > > >      64 pci 0000:00:1e.0:   bridge window [mem 0x81100000-0x812fffff 64bit pref]
> > > >      64 pci 0000:00:1e.0:   bridge window [mem 0x80f00000-0x810fffff]
> > > >      64 pci 0000:00:1e.0:   bridge window [io  0x7000-0x7fff]
> > > >      38 pci 0000:00:1c.4: PCI bridge to [bus 05]
> > > >      38 pci 0000:00:1c.4:   bridge window [mem 0xf4f00000-0xf4ffffff]
> > > >      38 pci 0000:00:1c.0: PCI bridge to [bus 04]
> > > >      38 pci 0000:00:07.0: PCI bridge to [bus 03]
> > > >      38 pci 0000:00:07.0:   bridge window [mem 0xf2000000-0xf40fffff]
> > > >      38 pci 0000:00:07.0:   bridge window [mem 0xe0000000-0xf1ffffff 64bit pref]
> > > >      38 pci 0000:00:07.0:   bridge window [io  0x4000-0x4fff]
> > > >      38 pci 0000:00:03.0: PCI bridge to [bus 02]
> > > >      38 pci 0000:00:03.0:   bridge window [mem 0xf4e00000-0xf4efffff]
> > > >      38 pci 0000:00:03.0:   bridge window [mem 0xd0000000-0xdfffffff 64bit pref]
> > > >      38 pci 0000:00:03.0:   bridge window [io  0x3000-0x3fff]
> > > >      38 pci 0000:00:01.0: PCI bridge to [bus 01]
> > > >      38 pci 0000:00:01.0:   bridge window [mem 0xf4100000-0xf4bfffff]
> > > >      38 pci 0000:00:01.0:   bridge window [io  0x2000-0x2fff]
> > > >      37 pci 0000:00:1c.4:   bridge window [mem 0x80c00000-0x80dfffff 64bit pref]
> > > >      37 pci 0000:00:1c.4:   bridge window [io  0x6000-0x6fff]
> > > >      37 pci 0000:00:1c.0:   bridge window [mem 0x80a00000-0x80bfffff 64bit pref]
> > > >      37 pci 0000:00:1c.0:   bridge window [mem 0x80800000-0x809fffff]
> > > >      37 pci 0000:00:1c.0:   bridge window [io  0x5000-0x5fff]
> > > >      36 pci 0000:00:01.0:   bridge window [mem 0x80000000-0x807fffff 64bit pref]
> > > > 
> > > > This is nearly the entire difference, just 25 lines repeated over and
> > > > over.
> 
> Can you check how many times the lines above are repeated?

The line count is pre-pended to each line.  73 times for the first two
line, etc.

> > > 
> > > Well, this is the bridge sizing I talked about previously.  We still get
> > > apparently spurious bus check/device check events and they trigger bridge
> > > scans.
> > > 
> > > I'm not sure what to do about that and I wonder whether or not this is
> > > reproducible on any other machines you can test.
> > 
> > I can try it on a couple other systems, but probably not until tomorrow.
> 
> Tomorrow (or even later) works just fine for me. :-)
> 
> > > Can you please change dbg() to pr_info() under ACPI_NOTIFY_BUS_CHECK and
> > > ACPI_NOTIFY_DEVICE_CHECK in hotplug_event() (acpiphp_glue.c), grep the boot
> > > dmesg log for "check notify" and send the result?  I'm wondering what's
> > > going on there.
> > 
> > $ dmesg | grep "check notify"
> > [    1.633228] hotplug_event: Device check notify on \_SB_.PCI0.PEX2
> > [    2.472004] hotplug_event: Device check notify on \_SB_.PCI0.PEX3
> > [    2.477288] hotplug_event: Device check notify on \_SB_.PCI0.PEX4
> > [    2.482571] hotplug_event: Device check notify on \_SB_.PCI0.PEX5
> > [    2.482579] hotplug_event: Device check notify on \_SB_.PCI0.PEX6
> > [    8.204953] hotplug_event: Device check notify on \_SB_.PCI0.PEX2
> > [    8.209632] hotplug_event: Device check notify on \_SB_.PCI0.PEX3
> > [    8.214272] hotplug_event: Device check notify on \_SB_.PCI0.PEX4
> > [    8.218894] hotplug_event: Device check notify on \_SB_.PCI0.PEX5
> > [    8.218901] hotplug_event: Device check notify on \_SB_.PCI0.PEX6
> 
> So I guess the PEXn things are PCIe ports and we get two notifications
> for each of them, so everything below them gets rescanned.
> 
> I've just talked to Bjorn about that and we don't seem to have a good idea
> how to handle this.  The notifies shouldn't be there, but we kind of have
> to handle them.
> 
> I guess we could suppress the output from repeated bridge scans.  Alternatively,
> we could just blacklist this particular system somehow if the problem is
> specific to it.

Can't we determine that nothing has changed and avoid re-printing?  I
have a hard time believing this system is all that unique.  Thanks,

Alex

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

* Re: Excess dmesg output from ACPIPHP on boot (was: Re: [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots)
  2013-09-05 23:08                                 ` Alex Williamson
@ 2013-09-05 23:36                                   ` Rafael J. Wysocki
  2013-09-05 23:31                                     ` Alex Williamson
                                                       ` (2 more replies)
  0 siblings, 3 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-09-05 23:36 UTC (permalink / raw)
  To: Alex Williamson
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Thursday, September 05, 2013 05:08:03 PM Alex Williamson wrote:
> On Fri, 2013-09-06 at 00:40 +0200, Rafael J. Wysocki wrote:
> > On Thursday, September 05, 2013 04:17:25 PM Alex Williamson wrote:
> > > On Thu, 2013-09-05 at 23:39 +0200, Rafael J. Wysocki wrote:
> > > > On Thursday, September 05, 2013 09:44:26 PM Rafael J. Wysocki wrote:
> > > > > On Thursday, September 05, 2013 08:21:41 AM Alex Williamson wrote:
> > > > 
> > > > [...]
> > > > 
> > > > > > > 
> > > > > > > [   18.288122] pci 0000:00:00.0: no hotplug settings from platform
> > > > > > > [   18.288127] pcieport 0000:00:01.0: no hotplug settings from platform
> > > > > > > [   18.288142] pci 0000:01:00.0: no hotplug settings from platform
> > > > > > > [   18.288157] pci 0000:01:00.1: no hotplug settings from platform
> > > > > > > [   18.288162] pcieport 0000:00:03.0: no hotplug settings from platform
> > > > > > > [   18.288176] pci 0000:02:00.0: no hotplug settings from platform
> > > > > > > [   18.288190] pci 0000:02:00.1: no hotplug settings from platform
> > > > > > > [   18.288195] pcieport 0000:00:07.0: no hotplug settings from platform
> > > > > > > [   18.288209] pci 0000:03:00.0: no hotplug settings from platform
> > > > > > > [   18.288224] pci 0000:03:00.1: no hotplug settings from platform
> > > > > > > [   18.288228] pci 0000:00:14.0: no hotplug settings from platform
> > > > > > > [   18.288233] pci 0000:00:14.1: no hotplug settings from platform
> > > > > > > [   18.288237] pci 0000:00:14.2: no hotplug settings from platform
> > > > > > > [   18.288242] pci 0000:00:16.0: no hotplug settings from platform
> > > > > > > [   18.288247] pci 0000:00:16.1: no hotplug settings from platform
> > > > > > > [   18.288251] pci 0000:00:16.2: no hotplug settings from platform
> > > > > > > [   18.288256] pci 0000:00:16.3: no hotplug settings from platform
> > > > > > > [   18.288260] pci 0000:00:16.4: no hotplug settings from platform
> > > > > > > [   18.288265] pci 0000:00:16.5: no hotplug settings from platform
> > > > > > > [   18.288269] pci 0000:00:16.6: no hotplug settings from platform
> > > > > > > [   18.288274] pci 0000:00:16.7: no hotplug settings from platform
> > > > > > > [   18.288278] pci 0000:00:1a.0: no hotplug settings from platform
> > > > > > > [   18.288279] pci 0000:00:1a.0: using default PCI settings
> > > > > > > [   18.288292] pci 0000:00:1a.1: no hotplug settings from platform
> > > > > > > [   18.288293] pci 0000:00:1a.1: using default PCI settings
> > > > > > > [   18.288307] ehci-pci 0000:00:1a.7: no hotplug settings from platform
> > > > > > > [   18.288308] ehci-pci 0000:00:1a.7: using default PCI settings
> > > > > > > [   18.288322] pci 0000:00:1b.0: no hotplug settings from platform
> > > > > > > [   18.288327] pcieport 0000:00:1c.0: no hotplug settings from platform
> > > > > > > [   18.288332] pcieport 0000:00:1c.4: no hotplug settings from platform
> > > > > > > [   18.288344] pci 0000:05:00.0: no hotplug settings from platform
> > > > > > > [   18.288349] pci 0000:00:1d.0: no hotplug settings from platform
> > > > > > > [   18.288350] pci 0000:00:1d.0: using default PCI settings
> > > > > > > [   18.288360] pci 0000:00:1d.1: no hotplug settings from platform
> > > > > > > [   18.288361] pci 0000:00:1d.1: using default PCI settings
> > > > > > > [   18.288374] pci 0000:00:1d.2: no hotplug settings from platform
> > > > > > > [   18.288374] pci 0000:00:1d.2: using default PCI settings
> > > > > > > [   18.288387] pci 0000:00:1d.3: no hotplug settings from platform
> > > > > > > [   18.288387] pci 0000:00:1d.3: using default PCI settings
> > > > > > > 
> > > > > > > The boot is noticeably slower.  What's going to happen on systems that
> > > > > > > actually have a significant I/O topology vs my little workstation?
> > > > > 
> > > > > That depends on how many bus check/device check events they generate on boot.
> > > > > 
> > > > > My test machines don't generate them during boot at all (even the one with
> > > > > a Thunderbolt connector), so I don't see the messages in question during boot
> > > > > on any of them.  Mika doesn't see them either I suppose, or he would have told
> > > > > me about that before.
> > > > > 
> > > > > And let's just make it clear that it is not usual or even OK to generate bus
> > > > > checks or device checks during boot like this.  And since the changes in
> > > > > question have been in linux-next since right after the 3.11 merge window, I
> > > > > think that someone would have complained already had that been a common issue.
> > > > > 
> > > > > Of course, we need to deal with that somehow nevertheless. :-)
> > > > > 
> > > > > > Just to give you an idea:
> > > > > > 
> > > > > > CONFIG_HOTPLUG_PCI_ACPI=y
> > > > > > 
> > > > > > $ dmesg | wc
> > > > > >   5697  49935 384368
> > > > > > 
> > > > > > $ dmesg | tail --lines=1
> > > > > > [   53.137123] Ebtables v2.0 registered
> > > > > > 
> > > > > > -- vs --
> > > > > > 
> > > > > > # CONFIG_HOTPLUG_PCI_ACPI is not set
> > > > > > 
> > > > > > $ dmesg | wc
> > > > > >  1053  9176 71652
> > > > > > 
> > > > > > $dmesg | tail --lines=1
> > > > > > [   28.917220] Ebtables v2.0 registered
> > > > > > 
> > > > > > So it spews out 5x more output with acpiphp enabled and takes and extra
> > > > > > 24s to boot (nearly 2x).  Not good.
> > > > > 
> > > > > The "no hotplug settings from platform" message is from pci_configure_slot().
> > > > > I think the messages you're seeing are from the call to it in
> > > > > acpiphp_set_hpp_values() which is called by enable_slot().
> > > > > 
> > > > > There, I think, we can simply check the return value of pci_scan_slot() and
> > > > > if that is 0 (no new devices), we can just skip everything under the call to
> > > > > __pci_bus_assign_resources().
> > > > > 
> > > > > However, we can't skip the scanning of bridges, if any, because there may be
> > > > > new devices below them and I guess that's what takes so much time on your
> > > > > machine.
> > > > 
> > > > OK, one piece is missing.  We may need to evaluate _OSC after handling each
> > > > event to let the platform know the status.
> > > > 
> > > > Can you please check if the appended patch makes any difference (with the
> > > > previous fix applied, of course)?
> > > > 
> > > > If fact, it is two patches combined.  One of them optimizes enable_slot()
> > > > slightly and the other adds the missing _OSC evaluation.
> > > 
> > > Better, still double the output:
> > > 
> > > $ dmesg | wc
> > >    2169   19047  152710
> > 
> > I see.
> > 
> > What about the timing?
> 
> ~40s below vs ~29s for acpiphp config'd out above.

Well, that's better than before.

I'll prepare "official" patches with the last changes then too.

> > > $ dmesg | tail --lines=1
> > > [   39.980918] Ebtables v2.0 registered
> > > 
> > > Here's another interesting stat:
> > > 
> > > $ dmesg | colrm 1 15 | sort | uniq -c | sort -nr | head --lines=25
> > >      73 pci 0000:00:1f.0: BAR 13: [io  0x1000-0x107f] has bogus alignment
> > >      73 pci 0000:00:1e.0: PCI bridge to [bus 06]
> > >      64 pci 0000:00:1e.0:   bridge window [mem 0x81100000-0x812fffff 64bit pref]
> > >      64 pci 0000:00:1e.0:   bridge window [mem 0x80f00000-0x810fffff]
> > >      64 pci 0000:00:1e.0:   bridge window [io  0x7000-0x7fff]
> > >      38 pci 0000:00:1c.4: PCI bridge to [bus 05]
> > >      38 pci 0000:00:1c.4:   bridge window [mem 0xf4f00000-0xf4ffffff]
> > >      38 pci 0000:00:1c.0: PCI bridge to [bus 04]
> > >      38 pci 0000:00:07.0: PCI bridge to [bus 03]
> > >      38 pci 0000:00:07.0:   bridge window [mem 0xf2000000-0xf40fffff]
> > >      38 pci 0000:00:07.0:   bridge window [mem 0xe0000000-0xf1ffffff 64bit pref]
> > >      38 pci 0000:00:07.0:   bridge window [io  0x4000-0x4fff]
> > >      38 pci 0000:00:03.0: PCI bridge to [bus 02]
> > >      38 pci 0000:00:03.0:   bridge window [mem 0xf4e00000-0xf4efffff]
> > >      38 pci 0000:00:03.0:   bridge window [mem 0xd0000000-0xdfffffff 64bit pref]
> > >      38 pci 0000:00:03.0:   bridge window [io  0x3000-0x3fff]
> > >      38 pci 0000:00:01.0: PCI bridge to [bus 01]
> > >      38 pci 0000:00:01.0:   bridge window [mem 0xf4100000-0xf4bfffff]
> > >      38 pci 0000:00:01.0:   bridge window [io  0x2000-0x2fff]
> > >      37 pci 0000:00:1c.4:   bridge window [mem 0x80c00000-0x80dfffff 64bit pref]
> > >      37 pci 0000:00:1c.4:   bridge window [io  0x6000-0x6fff]
> > >      37 pci 0000:00:1c.0:   bridge window [mem 0x80a00000-0x80bfffff 64bit pref]
> > >      37 pci 0000:00:1c.0:   bridge window [mem 0x80800000-0x809fffff]
> > >      37 pci 0000:00:1c.0:   bridge window [io  0x5000-0x5fff]
> > >      36 pci 0000:00:01.0:   bridge window [mem 0x80000000-0x807fffff 64bit pref]
> > > 
> > > This is nearly the entire difference, just 25 lines repeated over and
> > > over.

Can you check how many times the lines above are repeated?

> > 
> > Well, this is the bridge sizing I talked about previously.  We still get
> > apparently spurious bus check/device check events and they trigger bridge
> > scans.
> > 
> > I'm not sure what to do about that and I wonder whether or not this is
> > reproducible on any other machines you can test.
> 
> I can try it on a couple other systems, but probably not until tomorrow.

Tomorrow (or even later) works just fine for me. :-)

> > Can you please change dbg() to pr_info() under ACPI_NOTIFY_BUS_CHECK and
> > ACPI_NOTIFY_DEVICE_CHECK in hotplug_event() (acpiphp_glue.c), grep the boot
> > dmesg log for "check notify" and send the result?  I'm wondering what's
> > going on there.
> 
> $ dmesg | grep "check notify"
> [    1.633228] hotplug_event: Device check notify on \_SB_.PCI0.PEX2
> [    2.472004] hotplug_event: Device check notify on \_SB_.PCI0.PEX3
> [    2.477288] hotplug_event: Device check notify on \_SB_.PCI0.PEX4
> [    2.482571] hotplug_event: Device check notify on \_SB_.PCI0.PEX5
> [    2.482579] hotplug_event: Device check notify on \_SB_.PCI0.PEX6
> [    8.204953] hotplug_event: Device check notify on \_SB_.PCI0.PEX2
> [    8.209632] hotplug_event: Device check notify on \_SB_.PCI0.PEX3
> [    8.214272] hotplug_event: Device check notify on \_SB_.PCI0.PEX4
> [    8.218894] hotplug_event: Device check notify on \_SB_.PCI0.PEX5
> [    8.218901] hotplug_event: Device check notify on \_SB_.PCI0.PEX6

So I guess the PEXn things are PCIe ports and we get two notifications
for each of them, so everything below them gets rescanned.

I've just talked to Bjorn about that and we don't seem to have a good idea
how to handle this.  The notifies shouldn't be there, but we kind of have
to handle them.

I guess we could suppress the output from repeated bridge scans.  Alternatively,
we could just blacklist this particular system somehow if the problem is
specific to it.

Thanks,
Rafael


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

* Re: Excess dmesg output from ACPIPHP on boot (was: Re: [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots)
  2013-09-05 23:31                                     ` Alex Williamson
@ 2013-09-05 23:48                                       ` Rafael J. Wysocki
  0 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-09-05 23:48 UTC (permalink / raw)
  To: Alex Williamson
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Thursday, September 05, 2013 05:31:58 PM Alex Williamson wrote:
> On Fri, 2013-09-06 at 01:36 +0200, Rafael J. Wysocki wrote:
> > On Thursday, September 05, 2013 05:08:03 PM Alex Williamson wrote:
> > > On Fri, 2013-09-06 at 00:40 +0200, Rafael J. Wysocki wrote:
> > > > On Thursday, September 05, 2013 04:17:25 PM Alex Williamson wrote:
> > > > > On Thu, 2013-09-05 at 23:39 +0200, Rafael J. Wysocki wrote:
> > > > > > On Thursday, September 05, 2013 09:44:26 PM Rafael J. Wysocki wrote:
> > > > > > > On Thursday, September 05, 2013 08:21:41 AM Alex Williamson wrote:
> > > > > > 
> > > > > > [...]
> > > > > > 
> > > > > > > > > 
> > > > > > > > > [   18.288122] pci 0000:00:00.0: no hotplug settings from platform
> > > > > > > > > [   18.288127] pcieport 0000:00:01.0: no hotplug settings from platform
> > > > > > > > > [   18.288142] pci 0000:01:00.0: no hotplug settings from platform
> > > > > > > > > [   18.288157] pci 0000:01:00.1: no hotplug settings from platform
> > > > > > > > > [   18.288162] pcieport 0000:00:03.0: no hotplug settings from platform
> > > > > > > > > [   18.288176] pci 0000:02:00.0: no hotplug settings from platform
> > > > > > > > > [   18.288190] pci 0000:02:00.1: no hotplug settings from platform
> > > > > > > > > [   18.288195] pcieport 0000:00:07.0: no hotplug settings from platform
> > > > > > > > > [   18.288209] pci 0000:03:00.0: no hotplug settings from platform
> > > > > > > > > [   18.288224] pci 0000:03:00.1: no hotplug settings from platform
> > > > > > > > > [   18.288228] pci 0000:00:14.0: no hotplug settings from platform
> > > > > > > > > [   18.288233] pci 0000:00:14.1: no hotplug settings from platform
> > > > > > > > > [   18.288237] pci 0000:00:14.2: no hotplug settings from platform
> > > > > > > > > [   18.288242] pci 0000:00:16.0: no hotplug settings from platform
> > > > > > > > > [   18.288247] pci 0000:00:16.1: no hotplug settings from platform
> > > > > > > > > [   18.288251] pci 0000:00:16.2: no hotplug settings from platform
> > > > > > > > > [   18.288256] pci 0000:00:16.3: no hotplug settings from platform
> > > > > > > > > [   18.288260] pci 0000:00:16.4: no hotplug settings from platform
> > > > > > > > > [   18.288265] pci 0000:00:16.5: no hotplug settings from platform
> > > > > > > > > [   18.288269] pci 0000:00:16.6: no hotplug settings from platform
> > > > > > > > > [   18.288274] pci 0000:00:16.7: no hotplug settings from platform
> > > > > > > > > [   18.288278] pci 0000:00:1a.0: no hotplug settings from platform
> > > > > > > > > [   18.288279] pci 0000:00:1a.0: using default PCI settings
> > > > > > > > > [   18.288292] pci 0000:00:1a.1: no hotplug settings from platform
> > > > > > > > > [   18.288293] pci 0000:00:1a.1: using default PCI settings
> > > > > > > > > [   18.288307] ehci-pci 0000:00:1a.7: no hotplug settings from platform
> > > > > > > > > [   18.288308] ehci-pci 0000:00:1a.7: using default PCI settings
> > > > > > > > > [   18.288322] pci 0000:00:1b.0: no hotplug settings from platform
> > > > > > > > > [   18.288327] pcieport 0000:00:1c.0: no hotplug settings from platform
> > > > > > > > > [   18.288332] pcieport 0000:00:1c.4: no hotplug settings from platform
> > > > > > > > > [   18.288344] pci 0000:05:00.0: no hotplug settings from platform
> > > > > > > > > [   18.288349] pci 0000:00:1d.0: no hotplug settings from platform
> > > > > > > > > [   18.288350] pci 0000:00:1d.0: using default PCI settings
> > > > > > > > > [   18.288360] pci 0000:00:1d.1: no hotplug settings from platform
> > > > > > > > > [   18.288361] pci 0000:00:1d.1: using default PCI settings
> > > > > > > > > [   18.288374] pci 0000:00:1d.2: no hotplug settings from platform
> > > > > > > > > [   18.288374] pci 0000:00:1d.2: using default PCI settings
> > > > > > > > > [   18.288387] pci 0000:00:1d.3: no hotplug settings from platform
> > > > > > > > > [   18.288387] pci 0000:00:1d.3: using default PCI settings
> > > > > > > > > 
> > > > > > > > > The boot is noticeably slower.  What's going to happen on systems that
> > > > > > > > > actually have a significant I/O topology vs my little workstation?
> > > > > > > 
> > > > > > > That depends on how many bus check/device check events they generate on boot.
> > > > > > > 
> > > > > > > My test machines don't generate them during boot at all (even the one with
> > > > > > > a Thunderbolt connector), so I don't see the messages in question during boot
> > > > > > > on any of them.  Mika doesn't see them either I suppose, or he would have told
> > > > > > > me about that before.
> > > > > > > 
> > > > > > > And let's just make it clear that it is not usual or even OK to generate bus
> > > > > > > checks or device checks during boot like this.  And since the changes in
> > > > > > > question have been in linux-next since right after the 3.11 merge window, I
> > > > > > > think that someone would have complained already had that been a common issue.
> > > > > > > 
> > > > > > > Of course, we need to deal with that somehow nevertheless. :-)
> > > > > > > 
> > > > > > > > Just to give you an idea:
> > > > > > > > 
> > > > > > > > CONFIG_HOTPLUG_PCI_ACPI=y
> > > > > > > > 
> > > > > > > > $ dmesg | wc
> > > > > > > >   5697  49935 384368
> > > > > > > > 
> > > > > > > > $ dmesg | tail --lines=1
> > > > > > > > [   53.137123] Ebtables v2.0 registered
> > > > > > > > 
> > > > > > > > -- vs --
> > > > > > > > 
> > > > > > > > # CONFIG_HOTPLUG_PCI_ACPI is not set
> > > > > > > > 
> > > > > > > > $ dmesg | wc
> > > > > > > >  1053  9176 71652
> > > > > > > > 
> > > > > > > > $dmesg | tail --lines=1
> > > > > > > > [   28.917220] Ebtables v2.0 registered
> > > > > > > > 
> > > > > > > > So it spews out 5x more output with acpiphp enabled and takes and extra
> > > > > > > > 24s to boot (nearly 2x).  Not good.
> > > > > > > 
> > > > > > > The "no hotplug settings from platform" message is from pci_configure_slot().
> > > > > > > I think the messages you're seeing are from the call to it in
> > > > > > > acpiphp_set_hpp_values() which is called by enable_slot().
> > > > > > > 
> > > > > > > There, I think, we can simply check the return value of pci_scan_slot() and
> > > > > > > if that is 0 (no new devices), we can just skip everything under the call to
> > > > > > > __pci_bus_assign_resources().
> > > > > > > 
> > > > > > > However, we can't skip the scanning of bridges, if any, because there may be
> > > > > > > new devices below them and I guess that's what takes so much time on your
> > > > > > > machine.
> > > > > > 
> > > > > > OK, one piece is missing.  We may need to evaluate _OSC after handling each
> > > > > > event to let the platform know the status.
> > > > > > 
> > > > > > Can you please check if the appended patch makes any difference (with the
> > > > > > previous fix applied, of course)?
> > > > > > 
> > > > > > If fact, it is two patches combined.  One of them optimizes enable_slot()
> > > > > > slightly and the other adds the missing _OSC evaluation.
> > > > > 
> > > > > Better, still double the output:
> > > > > 
> > > > > $ dmesg | wc
> > > > >    2169   19047  152710
> > > > 
> > > > I see.
> > > > 
> > > > What about the timing?
> > > 
> > > ~40s below vs ~29s for acpiphp config'd out above.
> > 
> > Well, that's better than before.
> > 
> > I'll prepare "official" patches with the last changes then too.
> > 
> > > > > $ dmesg | tail --lines=1
> > > > > [   39.980918] Ebtables v2.0 registered
> > > > > 
> > > > > Here's another interesting stat:
> > > > > 
> > > > > $ dmesg | colrm 1 15 | sort | uniq -c | sort -nr | head --lines=25
> > > > >      73 pci 0000:00:1f.0: BAR 13: [io  0x1000-0x107f] has bogus alignment
> > > > >      73 pci 0000:00:1e.0: PCI bridge to [bus 06]
> > > > >      64 pci 0000:00:1e.0:   bridge window [mem 0x81100000-0x812fffff 64bit pref]
> > > > >      64 pci 0000:00:1e.0:   bridge window [mem 0x80f00000-0x810fffff]
> > > > >      64 pci 0000:00:1e.0:   bridge window [io  0x7000-0x7fff]
> > > > >      38 pci 0000:00:1c.4: PCI bridge to [bus 05]
> > > > >      38 pci 0000:00:1c.4:   bridge window [mem 0xf4f00000-0xf4ffffff]
> > > > >      38 pci 0000:00:1c.0: PCI bridge to [bus 04]
> > > > >      38 pci 0000:00:07.0: PCI bridge to [bus 03]
> > > > >      38 pci 0000:00:07.0:   bridge window [mem 0xf2000000-0xf40fffff]
> > > > >      38 pci 0000:00:07.0:   bridge window [mem 0xe0000000-0xf1ffffff 64bit pref]
> > > > >      38 pci 0000:00:07.0:   bridge window [io  0x4000-0x4fff]
> > > > >      38 pci 0000:00:03.0: PCI bridge to [bus 02]
> > > > >      38 pci 0000:00:03.0:   bridge window [mem 0xf4e00000-0xf4efffff]
> > > > >      38 pci 0000:00:03.0:   bridge window [mem 0xd0000000-0xdfffffff 64bit pref]
> > > > >      38 pci 0000:00:03.0:   bridge window [io  0x3000-0x3fff]
> > > > >      38 pci 0000:00:01.0: PCI bridge to [bus 01]
> > > > >      38 pci 0000:00:01.0:   bridge window [mem 0xf4100000-0xf4bfffff]
> > > > >      38 pci 0000:00:01.0:   bridge window [io  0x2000-0x2fff]
> > > > >      37 pci 0000:00:1c.4:   bridge window [mem 0x80c00000-0x80dfffff 64bit pref]
> > > > >      37 pci 0000:00:1c.4:   bridge window [io  0x6000-0x6fff]
> > > > >      37 pci 0000:00:1c.0:   bridge window [mem 0x80a00000-0x80bfffff 64bit pref]
> > > > >      37 pci 0000:00:1c.0:   bridge window [mem 0x80800000-0x809fffff]
> > > > >      37 pci 0000:00:1c.0:   bridge window [io  0x5000-0x5fff]
> > > > >      36 pci 0000:00:01.0:   bridge window [mem 0x80000000-0x807fffff 64bit pref]
> > > > > 
> > > > > This is nearly the entire difference, just 25 lines repeated over and
> > > > > over.
> > 
> > Can you check how many times the lines above are repeated?
> 
> The line count is pre-pended to each line.  73 times for the first two
> line, etc.

Too late, too tired.  Sorry.

Hmm, there's kind of too many of them given the number of notifications.
Interesting.

OK, I'll look deeper into things tomorrow, maybe I'll find some clues.

> > > > 
> > > > Well, this is the bridge sizing I talked about previously.  We still get
> > > > apparently spurious bus check/device check events and they trigger bridge
> > > > scans.
> > > > 
> > > > I'm not sure what to do about that and I wonder whether or not this is
> > > > reproducible on any other machines you can test.
> > > 
> > > I can try it on a couple other systems, but probably not until tomorrow.
> > 
> > Tomorrow (or even later) works just fine for me. :-)
> > 
> > > > Can you please change dbg() to pr_info() under ACPI_NOTIFY_BUS_CHECK and
> > > > ACPI_NOTIFY_DEVICE_CHECK in hotplug_event() (acpiphp_glue.c), grep the boot
> > > > dmesg log for "check notify" and send the result?  I'm wondering what's
> > > > going on there.
> > > 
> > > $ dmesg | grep "check notify"
> > > [    1.633228] hotplug_event: Device check notify on \_SB_.PCI0.PEX2
> > > [    2.472004] hotplug_event: Device check notify on \_SB_.PCI0.PEX3
> > > [    2.477288] hotplug_event: Device check notify on \_SB_.PCI0.PEX4
> > > [    2.482571] hotplug_event: Device check notify on \_SB_.PCI0.PEX5
> > > [    2.482579] hotplug_event: Device check notify on \_SB_.PCI0.PEX6
> > > [    8.204953] hotplug_event: Device check notify on \_SB_.PCI0.PEX2
> > > [    8.209632] hotplug_event: Device check notify on \_SB_.PCI0.PEX3
> > > [    8.214272] hotplug_event: Device check notify on \_SB_.PCI0.PEX4
> > > [    8.218894] hotplug_event: Device check notify on \_SB_.PCI0.PEX5
> > > [    8.218901] hotplug_event: Device check notify on \_SB_.PCI0.PEX6
> > 
> > So I guess the PEXn things are PCIe ports and we get two notifications
> > for each of them, so everything below them gets rescanned.
> > 
> > I've just talked to Bjorn about that and we don't seem to have a good idea
> > how to handle this.  The notifies shouldn't be there, but we kind of have
> > to handle them.
> > 
> > I guess we could suppress the output from repeated bridge scans.  Alternatively,
> > we could just blacklist this particular system somehow if the problem is
> > specific to it.
> 
> Can't we determine that nothing has changed and avoid re-printing?

I suppose so, but that's not going to be a simple modification, because the
output is from somewhat deep in the stack.

> I have a hard time believing this system is all that unique.

Yes, it is quite likely that there are more systems like that.

Thanks,
Rafael


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

* Re: Excess dmesg output from ACPIPHP on boot (was: Re: [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots)
  2013-09-05 23:36                                   ` Rafael J. Wysocki
  2013-09-05 23:31                                     ` Alex Williamson
@ 2013-09-06 12:19                                     ` Bjorn Helgaas
  2013-09-06 12:40                                       ` Rafael J. Wysocki
  2013-09-06 15:34                                       ` Alex Williamson
  2013-09-06 13:42                                     ` [PATCH 0/2] Re: Excess dmesg output from ACPIPHP on boot Rafael J. Wysocki
  2 siblings, 2 replies; 135+ messages in thread
From: Bjorn Helgaas @ 2013-09-06 12:19 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Alex Williamson, ACPI Devel Maling List, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Thu, Sep 5, 2013 at 5:36 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> On Thursday, September 05, 2013 05:08:03 PM Alex Williamson wrote:
>> On Fri, 2013-09-06 at 00:40 +0200, Rafael J. Wysocki wrote:
>> > On Thursday, September 05, 2013 04:17:25 PM Alex Williamson wrote:
>> > > On Thu, 2013-09-05 at 23:39 +0200, Rafael J. Wysocki wrote:
>> > > > On Thursday, September 05, 2013 09:44:26 PM Rafael J. Wysocki wrote:
>> > > > > On Thursday, September 05, 2013 08:21:41 AM Alex Williamson wrote:
>> > > >
>> > > > [...]
>> > > >
>> > > > > > >
>> > > > > > > [   18.288122] pci 0000:00:00.0: no hotplug settings from platform
>> > > > > > > [   18.288127] pcieport 0000:00:01.0: no hotplug settings from platform
>> > > > > > > [   18.288142] pci 0000:01:00.0: no hotplug settings from platform
>> > > > > > > [   18.288157] pci 0000:01:00.1: no hotplug settings from platform
>> > > > > > > [   18.288162] pcieport 0000:00:03.0: no hotplug settings from platform
>> > > > > > > [   18.288176] pci 0000:02:00.0: no hotplug settings from platform
>> > > > > > > [   18.288190] pci 0000:02:00.1: no hotplug settings from platform
>> > > > > > > [   18.288195] pcieport 0000:00:07.0: no hotplug settings from platform
>> > > > > > > [   18.288209] pci 0000:03:00.0: no hotplug settings from platform
>> > > > > > > [   18.288224] pci 0000:03:00.1: no hotplug settings from platform
>> > > > > > > [   18.288228] pci 0000:00:14.0: no hotplug settings from platform
>> > > > > > > [   18.288233] pci 0000:00:14.1: no hotplug settings from platform
>> > > > > > > [   18.288237] pci 0000:00:14.2: no hotplug settings from platform
>> > > > > > > [   18.288242] pci 0000:00:16.0: no hotplug settings from platform
>> > > > > > > [   18.288247] pci 0000:00:16.1: no hotplug settings from platform
>> > > > > > > [   18.288251] pci 0000:00:16.2: no hotplug settings from platform
>> > > > > > > [   18.288256] pci 0000:00:16.3: no hotplug settings from platform
>> > > > > > > [   18.288260] pci 0000:00:16.4: no hotplug settings from platform
>> > > > > > > [   18.288265] pci 0000:00:16.5: no hotplug settings from platform
>> > > > > > > [   18.288269] pci 0000:00:16.6: no hotplug settings from platform
>> > > > > > > [   18.288274] pci 0000:00:16.7: no hotplug settings from platform
>> > > > > > > [   18.288278] pci 0000:00:1a.0: no hotplug settings from platform
>> > > > > > > [   18.288279] pci 0000:00:1a.0: using default PCI settings
>> > > > > > > [   18.288292] pci 0000:00:1a.1: no hotplug settings from platform
>> > > > > > > [   18.288293] pci 0000:00:1a.1: using default PCI settings
>> > > > > > > [   18.288307] ehci-pci 0000:00:1a.7: no hotplug settings from platform
>> > > > > > > [   18.288308] ehci-pci 0000:00:1a.7: using default PCI settings
>> > > > > > > [   18.288322] pci 0000:00:1b.0: no hotplug settings from platform
>> > > > > > > [   18.288327] pcieport 0000:00:1c.0: no hotplug settings from platform
>> > > > > > > [   18.288332] pcieport 0000:00:1c.4: no hotplug settings from platform
>> > > > > > > [   18.288344] pci 0000:05:00.0: no hotplug settings from platform
>> > > > > > > [   18.288349] pci 0000:00:1d.0: no hotplug settings from platform
>> > > > > > > [   18.288350] pci 0000:00:1d.0: using default PCI settings
>> > > > > > > [   18.288360] pci 0000:00:1d.1: no hotplug settings from platform
>> > > > > > > [   18.288361] pci 0000:00:1d.1: using default PCI settings
>> > > > > > > [   18.288374] pci 0000:00:1d.2: no hotplug settings from platform
>> > > > > > > [   18.288374] pci 0000:00:1d.2: using default PCI settings
>> > > > > > > [   18.288387] pci 0000:00:1d.3: no hotplug settings from platform
>> > > > > > > [   18.288387] pci 0000:00:1d.3: using default PCI settings
>> > > > > > >
>> > > > > > > The boot is noticeably slower.  What's going to happen on systems that
>> > > > > > > actually have a significant I/O topology vs my little workstation?
>> > > > >
>> > > > > That depends on how many bus check/device check events they generate on boot.
>> > > > >
>> > > > > My test machines don't generate them during boot at all (even the one with
>> > > > > a Thunderbolt connector), so I don't see the messages in question during boot
>> > > > > on any of them.  Mika doesn't see them either I suppose, or he would have told
>> > > > > me about that before.
>> > > > >
>> > > > > And let's just make it clear that it is not usual or even OK to generate bus
>> > > > > checks or device checks during boot like this.  And since the changes in
>> > > > > question have been in linux-next since right after the 3.11 merge window, I
>> > > > > think that someone would have complained already had that been a common issue.
>> > > > >
>> > > > > Of course, we need to deal with that somehow nevertheless. :-)
>> > > > >
>> > > > > > Just to give you an idea:
>> > > > > >
>> > > > > > CONFIG_HOTPLUG_PCI_ACPI=y
>> > > > > >
>> > > > > > $ dmesg | wc
>> > > > > >   5697  49935 384368
>> > > > > >
>> > > > > > $ dmesg | tail --lines=1
>> > > > > > [   53.137123] Ebtables v2.0 registered
>> > > > > >
>> > > > > > -- vs --
>> > > > > >
>> > > > > > # CONFIG_HOTPLUG_PCI_ACPI is not set
>> > > > > >
>> > > > > > $ dmesg | wc
>> > > > > >  1053  9176 71652
>> > > > > >
>> > > > > > $dmesg | tail --lines=1
>> > > > > > [   28.917220] Ebtables v2.0 registered
>> > > > > >
>> > > > > > So it spews out 5x more output with acpiphp enabled and takes and extra
>> > > > > > 24s to boot (nearly 2x).  Not good.
>> > > > >
>> > > > > The "no hotplug settings from platform" message is from pci_configure_slot().
>> > > > > I think the messages you're seeing are from the call to it in
>> > > > > acpiphp_set_hpp_values() which is called by enable_slot().
>> > > > >
>> > > > > There, I think, we can simply check the return value of pci_scan_slot() and
>> > > > > if that is 0 (no new devices), we can just skip everything under the call to
>> > > > > __pci_bus_assign_resources().
>> > > > >
>> > > > > However, we can't skip the scanning of bridges, if any, because there may be
>> > > > > new devices below them and I guess that's what takes so much time on your
>> > > > > machine.
>> > > >
>> > > > OK, one piece is missing.  We may need to evaluate _OSC after handling each
>> > > > event to let the platform know the status.
>> > > >
>> > > > Can you please check if the appended patch makes any difference (with the
>> > > > previous fix applied, of course)?
>> > > >
>> > > > If fact, it is two patches combined.  One of them optimizes enable_slot()
>> > > > slightly and the other adds the missing _OSC evaluation.
>> > >
>> > > Better, still double the output:
>> > >
>> > > $ dmesg | wc
>> > >    2169   19047  152710
>> >
>> > I see.
>> >
>> > What about the timing?
>>
>> ~40s below vs ~29s for acpiphp config'd out above.
>
> Well, that's better than before.
>
> I'll prepare "official" patches with the last changes then too.
>
>> > > $ dmesg | tail --lines=1
>> > > [   39.980918] Ebtables v2.0 registered
>> > >
>> > > Here's another interesting stat:
>> > >
>> > > $ dmesg | colrm 1 15 | sort | uniq -c | sort -nr | head --lines=25
>> > >      73 pci 0000:00:1f.0: BAR 13: [io  0x1000-0x107f] has bogus alignment
>> > >      73 pci 0000:00:1e.0: PCI bridge to [bus 06]
>> > >      64 pci 0000:00:1e.0:   bridge window [mem 0x81100000-0x812fffff 64bit pref]
>> > >      64 pci 0000:00:1e.0:   bridge window [mem 0x80f00000-0x810fffff]
>> > >      64 pci 0000:00:1e.0:   bridge window [io  0x7000-0x7fff]
>> > >      38 pci 0000:00:1c.4: PCI bridge to [bus 05]
>> > >      38 pci 0000:00:1c.4:   bridge window [mem 0xf4f00000-0xf4ffffff]
>> > >      38 pci 0000:00:1c.0: PCI bridge to [bus 04]
>> > >      38 pci 0000:00:07.0: PCI bridge to [bus 03]
>> > >      38 pci 0000:00:07.0:   bridge window [mem 0xf2000000-0xf40fffff]
>> > >      38 pci 0000:00:07.0:   bridge window [mem 0xe0000000-0xf1ffffff 64bit pref]
>> > >      38 pci 0000:00:07.0:   bridge window [io  0x4000-0x4fff]
>> > >      38 pci 0000:00:03.0: PCI bridge to [bus 02]
>> > >      38 pci 0000:00:03.0:   bridge window [mem 0xf4e00000-0xf4efffff]
>> > >      38 pci 0000:00:03.0:   bridge window [mem 0xd0000000-0xdfffffff 64bit pref]
>> > >      38 pci 0000:00:03.0:   bridge window [io  0x3000-0x3fff]
>> > >      38 pci 0000:00:01.0: PCI bridge to [bus 01]
>> > >      38 pci 0000:00:01.0:   bridge window [mem 0xf4100000-0xf4bfffff]
>> > >      38 pci 0000:00:01.0:   bridge window [io  0x2000-0x2fff]
>> > >      37 pci 0000:00:1c.4:   bridge window [mem 0x80c00000-0x80dfffff 64bit pref]
>> > >      37 pci 0000:00:1c.4:   bridge window [io  0x6000-0x6fff]
>> > >      37 pci 0000:00:1c.0:   bridge window [mem 0x80a00000-0x80bfffff 64bit pref]
>> > >      37 pci 0000:00:1c.0:   bridge window [mem 0x80800000-0x809fffff]
>> > >      37 pci 0000:00:1c.0:   bridge window [io  0x5000-0x5fff]
>> > >      36 pci 0000:00:01.0:   bridge window [mem 0x80000000-0x807fffff 64bit pref]
>> > >
>> > > This is nearly the entire difference, just 25 lines repeated over and
>> > > over.
>
> Can you check how many times the lines above are repeated?
>
>> >
>> > Well, this is the bridge sizing I talked about previously.  We still get
>> > apparently spurious bus check/device check events and they trigger bridge
>> > scans.
>> >
>> > I'm not sure what to do about that and I wonder whether or not this is
>> > reproducible on any other machines you can test.
>>
>> I can try it on a couple other systems, but probably not until tomorrow.
>
> Tomorrow (or even later) works just fine for me. :-)
>
>> > Can you please change dbg() to pr_info() under ACPI_NOTIFY_BUS_CHECK and
>> > ACPI_NOTIFY_DEVICE_CHECK in hotplug_event() (acpiphp_glue.c), grep the boot
>> > dmesg log for "check notify" and send the result?  I'm wondering what's
>> > going on there.
>>
>> $ dmesg | grep "check notify"
>> [    1.633228] hotplug_event: Device check notify on \_SB_.PCI0.PEX2
>> [    2.472004] hotplug_event: Device check notify on \_SB_.PCI0.PEX3
>> [    2.477288] hotplug_event: Device check notify on \_SB_.PCI0.PEX4
>> [    2.482571] hotplug_event: Device check notify on \_SB_.PCI0.PEX5
>> [    2.482579] hotplug_event: Device check notify on \_SB_.PCI0.PEX6
>> [    8.204953] hotplug_event: Device check notify on \_SB_.PCI0.PEX2
>> [    8.209632] hotplug_event: Device check notify on \_SB_.PCI0.PEX3
>> [    8.214272] hotplug_event: Device check notify on \_SB_.PCI0.PEX4
>> [    8.218894] hotplug_event: Device check notify on \_SB_.PCI0.PEX5
>> [    8.218901] hotplug_event: Device check notify on \_SB_.PCI0.PEX6
>
> So I guess the PEXn things are PCIe ports and we get two notifications
> for each of them, so everything below them gets rescanned.
>
> I've just talked to Bjorn about that and we don't seem to have a good idea
> how to handle this.  The notifies shouldn't be there, but we kind of have
> to handle them.

What I said was "We aren't going to be able to get rid of the
notifications, but we can probably figure out how to clean up some of
the output."  I don't think there's anything *wrong* with the
notifications themselves, and as far as I know, there's nothing in the
spec that limits how many notifications the platform can send.

> I guess we could suppress the output from repeated bridge scans.  Alternatively,
> we could just blacklist this particular system somehow if the problem is
> specific to it.

I'm opposed to blacklisting in principle because this doesn't sound
like a platform defect.  And I think we pretty much have to
re-enumerate for each Device Check, because that's what the spec tells
us to do.

My goal is for PCI to print stuff only for significant events, when we
discover something new, or when we change something (BAR, bridge
window, etc.)  A hot-plug event, e.g., a Device Check, is arguably
significant all by itself, but that's in ACPI, and it sounds like we
only have a dbg() there now.  The repeated PCI bridge info seems like
it's useless.  I've looked at cleaning up some of that in the past,
but it wasn't trivial and it wasn't urgent enough at the time.  But it
sure sounds urgent now.

Alex, would you mind collecting the full dmesg or console log (with
"debug ignore_loglevel") and "lspci -vv" output and attaching them to
a bugzilla?  Keep the hotplug_event() pr_info() change so we have more
clues about what triggers things.  This seems like an interesting
situation, and there might be other things we can learn from it.  It
looks like the "hotplug settings" output is probably more than is
necessary also.

Bjorn

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

* Re: Excess dmesg output from ACPIPHP on boot (was: Re: [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots)
  2013-09-06 12:19                                     ` Bjorn Helgaas
@ 2013-09-06 12:40                                       ` Rafael J. Wysocki
  2013-09-06 15:34                                       ` Alex Williamson
  1 sibling, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-09-06 12:40 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: Alex Williamson, ACPI Devel Maling List, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Friday, September 06, 2013 06:19:11 AM Bjorn Helgaas wrote:
> On Thu, Sep 5, 2013 at 5:36 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> > On Thursday, September 05, 2013 05:08:03 PM Alex Williamson wrote:
> >> On Fri, 2013-09-06 at 00:40 +0200, Rafael J. Wysocki wrote:
> >> > On Thursday, September 05, 2013 04:17:25 PM Alex Williamson wrote:
> >> > > On Thu, 2013-09-05 at 23:39 +0200, Rafael J. Wysocki wrote:
> >> > > > On Thursday, September 05, 2013 09:44:26 PM Rafael J. Wysocki wrote:
> >> > > > > On Thursday, September 05, 2013 08:21:41 AM Alex Williamson wrote:
> >> > > >
> >> > > > [...]
> >> > > >
> >> > > > > > >
> >> > > > > > > [   18.288122] pci 0000:00:00.0: no hotplug settings from platform
> >> > > > > > > [   18.288127] pcieport 0000:00:01.0: no hotplug settings from platform
> >> > > > > > > [   18.288142] pci 0000:01:00.0: no hotplug settings from platform
> >> > > > > > > [   18.288157] pci 0000:01:00.1: no hotplug settings from platform
> >> > > > > > > [   18.288162] pcieport 0000:00:03.0: no hotplug settings from platform
> >> > > > > > > [   18.288176] pci 0000:02:00.0: no hotplug settings from platform
> >> > > > > > > [   18.288190] pci 0000:02:00.1: no hotplug settings from platform
> >> > > > > > > [   18.288195] pcieport 0000:00:07.0: no hotplug settings from platform
> >> > > > > > > [   18.288209] pci 0000:03:00.0: no hotplug settings from platform
> >> > > > > > > [   18.288224] pci 0000:03:00.1: no hotplug settings from platform
> >> > > > > > > [   18.288228] pci 0000:00:14.0: no hotplug settings from platform
> >> > > > > > > [   18.288233] pci 0000:00:14.1: no hotplug settings from platform
> >> > > > > > > [   18.288237] pci 0000:00:14.2: no hotplug settings from platform
> >> > > > > > > [   18.288242] pci 0000:00:16.0: no hotplug settings from platform
> >> > > > > > > [   18.288247] pci 0000:00:16.1: no hotplug settings from platform
> >> > > > > > > [   18.288251] pci 0000:00:16.2: no hotplug settings from platform
> >> > > > > > > [   18.288256] pci 0000:00:16.3: no hotplug settings from platform
> >> > > > > > > [   18.288260] pci 0000:00:16.4: no hotplug settings from platform
> >> > > > > > > [   18.288265] pci 0000:00:16.5: no hotplug settings from platform
> >> > > > > > > [   18.288269] pci 0000:00:16.6: no hotplug settings from platform
> >> > > > > > > [   18.288274] pci 0000:00:16.7: no hotplug settings from platform
> >> > > > > > > [   18.288278] pci 0000:00:1a.0: no hotplug settings from platform
> >> > > > > > > [   18.288279] pci 0000:00:1a.0: using default PCI settings
> >> > > > > > > [   18.288292] pci 0000:00:1a.1: no hotplug settings from platform
> >> > > > > > > [   18.288293] pci 0000:00:1a.1: using default PCI settings
> >> > > > > > > [   18.288307] ehci-pci 0000:00:1a.7: no hotplug settings from platform
> >> > > > > > > [   18.288308] ehci-pci 0000:00:1a.7: using default PCI settings
> >> > > > > > > [   18.288322] pci 0000:00:1b.0: no hotplug settings from platform
> >> > > > > > > [   18.288327] pcieport 0000:00:1c.0: no hotplug settings from platform
> >> > > > > > > [   18.288332] pcieport 0000:00:1c.4: no hotplug settings from platform
> >> > > > > > > [   18.288344] pci 0000:05:00.0: no hotplug settings from platform
> >> > > > > > > [   18.288349] pci 0000:00:1d.0: no hotplug settings from platform
> >> > > > > > > [   18.288350] pci 0000:00:1d.0: using default PCI settings
> >> > > > > > > [   18.288360] pci 0000:00:1d.1: no hotplug settings from platform
> >> > > > > > > [   18.288361] pci 0000:00:1d.1: using default PCI settings
> >> > > > > > > [   18.288374] pci 0000:00:1d.2: no hotplug settings from platform
> >> > > > > > > [   18.288374] pci 0000:00:1d.2: using default PCI settings
> >> > > > > > > [   18.288387] pci 0000:00:1d.3: no hotplug settings from platform
> >> > > > > > > [   18.288387] pci 0000:00:1d.3: using default PCI settings
> >> > > > > > >
> >> > > > > > > The boot is noticeably slower.  What's going to happen on systems that
> >> > > > > > > actually have a significant I/O topology vs my little workstation?
> >> > > > >
> >> > > > > That depends on how many bus check/device check events they generate on boot.
> >> > > > >
> >> > > > > My test machines don't generate them during boot at all (even the one with
> >> > > > > a Thunderbolt connector), so I don't see the messages in question during boot
> >> > > > > on any of them.  Mika doesn't see them either I suppose, or he would have told
> >> > > > > me about that before.
> >> > > > >
> >> > > > > And let's just make it clear that it is not usual or even OK to generate bus
> >> > > > > checks or device checks during boot like this.  And since the changes in
> >> > > > > question have been in linux-next since right after the 3.11 merge window, I
> >> > > > > think that someone would have complained already had that been a common issue.
> >> > > > >
> >> > > > > Of course, we need to deal with that somehow nevertheless. :-)
> >> > > > >
> >> > > > > > Just to give you an idea:
> >> > > > > >
> >> > > > > > CONFIG_HOTPLUG_PCI_ACPI=y
> >> > > > > >
> >> > > > > > $ dmesg | wc
> >> > > > > >   5697  49935 384368
> >> > > > > >
> >> > > > > > $ dmesg | tail --lines=1
> >> > > > > > [   53.137123] Ebtables v2.0 registered
> >> > > > > >
> >> > > > > > -- vs --
> >> > > > > >
> >> > > > > > # CONFIG_HOTPLUG_PCI_ACPI is not set
> >> > > > > >
> >> > > > > > $ dmesg | wc
> >> > > > > >  1053  9176 71652
> >> > > > > >
> >> > > > > > $dmesg | tail --lines=1
> >> > > > > > [   28.917220] Ebtables v2.0 registered
> >> > > > > >
> >> > > > > > So it spews out 5x more output with acpiphp enabled and takes and extra
> >> > > > > > 24s to boot (nearly 2x).  Not good.
> >> > > > >
> >> > > > > The "no hotplug settings from platform" message is from pci_configure_slot().
> >> > > > > I think the messages you're seeing are from the call to it in
> >> > > > > acpiphp_set_hpp_values() which is called by enable_slot().
> >> > > > >
> >> > > > > There, I think, we can simply check the return value of pci_scan_slot() and
> >> > > > > if that is 0 (no new devices), we can just skip everything under the call to
> >> > > > > __pci_bus_assign_resources().
> >> > > > >
> >> > > > > However, we can't skip the scanning of bridges, if any, because there may be
> >> > > > > new devices below them and I guess that's what takes so much time on your
> >> > > > > machine.
> >> > > >
> >> > > > OK, one piece is missing.  We may need to evaluate _OSC after handling each
> >> > > > event to let the platform know the status.
> >> > > >
> >> > > > Can you please check if the appended patch makes any difference (with the
> >> > > > previous fix applied, of course)?
> >> > > >
> >> > > > If fact, it is two patches combined.  One of them optimizes enable_slot()
> >> > > > slightly and the other adds the missing _OSC evaluation.
> >> > >
> >> > > Better, still double the output:
> >> > >
> >> > > $ dmesg | wc
> >> > >    2169   19047  152710
> >> >
> >> > I see.
> >> >
> >> > What about the timing?
> >>
> >> ~40s below vs ~29s for acpiphp config'd out above.
> >
> > Well, that's better than before.
> >
> > I'll prepare "official" patches with the last changes then too.
> >
> >> > > $ dmesg | tail --lines=1
> >> > > [   39.980918] Ebtables v2.0 registered
> >> > >
> >> > > Here's another interesting stat:
> >> > >
> >> > > $ dmesg | colrm 1 15 | sort | uniq -c | sort -nr | head --lines=25
> >> > >      73 pci 0000:00:1f.0: BAR 13: [io  0x1000-0x107f] has bogus alignment
> >> > >      73 pci 0000:00:1e.0: PCI bridge to [bus 06]
> >> > >      64 pci 0000:00:1e.0:   bridge window [mem 0x81100000-0x812fffff 64bit pref]
> >> > >      64 pci 0000:00:1e.0:   bridge window [mem 0x80f00000-0x810fffff]
> >> > >      64 pci 0000:00:1e.0:   bridge window [io  0x7000-0x7fff]
> >> > >      38 pci 0000:00:1c.4: PCI bridge to [bus 05]
> >> > >      38 pci 0000:00:1c.4:   bridge window [mem 0xf4f00000-0xf4ffffff]
> >> > >      38 pci 0000:00:1c.0: PCI bridge to [bus 04]
> >> > >      38 pci 0000:00:07.0: PCI bridge to [bus 03]
> >> > >      38 pci 0000:00:07.0:   bridge window [mem 0xf2000000-0xf40fffff]
> >> > >      38 pci 0000:00:07.0:   bridge window [mem 0xe0000000-0xf1ffffff 64bit pref]
> >> > >      38 pci 0000:00:07.0:   bridge window [io  0x4000-0x4fff]
> >> > >      38 pci 0000:00:03.0: PCI bridge to [bus 02]
> >> > >      38 pci 0000:00:03.0:   bridge window [mem 0xf4e00000-0xf4efffff]
> >> > >      38 pci 0000:00:03.0:   bridge window [mem 0xd0000000-0xdfffffff 64bit pref]
> >> > >      38 pci 0000:00:03.0:   bridge window [io  0x3000-0x3fff]
> >> > >      38 pci 0000:00:01.0: PCI bridge to [bus 01]
> >> > >      38 pci 0000:00:01.0:   bridge window [mem 0xf4100000-0xf4bfffff]
> >> > >      38 pci 0000:00:01.0:   bridge window [io  0x2000-0x2fff]
> >> > >      37 pci 0000:00:1c.4:   bridge window [mem 0x80c00000-0x80dfffff 64bit pref]
> >> > >      37 pci 0000:00:1c.4:   bridge window [io  0x6000-0x6fff]
> >> > >      37 pci 0000:00:1c.0:   bridge window [mem 0x80a00000-0x80bfffff 64bit pref]
> >> > >      37 pci 0000:00:1c.0:   bridge window [mem 0x80800000-0x809fffff]
> >> > >      37 pci 0000:00:1c.0:   bridge window [io  0x5000-0x5fff]
> >> > >      36 pci 0000:00:01.0:   bridge window [mem 0x80000000-0x807fffff 64bit pref]
> >> > >
> >> > > This is nearly the entire difference, just 25 lines repeated over and
> >> > > over.
> >
> > Can you check how many times the lines above are repeated?
> >
> >> >
> >> > Well, this is the bridge sizing I talked about previously.  We still get
> >> > apparently spurious bus check/device check events and they trigger bridge
> >> > scans.
> >> >
> >> > I'm not sure what to do about that and I wonder whether or not this is
> >> > reproducible on any other machines you can test.
> >>
> >> I can try it on a couple other systems, but probably not until tomorrow.
> >
> > Tomorrow (or even later) works just fine for me. :-)
> >
> >> > Can you please change dbg() to pr_info() under ACPI_NOTIFY_BUS_CHECK and
> >> > ACPI_NOTIFY_DEVICE_CHECK in hotplug_event() (acpiphp_glue.c), grep the boot
> >> > dmesg log for "check notify" and send the result?  I'm wondering what's
> >> > going on there.
> >>
> >> $ dmesg | grep "check notify"
> >> [    1.633228] hotplug_event: Device check notify on \_SB_.PCI0.PEX2
> >> [    2.472004] hotplug_event: Device check notify on \_SB_.PCI0.PEX3
> >> [    2.477288] hotplug_event: Device check notify on \_SB_.PCI0.PEX4
> >> [    2.482571] hotplug_event: Device check notify on \_SB_.PCI0.PEX5
> >> [    2.482579] hotplug_event: Device check notify on \_SB_.PCI0.PEX6
> >> [    8.204953] hotplug_event: Device check notify on \_SB_.PCI0.PEX2
> >> [    8.209632] hotplug_event: Device check notify on \_SB_.PCI0.PEX3
> >> [    8.214272] hotplug_event: Device check notify on \_SB_.PCI0.PEX4
> >> [    8.218894] hotplug_event: Device check notify on \_SB_.PCI0.PEX5
> >> [    8.218901] hotplug_event: Device check notify on \_SB_.PCI0.PEX6
> >
> > So I guess the PEXn things are PCIe ports and we get two notifications
> > for each of them, so everything below them gets rescanned.
> >
> > I've just talked to Bjorn about that and we don't seem to have a good idea
> > how to handle this.  The notifies shouldn't be there, but we kind of have
> > to handle them.
> 
> What I said was "We aren't going to be able to get rid of the
> notifications, but we can probably figure out how to clean up some of
> the output."  I don't think there's anything *wrong* with the
> notifications themselves, and as far as I know, there's nothing in the
> spec that limits how many notifications the platform can send.

One would think that it wouldn't send notifications if nothing changed,
however.

> > I guess we could suppress the output from repeated bridge scans.  Alternatively,
> > we could just blacklist this particular system somehow if the problem is
> > specific to it.
> 
> I'm opposed to blacklisting in principle because this doesn't sound
> like a platform defect.

I'm not sure about that.  Sending notifications without a reason is not a good
practice at least, even if the spec does't forbid it directly.

There are many things for which there are no "don't do that" statements in the
spec which nevertheless may be regarded as incorrect behavior.  Therefore I'm
opposed to the "the spec doesn't forbid that openly, so it has to be OK to do it"
way of thinking.  Sorry.

> And I think we pretty much have to
> re-enumerate for each Device Check, because that's what the spec tells
> us to do.

Yes, it is.

> My goal is for PCI to print stuff only for significant events, when we
> discover something new, or when we change something (BAR, bridge
> window, etc.)  A hot-plug event, e.g., a Device Check, is arguably
> significant all by itself, but that's in ACPI, and it sounds like we
> only have a dbg() there now.  The repeated PCI bridge info seems like
> it's useless.  I've looked at cleaning up some of that in the past,
> but it wasn't trivial and it wasn't urgent enough at the time.  But it
> sure sounds urgent now.
>
> Alex, would you mind collecting the full dmesg or console log (with
> "debug ignore_loglevel") and "lspci -vv" output and attaching them to
> a bugzilla?  Keep the hotplug_event() pr_info() change so we have more
> clues about what triggers things.  This seems like an interesting
> situation, and there might be other things we can learn from it.  It
> looks like the "hotplug settings" output is probably more than is
> necessary also.

That can be changed to dev_dbg() I think and no one will really miss it. :-)

Thanks,
Rafael


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

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

* [PATCH 0/2] Re: Excess dmesg output from ACPIPHP on boot
  2013-09-05 23:36                                   ` Rafael J. Wysocki
  2013-09-05 23:31                                     ` Alex Williamson
  2013-09-06 12:19                                     ` Bjorn Helgaas
@ 2013-09-06 13:42                                     ` Rafael J. Wysocki
  2013-09-06 13:43                                       ` [PATCH 1/2] ACPI / hotplug / PCI: Avoid doing too much for spurious notifies Rafael J. Wysocki
                                                         ` (2 more replies)
  2 siblings, 3 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-09-06 13:42 UTC (permalink / raw)
  To: Alex Williamson
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Friday, September 06, 2013 01:36:28 AM Rafael J. Wysocki wrote:
> On Thursday, September 05, 2013 05:08:03 PM Alex Williamson wrote:
> > On Fri, 2013-09-06 at 00:40 +0200, Rafael J. Wysocki wrote:
> > > On Thursday, September 05, 2013 04:17:25 PM Alex Williamson wrote:
> > > > On Thu, 2013-09-05 at 23:39 +0200, Rafael J. Wysocki wrote:
> > > > > On Thursday, September 05, 2013 09:44:26 PM Rafael J. Wysocki wrote:
> > > > > > On Thursday, September 05, 2013 08:21:41 AM Alex Williamson wrote:
> > > > > 
> > > > > [...]
> > > > > 
> > > > > > > > 
> > > > > > > > [   18.288122] pci 0000:00:00.0: no hotplug settings from platform
> > > > > > > > [   18.288127] pcieport 0000:00:01.0: no hotplug settings from platform
> > > > > > > > [   18.288142] pci 0000:01:00.0: no hotplug settings from platform
> > > > > > > > [   18.288157] pci 0000:01:00.1: no hotplug settings from platform
> > > > > > > > [   18.288162] pcieport 0000:00:03.0: no hotplug settings from platform
> > > > > > > > [   18.288176] pci 0000:02:00.0: no hotplug settings from platform
> > > > > > > > [   18.288190] pci 0000:02:00.1: no hotplug settings from platform
> > > > > > > > [   18.288195] pcieport 0000:00:07.0: no hotplug settings from platform
> > > > > > > > [   18.288209] pci 0000:03:00.0: no hotplug settings from platform
> > > > > > > > [   18.288224] pci 0000:03:00.1: no hotplug settings from platform
> > > > > > > > [   18.288228] pci 0000:00:14.0: no hotplug settings from platform
> > > > > > > > [   18.288233] pci 0000:00:14.1: no hotplug settings from platform
> > > > > > > > [   18.288237] pci 0000:00:14.2: no hotplug settings from platform
> > > > > > > > [   18.288242] pci 0000:00:16.0: no hotplug settings from platform
> > > > > > > > [   18.288247] pci 0000:00:16.1: no hotplug settings from platform
> > > > > > > > [   18.288251] pci 0000:00:16.2: no hotplug settings from platform
> > > > > > > > [   18.288256] pci 0000:00:16.3: no hotplug settings from platform
> > > > > > > > [   18.288260] pci 0000:00:16.4: no hotplug settings from platform
> > > > > > > > [   18.288265] pci 0000:00:16.5: no hotplug settings from platform
> > > > > > > > [   18.288269] pci 0000:00:16.6: no hotplug settings from platform
> > > > > > > > [   18.288274] pci 0000:00:16.7: no hotplug settings from platform
> > > > > > > > [   18.288278] pci 0000:00:1a.0: no hotplug settings from platform
> > > > > > > > [   18.288279] pci 0000:00:1a.0: using default PCI settings
> > > > > > > > [   18.288292] pci 0000:00:1a.1: no hotplug settings from platform
> > > > > > > > [   18.288293] pci 0000:00:1a.1: using default PCI settings
> > > > > > > > [   18.288307] ehci-pci 0000:00:1a.7: no hotplug settings from platform
> > > > > > > > [   18.288308] ehci-pci 0000:00:1a.7: using default PCI settings
> > > > > > > > [   18.288322] pci 0000:00:1b.0: no hotplug settings from platform
> > > > > > > > [   18.288327] pcieport 0000:00:1c.0: no hotplug settings from platform
> > > > > > > > [   18.288332] pcieport 0000:00:1c.4: no hotplug settings from platform
> > > > > > > > [   18.288344] pci 0000:05:00.0: no hotplug settings from platform
> > > > > > > > [   18.288349] pci 0000:00:1d.0: no hotplug settings from platform
> > > > > > > > [   18.288350] pci 0000:00:1d.0: using default PCI settings
> > > > > > > > [   18.288360] pci 0000:00:1d.1: no hotplug settings from platform
> > > > > > > > [   18.288361] pci 0000:00:1d.1: using default PCI settings
> > > > > > > > [   18.288374] pci 0000:00:1d.2: no hotplug settings from platform
> > > > > > > > [   18.288374] pci 0000:00:1d.2: using default PCI settings
> > > > > > > > [   18.288387] pci 0000:00:1d.3: no hotplug settings from platform
> > > > > > > > [   18.288387] pci 0000:00:1d.3: using default PCI settings
> > > > > > > > 
> > > > > > > > The boot is noticeably slower.  What's going to happen on systems that
> > > > > > > > actually have a significant I/O topology vs my little workstation?
> > > > > > 
> > > > > > That depends on how many bus check/device check events they generate on boot.
> > > > > > 
> > > > > > My test machines don't generate them during boot at all (even the one with
> > > > > > a Thunderbolt connector), so I don't see the messages in question during boot
> > > > > > on any of them.  Mika doesn't see them either I suppose, or he would have told
> > > > > > me about that before.
> > > > > > 
> > > > > > And let's just make it clear that it is not usual or even OK to generate bus
> > > > > > checks or device checks during boot like this.  And since the changes in
> > > > > > question have been in linux-next since right after the 3.11 merge window, I
> > > > > > think that someone would have complained already had that been a common issue.
> > > > > > 
> > > > > > Of course, we need to deal with that somehow nevertheless. :-)
> > > > > > 
> > > > > > > Just to give you an idea:
> > > > > > > 
> > > > > > > CONFIG_HOTPLUG_PCI_ACPI=y
> > > > > > > 
> > > > > > > $ dmesg | wc
> > > > > > >   5697  49935 384368
> > > > > > > 
> > > > > > > $ dmesg | tail --lines=1
> > > > > > > [   53.137123] Ebtables v2.0 registered
> > > > > > > 
> > > > > > > -- vs --
> > > > > > > 
> > > > > > > # CONFIG_HOTPLUG_PCI_ACPI is not set
> > > > > > > 
> > > > > > > $ dmesg | wc
> > > > > > >  1053  9176 71652
> > > > > > > 
> > > > > > > $dmesg | tail --lines=1
> > > > > > > [   28.917220] Ebtables v2.0 registered
> > > > > > > 
> > > > > > > So it spews out 5x more output with acpiphp enabled and takes and extra
> > > > > > > 24s to boot (nearly 2x).  Not good.
> > > > > > 
> > > > > > The "no hotplug settings from platform" message is from pci_configure_slot().
> > > > > > I think the messages you're seeing are from the call to it in
> > > > > > acpiphp_set_hpp_values() which is called by enable_slot().
> > > > > > 
> > > > > > There, I think, we can simply check the return value of pci_scan_slot() and
> > > > > > if that is 0 (no new devices), we can just skip everything under the call to
> > > > > > __pci_bus_assign_resources().
> > > > > > 
> > > > > > However, we can't skip the scanning of bridges, if any, because there may be
> > > > > > new devices below them and I guess that's what takes so much time on your
> > > > > > machine.
> > > > > 
> > > > > OK, one piece is missing.  We may need to evaluate _OSC after handling each
> > > > > event to let the platform know the status.
> > > > > 
> > > > > Can you please check if the appended patch makes any difference (with the
> > > > > previous fix applied, of course)?
> > > > > 
> > > > > If fact, it is two patches combined.  One of them optimizes enable_slot()
> > > > > slightly and the other adds the missing _OSC evaluation.
> > > > 
> > > > Better, still double the output:
> > > > 
> > > > $ dmesg | wc
> > > >    2169   19047  152710
> > > 
> > > I see.
> > > 
> > > What about the timing?
> > 
> > ~40s below vs ~29s for acpiphp config'd out above.
> 
> Well, that's better than before.
> 
> I'll prepare "official" patches with the last changes then too.

The patches follow as [1/2] and [2/2].  The change in enable_slot() is
literally the same, but the _OST patch is somewhat different, although the
changes mostly affect the eject code path and the notifies that we don't
actually handle, so they should not matter on your machine.

Thanks,
Rafael

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

* [PATCH 1/2] ACPI / hotplug / PCI: Avoid doing too much for spurious notifies
  2013-09-06 13:42                                     ` [PATCH 0/2] Re: Excess dmesg output from ACPIPHP on boot Rafael J. Wysocki
@ 2013-09-06 13:43                                       ` Rafael J. Wysocki
  2013-09-06 15:46                                         ` Yinghai Lu
  2013-09-06 13:46                                       ` [PATCH 2/2] ACPI / hotplug / PCI: Use _OST to notify firmware about notify status Rafael J. Wysocki
  2013-09-06 15:36                                       ` [PATCH 0/2] Re: Excess dmesg output from ACPIPHP on boot Alex Williamson
  2 siblings, 1 reply; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-09-06 13:43 UTC (permalink / raw)
  To: Alex Williamson
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

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

Sometimes we may get a spurious device check or bus check notify for
a hotplug device and in those cases we should avoid doing all of the
configuration work needed when something actually changes.  To that
end, check the return value of pci_scan_slot() in enable_slot() and
bail out early if it is 0.

This turns out to help reduce the amount of diagnostic output from
the ACPIPHP subsystem and speed up boot on at least one system that
generates multiple device check notifies for PCIe ports during
boot.

Reported-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp_glue.c |   35 +++++++++++++++++++++++++++--------
 1 file changed, 27 insertions(+), 8 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
@@ -542,12 +542,12 @@ static void __ref enable_slot(struct acp
 	struct acpiphp_func *func;
 	int max, pass;
 	LIST_HEAD(add_list);
+	int nr_found;
 
 	list_for_each_entry(func, &slot->funcs, sibling)
 		acpiphp_bus_add(func_to_handle(func));
 
-	pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
-
+	nr_found = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
 	max = acpiphp_max_busnr(bus);
 	for (pass = 0; pass < 2; pass++) {
 		list_for_each_entry(dev, &bus->devices, bus_list) {
@@ -566,8 +566,11 @@ static void __ref enable_slot(struct acp
 			}
 		}
 	}
-
 	__pci_bus_assign_resources(bus, &add_list, NULL);
+	/* Nothing more to do here if there are no new devices on this bus. */
+	if (!nr_found && (slot->flags & SLOT_ENABLED))
+		return;
+
 	acpiphp_sanitize_bus(bus);
 	acpiphp_set_hpp_values(bus);
 	acpiphp_set_acpi_region(slot);


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

* [PATCH 2/2] ACPI / hotplug / PCI: Use _OST to notify firmware about notify status
  2013-09-06 13:42                                     ` [PATCH 0/2] Re: Excess dmesg output from ACPIPHP on boot Rafael J. Wysocki
  2013-09-06 13:43                                       ` [PATCH 1/2] ACPI / hotplug / PCI: Avoid doing too much for spurious notifies Rafael J. Wysocki
@ 2013-09-06 13:46                                       ` Rafael J. Wysocki
  2013-09-06 15:36                                       ` [PATCH 0/2] Re: Excess dmesg output from ACPIPHP on boot Alex Williamson
  2 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-09-06 13:46 UTC (permalink / raw)
  To: Alex Williamson
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

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

The spec suggests that we should use _OST to inform the platform
of the status of notifications it sends us, for example so that
it doesn't repeate a notification that has been handled already.

For this reason, add _OST evaluation to the ACPIPHP subsystem.

This turns out to help reduce the amount of diagnostic output from
the ACPIPHP subsystem and speed up boot on at least one system that
generates multiple device check notifies for PCIe ports during
boot.

Reported-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/pci/hotplug/acpiphp_glue.c |   21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 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
@@ -870,6 +870,8 @@ static void hotplug_event_work(struct wo
 	hotplug_event(hp_work->handle, hp_work->type, context);
 
 	acpi_scan_lock_release();
+	acpi_evaluate_hotplug_ost(hp_work->handle, hp_work->type,
+				  ACPI_OST_SC_SUCCESS, NULL);
 	kfree(hp_work); /* allocated in handle_hotplug_event() */
 	put_bridge(context->func.parent);
 }
@@ -885,11 +887,15 @@ static void hotplug_event_work(struct wo
 static void handle_hotplug_event(acpi_handle handle, u32 type, void *data)
 {
 	struct acpiphp_context *context;
+	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:
@@ -898,20 +904,21 @@ static void handle_hotplug_event(acpi_ha
 	case ACPI_NOTIFY_FREQUENCY_MISMATCH:
 		acpi_handle_err(handle, "Device cannot be configured due "
 				"to a frequency mismatch\n");
-		return;
+		goto out;
 
 	case ACPI_NOTIFY_BUS_MODE_MISMATCH:
 		acpi_handle_err(handle, "Device cannot be configured due "
 				"to a bus mode mismatch\n");
-		return;
+		goto out;
 
 	case ACPI_NOTIFY_POWER_FAULT:
 		acpi_handle_err(handle, "Device has suffered a power fault\n");
-		return;
+		goto out;
 
 	default:
 		acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type);
-		return;
+		ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY;
+		goto out;
 	}
 
 	mutex_lock(&acpiphp_context_lock);
@@ -920,8 +927,14 @@ static void handle_hotplug_event(acpi_ha
 		get_bridge(context->func.parent);
 		acpiphp_put_context(context);
 		alloc_acpi_hp_work(handle, type, context, hotplug_event_work);
+		mutex_unlock(&acpiphp_context_lock);
+		return;
 	}
 	mutex_unlock(&acpiphp_context_lock);
+	ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
+
+ out:
+	acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
 }
 
 /*

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

* Re: Excess dmesg output from ACPIPHP on boot (was: Re: [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots)
  2013-09-06 12:19                                     ` Bjorn Helgaas
  2013-09-06 12:40                                       ` Rafael J. Wysocki
@ 2013-09-06 15:34                                       ` Alex Williamson
  2013-09-07 22:16                                         ` [PATCH] ACPI / hotplug / PCI: Avoid parent bus rescans on spurious device checks Rafael J. Wysocki
  1 sibling, 1 reply; 135+ messages in thread
From: Alex Williamson @ 2013-09-06 15:34 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: Rafael J. Wysocki, ACPI Devel Maling List, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Fri, 2013-09-06 at 06:19 -0600, Bjorn Helgaas wrote:
> On Thu, Sep 5, 2013 at 5:36 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> > On Thursday, September 05, 2013 05:08:03 PM Alex Williamson wrote:
> >> On Fri, 2013-09-06 at 00:40 +0200, Rafael J. Wysocki wrote:
> >> > On Thursday, September 05, 2013 04:17:25 PM Alex Williamson wrote:
> >> > > On Thu, 2013-09-05 at 23:39 +0200, Rafael J. Wysocki wrote:
> >> > > > On Thursday, September 05, 2013 09:44:26 PM Rafael J. Wysocki wrote:
> >> > > > > On Thursday, September 05, 2013 08:21:41 AM Alex Williamson wrote:
> >> > > >
> >> > > > [...]
> >> > > >
> >> > > > > > >
> >> > > > > > > [   18.288122] pci 0000:00:00.0: no hotplug settings from platform
> >> > > > > > > [   18.288127] pcieport 0000:00:01.0: no hotplug settings from platform
> >> > > > > > > [   18.288142] pci 0000:01:00.0: no hotplug settings from platform
> >> > > > > > > [   18.288157] pci 0000:01:00.1: no hotplug settings from platform
> >> > > > > > > [   18.288162] pcieport 0000:00:03.0: no hotplug settings from platform
> >> > > > > > > [   18.288176] pci 0000:02:00.0: no hotplug settings from platform
> >> > > > > > > [   18.288190] pci 0000:02:00.1: no hotplug settings from platform
> >> > > > > > > [   18.288195] pcieport 0000:00:07.0: no hotplug settings from platform
> >> > > > > > > [   18.288209] pci 0000:03:00.0: no hotplug settings from platform
> >> > > > > > > [   18.288224] pci 0000:03:00.1: no hotplug settings from platform
> >> > > > > > > [   18.288228] pci 0000:00:14.0: no hotplug settings from platform
> >> > > > > > > [   18.288233] pci 0000:00:14.1: no hotplug settings from platform
> >> > > > > > > [   18.288237] pci 0000:00:14.2: no hotplug settings from platform
> >> > > > > > > [   18.288242] pci 0000:00:16.0: no hotplug settings from platform
> >> > > > > > > [   18.288247] pci 0000:00:16.1: no hotplug settings from platform
> >> > > > > > > [   18.288251] pci 0000:00:16.2: no hotplug settings from platform
> >> > > > > > > [   18.288256] pci 0000:00:16.3: no hotplug settings from platform
> >> > > > > > > [   18.288260] pci 0000:00:16.4: no hotplug settings from platform
> >> > > > > > > [   18.288265] pci 0000:00:16.5: no hotplug settings from platform
> >> > > > > > > [   18.288269] pci 0000:00:16.6: no hotplug settings from platform
> >> > > > > > > [   18.288274] pci 0000:00:16.7: no hotplug settings from platform
> >> > > > > > > [   18.288278] pci 0000:00:1a.0: no hotplug settings from platform
> >> > > > > > > [   18.288279] pci 0000:00:1a.0: using default PCI settings
> >> > > > > > > [   18.288292] pci 0000:00:1a.1: no hotplug settings from platform
> >> > > > > > > [   18.288293] pci 0000:00:1a.1: using default PCI settings
> >> > > > > > > [   18.288307] ehci-pci 0000:00:1a.7: no hotplug settings from platform
> >> > > > > > > [   18.288308] ehci-pci 0000:00:1a.7: using default PCI settings
> >> > > > > > > [   18.288322] pci 0000:00:1b.0: no hotplug settings from platform
> >> > > > > > > [   18.288327] pcieport 0000:00:1c.0: no hotplug settings from platform
> >> > > > > > > [   18.288332] pcieport 0000:00:1c.4: no hotplug settings from platform
> >> > > > > > > [   18.288344] pci 0000:05:00.0: no hotplug settings from platform
> >> > > > > > > [   18.288349] pci 0000:00:1d.0: no hotplug settings from platform
> >> > > > > > > [   18.288350] pci 0000:00:1d.0: using default PCI settings
> >> > > > > > > [   18.288360] pci 0000:00:1d.1: no hotplug settings from platform
> >> > > > > > > [   18.288361] pci 0000:00:1d.1: using default PCI settings
> >> > > > > > > [   18.288374] pci 0000:00:1d.2: no hotplug settings from platform
> >> > > > > > > [   18.288374] pci 0000:00:1d.2: using default PCI settings
> >> > > > > > > [   18.288387] pci 0000:00:1d.3: no hotplug settings from platform
> >> > > > > > > [   18.288387] pci 0000:00:1d.3: using default PCI settings
> >> > > > > > >
> >> > > > > > > The boot is noticeably slower.  What's going to happen on systems that
> >> > > > > > > actually have a significant I/O topology vs my little workstation?
> >> > > > >
> >> > > > > That depends on how many bus check/device check events they generate on boot.
> >> > > > >
> >> > > > > My test machines don't generate them during boot at all (even the one with
> >> > > > > a Thunderbolt connector), so I don't see the messages in question during boot
> >> > > > > on any of them.  Mika doesn't see them either I suppose, or he would have told
> >> > > > > me about that before.
> >> > > > >
> >> > > > > And let's just make it clear that it is not usual or even OK to generate bus
> >> > > > > checks or device checks during boot like this.  And since the changes in
> >> > > > > question have been in linux-next since right after the 3.11 merge window, I
> >> > > > > think that someone would have complained already had that been a common issue.
> >> > > > >
> >> > > > > Of course, we need to deal with that somehow nevertheless. :-)
> >> > > > >
> >> > > > > > Just to give you an idea:
> >> > > > > >
> >> > > > > > CONFIG_HOTPLUG_PCI_ACPI=y
> >> > > > > >
> >> > > > > > $ dmesg | wc
> >> > > > > >   5697  49935 384368
> >> > > > > >
> >> > > > > > $ dmesg | tail --lines=1
> >> > > > > > [   53.137123] Ebtables v2.0 registered
> >> > > > > >
> >> > > > > > -- vs --
> >> > > > > >
> >> > > > > > # CONFIG_HOTPLUG_PCI_ACPI is not set
> >> > > > > >
> >> > > > > > $ dmesg | wc
> >> > > > > >  1053  9176 71652
> >> > > > > >
> >> > > > > > $dmesg | tail --lines=1
> >> > > > > > [   28.917220] Ebtables v2.0 registered
> >> > > > > >
> >> > > > > > So it spews out 5x more output with acpiphp enabled and takes and extra
> >> > > > > > 24s to boot (nearly 2x).  Not good.
> >> > > > >
> >> > > > > The "no hotplug settings from platform" message is from pci_configure_slot().
> >> > > > > I think the messages you're seeing are from the call to it in
> >> > > > > acpiphp_set_hpp_values() which is called by enable_slot().
> >> > > > >
> >> > > > > There, I think, we can simply check the return value of pci_scan_slot() and
> >> > > > > if that is 0 (no new devices), we can just skip everything under the call to
> >> > > > > __pci_bus_assign_resources().
> >> > > > >
> >> > > > > However, we can't skip the scanning of bridges, if any, because there may be
> >> > > > > new devices below them and I guess that's what takes so much time on your
> >> > > > > machine.
> >> > > >
> >> > > > OK, one piece is missing.  We may need to evaluate _OSC after handling each
> >> > > > event to let the platform know the status.
> >> > > >
> >> > > > Can you please check if the appended patch makes any difference (with the
> >> > > > previous fix applied, of course)?
> >> > > >
> >> > > > If fact, it is two patches combined.  One of them optimizes enable_slot()
> >> > > > slightly and the other adds the missing _OSC evaluation.
> >> > >
> >> > > Better, still double the output:
> >> > >
> >> > > $ dmesg | wc
> >> > >    2169   19047  152710
> >> >
> >> > I see.
> >> >
> >> > What about the timing?
> >>
> >> ~40s below vs ~29s for acpiphp config'd out above.
> >
> > Well, that's better than before.
> >
> > I'll prepare "official" patches with the last changes then too.
> >
> >> > > $ dmesg | tail --lines=1
> >> > > [   39.980918] Ebtables v2.0 registered
> >> > >
> >> > > Here's another interesting stat:
> >> > >
> >> > > $ dmesg | colrm 1 15 | sort | uniq -c | sort -nr | head --lines=25
> >> > >      73 pci 0000:00:1f.0: BAR 13: [io  0x1000-0x107f] has bogus alignment
> >> > >      73 pci 0000:00:1e.0: PCI bridge to [bus 06]
> >> > >      64 pci 0000:00:1e.0:   bridge window [mem 0x81100000-0x812fffff 64bit pref]
> >> > >      64 pci 0000:00:1e.0:   bridge window [mem 0x80f00000-0x810fffff]
> >> > >      64 pci 0000:00:1e.0:   bridge window [io  0x7000-0x7fff]
> >> > >      38 pci 0000:00:1c.4: PCI bridge to [bus 05]
> >> > >      38 pci 0000:00:1c.4:   bridge window [mem 0xf4f00000-0xf4ffffff]
> >> > >      38 pci 0000:00:1c.0: PCI bridge to [bus 04]
> >> > >      38 pci 0000:00:07.0: PCI bridge to [bus 03]
> >> > >      38 pci 0000:00:07.0:   bridge window [mem 0xf2000000-0xf40fffff]
> >> > >      38 pci 0000:00:07.0:   bridge window [mem 0xe0000000-0xf1ffffff 64bit pref]
> >> > >      38 pci 0000:00:07.0:   bridge window [io  0x4000-0x4fff]
> >> > >      38 pci 0000:00:03.0: PCI bridge to [bus 02]
> >> > >      38 pci 0000:00:03.0:   bridge window [mem 0xf4e00000-0xf4efffff]
> >> > >      38 pci 0000:00:03.0:   bridge window [mem 0xd0000000-0xdfffffff 64bit pref]
> >> > >      38 pci 0000:00:03.0:   bridge window [io  0x3000-0x3fff]
> >> > >      38 pci 0000:00:01.0: PCI bridge to [bus 01]
> >> > >      38 pci 0000:00:01.0:   bridge window [mem 0xf4100000-0xf4bfffff]
> >> > >      38 pci 0000:00:01.0:   bridge window [io  0x2000-0x2fff]
> >> > >      37 pci 0000:00:1c.4:   bridge window [mem 0x80c00000-0x80dfffff 64bit pref]
> >> > >      37 pci 0000:00:1c.4:   bridge window [io  0x6000-0x6fff]
> >> > >      37 pci 0000:00:1c.0:   bridge window [mem 0x80a00000-0x80bfffff 64bit pref]
> >> > >      37 pci 0000:00:1c.0:   bridge window [mem 0x80800000-0x809fffff]
> >> > >      37 pci 0000:00:1c.0:   bridge window [io  0x5000-0x5fff]
> >> > >      36 pci 0000:00:01.0:   bridge window [mem 0x80000000-0x807fffff 64bit pref]
> >> > >
> >> > > This is nearly the entire difference, just 25 lines repeated over and
> >> > > over.
> >
> > Can you check how many times the lines above are repeated?
> >
> >> >
> >> > Well, this is the bridge sizing I talked about previously.  We still get
> >> > apparently spurious bus check/device check events and they trigger bridge
> >> > scans.
> >> >
> >> > I'm not sure what to do about that and I wonder whether or not this is
> >> > reproducible on any other machines you can test.
> >>
> >> I can try it on a couple other systems, but probably not until tomorrow.
> >
> > Tomorrow (or even later) works just fine for me. :-)
> >
> >> > Can you please change dbg() to pr_info() under ACPI_NOTIFY_BUS_CHECK and
> >> > ACPI_NOTIFY_DEVICE_CHECK in hotplug_event() (acpiphp_glue.c), grep the boot
> >> > dmesg log for "check notify" and send the result?  I'm wondering what's
> >> > going on there.
> >>
> >> $ dmesg | grep "check notify"
> >> [    1.633228] hotplug_event: Device check notify on \_SB_.PCI0.PEX2
> >> [    2.472004] hotplug_event: Device check notify on \_SB_.PCI0.PEX3
> >> [    2.477288] hotplug_event: Device check notify on \_SB_.PCI0.PEX4
> >> [    2.482571] hotplug_event: Device check notify on \_SB_.PCI0.PEX5
> >> [    2.482579] hotplug_event: Device check notify on \_SB_.PCI0.PEX6
> >> [    8.204953] hotplug_event: Device check notify on \_SB_.PCI0.PEX2
> >> [    8.209632] hotplug_event: Device check notify on \_SB_.PCI0.PEX3
> >> [    8.214272] hotplug_event: Device check notify on \_SB_.PCI0.PEX4
> >> [    8.218894] hotplug_event: Device check notify on \_SB_.PCI0.PEX5
> >> [    8.218901] hotplug_event: Device check notify on \_SB_.PCI0.PEX6
> >
> > So I guess the PEXn things are PCIe ports and we get two notifications
> > for each of them, so everything below them gets rescanned.
> >
> > I've just talked to Bjorn about that and we don't seem to have a good idea
> > how to handle this.  The notifies shouldn't be there, but we kind of have
> > to handle them.
> 
> What I said was "We aren't going to be able to get rid of the
> notifications, but we can probably figure out how to clean up some of
> the output."  I don't think there's anything *wrong* with the
> notifications themselves, and as far as I know, there's nothing in the
> spec that limits how many notifications the platform can send.
> 
> > I guess we could suppress the output from repeated bridge scans.  Alternatively,
> > we could just blacklist this particular system somehow if the problem is
> > specific to it.
> 
> I'm opposed to blacklisting in principle because this doesn't sound
> like a platform defect.  And I think we pretty much have to
> re-enumerate for each Device Check, because that's what the spec tells
> us to do.
> 
> My goal is for PCI to print stuff only for significant events, when we
> discover something new, or when we change something (BAR, bridge
> window, etc.)  A hot-plug event, e.g., a Device Check, is arguably
> significant all by itself, but that's in ACPI, and it sounds like we
> only have a dbg() there now.  The repeated PCI bridge info seems like
> it's useless.  I've looked at cleaning up some of that in the past,
> but it wasn't trivial and it wasn't urgent enough at the time.  But it
> sure sounds urgent now.
> 
> Alex, would you mind collecting the full dmesg or console log (with
> "debug ignore_loglevel") and "lspci -vv" output and attaching them to
> a bugzilla?  Keep the hotplug_event() pr_info() change so we have more
> clues about what triggers things.  This seems like an interesting
> situation, and there might be other things we can learn from it.  It
> looks like the "hotplug settings" output is probably more than is
> necessary also.

bz here:

https://bugzilla.kernel.org/show_bug.cgi?id=60865

Thanks,
Alex


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

* Re: [PATCH 0/2] Re: Excess dmesg output from ACPIPHP on boot
  2013-09-06 13:42                                     ` [PATCH 0/2] Re: Excess dmesg output from ACPIPHP on boot Rafael J. Wysocki
  2013-09-06 13:43                                       ` [PATCH 1/2] ACPI / hotplug / PCI: Avoid doing too much for spurious notifies Rafael J. Wysocki
  2013-09-06 13:46                                       ` [PATCH 2/2] ACPI / hotplug / PCI: Use _OST to notify firmware about notify status Rafael J. Wysocki
@ 2013-09-06 15:36                                       ` Alex Williamson
  2013-09-06 23:46                                         ` Rafael J. Wysocki
  2 siblings, 1 reply; 135+ messages in thread
From: Alex Williamson @ 2013-09-06 15:36 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Fri, 2013-09-06 at 15:42 +0200, Rafael J. Wysocki wrote:
> On Friday, September 06, 2013 01:36:28 AM Rafael J. Wysocki wrote:
> > On Thursday, September 05, 2013 05:08:03 PM Alex Williamson wrote:
> > > On Fri, 2013-09-06 at 00:40 +0200, Rafael J. Wysocki wrote:
> > > > On Thursday, September 05, 2013 04:17:25 PM Alex Williamson wrote:
> > > > > On Thu, 2013-09-05 at 23:39 +0200, Rafael J. Wysocki wrote:
> > > > > > On Thursday, September 05, 2013 09:44:26 PM Rafael J. Wysocki wrote:
> > > > > > > On Thursday, September 05, 2013 08:21:41 AM Alex Williamson wrote:
> > > > > > 
> > > > > > [...]
> > > > > > 
> > > > > > > > > 
> > > > > > > > > [   18.288122] pci 0000:00:00.0: no hotplug settings from platform
> > > > > > > > > [   18.288127] pcieport 0000:00:01.0: no hotplug settings from platform
> > > > > > > > > [   18.288142] pci 0000:01:00.0: no hotplug settings from platform
> > > > > > > > > [   18.288157] pci 0000:01:00.1: no hotplug settings from platform
> > > > > > > > > [   18.288162] pcieport 0000:00:03.0: no hotplug settings from platform
> > > > > > > > > [   18.288176] pci 0000:02:00.0: no hotplug settings from platform
> > > > > > > > > [   18.288190] pci 0000:02:00.1: no hotplug settings from platform
> > > > > > > > > [   18.288195] pcieport 0000:00:07.0: no hotplug settings from platform
> > > > > > > > > [   18.288209] pci 0000:03:00.0: no hotplug settings from platform
> > > > > > > > > [   18.288224] pci 0000:03:00.1: no hotplug settings from platform
> > > > > > > > > [   18.288228] pci 0000:00:14.0: no hotplug settings from platform
> > > > > > > > > [   18.288233] pci 0000:00:14.1: no hotplug settings from platform
> > > > > > > > > [   18.288237] pci 0000:00:14.2: no hotplug settings from platform
> > > > > > > > > [   18.288242] pci 0000:00:16.0: no hotplug settings from platform
> > > > > > > > > [   18.288247] pci 0000:00:16.1: no hotplug settings from platform
> > > > > > > > > [   18.288251] pci 0000:00:16.2: no hotplug settings from platform
> > > > > > > > > [   18.288256] pci 0000:00:16.3: no hotplug settings from platform
> > > > > > > > > [   18.288260] pci 0000:00:16.4: no hotplug settings from platform
> > > > > > > > > [   18.288265] pci 0000:00:16.5: no hotplug settings from platform
> > > > > > > > > [   18.288269] pci 0000:00:16.6: no hotplug settings from platform
> > > > > > > > > [   18.288274] pci 0000:00:16.7: no hotplug settings from platform
> > > > > > > > > [   18.288278] pci 0000:00:1a.0: no hotplug settings from platform
> > > > > > > > > [   18.288279] pci 0000:00:1a.0: using default PCI settings
> > > > > > > > > [   18.288292] pci 0000:00:1a.1: no hotplug settings from platform
> > > > > > > > > [   18.288293] pci 0000:00:1a.1: using default PCI settings
> > > > > > > > > [   18.288307] ehci-pci 0000:00:1a.7: no hotplug settings from platform
> > > > > > > > > [   18.288308] ehci-pci 0000:00:1a.7: using default PCI settings
> > > > > > > > > [   18.288322] pci 0000:00:1b.0: no hotplug settings from platform
> > > > > > > > > [   18.288327] pcieport 0000:00:1c.0: no hotplug settings from platform
> > > > > > > > > [   18.288332] pcieport 0000:00:1c.4: no hotplug settings from platform
> > > > > > > > > [   18.288344] pci 0000:05:00.0: no hotplug settings from platform
> > > > > > > > > [   18.288349] pci 0000:00:1d.0: no hotplug settings from platform
> > > > > > > > > [   18.288350] pci 0000:00:1d.0: using default PCI settings
> > > > > > > > > [   18.288360] pci 0000:00:1d.1: no hotplug settings from platform
> > > > > > > > > [   18.288361] pci 0000:00:1d.1: using default PCI settings
> > > > > > > > > [   18.288374] pci 0000:00:1d.2: no hotplug settings from platform
> > > > > > > > > [   18.288374] pci 0000:00:1d.2: using default PCI settings
> > > > > > > > > [   18.288387] pci 0000:00:1d.3: no hotplug settings from platform
> > > > > > > > > [   18.288387] pci 0000:00:1d.3: using default PCI settings
> > > > > > > > > 
> > > > > > > > > The boot is noticeably slower.  What's going to happen on systems that
> > > > > > > > > actually have a significant I/O topology vs my little workstation?
> > > > > > > 
> > > > > > > That depends on how many bus check/device check events they generate on boot.
> > > > > > > 
> > > > > > > My test machines don't generate them during boot at all (even the one with
> > > > > > > a Thunderbolt connector), so I don't see the messages in question during boot
> > > > > > > on any of them.  Mika doesn't see them either I suppose, or he would have told
> > > > > > > me about that before.
> > > > > > > 
> > > > > > > And let's just make it clear that it is not usual or even OK to generate bus
> > > > > > > checks or device checks during boot like this.  And since the changes in
> > > > > > > question have been in linux-next since right after the 3.11 merge window, I
> > > > > > > think that someone would have complained already had that been a common issue.
> > > > > > > 
> > > > > > > Of course, we need to deal with that somehow nevertheless. :-)
> > > > > > > 
> > > > > > > > Just to give you an idea:
> > > > > > > > 
> > > > > > > > CONFIG_HOTPLUG_PCI_ACPI=y
> > > > > > > > 
> > > > > > > > $ dmesg | wc
> > > > > > > >   5697  49935 384368
> > > > > > > > 
> > > > > > > > $ dmesg | tail --lines=1
> > > > > > > > [   53.137123] Ebtables v2.0 registered
> > > > > > > > 
> > > > > > > > -- vs --
> > > > > > > > 
> > > > > > > > # CONFIG_HOTPLUG_PCI_ACPI is not set
> > > > > > > > 
> > > > > > > > $ dmesg | wc
> > > > > > > >  1053  9176 71652
> > > > > > > > 
> > > > > > > > $dmesg | tail --lines=1
> > > > > > > > [   28.917220] Ebtables v2.0 registered
> > > > > > > > 
> > > > > > > > So it spews out 5x more output with acpiphp enabled and takes and extra
> > > > > > > > 24s to boot (nearly 2x).  Not good.
> > > > > > > 
> > > > > > > The "no hotplug settings from platform" message is from pci_configure_slot().
> > > > > > > I think the messages you're seeing are from the call to it in
> > > > > > > acpiphp_set_hpp_values() which is called by enable_slot().
> > > > > > > 
> > > > > > > There, I think, we can simply check the return value of pci_scan_slot() and
> > > > > > > if that is 0 (no new devices), we can just skip everything under the call to
> > > > > > > __pci_bus_assign_resources().
> > > > > > > 
> > > > > > > However, we can't skip the scanning of bridges, if any, because there may be
> > > > > > > new devices below them and I guess that's what takes so much time on your
> > > > > > > machine.
> > > > > > 
> > > > > > OK, one piece is missing.  We may need to evaluate _OSC after handling each
> > > > > > event to let the platform know the status.
> > > > > > 
> > > > > > Can you please check if the appended patch makes any difference (with the
> > > > > > previous fix applied, of course)?
> > > > > > 
> > > > > > If fact, it is two patches combined.  One of them optimizes enable_slot()
> > > > > > slightly and the other adds the missing _OSC evaluation.
> > > > > 
> > > > > Better, still double the output:
> > > > > 
> > > > > $ dmesg | wc
> > > > >    2169   19047  152710
> > > > 
> > > > I see.
> > > > 
> > > > What about the timing?
> > > 
> > > ~40s below vs ~29s for acpiphp config'd out above.
> > 
> > Well, that's better than before.
> > 
> > I'll prepare "official" patches with the last changes then too.
> 
> The patches follow as [1/2] and [2/2].  The change in enable_slot() is
> literally the same, but the _OST patch is somewhat different, although the
> changes mostly affect the eject code path and the notifies that we don't
> actually handle, so they should not matter on your machine.

Tested-by: Alex Williamson <alex.williamson@redhat.com>

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

* Re: [PATCH 1/2] ACPI / hotplug / PCI: Avoid doing too much for spurious notifies
  2013-09-06 13:43                                       ` [PATCH 1/2] ACPI / hotplug / PCI: Avoid doing too much for spurious notifies Rafael J. Wysocki
@ 2013-09-06 15:46                                         ` Yinghai Lu
  2013-09-06 23:45                                           ` Rafael J. Wysocki
  0 siblings, 1 reply; 135+ messages in thread
From: Yinghai Lu @ 2013-09-06 15:46 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Alex Williamson, ACPI Devel Maling List, Bjorn Helgaas, LKML,
	Linux PCI, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Fri, Sep 6, 2013 at 6:43 AM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>
> Sometimes we may get a spurious device check or bus check notify for
> a hotplug device and in those cases we should avoid doing all of the
> configuration work needed when something actually changes.  To that
> end, check the return value of pci_scan_slot() in enable_slot() and
> bail out early if it is 0.
>
> This turns out to help reduce the amount of diagnostic output from
> the ACPIPHP subsystem and speed up boot on at least one system that
> generates multiple device check notifies for PCIe ports during
> boot.
>
> Reported-by: Alex Williamson <alex.williamson@redhat.com>
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> ---
>  drivers/pci/hotplug/acpiphp_glue.c |   35 +++++++++++++++++++++++++++--------
>  1 file changed, 27 insertions(+), 8 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
> @@ -542,12 +542,12 @@ static void __ref enable_slot(struct acp
>         struct acpiphp_func *func;
>         int max, pass;
>         LIST_HEAD(add_list);
> +       int nr_found;
>
>         list_for_each_entry(func, &slot->funcs, sibling)
>                 acpiphp_bus_add(func_to_handle(func));
>
> -       pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
> -
> +       nr_found = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
>         max = acpiphp_max_busnr(bus);
>         for (pass = 0; pass < 2; pass++) {
>                 list_for_each_entry(dev, &bus->devices, bus_list) {
> @@ -566,8 +566,11 @@ static void __ref enable_slot(struct acp
>                         }
>                 }
>         }
> -
>         __pci_bus_assign_resources(bus, &add_list, NULL);
> +       /* Nothing more to do here if there are no new devices on this bus. */
> +       if (!nr_found && (slot->flags & SLOT_ENABLED))
> +               return;
> +
>         acpiphp_sanitize_bus(bus);
>         acpiphp_set_hpp_values(bus);
>         acpiphp_set_acpi_region(slot);
>

why not just returning early before size bridges and assign unassign resources?

Yinghai

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

* Re: [PATCH 1/2] ACPI / hotplug / PCI: Avoid doing too much for spurious notifies
  2013-09-06 15:46                                         ` Yinghai Lu
@ 2013-09-06 23:45                                           ` Rafael J. Wysocki
  0 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-09-06 23:45 UTC (permalink / raw)
  To: Yinghai Lu
  Cc: Alex Williamson, ACPI Devel Maling List, Bjorn Helgaas, LKML,
	Linux PCI, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Friday, September 06, 2013 08:46:28 AM Yinghai Lu wrote:
> On Fri, Sep 6, 2013 at 6:43 AM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
> > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> >
> > Sometimes we may get a spurious device check or bus check notify for
> > a hotplug device and in those cases we should avoid doing all of the
> > configuration work needed when something actually changes.  To that
> > end, check the return value of pci_scan_slot() in enable_slot() and
> > bail out early if it is 0.
> >
> > This turns out to help reduce the amount of diagnostic output from
> > the ACPIPHP subsystem and speed up boot on at least one system that
> > generates multiple device check notifies for PCIe ports during
> > boot.
> >
> > Reported-by: Alex Williamson <alex.williamson@redhat.com>
> > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > ---
> >  drivers/pci/hotplug/acpiphp_glue.c |   35 +++++++++++++++++++++++++++--------
> >  1 file changed, 27 insertions(+), 8 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
> > @@ -542,12 +542,12 @@ static void __ref enable_slot(struct acp
> >         struct acpiphp_func *func;
> >         int max, pass;
> >         LIST_HEAD(add_list);
> > +       int nr_found;
> >
> >         list_for_each_entry(func, &slot->funcs, sibling)
> >                 acpiphp_bus_add(func_to_handle(func));
> >
> > -       pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
> > -
> > +       nr_found = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
> >         max = acpiphp_max_busnr(bus);
> >         for (pass = 0; pass < 2; pass++) {
> >                 list_for_each_entry(dev, &bus->devices, bus_list) {
> > @@ -566,8 +566,11 @@ static void __ref enable_slot(struct acp
> >                         }
> >                 }
> >         }
> > -
> >         __pci_bus_assign_resources(bus, &add_list, NULL);
> > +       /* Nothing more to do here if there are no new devices on this bus. */
> > +       if (!nr_found && (slot->flags & SLOT_ENABLED))
> > +               return;
> > +
> >         acpiphp_sanitize_bus(bus);
> >         acpiphp_set_hpp_values(bus);
> >         acpiphp_set_acpi_region(slot);
> >
> 
> why not just returning early before size bridges and assign unassign resources?

Because we still need to do that even if pci_scan_slot() returns 0.

There may be new devices down in the hierarchy and we need to look for them.

Thanks,
Rafael


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

* Re: [PATCH 0/2] Re: Excess dmesg output from ACPIPHP on boot
  2013-09-06 15:36                                       ` [PATCH 0/2] Re: Excess dmesg output from ACPIPHP on boot Alex Williamson
@ 2013-09-06 23:46                                         ` Rafael J. Wysocki
  0 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-09-06 23:46 UTC (permalink / raw)
  To: Alex Williamson
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Friday, September 06, 2013 09:36:08 AM Alex Williamson wrote:
> On Fri, 2013-09-06 at 15:42 +0200, Rafael J. Wysocki wrote:
> > On Friday, September 06, 2013 01:36:28 AM Rafael J. Wysocki wrote:
> > > On Thursday, September 05, 2013 05:08:03 PM Alex Williamson wrote:
> > > > On Fri, 2013-09-06 at 00:40 +0200, Rafael J. Wysocki wrote:
> > > > > On Thursday, September 05, 2013 04:17:25 PM Alex Williamson wrote:
> > > > > > On Thu, 2013-09-05 at 23:39 +0200, Rafael J. Wysocki wrote:
> > > > > > > On Thursday, September 05, 2013 09:44:26 PM Rafael J. Wysocki wrote:
> > > > > > > > On Thursday, September 05, 2013 08:21:41 AM Alex Williamson wrote:
> > > > > > > 
> > > > > > > [...]
> > > > > > > 
> > > > > > > > > > 
> > > > > > > > > > [   18.288122] pci 0000:00:00.0: no hotplug settings from platform
> > > > > > > > > > [   18.288127] pcieport 0000:00:01.0: no hotplug settings from platform
> > > > > > > > > > [   18.288142] pci 0000:01:00.0: no hotplug settings from platform
> > > > > > > > > > [   18.288157] pci 0000:01:00.1: no hotplug settings from platform
> > > > > > > > > > [   18.288162] pcieport 0000:00:03.0: no hotplug settings from platform
> > > > > > > > > > [   18.288176] pci 0000:02:00.0: no hotplug settings from platform
> > > > > > > > > > [   18.288190] pci 0000:02:00.1: no hotplug settings from platform
> > > > > > > > > > [   18.288195] pcieport 0000:00:07.0: no hotplug settings from platform
> > > > > > > > > > [   18.288209] pci 0000:03:00.0: no hotplug settings from platform
> > > > > > > > > > [   18.288224] pci 0000:03:00.1: no hotplug settings from platform
> > > > > > > > > > [   18.288228] pci 0000:00:14.0: no hotplug settings from platform
> > > > > > > > > > [   18.288233] pci 0000:00:14.1: no hotplug settings from platform
> > > > > > > > > > [   18.288237] pci 0000:00:14.2: no hotplug settings from platform
> > > > > > > > > > [   18.288242] pci 0000:00:16.0: no hotplug settings from platform
> > > > > > > > > > [   18.288247] pci 0000:00:16.1: no hotplug settings from platform
> > > > > > > > > > [   18.288251] pci 0000:00:16.2: no hotplug settings from platform
> > > > > > > > > > [   18.288256] pci 0000:00:16.3: no hotplug settings from platform
> > > > > > > > > > [   18.288260] pci 0000:00:16.4: no hotplug settings from platform
> > > > > > > > > > [   18.288265] pci 0000:00:16.5: no hotplug settings from platform
> > > > > > > > > > [   18.288269] pci 0000:00:16.6: no hotplug settings from platform
> > > > > > > > > > [   18.288274] pci 0000:00:16.7: no hotplug settings from platform
> > > > > > > > > > [   18.288278] pci 0000:00:1a.0: no hotplug settings from platform
> > > > > > > > > > [   18.288279] pci 0000:00:1a.0: using default PCI settings
> > > > > > > > > > [   18.288292] pci 0000:00:1a.1: no hotplug settings from platform
> > > > > > > > > > [   18.288293] pci 0000:00:1a.1: using default PCI settings
> > > > > > > > > > [   18.288307] ehci-pci 0000:00:1a.7: no hotplug settings from platform
> > > > > > > > > > [   18.288308] ehci-pci 0000:00:1a.7: using default PCI settings
> > > > > > > > > > [   18.288322] pci 0000:00:1b.0: no hotplug settings from platform
> > > > > > > > > > [   18.288327] pcieport 0000:00:1c.0: no hotplug settings from platform
> > > > > > > > > > [   18.288332] pcieport 0000:00:1c.4: no hotplug settings from platform
> > > > > > > > > > [   18.288344] pci 0000:05:00.0: no hotplug settings from platform
> > > > > > > > > > [   18.288349] pci 0000:00:1d.0: no hotplug settings from platform
> > > > > > > > > > [   18.288350] pci 0000:00:1d.0: using default PCI settings
> > > > > > > > > > [   18.288360] pci 0000:00:1d.1: no hotplug settings from platform
> > > > > > > > > > [   18.288361] pci 0000:00:1d.1: using default PCI settings
> > > > > > > > > > [   18.288374] pci 0000:00:1d.2: no hotplug settings from platform
> > > > > > > > > > [   18.288374] pci 0000:00:1d.2: using default PCI settings
> > > > > > > > > > [   18.288387] pci 0000:00:1d.3: no hotplug settings from platform
> > > > > > > > > > [   18.288387] pci 0000:00:1d.3: using default PCI settings
> > > > > > > > > > 
> > > > > > > > > > The boot is noticeably slower.  What's going to happen on systems that
> > > > > > > > > > actually have a significant I/O topology vs my little workstation?
> > > > > > > > 
> > > > > > > > That depends on how many bus check/device check events they generate on boot.
> > > > > > > > 
> > > > > > > > My test machines don't generate them during boot at all (even the one with
> > > > > > > > a Thunderbolt connector), so I don't see the messages in question during boot
> > > > > > > > on any of them.  Mika doesn't see them either I suppose, or he would have told
> > > > > > > > me about that before.
> > > > > > > > 
> > > > > > > > And let's just make it clear that it is not usual or even OK to generate bus
> > > > > > > > checks or device checks during boot like this.  And since the changes in
> > > > > > > > question have been in linux-next since right after the 3.11 merge window, I
> > > > > > > > think that someone would have complained already had that been a common issue.
> > > > > > > > 
> > > > > > > > Of course, we need to deal with that somehow nevertheless. :-)
> > > > > > > > 
> > > > > > > > > Just to give you an idea:
> > > > > > > > > 
> > > > > > > > > CONFIG_HOTPLUG_PCI_ACPI=y
> > > > > > > > > 
> > > > > > > > > $ dmesg | wc
> > > > > > > > >   5697  49935 384368
> > > > > > > > > 
> > > > > > > > > $ dmesg | tail --lines=1
> > > > > > > > > [   53.137123] Ebtables v2.0 registered
> > > > > > > > > 
> > > > > > > > > -- vs --
> > > > > > > > > 
> > > > > > > > > # CONFIG_HOTPLUG_PCI_ACPI is not set
> > > > > > > > > 
> > > > > > > > > $ dmesg | wc
> > > > > > > > >  1053  9176 71652
> > > > > > > > > 
> > > > > > > > > $dmesg | tail --lines=1
> > > > > > > > > [   28.917220] Ebtables v2.0 registered
> > > > > > > > > 
> > > > > > > > > So it spews out 5x more output with acpiphp enabled and takes and extra
> > > > > > > > > 24s to boot (nearly 2x).  Not good.
> > > > > > > > 
> > > > > > > > The "no hotplug settings from platform" message is from pci_configure_slot().
> > > > > > > > I think the messages you're seeing are from the call to it in
> > > > > > > > acpiphp_set_hpp_values() which is called by enable_slot().
> > > > > > > > 
> > > > > > > > There, I think, we can simply check the return value of pci_scan_slot() and
> > > > > > > > if that is 0 (no new devices), we can just skip everything under the call to
> > > > > > > > __pci_bus_assign_resources().
> > > > > > > > 
> > > > > > > > However, we can't skip the scanning of bridges, if any, because there may be
> > > > > > > > new devices below them and I guess that's what takes so much time on your
> > > > > > > > machine.
> > > > > > > 
> > > > > > > OK, one piece is missing.  We may need to evaluate _OSC after handling each
> > > > > > > event to let the platform know the status.
> > > > > > > 
> > > > > > > Can you please check if the appended patch makes any difference (with the
> > > > > > > previous fix applied, of course)?
> > > > > > > 
> > > > > > > If fact, it is two patches combined.  One of them optimizes enable_slot()
> > > > > > > slightly and the other adds the missing _OSC evaluation.
> > > > > > 
> > > > > > Better, still double the output:
> > > > > > 
> > > > > > $ dmesg | wc
> > > > > >    2169   19047  152710
> > > > > 
> > > > > I see.
> > > > > 
> > > > > What about the timing?
> > > > 
> > > > ~40s below vs ~29s for acpiphp config'd out above.
> > > 
> > > Well, that's better than before.
> > > 
> > > I'll prepare "official" patches with the last changes then too.
> > 
> > The patches follow as [1/2] and [2/2].  The change in enable_slot() is
> > literally the same, but the _OST patch is somewhat different, although the
> > changes mostly affect the eject code path and the notifies that we don't
> > actually handle, so they should not matter on your machine.
> 
> Tested-by: Alex Williamson <alex.williamson@redhat.com>

Thanks!


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

* [PATCH] ACPI / hotplug / PCI: Avoid parent bus rescans on spurious device checks
  2013-09-06 15:34                                       ` Alex Williamson
@ 2013-09-07 22:16                                         ` Rafael J. Wysocki
  2013-09-09 16:32                                           ` Alex Williamson
  0 siblings, 1 reply; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-09-07 22:16 UTC (permalink / raw)
  To: Alex Williamson, ACPI Devel Maling List
  Cc: Bjorn Helgaas, LKML, Linux PCI, Yinghai Lu, Jiang Liu,
	Mika Westerberg, Kirill A. Shutemov

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

In the current ACPIPHP notify handler we always go directly for a
rescan of the parent bus if we get a device check notification for
a device that is not a bridge.  However, this obviously is
overzealous if nothing really changes, because this way we may rescan
the whole PCI hierarchy pretty much in vain.

That happens on Alex Williamson's machine whose ACPI tables contain
device objects that are supposed to coresspond to PCIe root ports,
but those ports aren't physically present (or at least they aren't
visible in the PCI config space to us).  The BIOS generates multiple
device check notifies for those objects during boot and for each of
them we go straight for the parent bus rescan, but the parent bus is
the root bus in this particular case.  In consequence, we rescan the
whole PCI bus from the top several times in a row, which is
completely unnecessary, increases boot time by 50% (after previous
fixes) and generates excess dmesg output from the PCI subsystem.

Fix the problem by checking if we can find anything new in the
slot corresponding to the device we've got a device check notify
for and doing nothig if that's not the case.

The spec (ACPI 5.0, Section 5.6.6) appears to mandate this behavior,
as it says:

  Device Check. Used to notify OSPM that the device either appeared
  or disappeared. If the device has appeared, OSPM will re-enumerate
  from the parent. If the device has disappeared, OSPM will
  invalidate the state of the device. OSPM may optimize out
  re-enumeration.

Therefore, according to the spec, we are free to do nothing if
nothing changes.

References: https://bugzilla.kernel.org/show_bug.cgi?id=60865
Reported-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---

On top of linux-pm.git/linux-next.

Thanks,
Rafael

---
 drivers/pci/hotplug/acpiphp_glue.c |   32 +++++++++++++++++++++++++-------
 1 file changed, 25 insertions(+), 7 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
@@ -528,6 +528,16 @@ static void check_hotplug_bridge(struct
 	}
 }
 
+static int acpiphp_rescan_slot(struct acpiphp_slot *slot)
+{
+	struct acpiphp_func *func;
+
+	list_for_each_entry(func, &slot->funcs, sibling)
+		acpiphp_bus_add(func_to_handle(func));
+
+	return pci_scan_slot(slot->bus, PCI_DEVFN(slot->device, 0));
+}
+
 /**
  * enable_slot - enable, configure a slot
  * @slot: slot to be enabled
@@ -544,10 +554,7 @@ static void __ref enable_slot(struct acp
 	LIST_HEAD(add_list);
 	int nr_found;
 
-	list_for_each_entry(func, &slot->funcs, sibling)
-		acpiphp_bus_add(func_to_handle(func));
-
-	nr_found = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
+	nr_found = acpiphp_rescan_slot(slot);
 	max = acpiphp_max_busnr(bus);
 	for (pass = 0; pass < 2; pass++) {
 		list_for_each_entry(dev, &bus->devices, bus_list) {
@@ -840,11 +847,22 @@ static void hotplug_event(acpi_handle ha
 	case ACPI_NOTIFY_DEVICE_CHECK:
 		/* device check */
 		dbg("%s: Device check notify on %s\n", __func__, objname);
-		if (bridge)
+		if (bridge) {
 			acpiphp_check_bridge(bridge);
-		else
-			acpiphp_check_bridge(func->parent);
+		} else {
+			struct acpiphp_slot *slot = func->slot;
+			int ret;
 
+			/*
+			 * Check if anything has changed in the slot and rescan
+			 * from the parent if that's the case.
+			 */
+			mutex_lock(&slot->crit_sect);
+			ret = acpiphp_rescan_slot(slot);
+			mutex_unlock(&slot->crit_sect);
+			if (ret)
+				acpiphp_check_bridge(func->parent);
+		}
 		break;
 
 	case ACPI_NOTIFY_EJECT_REQUEST:


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

* Re: [PATCH] ACPI / hotplug / PCI: Avoid parent bus rescans on spurious device checks
  2013-09-07 22:16                                         ` [PATCH] ACPI / hotplug / PCI: Avoid parent bus rescans on spurious device checks Rafael J. Wysocki
@ 2013-09-09 16:32                                           ` Alex Williamson
  2013-09-09 20:02                                             ` Rafael J. Wysocki
  0 siblings, 1 reply; 135+ messages in thread
From: Alex Williamson @ 2013-09-09 16:32 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Sun, 2013-09-08 at 00:16 +0200, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> 
> In the current ACPIPHP notify handler we always go directly for a
> rescan of the parent bus if we get a device check notification for
> a device that is not a bridge.  However, this obviously is
> overzealous if nothing really changes, because this way we may rescan
> the whole PCI hierarchy pretty much in vain.
> 
> That happens on Alex Williamson's machine whose ACPI tables contain
> device objects that are supposed to coresspond to PCIe root ports,
> but those ports aren't physically present (or at least they aren't
> visible in the PCI config space to us).  The BIOS generates multiple
> device check notifies for those objects during boot and for each of
> them we go straight for the parent bus rescan, but the parent bus is
> the root bus in this particular case.  In consequence, we rescan the
> whole PCI bus from the top several times in a row, which is
> completely unnecessary, increases boot time by 50% (after previous
> fixes) and generates excess dmesg output from the PCI subsystem.
> 
> Fix the problem by checking if we can find anything new in the
> slot corresponding to the device we've got a device check notify
> for and doing nothig if that's not the case.
> 
> The spec (ACPI 5.0, Section 5.6.6) appears to mandate this behavior,
> as it says:
> 
>   Device Check. Used to notify OSPM that the device either appeared
>   or disappeared. If the device has appeared, OSPM will re-enumerate
>   from the parent. If the device has disappeared, OSPM will
>   invalidate the state of the device. OSPM may optimize out
>   re-enumeration.
> 
> Therefore, according to the spec, we are free to do nothing if
> nothing changes.
> 
> References: https://bugzilla.kernel.org/show_bug.cgi?id=60865
> Reported-by: Alex Williamson <alex.williamson@redhat.com>
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> ---

Works for me.  Thanks!

Tested-by: Alex Williamson <alex.williamson@redhat.com>

> On top of linux-pm.git/linux-next.
> 
> Thanks,
> Rafael
> 
> ---
>  drivers/pci/hotplug/acpiphp_glue.c |   32 +++++++++++++++++++++++++-------
>  1 file changed, 25 insertions(+), 7 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
> @@ -528,6 +528,16 @@ static void check_hotplug_bridge(struct
>  	}
>  }
>  
> +static int acpiphp_rescan_slot(struct acpiphp_slot *slot)
> +{
> +	struct acpiphp_func *func;
> +
> +	list_for_each_entry(func, &slot->funcs, sibling)
> +		acpiphp_bus_add(func_to_handle(func));
> +
> +	return pci_scan_slot(slot->bus, PCI_DEVFN(slot->device, 0));
> +}
> +
>  /**
>   * enable_slot - enable, configure a slot
>   * @slot: slot to be enabled
> @@ -544,10 +554,7 @@ static void __ref enable_slot(struct acp
>  	LIST_HEAD(add_list);
>  	int nr_found;
>  
> -	list_for_each_entry(func, &slot->funcs, sibling)
> -		acpiphp_bus_add(func_to_handle(func));
> -
> -	nr_found = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
> +	nr_found = acpiphp_rescan_slot(slot);
>  	max = acpiphp_max_busnr(bus);
>  	for (pass = 0; pass < 2; pass++) {
>  		list_for_each_entry(dev, &bus->devices, bus_list) {
> @@ -840,11 +847,22 @@ static void hotplug_event(acpi_handle ha
>  	case ACPI_NOTIFY_DEVICE_CHECK:
>  		/* device check */
>  		dbg("%s: Device check notify on %s\n", __func__, objname);
> -		if (bridge)
> +		if (bridge) {
>  			acpiphp_check_bridge(bridge);
> -		else
> -			acpiphp_check_bridge(func->parent);
> +		} else {
> +			struct acpiphp_slot *slot = func->slot;
> +			int ret;
>  
> +			/*
> +			 * Check if anything has changed in the slot and rescan
> +			 * from the parent if that's the case.
> +			 */
> +			mutex_lock(&slot->crit_sect);
> +			ret = acpiphp_rescan_slot(slot);
> +			mutex_unlock(&slot->crit_sect);
> +			if (ret)
> +				acpiphp_check_bridge(func->parent);
> +		}
>  		break;
>  
>  	case ACPI_NOTIFY_EJECT_REQUEST:



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

* Re: [PATCH] ACPI / hotplug / PCI: Avoid parent bus rescans on spurious device checks
  2013-09-09 16:32                                           ` Alex Williamson
@ 2013-09-09 20:02                                             ` Rafael J. Wysocki
  0 siblings, 0 replies; 135+ messages in thread
From: Rafael J. Wysocki @ 2013-09-09 20:02 UTC (permalink / raw)
  To: Alex Williamson
  Cc: ACPI Devel Maling List, Bjorn Helgaas, LKML, Linux PCI,
	Yinghai Lu, Jiang Liu, Mika Westerberg, Kirill A. Shutemov

On Monday, September 09, 2013 10:32:57 AM Alex Williamson wrote:
> On Sun, 2013-09-08 at 00:16 +0200, Rafael J. Wysocki wrote:
> > From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > 
> > In the current ACPIPHP notify handler we always go directly for a
> > rescan of the parent bus if we get a device check notification for
> > a device that is not a bridge.  However, this obviously is
> > overzealous if nothing really changes, because this way we may rescan
> > the whole PCI hierarchy pretty much in vain.
> > 
> > That happens on Alex Williamson's machine whose ACPI tables contain
> > device objects that are supposed to coresspond to PCIe root ports,
> > but those ports aren't physically present (or at least they aren't
> > visible in the PCI config space to us).  The BIOS generates multiple
> > device check notifies for those objects during boot and for each of
> > them we go straight for the parent bus rescan, but the parent bus is
> > the root bus in this particular case.  In consequence, we rescan the
> > whole PCI bus from the top several times in a row, which is
> > completely unnecessary, increases boot time by 50% (after previous
> > fixes) and generates excess dmesg output from the PCI subsystem.
> > 
> > Fix the problem by checking if we can find anything new in the
> > slot corresponding to the device we've got a device check notify
> > for and doing nothig if that's not the case.
> > 
> > The spec (ACPI 5.0, Section 5.6.6) appears to mandate this behavior,
> > as it says:
> > 
> >   Device Check. Used to notify OSPM that the device either appeared
> >   or disappeared. If the device has appeared, OSPM will re-enumerate
> >   from the parent. If the device has disappeared, OSPM will
> >   invalidate the state of the device. OSPM may optimize out
> >   re-enumeration.
> > 
> > Therefore, according to the spec, we are free to do nothing if
> > nothing changes.
> > 
> > References: https://bugzilla.kernel.org/show_bug.cgi?id=60865
> > Reported-by: Alex Williamson <alex.williamson@redhat.com>
> > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> > ---
> 
> Works for me.  Thanks!
> 
> Tested-by: Alex Williamson <alex.williamson@redhat.com>

Great, thanks for testing.


> > ---
> >  drivers/pci/hotplug/acpiphp_glue.c |   32 +++++++++++++++++++++++++-------
> >  1 file changed, 25 insertions(+), 7 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
> > @@ -528,6 +528,16 @@ static void check_hotplug_bridge(struct
> >  	}
> >  }
> >  
> > +static int acpiphp_rescan_slot(struct acpiphp_slot *slot)
> > +{
> > +	struct acpiphp_func *func;
> > +
> > +	list_for_each_entry(func, &slot->funcs, sibling)
> > +		acpiphp_bus_add(func_to_handle(func));
> > +
> > +	return pci_scan_slot(slot->bus, PCI_DEVFN(slot->device, 0));
> > +}
> > +
> >  /**
> >   * enable_slot - enable, configure a slot
> >   * @slot: slot to be enabled
> > @@ -544,10 +554,7 @@ static void __ref enable_slot(struct acp
> >  	LIST_HEAD(add_list);
> >  	int nr_found;
> >  
> > -	list_for_each_entry(func, &slot->funcs, sibling)
> > -		acpiphp_bus_add(func_to_handle(func));
> > -
> > -	nr_found = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
> > +	nr_found = acpiphp_rescan_slot(slot);
> >  	max = acpiphp_max_busnr(bus);
> >  	for (pass = 0; pass < 2; pass++) {
> >  		list_for_each_entry(dev, &bus->devices, bus_list) {
> > @@ -840,11 +847,22 @@ static void hotplug_event(acpi_handle ha
> >  	case ACPI_NOTIFY_DEVICE_CHECK:
> >  		/* device check */
> >  		dbg("%s: Device check notify on %s\n", __func__, objname);
> > -		if (bridge)
> > +		if (bridge) {
> >  			acpiphp_check_bridge(bridge);
> > -		else
> > -			acpiphp_check_bridge(func->parent);
> > +		} else {
> > +			struct acpiphp_slot *slot = func->slot;
> > +			int ret;
> >  
> > +			/*
> > +			 * Check if anything has changed in the slot and rescan
> > +			 * from the parent if that's the case.
> > +			 */
> > +			mutex_lock(&slot->crit_sect);
> > +			ret = acpiphp_rescan_slot(slot);
> > +			mutex_unlock(&slot->crit_sect);
> > +			if (ret)
> > +				acpiphp_check_bridge(func->parent);
> > +		}
> >  		break;
> >  
> >  	case ACPI_NOTIFY_EJECT_REQUEST:
> 
> 
-- 
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

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

end of thread, other threads:[~2013-09-09 19:51 UTC | newest]

Thread overview: 135+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-07-09  0:01 [RFC][PATCH 0/8] ACPI / hotplug / PCI: Consolidation of handling notifications (in progress) Rafael J. Wysocki
2013-07-09  0:14 ` [RFC][PATCH 1/8] ACPI / PCI: Make bus registration and unregistration symmetric Rafael J. Wysocki
2013-07-09  0:16 ` [RFC][PATCH 2/8] ACPI / hotplug / PCI: Consolidate acpiphp_enumerate_slots() Rafael J. Wysocki
2013-07-09  0:17 ` [RFC][PATCH 3/8] ACPI / hotplug / PCI: Always return success after adding a function Rafael J. Wysocki
2013-07-09  0:18 ` [RFC][PATCH 4/8] ACPI / hotplug / PCI: Hotplug context objects for bridges and functions Rafael J. Wysocki
2013-07-09  9:23   ` Mika Westerberg
2013-07-09 23:54     ` [Update][RFC][PATCH " Rafael J. Wysocki
2013-07-09  0:19 ` [RFC][PATCH 5/8] ACPI / hotplug / PCI: Unified notify handler for hotplug events Rafael J. Wysocki
2013-07-09  9:30   ` Mika Westerberg
2013-07-09 23:49     ` Rafael J. Wysocki
2013-07-09  0:20 ` [RFC][PATCH 6/8] ACPI / hotplug / PCI: Drop acpiphp_handle_to_bridge() Rafael J. Wysocki
2013-07-09  9:37   ` Mika Westerberg
2013-07-09 23:46     ` Rafael J. Wysocki
2013-07-09  0:21 ` [RFC][PATCH 7/8] ACPI / hotplug / PCI: Pass hotplug context object to event handlers Rafael J. Wysocki
2013-07-09  0:22 ` [RFC][PATCH 8/8] ACPI / hotplug / PCI: Merge hotplug event handling functions Rafael J. Wysocki
2013-07-11 23:34 ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Rafael J. Wysocki
2013-07-11 23:36   ` [RFC][PATCH 1/30] ACPI / PCI: Make bus registration and unregistration symmetric Rafael J. Wysocki
2013-07-11 23:37   ` [RFC][PATCH 2/30] ACPI / hotplug / PCI: Consolidate acpiphp_enumerate_slots() Rafael J. Wysocki
2013-07-11 23:38   ` [RFC][PATCH 3/30] ACPI / hotplug / PCI: Always return success after adding a function Rafael J. Wysocki
2013-07-11 23:39   ` [RFC][PATCH 4/30] ACPI / hotplug / PCI: Hotplug context objects for bridges and functions Rafael J. Wysocki
2013-07-11 23:40   ` [RFC][PATCH 5/30] ACPI / hotplug / PCI: Unified notify handler for hotplug events Rafael J. Wysocki
2013-07-11 23:44   ` [RFC][PATCH 6/30] ACPI / hotplug / PCI: Rework acpiphp_handle_to_bridge() Rafael J. Wysocki
2013-07-11 23:45   ` [RFC][PATCH 7/30] ACPI / hotplug / PCI: Pass hotplug context objects to event handlers Rafael J. Wysocki
2013-07-11 23:47   ` [RFC][PATCH 8/30] ACPI / hotplug / PCI: Merge hotplug event handling functions Rafael J. Wysocki
2013-07-11 23:48   ` [RFC][PATCH 9/30] ACPI / hotplug / PCI: Drop func field from struct acpiphp_bridge Rafael J. Wysocki
2013-07-11 23:49   ` [RFC][PATCH 10/30] ACPI / hotplug / PCI: Refactor slot allocation code in register_slot() Rafael J. Wysocki
2013-07-11 23:50   ` [RFC][PATCH 11/30] ACPI / hotplug / PCI: Register all devices under the given bridge Rafael J. Wysocki
2013-07-12 11:54     ` Mika Westerberg
2013-07-12 13:01       ` Mika Westerberg
2013-07-11 23:51   ` [RFC][PATCH 12/30] ACPI / hotplug / PCI: Drop sun field from struct acpiphp_slot Rafael J. Wysocki
2013-07-11 23:52   ` [RFC][PATCH 13/30] ACPI / hotplug / PCI: Use common slot count variable in register_slot() Rafael J. Wysocki
2013-07-11 23:54   ` [RFC][PATCH 14/30] ACPI / hotplug / PCI: Drop flags field from struct acpiphp_bridge Rafael J. Wysocki
2013-07-11 23:54   ` [RFC][PATCH 15/30] ACPI / hotplug / PCI: Embed function struct into struct acpiphp_context Rafael J. Wysocki
2013-07-11 23:55   ` [RFC][PATCH 16/30] ACPI / hotplug / PCI: Drop handle field from struct acpiphp_func Rafael J. Wysocki
2013-07-11 23:56   ` [RFC][PATCH 17/30] ACPI / hotplug / PCI: Drop handle field from struct acpiphp_bridge Rafael J. Wysocki
2013-07-11 23:56   ` [RFC][PATCH 18/30] ACPI / hotplug / PCI: Store parent in functions and bus in slots Rafael J. Wysocki
2013-07-11 23:57   ` [RFC][PATCH 19/30] ACPI / hotplug / PCI: Rework namespace scanning and trimming routines Rafael J. Wysocki
2013-07-11 23:58   ` [RFC][PATCH 20/30] ACPI / hotplug / PCI: Drop redundant checks from check_hotplug_bridge() Rafael J. Wysocki
2013-07-11 23:59   ` [RFC][PATCH 21/30] ACPI / hotplug / PCI: Consolidate slot disabling and ejecting Rafael J. Wysocki
2013-07-12  0:00   ` [RFC][PATCH 22/30] ACPI / hotplug / PCI: Do not queue up event handling work items in vain Rafael J. Wysocki
2013-07-12  0:01   ` [RFC][PATCH 23/30] ACPI / hotplug / PCI: Do not exectute _PS0 and _PS3 directly Rafael J. Wysocki
2013-07-12 13:05     ` Mika Westerberg
2013-07-12 21:09       ` Rafael J. Wysocki
2013-07-12  0:02   ` [RFC][PATCH 24/30] ACPI / hotplug / PCI: Do not check SLOT_ENABLED in enable_device() Rafael J. Wysocki
2013-07-12  0:03   ` [RFC][PATCH 25/30] ACPI / hotplug / PCI: Allow slots without new devices to be rescanned Rafael J. Wysocki
2013-07-12  0:04   ` [RFC][PATCH 26/30] ACPI / hotplug / PCI: Check for new devices on enabled slots Rafael J. Wysocki
2013-07-12  0:05   ` [RFC][PATCH 27/30] ACPI / hotplug / PCI: Get rid of unused constants in acpiphp.h Rafael J. Wysocki
2013-07-12  0:06   ` [RFC][PATCH 28/30] ACPI / hotplug / PCI: Sanitize acpiphp_get_(latch)|(adapter)_status() Rafael J. Wysocki
2013-07-12  0:07   ` [RFC][PATCH 29/30] ACPI / hotplug / PCI: Redefine enable_device() and disable_device() Rafael J. Wysocki
2013-07-12  0:07   ` [RFC][PATCH 30/30] ACPI / hotplug / PCI: Clean up bridge_mutex usage Rafael J. Wysocki
2013-07-12 13:18   ` [RFC][PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Mika Westerberg
2013-07-12 21:04     ` Rafael J. Wysocki
2013-07-17 23:05   ` [PATCH " Rafael J. Wysocki
2013-07-17 23:15     ` [PATCH 1/30] ACPI / PCI: Make bus registration and unregistration symmetric Rafael J. Wysocki
2013-07-18  1:00       ` Yinghai Lu
2013-07-17 23:16     ` [PATCH 2/30] ACPI / hotplug / PCI: Consolidate acpiphp_enumerate_slots() Rafael J. Wysocki
2013-07-18  1:40       ` Yinghai Lu
2013-07-18 19:09         ` Rafael J. Wysocki
2013-07-17 23:17     ` [PATCH 3/30] ACPI / hotplug / PCI: Always return success after adding a function Rafael J. Wysocki
2013-07-17 23:17     ` [PATCH 4/30] ACPI / hotplug / PCI: Hotplug context objects for bridges and functions Rafael J. Wysocki
2013-07-18  2:00       ` Yinghai Lu
2013-07-18 19:04         ` Rafael J. Wysocki
2013-07-18 20:06           ` Rafael J. Wysocki
2013-07-17 23:18     ` [PATCH 5/30] ACPI / hotplug / PCI: Unified notify handler for hotplug events Rafael J. Wysocki
2013-07-18  2:07       ` Yinghai Lu
2013-07-18 18:59         ` Rafael J. Wysocki
2013-07-17 23:19     ` [PATCH 6/30] ACPI / hotplug / PCI: Rework acpiphp_handle_to_bridge() Rafael J. Wysocki
2013-07-17 23:19     ` [PATCH 7/30] ACPI / hotplug / PCI: Pass hotplug context objects to event handlers Rafael J. Wysocki
2013-07-17 23:20     ` [PATCH 8/30] ACPI / hotplug / PCI: Merge hotplug event handling functions Rafael J. Wysocki
2013-07-17 23:21     ` [PATCH 9/30] ACPI / hotplug / PCI: Drop func field from struct acpiphp_bridge Rafael J. Wysocki
2013-07-17 23:22     ` [PATCH 10/30] ACPI / hotplug / PCI: Refactor slot allocation code in register_slot() Rafael J. Wysocki
2013-07-17 23:22     ` [PATCH 11/30] ACPI / hotplug / PCI: Register all devices under the given bridge Rafael J. Wysocki
2013-07-17 23:23     ` [PATCH 12/30] ACPI / hotplug / PCI: Drop sun field from struct acpiphp_slot Rafael J. Wysocki
2013-07-17 23:24     ` [PATCH 13/30] ACPI / hotplug / PCI: Drop flags field from struct acpiphp_bridge Rafael J. Wysocki
2013-07-17 23:24     ` [PATCH 14/30] ACPI / hotplug / PCI: Embed function struct into struct acpiphp_context Rafael J. Wysocki
2013-07-17 23:25     ` [PATCH 15/30] ACPI / hotplug / PCI: Drop handle field from struct acpiphp_func Rafael J. Wysocki
2013-07-17 23:26     ` [PATCH 16/30] ACPI / hotplug / PCI: Drop handle field from struct acpiphp_bridge Rafael J. Wysocki
2013-07-17 23:26     ` [PATCH 17/30] ACPI / hotplug / PCI: Store parent in functions and bus in slots Rafael J. Wysocki
2013-07-17 23:27     ` [PATCH 18/30] ACPI / hotplug / PCI: Rework namespace scanning and trimming routines Rafael J. Wysocki
2013-07-17 23:27     ` [PATCH 19/30] ACPI / hotplug / PCI: Drop redundant checks from check_hotplug_bridge() Rafael J. Wysocki
2013-07-17 23:28     ` [PATCH 20/30] ACPI / hotplug / PCI: Consolidate slot disabling and ejecting Rafael J. Wysocki
2013-07-17 23:29     ` [PATCH 21/30] ACPI / hotplug / PCI: Do not queue up event handling work items in vain Rafael J. Wysocki
2013-07-17 23:30     ` [PATCH 22/30] ACPI / hotplug / PCI: Do not exectute _PS0 and _PS3 directly Rafael J. Wysocki
2013-07-17 23:31     ` [PATCH 23/30] ACPI / hotplug / PCI: Do not check SLOT_ENABLED in enable_device() Rafael J. Wysocki
2013-07-17 23:31     ` [PATCH 24/30] ACPI / hotplug / PCI: Allow slots without new devices to be rescanned Rafael J. Wysocki
2013-07-17 23:32     ` [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots Rafael J. Wysocki
2013-09-04 20:36       ` Alex Williamson
2013-09-04 22:54         ` Rafael J. Wysocki
2013-09-04 23:12           ` Alex Williamson
2013-09-04 23:35             ` Rafael J. Wysocki
2013-09-05  3:37               ` Alex Williamson
2013-09-05  4:06                 ` Alex Williamson
2013-09-05 11:54                   ` Rafael J. Wysocki
2013-09-05 13:19                     ` Alex Williamson
2013-09-05 14:21                       ` Alex Williamson
2013-09-05 19:44                         ` Excess dmesg output from ACPIPHP on boot (was: Re: [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots) Rafael J. Wysocki
2013-09-05 21:39                           ` Rafael J. Wysocki
2013-09-05 21:45                             ` Rafael J. Wysocki
2013-09-05 22:17                             ` Alex Williamson
2013-09-05 22:40                               ` Rafael J. Wysocki
2013-09-05 23:08                                 ` Alex Williamson
2013-09-05 23:36                                   ` Rafael J. Wysocki
2013-09-05 23:31                                     ` Alex Williamson
2013-09-05 23:48                                       ` Rafael J. Wysocki
2013-09-06 12:19                                     ` Bjorn Helgaas
2013-09-06 12:40                                       ` Rafael J. Wysocki
2013-09-06 15:34                                       ` Alex Williamson
2013-09-07 22:16                                         ` [PATCH] ACPI / hotplug / PCI: Avoid parent bus rescans on spurious device checks Rafael J. Wysocki
2013-09-09 16:32                                           ` Alex Williamson
2013-09-09 20:02                                             ` Rafael J. Wysocki
2013-09-06 13:42                                     ` [PATCH 0/2] Re: Excess dmesg output from ACPIPHP on boot Rafael J. Wysocki
2013-09-06 13:43                                       ` [PATCH 1/2] ACPI / hotplug / PCI: Avoid doing too much for spurious notifies Rafael J. Wysocki
2013-09-06 15:46                                         ` Yinghai Lu
2013-09-06 23:45                                           ` Rafael J. Wysocki
2013-09-06 13:46                                       ` [PATCH 2/2] ACPI / hotplug / PCI: Use _OST to notify firmware about notify status Rafael J. Wysocki
2013-09-06 15:36                                       ` [PATCH 0/2] Re: Excess dmesg output from ACPIPHP on boot Alex Williamson
2013-09-06 23:46                                         ` Rafael J. Wysocki
2013-09-05  6:17                 ` [PATCH 25/30] ACPI / hotplug / PCI: Check for new devices on enabled slots Lan Tianyu
2013-09-05 11:57                   ` Rafael J. Wysocki
2013-09-05 13:11                     ` Lan Tianyu
2013-09-05 21:43                       ` Rafael J. Wysocki
2013-07-17 23:33     ` [PATCH 26/30] ACPI / hotplug / PCI: Get rid of unused constants in acpiphp.h Rafael J. Wysocki
2013-07-17 23:34     ` [PATCH 27/30] ACPI / hotplug / PCI: Sanitize acpiphp_get_(latch)|(adapter)_status() Rafael J. Wysocki
2013-07-17 23:35     ` [PATCH 28/30] ACPI / hotplug / PCI: Redefine enable_device() and disable_device() Rafael J. Wysocki
2013-07-17 23:35     ` [PATCH 29/30] ACPI / hotplug / PCI: Clean up bridge_mutex usage Rafael J. Wysocki
2013-07-17 23:36     ` [PATCH 30/30] ACPI / hotplug / PCI: Get rid of check_sub_bridges() Rafael J. Wysocki
2013-07-23  6:49     ` [PATCH 0/30] ACPI / hotplug / PCI: Major rework + Thunderbolt workarounds Yinghai Lu
2013-07-23 21:39       ` Rafael J. Wysocki
2013-07-24  2:20         ` Yinghai Lu
2013-07-24 12:22           ` Rafael J. Wysocki
2013-07-24 12:58           ` Rafael J. Wysocki
2013-07-24 16:06             ` Bjorn Helgaas
2013-07-24 20:02               ` Rafael J. Wysocki
2013-07-25 13:25             ` Yinghai Lu
2013-07-25 19:57               ` Rafael J. Wysocki

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.