Skip to content

Commit

Permalink
irqchip/gic: Make locking a BL_SWITCHER only feature
Browse files Browse the repository at this point in the history
The BL switcher code manipulates the logical/physical CPU mapping,
forcing a lock to be taken on the IPI path. With an IPI heavy load,
this single lock becomes contended.

But when CONFIG_BL_SWITCHER is not enabled, there is no reason
to take this lock at all since the CPU mapping is immutable.

This patch allows the lock to be entierely removed when BL_SWITCHER
is not enabled (which is the case in most configurations), leading
to a small improvement of "perf bench sched pipe" (measured on
an 8 core AMD Seattle system):

Before: 101370 ops/sec
After:  103680 ops/sec

Take this opportunity to remove a useless lock being taken when
handling an interrupt on a secondary GIC.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
  • Loading branch information
Marc Zyngier committed Sep 12, 2016
1 parent 9395452 commit 04c8b0f
Showing 1 changed file with 27 additions and 9 deletions.
36 changes: 27 additions & 9 deletions drivers/irqchip/irq-gic.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,27 @@ struct gic_chip_data {
#endif
};

static DEFINE_RAW_SPINLOCK(irq_controller_lock);
#ifdef CONFIG_BL_SWITCHER

static DEFINE_RAW_SPINLOCK(cpu_map_lock);

#define gic_lock_irqsave(f) \
raw_spin_lock_irqsave(&cpu_map_lock, (f))
#define gic_unlock_irqrestore(f) \
raw_spin_unlock_irqrestore(&cpu_map_lock, (f))

#define gic_lock() raw_spin_lock(&cpu_map_lock)
#define gic_unlock() raw_spin_unlock(&cpu_map_lock)

#else

#define gic_lock_irqsave(f) do { (void)(f); } while(0)
#define gic_unlock_irqrestore(f) do { (void)(f); } while(0)

#define gic_lock() do { } while(0)
#define gic_unlock() do { } while(0)

#endif

/*
* The GIC mapping of CPU interfaces does not necessarily match
Expand Down Expand Up @@ -317,12 +337,12 @@ 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_irqsave(&irq_controller_lock, flags);
gic_lock_irqsave(flags);
mask = 0xff << shift;
bit = gic_cpu_map[cpu] << shift;
val = readl_relaxed(reg) & ~mask;
writel_relaxed(val | bit, reg);
raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
gic_unlock_irqrestore(flags);

return IRQ_SET_MASK_OK_DONE;
}
Expand Down Expand Up @@ -374,9 +394,7 @@ static void gic_handle_cascade_irq(struct irq_desc *desc)

chained_irq_enter(chip, desc);

raw_spin_lock(&irq_controller_lock);
status = readl_relaxed(gic_data_cpu_base(chip_data) + GIC_CPU_INTACK);
raw_spin_unlock(&irq_controller_lock);

gic_irq = (status & GICC_IAR_INT_ID_MASK);
if (gic_irq == GICC_INT_SPURIOUS)
Expand Down Expand Up @@ -776,7 +794,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
return;
}

raw_spin_lock_irqsave(&irq_controller_lock, flags);
gic_lock_irqsave(flags);

/* Convert our logical CPU mask into a physical one. */
for_each_cpu(cpu, mask)
Expand All @@ -791,7 +809,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);
gic_unlock_irqrestore(flags);
}
#endif

Expand Down Expand Up @@ -859,7 +877,7 @@ 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);
gic_lock();

/* Update the target interface for this logical CPU */
gic_cpu_map[cpu] = 1 << new_cpu_id;
Expand All @@ -879,7 +897,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
}
}

raw_spin_unlock(&irq_controller_lock);
gic_unlock();

/*
* Now let's migrate and clear any potential SGIs that might be
Expand Down

0 comments on commit 04c8b0f

Please sign in to comment.