diff options
Diffstat (limited to 'include/linux/irqdomain.h')
-rw-r--r-- | include/linux/irqdomain.h | 142 |
1 files changed, 75 insertions, 67 deletions
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index ba2c708adcff..c983ed18c332 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h | |||
@@ -73,57 +73,48 @@ struct irq_domain_chip_generic; | |||
73 | /** | 73 | /** |
74 | * struct irq_domain - Hardware interrupt number translation object | 74 | * struct irq_domain - Hardware interrupt number translation object |
75 | * @link: Element in global irq_domain list. | 75 | * @link: Element in global irq_domain list. |
76 | * @revmap_type: Method used for reverse mapping hwirq numbers to linux irq. This | 76 | * @name: Name of interrupt domain |
77 | * will be one of the IRQ_DOMAIN_MAP_* values. | ||
78 | * @revmap_data: Revmap method specific data. | ||
79 | * @ops: pointer to irq_domain methods | 77 | * @ops: pointer to irq_domain methods |
80 | * @host_data: private data pointer for use by owner. Not touched by irq_domain | 78 | * @host_data: private data pointer for use by owner. Not touched by irq_domain |
81 | * core code. | 79 | * core code. |
82 | * @irq_base: Start of irq_desc range assigned to the irq_domain. The creator | 80 | * |
83 | * of the irq_domain is responsible for allocating the array of | 81 | * Optional elements |
84 | * irq_desc structures. | 82 | * @of_node: Pointer to device tree nodes associated with the irq_domain. Used |
85 | * @nr_irq: Number of irqs managed by the irq domain | 83 | * when decoding device tree interrupt specifiers. |
86 | * @hwirq_base: Starting number for hwirqs managed by the irq domain | 84 | * @gc: Pointer to a list of generic chips. There is a helper function for |
87 | * @of_node: (optional) Pointer to device tree nodes associated with the | 85 | * setting up one or more generic chips for interrupt controllers |
88 | * irq_domain. Used when decoding device tree interrupt specifiers. | 86 | * drivers using the generic chip library which uses this pointer. |
87 | * | ||
88 | * Revmap data, used internally by irq_domain | ||
89 | * @revmap_direct_max_irq: The largest hwirq that can be set for controllers that | ||
90 | * support direct mapping | ||
91 | * @revmap_size: Size of the linear map table @linear_revmap[] | ||
92 | * @revmap_tree: Radix map tree for hwirqs that don't fit in the linear map | ||
93 | * @linear_revmap: Linear table of hwirq->virq reverse mappings | ||
89 | */ | 94 | */ |
90 | struct irq_domain { | 95 | struct irq_domain { |
91 | struct list_head link; | 96 | struct list_head link; |
92 | 97 | const char *name; | |
93 | /* type of reverse mapping_technique */ | ||
94 | unsigned int revmap_type; | ||
95 | union { | ||
96 | struct { | ||
97 | unsigned int size; | ||
98 | unsigned int first_irq; | ||
99 | irq_hw_number_t first_hwirq; | ||
100 | } legacy; | ||
101 | struct { | ||
102 | unsigned int size; | ||
103 | unsigned int *revmap; | ||
104 | } linear; | ||
105 | struct { | ||
106 | unsigned int max_irq; | ||
107 | } nomap; | ||
108 | struct radix_tree_root tree; | ||
109 | } revmap_data; | ||
110 | const struct irq_domain_ops *ops; | 98 | const struct irq_domain_ops *ops; |
111 | void *host_data; | 99 | void *host_data; |
112 | irq_hw_number_t inval_irq; | ||
113 | 100 | ||
114 | /* Optional device node pointer */ | 101 | /* Optional data */ |
115 | struct device_node *of_node; | 102 | struct device_node *of_node; |
116 | /* Optional pointer to generic interrupt chips */ | ||
117 | struct irq_domain_chip_generic *gc; | 103 | struct irq_domain_chip_generic *gc; |
118 | }; | ||
119 | 104 | ||
120 | #define IRQ_DOMAIN_MAP_LEGACY 0 /* driver allocated fixed range of irqs. | 105 | /* reverse map data. The linear map gets appended to the irq_domain */ |
121 | * ie. legacy 8259, gets irqs 1..15 */ | 106 | irq_hw_number_t hwirq_max; |
122 | #define IRQ_DOMAIN_MAP_NOMAP 1 /* no fast reverse mapping */ | 107 | unsigned int revmap_direct_max_irq; |
123 | #define IRQ_DOMAIN_MAP_LINEAR 2 /* linear map of interrupts */ | 108 | unsigned int revmap_size; |
124 | #define IRQ_DOMAIN_MAP_TREE 3 /* radix tree */ | 109 | struct radix_tree_root revmap_tree; |
110 | unsigned int linear_revmap[]; | ||
111 | }; | ||
125 | 112 | ||
126 | #ifdef CONFIG_IRQ_DOMAIN | 113 | #ifdef CONFIG_IRQ_DOMAIN |
114 | struct irq_domain *__irq_domain_add(struct device_node *of_node, int size, | ||
115 | irq_hw_number_t hwirq_max, int direct_max, | ||
116 | const struct irq_domain_ops *ops, | ||
117 | void *host_data); | ||
127 | struct irq_domain *irq_domain_add_simple(struct device_node *of_node, | 118 | struct irq_domain *irq_domain_add_simple(struct device_node *of_node, |
128 | unsigned int size, | 119 | unsigned int size, |
129 | unsigned int first_irq, | 120 | unsigned int first_irq, |
@@ -135,21 +126,30 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node, | |||
135 | irq_hw_number_t first_hwirq, | 126 | irq_hw_number_t first_hwirq, |
136 | const struct irq_domain_ops *ops, | 127 | const struct irq_domain_ops *ops, |
137 | void *host_data); | 128 | void *host_data); |
138 | struct irq_domain *irq_domain_add_linear(struct device_node *of_node, | 129 | extern struct irq_domain *irq_find_host(struct device_node *node); |
130 | extern void irq_set_default_host(struct irq_domain *host); | ||
131 | |||
132 | /** | ||
133 | * irq_domain_add_linear() - Allocate and register a linear revmap irq_domain. | ||
134 | * @of_node: pointer to interrupt controller's device tree node. | ||
135 | * @size: Number of interrupts in the domain. | ||
136 | * @ops: map/unmap domain callbacks | ||
137 | * @host_data: Controller private data pointer | ||
138 | */ | ||
139 | static inline struct irq_domain *irq_domain_add_linear(struct device_node *of_node, | ||
139 | unsigned int size, | 140 | unsigned int size, |
140 | const struct irq_domain_ops *ops, | 141 | const struct irq_domain_ops *ops, |
141 | void *host_data); | 142 | void *host_data) |
142 | struct irq_domain *irq_domain_add_nomap(struct device_node *of_node, | 143 | { |
144 | return __irq_domain_add(of_node, size, size, 0, ops, host_data); | ||
145 | } | ||
146 | static inline struct irq_domain *irq_domain_add_nomap(struct device_node *of_node, | ||
143 | unsigned int max_irq, | 147 | unsigned int max_irq, |
144 | const struct irq_domain_ops *ops, | 148 | const struct irq_domain_ops *ops, |
145 | void *host_data); | 149 | void *host_data) |
146 | struct irq_domain *irq_domain_add_tree(struct device_node *of_node, | 150 | { |
147 | const struct irq_domain_ops *ops, | 151 | return __irq_domain_add(of_node, 0, max_irq, max_irq, ops, host_data); |
148 | void *host_data); | 152 | } |
149 | |||
150 | extern struct irq_domain *irq_find_host(struct device_node *node); | ||
151 | extern void irq_set_default_host(struct irq_domain *host); | ||
152 | |||
153 | static inline struct irq_domain *irq_domain_add_legacy_isa( | 153 | static inline struct irq_domain *irq_domain_add_legacy_isa( |
154 | struct device_node *of_node, | 154 | struct device_node *of_node, |
155 | const struct irq_domain_ops *ops, | 155 | const struct irq_domain_ops *ops, |
@@ -158,21 +158,40 @@ static inline struct irq_domain *irq_domain_add_legacy_isa( | |||
158 | return irq_domain_add_legacy(of_node, NUM_ISA_INTERRUPTS, 0, 0, ops, | 158 | return irq_domain_add_legacy(of_node, NUM_ISA_INTERRUPTS, 0, 0, ops, |
159 | host_data); | 159 | host_data); |
160 | } | 160 | } |
161 | static inline struct irq_domain *irq_domain_add_tree(struct device_node *of_node, | ||
162 | const struct irq_domain_ops *ops, | ||
163 | void *host_data) | ||
164 | { | ||
165 | return __irq_domain_add(of_node, 0, ~0, 0, ops, host_data); | ||
166 | } | ||
161 | 167 | ||
162 | extern void irq_domain_remove(struct irq_domain *host); | 168 | extern void irq_domain_remove(struct irq_domain *host); |
163 | 169 | ||
164 | extern int irq_domain_associate_many(struct irq_domain *domain, | 170 | extern int irq_domain_associate(struct irq_domain *domain, unsigned int irq, |
165 | unsigned int irq_base, | 171 | irq_hw_number_t hwirq); |
166 | irq_hw_number_t hwirq_base, int count); | 172 | extern void irq_domain_associate_many(struct irq_domain *domain, |
167 | static inline int irq_domain_associate(struct irq_domain *domain, unsigned int irq, | 173 | unsigned int irq_base, |
168 | irq_hw_number_t hwirq) | 174 | irq_hw_number_t hwirq_base, int count); |
169 | { | ||
170 | return irq_domain_associate_many(domain, irq, hwirq, 1); | ||
171 | } | ||
172 | 175 | ||
173 | extern unsigned int irq_create_mapping(struct irq_domain *host, | 176 | extern unsigned int irq_create_mapping(struct irq_domain *host, |
174 | irq_hw_number_t hwirq); | 177 | irq_hw_number_t hwirq); |
175 | extern void irq_dispose_mapping(unsigned int virq); | 178 | extern void irq_dispose_mapping(unsigned int virq); |
179 | |||
180 | /** | ||
181 | * irq_linear_revmap() - Find a linux irq from a hw irq number. | ||
182 | * @domain: domain owning this hardware interrupt | ||
183 | * @hwirq: hardware irq number in that domain space | ||
184 | * | ||
185 | * This is a fast path alternative to irq_find_mapping() that can be | ||
186 | * called directly by irq controller code to save a handful of | ||
187 | * instructions. It is always safe to call, but won't find irqs mapped | ||
188 | * using the radix tree. | ||
189 | */ | ||
190 | static inline unsigned int irq_linear_revmap(struct irq_domain *domain, | ||
191 | irq_hw_number_t hwirq) | ||
192 | { | ||
193 | return hwirq < domain->revmap_size ? domain->linear_revmap[hwirq] : 0; | ||
194 | } | ||
176 | extern unsigned int irq_find_mapping(struct irq_domain *host, | 195 | extern unsigned int irq_find_mapping(struct irq_domain *host, |
177 | irq_hw_number_t hwirq); | 196 | irq_hw_number_t hwirq); |
178 | extern unsigned int irq_create_direct_mapping(struct irq_domain *host); | 197 | extern unsigned int irq_create_direct_mapping(struct irq_domain *host); |
@@ -186,9 +205,6 @@ static inline int irq_create_identity_mapping(struct irq_domain *host, | |||
186 | return irq_create_strict_mappings(host, hwirq, hwirq, 1); | 205 | return irq_create_strict_mappings(host, hwirq, hwirq, 1); |
187 | } | 206 | } |
188 | 207 | ||
189 | extern unsigned int irq_linear_revmap(struct irq_domain *host, | ||
190 | irq_hw_number_t hwirq); | ||
191 | |||
192 | extern const struct irq_domain_ops irq_domain_simple_ops; | 208 | extern const struct irq_domain_ops irq_domain_simple_ops; |
193 | 209 | ||
194 | /* stock xlate functions */ | 210 | /* stock xlate functions */ |
@@ -202,14 +218,6 @@ int irq_domain_xlate_onetwocell(struct irq_domain *d, struct device_node *ctrlr, | |||
202 | const u32 *intspec, unsigned int intsize, | 218 | const u32 *intspec, unsigned int intsize, |
203 | irq_hw_number_t *out_hwirq, unsigned int *out_type); | 219 | irq_hw_number_t *out_hwirq, unsigned int *out_type); |
204 | 220 | ||
205 | #if defined(CONFIG_OF_IRQ) | ||
206 | extern void irq_domain_generate_simple(const struct of_device_id *match, | ||
207 | u64 phys_base, unsigned int irq_start); | ||
208 | #else /* CONFIG_OF_IRQ */ | ||
209 | static inline void irq_domain_generate_simple(const struct of_device_id *match, | ||
210 | u64 phys_base, unsigned int irq_start) { } | ||
211 | #endif /* !CONFIG_OF_IRQ */ | ||
212 | |||
213 | #else /* CONFIG_IRQ_DOMAIN */ | 221 | #else /* CONFIG_IRQ_DOMAIN */ |
214 | static inline void irq_dispose_mapping(unsigned int virq) { } | 222 | static inline void irq_dispose_mapping(unsigned int virq) { } |
215 | #endif /* !CONFIG_IRQ_DOMAIN */ | 223 | #endif /* !CONFIG_IRQ_DOMAIN */ |