]>
Commit | Line | Data |
---|---|---|
1da177e4 | 1 | #ifdef __KERNEL__ |
1b92313d PM |
2 | #ifndef _ASM_POWERPC_IRQ_H |
3 | #define _ASM_POWERPC_IRQ_H | |
4 | ||
5 | /* | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU General Public License | |
8 | * as published by the Free Software Foundation; either version | |
9 | * 2 of the License, or (at your option) any later version. | |
10 | */ | |
1da177e4 | 11 | |
1b92313d | 12 | #include <linux/threads.h> |
0ebfff14 BH |
13 | #include <linux/list.h> |
14 | #include <linux/radix-tree.h> | |
1b92313d PM |
15 | |
16 | #include <asm/types.h> | |
60063497 | 17 | #include <linux/atomic.h> |
1da177e4 | 18 | |
1da177e4 | 19 | |
b671ad2b KG |
20 | /* Define a way to iterate across irqs. */ |
21 | #define for_each_irq(i) \ | |
22 | for ((i) = 0; (i) < NR_IRQS; ++(i)) | |
23 | ||
0ebfff14 | 24 | extern atomic_t ppc_n_lost_interrupts; |
1b92313d | 25 | |
0ebfff14 BH |
26 | /* This number is used when no interrupt has been assigned */ |
27 | #define NO_IRQ (0) | |
28 | ||
29 | /* This is a special irq number to return from get_irq() to tell that | |
30 | * no interrupt happened _and_ ignore it (don't count it as bad). Some | |
31 | * platforms like iSeries rely on that. | |
1b92313d | 32 | */ |
0ebfff14 BH |
33 | #define NO_IRQ_IGNORE ((unsigned int)-1) |
34 | ||
551b81f2 ME |
35 | /* Total number of virq in the platform */ |
36 | #define NR_IRQS CONFIG_NR_IRQS | |
1b92313d | 37 | |
0ebfff14 BH |
38 | /* Number of irqs reserved for the legacy controller */ |
39 | #define NUM_ISA_INTERRUPTS 16 | |
40 | ||
cd015707 ME |
41 | /* Same thing, used by the generic IRQ code */ |
42 | #define NR_IRQS_LEGACY NUM_ISA_INTERRUPTS | |
43 | ||
0ebfff14 BH |
44 | /* This type is the placeholder for a hardware interrupt number. It has to |
45 | * be big enough to enclose whatever representation is used by a given | |
46 | * platform. | |
47 | */ | |
48 | typedef unsigned long irq_hw_number_t; | |
49 | ||
50 | /* Interrupt controller "host" data structure. This could be defined as a | |
51 | * irq domain controller. That is, it handles the mapping between hardware | |
52 | * and virtual interrupt numbers for a given interrupt domain. The host | |
53 | * structure is generally created by the PIC code for a given PIC instance | |
54 | * (though a host can cover more than one PIC if they have a flat number | |
55 | * model). It's the host callbacks that are responsible for setting the | |
56 | * irq_chip on a given irq_desc after it's been mapped. | |
57 | * | |
58 | * The host code and data structures are fairly agnostic to the fact that | |
59 | * we use an open firmware device-tree. We do have references to struct | |
60 | * device_node in two places: in irq_find_host() to find the host matching | |
61 | * a given interrupt controller node, and of course as an argument to its | |
62 | * counterpart host->ops->match() callback. However, those are treated as | |
63 | * generic pointers by the core and the fact that it's actually a device-node | |
64 | * pointer is purely a convention between callers and implementation. This | |
65 | * code could thus be used on other architectures by replacing those two | |
66 | * by some sort of arch-specific void * "token" used to identify interrupt | |
67 | * controllers. | |
68 | */ | |
69 | struct irq_host; | |
70 | struct radix_tree_root; | |
71 | ||
72 | /* Functions below are provided by the host and called whenever a new mapping | |
73 | * is created or an old mapping is disposed. The host can then proceed to | |
74 | * whatever internal data structures management is required. It also needs | |
75 | * to setup the irq_desc when returning from map(). | |
76 | */ | |
77 | struct irq_host_ops { | |
78 | /* Match an interrupt controller device node to a host, returns | |
79 | * 1 on a match | |
80 | */ | |
81 | int (*match)(struct irq_host *h, struct device_node *node); | |
82 | ||
83 | /* Create or update a mapping between a virtual irq number and a hw | |
6e99e458 | 84 | * irq number. This is called only once for a given mapping. |
0ebfff14 | 85 | */ |
6e99e458 | 86 | int (*map)(struct irq_host *h, unsigned int virq, irq_hw_number_t hw); |
0ebfff14 BH |
87 | |
88 | /* Dispose of such a mapping */ | |
89 | void (*unmap)(struct irq_host *h, unsigned int virq); | |
90 | ||
91 | /* Translate device-tree interrupt specifier from raw format coming | |
92 | * from the firmware to a irq_hw_number_t (interrupt line number) and | |
6e99e458 BH |
93 | * type (sense) that can be passed to set_irq_type(). In the absence |
94 | * of this callback, irq_create_of_mapping() and irq_of_parse_and_map() | |
95 | * will return the hw number in the first cell and IRQ_TYPE_NONE for | |
96 | * the type (which amount to keeping whatever default value the | |
97 | * interrupt controller has for that line) | |
0ebfff14 BH |
98 | */ |
99 | int (*xlate)(struct irq_host *h, struct device_node *ctrler, | |
40d50cf7 | 100 | const u32 *intspec, unsigned int intsize, |
6e99e458 | 101 | irq_hw_number_t *out_hwirq, unsigned int *out_type); |
0ebfff14 BH |
102 | }; |
103 | ||
104 | struct irq_host { | |
105 | struct list_head link; | |
106 | ||
107 | /* type of reverse mapping technique */ | |
108 | unsigned int revmap_type; | |
109 | #define IRQ_HOST_MAP_LEGACY 0 /* legacy 8259, gets irqs 1..15 */ | |
110 | #define IRQ_HOST_MAP_NOMAP 1 /* no fast reverse mapping */ | |
111 | #define IRQ_HOST_MAP_LINEAR 2 /* linear map of interrupts */ | |
112 | #define IRQ_HOST_MAP_TREE 3 /* radix tree */ | |
113 | union { | |
114 | struct { | |
115 | unsigned int size; | |
116 | unsigned int *revmap; | |
117 | } linear; | |
118 | struct radix_tree_root tree; | |
119 | } revmap_data; | |
120 | struct irq_host_ops *ops; | |
121 | void *host_data; | |
122 | irq_hw_number_t inval_irq; | |
52964f87 ME |
123 | |
124 | /* Optional device node pointer */ | |
125 | struct device_node *of_node; | |
0ebfff14 BH |
126 | }; |
127 | ||
476eb491 GL |
128 | struct irq_data; |
129 | extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d); | |
35923f12 | 130 | extern irq_hw_number_t virq_to_hw(unsigned int virq); |
3ee62d36 | 131 | extern bool virq_is_host(unsigned int virq, struct irq_host *host); |
0b05ac6e | 132 | |
40681b95 | 133 | /** |
0ebfff14 | 134 | * irq_alloc_host - Allocate a new irq_host data structure |
52964f87 | 135 | * @of_node: optional device-tree node of the interrupt controller |
0ebfff14 BH |
136 | * @revmap_type: type of reverse mapping to use |
137 | * @revmap_arg: for IRQ_HOST_MAP_LINEAR linear only: size of the map | |
138 | * @ops: map/unmap host callbacks | |
139 | * @inval_irq: provide a hw number in that host space that is always invalid | |
140 | * | |
141 | * Allocates and initialize and irq_host structure. Note that in the case of | |
142 | * IRQ_HOST_MAP_LEGACY, the map() callback will be called before this returns | |
143 | * for all legacy interrupts except 0 (which is always the invalid irq for | |
144 | * a legacy controller). For a IRQ_HOST_MAP_LINEAR, the map is allocated by | |
145 | * this call as well. For a IRQ_HOST_MAP_TREE, the radix tree will be allocated | |
146 | * later during boot automatically (the reverse mapping will use the slow path | |
147 | * until that happens). | |
148 | */ | |
52964f87 ME |
149 | extern struct irq_host *irq_alloc_host(struct device_node *of_node, |
150 | unsigned int revmap_type, | |
0ebfff14 BH |
151 | unsigned int revmap_arg, |
152 | struct irq_host_ops *ops, | |
153 | irq_hw_number_t inval_irq); | |
154 | ||
155 | ||
40681b95 | 156 | /** |
0ebfff14 BH |
157 | * irq_find_host - Locates a host for a given device node |
158 | * @node: device-tree node of the interrupt controller | |
159 | */ | |
160 | extern struct irq_host *irq_find_host(struct device_node *node); | |
161 | ||
162 | ||
40681b95 | 163 | /** |
0ebfff14 BH |
164 | * irq_set_default_host - Set a "default" host |
165 | * @host: default host pointer | |
166 | * | |
167 | * For convenience, it's possible to set a "default" host that will be used | |
168 | * whenever NULL is passed to irq_create_mapping(). It makes life easier for | |
169 | * platforms that want to manipulate a few hard coded interrupt numbers that | |
170 | * aren't properly represented in the device-tree. | |
171 | */ | |
172 | extern void irq_set_default_host(struct irq_host *host); | |
173 | ||
174 | ||
40681b95 | 175 | /** |
0ebfff14 BH |
176 | * irq_set_virq_count - Set the maximum number of virt irqs |
177 | * @count: number of linux virtual irqs, capped with NR_IRQS | |
178 | * | |
179 | * This is mainly for use by platforms like iSeries who want to program | |
180 | * the virtual irq number in the controller to avoid the reverse mapping | |
181 | */ | |
182 | extern void irq_set_virq_count(unsigned int count); | |
183 | ||
184 | ||
40681b95 | 185 | /** |
0ebfff14 BH |
186 | * irq_create_mapping - Map a hardware interrupt into linux virq space |
187 | * @host: host owning this hardware interrupt or NULL for default host | |
188 | * @hwirq: hardware irq number in that host space | |
0ebfff14 BH |
189 | * |
190 | * Only one mapping per hardware interrupt is permitted. Returns a linux | |
6e99e458 BH |
191 | * virq number. |
192 | * If the sense/trigger is to be specified, set_irq_type() should be called | |
193 | * on the number returned from that call. | |
0ebfff14 BH |
194 | */ |
195 | extern unsigned int irq_create_mapping(struct irq_host *host, | |
6e99e458 | 196 | irq_hw_number_t hwirq); |
0ebfff14 BH |
197 | |
198 | ||
40681b95 | 199 | /** |
0ebfff14 BH |
200 | * irq_dispose_mapping - Unmap an interrupt |
201 | * @virq: linux virq number of the interrupt to unmap | |
1b92313d | 202 | */ |
0ebfff14 | 203 | extern void irq_dispose_mapping(unsigned int virq); |
1b92313d | 204 | |
40681b95 | 205 | /** |
0ebfff14 BH |
206 | * irq_find_mapping - Find a linux virq from an hw irq number. |
207 | * @host: host owning this hardware interrupt | |
208 | * @hwirq: hardware irq number in that host space | |
209 | * | |
210 | * This is a slow path, for use by generic code. It's expected that an | |
211 | * irq controller implementation directly calls the appropriate low level | |
212 | * mapping function. | |
7d01c880 | 213 | */ |
0ebfff14 BH |
214 | extern unsigned int irq_find_mapping(struct irq_host *host, |
215 | irq_hw_number_t hwirq); | |
7d01c880 | 216 | |
ee51de56 ME |
217 | /** |
218 | * irq_create_direct_mapping - Allocate a virq for direct mapping | |
219 | * @host: host to allocate the virq for or NULL for default host | |
220 | * | |
221 | * This routine is used for irq controllers which can choose the hardware | |
222 | * interrupt numbers they generate. In such a case it's simplest to use | |
223 | * the linux virq as the hardware interrupt number. | |
224 | */ | |
225 | extern unsigned int irq_create_direct_mapping(struct irq_host *host); | |
0ebfff14 | 226 | |
40681b95 | 227 | /** |
967e012e SD |
228 | * irq_radix_revmap_insert - Insert a hw irq to linux virq number mapping. |
229 | * @host: host owning this hardware interrupt | |
230 | * @virq: linux irq number | |
231 | * @hwirq: hardware irq number in that host space | |
232 | * | |
233 | * This is for use by irq controllers that use a radix tree reverse | |
234 | * mapping for fast lookup. | |
235 | */ | |
236 | extern void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq, | |
237 | irq_hw_number_t hwirq); | |
238 | ||
239 | /** | |
240 | * irq_radix_revmap_lookup - Find a linux virq from a hw irq number. | |
0ebfff14 BH |
241 | * @host: host owning this hardware interrupt |
242 | * @hwirq: hardware irq number in that host space | |
243 | * | |
244 | * This is a fast path, for use by irq controller code that uses radix tree | |
245 | * revmaps | |
246 | */ | |
967e012e SD |
247 | extern unsigned int irq_radix_revmap_lookup(struct irq_host *host, |
248 | irq_hw_number_t hwirq); | |
0ebfff14 | 249 | |
40681b95 | 250 | /** |
0ebfff14 BH |
251 | * irq_linear_revmap - Find a linux virq from a hw irq number. |
252 | * @host: host owning this hardware interrupt | |
253 | * @hwirq: hardware irq number in that host space | |
254 | * | |
255 | * This is a fast path, for use by irq controller code that uses linear | |
256 | * revmaps. It does fallback to the slow path if the revmap doesn't exist | |
257 | * yet and will create the revmap entry with appropriate locking | |
258 | */ | |
259 | ||
260 | extern unsigned int irq_linear_revmap(struct irq_host *host, | |
261 | irq_hw_number_t hwirq); | |
262 | ||
263 | ||
264 | ||
40681b95 | 265 | /** |
0ebfff14 BH |
266 | * irq_alloc_virt - Allocate virtual irq numbers |
267 | * @host: host owning these new virtual irqs | |
268 | * @count: number of consecutive numbers to allocate | |
269 | * @hint: pass a hint number, the allocator will try to use a 1:1 mapping | |
270 | * | |
271 | * This is a low level function that is used internally by irq_create_mapping() | |
272 | * and that can be used by some irq controllers implementations for things | |
273 | * like allocating ranges of numbers for MSIs. The revmaps are left untouched. | |
1b92313d | 274 | */ |
0ebfff14 BH |
275 | extern unsigned int irq_alloc_virt(struct irq_host *host, |
276 | unsigned int count, | |
277 | unsigned int hint); | |
278 | ||
40681b95 | 279 | /** |
0ebfff14 BH |
280 | * irq_free_virt - Free virtual irq numbers |
281 | * @virq: virtual irq number of the first interrupt to free | |
282 | * @count: number of interrupts to free | |
283 | * | |
284 | * This function is the opposite of irq_alloc_virt. It will not clear reverse | |
285 | * maps, this should be done previously by unmap'ing the interrupt. In fact, | |
286 | * all interrupts covered by the range being freed should have been unmapped | |
287 | * prior to calling this. | |
288 | */ | |
289 | extern void irq_free_virt(unsigned int virq, unsigned int count); | |
290 | ||
40681b95 | 291 | /** |
0ebfff14 BH |
292 | * irq_early_init - Init irq remapping subsystem |
293 | */ | |
294 | extern void irq_early_init(void); | |
295 | ||
296 | static __inline__ int irq_canonicalize(int irq) | |
1b92313d | 297 | { |
0ebfff14 | 298 | return irq; |
1b92313d PM |
299 | } |
300 | ||
1b92313d | 301 | extern int distribute_irqs; |
1da177e4 | 302 | |
1b92313d PM |
303 | struct irqaction; |
304 | struct pt_regs; | |
305 | ||
c6622f63 PM |
306 | #define __ARCH_HAS_DO_SOFTIRQ |
307 | ||
bcf0b088 KG |
308 | #if defined(CONFIG_BOOKE) || defined(CONFIG_40x) |
309 | /* | |
310 | * Per-cpu stacks for handling critical, debug and machine check | |
311 | * level interrupts. | |
312 | */ | |
313 | extern struct thread_info *critirq_ctx[NR_CPUS]; | |
314 | extern struct thread_info *dbgirq_ctx[NR_CPUS]; | |
315 | extern struct thread_info *mcheckirq_ctx[NR_CPUS]; | |
316 | extern void exc_lvl_ctx_init(void); | |
317 | #else | |
318 | #define exc_lvl_ctx_init() | |
319 | #endif | |
320 | ||
1b92313d PM |
321 | /* |
322 | * Per-cpu stacks for handling hard and soft interrupts. | |
323 | */ | |
324 | extern struct thread_info *hardirq_ctx[NR_CPUS]; | |
325 | extern struct thread_info *softirq_ctx[NR_CPUS]; | |
326 | ||
327 | extern void irq_ctx_init(void); | |
328 | extern void call_do_softirq(struct thread_info *tp); | |
7d12e780 | 329 | extern int call_handle_irq(int irq, void *p1, |
b9e5b4e6 | 330 | struct thread_info *tp, void *func); |
f2783c15 PM |
331 | extern void do_IRQ(struct pt_regs *regs); |
332 | ||
6ec36b58 SY |
333 | int irq_choose_cpu(const struct cpumask *mask); |
334 | ||
1da177e4 LT |
335 | #endif /* _ASM_IRQ_H */ |
336 | #endif /* __KERNEL__ */ |