ioremap.c 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. // SPDX-License-Identifier: GPL-2.0
  2. // Copyright (C) 2005-2017 Andes Technology Corporation
  3. #include <linux/vmalloc.h>
  4. #include <linux/io.h>
  5. #include <linux/mm.h>
  6. #include <asm/pgtable.h>
  7. void __iomem *ioremap(phys_addr_t phys_addr, size_t size);
  8. static void __iomem *__ioremap_caller(phys_addr_t phys_addr, size_t size,
  9. void *caller)
  10. {
  11. struct vm_struct *area;
  12. unsigned long addr, offset, last_addr;
  13. pgprot_t prot;
  14. /* Don't allow wraparound or zero size */
  15. last_addr = phys_addr + size - 1;
  16. if (!size || last_addr < phys_addr)
  17. return NULL;
  18. /*
  19. * Mappings have to be page-aligned
  20. */
  21. offset = phys_addr & ~PAGE_MASK;
  22. phys_addr &= PAGE_MASK;
  23. size = PAGE_ALIGN(last_addr + 1) - phys_addr;
  24. /*
  25. * Ok, go for it..
  26. */
  27. area = get_vm_area_caller(size, VM_IOREMAP, caller);
  28. if (!area)
  29. return NULL;
  30. area->phys_addr = phys_addr;
  31. addr = (unsigned long)area->addr;
  32. prot = __pgprot(_PAGE_V | _PAGE_M_KRW | _PAGE_D |
  33. _PAGE_G | _PAGE_C_DEV);
  34. if (ioremap_page_range(addr, addr + size, phys_addr, prot)) {
  35. vunmap((void *)addr);
  36. return NULL;
  37. }
  38. return (__force void __iomem *)(offset + (char *)addr);
  39. }
  40. void __iomem *ioremap(phys_addr_t phys_addr, size_t size)
  41. {
  42. return __ioremap_caller(phys_addr, size,
  43. __builtin_return_address(0));
  44. }
  45. EXPORT_SYMBOL(ioremap);
  46. void iounmap(volatile void __iomem * addr)
  47. {
  48. vunmap((void *)(PAGE_MASK & (unsigned long)addr));
  49. }
  50. EXPORT_SYMBOL(iounmap);