open_pic2.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712
  1. /*
  2. * arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling
  3. *
  4. * Copyright (C) 1997 Geert Uytterhoeven
  5. *
  6. * This file is subject to the terms and conditions of the GNU General Public
  7. * License. See the file COPYING in the main directory of this archive
  8. * for more details.
  9. *
  10. * This is a duplicate of open_pic.c that deals with U3s MPIC on
  11. * G5 PowerMacs. It's the same file except it's using big endian
  12. * register accesses
  13. */
  14. #include <linux/config.h>
  15. #include <linux/types.h>
  16. #include <linux/kernel.h>
  17. #include <linux/sched.h>
  18. #include <linux/init.h>
  19. #include <linux/interrupt.h>
  20. #include <linux/sysdev.h>
  21. #include <linux/errno.h>
  22. #include <asm/ptrace.h>
  23. #include <asm/signal.h>
  24. #include <asm/io.h>
  25. #include <asm/irq.h>
  26. #include <asm/sections.h>
  27. #include <asm/open_pic.h>
  28. #include <asm/i8259.h>
  29. #include "open_pic_defs.h"
  30. void *OpenPIC2_Addr;
  31. static volatile struct OpenPIC *OpenPIC2 = NULL;
  32. /*
  33. * We define OpenPIC_InitSenses table thusly:
  34. * bit 0x1: sense, 0 for edge and 1 for level.
  35. * bit 0x2: polarity, 0 for negative, 1 for positive.
  36. */
  37. extern u_int OpenPIC_NumInitSenses;
  38. extern u_char *OpenPIC_InitSenses;
  39. extern int use_of_interrupt_tree;
  40. static u_int NumProcessors;
  41. static u_int NumSources;
  42. static int open_pic2_irq_offset;
  43. static volatile OpenPIC_Source *ISR[NR_IRQS];
  44. /* Global Operations */
  45. static void openpic2_disable_8259_pass_through(void);
  46. static void openpic2_set_priority(u_int pri);
  47. static void openpic2_set_spurious(u_int vector);
  48. /* Timer Interrupts */
  49. static void openpic2_inittimer(u_int timer, u_int pri, u_int vector);
  50. static void openpic2_maptimer(u_int timer, u_int cpumask);
  51. /* Interrupt Sources */
  52. static void openpic2_enable_irq(u_int irq);
  53. static void openpic2_disable_irq(u_int irq);
  54. static void openpic2_initirq(u_int irq, u_int pri, u_int vector, int polarity,
  55. int is_level);
  56. static void openpic2_mapirq(u_int irq, u_int cpumask, u_int keepmask);
  57. /*
  58. * These functions are not used but the code is kept here
  59. * for completeness and future reference.
  60. */
  61. static void openpic2_reset(void);
  62. #ifdef notused
  63. static void openpic2_enable_8259_pass_through(void);
  64. static u_int openpic2_get_priority(void);
  65. static u_int openpic2_get_spurious(void);
  66. static void openpic2_set_sense(u_int irq, int sense);
  67. #endif /* notused */
  68. /*
  69. * Description of the openpic for the higher-level irq code
  70. */
  71. static void openpic2_end_irq(unsigned int irq_nr);
  72. static void openpic2_ack_irq(unsigned int irq_nr);
  73. struct hw_interrupt_type open_pic2 = {
  74. .typename = " OpenPIC2 ",
  75. .enable = openpic2_enable_irq,
  76. .disable = openpic2_disable_irq,
  77. .ack = openpic2_ack_irq,
  78. .end = openpic2_end_irq,
  79. };
  80. /*
  81. * Accesses to the current processor's openpic registers
  82. * On cascaded controller, this is only CPU 0
  83. */
  84. #define THIS_CPU Processor[0]
  85. #define DECL_THIS_CPU
  86. #define CHECK_THIS_CPU
  87. #if 1
  88. #define check_arg_ipi(ipi) \
  89. if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \
  90. printk("open_pic.c:%d: illegal ipi %d\n", __LINE__, ipi);
  91. #define check_arg_timer(timer) \
  92. if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \
  93. printk("open_pic.c:%d: illegal timer %d\n", __LINE__, timer);
  94. #define check_arg_vec(vec) \
  95. if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \
  96. printk("open_pic.c:%d: illegal vector %d\n", __LINE__, vec);
  97. #define check_arg_pri(pri) \
  98. if (pri < 0 || pri >= OPENPIC_NUM_PRI) \
  99. printk("open_pic.c:%d: illegal priority %d\n", __LINE__, pri);
  100. /*
  101. * Print out a backtrace if it's out of range, since if it's larger than NR_IRQ's
  102. * data has probably been corrupted and we're going to panic or deadlock later
  103. * anyway --Troy
  104. */
  105. extern unsigned long* _get_SP(void);
  106. #define check_arg_irq(irq) \
  107. if (irq < open_pic2_irq_offset || irq >= NumSources+open_pic2_irq_offset \
  108. || ISR[irq - open_pic2_irq_offset] == 0) { \
  109. printk("open_pic.c:%d: illegal irq %d\n", __LINE__, irq); \
  110. /*print_backtrace(_get_SP());*/ }
  111. #define check_arg_cpu(cpu) \
  112. if (cpu < 0 || cpu >= NumProcessors){ \
  113. printk("open_pic2.c:%d: illegal cpu %d\n", __LINE__, cpu); \
  114. /*print_backtrace(_get_SP());*/ }
  115. #else
  116. #define check_arg_ipi(ipi) do {} while (0)
  117. #define check_arg_timer(timer) do {} while (0)
  118. #define check_arg_vec(vec) do {} while (0)
  119. #define check_arg_pri(pri) do {} while (0)
  120. #define check_arg_irq(irq) do {} while (0)
  121. #define check_arg_cpu(cpu) do {} while (0)
  122. #endif
  123. static u_int openpic2_read(volatile u_int *addr)
  124. {
  125. u_int val;
  126. val = in_be32(addr);
  127. return val;
  128. }
  129. static inline void openpic2_write(volatile u_int *addr, u_int val)
  130. {
  131. out_be32(addr, val);
  132. }
  133. static inline u_int openpic2_readfield(volatile u_int *addr, u_int mask)
  134. {
  135. u_int val = openpic2_read(addr);
  136. return val & mask;
  137. }
  138. inline void openpic2_writefield(volatile u_int *addr, u_int mask,
  139. u_int field)
  140. {
  141. u_int val = openpic2_read(addr);
  142. openpic2_write(addr, (val & ~mask) | (field & mask));
  143. }
  144. static inline void openpic2_clearfield(volatile u_int *addr, u_int mask)
  145. {
  146. openpic2_writefield(addr, mask, 0);
  147. }
  148. static inline void openpic2_setfield(volatile u_int *addr, u_int mask)
  149. {
  150. openpic2_writefield(addr, mask, mask);
  151. }
  152. static void openpic2_safe_writefield(volatile u_int *addr, u_int mask,
  153. u_int field)
  154. {
  155. openpic2_setfield(addr, OPENPIC_MASK);
  156. while (openpic2_read(addr) & OPENPIC_ACTIVITY);
  157. openpic2_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
  158. }
  159. static void openpic2_reset(void)
  160. {
  161. openpic2_setfield(&OpenPIC2->Global.Global_Configuration0,
  162. OPENPIC_CONFIG_RESET);
  163. while (openpic2_readfield(&OpenPIC2->Global.Global_Configuration0,
  164. OPENPIC_CONFIG_RESET))
  165. mb();
  166. }
  167. void __init openpic2_set_sources(int first_irq, int num_irqs, void *first_ISR)
  168. {
  169. volatile OpenPIC_Source *src = first_ISR;
  170. int i, last_irq;
  171. last_irq = first_irq + num_irqs;
  172. if (last_irq > NumSources)
  173. NumSources = last_irq;
  174. if (src == 0)
  175. src = &((struct OpenPIC *)OpenPIC2_Addr)->Source[first_irq];
  176. for (i = first_irq; i < last_irq; ++i, ++src)
  177. ISR[i] = src;
  178. }
  179. /*
  180. * The `offset' parameter defines where the interrupts handled by the
  181. * OpenPIC start in the space of interrupt numbers that the kernel knows
  182. * about. In other words, the OpenPIC's IRQ0 is numbered `offset' in the
  183. * kernel's interrupt numbering scheme.
  184. * We assume there is only one OpenPIC.
  185. */
  186. void __init openpic2_init(int offset)
  187. {
  188. u_int t, i;
  189. u_int timerfreq;
  190. const char *version;
  191. if (!OpenPIC2_Addr) {
  192. printk("No OpenPIC2 found !\n");
  193. return;
  194. }
  195. OpenPIC2 = (volatile struct OpenPIC *)OpenPIC2_Addr;
  196. if (ppc_md.progress) ppc_md.progress("openpic: enter", 0x122);
  197. t = openpic2_read(&OpenPIC2->Global.Feature_Reporting0);
  198. switch (t & OPENPIC_FEATURE_VERSION_MASK) {
  199. case 1:
  200. version = "1.0";
  201. break;
  202. case 2:
  203. version = "1.2";
  204. break;
  205. case 3:
  206. version = "1.3";
  207. break;
  208. default:
  209. version = "?";
  210. break;
  211. }
  212. NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
  213. OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1;
  214. if (NumSources == 0)
  215. openpic2_set_sources(0,
  216. ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >>
  217. OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1,
  218. NULL);
  219. printk("OpenPIC (2) Version %s (%d CPUs and %d IRQ sources) at %p\n",
  220. version, NumProcessors, NumSources, OpenPIC2);
  221. timerfreq = openpic2_read(&OpenPIC2->Global.Timer_Frequency);
  222. if (timerfreq)
  223. printk("OpenPIC timer frequency is %d.%06d MHz\n",
  224. timerfreq / 1000000, timerfreq % 1000000);
  225. open_pic2_irq_offset = offset;
  226. /* Initialize timer interrupts */
  227. if ( ppc_md.progress ) ppc_md.progress("openpic2: timer",0x3ba);
  228. for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
  229. /* Disabled, Priority 0 */
  230. openpic2_inittimer(i, 0, OPENPIC2_VEC_TIMER+i+offset);
  231. /* No processor */
  232. openpic2_maptimer(i, 0);
  233. }
  234. /* Initialize external interrupts */
  235. if (ppc_md.progress) ppc_md.progress("openpic2: external",0x3bc);
  236. openpic2_set_priority(0xf);
  237. /* Init all external sources, including possibly the cascade. */
  238. for (i = 0; i < NumSources; i++) {
  239. int sense;
  240. if (ISR[i] == 0)
  241. continue;
  242. /* the bootloader may have left it enabled (bad !) */
  243. openpic2_disable_irq(i+offset);
  244. sense = (i < OpenPIC_NumInitSenses)? OpenPIC_InitSenses[i]: \
  245. (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE);
  246. if (sense & IRQ_SENSE_MASK)
  247. irq_desc[i+offset].status = IRQ_LEVEL;
  248. /* Enabled, Priority 8 */
  249. openpic2_initirq(i, 8, i+offset, (sense & IRQ_POLARITY_MASK),
  250. (sense & IRQ_SENSE_MASK));
  251. /* Processor 0 */
  252. openpic2_mapirq(i, 1<<0, 0);
  253. }
  254. /* Init descriptors */
  255. for (i = offset; i < NumSources + offset; i++)
  256. irq_desc[i].handler = &open_pic2;
  257. /* Initialize the spurious interrupt */
  258. if (ppc_md.progress) ppc_md.progress("openpic2: spurious",0x3bd);
  259. openpic2_set_spurious(OPENPIC2_VEC_SPURIOUS+offset);
  260. openpic2_disable_8259_pass_through();
  261. openpic2_set_priority(0);
  262. if (ppc_md.progress) ppc_md.progress("openpic2: exit",0x222);
  263. }
  264. #ifdef notused
  265. static void openpic2_enable_8259_pass_through(void)
  266. {
  267. openpic2_clearfield(&OpenPIC2->Global.Global_Configuration0,
  268. OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
  269. }
  270. #endif /* notused */
  271. /* This can't be __init, it is used in openpic_sleep_restore_intrs */
  272. static void openpic2_disable_8259_pass_through(void)
  273. {
  274. openpic2_setfield(&OpenPIC2->Global.Global_Configuration0,
  275. OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
  276. }
  277. /*
  278. * Find out the current interrupt
  279. */
  280. u_int openpic2_irq(void)
  281. {
  282. u_int vec;
  283. DECL_THIS_CPU;
  284. CHECK_THIS_CPU;
  285. vec = openpic2_readfield(&OpenPIC2->THIS_CPU.Interrupt_Acknowledge,
  286. OPENPIC_VECTOR_MASK);
  287. return vec;
  288. }
  289. void openpic2_eoi(void)
  290. {
  291. DECL_THIS_CPU;
  292. CHECK_THIS_CPU;
  293. openpic2_write(&OpenPIC2->THIS_CPU.EOI, 0);
  294. /* Handle PCI write posting */
  295. (void)openpic2_read(&OpenPIC2->THIS_CPU.EOI);
  296. }
  297. #ifdef notused
  298. static u_int openpic2_get_priority(void)
  299. {
  300. DECL_THIS_CPU;
  301. CHECK_THIS_CPU;
  302. return openpic2_readfield(&OpenPIC2->THIS_CPU.Current_Task_Priority,
  303. OPENPIC_CURRENT_TASK_PRIORITY_MASK);
  304. }
  305. #endif /* notused */
  306. static void __init openpic2_set_priority(u_int pri)
  307. {
  308. DECL_THIS_CPU;
  309. CHECK_THIS_CPU;
  310. check_arg_pri(pri);
  311. openpic2_writefield(&OpenPIC2->THIS_CPU.Current_Task_Priority,
  312. OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri);
  313. }
  314. /*
  315. * Get/set the spurious vector
  316. */
  317. #ifdef notused
  318. static u_int openpic2_get_spurious(void)
  319. {
  320. return openpic2_readfield(&OpenPIC2->Global.Spurious_Vector,
  321. OPENPIC_VECTOR_MASK);
  322. }
  323. #endif /* notused */
  324. /* This can't be __init, it is used in openpic_sleep_restore_intrs */
  325. static void openpic2_set_spurious(u_int vec)
  326. {
  327. check_arg_vec(vec);
  328. openpic2_writefield(&OpenPIC2->Global.Spurious_Vector, OPENPIC_VECTOR_MASK,
  329. vec);
  330. }
  331. static DEFINE_SPINLOCK(openpic2_setup_lock);
  332. /*
  333. * Initialize a timer interrupt (and disable it)
  334. *
  335. * timer: OpenPIC timer number
  336. * pri: interrupt source priority
  337. * vec: the vector it will produce
  338. */
  339. static void __init openpic2_inittimer(u_int timer, u_int pri, u_int vec)
  340. {
  341. check_arg_timer(timer);
  342. check_arg_pri(pri);
  343. check_arg_vec(vec);
  344. openpic2_safe_writefield(&OpenPIC2->Global.Timer[timer].Vector_Priority,
  345. OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
  346. (pri << OPENPIC_PRIORITY_SHIFT) | vec);
  347. }
  348. /*
  349. * Map a timer interrupt to one or more CPUs
  350. */
  351. static void __init openpic2_maptimer(u_int timer, u_int cpumask)
  352. {
  353. check_arg_timer(timer);
  354. openpic2_write(&OpenPIC2->Global.Timer[timer].Destination,
  355. cpumask);
  356. }
  357. /*
  358. * Initalize the interrupt source which will generate an NMI.
  359. * This raises the interrupt's priority from 8 to 9.
  360. *
  361. * irq: The logical IRQ which generates an NMI.
  362. */
  363. void __init
  364. openpic2_init_nmi_irq(u_int irq)
  365. {
  366. check_arg_irq(irq);
  367. openpic2_safe_writefield(&ISR[irq - open_pic2_irq_offset]->Vector_Priority,
  368. OPENPIC_PRIORITY_MASK,
  369. 9 << OPENPIC_PRIORITY_SHIFT);
  370. }
  371. /*
  372. *
  373. * All functions below take an offset'ed irq argument
  374. *
  375. */
  376. /*
  377. * Enable/disable an external interrupt source
  378. *
  379. * Externally called, irq is an offseted system-wide interrupt number
  380. */
  381. static void openpic2_enable_irq(u_int irq)
  382. {
  383. volatile u_int *vpp;
  384. check_arg_irq(irq);
  385. vpp = &ISR[irq - open_pic2_irq_offset]->Vector_Priority;
  386. openpic2_clearfield(vpp, OPENPIC_MASK);
  387. /* make sure mask gets to controller before we return to user */
  388. do {
  389. mb(); /* sync is probably useless here */
  390. } while (openpic2_readfield(vpp, OPENPIC_MASK));
  391. }
  392. static void openpic2_disable_irq(u_int irq)
  393. {
  394. volatile u_int *vpp;
  395. u32 vp;
  396. check_arg_irq(irq);
  397. vpp = &ISR[irq - open_pic2_irq_offset]->Vector_Priority;
  398. openpic2_setfield(vpp, OPENPIC_MASK);
  399. /* make sure mask gets to controller before we return to user */
  400. do {
  401. mb(); /* sync is probably useless here */
  402. vp = openpic2_readfield(vpp, OPENPIC_MASK | OPENPIC_ACTIVITY);
  403. } while((vp & OPENPIC_ACTIVITY) && !(vp & OPENPIC_MASK));
  404. }
  405. /*
  406. * Initialize an interrupt source (and disable it!)
  407. *
  408. * irq: OpenPIC interrupt number
  409. * pri: interrupt source priority
  410. * vec: the vector it will produce
  411. * pol: polarity (1 for positive, 0 for negative)
  412. * sense: 1 for level, 0 for edge
  413. */
  414. static void __init
  415. openpic2_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense)
  416. {
  417. openpic2_safe_writefield(&ISR[irq]->Vector_Priority,
  418. OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
  419. OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK,
  420. (pri << OPENPIC_PRIORITY_SHIFT) | vec |
  421. (pol ? OPENPIC_POLARITY_POSITIVE :
  422. OPENPIC_POLARITY_NEGATIVE) |
  423. (sense ? OPENPIC_SENSE_LEVEL : OPENPIC_SENSE_EDGE));
  424. }
  425. /*
  426. * Map an interrupt source to one or more CPUs
  427. */
  428. static void openpic2_mapirq(u_int irq, u_int physmask, u_int keepmask)
  429. {
  430. if (ISR[irq] == 0)
  431. return;
  432. if (keepmask != 0)
  433. physmask |= openpic2_read(&ISR[irq]->Destination) & keepmask;
  434. openpic2_write(&ISR[irq]->Destination, physmask);
  435. }
  436. #ifdef notused
  437. /*
  438. * Set the sense for an interrupt source (and disable it!)
  439. *
  440. * sense: 1 for level, 0 for edge
  441. */
  442. static void openpic2_set_sense(u_int irq, int sense)
  443. {
  444. if (ISR[irq] != 0)
  445. openpic2_safe_writefield(&ISR[irq]->Vector_Priority,
  446. OPENPIC_SENSE_LEVEL,
  447. (sense ? OPENPIC_SENSE_LEVEL : 0));
  448. }
  449. #endif /* notused */
  450. /* No spinlocks, should not be necessary with the OpenPIC
  451. * (1 register = 1 interrupt and we have the desc lock).
  452. */
  453. static void openpic2_ack_irq(unsigned int irq_nr)
  454. {
  455. openpic2_disable_irq(irq_nr);
  456. openpic2_eoi();
  457. }
  458. static void openpic2_end_irq(unsigned int irq_nr)
  459. {
  460. if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
  461. openpic2_enable_irq(irq_nr);
  462. }
  463. int
  464. openpic2_get_irq(struct pt_regs *regs)
  465. {
  466. int irq = openpic2_irq();
  467. if (irq == (OPENPIC2_VEC_SPURIOUS + open_pic2_irq_offset))
  468. irq = -1;
  469. return irq;
  470. }
  471. #ifdef CONFIG_PM
  472. /*
  473. * We implement the IRQ controller as a sysdev and put it
  474. * to sleep at powerdown stage (the callback is named suspend,
  475. * but it's old semantics, for the Device Model, it's really
  476. * powerdown). The possible problem is that another sysdev that
  477. * happens to be suspend after this one will have interrupts off,
  478. * that may be an issue... For now, this isn't an issue on pmac
  479. * though...
  480. */
  481. static u32 save_ipi_vp[OPENPIC_NUM_IPI];
  482. static u32 save_irq_src_vp[OPENPIC_MAX_SOURCES];
  483. static u32 save_irq_src_dest[OPENPIC_MAX_SOURCES];
  484. static u32 save_cpu_task_pri[OPENPIC_MAX_PROCESSORS];
  485. static int openpic_suspend_count;
  486. static void openpic2_cached_enable_irq(u_int irq)
  487. {
  488. check_arg_irq(irq);
  489. save_irq_src_vp[irq - open_pic2_irq_offset] &= ~OPENPIC_MASK;
  490. }
  491. static void openpic2_cached_disable_irq(u_int irq)
  492. {
  493. check_arg_irq(irq);
  494. save_irq_src_vp[irq - open_pic2_irq_offset] |= OPENPIC_MASK;
  495. }
  496. /* WARNING: Can be called directly by the cpufreq code with NULL parameter,
  497. * we need something better to deal with that... Maybe switch to S1 for
  498. * cpufreq changes
  499. */
  500. int openpic2_suspend(struct sys_device *sysdev, pm_message_t state)
  501. {
  502. int i;
  503. unsigned long flags;
  504. spin_lock_irqsave(&openpic2_setup_lock, flags);
  505. if (openpic_suspend_count++ > 0) {
  506. spin_unlock_irqrestore(&openpic2_setup_lock, flags);
  507. return 0;
  508. }
  509. open_pic2.enable = openpic2_cached_enable_irq;
  510. open_pic2.disable = openpic2_cached_disable_irq;
  511. for (i=0; i<NumProcessors; i++) {
  512. save_cpu_task_pri[i] = openpic2_read(&OpenPIC2->Processor[i].Current_Task_Priority);
  513. openpic2_writefield(&OpenPIC2->Processor[i].Current_Task_Priority,
  514. OPENPIC_CURRENT_TASK_PRIORITY_MASK, 0xf);
  515. }
  516. for (i=0; i<OPENPIC_NUM_IPI; i++)
  517. save_ipi_vp[i] = openpic2_read(&OpenPIC2->Global.IPI_Vector_Priority(i));
  518. for (i=0; i<NumSources; i++) {
  519. if (ISR[i] == 0)
  520. continue;
  521. save_irq_src_vp[i] = openpic2_read(&ISR[i]->Vector_Priority) & ~OPENPIC_ACTIVITY;
  522. save_irq_src_dest[i] = openpic2_read(&ISR[i]->Destination);
  523. }
  524. spin_unlock_irqrestore(&openpic2_setup_lock, flags);
  525. return 0;
  526. }
  527. /* WARNING: Can be called directly by the cpufreq code with NULL parameter,
  528. * we need something better to deal with that... Maybe switch to S1 for
  529. * cpufreq changes
  530. */
  531. int openpic2_resume(struct sys_device *sysdev)
  532. {
  533. int i;
  534. unsigned long flags;
  535. u32 vppmask = OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
  536. OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK |
  537. OPENPIC_MASK;
  538. spin_lock_irqsave(&openpic2_setup_lock, flags);
  539. if ((--openpic_suspend_count) > 0) {
  540. spin_unlock_irqrestore(&openpic2_setup_lock, flags);
  541. return 0;
  542. }
  543. openpic2_reset();
  544. /* OpenPIC sometimes seem to need some time to be fully back up... */
  545. do {
  546. openpic2_set_spurious(OPENPIC2_VEC_SPURIOUS+open_pic2_irq_offset);
  547. } while(openpic2_readfield(&OpenPIC2->Global.Spurious_Vector, OPENPIC_VECTOR_MASK)
  548. != (OPENPIC2_VEC_SPURIOUS + open_pic2_irq_offset));
  549. openpic2_disable_8259_pass_through();
  550. for (i=0; i<OPENPIC_NUM_IPI; i++)
  551. openpic2_write(&OpenPIC2->Global.IPI_Vector_Priority(i),
  552. save_ipi_vp[i]);
  553. for (i=0; i<NumSources; i++) {
  554. if (ISR[i] == 0)
  555. continue;
  556. openpic2_write(&ISR[i]->Destination, save_irq_src_dest[i]);
  557. openpic2_write(&ISR[i]->Vector_Priority, save_irq_src_vp[i]);
  558. /* make sure mask gets to controller before we return to user */
  559. do {
  560. openpic2_write(&ISR[i]->Vector_Priority, save_irq_src_vp[i]);
  561. } while (openpic2_readfield(&ISR[i]->Vector_Priority, vppmask)
  562. != (save_irq_src_vp[i] & vppmask));
  563. }
  564. for (i=0; i<NumProcessors; i++)
  565. openpic2_write(&OpenPIC2->Processor[i].Current_Task_Priority,
  566. save_cpu_task_pri[i]);
  567. open_pic2.enable = openpic2_enable_irq;
  568. open_pic2.disable = openpic2_disable_irq;
  569. spin_unlock_irqrestore(&openpic2_setup_lock, flags);
  570. return 0;
  571. }
  572. #endif /* CONFIG_PM */
  573. /* HACK ALERT */
  574. static struct sysdev_class openpic2_sysclass = {
  575. set_kset_name("openpic2"),
  576. };
  577. static struct sys_device device_openpic2 = {
  578. .id = 0,
  579. .cls = &openpic2_sysclass,
  580. };
  581. static struct sysdev_driver driver_openpic2 = {
  582. #ifdef CONFIG_PM
  583. .suspend = &openpic2_suspend,
  584. .resume = &openpic2_resume,
  585. #endif /* CONFIG_PM */
  586. };
  587. static int __init init_openpic2_sysfs(void)
  588. {
  589. int rc;
  590. if (!OpenPIC2_Addr)
  591. return -ENODEV;
  592. printk(KERN_DEBUG "Registering openpic2 with sysfs...\n");
  593. rc = sysdev_class_register(&openpic2_sysclass);
  594. if (rc) {
  595. printk(KERN_ERR "Failed registering openpic sys class\n");
  596. return -ENODEV;
  597. }
  598. rc = sysdev_register(&device_openpic2);
  599. if (rc) {
  600. printk(KERN_ERR "Failed registering openpic sys device\n");
  601. return -ENODEV;
  602. }
  603. rc = sysdev_driver_register(&openpic2_sysclass, &driver_openpic2);
  604. if (rc) {
  605. printk(KERN_ERR "Failed registering openpic sys driver\n");
  606. return -ENODEV;
  607. }
  608. return 0;
  609. }
  610. subsys_initcall(init_openpic2_sysfs);