Merge branch 'acpi-cleanup' into acpi-hotplug
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Sat, 7 Dec 2013 00:05:17 +0000 (01:05 +0100)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Sat, 7 Dec 2013 00:05:17 +0000 (01:05 +0100)
Conflicts:
drivers/acpi/scan.c

22 files changed:
Documentation/acpi/namespace.txt
drivers/acpi/acpica/acresrc.h
drivers/acpi/acpica/nsalloc.c
drivers/acpi/acpica/nsutils.c
drivers/acpi/acpica/rscalc.c
drivers/acpi/acpica/rscreate.c
drivers/acpi/acpica/rsutils.c
drivers/acpi/acpica/utdebug.c
drivers/acpi/bus.c
drivers/acpi/container.c
drivers/acpi/device_pm.c
drivers/acpi/dock.c
drivers/acpi/internal.h
drivers/acpi/osl.c
drivers/acpi/pci_root.c
drivers/acpi/scan.c
drivers/pci/hotplug/acpiphp_glue.c
drivers/xen/xen-acpi-cpuhotplug.c
drivers/xen/xen-acpi-memhotplug.c
include/acpi/acconfig.h
include/acpi/acpi_bus.h
include/acpi/acpixf.h

index 260f6a3661faff625aabda6bc3dc6ba9eda84012..1860cb3865c6b26474a2d07d3944a9858a9f07c6 100644 (file)
@@ -235,10 +235,6 @@ Wysocki <rafael.j.wysocki@intel.com>.
       named object's type in the second column).  In that case the object's
       directory in sysfs will contain the 'path' attribute whose value is
       the full path to the node from the namespace root.
-      struct acpi_device objects are created for the ACPI namespace nodes
-      whose _STA control methods return PRESENT or FUNCTIONING.  The power
-      resource nodes or nodes without _STA are assumed to be both PRESENT
-      and FUNCTIONING.
    F:
       The struct acpi_device object is created for a fixed hardware
       feature (as indicated by the fixed feature flag's name in the second
@@ -340,7 +336,7 @@ Wysocki <rafael.j.wysocki@intel.com>.
      | +-------------+-------+----------------+
      |   |
      |   | +- - - - - - - +- - - - - - +- - - - - - - -+
-     |   +-| PNP0C0D:00 | \_SB_.LID0 | acpi:PNP0C0D: |
+     |   +-| PNP0C0D:00 | \_SB_.LID0 | acpi:PNP0C0D: |
      |   | +- - - - - - - +- - - - - - +- - - - - - - -+
      |   |
      |   | +------------+------------+-----------------------+
@@ -390,6 +386,3 @@ Wysocki <rafael.j.wysocki@intel.com>.
             attribute (as described earlier in this document).
    NOTE: N/A indicates the device object does not have the 'path' or the
          'modalias' attribute.
-   NOTE: The PNP0C0D device listed above is highlighted (marked by "*")
-         to indicate it will be created only when its _STA methods return
-         PRESENT or FUNCTIONING.
index f691d0e4d9fa091faeb0ebc231e8701b399c264b..ff97430455cbe923d3bad4f453635371b9388867 100644 (file)
@@ -184,7 +184,7 @@ acpi_rs_create_resource_list(union acpi_operand_object *aml_buffer,
                             struct acpi_buffer *output_buffer);
 
 acpi_status
-acpi_rs_create_aml_resources(struct acpi_resource *linked_list_buffer,
+acpi_rs_create_aml_resources(struct acpi_buffer *resource_list,
                             struct acpi_buffer *output_buffer);
 
 acpi_status
@@ -227,8 +227,8 @@ acpi_rs_get_list_length(u8 * aml_buffer,
                        u32 aml_buffer_length, acpi_size * size_needed);
 
 acpi_status
-acpi_rs_get_aml_length(struct acpi_resource *linked_list_buffer,
-                      acpi_size * size_needed);
+acpi_rs_get_aml_length(struct acpi_resource *resource_list,
+                      acpi_size resource_list_size, acpi_size * size_needed);
 
 acpi_status
 acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object,
index 243737363fb8ea51c80f77a16908659a29271a48..fd1ff54cda1911a1e520440afd8a48125d927069 100644 (file)
@@ -106,6 +106,7 @@ struct acpi_namespace_node *acpi_ns_create_node(u32 name)
 void acpi_ns_delete_node(struct acpi_namespace_node *node)
 {
        union acpi_operand_object *obj_desc;
+       union acpi_operand_object *next_desc;
 
        ACPI_FUNCTION_NAME(ns_delete_node);
 
@@ -114,12 +115,13 @@ void acpi_ns_delete_node(struct acpi_namespace_node *node)
        acpi_ns_detach_object(node);
 
        /*
-        * Delete an attached data object if present (an object that was created
-        * and attached via acpi_attach_data). Note: After any normal object is
-        * detached above, the only possible remaining object is a data object.
+        * Delete an attached data object list if present (objects that were
+        * attached via acpi_attach_data). Note: After any normal object is
+        * detached above, the only possible remaining object(s) are data
+        * objects, in a linked list.
         */
        obj_desc = node->object;
-       if (obj_desc && (obj_desc->common.type == ACPI_TYPE_LOCAL_DATA)) {
+       while (obj_desc && (obj_desc->common.type == ACPI_TYPE_LOCAL_DATA)) {
 
                /* Invoke the attached data deletion handler if present */
 
@@ -127,7 +129,15 @@ void acpi_ns_delete_node(struct acpi_namespace_node *node)
                        obj_desc->data.handler(node, obj_desc->data.pointer);
                }
 
+               next_desc = obj_desc->common.next_object;
                acpi_ut_remove_reference(obj_desc);
+               obj_desc = next_desc;
+       }
+
+       /* Special case for the statically allocated root node */
+
+       if (node == acpi_gbl_root_node) {
+               return;
        }
 
        /* Now we can delete the node */
index cc2fea94c5f0939fcbfe87c676c0e869171a14f5..4a0665b6bcc11c6c6eb8aad3ee62be15b6122694 100644 (file)
@@ -593,24 +593,26 @@ struct acpi_namespace_node *acpi_ns_validate_handle(acpi_handle handle)
 
 void acpi_ns_terminate(void)
 {
-       union acpi_operand_object *obj_desc;
+       acpi_status status;
 
        ACPI_FUNCTION_TRACE(ns_terminate);
 
        /*
-        * 1) Free the entire namespace -- all nodes and objects
-        *
-        * Delete all object descriptors attached to namepsace nodes
+        * Free the entire namespace -- all nodes and all objects
+        * attached to the nodes
         */
        acpi_ns_delete_namespace_subtree(acpi_gbl_root_node);
 
-       /* Detach any objects attached to the root */
+       /* Delete any objects attached to the root node */
 
-       obj_desc = acpi_ns_get_attached_object(acpi_gbl_root_node);
-       if (obj_desc) {
-               acpi_ns_detach_object(acpi_gbl_root_node);
+       status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+       if (ACPI_FAILURE(status)) {
+               return_VOID;
        }
 
+       acpi_ns_delete_node(acpi_gbl_root_node);
+       (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+
        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Namespace freed\n"));
        return_VOID;
 }
index b62a0f4f4f9bb527cd49fc95279b7032ba1a689a..b60c9cf82862f9e94dfb254b6a30b003e2dd5426 100644 (file)
@@ -174,6 +174,7 @@ acpi_rs_stream_option_length(u32 resource_length,
  * FUNCTION:    acpi_rs_get_aml_length
  *
  * PARAMETERS:  resource            - Pointer to the resource linked list
+ *              resource_list_size  - Size of the resource linked list
  *              size_needed         - Where the required size is returned
  *
  * RETURN:      Status
@@ -185,16 +186,20 @@ acpi_rs_stream_option_length(u32 resource_length,
  ******************************************************************************/
 
 acpi_status
-acpi_rs_get_aml_length(struct acpi_resource * resource, acpi_size * size_needed)
+acpi_rs_get_aml_length(struct acpi_resource *resource,
+                      acpi_size resource_list_size, acpi_size * size_needed)
 {
        acpi_size aml_size_needed = 0;
+       struct acpi_resource *resource_end;
        acpi_rs_length total_size;
 
        ACPI_FUNCTION_TRACE(rs_get_aml_length);
 
        /* Traverse entire list of internal resource descriptors */
 
-       while (resource) {
+       resource_end =
+           ACPI_ADD_PTR(struct acpi_resource, resource, resource_list_size);
+       while (resource < resource_end) {
 
                /* Validate the descriptor type */
 
index 65f3e1c5b5989f61bdcb03e6620cdd1a7371dba9..3a2ace93e62cf5d11690a4a4a907ae5539007f9e 100644 (file)
@@ -418,22 +418,21 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
  *
  * FUNCTION:    acpi_rs_create_aml_resources
  *
- * PARAMETERS:  linked_list_buffer      - Pointer to the resource linked list
- *              output_buffer           - Pointer to the user's buffer
+ * PARAMETERS:  resource_list           - Pointer to the resource list buffer
+ *              output_buffer           - Where the AML buffer is returned
  *
  * RETURN:      Status  AE_OK if okay, else a valid acpi_status code.
  *              If the output_buffer is too small, the error will be
  *              AE_BUFFER_OVERFLOW and output_buffer->Length will point
  *              to the size buffer needed.
  *
- * DESCRIPTION: Takes the linked list of device resources and
- *              creates a bytestream to be used as input for the
- *              _SRS control method.
+ * DESCRIPTION: Converts a list of device resources to an AML bytestream
+ *              to be used as input for the _SRS control method.
  *
  ******************************************************************************/
 
 acpi_status
-acpi_rs_create_aml_resources(struct acpi_resource *linked_list_buffer,
+acpi_rs_create_aml_resources(struct acpi_buffer *resource_list,
                             struct acpi_buffer *output_buffer)
 {
        acpi_status status;
@@ -441,16 +440,16 @@ acpi_rs_create_aml_resources(struct acpi_resource *linked_list_buffer,
 
        ACPI_FUNCTION_TRACE(rs_create_aml_resources);
 
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "LinkedListBuffer = %p\n",
-                         linked_list_buffer));
+       /* Params already validated, no need to re-validate here */
 
-       /*
-        * Params already validated, so we don't re-validate here
-        *
-        * Pass the linked_list_buffer into a module that calculates
-        * the buffer size needed for the byte stream.
-        */
-       status = acpi_rs_get_aml_length(linked_list_buffer, &aml_size_needed);
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ResourceList Buffer = %p\n",
+                         resource_list->pointer));
+
+       /* Get the buffer size needed for the AML byte stream */
+
+       status = acpi_rs_get_aml_length(resource_list->pointer,
+                                       resource_list->length,
+                                       &aml_size_needed);
 
        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "AmlSizeNeeded=%X, %s\n",
                          (u32)aml_size_needed, acpi_format_exception(status)));
@@ -467,10 +466,9 @@ acpi_rs_create_aml_resources(struct acpi_resource *linked_list_buffer,
 
        /* Do the conversion */
 
-       status =
-           acpi_rs_convert_resources_to_aml(linked_list_buffer,
-                                            aml_size_needed,
-                                            output_buffer->pointer);
+       status = acpi_rs_convert_resources_to_aml(resource_list->pointer,
+                                                 aml_size_needed,
+                                                 output_buffer->pointer);
        if (ACPI_FAILURE(status)) {
                return_ACPI_STATUS(status);
        }
index aef303d56d86fecc84e397cad3c24280a874dbb4..14a7982c9961088ae50c0283bfefb4b4b5ccb488 100644 (file)
@@ -753,7 +753,7 @@ acpi_rs_set_srs_method_data(struct acpi_namespace_node *node,
         * Convert the linked list into a byte stream
         */
        buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
-       status = acpi_rs_create_aml_resources(in_buffer->pointer, &buffer);
+       status = acpi_rs_create_aml_resources(in_buffer, &buffer);
        if (ACPI_FAILURE(status)) {
                goto cleanup;
        }
index 1a67b3944b3b8db426fb3edf7b878153785b7631..03ae8affe48f097b1aae7346edd25a165f23186a 100644 (file)
@@ -185,6 +185,7 @@ acpi_debug_print(u32 requested_debug_level,
                }
 
                acpi_gbl_prev_thread_id = thread_id;
+               acpi_gbl_nesting_level = 0;
        }
 
        /*
@@ -193,13 +194,21 @@ acpi_debug_print(u32 requested_debug_level,
         */
        acpi_os_printf("%9s-%04ld ", module_name, line_number);
 
+#ifdef ACPI_EXEC_APP
+       /*
+        * For acpi_exec only, emit the thread ID and nesting level.
+        * Note: nesting level is really only useful during a single-thread
+        * execution. Otherwise, multiple threads will keep resetting the
+        * level.
+        */
        if (ACPI_LV_THREADS & acpi_dbg_level) {
                acpi_os_printf("[%u] ", (u32)thread_id);
        }
 
-       acpi_os_printf("[%02ld] %-22.22s: ",
-                      acpi_gbl_nesting_level,
-                      acpi_ut_trim_function_name(function_name));
+       acpi_os_printf("[%02ld] ", acpi_gbl_nesting_level);
+#endif
+
+       acpi_os_printf("%-22.22s: ", acpi_ut_trim_function_name(function_name));
 
        va_start(args, format);
        acpi_os_vprintf(format, args);
@@ -420,7 +429,9 @@ acpi_ut_exit(u32 line_number,
                                 component_id, "%s\n", acpi_gbl_fn_exit_str);
        }
 
-       acpi_gbl_nesting_level--;
+       if (acpi_gbl_nesting_level) {
+               acpi_gbl_nesting_level--;
+       }
 }
 
 ACPI_EXPORT_SYMBOL(acpi_ut_exit)
@@ -467,7 +478,9 @@ acpi_ut_status_exit(u32 line_number,
                }
        }
 
-       acpi_gbl_nesting_level--;
+       if (acpi_gbl_nesting_level) {
+               acpi_gbl_nesting_level--;
+       }
 }
 
 ACPI_EXPORT_SYMBOL(acpi_ut_status_exit)
@@ -504,7 +517,9 @@ acpi_ut_value_exit(u32 line_number,
                                 ACPI_FORMAT_UINT64(value));
        }
 
-       acpi_gbl_nesting_level--;
+       if (acpi_gbl_nesting_level) {
+               acpi_gbl_nesting_level--;
+       }
 }
 
 ACPI_EXPORT_SYMBOL(acpi_ut_value_exit)
@@ -540,7 +555,9 @@ acpi_ut_ptr_exit(u32 line_number,
                                 ptr);
        }
 
-       acpi_gbl_nesting_level--;
+       if (acpi_gbl_nesting_level) {
+               acpi_gbl_nesting_level--;
+       }
 }
 
 #endif
index cfea1c58f034ccdf32f33ccc5ff8f27d2eda72de..2c38ae22c17f1dad8283f4c6aa03b365a0232a69 100644 (file)
@@ -50,9 +50,6 @@ struct acpi_device *acpi_root;
 struct proc_dir_entry *acpi_root_dir;
 EXPORT_SYMBOL(acpi_root_dir);
 
-#define STRUCT_TO_INT(s)       (*((int*)&s))
-
-
 #ifdef CONFIG_X86
 static int set_copy_dsdt(const struct dmi_system_id *id)
 {
@@ -113,18 +110,16 @@ int acpi_bus_get_status(struct acpi_device *device)
        if (ACPI_FAILURE(status))
                return -ENODEV;
 
-       STRUCT_TO_INT(device->status) = (int) sta;
+       acpi_set_device_status(device, sta);
 
        if (device->status.functional && !device->status.present) {
                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]: "
                       "functional but not present;\n",
-                       device->pnp.bus_id,
-                       (u32) STRUCT_TO_INT(device->status)));
+                       device->pnp.bus_id, (u32)sta));
        }
 
        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]\n",
-                         device->pnp.bus_id,
-                         (u32) STRUCT_TO_INT(device->status)));
+                         device->pnp.bus_id, (u32)sta));
        return 0;
 }
 EXPORT_SYMBOL(acpi_bus_get_status);
@@ -327,58 +322,6 @@ static void acpi_bus_osc_support(void)
                              Notification Handling
    -------------------------------------------------------------------------- */
 
-static void acpi_bus_check_device(acpi_handle handle)
-{
-       struct acpi_device *device;
-       acpi_status status;
-       struct acpi_device_status old_status;
-
-       if (acpi_bus_get_device(handle, &device))
-               return;
-       if (!device)
-               return;
-
-       old_status = device->status;
-
-       /*
-        * Make sure this device's parent is present before we go about
-        * messing with the device.
-        */
-       if (device->parent && !device->parent->status.present) {
-               device->status = device->parent->status;
-               return;
-       }
-
-       status = acpi_bus_get_status(device);
-       if (ACPI_FAILURE(status))
-               return;
-
-       if (STRUCT_TO_INT(old_status) == STRUCT_TO_INT(device->status))
-               return;
-
-       /*
-        * Device Insertion/Removal
-        */
-       if ((device->status.present) && !(old_status.present)) {
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device insertion detected\n"));
-               /* TBD: Handle device insertion */
-       } else if (!(device->status.present) && (old_status.present)) {
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device removal detected\n"));
-               /* TBD: Handle device removal */
-       }
-}
-
-static void acpi_bus_check_scope(acpi_handle handle)
-{
-       /* Status Change? */
-       acpi_bus_check_device(handle);
-
-       /*
-        * TBD: Enumerate child devices within this device's scope and
-        *       run acpi_bus_check_device()'s on them.
-        */
-}
-
 /**
  * acpi_bus_notify
  * ---------------
@@ -395,19 +338,11 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
        switch (type) {
 
        case ACPI_NOTIFY_BUS_CHECK:
-               acpi_bus_check_scope(handle);
-               /*
-                * TBD: We'll need to outsource certain events to non-ACPI
-                *      drivers via the device manager (device.c).
-                */
+               /* TBD */
                break;
 
        case ACPI_NOTIFY_DEVICE_CHECK:
-               acpi_bus_check_device(handle);
-               /*
-                * TBD: We'll need to outsource certain events to non-ACPI
-                *      drivers via the device manager (device.c).
-                */
+               /* TBD */
                break;
 
        case ACPI_NOTIFY_DEVICE_WAKE:
index e2315166765501b479259269ea5888d44042868b..83d232c10f139d697513be3e718cbff8b2342bb9 100644 (file)
@@ -44,19 +44,24 @@ static const struct acpi_device_id container_device_ids[] = {
        {"", 0},
 };
 
-static int container_device_attach(struct acpi_device *device,
+static int container_device_attach(struct acpi_device *adev,
                                   const struct acpi_device_id *not_used)
 {
-       /* This is necessary for container hotplug to work. */
+       kobject_uevent(&adev->dev.kobj, KOBJ_ONLINE);
        return 1;
 }
 
+static void container_device_detach(struct acpi_device *adev)
+{
+       kobject_uevent(&adev->dev.kobj, KOBJ_OFFLINE);
+}
+
 static struct acpi_scan_handler container_handler = {
        .ids = container_device_ids,
        .attach = container_device_attach,
+       .detach = container_device_detach,
        .hotplug = {
                .enabled = true,
-               .mode = AHM_CONTAINER,
        },
 };
 
index b3480cf7db1a1d1eba0e8d884cb456f92b76b660..d49f1e46470370908d72b6efb7677d70f80ded98 100644 (file)
@@ -256,6 +256,8 @@ int acpi_bus_init_power(struct acpi_device *device)
                return -EINVAL;
 
        device->power.state = ACPI_STATE_UNKNOWN;
+       if (!acpi_device_is_present(device))
+               return 0;
 
        result = acpi_device_get_power(device, &state);
        if (result)
@@ -302,15 +304,18 @@ int acpi_device_fix_up_power(struct acpi_device *device)
        return ret;
 }
 
-int acpi_bus_update_power(acpi_handle handle, int *state_p)
+int acpi_device_update_power(struct acpi_device *device, int *state_p)
 {
-       struct acpi_device *device;
        int state;
        int result;
 
-       result = acpi_bus_get_device(handle, &device);
-       if (result)
+       if (device->power.state == ACPI_STATE_UNKNOWN) {
+               result = acpi_bus_init_power(device);
+               if (!result && state_p)
+                       *state_p = device->power.state;
+
                return result;
+       }
 
        result = acpi_device_get_power(device, &state);
        if (result)
@@ -338,6 +343,15 @@ int acpi_bus_update_power(acpi_handle handle, int *state_p)
 
        return 0;
 }
+
+int acpi_bus_update_power(acpi_handle handle, int *state_p)
+{
+       struct acpi_device *device;
+       int result;
+
+       result = acpi_bus_get_device(handle, &device);
+       return result ? result : acpi_device_update_power(device, state_p);
+}
 EXPORT_SYMBOL_GPL(acpi_bus_update_power);
 
 bool acpi_bus_power_manageable(acpi_handle handle)
index 9ab9e783a8941c2902dd9c36f6392e46db4ca06f..8da6be99ba4206b8ebc82eb669be2f447e53b3ab 100644 (file)
@@ -321,14 +321,11 @@ static int dock_present(struct dock_station *ds)
  */
 static void dock_create_acpi_device(acpi_handle handle)
 {
-       struct acpi_device *device;
+       struct acpi_device *device = NULL;
        int ret;
 
-       if (acpi_bus_get_device(handle, &device)) {
-               /*
-                * no device created for this object,
-                * so we should create one.
-                */
+       acpi_bus_get_device(handle, &device);
+       if (!acpi_device_enumerated(device)) {
                ret = acpi_bus_scan(handle);
                if (ret)
                        pr_debug("error adding bus, %x\n", -ret);
index a29739c0ba790af9c967efc29ef6907bf06b63d6..f4aa467c407e5b8f28a0a26a236ae57f2753f714 100644 (file)
@@ -28,7 +28,6 @@ int init_acpi_device_notify(void);
 int acpi_scan_init(void);
 void acpi_pci_root_init(void);
 void acpi_pci_link_init(void);
-void acpi_pci_root_hp_init(void);
 void acpi_processor_init(void);
 void acpi_platform_init(void);
 int acpi_sysfs_init(void);
@@ -73,6 +72,8 @@ void acpi_lpss_init(void);
 static inline void acpi_lpss_init(void) {}
 #endif
 
+bool acpi_queue_hotplug_work(struct work_struct *work);
+
 /* --------------------------------------------------------------------------
                      Device Node Initialization / Removal
    -------------------------------------------------------------------------- */
@@ -87,7 +88,7 @@ void acpi_device_add_finalize(struct acpi_device *device);
 void acpi_free_pnp_ids(struct acpi_device_pnp *pnp);
 int acpi_bind_one(struct device *dev, acpi_handle handle);
 int acpi_unbind_one(struct device *dev);
-void acpi_bus_device_eject(void *data, u32 ost_src);
+bool acpi_device_is_present(struct acpi_device *adev);
 
 /* --------------------------------------------------------------------------
                                   Power Resource
@@ -105,6 +106,8 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state);
 int acpi_power_on_resources(struct acpi_device *device, int state);
 int acpi_power_transition(struct acpi_device *device, int state);
 
+int acpi_device_update_power(struct acpi_device *device, int *state_p);
+
 int acpi_wakeup_device_init(void);
 void acpi_early_processor_set_pdc(void);
 
index 244be2affea781426740122e38420c87433a3f76..7e2d8140c33464336cd1eff96bb4a132fceeef5a 100644 (file)
@@ -1212,6 +1212,10 @@ acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src)
        return AE_OK;
 }
 
+bool acpi_queue_hotplug_work(struct work_struct *work)
+{
+       return queue_work(kacpi_hotplug_wq, work);
+}
 
 acpi_status
 acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle)
@@ -1791,7 +1795,7 @@ acpi_status __init acpi_os_initialize1(void)
 {
        kacpid_wq = alloc_workqueue("kacpid", 0, 1);
        kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1);
-       kacpi_hotplug_wq = alloc_workqueue("kacpi_hotplug", 0, 1);
+       kacpi_hotplug_wq = alloc_ordered_workqueue("kacpi_hotplug", 0);
        BUG_ON(!kacpid_wq);
        BUG_ON(!kacpi_notify_wq);
        BUG_ON(!kacpi_hotplug_wq);
index cd20f3486cfac9dcd97bbc0c674cececd20354d5..afafee56cf8be2b7d1dfe5d2de91180ba30a370c 100644 (file)
@@ -49,6 +49,12 @@ static int acpi_pci_root_add(struct acpi_device *device,
                             const struct acpi_device_id *not_used);
 static void acpi_pci_root_remove(struct acpi_device *device);
 
+static int acpi_pci_root_scan_dependent(struct acpi_device *adev)
+{
+       acpiphp_check_host_bridge(adev->handle);
+       return 0;
+}
+
 #define ACPI_PCIE_REQ_SUPPORT (OSC_PCI_EXT_CONFIG_SUPPORT \
                                | OSC_PCI_ASPM_SUPPORT \
                                | OSC_PCI_CLOCK_PM_SUPPORT \
@@ -63,6 +69,10 @@ static struct acpi_scan_handler pci_root_handler = {
        .ids = root_device_ids,
        .attach = acpi_pci_root_add,
        .detach = acpi_pci_root_remove,
+       .hotplug = {
+               .enabled = true,
+               .scan_dependent = acpi_pci_root_scan_dependent,
+       },
 };
 
 static DEFINE_MUTEX(osc_lock);
@@ -619,116 +629,9 @@ static void acpi_pci_root_remove(struct acpi_device *device)
 void __init acpi_pci_root_init(void)
 {
        acpi_hest_init();
-
-       if (!acpi_pci_disabled) {
-               pci_acpi_crs_quirks();
-               acpi_scan_add_handler(&pci_root_handler);
-       }
-}
-/* Support root bridge hotplug */
-
-static void handle_root_bridge_insertion(acpi_handle handle)
-{
-       struct acpi_device *device;
-
-       if (!acpi_bus_get_device(handle, &device)) {
-               dev_printk(KERN_DEBUG, &device->dev,
-                          "acpi device already exists; ignoring notify\n");
+       if (acpi_pci_disabled)
                return;
-       }
-
-       if (acpi_bus_scan(handle))
-               acpi_handle_err(handle, "cannot add bridge to acpi list\n");
-}
-
-static void hotplug_event_root(void *data, u32 type)
-{
-       acpi_handle handle = data;
-       struct acpi_pci_root *root;
-
-       acpi_scan_lock_acquire();
-
-       root = acpi_pci_find_root(handle);
-
-       switch (type) {
-       case ACPI_NOTIFY_BUS_CHECK:
-               /* bus enumerate */
-               acpi_handle_printk(KERN_DEBUG, handle,
-                                  "Bus check notify on %s\n", __func__);
-               if (root)
-                       acpiphp_check_host_bridge(handle);
-               else
-                       handle_root_bridge_insertion(handle);
-
-               break;
-
-       case ACPI_NOTIFY_DEVICE_CHECK:
-               /* device check */
-               acpi_handle_printk(KERN_DEBUG, handle,
-                                  "Device check notify on %s\n", __func__);
-               if (!root)
-                       handle_root_bridge_insertion(handle);
-               break;
-
-       case ACPI_NOTIFY_EJECT_REQUEST:
-               /* request device eject */
-               acpi_handle_printk(KERN_DEBUG, handle,
-                                  "Device eject notify on %s\n", __func__);
-               if (!root)
-                       break;
-
-               get_device(&root->device->dev);
-
-               acpi_scan_lock_release();
-
-               acpi_bus_device_eject(root->device, ACPI_NOTIFY_EJECT_REQUEST);
-               return;
-       default:
-               acpi_handle_warn(handle,
-                                "notify_handler: unknown event type 0x%x\n",
-                                type);
-               break;
-       }
-
-       acpi_scan_lock_release();
-}
-
-static void handle_hotplug_event_root(acpi_handle handle, u32 type,
-                                       void *context)
-{
-       acpi_hotplug_execute(hotplug_event_root, handle, type);
-}
-
-static acpi_status __init
-find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
-       acpi_status status;
-       int *count = (int *)context;
-
-       if (!acpi_is_root_bridge(handle))
-               return AE_OK;
-
-       (*count)++;
-
-       status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
-                                       handle_hotplug_event_root, NULL);
-       if (ACPI_FAILURE(status))
-               acpi_handle_printk(KERN_DEBUG, handle,
-                       "notify handler is not installed, exit status: %u\n",
-                        (unsigned int)status);
-       else
-               acpi_handle_printk(KERN_DEBUG, handle,
-                                  "notify handler is installed\n");
-
-       return AE_OK;
-}
-
-void __init acpi_pci_root_hp_init(void)
-{
-       int num = 0;
-
-       acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
-               ACPI_UINT32_MAX, find_root_bridges, NULL, &num, NULL);
 
-       printk(KERN_DEBUG "Found %d acpi root devices\n", num);
+       pci_acpi_crs_quirks();
+       acpi_scan_add_handler_with_hotplug(&pci_root_handler, "pci_root");
 }
index 56421a921a2b33eb5ae50babf9251604016e3550..5383c81a8a1bdb4b2fe6b6d7d6547efa3b328cc5 100644 (file)
 #include <linux/dmi.h>
 #include <linux/nls.h>
 
+#include <asm/pgtable.h>
+
 #include "internal.h"
 
 #define _COMPONENT             ACPI_BUS_COMPONENT
 ACPI_MODULE_NAME("scan");
-#define STRUCT_TO_INT(s)       (*((int*)&s))
 extern struct acpi_device *acpi_root;
 
 #define ACPI_BUS_CLASS                 "system_bus"
@@ -25,6 +26,8 @@ extern struct acpi_device *acpi_root;
 
 #define ACPI_IS_ROOT_DEVICE(device)    (!(device)->parent)
 
+#define INVALID_ACPI_HANDLE    ((acpi_handle)empty_zero_page)
+
 /*
  * If set, devices will be hot-removed even if they cannot be put offline
  * gracefully (from the kernel's standpoint).
@@ -200,13 +203,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
        acpi_status status;
        unsigned long long sta;
 
-       /* If there is no handle, the device node has been unregistered. */
-       if (!handle) {
-               dev_dbg(&device->dev, "ACPI handle missing\n");
-               put_device(&device->dev);
-               return -EINVAL;
-       }
-
        /*
         * Carry out two passes here and ignore errors in the first pass,
         * because if the devices in question are memory blocks and
@@ -224,7 +220,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
                dev_warn(errdev, "Offline disabled.\n");
                acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
                                    acpi_bus_online, NULL, NULL, NULL);
-               put_device(&device->dev);
                return -EPERM;
        }
        acpi_bus_offline(handle, 0, (void *)false, (void **)&errdev);
@@ -243,7 +238,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
                        acpi_walk_namespace(ACPI_TYPE_ANY, handle,
                                            ACPI_UINT32_MAX, acpi_bus_online,
                                            NULL, NULL, NULL);
-                       put_device(&device->dev);
                        return -EBUSY;
                }
        }
@@ -253,10 +247,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
 
        acpi_bus_trim(device);
 
-       /* Device node has been unregistered. */
-       put_device(&device->dev);
-       device = NULL;
-
        acpi_evaluate_lck(handle, 0);
        /*
         * TBD: _EJD support.
@@ -283,115 +273,127 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
        return 0;
 }
 
-void acpi_bus_device_eject(void *data, u32 ost_src)
+static int acpi_scan_device_not_present(struct acpi_device *adev)
 {
-       struct acpi_device *device = data;
-       acpi_handle handle = device->handle;
-       u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
-       int error;
+       if (!acpi_device_enumerated(adev)) {
+               dev_warn(&adev->dev, "Still not present\n");
+               return -EALREADY;
+       }
+       acpi_bus_trim(adev);
+       return 0;
+}
 
-       lock_device_hotplug();
-       mutex_lock(&acpi_scan_lock);
+static int acpi_scan_device_check(struct acpi_device *adev)
+{
+       int error;
 
-       if (ost_src == ACPI_NOTIFY_EJECT_REQUEST)
-               acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
-                                         ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+       acpi_bus_get_status(adev);
+       if (adev->status.present || adev->status.functional) {
+               /*
+                * This function is only called for device objects for which
+                * matching scan handlers exist.  The only situation in which
+                * the scan handler is not attached to this device object yet
+                * is when the device has just appeared (either it wasn't
+                * present at all before or it was removed and then added
+                * again).
+                */
+               if (adev->handler) {
+                       dev_warn(&adev->dev, "Already enumerated\n");
+                       return -EALREADY;
+               }
+               error = acpi_bus_scan(adev->handle);
+               if (error) {
+                       dev_warn(&adev->dev, "Namespace scan failure\n");
+                       return error;
+               }
+               if (!adev->handler) {
+                       dev_warn(&adev->dev, "Enumeration failure\n");
+                       error = -ENODEV;
+               }
+       } else {
+               error = acpi_scan_device_not_present(adev);
+       }
+       return error;
+}
 
-       if (device->handler && device->handler->hotplug.mode == AHM_CONTAINER)
-               kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
+static int acpi_scan_bus_check(struct acpi_device *adev)
+{
+       struct acpi_scan_handler *handler = adev->handler;
+       struct acpi_device *child;
+       int error;
 
-       error = acpi_scan_hot_remove(device);
-       if (error == -EPERM) {
-               goto err_support;
-       } else if (error) {
-               goto err_out;
+       acpi_bus_get_status(adev);
+       if (!(adev->status.present || adev->status.functional)) {
+               acpi_scan_device_not_present(adev);
+               return 0;
        }
+       if (handler && handler->hotplug.scan_dependent)
+               return handler->hotplug.scan_dependent(adev);
 
- out:
-       mutex_unlock(&acpi_scan_lock);
-       unlock_device_hotplug();
-       return;
-
- err_support:
-       ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
- err_out:
-       acpi_evaluate_hotplug_ost(handle, ost_src, ost_code, NULL);
-       goto out;
+       error = acpi_bus_scan(adev->handle);
+       if (error) {
+               dev_warn(&adev->dev, "Namespace scan failure\n");
+               return error;
+       }
+       list_for_each_entry(child, &adev->children, node) {
+               error = acpi_scan_bus_check(child);
+               if (error)
+                       return error;
+       }
+       return 0;
 }
 
-static void acpi_scan_bus_device_check(void *data, u32 ost_source)
+static void acpi_device_hotplug(void *data, u32 src)
 {
-       acpi_handle handle = data;
-       struct acpi_device *device = NULL;
        u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
+       struct acpi_device *adev = data;
        int error;
 
        lock_device_hotplug();
        mutex_lock(&acpi_scan_lock);
 
-       if (ost_source != ACPI_NOTIFY_BUS_CHECK) {
-               acpi_bus_get_device(handle, &device);
-               if (device) {
-                       dev_warn(&device->dev, "Attempt to re-insert\n");
-                       goto out;
-               }
-       }
-       error = acpi_bus_scan(handle);
-       if (error) {
-               acpi_handle_warn(handle, "Namespace scan failure\n");
-               goto out;
-       }
-       error = acpi_bus_get_device(handle, &device);
-       if (error) {
-               acpi_handle_warn(handle, "Missing device node object\n");
+       /*
+        * 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
+        * that lock was acquired.
+        */
+       if (adev->handle == INVALID_ACPI_HANDLE)
                goto out;
-       }
-       ost_code = ACPI_OST_SC_SUCCESS;
-       if (device->handler && device->handler->hotplug.mode == AHM_CONTAINER)
-               kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
 
- out:
-       acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL);
-       mutex_unlock(&acpi_scan_lock);
-       unlock_device_hotplug();
-}
-
-static void acpi_hotplug_unsupported(acpi_handle handle, u32 type)
-{
-       u32 ost_status;
-
-       switch (type) {
+       switch (src) {
        case ACPI_NOTIFY_BUS_CHECK:
-               acpi_handle_debug(handle,
-                       "ACPI_NOTIFY_BUS_CHECK event: unsupported\n");
-               ost_status = ACPI_OST_SC_INSERT_NOT_SUPPORTED;
+               error = acpi_scan_bus_check(adev);
                break;
        case ACPI_NOTIFY_DEVICE_CHECK:
-               acpi_handle_debug(handle,
-                       "ACPI_NOTIFY_DEVICE_CHECK event: unsupported\n");
-               ost_status = ACPI_OST_SC_INSERT_NOT_SUPPORTED;
+               error = acpi_scan_device_check(adev);
                break;
        case ACPI_NOTIFY_EJECT_REQUEST:
-               acpi_handle_debug(handle,
-                       "ACPI_NOTIFY_EJECT_REQUEST event: unsupported\n");
-               ost_status = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
+       case ACPI_OST_EC_OSPM_EJECT:
+               error = acpi_scan_hot_remove(adev);
                break;
        default:
-               /* non-hotplug event; possibly handled by other handler */
-               return;
+               error = -EINVAL;
+               break;
        }
+       if (!error)
+               ost_code = ACPI_OST_SC_SUCCESS;
 
-       acpi_evaluate_hotplug_ost(handle, type, ost_status, NULL);
+ 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_scan_handler *handler = data;
        struct acpi_device *adev;
        acpi_status status;
 
-       if (!handler->hotplug.enabled)
-               return acpi_hotplug_unsupported(handle, type);
+       if (acpi_bus_get_device(handle, &adev))
+               goto err_out;
 
        switch (type) {
        case ACPI_NOTIFY_BUS_CHECK:
@@ -402,27 +404,27 @@ static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data)
                break;
        case ACPI_NOTIFY_EJECT_REQUEST:
                acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
-               if (acpi_bus_get_device(handle, &adev))
+               if (!handler->hotplug.enabled) {
+                       acpi_handle_err(handle, "Eject disabled\n");
+                       ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
                        goto err_out;
-
-               get_device(&adev->dev);
-               status = acpi_hotplug_execute(acpi_bus_device_eject, adev, type);
-               if (ACPI_SUCCESS(status))
-                       return;
-
-               put_device(&adev->dev);
-               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;
        }
-       status = acpi_hotplug_execute(acpi_scan_bus_device_check, handle, type);
+       get_device(&adev->dev);
+       status = acpi_hotplug_execute(acpi_device_hotplug, adev, type);
        if (ACPI_SUCCESS(status))
                return;
 
+       put_device(&adev->dev);
+
  err_out:
-       acpi_evaluate_hotplug_ost(handle, type,
-                                 ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
+       acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
 }
 
 static ssize_t real_power_state_show(struct device *dev,
@@ -473,7 +475,7 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
        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_bus_device_eject, acpi_device,
+       status = acpi_hotplug_execute(acpi_device_hotplug, acpi_device,
                                      ACPI_OST_EC_OSPM_EJECT);
        if (ACPI_SUCCESS(status))
                return count;
@@ -905,9 +907,91 @@ struct bus_type acpi_bus_type = {
        .uevent         = acpi_device_uevent,
 };
 
-static void acpi_bus_data_handler(acpi_handle handle, void *context)
+static void acpi_device_del(struct acpi_device *device)
 {
-       /* Intentionally empty. */
+       mutex_lock(&acpi_device_lock);
+       if (device->parent)
+               list_del(&device->node);
+
+       list_del(&device->wakeup_list);
+       mutex_unlock(&acpi_device_lock);
+
+       acpi_power_add_remove_device(device, false);
+       acpi_device_remove_files(device);
+       if (device->remove)
+               device->remove(device);
+
+       device_del(&device->dev);
+}
+
+static LIST_HEAD(acpi_device_del_list);
+static DEFINE_MUTEX(acpi_device_del_lock);
+
+static void acpi_device_del_work_fn(struct work_struct *work_not_used)
+{
+       for (;;) {
+               struct acpi_device *adev;
+
+               mutex_lock(&acpi_device_del_lock);
+
+               if (list_empty(&acpi_device_del_list)) {
+                       mutex_unlock(&acpi_device_del_lock);
+                       break;
+               }
+               adev = list_first_entry(&acpi_device_del_list,
+                                       struct acpi_device, del_list);
+               list_del(&adev->del_list);
+
+               mutex_unlock(&acpi_device_del_lock);
+
+               acpi_device_del(adev);
+               /*
+                * Drop references to all power resources that might have been
+                * used by the device.
+                */
+               acpi_power_transition(adev, ACPI_STATE_D3_COLD);
+               put_device(&adev->dev);
+       }
+}
+
+/**
+ * acpi_scan_drop_device - Drop an ACPI device object.
+ * @handle: Handle of an ACPI namespace node, not used.
+ * @context: Address of the ACPI device object to drop.
+ *
+ * This is invoked by acpi_ns_delete_node() during the removal of the ACPI
+ * namespace node the device object pointed to by @context is attached to.
+ *
+ * The unregistration is carried out asynchronously to avoid running
+ * acpi_device_del() under the ACPICA's namespace mutex and the list is used to
+ * ensure the correct ordering (the device objects must be unregistered in the
+ * same order in which the corresponding namespace nodes are deleted).
+ */
+static void acpi_scan_drop_device(acpi_handle handle, void *context)
+{
+       static DECLARE_WORK(work, acpi_device_del_work_fn);
+       struct acpi_device *adev = context;
+
+       mutex_lock(&acpi_device_del_lock);
+
+       /*
+        * Use the ACPI hotplug workqueue which is ordered, so this work item
+        * won't run after any hotplug work items submitted subsequently.  That
+        * prevents attempts to register device objects identical to those being
+        * deleted from happening concurrently (such attempts result from
+        * hotplug events handled via the ACPI hotplug workqueue).  It also will
+        * run after all of the work items submitted previosuly, which helps
+        * those work items to ensure that they are not accessing stale device
+        * objects.
+        */
+       if (list_empty(&acpi_device_del_list))
+               acpi_queue_hotplug_work(&work);
+
+       list_add_tail(&adev->del_list, &acpi_device_del_list);
+       /* Make acpi_ns_validate_handle() return NULL for this handle. */
+       adev->handle = INVALID_ACPI_HANDLE;
+
+       mutex_unlock(&acpi_device_del_lock);
 }
 
 int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
@@ -917,7 +1001,7 @@ int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
        if (!device)
                return -EINVAL;
 
-       status = acpi_get_data(handle, acpi_bus_data_handler, (void **)device);
+       status = acpi_get_data(handle, acpi_scan_drop_device, (void **)device);
        if (ACPI_FAILURE(status) || !*device) {
                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
                                  handle));
@@ -937,7 +1021,7 @@ int acpi_device_add(struct acpi_device *device,
        if (device->handle) {
                acpi_status status;
 
-               status = acpi_attach_data(device->handle, acpi_bus_data_handler,
+               status = acpi_attach_data(device->handle, acpi_scan_drop_device,
                                          device);
                if (ACPI_FAILURE(status)) {
                        acpi_handle_err(device->handle,
@@ -955,6 +1039,7 @@ int acpi_device_add(struct acpi_device *device,
        INIT_LIST_HEAD(&device->node);
        INIT_LIST_HEAD(&device->wakeup_list);
        INIT_LIST_HEAD(&device->physical_node_list);
+       INIT_LIST_HEAD(&device->del_list);
        mutex_init(&device->physical_node_lock);
 
        new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL);
@@ -1018,37 +1103,10 @@ int acpi_device_add(struct acpi_device *device,
        mutex_unlock(&acpi_device_lock);
 
  err_detach:
-       acpi_detach_data(device->handle, acpi_bus_data_handler);
+       acpi_detach_data(device->handle, acpi_scan_drop_device);
        return result;
 }
 
-static void acpi_device_unregister(struct acpi_device *device)
-{
-       mutex_lock(&acpi_device_lock);
-       if (device->parent)
-               list_del(&device->node);
-
-       list_del(&device->wakeup_list);
-       mutex_unlock(&acpi_device_lock);
-
-       acpi_detach_data(device->handle, acpi_bus_data_handler);
-
-       acpi_power_add_remove_device(device, false);
-       acpi_device_remove_files(device);
-       if (device->remove)
-               device->remove(device);
-
-       device_del(&device->dev);
-       /*
-        * Transition the device to D3cold to drop the reference counts of all
-        * 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);
-       device->handle = NULL;
-       put_device(&device->dev);
-}
-
 /* --------------------------------------------------------------------------
                                  Driver Management
    -------------------------------------------------------------------------- */
@@ -1622,11 +1680,13 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
        device->device_type = type;
        device->handle = handle;
        device->parent = acpi_bus_get_parent(handle);
-       STRUCT_TO_INT(device->status) = sta;
+       acpi_set_device_status(device, sta);
        acpi_device_get_busid(device);
        acpi_set_pnp_ids(handle, &device->pnp, type);
        acpi_bus_get_flags(device);
        device->flags.match_driver = false;
+       device->flags.initialized = true;
+       device->flags.visited = false;
        device_initialize(&device->dev);
        dev_set_uevent_suppress(&device->dev, true);
 }
@@ -1711,6 +1771,15 @@ static int acpi_bus_type_and_status(acpi_handle handle, int *type,
        return 0;
 }
 
+bool acpi_device_is_present(struct acpi_device *adev)
+{
+       if (adev->status.present || adev->status.functional)
+               return true;
+
+       adev->flags.initialized = false;
+       return false;
+}
+
 static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler,
                                       char *idstr,
                                       const struct acpi_device_id **matchid)
@@ -1804,18 +1873,6 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
 
        acpi_scan_init_hotplug(handle, type);
 
-       if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
-           !(sta & ACPI_STA_DEVICE_FUNCTIONING)) {
-               struct acpi_device_wakeup wakeup;
-
-               if (acpi_has_method(handle, "_PRW")) {
-                       acpi_bus_extract_wakeup_device_power_package(handle,
-                                                                    &wakeup);
-                       acpi_power_resources_list_free(&wakeup.resources);
-               }
-               return AE_CTRL_DEPTH;
-       }
-
        acpi_add_single_object(&device, handle, type, sta);
        if (!device)
                return AE_CTRL_DEPTH;
@@ -1850,36 +1907,40 @@ static int acpi_scan_attach_handler(struct acpi_device *device)
        return ret;
 }
 
-static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used,
-                                         void *not_used, void **ret_not_used)
+static void acpi_bus_attach(struct acpi_device *device)
 {
-       struct acpi_device *device;
-       unsigned long long sta_not_used;
+       struct acpi_device *child;
        int ret;
 
-       /*
-        * Ignore errors ignored by acpi_bus_check_add() to avoid terminating
-        * namespace walks prematurely.
-        */
-       if (acpi_bus_type_and_status(handle, &ret, &sta_not_used))
-               return AE_OK;
-
-       if (acpi_bus_get_device(handle, &device))
-               return AE_CTRL_DEPTH;
-
+       acpi_bus_get_status(device);
+       /* Skip devices that are not present. */
+       if (!acpi_device_is_present(device)) {
+               device->flags.visited = false;
+               return;
+       }
        if (device->handler)
-               return AE_OK;
+               goto ok;
 
+       if (!device->flags.initialized) {
+               acpi_bus_update_power(device, NULL);
+               device->flags.initialized = true;
+       }
+       device->flags.visited = false;
        ret = acpi_scan_attach_handler(device);
        if (ret < 0)
-               return AE_CTRL_DEPTH;
+               return;
 
        device->flags.match_driver = true;
-       if (ret > 0)
-               return AE_OK;
+       if (!ret) {
+               ret = device_attach(&device->dev);
+               if (ret < 0)
+                       return;
+       }
+       device->flags.visited = true;
 
-       ret = device_attach(&device->dev);
-       return ret >= 0 ? AE_OK : AE_CTRL_DEPTH;
+ ok:
+       list_for_each_entry(child, &device->children, node)
+               acpi_bus_attach(child);
 }
 
 /**
@@ -1899,75 +1960,48 @@ static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used,
 int acpi_bus_scan(acpi_handle handle)
 {
        void *device = NULL;
-       int error = 0;
 
        if (ACPI_SUCCESS(acpi_bus_check_add(handle, 0, NULL, &device)))
                acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
                                    acpi_bus_check_add, NULL, NULL, &device);
 
-       if (!device)
-               error = -ENODEV;
-       else if (ACPI_SUCCESS(acpi_bus_device_attach(handle, 0, NULL, NULL)))
-               acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
-                                   acpi_bus_device_attach, NULL, NULL, NULL);
-
-       return error;
-}
-EXPORT_SYMBOL(acpi_bus_scan);
-
-static acpi_status acpi_bus_device_detach(acpi_handle handle, u32 lvl_not_used,
-                                         void *not_used, void **ret_not_used)
-{
-       struct acpi_device *device = NULL;
-
-       if (!acpi_bus_get_device(handle, &device)) {
-               struct acpi_scan_handler *dev_handler = device->handler;
-
-               if (dev_handler) {
-                       if (dev_handler->detach)
-                               dev_handler->detach(device);
-
-                       device->handler = NULL;
-               } else {
-                       device_release_driver(&device->dev);
-               }
+       if (device) {
+               acpi_bus_attach(device);
+               return 0;
        }
-       return AE_OK;
-}
-
-static acpi_status acpi_bus_remove(acpi_handle handle, u32 lvl_not_used,
-                                  void *not_used, void **ret_not_used)
-{
-       struct acpi_device *device = NULL;
-
-       if (!acpi_bus_get_device(handle, &device))
-               acpi_device_unregister(device);
-
-       return AE_OK;
+       return -ENODEV;
 }
+EXPORT_SYMBOL(acpi_bus_scan);
 
 /**
- * acpi_bus_trim - Remove ACPI device node and all of its descendants
- * @start: Root of the ACPI device nodes subtree to remove.
+ * acpi_bus_trim - Detach scan handlers and drivers from ACPI device objects.
+ * @adev: Root of the ACPI namespace scope to walk.
  *
  * Must be called under acpi_scan_lock.
  */
-void acpi_bus_trim(struct acpi_device *start)
+void acpi_bus_trim(struct acpi_device *adev)
 {
+       struct acpi_scan_handler *handler = adev->handler;
+       struct acpi_device *child;
+
+       list_for_each_entry_reverse(child, &adev->children, node)
+               acpi_bus_trim(child);
+
+       if (handler) {
+               if (handler->detach)
+                       handler->detach(adev);
+
+               adev->handler = NULL;
+       } else {
+               device_release_driver(&adev->dev);
+       }
        /*
-        * Execute acpi_bus_device_detach() as a post-order callback to detach
-        * all ACPI drivers from the device nodes being removed.
-        */
-       acpi_walk_namespace(ACPI_TYPE_ANY, start->handle, ACPI_UINT32_MAX, NULL,
-                           acpi_bus_device_detach, NULL, NULL);
-       acpi_bus_device_detach(start->handle, 0, NULL, NULL);
-       /*
-        * Execute acpi_bus_remove() as a post-order callback to remove device
-        * nodes in the given namespace scope.
+        * Most likely, the device is going away, so put it into D3cold before
+        * that.
         */
-       acpi_walk_namespace(ACPI_TYPE_ANY, start->handle, ACPI_UINT32_MAX, NULL,
-                           acpi_bus_remove, NULL, NULL);
-       acpi_bus_remove(start->handle, 0, NULL, NULL);
+       acpi_device_set_power(adev, ACPI_STATE_D3_COLD);
+       adev->flags.initialized = false;
+       adev->flags.visited = false;
 }
 EXPORT_SYMBOL_GPL(acpi_bus_trim);
 
@@ -2045,14 +2079,14 @@ int __init acpi_scan_init(void)
 
        result = acpi_bus_scan_fixed();
        if (result) {
-               acpi_device_unregister(acpi_root);
+               acpi_detach_data(acpi_root->handle, acpi_scan_drop_device);
+               acpi_device_del(acpi_root);
+               put_device(&acpi_root->dev);
                goto out;
        }
 
        acpi_update_all_gpes();
 
-       acpi_pci_root_hp_init();
-
  out:
        mutex_unlock(&acpi_scan_lock);
        return result;
index 1cf605f6767357947e9a097981caa7d7869ca2f0..ec4ddae1fb54a68641bf4e4b90e6cbec2def6814 100644 (file)
@@ -279,7 +279,9 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
 
        status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
        if (ACPI_FAILURE(status)) {
-               acpi_handle_warn(handle, "can't evaluate _ADR (%#x)\n", status);
+               if (status != AE_NOT_FOUND)
+                       acpi_handle_warn(handle,
+                               "can't evaluate _ADR (%#x)\n", status);
                return AE_OK;
        }
 
@@ -489,7 +491,7 @@ static void acpiphp_bus_add(acpi_handle handle)
 
        acpi_bus_scan(handle);
        acpi_bus_get_device(handle, &adev);
-       if (adev)
+       if (acpi_device_enumerated(adev))
                acpi_device_set_power(adev, ACPI_STATE_D0);
 }
 
index cd5bb0a507a2abeccf57547403a77ddbebb5c037..80875fb770ed931681c75db5aa4209c15acfc7a7 100644 (file)
@@ -266,7 +266,8 @@ static void acpi_processor_hotplug_notify(acpi_handle handle,
                if (!is_processor_present(handle))
                        break;
 
-               if (!acpi_bus_get_device(handle, &device))
+               acpi_bus_get_device(handle, &device);
+               if (acpi_device_enumerated(device))
                        break;
 
                result = acpi_bus_scan(handle);
@@ -274,8 +275,9 @@ static void acpi_processor_hotplug_notify(acpi_handle handle,
                        pr_err(PREFIX "Unable to add the device\n");
                        break;
                }
-               result = acpi_bus_get_device(handle, &device);
-               if (result) {
+               device = NULL;
+               acpi_bus_get_device(handle, &device);
+               if (!acpi_device_enumerated(device)) {
                        pr_err(PREFIX "Missing device object\n");
                        break;
                }
index f2872a1bb0966d68583021b714a1e66d2a630cc6..f8d18626969a48819ae5810f1d424dc4eacf3f31 100644 (file)
@@ -168,7 +168,7 @@ static int acpi_memory_get_device(acpi_handle handle,
        acpi_scan_lock_acquire();
 
        acpi_bus_get_device(handle, &device);
-       if (device)
+       if (acpi_device_enumerated(device))
                goto end;
 
        /*
@@ -181,8 +181,9 @@ static int acpi_memory_get_device(acpi_handle handle,
                result = -EINVAL;
                goto out;
        }
-       result = acpi_bus_get_device(handle, &device);
-       if (result) {
+       device = NULL;
+       acpi_bus_get_device(handle, &device);
+       if (!acpi_device_enumerated(device)) {
                pr_warn(PREFIX "Missing device object\n");
                result = -EINVAL;
                goto out;
index d98c67001840b705db746e4a1bc89ccba209652b..3ea214cff349c87482d4d3a29b0370bb6c90cd42 100644 (file)
@@ -83,7 +83,9 @@
  * Should the subsystem abort the loading of an ACPI table if the
  * table checksum is incorrect?
  */
+#ifndef ACPI_CHECKSUM_ABORT
 #define ACPI_CHECKSUM_ABORT             FALSE
+#endif
 
 /*
  * Generate a version of ACPICA that only supports "reduced hardware"
index 510119a63fb23d76a6b35f3f1be5351cbd18ebb9..b241b733052e731592afd9e374fb4a49546bd78f 100644 (file)
@@ -89,16 +89,10 @@ struct acpi_device;
  * -----------------
  */
 
-enum acpi_hotplug_mode {
-       AHM_GENERIC = 0,
-       AHM_CONTAINER,
-       AHM_COUNT
-};
-
 struct acpi_hotplug_profile {
        struct kobject kobj;
        bool enabled:1;
-       enum acpi_hotplug_mode mode;
+       int (*scan_dependent)(struct acpi_device *adev);
 };
 
 static inline struct acpi_hotplug_profile *to_acpi_hotplug_profile(
@@ -166,7 +160,9 @@ struct acpi_device_flags {
        u32 ejectable:1;
        u32 power_manageable:1;
        u32 match_driver:1;
-       u32 reserved:27;
+       u32 initialized:1;
+       u32 visited:1;
+       u32 reserved:25;
 };
 
 /* File System */
@@ -296,6 +292,7 @@ struct acpi_device {
        struct list_head children;
        struct list_head node;
        struct list_head wakeup_list;
+       struct list_head del_list;
        struct acpi_device_status status;
        struct acpi_device_flags flags;
        struct acpi_device_pnp pnp;
@@ -321,6 +318,11 @@ static inline void *acpi_driver_data(struct acpi_device *d)
 #define to_acpi_device(d)      container_of(d, struct acpi_device, dev)
 #define to_acpi_driver(d)      container_of(d, struct acpi_driver, drv)
 
+static inline void acpi_set_device_status(struct acpi_device *adev, u32 sta)
+{
+       *((u32 *)&adev->status) = sta;
+}
+
 /* acpi_device.dev.bus == &acpi_bus_type */
 extern struct bus_type acpi_bus_type;
 
@@ -382,6 +384,11 @@ int acpi_match_device_ids(struct acpi_device *device,
 int acpi_create_dir(struct acpi_device *);
 void acpi_remove_dir(struct acpi_device *);
 
+static inline bool acpi_device_enumerated(struct acpi_device *adev)
+{
+       return adev && adev->flags.initialized && adev->flags.visited;
+}
+
 typedef void (*acpi_hp_callback)(void *data, u32 src);
 
 acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src);
index d8f9457755b4168787a66f903c15cb9d6506af25..4278aba9650381c932a687ca871a47f874b6aa1e 100644 (file)
@@ -46,7 +46,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20130927
+#define ACPI_CA_VERSION                 0x20131115
 
 #include <acpi/acconfig.h>
 #include <acpi/actypes.h>
This page took 0.051404 seconds and 5 git commands to generate.