aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-02-06 11:31:37 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-02-06 11:31:37 -0500
commit3c2cc7ff9e2522e42468f8e81a7277be386c5ec4 (patch)
treee8a8405373896d0ff02a7d41a244fa81547c6f73 /drivers/pci
parente525506fcb67a9bbd94f01eac84af802139004eb (diff)
ACPI / hotplug / PCI: Consolidate ACPIPHP with ACPI core hotplug
The ACPI-based PCI hotplug (ACPIPHP) code currently attaches its hotplug context objects directly to ACPI namespace nodes representing hotplug devices. However, after recent changes causing struct acpi_device to be created for every namespace node representing a device (regardless of its status), that is not necessary any more. Moreover, it's vulnerable to the theoretical issue that the ACPI handle passed in the context between handle_hotplug_event() and hotplug_event_work() may become invalid in the meantime (as a result of a concurrent table unload). In principle, this issue might be addressed by adding a non-empty release handler for ACPIPHP hotplug context objects analogous to acpi_scan_drop_device(), but that would duplicate the code in that function and in acpi_device_del_work_fn(). For this reason, it's better to modify ACPIPHP to attach its device hotplug contexts to struct device objects representing hotplug devices and make it use acpi_hotplug_notify_cb() as its notify handler. At the same time, acpi_device_hotplug() can be modified to dispatch the new .hp.event() callback pointing to acpiphp_hotplug_event() from ACPI device objects associated with PCI devices or use the generic ACPI device hotplug code for device objects with matching scan handlers. This allows the existing code duplication between ACPIPHP and the ACPI core to be reduced too and makes further ACPI-based device hotplug consolidation possible. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/hotplug/acpiphp.h9
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c168
2 files changed, 45 insertions, 132 deletions
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
index 373c7aa3b4a6..d7c1fc9712ad 100644
--- a/drivers/pci/hotplug/acpiphp.h
+++ b/drivers/pci/hotplug/acpiphp.h
@@ -116,12 +116,17 @@ struct acpiphp_func {
116}; 116};
117 117
118struct acpiphp_context { 118struct acpiphp_context {
119 struct acpi_hotplug_context hp;
119 struct acpiphp_func func; 120 struct acpiphp_func func;
120 struct acpi_device *adev;
121 struct acpiphp_bridge *bridge; 121 struct acpiphp_bridge *bridge;
122 unsigned int refcount; 122 unsigned int refcount;
123}; 123};
124 124
125static inline struct acpiphp_context *to_acpiphp_context(struct acpi_hotplug_context *hp)
126{
127 return container_of(hp, struct acpiphp_context, hp);
128}
129
125static inline struct acpiphp_context *func_to_context(struct acpiphp_func *func) 130static inline struct acpiphp_context *func_to_context(struct acpiphp_func *func)
126{ 131{
127 return container_of(func, struct acpiphp_context, func); 132 return container_of(func, struct acpiphp_context, func);
@@ -129,7 +134,7 @@ static inline struct acpiphp_context *func_to_context(struct acpiphp_func *func)
129 134
130static inline struct acpi_device *func_to_acpi_device(struct acpiphp_func *func) 135static inline struct acpi_device *func_to_acpi_device(struct acpiphp_func *func)
131{ 136{
132 return func_to_context(func)->adev; 137 return func_to_context(func)->hp.self;
133} 138}
134 139
135static inline acpi_handle func_to_handle(struct acpiphp_func *func) 140static inline acpi_handle func_to_handle(struct acpiphp_func *func)
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 8139a4b0d389..7c498d663eb3 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -59,17 +59,12 @@
59static LIST_HEAD(bridge_list); 59static LIST_HEAD(bridge_list);
60static DEFINE_MUTEX(bridge_mutex); 60static DEFINE_MUTEX(bridge_mutex);
61 61
62static void handle_hotplug_event(acpi_handle handle, u32 type, void *data); 62static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type);
63static void acpiphp_sanitize_bus(struct pci_bus *bus); 63static void acpiphp_sanitize_bus(struct pci_bus *bus);
64static void acpiphp_set_hpp_values(struct pci_bus *bus); 64static void acpiphp_set_hpp_values(struct pci_bus *bus);
65static void hotplug_event(u32 type, struct acpiphp_context *context); 65static void hotplug_event(u32 type, struct acpiphp_context *context);
66static void free_bridge(struct kref *kref); 66static void free_bridge(struct kref *kref);
67 67
68static void acpiphp_context_handler(acpi_handle handle, void *context)
69{
70 /* Intentionally empty. */
71}
72
73/** 68/**
74 * acpiphp_init_context - Create hotplug context and grab a reference to it. 69 * acpiphp_init_context - Create hotplug context and grab a reference to it.
75 * @adev: ACPI device object to create the context for. 70 * @adev: ACPI device object to create the context for.
@@ -79,39 +74,31 @@ static void acpiphp_context_handler(acpi_handle handle, void *context)
79static struct acpiphp_context *acpiphp_init_context(struct acpi_device *adev) 74static struct acpiphp_context *acpiphp_init_context(struct acpi_device *adev)
80{ 75{
81 struct acpiphp_context *context; 76 struct acpiphp_context *context;
82 acpi_status status;
83 77
84 context = kzalloc(sizeof(*context), GFP_KERNEL); 78 context = kzalloc(sizeof(*context), GFP_KERNEL);
85 if (!context) 79 if (!context)
86 return NULL; 80 return NULL;
87 81
88 context->adev = adev;
89 context->refcount = 1; 82 context->refcount = 1;
90 status = acpi_attach_data(adev->handle, acpiphp_context_handler, context); 83 acpi_set_hp_context(adev, &context->hp, acpiphp_hotplug_event);
91 if (ACPI_FAILURE(status)) {
92 kfree(context);
93 return NULL;
94 }
95 return context; 84 return context;
96} 85}
97 86
98/** 87/**
99 * acpiphp_get_context - Get hotplug context and grab a reference to it. 88 * acpiphp_get_context - Get hotplug context and grab a reference to it.
100 * @handle: ACPI object handle to get the context for. 89 * @adev: ACPI device object to get the context for.
101 * 90 *
102 * Call under acpi_hp_context_lock. 91 * Call under acpi_hp_context_lock.
103 */ 92 */
104static struct acpiphp_context *acpiphp_get_context(acpi_handle handle) 93static struct acpiphp_context *acpiphp_get_context(struct acpi_device *adev)
105{ 94{
106 struct acpiphp_context *context = NULL; 95 struct acpiphp_context *context;
107 acpi_status status;
108 void *data;
109 96
110 status = acpi_get_data(handle, acpiphp_context_handler, &data); 97 if (!adev->hp)
111 if (ACPI_SUCCESS(status)) { 98 return NULL;
112 context = data; 99
113 context->refcount++; 100 context = to_acpiphp_context(adev->hp);
114 } 101 context->refcount++;
115 return context; 102 return context;
116} 103}
117 104
@@ -129,7 +116,7 @@ static void acpiphp_put_context(struct acpiphp_context *context)
129 return; 116 return;
130 117
131 WARN_ON(context->bridge); 118 WARN_ON(context->bridge);
132 acpi_detach_data(context->adev->handle, acpiphp_context_handler); 119 context->hp.self->hp = NULL;
133 kfree(context); 120 kfree(context);
134} 121}
135 122
@@ -211,22 +198,13 @@ static void post_dock_fixups(acpi_handle not_used, u32 event, void *data)
211 198
212static void dock_event(acpi_handle handle, u32 type, void *data) 199static void dock_event(acpi_handle handle, u32 type, void *data)
213{ 200{
214 struct acpiphp_context *context; 201 struct acpi_device *adev;
215 202
216 acpi_lock_hp_context(); 203 adev = acpi_bus_get_acpi_device(handle);
217 context = acpiphp_get_context(handle); 204 if (adev) {
218 if (!context || WARN_ON(context->adev->handle != handle) 205 acpiphp_hotplug_event(adev, type);
219 || context->func.parent->is_going_away) { 206 acpi_bus_put_acpi_device(adev);
220 acpi_unlock_hp_context();
221 return;
222 } 207 }
223 get_bridge(context->func.parent);
224 acpiphp_put_context(context);
225 acpi_unlock_hp_context();
226
227 hotplug_event(type, context);
228
229 put_bridge(context->func.parent);
230} 208}
231 209
232static const struct acpi_dock_ops acpiphp_dock_ops = { 210static const struct acpi_dock_ops acpiphp_dock_ops = {
@@ -397,25 +375,23 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
397 } 375 }
398 376
399 /* install notify handler */ 377 /* install notify handler */
400 if (!(newfunc->flags & FUNC_HAS_DCK)) { 378 if (!(newfunc->flags & FUNC_HAS_DCK))
401 status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, 379 acpi_install_hotplug_notify_handler(handle, NULL);
402 handle_hotplug_event,
403 context);
404 if (ACPI_FAILURE(status))
405 acpi_handle_err(handle,
406 "failed to install notify handler\n");
407 }
408 380
409 return AE_OK; 381 return AE_OK;
410} 382}
411 383
412static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) 384static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle)
413{ 385{
386 struct acpi_device *adev = acpi_bus_get_acpi_device(handle);
414 struct acpiphp_context *context; 387 struct acpiphp_context *context;
415 struct acpiphp_bridge *bridge = NULL; 388 struct acpiphp_bridge *bridge = NULL;
416 389
390 if (!adev)
391 return NULL;
392
417 acpi_lock_hp_context(); 393 acpi_lock_hp_context();
418 context = acpiphp_get_context(handle); 394 context = acpiphp_get_context(adev);
419 if (context) { 395 if (context) {
420 bridge = context->bridge; 396 bridge = context->bridge;
421 if (bridge) 397 if (bridge)
@@ -424,6 +400,7 @@ static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle)
424 acpiphp_put_context(context); 400 acpiphp_put_context(context);
425 } 401 }
426 acpi_unlock_hp_context(); 402 acpi_unlock_hp_context();
403 acpi_bus_put_acpi_device(adev);
427 return bridge; 404 return bridge;
428} 405}
429 406
@@ -431,7 +408,6 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
431{ 408{
432 struct acpiphp_slot *slot; 409 struct acpiphp_slot *slot;
433 struct acpiphp_func *func; 410 struct acpiphp_func *func;
434 acpi_status status;
435 411
436 list_for_each_entry(slot, &bridge->slots, node) { 412 list_for_each_entry(slot, &bridge->slots, node) {
437 list_for_each_entry(func, &slot->funcs, sibling) { 413 list_for_each_entry(func, &slot->funcs, sibling) {
@@ -440,13 +416,8 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
440 if (is_dock_device(handle)) 416 if (is_dock_device(handle))
441 unregister_hotplug_dock_device(handle); 417 unregister_hotplug_dock_device(handle);
442 418
443 if (!(func->flags & FUNC_HAS_DCK)) { 419 if (!(func->flags & FUNC_HAS_DCK))
444 status = acpi_remove_notify_handler(handle, 420 acpi_remove_hotplug_notify_handler(handle);
445 ACPI_SYSTEM_NOTIFY,
446 handle_hotplug_event);
447 if (ACPI_FAILURE(status))
448 pr_err("failed to remove notify handler\n");
449 }
450 } 421 }
451 slot->flags |= SLOT_IS_GOING_AWAY; 422 slot->flags |= SLOT_IS_GOING_AWAY;
452 if (slot->slot) 423 if (slot->slot)
@@ -814,7 +785,7 @@ static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot);
814 785
815static void hotplug_event(u32 type, struct acpiphp_context *context) 786static void hotplug_event(u32 type, struct acpiphp_context *context)
816{ 787{
817 acpi_handle handle = context->adev->handle; 788 acpi_handle handle = context->hp.self->handle;
818 struct acpiphp_func *func = &context->func; 789 struct acpiphp_func *func = &context->func;
819 struct acpiphp_slot *slot = func->slot; 790 struct acpiphp_slot *slot = func->slot;
820 struct acpiphp_bridge *bridge; 791 struct acpiphp_bridge *bridge;
@@ -866,87 +837,24 @@ static void hotplug_event(u32 type, struct acpiphp_context *context)
866 put_bridge(bridge); 837 put_bridge(bridge);
867} 838}
868 839
869static void hotplug_event_work(void *data, u32 type) 840static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type)
870{
871 struct acpiphp_context *context = data;
872
873 acpi_scan_lock_acquire();
874
875 hotplug_event(type, context);
876
877 acpi_scan_lock_release();
878 acpi_evaluate_hotplug_ost(context->adev->handle, type,
879 ACPI_OST_SC_SUCCESS, NULL);
880 put_bridge(context->func.parent);
881}
882
883/**
884 * handle_hotplug_event - handle ACPI hotplug event
885 * @handle: Notify()'ed acpi_handle
886 * @type: Notify code
887 * @data: pointer to acpiphp_context structure
888 *
889 * Handles ACPI event notification on slots.
890 */
891static void handle_hotplug_event(acpi_handle handle, u32 type, void *data)
892{ 841{
893 struct acpiphp_context *context; 842 struct acpiphp_context *context;
894 u32 ost_code = ACPI_OST_SC_SUCCESS;
895 acpi_status status;
896
897 switch (type) {
898 case ACPI_NOTIFY_BUS_CHECK:
899 case ACPI_NOTIFY_DEVICE_CHECK:
900 break;
901 case ACPI_NOTIFY_EJECT_REQUEST:
902 ost_code = ACPI_OST_SC_EJECT_IN_PROGRESS;
903 acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
904 break;
905
906 case ACPI_NOTIFY_DEVICE_WAKE:
907 return;
908
909 case ACPI_NOTIFY_FREQUENCY_MISMATCH:
910 acpi_handle_err(handle, "Device cannot be configured due "
911 "to a frequency mismatch\n");
912 goto out;
913
914 case ACPI_NOTIFY_BUS_MODE_MISMATCH:
915 acpi_handle_err(handle, "Device cannot be configured due "
916 "to a bus mode mismatch\n");
917 goto out;
918
919 case ACPI_NOTIFY_POWER_FAULT:
920 acpi_handle_err(handle, "Device has suffered a power fault\n");
921 goto out;
922
923 default:
924 acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type);
925 ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY;
926 goto out;
927 }
928 843
929 acpi_lock_hp_context(); 844 acpi_lock_hp_context();
930 context = acpiphp_get_context(handle); 845 context = acpiphp_get_context(adev);
931 if (!context || WARN_ON(context->adev->handle != handle) 846 if (!context || context->func.parent->is_going_away) {
932 || context->func.parent->is_going_away)
933 goto err_out;
934
935 get_bridge(context->func.parent);
936 acpiphp_put_context(context);
937 status = acpi_hotplug_execute(hotplug_event_work, context, type);
938 if (ACPI_SUCCESS(status)) {
939 acpi_unlock_hp_context(); 847 acpi_unlock_hp_context();
940 return; 848 return -ENODATA;
941 } 849 }
942 put_bridge(context->func.parent); 850 get_bridge(context->func.parent);
943 851 acpiphp_put_context(context);
944 err_out:
945 acpi_unlock_hp_context(); 852 acpi_unlock_hp_context();
946 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
947 853
948 out: 854 hotplug_event(type, context);
949 acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL); 855
856 put_bridge(context->func.parent);
857 return 0;
950} 858}
951 859
952/** 860/**
@@ -999,7 +907,7 @@ void acpiphp_enumerate_slots(struct pci_bus *bus)
999 * bridge is not interesting to us either. 907 * bridge is not interesting to us either.
1000 */ 908 */
1001 acpi_lock_hp_context(); 909 acpi_lock_hp_context();
1002 context = acpiphp_get_context(handle); 910 context = acpiphp_get_context(adev);
1003 if (!context) { 911 if (!context) {
1004 acpi_unlock_hp_context(); 912 acpi_unlock_hp_context();
1005 put_device(&bus->dev); 913 put_device(&bus->dev);