1 /* 2 * Port on Texas Instruments TMS320C6x architecture 3 * 4 * Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated 5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com) 6 * 7 * Large parts taken directly from powerpc. 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12 */ 13 #ifndef _ASM_C6X_IRQ_H 14 #define _ASM_C6X_IRQ_H 15 16 #include <linux/threads.h> 17 #include <linux/list.h> 18 #include <linux/radix-tree.h> 19 #include <asm/percpu.h> 20 21 #define irq_canonicalize(irq) (irq) 22 23 /* 24 * The C64X+ core has 16 IRQ vectors. One each is used by Reset and NMI. Two 25 * are reserved. The remaining 12 vectors are used to route SoC interrupts. 26 * These interrupt vectors are prioritized with IRQ 4 having the highest 27 * priority and IRQ 15 having the lowest. 28 * 29 * The C64x+ megamodule provides a PIC which combines SoC IRQ sources into a 30 * single core IRQ vector. There are four combined sources, each of which 31 * feed into one of the 12 general interrupt vectors. The remaining 8 vectors 32 * can each route a single SoC interrupt directly. 33 */ 34 #define NR_PRIORITY_IRQS 16 35 36 #define NR_IRQS_LEGACY NR_PRIORITY_IRQS 37 38 /* Total number of virq in the platform */ 39 #define NR_IRQS 256 40 41 /* This number is used when no interrupt has been assigned */ 42 #define NO_IRQ 0 43 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 struct device_node; 72 73 /* Functions below are provided by the host and called whenever a new mapping 74 * is created or an old mapping is disposed. The host can then proceed to 75 * whatever internal data structures management is required. It also needs 76 * to setup the irq_desc when returning from map(). 77 */ 78 struct irq_host_ops { 79 /* Match an interrupt controller device node to a host, returns 80 * 1 on a match 81 */ 82 int (*match)(struct irq_host *h, struct device_node *node); 83 84 /* Create or update a mapping between a virtual irq number and a hw 85 * irq number. This is called only once for a given mapping. 86 */ 87 int (*map)(struct irq_host *h, unsigned int virq, irq_hw_number_t hw); 88 89 /* Dispose of such a mapping */ 90 void (*unmap)(struct irq_host *h, unsigned int virq); 91 92 /* Translate device-tree interrupt specifier from raw format coming 93 * from the firmware to a irq_hw_number_t (interrupt line number) and 94 * type (sense) that can be passed to set_irq_type(). In the absence 95 * of this callback, irq_create_of_mapping() and irq_of_parse_and_map() 96 * will return the hw number in the first cell and IRQ_TYPE_NONE for 97 * the type (which amount to keeping whatever default value the 98 * interrupt controller has for that line) 99 */ 100 int (*xlate)(struct irq_host *h, struct device_node *ctrler, 101 const u32 *intspec, unsigned int intsize, 102 irq_hw_number_t *out_hwirq, unsigned int *out_type); 103 }; 104 105 struct irq_host { 106 struct list_head link; 107 108 /* type of reverse mapping technique */ 109 unsigned int revmap_type; 110 #define IRQ_HOST_MAP_PRIORITY 0 /* core priority irqs, get irqs 1..15 */ 111 #define IRQ_HOST_MAP_NOMAP 1 /* no fast reverse mapping */ 112 #define IRQ_HOST_MAP_LINEAR 2 /* linear map of interrupts */ 113 #define IRQ_HOST_MAP_TREE 3 /* radix tree */ 114 union { 115 struct { 116 unsigned int size; 117 unsigned int *revmap; 118 } linear; 119 struct radix_tree_root tree; 120 } revmap_data; 121 struct irq_host_ops *ops; 122 void *host_data; 123 irq_hw_number_t inval_irq; 124 125 /* Optional device node pointer */ 126 struct device_node *of_node; 127 }; 128 129 struct irq_data; 130 extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d); 131 extern irq_hw_number_t virq_to_hw(unsigned int virq); 132 extern bool virq_is_host(unsigned int virq, struct irq_host *host); 133 134 /** 135 * irq_alloc_host - Allocate a new irq_host data structure 136 * @of_node: optional device-tree node of the interrupt controller 137 * @revmap_type: type of reverse mapping to use 138 * @revmap_arg: for IRQ_HOST_MAP_LINEAR linear only: size of the map 139 * @ops: map/unmap host callbacks 140 * @inval_irq: provide a hw number in that host space that is always invalid 141 * 142 * Allocates and initialize and irq_host structure. Note that in the case of 143 * IRQ_HOST_MAP_LEGACY, the map() callback will be called before this returns 144 * for all legacy interrupts except 0 (which is always the invalid irq for 145 * a legacy controller). For a IRQ_HOST_MAP_LINEAR, the map is allocated by 146 * this call as well. For a IRQ_HOST_MAP_TREE, the radix tree will be allocated 147 * later during boot automatically (the reverse mapping will use the slow path 148 * until that happens). 149 */ 150 extern struct irq_host *irq_alloc_host(struct device_node *of_node, 151 unsigned int revmap_type, 152 unsigned int revmap_arg, 153 struct irq_host_ops *ops, 154 irq_hw_number_t inval_irq); 155 156 157 /** 158 * irq_find_host - Locates a host for a given device node 159 * @node: device-tree node of the interrupt controller 160 */ 161 extern struct irq_host *irq_find_host(struct device_node *node); 162 163 164 /** 165 * irq_set_default_host - Set a "default" host 166 * @host: default host pointer 167 * 168 * For convenience, it's possible to set a "default" host that will be used 169 * whenever NULL is passed to irq_create_mapping(). It makes life easier for 170 * platforms that want to manipulate a few hard coded interrupt numbers that 171 * aren't properly represented in the device-tree. 172 */ 173 extern void irq_set_default_host(struct irq_host *host); 174 175 176 /** 177 * irq_set_virq_count - Set the maximum number of virt irqs 178 * @count: number of linux virtual irqs, capped with NR_IRQS 179 * 180 * This is mainly for use by platforms like iSeries who want to program 181 * the virtual irq number in the controller to avoid the reverse mapping 182 */ 183 extern void irq_set_virq_count(unsigned int count); 184 185 186 /** 187 * irq_create_mapping - Map a hardware interrupt into linux virq space 188 * @host: host owning this hardware interrupt or NULL for default host 189 * @hwirq: hardware irq number in that host space 190 * 191 * Only one mapping per hardware interrupt is permitted. Returns a linux 192 * virq number. 193 * If the sense/trigger is to be specified, set_irq_type() should be called 194 * on the number returned from that call. 195 */ 196 extern unsigned int irq_create_mapping(struct irq_host *host, 197 irq_hw_number_t hwirq); 198 199 200 /** 201 * irq_dispose_mapping - Unmap an interrupt 202 * @virq: linux virq number of the interrupt to unmap 203 */ 204 extern void irq_dispose_mapping(unsigned int virq); 205 206 /** 207 * irq_find_mapping - Find a linux virq from an hw irq number. 208 * @host: host owning this hardware interrupt 209 * @hwirq: hardware irq number in that host space 210 * 211 * This is a slow path, for use by generic code. It's expected that an 212 * irq controller implementation directly calls the appropriate low level 213 * mapping function. 214 */ 215 extern unsigned int irq_find_mapping(struct irq_host *host, 216 irq_hw_number_t hwirq); 217 218 /** 219 * irq_create_direct_mapping - Allocate a virq for direct mapping 220 * @host: host to allocate the virq for or NULL for default host 221 * 222 * This routine is used for irq controllers which can choose the hardware 223 * interrupt numbers they generate. In such a case it's simplest to use 224 * the linux virq as the hardware interrupt number. 225 */ 226 extern unsigned int irq_create_direct_mapping(struct irq_host *host); 227 228 /** 229 * irq_radix_revmap_insert - Insert a hw irq to linux virq number mapping. 230 * @host: host owning this hardware interrupt 231 * @virq: linux irq number 232 * @hwirq: hardware irq number in that host space 233 * 234 * This is for use by irq controllers that use a radix tree reverse 235 * mapping for fast lookup. 236 */ 237 extern void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq, 238 irq_hw_number_t hwirq); 239 240 /** 241 * irq_radix_revmap_lookup - Find a linux virq from a hw irq number. 242 * @host: host owning this hardware interrupt 243 * @hwirq: hardware irq number in that host space 244 * 245 * This is a fast path, for use by irq controller code that uses radix tree 246 * revmaps 247 */ 248 extern unsigned int irq_radix_revmap_lookup(struct irq_host *host, 249 irq_hw_number_t hwirq); 250 251 /** 252 * irq_linear_revmap - Find a linux virq from a hw irq number. 253 * @host: host owning this hardware interrupt 254 * @hwirq: hardware irq number in that host space 255 * 256 * This is a fast path, for use by irq controller code that uses linear 257 * revmaps. It does fallback to the slow path if the revmap doesn't exist 258 * yet and will create the revmap entry with appropriate locking 259 */ 260 261 extern unsigned int irq_linear_revmap(struct irq_host *host, 262 irq_hw_number_t hwirq); 263 264 265 266 /** 267 * irq_alloc_virt - Allocate virtual irq numbers 268 * @host: host owning these new virtual irqs 269 * @count: number of consecutive numbers to allocate 270 * @hint: pass a hint number, the allocator will try to use a 1:1 mapping 271 * 272 * This is a low level function that is used internally by irq_create_mapping() 273 * and that can be used by some irq controllers implementations for things 274 * like allocating ranges of numbers for MSIs. The revmaps are left untouched. 275 */ 276 extern unsigned int irq_alloc_virt(struct irq_host *host, 277 unsigned int count, 278 unsigned int hint); 279 280 /** 281 * irq_free_virt - Free virtual irq numbers 282 * @virq: virtual irq number of the first interrupt to free 283 * @count: number of interrupts to free 284 * 285 * This function is the opposite of irq_alloc_virt. It will not clear reverse 286 * maps, this should be done previously by unmap'ing the interrupt. In fact, 287 * all interrupts covered by the range being freed should have been unmapped 288 * prior to calling this. 289 */ 290 extern void irq_free_virt(unsigned int virq, unsigned int count); 291 292 extern void __init init_pic_c64xplus(void); 293 294 extern void init_IRQ(void); 295 296 struct pt_regs; 297 298 extern asmlinkage void c6x_do_IRQ(unsigned int prio, struct pt_regs *regs); 299 300 extern unsigned long irq_err_count; 301 302 #endif /* _ASM_C6X_IRQ_H */ 303