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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * BK Id: SCCS/s.open_pic.c 1.33 12/19/01 09:45:54 trini
  3.  */
  4. /*
  5.  *  arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling
  6.  *
  7.  *  Copyright (C) 1997 Geert Uytterhoeven
  8.  *
  9.  *  This file is subject to the terms and conditions of the GNU General Public
  10.  *  License.  See the file COPYING in the main directory of this archive
  11.  *  for more details.
  12.  */
  13. #include <linux/config.h>
  14. #include <linux/types.h>
  15. #include <linux/kernel.h>
  16. #include <linux/sched.h>
  17. #include <linux/init.h>
  18. #include <linux/irq.h>
  19. #include <linux/init.h>
  20. #include <asm/ptrace.h>
  21. #include <asm/signal.h>
  22. #include <asm/io.h>
  23. #include <asm/irq.h>
  24. #include <asm/prom.h>
  25. #include <asm/sections.h>
  26. #include "local_irq.h"
  27. #include "open_pic.h"
  28. #include "open_pic_defs.h"
  29. #include "i8259.h"
  30. void* OpenPIC_Addr;
  31. static volatile struct OpenPIC *OpenPIC = NULL;
  32. u_int OpenPIC_NumInitSenses __initdata = 0;
  33. u_char *OpenPIC_InitSenses __initdata = NULL;
  34. extern int use_of_interrupt_tree;
  35. void find_ISUs(void);
  36. static u_int NumProcessors;
  37. static u_int NumSources;
  38. #ifdef CONFIG_POWER3
  39. static int NumISUs;
  40. #endif
  41. static int open_pic_irq_offset;
  42. static volatile unsigned char* chrp_int_ack_special;
  43. OpenPIC_SourcePtr ISU[OPENPIC_MAX_ISU];
  44. /* Global Operations */
  45. static void openpic_disable_8259_pass_through(void);
  46. static void openpic_set_priority(u_int pri);
  47. static void openpic_set_spurious(u_int vector);
  48. #ifdef CONFIG_SMP
  49. /* Interprocessor Interrupts */
  50. static void openpic_initipi(u_int ipi, u_int pri, u_int vector);
  51. static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs);
  52. #endif
  53. /* Timer Interrupts */
  54. static void openpic_inittimer(u_int timer, u_int pri, u_int vector);
  55. static void openpic_maptimer(u_int timer, u_int cpumask);
  56. /* Interrupt Sources */
  57. static void openpic_enable_irq(u_int irq);
  58. static void openpic_disable_irq(u_int irq);
  59. static void openpic_initirq(u_int irq, u_int pri, u_int vector, int polarity,
  60.     int is_level);
  61. static void openpic_mapirq(u_int irq, u_int cpumask);
  62. /*
  63.  * These functions are not used but the code is kept here
  64.  * for completeness and future reference.
  65.  */
  66. static void openpic_reset(void);
  67. #ifdef notused
  68. static void openpic_enable_8259_pass_through(void);
  69. static u_int openpic_get_priority(void);
  70. static u_int openpic_get_spurious(void);
  71. static void openpic_set_sense(u_int irq, int sense);
  72. #endif /* notused */
  73. /*
  74.  * Description of the openpic for the higher-level irq code
  75.  */
  76. static void openpic_end_irq(unsigned int irq_nr);
  77. static void openpic_ack_irq(unsigned int irq_nr);
  78. static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask);
  79. struct hw_interrupt_type open_pic = {
  80. " OpenPIC  ",
  81. NULL,
  82. NULL,
  83. openpic_enable_irq,
  84. openpic_disable_irq,
  85. openpic_ack_irq,
  86. openpic_end_irq,
  87. openpic_set_affinity
  88. };
  89. #ifdef CONFIG_SMP
  90. static void openpic_end_ipi(unsigned int irq_nr);
  91. static void openpic_ack_ipi(unsigned int irq_nr);
  92. static void openpic_enable_ipi(unsigned int irq_nr);
  93. static void openpic_disable_ipi(unsigned int irq_nr);
  94. struct hw_interrupt_type open_pic_ipi = {
  95. " OpenPIC  ",
  96. NULL,
  97. NULL,
  98. openpic_enable_ipi,
  99. openpic_disable_ipi,
  100. openpic_ack_ipi,
  101. openpic_end_ipi,
  102. 0
  103. };
  104. #endif /* CONFIG_SMP */
  105. /*
  106.  *  Accesses to the current processor's openpic registers
  107.  */
  108. #ifdef CONFIG_SMP
  109. #define THIS_CPU Processor[cpu]
  110. #define DECL_THIS_CPU int cpu = smp_hw_index[smp_processor_id()]
  111. #define CHECK_THIS_CPU check_arg_cpu(cpu)
  112. #else
  113. #define THIS_CPU Processor[0]
  114. #define DECL_THIS_CPU
  115. #define CHECK_THIS_CPU
  116. #endif /* CONFIG_SMP */
  117. #if 1
  118. #define check_arg_ipi(ipi) 
  119.     if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) 
  120. printk("open_pic.c:%d: illegal ipi %dn", __LINE__, ipi);
  121. #define check_arg_timer(timer) 
  122.     if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) 
  123. printk("open_pic.c:%d: illegal timer %dn", __LINE__, timer);
  124. #define check_arg_vec(vec) 
  125.     if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) 
  126. printk("open_pic.c:%d: illegal vector %dn", __LINE__, vec);
  127. #define check_arg_pri(pri) 
  128.     if (pri < 0 || pri >= OPENPIC_NUM_PRI) 
  129. printk("open_pic.c:%d: illegal priority %dn", __LINE__, pri);
  130. /*
  131.  * Print out a backtrace if it's out of range, since if it's larger than NR_IRQ's
  132.  * data has probably been corrupted and we're going to panic or deadlock later
  133.  * anyway --Troy
  134.  */
  135. extern unsigned long* _get_SP(void);
  136. #define check_arg_irq(irq) 
  137.     if (irq < open_pic_irq_offset || irq >= (NumSources+open_pic_irq_offset)){ 
  138.       printk("open_pic.c:%d: illegal irq %dn", __LINE__, irq); 
  139.       print_backtrace(_get_SP()); }
  140. #define check_arg_cpu(cpu) 
  141.     if (cpu < 0 || cpu >= NumProcessors){ 
  142. printk("open_pic.c:%d: illegal cpu %dn", __LINE__, cpu); 
  143. print_backtrace(_get_SP()); }
  144. #else
  145. #define check_arg_ipi(ipi) do {} while (0)
  146. #define check_arg_timer(timer) do {} while (0)
  147. #define check_arg_vec(vec) do {} while (0)
  148. #define check_arg_pri(pri) do {} while (0)
  149. #define check_arg_irq(irq) do {} while (0)
  150. #define check_arg_cpu(cpu) do {} while (0)
  151. #endif
  152. #ifdef CONFIG_POWER3
  153. #define GET_ISU(source) ISU[(source) >> 4][(source) & 0xf]
  154. #else
  155. #define GET_ISU(source) ISU[0][(source)]
  156. #endif
  157. u_int openpic_read(volatile u_int *addr)
  158. {
  159. u_int val;
  160. val = in_le32(addr);
  161. return val;
  162. }
  163. static inline void openpic_write(volatile u_int *addr, u_int val)
  164. {
  165. out_le32(addr, val);
  166. }
  167. static inline u_int openpic_readfield(volatile u_int *addr, u_int mask)
  168. {
  169. u_int val = openpic_read(addr);
  170. return val & mask;
  171. }
  172. inline void openpic_writefield(volatile u_int *addr, u_int mask,
  173.        u_int field)
  174. {
  175. u_int val = openpic_read(addr);
  176. openpic_write(addr, (val & ~mask) | (field & mask));
  177. }
  178. static inline void openpic_clearfield(volatile u_int *addr, u_int mask)
  179. {
  180. openpic_writefield(addr, mask, 0);
  181. }
  182. static inline void openpic_setfield(volatile u_int *addr, u_int mask)
  183. {
  184. openpic_writefield(addr, mask, mask);
  185. }
  186. static void openpic_safe_writefield(volatile u_int *addr, u_int mask,
  187.     u_int field)
  188. {
  189. openpic_setfield(addr, OPENPIC_MASK);
  190. while (openpic_read(addr) & OPENPIC_ACTIVITY);
  191. openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
  192. }
  193. #ifdef CONFIG_SMP
  194. /* yes this is right ... bug, feature, you decide! -- tgall */
  195. u_int openpic_read_IPI(volatile u_int* addr)
  196. {
  197.          u_int val = 0;
  198. #ifdef CONFIG_POWER3
  199.         val = in_be32(addr);
  200. #else
  201.         val = in_le32(addr);
  202. #endif
  203.         return val;
  204. }
  205. /* because of the power3 be / le above, this is needed */
  206. inline void openpic_writefield_IPI(volatile u_int* addr, u_int mask, u_int field)
  207. {
  208.         u_int  val = openpic_read_IPI(addr);
  209.         openpic_write(addr, (val & ~mask) | (field & mask));
  210. }
  211. static inline void openpic_clearfield_IPI(volatile u_int *addr, u_int mask)
  212. {
  213.         openpic_writefield_IPI(addr, mask, 0);
  214. }
  215. static inline void openpic_setfield_IPI(volatile u_int *addr, u_int mask)
  216. {
  217.         openpic_writefield_IPI(addr, mask, mask);
  218. }
  219. static void openpic_safe_writefield_IPI(volatile u_int *addr, u_int mask, u_int field)
  220. {
  221.         openpic_setfield_IPI(addr, OPENPIC_MASK);
  222.         /* wait until it's not in use */
  223.         /* BenH: Is this code really enough ? I would rather check the result
  224.          *       and eventually retry ...
  225.          */
  226.         while(openpic_read_IPI(addr) & OPENPIC_ACTIVITY);
  227.         openpic_writefield_IPI(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
  228. }
  229. #endif /* CONFIG_SMP */
  230. void __init openpic_init(int main_pic, int offset, unsigned char* chrp_ack,
  231.  int programmer_switch_irq)
  232. {
  233. u_int t, i;
  234. u_int timerfreq;
  235. const char *version;
  236. if (!OpenPIC_Addr) {
  237. printk("No OpenPIC found !n");
  238. return;
  239. }
  240. OpenPIC = (volatile struct OpenPIC *)OpenPIC_Addr;
  241. if ( ppc_md.progress ) ppc_md.progress("openpic enter",0x122);
  242. t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
  243. switch (t & OPENPIC_FEATURE_VERSION_MASK) {
  244. case 1:
  245. version = "1.0";
  246. break;
  247. case 2:
  248. version = "1.2";
  249. break;
  250. case 3:
  251. version = "1.3";
  252. break;
  253. default:
  254. version = "?";
  255. break;
  256. }
  257. NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
  258.  OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1;
  259. NumSources = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >>
  260.       OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1;
  261. printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %pn",
  262.        version, NumProcessors, NumSources, OpenPIC);
  263. timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
  264. if (timerfreq)
  265. printk("OpenPIC timer frequency is %d.%06d MHzn",
  266.        timerfreq / 1000000, timerfreq % 1000000);
  267. if (!main_pic)
  268. return;
  269. open_pic_irq_offset = offset;
  270. chrp_int_ack_special = (volatile unsigned char*)chrp_ack;
  271. /* Initialize timer interrupts */
  272. if ( ppc_md.progress ) ppc_md.progress("openpic timer",0x3ba);
  273. for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
  274. /* Disabled, Priority 0 */
  275. openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i+offset);
  276. /* No processor */
  277. openpic_maptimer(i, 0);
  278. }
  279. #ifdef CONFIG_SMP
  280. /* Initialize IPI interrupts */
  281. if ( ppc_md.progress ) ppc_md.progress("openpic ipi",0x3bb);
  282. for (i = 0; i < OPENPIC_NUM_IPI; i++) {
  283. /* Disabled, Priority 10..13 */
  284. openpic_initipi(i, 10+i, OPENPIC_VEC_IPI+i+offset);
  285. /* IPIs are per-CPU */
  286. irq_desc[OPENPIC_VEC_IPI+i+offset].status |= IRQ_PER_CPU;
  287. irq_desc[OPENPIC_VEC_IPI+i+offset].handler = &open_pic_ipi;
  288. }
  289. #endif
  290. find_ISUs();
  291. /* Initialize external interrupts */
  292. if (ppc_md.progress) ppc_md.progress("openpic ext",0x3bc);
  293. openpic_set_priority(0xf);
  294. /* SIOint (8259 cascade) is special */
  295. if (offset) {
  296. openpic_initirq(0, 8, offset, 1, 1);
  297. openpic_mapirq(0, 1<<0);
  298. }
  299. /* Init all external sources */
  300. for (i = 1; i < NumSources; i++) {
  301. int pri, sense;
  302. /* the bootloader may have left it enabled (bad !) */
  303. openpic_disable_irq(i+offset);
  304. pri = (i == programmer_switch_irq)? 9: 8;
  305. sense = (i < OpenPIC_NumInitSenses)? OpenPIC_InitSenses[i]: 1;
  306. if (sense)
  307. irq_desc[i+offset].status = IRQ_LEVEL;
  308. /* Enabled, Priority 8 or 9 */
  309. openpic_initirq(i, pri, i+offset, !sense, sense);
  310. /* Processor 0 */
  311. openpic_mapirq(i, 1<<0);
  312. }
  313. /* Init descriptors */
  314. for (i = offset; i < NumSources + offset; i++)
  315. irq_desc[i].handler = &open_pic;
  316. /* Initialize the spurious interrupt */
  317. if (ppc_md.progress) ppc_md.progress("openpic spurious",0x3bd);
  318. openpic_set_spurious(OPENPIC_VEC_SPURIOUS+offset);
  319. /* Initialize the cascade */
  320. if (offset) {
  321. if (request_irq(offset, no_action, SA_INTERRUPT,
  322. "82c59 cascade", NULL))
  323. printk("Unable to get OpenPIC IRQ 0 for cascaden");
  324. }
  325. openpic_set_priority(0);
  326. openpic_disable_8259_pass_through();
  327. if (ppc_md.progress) ppc_md.progress("openpic exit",0x222);
  328. }
  329. #ifdef CONFIG_POWER3
  330. void openpic_setup_ISU(int isu_num, unsigned long addr)
  331. {
  332. if (isu_num >= OPENPIC_MAX_ISU)
  333. return;
  334. ISU[isu_num] = (OpenPIC_SourcePtr) ioremap(addr, 0x400);
  335. if (isu_num >= NumISUs)
  336. NumISUs = isu_num + 1;
  337. }
  338. #endif
  339. void find_ISUs(void)
  340. {
  341. #ifdef CONFIG_POWER3
  342.         /* Use /interrupt-controller/reg and
  343.          * /interrupt-controller/interrupt-ranges from OF device tree
  344.  * the ISU array is setup in chrp_pci.c in ibm_add_bridges
  345.  * as a result
  346.  * -- tgall
  347.          */
  348. /* basically each ISU is a bus, and this assumes that
  349.  * open_pic_isu_count interrupts per bus are possible 
  350.  * ISU == Interrupt Source
  351.  */
  352. NumSources = NumISUs * 0x10;
  353. #else
  354. /* for non-distributed OpenPIC implementations it's in the IDU -- Cort */
  355. ISU[0] = (OpenPIC_Source *)OpenPIC->Source;
  356. #endif
  357. }
  358. static void openpic_reset(void)
  359. {
  360. openpic_setfield(&OpenPIC->Global.Global_Configuration0,
  361.  OPENPIC_CONFIG_RESET);
  362. while (openpic_readfield(&OpenPIC->Global.Global_Configuration0,
  363.  OPENPIC_CONFIG_RESET))
  364. mb();
  365. }
  366. #ifdef notused
  367. static void openpic_enable_8259_pass_through(void)
  368. {
  369. openpic_clearfield(&OpenPIC->Global.Global_Configuration0,
  370.    OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
  371. }
  372. #endif /* notused */
  373. static void openpic_disable_8259_pass_through(void)
  374. {
  375. openpic_setfield(&OpenPIC->Global.Global_Configuration0,
  376.  OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
  377. }
  378. /*
  379.  *  Find out the current interrupt
  380.  */
  381. u_int openpic_irq(void)
  382. {
  383. u_int vec;
  384. DECL_THIS_CPU;
  385. CHECK_THIS_CPU;
  386. vec = openpic_readfield(&OpenPIC->THIS_CPU.Interrupt_Acknowledge,
  387. OPENPIC_VECTOR_MASK);
  388. return vec;
  389. }
  390. void openpic_eoi(void)
  391. {
  392. DECL_THIS_CPU;
  393. CHECK_THIS_CPU;
  394. openpic_write(&OpenPIC->THIS_CPU.EOI, 0);
  395. /* Handle PCI write posting */
  396. (void)openpic_read(&OpenPIC->THIS_CPU.EOI);
  397. }
  398. #ifdef notused
  399. static u_int openpic_get_priority(void)
  400. {
  401. DECL_THIS_CPU;
  402. CHECK_THIS_CPU;
  403. return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority,
  404.  OPENPIC_CURRENT_TASK_PRIORITY_MASK);
  405. }
  406. #endif /* notused */
  407. static void openpic_set_priority(u_int pri)
  408. {
  409. DECL_THIS_CPU;
  410. CHECK_THIS_CPU;
  411. check_arg_pri(pri);
  412. openpic_writefield(&OpenPIC->THIS_CPU.Current_Task_Priority,
  413.    OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri);
  414. }
  415. /*
  416.  *  Get/set the spurious vector
  417.  */
  418. #ifdef notused
  419. static u_int openpic_get_spurious(void)
  420. {
  421. return openpic_readfield(&OpenPIC->Global.Spurious_Vector,
  422.  OPENPIC_VECTOR_MASK);
  423. }
  424. #endif /* notused */
  425. static void openpic_set_spurious(u_int vec)
  426. {
  427. check_arg_vec(vec);
  428. openpic_writefield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK,
  429.    vec);
  430. }
  431. #ifdef CONFIG_SMP
  432. /*
  433.  * Convert a cpu mask from logical to physical cpu numbers.
  434.  */
  435. static inline u32 physmask(u32 cpumask)
  436. {
  437. int i;
  438. u32 mask = 0;
  439. for (i = 0; i < smp_num_cpus; ++i, cpumask >>= 1)
  440. mask |= (cpumask & 1) << smp_hw_index[i];
  441. return mask;
  442. }
  443. #else
  444. #define physmask(cpumask) (cpumask)
  445. #endif
  446. void openpic_reset_processor_phys(u_int mask)
  447. {
  448. openpic_write(&OpenPIC->Global.Processor_Initialization, mask);
  449. }
  450. static spinlock_t openpic_setup_lock = SPIN_LOCK_UNLOCKED;
  451. #ifdef CONFIG_SMP
  452. /*
  453.  *  Initialize an interprocessor interrupt (and disable it)
  454.  *
  455.  *  ipi: OpenPIC interprocessor interrupt number
  456.  *  pri: interrupt source priority
  457.  *  vec: the vector it will produce
  458.  */
  459. static void __init openpic_initipi(u_int ipi, u_int pri, u_int vec)
  460. {
  461. check_arg_ipi(ipi);
  462. check_arg_pri(pri);
  463. check_arg_vec(vec);
  464. openpic_safe_writefield_IPI(&OpenPIC->Global.IPI_Vector_Priority(ipi),
  465. OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
  466. (pri << OPENPIC_PRIORITY_SHIFT) | vec);
  467. }
  468. /*
  469.  *  Send an IPI to one or more CPUs
  470.  *  
  471.  *  Externally called, however, it takes an IPI number (0...OPENPIC_NUM_IPI)
  472.  *  and not a system-wide interrupt number
  473.  */
  474. void openpic_cause_IPI(u_int ipi, u_int cpumask)
  475. {
  476. DECL_THIS_CPU;
  477. CHECK_THIS_CPU;
  478. check_arg_ipi(ipi);
  479. openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi),
  480.       physmask(cpumask));
  481. }
  482. void openpic_request_IPIs(void)
  483. {
  484. int i;
  485. /*
  486.  * Make sure this matches what is defined in smp.c for 
  487.  * smp_message_{pass|recv}() or what shows up in 
  488.  * /proc/interrupts will be wrong!!! --Troy */
  489. if (OpenPIC == NULL)
  490. return;
  491. request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset,
  492.     openpic_ipi_action, 0, "IPI0 (call function)", 0);
  493. request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+1,
  494.     openpic_ipi_action, 0, "IPI1 (reschedule)", 0);
  495. request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+2,
  496.     openpic_ipi_action, 0, "IPI2 (invalidate tlb)", 0);
  497. request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+3,
  498.     openpic_ipi_action, 0, "IPI3 (xmon break)", 0);
  499. for ( i = 0; i < OPENPIC_NUM_IPI ; i++ )
  500. openpic_enable_ipi(OPENPIC_VEC_IPI+open_pic_irq_offset+i);
  501. }
  502. /*
  503.  * Do per-cpu setup for SMP systems.
  504.  *
  505.  * Get IPI's working and start taking interrupts.
  506.  *   -- Cort
  507.  */
  508. void __init do_openpic_setup_cpu(void)
  509. {
  510.   int i;
  511. u32 msk = 1 << smp_hw_index[smp_processor_id()];
  512. spin_lock(&openpic_setup_lock);
  513. #ifdef CONFIG_IRQ_ALL_CPUS
  514.   /* let the openpic know we want intrs. default affinity
  515.    * is 0xffffffff until changed via /proc
  516.    * That's how it's done on x86. If we want it differently, then
  517.    * we should make sure we also change the default values of irq_affinity
  518.    * in irq.c.
  519.    */
  520.   for (i = 0; i < NumSources ; i++)
  521. openpic_mapirq(i, openpic_read(&GET_ISU(i).Destination) | msk);
  522. #endif /* CONFIG_IRQ_ALL_CPUS */
  523.   openpic_set_priority(0);
  524. spin_unlock(&openpic_setup_lock);
  525. }
  526. #endif /* CONFIG_SMP */
  527. /*
  528.  *  Initialize a timer interrupt (and disable it)
  529.  *
  530.  *  timer: OpenPIC timer number
  531.  *  pri: interrupt source priority
  532.  *  vec: the vector it will produce
  533.  */
  534. static void __init openpic_inittimer(u_int timer, u_int pri, u_int vec)
  535. {
  536. check_arg_timer(timer);
  537. check_arg_pri(pri);
  538. check_arg_vec(vec);
  539. openpic_safe_writefield(&OpenPIC->Global.Timer[timer].Vector_Priority,
  540. OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
  541. (pri << OPENPIC_PRIORITY_SHIFT) | vec);
  542. }
  543. /*
  544.  *  Map a timer interrupt to one or more CPUs
  545.  */
  546. static void __init openpic_maptimer(u_int timer, u_int cpumask)
  547. {
  548. check_arg_timer(timer);
  549. openpic_write(&OpenPIC->Global.Timer[timer].Destination,
  550.       physmask(cpumask));
  551. }
  552. /*
  553.  *
  554.  * All functions below take an offset'ed irq argument
  555.  *
  556.  */
  557. /*
  558.  *  Enable/disable an external interrupt source
  559.  *
  560.  *  Externally called, irq is an offseted system-wide interrupt number
  561.  */
  562. static void openpic_enable_irq(u_int irq)
  563. {
  564. check_arg_irq(irq);
  565. openpic_clearfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, OPENPIC_MASK);
  566. /* make sure mask gets to controller before we return to user */
  567. do {
  568. mb(); /* sync is probably useless here */
  569. } while(openpic_readfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority,
  570. OPENPIC_MASK));
  571. }
  572. static void openpic_disable_irq(u_int irq)
  573. {
  574. u32 vp;
  575. check_arg_irq(irq);
  576. openpic_setfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, OPENPIC_MASK);
  577. /* make sure mask gets to controller before we return to user */
  578. do {
  579. mb();  /* sync is probably useless here */
  580. vp = openpic_readfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority,
  581.      OPENPIC_MASK | OPENPIC_ACTIVITY);
  582. } while((vp & OPENPIC_ACTIVITY) && !(vp & OPENPIC_MASK));
  583. }
  584. #ifdef CONFIG_SMP
  585. /*
  586.  *  Enable/disable an IPI interrupt source
  587.  *  
  588.  *  Externally called, irq is an offseted system-wide interrupt number
  589.  */
  590. void openpic_enable_ipi(u_int irq)
  591. {
  592. irq -= (OPENPIC_VEC_IPI+open_pic_irq_offset);
  593. check_arg_ipi(irq);
  594. openpic_clearfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK);
  595. }
  596. void openpic_disable_ipi(u_int irq)
  597. {
  598. irq -= (OPENPIC_VEC_IPI+open_pic_irq_offset);
  599. check_arg_ipi(irq);
  600. openpic_setfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK);
  601. }
  602. #endif
  603. /*
  604.  *  Initialize an interrupt source (and disable it!)
  605.  *
  606.  *  irq: OpenPIC interrupt number
  607.  *  pri: interrupt source priority
  608.  *  vec: the vector it will produce
  609.  *  pol: polarity (1 for positive, 0 for negative)
  610.  *  sense: 1 for level, 0 for edge
  611.  */
  612. static void openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense)
  613. {
  614. openpic_safe_writefield(&GET_ISU(irq).Vector_Priority,
  615. OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
  616. OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK,
  617. (pri << OPENPIC_PRIORITY_SHIFT) | vec |
  618. (pol ? OPENPIC_POLARITY_POSITIVE :
  619.      OPENPIC_POLARITY_NEGATIVE) |
  620. (sense ? OPENPIC_SENSE_LEVEL : OPENPIC_SENSE_EDGE));
  621. }
  622. /*
  623.  *  Map an interrupt source to one or more CPUs
  624.  */
  625. static void openpic_mapirq(u_int irq, u_int physmask)
  626. {
  627. openpic_write(&GET_ISU(irq).Destination, physmask);
  628. }
  629. #ifdef notused
  630. /*
  631.  *  Set the sense for an interrupt source (and disable it!)
  632.  *
  633.  *  sense: 1 for level, 0 for edge
  634.  */
  635. static void openpic_set_sense(u_int irq, int sense)
  636. {
  637. openpic_safe_writefield(&GET_ISU(irq).Vector_Priority,
  638. OPENPIC_SENSE_LEVEL,
  639. (sense ? OPENPIC_SENSE_LEVEL : 0));
  640. }
  641. #endif /* notused */
  642. /* No spinlocks, should not be necessary with the OpenPIC
  643.  * (1 register = 1 interrupt and we have the desc lock).
  644.  */
  645. static void openpic_ack_irq(unsigned int irq_nr)
  646. {
  647. openpic_disable_irq(irq_nr);
  648. openpic_eoi();
  649. }
  650. static void openpic_end_irq(unsigned int irq_nr)
  651. {
  652. if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
  653. openpic_enable_irq(irq_nr);
  654. }
  655. static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask)
  656. {
  657. openpic_mapirq(irq_nr - open_pic_irq_offset, physmask(cpumask));
  658. }
  659. #ifdef CONFIG_SMP
  660. static void openpic_ack_ipi(unsigned int irq_nr)
  661. {
  662. openpic_eoi();
  663. }
  664. static void openpic_end_ipi(unsigned int irq_nr)
  665. {
  666. }
  667. static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
  668. {
  669. smp_message_recv(cpl-OPENPIC_VEC_IPI-open_pic_irq_offset, regs);
  670. }
  671. #endif /* CONFIG_SMP */
  672. /* This one may be merged with PReP and CHRP */
  673. int
  674. openpic_get_irq(struct pt_regs *regs)
  675. {
  676. /*
  677.  * Clean up needed. -VAL
  678.  */
  679. int irq = openpic_irq();
  680. /* Management of the cascade should be moved out of here */
  681. /* Yep - because openpic !=> i8259, for one thing. -VAL */
  682.         if (open_pic_irq_offset && irq == open_pic_irq_offset)
  683.         {
  684.                 /*
  685.                  * This magic address generates a PCI IACK cycle.
  686.                  */
  687. if ( chrp_int_ack_special )
  688. irq = *chrp_int_ack_special;
  689. #ifndef CONFIG_GEMINI
  690. else
  691. irq = i8259_poll();
  692. #endif
  693. openpic_eoi();
  694.         }
  695. if (irq == OPENPIC_VEC_SPURIOUS + open_pic_irq_offset)
  696. irq = -1;
  697. return irq;
  698. }
  699. #ifdef CONFIG_SMP
  700. void
  701. smp_openpic_message_pass(int target, int msg, unsigned long data, int wait)
  702. {
  703. /* make sure we're sending something that translates to an IPI */
  704. if (msg > 0x3) {
  705. printk("SMP %d: smp_message_pass: unknown msg %dn",
  706.        smp_processor_id(), msg);
  707. return;
  708. }
  709. switch (target) {
  710. case MSG_ALL:
  711. openpic_cause_IPI(msg, 0xffffffff);
  712. break;
  713. case MSG_ALL_BUT_SELF:
  714. openpic_cause_IPI(msg,
  715.   0xffffffff & ~(1 << smp_processor_id()));
  716. break;
  717. default:
  718. openpic_cause_IPI(msg, 1<<target);
  719. break;
  720. }
  721. }
  722. #endif /* CONFIG_SMP */
  723. #ifdef CONFIG_PMAC_PBOOK
  724. static u32 save_ipi_vp[OPENPIC_NUM_IPI];
  725. static u32 save_irq_src_vp[OPENPIC_MAX_SOURCES];
  726. static u32 save_irq_src_dest[OPENPIC_MAX_SOURCES];
  727. static u32 save_cpu_task_pri[OPENPIC_MAX_PROCESSORS];
  728. void __pmac
  729. openpic_sleep_save_intrs(void)
  730. {
  731. int i;
  732. unsigned long flags;
  733. spin_lock_irqsave(&openpic_setup_lock, flags);
  734. for (i=0; i<NumProcessors; i++) {
  735. save_cpu_task_pri[i] = openpic_read(&OpenPIC->Processor[i].Current_Task_Priority);
  736. openpic_writefield(&OpenPIC->Processor[i].Current_Task_Priority,
  737.    OPENPIC_CURRENT_TASK_PRIORITY_MASK, 0xf);
  738. }
  739. for (i=0; i<OPENPIC_NUM_IPI; i++)
  740. save_ipi_vp[i] = openpic_read(&OpenPIC->Global.IPI_Vector_Priority(i));
  741. for (i=0; i<NumSources; i++) {
  742. save_irq_src_vp[i] = openpic_read(&OpenPIC->Source[i].Vector_Priority)
  743. & ~OPENPIC_ACTIVITY;
  744. save_irq_src_dest[i] = openpic_read(&OpenPIC->Source[i].Destination);
  745. }
  746. spin_unlock_irqrestore(&openpic_setup_lock, flags);
  747. }
  748. void __pmac
  749. openpic_sleep_restore_intrs(void)
  750. {
  751. int i;
  752. unsigned long flags;
  753. spin_lock_irqsave(&openpic_setup_lock, flags);
  754. openpic_reset();
  755. for (i=0; i<OPENPIC_NUM_IPI; i++)
  756. openpic_write(&OpenPIC->Global.IPI_Vector_Priority(i), save_ipi_vp[i]);
  757. for (i=0; i<NumSources; i++) {
  758. openpic_write(&OpenPIC->Source[i].Vector_Priority, save_irq_src_vp[i]);
  759. openpic_write(&OpenPIC->Source[i].Destination, save_irq_src_dest[i]);
  760. }
  761. openpic_set_spurious(OPENPIC_VEC_SPURIOUS+open_pic_irq_offset);
  762. openpic_disable_8259_pass_through();
  763. for (i=0; i<NumProcessors; i++)
  764. openpic_write(&OpenPIC->Processor[i].Current_Task_Priority, save_cpu_task_pri[i]);
  765. spin_unlock_irqrestore(&openpic_setup_lock, flags);
  766. }
  767. #endif /* CONFIG_PMAC_PBOOK */