aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/hotplug/acpiphp_glue.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-07-13 17:27:24 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-07-22 22:00:20 -0400
commitcb7b8cedf6c88b9d1d08e0565e8da52180921071 (patch)
tree8be6732fd4b1bc84a2bf1f4f3f24bad5d6486025 /drivers/pci/hotplug/acpiphp_glue.c
parent2e862c51904ddd12be2d256513160e1f87beafee (diff)
ACPI / hotplug / PCI: Hotplug context objects for bridges and functions
When either a new hotplug bridge or a new hotplug function is added by the ACPI-based PCI hotplug (ACPIPHP) code, attach a context object to its ACPI handle to store hotplug-related information in it. To start with, put the handle's bridge and function pointers into that object. Count references to the context objects and drop them when they are not needed any more. First of all, this makes it possible to find out if the given bridge has been registered as a function already in a much more straightforward way and acpiphp_bridge_handle_to_function() can be dropped (Yay!). This also will allow some more simplifications to be made going forward. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Diffstat (limited to 'drivers/pci/hotplug/acpiphp_glue.c')
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c179
1 files changed, 136 insertions, 43 deletions
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index d75ba7e0ca8d..a0c518c2185e 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -55,6 +55,7 @@
55 55
56static LIST_HEAD(bridge_list); 56static LIST_HEAD(bridge_list);
57static DEFINE_MUTEX(bridge_mutex); 57static DEFINE_MUTEX(bridge_mutex);
58static DEFINE_MUTEX(acpiphp_context_lock);
58 59
59#define MY_NAME "acpiphp_glue" 60#define MY_NAME "acpiphp_glue"
60 61
@@ -79,6 +80,74 @@ is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv)
79 } 80 }
80} 81}
81 82
83static void acpiphp_context_handler(acpi_handle handle, void *context)
84{
85 /* Intentionally empty. */
86}
87
88/**
89 * acpiphp_init_context - Create hotplug context and grab a reference to it.
90 * @handle: ACPI object handle to create the context for.
91 *
92 * Call under acpiphp_context_lock.
93 */
94static struct acpiphp_context *acpiphp_init_context(acpi_handle handle)
95{
96 struct acpiphp_context *context;
97 acpi_status status;
98
99 context = kzalloc(sizeof(*context), GFP_KERNEL);
100 if (!context)
101 return NULL;
102
103 context->handle = handle;
104 context->refcount = 1;
105 status = acpi_attach_data(handle, acpiphp_context_handler, context);
106 if (ACPI_FAILURE(status)) {
107 kfree(context);
108 return NULL;
109 }
110 return context;
111}
112
113/**
114 * acpiphp_get_context - Get hotplug context and grab a reference to it.
115 * @handle: ACPI object handle to get the context for.
116 *
117 * Call under acpiphp_context_lock.
118 */
119static struct acpiphp_context *acpiphp_get_context(acpi_handle handle)
120{
121 struct acpiphp_context *context = NULL;
122 acpi_status status;
123 void *data;
124
125 status = acpi_get_data(handle, acpiphp_context_handler, &data);
126 if (ACPI_SUCCESS(status)) {
127 context = data;
128 context->refcount++;
129 }
130 return context;
131}
132
133/**
134 * acpiphp_put_context - Drop a reference to ACPI hotplug context.
135 * @handle: ACPI object handle to put the context for.
136 *
137 * The context object is removed if there are no more references to it.
138 *
139 * Call under acpiphp_context_lock.
140 */
141static void acpiphp_put_context(struct acpiphp_context *context)
142{
143 if (--context->refcount)
144 return;
145
146 WARN_ON(context->func || context->bridge);
147 acpi_detach_data(context->handle, acpiphp_context_handler);
148 kfree(context);
149}
150
82static inline void get_bridge(struct acpiphp_bridge *bridge) 151static inline void get_bridge(struct acpiphp_bridge *bridge)
83{ 152{
84 kref_get(&bridge->ref); 153 kref_get(&bridge->ref);
@@ -91,25 +160,37 @@ static inline void put_bridge(struct acpiphp_bridge *bridge)
91 160
92static void free_bridge(struct kref *kref) 161static void free_bridge(struct kref *kref)
93{ 162{
163 struct acpiphp_context *context;
94 struct acpiphp_bridge *bridge; 164 struct acpiphp_bridge *bridge;
95 struct acpiphp_slot *slot, *next; 165 struct acpiphp_slot *slot, *next;
96 struct acpiphp_func *func, *tmp; 166 struct acpiphp_func *func, *tmp;
97 167
168 mutex_lock(&acpiphp_context_lock);
169
98 bridge = container_of(kref, struct acpiphp_bridge, ref); 170 bridge = container_of(kref, struct acpiphp_bridge, ref);
99 171
100 list_for_each_entry_safe(slot, next, &bridge->slots, node) { 172 list_for_each_entry_safe(slot, next, &bridge->slots, node) {
101 list_for_each_entry_safe(func, tmp, &slot->funcs, sibling) { 173 list_for_each_entry_safe(func, tmp, &slot->funcs, sibling) {
174 context = func->context;
175 context->func = NULL;
176 acpiphp_put_context(context);
102 kfree(func); 177 kfree(func);
103 } 178 }
104 kfree(slot); 179 kfree(slot);
105 } 180 }
106 181
107 /* Release reference acquired by acpiphp_bridge_handle_to_function() */ 182 /* Release the reference acquired by acpiphp_enumerate_slots(). */
108 if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) 183 if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func)
109 put_bridge(bridge->func->slot->bridge); 184 put_bridge(bridge->func->slot->bridge);
185
110 put_device(&bridge->pci_bus->dev); 186 put_device(&bridge->pci_bus->dev);
111 pci_dev_put(bridge->pci_dev); 187 pci_dev_put(bridge->pci_dev);
188 context = bridge->context;
189 context->bridge = NULL;
190 acpiphp_put_context(context);
112 kfree(bridge); 191 kfree(bridge);
192
193 mutex_unlock(&acpiphp_context_lock);
113} 194}
114 195
115/* 196/*
@@ -194,10 +275,11 @@ static void acpiphp_dock_release(void *data)
194} 275}
195 276
196/* callback routine to register each ACPI PCI slot object */ 277/* callback routine to register each ACPI PCI slot object */
197static acpi_status 278static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
198register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) 279 void **rv)
199{ 280{
200 struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context; 281 struct acpiphp_bridge *bridge = data;
282 struct acpiphp_context *context;
201 struct acpiphp_slot *slot; 283 struct acpiphp_slot *slot;
202 struct acpiphp_func *newfunc; 284 struct acpiphp_func *newfunc;
203 acpi_status status = AE_OK; 285 acpi_status status = AE_OK;
@@ -230,6 +312,18 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
230 newfunc->handle = handle; 312 newfunc->handle = handle;
231 newfunc->function = function; 313 newfunc->function = function;
232 314
315 mutex_lock(&acpiphp_context_lock);
316 context = acpiphp_init_context(handle);
317 if (!context) {
318 mutex_unlock(&acpiphp_context_lock);
319 acpi_handle_err(handle, "No hotplug context\n");
320 kfree(newfunc);
321 return AE_NOT_EXIST;
322 }
323 newfunc->context = context;
324 context->func = newfunc;
325 mutex_unlock(&acpiphp_context_lock);
326
233 if (acpi_has_method(handle, "_EJ0")) 327 if (acpi_has_method(handle, "_EJ0"))
234 newfunc->flags = FUNC_HAS_EJ0; 328 newfunc->flags = FUNC_HAS_EJ0;
235 329
@@ -266,8 +360,8 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
266 if (!found) { 360 if (!found) {
267 slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); 361 slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL);
268 if (!slot) { 362 if (!slot) {
269 kfree(newfunc); 363 status = AE_NO_MEMORY;
270 return AE_NO_MEMORY; 364 goto err_out;
271 } 365 }
272 366
273 slot->bridge = bridge; 367 slot->bridge = bridge;
@@ -291,7 +385,9 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
291 else 385 else
292 warn("acpiphp_register_hotplug_slot failed " 386 warn("acpiphp_register_hotplug_slot failed "
293 "(err code = 0x%x)\n", retval); 387 "(err code = 0x%x)\n", retval);
294 goto err_exit; 388
389 status = AE_OK;
390 goto err;
295 } 391 }
296 } 392 }
297 393
@@ -329,15 +425,20 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
329 425
330 return AE_OK; 426 return AE_OK;
331 427
332 err_exit: 428 err:
333 bridge->nr_slots--; 429 bridge->nr_slots--;
334 mutex_lock(&bridge_mutex); 430 mutex_lock(&bridge_mutex);
335 list_del(&slot->node); 431 list_del(&slot->node);
336 mutex_unlock(&bridge_mutex); 432 mutex_unlock(&bridge_mutex);
337 kfree(slot); 433 kfree(slot);
338 kfree(newfunc);
339 434
340 return AE_OK; 435 err_out:
436 mutex_lock(&acpiphp_context_lock);
437 context->func = NULL;
438 acpiphp_put_context(context);
439 mutex_unlock(&acpiphp_context_lock);
440 kfree(newfunc);
441 return status;
341} 442}
342 443
343 444
@@ -352,32 +453,6 @@ static int detect_ejectable_slots(acpi_handle handle)
352 return found; 453 return found;
353} 454}
354 455
355
356/* find acpiphp_func from acpiphp_bridge */
357static struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle)
358{
359 struct acpiphp_bridge *bridge;
360 struct acpiphp_slot *slot;
361 struct acpiphp_func *func = NULL;
362
363 mutex_lock(&bridge_mutex);
364 list_for_each_entry(bridge, &bridge_list, list) {
365 list_for_each_entry(slot, &bridge->slots, node) {
366 list_for_each_entry(func, &slot->funcs, sibling) {
367 if (func->handle == handle) {
368 get_bridge(func->slot->bridge);
369 mutex_unlock(&bridge_mutex);
370 return func;
371 }
372 }
373 }
374 }
375 mutex_unlock(&bridge_mutex);
376
377 return NULL;
378}
379
380
381static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) 456static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle)
382{ 457{
383 struct acpiphp_bridge *bridge; 458 struct acpiphp_bridge *bridge;
@@ -1108,6 +1183,7 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type,
1108 */ 1183 */
1109void acpiphp_enumerate_slots(struct pci_bus *bus) 1184void acpiphp_enumerate_slots(struct pci_bus *bus)
1110{ 1185{
1186 struct acpiphp_context *context;
1111 struct acpiphp_bridge *bridge; 1187 struct acpiphp_bridge *bridge;
1112 acpi_handle handle; 1188 acpi_handle handle;
1113 acpi_status status; 1189 acpi_status status;
@@ -1120,8 +1196,8 @@ void acpiphp_enumerate_slots(struct pci_bus *bus)
1120 return; 1196 return;
1121 1197
1122 bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); 1198 bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
1123 if (bridge == NULL) { 1199 if (!bridge) {
1124 err("out of memory\n"); 1200 acpi_handle_err(handle, "No memory for bridge object\n");
1125 return; 1201 return;
1126 } 1202 }
1127 1203
@@ -1131,6 +1207,21 @@ void acpiphp_enumerate_slots(struct pci_bus *bus)
1131 bridge->pci_dev = pci_dev_get(bus->self); 1207 bridge->pci_dev = pci_dev_get(bus->self);
1132 bridge->pci_bus = bus; 1208 bridge->pci_bus = bus;
1133 1209
1210 mutex_lock(&acpiphp_context_lock);
1211 context = acpiphp_get_context(handle);
1212 if (!context) {
1213 context = acpiphp_init_context(handle);
1214 if (!context) {
1215 mutex_unlock(&acpiphp_context_lock);
1216 acpi_handle_err(handle, "No hotplug context\n");
1217 kfree(bridge);
1218 return;
1219 }
1220 }
1221 bridge->context = context;
1222 context->bridge = bridge;
1223 mutex_unlock(&acpiphp_context_lock);
1224
1134 /* 1225 /*
1135 * Grab a ref to the subordinate PCI bus in case the bus is 1226 * Grab a ref to the subordinate PCI bus in case the bus is
1136 * removed via PCI core logical hotplug. The ref pins the bus 1227 * removed via PCI core logical hotplug. The ref pins the bus
@@ -1169,13 +1260,15 @@ void acpiphp_enumerate_slots(struct pci_bus *bus)
1169 1260
1170 dbg("found ejectable p2p bridge\n"); 1261 dbg("found ejectable p2p bridge\n");
1171 bridge->flags |= BRIDGE_HAS_EJ0; 1262 bridge->flags |= BRIDGE_HAS_EJ0;
1172 bridge->func = acpiphp_bridge_handle_to_function(bridge->handle); 1263 if (context->func) {
1173 if (bridge->func) { 1264 get_bridge(context->func->slot->bridge);
1174 status = acpi_remove_notify_handler(bridge->func->handle, 1265 bridge->func = context->func;
1175 ACPI_SYSTEM_NOTIFY, 1266 handle = context->handle;
1267 WARN_ON(bridge->handle != handle);
1268 status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
1176 handle_hotplug_event_func); 1269 handle_hotplug_event_func);
1177 if (ACPI_FAILURE(status)) 1270 if (ACPI_FAILURE(status))
1178 acpi_handle_err(bridge->func->handle, 1271 acpi_handle_err(handle,
1179 "failed to remove notify handler\n"); 1272 "failed to remove notify handler\n");
1180 } 1273 }
1181 return; 1274 return;