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