diff options
Diffstat (limited to 'drivers/acpi/osl.c')
-rw-r--r-- | drivers/acpi/osl.c | 242 |
1 files changed, 38 insertions, 204 deletions
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index f31c5c5f1b7e..fcc12d842bcc 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c | |||
@@ -83,19 +83,6 @@ static struct workqueue_struct *kacpi_notify_wq; | |||
83 | struct workqueue_struct *kacpi_hotplug_wq; | 83 | struct workqueue_struct *kacpi_hotplug_wq; |
84 | EXPORT_SYMBOL(kacpi_hotplug_wq); | 84 | EXPORT_SYMBOL(kacpi_hotplug_wq); |
85 | 85 | ||
86 | struct acpi_res_list { | ||
87 | resource_size_t start; | ||
88 | resource_size_t end; | ||
89 | acpi_adr_space_type resource_type; /* IO port, System memory, ...*/ | ||
90 | char name[5]; /* only can have a length of 4 chars, make use of this | ||
91 | one instead of res->name, no need to kalloc then */ | ||
92 | struct list_head resource_list; | ||
93 | int count; | ||
94 | }; | ||
95 | |||
96 | static LIST_HEAD(resource_list_head); | ||
97 | static DEFINE_SPINLOCK(acpi_res_lock); | ||
98 | |||
99 | /* | 86 | /* |
100 | * This list of permanent mappings is for memory that may be accessed from | 87 | * This list of permanent mappings is for memory that may be accessed from |
101 | * interrupt context, where we can't do the ioremap(). | 88 | * interrupt context, where we can't do the ioremap(). |
@@ -166,17 +153,21 @@ static u32 acpi_osi_handler(acpi_string interface, u32 supported) | |||
166 | return supported; | 153 | return supported; |
167 | } | 154 | } |
168 | 155 | ||
169 | static void __init acpi_request_region (struct acpi_generic_address *addr, | 156 | static void __init acpi_request_region (struct acpi_generic_address *gas, |
170 | unsigned int length, char *desc) | 157 | unsigned int length, char *desc) |
171 | { | 158 | { |
172 | if (!addr->address || !length) | 159 | u64 addr; |
160 | |||
161 | /* Handle possible alignment issues */ | ||
162 | memcpy(&addr, &gas->address, sizeof(addr)); | ||
163 | if (!addr || !length) | ||
173 | return; | 164 | return; |
174 | 165 | ||
175 | /* Resources are never freed */ | 166 | /* Resources are never freed */ |
176 | if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_IO) | 167 | if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) |
177 | request_region(addr->address, length, desc); | 168 | request_region(addr, length, desc); |
178 | else if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) | 169 | else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) |
179 | request_mem_region(addr->address, length, desc); | 170 | request_mem_region(addr, length, desc); |
180 | } | 171 | } |
181 | 172 | ||
182 | static int __init acpi_reserve_resources(void) | 173 | static int __init acpi_reserve_resources(void) |
@@ -427,35 +418,42 @@ void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size) | |||
427 | __acpi_unmap_table(virt, size); | 418 | __acpi_unmap_table(virt, size); |
428 | } | 419 | } |
429 | 420 | ||
430 | static int acpi_os_map_generic_address(struct acpi_generic_address *addr) | 421 | int acpi_os_map_generic_address(struct acpi_generic_address *gas) |
431 | { | 422 | { |
423 | u64 addr; | ||
432 | void __iomem *virt; | 424 | void __iomem *virt; |
433 | 425 | ||
434 | if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) | 426 | if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) |
435 | return 0; | 427 | return 0; |
436 | 428 | ||
437 | if (!addr->address || !addr->bit_width) | 429 | /* Handle possible alignment issues */ |
430 | memcpy(&addr, &gas->address, sizeof(addr)); | ||
431 | if (!addr || !gas->bit_width) | ||
438 | return -EINVAL; | 432 | return -EINVAL; |
439 | 433 | ||
440 | virt = acpi_os_map_memory(addr->address, addr->bit_width / 8); | 434 | virt = acpi_os_map_memory(addr, gas->bit_width / 8); |
441 | if (!virt) | 435 | if (!virt) |
442 | return -EIO; | 436 | return -EIO; |
443 | 437 | ||
444 | return 0; | 438 | return 0; |
445 | } | 439 | } |
440 | EXPORT_SYMBOL(acpi_os_map_generic_address); | ||
446 | 441 | ||
447 | static void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) | 442 | void acpi_os_unmap_generic_address(struct acpi_generic_address *gas) |
448 | { | 443 | { |
444 | u64 addr; | ||
449 | struct acpi_ioremap *map; | 445 | struct acpi_ioremap *map; |
450 | 446 | ||
451 | if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) | 447 | if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) |
452 | return; | 448 | return; |
453 | 449 | ||
454 | if (!addr->address || !addr->bit_width) | 450 | /* Handle possible alignment issues */ |
451 | memcpy(&addr, &gas->address, sizeof(addr)); | ||
452 | if (!addr || !gas->bit_width) | ||
455 | return; | 453 | return; |
456 | 454 | ||
457 | mutex_lock(&acpi_ioremap_lock); | 455 | mutex_lock(&acpi_ioremap_lock); |
458 | map = acpi_map_lookup(addr->address, addr->bit_width / 8); | 456 | map = acpi_map_lookup(addr, gas->bit_width / 8); |
459 | if (!map) { | 457 | if (!map) { |
460 | mutex_unlock(&acpi_ioremap_lock); | 458 | mutex_unlock(&acpi_ioremap_lock); |
461 | return; | 459 | return; |
@@ -465,6 +463,7 @@ static void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) | |||
465 | 463 | ||
466 | acpi_os_map_cleanup(map); | 464 | acpi_os_map_cleanup(map); |
467 | } | 465 | } |
466 | EXPORT_SYMBOL(acpi_os_unmap_generic_address); | ||
468 | 467 | ||
469 | #ifdef ACPI_FUTURE_USAGE | 468 | #ifdef ACPI_FUTURE_USAGE |
470 | acpi_status | 469 | acpi_status |
@@ -1278,44 +1277,28 @@ __setup("acpi_enforce_resources=", acpi_enforce_resources_setup); | |||
1278 | * drivers */ | 1277 | * drivers */ |
1279 | int acpi_check_resource_conflict(const struct resource *res) | 1278 | int acpi_check_resource_conflict(const struct resource *res) |
1280 | { | 1279 | { |
1281 | struct acpi_res_list *res_list_elem; | 1280 | acpi_adr_space_type space_id; |
1282 | int ioport = 0, clash = 0; | 1281 | acpi_size length; |
1282 | u8 warn = 0; | ||
1283 | int clash = 0; | ||
1283 | 1284 | ||
1284 | if (acpi_enforce_resources == ENFORCE_RESOURCES_NO) | 1285 | if (acpi_enforce_resources == ENFORCE_RESOURCES_NO) |
1285 | return 0; | 1286 | return 0; |
1286 | if (!(res->flags & IORESOURCE_IO) && !(res->flags & IORESOURCE_MEM)) | 1287 | if (!(res->flags & IORESOURCE_IO) && !(res->flags & IORESOURCE_MEM)) |
1287 | return 0; | 1288 | return 0; |
1288 | 1289 | ||
1289 | ioport = res->flags & IORESOURCE_IO; | 1290 | if (res->flags & IORESOURCE_IO) |
1290 | 1291 | space_id = ACPI_ADR_SPACE_SYSTEM_IO; | |
1291 | spin_lock(&acpi_res_lock); | 1292 | else |
1292 | list_for_each_entry(res_list_elem, &resource_list_head, | 1293 | space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY; |
1293 | resource_list) { | ||
1294 | if (ioport && (res_list_elem->resource_type | ||
1295 | != ACPI_ADR_SPACE_SYSTEM_IO)) | ||
1296 | continue; | ||
1297 | if (!ioport && (res_list_elem->resource_type | ||
1298 | != ACPI_ADR_SPACE_SYSTEM_MEMORY)) | ||
1299 | continue; | ||
1300 | 1294 | ||
1301 | if (res->end < res_list_elem->start | 1295 | length = res->end - res->start + 1; |
1302 | || res_list_elem->end < res->start) | 1296 | if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) |
1303 | continue; | 1297 | warn = 1; |
1304 | clash = 1; | 1298 | clash = acpi_check_address_range(space_id, res->start, length, warn); |
1305 | break; | ||
1306 | } | ||
1307 | spin_unlock(&acpi_res_lock); | ||
1308 | 1299 | ||
1309 | if (clash) { | 1300 | if (clash) { |
1310 | if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) { | 1301 | if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) { |
1311 | printk(KERN_WARNING "ACPI: resource %s %pR" | ||
1312 | " conflicts with ACPI region %s " | ||
1313 | "[%s 0x%zx-0x%zx]\n", | ||
1314 | res->name, res, res_list_elem->name, | ||
1315 | (res_list_elem->resource_type == | ||
1316 | ACPI_ADR_SPACE_SYSTEM_IO) ? "io" : "mem", | ||
1317 | (size_t) res_list_elem->start, | ||
1318 | (size_t) res_list_elem->end); | ||
1319 | if (acpi_enforce_resources == ENFORCE_RESOURCES_LAX) | 1302 | if (acpi_enforce_resources == ENFORCE_RESOURCES_LAX) |
1320 | printk(KERN_NOTICE "ACPI: This conflict may" | 1303 | printk(KERN_NOTICE "ACPI: This conflict may" |
1321 | " cause random problems and system" | 1304 | " cause random problems and system" |
@@ -1467,155 +1450,6 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object) | |||
1467 | kmem_cache_free(cache, object); | 1450 | kmem_cache_free(cache, object); |
1468 | return (AE_OK); | 1451 | return (AE_OK); |
1469 | } | 1452 | } |
1470 | |||
1471 | static inline int acpi_res_list_add(struct acpi_res_list *res) | ||
1472 | { | ||
1473 | struct acpi_res_list *res_list_elem; | ||
1474 | |||
1475 | list_for_each_entry(res_list_elem, &resource_list_head, | ||
1476 | resource_list) { | ||
1477 | |||
1478 | if (res->resource_type == res_list_elem->resource_type && | ||
1479 | res->start == res_list_elem->start && | ||
1480 | res->end == res_list_elem->end) { | ||
1481 | |||
1482 | /* | ||
1483 | * The Region(addr,len) already exist in the list, | ||
1484 | * just increase the count | ||
1485 | */ | ||
1486 | |||
1487 | res_list_elem->count++; | ||
1488 | return 0; | ||
1489 | } | ||
1490 | } | ||
1491 | |||
1492 | res->count = 1; | ||
1493 | list_add(&res->resource_list, &resource_list_head); | ||
1494 | return 1; | ||
1495 | } | ||
1496 | |||
1497 | static inline void acpi_res_list_del(struct acpi_res_list *res) | ||
1498 | { | ||
1499 | struct acpi_res_list *res_list_elem; | ||
1500 | |||
1501 | list_for_each_entry(res_list_elem, &resource_list_head, | ||
1502 | resource_list) { | ||
1503 | |||
1504 | if (res->resource_type == res_list_elem->resource_type && | ||
1505 | res->start == res_list_elem->start && | ||
1506 | res->end == res_list_elem->end) { | ||
1507 | |||
1508 | /* | ||
1509 | * If the res count is decreased to 0, | ||
1510 | * remove and free it | ||
1511 | */ | ||
1512 | |||
1513 | if (--res_list_elem->count == 0) { | ||
1514 | list_del(&res_list_elem->resource_list); | ||
1515 | kfree(res_list_elem); | ||
1516 | } | ||
1517 | return; | ||
1518 | } | ||
1519 | } | ||
1520 | } | ||
1521 | |||
1522 | acpi_status | ||
1523 | acpi_os_invalidate_address( | ||
1524 | u8 space_id, | ||
1525 | acpi_physical_address address, | ||
1526 | acpi_size length) | ||
1527 | { | ||
1528 | struct acpi_res_list res; | ||
1529 | |||
1530 | switch (space_id) { | ||
1531 | case ACPI_ADR_SPACE_SYSTEM_IO: | ||
1532 | case ACPI_ADR_SPACE_SYSTEM_MEMORY: | ||
1533 | /* Only interference checks against SystemIO and SystemMemory | ||
1534 | are needed */ | ||
1535 | res.start = address; | ||
1536 | res.end = address + length - 1; | ||
1537 | res.resource_type = space_id; | ||
1538 | spin_lock(&acpi_res_lock); | ||
1539 | acpi_res_list_del(&res); | ||
1540 | spin_unlock(&acpi_res_lock); | ||
1541 | break; | ||
1542 | case ACPI_ADR_SPACE_PCI_CONFIG: | ||
1543 | case ACPI_ADR_SPACE_EC: | ||
1544 | case ACPI_ADR_SPACE_SMBUS: | ||
1545 | case ACPI_ADR_SPACE_CMOS: | ||
1546 | case ACPI_ADR_SPACE_PCI_BAR_TARGET: | ||
1547 | case ACPI_ADR_SPACE_DATA_TABLE: | ||
1548 | case ACPI_ADR_SPACE_FIXED_HARDWARE: | ||
1549 | break; | ||
1550 | } | ||
1551 | return AE_OK; | ||
1552 | } | ||
1553 | |||
1554 | /****************************************************************************** | ||
1555 | * | ||
1556 | * FUNCTION: acpi_os_validate_address | ||
1557 | * | ||
1558 | * PARAMETERS: space_id - ACPI space ID | ||
1559 | * address - Physical address | ||
1560 | * length - Address length | ||
1561 | * | ||
1562 | * RETURN: AE_OK if address/length is valid for the space_id. Otherwise, | ||
1563 | * should return AE_AML_ILLEGAL_ADDRESS. | ||
1564 | * | ||
1565 | * DESCRIPTION: Validate a system address via the host OS. Used to validate | ||
1566 | * the addresses accessed by AML operation regions. | ||
1567 | * | ||
1568 | *****************************************************************************/ | ||
1569 | |||
1570 | acpi_status | ||
1571 | acpi_os_validate_address ( | ||
1572 | u8 space_id, | ||
1573 | acpi_physical_address address, | ||
1574 | acpi_size length, | ||
1575 | char *name) | ||
1576 | { | ||
1577 | struct acpi_res_list *res; | ||
1578 | int added; | ||
1579 | if (acpi_enforce_resources == ENFORCE_RESOURCES_NO) | ||
1580 | return AE_OK; | ||
1581 | |||
1582 | switch (space_id) { | ||
1583 | case ACPI_ADR_SPACE_SYSTEM_IO: | ||
1584 | case ACPI_ADR_SPACE_SYSTEM_MEMORY: | ||
1585 | /* Only interference checks against SystemIO and SystemMemory | ||
1586 | are needed */ | ||
1587 | res = kzalloc(sizeof(struct acpi_res_list), GFP_KERNEL); | ||
1588 | if (!res) | ||
1589 | return AE_OK; | ||
1590 | /* ACPI names are fixed to 4 bytes, still better use strlcpy */ | ||
1591 | strlcpy(res->name, name, 5); | ||
1592 | res->start = address; | ||
1593 | res->end = address + length - 1; | ||
1594 | res->resource_type = space_id; | ||
1595 | spin_lock(&acpi_res_lock); | ||
1596 | added = acpi_res_list_add(res); | ||
1597 | spin_unlock(&acpi_res_lock); | ||
1598 | pr_debug("%s %s resource: start: 0x%llx, end: 0x%llx, " | ||
1599 | "name: %s\n", added ? "Added" : "Already exist", | ||
1600 | (space_id == ACPI_ADR_SPACE_SYSTEM_IO) | ||
1601 | ? "SystemIO" : "System Memory", | ||
1602 | (unsigned long long)res->start, | ||
1603 | (unsigned long long)res->end, | ||
1604 | res->name); | ||
1605 | if (!added) | ||
1606 | kfree(res); | ||
1607 | break; | ||
1608 | case ACPI_ADR_SPACE_PCI_CONFIG: | ||
1609 | case ACPI_ADR_SPACE_EC: | ||
1610 | case ACPI_ADR_SPACE_SMBUS: | ||
1611 | case ACPI_ADR_SPACE_CMOS: | ||
1612 | case ACPI_ADR_SPACE_PCI_BAR_TARGET: | ||
1613 | case ACPI_ADR_SPACE_DATA_TABLE: | ||
1614 | case ACPI_ADR_SPACE_FIXED_HARDWARE: | ||
1615 | break; | ||
1616 | } | ||
1617 | return AE_OK; | ||
1618 | } | ||
1619 | #endif | 1453 | #endif |
1620 | 1454 | ||
1621 | acpi_status __init acpi_os_initialize(void) | 1455 | acpi_status __init acpi_os_initialize(void) |