forked from luck/tmp_suning_uos_patched
irqchip/hip04: Configure IPIs as standard interrupts
In order to switch the hip04 driver to provide standard interrupts for IPIs, rework the way interrupts are allocated, making sure the irqdomain covers the SGIs as well as the rest of the interrupt range. The driver is otherwise so old-school that it creates all interrupts upfront (duh!), so there is hardly anything else to change, apart from communicating the IPIs to the arch code. Signed-off-by: Marc Zyngier <maz@kernel.org>
This commit is contained in:
parent
0809ae7249
commit
a2df12c589
|
@ -171,6 +171,29 @@ static int hip04_irq_set_affinity(struct irq_data *d,
|
||||||
|
|
||||||
return IRQ_SET_MASK_OK;
|
return IRQ_SET_MASK_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hip04_ipi_send_mask(struct irq_data *d, const struct cpumask *mask)
|
||||||
|
{
|
||||||
|
int cpu;
|
||||||
|
unsigned long flags, map = 0;
|
||||||
|
|
||||||
|
raw_spin_lock_irqsave(&irq_controller_lock, flags);
|
||||||
|
|
||||||
|
/* Convert our logical CPU mask into a physical one. */
|
||||||
|
for_each_cpu(cpu, mask)
|
||||||
|
map |= hip04_cpu_map[cpu];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ensure that stores to Normal memory are visible to the
|
||||||
|
* other CPUs before they observe us issuing the IPI.
|
||||||
|
*/
|
||||||
|
dmb(ishst);
|
||||||
|
|
||||||
|
/* this always happens on GIC0 */
|
||||||
|
writel_relaxed(map << 8 | d->hwirq, hip04_data.dist_base + GIC_DIST_SOFTINT);
|
||||||
|
|
||||||
|
raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void __exception_irq_entry hip04_handle_irq(struct pt_regs *regs)
|
static void __exception_irq_entry hip04_handle_irq(struct pt_regs *regs)
|
||||||
|
@ -182,19 +205,9 @@ static void __exception_irq_entry hip04_handle_irq(struct pt_regs *regs)
|
||||||
irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
|
irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
|
||||||
irqnr = irqstat & GICC_IAR_INT_ID_MASK;
|
irqnr = irqstat & GICC_IAR_INT_ID_MASK;
|
||||||
|
|
||||||
if (likely(irqnr > 15 && irqnr <= HIP04_MAX_IRQS)) {
|
if (irqnr <= HIP04_MAX_IRQS)
|
||||||
handle_domain_irq(hip04_data.domain, irqnr, regs);
|
handle_domain_irq(hip04_data.domain, irqnr, regs);
|
||||||
continue;
|
} while (irqnr > HIP04_MAX_IRQS);
|
||||||
}
|
|
||||||
if (irqnr < 16) {
|
|
||||||
writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
|
|
||||||
#ifdef CONFIG_SMP
|
|
||||||
handle_IPI(irqnr, regs);
|
|
||||||
#endif
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
} while (1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct irq_chip hip04_irq_chip = {
|
static struct irq_chip hip04_irq_chip = {
|
||||||
|
@ -205,6 +218,7 @@ static struct irq_chip hip04_irq_chip = {
|
||||||
.irq_set_type = hip04_irq_set_type,
|
.irq_set_type = hip04_irq_set_type,
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
.irq_set_affinity = hip04_irq_set_affinity,
|
.irq_set_affinity = hip04_irq_set_affinity,
|
||||||
|
.ipi_send_mask = hip04_ipi_send_mask,
|
||||||
#endif
|
#endif
|
||||||
.flags = IRQCHIP_SET_TYPE_MASKED |
|
.flags = IRQCHIP_SET_TYPE_MASKED |
|
||||||
IRQCHIP_SKIP_SET_WAKE |
|
IRQCHIP_SKIP_SET_WAKE |
|
||||||
|
@ -279,39 +293,17 @@ static void hip04_irq_cpu_init(struct hip04_irq_data *intc)
|
||||||
writel_relaxed(1, base + GIC_CPU_CTRL);
|
writel_relaxed(1, base + GIC_CPU_CTRL);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
|
||||||
static void hip04_raise_softirq(const struct cpumask *mask, unsigned int irq)
|
|
||||||
{
|
|
||||||
int cpu;
|
|
||||||
unsigned long flags, map = 0;
|
|
||||||
|
|
||||||
raw_spin_lock_irqsave(&irq_controller_lock, flags);
|
|
||||||
|
|
||||||
/* Convert our logical CPU mask into a physical one. */
|
|
||||||
for_each_cpu(cpu, mask)
|
|
||||||
map |= hip04_cpu_map[cpu];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Ensure that stores to Normal memory are visible to the
|
|
||||||
* other CPUs before they observe us issuing the IPI.
|
|
||||||
*/
|
|
||||||
dmb(ishst);
|
|
||||||
|
|
||||||
/* this always happens on GIC0 */
|
|
||||||
writel_relaxed(map << 8 | irq, hip04_data.dist_base + GIC_DIST_SOFTINT);
|
|
||||||
|
|
||||||
raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int hip04_irq_domain_map(struct irq_domain *d, unsigned int irq,
|
static int hip04_irq_domain_map(struct irq_domain *d, unsigned int irq,
|
||||||
irq_hw_number_t hw)
|
irq_hw_number_t hw)
|
||||||
{
|
{
|
||||||
if (hw < 32) {
|
if (hw < 16) {
|
||||||
|
irq_set_percpu_devid(irq);
|
||||||
|
irq_set_chip_and_handler(irq, &hip04_irq_chip,
|
||||||
|
handle_percpu_devid_fasteoi_ipi);
|
||||||
|
} else if (hw < 32) {
|
||||||
irq_set_percpu_devid(irq);
|
irq_set_percpu_devid(irq);
|
||||||
irq_set_chip_and_handler(irq, &hip04_irq_chip,
|
irq_set_chip_and_handler(irq, &hip04_irq_chip,
|
||||||
handle_percpu_devid_irq);
|
handle_percpu_devid_irq);
|
||||||
irq_set_status_flags(irq, IRQ_NOAUTOEN);
|
|
||||||
} else {
|
} else {
|
||||||
irq_set_chip_and_handler(irq, &hip04_irq_chip,
|
irq_set_chip_and_handler(irq, &hip04_irq_chip,
|
||||||
handle_fasteoi_irq);
|
handle_fasteoi_irq);
|
||||||
|
@ -328,10 +320,13 @@ static int hip04_irq_domain_xlate(struct irq_domain *d,
|
||||||
unsigned long *out_hwirq,
|
unsigned long *out_hwirq,
|
||||||
unsigned int *out_type)
|
unsigned int *out_type)
|
||||||
{
|
{
|
||||||
unsigned long ret = 0;
|
|
||||||
|
|
||||||
if (irq_domain_get_of_node(d) != controller)
|
if (irq_domain_get_of_node(d) != controller)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
if (intsize == 1 && intspec[0] < 16) {
|
||||||
|
*out_hwirq = intspec[0];
|
||||||
|
*out_type = IRQ_TYPE_EDGE_RISING;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (intsize < 3)
|
if (intsize < 3)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
@ -344,7 +339,7 @@ static int hip04_irq_domain_xlate(struct irq_domain *d,
|
||||||
|
|
||||||
*out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
|
*out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
|
||||||
|
|
||||||
return ret;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hip04_irq_starting_cpu(unsigned int cpu)
|
static int hip04_irq_starting_cpu(unsigned int cpu)
|
||||||
|
@ -361,7 +356,6 @@ static const struct irq_domain_ops hip04_irq_domain_ops = {
|
||||||
static int __init
|
static int __init
|
||||||
hip04_of_init(struct device_node *node, struct device_node *parent)
|
hip04_of_init(struct device_node *node, struct device_node *parent)
|
||||||
{
|
{
|
||||||
irq_hw_number_t hwirq_base = 16;
|
|
||||||
int nr_irqs, irq_base, i;
|
int nr_irqs, irq_base, i;
|
||||||
|
|
||||||
if (WARN_ON(!node))
|
if (WARN_ON(!node))
|
||||||
|
@ -390,24 +384,21 @@ hip04_of_init(struct device_node *node, struct device_node *parent)
|
||||||
nr_irqs = HIP04_MAX_IRQS;
|
nr_irqs = HIP04_MAX_IRQS;
|
||||||
hip04_data.nr_irqs = nr_irqs;
|
hip04_data.nr_irqs = nr_irqs;
|
||||||
|
|
||||||
nr_irqs -= hwirq_base; /* calculate # of irqs to allocate */
|
irq_base = irq_alloc_descs(-1, 0, nr_irqs, numa_node_id());
|
||||||
|
|
||||||
irq_base = irq_alloc_descs(-1, hwirq_base, nr_irqs, numa_node_id());
|
|
||||||
if (irq_base < 0) {
|
if (irq_base < 0) {
|
||||||
pr_err("failed to allocate IRQ numbers\n");
|
pr_err("failed to allocate IRQ numbers\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
hip04_data.domain = irq_domain_add_legacy(node, nr_irqs, irq_base,
|
hip04_data.domain = irq_domain_add_legacy(node, nr_irqs, irq_base,
|
||||||
hwirq_base,
|
0,
|
||||||
&hip04_irq_domain_ops,
|
&hip04_irq_domain_ops,
|
||||||
&hip04_data);
|
&hip04_data);
|
||||||
|
|
||||||
if (WARN_ON(!hip04_data.domain))
|
if (WARN_ON(!hip04_data.domain))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
set_smp_cross_call(hip04_raise_softirq);
|
set_smp_ipi_range(irq_base, 16);
|
||||||
#endif
|
#endif
|
||||||
set_handle_irq(hip04_handle_irq);
|
set_handle_irq(hip04_handle_irq);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user