1 /* 2 * linux/arch/alpha/kernel/irq_pyxis.c 3 * 4 * Based on code written by David A Rusling (david.rusling@reo.mts.dec.com). 5 * 6 * IRQ Code common to all PYXIS core logic chips. 7 */ 8 9 #include <linux/init.h> 10 #include <linux/sched.h> 11 #include <linux/irq.h> 12 13 #include <asm/io.h> 14 #include <asm/core_cia.h> 15 16 #include "proto.h" 17 #include "irq_impl.h" 18 19 20 /* Note mask bit is true for ENABLED irqs. */ 21 static unsigned long cached_irq_mask; 22 23 static inline void pyxis_update_irq_hw(unsigned long mask)24pyxis_update_irq_hw(unsigned long mask) 25 { 26 *(vulp)PYXIS_INT_MASK = mask; 27 mb(); 28 *(vulp)PYXIS_INT_MASK; 29 } 30 31 static inline void pyxis_enable_irq(unsigned int irq)32pyxis_enable_irq(unsigned int irq) 33 { 34 pyxis_update_irq_hw(cached_irq_mask |= 1UL << (irq - 16)); 35 } 36 37 static void pyxis_disable_irq(unsigned int irq)38pyxis_disable_irq(unsigned int irq) 39 { 40 pyxis_update_irq_hw(cached_irq_mask &= ~(1UL << (irq - 16))); 41 } 42 43 static unsigned int pyxis_startup_irq(unsigned int irq)44pyxis_startup_irq(unsigned int irq) 45 { 46 pyxis_enable_irq(irq); 47 return 0; 48 } 49 50 static void pyxis_end_irq(unsigned int irq)51pyxis_end_irq(unsigned int irq) 52 { 53 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) 54 pyxis_enable_irq(irq); 55 } 56 57 static void pyxis_mask_and_ack_irq(unsigned int irq)58pyxis_mask_and_ack_irq(unsigned int irq) 59 { 60 unsigned long bit = 1UL << (irq - 16); 61 unsigned long mask = cached_irq_mask &= ~bit; 62 63 /* Disable the interrupt. */ 64 *(vulp)PYXIS_INT_MASK = mask; 65 wmb(); 66 /* Ack PYXIS PCI interrupt. */ 67 *(vulp)PYXIS_INT_REQ = bit; 68 mb(); 69 /* Re-read to force both writes. */ 70 *(vulp)PYXIS_INT_MASK; 71 } 72 73 static struct hw_interrupt_type pyxis_irq_type = { 74 .typename = "PYXIS", 75 .startup = pyxis_startup_irq, 76 .shutdown = pyxis_disable_irq, 77 .enable = pyxis_enable_irq, 78 .disable = pyxis_disable_irq, 79 .ack = pyxis_mask_and_ack_irq, 80 .end = pyxis_end_irq, 81 }; 82 83 void pyxis_device_interrupt(unsigned long vector)84pyxis_device_interrupt(unsigned long vector) 85 { 86 unsigned long pld; 87 unsigned int i; 88 89 /* Read the interrupt summary register of PYXIS */ 90 pld = *(vulp)PYXIS_INT_REQ; 91 pld &= cached_irq_mask; 92 93 /* 94 * Now for every possible bit set, work through them and call 95 * the appropriate interrupt handler. 96 */ 97 while (pld) { 98 i = ffz(~pld); 99 pld &= pld - 1; /* clear least bit set */ 100 if (i == 7) 101 isa_device_interrupt(vector); 102 else 103 handle_irq(16+i); 104 } 105 } 106 107 void __init init_pyxis_irqs(unsigned long ignore_mask)108init_pyxis_irqs(unsigned long ignore_mask) 109 { 110 long i; 111 112 *(vulp)PYXIS_INT_MASK = 0; /* disable all */ 113 *(vulp)PYXIS_INT_REQ = -1; /* flush all */ 114 mb(); 115 116 /* Send -INTA pulses to clear any pending interrupts ...*/ 117 *(vuip) CIA_IACK_SC; 118 119 for (i = 16; i < 48; ++i) { 120 if ((ignore_mask >> i) & 1) 121 continue; 122 irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; 123 irq_desc[i].chip = &pyxis_irq_type; 124 } 125 126 setup_irq(16+7, &isa_cascade_irqaction); 127 } 128