Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / arch / s390 / pci / pci_mmio.c
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
14 static long get_pfn(unsigned long user_addr, unsigned long access,
15                     unsigned long *pfn)
16 {
17         struct vm_area_struct *vma;
18         long ret;
19
20         down_read(&current->mm->mmap_sem);
21         ret = -EINVAL;
22         vma = find_vma(current->mm, user_addr);
23         if (!vma)
24                 goto out;
25         ret = -EACCES;
26         if (!(vma->vm_flags & access))
27                 goto out;
28         ret = follow_pfn(vma, user_addr, pfn);
29 out:
30         up_read(&current->mm->mmap_sem);
31         return ret;
32 }
33
34 SYSCALL_DEFINE3(s390_pci_mmio_write, unsigned long, mmio_addr,
35                 const void __user *, user_buffer, size_t, length)
36 {
37         u8 local_buf[64];
38         void __iomem *io_addr;
39         void *buf;
40         unsigned long pfn;
41         long ret;
42
43         if (!zpci_is_enabled())
44                 return -ENODEV;
45
46         if (length <= 0 || PAGE_SIZE - (mmio_addr & ~PAGE_MASK) < length)
47                 return -EINVAL;
48         if (length > 64) {
49                 buf = kmalloc(length, GFP_KERNEL);
50                 if (!buf)
51                         return -ENOMEM;
52         } else
53                 buf = local_buf;
54
55         ret = get_pfn(mmio_addr, VM_WRITE, &pfn);
56         if (ret)
57                 goto out;
58         io_addr = (void __iomem *)((pfn << PAGE_SHIFT) | (mmio_addr & ~PAGE_MASK));
59
60         ret = -EFAULT;
61         if ((unsigned long) io_addr < ZPCI_IOMAP_ADDR_BASE)
62                 goto out;
63
64         if (copy_from_user(buf, user_buffer, length))
65                 goto out;
66
67         ret = zpci_memcpy_toio(io_addr, buf, length);
68 out:
69         if (buf != local_buf)
70                 kfree(buf);
71         return ret;
72 }
73
74 SYSCALL_DEFINE3(s390_pci_mmio_read, unsigned long, mmio_addr,
75                 void __user *, user_buffer, size_t, length)
76 {
77         u8 local_buf[64];
78         void __iomem *io_addr;
79         void *buf;
80         unsigned long pfn;
81         long ret;
82
83         if (!zpci_is_enabled())
84                 return -ENODEV;
85
86         if (length <= 0 || PAGE_SIZE - (mmio_addr & ~PAGE_MASK) < length)
87                 return -EINVAL;
88         if (length > 64) {
89                 buf = kmalloc(length, GFP_KERNEL);
90                 if (!buf)
91                         return -ENOMEM;
92         } else
93                 buf = local_buf;
94
95         ret = get_pfn(mmio_addr, VM_READ, &pfn);
96         if (ret)
97                 goto out;
98         io_addr = (void __iomem *)((pfn << PAGE_SHIFT) | (mmio_addr & ~PAGE_MASK));
99
100         if ((unsigned long) io_addr < ZPCI_IOMAP_ADDR_BASE) {
101                 ret = -EFAULT;
102                 goto out;
103         }
104         ret = zpci_memcpy_fromio(buf, io_addr, length);
105         if (ret)
106                 goto out;
107         if (copy_to_user(user_buffer, buf, length))
108                 ret = -EFAULT;
109
110 out:
111         if (buf != local_buf)
112                 kfree(buf);
113         return ret;
114 }