Commit | Line | Data |
---|---|---|
0fde6637 JW |
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 | ||
f29c5041 | 19 | long probe_kernel_read(void *dst, const void *src, size_t size) |
0fde6637 JW |
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 | ||
f29c5041 | 58 | long probe_kernel_write(void *dst, const void *src, size_t size) |
0fde6637 JW |
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 | } |