]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - arch/metag/mm/maccess.c
License cleanup: add SPDX GPL-2.0 license identifier to files with no license
[mirror_ubuntu-bionic-kernel.git] / arch / metag / mm / maccess.c
CommitLineData
b2441318 1// SPDX-License-Identifier: GPL-2.0
373cd784
JH
2/*
3 * safe read and write memory routines callable while atomic
4 *
5 * Copyright 2012 Imagination Technologies
6 */
7
8#include <linux/uaccess.h>
9#include <asm/io.h>
10
11/*
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.
17 */
18#ifdef CONFIG_METAG_META21
19long probe_kernel_write(void *dst, const void *src, size_t size)
20{
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);
27
28 if (!size)
29 return 0;
30
31 /* Use the write combine bit to decide is the destination is MMIO. */
32 pte = __builtin_meta2_cacherd(dst);
33
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;
38
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);
45
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;
51 }
52
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;
66 }
67 return 0;
68}
69#endif