aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-02-15 19:51:01 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-02-15 19:51:01 -0500
commit1e2380cd144f6a9619f72f80ad9a93268f63b8dc (patch)
tree03f661af52c942b0d1c7523c1bd05af59b610671
parentd6a40224a30687f6e0471c4476e3a1a9adc28a96 (diff)
ACPI / dock: Dispatch dock notifications from the global notify handler
The ACPI dock station code carries out an extra namespace scan before the main one in order to find and register all of the dock device objects. Then, it registers a notify handler for each of them for handling dock events. However, dock device objects need not be scanned for upfront. They very well can be enumerated and registered during the first phase of the main namespace scan, before attaching scan handlers and ACPI drivers to ACPI device objects. Then, the dependent devices can be added to the in the second phase. That makes it possible to drop the extra namespace scan, so do it. Moreover, it is not necessary to register notify handlers for all of the dock stations' namespace nodes, becuase notifications may be dispatched from the global notify handler for them. Do that and drop two functions used for dock notify handling, acpi_dock_deferred_cb() and dock_notify_handler(), that aren't necessary any more. Finally, some dock station objects have _HID objects matching the ACPI container scan handler which causes it to claim those objects and try to handle their hotplug, but that is not a good idea, because those objects have their own special hotplug handling anyway. For this reason, the hotplug_notify flag should not be set for ACPI device objects representing dock stations and the container scan handler should be made ignore those objects, so make that happen. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/acpi/container.c3
-rw-r--r--drivers/acpi/dock.c171
-rw-r--r--drivers/acpi/internal.h11
-rw-r--r--drivers/acpi/scan.c36
-rw-r--r--include/acpi/acpi_bus.h3
5 files changed, 90 insertions, 134 deletions
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c
index 0b6ae6eb5c4a..9c35765ac5e9 100644
--- a/drivers/acpi/container.c
+++ b/drivers/acpi/container.c
@@ -68,6 +68,9 @@ static int container_device_attach(struct acpi_device *adev,
68 struct device *dev; 68 struct device *dev;
69 int ret; 69 int ret;
70 70
71 if (adev->flags.is_dock_station)
72 return 0;
73
71 cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); 74 cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
72 if (!cdev) 75 if (!cdev)
73 return -ENOMEM; 76 return -ENOMEM;
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 5bfd769fc91f..44c6e6c0d545 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -103,8 +103,7 @@ enum dock_callback_type {
103 * 103 *
104 * Add the dependent device to the dock's dependent device list. 104 * Add the dependent device to the dock's dependent device list.
105 */ 105 */
106static int __init 106static int add_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
107add_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
108{ 107{
109 struct dock_dependent_device *dd; 108 struct dock_dependent_device *dd;
110 109
@@ -218,6 +217,17 @@ static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event,
218 dock_release_hotplug(dd); 217 dock_release_hotplug(dd);
219} 218}
220 219
220static struct dock_station *find_dock_station(acpi_handle handle)
221{
222 struct dock_station *ds;
223
224 list_for_each_entry(ds, &dock_stations, sibling)
225 if (ds->handle == handle)
226 return ds;
227
228 return NULL;
229}
230
221/** 231/**
222 * find_dock_dependent_device - get a device dependent on this dock 232 * find_dock_dependent_device - get a device dependent on this dock
223 * @ds: the dock station 233 * @ds: the dock station
@@ -238,33 +248,19 @@ find_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
238 return NULL; 248 return NULL;
239} 249}
240 250
241/***************************************************************************** 251void register_dock_dependent_device(struct acpi_device *adev,
242 * Dock functions * 252 acpi_handle dshandle)
243 *****************************************************************************/
244static int __init is_battery(acpi_handle handle)
245{ 253{
246 struct acpi_device_info *info; 254 struct dock_station *ds = find_dock_station(dshandle);
247 int ret = 1; 255 acpi_handle handle = adev->handle;
248 256
249 if (!ACPI_SUCCESS(acpi_get_object_info(handle, &info))) 257 if (ds && !find_dock_dependent_device(ds, handle))
250 return 0; 258 add_dock_dependent_device(ds, handle);
251 if (!(info->valid & ACPI_VALID_HID))
252 ret = 0;
253 else
254 ret = !strcmp("PNP0C0A", info->hardware_id.string);
255
256 kfree(info);
257 return ret;
258} 259}
259 260
260/* Check whether ACPI object is an ejectable battery or disk bay */ 261/*****************************************************************************
261static bool __init is_ejectable_bay(acpi_handle handle) 262 * Dock functions *
262{ 263 *****************************************************************************/
263 if (acpi_has_method(handle, "_EJ0") && is_battery(handle))
264 return true;
265
266 return acpi_bay_match(handle);
267}
268 264
269/** 265/**
270 * is_dock_device - see if a device is on a dock station 266 * is_dock_device - see if a device is on a dock station
@@ -598,20 +594,23 @@ static int handle_eject_request(struct dock_station *ds, u32 event)
598} 594}
599 595
600/** 596/**
601 * dock_notify - act upon an acpi dock notification 597 * dock_notify - Handle ACPI dock notification.
602 * @ds: dock station 598 * @adev: Dock station's ACPI device object.
603 * @event: the acpi event 599 * @event: Event code.
604 * 600 *
605 * If we are notified to dock, then check to see if the dock is 601 * If we are notified to dock, then check to see if the dock is
606 * present and then dock. Notify all drivers of the dock event, 602 * present and then dock. Notify all drivers of the dock event,
607 * and then hotplug and devices that may need hotplugging. 603 * and then hotplug and devices that may need hotplugging.
608 */ 604 */
609static void dock_notify(struct dock_station *ds, u32 event) 605int dock_notify(struct acpi_device *adev, u32 event)
610{ 606{
611 acpi_handle handle = ds->handle; 607 acpi_handle handle = adev->handle;
612 struct acpi_device *adev = NULL; 608 struct dock_station *ds = find_dock_station(handle);
613 int surprise_removal = 0; 609 int surprise_removal = 0;
614 610
611 if (!ds)
612 return -ENODEV;
613
615 /* 614 /*
616 * According to acpi spec 3.0a, if a DEVICE_CHECK notification 615 * According to acpi spec 3.0a, if a DEVICE_CHECK notification
617 * is sent and _DCK is present, it is assumed to mean an undock 616 * is sent and _DCK is present, it is assumed to mean an undock
@@ -632,7 +631,6 @@ static void dock_notify(struct dock_station *ds, u32 event)
632 switch (event) { 631 switch (event) {
633 case ACPI_NOTIFY_BUS_CHECK: 632 case ACPI_NOTIFY_BUS_CHECK:
634 case ACPI_NOTIFY_DEVICE_CHECK: 633 case ACPI_NOTIFY_DEVICE_CHECK:
635 acpi_bus_get_device(handle, &adev);
636 if (!dock_in_progress(ds) && !acpi_device_enumerated(adev)) { 634 if (!dock_in_progress(ds) && !acpi_device_enumerated(adev)) {
637 begin_dock(ds); 635 begin_dock(ds);
638 dock(ds); 636 dock(ds);
@@ -662,49 +660,8 @@ static void dock_notify(struct dock_station *ds, u32 event)
662 else 660 else
663 dock_event(ds, event, UNDOCK_EVENT); 661 dock_event(ds, event, UNDOCK_EVENT);
664 break; 662 break;
665 default:
666 acpi_handle_err(handle, "Unknown dock event %d\n", event);
667 } 663 }
668} 664 return 0;
669
670static void acpi_dock_deferred_cb(void *data, u32 event)
671{
672 acpi_scan_lock_acquire();
673 dock_notify(data, event);
674 acpi_scan_lock_release();
675}
676
677static void dock_notify_handler(acpi_handle handle, u32 event, void *data)
678{
679 if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK
680 && event != ACPI_NOTIFY_EJECT_REQUEST)
681 return;
682
683 acpi_hotplug_execute(acpi_dock_deferred_cb, data, event);
684}
685
686/**
687 * find_dock_devices - find devices on the dock station
688 * @handle: the handle of the device we are examining
689 * @lvl: unused
690 * @context: the dock station private data
691 * @rv: unused
692 *
693 * This function is called by acpi_walk_namespace. It will
694 * check to see if an object has an _EJD method. If it does, then it
695 * will see if it is dependent on the dock station.
696 */
697static acpi_status __init find_dock_devices(acpi_handle handle, u32 lvl,
698 void *context, void **rv)
699{
700 struct dock_station *ds = context;
701 acpi_handle ejd = NULL;
702
703 acpi_bus_get_ejd(handle, &ejd);
704 if (ejd == ds->handle)
705 add_dock_dependent_device(ds, handle);
706
707 return AE_OK;
708} 665}
709 666
710/* 667/*
@@ -803,23 +760,22 @@ static struct attribute_group dock_attribute_group = {
803}; 760};
804 761
805/** 762/**
806 * dock_add - add a new dock station 763 * acpi_dock_add - Add a new dock station
807 * @handle: the dock station handle 764 * @adev: Dock station ACPI device object.
808 * 765 *
809 * allocated and initialize a new dock station device. Find all devices 766 * allocated and initialize a new dock station device.
810 * that are on the dock station, and register for dock event notifications.
811 */ 767 */
812static int __init dock_add(acpi_handle handle) 768void acpi_dock_add(struct acpi_device *adev)
813{ 769{
814 struct dock_station *dock_station, ds = { NULL, }; 770 struct dock_station *dock_station, ds = { NULL, };
771 acpi_handle handle = adev->handle;
815 struct platform_device *dd; 772 struct platform_device *dd;
816 acpi_status status;
817 int ret; 773 int ret;
818 774
819 dd = platform_device_register_data(NULL, "dock", dock_station_count, 775 dd = platform_device_register_data(NULL, "dock", dock_station_count,
820 &ds, sizeof(ds)); 776 &ds, sizeof(ds));
821 if (IS_ERR(dd)) 777 if (IS_ERR(dd))
822 return PTR_ERR(dd); 778 return;
823 779
824 dock_station = dd->dev.platform_data; 780 dock_station = dd->dev.platform_data;
825 781
@@ -837,33 +793,24 @@ static int __init dock_add(acpi_handle handle)
837 dock_station->flags |= DOCK_IS_DOCK; 793 dock_station->flags |= DOCK_IS_DOCK;
838 if (acpi_ata_match(handle)) 794 if (acpi_ata_match(handle))
839 dock_station->flags |= DOCK_IS_ATA; 795 dock_station->flags |= DOCK_IS_ATA;
840 if (is_battery(handle)) 796 if (acpi_device_is_battery(handle))
841 dock_station->flags |= DOCK_IS_BAT; 797 dock_station->flags |= DOCK_IS_BAT;
842 798
843 ret = sysfs_create_group(&dd->dev.kobj, &dock_attribute_group); 799 ret = sysfs_create_group(&dd->dev.kobj, &dock_attribute_group);
844 if (ret) 800 if (ret)
845 goto err_unregister; 801 goto err_unregister;
846 802
847 /* Find dependent devices */
848 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
849 ACPI_UINT32_MAX, find_dock_devices, NULL,
850 dock_station, NULL);
851
852 /* add the dock station as a device dependent on itself */ 803 /* add the dock station as a device dependent on itself */
853 ret = add_dock_dependent_device(dock_station, handle); 804 ret = add_dock_dependent_device(dock_station, handle);
854 if (ret) 805 if (ret)
855 goto err_rmgroup; 806 goto err_rmgroup;
856 807
857 status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
858 dock_notify_handler, dock_station);
859 if (ACPI_FAILURE(status)) {
860 ret = -ENODEV;
861 goto err_rmgroup;
862 }
863
864 dock_station_count++; 808 dock_station_count++;
865 list_add(&dock_station->sibling, &dock_stations); 809 list_add(&dock_station->sibling, &dock_stations);
866 return 0; 810 adev->flags.is_dock_station = true;
811 dev_info(&adev->dev, "ACPI dock station (docks/bays count: %d)\n",
812 dock_station_count);
813 return;
867 814
868err_rmgroup: 815err_rmgroup:
869 remove_dock_dependent_devices(dock_station); 816 remove_dock_dependent_devices(dock_station);
@@ -871,38 +818,4 @@ err_rmgroup:
871err_unregister: 818err_unregister:
872 platform_device_unregister(dd); 819 platform_device_unregister(dd);
873 acpi_handle_err(handle, "%s encountered error %d\n", __func__, ret); 820 acpi_handle_err(handle, "%s encountered error %d\n", __func__, ret);
874 return ret;
875}
876
877/**
878 * find_dock_and_bay - look for dock stations and bays
879 * @handle: acpi handle of a device
880 * @lvl: unused
881 * @context: unused
882 * @rv: unused
883 *
884 * This is called by acpi_walk_namespace to look for dock stations and bays.
885 */
886static acpi_status __init
887find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
888{
889 if (acpi_dock_match(handle) || is_ejectable_bay(handle))
890 dock_add(handle);
891
892 return AE_OK;
893}
894
895void __init acpi_dock_init(void)
896{
897 /* look for dock stations and bays */
898 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
899 ACPI_UINT32_MAX, find_dock_and_bay, NULL, NULL, NULL);
900
901 if (!dock_station_count) {
902 pr_info(PREFIX "No dock devices found.\n");
903 return;
904 }
905
906 pr_info(PREFIX "%s: %d docks/bays found\n",
907 ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count);
908} 821}
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 143d5df5ec32..00e3220febda 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -37,9 +37,15 @@ void acpi_container_init(void);
37static inline void acpi_container_init(void) {} 37static inline void acpi_container_init(void) {}
38#endif 38#endif
39#ifdef CONFIG_ACPI_DOCK 39#ifdef CONFIG_ACPI_DOCK
40void acpi_dock_init(void); 40void register_dock_dependent_device(struct acpi_device *adev,
41 acpi_handle dshandle);
42int dock_notify(struct acpi_device *adev, u32 event);
43void acpi_dock_add(struct acpi_device *adev);
41#else 44#else
42static inline void acpi_dock_init(void) {} 45static inline void register_dock_dependent_device(struct acpi_device *adev,
46 acpi_handle dshandle) {}
47static inline int dock_notify(struct acpi_device *adev, u32 event) { return -ENODEV; }
48static inline void acpi_dock_add(struct acpi_device *adev) {}
43#endif 49#endif
44#ifdef CONFIG_ACPI_HOTPLUG_MEMORY 50#ifdef CONFIG_ACPI_HOTPLUG_MEMORY
45void acpi_memory_hotplug_init(void); 51void acpi_memory_hotplug_init(void);
@@ -91,6 +97,7 @@ void acpi_free_pnp_ids(struct acpi_device_pnp *pnp);
91int acpi_bind_one(struct device *dev, struct acpi_device *adev); 97int acpi_bind_one(struct device *dev, struct acpi_device *adev);
92int acpi_unbind_one(struct device *dev); 98int acpi_unbind_one(struct device *dev);
93bool acpi_device_is_present(struct acpi_device *adev); 99bool acpi_device_is_present(struct acpi_device *adev);
100bool acpi_device_is_battery(acpi_handle handle);
94 101
95/* -------------------------------------------------------------------------- 102/* --------------------------------------------------------------------------
96 Power Resource 103 Power Resource
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 8bb48bfab1df..ec12d970d78d 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -487,7 +487,9 @@ void acpi_device_hotplug(void *data, u32 src)
487 if (adev->handle == INVALID_ACPI_HANDLE) 487 if (adev->handle == INVALID_ACPI_HANDLE)
488 goto err_out; 488 goto err_out;
489 489
490 if (adev->flags.hotplug_notify) { 490 if (adev->flags.is_dock_station) {
491 error = dock_notify(adev, src);
492 } else if (adev->flags.hotplug_notify) {
491 error = acpi_generic_hotplug_event(adev, src); 493 error = acpi_generic_hotplug_event(adev, src);
492 if (error == -EPERM) { 494 if (error == -EPERM) {
493 ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; 495 ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
@@ -1660,6 +1662,29 @@ bool acpi_bay_match(acpi_handle handle)
1660 return acpi_ata_match(phandle); 1662 return acpi_ata_match(phandle);
1661} 1663}
1662 1664
1665bool acpi_device_is_battery(acpi_handle handle)
1666{
1667 struct acpi_device_info *info;
1668 bool ret = false;
1669
1670 if (!ACPI_SUCCESS(acpi_get_object_info(handle, &info)))
1671 return false;
1672
1673 if (info->valid & ACPI_VALID_HID)
1674 ret = !strcmp("PNP0C0A", info->hardware_id.string);
1675
1676 kfree(info);
1677 return ret;
1678}
1679
1680static bool is_ejectable_bay(acpi_handle handle)
1681{
1682 if (acpi_has_method(handle, "_EJ0") && acpi_device_is_battery(handle))
1683 return true;
1684
1685 return acpi_bay_match(handle);
1686}
1687
1663/* 1688/*
1664 * acpi_dock_match - see if an acpi object has a _DCK method 1689 * acpi_dock_match - see if an acpi object has a _DCK method
1665 */ 1690 */
@@ -1964,6 +1989,10 @@ static void acpi_scan_init_hotplug(struct acpi_device *adev)
1964{ 1989{
1965 struct acpi_hardware_id *hwid; 1990 struct acpi_hardware_id *hwid;
1966 1991
1992 if (acpi_dock_match(adev->handle) || is_ejectable_bay(adev->handle)) {
1993 acpi_dock_add(adev);
1994 return;
1995 }
1967 list_for_each_entry(hwid, &adev->pnp.ids, list) { 1996 list_for_each_entry(hwid, &adev->pnp.ids, list) {
1968 struct acpi_scan_handler *handler; 1997 struct acpi_scan_handler *handler;
1969 1998
@@ -2035,8 +2064,12 @@ static int acpi_scan_attach_handler(struct acpi_device *device)
2035static void acpi_bus_attach(struct acpi_device *device) 2064static void acpi_bus_attach(struct acpi_device *device)
2036{ 2065{
2037 struct acpi_device *child; 2066 struct acpi_device *child;
2067 acpi_handle ejd;
2038 int ret; 2068 int ret;
2039 2069
2070 if (ACPI_SUCCESS(acpi_bus_get_ejd(device->handle, &ejd)))
2071 register_dock_dependent_device(device, ejd);
2072
2040 acpi_bus_get_status(device); 2073 acpi_bus_get_status(device);
2041 /* Skip devices that are not present. */ 2074 /* Skip devices that are not present. */
2042 if (!acpi_device_is_present(device)) { 2075 if (!acpi_device_is_present(device)) {
@@ -2189,7 +2222,6 @@ int __init acpi_scan_init(void)
2189 acpi_cmos_rtc_init(); 2222 acpi_cmos_rtc_init();
2190 acpi_container_init(); 2223 acpi_container_init();
2191 acpi_memory_hotplug_init(); 2224 acpi_memory_hotplug_init();
2192 acpi_dock_init();
2193 2225
2194 mutex_lock(&acpi_scan_lock); 2226 mutex_lock(&acpi_scan_lock);
2195 /* 2227 /*
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 32f90c7bcb03..8fb297b5307c 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -201,7 +201,8 @@ struct acpi_device_flags {
201 u32 visited:1; 201 u32 visited:1;
202 u32 no_hotplug:1; 202 u32 no_hotplug:1;
203 u32 hotplug_notify:1; 203 u32 hotplug_notify:1;
204 u32 reserved:23; 204 u32 is_dock_station:1;
205 u32 reserved:22;
205}; 206};
206 207
207/* File System */ 208/* File System */