summaryrefslogtreecommitdiff
path: root/arch/mips/kernel
diff options
context:
space:
mode:
authorMatt Redfearn <matt.redfearn@imgtec.com>2016-09-20 09:47:26 +0100
committerRalf Baechle <ralf@linux-mips.org>2016-10-05 01:31:20 +0200
commit7688c5391038e60377275f078e6d7043dc115efc (patch)
tree002e34a6755e5200f01d432bf10ca35dfa8c6f45 /arch/mips/kernel
parente710d6668309d227cc7a46e9c222d97d4a502b9e (diff)
MIPS: smp.c: Introduce mechanism for freeing and allocating IPIs
For the MIPS remote processor implementation, we need additional IPIs to talk to the remote processor. Since MIPS GIC reserves exactly the right number of IPI IRQs required by Linux for the number of VPs in the system, this is not possible without releasing some recources. This commit introduces mips_smp_ipi_allocate() which allocates IPIs to a given cpumask. It is called as normal with the cpu_possible_mask at bootup to initialise IPIs to all CPUs. mips_smp_ipi_free() may then be used to free IPIs to a subset of those CPUs so that their hardware resources can be reused. Signed-off-by: Matt Redfearn <matt.redfearn@imgtec.com> Cc: Bjorn Andersson <bjorn.andersson@linaro.org> Cc: Ohad Ben-Cohen <ohad@wizery.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Lisa Parratt <Lisa.Parratt@imgtec.com> Cc: James Hogan <james.hogan@imgtec.com> Cc: Qais Yousef <qsyousef@gmail.com> Cc: Paul Burton <paul.burton@imgtec.com> Cc: linux-mips@linux-mips.org Cc: linux-remoteproc@vger.kernel.org Cc: lisa.parratt@imgtec.com Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/14285/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r--arch/mips/kernel/smp.c61
1 files changed, 53 insertions, 8 deletions
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index cb02df215365..0e131c9c39f6 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -231,7 +231,7 @@ static struct irqaction irq_call = {
.name = "IPI call"
};
-static __init void smp_ipi_init_one(unsigned int virq,
+static void smp_ipi_init_one(unsigned int virq,
struct irqaction *action)
{
int ret;
@@ -241,9 +241,11 @@ static __init void smp_ipi_init_one(unsigned int virq,
BUG_ON(ret);
}
-static int __init mips_smp_ipi_init(void)
+static unsigned int call_virq, sched_virq;
+
+int mips_smp_ipi_allocate(const struct cpumask *mask)
{
- unsigned int call_virq, sched_virq;
+ int virq;
struct irq_domain *ipidomain;
struct device_node *node;
@@ -270,16 +272,20 @@ static int __init mips_smp_ipi_init(void)
if (!ipidomain)
return 0;
- call_virq = irq_reserve_ipi(ipidomain, cpu_possible_mask);
- BUG_ON(!call_virq);
+ virq = irq_reserve_ipi(ipidomain, mask);
+ BUG_ON(!virq);
+ if (!call_virq)
+ call_virq = virq;
- sched_virq = irq_reserve_ipi(ipidomain, cpu_possible_mask);
- BUG_ON(!sched_virq);
+ virq = irq_reserve_ipi(ipidomain, mask);
+ BUG_ON(!virq);
+ if (!sched_virq)
+ sched_virq = virq;
if (irq_domain_is_ipi_per_cpu(ipidomain)) {
int cpu;
- for_each_cpu(cpu, cpu_possible_mask) {
+ for_each_cpu(cpu, mask) {
smp_ipi_init_one(call_virq + cpu, &irq_call);
smp_ipi_init_one(sched_virq + cpu, &irq_resched);
}
@@ -288,6 +294,45 @@ static int __init mips_smp_ipi_init(void)
smp_ipi_init_one(sched_virq, &irq_resched);
}
+ return 0;
+}
+
+int mips_smp_ipi_free(const struct cpumask *mask)
+{
+ struct irq_domain *ipidomain;
+ struct device_node *node;
+
+ node = of_irq_find_parent(of_root);
+ ipidomain = irq_find_matching_host(node, DOMAIN_BUS_IPI);
+
+ /*
+ * Some platforms have half DT setup. So if we found irq node but
+ * didn't find an ipidomain, try to search for one that is not in the
+ * DT.
+ */
+ if (node && !ipidomain)
+ ipidomain = irq_find_matching_host(NULL, DOMAIN_BUS_IPI);
+
+ BUG_ON(!ipidomain);
+
+ if (irq_domain_is_ipi_per_cpu(ipidomain)) {
+ int cpu;
+
+ for_each_cpu(cpu, mask) {
+ remove_irq(call_virq + cpu, &irq_call);
+ remove_irq(sched_virq + cpu, &irq_resched);
+ }
+ }
+ irq_destroy_ipi(call_virq, mask);
+ irq_destroy_ipi(sched_virq, mask);
+ return 0;
+}
+
+
+static int __init mips_smp_ipi_init(void)
+{
+ mips_smp_ipi_allocate(cpu_possible_mask);
+
call_desc = irq_to_desc(call_virq);
sched_desc = irq_to_desc(sched_virq);