aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/osl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/osl.c')
-rw-r--r--drivers/acpi/osl.c152
1 files changed, 150 insertions, 2 deletions
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index fcc12d842bcc..412a1e04a922 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -31,6 +31,7 @@
31#include <linux/kernel.h> 31#include <linux/kernel.h>
32#include <linux/slab.h> 32#include <linux/slab.h>
33#include <linux/mm.h> 33#include <linux/mm.h>
34#include <linux/highmem.h>
34#include <linux/pci.h> 35#include <linux/pci.h>
35#include <linux/interrupt.h> 36#include <linux/interrupt.h>
36#include <linux/kmod.h> 37#include <linux/kmod.h>
@@ -321,6 +322,37 @@ acpi_map_lookup_virt(void __iomem *virt, acpi_size size)
321 return NULL; 322 return NULL;
322} 323}
323 324
325#ifndef CONFIG_IA64
326#define should_use_kmap(pfn) page_is_ram(pfn)
327#else
328/* ioremap will take care of cache attributes */
329#define should_use_kmap(pfn) 0
330#endif
331
332static void __iomem *acpi_map(acpi_physical_address pg_off, unsigned long pg_sz)
333{
334 unsigned long pfn;
335
336 pfn = pg_off >> PAGE_SHIFT;
337 if (should_use_kmap(pfn)) {
338 if (pg_sz > PAGE_SIZE)
339 return NULL;
340 return (void __iomem __force *)kmap(pfn_to_page(pfn));
341 } else
342 return acpi_os_ioremap(pg_off, pg_sz);
343}
344
345static void acpi_unmap(acpi_physical_address pg_off, void __iomem *vaddr)
346{
347 unsigned long pfn;
348
349 pfn = pg_off >> PAGE_SHIFT;
350 if (page_is_ram(pfn))
351 kunmap(pfn_to_page(pfn));
352 else
353 iounmap(vaddr);
354}
355
324void __iomem *__init_refok 356void __iomem *__init_refok
325acpi_os_map_memory(acpi_physical_address phys, acpi_size size) 357acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
326{ 358{
@@ -353,7 +385,7 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
353 385
354 pg_off = round_down(phys, PAGE_SIZE); 386 pg_off = round_down(phys, PAGE_SIZE);
355 pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off; 387 pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off;
356 virt = acpi_os_ioremap(pg_off, pg_sz); 388 virt = acpi_map(pg_off, pg_sz);
357 if (!virt) { 389 if (!virt) {
358 mutex_unlock(&acpi_ioremap_lock); 390 mutex_unlock(&acpi_ioremap_lock);
359 kfree(map); 391 kfree(map);
@@ -384,7 +416,7 @@ static void acpi_os_map_cleanup(struct acpi_ioremap *map)
384{ 416{
385 if (!map->refcount) { 417 if (!map->refcount) {
386 synchronize_rcu(); 418 synchronize_rcu();
387 iounmap(map->virt); 419 acpi_unmap(map->phys, map->virt);
388 kfree(map); 420 kfree(map);
389 } 421 }
390} 422}
@@ -710,6 +742,67 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)
710 return AE_OK; 742 return AE_OK;
711} 743}
712 744
745#ifdef readq
746static inline u64 read64(const volatile void __iomem *addr)
747{
748 return readq(addr);
749}
750#else
751static inline u64 read64(const volatile void __iomem *addr)
752{
753 u64 l, h;
754 l = readl(addr);
755 h = readl(addr+4);
756 return l | (h << 32);
757}
758#endif
759
760acpi_status
761acpi_os_read_memory64(acpi_physical_address phys_addr, u64 *value, u32 width)
762{
763 void __iomem *virt_addr;
764 unsigned int size = width / 8;
765 bool unmap = false;
766 u64 dummy;
767
768 rcu_read_lock();
769 virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
770 if (!virt_addr) {
771 rcu_read_unlock();
772 virt_addr = acpi_os_ioremap(phys_addr, size);
773 if (!virt_addr)
774 return AE_BAD_ADDRESS;
775 unmap = true;
776 }
777
778 if (!value)
779 value = &dummy;
780
781 switch (width) {
782 case 8:
783 *(u8 *) value = readb(virt_addr);
784 break;
785 case 16:
786 *(u16 *) value = readw(virt_addr);
787 break;
788 case 32:
789 *(u32 *) value = readl(virt_addr);
790 break;
791 case 64:
792 *(u64 *) value = read64(virt_addr);
793 break;
794 default:
795 BUG();
796 }
797
798 if (unmap)
799 iounmap(virt_addr);
800 else
801 rcu_read_unlock();
802
803 return AE_OK;
804}
805
713acpi_status 806acpi_status
714acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width) 807acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
715{ 808{
@@ -749,6 +842,61 @@ acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
749 return AE_OK; 842 return AE_OK;
750} 843}
751 844
845#ifdef writeq
846static inline void write64(u64 val, volatile void __iomem *addr)
847{
848 writeq(val, addr);
849}
850#else
851static inline void write64(u64 val, volatile void __iomem *addr)
852{
853 writel(val, addr);
854 writel(val>>32, addr+4);
855}
856#endif
857
858acpi_status
859acpi_os_write_memory64(acpi_physical_address phys_addr, u64 value, u32 width)
860{
861 void __iomem *virt_addr;
862 unsigned int size = width / 8;
863 bool unmap = false;
864
865 rcu_read_lock();
866 virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
867 if (!virt_addr) {
868 rcu_read_unlock();
869 virt_addr = acpi_os_ioremap(phys_addr, size);
870 if (!virt_addr)
871 return AE_BAD_ADDRESS;
872 unmap = true;
873 }
874
875 switch (width) {
876 case 8:
877 writeb(value, virt_addr);
878 break;
879 case 16:
880 writew(value, virt_addr);
881 break;
882 case 32:
883 writel(value, virt_addr);
884 break;
885 case 64:
886 write64(value, virt_addr);
887 break;
888 default:
889 BUG();
890 }
891
892 if (unmap)
893 iounmap(virt_addr);
894 else
895 rcu_read_unlock();
896
897 return AE_OK;
898}
899
752acpi_status 900acpi_status
753acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, 901acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
754 u64 *value, u32 width) 902 u64 *value, u32 width)