diff options
author | Linus Walleij <linus.walleij@linaro.org> | 2012-10-26 19:05:06 -0400 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2012-10-26 19:05:06 -0400 |
commit | 3a6ca8c5c9e310d26fe090ac7c777c269661f0e6 (patch) | |
tree | 0e61e6fa28b7a22e1fdc47100bc5a8207cbeb5ca /arch/arm | |
parent | 6f0c0580b70c89094b3422ba81118c7b959c7556 (diff) |
ARM: plat-versatile: use simple irqdomain for FPGA IRQ
This switches the FPGA IRQ driver over to using the simple IRQ
domain. We can then use the same codepath for this in the
DT and non-DT cases.
To be able to use quicker irq_find_mapping() in the handlers
we first call irq_create_mapping() on all the valid HW IRQ
numbers so that descriptors will be created for them in the
DT case where a linear domain will be the outcome of the
call.
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/plat-versatile/fpga-irq.c | 50 |
1 files changed, 22 insertions, 28 deletions
diff --git a/arch/arm/plat-versatile/fpga-irq.c b/arch/arm/plat-versatile/fpga-irq.c index 091ae1030045..dfe317c20354 100644 --- a/arch/arm/plat-versatile/fpga-irq.c +++ b/arch/arm/plat-versatile/fpga-irq.c | |||
@@ -1,6 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Support for Versatile FPGA-based IRQ controllers | 2 | * Support for Versatile FPGA-based IRQ controllers |
3 | */ | 3 | */ |
4 | #include <linux/bitops.h> | ||
4 | #include <linux/irq.h> | 5 | #include <linux/irq.h> |
5 | #include <linux/io.h> | 6 | #include <linux/io.h> |
6 | #include <linux/irqdomain.h> | 7 | #include <linux/irqdomain.h> |
@@ -117,13 +118,12 @@ static int fpga_irqdomain_map(struct irq_domain *d, unsigned int irq, | |||
117 | struct fpga_irq_data *f = d->host_data; | 118 | struct fpga_irq_data *f = d->host_data; |
118 | 119 | ||
119 | /* Skip invalid IRQs, only register handlers for the real ones */ | 120 | /* Skip invalid IRQs, only register handlers for the real ones */ |
120 | if (!(f->valid & (1 << hwirq))) | 121 | if (!(f->valid & BIT(hwirq))) |
121 | return -ENOTSUPP; | 122 | return -ENOTSUPP; |
122 | irq_set_chip_data(irq, f); | 123 | irq_set_chip_data(irq, f); |
123 | irq_set_chip_and_handler(irq, &f->chip, | 124 | irq_set_chip_and_handler(irq, &f->chip, |
124 | handle_level_irq); | 125 | handle_level_irq); |
125 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 126 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
126 | f->used_irqs++; | ||
127 | return 0; | 127 | return 0; |
128 | } | 128 | } |
129 | 129 | ||
@@ -132,13 +132,15 @@ static struct irq_domain_ops fpga_irqdomain_ops = { | |||
132 | .xlate = irq_domain_xlate_onetwocell, | 132 | .xlate = irq_domain_xlate_onetwocell, |
133 | }; | 133 | }; |
134 | 134 | ||
135 | static __init struct fpga_irq_data * | 135 | void __init fpga_irq_init(void __iomem *base, const char *name, int irq_start, |
136 | fpga_irq_prep_struct(void __iomem *base, const char *name, u32 valid) { | 136 | int parent_irq, u32 valid, struct device_node *node) |
137 | { | ||
137 | struct fpga_irq_data *f; | 138 | struct fpga_irq_data *f; |
139 | int i; | ||
138 | 140 | ||
139 | if (fpga_irq_id >= ARRAY_SIZE(fpga_irq_devices)) { | 141 | if (fpga_irq_id >= ARRAY_SIZE(fpga_irq_devices)) { |
140 | printk(KERN_ERR "%s: too few FPGA IRQ controllers, increase CONFIG_PLAT_VERSATILE_FPGA_IRQ_NR\n", __func__); | 142 | pr_err("%s: too few FPGA IRQ controllers, increase CONFIG_PLAT_VERSATILE_FPGA_IRQ_NR\n", __func__); |
141 | return NULL; | 143 | return; |
142 | } | 144 | } |
143 | f = &fpga_irq_devices[fpga_irq_id]; | 145 | f = &fpga_irq_devices[fpga_irq_id]; |
144 | f->base = base; | 146 | f->base = base; |
@@ -147,29 +149,28 @@ fpga_irq_prep_struct(void __iomem *base, const char *name, u32 valid) { | |||
147 | f->chip.irq_mask = fpga_irq_mask; | 149 | f->chip.irq_mask = fpga_irq_mask; |
148 | f->chip.irq_unmask = fpga_irq_unmask; | 150 | f->chip.irq_unmask = fpga_irq_unmask; |
149 | f->valid = valid; | 151 | f->valid = valid; |
150 | fpga_irq_id++; | ||
151 | |||
152 | return f; | ||
153 | } | ||
154 | |||
155 | void __init fpga_irq_init(void __iomem *base, const char *name, int irq_start, | ||
156 | int parent_irq, u32 valid, struct device_node *node) | ||
157 | { | ||
158 | struct fpga_irq_data *f; | ||
159 | |||
160 | f = fpga_irq_prep_struct(base, name, valid); | ||
161 | if (!f) | ||
162 | return; | ||
163 | 152 | ||
164 | if (parent_irq != -1) { | 153 | if (parent_irq != -1) { |
165 | irq_set_handler_data(parent_irq, f); | 154 | irq_set_handler_data(parent_irq, f); |
166 | irq_set_chained_handler(parent_irq, fpga_irq_handle); | 155 | irq_set_chained_handler(parent_irq, fpga_irq_handle); |
167 | } | 156 | } |
168 | 157 | ||
169 | f->domain = irq_domain_add_legacy(node, fls(valid), irq_start, 0, | 158 | /* This will also allocate irq descriptors */ |
159 | f->domain = irq_domain_add_simple(node, fls(valid), irq_start, | ||
170 | &fpga_irqdomain_ops, f); | 160 | &fpga_irqdomain_ops, f); |
161 | |||
162 | /* This will allocate all valid descriptors in the linear case */ | ||
163 | for (i = 0; i < fls(valid); i++) | ||
164 | if (valid & BIT(i)) { | ||
165 | if (!irq_start) | ||
166 | irq_create_mapping(f->domain, i); | ||
167 | f->used_irqs++; | ||
168 | } | ||
169 | |||
171 | pr_info("FPGA IRQ chip %d \"%s\" @ %p, %u irqs\n", | 170 | pr_info("FPGA IRQ chip %d \"%s\" @ %p, %u irqs\n", |
172 | fpga_irq_id, name, base, f->used_irqs); | 171 | fpga_irq_id, name, base, f->used_irqs); |
172 | |||
173 | fpga_irq_id++; | ||
173 | } | 174 | } |
174 | 175 | ||
175 | #ifdef CONFIG_OF | 176 | #ifdef CONFIG_OF |
@@ -193,18 +194,11 @@ int __init fpga_irq_of_init(struct device_node *node, | |||
193 | if (of_property_read_u32(node, "valid-mask", &valid_mask)) | 194 | if (of_property_read_u32(node, "valid-mask", &valid_mask)) |
194 | valid_mask = 0; | 195 | valid_mask = 0; |
195 | 196 | ||
196 | f = fpga_irq_prep_struct(base, node->name, valid_mask); | 197 | fpga_irq_init(base, node->name, 0, -1, valid_mask, node); |
197 | if (!f) | ||
198 | return -ENOMEM; | ||
199 | 198 | ||
200 | writel(clear_mask, base + IRQ_ENABLE_CLEAR); | 199 | writel(clear_mask, base + IRQ_ENABLE_CLEAR); |
201 | writel(clear_mask, base + FIQ_ENABLE_CLEAR); | 200 | writel(clear_mask, base + FIQ_ENABLE_CLEAR); |
202 | 201 | ||
203 | f->domain = irq_domain_add_linear(node, fls(valid_mask), &fpga_irqdomain_ops, f); | ||
204 | f->used_irqs = hweight32(valid_mask); | ||
205 | |||
206 | pr_info("FPGA IRQ chip %d \"%s\" @ %p, %u irqs\n", | ||
207 | fpga_irq_id, node->name, base, f->used_irqs); | ||
208 | return 0; | 202 | return 0; |
209 | } | 203 | } |
210 | #endif | 204 | #endif |