diff options
author | Rajesh Shah <rajesh.shah@intel.com> | 2005-04-28 03:25:52 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2005-06-28 00:52:42 -0400 |
commit | 3fb02738b0fd36f47710a2bf207129efd2f5daa2 (patch) | |
tree | 56bd70ea1b957b601402745ee03b4c1b293ab23b | |
parent | f7d473d919627262816459f8dba70d72812be074 (diff) |
[PATCH] acpi bridge hotadd: Allow ACPI .add and .start operations to be done independently
Create new interfaces to recursively add an acpi namespace object to the acpi
device list, and recursively start the namespace object. This is needed for
ACPI based hotplug of a root bridge hierarchy where the add operation must be
performed first and the start operation must be performed separately after the
hot-plugged devices have been properly configured.
Signed-off-by: Rajesh Shah <rajesh.shah@intel.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/acpi/container.c | 2 | ||||
-rw-r--r-- | drivers/acpi/processor_core.c | 2 | ||||
-rw-r--r-- | drivers/acpi/scan.c | 126 | ||||
-rw-r--r-- | include/acpi/acpi_bus.h | 17 |
4 files changed, 119 insertions, 28 deletions
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index 5a0adbf8bc04..97013ddfa202 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c | |||
@@ -153,7 +153,7 @@ container_device_add(struct acpi_device **device, acpi_handle handle) | |||
153 | return_VALUE(-ENODEV); | 153 | return_VALUE(-ENODEV); |
154 | } | 154 | } |
155 | 155 | ||
156 | result = acpi_bus_scan(*device); | 156 | result = acpi_bus_start(*device); |
157 | 157 | ||
158 | return_VALUE(result); | 158 | return_VALUE(result); |
159 | } | 159 | } |
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index f4778747e889..76156ac91bd3 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c | |||
@@ -723,7 +723,7 @@ int acpi_processor_device_add( | |||
723 | return_VALUE(-ENODEV); | 723 | return_VALUE(-ENODEV); |
724 | } | 724 | } |
725 | 725 | ||
726 | acpi_bus_scan(*device); | 726 | acpi_bus_start(*device); |
727 | 727 | ||
728 | pr = acpi_driver_data(*device); | 728 | pr = acpi_driver_data(*device); |
729 | if (!pr) | 729 | if (!pr) |
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index e85885593280..337d49b5564b 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
@@ -553,20 +553,29 @@ acpi_bus_driver_init ( | |||
553 | * upon possible configuration and currently allocated resources. | 553 | * upon possible configuration and currently allocated resources. |
554 | */ | 554 | */ |
555 | 555 | ||
556 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Driver successfully bound to device\n")); | ||
557 | return_VALUE(0); | ||
558 | } | ||
559 | |||
560 | int | ||
561 | acpi_start_single_object ( | ||
562 | struct acpi_device *device) | ||
563 | { | ||
564 | int result = 0; | ||
565 | struct acpi_driver *driver; | ||
566 | |||
567 | ACPI_FUNCTION_TRACE("acpi_start_single_object"); | ||
568 | |||
569 | if (!(driver = device->driver)) | ||
570 | return_VALUE(0); | ||
571 | |||
556 | if (driver->ops.start) { | 572 | if (driver->ops.start) { |
557 | result = driver->ops.start(device); | 573 | result = driver->ops.start(device); |
558 | if (result && driver->ops.remove) | 574 | if (result && driver->ops.remove) |
559 | driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL); | 575 | driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL); |
560 | return_VALUE(result); | ||
561 | } | 576 | } |
562 | 577 | ||
563 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Driver successfully bound to device\n")); | 578 | return_VALUE(result); |
564 | |||
565 | if (driver->ops.scan) { | ||
566 | driver->ops.scan(device); | ||
567 | } | ||
568 | |||
569 | return_VALUE(0); | ||
570 | } | 579 | } |
571 | 580 | ||
572 | static int acpi_driver_attach(struct acpi_driver * drv) | 581 | static int acpi_driver_attach(struct acpi_driver * drv) |
@@ -586,6 +595,7 @@ static int acpi_driver_attach(struct acpi_driver * drv) | |||
586 | 595 | ||
587 | if (!acpi_bus_match(dev, drv)) { | 596 | if (!acpi_bus_match(dev, drv)) { |
588 | if (!acpi_bus_driver_init(dev, drv)) { | 597 | if (!acpi_bus_driver_init(dev, drv)) { |
598 | acpi_start_single_object(dev); | ||
589 | atomic_inc(&drv->references); | 599 | atomic_inc(&drv->references); |
590 | count++; | 600 | count++; |
591 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found driver [%s] for device [%s]\n", | 601 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found driver [%s] for device [%s]\n", |
@@ -1009,8 +1019,8 @@ acpi_bus_remove ( | |||
1009 | } | 1019 | } |
1010 | 1020 | ||
1011 | 1021 | ||
1012 | int | 1022 | static int |
1013 | acpi_bus_add ( | 1023 | acpi_add_single_object ( |
1014 | struct acpi_device **child, | 1024 | struct acpi_device **child, |
1015 | struct acpi_device *parent, | 1025 | struct acpi_device *parent, |
1016 | acpi_handle handle, | 1026 | acpi_handle handle, |
@@ -1019,7 +1029,7 @@ acpi_bus_add ( | |||
1019 | int result = 0; | 1029 | int result = 0; |
1020 | struct acpi_device *device = NULL; | 1030 | struct acpi_device *device = NULL; |
1021 | 1031 | ||
1022 | ACPI_FUNCTION_TRACE("acpi_bus_add"); | 1032 | ACPI_FUNCTION_TRACE("acpi_add_single_object"); |
1023 | 1033 | ||
1024 | if (!child) | 1034 | if (!child) |
1025 | return_VALUE(-EINVAL); | 1035 | return_VALUE(-EINVAL); |
@@ -1140,7 +1150,7 @@ acpi_bus_add ( | |||
1140 | * | 1150 | * |
1141 | * TBD: Assumes LDM provides driver hot-plug capability. | 1151 | * TBD: Assumes LDM provides driver hot-plug capability. |
1142 | */ | 1152 | */ |
1143 | acpi_bus_find_driver(device); | 1153 | result = acpi_bus_find_driver(device); |
1144 | 1154 | ||
1145 | end: | 1155 | end: |
1146 | if (!result) | 1156 | if (!result) |
@@ -1153,10 +1163,10 @@ end: | |||
1153 | 1163 | ||
1154 | return_VALUE(result); | 1164 | return_VALUE(result); |
1155 | } | 1165 | } |
1156 | EXPORT_SYMBOL(acpi_bus_add); | ||
1157 | 1166 | ||
1158 | 1167 | ||
1159 | int acpi_bus_scan (struct acpi_device *start) | 1168 | static int acpi_bus_scan (struct acpi_device *start, |
1169 | struct acpi_bus_ops *ops) | ||
1160 | { | 1170 | { |
1161 | acpi_status status = AE_OK; | 1171 | acpi_status status = AE_OK; |
1162 | struct acpi_device *parent = NULL; | 1172 | struct acpi_device *parent = NULL; |
@@ -1229,9 +1239,20 @@ int acpi_bus_scan (struct acpi_device *start) | |||
1229 | continue; | 1239 | continue; |
1230 | } | 1240 | } |
1231 | 1241 | ||
1232 | status = acpi_bus_add(&child, parent, chandle, type); | 1242 | if (ops->acpi_op_add) |
1233 | if (ACPI_FAILURE(status)) | 1243 | status = acpi_add_single_object(&child, parent, |
1234 | continue; | 1244 | chandle, type); |
1245 | else | ||
1246 | status = acpi_bus_get_device(chandle, &child); | ||
1247 | |||
1248 | if (ACPI_FAILURE(status)) | ||
1249 | continue; | ||
1250 | |||
1251 | if (ops->acpi_op_start) { | ||
1252 | status = acpi_start_single_object(child); | ||
1253 | if (ACPI_FAILURE(status)) | ||
1254 | continue; | ||
1255 | } | ||
1235 | 1256 | ||
1236 | /* | 1257 | /* |
1237 | * If the device is present, enabled, and functioning then | 1258 | * If the device is present, enabled, and functioning then |
@@ -1257,8 +1278,50 @@ int acpi_bus_scan (struct acpi_device *start) | |||
1257 | 1278 | ||
1258 | return_VALUE(0); | 1279 | return_VALUE(0); |
1259 | } | 1280 | } |
1260 | EXPORT_SYMBOL(acpi_bus_scan); | ||
1261 | 1281 | ||
1282 | int | ||
1283 | acpi_bus_add ( | ||
1284 | struct acpi_device **child, | ||
1285 | struct acpi_device *parent, | ||
1286 | acpi_handle handle, | ||
1287 | int type) | ||
1288 | { | ||
1289 | int result; | ||
1290 | struct acpi_bus_ops ops; | ||
1291 | |||
1292 | ACPI_FUNCTION_TRACE("acpi_bus_add"); | ||
1293 | |||
1294 | result = acpi_add_single_object(child, parent, handle, type); | ||
1295 | if (!result) { | ||
1296 | memset(&ops, 0, sizeof(ops)); | ||
1297 | ops.acpi_op_add = 1; | ||
1298 | result = acpi_bus_scan(*child, &ops); | ||
1299 | } | ||
1300 | return_VALUE(result); | ||
1301 | } | ||
1302 | EXPORT_SYMBOL(acpi_bus_add); | ||
1303 | |||
1304 | int | ||
1305 | acpi_bus_start ( | ||
1306 | struct acpi_device *device) | ||
1307 | { | ||
1308 | int result; | ||
1309 | struct acpi_bus_ops ops; | ||
1310 | |||
1311 | ACPI_FUNCTION_TRACE("acpi_bus_start"); | ||
1312 | |||
1313 | if (!device) | ||
1314 | return_VALUE(-EINVAL); | ||
1315 | |||
1316 | result = acpi_start_single_object(device); | ||
1317 | if (!result) { | ||
1318 | memset(&ops, 0, sizeof(ops)); | ||
1319 | ops.acpi_op_start = 1; | ||
1320 | result = acpi_bus_scan(device, &ops); | ||
1321 | } | ||
1322 | return_VALUE(result); | ||
1323 | } | ||
1324 | EXPORT_SYMBOL(acpi_bus_start); | ||
1262 | 1325 | ||
1263 | static int | 1326 | static int |
1264 | acpi_bus_trim(struct acpi_device *start, | 1327 | acpi_bus_trim(struct acpi_device *start, |
@@ -1331,13 +1394,19 @@ acpi_bus_scan_fixed ( | |||
1331 | /* | 1394 | /* |
1332 | * Enumerate all fixed-feature devices. | 1395 | * Enumerate all fixed-feature devices. |
1333 | */ | 1396 | */ |
1334 | if (acpi_fadt.pwr_button == 0) | 1397 | if (acpi_fadt.pwr_button == 0) { |
1335 | result = acpi_bus_add(&device, acpi_root, | 1398 | result = acpi_add_single_object(&device, acpi_root, |
1336 | NULL, ACPI_BUS_TYPE_POWER_BUTTON); | 1399 | NULL, ACPI_BUS_TYPE_POWER_BUTTON); |
1400 | if (!result) | ||
1401 | result = acpi_start_single_object(device); | ||
1402 | } | ||
1337 | 1403 | ||
1338 | if (acpi_fadt.sleep_button == 0) | 1404 | if (acpi_fadt.sleep_button == 0) { |
1339 | result = acpi_bus_add(&device, acpi_root, | 1405 | result = acpi_add_single_object(&device, acpi_root, |
1340 | NULL, ACPI_BUS_TYPE_SLEEP_BUTTON); | 1406 | NULL, ACPI_BUS_TYPE_SLEEP_BUTTON); |
1407 | if (!result) | ||
1408 | result = acpi_start_single_object(device); | ||
1409 | } | ||
1341 | 1410 | ||
1342 | return_VALUE(result); | 1411 | return_VALUE(result); |
1343 | } | 1412 | } |
@@ -1346,6 +1415,7 @@ acpi_bus_scan_fixed ( | |||
1346 | static int __init acpi_scan_init(void) | 1415 | static int __init acpi_scan_init(void) |
1347 | { | 1416 | { |
1348 | int result; | 1417 | int result; |
1418 | struct acpi_bus_ops ops; | ||
1349 | 1419 | ||
1350 | ACPI_FUNCTION_TRACE("acpi_scan_init"); | 1420 | ACPI_FUNCTION_TRACE("acpi_scan_init"); |
1351 | 1421 | ||
@@ -1357,17 +1427,23 @@ static int __init acpi_scan_init(void) | |||
1357 | /* | 1427 | /* |
1358 | * Create the root device in the bus's device tree | 1428 | * Create the root device in the bus's device tree |
1359 | */ | 1429 | */ |
1360 | result = acpi_bus_add(&acpi_root, NULL, ACPI_ROOT_OBJECT, | 1430 | result = acpi_add_single_object(&acpi_root, NULL, ACPI_ROOT_OBJECT, |
1361 | ACPI_BUS_TYPE_SYSTEM); | 1431 | ACPI_BUS_TYPE_SYSTEM); |
1362 | if (result) | 1432 | if (result) |
1363 | goto Done; | 1433 | goto Done; |
1364 | 1434 | ||
1435 | result = acpi_start_single_object(acpi_root); | ||
1436 | |||
1365 | /* | 1437 | /* |
1366 | * Enumerate devices in the ACPI namespace. | 1438 | * Enumerate devices in the ACPI namespace. |
1367 | */ | 1439 | */ |
1368 | result = acpi_bus_scan_fixed(acpi_root); | 1440 | result = acpi_bus_scan_fixed(acpi_root); |
1369 | if (!result) | 1441 | if (!result) { |
1370 | result = acpi_bus_scan(acpi_root); | 1442 | memset(&ops, 0, sizeof(ops)); |
1443 | ops.acpi_op_add = 1; | ||
1444 | ops.acpi_op_start = 1; | ||
1445 | result = acpi_bus_scan(acpi_root, &ops); | ||
1446 | } | ||
1371 | 1447 | ||
1372 | if (result) | 1448 | if (result) |
1373 | acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL); | 1449 | acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL); |
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index c627bc408a6b..9ad142476f33 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h | |||
@@ -108,6 +108,21 @@ typedef int (*acpi_op_unbind) (struct acpi_device *device); | |||
108 | typedef int (*acpi_op_match) (struct acpi_device *device, | 108 | typedef int (*acpi_op_match) (struct acpi_device *device, |
109 | struct acpi_driver *driver); | 109 | struct acpi_driver *driver); |
110 | 110 | ||
111 | struct acpi_bus_ops { | ||
112 | u32 acpi_op_add:1; | ||
113 | u32 acpi_op_remove:1; | ||
114 | u32 acpi_op_lock:1; | ||
115 | u32 acpi_op_start:1; | ||
116 | u32 acpi_op_stop:1; | ||
117 | u32 acpi_op_suspend:1; | ||
118 | u32 acpi_op_resume:1; | ||
119 | u32 acpi_op_scan:1; | ||
120 | u32 acpi_op_bind:1; | ||
121 | u32 acpi_op_unbind:1; | ||
122 | u32 acpi_op_match:1; | ||
123 | u32 reserved:21; | ||
124 | }; | ||
125 | |||
111 | struct acpi_device_ops { | 126 | struct acpi_device_ops { |
112 | acpi_op_add add; | 127 | acpi_op_add add; |
113 | acpi_op_remove remove; | 128 | acpi_op_remove remove; |
@@ -327,9 +342,9 @@ int acpi_bus_generate_event (struct acpi_device *device, u8 type, int data); | |||
327 | int acpi_bus_receive_event (struct acpi_bus_event *event); | 342 | int acpi_bus_receive_event (struct acpi_bus_event *event); |
328 | int acpi_bus_register_driver (struct acpi_driver *driver); | 343 | int acpi_bus_register_driver (struct acpi_driver *driver); |
329 | int acpi_bus_unregister_driver (struct acpi_driver *driver); | 344 | int acpi_bus_unregister_driver (struct acpi_driver *driver); |
330 | int acpi_bus_scan (struct acpi_device *start); | ||
331 | int acpi_bus_add (struct acpi_device **child, struct acpi_device *parent, | 345 | int acpi_bus_add (struct acpi_device **child, struct acpi_device *parent, |
332 | acpi_handle handle, int type); | 346 | acpi_handle handle, int type); |
347 | int acpi_bus_start (struct acpi_device *device); | ||
333 | 348 | ||
334 | 349 | ||
335 | int acpi_match_ids (struct acpi_device *device, char *ids); | 350 | int acpi_match_ids (struct acpi_device *device, char *ids); |