aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/osl.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2011-02-08 17:37:16 -0500
committerRafael J. Wysocki <rjw@sisk.pl>2011-02-08 17:37:16 -0500
commit884b821fa27a5e3714d4871976d3e7c3abfa0d1b (patch)
tree3ac23b3a2a3fc881efb3a255d5ad42bde8737051 /drivers/acpi/osl.c
parent100b33c8bd8a3235fd0b7948338d6cbb3db3c63d (diff)
ACPI: Fix acpi_os_read_memory() and acpi_os_write_memory() (v2)
The functions acpi_os_read_memory() and acpi_os_write_memory() do two wrong things. First, they shouldn't call rcu_read_unlock() before the looked up address is actually used for I/O, because in that case the iomap it belongs to may be removed before the I/O is done. Second, if they have to create a new mapping, they should check the returned virtual address and tell the caller that the operation failed if it is NULL (in fact, I think they even should not attempt to map an address that's not present in one of the existing ACPI iomaps, because that may cause problems to happen when they are called from nonpreemptible context and their callers ought to know what they are doing and map the requisite memory regions beforehand). Make these functions call rcu_read_unlock() when the I/O is complete (or if it's necessary to map the given address "on the fly") and return an error code if the requested physical address is not present in the existing ACPI iomaps and cannot be mapped. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'drivers/acpi/osl.c')
-rw-r--r--drivers/acpi/osl.c25
1 files changed, 18 insertions, 7 deletions
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index b0931818cf98..c90c76aa7f8b 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -636,17 +636,21 @@ EXPORT_SYMBOL(acpi_os_write_port);
636acpi_status 636acpi_status
637acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width) 637acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)
638{ 638{
639 u32 dummy;
640 void __iomem *virt_addr; 639 void __iomem *virt_addr;
641 int size = width / 8, unmap = 0; 640 unsigned int size = width / 8;
641 bool unmap = false;
642 u32 dummy;
642 643
643 rcu_read_lock(); 644 rcu_read_lock();
644 virt_addr = acpi_map_vaddr_lookup(phys_addr, size); 645 virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
645 rcu_read_unlock();
646 if (!virt_addr) { 646 if (!virt_addr) {
647 rcu_read_unlock();
647 virt_addr = acpi_os_ioremap(phys_addr, size); 648 virt_addr = acpi_os_ioremap(phys_addr, size);
648 unmap = 1; 649 if (!virt_addr)
650 return AE_BAD_ADDRESS;
651 unmap = true;
649 } 652 }
653
650 if (!value) 654 if (!value)
651 value = &dummy; 655 value = &dummy;
652 656
@@ -666,6 +670,8 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)
666 670
667 if (unmap) 671 if (unmap)
668 iounmap(virt_addr); 672 iounmap(virt_addr);
673 else
674 rcu_read_unlock();
669 675
670 return AE_OK; 676 return AE_OK;
671} 677}
@@ -674,14 +680,17 @@ acpi_status
674acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width) 680acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
675{ 681{
676 void __iomem *virt_addr; 682 void __iomem *virt_addr;
677 int size = width / 8, unmap = 0; 683 unsigned int size = width / 8;
684 bool unmap = false;
678 685
679 rcu_read_lock(); 686 rcu_read_lock();
680 virt_addr = acpi_map_vaddr_lookup(phys_addr, size); 687 virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
681 rcu_read_unlock();
682 if (!virt_addr) { 688 if (!virt_addr) {
689 rcu_read_unlock();
683 virt_addr = acpi_os_ioremap(phys_addr, size); 690 virt_addr = acpi_os_ioremap(phys_addr, size);
684 unmap = 1; 691 if (!virt_addr)
692 return AE_BAD_ADDRESS;
693 unmap = true;
685 } 694 }
686 695
687 switch (width) { 696 switch (width) {
@@ -700,6 +709,8 @@ acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
700 709
701 if (unmap) 710 if (unmap)
702 iounmap(virt_addr); 711 iounmap(virt_addr);
712 else
713 rcu_read_unlock();
703 714
704 return AE_OK; 715 return AE_OK;
705} 716}