pci_mmio.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. /*
  2. * Access to PCI I/O memory from user space programs.
  3. *
  4. * Copyright IBM Corp. 2014
  5. * Author(s): Alexey Ishchuk <aishchuk@linux.vnet.ibm.com>
  6. */
  7. #include <linux/kernel.h>
  8. #include <linux/syscalls.h>
  9. #include <linux/init.h>
  10. #include <linux/mm.h>
  11. #include <linux/errno.h>
  12. #include <linux/pci.h>
  13. static long get_pfn(unsigned long user_addr, unsigned long access,
  14. unsigned long *pfn)
  15. {
  16. struct vm_area_struct *vma;
  17. long ret;
  18. down_read(&current->mm->mmap_sem);
  19. ret = -EINVAL;
  20. vma = find_vma(current->mm, user_addr);
  21. if (!vma)
  22. goto out;
  23. ret = -EACCES;
  24. if (!(vma->vm_flags & access))
  25. goto out;
  26. ret = follow_pfn(vma, user_addr, pfn);
  27. out:
  28. up_read(&current->mm->mmap_sem);
  29. return ret;
  30. }
  31. SYSCALL_DEFINE3(s390_pci_mmio_write, unsigned long, mmio_addr,
  32. const void __user *, user_buffer, size_t, length)
  33. {
  34. u8 local_buf[64];
  35. void __iomem *io_addr;
  36. void *buf;
  37. unsigned long pfn;
  38. long ret;
  39. if (!zpci_is_enabled())
  40. return -ENODEV;
  41. if (length <= 0 || PAGE_SIZE - (mmio_addr & ~PAGE_MASK) < length)
  42. return -EINVAL;
  43. if (length > 64) {
  44. buf = kmalloc(length, GFP_KERNEL);
  45. if (!buf)
  46. return -ENOMEM;
  47. } else
  48. buf = local_buf;
  49. ret = get_pfn(mmio_addr, VM_WRITE, &pfn);
  50. if (ret)
  51. goto out;
  52. io_addr = (void __iomem *)((pfn << PAGE_SHIFT) | (mmio_addr & ~PAGE_MASK));
  53. ret = -EFAULT;
  54. if ((unsigned long) io_addr < ZPCI_IOMAP_ADDR_BASE)
  55. goto out;
  56. if (copy_from_user(buf, user_buffer, length))
  57. goto out;
  58. ret = zpci_memcpy_toio(io_addr, buf, length);
  59. out:
  60. if (buf != local_buf)
  61. kfree(buf);
  62. return ret;
  63. }
  64. SYSCALL_DEFINE3(s390_pci_mmio_read, unsigned long, mmio_addr,
  65. void __user *, user_buffer, size_t, length)
  66. {
  67. u8 local_buf[64];
  68. void __iomem *io_addr;
  69. void *buf;
  70. unsigned long pfn;
  71. long ret;
  72. if (!zpci_is_enabled())
  73. return -ENODEV;
  74. if (length <= 0 || PAGE_SIZE - (mmio_addr & ~PAGE_MASK) < length)
  75. return -EINVAL;
  76. if (length > 64) {
  77. buf = kmalloc(length, GFP_KERNEL);
  78. if (!buf)
  79. return -ENOMEM;
  80. } else
  81. buf = local_buf;
  82. ret = get_pfn(mmio_addr, VM_READ, &pfn);
  83. if (ret)
  84. goto out;
  85. io_addr = (void __iomem *)((pfn << PAGE_SHIFT) | (mmio_addr & ~PAGE_MASK));
  86. if ((unsigned long) io_addr < ZPCI_IOMAP_ADDR_BASE) {
  87. ret = -EFAULT;
  88. goto out;
  89. }
  90. ret = zpci_memcpy_fromio(buf, io_addr, length);
  91. if (ret)
  92. goto out;
  93. if (copy_to_user(user_buffer, buf, length))
  94. ret = -EFAULT;
  95. out:
  96. if (buf != local_buf)
  97. kfree(buf);
  98. return ret;
  99. }