linux/arch/metag/mm/maccess.c
<<
>>
Prefs
   1/*
   2 * safe read and write memory routines callable while atomic
   3 *
   4 * Copyright 2012 Imagination Technologies
   5 */
   6
   7#include <linux/uaccess.h>
   8#include <asm/io.h>
   9
  10/*
  11 * The generic probe_kernel_write() uses the user copy code which can split the
  12 * writes if the source is unaligned, and repeats writes to make exceptions
  13 * precise. We override it here to avoid these things happening to memory mapped
  14 * IO memory where they could have undesired effects.
  15 * Due to the use of CACHERD instruction this only works on Meta2 onwards.
  16 */
  17#ifdef CONFIG_METAG_META21
  18long probe_kernel_write(void *dst, const void *src, size_t size)
  19{
  20        unsigned long ldst = (unsigned long)dst;
  21        void __iomem *iodst = (void __iomem *)dst;
  22        unsigned long lsrc = (unsigned long)src;
  23        const u8 *psrc = (u8 *)src;
  24        unsigned int pte, i;
  25        u8 bounce[8] __aligned(8);
  26
  27        if (!size)
  28                return 0;
  29
  30        /* Use the write combine bit to decide is the destination is MMIO. */
  31        pte = __builtin_meta2_cacherd(dst);
  32
  33        /* Check the mapping is valid and writeable. */
  34        if ((pte & (MMCU_ENTRY_WR_BIT | MMCU_ENTRY_VAL_BIT))
  35            != (MMCU_ENTRY_WR_BIT | MMCU_ENTRY_VAL_BIT))
  36                return -EFAULT;
  37
  38        /* Fall back to generic version for cases we're not interested in. */
  39        if (pte & MMCU_ENTRY_WRC_BIT    || /* write combined memory */
  40            (ldst & (size - 1))         || /* destination unaligned */
  41            size > 8                    || /* more than max write size */
  42            (size & (size - 1)))           /* non power of 2 size */
  43                return __probe_kernel_write(dst, src, size);
  44
  45        /* If src is unaligned, copy to the aligned bounce buffer first. */
  46        if (lsrc & (size - 1)) {
  47                for (i = 0; i < size; ++i)
  48                        bounce[i] = psrc[i];
  49                psrc = bounce;
  50        }
  51
  52        switch (size) {
  53        case 1:
  54                writeb(*psrc, iodst);
  55                break;
  56        case 2:
  57                writew(*(const u16 *)psrc, iodst);
  58                break;
  59        case 4:
  60                writel(*(const u32 *)psrc, iodst);
  61                break;
  62        case 8:
  63                writeq(*(const u64 *)psrc, iodst);
  64                break;
  65        }
  66        return 0;
  67}
  68#endif
  69