maccess.c 1.9 KB

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