diff options
author | Takashi Iwai <tiwai@suse.de> | 2010-02-17 16:24:46 +0300 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2010-02-17 16:24:46 +0300 |
commit | 7fb3a069bc5d3577409c2ae89f89cd264ff85816 (patch) | |
tree | 7fe3ba3b95faeecb01e4feafb9288ef4b523c6b3 /arch/blackfin/mm/maccess.c | |
parent | 291186e049d7f8178ad31d43c38a53889f25d79e (diff) | |
parent | 9d3415a8cc76ff65c6602a121ac318432c5cd7ba (diff) | |
download | linux-7fb3a069bc5d3577409c2ae89f89cd264ff85816.tar.xz |
Merge branch 'fix/misc' into topic/misc
Conflicts:
sound/pci/hda/patch_realtek.c
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 @@ +/* + * safe read and write memory routines callable while atomic + * + * Copyright 2005-2008 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include <linux/uaccess.h> +#include <asm/dma.h> + +static int validate_memory_access_address(unsigned long addr, int size) +{ + if (size < 0 || addr == 0) + return -EFAULT; + return bfin_mem_access_type(addr, size); +} + +long probe_kernel_read(void *dst, void *src, size_t size) +{ + unsigned long lsrc = (unsigned long)src; + int mem_type; + + mem_type = validate_memory_access_address(lsrc, size); + if (mem_type < 0) + return mem_type; + + if (lsrc >= SYSMMR_BASE) { + if (size == 2 && lsrc % 2 == 0) { + u16 mmr = bfin_read16(src); + memcpy(dst, &mmr, sizeof(mmr)); + return 0; + } else if (size == 4 && lsrc % 4 == 0) { + u32 mmr = bfin_read32(src); + memcpy(dst, &mmr, sizeof(mmr)); + return 0; + } + } else { + switch (mem_type) { + case BFIN_MEM_ACCESS_CORE: + case BFIN_MEM_ACCESS_CORE_ONLY: + return __probe_kernel_read(dst, src, size); + /* XXX: should support IDMA here with SMP */ + case BFIN_MEM_ACCESS_DMA: + if (dma_memcpy(dst, src, size)) + return 0; + break; + case BFIN_MEM_ACCESS_ITEST: + if (isram_memcpy(dst, src, size)) + return 0; + break; + } + } + + return -EFAULT; +} + +long probe_kernel_write(void *dst, void *src, size_t size) +{ + unsigned long ldst = (unsigned long)dst; + int mem_type; + + mem_type = validate_memory_access_address(ldst, size); + if (mem_type < 0) + return mem_type; + + if (ldst >= SYSMMR_BASE) { + if (size == 2 && ldst % 2 == 0) { + u16 mmr; + memcpy(&mmr, src, sizeof(mmr)); + bfin_write16(dst, mmr); + return 0; + } else if (size == 4 && ldst % 4 == 0) { + u32 mmr; + memcpy(&mmr, src, sizeof(mmr)); + bfin_write32(dst, mmr); + return 0; + } + } else { + switch (mem_type) { + case BFIN_MEM_ACCESS_CORE: + case BFIN_MEM_ACCESS_CORE_ONLY: + return __probe_kernel_write(dst, src, size); + /* XXX: should support IDMA here with SMP */ + case BFIN_MEM_ACCESS_DMA: + if (dma_memcpy(dst, src, size)) + return 0; + break; + case BFIN_MEM_ACCESS_ITEST: + if (isram_memcpy(dst, src, size)) + return 0; + break; + } + } + + return -EFAULT; +} |