p1275.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:11k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /* $Id: p1275.c,v 1.22 2001/10/18 09:40:00 davem Exp $
  2.  * p1275.c: Sun IEEE 1275 PROM low level interface routines
  3.  *
  4.  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  5.  */
  6. #include <linux/kernel.h>
  7. #include <linux/init.h>
  8. #include <linux/sched.h>
  9. #include <linux/smp.h>
  10. #include <linux/string.h>
  11. #include <linux/spinlock.h>
  12. #include <asm/openprom.h>
  13. #include <asm/oplib.h>
  14. #include <asm/system.h>
  15. #include <asm/spitfire.h>
  16. #include <asm/pstate.h>
  17. struct {
  18. long prom_callback; /* 0x00 */
  19. void (*prom_cif_handler)(long *); /* 0x08 */
  20. unsigned long prom_cif_stack; /* 0x10 */
  21. unsigned long prom_args [23]; /* 0x18 */
  22. char prom_buffer [3000];
  23. } p1275buf;
  24. extern void prom_world(int);
  25. void prom_cif_interface (void)
  26. {
  27. __asm__ __volatile__ (
  28. " mov %0, %%o0n"
  29. " ldx [%%o0 + 0x010], %%o1 ! prom_cif_stackn"
  30. " save %%o1, -0x190, %%spn"
  31. " ldx [%%i0 + 0x008], %%l2 ! prom_cif_handlern"
  32. " rdpr %%pstate, %%l4n"
  33. " wrpr %%g0, 0x15, %%pstate ! save alternate globalsn"
  34. " stx %%g1, [%%sp + 2047 + 0x0b0]n"
  35. " stx %%g2, [%%sp + 2047 + 0x0b8]n"
  36. " stx %%g3, [%%sp + 2047 + 0x0c0]n"
  37. " stx %%g4, [%%sp + 2047 + 0x0c8]n"
  38. " stx %%g5, [%%sp + 2047 + 0x0d0]n"
  39. " stx %%g6, [%%sp + 2047 + 0x0d8]n"
  40. " stx %%g7, [%%sp + 2047 + 0x0e0]n"
  41. " wrpr %%g0, 0x814, %%pstate ! save interrupt globalsn"
  42. " stx %%g1, [%%sp + 2047 + 0x0e8]n"
  43. " stx %%g2, [%%sp + 2047 + 0x0f0]n"
  44. " stx %%g3, [%%sp + 2047 + 0x0f8]n"
  45. " stx %%g4, [%%sp + 2047 + 0x100]n"
  46. " stx %%g5, [%%sp + 2047 + 0x108]n"
  47. " stx %%g6, [%%sp + 2047 + 0x110]n"
  48. " stx %%g7, [%%sp + 2047 + 0x118]n"
  49. " wrpr %%g0, 0x14, %%pstate ! save normal globalsn"
  50. " stx %%g1, [%%sp + 2047 + 0x120]n"
  51. " stx %%g2, [%%sp + 2047 + 0x128]n"
  52. " stx %%g3, [%%sp + 2047 + 0x130]n"
  53. " stx %%g4, [%%sp + 2047 + 0x138]n"
  54. " stx %%g5, [%%sp + 2047 + 0x140]n"
  55. " stx %%g6, [%%sp + 2047 + 0x148]n"
  56. " stx %%g7, [%%sp + 2047 + 0x150]n"
  57. " wrpr %%g0, 0x414, %%pstate ! save mmu globalsn"
  58. " stx %%g1, [%%sp + 2047 + 0x158]n"
  59. " stx %%g2, [%%sp + 2047 + 0x160]n"
  60. " stx %%g3, [%%sp + 2047 + 0x168]n"
  61. " stx %%g4, [%%sp + 2047 + 0x170]n"
  62. " stx %%g5, [%%sp + 2047 + 0x178]n"
  63. " stx %%g6, [%%sp + 2047 + 0x180]n"
  64. " stx %%g7, [%%sp + 2047 + 0x188]n"
  65. " mov %%g1, %%l0 ! also save to locals, so we can handlen"
  66. " mov %%g2, %%l1 ! tlb faults later on, when accessingn"
  67. " mov %%g3, %%l3 ! the stack.n"
  68. " mov %%g7, %%l5n"
  69. " wrpr %%l4, %1, %%pstate ! turn off interruptsn"
  70. " call %%l2n"
  71. "  add %%i0, 0x018, %%o0 ! prom_argsn"
  72. " wrpr %%g0, 0x414, %%pstate ! restore mmu globalsn"
  73. " mov %%l0, %%g1n"
  74. " mov %%l1, %%g2n"
  75. " mov %%l3, %%g3n"
  76. " mov %%l5, %%g7n"
  77. " wrpr %%g0, 0x14, %%pstate ! restore normal globalsn"
  78. " ldx [%%sp + 2047 + 0x120], %%g1n"
  79. " ldx [%%sp + 2047 + 0x128], %%g2n"
  80. " ldx [%%sp + 2047 + 0x130], %%g3n"
  81. " ldx [%%sp + 2047 + 0x138], %%g4n"
  82. " ldx [%%sp + 2047 + 0x140], %%g5n"
  83. " ldx [%%sp + 2047 + 0x148], %%g6n"
  84. " ldx [%%sp + 2047 + 0x150], %%g7n"
  85. " wrpr %%g0, 0x814, %%pstate ! restore interrupt globalsn"
  86. " ldx [%%sp + 2047 + 0x0e8], %%g1n"
  87. " ldx [%%sp + 2047 + 0x0f0], %%g2n"
  88. " ldx [%%sp + 2047 + 0x0f8], %%g3n"
  89. " ldx [%%sp + 2047 + 0x100], %%g4n"
  90. " ldx [%%sp + 2047 + 0x108], %%g5n"
  91. " ldx [%%sp + 2047 + 0x110], %%g6n"
  92. " ldx [%%sp + 2047 + 0x118], %%g7n"
  93. " wrpr %%g0, 0x15, %%pstate ! restore alternate globalsn"
  94. " ldx [%%sp + 2047 + 0x0b0], %%g1n"
  95. " ldx [%%sp + 2047 + 0x0b8], %%g2n"
  96. " ldx [%%sp + 2047 + 0x0c0], %%g3n"
  97. " ldx [%%sp + 2047 + 0x0c8], %%g4n"
  98. " ldx [%%sp + 2047 + 0x0d0], %%g5n"
  99. " ldx [%%sp + 2047 + 0x0d8], %%g6n"
  100. " ldx [%%sp + 2047 + 0x0e0], %%g7n"
  101. " wrpr %%l4, 0, %%pstate ! restore original pstaten"
  102. " retn"
  103. "  restoren"
  104. " " : : "r" (&p1275buf), "i" (PSTATE_IE));
  105. }
  106. void prom_cif_callback(void)
  107. {
  108. __asm__ __volatile__ (
  109. " mov %0, %%o1n"
  110. " save %%sp, -0x270, %%spn"
  111. " rdpr %%pstate, %%l4n"
  112. " wrpr %%g0, 0x15, %%pstate ! save PROM alternate globalsn"
  113. " stx %%g1, [%%sp + 2047 + 0x0b0]n"
  114. " stx %%g2, [%%sp + 2047 + 0x0b8]n"
  115. " stx %%g3, [%%sp + 2047 + 0x0c0]n"
  116. " stx %%g4, [%%sp + 2047 + 0x0c8]n"
  117. " stx %%g5, [%%sp + 2047 + 0x0d0]n"
  118. " stx %%g6, [%%sp + 2047 + 0x0d8]n"
  119. " stx %%g7, [%%sp + 2047 + 0x0e0]n"
  120. " ! restore Linux alternate globalsn"
  121. " ldx [%%sp + 2047 + 0x190], %%g1n"
  122. " ldx [%%sp + 2047 + 0x198], %%g2n"
  123. " ldx [%%sp + 2047 + 0x1a0], %%g3n"
  124. " ldx [%%sp + 2047 + 0x1a8], %%g4n"
  125. " ldx [%%sp + 2047 + 0x1b0], %%g5n"
  126. " ldx [%%sp + 2047 + 0x1b8], %%g6n"
  127. " ldx [%%sp + 2047 + 0x1c0], %%g7n"
  128. " wrpr %%g0, 0x814, %%pstate ! save PROM interrupt globalsn"
  129. " stx %%g1, [%%sp + 2047 + 0x0e8]n"
  130. " stx %%g2, [%%sp + 2047 + 0x0f0]n"
  131. " stx %%g3, [%%sp + 2047 + 0x0f8]n"
  132. " stx %%g4, [%%sp + 2047 + 0x100]n"
  133. " stx %%g5, [%%sp + 2047 + 0x108]n"
  134. " stx %%g6, [%%sp + 2047 + 0x110]n"
  135. " stx %%g7, [%%sp + 2047 + 0x118]n"
  136. " ! restore Linux interrupt globalsn"
  137. " ldx [%%sp + 2047 + 0x1c8], %%g1n"
  138. " ldx [%%sp + 2047 + 0x1d0], %%g2n"
  139. " ldx [%%sp + 2047 + 0x1d8], %%g3n"
  140. " ldx [%%sp + 2047 + 0x1e0], %%g4n"
  141. " ldx [%%sp + 2047 + 0x1e8], %%g5n"
  142. " ldx [%%sp + 2047 + 0x1f0], %%g6n"
  143. " ldx [%%sp + 2047 + 0x1f8], %%g7n"
  144. " wrpr %%g0, 0x14, %%pstate ! save PROM normal globalsn"
  145. " stx %%g1, [%%sp + 2047 + 0x120]n"
  146. " stx %%g2, [%%sp + 2047 + 0x128]n"
  147. " stx %%g3, [%%sp + 2047 + 0x130]n"
  148. " stx %%g4, [%%sp + 2047 + 0x138]n"
  149. " stx %%g5, [%%sp + 2047 + 0x140]n"
  150. " stx %%g6, [%%sp + 2047 + 0x148]n"
  151. " stx %%g7, [%%sp + 2047 + 0x150]n"
  152. " ! restore Linux normal globalsn"
  153. " ldx [%%sp + 2047 + 0x200], %%g1n"
  154. " ldx [%%sp + 2047 + 0x208], %%g2n"
  155. " ldx [%%sp + 2047 + 0x210], %%g3n"
  156. " ldx [%%sp + 2047 + 0x218], %%g4n"
  157. " ldx [%%sp + 2047 + 0x220], %%g5n"
  158. " ldx [%%sp + 2047 + 0x228], %%g6n"
  159. " ldx [%%sp + 2047 + 0x230], %%g7n"
  160. " wrpr %%g0, 0x414, %%pstate ! save PROM mmu globalsn"
  161. " stx %%g1, [%%sp + 2047 + 0x158]n"
  162. " stx %%g2, [%%sp + 2047 + 0x160]n"
  163. " stx %%g3, [%%sp + 2047 + 0x168]n"
  164. " stx %%g4, [%%sp + 2047 + 0x170]n"
  165. " stx %%g5, [%%sp + 2047 + 0x178]n"
  166. " stx %%g6, [%%sp + 2047 + 0x180]n"
  167. " stx %%g7, [%%sp + 2047 + 0x188]n"
  168. " ! restore Linux mmu globalsn"
  169. " ldx [%%sp + 2047 + 0x238], %%o0n"
  170. " ldx [%%sp + 2047 + 0x240], %%o1n"
  171. " ldx [%%sp + 2047 + 0x248], %%l2n"
  172. " ldx [%%sp + 2047 + 0x250], %%l3n"
  173. " ldx [%%sp + 2047 + 0x258], %%l5n"
  174. " ldx [%%sp + 2047 + 0x260], %%l6n"
  175. " ldx [%%sp + 2047 + 0x268], %%l7n"
  176. " ! switch to Linux tban"
  177. " sethi %%hi(sparc64_ttable_tl0), %%l1n"
  178. " rdpr %%tba, %%l0 ! save PROM tban"
  179. " mov %%o0, %%g1n"
  180. " mov %%o1, %%g2n"
  181. " mov %%l2, %%g3n"
  182. " mov %%l3, %%g4n"
  183. " mov %%l5, %%g5n"
  184. " mov %%l6, %%g6n"
  185. " mov %%l7, %%g7n"
  186. " wrpr %%l1, %%tba ! install Linux tban"
  187. " wrpr %%l4, 0, %%pstate ! restore PSTATEn"
  188. " call prom_worldn"
  189. "  mov %%g0, %%o0n"
  190. " ldx [%%i1 + 0x000], %%l2n"
  191. " call %%l2n"
  192. "  mov %%i0, %%o0n"
  193. " mov %%o0, %%l1n"
  194. " call prom_worldn"
  195. "  or %%g0, 1, %%o0n"
  196. " wrpr %%g0, 0x14, %%pstate ! interrupts offn"
  197. " ! restore PROM mmu globalsn"
  198. " ldx [%%sp + 2047 + 0x158], %%o0n"
  199. " ldx [%%sp + 2047 + 0x160], %%o1n"
  200. " ldx [%%sp + 2047 + 0x168], %%l2n"
  201. " ldx [%%sp + 2047 + 0x170], %%l3n"
  202. " ldx [%%sp + 2047 + 0x178], %%l5n"
  203. " ldx [%%sp + 2047 + 0x180], %%l6n"
  204. " ldx [%%sp + 2047 + 0x188], %%l7n"
  205. " wrpr %%g0, 0x414, %%pstate ! restore PROM mmu globalsn"
  206. " mov %%o0, %%g1n"
  207. " mov %%o1, %%g2n"
  208. " mov %%l2, %%g3n"
  209. " mov %%l3, %%g4n"
  210. " mov %%l5, %%g5n"
  211. " mov %%l6, %%g6n"
  212. " mov %%l7, %%g7n"
  213. " wrpr %%l0, %%tba ! restore PROM tban"
  214. " wrpr %%g0, 0x14, %%pstate ! restore PROM normal globalsn"
  215. " ldx [%%sp + 2047 + 0x120], %%g1n"
  216. " ldx [%%sp + 2047 + 0x128], %%g2n"
  217. " ldx [%%sp + 2047 + 0x130], %%g3n"
  218. " ldx [%%sp + 2047 + 0x138], %%g4n"
  219. " ldx [%%sp + 2047 + 0x140], %%g5n"
  220. " ldx [%%sp + 2047 + 0x148], %%g6n"
  221. " ldx [%%sp + 2047 + 0x150], %%g7n"
  222. " wrpr %%g0, 0x814, %%pstate ! restore PROM interrupt globalsn"
  223. " ldx [%%sp + 2047 + 0x0e8], %%g1n"
  224. " ldx [%%sp + 2047 + 0x0f0], %%g2n"
  225. " ldx [%%sp + 2047 + 0x0f8], %%g3n"
  226. " ldx [%%sp + 2047 + 0x100], %%g4n"
  227. " ldx [%%sp + 2047 + 0x108], %%g5n"
  228. " ldx [%%sp + 2047 + 0x110], %%g6n"
  229. " ldx [%%sp + 2047 + 0x118], %%g7n"
  230. " wrpr %%g0, 0x15, %%pstate ! restore PROM alternate globalsn"
  231. " ldx [%%sp + 2047 + 0x0b0], %%g1n"
  232. " ldx [%%sp + 2047 + 0x0b8], %%g2n"
  233. " ldx [%%sp + 2047 + 0x0c0], %%g3n"
  234. " ldx [%%sp + 2047 + 0x0c8], %%g4n"
  235. " ldx [%%sp + 2047 + 0x0d0], %%g5n"
  236. " ldx [%%sp + 2047 + 0x0d8], %%g6n"
  237. " ldx [%%sp + 2047 + 0x0e0], %%g7n"
  238. " wrpr %%l4, 0, %%pstaten"
  239. " retn"
  240. "  restore %%l1, 0, %%o0n"
  241. " " : : "r" (&p1275buf), "i" (PSTATE_PRIV));
  242. }
  243. /*
  244.  * This provides SMP safety on the p1275buf. prom_callback() drops this lock
  245.  * to allow recursuve acquisition.
  246.  */
  247. spinlock_t prom_entry_lock = SPIN_LOCK_UNLOCKED;
  248. long p1275_cmd (char *service, long fmt, ...)
  249. {
  250. char *p, *q;
  251. unsigned long flags;
  252. int nargs, nrets, i;
  253. va_list list;
  254. long attrs, x;
  255. long ctx = 0;
  256. p = p1275buf.prom_buffer;
  257. ctx = spitfire_get_primary_context ();
  258. if (ctx) {
  259. flushw_user ();
  260. spitfire_set_primary_context (0);
  261. }
  262. spin_lock_irqsave(&prom_entry_lock, flags);
  263. p1275buf.prom_args[0] = (unsigned long)p; /* service */
  264. strcpy (p, service);
  265. p = (char *)(((long)(strchr (p, 0) + 8)) & ~7);
  266. p1275buf.prom_args[1] = nargs = (fmt & 0x0f); /* nargs */
  267. p1275buf.prom_args[2] = nrets = ((fmt & 0xf0) >> 4);  /* nrets */
  268. attrs = fmt >> 8;
  269. va_start(list, fmt);
  270. for (i = 0; i < nargs; i++, attrs >>= 3) {
  271. switch (attrs & 0x7) {
  272. case P1275_ARG_NUMBER:
  273. p1275buf.prom_args[i + 3] =
  274. (unsigned)va_arg(list, long);
  275. break;
  276. case P1275_ARG_IN_64B:
  277. p1275buf.prom_args[i + 3] =
  278. va_arg(list, unsigned long);
  279. break;
  280. case P1275_ARG_IN_STRING:
  281. strcpy (p, va_arg(list, char *));
  282. p1275buf.prom_args[i + 3] = (unsigned long)p;
  283. p = (char *)(((long)(strchr (p, 0) + 8)) & ~7);
  284. break;
  285. case P1275_ARG_OUT_BUF:
  286. (void) va_arg(list, char *);
  287. p1275buf.prom_args[i + 3] = (unsigned long)p;
  288. x = va_arg(list, long);
  289. i++; attrs >>= 3;
  290. p = (char *)(((long)(p + (int)x + 7)) & ~7);
  291. p1275buf.prom_args[i + 3] = x;
  292. break;
  293. case P1275_ARG_IN_BUF:
  294. q = va_arg(list, char *);
  295. p1275buf.prom_args[i + 3] = (unsigned long)p;
  296. x = va_arg(list, long);
  297. i++; attrs >>= 3;
  298. memcpy (p, q, (int)x);
  299. p = (char *)(((long)(p + (int)x + 7)) & ~7);
  300. p1275buf.prom_args[i + 3] = x;
  301. break;
  302. case P1275_ARG_OUT_32B:
  303. (void) va_arg(list, char *);
  304. p1275buf.prom_args[i + 3] = (unsigned long)p;
  305. p += 32;
  306. break;
  307. case P1275_ARG_IN_FUNCTION:
  308. p1275buf.prom_args[i + 3] =
  309. (unsigned long)prom_cif_callback;
  310. p1275buf.prom_callback = va_arg(list, long);
  311. break;
  312. }
  313. }
  314. va_end(list);
  315. prom_world(1);
  316. prom_cif_interface();
  317. prom_world(0);
  318. attrs = fmt >> 8;
  319. va_start(list, fmt);
  320. for (i = 0; i < nargs; i++, attrs >>= 3) {
  321. switch (attrs & 0x7) {
  322. case P1275_ARG_NUMBER:
  323. (void) va_arg(list, long);
  324. break;
  325. case P1275_ARG_IN_STRING:
  326. (void) va_arg(list, char *);
  327. break;
  328. case P1275_ARG_IN_FUNCTION:
  329. (void) va_arg(list, long);
  330. break;
  331. case P1275_ARG_IN_BUF:
  332. (void) va_arg(list, char *);
  333. (void) va_arg(list, long);
  334. i++; attrs >>= 3;
  335. break;
  336. case P1275_ARG_OUT_BUF:
  337. p = va_arg(list, char *);
  338. x = va_arg(list, long);
  339. memcpy (p, (char *)(p1275buf.prom_args[i + 3]), (int)x);
  340. i++; attrs >>= 3;
  341. break;
  342. case P1275_ARG_OUT_32B:
  343. p = va_arg(list, char *);
  344. memcpy (p, (char *)(p1275buf.prom_args[i + 3]), 32);
  345. break;
  346. }
  347. }
  348. va_end(list);
  349. x = p1275buf.prom_args [nargs + 3];
  350. spin_unlock_irqrestore(&prom_entry_lock, flags);
  351. if (ctx)
  352. spitfire_set_primary_context (ctx);
  353. return x;
  354. }
  355. void prom_cif_init(void *cif_handler, void *cif_stack)
  356. {
  357. p1275buf.prom_cif_handler = (void (*)(long *))cif_handler;
  358. p1275buf.prom_cif_stack = (unsigned long)cif_stack;
  359. }