MIPS: bmips: Add bcm63168-l1 interrupt controller
PATCH 1/2 MIPS: bmips: Add bcm63168-l1 interrupt controller
Add device tree binding for the BCM63168 interrupt controller.
This controller is similar to the SMP-capable BCM7038 and the BCM3380 but with packed interrupt registers.
--- .../interrupt-controller/brcm,bcm63168-l1-intc.txt | 57 ++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/brcm,bcm63168-l1-intc.txt
Documentation/devicetree/bindings/interrupt-controller/brcm,bcm63168-l1-intc.txt new file +57 -0
@@ -0,0 +1,57 @@ +Broadcom BCM63168-style Level 1 interrupt controller + +This block is a first level interrupt controller that is typically connected +directly to one of the HW INT lines on each CPU. + +Key elements of the hardware design include: + +- 64 or 128 incoming level IRQ lines + +- Most onchip peripherals are wired directly to an L1 input + +- A separate instance of the register set for each CPU, allowing individual + peripheral IRQs to be routed to any CPU + +- Contains one or more enable/status word pairs per CPU + +- No atomic set/clear operations + +- No polarity/level/edge settings + +- No FIFO or priority encoder logic; software is expected to read all + 2-4 status words to determine which IRQs are pending + +Required properties: + +- compatible: should be "brcm,bcm63168-l1-intc" +- reg: specifies the base physical address and size of the registers; + the number of supported IRQs is inferred from the size argument +- interrupt-controller: identifies the node as an interrupt controller +- #interrupt-cells: specifies the number of cells needed to encode an interrupt + source, should be 1. +- interrupt-parent: specifies the phandle to the parent interrupt controller(s) + this one is cascaded from +- interrupts: specifies the interrupt line(s) in the interrupt-parent controller + node; valid values depend on the type of parent interrupt controller + +If multiple reg ranges and interrupt-parent entries are present on an SMP +system, the driver will allow IRQ SMP affinity to be set up through the +/proc/irq/ interface. In the simplest possible configuration, only one +reg range and one interrupt-parent is needed. + +The driver operates in native CPU endian by default, there is no support for +specifying an alternative endianness. + +Example: + +periph_intc: periph_intc@10000000 { + compatible = "brcm,bcm63168-l1-intc"; + reg = <0x10000020 0x20>, + <0x10000040 0x20>; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&cpu_intc>; + interrupts = <2>, <3>; +};
Signature · 4 lines
2.1.4 -- Simon Arlott
PATCH 2/2 MIPS: bmips: Add bcm63168-l1 interrupt controller
Add the BCM63168 interrupt controller based on the SMP-capable BCM7038 and the BCM3380 but with packed interrupt registers.
Add the BCM63168 interrupt controller to a list with the existing BCM7038 so that interrupts on CPU1 are not ignored.
Update the maintainers file list for BMIPS to include this driver.
--- MAINTAINERS | 1 + arch/mips/Kconfig | 1 + arch/mips/bmips/irq.c | 10 +- drivers/irqchip/Kconfig | 5 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-bcm63168-l1.c | 372 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 388 insertions(+), 2 deletions(-) create mode 100644 drivers/irqchip/irq-bcm63168-l1.c
MAINTAINERS +1 -0
@@ -2373,6 +2373,7 @@ F: arch/mips/bmips/* F: arch/mips/include/asm/mach-bmips/* F: arch/mips/kernel/*bmips* F: arch/mips/boot/dts/brcm/bcm*.dts* +F: drivers/irqchip/irq-bcm63* F: drivers/irqchip/irq-bcm7* F: drivers/irqchip/irq-brcmstb*
arch/mips/Kconfig +1 -0
@@ -149,6 +149,7 @@ config BMIPS_GENERIC select CSRC_R4K select SYNC_R4K select COMMON_CLK + select BCM63168_L1_IRQ select BCM7038_L1_IRQ select BCM7120_L2_IRQ select BRCMSTB_L2_IRQ
arch/mips/bmips/irq.c +8 -2
@@ -15,6 +15,12 @@#include <asm/irq_cpu.h> #include <asm/time.h> +static const struct of_device_id smp_intc_dt_match[] = { + { .compatible ="brcm,bcm7038-l1-intc" }, + { .compatible ="brcm,bcm63168-l1-intc" }, + {} +}; +unsigned int get_c0_compare_int (void ) {return CP0_LEGACY_COMPARE_IRQ ;
@@ -24,8 +30,8 @@ void __init arch_init_irq(void) {struct device_node *dn; -/* Only the STB (bcm7038) controller supports SMP IRQ affinity */ - dn =of_find_compatible_node (NULL ,NULL ,"brcm,bcm7038-l1-intc" ); +/* Only these controllers support SMP IRQ affinity */ + dn =of_find_matching_node (NULL , smp_intc_dt_match);if (dn)of_node_put (dn);else
drivers/irqchip/Kconfig +5 -0
@@ -65,6 +65,11 @@ config I8259 bool select IRQ_DOMAIN +config BCM63168_L1_IRQ + bool + select GENERIC_IRQ_CHIP + select IRQ_DOMAIN + config BCM7038_L1_IRQ bool select GENERIC_IRQ_CHIP
drivers/irqchip/Makefile +1 -0
@@ -43,6 +43,7 @@ obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o obj-$(CONFIG_SOC_VF610) += irq-vf610-mscm-ir.o +obj-$(CONFIG_BCM63168_L1_IRQ) += irq-bcm63168-l1.o obj-$(CONFIG_BCM7038_L1_IRQ) += irq-bcm7038-l1.o obj-$(CONFIG_BCM7120_L2_IRQ) += irq-bcm7120-l2.o obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.o
drivers/irqchip/irq-bcm63168-l1.c new file +372 -0
372 lines not on this page · raw message
Signature · 4 lines
2.1.4 -- Simon Arlott
Quoted 196 lines · Simon Arlott
Add the BCM63168 interrupt controller based on the SMP-capable BCM7038 and the BCM3380 but with packed interrupt registers.
Add the BCM63168 interrupt controller to a list with the existing BCM7038 so that interrupts on CPU1 are not ignored.
Update the maintainers file list for BMIPS to include this driver.
Signed-off-by Simon Arlott <[email protected]>--- MAINTAINERS | 1 + arch/mips/Kconfig | 1 + arch/mips/bmips/irq.c | 10 +- drivers/irqchip/Kconfig | 5 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-bcm63168-l1.c | 372 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 388 insertions(+), 2 deletions(-) create mode 100644 drivers/irqchip/irq-bcm63168-l1.cMAINTAINERS +1
-0@@ -2373,6 +2373,7 @@ F: arch/mips/bmips/* F: arch/mips/include/asm/mach-bmips/* F: arch/mips/kernel/*bmips* F: arch/mips/boot/dts/brcm/bcm*.dts* +F: drivers/irqchip/irq-bcm63* F: drivers/irqchip/irq-bcm7* F: drivers/irqchip/irq-brcmstb*arch/mips/Kconfig +1
-0@@ -149,6 +149,7 @@ config BMIPS_GENERIC select CSRC_R4K select SYNC_R4K select COMMON_CLK + select BCM63168_L1_IRQ select BCM7038_L1_IRQ select BCM7120_L2_IRQ select BRCMSTB_L2_IRQarch/mips/bmips/irq.c +8
-2@@ -15,6 +15,12 @@#include <asm/irq_cpu.h> #include <asm/time.h> +static const struct of_device_id smp_intc_dt_match[] = { + { .compatible ="brcm,bcm7038-l1-intc" }, + { .compatible ="brcm,bcm63168-l1-intc" }, + {} +}; +unsigned int get_c0_compare_int (void ) {return CP0_LEGACY_COMPARE_IRQ ;@@ -24,8 +30,8 @@ void __init arch_init_irq(void) {struct device_node *dn; -/* Only the STB (bcm7038) controller supports SMP IRQ affinity */ - dn =of_find_compatible_node (NULL ,NULL ,"brcm,bcm7038-l1-intc" ); +/* Only these controllers support SMP IRQ affinity */ + dn =of_find_matching_node (NULL , smp_intc_dt_match);if (dn)of_node_put (dn);else drivers/irqchip/Kconfig +5
-0@@ -65,6 +65,11 @@ config I8259 bool select IRQ_DOMAIN +config BCM63168_L1_IRQ + bool + select GENERIC_IRQ_CHIP + select IRQ_DOMAIN + config BCM7038_L1_IRQ bool select GENERIC_IRQ_CHIPdrivers/irqchip/Makefile +1
-0@@ -43,6 +43,7 @@ obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o obj-$(CONFIG_SOC_VF610) += irq-vf610-mscm-ir.o +obj-$(CONFIG_BCM63168_L1_IRQ) += irq-bcm63168-l1.o obj-$(CONFIG_BCM7038_L1_IRQ) += irq-bcm7038-l1.o obj-$(CONFIG_BCM7120_L2_IRQ) += irq-bcm7120-l2.o obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.odrivers/irqchip/irq-bcm63168-l1.c new file +91
-0@@ -0,0 +1,372 @@ +/* +* Broadcom BCM63168 style Level 1 interrupt controller driver +* +* Copyright (C) 2014 Broadcom Corporation +* Copyright 2015 Simon Arlott +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This is based on the BCM7038 (which supports SMP) but with a single +* enable register instead of separate mask/set/clear registers. +* +* The BCM3380 has a similar mask/status register layout, but each pair +* of words is at separate locations (and SMP is not supported). +* +* ENABLE/STATUS words are packed next to each other for each CPU: +* +* 6368: +* 0x1000_0020: CPU0_W0_ENABLE +* 0x1000_0024: CPU0_W1_ENABLE +* 0x1000_0028: CPU0_W0_STATUS IRQs 31-63 +* 0x1000_002c: CPU0_W1_STATUS IRQs 0-31 +* 0x1000_0030: CPU1_W0_ENABLE +* 0x1000_0034: CPU1_W1_ENABLE +* 0x1000_0038: CPU1_W0_STATUS IRQs 31-63 +* 0x1000_003c: CPU1_W1_STATUS IRQs 0-31 +* +* 63168: +* 0x1000_0020: CPU0_W0_ENABLE +* 0x1000_0024: CPU0_W1_ENABLE +* 0x1000_0028: CPU0_W2_ENABLE +* 0x1000_002c: CPU0_W3_ENABLE +* 0x1000_0030: CPU0_W0_STATUS IRQs 96-127 +* 0x1000_0034: CPU0_W1_STATUS IRQs 64-95 +* 0x1000_0038: CPU0_W2_STATUS IRQs 32-63 +* 0x1000_003c: CPU0_W3_STATUS IRQs 0-31 +* 0x1000_0040: CPU1_W0_ENABLE +* 0x1000_0044: CPU1_W1_ENABLE +* 0x1000_0048: CPU1_W2_ENABLE +* 0x1000_004c: CPU1_W3_ENABLE +* 0x1000_0050: CPU1_W0_STATUS IRQs 96-127 +* 0x1000_0054: CPU1_W1_STATUS IRQs 64-95 +* 0x1000_0058: CPU1_W2_STATUS IRQs 32-63 +* 0x1000_005c: CPU1_W3_STATUS IRQs 0-31 +* +* IRQs are numbered in CPU native endian order +* (which is big-endian in these examples) +*/ + +#define pr_fmt (fmt) KBUILD_MODNAME ": " fmt + +#include <linux/bitops.h> +#include <linux/cpumask.h> +#include <linux/kconfig.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/smp.h> +#include <linux/types.h> +#include <linux/irqchip.h> +#include <linux/irqchip/chained_irq.h> + +#define IRQS_PER_WORD 32 +#define REG_BYTES_PER_IRQ_WORD (sizeof(u32) * 2) +#define MAX_WORDS 4 + +struct bcm63168_l1_cpu ; + +struct bcm63168_l1_chip { +raw_spinlock_t lock[MAX_WORDS ]; +unsigned int n_words; +struct irq_domain *domain; +struct cpumask cpumask; +struct bcm63168_l1_cpu *cpus[NR_CPUS ]; +}; + +struct bcm63168_l1_cpu { +void __iomem *map_base; +unsigned int parent_irq;
drivers/irqchip/irq-bcm63168-l1.c line 101
Quoted 10 lines
drivers/irqchip/irq-bcm63168-l1.c new file +10
-0+u32 enable_cache[]; +}; + +static inline unsigned int reg_enable (struct bcm63168_l1_chip *intc, +unsigned int word) +{ +#ifdef __BIG_ENDIAN +return (1 * intc->n_words - word -1 ) *sizeof (u32); +#else +return (0 * intc->n_words + word) *sizeof (u32);
Huh, do the words really change the order when running in LE? I would have expected
to each 32-bit word to contain the same interrupts, just bit-order reversed.
Quoted 21 lines
drivers/irqchip/irq-bcm63168-l1.c new file +21
-0+#endif +} + +static inline unsigned int reg_status (struct bcm63168_l1_chip *intc, +unsigned int word) +{ +#ifdef __BIG_ENDIAN +return (2 * intc->n_words - word -1 ) *sizeof (u32); +#else +return (1 * intc->n_words + word) *sizeof (u32); +#endif +} + +static inline unsigned int cpu_for_irq (struct bcm63168_l1_chip *intc, +struct irq_data *d) +{ +return cpumask_first_and (&intc->cpumask,irq_data_get_affinity_mask (d)); +} + +static void bcm63168_l1_irq_handle (struct irq_desc *desc) +{
drivers/irqchip/irq-bcm63168-l1.c line 132
Quoted 10 lines
drivers/irqchip/irq-bcm63168-l1.c new file +10
-0+struct bcm63168_l1_chip *intc =irq_desc_get_handler_data (desc); +struct bcm63168_l1_cpu *cpu; +struct irq_chip *chip =irq_desc_get_chip (desc); +unsigned int idx; + +#ifdef CONFIG_SMP + cpu = intc->cpus[cpu_logical_map (smp_processor_id ())]; +#else + cpu = intc->cpus[0 ]; +#endif
This looks expensive, can they change during runtime? If not, maybe just assign intc->cpus[] accordingly at probe time, so you can just do intc->cpus[smp_processor_id()] without any #ifdefs.
drivers/irqchip/irq-bcm63168-l1.c line 143
Quoted 11 lines
drivers/irqchip/irq-bcm63168-l1.c new file +11
-0+ +chained_irq_enter (chip, desc); + +for (idx =0 ; idx < intc->n_words; idx++) { +int base = idx *IRQS_PER_WORD ; +unsigned long pending; +irq_hw_number_t hwirq; +unsigned int irq; + + pending =__raw_readl (cpu->map_base +reg_status (intc, idx)); + pending &=__raw_readl (cpu->map_base +reg_enable (intc, idx));
Is it save to access the registers without any locking? 7038-l1 doesn't think so.
Quoted 139 lines
drivers/irqchip/irq-bcm63168-l1.c new file +139
-0+ +for_each_set_bit (hwirq, &pending,IRQS_PER_WORD ) { + irq =irq_linear_revmap (intc->domain, base + hwirq); +if (irq) +do_IRQ (irq); +else +spurious_interrupt (); + } + } + +chained_irq_exit (chip, desc); +} + +static inline void __bcm63168_l1_unmask (struct irq_data *d) +{ +struct bcm63168_l1_chip *intc =irq_data_get_irq_chip_data (d); +u32 word = d->hwirq /IRQS_PER_WORD ; +u32 mask =BIT (d->hwirq %IRQS_PER_WORD ); +unsigned int cpu_idx =cpu_for_irq (intc, d); + + intc->cpus[cpu_idx]->enable_cache[word] |= mask; +__raw_writel (intc->cpus[cpu_idx]->enable_cache[word], + intc->cpus[cpu_idx]->map_base +reg_enable (intc, word)); +} + +static inline void __bcm63168_l1_mask (struct irq_data *d) +{ +struct bcm63168_l1_chip *intc =irq_data_get_irq_chip_data (d); +u32 word = d->hwirq /IRQS_PER_WORD ; +u32 mask =BIT (d->hwirq %IRQS_PER_WORD ); +unsigned int cpu_idx =cpu_for_irq (intc, d); + + intc->cpus[cpu_idx]->enable_cache[word] &= ~mask; +__raw_writel (intc->cpus[cpu_idx]->enable_cache[word], + intc->cpus[cpu_idx]->map_base +reg_enable (intc, word)); +} + +static void bcm63168_l1_unmask (struct irq_data *d) +{ +struct bcm63168_l1_chip *intc =irq_data_get_irq_chip_data (d); +u32 word = d->hwirq /IRQS_PER_WORD ; +unsigned long flags; + +raw_spin_lock_irqsave (&intc->lock[word], flags); +__bcm63168_l1_unmask (d); +raw_spin_unlock_irqrestore (&intc->lock[word], flags); +} + +static void bcm63168_l1_mask (struct irq_data *d) +{ +struct bcm63168_l1_chip *intc =irq_data_get_irq_chip_data (d); +u32 word = d->hwirq /IRQS_PER_WORD ; +unsigned long flags; + +raw_spin_lock_irqsave (&intc->lock[word], flags); +__bcm63168_l1_mask (d); +raw_spin_unlock_irqrestore (&intc->lock[word], flags); +} + +static int bcm63168_l1_set_affinity (struct irq_data *d, +const struct cpumask *dest, +bool force) +{ +struct bcm63168_l1_chip *intc =irq_data_get_irq_chip_data (d); +u32 word = d->hwirq /IRQS_PER_WORD ; +u32 mask =BIT (d->hwirq %IRQS_PER_WORD ); +unsigned int old_cpu =cpu_for_irq (intc, d); +unsigned int new_cpu; +struct cpumask valid; +unsigned long flags; +bool enabled; + +if (!cpumask_and (&valid, &intc->cpumask, dest)) +return -EINVAL ; + + new_cpu =cpumask_any_and (&valid, cpu_online_mask); +if (new_cpu >= nr_cpu_ids) +return -EINVAL ; + + dest =cpumask_of (new_cpu); + +raw_spin_lock_irqsave (&intc->lock[word], flags); +if (old_cpu != new_cpu) { + enabled = intc->cpus[old_cpu]->enable_cache[word] & mask; +if (enabled) +__bcm63168_l1_mask (d); +cpumask_copy (irq_data_get_affinity_mask (d), dest); +if (enabled) +__bcm63168_l1_unmask (d); + }else { +cpumask_copy (irq_data_get_affinity_mask (d), dest); + } +raw_spin_unlock_irqrestore (&intc->lock[word], flags); + +return IRQ_SET_MASK_OK_NOCOPY ; +} + +static int __init bcm63168_l1_init_one (struct device_node *dn, +unsigned int idx, +struct bcm63168_l1_chip *intc) +{ +struct resource res; +resource_size_t sz; +struct bcm63168_l1_cpu *cpu; +unsigned int i, n_words; + +if (of_address_to_resource (dn, idx, &res)) +return -EINVAL ; + sz =resource_size (&res); + n_words = sz /REG_BYTES_PER_IRQ_WORD ; + +if (n_words >MAX_WORDS ) +return -EINVAL ; +else if (!intc->n_words) + intc->n_words = n_words; +else if (intc->n_words != n_words) +return -EINVAL ; + + cpu = intc->cpus[idx] =kzalloc (sizeof (*cpu) + n_words *sizeof (u32), +GFP_KERNEL ); +if (!cpu) +return -ENOMEM ; + + cpu->map_base =ioremap (res.start, sz); +if (!cpu->map_base) +return -ENOMEM ; + +for (i =0 ; i < n_words; i++) { + cpu->enable_cache[i] =0 ; +__raw_writel (0 , cpu->map_base +reg_enable (intc, i)); + } + + cpu->parent_irq =irq_of_parse_and_map (dn, idx); +if (!cpu->parent_irq) { +pr_err ("failed to map parent interrupt %d\n" , cpu->parent_irq); +return -EINVAL ; + } +irq_set_chained_handler_and_data (cpu->parent_irq, + bcm63168_l1_irq_handle, intc);
drivers/irqchip/irq-bcm63168-l1.c line 292
Quoted 10 lines
drivers/irqchip/irq-bcm63168-l1.c new file +10
-0+ +return 0 ; +} + +static struct irq_chip bcm63168_l1_irq_chip = { + .name ="bcm63168-l1" , + .irq_mask = bcm63168_l1_mask, + .irq_unmask = bcm63168_l1_unmask, + .irq_set_affinity = bcm63168_l1_set_affinity, +};
You are already allocing memory, why not alloc this one as well?
Quoted 17 lines
drivers/irqchip/irq-bcm63168-l1.c new file +17
-0+ +static int bcm63168_l1_map (struct irq_domain *d,unsigned int virq, +irq_hw_number_t hw_irq) +{ +irq_set_chip_and_handler (virq, + &bcm63168_l1_irq_chip, handle_percpu_irq); +irq_set_chip_data (virq, d->host_data); +return 0 ; +} + +static const struct irq_domain_ops bcm63168_l1_domain_ops = { + .xlate = irq_domain_xlate_onecell, + .map = bcm63168_l1_map, +}; + +static int __init bcm63168_l1_of_init (struct device_node *dn, +struct device_node *parent)
drivers/irqchip/irq-bcm63168-l1.c line 319
Quoted 10 lines
drivers/irqchip/irq-bcm63168-l1.c new file +10
-0+{ +struct bcm63168_l1_chip *intc; +unsigned int idx; +int ret; + + intc =kzalloc (sizeof (*intc),GFP_KERNEL ); +if (!intc) +return -ENOMEM ; + +cpumask_clear (&intc->cpumask);
intc->cpumask is already cleared since kzalloc'd.
Quoted 7 lines
drivers/irqchip/irq-bcm63168-l1.c new file +7
-0+ +for_each_possible_cpu (idx) { + ret =bcm63168_l1_init_one (dn, idx, intc); +if (ret) +pr_err ("failed to init intc L1 for cpu %d: %d\n" , + idx, ret); +else
drivers/irqchip/irq-bcm63168-l1.c line 336
Quoted 10 lines
drivers/irqchip/irq-bcm63168-l1.c new file +10
-0+cpumask_set_cpu (idx, &intc->cpumask); + } + +if (!cpumask_weight (&intc->cpumask)) { + ret = -ENODEV ; + goto out_free; + } + +for (idx =0 ; idx < intc->n_words; idx++) +raw_spin_lock_init (&intc->lock[idx]);
Do you really need a spinlock for each word?
Quoted 37 lines
drivers/irqchip/irq-bcm63168-l1.c new file +36
-1+ + intc->domain =irq_domain_add_linear (dn,IRQS_PER_WORD * intc->n_words, + &bcm63168_l1_domain_ops, + intc); +if (!intc->domain) { + ret = -ENOMEM ; + goto out_unmap; + } + +pr_info ("registered BCM63168 L1 intc (IRQs: %d)\n" , +IRQS_PER_WORD * intc->n_words); +for_each_cpu (idx, &intc->cpumask) { +struct bcm63168_l1_cpu *cpu = intc->cpus[idx]; + +pr_info (" CPU%u at MMIO 0x%p (irq = %d)\n" , idx, + cpu->map_base, cpu->parent_irq); + } + +return 0 ; + +out_unmap: +for_each_possible_cpu (idx) { +struct bcm63168_l1_cpu *cpu = intc->cpus[idx]; + +if (cpu) { +if (cpu->map_base) +iounmap (cpu->map_base); +kfree (cpu); + } + } +out_free: +kfree (intc); +return ret; +} + +IRQCHIP_DECLARE (bcm63168_l1,"brcm,bcm63168-l1-intc" , bcm63168_l1_of_init); --
Quoted 1 line
2.1.4
Jonas
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 6 lines · Jonas Gorski
Quoted 5 lines · Simon Arlott
Add the BCM63168 interrupt controller based on the SMP-capable BCM7038 and the BCM3380 but with packed interrupt registers.
Add the BCM63168 interrupt controller to a list with the existing BCM7038 so that interrupts on CPU1 are not ignored.
This will be renamed to bcm6345-l1.
...
Quoted 56 lines
Quoted 56 lines
drivers/irqchip/irq-bcm63168-l1.c new file +50
-0@@ -0,0 +1,372 @@ +/* +* Broadcom BCM63168 style Level 1 interrupt controller driver +* +* Copyright (C) 2014 Broadcom Corporation +* Copyright 2015 Simon Arlott +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This is based on the BCM7038 (which supports SMP) but with a single +* enable register instead of separate mask/set/clear registers. +* +* The BCM3380 has a similar mask/status register layout, but each pair +* of words is at separate locations (and SMP is not supported). +* +* ENABLE/STATUS words are packed next to each other for each CPU: +* +* 6368: +* 0x1000_0020: CPU0_W0_ENABLE +* 0x1000_0024: CPU0_W1_ENABLE +* 0x1000_0028: CPU0_W0_STATUS IRQs 31-63 +* 0x1000_002c: CPU0_W1_STATUS IRQs 0-31 +* 0x1000_0030: CPU1_W0_ENABLE +* 0x1000_0034: CPU1_W1_ENABLE +* 0x1000_0038: CPU1_W0_STATUS IRQs 31-63 +* 0x1000_003c: CPU1_W1_STATUS IRQs 0-31 +* +* 63168: +* 0x1000_0020: CPU0_W0_ENABLE +* 0x1000_0024: CPU0_W1_ENABLE +* 0x1000_0028: CPU0_W2_ENABLE +* 0x1000_002c: CPU0_W3_ENABLE +* 0x1000_0030: CPU0_W0_STATUS IRQs 96-127 +* 0x1000_0034: CPU0_W1_STATUS IRQs 64-95 +* 0x1000_0038: CPU0_W2_STATUS IRQs 32-63 +* 0x1000_003c: CPU0_W3_STATUS IRQs 0-31 +* 0x1000_0040: CPU1_W0_ENABLE +* 0x1000_0044: CPU1_W1_ENABLE +* 0x1000_0048: CPU1_W2_ENABLE +* 0x1000_004c: CPU1_W3_ENABLE +* 0x1000_0050: CPU1_W0_STATUS IRQs 96-127 +* 0x1000_0054: CPU1_W1_STATUS IRQs 64-95 +* 0x1000_0058: CPU1_W2_STATUS IRQs 32-63 +* 0x1000_005c: CPU1_W3_STATUS IRQs 0-31 +* +* IRQs are numbered in CPU native endian order +* (which is big-endian in these examples) +*/ +
...
Quoted 11 lines
drivers/irqchip/irq-bcm63168-l1.c line 101
Quoted 7 lines
drivers/irqchip/irq-bcm63168-l1.c new file +7
-0+static inline unsigned int reg_enable (struct bcm63168_l1_chip *intc, +unsigned int word) +{ +#ifdef __BIG_ENDIAN +return (1 * intc->n_words - word -1 ) *sizeof (u32); +#else +return (0 * intc->n_words + word) *sizeof (u32);Huh, do the words really change the order when running in LE? I would have expected
to each 32-bit word to contain the same interrupts, just bit-order reversed.
Without having a LE version of this SoC to check it on, I don't know... but this device binding is specified as native endian and the current ordering is definitely BE as interrupt "0" is in the last register.
Quoted 27 lines
Quoted 27 lines
drivers/irqchip/irq-bcm63168-l1.c new file +27
-0+#endif +} + +static inline unsigned int reg_status (struct bcm63168_l1_chip *intc, +unsigned int word) +{ +#ifdef __BIG_ENDIAN +return (2 * intc->n_words - word -1 ) *sizeof (u32); +#else +return (1 * intc->n_words + word) *sizeof (u32); +#endif +} + +static inline unsigned int cpu_for_irq (struct bcm63168_l1_chip *intc, +struct irq_data *d) +{ +return cpumask_first_and (&intc->cpumask,irq_data_get_affinity_mask (d)); +} + +static void bcm63168_l1_irq_handle (struct irq_desc *desc) +{ +struct bcm63168_l1_chip *intc =irq_desc_get_handler_data (desc); +struct bcm63168_l1_cpu *cpu; +struct irq_chip *chip =irq_desc_get_chip (desc); +unsigned int idx; + +#ifdef CONFIG_SMP
Quoted 8 lines
drivers/irqchip/irq-bcm63168-l1.c line 132
Quoted 4 lines
drivers/irqchip/irq-bcm63168-l1.c new file +4
-0+ cpu = intc->cpus[cpu_logical_map (smp_processor_id ())]; +#else + cpu = intc->cpus[0 ]; +#endif This looks expensive, can they change during runtime? If not, maybe just assign intc->cpus[] accordingly at probe time, so you can just do intc->cpus[smp_processor_id()] without any #ifdefs.
It's an array lookup in mips, so it becomes:
cpu = intc->cpus[__cpu_logical_map[smp_processor_id()]];
I could just remove the ifdef because smp_processor_id() becomes 0. It looks like it still does the array lookup.
The bcm7038-l1 driver had this ifdef.
Quoted 6 lines
Quoted 6 lines
drivers/irqchip/irq-bcm63168-l1.c new file +6
-0+ +chained_irq_enter (chip, desc); + +for (idx =0 ; idx < intc->n_words; idx++) { +int base = idx *IRQS_PER_WORD ; +unsigned long pending;
Quoted 8 lines
drivers/irqchip/irq-bcm63168-l1.c line 143
Quoted 5 lines
drivers/irqchip/irq-bcm63168-l1.c new file +5
-0+irq_hw_number_t hwirq; +unsigned int irq; + + pending =__raw_readl (cpu->map_base +reg_status (intc, idx)); + pending &=__raw_readl (cpu->map_base +reg_enable (intc, idx));Is it save to access the registers without any locking? 7038-l1 doesn't think so.
7038-l1 is using a lock because it's accessing its own copy of the enable mask. I read the controller's enable register to determine what is currently enabled.
When the enable mask is modified it uses intc->cpus[n]->enable_cache (with a lock held) and then writes it to the controller.
This way I don't need to have both CPUs compete with each other for the same lock within the interrupt handler itself.
Quoted 59 lines
Quoted 59 lines
drivers/irqchip/irq-bcm63168-l1.c new file +59
-0+ +for_each_set_bit (hwirq, &pending,IRQS_PER_WORD ) { + irq =irq_linear_revmap (intc->domain, base + hwirq); +if (irq) +do_IRQ (irq); +else +spurious_interrupt (); + } + } + +chained_irq_exit (chip, desc); +} + +static inline void __bcm63168_l1_unmask (struct irq_data *d) +{ +struct bcm63168_l1_chip *intc =irq_data_get_irq_chip_data (d); +u32 word = d->hwirq /IRQS_PER_WORD ; +u32 mask =BIT (d->hwirq %IRQS_PER_WORD ); +unsigned int cpu_idx =cpu_for_irq (intc, d); + + intc->cpus[cpu_idx]->enable_cache[word] |= mask; +__raw_writel (intc->cpus[cpu_idx]->enable_cache[word], + intc->cpus[cpu_idx]->map_base +reg_enable (intc, word)); +} + +static inline void __bcm63168_l1_mask (struct irq_data *d) +{ +struct bcm63168_l1_chip *intc =irq_data_get_irq_chip_data (d); +u32 word = d->hwirq /IRQS_PER_WORD ; +u32 mask =BIT (d->hwirq %IRQS_PER_WORD ); +unsigned int cpu_idx =cpu_for_irq (intc, d); + + intc->cpus[cpu_idx]->enable_cache[word] &= ~mask; +__raw_writel (intc->cpus[cpu_idx]->enable_cache[word], + intc->cpus[cpu_idx]->map_base +reg_enable (intc, word)); +} + +static void bcm63168_l1_unmask (struct irq_data *d) +{ +struct bcm63168_l1_chip *intc =irq_data_get_irq_chip_data (d); +u32 word = d->hwirq /IRQS_PER_WORD ; +unsigned long flags; + +raw_spin_lock_irqsave (&intc->lock[word], flags); +__bcm63168_l1_unmask (d); +raw_spin_unlock_irqrestore (&intc->lock[word], flags); +} + +static void bcm63168_l1_mask (struct irq_data *d) +{ +struct bcm63168_l1_chip *intc =irq_data_get_irq_chip_data (d); +u32 word = d->hwirq /IRQS_PER_WORD ; +unsigned long flags; + +raw_spin_lock_irqsave (&intc->lock[word], flags); +__bcm63168_l1_mask (d); +raw_spin_unlock_irqrestore (&intc->lock[word], flags); +} +
...
Quoted 9 lines
drivers/irqchip/irq-bcm63168-l1.c line 292
Quoted 7 lines
drivers/irqchip/irq-bcm63168-l1.c new file +7
-0+ +static struct irq_chip bcm63168_l1_irq_chip = { + .name ="bcm63168-l1" , + .irq_mask = bcm63168_l1_mask, + .irq_unmask = bcm63168_l1_unmask, + .irq_set_affinity = bcm63168_l1_set_affinity, +};You are already allocing memory, why not alloc this one as well?
The data is a const name and set of function pointers that is never modified.
Quoted 21 lines
Quoted 21 lines
drivers/irqchip/irq-bcm63168-l1.c new file +21
-0+ +static int bcm63168_l1_map (struct irq_domain *d,unsigned int virq, +irq_hw_number_t hw_irq) +{ +irq_set_chip_and_handler (virq, + &bcm63168_l1_irq_chip, handle_percpu_irq); +irq_set_chip_data (virq, d->host_data); +return 0 ; +} + +static const struct irq_domain_ops bcm63168_l1_domain_ops = { + .xlate = irq_domain_xlate_onecell, + .map = bcm63168_l1_map, +}; + +static int __init bcm63168_l1_of_init (struct device_node *dn, +struct device_node *parent) +{ +struct bcm63168_l1_chip *intc; +unsigned int idx; +int ret;
Quoted 8 lines
drivers/irqchip/irq-bcm63168-l1.c line 319
Quoted 6 lines
drivers/irqchip/irq-bcm63168-l1.c new file +6
-0+ + intc =kzalloc (sizeof (*intc),GFP_KERNEL ); +if (!intc) +return -ENOMEM ; + +cpumask_clear (&intc->cpumask);
intc->cpumaskis already cleared since kzalloc'd.
Ok.
Quoted 11 lines
Quoted 11 lines
drivers/irqchip/irq-bcm63168-l1.c new file +11
-0+ +for_each_possible_cpu (idx) { + ret =bcm63168_l1_init_one (dn, idx, intc); +if (ret) +pr_err ("failed to init intc L1 for cpu %d: %d\n" , + idx, ret); +else +cpumask_set_cpu (idx, &intc->cpumask); + } + +if (!cpumask_weight (&intc->cpumask)) {
Quoted 8 lines
drivers/irqchip/irq-bcm63168-l1.c line 336
Quoted 6 lines
drivers/irqchip/irq-bcm63168-l1.c new file +6
-0+ ret = -ENODEV ; + goto out_free; + } + +for (idx =0 ; idx < intc->n_words; idx++) +raw_spin_lock_init (&intc->lock[idx]);Do you really need a spinlock for each word?
No, this made more sense when I was using handle_level_irq and had interrupts going to both CPUs, but the controller is too eager to dispatch the same interrupt to both CPUs almost-simultaneously.
I'll change it to a single spinlock.
Quoted 42 lines
Quoted 37 lines
drivers/irqchip/irq-bcm63168-l1.c new file +36
-1+ + intc->domain =irq_domain_add_linear (dn,IRQS_PER_WORD * intc->n_words, + &bcm63168_l1_domain_ops, + intc); +if (!intc->domain) { + ret = -ENOMEM ; + goto out_unmap; + } + +pr_info ("registered BCM63168 L1 intc (IRQs: %d)\n" , +IRQS_PER_WORD * intc->n_words); +for_each_cpu (idx, &intc->cpumask) { +struct bcm63168_l1_cpu *cpu = intc->cpus[idx]; + +pr_info (" CPU%u at MMIO 0x%p (irq = %d)\n" , idx, + cpu->map_base, cpu->parent_irq); + } + +return 0 ; + +out_unmap: +for_each_possible_cpu (idx) { +struct bcm63168_l1_cpu *cpu = intc->cpus[idx]; + +if (cpu) { +if (cpu->map_base) +iounmap (cpu->map_base); +kfree (cpu); + } + } +out_free: +kfree (intc); +return ret; +} + +IRQCHIP_DECLARE (bcm63168_l1,"brcm,bcm63168-l1-intc" , bcm63168_l1_of_init); --Quoted 1 line
2.1.4
Jonas
Signature · 1 line
Simon Arlott
Hi,
Quoted 1 line · Simon Arlott
Add device tree binding for the BCM63168 interrupt controller.
Well, that's what I get for waiting for -rc1, I also planned to submit irqchip drivers[1] for bcm63xx/bmips for the next window ;p.
Quoted 16 lines
This controller is similar to the SMP-capable BCM7038 and the BCM3380 but with packed interrupt registers.
Signed-off-by Simon Arlott <[email protected]>--- .../interrupt-controller/brcm,bcm63168-l1-intc.txt | 57 ++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/brcm,bcm63168-l1-intc.txtDocumentation/devicetree/bindings/interrupt-controller/brcm,bcm63168-l1-intc.txt new file +0
-0
Documentation/devicetree/bindings/interrupt-controller/brcm,bcm63168-l1-intc.txt line 1
Quoted 1 line
Documentation/devicetree/bindings/interrupt-controller/brcm,bcm63168-l1-intc.txt new file +1
-0@@ -0,0 +1,57 @@ +Broadcom BCM63168-style Level 1 interrupt controller
Usually I would go by which SoC introduced it, and AFAICT tell BCM6358 was the first with per-CPU irq blocks, but since I don't see anything preventing it to be used with the older, single thread SoCs, the driver/binding would even support BCM6345's one.
Documentation/devicetree/bindings/interrupt-controller/brcm,bcm63168-l1-intc.txt line 8
Quoted 7 lines
Documentation/devicetree/bindings/interrupt-controller/brcm,bcm63168-l1-intc.txt new file +7
-0+ +This block is a first level interrupt controller that is typically connected +directly to one of the HW INT lines on each CPU. + +Key elements of the hardware design include: + +- 64 or 128 incoming level IRQ lines
Which, in this case, has 32 incoming IRQ lines.
Quoted 8 lines
Documentation/devicetree/bindings/interrupt-controller/brcm,bcm63168-l1-intc.txt new file +8
-0+ +- Most onchip peripherals are wired directly to an L1 input + +- A separate instance of the register set for each CPU, allowing individual + peripheral IRQs to be routed to any CPU + +- Contains one or more enable/status word pairs per CPU +
Documentation/devicetree/bindings/interrupt-controller/brcm,bcm63168-l1-intc.txt line 26
Quoted 10 lines
Documentation/devicetree/bindings/interrupt-controller/brcm,bcm63168-l1-intc.txt new file +10
-0+- No atomic set/clear operations + +- No polarity/level/edge settings + +- No FIFO or priority encoder logic; software is expected to read all + 2-4 status words to determine which IRQs are pending + +Required properties: + +- compatible: should be "brcm,bcm63168-l1-intc"
It's a bit strange using the newer chip name for older chips, so I suggest using brcm,bcm6345-l1-intc or brcm,bcm6358-l1-intc (I went with bcm6345-periph-intc, to avoid the l1/l2 discussion).
Also I'm not sure whether BCM63168 or BCM63268 is the right name for the family, as Broadcom seems to use the latter in their LDKs.
Furthermore, it's always good to specify that it should contain a brcm,bcm<soc>-l1-intc, in case one ever needs to tell them apart.
Quoted 11 lines
Documentation/devicetree/bindings/interrupt-controller/brcm,bcm63168-l1-intc.txt new file +11
-0+- reg: specifies the base physical address and size of the registers; + the number of supported IRQs is inferred from the size argument +- interrupt-controller: identifies the node as an interrupt controller +- #interrupt-cells: specifies the number of cells needed to encode an interrupt + source, should be 1. +- interrupt-parent: specifies the phandle to the parent interrupt controller(s) + this one is cascaded from +- interrupts: specifies the interrupt line(s) in the interrupt-parent controller + node; valid values depend on the type of parent interrupt controller + +If multiple reg ranges and interrupt-parent entries are present on an SMP
Documentation/devicetree/bindings/interrupt-controller/brcm,bcm63168-l1-intc.txt line 47
Quoted 10 lines
Documentation/devicetree/bindings/interrupt-controller/brcm,bcm63168-l1-intc.txt new file +10
-0+system, the driver will allow IRQ SMP affinity to be set up through the +/proc/irq/ interface. In the simplest possible configuration, only one +reg range and one interrupt-parent is needed. + +The driver operates in native CPU endian by default, there is no support for +specifying an alternative endianness. + +Example: + +periph_intc: periph_intc@10000000 {
interrupt-controller@10000020
Documentation/devicetree/bindings/interrupt-controller/brcm,bcm63168-l1-intc.txt line 57
Quoted 10 lines
Documentation/devicetree/bindings/interrupt-controller/brcm,bcm63168-l1-intc.txt new file +10
-0+ compatible = "brcm,bcm63168-l1-intc"; + reg = <0x10000020 0x20>, + <0x10000040 0x20>; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&cpu_intc>; + interrupts = <2>, <3>; +};
Regards
Jonas
Quoted 6 lines · Simon Arlott
Add device tree binding for the BCM63168 interrupt controller.
This controller is similar to the SMP-capable BCM7038 and the BCM3380 but with packed interrupt registers.
Signed-off-by Simon Arlott <[email protected]>
Quoted 73 lines
--- .../interrupt-controller/brcm,bcm63168-l1-intc.txt | 57 ++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/brcm,bcm63168-l1-intc.txtDocumentation/devicetree/bindings/interrupt-controller/brcm,bcm63168-l1-intc.txt new file +57
-0@@ -0,0 +1,57 @@ +Broadcom BCM63168-style Level 1 interrupt controller + +This block is a first level interrupt controller that is typically connected +directly to one of the HW INT lines on each CPU. + +Key elements of the hardware design include: + +- 64 or 128 incoming level IRQ lines + +- Most onchip peripherals are wired directly to an L1 input + +- A separate instance of the register set for each CPU, allowing individual + peripheral IRQs to be routed to any CPU + +- Contains one or more enable/status word pairs per CPU + +- No atomic set/clear operations + +- No polarity/level/edge settings + +- No FIFO or priority encoder logic; software is expected to read all + 2-4 status words to determine which IRQs are pending + +Required properties: + +- compatible: should be "brcm,bcm63168-l1-intc" +- reg: specifies the base physical address and size of the registers; + the number of supported IRQs is inferred from the size argument +- interrupt-controller: identifies the node as an interrupt controller +- #interrupt-cells: specifies the number of cells needed to encode an interrupt + source, should be 1. +- interrupt-parent: specifies the phandle to the parent interrupt controller(s) + this one is cascaded from +- interrupts: specifies the interrupt line(s) in the interrupt-parent controller + node; valid values depend on the type of parent interrupt controller + +If multiple reg ranges and interrupt-parent entries are present on an SMP +system, the driver will allow IRQ SMP affinity to be set up through the +/proc/irq/ interface. In the simplest possible configuration, only one +reg range and one interrupt-parent is needed. + +The driver operates in native CPU endian by default, there is no support for +specifying an alternative endianness. + +Example: + +periph_intc: periph_intc@10000000 { + compatible = "brcm,bcm63168-l1-intc"; + reg = <0x10000020 0x20>, + <0x10000040 0x20>; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&cpu_intc>; + interrupts = <2>, <3>; +};Signature · 4 lines
2.1.4 -- Simon Arlott
PATCH 1/2 irqchip: Add brcm,bcm6345-l1-intc device tree binding
Add device tree binding for the BCM6345 interrupt controller.
This controller is similar to the SMP-capable BCM7038 and the BCM3380 but with packed interrupt registers.
---
Quoted 9 lines · Rob Herring
Quoted 6 lines · Simon Arlott
Add device tree binding for the BCM63168 interrupt controller.
This controller is similar to the SMP-capable BCM7038 and the BCM3380 but with packed interrupt registers.
Signed-off-by Simon Arlott <[email protected]>Acked-by Rob Herring <[email protected]>
I'm going to rename this to bcm6345-l1 as suggested by Jonas Gorski, and the binding now specifies a <soc> version of the compatible name to be included.
.../interrupt-controller/brcm,bcm6345-l1-intc.txt | 57 ++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/brcm,bcm6345-l1-intc.txt
Documentation/devicetree/bindings/interrupt-controller/brcm,bcm6345-l1-intc.txt new file +57 -0
@@ -0,0 +1,57 @@ +Broadcom BCM6345-style Level 1 interrupt controller + +This block is a first level interrupt controller that is typically connected +directly to one of the HW INT lines on each CPU. + +Key elements of the hardware design include: + +- 32, 64 or 128 incoming level IRQ lines + +- Most onchip peripherals are wired directly to an L1 input + +- A separate instance of the register set for each CPU, allowing individual + peripheral IRQs to be routed to any CPU + +- Contains one or more enable/status word pairs per CPU + +- No atomic set/clear operations + +- No polarity/level/edge settings + +- No FIFO or priority encoder logic; software is expected to read all + 2-4 status words to determine which IRQs are pending + +Required properties: + +- compatible: should be "brcm,bcm<soc>-l1-intc", "brcm,bcm6345-l1-intc" +- reg: specifies the base physical address and size of the registers; + the number of supported IRQs is inferred from the size argument +- interrupt-controller: identifies the node as an interrupt controller +- #interrupt-cells: specifies the number of cells needed to encode an interrupt + source, should be 1. +- interrupt-parent: specifies the phandle to the parent interrupt controller(s) + this one is cascaded from +- interrupts: specifies the interrupt line(s) in the interrupt-parent controller + node; valid values depend on the type of parent interrupt controller + +If multiple reg ranges and interrupt-parent entries are present on an SMP +system, the driver will allow IRQ SMP affinity to be set up through the +/proc/irq/ interface. In the simplest possible configuration, only one +reg range and one interrupt-parent is needed. + +The driver operates in native CPU endian by default, there is no support for +specifying an alternative endianness. + +Example: + +periph_intc: periph_intc@10000000 { + compatible = "brcm,bcm63168-l1-intc", "brcm,bcm6345-l1-intc"; + reg = <0x10000020 0x20>, + <0x10000040 0x20>; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&cpu_intc>; + interrupts = <2>, <3>; +};
Signature · 8 lines
2.1.4 -- Simon Arlott -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/2] irqchip: Add brcm,bcm6345-l1-intc device tree binding
Quoted 14 lines · Simon Arlott
Add device tree binding for the BCM6345 interrupt controller.
This controller is similar to the SMP-capable BCM7038 and the BCM3380 but with packed interrupt registers.
Signed-off-by Simon Arlott <[email protected]>---
Quoted 6 lines · Rob Herring
Quoted 5 lines · Simon Arlott
Add device tree binding for the BCM63168 interrupt controller.
This controller is similar to the SMP-capable BCM7038 and the BCM3380 but with packed interrupt registers.
Quoted 7 lines
Quoted 3 lines
Quoted 1 line
Signed-off-by Simon Arlott <[email protected]>Acked-by Rob Herring <[email protected]>I'm going to rename this to bcm6345-l1 as suggested by Jonas Gorski, and the binding now specifies a <soc> version of the compatible name to be included.
Quoted 76 lines
.../interrupt-controller/brcm,bcm6345-l1-intc.txt | 57 ++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/brcm,bcm6345-l1-intc.txtDocumentation/devicetree/bindings/interrupt-controller/brcm,bcm6345-l1-intc.txt new file +57
-0@@ -0,0 +1,57 @@ +Broadcom BCM6345-style Level 1 interrupt controller + +This block is a first level interrupt controller that is typically connected +directly to one of the HW INT lines on each CPU. + +Key elements of the hardware design include: + +- 32, 64 or 128 incoming level IRQ lines + +- Most onchip peripherals are wired directly to an L1 input + +- A separate instance of the register set for each CPU, allowing individual + peripheral IRQs to be routed to any CPU + +- Contains one or more enable/status word pairs per CPU + +- No atomic set/clear operations + +- No polarity/level/edge settings + +- No FIFO or priority encoder logic; software is expected to read all + 2-4 status words to determine which IRQs are pending + +Required properties: + +- compatible: should be "brcm,bcm<soc>-l1-intc", "brcm,bcm6345-l1-intc" +- reg: specifies the base physical address and size of the registers; + the number of supported IRQs is inferred from the size argument +- interrupt-controller: identifies the node as an interrupt controller +- #interrupt-cells: specifies the number of cells needed to encode an interrupt + source, should be 1. +- interrupt-parent: specifies the phandle to the parent interrupt controller(s) + this one is cascaded from +- interrupts: specifies the interrupt line(s) in the interrupt-parent controller + node; valid values depend on the type of parent interrupt controller + +If multiple reg ranges and interrupt-parent entries are present on an SMP +system, the driver will allow IRQ SMP affinity to be set up through the +/proc/irq/ interface. In the simplest possible configuration, only one +reg range and one interrupt-parent is needed. + +The driver operates in native CPU endian by default, there is no support for +specifying an alternative endianness. + +Example: + +periph_intc: periph_intc@10000000 { + compatible = "brcm,bcm63168-l1-intc", "brcm,bcm6345-l1-intc"; + reg = <0x10000020 0x20>, + <0x10000040 0x20>; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&cpu_intc>; + interrupts = <2>, <3>; +};Signature · 8 lines
2.1.4 -- Simon Arlott -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 2/2 MIPS: bmips: Add bcm6345-l1 interrupt controller
In reply to Simon ArlottAdd the BCM6345 interrupt controller based on the SMP-capable BCM7038 and the BCM3380 but with packed interrupt registers.
Add the BCM6345 interrupt controller to a list with the existing BCM7038 so that interrupts on CPU1 are not ignored.
Update the maintainers file list for BMIPS to include this driver.
---
Renamed from bcm63168 to bcm6345.
Compared interrupt register word ordering with the bcm7038 driver which is LE and has the words in LE order, so using ordering that matches the CPU is appropriate.
Removed unnecessary cpumask memset.
Changed to use only one spinlock.
MAINTAINERS | 1 + arch/mips/Kconfig | 1 + arch/mips/bmips/irq.c | 10 +- drivers/irqchip/Kconfig | 5 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-bcm6345-l1.c | 366 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 382 insertions(+), 2 deletions(-) create mode 100644 drivers/irqchip/irq-bcm6345-l1.c
MAINTAINERS +1 -0
@@ -2373,6 +2373,7 @@ F: arch/mips/bmips/* F: arch/mips/include/asm/mach-bmips/* F: arch/mips/kernel/*bmips* F: arch/mips/boot/dts/brcm/bcm*.dts* +F: drivers/irqchip/irq-bcm63* F: drivers/irqchip/irq-bcm7* F: drivers/irqchip/irq-brcmstb*
arch/mips/Kconfig +1 -0
@@ -149,6 +149,7 @@ config BMIPS_GENERIC select CSRC_R4K select SYNC_R4K select COMMON_CLK + select BCM6345_L1_IRQ select BCM7038_L1_IRQ select BCM7120_L2_IRQ select BRCMSTB_L2_IRQ
arch/mips/bmips/irq.c +8 -2
@@ -15,6 +15,12 @@#include <asm/irq_cpu.h> #include <asm/time.h> +static const struct of_device_id smp_intc_dt_match[] = { + { .compatible ="brcm,bcm7038-l1-intc" }, + { .compatible ="brcm,bcm6345-l1-intc" }, + {} +}; +unsigned int get_c0_compare_int (void ) {return CP0_LEGACY_COMPARE_IRQ ;
@@ -24,8 +30,8 @@ void __init arch_init_irq(void) {struct device_node *dn; -/* Only the STB (bcm7038) controller supports SMP IRQ affinity */ - dn =of_find_compatible_node (NULL ,NULL ,"brcm,bcm7038-l1-intc" ); +/* Only these controllers support SMP IRQ affinity */ + dn =of_find_matching_node (NULL , smp_intc_dt_match);if (dn)of_node_put (dn);else
drivers/irqchip/Kconfig +5 -0
@@ -65,6 +65,11 @@ config I8259 bool select IRQ_DOMAIN +config BCM6345_L1_IRQ + bool + select GENERIC_IRQ_CHIP + select IRQ_DOMAIN + config BCM7038_L1_IRQ bool select GENERIC_IRQ_CHIP
drivers/irqchip/Makefile +1 -0
@@ -43,6 +43,7 @@ obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o obj-$(CONFIG_SOC_VF610) += irq-vf610-mscm-ir.o +obj-$(CONFIG_BCM6345_L1_IRQ) += irq-bcm6345-l1.o obj-$(CONFIG_BCM7038_L1_IRQ) += irq-bcm7038-l1.o obj-$(CONFIG_BCM7120_L2_IRQ) += irq-bcm7120-l2.o obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.o
drivers/irqchip/irq-bcm6345-l1.c new file +366 -0
366 lines not on this page · raw message
Signature · 4 lines
2.1.4 -- Simon Arlott
Re: [PATCH (v2) 2/2] MIPS: bmips: Add bcm6345-l1 interrupt controller
Add the BCM6345 interrupt controller based on the SMP-capable BCM7038 and the BCM3380 but with packed interrupt registers.
Add the BCM6345 interrupt controller to a list with the existing BCM7038 so that interrupts on CPU1 are not ignored.
Update the maintainers file list for BMIPS to include this driver.
---
Quoted 2 lines · Simon Arlott
Add the BCM6345 interrupt controller based on the SMP-capable BCM7038
drivers/irqchip/irq-bcm6345-l1.c | 366 +++++++++++++++++++++++++++++++++++++++
Removed unused variable "word" from bcm6345_l1_unmask/bcm6345_l1_mask.
MAINTAINERS | 1 + arch/mips/Kconfig | 1 + arch/mips/bmips/irq.c | 10 +- drivers/irqchip/Kconfig | 5 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-bcm6345-l1.c | 364 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 380 insertions(+), 2 deletions(-) create mode 100644 drivers/irqchip/irq-bcm6345-l1.c
MAINTAINERS +1 -0
@@ -2373,6 +2373,7 @@ F: arch/mips/bmips/* F: arch/mips/include/asm/mach-bmips/* F: arch/mips/kernel/*bmips* F: arch/mips/boot/dts/brcm/bcm*.dts* +F: drivers/irqchip/irq-bcm63* F: drivers/irqchip/irq-bcm7* F: drivers/irqchip/irq-brcmstb*
arch/mips/Kconfig +1 -0
@@ -149,6 +149,7 @@ config BMIPS_GENERIC select CSRC_R4K select SYNC_R4K select COMMON_CLK + select BCM6345_L1_IRQ select BCM7038_L1_IRQ select BCM7120_L2_IRQ select BRCMSTB_L2_IRQ
arch/mips/bmips/irq.c +8 -2
@@ -15,6 +15,12 @@#include <asm/irq_cpu.h> #include <asm/time.h> +static const struct of_device_id smp_intc_dt_match[] = { + { .compatible ="brcm,bcm7038-l1-intc" }, + { .compatible ="brcm,bcm6345-l1-intc" }, + {} +}; +unsigned int get_c0_compare_int (void ) {return CP0_LEGACY_COMPARE_IRQ ;
@@ -24,8 +30,8 @@ void __init arch_init_irq(void) {struct device_node *dn; -/* Only the STB (bcm7038) controller supports SMP IRQ affinity */ - dn =of_find_compatible_node (NULL ,NULL ,"brcm,bcm7038-l1-intc" ); +/* Only these controllers support SMP IRQ affinity */ + dn =of_find_matching_node (NULL , smp_intc_dt_match);if (dn)of_node_put (dn);else
drivers/irqchip/Kconfig +5 -0
@@ -65,6 +65,11 @@ config I8259 bool select IRQ_DOMAIN +config BCM6345_L1_IRQ + bool + select GENERIC_IRQ_CHIP + select IRQ_DOMAIN + config BCM7038_L1_IRQ bool select GENERIC_IRQ_CHIP
drivers/irqchip/Makefile +1 -0
@@ -43,6 +43,7 @@ obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o obj-$(CONFIG_SOC_VF610) += irq-vf610-mscm-ir.o +obj-$(CONFIG_BCM6345_L1_IRQ) += irq-bcm6345-l1.o obj-$(CONFIG_BCM7038_L1_IRQ) += irq-bcm7038-l1.o obj-$(CONFIG_BCM7120_L2_IRQ) += irq-bcm7120-l2.o obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.o
drivers/irqchip/irq-bcm6345-l1.c new file +364 -0
364 lines not on this page · raw message
Signature · 4 lines
2.1.4 -- Simon Arlott
tip-bot for Simon Arlott
merge bot[tip:irq/core] irqchips/bmips: Add bcm6345-l1 interrupt controller
irqchips/bmips: Add bcm6345-l1 interrupt controller
Commit-ID: 64e1741f92191a9d8c3949eff48a4670b440c9f8 Gitweb: http://git.kernel.org/tip/64e1741f92191a9d8c3949eff48a4670b440c9f8 Author: Simon Arlott <[email protected]> AuthorDate: Sun, 22 Nov 2015 14:30:14 +0000 Committer: Thomas Gleixner <[email protected]> CommitDate: Mon, 8 Feb 2016 11:45:21 +0100
irqchips/bmips: Add bcm6345-l1 interrupt controller
Add the BCM6345 interrupt controller based on the SMP-capable BCM7038 and the BCM3380 but with packed interrupt registers.
Add the BCM6345 interrupt controller to a list with the existing BCM7038 so that interrupts on CPU1 are not ignored.
Update the maintainers file list for BMIPS to include this driver.
--- MAINTAINERS | 1 + arch/mips/Kconfig | 1 + arch/mips/bmips/irq.c | 10 +- drivers/irqchip/Kconfig | 5 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-bcm6345-l1.c | 364 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 380 insertions(+), 2 deletions(-)
MAINTAINERS +1 -0
@@ -2423,6 +2423,7 @@ F: arch/mips/bmips/* F: arch/mips/include/asm/mach-bmips/* F: arch/mips/kernel/*bmips* F: arch/mips/boot/dts/brcm/bcm*.dts* +F: drivers/irqchip/irq-bcm63* F: drivers/irqchip/irq-bcm7* F: drivers/irqchip/irq-brcmstb* F: include/linux/bcm963xx_nvram.h
arch/mips/Kconfig +1 -0
@@ -151,6 +151,7 @@ config BMIPS_GENERIC select CSRC_R4K select SYNC_R4K select COMMON_CLK + select BCM6345_L1_IRQ select BCM7038_L1_IRQ select BCM7120_L2_IRQ select BRCMSTB_L2_IRQ
arch/mips/bmips/irq.c +8 -2
@@ -15,6 +15,12 @@#include <asm/irq_cpu.h> #include <asm/time.h> +static const struct of_device_id smp_intc_dt_match[] = { + { .compatible ="brcm,bcm7038-l1-intc" }, + { .compatible ="brcm,bcm6345-l1-intc" }, + {} +}; +unsigned int get_c0_compare_int (void ) {return CP0_LEGACY_COMPARE_IRQ ;
@@ -24,8 +30,8 @@ void __init arch_init_irq(void) {struct device_node *dn; -/* Only the STB (bcm7038) controller supports SMP IRQ affinity */ - dn =of_find_compatible_node (NULL ,NULL ,"brcm,bcm7038-l1-intc" ); +/* Only these controllers support SMP IRQ affinity */ + dn =of_find_matching_node (NULL , smp_intc_dt_match);if (dn)of_node_put (dn);else
drivers/irqchip/Kconfig +5 -0
@@ -78,6 +78,11 @@ config I8259 bool select IRQ_DOMAIN +config BCM6345_L1_IRQ + bool + select GENERIC_IRQ_CHIP + select IRQ_DOMAIN + config BCM7038_L1_IRQ bool select GENERIC_IRQ_CHIP
drivers/irqchip/Makefile +1 -0
@@ -46,6 +46,7 @@ obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o obj-$(CONFIG_SOC_VF610) += irq-vf610-mscm-ir.o +obj-$(CONFIG_BCM6345_L1_IRQ) += irq-bcm6345-l1.o obj-$(CONFIG_BCM7038_L1_IRQ) += irq-bcm7038-l1.o obj-$(CONFIG_BCM7120_L2_IRQ) += irq-bcm7120-l2.o obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.o
drivers/irqchip/irq-bcm6345-l1.c new file +364 -0
364 lines not on this page · raw message
tip-bot for Simon Arlott
merge bot[tip:irq/core] irqchips/bmips: Add bcm6345-l1 interrupt controller
In reply to Simon Arlottirqchips/bmips: Add bcm6345-l1 interrupt controller
Commit-ID: c7c42ec2baa1de7ab3965e4f1bf5073bee6065e4 Gitweb: http://git.kernel.org/tip/c7c42ec2baa1de7ab3965e4f1bf5073bee6065e4 Author: Simon Arlott <[email protected]> AuthorDate: Sun, 22 Nov 2015 14:30:14 +0000 Committer: Thomas Gleixner <[email protected]> CommitDate: Mon, 8 Feb 2016 15:03:42 +0100
irqchips/bmips: Add bcm6345-l1 interrupt controller
Add the BCM6345 interrupt controller based on the SMP-capable BCM7038 and the BCM3380 but with packed interrupt registers.
Add the BCM6345 interrupt controller to a list with the existing BCM7038 so that interrupts on CPU1 are not ignored.
Update the maintainers file list for BMIPS to include this driver.
--- MAINTAINERS | 1 + arch/mips/Kconfig | 1 + arch/mips/bmips/irq.c | 10 +- drivers/irqchip/Kconfig | 5 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-bcm6345-l1.c | 364 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 380 insertions(+), 2 deletions(-)
MAINTAINERS +1 -0
@@ -2423,6 +2423,7 @@ F: arch/mips/bmips/* F: arch/mips/include/asm/mach-bmips/* F: arch/mips/kernel/*bmips* F: arch/mips/boot/dts/brcm/bcm*.dts* +F: drivers/irqchip/irq-bcm63* F: drivers/irqchip/irq-bcm7* F: drivers/irqchip/irq-brcmstb* F: include/linux/bcm963xx_nvram.h
arch/mips/Kconfig +1 -0
@@ -151,6 +151,7 @@ config BMIPS_GENERIC select CSRC_R4K select SYNC_R4K select COMMON_CLK + select BCM6345_L1_IRQ select BCM7038_L1_IRQ select BCM7120_L2_IRQ select BRCMSTB_L2_IRQ
arch/mips/bmips/irq.c +8 -2
@@ -15,6 +15,12 @@#include <asm/irq_cpu.h> #include <asm/time.h> +static const struct of_device_id smp_intc_dt_match[] = { + { .compatible ="brcm,bcm7038-l1-intc" }, + { .compatible ="brcm,bcm6345-l1-intc" }, + {} +}; +unsigned int get_c0_compare_int (void ) {return CP0_LEGACY_COMPARE_IRQ ;
@@ -24,8 +30,8 @@ void __init arch_init_irq(void) {struct device_node *dn; -/* Only the STB (bcm7038) controller supports SMP IRQ affinity */ - dn =of_find_compatible_node (NULL ,NULL ,"brcm,bcm7038-l1-intc" ); +/* Only these controllers support SMP IRQ affinity */ + dn =of_find_matching_node (NULL , smp_intc_dt_match);if (dn)of_node_put (dn);else
drivers/irqchip/Kconfig +5 -0
@@ -78,6 +78,11 @@ config I8259 bool select IRQ_DOMAIN +config BCM6345_L1_IRQ + bool + select GENERIC_IRQ_CHIP + select IRQ_DOMAIN + config BCM7038_L1_IRQ bool select GENERIC_IRQ_CHIP
drivers/irqchip/Makefile +1 -0
@@ -46,6 +46,7 @@ obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o obj-$(CONFIG_SOC_VF610) += irq-vf610-mscm-ir.o +obj-$(CONFIG_BCM6345_L1_IRQ) += irq-bcm6345-l1.o obj-$(CONFIG_BCM7038_L1_IRQ) += irq-bcm7038-l1.o obj-$(CONFIG_BCM7120_L2_IRQ) += irq-bcm7120-l2.o obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.o
drivers/irqchip/irq-bcm6345-l1.c new file +364 -0
364 lines not on this page · raw message