2016-12-28 08:48:04

by Yuriy Kolerov

[permalink] [raw]
Subject: [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



2016-12-28 08:47:36

by Yuriy Kolerov

[permalink] [raw]
Subject: [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 <[email protected]>
---
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


2016-12-28 08:47:37

by Yuriy Kolerov

[permalink] [raw]
Subject: [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 <[email protected]>
---
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 <linux/smp.h>
#include <linux/irq.h>
+#include <linux/irqchip/chained_irq.h>
#include <linux/spinlock.h>
#include <asm/irqflags-arcv2.h>
#include <asm/mcip.h>
@@ -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


2016-12-28 08:48:03

by Yuriy Kolerov

[permalink] [raw]
Subject: [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 <[email protected]>
---
.../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(&mcip_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(&mcip_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(&mcip_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(&mcip_lock, flags);
- idu_set_dest(hwirq, cpu);
- idu_set_mode(hwirq, IDU_M_TRIG_LEVEL, IDU_M_DISTRI_DEST);
- raw_spin_unlock_irqrestore(&mcip_lock, flags);
- }
-
return 0;
}

--
2.7.4