Commit | Line | Data |
---|---|---|
1da177e4 LT |
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 | |
24 | pyxis_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 | |
592924c7 | 32 | pyxis_enable_irq(struct irq_data *d) |
1da177e4 | 33 | { |
592924c7 | 34 | pyxis_update_irq_hw(cached_irq_mask |= 1UL << (d->irq - 16)); |
1da177e4 LT |
35 | } |
36 | ||
37 | static void | |
592924c7 | 38 | pyxis_disable_irq(struct irq_data *d) |
1da177e4 | 39 | { |
592924c7 | 40 | pyxis_update_irq_hw(cached_irq_mask &= ~(1UL << (d->irq - 16))); |
1da177e4 LT |
41 | } |
42 | ||
1da177e4 | 43 | static void |
592924c7 | 44 | pyxis_mask_and_ack_irq(struct irq_data *d) |
1da177e4 | 45 | { |
592924c7 | 46 | unsigned long bit = 1UL << (d->irq - 16); |
1da177e4 LT |
47 | unsigned long mask = cached_irq_mask &= ~bit; |
48 | ||
49 | /* Disable the interrupt. */ | |
50 | *(vulp)PYXIS_INT_MASK = mask; | |
51 | wmb(); | |
52 | /* Ack PYXIS PCI interrupt. */ | |
53 | *(vulp)PYXIS_INT_REQ = bit; | |
54 | mb(); | |
55 | /* Re-read to force both writes. */ | |
56 | *(vulp)PYXIS_INT_MASK; | |
57 | } | |
58 | ||
44377f62 | 59 | static struct irq_chip pyxis_irq_type = { |
8ab1221c | 60 | .name = "PYXIS", |
592924c7 TG |
61 | .irq_mask_ack = pyxis_mask_and_ack_irq, |
62 | .irq_mask = pyxis_disable_irq, | |
63 | .irq_unmask = pyxis_enable_irq, | |
1da177e4 LT |
64 | }; |
65 | ||
66 | void | |
7ca56053 | 67 | pyxis_device_interrupt(unsigned long vector) |
1da177e4 LT |
68 | { |
69 | unsigned long pld; | |
70 | unsigned int i; | |
71 | ||
72 | /* Read the interrupt summary register of PYXIS */ | |
73 | pld = *(vulp)PYXIS_INT_REQ; | |
74 | pld &= cached_irq_mask; | |
75 | ||
76 | /* | |
77 | * Now for every possible bit set, work through them and call | |
78 | * the appropriate interrupt handler. | |
79 | */ | |
80 | while (pld) { | |
81 | i = ffz(~pld); | |
82 | pld &= pld - 1; /* clear least bit set */ | |
83 | if (i == 7) | |
7ca56053 | 84 | isa_device_interrupt(vector); |
1da177e4 | 85 | else |
3dbb8c62 | 86 | handle_irq(16+i); |
1da177e4 LT |
87 | } |
88 | } | |
89 | ||
90 | void __init | |
91 | init_pyxis_irqs(unsigned long ignore_mask) | |
92 | { | |
93 | long i; | |
94 | ||
95 | *(vulp)PYXIS_INT_MASK = 0; /* disable all */ | |
96 | *(vulp)PYXIS_INT_REQ = -1; /* flush all */ | |
97 | mb(); | |
98 | ||
99 | /* Send -INTA pulses to clear any pending interrupts ...*/ | |
100 | *(vuip) CIA_IACK_SC; | |
101 | ||
102 | for (i = 16; i < 48; ++i) { | |
103 | if ((ignore_mask >> i) & 1) | |
104 | continue; | |
a9eb076b | 105 | irq_set_chip_and_handler(i, &pyxis_irq_type, handle_level_irq); |
592924c7 | 106 | irq_set_status_flags(i, IRQ_LEVEL); |
1da177e4 LT |
107 | } |
108 | ||
109 | setup_irq(16+7, &isa_cascade_irqaction); | |
110 | } |