diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-21 13:27:19 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-21 13:27:19 -0400 |
commit | c207f3a43194e108dda43dc9a1ce507335cff6b9 (patch) | |
tree | 55880f8301e8546b1908f69947d0d41aaa044814 /arch/arm/common | |
parent | c7c66c0cb0c77b1a8edf09bca57d922312d58030 (diff) | |
parent | e7cc3aca0f6a36b018934264ee20bee45dc13e29 (diff) |
Merge tag 'irqdomain-for-linus' of git://git.secretlab.ca/git/linux-2.6
Pull irq_domain support for all architectures from Grant Likely:
"Generialize powerpc's irq_host as irq_domain
This branch takes the PowerPC irq_host infrastructure (reverse mapping
from Linux IRQ numbers to hardware irq numbering), generalizes it,
renames it to irq_domain, and makes it available to all architectures.
Originally the plan has been to create an all-new irq_domain
implementation which addresses some of the powerpc shortcomings such
as not handling 1:1 mappings well, but doing that proved to be far
more difficult and invasive than generalizing the working code and
refactoring it in-place. So, this branch rips out the 'new'
irq_domain and replaces it with the modified powerpc version (in a
fully bisectable way of course). It converts all users over to the
new API and makes irq_domain selectable on any architecture.
No architecture is forced to enable irq_domain, but the infrastructure
is required for doing OpenFirmware style irq translations. It will
even work on SPARC even though SPARC has it's own mechanism for
translating irqs at boot time. MIPS, microblaze, embedded x86 and c6x
are converted too.
The resulting irq_domain code is probably still too verbose and can be
optimized more, but that can be done incrementally and is a task for
follow-on patches."
* tag 'irqdomain-for-linus' of git://git.secretlab.ca/git/linux-2.6: (31 commits)
dt: fix twl4030 for non-dt compile on x86
mfd: twl-core: Add IRQ_DOMAIN dependency
devicetree: Add empty of_platform_populate() for !CONFIG_OF_ADDRESS (sparc)
irq_domain: Centralize definition of irq_dispose_mapping()
irq_domain/mips: Allow irq_domain on MIPS
irq_domain/x86: Convert x86 (embedded) to use common irq_domain
ppc-6xx: fix build failure in flipper-pic.c and hlwd-pic.c
irq_domain/microblaze: Convert microblaze to use irq_domains
irq_domain/powerpc: Replace custom xlate functions with library functions
irq_domain/powerpc: constify irq_domain_ops
irq_domain/c6x: Use library of xlate functions
irq_domain/c6x: constify irq_domain structures
irq_domain/c6x: Convert c6x to use generic irq_domain support.
irq_domain: constify irq_domain_ops
irq_domain: Create common xlate functions that device drivers can use
irq_domain: Remove irq_domain_add_simple()
irq_domain: Remove 'new' irq_domain in favour of the ppc one
mfd: twl-core.c: Fix the number of interrupts managed by twl4030
of/address: add empty static inlines for !CONFIG_OF
irq_domain: Add support for base irq and hwirq in legacy mappings
...
Diffstat (limited to 'arch/arm/common')
-rw-r--r-- | arch/arm/common/gic.c | 95 | ||||
-rw-r--r-- | arch/arm/common/vic.c | 16 |
2 files changed, 47 insertions, 64 deletions
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c index c47d6199b784..f0783be17352 100644 --- a/arch/arm/common/gic.c +++ b/arch/arm/common/gic.c | |||
@@ -51,7 +51,6 @@ union gic_base { | |||
51 | }; | 51 | }; |
52 | 52 | ||
53 | struct gic_chip_data { | 53 | struct gic_chip_data { |
54 | unsigned int irq_offset; | ||
55 | union gic_base dist_base; | 54 | union gic_base dist_base; |
56 | union gic_base cpu_base; | 55 | union gic_base cpu_base; |
57 | #ifdef CONFIG_CPU_PM | 56 | #ifdef CONFIG_CPU_PM |
@@ -61,9 +60,7 @@ struct gic_chip_data { | |||
61 | u32 __percpu *saved_ppi_enable; | 60 | u32 __percpu *saved_ppi_enable; |
62 | u32 __percpu *saved_ppi_conf; | 61 | u32 __percpu *saved_ppi_conf; |
63 | #endif | 62 | #endif |
64 | #ifdef CONFIG_IRQ_DOMAIN | 63 | struct irq_domain *domain; |
65 | struct irq_domain domain; | ||
66 | #endif | ||
67 | unsigned int gic_irqs; | 64 | unsigned int gic_irqs; |
68 | #ifdef CONFIG_GIC_NON_BANKED | 65 | #ifdef CONFIG_GIC_NON_BANKED |
69 | void __iomem *(*get_base)(union gic_base *); | 66 | void __iomem *(*get_base)(union gic_base *); |
@@ -282,7 +279,7 @@ asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) | |||
282 | irqnr = irqstat & ~0x1c00; | 279 | irqnr = irqstat & ~0x1c00; |
283 | 280 | ||
284 | if (likely(irqnr > 15 && irqnr < 1021)) { | 281 | if (likely(irqnr > 15 && irqnr < 1021)) { |
285 | irqnr = irq_domain_to_irq(&gic->domain, irqnr); | 282 | irqnr = irq_find_mapping(gic->domain, irqnr); |
286 | handle_IRQ(irqnr, regs); | 283 | handle_IRQ(irqnr, regs); |
287 | continue; | 284 | continue; |
288 | } | 285 | } |
@@ -314,8 +311,8 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) | |||
314 | if (gic_irq == 1023) | 311 | if (gic_irq == 1023) |
315 | goto out; | 312 | goto out; |
316 | 313 | ||
317 | cascade_irq = irq_domain_to_irq(&chip_data->domain, gic_irq); | 314 | cascade_irq = irq_find_mapping(chip_data->domain, gic_irq); |
318 | if (unlikely(gic_irq < 32 || gic_irq > 1020 || cascade_irq >= NR_IRQS)) | 315 | if (unlikely(gic_irq < 32 || gic_irq > 1020)) |
319 | do_bad_IRQ(cascade_irq, desc); | 316 | do_bad_IRQ(cascade_irq, desc); |
320 | else | 317 | else |
321 | generic_handle_irq(cascade_irq); | 318 | generic_handle_irq(cascade_irq); |
@@ -348,10 +345,9 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq) | |||
348 | 345 | ||
349 | static void __init gic_dist_init(struct gic_chip_data *gic) | 346 | static void __init gic_dist_init(struct gic_chip_data *gic) |
350 | { | 347 | { |
351 | unsigned int i, irq; | 348 | unsigned int i; |
352 | u32 cpumask; | 349 | u32 cpumask; |
353 | unsigned int gic_irqs = gic->gic_irqs; | 350 | unsigned int gic_irqs = gic->gic_irqs; |
354 | struct irq_domain *domain = &gic->domain; | ||
355 | void __iomem *base = gic_data_dist_base(gic); | 351 | void __iomem *base = gic_data_dist_base(gic); |
356 | u32 cpu = cpu_logical_map(smp_processor_id()); | 352 | u32 cpu = cpu_logical_map(smp_processor_id()); |
357 | 353 | ||
@@ -386,23 +382,6 @@ static void __init gic_dist_init(struct gic_chip_data *gic) | |||
386 | for (i = 32; i < gic_irqs; i += 32) | 382 | for (i = 32; i < gic_irqs; i += 32) |
387 | writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32); | 383 | writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32); |
388 | 384 | ||
389 | /* | ||
390 | * Setup the Linux IRQ subsystem. | ||
391 | */ | ||
392 | irq_domain_for_each_irq(domain, i, irq) { | ||
393 | if (i < 32) { | ||
394 | irq_set_percpu_devid(irq); | ||
395 | irq_set_chip_and_handler(irq, &gic_chip, | ||
396 | handle_percpu_devid_irq); | ||
397 | set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN); | ||
398 | } else { | ||
399 | irq_set_chip_and_handler(irq, &gic_chip, | ||
400 | handle_fasteoi_irq); | ||
401 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | ||
402 | } | ||
403 | irq_set_chip_data(irq, gic); | ||
404 | } | ||
405 | |||
406 | writel_relaxed(1, base + GIC_DIST_CTRL); | 385 | writel_relaxed(1, base + GIC_DIST_CTRL); |
407 | } | 386 | } |
408 | 387 | ||
@@ -618,11 +597,27 @@ static void __init gic_pm_init(struct gic_chip_data *gic) | |||
618 | } | 597 | } |
619 | #endif | 598 | #endif |
620 | 599 | ||
621 | #ifdef CONFIG_OF | 600 | static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, |
622 | static int gic_irq_domain_dt_translate(struct irq_domain *d, | 601 | irq_hw_number_t hw) |
623 | struct device_node *controller, | 602 | { |
624 | const u32 *intspec, unsigned int intsize, | 603 | if (hw < 32) { |
625 | unsigned long *out_hwirq, unsigned int *out_type) | 604 | irq_set_percpu_devid(irq); |
605 | irq_set_chip_and_handler(irq, &gic_chip, | ||
606 | handle_percpu_devid_irq); | ||
607 | set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN); | ||
608 | } else { | ||
609 | irq_set_chip_and_handler(irq, &gic_chip, | ||
610 | handle_fasteoi_irq); | ||
611 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | ||
612 | } | ||
613 | irq_set_chip_data(irq, d->host_data); | ||
614 | return 0; | ||
615 | } | ||
616 | |||
617 | static int gic_irq_domain_xlate(struct irq_domain *d, | ||
618 | struct device_node *controller, | ||
619 | const u32 *intspec, unsigned int intsize, | ||
620 | unsigned long *out_hwirq, unsigned int *out_type) | ||
626 | { | 621 | { |
627 | if (d->of_node != controller) | 622 | if (d->of_node != controller) |
628 | return -EINVAL; | 623 | return -EINVAL; |
@@ -639,26 +634,23 @@ static int gic_irq_domain_dt_translate(struct irq_domain *d, | |||
639 | *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; | 634 | *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; |
640 | return 0; | 635 | return 0; |
641 | } | 636 | } |
642 | #endif | ||
643 | 637 | ||
644 | const struct irq_domain_ops gic_irq_domain_ops = { | 638 | const struct irq_domain_ops gic_irq_domain_ops = { |
645 | #ifdef CONFIG_OF | 639 | .map = gic_irq_domain_map, |
646 | .dt_translate = gic_irq_domain_dt_translate, | 640 | .xlate = gic_irq_domain_xlate, |
647 | #endif | ||
648 | }; | 641 | }; |
649 | 642 | ||
650 | void __init gic_init_bases(unsigned int gic_nr, int irq_start, | 643 | void __init gic_init_bases(unsigned int gic_nr, int irq_start, |
651 | void __iomem *dist_base, void __iomem *cpu_base, | 644 | void __iomem *dist_base, void __iomem *cpu_base, |
652 | u32 percpu_offset) | 645 | u32 percpu_offset, struct device_node *node) |
653 | { | 646 | { |
647 | irq_hw_number_t hwirq_base; | ||
654 | struct gic_chip_data *gic; | 648 | struct gic_chip_data *gic; |
655 | struct irq_domain *domain; | 649 | int gic_irqs, irq_base; |
656 | int gic_irqs; | ||
657 | 650 | ||
658 | BUG_ON(gic_nr >= MAX_GIC_NR); | 651 | BUG_ON(gic_nr >= MAX_GIC_NR); |
659 | 652 | ||
660 | gic = &gic_data[gic_nr]; | 653 | gic = &gic_data[gic_nr]; |
661 | domain = &gic->domain; | ||
662 | #ifdef CONFIG_GIC_NON_BANKED | 654 | #ifdef CONFIG_GIC_NON_BANKED |
663 | if (percpu_offset) { /* Frankein-GIC without banked registers... */ | 655 | if (percpu_offset) { /* Frankein-GIC without banked registers... */ |
664 | unsigned int cpu; | 656 | unsigned int cpu; |
@@ -694,10 +686,10 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, | |||
694 | * For primary GICs, skip over SGIs. | 686 | * For primary GICs, skip over SGIs. |
695 | * For secondary GICs, skip over PPIs, too. | 687 | * For secondary GICs, skip over PPIs, too. |
696 | */ | 688 | */ |
697 | domain->hwirq_base = 32; | 689 | hwirq_base = 32; |
698 | if (gic_nr == 0) { | 690 | if (gic_nr == 0) { |
699 | if ((irq_start & 31) > 0) { | 691 | if ((irq_start & 31) > 0) { |
700 | domain->hwirq_base = 16; | 692 | hwirq_base = 16; |
701 | if (irq_start != -1) | 693 | if (irq_start != -1) |
702 | irq_start = (irq_start & ~31) + 16; | 694 | irq_start = (irq_start & ~31) + 16; |
703 | } | 695 | } |
@@ -713,17 +705,17 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, | |||
713 | gic_irqs = 1020; | 705 | gic_irqs = 1020; |
714 | gic->gic_irqs = gic_irqs; | 706 | gic->gic_irqs = gic_irqs; |
715 | 707 | ||
716 | domain->nr_irq = gic_irqs - domain->hwirq_base; | 708 | gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */ |
717 | domain->irq_base = irq_alloc_descs(irq_start, 16, domain->nr_irq, | 709 | irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, numa_node_id()); |
718 | numa_node_id()); | 710 | if (IS_ERR_VALUE(irq_base)) { |
719 | if (IS_ERR_VALUE(domain->irq_base)) { | ||
720 | WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", | 711 | WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", |
721 | irq_start); | 712 | irq_start); |
722 | domain->irq_base = irq_start; | 713 | irq_base = irq_start; |
723 | } | 714 | } |
724 | domain->priv = gic; | 715 | gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base, |
725 | domain->ops = &gic_irq_domain_ops; | 716 | hwirq_base, &gic_irq_domain_ops, gic); |
726 | irq_domain_add(domain); | 717 | if (WARN_ON(!gic->domain)) |
718 | return; | ||
727 | 719 | ||
728 | gic_chip.flags |= gic_arch_extn.flags; | 720 | gic_chip.flags |= gic_arch_extn.flags; |
729 | gic_dist_init(gic); | 721 | gic_dist_init(gic); |
@@ -768,7 +760,6 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent) | |||
768 | void __iomem *dist_base; | 760 | void __iomem *dist_base; |
769 | u32 percpu_offset; | 761 | u32 percpu_offset; |
770 | int irq; | 762 | int irq; |
771 | struct irq_domain *domain = &gic_data[gic_cnt].domain; | ||
772 | 763 | ||
773 | if (WARN_ON(!node)) | 764 | if (WARN_ON(!node)) |
774 | return -ENODEV; | 765 | return -ENODEV; |
@@ -782,9 +773,7 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent) | |||
782 | if (of_property_read_u32(node, "cpu-offset", &percpu_offset)) | 773 | if (of_property_read_u32(node, "cpu-offset", &percpu_offset)) |
783 | percpu_offset = 0; | 774 | percpu_offset = 0; |
784 | 775 | ||
785 | domain->of_node = of_node_get(node); | 776 | gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node); |
786 | |||
787 | gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset); | ||
788 | 777 | ||
789 | if (parent) { | 778 | if (parent) { |
790 | irq = irq_of_parse_and_map(node, 0); | 779 | irq = irq_of_parse_and_map(node, 0); |
diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c index dcb004a804c7..7a66311f3066 100644 --- a/arch/arm/common/vic.c +++ b/arch/arm/common/vic.c | |||
@@ -56,7 +56,7 @@ struct vic_device { | |||
56 | u32 int_enable; | 56 | u32 int_enable; |
57 | u32 soft_int; | 57 | u32 soft_int; |
58 | u32 protect; | 58 | u32 protect; |
59 | struct irq_domain domain; | 59 | struct irq_domain *domain; |
60 | }; | 60 | }; |
61 | 61 | ||
62 | /* we cannot allocate memory when VICs are initially registered */ | 62 | /* we cannot allocate memory when VICs are initially registered */ |
@@ -192,14 +192,8 @@ static void __init vic_register(void __iomem *base, unsigned int irq, | |||
192 | v->resume_sources = resume_sources; | 192 | v->resume_sources = resume_sources; |
193 | v->irq = irq; | 193 | v->irq = irq; |
194 | vic_id++; | 194 | vic_id++; |
195 | 195 | v->domain = irq_domain_add_legacy(node, 32, irq, 0, | |
196 | v->domain.irq_base = irq; | 196 | &irq_domain_simple_ops, v); |
197 | v->domain.nr_irq = 32; | ||
198 | #ifdef CONFIG_OF_IRQ | ||
199 | v->domain.of_node = of_node_get(node); | ||
200 | #endif /* CONFIG_OF */ | ||
201 | v->domain.ops = &irq_domain_simple_ops; | ||
202 | irq_domain_add(&v->domain); | ||
203 | } | 197 | } |
204 | 198 | ||
205 | static void vic_ack_irq(struct irq_data *d) | 199 | static void vic_ack_irq(struct irq_data *d) |
@@ -348,7 +342,7 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start, | |||
348 | vic_register(base, irq_start, 0, node); | 342 | vic_register(base, irq_start, 0, node); |
349 | } | 343 | } |
350 | 344 | ||
351 | static void __init __vic_init(void __iomem *base, unsigned int irq_start, | 345 | void __init __vic_init(void __iomem *base, unsigned int irq_start, |
352 | u32 vic_sources, u32 resume_sources, | 346 | u32 vic_sources, u32 resume_sources, |
353 | struct device_node *node) | 347 | struct device_node *node) |
354 | { | 348 | { |
@@ -444,7 +438,7 @@ static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs) | |||
444 | stat = readl_relaxed(vic->base + VIC_IRQ_STATUS); | 438 | stat = readl_relaxed(vic->base + VIC_IRQ_STATUS); |
445 | while (stat) { | 439 | while (stat) { |
446 | irq = ffs(stat) - 1; | 440 | irq = ffs(stat) - 1; |
447 | handle_IRQ(irq_domain_to_irq(&vic->domain, irq), regs); | 441 | handle_IRQ(irq_find_mapping(vic->domain, irq), regs); |
448 | stat &= ~(1 << irq); | 442 | stat &= ~(1 << irq); |
449 | handled = 1; | 443 | handled = 1; |
450 | } | 444 | } |