Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[sfrench/cifs-2.6.git] / arch / blackfin / mm / maccess.c
1 /*
2  * safe read and write memory routines callable while atomic
3  *
4  * Copyright 2005-2008 Analog Devices Inc.
5  *
6  * Licensed under the GPL-2 or later.
7  */
8
9 #include <linux/uaccess.h>
10 #include <asm/dma.h>
11
12 static int validate_memory_access_address(unsigned long addr, int size)
13 {
14         if (size < 0 || addr == 0)
15                 return -EFAULT;
16         return bfin_mem_access_type(addr, size);
17 }
18
19 long probe_kernel_read(void *dst, void *src, size_t size)
20 {
21         unsigned long lsrc = (unsigned long)src;
22         int mem_type;
23
24         mem_type = validate_memory_access_address(lsrc, size);
25         if (mem_type < 0)
26                 return mem_type;
27
28         if (lsrc >= SYSMMR_BASE) {
29                 if (size == 2 && lsrc % 2 == 0) {
30                         u16 mmr = bfin_read16(src);
31                         memcpy(dst, &mmr, sizeof(mmr));
32                         return 0;
33                 } else if (size == 4 && lsrc % 4 == 0) {
34                         u32 mmr = bfin_read32(src);
35                         memcpy(dst, &mmr, sizeof(mmr));
36                         return 0;
37                 }
38         } else {
39                 switch (mem_type) {
40                 case BFIN_MEM_ACCESS_CORE:
41                 case BFIN_MEM_ACCESS_CORE_ONLY:
42                         return __probe_kernel_read(dst, src, size);
43                         /* XXX: should support IDMA here with SMP */
44                 case BFIN_MEM_ACCESS_DMA:
45                         if (dma_memcpy(dst, src, size))
46                                 return 0;
47                         break;
48                 case BFIN_MEM_ACCESS_ITEST:
49                         if (isram_memcpy(dst, src, size))
50                                 return 0;
51                         break;
52                 }
53         }
54
55         return -EFAULT;
56 }
57
58 long probe_kernel_write(void *dst, void *src, size_t size)
59 {
60         unsigned long ldst = (unsigned long)dst;
61         int mem_type;
62
63         mem_type = validate_memory_access_address(ldst, size);
64         if (mem_type < 0)
65                 return mem_type;
66
67         if (ldst >= SYSMMR_BASE) {
68                 if (size == 2 && ldst % 2 == 0) {
69                         u16 mmr;
70                         memcpy(&mmr, src, sizeof(mmr));
71                         bfin_write16(dst, mmr);
72                         return 0;
73                 } else if (size == 4 && ldst % 4 == 0) {
74                         u32 mmr;
75                         memcpy(&mmr, src, sizeof(mmr));
76                         bfin_write32(dst, mmr);
77                         return 0;
78                 }
79         } else {
80                 switch (mem_type) {
81                 case BFIN_MEM_ACCESS_CORE:
82                 case BFIN_MEM_ACCESS_CORE_ONLY:
83                         return __probe_kernel_write(dst, src, size);
84                         /* XXX: should support IDMA here with SMP */
85                 case BFIN_MEM_ACCESS_DMA:
86                         if (dma_memcpy(dst, src, size))
87                                 return 0;
88                         break;
89                 case BFIN_MEM_ACCESS_ITEST:
90                         if (isram_memcpy(dst, src, size))
91                                 return 0;
92                         break;
93                 }
94         }
95
96         return -EFAULT;
97 }