frv: hide uncached_access() when pgprot_noncached is not #defined
[firefly-linux-kernel-4.4.55.git] / drivers / char / mem.c
index be832b6f8279919831df235a11738f7398668722..f54dab8acdcd6561c742b0541afdae3828dedfd9 100644 (file)
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *
- *  Added devfs support. 
+ *  Added devfs support.
  *    Jan-11-1998, C. Scott Ananian <cananian@alumni.princeton.edu>
  *  Shared /dev/zero mmapping support, Feb 2000, Kanoj Sarcar <kanoj@sgi.com>
  */
@@ -44,36 +44,6 @@ static inline unsigned long size_inside_page(unsigned long start,
        return min(sz, size);
 }
 
-/*
- * Architectures vary in how they handle caching for addresses
- * outside of main memory.
- *
- */
-static inline int uncached_access(struct file *file, unsigned long addr)
-{
-#if defined(CONFIG_IA64)
-       /*
-        * On ia64, we ignore O_DSYNC because we cannot tolerate memory attribute aliases.
-        */
-       return !(efi_mem_attributes(addr) & EFI_MEMORY_WB);
-#elif defined(CONFIG_MIPS)
-       {
-               extern int __uncached_access(struct file *file,
-                                            unsigned long addr);
-
-               return __uncached_access(file, addr);
-       }
-#else
-       /*
-        * Accessing memory above the top the kernel knows about or through a file pointer
-        * that was marked O_DSYNC will be done non-cached.
-        */
-       if (file->f_flags & O_DSYNC)
-               return 1;
-       return addr >= __pa(high_memory);
-#endif
-}
-
 #ifndef ARCH_HAS_VALID_PHYS_ADDR_RANGE
 static inline int valid_phys_addr_range(unsigned long addr, size_t count)
 {
@@ -115,15 +85,15 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size)
 }
 #endif
 
-void __attribute__((weak)) unxlate_dev_mem_ptr(unsigned long phys, void *addr)
+void __weak unxlate_dev_mem_ptr(unsigned long phys, void *addr)
 {
 }
 
 /*
- * This funcion reads the *physical* memory. The f_pos points directly to the 
- * memory location. 
+ * This funcion reads the *physical* memory. The f_pos points directly to the
+ * memory location.
  */
-static ssize_t read_mem(struct file * file, char __user * buf,
+static ssize_t read_mem(struct file *file, char __user *buf,
                        size_t count, loff_t *ppos)
 {
        unsigned long p = *ppos;
@@ -140,10 +110,10 @@ static ssize_t read_mem(struct file * file, char __user * buf,
                if (sz > 0) {
                        if (clear_user(buf, sz))
                                return -EFAULT;
-                       buf += sz; 
-                       p += sz; 
-                       count -= sz; 
-                       read += sz; 
+                       buf += sz;
+                       p += sz;
+                       count -= sz;
+                       read += sz;
                }
        }
 #endif
@@ -157,9 +127,9 @@ static ssize_t read_mem(struct file * file, char __user * buf,
                        return -EPERM;
 
                /*
-                * On ia64 if a page has been mapped somewhere as
-                * uncached, then it must also be accessed uncached
-                * by the kernel or data corruption may occur
+                * On ia64 if a page has been mapped somewhere as uncached, then
+                * it must also be accessed uncached by the kernel or data
+                * corruption may occur.
                 */
                ptr = xlate_dev_mem_ptr(p);
                if (!ptr)
@@ -180,7 +150,7 @@ static ssize_t read_mem(struct file * file, char __user * buf,
        return read;
 }
 
-static ssize_t write_mem(struct file * file, const char __user * buf, 
+static ssize_t write_mem(struct file *file, const char __user *buf,
                         size_t count, loff_t *ppos)
 {
        unsigned long p = *ppos;
@@ -212,9 +182,9 @@ static ssize_t write_mem(struct file * file, const char __user * buf,
                        return -EPERM;
 
                /*
-                * On ia64 if a page has been mapped somewhere as
-                * uncached, then it must also be accessed uncached
-                * by the kernel or data corruption may occur
+                * On ia64 if a page has been mapped somewhere as uncached, then
+                * it must also be accessed uncached by the kernel or data
+                * corruption may occur.
                 */
                ptr = xlate_dev_mem_ptr(p);
                if (!ptr) {
@@ -242,13 +212,48 @@ static ssize_t write_mem(struct file * file, const char __user * buf,
        return written;
 }
 
-int __attribute__((weak)) phys_mem_access_prot_allowed(struct file *file,
+int __weak phys_mem_access_prot_allowed(struct file *file,
        unsigned long pfn, unsigned long size, pgprot_t *vma_prot)
 {
        return 1;
 }
 
 #ifndef __HAVE_PHYS_MEM_ACCESS_PROT
+
+/*
+ * Architectures vary in how they handle caching for addresses
+ * outside of main memory.
+ *
+ */
+#ifdef pgprot_noncached
+static int uncached_access(struct file *file, unsigned long addr)
+{
+#if defined(CONFIG_IA64)
+       /*
+        * On ia64, we ignore O_DSYNC because we cannot tolerate memory
+        * attribute aliases.
+        */
+       return !(efi_mem_attributes(addr) & EFI_MEMORY_WB);
+#elif defined(CONFIG_MIPS)
+       {
+               extern int __uncached_access(struct file *file,
+                                            unsigned long addr);
+
+               return __uncached_access(file, addr);
+       }
+#else
+       /*
+        * Accessing memory above the top the kernel knows about or through a
+        * file pointer
+        * that was marked O_DSYNC will be done non-cached.
+        */
+       if (file->f_flags & O_DSYNC)
+               return 1;
+       return addr >= __pa(high_memory);
+#endif
+}
+#endif
+
 static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
                                     unsigned long size, pgprot_t vma_prot)
 {
@@ -294,7 +299,7 @@ static const struct vm_operations_struct mmap_mem_ops = {
 #endif
 };
 
-static int mmap_mem(struct file * file, struct vm_area_struct * vma)
+static int mmap_mem(struct file *file, struct vm_area_struct *vma)
 {
        size_t size = vma->vm_end - vma->vm_start;
 
@@ -329,7 +334,7 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma)
 }
 
 #ifdef CONFIG_DEVKMEM
-static int mmap_kmem(struct file * file, struct vm_area_struct * vma)
+static int mmap_kmem(struct file *file, struct vm_area_struct *vma)
 {
        unsigned long pfn;
 
@@ -337,9 +342,9 @@ static int mmap_kmem(struct file * file, struct vm_area_struct * vma)
        pfn = __pa((u64)vma->vm_pgoff << PAGE_SHIFT) >> PAGE_SHIFT;
 
        /*
-        * RED-PEN: on some architectures there is more mapped memory
-        * than available in mem_map which pfn_valid checks
-        * for. Perhaps should add a new macro here.
+        * RED-PEN: on some architectures there is more mapped memory than
+        * available in mem_map which pfn_valid checks for. Perhaps should add a
+        * new macro here.
         *
         * RED-PEN: vmalloc is not supported right now.
         */
@@ -389,18 +394,19 @@ static ssize_t read_oldmem(struct file *file, char __user *buf,
 /*
  * This function reads the *virtual* memory as seen by the kernel.
  */
-static ssize_t read_kmem(struct file *file, char __user *buf, 
+static ssize_t read_kmem(struct file *file, char __user *buf,
                         size_t count, loff_t *ppos)
 {
        unsigned long p = *ppos;
        ssize_t low_count, read, sz;
        char * kbuf; /* k-addr because vread() takes vmlist_lock rwlock */
+       int err = 0;
 
        read = 0;
        if (p < (unsigned long) high_memory) {
                low_count = count;
-               if (count > (unsigned long) high_memory - p)
-                       low_count = (unsigned long) high_memory - p;
+               if (count > (unsigned long)high_memory - p)
+                       low_count = (unsigned long)high_memory - p;
 
 #ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED
                /* we don't have page 0 mapped on sparc and m68k.. */
@@ -441,12 +447,16 @@ static ssize_t read_kmem(struct file *file, char __user *buf,
                        return -ENOMEM;
                while (count > 0) {
                        sz = size_inside_page(p, count);
+                       if (!is_vmalloc_or_module_addr((void *)p)) {
+                               err = -ENXIO;
+                               break;
+                       }
                        sz = vread(kbuf, (char *)p, sz);
                        if (!sz)
                                break;
                        if (copy_to_user(buf, kbuf, sz)) {
-                               free_page((unsigned long)kbuf);
-                               return -EFAULT;
+                               err = -EFAULT;
+                               break;
                        }
                        count -= sz;
                        buf += sz;
@@ -455,14 +465,13 @@ static ssize_t read_kmem(struct file *file, char __user *buf,
                }
                free_page((unsigned long)kbuf);
        }
-       *ppos = p;
-       return read;
+       *ppos = p;
+       return read ? read : err;
 }
 
 
-static inline ssize_t
-do_write_kmem(unsigned long p, const char __user *buf,
-             size_t count, loff_t *ppos)
+static ssize_t do_write_kmem(unsigned long p, const char __user *buf,
+                               size_t count, loff_t *ppos)
 {
        ssize_t written, sz;
        unsigned long copied;
@@ -486,9 +495,9 @@ do_write_kmem(unsigned long p, const char __user *buf,
                sz = size_inside_page(p, count);
 
                /*
-                * On ia64 if a page has been mapped somewhere as
-                * uncached, then it must also be accessed uncached
-                * by the kernel or data corruption may occur
+                * On ia64 if a page has been mapped somewhere as uncached, then
+                * it must also be accessed uncached by the kernel or data
+                * corruption may occur.
                 */
                ptr = xlate_dev_kmem_ptr((char *)p);
 
@@ -509,17 +518,17 @@ do_write_kmem(unsigned long p, const char __user *buf,
        return written;
 }
 
-
 /*
  * This function writes to the *virtual* memory as seen by the kernel.
  */
-static ssize_t write_kmem(struct file * file, const char __user * buf, 
+static ssize_t write_kmem(struct file *file, const char __user *buf,
                          size_t count, loff_t *ppos)
 {
        unsigned long p = *ppos;
        ssize_t wrote = 0;
        ssize_t virtr = 0;
        char * kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */
+       int err = 0;
 
        if (p < (unsigned long) high_memory) {
                unsigned long to_write = min_t(unsigned long, count,
@@ -540,14 +549,16 @@ static ssize_t write_kmem(struct file * file, const char __user * buf,
                        unsigned long sz = size_inside_page(p, count);
                        unsigned long n;
 
+                       if (!is_vmalloc_or_module_addr((void *)p)) {
+                               err = -ENXIO;
+                               break;
+                       }
                        n = copy_from_user(kbuf, buf, sz);
                        if (n) {
-                               if (wrote + virtr)
-                                       break;
-                               free_page((unsigned long)kbuf);
-                               return -EFAULT;
+                               err = -EFAULT;
+                               break;
                        }
-                       sz = vwrite(kbuf, (char *)p, sz);
+                       vwrite(kbuf, (char *)p, sz);
                        count -= sz;
                        buf += sz;
                        virtr += sz;
@@ -556,23 +567,23 @@ static ssize_t write_kmem(struct file * file, const char __user * buf,
                free_page((unsigned long)kbuf);
        }
 
-       *ppos = p;
-       return virtr + wrote;
+       *ppos = p;
+       return virtr + wrote ? : err;
 }
 #endif
 
 #ifdef CONFIG_DEVPORT
-static ssize_t read_port(struct file * file, char __user * buf,
+static ssize_t read_port(struct file *file, char __user *buf,
                         size_t count, loff_t *ppos)
 {
        unsigned long i = *ppos;
        char __user *tmp = buf;
 
        if (!access_ok(VERIFY_WRITE, buf, count))
-               return -EFAULT; 
+               return -EFAULT;
        while (count-- > 0 && i < 65536) {
-               if (__put_user(inb(i),tmp) < 0) 
-                       return -EFAULT;  
+               if (__put_user(inb(i), tmp) < 0)
+                       return -EFAULT;
                i++;
                tmp++;
        }
@@ -580,22 +591,22 @@ static ssize_t read_port(struct file * file, char __user * buf,
        return tmp-buf;
 }
 
-static ssize_t write_port(struct file * file, const char __user * buf,
+static ssize_t write_port(struct file *file, const char __user *buf,
                          size_t count, loff_t *ppos)
 {
        unsigned long i = *ppos;
        const char __user * tmp = buf;
 
-       if (!access_ok(VERIFY_READ,buf,count))
+       if (!access_ok(VERIFY_READ, buf, count))
                return -EFAULT;
        while (count-- > 0 && i < 65536) {
                char c;
                if (__get_user(c, tmp)) {
                        if (tmp > buf)
                                break;
-                       return -EFAULT; 
+                       return -EFAULT;
                }
-               outb(c,i);
+               outb(c, i);
                i++;
                tmp++;
        }
@@ -604,13 +615,13 @@ static ssize_t write_port(struct file * file, const char __user * buf,
 }
 #endif
 
-static ssize_t read_null(struct file * file, char __user * buf,
+static ssize_t read_null(struct file *file, char __user *buf,
                         size_t count, loff_t *ppos)
 {
        return 0;
 }
 
-static ssize_t write_null(struct file * file, const char __user * buf,
+static ssize_t write_null(struct file *file, const char __user *buf,
                          size_t count, loff_t *ppos)
 {
        return count;
@@ -622,13 +633,13 @@ static int pipe_to_null(struct pipe_inode_info *info, struct pipe_buffer *buf,
        return sd->len;
 }
 
-static ssize_t splice_write_null(struct pipe_inode_info *pipe,struct file *out,
+static ssize_t splice_write_null(struct pipe_inode_info *pipe, struct file *out,
                                 loff_t *ppos, size_t len, unsigned int flags)
 {
        return splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_null);
 }
 
-static ssize_t read_zero(struct file * file, char __user * buf, 
+static ssize_t read_zero(struct file *file, char __user *buf,
                         size_t count, loff_t *ppos)
 {
        size_t written;
@@ -659,7 +670,7 @@ static ssize_t read_zero(struct file * file, char __user * buf,
        return written ? written : -EFAULT;
 }
 
-static int mmap_zero(struct file * file, struct vm_area_struct * vma)
+static int mmap_zero(struct file *file, struct vm_area_struct *vma)
 {
 #ifndef CONFIG_MMU
        return -ENOSYS;
@@ -669,7 +680,7 @@ static int mmap_zero(struct file * file, struct vm_area_struct * vma)
        return 0;
 }
 
-static ssize_t write_full(struct file * file, const char __user * buf,
+static ssize_t write_full(struct file *file, const char __user *buf,
                          size_t count, loff_t *ppos)
 {
        return -ENOSPC;
@@ -680,8 +691,7 @@ static ssize_t write_full(struct file * file, const char __user * buf,
  * can fopen() both devices with "a" now.  This was previously impossible.
  * -- SRB.
  */
-
-static loff_t null_lseek(struct file * file, loff_t offset, int orig)
+static loff_t null_lseek(struct file *file, loff_t offset, int orig)
 {
        return file->f_pos = 0;
 }
@@ -694,24 +704,26 @@ static loff_t null_lseek(struct file * file, loff_t offset, int orig)
  * also note that seeking relative to the "end of file" isn't supported:
  * it has no meaning, so it returns -EINVAL.
  */
-static loff_t memory_lseek(struct file * file, loff_t offset, int orig)
+static loff_t memory_lseek(struct file *file, loff_t offset, int orig)
 {
        loff_t ret;
 
        mutex_lock(&file->f_path.dentry->d_inode->i_mutex);
        switch (orig) {
-               case 0:
-                       file->f_pos = offset;
-                       ret = file->f_pos;
-                       force_successful_syscall_return();
-                       break;
-               case 1:
-                       file->f_pos += offset;
-                       ret = file->f_pos;
-                       force_successful_syscall_return();
+       case SEEK_CUR:
+               offset += file->f_pos;
+       case SEEK_SET:
+               /* to avoid userland mistaking f_pos=-9 as -EBADF=-9 */
+               if ((unsigned long long)offset >= ~0xFFFULL) {
+                       ret = -EOVERFLOW;
                        break;
-               default:
-                       ret = -EINVAL;
+               }
+               file->f_pos = offset;
+               ret = file->f_pos;
+               force_successful_syscall_return();
+               break;
+       default:
+               ret = -EINVAL;
        }
        mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
        return ret;
@@ -795,7 +807,7 @@ static const struct file_operations oldmem_fops = {
 };
 #endif
 
-static ssize_t kmsg_write(struct file * file, const char __user * buf,
+static ssize_t kmsg_write(struct file *file, const char __user *buf,
                          size_t count, loff_t *ppos)
 {
        char *tmp;
@@ -817,7 +829,7 @@ static ssize_t kmsg_write(struct file * file, const char __user * buf,
 }
 
 static const struct file_operations kmsg_fops = {
-       .write =        kmsg_write,
+       .write = kmsg_write,
 };
 
 static const struct memdev {
@@ -868,7 +880,7 @@ static int memory_open(struct inode *inode, struct file *filp)
 }
 
 static const struct file_operations memory_fops = {
-       .open           = memory_open,
+       .open = memory_open,
 };
 
 static char *mem_devnode(struct device *dev, mode_t *mode)
@@ -889,10 +901,13 @@ static int __init chr_dev_init(void)
        if (err)
                return err;
 
-       if (register_chrdev(MEM_MAJOR,"mem",&memory_fops))
+       if (register_chrdev(MEM_MAJOR, "mem", &memory_fops))
                printk("unable to get major %d for memory devs\n", MEM_MAJOR);
 
        mem_class = class_create(THIS_MODULE, "mem");
+       if (IS_ERR(mem_class))
+               return PTR_ERR(mem_class);
+
        mem_class->devnode = mem_devnode;
        for (minor = 1; minor < ARRAY_SIZE(devlist); minor++) {
                if (!devlist[minor].name)