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. */ 21static unsigned long cached_irq_mask; 22 23static inline void 24pyxis_update_irq_hw(unsigned long mask) 25{ 26 *(vulp)PYXIS_INT_MASK = mask; 27 mb(); 28 *(vulp)PYXIS_INT_MASK; 29} 30 31static inline void 32pyxis_enable_irq(unsigned int irq) 33{ 34 pyxis_update_irq_hw(cached_irq_mask |= 1UL << (irq - 16)); 35} 36 37static void 38pyxis_disable_irq(unsigned int irq) 39{ 40 pyxis_update_irq_hw(cached_irq_mask &= ~(1UL << (irq - 16))); 41} 42 43static unsigned int 44pyxis_startup_irq(unsigned int irq) 45{ 46 pyxis_enable_irq(irq); 47 return 0; 48} 49 50static void 51pyxis_end_irq(unsigned int irq) 52{ 53 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) 54 pyxis_enable_irq(irq); 55} 56 57static void 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 73static 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 83void 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 107void __init 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