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