Skip to content

Commit

Permalink
MIPS: smp.c: Introduce mechanism for freeing and allocating IPIs
Browse files Browse the repository at this point in the history
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 <[email protected]>
Cc: Bjorn Andersson <[email protected]>
Cc: Ohad Ben-Cohen <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Lisa Parratt <[email protected]>
Cc: James Hogan <[email protected]>
Cc: Qais Yousef <[email protected]>
Cc: Paul Burton <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Patchwork: https://patchwork.linux-mips.org/patch/14285/
Signed-off-by: Ralf Baechle <[email protected]>
  • Loading branch information
mpredfearn authored and ralfbaechle committed Oct 4, 2016
1 parent e710d66 commit 7688c53
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 8 deletions.
14 changes: 14 additions & 0 deletions arch/mips/include/asm/smp.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,20 @@ static inline void __cpu_die(unsigned int cpu)
extern void play_dead(void);
#endif

/*
* This function will set up the necessary IPIs for Linux to communicate
* with the CPUs in mask.
* Return 0 on success.
*/
int mips_smp_ipi_allocate(const struct cpumask *mask);

/*
* This function will free up IPIs allocated with mips_smp_ipi_allocate to the
* CPUs in mask, which must be a subset of the IPIs that have been configured.
* Return 0 on success.
*/
int mips_smp_ipi_free(const struct cpumask *mask);

static inline void arch_send_call_function_single_ipi(int cpu)
{
extern struct plat_smp_ops *mp_ops; /* private */
Expand Down
61 changes: 53 additions & 8 deletions arch/mips/kernel/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand All @@ -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);
}
Expand All @@ -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);

Expand Down

0 comments on commit 7688c53

Please sign in to comment.