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 12static 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 19long 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) { 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 58long 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) { 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} 98