]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge branch 'acpi-pci-hotplug' into acpi-ost
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Fri, 21 Feb 2014 00:06:58 +0000 (01:06 +0100)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Fri, 21 Feb 2014 00:06:58 +0000 (01:06 +0100)
1  2 
drivers/acpi/scan.c
include/acpi/acpi_bus.h

diff --combined drivers/acpi/scan.c
index 62ec4ba7ecef8f5d07eebbeb0434c122d465bd5a,8bb48bfab1df17cf74fc361ad91703c7a5d3b940..3fc530a8d362b15dff064584de7bd40417143933
@@@ -41,6 -41,7 +41,7 @@@ static DEFINE_MUTEX(acpi_scan_lock)
  static LIST_HEAD(acpi_scan_handlers_list);
  DEFINE_MUTEX(acpi_device_lock);
  LIST_HEAD(acpi_wakeup_device_list);
+ static DEFINE_MUTEX(acpi_hp_context_lock);
  
  struct acpi_device_bus_id{
        char bus_id[15];
@@@ -60,6 -61,16 +61,16 @@@ void acpi_scan_lock_release(void
  }
  EXPORT_SYMBOL_GPL(acpi_scan_lock_release);
  
+ void acpi_lock_hp_context(void)
+ {
+       mutex_lock(&acpi_hp_context_lock);
+ }
+ void acpi_unlock_hp_context(void)
+ {
+       mutex_unlock(&acpi_hp_context_lock);
+ }
  int acpi_scan_add_handler(struct acpi_scan_handler *handler)
  {
        if (!handler || !handler->attach)
@@@ -439,90 -450,74 +450,74 @@@ static int acpi_scan_bus_check(struct a
        return 0;
  }
  
- static void acpi_device_hotplug(void *data, u32 src)
+ static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type)
+ {
+       switch (type) {
+       case ACPI_NOTIFY_BUS_CHECK:
+               return acpi_scan_bus_check(adev);
+       case ACPI_NOTIFY_DEVICE_CHECK:
+               return acpi_scan_device_check(adev);
+       case ACPI_NOTIFY_EJECT_REQUEST:
+       case ACPI_OST_EC_OSPM_EJECT:
+               if (adev->handler && !adev->handler->hotplug.enabled) {
+                       dev_info(&adev->dev, "Eject disabled\n");
+                       return -EPERM;
+               }
+               acpi_evaluate_hotplug_ost(adev->handle, ACPI_NOTIFY_EJECT_REQUEST,
+                                         ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+               return acpi_scan_hot_remove(adev);
+       }
+       return -EINVAL;
+ }
+ void acpi_device_hotplug(void *data, u32 src)
  {
        u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
        struct acpi_device *adev = data;
-       int error;
+       int error = -ENODEV;
  
        lock_device_hotplug();
        mutex_lock(&acpi_scan_lock);
  
        /*
         * The device object's ACPI handle cannot become invalid as long as we
-        * are holding acpi_scan_lock, but it may have become invalid before
+        * are holding acpi_scan_lock, but it might have become invalid before
         * that lock was acquired.
         */
        if (adev->handle == INVALID_ACPI_HANDLE)
-               goto out;
-       switch (src) {
-       case ACPI_NOTIFY_BUS_CHECK:
-               error = acpi_scan_bus_check(adev);
-               break;
-       case ACPI_NOTIFY_DEVICE_CHECK:
-               error = acpi_scan_device_check(adev);
-               break;
-       case ACPI_NOTIFY_EJECT_REQUEST:
-       case ACPI_OST_EC_OSPM_EJECT:
-               error = acpi_scan_hot_remove(adev);
-               break;
-       default:
-               error = -EINVAL;
-               break;
-       }
-       if (!error)
-               ost_code = ACPI_OST_SC_SUCCESS;
-  out:
-       acpi_evaluate_hotplug_ost(adev->handle, src, ost_code, NULL);
-       put_device(&adev->dev);
-       mutex_unlock(&acpi_scan_lock);
-       unlock_device_hotplug();
- }
- static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data)
- {
-       u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
-       struct acpi_device *adev;
-       acpi_status status;
-       if (acpi_bus_get_device(handle, &adev))
                goto err_out;
  
-       switch (type) {
-       case ACPI_NOTIFY_BUS_CHECK:
-               acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
-               break;
-       case ACPI_NOTIFY_DEVICE_CHECK:
-               acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
-               break;
-       case ACPI_NOTIFY_EJECT_REQUEST:
-               acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
-               if (!adev->handler)
-                       goto err_out;
-               if (!adev->handler->hotplug.enabled) {
-                       acpi_handle_err(handle, "Eject disabled\n");
+       if (adev->flags.hotplug_notify) {
+               error = acpi_generic_hotplug_event(adev, src);
+               if (error == -EPERM) {
                        ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
                        goto err_out;
                }
-               acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
-                                         ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
-               break;
-       default:
-               /* non-hotplug event; possibly handled by other handler */
-               return;
-       }
-       get_device(&adev->dev);
-       status = acpi_hotplug_execute(acpi_device_hotplug, adev, type);
-       if (ACPI_SUCCESS(status))
-               return;
+       } else {
+               int (*event)(struct acpi_device *, u32);
  
-       put_device(&adev->dev);
+               acpi_lock_hp_context();
+               event = adev->hp ? adev->hp->event : NULL;
+               acpi_unlock_hp_context();
+               /*
+                * There may be additional notify handlers for device objects
+                * without the .event() callback, so ignore them here.
+                */
+               if (event)
+                       error = event(adev, src);
+               else
+                       goto out;
+       }
+       if (!error)
+               ost_code = ACPI_OST_SC_SUCCESS;
  
   err_out:
-       acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
+       acpi_evaluate_hotplug_ost(adev->handle, src, ost_code, NULL);
+  out:
+       acpi_bus_put_acpi_device(adev);
+       mutex_unlock(&acpi_scan_lock);
+       unlock_device_hotplug();
  }
  
  static ssize_t real_power_state_show(struct device *dev,
@@@ -570,8 -565,6 +565,6 @@@ acpi_eject_store(struct device *d, stru
        if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable)
                return -ENODEV;
  
-       acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT,
-                                 ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
        get_device(&acpi_device->dev);
        status = acpi_hotplug_execute(acpi_device_hotplug, acpi_device,
                                      ACPI_OST_EC_OSPM_EJECT);
@@@ -1114,14 -1107,16 +1107,16 @@@ static void acpi_scan_drop_device(acpi_
        mutex_unlock(&acpi_device_del_lock);
  }
  
- int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
+ static int acpi_get_device_data(acpi_handle handle, struct acpi_device **device,
+                               void (*callback)(void *))
  {
        acpi_status status;
  
        if (!device)
                return -EINVAL;
  
-       status = acpi_get_data(handle, acpi_scan_drop_device, (void **)device);
+       status = acpi_get_data_full(handle, acpi_scan_drop_device,
+                                   (void **)device, callback);
        if (ACPI_FAILURE(status) || !*device) {
                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
                                  handle));
        }
        return 0;
  }
+ int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
+ {
+       return acpi_get_device_data(handle, device, NULL);
+ }
  EXPORT_SYMBOL(acpi_bus_get_device);
  
+ static void get_acpi_device(void *dev)
+ {
+       if (dev)
+               get_device(&((struct acpi_device *)dev)->dev);
+ }
+ struct acpi_device *acpi_bus_get_acpi_device(acpi_handle handle)
+ {
+       struct acpi_device *adev = NULL;
+       acpi_get_device_data(handle, &adev, get_acpi_device);
+       return adev;
+ }
+ void acpi_bus_put_acpi_device(struct acpi_device *adev)
+ {
+       put_device(&adev->dev);
+ }
  int acpi_device_add(struct acpi_device *device,
                    void (*release)(struct device *))
  {
@@@ -1706,20 -1725,6 +1725,20 @@@ static bool acpi_ibm_smbus_match(acpi_h
        return false;
  }
  
 +static bool acpi_object_is_system_bus(acpi_handle handle)
 +{
 +      acpi_handle tmp;
 +
 +      if (ACPI_SUCCESS(acpi_get_handle(NULL, "\\_SB", &tmp)) &&
 +          tmp == handle)
 +              return true;
 +      if (ACPI_SUCCESS(acpi_get_handle(NULL, "\\_TZ", &tmp)) &&
 +          tmp == handle)
 +              return true;
 +
 +      return false;
 +}
 +
  static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
                                int device_type)
  {
                        acpi_add_id(pnp, ACPI_DOCK_HID);
                else if (acpi_ibm_smbus_match(handle))
                        acpi_add_id(pnp, ACPI_SMBUS_IBM_HID);
 -              else if (list_empty(&pnp->ids) && handle == ACPI_ROOT_OBJECT) {
 -                      acpi_add_id(pnp, ACPI_BUS_HID); /* \_SB, LNXSYBUS */
 +              else if (list_empty(&pnp->ids) &&
 +                       acpi_object_is_system_bus(handle)) {
 +                      /* \_SB, \_TZ, LNXSYBUS */
 +                      acpi_add_id(pnp, ACPI_BUS_HID);
                        strcpy(pnp->device_name, ACPI_BUS_DEVICE_NAME);
                        strcpy(pnp->device_class, ACPI_BUS_CLASS);
                }
@@@ -1957,33 -1960,19 +1976,19 @@@ void acpi_scan_hotplug_enabled(struct a
        mutex_unlock(&acpi_scan_lock);
  }
  
- static void acpi_scan_init_hotplug(acpi_handle handle, int type)
+ static void acpi_scan_init_hotplug(struct acpi_device *adev)
  {
-       struct acpi_device_pnp pnp = {};
        struct acpi_hardware_id *hwid;
-       struct acpi_scan_handler *handler;
-       INIT_LIST_HEAD(&pnp.ids);
-       acpi_set_pnp_ids(handle, &pnp, type);
  
-       if (!pnp.type.hardware_id)
-               goto out;
+       list_for_each_entry(hwid, &adev->pnp.ids, list) {
+               struct acpi_scan_handler *handler;
  
-       /*
-        * This relies on the fact that acpi_install_notify_handler() will not
-        * install the same notify handler routine twice for the same handle.
-        */
-       list_for_each_entry(hwid, &pnp.ids, list) {
                handler = acpi_scan_match_handler(hwid->id, NULL);
                if (handler) {
-                       acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
-                                       acpi_hotplug_notify_cb, handler);
+                       adev->flags.hotplug_notify = true;
                        break;
                }
        }
- out:
-       acpi_free_pnp_ids(&pnp);
  }
  
  static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
                return AE_OK;
        }
  
-       acpi_scan_init_hotplug(handle, type);
        acpi_add_single_object(&device, handle, type, sta);
        if (!device)
                return AE_CTRL_DEPTH;
  
+       acpi_scan_init_hotplug(device);
   out:
        if (!*return_value)
                *return_value = device;
diff --combined include/acpi/acpi_bus.h
index adef502cb8f1805de8346f1833e1db4e9ca17c6a,32f90c7bcb0397f953209ca1557778d876aac128..5225fe06e4fff7695e9da1610ca02d6d17b65cb0
@@@ -49,16 -49,8 +49,16 @@@ acpi_evaluate_reference(acpi_handle han
                        struct acpi_object_list *arguments,
                        struct acpi_handle_list *list);
  acpi_status
 +acpi_evaluate_ost(acpi_handle handle, u32 source_event, u32 status_code,
 +                struct acpi_buffer *status_buf);
 +#ifdef ACPI_HOTPLUG_OST
 +#define       acpi_evaluate_hotplug_ost       acpi_evaluate_ost
 +#else
 +static inline acpi_status
  acpi_evaluate_hotplug_ost(acpi_handle handle, u32 source_event,
 -                      u32 status_code, struct acpi_buffer *status_buf);
 +                      u32 status_code, struct acpi_buffer *status_buf)
 +{ return AE_OK; }
 +#endif
  
  acpi_status
  acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld_info **pld);
@@@ -144,6 -136,16 +144,16 @@@ struct acpi_scan_handler 
        struct acpi_hotplug_profile hotplug;
  };
  
+ /*
+  * ACPI Hotplug Context
+  * --------------------
+  */
+ struct acpi_hotplug_context {
+       struct acpi_device *self;
+       int (*event)(struct acpi_device *, u32);
+ };
  /*
   * ACPI Driver
   * -----------
@@@ -198,7 -200,8 +208,8 @@@ struct acpi_device_flags 
        u32 initialized:1;
        u32 visited:1;
        u32 no_hotplug:1;
-       u32 reserved:24;
+       u32 hotplug_notify:1;
+       u32 reserved:23;
  };
  
  /* File System */
@@@ -337,6 -340,7 +348,7 @@@ struct acpi_device 
        struct acpi_device_perf performance;
        struct acpi_device_dir dir;
        struct acpi_scan_handler *handler;
+       struct acpi_hotplug_context *hp;
        struct acpi_driver *driver;
        void *driver_data;
        struct device dev;
@@@ -359,6 -363,15 +371,15 @@@ static inline void acpi_set_device_stat
        *((u32 *)&adev->status) = sta;
  }
  
+ static inline void acpi_set_hp_context(struct acpi_device *adev,
+                                      struct acpi_hotplug_context *hp,
+                                      int (*event)(struct acpi_device *, u32))
+ {
+       hp->self = adev;
+       hp->event = event;
+       adev->hp = hp;
+ }
  /* acpi_device.dev.bus == &acpi_bus_type */
  extern struct bus_type acpi_bus_type;
  
@@@ -389,6 -402,8 +410,8 @@@ extern int unregister_acpi_notifier(str
   */
  
  int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device);
+ struct acpi_device *acpi_bus_get_acpi_device(acpi_handle handle);
+ void acpi_bus_put_acpi_device(struct acpi_device *adev);
  acpi_status acpi_bus_get_status_handle(acpi_handle handle,
                                       unsigned long long *sta);
  int acpi_bus_get_status(struct acpi_device *device);
@@@ -410,6 -425,8 +433,8 @@@ static inline bool acpi_bus_can_wakeup(
  
  void acpi_scan_lock_acquire(void);
  void acpi_scan_lock_release(void);
+ void acpi_lock_hp_context(void);
+ void acpi_unlock_hp_context(void);
  int acpi_scan_add_handler(struct acpi_scan_handler *handler);
  int acpi_bus_register_driver(struct acpi_driver *driver);
  void acpi_bus_unregister_driver(struct acpi_driver *driver);