diff options
Diffstat (limited to 'drivers/acpi/osl.c')
-rw-r--r-- | drivers/acpi/osl.c | 126 |
1 files changed, 96 insertions, 30 deletions
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 5691f165a952..56071b67bed5 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c | |||
@@ -58,6 +58,7 @@ struct acpi_os_dpc { | |||
58 | acpi_osd_exec_callback function; | 58 | acpi_osd_exec_callback function; |
59 | void *context; | 59 | void *context; |
60 | struct work_struct work; | 60 | struct work_struct work; |
61 | int wait; | ||
61 | }; | 62 | }; |
62 | 63 | ||
63 | #ifdef CONFIG_ACPI_CUSTOM_DSDT | 64 | #ifdef CONFIG_ACPI_CUSTOM_DSDT |
@@ -88,6 +89,7 @@ struct acpi_res_list { | |||
88 | char name[5]; /* only can have a length of 4 chars, make use of this | 89 | char name[5]; /* only can have a length of 4 chars, make use of this |
89 | one instead of res->name, no need to kalloc then */ | 90 | one instead of res->name, no need to kalloc then */ |
90 | struct list_head resource_list; | 91 | struct list_head resource_list; |
92 | int count; | ||
91 | }; | 93 | }; |
92 | 94 | ||
93 | static LIST_HEAD(resource_list_head); | 95 | static LIST_HEAD(resource_list_head); |
@@ -697,31 +699,12 @@ void acpi_os_derive_pci_id(acpi_handle rhandle, /* upper bound */ | |||
697 | static void acpi_os_execute_deferred(struct work_struct *work) | 699 | static void acpi_os_execute_deferred(struct work_struct *work) |
698 | { | 700 | { |
699 | struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work); | 701 | struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work); |
700 | if (!dpc) { | ||
701 | printk(KERN_ERR PREFIX "Invalid (NULL) context\n"); | ||
702 | return; | ||
703 | } | ||
704 | |||
705 | dpc->function(dpc->context); | ||
706 | kfree(dpc); | ||
707 | |||
708 | return; | ||
709 | } | ||
710 | |||
711 | static void acpi_os_execute_hp_deferred(struct work_struct *work) | ||
712 | { | ||
713 | struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work); | ||
714 | if (!dpc) { | ||
715 | printk(KERN_ERR PREFIX "Invalid (NULL) context\n"); | ||
716 | return; | ||
717 | } | ||
718 | 702 | ||
719 | acpi_os_wait_events_complete(NULL); | 703 | if (dpc->wait) |
704 | acpi_os_wait_events_complete(NULL); | ||
720 | 705 | ||
721 | dpc->function(dpc->context); | 706 | dpc->function(dpc->context); |
722 | kfree(dpc); | 707 | kfree(dpc); |
723 | |||
724 | return; | ||
725 | } | 708 | } |
726 | 709 | ||
727 | /******************************************************************************* | 710 | /******************************************************************************* |
@@ -745,15 +728,11 @@ static acpi_status __acpi_os_execute(acpi_execute_type type, | |||
745 | acpi_status status = AE_OK; | 728 | acpi_status status = AE_OK; |
746 | struct acpi_os_dpc *dpc; | 729 | struct acpi_os_dpc *dpc; |
747 | struct workqueue_struct *queue; | 730 | struct workqueue_struct *queue; |
748 | work_func_t func; | ||
749 | int ret; | 731 | int ret; |
750 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, | 732 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
751 | "Scheduling function [%p(%p)] for deferred execution.\n", | 733 | "Scheduling function [%p(%p)] for deferred execution.\n", |
752 | function, context)); | 734 | function, context)); |
753 | 735 | ||
754 | if (!function) | ||
755 | return AE_BAD_PARAMETER; | ||
756 | |||
757 | /* | 736 | /* |
758 | * Allocate/initialize DPC structure. Note that this memory will be | 737 | * Allocate/initialize DPC structure. Note that this memory will be |
759 | * freed by the callee. The kernel handles the work_struct list in a | 738 | * freed by the callee. The kernel handles the work_struct list in a |
@@ -778,8 +757,8 @@ static acpi_status __acpi_os_execute(acpi_execute_type type, | |||
778 | */ | 757 | */ |
779 | queue = hp ? kacpi_hotplug_wq : | 758 | queue = hp ? kacpi_hotplug_wq : |
780 | (type == OSL_NOTIFY_HANDLER ? kacpi_notify_wq : kacpid_wq); | 759 | (type == OSL_NOTIFY_HANDLER ? kacpi_notify_wq : kacpid_wq); |
781 | func = hp ? acpi_os_execute_hp_deferred : acpi_os_execute_deferred; | 760 | dpc->wait = hp ? 1 : 0; |
782 | INIT_WORK(&dpc->work, func); | 761 | INIT_WORK(&dpc->work, acpi_os_execute_deferred); |
783 | ret = queue_work(queue, &dpc->work); | 762 | ret = queue_work(queue, &dpc->work); |
784 | 763 | ||
785 | if (!ret) { | 764 | if (!ret) { |
@@ -1358,6 +1337,89 @@ acpi_os_validate_interface (char *interface) | |||
1358 | return AE_SUPPORT; | 1337 | return AE_SUPPORT; |
1359 | } | 1338 | } |
1360 | 1339 | ||
1340 | static inline int acpi_res_list_add(struct acpi_res_list *res) | ||
1341 | { | ||
1342 | struct acpi_res_list *res_list_elem; | ||
1343 | |||
1344 | list_for_each_entry(res_list_elem, &resource_list_head, | ||
1345 | resource_list) { | ||
1346 | |||
1347 | if (res->resource_type == res_list_elem->resource_type && | ||
1348 | res->start == res_list_elem->start && | ||
1349 | res->end == res_list_elem->end) { | ||
1350 | |||
1351 | /* | ||
1352 | * The Region(addr,len) already exist in the list, | ||
1353 | * just increase the count | ||
1354 | */ | ||
1355 | |||
1356 | res_list_elem->count++; | ||
1357 | return 0; | ||
1358 | } | ||
1359 | } | ||
1360 | |||
1361 | res->count = 1; | ||
1362 | list_add(&res->resource_list, &resource_list_head); | ||
1363 | return 1; | ||
1364 | } | ||
1365 | |||
1366 | static inline void acpi_res_list_del(struct acpi_res_list *res) | ||
1367 | { | ||
1368 | struct acpi_res_list *res_list_elem; | ||
1369 | |||
1370 | list_for_each_entry(res_list_elem, &resource_list_head, | ||
1371 | resource_list) { | ||
1372 | |||
1373 | if (res->resource_type == res_list_elem->resource_type && | ||
1374 | res->start == res_list_elem->start && | ||
1375 | res->end == res_list_elem->end) { | ||
1376 | |||
1377 | /* | ||
1378 | * If the res count is decreased to 0, | ||
1379 | * remove and free it | ||
1380 | */ | ||
1381 | |||
1382 | if (--res_list_elem->count == 0) { | ||
1383 | list_del(&res_list_elem->resource_list); | ||
1384 | kfree(res_list_elem); | ||
1385 | } | ||
1386 | return; | ||
1387 | } | ||
1388 | } | ||
1389 | } | ||
1390 | |||
1391 | acpi_status | ||
1392 | acpi_os_invalidate_address( | ||
1393 | u8 space_id, | ||
1394 | acpi_physical_address address, | ||
1395 | acpi_size length) | ||
1396 | { | ||
1397 | struct acpi_res_list res; | ||
1398 | |||
1399 | switch (space_id) { | ||
1400 | case ACPI_ADR_SPACE_SYSTEM_IO: | ||
1401 | case ACPI_ADR_SPACE_SYSTEM_MEMORY: | ||
1402 | /* Only interference checks against SystemIO and SytemMemory | ||
1403 | are needed */ | ||
1404 | res.start = address; | ||
1405 | res.end = address + length - 1; | ||
1406 | res.resource_type = space_id; | ||
1407 | spin_lock(&acpi_res_lock); | ||
1408 | acpi_res_list_del(&res); | ||
1409 | spin_unlock(&acpi_res_lock); | ||
1410 | break; | ||
1411 | case ACPI_ADR_SPACE_PCI_CONFIG: | ||
1412 | case ACPI_ADR_SPACE_EC: | ||
1413 | case ACPI_ADR_SPACE_SMBUS: | ||
1414 | case ACPI_ADR_SPACE_CMOS: | ||
1415 | case ACPI_ADR_SPACE_PCI_BAR_TARGET: | ||
1416 | case ACPI_ADR_SPACE_DATA_TABLE: | ||
1417 | case ACPI_ADR_SPACE_FIXED_HARDWARE: | ||
1418 | break; | ||
1419 | } | ||
1420 | return AE_OK; | ||
1421 | } | ||
1422 | |||
1361 | /****************************************************************************** | 1423 | /****************************************************************************** |
1362 | * | 1424 | * |
1363 | * FUNCTION: acpi_os_validate_address | 1425 | * FUNCTION: acpi_os_validate_address |
@@ -1382,6 +1444,7 @@ acpi_os_validate_address ( | |||
1382 | char *name) | 1444 | char *name) |
1383 | { | 1445 | { |
1384 | struct acpi_res_list *res; | 1446 | struct acpi_res_list *res; |
1447 | int added; | ||
1385 | if (acpi_enforce_resources == ENFORCE_RESOURCES_NO) | 1448 | if (acpi_enforce_resources == ENFORCE_RESOURCES_NO) |
1386 | return AE_OK; | 1449 | return AE_OK; |
1387 | 1450 | ||
@@ -1399,14 +1462,17 @@ acpi_os_validate_address ( | |||
1399 | res->end = address + length - 1; | 1462 | res->end = address + length - 1; |
1400 | res->resource_type = space_id; | 1463 | res->resource_type = space_id; |
1401 | spin_lock(&acpi_res_lock); | 1464 | spin_lock(&acpi_res_lock); |
1402 | list_add(&res->resource_list, &resource_list_head); | 1465 | added = acpi_res_list_add(res); |
1403 | spin_unlock(&acpi_res_lock); | 1466 | spin_unlock(&acpi_res_lock); |
1404 | pr_debug("Added %s resource: start: 0x%llx, end: 0x%llx, " | 1467 | pr_debug("%s %s resource: start: 0x%llx, end: 0x%llx, " |
1405 | "name: %s\n", (space_id == ACPI_ADR_SPACE_SYSTEM_IO) | 1468 | "name: %s\n", added ? "Added" : "Already exist", |
1469 | (space_id == ACPI_ADR_SPACE_SYSTEM_IO) | ||
1406 | ? "SystemIO" : "System Memory", | 1470 | ? "SystemIO" : "System Memory", |
1407 | (unsigned long long)res->start, | 1471 | (unsigned long long)res->start, |
1408 | (unsigned long long)res->end, | 1472 | (unsigned long long)res->end, |
1409 | res->name); | 1473 | res->name); |
1474 | if (!added) | ||
1475 | kfree(res); | ||
1410 | break; | 1476 | break; |
1411 | case ACPI_ADR_SPACE_PCI_CONFIG: | 1477 | case ACPI_ADR_SPACE_PCI_CONFIG: |
1412 | case ACPI_ADR_SPACE_EC: | 1478 | case ACPI_ADR_SPACE_EC: |