open_pic.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:21k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  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. #include <linux/config.h>
  11. #include <linux/types.h>
  12. #include <linux/kernel.h>
  13. #include <linux/sched.h>
  14. #include <linux/init.h>
  15. #include <linux/irq.h>
  16. #include <asm/ptrace.h>
  17. #include <asm/signal.h>
  18. #include <asm/io.h>
  19. #include <asm/pgtable.h>
  20. #include <asm/irq.h>
  21. #include <asm/prom.h>
  22. #include <asm/machdep.h>
  23. #include "local_irq.h"
  24. #include "open_pic.h"
  25. #include "open_pic_defs.h"
  26. #include "i8259.h"
  27. #include <asm/ppcdebug.h>
  28. void* OpenPIC_Addr;
  29. static volatile struct OpenPIC *OpenPIC = NULL;
  30. u_int OpenPIC_NumInitSenses __initdata = 0;
  31. u_char *OpenPIC_InitSenses __initdata = NULL;
  32. void find_ISUs(void);
  33. static u_int NumProcessors;
  34. static u_int NumSources;
  35. static int NumISUs;
  36. static int open_pic_irq_offset;
  37. static volatile unsigned char* chrp_int_ack_special;
  38. static int broken_ipi_registers;
  39. OpenPIC_SourcePtr ISU[OPENPIC_MAX_ISU];
  40. static void openpic_end_irq(unsigned int irq_nr);
  41. static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask);
  42. struct hw_interrupt_type open_pic = {
  43. " OpenPIC  ",
  44. NULL,
  45. NULL,
  46. openpic_enable_irq,
  47. openpic_disable_irq,
  48. NULL,
  49. openpic_end_irq,
  50. openpic_set_affinity
  51. };
  52. #ifdef CONFIG_SMP
  53. static void openpic_end_ipi(unsigned int irq_nr);
  54. static void openpic_enable_ipi(unsigned int irq_nr);
  55. static void openpic_disable_ipi(unsigned int irq_nr);
  56. struct hw_interrupt_type open_pic_ipi = {
  57. " OpenPIC  ",
  58. NULL,
  59. NULL,
  60. openpic_enable_ipi,
  61. openpic_disable_ipi,
  62. NULL,
  63. openpic_end_ipi,
  64. NULL
  65. };
  66. #endif /* CONFIG_SMP */
  67. unsigned int openpic_vec_ipi;
  68. unsigned int openpic_vec_timer;
  69. unsigned int openpic_vec_spurious;
  70. /*
  71.  *  Accesses to the current processor's openpic registers
  72.  */
  73. #ifdef CONFIG_SMP
  74. #define THIS_CPU Processor[cpu]
  75. #define DECL_THIS_CPU int cpu = hard_smp_processor_id()
  76. #define CHECK_THIS_CPU check_arg_cpu(cpu)
  77. #else
  78. #define THIS_CPU Processor[hard_smp_processor_id()]
  79. #define DECL_THIS_CPU
  80. #define CHECK_THIS_CPU
  81. #endif /* CONFIG_SMP */
  82. #if 1
  83. #define check_arg_ipi(ipi) 
  84.     if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) 
  85. printk(KERN_ERR "open_pic.c:%d: illegal ipi %dn", __LINE__, ipi);
  86. #define check_arg_timer(timer) 
  87.     if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) 
  88. printk(KERN_ERR "open_pic.c:%d: illegal timer %dn", __LINE__, timer);
  89. #define check_arg_vec(vec) 
  90.     if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) 
  91. printk(KERN_ERR "open_pic.c:%d: illegal vector %dn", __LINE__, vec);
  92. #define check_arg_pri(pri) 
  93.     if (pri < 0 || pri >= OPENPIC_NUM_PRI) 
  94. printk(KERN_ERR "open_pic.c:%d: illegal priority %dn", __LINE__, pri);
  95. /*
  96.  * Print out a backtrace if it's out of range, since if it's larger than NR_IRQ's
  97.  * data has probably been corrupted and we're going to panic or deadlock later
  98.  * anyway --Troy
  99.  */
  100. extern unsigned long* _get_SP(void);
  101. #define check_arg_irq(irq) 
  102.     if (irq < open_pic_irq_offset || irq >= (NumSources+open_pic_irq_offset)){ 
  103.       printk(KERN_ERR "open_pic.c:%d: illegal irq %dn", __LINE__, irq); 
  104.       print_backtrace(_get_SP()); }
  105. #define check_arg_cpu(cpu) 
  106.     if (cpu < 0 || cpu >= OPENPIC_MAX_PROCESSORS){ 
  107. printk(KERN_ERR "open_pic.c:%d: illegal cpu %dn", __LINE__, cpu); 
  108. print_backtrace(_get_SP()); }
  109. #else
  110. #define check_arg_ipi(ipi) do {} while (0)
  111. #define check_arg_timer(timer) do {} while (0)
  112. #define check_arg_vec(vec) do {} while (0)
  113. #define check_arg_pri(pri) do {} while (0)
  114. #define check_arg_irq(irq) do {} while (0)
  115. #define check_arg_cpu(cpu) do {} while (0)
  116. #endif
  117. #define GET_ISU(source) ISU[(source) >> 4][(source) & 0xf]
  118. void __init openpic_init_IRQ(void)
  119. {
  120.         struct device_node *np;
  121.         int i;
  122.         unsigned int *addrp;
  123.         unsigned char* chrp_int_ack_special = 0;
  124.         unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS];
  125.         int nmi_irq = -1;
  126. #if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) && defined(XMON)
  127.         struct device_node *kbd;
  128. #endif
  129.         if (!(np = find_devices("pci"))
  130.             || !(addrp = (unsigned int *)
  131.                  get_property(np, "8259-interrupt-acknowledge", NULL)))
  132.                 printk(KERN_ERR "Cannot find pci to get ack addressn");
  133.         else
  134. chrp_int_ack_special = (unsigned char *)
  135. __ioremap(addrp[prom_n_addr_cells(np)-1], 1, _PAGE_NO_CACHE);
  136.         /* hydra still sets OpenPIC_InitSenses to a static set of values */
  137.         if (OpenPIC_InitSenses == NULL) {
  138.                 prom_get_irq_senses(init_senses, NUM_8259_INTERRUPTS, NR_IRQS);
  139.                 OpenPIC_InitSenses = init_senses;
  140.                 OpenPIC_NumInitSenses = NR_IRQS - NUM_8259_INTERRUPTS;
  141.         }
  142.         openpic_init(1, NUM_8259_INTERRUPTS, chrp_int_ack_special, nmi_irq);
  143.         for ( i = 0 ; i < NUM_8259_INTERRUPTS  ; i++ )
  144.                 irq_desc[i].handler = &i8259_pic;
  145.         i8259_init();
  146. }
  147. static inline u_int openpic_read(volatile u_int *addr)
  148. {
  149. u_int val;
  150. val = in_le32(addr);
  151. return val;
  152. }
  153. static inline void openpic_write(volatile u_int *addr, u_int val)
  154. {
  155. out_le32(addr, val);
  156. }
  157. static inline u_int openpic_readfield(volatile u_int *addr, u_int mask)
  158. {
  159. u_int val = openpic_read(addr);
  160. return val & mask;
  161. }
  162. static inline void openpic_writefield(volatile u_int *addr, u_int mask,
  163.        u_int field)
  164. {
  165. u_int val = openpic_read(addr);
  166. openpic_write(addr, (val & ~mask) | (field & mask));
  167. }
  168. static inline void openpic_clearfield(volatile u_int *addr, u_int mask)
  169. {
  170. openpic_writefield(addr, mask, 0);
  171. }
  172. static inline void openpic_setfield(volatile u_int *addr, u_int mask)
  173. {
  174. openpic_writefield(addr, mask, mask);
  175. }
  176. static void openpic_safe_writefield(volatile u_int *addr, u_int mask,
  177.     u_int field)
  178. {
  179. unsigned int loops = 100000;
  180. openpic_setfield(addr, OPENPIC_MASK);
  181. while (openpic_read(addr) & OPENPIC_ACTIVITY) {
  182. if (!loops--) {
  183. printk(KERN_ERR "openpic_safe_writefield timeoutn");
  184. break;
  185. }
  186. }
  187. openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
  188. }
  189. #ifdef CONFIG_SMP
  190. static u_int openpic_read_IPI(volatile u_int* addr)
  191. {
  192.         u_int val = 0;
  193. if (broken_ipi_registers)
  194. /* yes this is right ... bug, feature, you decide! -- tgall */
  195. val = in_be32(addr);
  196. else
  197. val = in_le32(addr);
  198.         return val;
  199. }
  200. static void openpic_test_broken_IPI(void)
  201. {
  202. u_int t;
  203. openpic_write(&OpenPIC->Global.IPI_Vector_Priority(0), OPENPIC_MASK);
  204. t = openpic_read(&OpenPIC->Global.IPI_Vector_Priority(0));
  205. if (t == le32_to_cpu(OPENPIC_MASK)) {
  206. printk(KERN_INFO "OpenPIC reversed IPI registers detectedn");
  207. broken_ipi_registers = 1;
  208. }
  209. }
  210. /* because of the power3 be / le above, this is needed */
  211. static inline void openpic_writefield_IPI(volatile u_int* addr, u_int mask, u_int field)
  212. {
  213.         u_int  val = openpic_read_IPI(addr);
  214.         openpic_write(addr, (val & ~mask) | (field & mask));
  215. }
  216. static inline void openpic_clearfield_IPI(volatile u_int *addr, u_int mask)
  217. {
  218.         openpic_writefield_IPI(addr, mask, 0);
  219. }
  220. static inline void openpic_setfield_IPI(volatile u_int *addr, u_int mask)
  221. {
  222.         openpic_writefield_IPI(addr, mask, mask);
  223. }
  224. static void openpic_safe_writefield_IPI(volatile u_int *addr, u_int mask, u_int field)
  225. {
  226. unsigned int loops = 100000;
  227.         openpic_setfield_IPI(addr, OPENPIC_MASK);
  228.         /* wait until it's not in use */
  229.         /* BenH: Is this code really enough ? I would rather check the result
  230.          *       and eventually retry ...
  231.          */
  232.         while(openpic_read_IPI(addr) & OPENPIC_ACTIVITY) {
  233. if (!loops--) {
  234. printk(KERN_ERR "openpic_safe_writefield timeoutn");
  235. break;
  236. }
  237. }
  238.         openpic_writefield_IPI(addr, mask, field | OPENPIC_MASK);
  239. }
  240. #endif /* CONFIG_SMP */
  241. void __init openpic_init(int main_pic, int offset, unsigned char* chrp_ack,
  242.  int programmer_switch_irq)
  243. {
  244. u_int t, i;
  245. u_int timerfreq;
  246. const char *version;
  247. if (!OpenPIC_Addr) {
  248. printk(KERN_INFO "No OpenPIC found !n");
  249. return;
  250. }
  251. OpenPIC = (volatile struct OpenPIC *)OpenPIC_Addr;
  252. ppc64_boot_msg(0x20, "OpenPic Init");
  253. t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
  254. switch (t & OPENPIC_FEATURE_VERSION_MASK) {
  255. case 1:
  256. version = "1.0";
  257. break;
  258. case 2:
  259. version = "1.2";
  260. break;
  261. case 3:
  262. version = "1.3";
  263. break;
  264. default:
  265. version = "?";
  266. break;
  267. }
  268. NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
  269.  OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1;
  270. NumSources = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >>
  271.       OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1;
  272. printk(KERN_INFO "OpenPIC Version %s (%d CPUs and %d IRQ sources) at %pn",
  273.        version, NumProcessors, NumSources, OpenPIC);
  274. timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
  275. if (timerfreq)
  276. printk(KERN_INFO "OpenPIC timer frequency is %d.%06d MHzn",
  277.        timerfreq / 1000000, timerfreq % 1000000);
  278. if (!main_pic)
  279. return;
  280. open_pic_irq_offset = offset;
  281. chrp_int_ack_special = (volatile unsigned char*)chrp_ack;
  282. find_ISUs();
  283. /* Initialize timer interrupts */
  284. ppc64_boot_msg(0x21, "OpenPic Timer");
  285. for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
  286. /* Disabled, Priority 0 */
  287. openpic_inittimer(i, 0, openpic_vec_timer+i);
  288. /* No processor */
  289. openpic_maptimer(i, 0);
  290. }
  291. #ifdef CONFIG_SMP
  292. /* Initialize IPI interrupts */
  293. ppc64_boot_msg(0x22, "OpenPic IPI");
  294. openpic_test_broken_IPI();
  295. for (i = 0; i < OPENPIC_NUM_IPI; i++) {
  296. /* Disabled, Priority 10..13 */
  297. openpic_initipi(i, 10+i, openpic_vec_ipi+i);
  298. /* IPIs are per-CPU */
  299. irq_desc[openpic_vec_ipi+i].status |= IRQ_PER_CPU;
  300. irq_desc[openpic_vec_ipi+i].handler = &open_pic_ipi;
  301. }
  302. #endif
  303. /* Initialize external interrupts */
  304. ppc64_boot_msg(0x23, "OpenPic Ext");
  305. openpic_set_priority(0xf);
  306. /* SIOint (8259 cascade) is special */
  307. if (offset) {
  308. openpic_initirq(0, 8, offset, 1, 1);
  309. openpic_mapirq(0, 1<<get_hard_smp_processor_id(0));
  310. }
  311. /* Init all external sources */
  312. for (i = 1; i < NumSources; i++) {
  313. int pri, sense;
  314. /* the bootloader may have left it enabled (bad !) */
  315. openpic_disable_irq(i+offset);
  316. pri = (i == programmer_switch_irq)? 9: 8;
  317. sense = (i < OpenPIC_NumInitSenses)? OpenPIC_InitSenses[i]: 1;
  318. if (sense)
  319. irq_desc[i+offset].status = IRQ_LEVEL;
  320. /* Enabled, Priority 8 or 9 */
  321. openpic_initirq(i, pri, i+offset, !sense, sense);
  322. /* Processor 0 */
  323. openpic_mapirq(i, 1<<get_hard_smp_processor_id(0));
  324. }
  325. /* Init descriptors */
  326. for (i = offset; i < NumSources + offset; i++)
  327. irq_desc[i].handler = &open_pic;
  328. /* Initialize the spurious interrupt */
  329. ppc64_boot_msg(0x24, "OpenPic Spurious");
  330. openpic_set_spurious(openpic_vec_spurious);
  331. /* Initialize the cascade */
  332. if (offset) {
  333. if (request_irq(offset, no_action, SA_INTERRUPT,
  334. "82c59 cascade", NULL))
  335. printk(KERN_ERR "Unable to get OpenPIC IRQ 0 for cascaden");
  336. }
  337. openpic_set_priority(0);
  338. openpic_disable_8259_pass_through();
  339. ppc64_boot_msg(0x25, "OpenPic Done");
  340. }
  341. void openpic_setup_ISU(int isu_num, unsigned long addr)
  342. {
  343. if (isu_num >= OPENPIC_MAX_ISU)
  344. return;
  345. ISU[isu_num] = (OpenPIC_SourcePtr) __ioremap(addr, 0x400, _PAGE_NO_CACHE);
  346. if (isu_num >= NumISUs)
  347. NumISUs = isu_num + 1;
  348. }
  349. void find_ISUs(void)
  350. {
  351.         /* Use /interrupt-controller/reg and
  352.          * /interrupt-controller/interrupt-ranges from OF device tree
  353.  * the ISU array is setup in chrp_pci.c in ibm_add_bridges
  354.  * as a result
  355.  * -- tgall
  356.          */
  357. /* basically each ISU is a bus, and this assumes that
  358.  * open_pic_isu_count interrupts per bus are possible 
  359.  * ISU == Interrupt Source
  360.  */
  361. NumSources = NumISUs * 0x10;
  362. openpic_vec_ipi = NumSources + open_pic_irq_offset;
  363. openpic_vec_timer = openpic_vec_ipi + OPENPIC_NUM_IPI; 
  364. openpic_vec_spurious = openpic_vec_timer + OPENPIC_NUM_TIMERS;
  365. }
  366. static inline void openpic_reset(void)
  367. {
  368. openpic_setfield(&OpenPIC->Global.Global_Configuration0,
  369.  OPENPIC_CONFIG_RESET);
  370. }
  371. static inline void openpic_enable_8259_pass_through(void)
  372. {
  373. openpic_clearfield(&OpenPIC->Global.Global_Configuration0,
  374.    OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
  375. }
  376. static void openpic_disable_8259_pass_through(void)
  377. {
  378. openpic_setfield(&OpenPIC->Global.Global_Configuration0,
  379.  OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
  380. }
  381. /*
  382.  *  Find out the current interrupt
  383.  */
  384. static u_int openpic_irq(void)
  385. {
  386. u_int vec;
  387. DECL_THIS_CPU;
  388. CHECK_THIS_CPU;
  389. vec = openpic_readfield(&OpenPIC->THIS_CPU.Interrupt_Acknowledge,
  390. OPENPIC_VECTOR_MASK);
  391. return vec;
  392. }
  393. static void openpic_eoi(void)
  394. {
  395. DECL_THIS_CPU;
  396. CHECK_THIS_CPU;
  397. openpic_write(&OpenPIC->THIS_CPU.EOI, 0);
  398. /* Handle PCI write posting */
  399. (void)openpic_read(&OpenPIC->THIS_CPU.EOI);
  400. }
  401. static inline u_int openpic_get_priority(void)
  402. {
  403. DECL_THIS_CPU;
  404. CHECK_THIS_CPU;
  405. return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority,
  406.  OPENPIC_CURRENT_TASK_PRIORITY_MASK);
  407. }
  408. static void openpic_set_priority(u_int pri)
  409. {
  410. DECL_THIS_CPU;
  411. CHECK_THIS_CPU;
  412. check_arg_pri(pri);
  413. openpic_writefield(&OpenPIC->THIS_CPU.Current_Task_Priority,
  414.    OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri);
  415. }
  416. /*
  417.  *  Get/set the spurious vector
  418.  */
  419. static inline u_int openpic_get_spurious(void)
  420. {
  421. return openpic_readfield(&OpenPIC->Global.Spurious_Vector,
  422.  OPENPIC_VECTOR_MASK);
  423. }
  424. static void openpic_set_spurious(u_int vec)
  425. {
  426. check_arg_vec(vec);
  427. openpic_writefield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK,
  428.    vec);
  429. }
  430. /*
  431.  * Convert a cpu mask from logical to physical cpu numbers.
  432.  */
  433. static inline u32 physmask(u32 cpumask)
  434. {
  435. int i;
  436. u32 mask = 0;
  437. for (i = 0; i < smp_num_cpus; ++i, cpumask >>= 1)
  438. mask |= (cpumask & 1) << get_hard_smp_processor_id(i);
  439. return mask;
  440. }
  441. void openpic_init_processor(u_int cpumask)
  442. {
  443. openpic_write(&OpenPIC->Global.Processor_Initialization,
  444.       physmask(cpumask));
  445. }
  446. #ifdef CONFIG_SMP
  447. /*
  448.  *  Initialize an interprocessor interrupt (and disable it)
  449.  *
  450.  *  ipi: OpenPIC interprocessor interrupt number
  451.  *  pri: interrupt source priority
  452.  *  vec: the vector it will produce
  453.  */
  454. static void __init openpic_initipi(u_int ipi, u_int pri, u_int vec)
  455. {
  456. check_arg_ipi(ipi);
  457. check_arg_pri(pri);
  458. check_arg_vec(vec);
  459. openpic_safe_writefield_IPI(&OpenPIC->Global.IPI_Vector_Priority(ipi),
  460. OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
  461. (pri << OPENPIC_PRIORITY_SHIFT) | vec);
  462. }
  463. /*
  464.  *  Send an IPI to one or more CPUs
  465.  *  
  466.  *  Externally called, however, it takes an IPI number (0...OPENPIC_NUM_IPI)
  467.  *  and not a system-wide interrupt number
  468.  */
  469. void openpic_cause_IPI(u_int ipi, u_int cpumask)
  470. {
  471. DECL_THIS_CPU;
  472. CHECK_THIS_CPU;
  473. check_arg_ipi(ipi);
  474. openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi),
  475.       physmask(cpumask));
  476. }
  477. void openpic_request_IPIs(void)
  478. {
  479. int i;
  480. /*
  481.  * Make sure this matches what is defined in smp.c for 
  482.  * smp_message_{pass|recv}() or what shows up in 
  483.  * /proc/interrupts will be wrong!!! --Troy */
  484. if (OpenPIC == NULL)
  485. return;
  486. request_irq(openpic_vec_ipi,
  487.     openpic_ipi_action, 0, "IPI0 (call function)", 0);
  488. request_irq(openpic_vec_ipi+1,
  489.     openpic_ipi_action, 0, "IPI1 (reschedule)", 0);
  490. request_irq(openpic_vec_ipi+2,
  491.     openpic_ipi_action, 0, "IPI2 (invalidate tlb)", 0);
  492. request_irq(openpic_vec_ipi+3,
  493.     openpic_ipi_action, 0, "IPI3 (xmon break)", 0);
  494. for ( i = 0; i < OPENPIC_NUM_IPI ; i++ )
  495. openpic_enable_ipi(openpic_vec_ipi+i);
  496. }
  497. /*
  498.  * Do per-cpu setup for SMP systems.
  499.  *
  500.  * Get IPI's working and start taking interrupts.
  501.  *   -- Cort
  502.  */
  503. static spinlock_t openpic_setup_lock __initdata = SPIN_LOCK_UNLOCKED;
  504. void __init do_openpic_setup_cpu(void)
  505. {
  506. #ifdef CONFIG_IRQ_ALL_CPUS
  507.   int i;
  508. u32 msk = 1 << hard_smp_processor_id();
  509. #endif
  510. spin_lock(&openpic_setup_lock);
  511. #ifdef CONFIG_IRQ_ALL_CPUS
  512.   /* let the openpic know we want intrs. default affinity
  513.    * is 0xffffffff until changed via /proc
  514.    * That's how it's done on x86. If we want it differently, then
  515.    * we should make sure we also change the default values of irq_affinity
  516.    * in irq.c.
  517.    */
  518.   for (i = 0; i < NumSources ; i++)
  519. openpic_mapirq(i, openpic_read(&GET_ISU(i).Destination) | msk);
  520. #endif /* CONFIG_IRQ_ALL_CPUS */
  521.   openpic_set_priority(0);
  522. spin_unlock(&openpic_setup_lock);
  523. }
  524. #endif /* CONFIG_SMP */
  525. /*
  526.  *  Initialize a timer interrupt (and disable it)
  527.  *
  528.  *  timer: OpenPIC timer number
  529.  *  pri: interrupt source priority
  530.  *  vec: the vector it will produce
  531.  */
  532. static void __init openpic_inittimer(u_int timer, u_int pri, u_int vec)
  533. {
  534. check_arg_timer(timer);
  535. check_arg_pri(pri);
  536. check_arg_vec(vec);
  537. openpic_safe_writefield(&OpenPIC->Global.Timer[timer].Vector_Priority,
  538. OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
  539. (pri << OPENPIC_PRIORITY_SHIFT) | vec);
  540. }
  541. /*
  542.  *  Map a timer interrupt to one or more CPUs
  543.  */
  544. static void __init openpic_maptimer(u_int timer, u_int cpumask)
  545. {
  546. check_arg_timer(timer);
  547. openpic_write(&OpenPIC->Global.Timer[timer].Destination,
  548.       physmask(cpumask));
  549. }
  550. /*
  551.  *
  552.  * All functions below take an offset'ed irq argument
  553.  *
  554.  */
  555. /*
  556.  *  Enable/disable an external interrupt source
  557.  *
  558.  *  Externally called, irq is an offseted system-wide interrupt number
  559.  */
  560. static void openpic_enable_irq(u_int irq)
  561. {
  562. unsigned int loops = 100000;
  563. check_arg_irq(irq);
  564. openpic_clearfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, OPENPIC_MASK);
  565. /* make sure mask gets to controller before we return to user */
  566. do {
  567. if (!loops--) {
  568. printk(KERN_ERR "openpic_enable_irq timeoutn");
  569. break;
  570. }
  571. mb(); /* sync is probably useless here */
  572. } while(openpic_readfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority,
  573. OPENPIC_MASK));
  574. }
  575. static void openpic_disable_irq(u_int irq)
  576. {
  577. u32 vp;
  578. unsigned int loops = 100000;
  579. check_arg_irq(irq);
  580. openpic_setfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, OPENPIC_MASK);
  581. /* make sure mask gets to controller before we return to user */
  582. do {
  583. if (!loops--) {
  584. printk(KERN_ERR "openpic_disable_irq timeoutn");
  585. break;
  586. }
  587. mb();  /* sync is probably useless here */
  588. vp = openpic_readfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority,
  589.      OPENPIC_MASK | OPENPIC_ACTIVITY);
  590. } while((vp & OPENPIC_ACTIVITY) && !(vp & OPENPIC_MASK));
  591. }
  592. #ifdef CONFIG_SMP
  593. /*
  594.  *  Enable/disable an IPI interrupt source
  595.  *  
  596.  *  Externally called, irq is an offseted system-wide interrupt number
  597.  */
  598. void openpic_enable_ipi(u_int irq)
  599. {
  600. irq -= openpic_vec_ipi;
  601. check_arg_ipi(irq);
  602. openpic_clearfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK);
  603. }
  604. void openpic_disable_ipi(u_int irq)
  605. {
  606.    /* NEVER disable an IPI... that's just plain wrong! */
  607. }
  608. #endif
  609. /*
  610.  *  Initialize an interrupt source (and disable it!)
  611.  *
  612.  *  irq: OpenPIC interrupt number
  613.  *  pri: interrupt source priority
  614.  *  vec: the vector it will produce
  615.  *  pol: polarity (1 for positive, 0 for negative)
  616.  *  sense: 1 for level, 0 for edge
  617.  */
  618. static void openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense)
  619. {
  620. openpic_safe_writefield(&GET_ISU(irq).Vector_Priority,
  621. OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
  622. OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK,
  623. (pri << OPENPIC_PRIORITY_SHIFT) | vec |
  624. (pol ? OPENPIC_POLARITY_POSITIVE :
  625.      OPENPIC_POLARITY_NEGATIVE) |
  626. (sense ? OPENPIC_SENSE_LEVEL : OPENPIC_SENSE_EDGE));
  627. }
  628. /*
  629.  *  Map an interrupt source to one or more CPUs
  630.  */
  631. static void openpic_mapirq(u_int irq, u_int physmask)
  632. {
  633. openpic_write(&GET_ISU(irq).Destination, physmask);
  634. }
  635. /*
  636.  *  Set the sense for an interrupt source (and disable it!)
  637.  *
  638.  *  sense: 1 for level, 0 for edge
  639.  */
  640. static inline void openpic_set_sense(u_int irq, int sense)
  641. {
  642. openpic_safe_writefield(&GET_ISU(irq).Vector_Priority,
  643. OPENPIC_SENSE_LEVEL,
  644. (sense ? OPENPIC_SENSE_LEVEL : 0));
  645. }
  646. static void openpic_end_irq(unsigned int irq_nr)
  647. {
  648. if ((irq_desc[irq_nr].status & IRQ_LEVEL) != 0)
  649. openpic_eoi();
  650. }
  651. static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask)
  652. {
  653. openpic_mapirq(irq_nr - open_pic_irq_offset, physmask(cpumask));
  654. }
  655. #ifdef CONFIG_SMP
  656. static void openpic_end_ipi(unsigned int irq_nr)
  657. {
  658. /* IPIs are marked IRQ_PER_CPU. This has the side effect of
  659.  * preventing the IRQ_PENDING/IRQ_INPROGRESS logic from
  660.  * applying to them. We EOI them late to avoid re-entering.
  661.  * however, I'm wondering if we could simply let them have the
  662.  * SA_INTERRUPT flag and let them execute with all interrupts OFF.
  663.  * This would have the side effect of either running cross-CPU
  664.  * functions with interrupts off, or we can re-enable them explicitely
  665.  * with a __sti() in smp_call_function_interrupt(), since
  666.  * smp_call_function() is protected by a spinlock.
  667.  * Or maybe we shouldn't set the IRQ_PER_CPU flag on cross-CPU
  668.  * function calls IPI at all but that would make a special case.
  669.  */
  670. openpic_eoi();
  671. }
  672. static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
  673. {
  674. smp_message_recv(cpl-openpic_vec_ipi, regs);
  675. }
  676. #endif /* CONFIG_SMP */
  677. int openpic_get_irq(struct pt_regs *regs)
  678. {
  679. extern int i8259_irq(int cpu);
  680. int irq = openpic_irq();
  681. /* Management of the cascade should be moved out of here */
  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. else
  690. irq = i8259_irq( smp_processor_id() );
  691. openpic_eoi();
  692.         }
  693. if (irq == openpic_vec_spurious)
  694. irq = -1;
  695. return irq;
  696. }