Linux Audio

Check our new training course

Loading...
v5.4
  1// SPDX-License-Identifier: GPL-2.0
  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;
 59	io_addr = (void __iomem *)((pfn << PAGE_SHIFT) | (mmio_addr & ~PAGE_MASK));
 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
 68	ret = zpci_memcpy_toio(io_addr, buf, length);
 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;
 99	io_addr = (void __iomem *)((pfn << PAGE_SHIFT) | (mmio_addr & ~PAGE_MASK));
100
101	if ((unsigned long) io_addr < ZPCI_IOMAP_ADDR_BASE) {
102		ret = -EFAULT;
103		goto out;
104	}
105	ret = zpci_memcpy_fromio(buf, io_addr, length);
106	if (ret)
107		goto out;
108	if (copy_to_user(user_buffer, buf, length))
109		ret = -EFAULT;
110
111out:
112	if (buf != local_buf)
113		kfree(buf);
114	return ret;
115}
v4.6
 
  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
 14static 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);
 29out:
 30	up_read(&current->mm->mmap_sem);
 31	return ret;
 32}
 33
 34SYSCALL_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);
 68out:
 69	if (buf != local_buf)
 70		kfree(buf);
 71	return ret;
 72}
 73
 74SYSCALL_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
110out:
111	if (buf != local_buf)
112		kfree(buf);
113	return ret;
114}