diff options
Diffstat (limited to 'drivers/acpi/osl.c')
-rw-r--r-- | drivers/acpi/osl.c | 94 |
1 files changed, 91 insertions, 3 deletions
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 5691f165a952..c5b4f1ed9b71 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c | |||
@@ -88,6 +88,7 @@ struct acpi_res_list { | |||
88 | char name[5]; /* only can have a length of 4 chars, make use of this | 88 | 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 */ | 89 | one instead of res->name, no need to kalloc then */ |
90 | struct list_head resource_list; | 90 | struct list_head resource_list; |
91 | int count; | ||
91 | }; | 92 | }; |
92 | 93 | ||
93 | static LIST_HEAD(resource_list_head); | 94 | static LIST_HEAD(resource_list_head); |
@@ -1358,6 +1359,89 @@ acpi_os_validate_interface (char *interface) | |||
1358 | return AE_SUPPORT; | 1359 | return AE_SUPPORT; |
1359 | } | 1360 | } |
1360 | 1361 | ||
1362 | static inline int acpi_res_list_add(struct acpi_res_list *res) | ||
1363 | { | ||
1364 | struct acpi_res_list *res_list_elem; | ||
1365 | |||
1366 | list_for_each_entry(res_list_elem, &resource_list_head, | ||
1367 | resource_list) { | ||
1368 | |||
1369 | if (res->resource_type == res_list_elem->resource_type && | ||
1370 | res->start == res_list_elem->start && | ||
1371 | res->end == res_list_elem->end) { | ||
1372 | |||
1373 | /* | ||
1374 | * The Region(addr,len) already exist in the list, | ||
1375 | * just increase the count | ||
1376 | */ | ||
1377 | |||
1378 | res_list_elem->count++; | ||
1379 | return 0; | ||
1380 | } | ||
1381 | } | ||
1382 | |||
1383 | res->count = 1; | ||
1384 | list_add(&res->resource_list, &resource_list_head); | ||
1385 | return 1; | ||
1386 | } | ||
1387 | |||
1388 | static inline void acpi_res_list_del(struct acpi_res_list *res) | ||
1389 | { | ||
1390 | struct acpi_res_list *res_list_elem; | ||
1391 | |||
1392 | list_for_each_entry(res_list_elem, &resource_list_head, | ||
1393 | resource_list) { | ||
1394 | |||
1395 | if (res->resource_type == res_list_elem->resource_type && | ||
1396 | res->start == res_list_elem->start && | ||
1397 | res->end == res_list_elem->end) { | ||
1398 | |||
1399 | /* | ||
1400 | * If the res count is decreased to 0, | ||
1401 | * remove and free it | ||
1402 | */ | ||
1403 | |||
1404 | if (--res_list_elem->count == 0) { | ||
1405 | list_del(&res_list_elem->resource_list); | ||
1406 | kfree(res_list_elem); | ||
1407 | } | ||
1408 | return; | ||
1409 | } | ||
1410 | } | ||
1411 | } | ||
1412 | |||
1413 | acpi_status | ||
1414 | acpi_os_invalidate_address( | ||
1415 | u8 space_id, | ||
1416 | acpi_physical_address address, | ||
1417 | acpi_size length) | ||
1418 | { | ||
1419 | struct acpi_res_list res; | ||
1420 | |||
1421 | switch (space_id) { | ||
1422 | case ACPI_ADR_SPACE_SYSTEM_IO: | ||
1423 | case ACPI_ADR_SPACE_SYSTEM_MEMORY: | ||
1424 | /* Only interference checks against SystemIO and SytemMemory | ||
1425 | are needed */ | ||
1426 | res.start = address; | ||
1427 | res.end = address + length - 1; | ||
1428 | res.resource_type = space_id; | ||
1429 | spin_lock(&acpi_res_lock); | ||
1430 | acpi_res_list_del(&res); | ||
1431 | spin_unlock(&acpi_res_lock); | ||
1432 | break; | ||
1433 | case ACPI_ADR_SPACE_PCI_CONFIG: | ||
1434 | case ACPI_ADR_SPACE_EC: | ||
1435 | case ACPI_ADR_SPACE_SMBUS: | ||
1436 | case ACPI_ADR_SPACE_CMOS: | ||
1437 | case ACPI_ADR_SPACE_PCI_BAR_TARGET: | ||
1438 | case ACPI_ADR_SPACE_DATA_TABLE: | ||
1439 | case ACPI_ADR_SPACE_FIXED_HARDWARE: | ||
1440 | break; | ||
1441 | } | ||
1442 | return AE_OK; | ||
1443 | } | ||
1444 | |||
1361 | /****************************************************************************** | 1445 | /****************************************************************************** |
1362 | * | 1446 | * |
1363 | * FUNCTION: acpi_os_validate_address | 1447 | * FUNCTION: acpi_os_validate_address |
@@ -1382,6 +1466,7 @@ acpi_os_validate_address ( | |||
1382 | char *name) | 1466 | char *name) |
1383 | { | 1467 | { |
1384 | struct acpi_res_list *res; | 1468 | struct acpi_res_list *res; |
1469 | int added; | ||
1385 | if (acpi_enforce_resources == ENFORCE_RESOURCES_NO) | 1470 | if (acpi_enforce_resources == ENFORCE_RESOURCES_NO) |
1386 | return AE_OK; | 1471 | return AE_OK; |
1387 | 1472 | ||
@@ -1399,14 +1484,17 @@ acpi_os_validate_address ( | |||
1399 | res->end = address + length - 1; | 1484 | res->end = address + length - 1; |
1400 | res->resource_type = space_id; | 1485 | res->resource_type = space_id; |
1401 | spin_lock(&acpi_res_lock); | 1486 | spin_lock(&acpi_res_lock); |
1402 | list_add(&res->resource_list, &resource_list_head); | 1487 | added = acpi_res_list_add(res); |
1403 | spin_unlock(&acpi_res_lock); | 1488 | spin_unlock(&acpi_res_lock); |
1404 | pr_debug("Added %s resource: start: 0x%llx, end: 0x%llx, " | 1489 | pr_debug("%s %s resource: start: 0x%llx, end: 0x%llx, " |
1405 | "name: %s\n", (space_id == ACPI_ADR_SPACE_SYSTEM_IO) | 1490 | "name: %s\n", added ? "Added" : "Already exist", |
1491 | (space_id == ACPI_ADR_SPACE_SYSTEM_IO) | ||
1406 | ? "SystemIO" : "System Memory", | 1492 | ? "SystemIO" : "System Memory", |
1407 | (unsigned long long)res->start, | 1493 | (unsigned long long)res->start, |
1408 | (unsigned long long)res->end, | 1494 | (unsigned long long)res->end, |
1409 | res->name); | 1495 | res->name); |
1496 | if (!added) | ||
1497 | kfree(res); | ||
1410 | break; | 1498 | break; |
1411 | case ACPI_ADR_SPACE_PCI_CONFIG: | 1499 | case ACPI_ADR_SPACE_PCI_CONFIG: |
1412 | case ACPI_ADR_SPACE_EC: | 1500 | case ACPI_ADR_SPACE_EC: |