aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c109
1 files changed, 94 insertions, 15 deletions
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 220285760b68..596172b4ae95 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -48,6 +48,7 @@
48#include <linux/pci-acpi.h> 48#include <linux/pci-acpi.h>
49#include <linux/mutex.h> 49#include <linux/mutex.h>
50#include <linux/slab.h> 50#include <linux/slab.h>
51#include <linux/acpi.h>
51 52
52#include "../pci.h" 53#include "../pci.h"
53#include "acpiphp.h" 54#include "acpiphp.h"
@@ -1149,15 +1150,35 @@ check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
1149 return AE_OK ; 1150 return AE_OK ;
1150} 1151}
1151 1152
1152/** 1153struct acpiphp_hp_work {
1153 * handle_hotplug_event_bridge - handle ACPI event on bridges 1154 struct work_struct work;
1154 * @handle: Notify()'ed acpi_handle 1155 acpi_handle handle;
1155 * @type: Notify code 1156 u32 type;
1156 * @context: pointer to acpiphp_bridge structure 1157 void *context;
1157 * 1158};
1158 * Handles ACPI event notification on {host,p2p} bridges. 1159
1159 */ 1160static void alloc_acpiphp_hp_work(acpi_handle handle, u32 type,
1160static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *context) 1161 void *context,
1162 void (*func)(struct work_struct *work))
1163{
1164 struct acpiphp_hp_work *hp_work;
1165 int ret;
1166
1167 hp_work = kmalloc(sizeof(*hp_work), GFP_KERNEL);
1168 if (!hp_work)
1169 return;
1170
1171 hp_work->handle = handle;
1172 hp_work->type = type;
1173 hp_work->context = context;
1174
1175 INIT_WORK(&hp_work->work, func);
1176 ret = queue_work(kacpi_hotplug_wq, &hp_work->work);
1177 if (!ret)
1178 kfree(hp_work);
1179}
1180
1181static void _handle_hotplug_event_bridge(struct work_struct *work)
1161{ 1182{
1162 struct acpiphp_bridge *bridge; 1183 struct acpiphp_bridge *bridge;
1163 char objname[64]; 1184 char objname[64];
@@ -1165,11 +1186,18 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont
1165 .pointer = objname }; 1186 .pointer = objname };
1166 struct acpi_device *device; 1187 struct acpi_device *device;
1167 int num_sub_bridges = 0; 1188 int num_sub_bridges = 0;
1189 struct acpiphp_hp_work *hp_work;
1190 acpi_handle handle;
1191 u32 type;
1192
1193 hp_work = container_of(work, struct acpiphp_hp_work, work);
1194 handle = hp_work->handle;
1195 type = hp_work->type;
1168 1196
1169 if (acpi_bus_get_device(handle, &device)) { 1197 if (acpi_bus_get_device(handle, &device)) {
1170 /* This bridge must have just been physically inserted */ 1198 /* This bridge must have just been physically inserted */
1171 handle_bridge_insertion(handle, type); 1199 handle_bridge_insertion(handle, type);
1172 return; 1200 goto out;
1173 } 1201 }
1174 1202
1175 bridge = acpiphp_handle_to_bridge(handle); 1203 bridge = acpiphp_handle_to_bridge(handle);
@@ -1180,7 +1208,7 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont
1180 1208
1181 if (!bridge && !num_sub_bridges) { 1209 if (!bridge && !num_sub_bridges) {
1182 err("cannot get bridge info\n"); 1210 err("cannot get bridge info\n");
1183 return; 1211 goto out;
1184 } 1212 }
1185 1213
1186 acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); 1214 acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
@@ -1241,22 +1269,49 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont
1241 warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); 1269 warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
1242 break; 1270 break;
1243 } 1271 }
1272
1273out:
1274 kfree(hp_work); /* allocated in handle_hotplug_event_bridge */
1244} 1275}
1245 1276
1246/** 1277/**
1247 * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots) 1278 * handle_hotplug_event_bridge - handle ACPI event on bridges
1248 * @handle: Notify()'ed acpi_handle 1279 * @handle: Notify()'ed acpi_handle
1249 * @type: Notify code 1280 * @type: Notify code
1250 * @context: pointer to acpiphp_func structure 1281 * @context: pointer to acpiphp_bridge structure
1251 * 1282 *
1252 * Handles ACPI event notification on slots. 1283 * Handles ACPI event notification on {host,p2p} bridges.
1253 */ 1284 */
1254static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context) 1285static void handle_hotplug_event_bridge(acpi_handle handle, u32 type,
1286 void *context)
1287{
1288 /*
1289 * Currently the code adds all hotplug events to the kacpid_wq
1290 * queue when it should add hotplug events to the kacpi_hotplug_wq.
1291 * The proper way to fix this is to reorganize the code so that
1292 * drivers (dock, etc.) do not call acpi_os_execute(), etc.
1293 * For now just re-add this work to the kacpi_hotplug_wq so we
1294 * don't deadlock on hotplug actions.
1295 */
1296 alloc_acpiphp_hp_work(handle, type, context,
1297 _handle_hotplug_event_bridge);
1298}
1299
1300static void _handle_hotplug_event_func(struct work_struct *work)
1255{ 1301{
1256 struct acpiphp_func *func; 1302 struct acpiphp_func *func;
1257 char objname[64]; 1303 char objname[64];
1258 struct acpi_buffer buffer = { .length = sizeof(objname), 1304 struct acpi_buffer buffer = { .length = sizeof(objname),
1259 .pointer = objname }; 1305 .pointer = objname };
1306 struct acpiphp_hp_work *hp_work;
1307 acpi_handle handle;
1308 u32 type;
1309 void *context;
1310
1311 hp_work = container_of(work, struct acpiphp_hp_work, work);
1312 handle = hp_work->handle;
1313 type = hp_work->type;
1314 context = hp_work->context;
1260 1315
1261 acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); 1316 acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
1262 1317
@@ -1291,8 +1346,32 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *contex
1291 warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); 1346 warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
1292 break; 1347 break;
1293 } 1348 }
1349
1350 kfree(hp_work); /* allocated in handle_hotplug_event_func */
1294} 1351}
1295 1352
1353/**
1354 * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots)
1355 * @handle: Notify()'ed acpi_handle
1356 * @type: Notify code
1357 * @context: pointer to acpiphp_func structure
1358 *
1359 * Handles ACPI event notification on slots.
1360 */
1361static void handle_hotplug_event_func(acpi_handle handle, u32 type,
1362 void *context)
1363{
1364 /*
1365 * Currently the code adds all hotplug events to the kacpid_wq
1366 * queue when it should add hotplug events to the kacpi_hotplug_wq.
1367 * The proper way to fix this is to reorganize the code so that
1368 * drivers (dock, etc.) do not call acpi_os_execute(), etc.
1369 * For now just re-add this work to the kacpi_hotplug_wq so we
1370 * don't deadlock on hotplug actions.
1371 */
1372 alloc_acpiphp_hp_work(handle, type, context,
1373 _handle_hotplug_event_func);
1374}
1296 1375
1297static acpi_status 1376static acpi_status
1298find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) 1377find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)