pci_mmio.c 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  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. memcpy_toio(io_addr, buf, length);
  59. ret = 0;
  60. out:
  61. if (buf != local_buf)
  62. kfree(buf);
  63. return ret;
  64. }
  65. SYSCALL_DEFINE3(s390_pci_mmio_read, unsigned long, mmio_addr,
  66. void __user *, user_buffer, size_t, length)
  67. {
  68. u8 local_buf[64];
  69. void __iomem *io_addr;
  70. void *buf;
  71. unsigned long pfn;
  72. long ret;
  73. if (!zpci_is_enabled())
  74. return -ENODEV;
  75. if (length <= 0 || PAGE_SIZE - (mmio_addr & ~PAGE_MASK) < length)
  76. return -EINVAL;
  77. if (length > 64) {
  78. buf = kmalloc(length, GFP_KERNEL);
  79. if (!buf)
  80. return -ENOMEM;
  81. } else
  82. buf = local_buf;
  83. ret = get_pfn(mmio_addr, VM_READ, &pfn);
  84. if (ret)
  85. goto out;
  86. io_addr = (void __iomem *)((pfn << PAGE_SHIFT) | (mmio_addr & ~PAGE_MASK));
  87. ret = -EFAULT;
  88. if ((unsigned long) io_addr < ZPCI_IOMAP_ADDR_BASE)
  89. goto out;
  90. memcpy_fromio(buf, io_addr, length);
  91. if (copy_to_user(user_buffer, buf, length))
  92. goto out;
  93. ret = 0;
  94. out:
  95. if (buf != local_buf)
  96. kfree(buf);
  97. return ret;
  98. }