diff options
Diffstat (limited to 'arch/blackfin/mm/maccess.c')
-rw-r--r-- | arch/blackfin/mm/maccess.c | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/arch/blackfin/mm/maccess.c b/arch/blackfin/mm/maccess.c new file mode 100644 index 000000000000..b71cebc1f8a3 --- /dev/null +++ b/arch/blackfin/mm/maccess.c | |||
@@ -0,0 +1,97 @@ | |||
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 | } | ||