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