1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768 |
- /*
- * safe read and write memory routines callable while atomic
- *
- * Copyright 2012 Imagination Technologies
- */
- #include <linux/uaccess.h>
- #include <asm/io.h>
- /*
- * The generic probe_kernel_write() uses the user copy code which can split the
- * writes if the source is unaligned, and repeats writes to make exceptions
- * precise. We override it here to avoid these things happening to memory mapped
- * IO memory where they could have undesired effects.
- * Due to the use of CACHERD instruction this only works on Meta2 onwards.
- */
- #ifdef CONFIG_METAG_META21
- long probe_kernel_write(void *dst, const void *src, size_t size)
- {
- unsigned long ldst = (unsigned long)dst;
- void __iomem *iodst = (void __iomem *)dst;
- unsigned long lsrc = (unsigned long)src;
- const u8 *psrc = (u8 *)src;
- unsigned int pte, i;
- u8 bounce[8] __aligned(8);
- if (!size)
- return 0;
- /* Use the write combine bit to decide is the destination is MMIO. */
- pte = __builtin_meta2_cacherd(dst);
- /* Check the mapping is valid and writeable. */
- if ((pte & (MMCU_ENTRY_WR_BIT | MMCU_ENTRY_VAL_BIT))
- != (MMCU_ENTRY_WR_BIT | MMCU_ENTRY_VAL_BIT))
- return -EFAULT;
- /* Fall back to generic version for cases we're not interested in. */
- if (pte & MMCU_ENTRY_WRC_BIT || /* write combined memory */
- (ldst & (size - 1)) || /* destination unaligned */
- size > 8 || /* more than max write size */
- (size & (size - 1))) /* non power of 2 size */
- return __probe_kernel_write(dst, src, size);
- /* If src is unaligned, copy to the aligned bounce buffer first. */
- if (lsrc & (size - 1)) {
- for (i = 0; i < size; ++i)
- bounce[i] = psrc[i];
- psrc = bounce;
- }
- switch (size) {
- case 1:
- writeb(*psrc, iodst);
- break;
- case 2:
- writew(*(const u16 *)psrc, iodst);
- break;
- case 4:
- writel(*(const u32 *)psrc, iodst);
- break;
- case 8:
- writeq(*(const u64 *)psrc, iodst);
- break;
- }
- return 0;
- }
- #endif
|