Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
maccess.c
Go to the documentation of this file.
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, const 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) {
42  return __probe_kernel_read(dst, src, size);
43  /* XXX: should support IDMA here with SMP */
45  if (dma_memcpy(dst, src, size))
46  return 0;
47  break;
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, const 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) {
83  return __probe_kernel_write(dst, src, size);
84  /* XXX: should support IDMA here with SMP */
86  if (dma_memcpy(dst, src, size))
87  return 0;
88  break;
90  if (isram_memcpy(dst, src, size))
91  return 0;
92  break;
93  }
94  }
95 
96  return -EFAULT;
97 }