Merge branch 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull irq fixes from Ingo Molnar: "Diverse irqchip driver fixes" * 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: irqchip/gic-v3-its: Fix command queue pointer comparison bug irqchip/mips-gic: Use the correct local interrupt map registers irqchip/ti-sci-inta: Fix kernel crash if irq_create_fwspec_mapping fail irqchip/irq-csky-mpintc: Support auto irq deliver to all cpus
This commit is contained in:
commit
eed7d30e12
|
@ -310,6 +310,36 @@ static inline bool mips_gic_present(void)
|
||||||
return IS_ENABLED(CONFIG_MIPS_GIC) && mips_gic_base;
|
return IS_ENABLED(CONFIG_MIPS_GIC) && mips_gic_base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mips_gic_vx_map_reg() - Return GIC_Vx_<intr>_MAP register offset
|
||||||
|
* @intr: A GIC local interrupt
|
||||||
|
*
|
||||||
|
* Determine the index of the GIC_VL_<intr>_MAP or GIC_VO_<intr>_MAP register
|
||||||
|
* within the block of GIC map registers. This is almost the same as the order
|
||||||
|
* of interrupts in the pending & mask registers, as used by enum
|
||||||
|
* mips_gic_local_interrupt, but moves the FDC interrupt & thus offsets the
|
||||||
|
* interrupts after it...
|
||||||
|
*
|
||||||
|
* Return: The map register index corresponding to @intr.
|
||||||
|
*
|
||||||
|
* The return value is suitable for use with the (read|write)_gic_v[lo]_map
|
||||||
|
* accessor functions.
|
||||||
|
*/
|
||||||
|
static inline unsigned int
|
||||||
|
mips_gic_vx_map_reg(enum mips_gic_local_interrupt intr)
|
||||||
|
{
|
||||||
|
/* WD, Compare & Timer are 1:1 */
|
||||||
|
if (intr <= GIC_LOCAL_INT_TIMER)
|
||||||
|
return intr;
|
||||||
|
|
||||||
|
/* FDC moves to after Timer... */
|
||||||
|
if (intr == GIC_LOCAL_INT_FDC)
|
||||||
|
return GIC_LOCAL_INT_TIMER + 1;
|
||||||
|
|
||||||
|
/* As a result everything else is offset by 1 */
|
||||||
|
return intr + 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gic_get_c0_compare_int() - Return cp0 count/compare interrupt virq
|
* gic_get_c0_compare_int() - Return cp0 count/compare interrupt virq
|
||||||
*
|
*
|
||||||
|
|
|
@ -89,8 +89,19 @@ static int csky_irq_set_affinity(struct irq_data *d,
|
||||||
if (cpu >= nr_cpu_ids)
|
if (cpu >= nr_cpu_ids)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* Enable interrupt destination */
|
/*
|
||||||
cpu |= BIT(31);
|
* The csky,mpintc could support auto irq deliver, but it only
|
||||||
|
* could deliver external irq to one cpu or all cpus. So it
|
||||||
|
* doesn't support deliver external irq to a group of cpus
|
||||||
|
* with cpu_mask.
|
||||||
|
* SO we only use auto deliver mode when affinity mask_val is
|
||||||
|
* equal to cpu_present_mask.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
if (cpumask_equal(mask_val, cpu_present_mask))
|
||||||
|
cpu = 0;
|
||||||
|
else
|
||||||
|
cpu |= BIT(31);
|
||||||
|
|
||||||
writel_relaxed(cpu, INTCG_base + INTCG_CIDSTR + offset);
|
writel_relaxed(cpu, INTCG_base + INTCG_CIDSTR + offset);
|
||||||
|
|
||||||
|
|
|
@ -733,32 +733,43 @@ static void its_flush_cmd(struct its_node *its, struct its_cmd_block *cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int its_wait_for_range_completion(struct its_node *its,
|
static int its_wait_for_range_completion(struct its_node *its,
|
||||||
struct its_cmd_block *from,
|
u64 prev_idx,
|
||||||
struct its_cmd_block *to)
|
struct its_cmd_block *to)
|
||||||
{
|
{
|
||||||
u64 rd_idx, from_idx, to_idx;
|
u64 rd_idx, to_idx, linear_idx;
|
||||||
u32 count = 1000000; /* 1s! */
|
u32 count = 1000000; /* 1s! */
|
||||||
|
|
||||||
from_idx = its_cmd_ptr_to_offset(its, from);
|
/* Linearize to_idx if the command set has wrapped around */
|
||||||
to_idx = its_cmd_ptr_to_offset(its, to);
|
to_idx = its_cmd_ptr_to_offset(its, to);
|
||||||
|
if (to_idx < prev_idx)
|
||||||
|
to_idx += ITS_CMD_QUEUE_SZ;
|
||||||
|
|
||||||
|
linear_idx = prev_idx;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
s64 delta;
|
||||||
|
|
||||||
rd_idx = readl_relaxed(its->base + GITS_CREADR);
|
rd_idx = readl_relaxed(its->base + GITS_CREADR);
|
||||||
|
|
||||||
/* Direct case */
|
/*
|
||||||
if (from_idx < to_idx && rd_idx >= to_idx)
|
* Compute the read pointer progress, taking the
|
||||||
break;
|
* potential wrap-around into account.
|
||||||
|
*/
|
||||||
|
delta = rd_idx - prev_idx;
|
||||||
|
if (rd_idx < prev_idx)
|
||||||
|
delta += ITS_CMD_QUEUE_SZ;
|
||||||
|
|
||||||
/* Wrapped case */
|
linear_idx += delta;
|
||||||
if (from_idx >= to_idx && rd_idx >= to_idx && rd_idx < from_idx)
|
if (linear_idx >= to_idx)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
count--;
|
count--;
|
||||||
if (!count) {
|
if (!count) {
|
||||||
pr_err_ratelimited("ITS queue timeout (%llu %llu %llu)\n",
|
pr_err_ratelimited("ITS queue timeout (%llu %llu)\n",
|
||||||
from_idx, to_idx, rd_idx);
|
to_idx, linear_idx);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
prev_idx = rd_idx;
|
||||||
cpu_relax();
|
cpu_relax();
|
||||||
udelay(1);
|
udelay(1);
|
||||||
}
|
}
|
||||||
|
@ -775,6 +786,7 @@ void name(struct its_node *its, \
|
||||||
struct its_cmd_block *cmd, *sync_cmd, *next_cmd; \
|
struct its_cmd_block *cmd, *sync_cmd, *next_cmd; \
|
||||||
synctype *sync_obj; \
|
synctype *sync_obj; \
|
||||||
unsigned long flags; \
|
unsigned long flags; \
|
||||||
|
u64 rd_idx; \
|
||||||
\
|
\
|
||||||
raw_spin_lock_irqsave(&its->lock, flags); \
|
raw_spin_lock_irqsave(&its->lock, flags); \
|
||||||
\
|
\
|
||||||
|
@ -796,10 +808,11 @@ void name(struct its_node *its, \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
post: \
|
post: \
|
||||||
|
rd_idx = readl_relaxed(its->base + GITS_CREADR); \
|
||||||
next_cmd = its_post_commands(its); \
|
next_cmd = its_post_commands(its); \
|
||||||
raw_spin_unlock_irqrestore(&its->lock, flags); \
|
raw_spin_unlock_irqrestore(&its->lock, flags); \
|
||||||
\
|
\
|
||||||
if (its_wait_for_range_completion(its, cmd, next_cmd)) \
|
if (its_wait_for_range_completion(its, rd_idx, next_cmd)) \
|
||||||
pr_err_ratelimited("ITS cmd %ps failed\n", builder); \
|
pr_err_ratelimited("ITS cmd %ps failed\n", builder); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -388,7 +388,7 @@ static void gic_all_vpes_irq_cpu_online(struct irq_data *d)
|
||||||
intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
|
intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
|
||||||
cd = irq_data_get_irq_chip_data(d);
|
cd = irq_data_get_irq_chip_data(d);
|
||||||
|
|
||||||
write_gic_vl_map(intr, cd->map);
|
write_gic_vl_map(mips_gic_vx_map_reg(intr), cd->map);
|
||||||
if (cd->mask)
|
if (cd->mask)
|
||||||
write_gic_vl_smask(BIT(intr));
|
write_gic_vl_smask(BIT(intr));
|
||||||
}
|
}
|
||||||
|
@ -517,7 +517,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
|
||||||
spin_lock_irqsave(&gic_lock, flags);
|
spin_lock_irqsave(&gic_lock, flags);
|
||||||
for_each_online_cpu(cpu) {
|
for_each_online_cpu(cpu) {
|
||||||
write_gic_vl_other(mips_cm_vp_id(cpu));
|
write_gic_vl_other(mips_cm_vp_id(cpu));
|
||||||
write_gic_vo_map(intr, map);
|
write_gic_vo_map(mips_gic_vx_map_reg(intr), map);
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&gic_lock, flags);
|
spin_unlock_irqrestore(&gic_lock, flags);
|
||||||
|
|
||||||
|
|
|
@ -159,9 +159,9 @@ static struct ti_sci_inta_vint_desc *ti_sci_inta_alloc_parent_irq(struct irq_dom
|
||||||
parent_fwspec.param[1] = vint_desc->vint_id;
|
parent_fwspec.param[1] = vint_desc->vint_id;
|
||||||
|
|
||||||
parent_virq = irq_create_fwspec_mapping(&parent_fwspec);
|
parent_virq = irq_create_fwspec_mapping(&parent_fwspec);
|
||||||
if (parent_virq <= 0) {
|
if (parent_virq == 0) {
|
||||||
kfree(vint_desc);
|
kfree(vint_desc);
|
||||||
return ERR_PTR(parent_virq);
|
return ERR_PTR(-EINVAL);
|
||||||
}
|
}
|
||||||
vint_desc->parent_virq = parent_virq;
|
vint_desc->parent_virq = parent_virq;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue