From: Stephen Boyd <sboyd@codeaurora.org>
To: Russell King - ARM Linux <linux@arm.linux.org.uk>
Cc: Thomas Gleixner <tglx@linutronix.de>,
Jason Cooper <jason@lakedaemon.net>,
linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
Nicolas Pitre <nico@linaro.org>
Subject: Re: [PATCH v5] irqchip: gic: Allow gic_arch_extn hooks to call into scheduler
Date: Thu, 21 Aug 2014 19:06:44 -0700 [thread overview]
Message-ID: <53F6A5B4.90602@codeaurora.org> (raw)
In-Reply-To: <20140821094759.GK30401@n2100.arm.linux.org.uk>
On 08/21/14 02:47, Russell King - ARM Linux wrote:
> What would make more sense is if this were a read-write lock, then
> gic_raise_softirq() could run concurrently on several CPUs without
> interfering with each other, yet still be safe with gic_migrate_target().
>
> I'd then argue that we wouldn't need the ifdeffery, we might as well
> keep the locking in place - it's overhead is likely small (when lockdep
> is disabled) when compared to everything else which goes on in this
> path.
Ok.
>> @@ -690,6 +700,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
>> ror_val = (cur_cpu_id - new_cpu_id) & 31;
>>
>> raw_spin_lock(&irq_controller_lock);
>> + raw_spin_lock(&gic_sgi_lock);
>>
>> /* Update the target interface for this logical CPU */
>> gic_cpu_map[cpu] = 1 << new_cpu_id;
>> @@ -709,6 +720,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
>> }
>> }
>>
>> + raw_spin_unlock(&gic_sgi_lock);
>> raw_spin_unlock(&irq_controller_lock);
> I would actually suggest we go a bit further. Use gic_sgi_lock to only
> lock gic_cpu_map[] itself, and not have it beneath any other lock.
> That's an advantage because right now, lockdep learns from the above that
> there's a dependency between irq_controller_lock and gic_sgi_lock.
> Reasonably keeping lock dependencies to a minimum is always a good idea.
>
> The places where gic_cpu_map[] is used are:
>
> static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
> bool force)
> {
> ...
> raw_spin_lock(&irq_controller_lock);
> mask = 0xff << shift;
> bit = gic_cpu_map[cpu] << shift;
> val = readl_relaxed(reg) & ~mask;
> writel_relaxed(val | bit, reg);
> raw_spin_unlock(&irq_controller_lock);
>
> So, we can move:
>
> mask = 0xff << shift;
> bit = gic_cpu_map[cpu] << shift;
>
> out from under irq_controller_lock and put it under gic_sgi_lock. The
> "mask" bit doesn't need to be under any lock at all.
>
> There's gic_cpu_init():
>
> cpu_mask = gic_get_cpumask(gic);
> gic_cpu_map[cpu] = cpu_mask;
>
> /*
> * Clear our mask from the other map entries in case they're
> * still undefined.
> */
> for (i = 0; i < NR_GIC_CPU_IF; i++)
> if (i != cpu)
> gic_cpu_map[i] &= ~cpu_mask;
>
> which better had be stable after boot - if not, this needs locking.
> Remember that the above will be called on hotplug too.
>
Perhaps you'd like to send this patch? It isn't clear to me from your
description how this would work. What happens if we update the
gic_cpu_map between the time we read the map and acquire the
irq_controller_lock in gic_set_affinity()? I think we would program the
affinity for the wrong CPU?
Either way, here's the patch I think you described.
----8<-----
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 4b959e606fe8..d159590461c7 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -39,6 +39,7 @@
#include <linux/slab.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/irqchip/arm-gic.h>
+#include <linux/rwlock.h>
#include <asm/cputype.h>
#include <asm/irq.h>
@@ -79,6 +80,7 @@ static DEFINE_RAW_SPINLOCK(irq_controller_lock);
*/
#define NR_GIC_CPU_IF 8
static u8 gic_cpu_map[NR_GIC_CPU_IF] __read_mostly;
+static DEFINE_RWLOCK(gic_cpu_map_lock);
/*
* Supported arch specific GIC irq extension.
@@ -233,9 +235,13 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
if (cpu >= NR_GIC_CPU_IF || cpu >= nr_cpu_ids)
return -EINVAL;
- raw_spin_lock(&irq_controller_lock);
mask = 0xff << shift;
+
+ read_lock(&gic_cpu_map_lock);
bit = gic_cpu_map[cpu] << shift;
+ read_unlock(&gic_cpu_map_lock);
+
+ raw_spin_lock(&irq_controller_lock);
val = readl_relaxed(reg) & ~mask;
writel_relaxed(val | bit, reg);
raw_spin_unlock(&irq_controller_lock);
@@ -605,7 +611,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
int cpu;
unsigned long flags, map = 0;
- raw_spin_lock_irqsave(&irq_controller_lock, flags);
+ read_lock_irqsave(&gic_cpu_map_lock, flags);
/* Convert our logical CPU mask into a physical one. */
for_each_cpu(cpu, mask)
@@ -620,7 +626,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
/* this always happens on GIC0 */
writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
- raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+ read_unlock_irqrestore(&gic_cpu_map_lock, flags);
}
#endif
@@ -689,11 +695,12 @@ void gic_migrate_target(unsigned int new_cpu_id)
cur_target_mask = 0x01010101 << cur_cpu_id;
ror_val = (cur_cpu_id - new_cpu_id) & 31;
- raw_spin_lock(&irq_controller_lock);
-
+ write_lock(&gic_cpu_map_lock);
/* Update the target interface for this logical CPU */
gic_cpu_map[cpu] = 1 << new_cpu_id;
+ write_unlock(&gic_cpu_map_lock);
+ raw_spin_lock(&irq_controller_lock);
/*
* Find all the peripheral interrupts targetting the current
* CPU interface and migrate them to the new CPU interface.
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
WARNING: multiple messages have this Message-ID (diff)
From: sboyd@codeaurora.org (Stephen Boyd)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v5] irqchip: gic: Allow gic_arch_extn hooks to call into scheduler
Date: Thu, 21 Aug 2014 19:06:44 -0700 [thread overview]
Message-ID: <53F6A5B4.90602@codeaurora.org> (raw)
In-Reply-To: <20140821094759.GK30401@n2100.arm.linux.org.uk>
On 08/21/14 02:47, Russell King - ARM Linux wrote:
> What would make more sense is if this were a read-write lock, then
> gic_raise_softirq() could run concurrently on several CPUs without
> interfering with each other, yet still be safe with gic_migrate_target().
>
> I'd then argue that we wouldn't need the ifdeffery, we might as well
> keep the locking in place - it's overhead is likely small (when lockdep
> is disabled) when compared to everything else which goes on in this
> path.
Ok.
>> @@ -690,6 +700,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
>> ror_val = (cur_cpu_id - new_cpu_id) & 31;
>>
>> raw_spin_lock(&irq_controller_lock);
>> + raw_spin_lock(&gic_sgi_lock);
>>
>> /* Update the target interface for this logical CPU */
>> gic_cpu_map[cpu] = 1 << new_cpu_id;
>> @@ -709,6 +720,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
>> }
>> }
>>
>> + raw_spin_unlock(&gic_sgi_lock);
>> raw_spin_unlock(&irq_controller_lock);
> I would actually suggest we go a bit further. Use gic_sgi_lock to only
> lock gic_cpu_map[] itself, and not have it beneath any other lock.
> That's an advantage because right now, lockdep learns from the above that
> there's a dependency between irq_controller_lock and gic_sgi_lock.
> Reasonably keeping lock dependencies to a minimum is always a good idea.
>
> The places where gic_cpu_map[] is used are:
>
> static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
> bool force)
> {
> ...
> raw_spin_lock(&irq_controller_lock);
> mask = 0xff << shift;
> bit = gic_cpu_map[cpu] << shift;
> val = readl_relaxed(reg) & ~mask;
> writel_relaxed(val | bit, reg);
> raw_spin_unlock(&irq_controller_lock);
>
> So, we can move:
>
> mask = 0xff << shift;
> bit = gic_cpu_map[cpu] << shift;
>
> out from under irq_controller_lock and put it under gic_sgi_lock. The
> "mask" bit doesn't need to be under any lock at all.
>
> There's gic_cpu_init():
>
> cpu_mask = gic_get_cpumask(gic);
> gic_cpu_map[cpu] = cpu_mask;
>
> /*
> * Clear our mask from the other map entries in case they're
> * still undefined.
> */
> for (i = 0; i < NR_GIC_CPU_IF; i++)
> if (i != cpu)
> gic_cpu_map[i] &= ~cpu_mask;
>
> which better had be stable after boot - if not, this needs locking.
> Remember that the above will be called on hotplug too.
>
Perhaps you'd like to send this patch? It isn't clear to me from your
description how this would work. What happens if we update the
gic_cpu_map between the time we read the map and acquire the
irq_controller_lock in gic_set_affinity()? I think we would program the
affinity for the wrong CPU?
Either way, here's the patch I think you described.
----8<-----
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 4b959e606fe8..d159590461c7 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -39,6 +39,7 @@
#include <linux/slab.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/irqchip/arm-gic.h>
+#include <linux/rwlock.h>
#include <asm/cputype.h>
#include <asm/irq.h>
@@ -79,6 +80,7 @@ static DEFINE_RAW_SPINLOCK(irq_controller_lock);
*/
#define NR_GIC_CPU_IF 8
static u8 gic_cpu_map[NR_GIC_CPU_IF] __read_mostly;
+static DEFINE_RWLOCK(gic_cpu_map_lock);
/*
* Supported arch specific GIC irq extension.
@@ -233,9 +235,13 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
if (cpu >= NR_GIC_CPU_IF || cpu >= nr_cpu_ids)
return -EINVAL;
- raw_spin_lock(&irq_controller_lock);
mask = 0xff << shift;
+
+ read_lock(&gic_cpu_map_lock);
bit = gic_cpu_map[cpu] << shift;
+ read_unlock(&gic_cpu_map_lock);
+
+ raw_spin_lock(&irq_controller_lock);
val = readl_relaxed(reg) & ~mask;
writel_relaxed(val | bit, reg);
raw_spin_unlock(&irq_controller_lock);
@@ -605,7 +611,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
int cpu;
unsigned long flags, map = 0;
- raw_spin_lock_irqsave(&irq_controller_lock, flags);
+ read_lock_irqsave(&gic_cpu_map_lock, flags);
/* Convert our logical CPU mask into a physical one. */
for_each_cpu(cpu, mask)
@@ -620,7 +626,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
/* this always happens on GIC0 */
writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
- raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+ read_unlock_irqrestore(&gic_cpu_map_lock, flags);
}
#endif
@@ -689,11 +695,12 @@ void gic_migrate_target(unsigned int new_cpu_id)
cur_target_mask = 0x01010101 << cur_cpu_id;
ror_val = (cur_cpu_id - new_cpu_id) & 31;
- raw_spin_lock(&irq_controller_lock);
-
+ write_lock(&gic_cpu_map_lock);
/* Update the target interface for this logical CPU */
gic_cpu_map[cpu] = 1 << new_cpu_id;
+ write_unlock(&gic_cpu_map_lock);
+ raw_spin_lock(&irq_controller_lock);
/*
* Find all the peripheral interrupts targetting the current
* CPU interface and migrate them to the new CPU interface.
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
next prev parent reply other threads:[~2014-08-22 2:06 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-08-20 19:22 [PATCH v5] irqchip: gic: Allow gic_arch_extn hooks to call into scheduler Stephen Boyd
2014-08-20 19:22 ` Stephen Boyd
2014-08-20 20:43 ` Nicolas Pitre
2014-08-20 20:43 ` Nicolas Pitre
2014-08-21 9:47 ` Russell King - ARM Linux
2014-08-21 9:47 ` Russell King - ARM Linux
2014-08-22 2:06 ` Stephen Boyd [this message]
2014-08-22 2:06 ` Stephen Boyd
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=53F6A5B4.90602@codeaurora.org \
--to=sboyd@codeaurora.org \
--cc=jason@lakedaemon.net \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@arm.linux.org.uk \
--cc=nico@linaro.org \
--cc=tglx@linutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.