RE: [PATCH] ARCv2: intc: Disable all core interrupts by default
Hi Vineet, > -Original Message- > From: Vineet Gupta [mailto:vgu...@synopsys.com] > Sent: Wednesday, February 08, 2017 7:08 PM > To: Yuriy Kolerov <yuriy.kole...@synopsys.com>; linux-snps- > a...@lists.infradead.org > Cc: alexey.brod...@synopsys.com; linux-ker...@vger.kernel.org; > marc.zyng...@arm.com > Subject: Re: [PATCH] ARCv2: intc: Disable all core interrupts by default > > On 02/07/2017 03:04 PM, Yuriy Kolerov wrote: > > The kernel emits a lot of warnings about unexpected IRQs when an > > appropriate driver is not presented. It happens because all interrupts > > in the core controller are enabled by default after reset. It would be > > wise to keep all interrupts masked by default. > > > > Thus disable all local and common interrupts. If CPU consists of only > > 1 core without IDU then it is necessary to disable all interrupts in > > the core interrupt controller. If CPU contains IDU it means that there > > are may be more than 1 cores and common interrupts (>= FIRST_EXT_IRQ) > > must be disabled in IDU. > > This is not elegant. core intc needs to do same thing to all interrupts coming > in > - irrespective of whether they are funneled via IDU or not. > > > > Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> > > --- > > arch/arc/kernel/intc-arcv2.c | 19 +++ > > [snip...] > > > + > > for (i = NR_EXCEPTIONS; i < irq_bcr.irqs + NR_EXCEPTIONS; i++) { > > write_aux_reg(AUX_IRQ_SELECT, i); > > write_aux_reg(AUX_IRQ_PRIORITY, ARCV2_IRQ_DEF_PRIO); > > + > > + /* > > +* If IDU exists then all common interrupts >= FIRST_EXT_IRQ > > +* are masked by IDU thus disable only local interrupts (below > > +* FIRST_EXT_IRQ). Otherwise disable all interrupts. > > +*/ > > + if (!mp.idu || i < FIRST_EXT_IRQ) > > + write_aux_reg(AUX_IRQ_ENABLE, 0); > > So you seem to assume that anything > FIRST_EXT_IRQ is coming in via IDU > which may not be case. > external Interrupts can be wired to core directly - not via IDU > - 16 .. 23 are cpu private reserved irq > - 24 .. C are common irqs (via IDU) > - C + 1 .. N are cpu private external irqs > > so better to disable all irq_bcr.irqs independent of how they are hooked up ! All IRQs >= 24 in ARC are marked as common interrupts and it is reasonable. It means that when "enable" or "mask" is called for hwirq < 24 then these functions are called on all cores. On the other hand these functions are called once only on 1 core for common interrupts. Then we have 3 cases: 1. We have UP and everything is easy. Just disable everything by default. When a driver comes up an appropriate IRQ is enable on single core. 2. We have SMP with IDU. We can enable/disable common interrupts in IDU and keep core interrupts enabled/unmasked by default. But what happens if a device is connected to one of the cores directly (is it even possible on SMP systems?)? Device Tree does not contain such information and the kernel does not know how it enable external IRQ for the specific core (as far as I know). 3. Assume that all core interrupts on all cores are disabled by default. When chained IRQ is created (IDU -> core intc) IDU automatically calls "enable" for an appropriate IRQ of core intc. But this "enable" is called only for 1 core so it is necessary to find a way to call "enable" on the rest of cores. I have a solution which solves this problem using "smp_call_function_single_async" in "enable" function of the core intc for IRQs >= 24 but I think that it may be overkill for such problem. Anyway I cannot find a solution for the same problem in other archs... > -Vineet ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[PATCH] ARCv2: intc: Disable all core interrupts by default
The kernel emits a lot of warnings about unexpected IRQs when an appropriate driver is not presented. It happens because all interrupts in the core controller are enabled by default after reset. It would be wise to keep all interrupts masked by default. Thus disable all local and common interrupts. If CPU consists of only 1 core without IDU then it is necessary to disable all interrupts in the core interrupt controller. If CPU contains IDU it means that there are may be more than 1 cores and common interrupts (>= FIRST_EXT_IRQ) must be disabled in IDU. Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- arch/arc/kernel/intc-arcv2.c | 19 +++ 1 file changed, 19 insertions(+) diff --git a/arch/arc/kernel/intc-arcv2.c b/arch/arc/kernel/intc-arcv2.c index f928795..ac84d09 100644 --- a/arch/arc/kernel/intc-arcv2.c +++ b/arch/arc/kernel/intc-arcv2.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #define NR_EXCEPTIONS 16 @@ -34,6 +35,7 @@ void arc_init_IRQ(void) { unsigned int tmp, irq_prio, i; struct bcr_irq_arcv2 irq_bcr; + struct mcip_bcr mp; struct aux_irq_ctrl { #ifdef CONFIG_CPU_BIG_ENDIAN @@ -75,10 +77,27 @@ void arc_init_IRQ(void) * Set a default priority for all available interrupts to prevent * switching of register banks if Fast IRQ and multiple register banks * are supported by CPU. +* +* Disable all local and common interrupts. If CPU consists of only 1 +* core without IDU then it is necessary to disable all interrupts +* in the core interrupt controller. If CPU contains IDU it means that +* there are may be more than 1 cores and common interrupts +* (>= FIRST_EXT_IRQ) must be disabled in IDU. */ + + READ_BCR(ARC_REG_MCIP_BCR, mp); + for (i = NR_EXCEPTIONS; i < irq_bcr.irqs + NR_EXCEPTIONS; i++) { write_aux_reg(AUX_IRQ_SELECT, i); write_aux_reg(AUX_IRQ_PRIORITY, ARCV2_IRQ_DEF_PRIO); + + /* +* If IDU exists then all common interrupts >= FIRST_EXT_IRQ +* are masked by IDU thus disable only local interrupts (below +* FIRST_EXT_IRQ). Otherwise disable all interrupts. +*/ + if (!mp.idu || i < FIRST_EXT_IRQ) + write_aux_reg(AUX_IRQ_ENABLE, 0); } /* setup status32, don't enable intr yet as kernel doesn't want */ -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[PATCH 0/2] Delete deprecated parameters in Device Trees
* Remove support of the second argument in IDU interrupts (it is deprecated and not used anymore). * Remove useless declaration of interrupts list in IDU intc because it is not used anymore and the kernel can obtain information about supported interrupts from build registers. * Some small clean ups. Yuriy Kolerov (2): ARCv2: IDU-intc: Delete deprecated parameters in Device Trees ARCv2: intc: Delete useless comments in Device Trees .../interrupt-controller/snps,archs-idu-intc.txt | 24 ++ arch/arc/boot/dts/axc003_idu.dtsi | 23 +++-- arch/arc/boot/dts/haps_hs_idu.dts | 11 ++ arch/arc/boot/dts/nsim_hs_idu.dts | 15 ++ arch/arc/boot/dts/nsimosci_hs_idu.dts | 21 --- arch/arc/boot/dts/vdk_axc003_idu.dtsi | 13 +++- arch/arc/kernel/mcip.c | 17 +-- 7 files changed, 21 insertions(+), 103 deletions(-) -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[PATCH 2/2] ARCv2: intc: Delete useless comments in Device Trees
Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- arch/arc/boot/dts/haps_hs_idu.dts | 1 - arch/arc/boot/dts/nsimosci_hs_idu.dts | 1 - 2 files changed, 2 deletions(-) diff --git a/arch/arc/boot/dts/haps_hs_idu.dts b/arch/arc/boot/dts/haps_hs_idu.dts index 0a857fa..215cddd 100644 --- a/arch/arc/boot/dts/haps_hs_idu.dts +++ b/arch/arc/boot/dts/haps_hs_idu.dts @@ -47,7 +47,6 @@ compatible = "snps,archs-intc"; interrupt-controller; #interrupt-cells = <1>; -/* interrupts = <16 17 18 19 20 21 22 23 24 25>; */ }; idu_intc: idu-interrupt-controller { diff --git a/arch/arc/boot/dts/nsimosci_hs_idu.dts b/arch/arc/boot/dts/nsimosci_hs_idu.dts index 37be2bb..5052917 100644 --- a/arch/arc/boot/dts/nsimosci_hs_idu.dts +++ b/arch/arc/boot/dts/nsimosci_hs_idu.dts @@ -43,7 +43,6 @@ compatible = "snps,archs-intc"; interrupt-controller; #interrupt-cells = <1>; -/* interrupts = <16 17 18 19 20 21 22 23 24 25>; */ }; idu_intc: idu-interrupt-controller { -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[PATCH 1/2] ARCv2: IDU-intc: Delete deprecated parameters in Device Trees
No need for specifying a list of interrupts in the declaration of IDU interrupt controller anymore since the kernel can obtain a number of supported interrupts from the build register. Also delete support of the second parameter for devices which are connected to IDU because it is not used anywhere. Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- .../interrupt-controller/snps,archs-idu-intc.txt | 24 ++ arch/arc/boot/dts/axc003_idu.dtsi | 23 +++-- arch/arc/boot/dts/haps_hs_idu.dts | 10 ++--- arch/arc/boot/dts/nsim_hs_idu.dts | 15 ++ arch/arc/boot/dts/nsimosci_hs_idu.dts | 20 -- arch/arc/boot/dts/vdk_axc003_idu.dtsi | 13 +++- arch/arc/kernel/mcip.c | 17 +-- 7 files changed, 21 insertions(+), 101 deletions(-) diff --git a/Documentation/devicetree/bindings/interrupt-controller/snps,archs-idu-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/snps,archs-idu-intc.txt index 9446576..8b46a34 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/snps,archs-idu-intc.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/snps,archs-idu-intc.txt @@ -8,15 +8,11 @@ Properties: - compatible: "snps,archs-idu-intc" - interrupt-controller: This is an interrupt controller. - interrupt-parent: -- #interrupt-cells: Must be <2>. -- interrupts: <...> specifies the upstream core irqs +- #interrupt-cells: Must be <1>. - First cell specifies the "common" IRQ from peripheral to IDU - Second cell specifies the irq distribution mode to cores - 0=Round Robin; 1=cpu0, 2=cpu1, 4=cpu2, 8=cpu3 - - The second cell in interrupts property is deprecated and may be ignored by - the kernel. + Value of the cell specifies the "common" IRQ from peripheral to IDU. Number N + of the particular interrupt line of IDU corresponds to the line N+24 of the + core interrupt controller. intc accessed via the special ARC AUX register interface, hence "reg" property is not specified. @@ -32,18 +28,10 @@ Example: compatible = "snps,archs-idu-intc"; interrupt-controller; interrupt-parent = <_intc>; - - /* -* -* distribution: 0=RR; 1=cpu0, 2=cpu1, 4=cpu2, 8=cpu3 -*/ - #interrupt-cells = <2>; - - /* upstream core irqs: downstream these are "COMMON" irq 0,1.. */ - interrupts = <24 25 26 27 28 29 30 31>; + #interrupt-cells = <1>; }; some_device: serial@c0fc1000 { interrupt-parent = <_intc>; - interrupts = <0 0>; /* upstream idu IRQ #24, Round Robin */ + interrupts = <0>; /* upstream idu IRQ #24 */ }; diff --git a/arch/arc/boot/dts/axc003_idu.dtsi b/arch/arc/boot/dts/axc003_idu.dtsi index 3d6cfa3..695f9fa 100644 --- a/arch/arc/boot/dts/axc003_idu.dtsi +++ b/arch/arc/boot/dts/axc003_idu.dtsi @@ -40,18 +40,7 @@ compatible = "snps,archs-idu-intc"; interrupt-controller; interrupt-parent = <_intc>; - - /* -* -* distribution: 0=RR; 1=cpu0, 2=cpu1, 4=cpu2, 8=cpu3 -*/ - #interrupt-cells = <2>; - - /* -* upstream irqs to core intc - downstream these are -* "COMMON" irq 0,1.. -*/ - interrupts = <24 25>; + #interrupt-cells = <1>; }; /* @@ -73,12 +62,7 @@ interrupt-controller; #interrupt-cells = <2>; interrupt-parent = <_intc>; - - /* -* cmn irq 1 -> cpu irq 25 -* Distribute to cpu0 only -*/ - interrupts = <1 1>; + interrupts = <1>; }; }; @@ -119,8 +103,7 @@ reg = < 0xe0012000 0x200 >; interrupt-controller; interrupt-parent = <_intc>; - interrupts = <0 1>; /* cmn irq 0 -> cpu irq 24 - distribute to cpu0 only */ + interrupts = <0>; }; memory { diff --git a/arch/arc/boot/dts/haps_hs_idu.dts
RE: [PATCH v2 4/4] ARCv2: IRQ: Set a default priority for all core interrupts
Hi Vineet, > -Original Message- > From: Vineet Gupta [mailto:vgu...@synopsys.com] > Sent: Tuesday, January 31, 2017 8:54 PM > To: Yuriy Kolerov <yuriy.kole...@synopsys.com>; linux-snps- > a...@lists.infradead.org > Cc: marc.zyng...@arm.com; alexey.brod...@synopsys.com; linux- > ker...@vger.kernel.org > Subject: Re: [PATCH v2 4/4] ARCv2: IRQ: Set a default priority for all core > interrupts > > On 01/31/2017 03:45 AM, Yuriy Kolerov wrote: > > After reset all interrupts in the core interrupt controller has the > > highest priority P0. If the platform supports Fast IRQs and has more > > than 1 banks of registers then CPU automatically switch banks of > > registers when P0 interrupt comes. > > > > The problem is that the kernel expects that by default switching of > > banks is not used by all interrupts. It is necessary to set a default > > nonzero priority for all available interrupts to avoid undefined > > behaviour. > > > > Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> > > --- > > arch/arc/kernel/intc-arcv2.c | 12 +++- > > 1 file changed, 11 insertions(+), 1 deletion(-) > > > > diff --git a/arch/arc/kernel/intc-arcv2.c > > b/arch/arc/kernel/intc-arcv2.c index 31246cc..d4fa4a5 100644 > > --- a/arch/arc/kernel/intc-arcv2.c > > +++ b/arch/arc/kernel/intc-arcv2.c > > @@ -22,7 +22,7 @@ > > */ > > void arc_init_IRQ(void) > > { > > - unsigned int tmp, irq_prio; > > + unsigned int tmp, irq_prio, i; > > > > struct bcr_irq_arcv2 irq_bcr; > > > > @@ -62,6 +62,16 @@ void arc_init_IRQ(void) > > irq_prio + 1, ARCV2_IRQ_DEF_PRIO, > > irq_bcr.firq ? " FIRQ (not used)":""); > > > > + /* > > +* Set a default priority for all available interrupts to prevent > > +* switching of register banks if Fast IRQ and multiple register banks > > +* are supported by CPU. > > +*/ > > + for (i = NR_EXCEPTIONS; i < irq_bcr.irqs + NR_EXCEPTIONS; i++) { > > + write_aux_reg(AUX_IRQ_SELECT, i); > > + write_aux_reg(AUX_IRQ_PRIORITY, ARCV2_IRQ_DEF_PRIO); > > + } > > + > > This itself is fine. However going forward can we move to the genirq > irq_cpu_online() etc instead of doing this in our platform per cpu hook ? > > https://www.linux-mips.org/archives/linux-mips/2011-03/msg00115.html We need to set a default priority for all interrupts for each CPU before interrupt controller is configured. In other words it this necessary to guaranty a default state of all interrupts before doing something else with interrupts. Moreover as I understand irq_cpu_online() is intended to be used with virtual IRQs (already allocated interrupts) but the configuration of priorities must be done for all hardware interrupts to bring CPU to the default state. > > /* setup status32, don't enable intr yet as kernel doesn't want */ > > tmp = read_aux_reg(ARC_REG_STATUS32); > > tmp |= STATUS_AD_MASK | (ARCV2_IRQ_DEF_PRIO << 1); > > ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[PATCH v2 4/4] ARCv2: IRQ: Set a default priority for all core interrupts
After reset all interrupts in the core interrupt controller has the highest priority P0. If the platform supports Fast IRQs and has more than 1 banks of registers then CPU automatically switch banks of registers when P0 interrupt comes. The problem is that the kernel expects that by default switching of banks is not used by all interrupts. It is necessary to set a default nonzero priority for all available interrupts to avoid undefined behaviour. Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- arch/arc/kernel/intc-arcv2.c | 12 +++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/arc/kernel/intc-arcv2.c b/arch/arc/kernel/intc-arcv2.c index 31246cc..d4fa4a5 100644 --- a/arch/arc/kernel/intc-arcv2.c +++ b/arch/arc/kernel/intc-arcv2.c @@ -22,7 +22,7 @@ */ void arc_init_IRQ(void) { - unsigned int tmp, irq_prio; + unsigned int tmp, irq_prio, i; struct bcr_irq_arcv2 irq_bcr; @@ -62,6 +62,16 @@ void arc_init_IRQ(void) irq_prio + 1, ARCV2_IRQ_DEF_PRIO, irq_bcr.firq ? " FIRQ (not used)":""); + /* +* Set a default priority for all available interrupts to prevent +* switching of register banks if Fast IRQ and multiple register banks +* are supported by CPU. +*/ + for (i = NR_EXCEPTIONS; i < irq_bcr.irqs + NR_EXCEPTIONS; i++) { + write_aux_reg(AUX_IRQ_SELECT, i); + write_aux_reg(AUX_IRQ_PRIORITY, ARCV2_IRQ_DEF_PRIO); + } + /* setup status32, don't enable intr yet as kernel doesn't want */ tmp = read_aux_reg(ARC_REG_STATUS32); tmp |= STATUS_AD_MASK | (ARCV2_IRQ_DEF_PRIO << 1); -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[PATCH v2 0/4] Use build registers for getting numbers of interrupts
A summary: * Use build registers for getting numbers of interrupts both for core interrupt controller and for IDU interrupt controller. * Set a default priority for all core interrupt to prevent unexpected switching of banks of registers. * Remove option for setting number of interrupts since it does not affect a number of interrupts in IRQ domains and breaks portability since it is impossible to change size of table of interrupts after linkage. Change in v2: * Squash some commits. * Do not move a structure for control register of core intc to the header since it is used only once. Yuriy Kolerov (4): ARCv2: IRQ: Move structure for build register of core intc to the header ARCv2: IRQ: Remove option for setting number of interrupts ARCv2: IRQ: Use build registers for getting numbers of interrupts ARCv2: IRQ: Set a default priority for all core interrupts arch/arc/Kconfig | 11 --- arch/arc/include/asm/arcregs.h | 11 +++ arch/arc/include/asm/irq.h | 32 +--- arch/arc/kernel/entry-arcv2.S | 3 ++- arch/arc/kernel/intc-arcv2.c | 31 --- arch/arc/kernel/mcip.c | 31 +++ include/soc/arc/mcip.h | 17 + 7 files changed, 98 insertions(+), 38 deletions(-) -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[PATCH v2 1/4] ARCv2: IRQ: Move structure for build register of core intc to the header
Also add new macro ARC_REG_STATUS32 for the address of STATUS32 auxiliary register. It is better to use it instead of magic numbers. Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- arch/arc/include/asm/arcregs.h | 11 +++ arch/arc/kernel/intc-arcv2.c | 10 ++ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/arch/arc/include/asm/arcregs.h b/arch/arc/include/asm/arcregs.h index f659942..2328244 100644 --- a/arch/arc/include/asm/arcregs.h +++ b/arch/arc/include/asm/arcregs.h @@ -38,6 +38,9 @@ #define ARC_REG_CLUSTER_BCR0xcf #define ARC_REG_AUX_ICCM 0x208 /* ICCM Base Addr (ARCv2) */ +/* Common for ARCompact and ARCv2 status register */ +#define ARC_REG_STATUS32 0x0A + /* status32 Bits Positions */ #define STATUS_AE_BIT 5 /* Exception active */ #define STATUS_DE_BIT 6 /* PC is in delay slot */ @@ -233,6 +236,14 @@ struct bcr_generic { #endif }; +struct bcr_irq_arcv2 { +#ifdef CONFIG_CPU_BIG_ENDIAN + unsigned int pad:3, firq:1, prio:4, exts:8, irqs:8, ver:8; +#else + unsigned int ver:8, irqs:8, exts:8, prio:4, firq:1, pad:3; +#endif +}; + /* *** * Generic structures to hold build configuration used at runtime diff --git a/arch/arc/kernel/intc-arcv2.c b/arch/arc/kernel/intc-arcv2.c index ecef0fb..9de0665 100644 --- a/arch/arc/kernel/intc-arcv2.c +++ b/arch/arc/kernel/intc-arcv2.c @@ -24,13 +24,7 @@ void arc_init_IRQ(void) { unsigned int tmp, irq_prio; - struct irq_build { -#ifdef CONFIG_CPU_BIG_ENDIAN - unsigned int pad:3, firq:1, prio:4, exts:8, irqs:8, ver:8; -#else - unsigned int ver:8, irqs:8, exts:8, prio:4, firq:1, pad:3; -#endif - } irq_bcr; + struct bcr_irq_arcv2 irq_bcr; struct aux_irq_ctrl { #ifdef CONFIG_CPU_BIG_ENDIAN @@ -69,7 +63,7 @@ void arc_init_IRQ(void) irq_bcr.firq ? " FIRQ (not used)":""); /* setup status32, don't enable intr yet as kernel doesn't want */ - tmp = read_aux_reg(0xa); + tmp = read_aux_reg(ARC_REG_STATUS32); tmp |= STATUS_AD_MASK | (ARCV2_IRQ_DEF_PRIO << 1); tmp &= ~STATUS_IE_MASK; asm volatile("kflag %0 \n"::"r"(tmp)); -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[PATCH v2 3/4] ARCv2: IRQ: Use build registers for getting numbers of interrupts
This enhancement allows to mask all available common interrupts in IDU interrupt controller in boot time since the kernel can discover a number of them from the build register. Also now there is no need to specify in device tree a list of used core interrupts by IDU. E.g. before: idu_intc: idu-interrupt-controller { compatible = "snps,archs-idu-intc"; interrupt-controller; interrupt-parent = <_intc>; #interrupt-cells = <2>; interrupts = <24 25 26 27 28 29 30 31>; }; and after: idu_intc: idu-interrupt-controller { compatible = "snps,archs-idu-intc"; interrupt-controller; interrupt-parent = <_intc>; #interrupt-cells = <2>; }; Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- arch/arc/include/asm/irq.h | 4 arch/arc/kernel/intc-arcv2.c | 9 +++-- arch/arc/kernel/mcip.c | 31 +++ include/soc/arc/mcip.h | 17 + 4 files changed, 47 insertions(+), 14 deletions(-) diff --git a/arch/arc/include/asm/irq.h b/arch/arc/include/asm/irq.h index d28499a..1970d78c 100644 --- a/arch/arc/include/asm/irq.h +++ b/arch/arc/include/asm/irq.h @@ -18,6 +18,9 @@ */ #define NR_CPU_IRQS240 +/* A fixed number of exceptions which occupy first interrupt lines */ +#define NR_EXCEPTIONS 16 + /* * ARCv2 can support 240 interrupts in the core interrupts controllers and * 128 interrupts in IDU. Thus 512 virtual IRQs must be enough for most @@ -28,6 +31,7 @@ /* Platform Independent IRQs */ #define IPI_IRQ19 #define SOFTIRQ_IRQ21 +#define FIRST_EXT_IRQ 24 #else diff --git a/arch/arc/kernel/intc-arcv2.c b/arch/arc/kernel/intc-arcv2.c index 9de0665..31246cc 100644 --- a/arch/arc/kernel/intc-arcv2.c +++ b/arch/arc/kernel/intc-arcv2.c @@ -109,7 +109,7 @@ static int arcv2_irq_map(struct irq_domain *d, unsigned int irq, * core intc IRQs [16, 23]: * Statically assigned always private-per-core (Timers, WDT, IPI, PCT) */ - if (hw < 24) { + if (hw < FIRST_EXT_IRQ) { /* * A subsequent request_percpu_irq() fails if percpu_devid is * not set. That in turns sets NOAUTOEN, meaning each core needs @@ -134,11 +134,16 @@ static int __init init_onchip_IRQ(struct device_node *intc, struct device_node *parent) { struct irq_domain *root_domain; + struct bcr_irq_arcv2 irq_bcr; + unsigned int nr_cpu_irqs; + + READ_BCR(ARC_REG_IRQ_BCR, irq_bcr); + nr_cpu_irqs = irq_bcr.irqs + NR_EXCEPTIONS; if (parent) panic("DeviceTree incore intc not a root irq controller\n"); - root_domain = irq_domain_add_linear(intc, NR_CPU_IRQS, _irq_ops, NULL); + root_domain = irq_domain_add_linear(intc, nr_cpu_irqs, _irq_ops, NULL); if (!root_domain) panic("root irq domain not avail\n"); diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index 9988b42..45d45fc 100644 --- a/arch/arc/kernel/mcip.c +++ b/arch/arc/kernel/mcip.c @@ -157,15 +157,20 @@ static void idu_set_mode(unsigned int cmn_irq, unsigned int lvl, __mcip_cmd_data(CMD_IDU_SET_MODE, cmn_irq, data.word); } -static void idu_irq_mask(struct irq_data *data) +static void idu_irq_mask_raw(irq_hw_number_t hwirq) { unsigned long flags; raw_spin_lock_irqsave(_lock, flags); - __mcip_cmd_data(CMD_IDU_SET_MASK, data->hwirq, 1); + __mcip_cmd_data(CMD_IDU_SET_MASK, hwirq, 1); raw_spin_unlock_irqrestore(_lock, flags); } +static void idu_irq_mask(struct irq_data *data) +{ + idu_irq_mask_raw(data->hwirq); +} + static void idu_irq_unmask(struct irq_data *data) { unsigned long flags; @@ -231,14 +236,12 @@ static struct irq_chip idu_irq_chip = { }; -static irq_hw_number_t idu_first_hwirq; - static void idu_cascade_isr(struct irq_desc *desc) { struct irq_domain *idu_domain = irq_desc_get_handler_data(desc); struct irq_chip *core_chip = irq_desc_get_chip(desc); irq_hw_number_t core_hwirq = irqd_to_hwirq(irq_desc_get_irq_data(desc)); - irq_hw_number_t idu_hwirq = core_hwirq - idu_first_hwirq; + irq_hw_number_t idu_hwirq = core_hwirq - FIRST_EXT_IRQ; chained_irq_enter(core_chip, desc); generic_handle_irq(irq_find_mapping(idu_domain, idu_hwirq)); @@ -284,33 +287,37 @@ static int __init idu_of_init(struct device_node *intc, struct device_node *parent) { struct irq_domain *domain; - /* Read IDU BCR to confirm nr_irqs */ - int nr_irqs = of_irq_count(intc); + int nr_irqs; int i, virq; struct mcip_bcr mp; + struct mcip_idu_bcr idu_bcr; READ_BCR(ARC_REG_MCIP_BCR, mp); if (!mp.idu) panic("IDU not detected, but DeviceTree using it"
[PATCH 5/6] ARCv2: IRQ: Use build registers for getting numbers of interrupts
This enhancement allows to mask all available common interrupts in IDU interrupt controller in boot time since the kernel can discover a number of them from the build register. Also now there is no need to specify in device tree a list of used core interrupts by IDU. E.g. before: idu_intc: idu-interrupt-controller { compatible = "snps,archs-idu-intc"; interrupt-controller; interrupt-parent = <_intc>; #interrupt-cells = <2>; interrupts = <24 25 26 27 28 29 30 31>; }; and after: idu_intc: idu-interrupt-controller { compatible = "snps,archs-idu-intc"; interrupt-controller; interrupt-parent = <_intc>; #interrupt-cells = <2>; }; Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- arch/arc/include/asm/irq.h | 3 +++ arch/arc/kernel/intc-arcv2.c | 7 ++- arch/arc/kernel/mcip.c | 31 +++ 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/arch/arc/include/asm/irq.h b/arch/arc/include/asm/irq.h index dfa09e3..1970d78c 100644 --- a/arch/arc/include/asm/irq.h +++ b/arch/arc/include/asm/irq.h @@ -18,6 +18,9 @@ */ #define NR_CPU_IRQS240 +/* A fixed number of exceptions which occupy first interrupt lines */ +#define NR_EXCEPTIONS 16 + /* * ARCv2 can support 240 interrupts in the core interrupts controllers and * 128 interrupts in IDU. Thus 512 virtual IRQs must be enough for most diff --git a/arch/arc/kernel/intc-arcv2.c b/arch/arc/kernel/intc-arcv2.c index a9a7497..b2a6de4 100644 --- a/arch/arc/kernel/intc-arcv2.c +++ b/arch/arc/kernel/intc-arcv2.c @@ -123,11 +123,16 @@ static int __init init_onchip_IRQ(struct device_node *intc, struct device_node *parent) { struct irq_domain *root_domain; + struct bcr_irq_arcv2 irq_bcr; + unsigned int nr_cpu_irqs; + + READ_BCR(ARC_REG_IRQ_BCR, irq_bcr); + nr_cpu_irqs = irq_bcr.irqs + NR_EXCEPTIONS; if (parent) panic("DeviceTree incore intc not a root irq controller\n"); - root_domain = irq_domain_add_linear(intc, NR_CPU_IRQS, _irq_ops, NULL); + root_domain = irq_domain_add_linear(intc, nr_cpu_irqs, _irq_ops, NULL); if (!root_domain) panic("root irq domain not avail\n"); diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index 9988b42..45d45fc 100644 --- a/arch/arc/kernel/mcip.c +++ b/arch/arc/kernel/mcip.c @@ -157,15 +157,20 @@ static void idu_set_mode(unsigned int cmn_irq, unsigned int lvl, __mcip_cmd_data(CMD_IDU_SET_MODE, cmn_irq, data.word); } -static void idu_irq_mask(struct irq_data *data) +static void idu_irq_mask_raw(irq_hw_number_t hwirq) { unsigned long flags; raw_spin_lock_irqsave(_lock, flags); - __mcip_cmd_data(CMD_IDU_SET_MASK, data->hwirq, 1); + __mcip_cmd_data(CMD_IDU_SET_MASK, hwirq, 1); raw_spin_unlock_irqrestore(_lock, flags); } +static void idu_irq_mask(struct irq_data *data) +{ + idu_irq_mask_raw(data->hwirq); +} + static void idu_irq_unmask(struct irq_data *data) { unsigned long flags; @@ -231,14 +236,12 @@ static struct irq_chip idu_irq_chip = { }; -static irq_hw_number_t idu_first_hwirq; - static void idu_cascade_isr(struct irq_desc *desc) { struct irq_domain *idu_domain = irq_desc_get_handler_data(desc); struct irq_chip *core_chip = irq_desc_get_chip(desc); irq_hw_number_t core_hwirq = irqd_to_hwirq(irq_desc_get_irq_data(desc)); - irq_hw_number_t idu_hwirq = core_hwirq - idu_first_hwirq; + irq_hw_number_t idu_hwirq = core_hwirq - FIRST_EXT_IRQ; chained_irq_enter(core_chip, desc); generic_handle_irq(irq_find_mapping(idu_domain, idu_hwirq)); @@ -284,33 +287,37 @@ static int __init idu_of_init(struct device_node *intc, struct device_node *parent) { struct irq_domain *domain; - /* Read IDU BCR to confirm nr_irqs */ - int nr_irqs = of_irq_count(intc); + int nr_irqs; int i, virq; struct mcip_bcr mp; + struct mcip_idu_bcr idu_bcr; READ_BCR(ARC_REG_MCIP_BCR, mp); if (!mp.idu) panic("IDU not detected, but DeviceTree using it"); - pr_info("MCIP: IDU referenced from Devicetree %d irqs\n", nr_irqs); + READ_BCR(ARC_REG_MCIP_IDU_BCR, idu_bcr); + nr_irqs = mcip_idu_bcr_to_nr_irqs(idu_bcr); + + pr_info("MCIP: IDU supports %u common irqs\n", nr_irqs); domain = irq_domain_add_linear(intc, nr_irqs, _irq_ops, NULL); /* Parent interrupts (core-intc) are already mapped */ for (i = 0; i < nr_irqs; i++) { + /* Mask all common interrupts by default */ + idu_irq_mask_raw(i); + /* * Return parent uplink IRQs (towards core intc) 24,25,. * this
[PATCH 6/6] ARCv2: IRQ: Set a default priority for all core interrupts
After reset all interrupts in the core interrupt controller has the highest priority P0. If the platform supports Fast IRQs and has more than 1 banks of registers then CPU automatically switch banks of registers when P0 interrupt comes. The problem is that the kernel expects that by default switching of banks is not used by all interrupts. It is necessary to set a default nonzero priority for all available interrupts to avoid undefined behaviour. Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- arch/arc/kernel/intc-arcv2.c | 12 +++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/arc/kernel/intc-arcv2.c b/arch/arc/kernel/intc-arcv2.c index b2a6de4..b9d9ce6 100644 --- a/arch/arc/kernel/intc-arcv2.c +++ b/arch/arc/kernel/intc-arcv2.c @@ -22,7 +22,7 @@ */ void arc_init_IRQ(void) { - unsigned int tmp, irq_prio; + unsigned int tmp, irq_prio, i; struct bcr_irq_arcv2 irq_bcr; struct aux_irq_ctrl_arcv2 ictrl; @@ -51,6 +51,16 @@ void arc_init_IRQ(void) irq_prio + 1, ARCV2_IRQ_DEF_PRIO, irq_bcr.firq ? " FIRQ (not used)":""); + /* +* Set a default priority for all available interrupts to prevent +* switching of register banks if Fast IRQ and multiple register banks +* are supported by CPU. +*/ + for (i = NR_EXCEPTIONS; i < irq_bcr.irqs + NR_EXCEPTIONS; i++) { + write_aux_reg(AUX_IRQ_SELECT, i); + write_aux_reg(AUX_IRQ_PRIORITY, ARCV2_IRQ_DEF_PRIO); + } + /* setup status32, don't enable intr yet as kernel doesn't want */ tmp = read_aux_reg(ARC_REG_STATUS32); tmp |= STATUS_AD_MASK | (ARCV2_IRQ_DEF_PRIO << 1); -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[PATCH 3/6] ARCv2: IRQ: Add macro for the first external interrupt number
Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- arch/arc/include/asm/irq.h | 1 + arch/arc/kernel/intc-arcv2.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arc/include/asm/irq.h b/arch/arc/include/asm/irq.h index c0fa0d2..e61ad30 100644 --- a/arch/arc/include/asm/irq.h +++ b/arch/arc/include/asm/irq.h @@ -16,6 +16,7 @@ #ifdef CONFIG_ISA_ARCV2 #define IPI_IRQ19 #define SOFTIRQ_IRQ21 +#define FIRST_EXT_IRQ 24 #endif #include diff --git a/arch/arc/kernel/intc-arcv2.c b/arch/arc/kernel/intc-arcv2.c index 2f31bb1..a9a7497 100644 --- a/arch/arc/kernel/intc-arcv2.c +++ b/arch/arc/kernel/intc-arcv2.c @@ -98,7 +98,7 @@ static int arcv2_irq_map(struct irq_domain *d, unsigned int irq, * core intc IRQs [16, 23]: * Statically assigned always private-per-core (Timers, WDT, IPI, PCT) */ - if (hw < 24) { + if (hw < FIRST_EXT_IRQ) { /* * A subsequent request_percpu_irq() fails if percpu_devid is * not set. That in turns sets NOAUTOEN, meaning each core needs -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[PATCH 2/6] ARCv2: MCIP: Add structure for build register of IDU
This structure is necessary for retrieving of supported number of common interrupts in IDU interrupt controller. Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- include/soc/arc/mcip.h | 17 + 1 file changed, 17 insertions(+) diff --git a/include/soc/arc/mcip.h b/include/soc/arc/mcip.h index 6902c2a..798c01b 100644 --- a/include/soc/arc/mcip.h +++ b/include/soc/arc/mcip.h @@ -14,6 +14,7 @@ #include #define ARC_REG_MCIP_BCR 0x0d0 +#define ARC_REG_MCIP_IDU_BCR 0x0D5 #define ARC_REG_MCIP_CMD 0x600 #define ARC_REG_MCIP_WDATA 0x601 #define ARC_REG_MCIP_READBACK 0x602 @@ -69,6 +70,22 @@ struct mcip_bcr { #endif }; +struct mcip_idu_bcr { +#ifdef CONFIG_CPU_BIG_ENDIAN + unsigned int pad:21, cirqnum:3, ver:8; +#else + unsigned int ver:8, cirqnum:3, pad:21; +#endif +}; + + +/* + * Build register for IDU contains not an actual number of supported common + * interrupts but an exponent of 2 which must be multiplied by 4 to + * get a number of supported common interrupts. + */ +#define mcip_idu_bcr_to_nr_irqs(bcr) (4 * (1 << (bcr).cirqnum)) + /* * MCIP programming model * -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[PATCH 4/6] ARCv2: IRQ: Remove option for setting number of interrupts
When you set a value of ARC_NUMBER_OF_INTERRUPTS option it affects only a size of the interrupts table but macros for number of virtual interrupts (NR_IRQS) and for number of hardware interrupts (NR_CPU_IRQS) remain unchanged. Moreover usage of ARC_NUMBER_OF_INTERRUPTS is bad for portability since it is not possible to change size of the interrupts table after linkage. This patch makes these changes in IRQ subsystem: * NR_CPU_IRQS defines a maximum number of hardware interrupts. * Remove ARC_NUMBER_OF_INTERRUPTS option and create interrupts table for all possible hardware interrupts. * Increase a maximum number of virtual IRQs to 512. ARCv2 can support 240 interrupts in the core interrupts controllers and 128 interrupts in IDU. Thus 512 virtual IRQs must be enough for most configurations of boards. Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- arch/arc/Kconfig | 11 --- arch/arc/include/asm/irq.h| 28 +--- arch/arc/kernel/entry-arcv2.S | 3 ++- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index 283099c..ba15cb8 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -412,17 +412,6 @@ config ARC_HAS_DIV_REM bool "Insn: div, divu, rem, remu" default y -config ARC_NUMBER_OF_INTERRUPTS - int "Number of interrupts" - range 8 240 - default 32 - help - This defines the number of interrupts on the ARCv2HS core. - It affects the size of vector table. - The initial 8 IRQs are fixed (Timer, ICI etc) and although configurable - in hardware, it keep things simple for Linux to assume they are always - present. - endif # ISA_ARCV2 endmenu # "ARC CPU Configuration" diff --git a/arch/arc/include/asm/irq.h b/arch/arc/include/asm/irq.h index e61ad30..dfa09e3 100644 --- a/arch/arc/include/asm/irq.h +++ b/arch/arc/include/asm/irq.h @@ -9,19 +9,41 @@ #ifndef __ASM_ARC_IRQ_H #define __ASM_ARC_IRQ_H -#define NR_CPU_IRQS32 /* number of interrupt lines of ARC770 CPU */ -#define NR_IRQS128 /* allow some CPU external IRQ handling */ +#ifdef CONFIG_ISA_ARCV2 + +/* + * A maximum number of supported interrupts in the core interrupt controller. + * This number is not equal to the maximum interrupt number (256) because + * first 16 lines are reserved for exceptions and are not configurable. + */ +#define NR_CPU_IRQS240 + +/* + * ARCv2 can support 240 interrupts in the core interrupts controllers and + * 128 interrupts in IDU. Thus 512 virtual IRQs must be enough for most + * configurations of boards. + */ +#define NR_IRQS512 /* Platform Independent IRQs */ -#ifdef CONFIG_ISA_ARCV2 #define IPI_IRQ19 #define SOFTIRQ_IRQ21 #define FIRST_EXT_IRQ 24 + +#else + +#define NR_CPU_IRQS32 /* number of interrupt lines of ARC770 CPU */ +#define NR_IRQS128 /* allow some CPU external IRQ handling */ + #endif +#ifndef __ASSEMBLY__ + #include #include extern void arc_init_IRQ(void); #endif + +#endif diff --git a/arch/arc/kernel/entry-arcv2.S b/arch/arc/kernel/entry-arcv2.S index 0b6388a..f22101e 100644 --- a/arch/arc/kernel/entry-arcv2.S +++ b/arch/arc/kernel/entry-arcv2.S @@ -13,6 +13,7 @@ #include #include #include +#include .cpu HS @@ -52,7 +53,7 @@ VECTORhandle_interrupt; unused VECTOR handle_interrupt; (23) unused # End of fixed IRQs -.rept CONFIG_ARC_NUMBER_OF_INTERRUPTS - 8 +.rept NR_CPU_IRQS - 8 VECTOR handle_interrupt .endr -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
RE: [PATCH v3 3/3] ARCv2: MCIP: Deprecate setting of affinity in Device Tree
> -Original Message- > From: Vineet Gupta [mailto:vgu...@synopsys.com] > Sent: Tuesday, January 03, 2017 9:11 PM > To: Yuriy Kolerov <yuriy.kole...@synopsys.com>; linux-snps- > a...@lists.infradead.org > Cc: alexey.brod...@synopsys.com; linux-ker...@vger.kernel.org; > marc.zyng...@arm.com > Subject: Re: [PATCH v3 3/3] ARCv2: MCIP: Deprecate setting of affinity in > Device Tree > > On 12/28/2016 12:47 AM, Yuriy Kolerov wrote: > > Ignore value of interrupt distribution mode for common interrupts in > > IDU since setting of affinity using value from Device Tree is > > deprecated in ARC. Originally it is done in idu_irq_xlate() function > > and it is semantically wrong and does not guaranty that an affinity > > value will be set properly. idu_irq_enable() function is better place > > for initialization of common interrupts. > > > > By default send all common interrupts to all available online CPUs. > > Is this a departure from our original idea to route everything only to boot > cpu > ? > Otherwise this looks OK to me ! I have come to the conclusion that now there is no way to route all interrupts to the boot CPU in a right manner. It may be implemented properly in the future. > -Vineet > > > The affinity of common interrupts in IDU must be set manually since in > > some cases the kernel will not call irq_set_affinity() by itself: > > > > 1. When the kernel is not configured with support of SMP. > > 2. When the kernel is configured with support of SMP but upper > > interrupt controllers does not support setting of the affinity > > and cannot propagate it to IDU. > > > > Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> > > --- > > .../interrupt-controller/snps,archs-idu-intc.txt | 3 ++ > > arch/arc/kernel/mcip.c | 52 > > +- > > 2 files changed, 25 insertions(+), 30 deletions(-) > > > > diff --git > > a/Documentation/devicetree/bindings/interrupt-controller/snps,archs-id > > u-intc.txt > > b/Documentation/devicetree/bindings/interrupt-controller/snps,archs-id > > u-intc.txt > > index 0dcb7c7..9446576 100644 > > --- > > a/Documentation/devicetree/bindings/interrupt-controller/snps,archs-id > > u-intc.txt > > +++ b/Documentation/devicetree/bindings/interrupt-controller/snps,arch > > +++ s-idu-intc.txt > > @@ -15,6 +15,9 @@ Properties: > >Second cell specifies the irq distribution mode to cores > > 0=Round Robin; 1=cpu0, 2=cpu1, 4=cpu2, 8=cpu3 > > > > + The second cell in interrupts property is deprecated and may be > > + ignored by the kernel. > > + > >intc accessed via the special ARC AUX register interface, hence "reg" > property > >is not specified. > > > > diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index > > be131b2..d492a3c 100644 > > --- a/arch/arc/kernel/mcip.c > > +++ b/arch/arc/kernel/mcip.c > > @@ -175,7 +175,6 @@ static void idu_irq_unmask(struct irq_data *data) > > raw_spin_unlock_irqrestore(_lock, flags); } > > > > -#ifdef CONFIG_SMP > > static int > > idu_irq_set_affinity(struct irq_data *data, const struct cpumask > *cpumask, > > bool force) > > @@ -205,12 +204,27 @@ idu_irq_set_affinity(struct irq_data *data, > > const struct cpumask *cpumask, > > > > return IRQ_SET_MASK_OK; > > } > > -#endif > > + > > +static void idu_irq_enable(struct irq_data *data) { > > + /* > > +* By default send all common interrupts to all available online CPUs. > > +* The affinity of common interrupts in IDU must be set manually > since > > +* in some cases the kernel will not call irq_set_affinity() by itself: > > +* 1. When the kernel is not configured with support of SMP. > > +* 2. When the kernel is configured with support of SMP but upper > > +* interrupt controllers does not support setting of the affinity > > +* and cannot propagate it to IDU. > > +*/ > > + idu_irq_set_affinity(data, cpu_online_mask, false); > > + idu_irq_unmask(data); > > +} > > > > static struct irq_chip idu_irq_chip = { > > .name = "MCIP IDU Intc", > > .irq_mask = idu_irq_mask, > > .irq_unmask = idu_irq_unmask, > > + .irq_enable = idu_irq_enable, > > #ifdef CONFIG_SMP > > .irq_set_affinity = idu_irq_set_affinity, > > #endif > > @@ -243,36 +257,14 @@ static
[PATCH v3 1/3] ARC: IRQ: Use hwirq instead of virq in mask/unmask
It is necessary to use hwirq instead of virq when you communicate with an interrupt controller since there is no guaranty that virq numbers match hwirq numbers. Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- arch/arc/kernel/intc-arcv2.c | 6 +++--- arch/arc/kernel/intc-compact.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arc/kernel/intc-arcv2.c b/arch/arc/kernel/intc-arcv2.c index 62b59409..fa171e1 100644 --- a/arch/arc/kernel/intc-arcv2.c +++ b/arch/arc/kernel/intc-arcv2.c @@ -79,20 +79,20 @@ void arc_init_IRQ(void) static void arcv2_irq_mask(struct irq_data *data) { - write_aux_reg(AUX_IRQ_SELECT, data->irq); + write_aux_reg(AUX_IRQ_SELECT, data->hwirq); write_aux_reg(AUX_IRQ_ENABLE, 0); } static void arcv2_irq_unmask(struct irq_data *data) { - write_aux_reg(AUX_IRQ_SELECT, data->irq); + write_aux_reg(AUX_IRQ_SELECT, data->hwirq); write_aux_reg(AUX_IRQ_ENABLE, 1); } void arcv2_irq_enable(struct irq_data *data) { /* set default priority */ - write_aux_reg(AUX_IRQ_SELECT, data->irq); + write_aux_reg(AUX_IRQ_SELECT, data->hwirq); write_aux_reg(AUX_IRQ_PRIORITY, irq_prio); /* diff --git a/arch/arc/kernel/intc-compact.c b/arch/arc/kernel/intc-compact.c index ce9deb9..8c1fd5c 100644 --- a/arch/arc/kernel/intc-compact.c +++ b/arch/arc/kernel/intc-compact.c @@ -57,7 +57,7 @@ static void arc_irq_mask(struct irq_data *data) unsigned int ienb; ienb = read_aux_reg(AUX_IENABLE); - ienb &= ~(1 << data->irq); + ienb &= ~(1 << data->hwirq); write_aux_reg(AUX_IENABLE, ienb); } @@ -66,7 +66,7 @@ static void arc_irq_unmask(struct irq_data *data) unsigned int ienb; ienb = read_aux_reg(AUX_IENABLE); - ienb |= (1 << data->irq); + ienb |= (1 << data->hwirq); write_aux_reg(AUX_IENABLE, ienb); } -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[PATCH v3 2/3] ARCv2: IRQ: Call entry/exit functions for chained handlers in MCIP
It is necessary to call entry/exit functions for parent interrupt controllers for proper masking/unmasking of interrupt lines. Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- arch/arc/kernel/mcip.c | 4 1 file changed, 4 insertions(+) diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index f39142a..be131b2 100644 --- a/arch/arc/kernel/mcip.c +++ b/arch/arc/kernel/mcip.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -221,10 +222,13 @@ static irq_hw_number_t idu_first_hwirq; static void idu_cascade_isr(struct irq_desc *desc) { struct irq_domain *idu_domain = irq_desc_get_handler_data(desc); + struct irq_chip *core_chip = irq_desc_get_chip(desc); irq_hw_number_t core_hwirq = irqd_to_hwirq(irq_desc_get_irq_data(desc)); irq_hw_number_t idu_hwirq = core_hwirq - idu_first_hwirq; + chained_irq_enter(core_chip, desc); generic_handle_irq(irq_find_mapping(idu_domain, idu_hwirq)); + chained_irq_exit(core_chip, desc); } static int idu_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hwirq) -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[PATCH v3 3/3] ARCv2: MCIP: Deprecate setting of affinity in Device Tree
Ignore value of interrupt distribution mode for common interrupts in IDU since setting of affinity using value from Device Tree is deprecated in ARC. Originally it is done in idu_irq_xlate() function and it is semantically wrong and does not guaranty that an affinity value will be set properly. idu_irq_enable() function is better place for initialization of common interrupts. By default send all common interrupts to all available online CPUs. The affinity of common interrupts in IDU must be set manually since in some cases the kernel will not call irq_set_affinity() by itself: 1. When the kernel is not configured with support of SMP. 2. When the kernel is configured with support of SMP but upper interrupt controllers does not support setting of the affinity and cannot propagate it to IDU. Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- .../interrupt-controller/snps,archs-idu-intc.txt | 3 ++ arch/arc/kernel/mcip.c | 52 +- 2 files changed, 25 insertions(+), 30 deletions(-) diff --git a/Documentation/devicetree/bindings/interrupt-controller/snps,archs-idu-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/snps,archs-idu-intc.txt index 0dcb7c7..9446576 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/snps,archs-idu-intc.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/snps,archs-idu-intc.txt @@ -15,6 +15,9 @@ Properties: Second cell specifies the irq distribution mode to cores 0=Round Robin; 1=cpu0, 2=cpu1, 4=cpu2, 8=cpu3 + The second cell in interrupts property is deprecated and may be ignored by + the kernel. + intc accessed via the special ARC AUX register interface, hence "reg" property is not specified. diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index be131b2..d492a3c 100644 --- a/arch/arc/kernel/mcip.c +++ b/arch/arc/kernel/mcip.c @@ -175,7 +175,6 @@ static void idu_irq_unmask(struct irq_data *data) raw_spin_unlock_irqrestore(_lock, flags); } -#ifdef CONFIG_SMP static int idu_irq_set_affinity(struct irq_data *data, const struct cpumask *cpumask, bool force) @@ -205,12 +204,27 @@ idu_irq_set_affinity(struct irq_data *data, const struct cpumask *cpumask, return IRQ_SET_MASK_OK; } -#endif + +static void idu_irq_enable(struct irq_data *data) +{ + /* +* By default send all common interrupts to all available online CPUs. +* The affinity of common interrupts in IDU must be set manually since +* in some cases the kernel will not call irq_set_affinity() by itself: +* 1. When the kernel is not configured with support of SMP. +* 2. When the kernel is configured with support of SMP but upper +* interrupt controllers does not support setting of the affinity +* and cannot propagate it to IDU. +*/ + idu_irq_set_affinity(data, cpu_online_mask, false); + idu_irq_unmask(data); +} static struct irq_chip idu_irq_chip = { .name = "MCIP IDU Intc", .irq_mask = idu_irq_mask, .irq_unmask = idu_irq_unmask, + .irq_enable = idu_irq_enable, #ifdef CONFIG_SMP .irq_set_affinity = idu_irq_set_affinity, #endif @@ -243,36 +257,14 @@ static int idu_irq_xlate(struct irq_domain *d, struct device_node *n, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_type) { - irq_hw_number_t hwirq = *out_hwirq = intspec[0]; - int distri = intspec[1]; - unsigned long flags; - + /* +* Ignore value of interrupt distribution mode for common interrupts in +* IDU which resides in intspec[1] since setting an affinity using value +* from Device Tree is deprecated in ARC. +*/ + *out_hwirq = intspec[0]; *out_type = IRQ_TYPE_NONE; - /* XXX: validate distribution scheme again online cpu mask */ - if (distri == 0) { - /* 0 - Round Robin to all cpus, otherwise 1 bit per core */ - raw_spin_lock_irqsave(_lock, flags); - idu_set_dest(hwirq, BIT(num_online_cpus()) - 1); - idu_set_mode(hwirq, IDU_M_TRIG_LEVEL, IDU_M_DISTRI_RR); - raw_spin_unlock_irqrestore(_lock, flags); - } else { - /* -* DEST based distribution for Level Triggered intr can only -* have 1 CPU, so generalize it to always contain 1 cpu -*/ - int cpu = ffs(distri); - - if (cpu != fls(distri)) - pr_warn("IDU irq %lx distri mode set to cpu %x\n", - hwirq, cpu); - - raw_spin_lock_irqsave(_lock, flags); - idu_set_dest(hwirq, cpu)
[PATCH v3 0/3] Fixes for IRQ subsystem
First 2 patches fix potential bugs in IRQ subsystem. The third one deprecates setting of affinity in Device Tree and moves setting of the initial value of affinity to irq_enable() function of IRQ chip. Changes for v3: * Remove patch for manual setting of the global variable irq_default_affinity to avoid messing with generic code. * Fix 2 potential bugs. * Use irq_enable() for setting of the initial value for affinity in IDU. Changes for v2: * Set the value of irq_default_affinity to the boot CPU. It is necessary because if an interrupt controller is connected to IDU then set_affinity() is not called for IDU interrupts and the real affinity of IDU does not correspond to the value in the descriptor of IRQ (irq_default_affinity by default). Yuriy Kolerov (3): ARC: IRQ: Use hwirq instead of virq in mask/unmask ARCv2: IRQ: Call entry/exit functions for chained handlers in MCIP ARCv2: MCIP: Deprecate setting of affinity in Device Tree .../interrupt-controller/snps,archs-idu-intc.txt | 3 ++ arch/arc/kernel/intc-arcv2.c | 6 +-- arch/arc/kernel/intc-compact.c | 4 +- arch/arc/kernel/mcip.c | 56 ++ 4 files changed, 34 insertions(+), 35 deletions(-) -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[PATCH v2 1/2] ARC: SMP: Set the default affinity to the boot cpu
By default the kernel sets a value for default affinity which may not correspond to the real bitmap of potentially online CPUs. E.g. for ARC HS processors with 2 cores the default value of affinity in the kernel may be 0xF and it is wrong in this case. This happens because init_irq_default_affinity() sets all bits in irq_default_affinity variable by default. It is better to set the default value of affinity to the boot core to guarantee that value of irq_default_affinity contains at least one valid online CPU during the early stage of booting. It is necessary for proper configuration of affinity for common interrupt. Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- arch/arc/kernel/irq.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/arch/arc/kernel/irq.c b/arch/arc/kernel/irq.c index 538b36a..e53bfd5 100644 --- a/arch/arc/kernel/irq.c +++ b/arch/arc/kernel/irq.c @@ -20,6 +20,12 @@ */ void __init init_IRQ(void) { +#ifdef CONFIG_SMP + /* Set the default affinity to the boot cpu. */ + cpumask_clear(irq_default_affinity); + cpumask_set_cpu(smp_processor_id(), irq_default_affinity); +#endif + /* * process the entire interrupt tree in one go * Any external intc will be setup provided DT chains them -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[PATCH v2 2/2] ARCv2: MCIP: Deprecate setting of affinity in Device Tree
Ignore value of interrupt distribution mode for common interrupts in IDU since setting of affinity using value from Device Tree is deprecated in ARC. Originally it is done in idu_irq_xlate() function and it is semantically wrong and does not guaranty that an affinity value will be set properly. idu_irq_map() function is better place since it is called once for each IRQ. The affinity of common interrupts in IDU must be set manually since in some cases the kernel will not call irq_set_affinity() by itself: 1. When the kernel is not configured with support of SMP. 2. When the kernel is configured with support of SMP but upper interrupt controllers does not support setting of the affinity and cannot propagate it to IDU. By default send all common interrupts to the boot CPU. If the kernel has support of SMP then use irq_default_affinity as the affinity for IDU common interrupts since it is set to the boot CPU by default. If the kernel is configured without support of SMP then use cpu_online_mask since in this case it must always contain a valid bitmap with only 1 online CPU. Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- .../interrupt-controller/snps,archs-idu-intc.txt | 3 ++ arch/arc/kernel/mcip.c | 60 +++--- 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/Documentation/devicetree/bindings/interrupt-controller/snps,archs-idu-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/snps,archs-idu-intc.txt index 0dcb7c7..9446576 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/snps,archs-idu-intc.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/snps,archs-idu-intc.txt @@ -15,6 +15,9 @@ Properties: Second cell specifies the irq distribution mode to cores 0=Round Robin; 1=cpu0, 2=cpu1, 4=cpu2, 8=cpu3 + The second cell in interrupts property is deprecated and may be ignored by + the kernel. + intc accessed via the special ARC AUX register interface, hence "reg" property is not specified. diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index f39142a..5b36f7b 100644 --- a/arch/arc/kernel/mcip.c +++ b/arch/arc/kernel/mcip.c @@ -174,7 +174,6 @@ static void idu_irq_unmask(struct irq_data *data) raw_spin_unlock_irqrestore(_lock, flags); } -#ifdef CONFIG_SMP static int idu_irq_set_affinity(struct irq_data *data, const struct cpumask *cpumask, bool force) @@ -204,7 +203,6 @@ idu_irq_set_affinity(struct irq_data *data, const struct cpumask *cpumask, return IRQ_SET_MASK_OK; } -#endif static struct irq_chip idu_irq_chip = { .name = "MCIP IDU Intc", @@ -229,9 +227,33 @@ static void idu_cascade_isr(struct irq_desc *desc) static int idu_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hwirq) { + struct irq_data *irqd = irq_get_irq_data(virq); + irq_set_chip_and_handler(virq, _irq_chip, handle_level_irq); irq_set_status_flags(virq, IRQ_MOVE_PCNTXT); + /* +* The affinity of common interrupts in IDU must be set manually since +* in some cases the kernel will not call irq_set_affinity() by itself: +* +* 1. When the kernel is not configured with support of SMP. +* 2. When the kernel is configured with support of SMP but upper +* interrupt controllers does not support setting of the affinity +* and cannot propagate it to IDU. +* +* By default send all common interrupts to the boot CPU. If the kernel +* has support of SMP then use irq_default_affinity as the affinity +* for IDU common interrupts since it is set to the boot CPU by default. +* If the kernel is configured without support of SMP then use +* cpu_online_mask since in this case it must always contain a valid +* bitmap with only 1 online CPU. +*/ +#ifdef CONFIG_SMP + idu_irq_set_affinity(irqd, irq_default_affinity, false); +#else + idu_irq_set_affinity(irqd, cpu_online_mask, false); +#endif + return 0; } @@ -239,36 +261,14 @@ static int idu_irq_xlate(struct irq_domain *d, struct device_node *n, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_type) { - irq_hw_number_t hwirq = *out_hwirq = intspec[0]; - int distri = intspec[1]; - unsigned long flags; - + /* +* Ignore value of interrupt distribution mode for common interrupts in +* IDU which resides in intspec[1] since setting an affinity using value +* from Device Tree is deprecated in ARC. +*/ + *out_hwirq = intspec[0]; *out_type = IRQ_TYPE_NONE; - /* XXX: validate distribution scheme again online cpu mask */ - if (distri == 0) { - /* 0 - Round Robi
RE: [RFC] ARC: mm: Restrict definition of pfn_valid() macro for CONFIG_FLATMEM
> -Original Message- > From: Vineet Gupta [mailto:vgu...@synopsys.com] > Sent: Wednesday, November 30, 2016 7:55 PM > To: Yuriy Kolerov <yuriy.kole...@synopsys.com>; Michal Hocko > <mho...@kernel.org> > Cc: linux-snps-arc@lists.infradead.org; alexey.brod...@synopsys.com; linux- > ker...@vger.kernel.org > Subject: Re: [RFC] ARC: mm: Restrict definition of pfn_valid() macro for > CONFIG_FLATMEM > > On 11/30/2016 06:21 AM, Yuriy Kolerov wrote: > >> On Tue 29-11-16 18:29:06, Yuriy Kolerov wrote: > >>> > > Despite the fact that subtraction of unsigned integers is a > >>> > > defined behaviour however such operations can lead to unexpected > >>> > > results. Thus it is better to check both left and right > >>> > > boundaries to avoid potential bugs as it done in the generic page.h. > >> > > >> > Why and which code would use an out of range pfn? Why other arches > >> > do not need to care? > > Actually some arches do care about checking of both left and right > boundaries (e.g. avr32, sparc, etc). The problem is that a value of pfn may be > calculated incorrectly in some places of the kernel. E.g. not long ago I sent > a > patch which fixes truncation of the most significant byte in pfn/pte in some > cases (in the kernel with PAE40, however it is not a FLATMEM case). So such > situations can happens in the most unexpected places. > > > > So the point is - is this a preventive fix (desired thing) or it being there > would > have helped find the PAE40 bug earlier / easier. Woudl it have prevented the > kernel crash. If so then this is a nobrainer fix. This fix can help to find bugs which are related to wrong pfn values and only for FLATMEM case (usually when PAE40 is turned off). However I have just figured out that it is impossible to pass such bad unsigned pfn value which passes pfn_valid() check (usually the kernel passes a value from unsigned long variable)... This fix may help in cases when the kernel accidently passes a signed long value as pfn to the macro. Frankly speaking there are low chances that such thing can ever happen so I'm a little paranoid about it. > BTW did you try to gauge the code gen impact - this function gets pulled all > over the place in mm code. So build kernel with and w/o change and do a > scripts/bloat-o-meter Report from that script (extra 112 bytes): add/remove: 0/0 grow/shrink: 9/1 up/down: 122/-10 (112) function old new delta set_zone_contiguous 212 248 +36 __pageblock_pfn_to_page 120 136 +16 vm_insert_pfn_prot 432 444 +12 vm_insert_pfn436 448 +12 kpagecount_read 360 372 +12 reserve_bootmem_region 110 120 +10 memremap 248 256 +8 kpageflags_read 840 848 +8 devm_memremap356 364 +8 pagetypeinfo_show752 742 -10 Total: Before=3785631, After=3785743, chg +0.00% > -Vineet ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[RFC] ARC: mm: Restrict definition of pfn_valid() macro for CONFIG_FLATMEM
Despite the fact that subtraction of unsigned integers is a defined behaviour however such operations can lead to unexpected results. Thus it is better to check both left and right boundaries to avoid potential bugs as it done in the generic page.h. Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- arch/arc/include/asm/page.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arc/include/asm/page.h b/arch/arc/include/asm/page.h index 296c342..81cfc6c7 100644 --- a/arch/arc/include/asm/page.h +++ b/arch/arc/include/asm/page.h @@ -88,7 +88,7 @@ typedef pte_t * pgtable_t; #define ARCH_PFN_OFFSETvirt_to_pfn(CONFIG_LINUX_LINK_BASE) #ifdef CONFIG_FLATMEM -#define pfn_valid(pfn) (((pfn) - ARCH_PFN_OFFSET) < max_mapnr) +#define pfn_valid(pfn) ((pfn) >= ARCH_PFN_OFFSET && ((pfn) - ARCH_PFN_OFFSET) < max_mapnr) #endif /* -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[PATCH] ARC: mm: PAE40: Cast pfn to pte_t in pfn_pte() macro
Originally pfn_pte(pfn, prot) macro had this definition: __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) The value of pfn (Page Frame Number) is shifted to the left to get the value of pte (Page Table Entry). Usually a 4-byte value is passed to this macro as value of pfn. However if Linux is configured with support of PAE40 then value of pte has 8-byte type because it must contain additional 8 bits of the physical address. Thus if value of pfn represents a physical page frame above of 4GB boundary then shifting of pfn to the left by PAGE_SHIFT wipes most significant bits of the 40-bit physical address. As a result all physical addresses above of 4GB boundary in systems with PAE40 are mapped to virtual address incorrectly. An error may occur when the kernel tries to unmap such bad pages: [ECR ]: 0x00050100 => Invalid Read @ 0x41414144 by insn @ 0x801644c6 [EFA ]: 0x41414144 [BLINK ]: unmap_page_range+0x134/0x700 [ERET ]: unmap_page_range+0x17a/0x700 [STAT32]: 0x8008021e : IE K BTA: 0x801644c6 SP: 0x901a5e84 FP: 0x5ff35de8 LPS: 0x8026462c LPE: 0x80264630 LPC: 0x r00: 0x8fcc4fc0 r01: 0x2fe68000 r02: 0x41414140 r03: 0x2c05c000 r04: 0x2fe6a000 r05: 0x0009 r06: 0x901b6898 r07: 0x2fe68000 r08: 0x0001 r09: 0x804a807c r10: 0x067e r11: 0x r12: 0x80164480 Stack Trace: unmap_page_range+0x17a/0x700 unmap_vmas+0x46/0x64 do_munmap+0x210/0x450 SyS_munmap+0x2c/0x50 EV_Trap+0xfc/0x100 So the value of pfn must be casted to pte_t before shifting to ensure that 40-bit address will not be truncated: __pte(((pte_t) (pfn) << PAGE_SHIFT) | pgprot_val(prot)) Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- arch/arc/include/asm/pgtable.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arc/include/asm/pgtable.h b/arch/arc/include/asm/pgtable.h index 89eeb37..77bc51c 100644 --- a/arch/arc/include/asm/pgtable.h +++ b/arch/arc/include/asm/pgtable.h @@ -280,7 +280,8 @@ static inline void pmd_set(pmd_t *pmdp, pte_t *ptep) #define pte_page(pte) pfn_to_page(pte_pfn(pte)) #define mk_pte(page, prot) pfn_pte(page_to_pfn(page), prot) -#define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) +#define pfn_pte(pfn, prot) \ + __pte(((pte_t) (pfn) << PAGE_SHIFT) | pgprot_val(prot)) /* Don't use virt_to_pfn for macros below: could cause truncations for PAE40*/ #define pte_pfn(pte) (pte_val(pte) >> PAGE_SHIFT) -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
RE: [PATCH] ARCv2: MCIP: Deprecate setting of affinity in Device Tree
Hi Marc, > -Original Message- > From: Marc Zyngier [mailto:marc.zyng...@arm.com] > Sent: Friday, November 11, 2016 6:29 PM > To: Yuriy Kolerov <yuriy.kole...@synopsys.com>; linux-snps- > a...@lists.infradead.org > Cc: vineet.gup...@synopsys.com; alexey.brod...@synopsys.com; > t...@linutronix.de; linux-ker...@vger.kernel.org > Subject: Re: [PATCH] ARCv2: MCIP: Deprecate setting of affinity in Device > Tree > > Hi Yuriy, > > On 11/11/16 14:38, Yuriy Kolerov wrote: > > Ignore value of interrupt distribution mode for common interrupts in > > IDU since setting of affinity using value from Device Tree is > > deprecated in ARC. Originally it is done in idu_irq_xlate() function > > and it is semantically wrong and does not guaranty that an affinity > > value will be set properly. > > > > However it is necessary to set a default affinity value manually for > > all common interrupts since initially all of them are disabled by IDU > > (a CPU mask for common interrupts is set to 0 after CPU reset) and in > > some cases the kernel cannot do it itself after initialization of > > endpoint devices (e.g. when IRQ chip below of IDU does not support > > setting of affinity and it cannot propagate an affinity value to IDU). > > > > By default send all common interrupts to the first online CPU. > > Usually it is a boot CPU. If the kernel is built without support of > > SMP then idu_irq_set_affinity() must be called manually since > > irq_set_affinity() does nothing in this case. > > > > Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> > > --- > > .../interrupt-controller/snps,archs-idu-intc.txt | 3 ++ > > arch/arc/kernel/mcip.c | 51 > > +- > > 2 files changed, 24 insertions(+), 30 deletions(-) > > > > diff --git > > a/Documentation/devicetree/bindings/interrupt-controller/snps,archs-id > > u-intc.txt > > b/Documentation/devicetree/bindings/interrupt-controller/snps,archs-id > > u-intc.txt > > index 0dcb7c7..0607bab 100644 > > --- > > a/Documentation/devicetree/bindings/interrupt-controller/snps,archs-id > > u-intc.txt > > +++ b/Documentation/devicetree/bindings/interrupt-controller/snps,arch > > +++ s-idu-intc.txt > > @@ -15,6 +15,9 @@ Properties: > >Second cell specifies the irq distribution mode to cores > > 0=Round Robin; 1=cpu0, 2=cpu1, 4=cpu2, 8=cpu3 > > > > + The second cell in interrupts property is deprecated and ignored. > > + All common interrupts are sent to the boot CPU core by default. > > + > > > This comment only affects the behaviour of the driver, and not the > hardware. I'd rather see something along the lines of: > > "The second cell is only a hint, and an operating system is free to ignore > it." > > >intc accessed via the special ARC AUX register interface, hence "reg" > property > >is not specified. > > > > diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index > > 6d90e4b..f36b8d7 100644 > > --- a/arch/arc/kernel/mcip.c > > +++ b/arch/arc/kernel/mcip.c > > @@ -174,7 +174,6 @@ static void idu_irq_unmask(struct irq_data *data) > > raw_spin_unlock_irqrestore(_lock, flags); } > > > > -#ifdef CONFIG_SMP > > static int > > idu_irq_set_affinity(struct irq_data *data, const struct cpumask > *cpumask, > > bool force) > > @@ -204,7 +203,6 @@ idu_irq_set_affinity(struct irq_data *data, const > > struct cpumask *cpumask, > > > > return IRQ_SET_MASK_OK; > > } > > -#endif > > > > static struct irq_chip idu_irq_chip = { > > .name = "MCIP IDU Intc", > > @@ -228,9 +226,24 @@ static void idu_cascade_isr(struct irq_desc > > *desc) > > > > static int idu_irq_map(struct irq_domain *d, unsigned int virq, > > irq_hw_number_t hwirq) { > > + cpumask_t affinity; > > + > > irq_set_chip_and_handler(virq, _irq_chip, handle_level_irq); > > irq_set_status_flags(virq, IRQ_MOVE_PCNTXT); > > > > + /* By default send all common interrupts to the first online CPU. > > +* Usually it is a boot CPU. If the kernel is built without support > > +* of SMP then idu_irq_set_affinity() must be called manually since > > +* irq_set_affinity() does nothing in this case. > > +*/ > > + cpumask_copy(, > cpumask_of(cpumask_first(cpu_online_mask))); > > + > > +#ifdef CONFIG_SMP > > + irq_set_affinity(virq, ); > > Ghhha. Please do
[PATCH] ARCv2: MCIP: Deprecate setting of affinity in Device Tree
Ignore value of interrupt distribution mode for common interrupts in IDU since setting of affinity using value from Device Tree is deprecated in ARC. Originally it is done in idu_irq_xlate() function and it is semantically wrong and does not guaranty that an affinity value will be set properly. However it is necessary to set a default affinity value manually for all common interrupts since initially all of them are disabled by IDU (a CPU mask for common interrupts is set to 0 after CPU reset) and in some cases the kernel cannot do it itself after initialization of endpoint devices (e.g. when IRQ chip below of IDU does not support setting of affinity and it cannot propagate an affinity value to IDU). By default send all common interrupts to the first online CPU. Usually it is a boot CPU. If the kernel is built without support of SMP then idu_irq_set_affinity() must be called manually since irq_set_affinity() does nothing in this case. Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- .../interrupt-controller/snps,archs-idu-intc.txt | 3 ++ arch/arc/kernel/mcip.c | 51 +- 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/Documentation/devicetree/bindings/interrupt-controller/snps,archs-idu-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/snps,archs-idu-intc.txt index 0dcb7c7..0607bab 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/snps,archs-idu-intc.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/snps,archs-idu-intc.txt @@ -15,6 +15,9 @@ Properties: Second cell specifies the irq distribution mode to cores 0=Round Robin; 1=cpu0, 2=cpu1, 4=cpu2, 8=cpu3 + The second cell in interrupts property is deprecated and ignored. All common + interrupts are sent to the boot CPU core by default. + intc accessed via the special ARC AUX register interface, hence "reg" property is not specified. diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index 6d90e4b..f36b8d7 100644 --- a/arch/arc/kernel/mcip.c +++ b/arch/arc/kernel/mcip.c @@ -174,7 +174,6 @@ static void idu_irq_unmask(struct irq_data *data) raw_spin_unlock_irqrestore(_lock, flags); } -#ifdef CONFIG_SMP static int idu_irq_set_affinity(struct irq_data *data, const struct cpumask *cpumask, bool force) @@ -204,7 +203,6 @@ idu_irq_set_affinity(struct irq_data *data, const struct cpumask *cpumask, return IRQ_SET_MASK_OK; } -#endif static struct irq_chip idu_irq_chip = { .name = "MCIP IDU Intc", @@ -228,9 +226,24 @@ static void idu_cascade_isr(struct irq_desc *desc) static int idu_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hwirq) { + cpumask_t affinity; + irq_set_chip_and_handler(virq, _irq_chip, handle_level_irq); irq_set_status_flags(virq, IRQ_MOVE_PCNTXT); + /* By default send all common interrupts to the first online CPU. +* Usually it is a boot CPU. If the kernel is built without support +* of SMP then idu_irq_set_affinity() must be called manually since +* irq_set_affinity() does nothing in this case. +*/ + cpumask_copy(, cpumask_of(cpumask_first(cpu_online_mask))); + +#ifdef CONFIG_SMP + irq_set_affinity(virq, ); +#else + idu_irq_set_affinity(irq_get_irq_data(virq), , false); +#endif + return 0; } @@ -238,36 +251,14 @@ static int idu_irq_xlate(struct irq_domain *d, struct device_node *n, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_type) { - irq_hw_number_t hwirq = *out_hwirq = intspec[0]; - int distri = intspec[1]; - unsigned long flags; - + /* +* Ignore value of interrupt distribution mode for common interrupts in +* IDU which resides in intspec[1] since setting an affinity using value +* from Device Tree is deprecated in ARC. +*/ + *out_hwirq = intspec[0]; *out_type = IRQ_TYPE_NONE; - /* XXX: validate distribution scheme again online cpu mask */ - if (distri == 0) { - /* 0 - Round Robin to all cpus, otherwise 1 bit per core */ - raw_spin_lock_irqsave(_lock, flags); - idu_set_dest(hwirq, BIT(num_online_cpus()) - 1); - idu_set_mode(hwirq, IDU_M_TRIG_LEVEL, IDU_M_DISTRI_RR); - raw_spin_unlock_irqrestore(_lock, flags); - } else { - /* -* DEST based distribution for Level Triggered intr can only -* have 1 CPU, so generalize it to always contain 1 cpu -*/ - int cpu = ffs(distri); - - if (cpu != fls(distri)) - pr_warn("IDU irq %lx distri mode set to cpu %x\n", - hwirq, cpu); - -
[PATCH v4 1/2] ARC: IRQ: Do not use hwirq as virq and vice versa
At first smp_ipi_irq_setup() takes a cpu number and a hwirq number for the per core local interrupt line in the root interrupt controller and registers an appropriate IPI handler per cpu. However this function tries to bind a handler to the hwirq as virtual IRQ number and it is a wrong behavior. It is necessary to find a mapping of hwirq in the root IRQ domain to the actual virq using irq_find_mapping(). Also a declaration of smp_ipi_irq_setup() is corrected to denote that this function takes a hardware IRQ number but not a virtual IRQ number. Also there is one more problem related to usage of IRQ numbers. Multicore ARC configurations use IDU (Interrupt Distribution Unit) for distributing of common interrupts. In fact IDU is a interrupt controller on top of main per core interrupt controller. All common IRQs are physically and linearly mapped to per core interrupts. E.g. <0, 1, 2, 3> common IDU interrupts may be mapped to per core <24, 25, 26, 27> interrupts. An initialization code of IDU controller (idu_of_init()) creates mappings for all parent interrupts <24, 25, ...> and sets a chained IDU handler for them. In the same time idu_of_init() must save the first met parent hwirq (idu_first_irq) thus in future it is possible to figure out what common hwirq has come by subtracting of idu_first_irq from the current parent hwirq (see idu_cascade_isr()). The problem is that idu_of_init() and idu_cascade_isr() use parent virtual IRQs as hardware IRQs and perform all the above-described manipulations on virtual IRQs. But it is wrong and hardware IRQs must be used instead. Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- arch/arc/include/asm/smp.h | 4 ++-- arch/arc/kernel/mcip.c | 20 +--- arch/arc/kernel/smp.c | 13 + 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/arch/arc/include/asm/smp.h b/arch/arc/include/asm/smp.h index 89fdd1b..0861007 100644 --- a/arch/arc/include/asm/smp.h +++ b/arch/arc/include/asm/smp.h @@ -37,9 +37,9 @@ extern const char *arc_platform_smp_cpuinfo(void); * API expected BY platform smp code (FROM arch smp code) * * smp_ipi_irq_setup: - * Takes @cpu and @irq to which the arch-common ISR is hooked up + * Takes @cpu and @hwirq to which the arch-common ISR is hooked up */ -extern int smp_ipi_irq_setup(int cpu, int irq); +extern int smp_ipi_irq_setup(int cpu, irq_hw_number_t hwirq); /* * struct plat_smp_ops - SMP callbacks provided by platform to ARC SMP diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index 72f9179..4f4f04b 100644 --- a/arch/arc/kernel/mcip.c +++ b/arch/arc/kernel/mcip.c @@ -219,16 +219,14 @@ static struct irq_chip idu_irq_chip = { }; -static int idu_first_irq; +static irq_hw_number_t idu_first_hwirq; static void idu_cascade_isr(struct irq_desc *desc) { - struct irq_domain *domain = irq_desc_get_handler_data(desc); - unsigned int core_irq = irq_desc_get_irq(desc); - unsigned int idu_irq; - - idu_irq = core_irq - idu_first_irq; - generic_handle_irq(irq_find_mapping(domain, idu_irq)); + struct irq_domain *idu_domain = irq_desc_get_handler_data(desc); + irq_hw_number_t core_hwirq = irqd_to_hwirq(irq_desc_get_irq_data(desc)); + irq_hw_number_t idu_hwirq = core_hwirq - idu_first_hwirq; + generic_handle_irq(irq_find_mapping(idu_domain, idu_hwirq)); } static int idu_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hwirq) @@ -294,7 +292,7 @@ idu_of_init(struct device_node *intc, struct device_node *parent) struct irq_domain *domain; /* Read IDU BCR to confirm nr_irqs */ int nr_irqs = of_irq_count(intc); - int i, irq; + int i, virq; if (!idu_detected) panic("IDU not detected, but DeviceTree using it"); @@ -312,11 +310,11 @@ idu_of_init(struct device_node *intc, struct device_node *parent) * however we need it to get the parent virq and set IDU handler * as first level isr */ - irq = irq_of_parse_and_map(intc, i); + virq = irq_of_parse_and_map(intc, i); if (!i) - idu_first_irq = irq; + idu_first_hwirq = irqd_to_hwirq(irq_get_irq_data(virq)); - irq_set_chained_handler_and_data(irq, idu_cascade_isr, domain); + irq_set_chained_handler_and_data(virq, idu_cascade_isr, domain); } __mcip_cmd(CMD_IDU_ENABLE, 0); diff --git a/arch/arc/kernel/smp.c b/arch/arc/kernel/smp.c index f183cc6..692ca51 100644 --- a/arch/arc/kernel/smp.c +++ b/arch/arc/kernel/smp.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -351,20 +352,24 @@ irqreturn_t do_IPI(int irq, void *dev_id) */ static DEFINE_PER_CPU(int, ipi_dev); -int smp_ipi_irq_setup(int cpu, int irq) +int smp_ipi_irq_se
RE: [PATCH v3 2/3] ARCv2: MCIP: Use hwirq instead of virq for resolution of IDU IRQ handlers
Yes, theoretically this may not work with 1/3 and 2/3. I will merge those patches. > -Original Message- > From: Vineet Gupta [mailto:vgu...@synopsys.com] > Sent: Tuesday, November 08, 2016 4:59 AM > To: Yuriy Kolerov <yuriy.kole...@synopsys.com>; linux-snps- > a...@lists.infradead.org > Cc: alexey.brod...@synopsys.com; t...@linutronix.de; linux- > ker...@vger.kernel.org > Subject: Re: [PATCH v3 2/3] ARCv2: MCIP: Use hwirq instead of virq for > resolution of IDU IRQ handlers > > On 11/03/2016 05:23 AM, Yuriy Kolerov wrote: > > Multicore ARC configurations use IDU (Interrupt Distribution Unit) for > > distributing of common interrupts. In fact IDU is a interrupt > > controller on top of main per core interrupt controller. > > > > All common IRQs are physically and linearly mapped to per core > > interrupts. E.g. <0, 1, 2, 3> common IDU interrupts may be mapped to > > per core <24, 25, 26, 27> interrupts. An initialization code of IDU > > controller (idu_of_init) creates mappings for all parent interrupts > > <24, 25, ...> and sets a chained IDU handler for them. In the same > > time idu_of_init must save the first met parent hwirq (idu_first_irq) > > thus in future it is possible to figure out what common hwirq has come > > by subtracting of idu_first_irq from the current parent hwirq (see > > idu_cascade_isr). > > > > The problem is that idu_of_init and idu_cascade_isr use parent virtual > > IRQs as hardware IRQs and perform all the above-described > > manipulations on virtual IRQs. But it is wrong and hardware IRQs must be > used instead. > > Is this series bisectable ? > > So if one only applies patch 1/3 (and not 2/3) - as might happen in case of a > bisect for some arbit problem, will it still work - to me it seems not. > > > > > Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> > > --- > > arch/arc/kernel/mcip.c | 20 +--- > > 1 file changed, 9 insertions(+), 11 deletions(-) > > > > diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index > > 72f9179..4f4f04b 100644 > > --- a/arch/arc/kernel/mcip.c > > +++ b/arch/arc/kernel/mcip.c > > @@ -219,16 +219,14 @@ static struct irq_chip idu_irq_chip = { > > > > }; > > > > -static int idu_first_irq; > > +static irq_hw_number_t idu_first_hwirq; > > > > static void idu_cascade_isr(struct irq_desc *desc) { > > - struct irq_domain *domain = irq_desc_get_handler_data(desc); > > - unsigned int core_irq = irq_desc_get_irq(desc); > > - unsigned int idu_irq; > > - > > - idu_irq = core_irq - idu_first_irq; > > - generic_handle_irq(irq_find_mapping(domain, idu_irq)); > > + struct irq_domain *idu_domain = irq_desc_get_handler_data(desc); > > + irq_hw_number_t core_hwirq = > irqd_to_hwirq(irq_desc_get_irq_data(desc)); > > + irq_hw_number_t idu_hwirq = core_hwirq - idu_first_hwirq; > > + generic_handle_irq(irq_find_mapping(idu_domain, idu_hwirq)); > > } > > > > static int idu_irq_map(struct irq_domain *d, unsigned int virq, > > irq_hw_number_t hwirq) @@ -294,7 +292,7 @@ idu_of_init(struct > device_node *intc, struct device_node *parent) > > struct irq_domain *domain; > > /* Read IDU BCR to confirm nr_irqs */ > > int nr_irqs = of_irq_count(intc); > > - int i, irq; > > + int i, virq; > > > > if (!idu_detected) > > panic("IDU not detected, but DeviceTree using it"); @@ - > 312,11 > > +310,11 @@ idu_of_init(struct device_node *intc, struct device_node > *parent) > > * however we need it to get the parent virq and set IDU > handler > > * as first level isr > > */ > > - irq = irq_of_parse_and_map(intc, i); > > + virq = irq_of_parse_and_map(intc, i); > > if (!i) > > - idu_first_irq = irq; > > + idu_first_hwirq = > irqd_to_hwirq(irq_get_irq_data(virq)); > > > > - irq_set_chained_handler_and_data(irq, idu_cascade_isr, > domain); > > + irq_set_chained_handler_and_data(virq, idu_cascade_isr, > domain); > > } > > > > __mcip_cmd(CMD_IDU_ENABLE, 0); > > ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[RFC] ARCv2: MCIP: Deprecate setting of affinity in Device Tree
Ignore value of interrupt distribution mode for common interrupts in IDU since setting an affinity using value from Device Tree is deprecated in ARC. Originially it is done in idu_irq_xlate function and it is semantically wrong and does not guaranty that an affinity value will be set properly. However it is necessary to set a default affinity value manually for all common interrupts since initially all of them are disabled by IDU (a CPU mask for common interrupts is set to 0 after CPU reset) and in some cases the kernel cannot do it itself after initialization of endpoint devices (e.g. when IRQ chip below of IDU does not support setting of affinity and it cannot propagate an affinity value to IDU). P.S. Despite the fact that the patch works fine I would like to discuss few topics which are one way or another related to the original problem. Despite the fact that this patch works fine it does not work well when the intc below IDU does not support setting and propagating of affinity (e.g. GPIO intc in AXS103 configuration which does not implement a function for setting an affinity). That is why it is necessary to set an affinity manually for IDU - you cannot be sure that an affinity will be propagated to IDU properly even with support of hierarchical IRQ domains. But an affinity *must* be set because IDU common interrupts are disabled by default (registers which stores cpu masks are zeroes). In this patch I use this soulution in idu_irq_map() function: irq_set_affinity(virq, cpu_online_mask); And there is a second problem. You cannot be sure that all cpus are online at the moment of calling idu_irq_map() that is why cpu_online_mask mask is used for setting of the initial affinity. It means that affinity of all common interrupts is unpredictable after kernel boot (of course it would be cool to distribute all common interrupts to all available cores by default). And the third topic is setting of affinity for AXS103 devices. Devices in AXS103 are connected to CPU through a chain of GPIO controllers which funnel all signals to 2 IDU common interrupts. Thus you cannot simply set an affinity for devices using something like: echo 2 > /proc/irq/3/... because 1) GPIO contorrels in AXS103 does not support setting an affinity and 2) there is a logical explanation for it: if you want to set an affinity for a device connected to GPIO you produce a side affect by touchin an affinity for nearby devices. So if in case of AXS103 you must set an affinity not for devices but for GPIO controllers which are connected to IDU. Also you must to know a virq of the common interrupt line in IDU to set an affinity for it. Problem is that you cannot retrieve this value from /proc/interrupts for AXS103 even if support of hierarchical domains is implemented: /proc/interrupts does not show chained virqs and virqs without actions (e.g. all virqs of IDU). P.S.S. The question is how to solve all those problems properly. Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- .../interrupt-controller/snps,archs-idu-intc.txt | 2 ++ arch/arc/kernel/mcip.c | 35 +- 2 files changed, 9 insertions(+), 28 deletions(-) diff --git a/Documentation/devicetree/bindings/interrupt-controller/snps,archs-idu-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/snps,archs-idu-intc.txt index 0dcb7c7..e967e7f 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/snps,archs-idu-intc.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/snps,archs-idu-intc.txt @@ -15,6 +15,8 @@ Properties: Second cell specifies the irq distribution mode to cores 0=Round Robin; 1=cpu0, 2=cpu1, 4=cpu2, 8=cpu3 + The second cell in interrupts property is deprecated and ignored. + intc accessed via the special ARC AUX register interface, hence "reg" property is not specified. diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index 90f9934..2f4b0dc 100644 --- a/arch/arc/kernel/mcip.c +++ b/arch/arc/kernel/mcip.c @@ -242,6 +242,7 @@ static int idu_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t { irq_set_chip_and_handler(virq, _irq_chip, handle_level_irq); irq_set_status_flags(virq, IRQ_MOVE_PCNTXT); + irq_set_affinity(virq, cpu_online_mask); return 0; } @@ -250,36 +251,14 @@ static int idu_irq_xlate(struct irq_domain *d, struct device_node *n, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_type) { - irq_hw_number_t hwirq = *out_hwirq = intspec[0]; - int distri = intspec[1]; - unsigned long flags; - + /* +* Ignore value of interrupt distribution mode for common interrupts in +* IDU which resides in intspec[1] since setting an affinity using value +* from Device Tree is deprecated in ARC. +*/ + *ou
[PATCH v3 3/3] ARCv2: MCIP: Use IDU_M_DISTRI_DEST mode if there is only 1 destination core
ARC linux uses 2 distribution modes for common interrupts: round robin mode (IDU_M_DISTRI_RR) and a simple destination mode (IDU_M_DISTRI_DEST). The first one is used when more than 1 cores may handle a common interrupt and the second one is used when only 1 core may handle a common interrupt. However idu_irq_set_affinity always sets IDU_M_DISTRI_RR for all affinity values. But there is no sense in setting of such mode if only 1 core must handle a common interrupt. Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- arch/arc/kernel/mcip.c | 13 +++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index 4f4f04b..90f9934 100644 --- a/arch/arc/kernel/mcip.c +++ b/arch/arc/kernel/mcip.c @@ -193,6 +193,8 @@ idu_irq_set_affinity(struct irq_data *data, const struct cpumask *cpumask, { unsigned long flags; cpumask_t online; + unsigned int destination_bits; + unsigned int distribution_mode; /* errout if no online cpu per @cpumask */ if (!cpumask_and(, cpumask, cpu_online_mask)) @@ -200,8 +202,15 @@ idu_irq_set_affinity(struct irq_data *data, const struct cpumask *cpumask, raw_spin_lock_irqsave(_lock, flags); - idu_set_dest(data->hwirq, cpumask_bits()[0]); - idu_set_mode(data->hwirq, IDU_M_TRIG_LEVEL, IDU_M_DISTRI_RR); + destination_bits = cpumask_bits()[0]; + idu_set_dest(data->hwirq, destination_bits); + + if (ffs(destination_bits) == fls(destination_bits)) + distribution_mode = IDU_M_DISTRI_DEST; + else + distribution_mode = IDU_M_DISTRI_RR; + + idu_set_mode(data->hwirq, IDU_M_TRIG_LEVEL, distribution_mode); raw_spin_unlock_irqrestore(_lock, flags); -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[PATCH v3 2/3] ARCv2: MCIP: Use hwirq instead of virq for resolution of IDU IRQ handlers
Multicore ARC configurations use IDU (Interrupt Distribution Unit) for distributing of common interrupts. In fact IDU is a interrupt controller on top of main per core interrupt controller. All common IRQs are physically and linearly mapped to per core interrupts. E.g. <0, 1, 2, 3> common IDU interrupts may be mapped to per core <24, 25, 26, 27> interrupts. An initialization code of IDU controller (idu_of_init) creates mappings for all parent interrupts <24, 25, ...> and sets a chained IDU handler for them. In the same time idu_of_init must save the first met parent hwirq (idu_first_irq) thus in future it is possible to figure out what common hwirq has come by subtracting of idu_first_irq from the current parent hwirq (see idu_cascade_isr). The problem is that idu_of_init and idu_cascade_isr use parent virtual IRQs as hardware IRQs and perform all the above-described manipulations on virtual IRQs. But it is wrong and hardware IRQs must be used instead. Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- arch/arc/kernel/mcip.c | 20 +--- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index 72f9179..4f4f04b 100644 --- a/arch/arc/kernel/mcip.c +++ b/arch/arc/kernel/mcip.c @@ -219,16 +219,14 @@ static struct irq_chip idu_irq_chip = { }; -static int idu_first_irq; +static irq_hw_number_t idu_first_hwirq; static void idu_cascade_isr(struct irq_desc *desc) { - struct irq_domain *domain = irq_desc_get_handler_data(desc); - unsigned int core_irq = irq_desc_get_irq(desc); - unsigned int idu_irq; - - idu_irq = core_irq - idu_first_irq; - generic_handle_irq(irq_find_mapping(domain, idu_irq)); + struct irq_domain *idu_domain = irq_desc_get_handler_data(desc); + irq_hw_number_t core_hwirq = irqd_to_hwirq(irq_desc_get_irq_data(desc)); + irq_hw_number_t idu_hwirq = core_hwirq - idu_first_hwirq; + generic_handle_irq(irq_find_mapping(idu_domain, idu_hwirq)); } static int idu_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hwirq) @@ -294,7 +292,7 @@ idu_of_init(struct device_node *intc, struct device_node *parent) struct irq_domain *domain; /* Read IDU BCR to confirm nr_irqs */ int nr_irqs = of_irq_count(intc); - int i, irq; + int i, virq; if (!idu_detected) panic("IDU not detected, but DeviceTree using it"); @@ -312,11 +310,11 @@ idu_of_init(struct device_node *intc, struct device_node *parent) * however we need it to get the parent virq and set IDU handler * as first level isr */ - irq = irq_of_parse_and_map(intc, i); + virq = irq_of_parse_and_map(intc, i); if (!i) - idu_first_irq = irq; + idu_first_hwirq = irqd_to_hwirq(irq_get_irq_data(virq)); - irq_set_chained_handler_and_data(irq, idu_cascade_isr, domain); + irq_set_chained_handler_and_data(virq, idu_cascade_isr, domain); } __mcip_cmd(CMD_IDU_ENABLE, 0); -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
RE: [PATCH v2 5/5] ARC: MCIP: Use IDU_M_DISTRI_DEST mode if there is only 1 destination core
> -Original Message- > From: Vineet Gupta [mailto:vgu...@synopsys.com] > Sent: Tuesday, October 25, 2016 8:53 PM > To: Yuriy Kolerov <yuriy.kole...@synopsys.com>; linux-snps- > a...@lists.infradead.org > Cc: marc.zyng...@arm.com; vineet.gup...@synopsys.com; > alexey.brod...@synopsys.com; linux-ker...@vger.kernel.org; > t...@linutronix.de > Subject: Re: [PATCH v2 5/5] ARC: MCIP: Use IDU_M_DISTRI_DEST mode if > there is only 1 destination core > > On 10/24/2016 05:46 AM, Yuriy Kolerov wrote: > > ARC linux uses 2 distribution modes for common interrupts: round robin > > mode (IDU_M_DISTRI_RR) and a simple destination mode > (IDU_M_DISTRI_DEST). > > The first one is used when more than 1 cores may handle a common > > interrupt and the second one is used when only 1 core may handle a > common interrupt. > > > > However idu_irq_set_affinity always sets IDU_M_DISTRI_RR for all > > affinity values. But there is no sense in setting of such mode if only > > 1 core must handle a common interrupt. > > > > Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> > > --- > > arch/arc/kernel/mcip.c | 11 +-- > > 1 file changed, 9 insertions(+), 2 deletions(-) > > > > diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index > > 090f0a1..75e6d73 100644 > > --- a/arch/arc/kernel/mcip.c > > +++ b/arch/arc/kernel/mcip.c > > @@ -197,6 +197,7 @@ idu_irq_set_affinity(struct irq_data *data, const > > struct cpumask *cpumask, { > > unsigned long flags; > > cpumask_t online; > > + unsigned long dest_bits; > > > > /* errout if no online cpu per @cpumask */ > > if (!cpumask_and(, cpumask, cpu_online_mask)) @@ -204,8 > > +205,14 @@ idu_irq_set_affinity(struct irq_data *data, const struct > > cpumask *cpumask, > > > > raw_spin_lock_irqsave(_lock, flags); > > > > - idu_set_dest(data->hwirq, cpumask_bits()[0]); > > - idu_set_mode(data->hwirq, IDU_M_TRIG_LEVEL, > IDU_M_DISTRI_RR); > > + dest_bits = cpumask_bits()[0]; > > + idu_set_dest(data->hwirq, dest_bits); > > + > > + if (ffs(dest_bits) == fls(dest_bits)) { > > + idu_set_mode(data->hwirq, IDU_M_TRIG_LEVEL, > IDU_M_DISTRI_DEST); > > + } else { > > + idu_set_mode(data->hwirq, IDU_M_TRIG_LEVEL, > IDU_M_DISTRI_RR); > > + } > > Better to use a local variable to assign IDU_M_xxx and then call > idu_set_mode() outside the if. I know the compiler would do that anyways, > but that looks simpler to read ! Yep. > But on the other hand, adding all of this here - isn't there some sort of > duplication of code now between here and in the idu_irq_xlate() ? > Do we need the same stuff in 2 places ? I tried to explain in in [PATCH v2 4/5]. In short I moved logic for setting affinity to idu_irq_set_affinity because xlate function is not the best place where it must be done (see commit message for that patch). > > > > raw_spin_unlock_irqrestore(_lock, flags); > > > > ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[PATCH v2 4/5] ARC: MCIP: Set an initial affinity value in idu_irq_map
Originally an initial distribution mode (its value resides in Device Tree) for each common interrupt is set in idu_irq_xlate. This leads to the following problems. idu_irq_xlate may be called several times during parsing of the Device Tree and it is semantically wrong to configure an initial distribution mode here. Also a value of affinity (CPUs bitmap) is not saved to irq_desc structure for the virq - later (after parsing of the DT) kernel sees that affinity is not set and sets a default value of affinity (all cores in round robin mode). As a result a value of affinity from Device Tree is ignored. To fix it I created a buffer for initial CPUs bitmaps from Device Tree. In idu_irq_xlate those bitmaps are saved to the buffer. Then affinity for virq is set manually in idu_irq_map. It works because idu_irq_xlate is always called before idu_irq_map. Despite the fact that it works I think that it must be rewritten to eliminate usage of the buffer and move all logic to idu_irq_map but I do not know how to do it correctly. Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- arch/arc/kernel/mcip.c | 15 +++ 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index 51a218c..090f0a1 100644 --- a/arch/arc/kernel/mcip.c +++ b/arch/arc/kernel/mcip.c @@ -12,12 +12,15 @@ #include #include #include +#include +#include #include #include #include static char smp_cpuinfo_buf[128]; static int idu_detected; +static unsigned long idu_cirq_to_dest[CONFIG_ARC_NUMBER_OF_INTERRUPTS]; static DEFINE_RAW_SPINLOCK(mcip_lock); @@ -232,9 +235,15 @@ static void idu_cascade_isr(struct irq_desc *desc) static int idu_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hwirq) { + cpumask_t mask; + irq_set_chip_and_handler(virq, _irq_chip, handle_level_irq); irq_set_status_flags(virq, IRQ_MOVE_PCNTXT); + cpumask_clear(); + cpumask_bits()[0] |= idu_cirq_to_dest[hwirq]; + irq_set_affinity(virq, ); + return 0; } @@ -252,8 +261,7 @@ static int idu_irq_xlate(struct irq_domain *d, struct device_node *n, if (distri == 0) { /* 0 - Round Robin to all cpus, otherwise 1 bit per core */ raw_spin_lock_irqsave(_lock, flags); - idu_set_dest(hwirq, BIT(num_online_cpus()) - 1); - idu_set_mode(hwirq, IDU_M_TRIG_LEVEL, IDU_M_DISTRI_RR); + idu_cirq_to_dest[hwirq] = BIT(num_online_cpus()) - 1; raw_spin_unlock_irqrestore(_lock, flags); } else { /* @@ -267,8 +275,7 @@ static int idu_irq_xlate(struct irq_domain *d, struct device_node *n, hwirq, cpu); raw_spin_lock_irqsave(_lock, flags); - idu_set_dest(hwirq, cpu); - idu_set_mode(hwirq, IDU_M_TRIG_LEVEL, IDU_M_DISTRI_DEST); + idu_cirq_to_dest[hwirq] = cpu; raw_spin_unlock_irqrestore(_lock, flags); } -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[PATCH v2 3/5] ARC: MCIP: Use hwirq instead of virq for resolution of IDU IRQ handlers
Multicore ARC configurations use IDU (Interrupt Distribution Unit) for distributing of common interrupts. In fact IDU is a interrupt controller on top of main per core interrupt controller. All common IRQs are physically and linearly mapped to per core interrupts. E.g. <0, 1, 2, 3> common IDU interrupts may be mapped to per core <24, 25, 26, 27> interrupts. An initialization code of IDU controller (idu_of_init) creates mappings for all parent interrupts <24, 25, ...> and sets a chained IDU handler for them. In the same time idu_of_init must save the first met parent hwirq (idu_first_irq) thus in future it is possible to figure out what common hwirq has come by subtracting of idu_first_irq from the current parent hwirq (see idu_cascade_isr). The problem is that idu_of_init and idu_cascade_isr use parent virtual IRQs as hardware IRQs and perform all the above-described manipulations on virtual IRQs. But it is wrong and hardware IRQs must be used instead. Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- arch/arc/kernel/mcip.c | 20 +--- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index 28ff766..51a218c 100644 --- a/arch/arc/kernel/mcip.c +++ b/arch/arc/kernel/mcip.c @@ -220,16 +220,14 @@ static struct irq_chip idu_irq_chip = { }; -static int idu_first_irq; +static irq_hw_number_t idu_first_hwirq; static void idu_cascade_isr(struct irq_desc *desc) { - struct irq_domain *domain = irq_desc_get_handler_data(desc); - unsigned int core_irq = irq_desc_get_irq(desc); - unsigned int idu_irq; - - idu_irq = core_irq - idu_first_irq; - generic_handle_irq(irq_find_mapping(domain, idu_irq)); + struct irq_domain *idu_domain = irq_desc_get_handler_data(desc); + irq_hw_number_t core_hwirq = irqd_to_hwirq(irq_desc_get_irq_data(desc)); + irq_hw_number_t idu_hwirq = core_hwirq - idu_first_hwirq; + generic_handle_irq(irq_find_mapping(idu_domain, idu_hwirq)); } static int idu_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hwirq) @@ -295,7 +293,7 @@ idu_of_init(struct device_node *intc, struct device_node *parent) struct irq_domain *domain; /* Read IDU BCR to confirm nr_irqs */ int nr_irqs = of_irq_count(intc); - int i, irq; + int i, virq; if (!idu_detected) panic("IDU not detected, but DeviceTree using it"); @@ -313,11 +311,11 @@ idu_of_init(struct device_node *intc, struct device_node *parent) * however we need it to get the parent virq and set IDU handler * as first level isr */ - irq = irq_of_parse_and_map(intc, i); + virq = irq_of_parse_and_map(intc, i); if (!i) - idu_first_irq = irq; + idu_first_hwirq = irqd_to_hwirq(irq_get_irq_data(virq)); - irq_set_chained_handler_and_data(irq, idu_cascade_isr, domain); + irq_set_chained_handler_and_data(virq, idu_cascade_isr, domain); } __mcip_cmd(CMD_IDU_ENABLE, 0); -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[PATCH v2 2/5] ARC: SMP: Pass virq to smp_ipi_irq_setup instead of hwirq
This function takes a cpu number and a virq number and registers an appropriate handler per cpu. However smp_ipi_irq_setup is incorrectly used in several places of ARC platform code - hwirq is passed instead of virq. There is a code with an example of inccorect usage of smp_ipi_irq_setup: smp_ipi_irq_setup(cpu, IPI_IRQ); smp_ipi_irq_setup(cpu, SOFTIRQ_IRQ); where IPI_IRQ and SOFTIRQ_IRQ are hwirq numbers for per cpu interrupts. Since smp_ipi_irq_setup must be taken a virq number insdead of a hwirq number then it is necessary to fix usage of this function this way: smp_ipi_irq_setup(cpu, irq_find_mapping(NULL, IPI_IRQ)); smp_ipi_irq_setup(cpu, irq_find_mapping(NULL, SOFTIRQ_IRQ)); The idea is to find an appropriate mapping of <domain, hwirq> to virq by using irq_find_mapping function. NULL value is used as a domain argument (a default domain) since smp_ipi_irq_setup is used for registering an IRQ handler for a root interrupt controller (a default IRQ domain must be used). Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- arch/arc/kernel/mcip.c| 5 +++-- arch/arc/plat-eznps/smp.c | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index 72f9179..28ff766 100644 --- a/arch/arc/kernel/mcip.c +++ b/arch/arc/kernel/mcip.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -22,8 +23,8 @@ static DEFINE_RAW_SPINLOCK(mcip_lock); static void mcip_setup_per_cpu(int cpu) { - smp_ipi_irq_setup(cpu, IPI_IRQ); - smp_ipi_irq_setup(cpu, SOFTIRQ_IRQ); + smp_ipi_irq_setup(cpu, irq_find_mapping(NULL, IPI_IRQ)); + smp_ipi_irq_setup(cpu, irq_find_mapping(NULL, SOFTIRQ_IRQ)); } static void mcip_ipi_send(int cpu) diff --git a/arch/arc/plat-eznps/smp.c b/arch/arc/plat-eznps/smp.c index 5e901f8..dd996e0 100644 --- a/arch/arc/plat-eznps/smp.c +++ b/arch/arc/plat-eznps/smp.c @@ -134,7 +134,7 @@ static void eznps_ipi_send(int cpu) static void eznps_init_per_cpu(int cpu) { - smp_ipi_irq_setup(cpu, NPS_IPI_IRQ); + smp_ipi_irq_setup(cpu, irq_find_mapping(NULL, NPS_IPI_IRQ)); eznps_init_core(cpu); mtm_enable_core(cpu); -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[PATCH 4/5] ARC: MCIP: Set an initial affinity value in idu_irq_map
Originally an initial distribution mode (its value resides in Device Tree) for each common interrupt is set in idu_irq_xlate. This leads to the following problems. idu_irq_xlate may be called several times during parsing of the Device Tree and it is semantically wrong to configure an initial distribution mode here. Also a value of affinity (CPUs bitmap) is not saved to irq_desc structure for the virq - later (after parsing of the DT) kernel sees that affinity is not set and sets a default value of affinity (all cores in round robin mode). As a result a value of affinity from Device Tree is ignored. To fix it I created a buffer for initial CPUs bitmaps from Device Tree. In idu_irq_xlate those bitmaps are saved to the buffer. Then affinity for virq is set manually in idu_irq_map. It works because idu_irq_xlate is always called before idu_irq_map. Despite the fact that it works I think that it must be rewritten to eliminate usage of the buffer and move all logic to idu_irq_map but I do not know how to do it correctly. Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- arch/arc/kernel/mcip.c | 15 +++ 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index 51a218c..090f0a1 100644 --- a/arch/arc/kernel/mcip.c +++ b/arch/arc/kernel/mcip.c @@ -12,12 +12,15 @@ #include #include #include +#include +#include #include #include #include static char smp_cpuinfo_buf[128]; static int idu_detected; +static unsigned long idu_cirq_to_dest[CONFIG_ARC_NUMBER_OF_INTERRUPTS]; static DEFINE_RAW_SPINLOCK(mcip_lock); @@ -232,9 +235,15 @@ static void idu_cascade_isr(struct irq_desc *desc) static int idu_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hwirq) { + cpumask_t mask; + irq_set_chip_and_handler(virq, _irq_chip, handle_level_irq); irq_set_status_flags(virq, IRQ_MOVE_PCNTXT); + cpumask_clear(); + cpumask_bits()[0] |= idu_cirq_to_dest[hwirq]; + irq_set_affinity(virq, ); + return 0; } @@ -252,8 +261,7 @@ static int idu_irq_xlate(struct irq_domain *d, struct device_node *n, if (distri == 0) { /* 0 - Round Robin to all cpus, otherwise 1 bit per core */ raw_spin_lock_irqsave(_lock, flags); - idu_set_dest(hwirq, BIT(num_online_cpus()) - 1); - idu_set_mode(hwirq, IDU_M_TRIG_LEVEL, IDU_M_DISTRI_RR); + idu_cirq_to_dest[hwirq] = BIT(num_online_cpus()) - 1; raw_spin_unlock_irqrestore(_lock, flags); } else { /* @@ -267,8 +275,7 @@ static int idu_irq_xlate(struct irq_domain *d, struct device_node *n, hwirq, cpu); raw_spin_lock_irqsave(_lock, flags); - idu_set_dest(hwirq, cpu); - idu_set_mode(hwirq, IDU_M_TRIG_LEVEL, IDU_M_DISTRI_DEST); + idu_cirq_to_dest[hwirq] = cpu; raw_spin_unlock_irqrestore(_lock, flags); } -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[PATCH 2/5] ARC: SMP: Pass virq to smp_ipi_irq_setup instead of hwirq
This function takes a cpu number and a virq number and registers an appropriate handler per cpu. However smp_ipi_irq_setup is incorrectly used in several places of ARC platform code - hwirq is passed instead of virq. There is a code with an example of inccorect usage of smp_ipi_irq_setup: smp_ipi_irq_setup(cpu, IPI_IRQ); smp_ipi_irq_setup(cpu, SOFTIRQ_IRQ); where IPI_IRQ and SOFTIRQ_IRQ are hwirq numbers for per cpu interrupts. Since smp_ipi_irq_setup must be taken a virq number insdead of a hwirq number then it is necessary to fix usage of this function this way: smp_ipi_irq_setup(cpu, irq_find_mapping(NULL, IPI_IRQ)); smp_ipi_irq_setup(cpu, irq_find_mapping(NULL, SOFTIRQ_IRQ)); The idea is to find an appropriate mapping of <domain, hwirq> to virq by using irq_find_mapping function. NULL value is used as a domain argument (a default domain) since smp_ipi_irq_setup is used for registering an IRQ handler for a root interrupt controller (a default IRQ domain must be used). Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- arch/arc/kernel/mcip.c| 5 +++-- arch/arc/plat-eznps/smp.c | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index 72f9179..28ff766 100644 --- a/arch/arc/kernel/mcip.c +++ b/arch/arc/kernel/mcip.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -22,8 +23,8 @@ static DEFINE_RAW_SPINLOCK(mcip_lock); static void mcip_setup_per_cpu(int cpu) { - smp_ipi_irq_setup(cpu, IPI_IRQ); - smp_ipi_irq_setup(cpu, SOFTIRQ_IRQ); + smp_ipi_irq_setup(cpu, irq_find_mapping(NULL, IPI_IRQ)); + smp_ipi_irq_setup(cpu, irq_find_mapping(NULL, SOFTIRQ_IRQ)); } static void mcip_ipi_send(int cpu) diff --git a/arch/arc/plat-eznps/smp.c b/arch/arc/plat-eznps/smp.c index 5e901f8..dd996e0 100644 --- a/arch/arc/plat-eznps/smp.c +++ b/arch/arc/plat-eznps/smp.c @@ -134,7 +134,7 @@ static void eznps_ipi_send(int cpu) static void eznps_init_per_cpu(int cpu) { - smp_ipi_irq_setup(cpu, NPS_IPI_IRQ); + smp_ipi_irq_setup(cpu, irq_find_mapping(NULL, NPS_IPI_IRQ)); eznps_init_core(cpu); mtm_enable_core(cpu); -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[PATCH 5/5] ARC: MCIP: Use IDU_M_DISTRI_DEST mode if there is only 1 destination core
ARC linux uses 2 distribution modes for common interrupts: round robin mode (IDU_M_DISTRI_RR) and a simple destination mode (IDU_M_DISTRI_DEST). The first one is used when more than 1 cores may handle a common interrupt and the second one is used when only 1 core may handle a common interrupt. However idu_irq_set_affinity always sets IDU_M_DISTRI_RR for all affinity values. But there is no sense in setting of such mode if only 1 core must handle a common interrupt. Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- arch/arc/kernel/mcip.c | 11 +-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index 090f0a1..75e6d73 100644 --- a/arch/arc/kernel/mcip.c +++ b/arch/arc/kernel/mcip.c @@ -197,6 +197,7 @@ idu_irq_set_affinity(struct irq_data *data, const struct cpumask *cpumask, { unsigned long flags; cpumask_t online; + unsigned long dest_bits; /* errout if no online cpu per @cpumask */ if (!cpumask_and(, cpumask, cpu_online_mask)) @@ -204,8 +205,14 @@ idu_irq_set_affinity(struct irq_data *data, const struct cpumask *cpumask, raw_spin_lock_irqsave(_lock, flags); - idu_set_dest(data->hwirq, cpumask_bits()[0]); - idu_set_mode(data->hwirq, IDU_M_TRIG_LEVEL, IDU_M_DISTRI_RR); + dest_bits = cpumask_bits()[0]; + idu_set_dest(data->hwirq, dest_bits); + + if (ffs(dest_bits) == fls(dest_bits)) { + idu_set_mode(data->hwirq, IDU_M_TRIG_LEVEL, IDU_M_DISTRI_DEST); + } else { + idu_set_mode(data->hwirq, IDU_M_TRIG_LEVEL, IDU_M_DISTRI_RR); + } raw_spin_unlock_irqrestore(_lock, flags); -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[PATCH 3/5] ARC: MCIP: Use hwirq instead of virq for resolution of IDU IRQ handlers
Multicore ARC configurations use IDU (Interrupt Distribution Unit) for distributing of common interrupts. In fact IDU is a interrupt controller on top of main per core interrupt controller. All common IRQs are physically and linearly mapped to per core interrupts. E.g. <0, 1, 2, 3> common IDU interrupts may be mapped to per core <24, 25, 26, 27> interrupts. An initialization code of IDU controller (idu_of_init) creates mappings for all parent interrupts <24, 25, ...> and sets a chained IDU handler for them. In the same time idu_of_init must save the first met parent hwirq (idu_first_irq) thus in future it is possible to figure out what common hwirq has come by subtracting of idu_first_irq from the current parent hwirq (see idu_cascade_isr). The problem is that idu_of_init and idu_cascade_isr use parent virtual IRQs as hardware IRQs and perform all the above-described manipulations on virtual IRQs. But it is wrong and hardware IRQs must be used instead. Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- arch/arc/kernel/mcip.c | 20 +--- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index 28ff766..51a218c 100644 --- a/arch/arc/kernel/mcip.c +++ b/arch/arc/kernel/mcip.c @@ -220,16 +220,14 @@ static struct irq_chip idu_irq_chip = { }; -static int idu_first_irq; +static irq_hw_number_t idu_first_hwirq; static void idu_cascade_isr(struct irq_desc *desc) { - struct irq_domain *domain = irq_desc_get_handler_data(desc); - unsigned int core_irq = irq_desc_get_irq(desc); - unsigned int idu_irq; - - idu_irq = core_irq - idu_first_irq; - generic_handle_irq(irq_find_mapping(domain, idu_irq)); + struct irq_domain *idu_domain = irq_desc_get_handler_data(desc); + irq_hw_number_t core_hwirq = irqd_to_hwirq(irq_desc_get_irq_data(desc)); + irq_hw_number_t idu_hwirq = core_hwirq - idu_first_hwirq; + generic_handle_irq(irq_find_mapping(idu_domain, idu_hwirq)); } static int idu_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hwirq) @@ -295,7 +293,7 @@ idu_of_init(struct device_node *intc, struct device_node *parent) struct irq_domain *domain; /* Read IDU BCR to confirm nr_irqs */ int nr_irqs = of_irq_count(intc); - int i, irq; + int i, virq; if (!idu_detected) panic("IDU not detected, but DeviceTree using it"); @@ -313,11 +311,11 @@ idu_of_init(struct device_node *intc, struct device_node *parent) * however we need it to get the parent virq and set IDU handler * as first level isr */ - irq = irq_of_parse_and_map(intc, i); + virq = irq_of_parse_and_map(intc, i); if (!i) - idu_first_irq = irq; + idu_first_hwirq = irqd_to_hwirq(irq_get_irq_data(virq)); - irq_set_chained_handler_and_data(irq, idu_cascade_isr, domain); + irq_set_chained_handler_and_data(virq, idu_cascade_isr, domain); } __mcip_cmd(CMD_IDU_ENABLE, 0); -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[PATCH] ARCv2: intc: Use kflag if STATUS32.IE must be reset
In the end of "arc_init_IRQ" STATUS32.IE flag is going to be affected by "flag" instruction but "flag" never touches IE flag on ARCv2. So "kflag" instruction must be used instead of "flag". Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- arch/arc/kernel/intc-arcv2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arc/kernel/intc-arcv2.c b/arch/arc/kernel/intc-arcv2.c index 6c24faf..62b59409 100644 --- a/arch/arc/kernel/intc-arcv2.c +++ b/arch/arc/kernel/intc-arcv2.c @@ -74,7 +74,7 @@ void arc_init_IRQ(void) tmp = read_aux_reg(0xa); tmp |= STATUS_AD_MASK | (irq_prio << 1); tmp &= ~STATUS_IE_MASK; - asm volatile("flag %0 \n"::"r"(tmp)); + asm volatile("kflag %0 \n"::"r"(tmp)); } static void arcv2_irq_mask(struct irq_data *data) -- 2.7.4 ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
[LTP] [PATCH v2] syscalls/fcntl34: Use flock64 instead of flock
This test uses OFD locks which are supported only by 64-bit ABI. Thus OFD locks must be used with flock64 structure for sure in this test. It is necessary because on some 32-bit targets (e.g. 32-bit uClibc) flock is not mapped to flock64 when _FILE_OFFSET_BITS is not set to 64. Signed-off-by: Yuriy Kolerov <yuriy.kole...@synopsys.com> --- testcases/kernel/syscalls/fcntl/fcntl34.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testcases/kernel/syscalls/fcntl/fcntl34.c b/testcases/kernel/syscalls/fcntl/fcntl34.c index c72951e..2f89dea 100644 --- a/testcases/kernel/syscalls/fcntl/fcntl34.c +++ b/testcases/kernel/syscalls/fcntl/fcntl34.c @@ -66,7 +66,7 @@ void *thread_fn_01(void *arg) memset(buf, (intptr_t)arg, write_size); - struct flock lck = { + struct flock64 lck = { .l_whence = SEEK_SET, .l_start = 0, .l_len= 1, ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc
RE: Problems with support of file locks for ARC (maybe for other targets too)
> -Original Message- > From: Vineet Gupta > Sent: Friday, August 12, 2016 2:39 AM > To: Yuriy Kolerov <ykole...@synopsys.com>; ucl...@uclibc.org > Cc: Waldemar Brodkorb <w...@openadk.org>; Alexey Brodkin > <abrod...@synopsys.com>; Anton Kolesov <akole...@synopsys.com>; > arcml <linux-snps-arc@lists.infradead.org> > Subject: Re: Problems with support of file locks for ARC (maybe for other > targets too) > > On 08/11/2016 09:12 AM, Yuriy Kolerov wrote: > > > >>> Moreover the whole uClibc and every application must be compiled > >>> with > >> those macros. Here is my question. Is it acceptable just to compile > >> toolchain itself using CFLAGS_FOR_TARGET with those macros and don’t > >> define them manually in each application? > >> > >> If you enable LFS support in build system (uClibc or buildroot) these > >> macros will be automatically defined - no point or need to pass them > >> as CFLAGS etc - infact that would be wrong IMO. > > If you enable __UCLIBC_HAS_LFS__ while configuring uClibc then > _LARGEFILE64_SOURCE and _FILE_OFFSET_BITS=64 will not be defined > automatically. > > What was I smoking when replying ? You are correct - these macros have to > be added to each application's makefile or at top level as target C flags. > > > E.g. Buildroot has this generic line in Makefile for packages: > > > > TARGET_CPPFLAGS += -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE > > -D_FILE_OFFSET_BITS=64 > > Actually BR dropped support for disabling LFS in 2015 - before that the line > above used to be guarded by BR2_LARGEFILE. > > > These defines are not placed to config.h or somewhere else. They must be > defined each time you compile anything. uClibc may be built by Buildroot > with these flags by default (actually it is not true at least for ARC - > Buildroot > must be fixed but it is not a subject of this discussion). However you must > define these macros manually when building every application later. > > Right, I stand corrected. > > > I don’t understand this thing - is it possible to compile uClibc with full > support of LFS (see macros above) and don’t use this feature in applications > and everything will be ok? > > Indeed this is the case - if you don't build with LFS, xxx64 won't even be > available to begin with. > > > And is it possible to compile uClibc without _LARGEFILE64_SOURCE and > _FILE_OFFSET_BITS=64 and compile applications with them and everything > will be ok? > > This mostly likely won't work as those defines will not be present in headers > to use in application. But actually it works... As for now uClibc in Buildroot is built without -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 because uClibc does not use global TARGET_CFLAGS. And all other applications (e.g. BusyBox) use those flags. Again - all those defines are presented in features.h and must be activating just by passing those -D options. I'll try to push a patch to Buildroot to force using LFS flags but what frustrates me is that everything works somehow together. > > Right now when we build toolchain for ARC using Buildroot uClibc is > compiled without them and e.g. BusyBox is compiled with - > D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 > ... > > Buildroot now assumes LFS to be default (and you can't switch it off) so > everything including uClibc / Busybox has LFS enabled already. > > > > >> So you really don't need LFS to be able to use locks - but need to > >> make sure that for common generic ABI - user struct flock pairs > >> correctly with kernel struct > >> flock64 with or w/o LFS. > > But this point remains valid - for our ABI - kernel uses struct flock64 and > this > needs to be binary compatible with uClibc struct flock and struct flock64 (LFS > only) > > Read the comment in libc/sysdeps/linux/common-generic/bits/stat.h > > -Vineet ___ linux-snps-arc mailing list linux-snps-arc@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-snps-arc