summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/irqchip/irq-gic-v3-its.c4
-rw-r--r--drivers/irqchip/irq-ls-extirq.c53
-rw-r--r--drivers/irqchip/irq-mmp.c2
-rw-r--r--drivers/irqchip/irq-sifive-plic.c7
-rw-r--r--include/linux/irqchip/arm-gic-v3.h1
5 files changed, 46 insertions, 21 deletions
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 30783814f9d9..291d7668cc8d 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -3474,6 +3474,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
int lpi_base;
int nr_lpis;
int nr_ites;
+ int id_bits;
int sz;
if (!its_alloc_device_table(its, dev_id))
@@ -3485,7 +3486,10 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
/*
* Even if the device wants a single LPI, the ITT must be
* sized as a power of two (and you need at least one bit...).
+ * Also honor the ITS's own EID limit.
*/
+ id_bits = FIELD_GET(GITS_TYPER_IDBITS, its->typer) + 1;
+ nvecs = min_t(unsigned int, nvecs, BIT(id_bits));
nr_ites = max(2, nvecs);
sz = nr_ites * (FIELD_GET(GITS_TYPER_ITT_ENTRY_SIZE, its->typer) + 1);
sz = max(sz, ITS_ITT_ALIGN);
diff --git a/drivers/irqchip/irq-ls-extirq.c b/drivers/irqchip/irq-ls-extirq.c
index a7e9c3885b09..d724fe843980 100644
--- a/drivers/irqchip/irq-ls-extirq.c
+++ b/drivers/irqchip/irq-ls-extirq.c
@@ -125,32 +125,45 @@ static const struct irq_domain_ops extirq_domain_ops = {
static int
ls_extirq_parse_map(struct ls_extirq_data *priv, struct device_node *node)
{
- struct of_imap_parser imap_parser;
- struct of_imap_item imap_item;
+ const __be32 *map;
+ u32 mapsize;
int ret;
- ret = of_imap_parser_init(&imap_parser, node, &imap_item);
- if (ret)
- return ret;
+ map = of_get_property(node, "interrupt-map", &mapsize);
+ if (!map)
+ return -ENOENT;
+ if (mapsize % sizeof(*map))
+ return -EINVAL;
+ mapsize /= sizeof(*map);
- for_each_of_imap_item(&imap_parser, &imap_item) {
+ while (mapsize) {
struct device_node *ipar;
- u32 hwirq;
- int i;
+ u32 hwirq, intsize, j;
- hwirq = imap_item.child_imap[0];
- if (hwirq >= MAXIRQ) {
- of_node_put(imap_item.parent_args.np);
+ if (mapsize < 3)
+ return -EINVAL;
+ hwirq = be32_to_cpup(map);
+ if (hwirq >= MAXIRQ)
return -EINVAL;
- }
priv->nirq = max(priv->nirq, hwirq + 1);
- ipar = of_node_get(imap_item.parent_args.np);
- priv->map[hwirq].fwnode = of_fwnode_handle(ipar);
+ ipar = of_find_node_by_phandle(be32_to_cpup(map + 2));
+ map += 3;
+ mapsize -= 3;
+ if (!ipar)
+ return -EINVAL;
+ priv->map[hwirq].fwnode = &ipar->fwnode;
+ ret = of_property_read_u32(ipar, "#interrupt-cells", &intsize);
+ if (ret)
+ return ret;
- priv->map[hwirq].param_count = imap_item.parent_args.args_count;
- for (i = 0; i < priv->map[hwirq].param_count; i++)
- priv->map[hwirq].param[i] = imap_item.parent_args.args[i];
+ if (intsize > mapsize)
+ return -EINVAL;
+
+ priv->map[hwirq].param_count = intsize;
+ for (j = 0; j < intsize; ++j)
+ priv->map[hwirq].param[j] = be32_to_cpup(map++);
+ mapsize -= intsize;
}
return 0;
}
@@ -177,8 +190,10 @@ static int ls_extirq_probe(struct platform_device *pdev)
return dev_err_probe(dev, -ENOMEM, "Failed to allocate memory\n");
priv->intpcr = devm_of_iomap(dev, node, 0, NULL);
- if (!priv->intpcr)
- return dev_err_probe(dev, -ENOMEM, "Cannot ioremap OF node %pOF\n", node);
+ if (IS_ERR(priv->intpcr)) {
+ return dev_err_probe(dev, PTR_ERR(priv->intpcr),
+ "Cannot ioremap OF node %pOF\n", node);
+ }
ret = ls_extirq_parse_map(priv, node);
if (ret)
diff --git a/drivers/irqchip/irq-mmp.c b/drivers/irqchip/irq-mmp.c
index 09e640430208..8e210cb451be 100644
--- a/drivers/irqchip/irq-mmp.c
+++ b/drivers/irqchip/irq-mmp.c
@@ -136,7 +136,7 @@ static void icu_unmask_irq(struct irq_data *d)
}
}
-struct irq_chip icu_irq_chip = {
+static const struct irq_chip icu_irq_chip = {
.name = "icu_irq",
.irq_mask = icu_mask_irq,
.irq_mask_ack = icu_mask_ack_irq,
diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c
index 686d39254426..5b0dac104814 100644
--- a/drivers/irqchip/irq-sifive-plic.c
+++ b/drivers/irqchip/irq-sifive-plic.c
@@ -172,8 +172,13 @@ static void plic_irq_disable(struct irq_data *d)
static void plic_irq_eoi(struct irq_data *d)
{
struct plic_handler *handler = this_cpu_ptr(&plic_handlers);
+ u32 __iomem *reg;
+ bool enabled;
+
+ reg = handler->enable_base + (d->hwirq / 32) * sizeof(u32);
+ enabled = readl(reg) & BIT(d->hwirq % 32);
- if (unlikely(irqd_irq_disabled(d))) {
+ if (unlikely(!enabled)) {
plic_toggle(handler, d->hwirq, 1);
writel(d->hwirq, handler->hart_base + CONTEXT_CLAIM);
plic_toggle(handler, d->hwirq, 0);
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index 70c0948f978e..0225121f3013 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -394,6 +394,7 @@
#define GITS_TYPER_VLPIS (1UL << 1)
#define GITS_TYPER_ITT_ENTRY_SIZE_SHIFT 4
#define GITS_TYPER_ITT_ENTRY_SIZE GENMASK_ULL(7, 4)
+#define GITS_TYPER_IDBITS GENMASK_ULL(12, 8)
#define GITS_TYPER_IDBITS_SHIFT 8
#define GITS_TYPER_DEVBITS_SHIFT 13
#define GITS_TYPER_DEVBITS GENMASK_ULL(17, 13)