uncached.c 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. /*
  2. * This file is subject to the terms and conditions of the GNU General Public
  3. * License. See the file "COPYING" in the main directory of this archive
  4. * for more details.
  5. *
  6. * Copyright (C) 2005 Thiemo Seufer
  7. * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved.
  8. * Author: Maciej W. Rozycki <macro@mips.com>
  9. */
  10. #include <linux/init.h>
  11. #include <asm/addrspace.h>
  12. #include <asm/bug.h>
  13. #ifndef CKSEG2
  14. #define CKSEG2 CKSSEG
  15. #endif
  16. #ifndef TO_PHYS_MASK
  17. #define TO_PHYS_MASK -1
  18. #endif
  19. /*
  20. * FUNC is executed in one of the uncached segments, depending on its
  21. * original address as follows:
  22. *
  23. * 1. If the original address is in CKSEG0 or CKSEG1, then the uncached
  24. * segment used is CKSEG1.
  25. * 2. If the original address is in XKPHYS, then the uncached segment
  26. * used is XKPHYS(2).
  27. * 3. Otherwise it's a bug.
  28. *
  29. * The same remapping is done with the stack pointer. Stack handling
  30. * works because we don't handle stack arguments or more complex return
  31. * values, so we can avoid sharing the same stack area between a cached
  32. * and the uncached mode.
  33. */
  34. unsigned long __init run_uncached(void *func)
  35. {
  36. register long sp __asm__("$sp");
  37. register long ret __asm__("$2");
  38. long lfunc = (long)func, ufunc;
  39. long usp;
  40. if (sp >= (long)CKSEG0 && sp < (long)CKSEG2)
  41. usp = CKSEG1ADDR(sp);
  42. else if ((long long)sp >= (long long)PHYS_TO_XKPHYS(0LL, 0) &&
  43. (long long)sp < (long long)PHYS_TO_XKPHYS(8LL, 0))
  44. usp = PHYS_TO_XKPHYS((long long)K_CALG_UNCACHED,
  45. XKPHYS_TO_PHYS((long long)sp));
  46. else {
  47. BUG();
  48. usp = sp;
  49. }
  50. if (lfunc >= (long)CKSEG0 && lfunc < (long)CKSEG2)
  51. ufunc = CKSEG1ADDR(lfunc);
  52. else if ((long long)lfunc >= (long long)PHYS_TO_XKPHYS(0LL, 0) &&
  53. (long long)lfunc < (long long)PHYS_TO_XKPHYS(8LL, 0))
  54. ufunc = PHYS_TO_XKPHYS((long long)K_CALG_UNCACHED,
  55. XKPHYS_TO_PHYS((long long)lfunc));
  56. else {
  57. BUG();
  58. ufunc = lfunc;
  59. }
  60. __asm__ __volatile__ (
  61. " move $16, $sp\n"
  62. " move $sp, %1\n"
  63. " jalr %2\n"
  64. " move $sp, $16"
  65. : "=r" (ret)
  66. : "r" (usp), "r" (ufunc)
  67. : "$16", "$31");
  68. return ret;
  69. }