Re: [PATCH 2/3] ACPI / hotplug / PCI: Hotplug context objects for bridges and functions

2013-07-08 Thread Rafael J. Wysocki
On Monday, July 08, 2013 03:30:16 PM Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki 
> 
> When either a new hotplug brigde or a new hotplug function is added
> by the ACPI-based PCI hotplug (acpiphp) code, attach a context object
> to its ACPI handle to store hotplug-related information in it.  To
> start with, put the handle's bridge and function pointers into that
> object.  Count references to the context objects and drop them when
> they are not needed any more.
> 
> First of all, this makes it possible to find out if the given bridge
> has been registered as a function already in a much more
> straightforward way and acpiphp_bridge_handle_to_function() can be
> dropped (Yay!).
> 
> This also will allow some more simplifications to be made going
> forward.

Unfortunately, this one is buggy. ->

> Signed-off-by: Rafael J. Wysocki 
> ---
>  drivers/pci/hotplug/acpiphp.h  |   10 ++
>  drivers/pci/hotplug/acpiphp_glue.c |  149 
> ++---
>  2 files changed, 116 insertions(+), 43 deletions(-)
> 
> Index: linux-pm/drivers/pci/hotplug/acpiphp.h
> ===
> --- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
> +++ linux-pm/drivers/pci/hotplug/acpiphp.h
> @@ -49,6 +49,7 @@
>  #define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## 
> arg)
>  #define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## 
> arg)
>  
> +struct acpiphp_context;
>  struct acpiphp_bridge;
>  struct acpiphp_slot;
>  
> @@ -77,6 +78,7 @@ struct acpiphp_bridge {
>   struct kref ref;
>   acpi_handle handle;
>  
> + struct acpiphp_context *context;
>   /* Ejectable PCI-to-PCI bridge (PCI bridge and PCI function) */
>   struct acpiphp_func *func;
>  
> @@ -119,6 +121,7 @@ struct acpiphp_slot {
>   * typically 8 objects per slot (i.e. for each PCI function)
>   */
>  struct acpiphp_func {
> + struct acpiphp_context *context;
>   struct acpiphp_slot *slot;  /* parent */
>  
>   struct list_head sibling;
> @@ -129,6 +132,13 @@ struct acpiphp_func {
>   u32 flags;  /* see below */
>  };
>  
> +struct acpiphp_context {
> + struct kref kref;
> + acpi_handle handle;
> + struct acpiphp_func *func;
> + struct acpiphp_bridge *bridge;
> +};
> +
>  /*
>   * struct acpiphp_attention_info - device specific attention registration
>   *
> Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c
> ===
> --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c
> +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c
> @@ -79,6 +79,61 @@ is_pci_dock_device(acpi_handle handle, u
>   }
>  }
>  
> +static void acpiphp_context_handler(acpi_handle handle, void *context)
> +{
> + /* Intentionally empty. */
> +}
> +
> +static struct acpiphp_context *acpiphp_init_context(acpi_handle handle)
> +{
> + struct acpiphp_context *context;
> + acpi_status status;
> +
> + context = kzalloc(sizeof(*context), GFP_KERNEL);
> + if (!context)
> + return NULL;
> +
> + context->handle = handle;
> + kref_init(>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, );
> + if (ACPI_SUCCESS(status)) {
> + context = data;
> + kref_get(>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(>kref, acpiphp_release_context);
> +}
> +
>  static inline void get_bridge(struct acpiphp_bridge *bridge)
>  {
>   kref_get(>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, >slots, node) {
>   list_for_each_entry_safe(func, tmp, >funcs, sibling) {
> + context = func->context;
> +   

Re: [PATCH 2/3] ACPI / hotplug / PCI: Hotplug context objects for bridges and functions

2013-07-08 Thread Rafael J. Wysocki
On Monday, July 08, 2013 03:30:16 PM Rafael J. Wysocki wrote:
 From: Rafael J. Wysocki rafael.j.wyso...@intel.com
 
 When either a new hotplug brigde or a new hotplug function is added
 by the ACPI-based PCI hotplug (acpiphp) code, attach a context object
 to its ACPI handle to store hotplug-related information in it.  To
 start with, put the handle's bridge and function pointers into that
 object.  Count references to the context objects and drop them when
 they are not needed any more.
 
 First of all, this makes it possible to find out if the given bridge
 has been registered as a function already in a much more
 straightforward way and acpiphp_bridge_handle_to_function() can be
 dropped (Yay!).
 
 This also will allow some more simplifications to be made going
 forward.

Unfortunately, this one is buggy. -

 Signed-off-by: Rafael J. Wysocki rafael.j.wyso...@intel.com
 ---
  drivers/pci/hotplug/acpiphp.h  |   10 ++
  drivers/pci/hotplug/acpiphp_glue.c |  149 
 ++---
  2 files changed, 116 insertions(+), 43 deletions(-)
 
 Index: linux-pm/drivers/pci/hotplug/acpiphp.h
 ===
 --- linux-pm.orig/drivers/pci/hotplug/acpiphp.h
 +++ linux-pm/drivers/pci/hotplug/acpiphp.h
 @@ -49,6 +49,7 @@
  #define info(format, arg...) printk(KERN_INFO %s:  format, MY_NAME , ## 
 arg)
  #define warn(format, arg...) printk(KERN_WARNING %s:  format, MY_NAME , ## 
 arg)
  
 +struct acpiphp_context;
  struct acpiphp_bridge;
  struct acpiphp_slot;
  
 @@ -77,6 +78,7 @@ struct acpiphp_bridge {
   struct kref ref;
   acpi_handle handle;
  
 + struct acpiphp_context *context;
   /* Ejectable PCI-to-PCI bridge (PCI bridge and PCI function) */
   struct acpiphp_func *func;
  
 @@ -119,6 +121,7 @@ struct acpiphp_slot {
   * typically 8 objects per slot (i.e. for each PCI function)
   */
  struct acpiphp_func {
 + struct acpiphp_context *context;
   struct acpiphp_slot *slot;  /* parent */
  
   struct list_head sibling;
 @@ -129,6 +132,13 @@ struct acpiphp_func {
   u32 flags;  /* see below */
  };
  
 +struct acpiphp_context {
 + struct kref kref;
 + acpi_handle handle;
 + struct acpiphp_func *func;
 + struct acpiphp_bridge *bridge;
 +};
 +
  /*
   * struct acpiphp_attention_info - device specific attention registration
   *
 Index: linux-pm/drivers/pci/hotplug/acpiphp_glue.c
 ===
 --- linux-pm.orig/drivers/pci/hotplug/acpiphp_glue.c
 +++ linux-pm/drivers/pci/hotplug/acpiphp_glue.c
 @@ -79,6 +79,61 @@ is_pci_dock_device(acpi_handle handle, u
   }
  }
  
 +static void acpiphp_context_handler(acpi_handle handle, void *context)
 +{
 + /* Intentionally empty. */
 +}
 +
 +static struct acpiphp_context *acpiphp_init_context(acpi_handle handle)
 +{
 + struct acpiphp_context *context;
 + acpi_status status;
 +
 + context = kzalloc(sizeof(*context), GFP_KERNEL);
 + if (!context)
 + return NULL;
 +
 + context-handle = handle;
 + kref_init(context-kref);
 + status = acpi_attach_data(handle, acpiphp_context_handler, context);
 + if (ACPI_FAILURE(status)) {
 + kfree(context);
 + return NULL;
 + }
 + return context;
 +}
 +
 +static struct acpiphp_context *acpiphp_get_context(acpi_handle handle)
 +{
 + struct acpiphp_context *context = NULL;
 + acpi_status status;
 + void *data;
 +
 + status = acpi_get_data(handle, acpiphp_context_handler, data);
 + if (ACPI_SUCCESS(status)) {
 + context = data;
 + kref_get(context-kref);
 + } else if (status == AE_NOT_FOUND) {
 + context = acpiphp_init_context(handle);
 + }
 + return context;
 +}
 +
 +static void acpiphp_release_context(struct kref *kref)
 +{
 + struct acpiphp_context *context;
 +
 + context = container_of(kref, struct acpiphp_context, kref);
 + WARN_ON(context-func || context-bridge);
 + acpi_detach_data(context-handle, acpiphp_context_handler);
 + kfree(context);
 +}
 +
 +static void acpiphp_put_context(struct acpiphp_context *context)
 +{
 + kref_put(context-kref, acpiphp_release_context);
 +}
 +
  static inline void get_bridge(struct acpiphp_bridge *bridge)
  {
   kref_get(bridge-ref);
 @@ -91,6 +146,7 @@ static inline void put_bridge(struct acp
  
  static void free_bridge(struct kref *kref)
  {
 + struct acpiphp_context *context;
   struct acpiphp_bridge *bridge;
   struct acpiphp_slot *slot, *next;
   struct acpiphp_func *func, *tmp;
 @@ -99,17 +155,24 @@ static void free_bridge(struct kref *kre
  
   list_for_each_entry_safe(slot, next, bridge-slots, node) {
   list_for_each_entry_safe(func, tmp, slot-funcs, sibling) {
 + context = func-context;
 + context-func = NULL;
   kfree(func);
 +