Merge tag 'for-linus' of git://linux-c6x.org/git/projects/linux-c6x-upstreaming
[sfrench/cifs-2.6.git] / arch / csky / abiv1 / mmap.c
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
3
4 #include <linux/fs.h>
5 #include <linux/mm.h>
6 #include <linux/mman.h>
7 #include <linux/shm.h>
8 #include <linux/sched.h>
9 #include <linux/random.h>
10 #include <linux/io.h>
11
12 unsigned long shm_align_mask = (0x4000 >> 1) - 1;   /* Sane caches */
13
14 #define COLOUR_ALIGN(addr, pgoff) \
15         ((((addr) + shm_align_mask) & ~shm_align_mask) + \
16          (((pgoff) << PAGE_SHIFT) & shm_align_mask))
17
18 unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
19                 unsigned long len, unsigned long pgoff, unsigned long flags)
20 {
21         struct vm_area_struct *vmm;
22         int do_color_align;
23
24         if (flags & MAP_FIXED) {
25                 /*
26                  * We do not accept a shared mapping if it would violate
27                  * cache aliasing constraints.
28                  */
29                 if ((flags & MAP_SHARED) &&
30                         ((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask))
31                         return -EINVAL;
32                 return addr;
33         }
34
35         if (len > TASK_SIZE)
36                 return -ENOMEM;
37         do_color_align = 0;
38         if (filp || (flags & MAP_SHARED))
39                 do_color_align = 1;
40         if (addr) {
41                 if (do_color_align)
42                         addr = COLOUR_ALIGN(addr, pgoff);
43                 else
44                         addr = PAGE_ALIGN(addr);
45                 vmm = find_vma(current->mm, addr);
46                 if (TASK_SIZE - len >= addr &&
47                                 (!vmm || addr + len <= vmm->vm_start))
48                         return addr;
49         }
50         addr = TASK_UNMAPPED_BASE;
51         if (do_color_align)
52                 addr = COLOUR_ALIGN(addr, pgoff);
53         else
54                 addr = PAGE_ALIGN(addr);
55
56         for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
57                 /* At this point: (!vmm || addr < vmm->vm_end). */
58                 if (TASK_SIZE - len < addr)
59                         return -ENOMEM;
60                 if (!vmm || addr + len <= vmm->vm_start)
61                         return addr;
62                 addr = vmm->vm_end;
63                 if (do_color_align)
64                         addr = COLOUR_ALIGN(addr, pgoff);
65         }
66 }