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