Commit b8d49bcd authored by Thomas Gleixner's avatar Thomas Gleixner

Merge tag 'irqchip-fixes-6.1-1' of...

Merge tag 'irqchip-fixes-6.1-1' of git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms into irq/core

Pull irqchip fixes from Marc Zyngier:

  - Fix IMX-MU Kconfig, keeping it private to IMX

  - Fix a register offset for the same IMX-MU driver

  - Fix the ls-extirq irqchip driver that would use the wrong
    flavour of spinlocks

Link: https://lore.kernel.org/r/20221012075125.1244143-1-maz@kernel.org
parents 36de4f94 6c9f7434
...@@ -484,14 +484,15 @@ config IMX_INTMUX ...@@ -484,14 +484,15 @@ config IMX_INTMUX
config IMX_MU_MSI config IMX_MU_MSI
tristate "i.MX MU used as MSI controller" tristate "i.MX MU used as MSI controller"
depends on OF && HAS_IOMEM depends on OF && HAS_IOMEM
depends on ARCH_MXC || COMPILE_TEST
default m if ARCH_MXC default m if ARCH_MXC
select IRQ_DOMAIN select IRQ_DOMAIN
select IRQ_DOMAIN_HIERARCHY select IRQ_DOMAIN_HIERARCHY
select GENERIC_MSI_IRQ_DOMAIN select GENERIC_MSI_IRQ_DOMAIN
help help
Provide a driver for the MU block used as a CPU-to-CPU MSI Provide a driver for the i.MX Messaging Unit block used as a
controller. This requires a specially crafted DT to make use CPU-to-CPU MSI controller. This requires a specially crafted DT
of this driver. to make use of this driver.
If unsure, say N If unsure, say N
......
...@@ -292,7 +292,7 @@ static const struct imx_mu_dcfg imx_mu_cfg_imx8ulp = { ...@@ -292,7 +292,7 @@ static const struct imx_mu_dcfg imx_mu_cfg_imx8ulp = {
.xSR = { .xSR = {
[IMX_MU_SR] = 0xC, [IMX_MU_SR] = 0xC,
[IMX_MU_GSR] = 0x118, [IMX_MU_GSR] = 0x118,
[IMX_MU_GSR] = 0x124, [IMX_MU_TSR] = 0x124,
[IMX_MU_RSR] = 0x12C, [IMX_MU_RSR] = 0x12C,
}, },
.xCR = { .xCR = {
......
...@@ -6,8 +6,7 @@ ...@@ -6,8 +6,7 @@
#include <linux/irqchip.h> #include <linux/irqchip.h>
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/mfd/syscon.h> #include <linux/of_address.h>
#include <linux/regmap.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/interrupt-controller/arm-gic.h>
...@@ -16,13 +15,41 @@ ...@@ -16,13 +15,41 @@
#define LS1021A_SCFGREVCR 0x200 #define LS1021A_SCFGREVCR 0x200
struct ls_extirq_data { struct ls_extirq_data {
struct regmap *syscon; void __iomem *intpcr;
u32 intpcr; raw_spinlock_t lock;
bool big_endian;
bool is_ls1021a_or_ls1043a; bool is_ls1021a_or_ls1043a;
u32 nirq; u32 nirq;
struct irq_fwspec map[MAXIRQ]; struct irq_fwspec map[MAXIRQ];
}; };
static void ls_extirq_intpcr_rmw(struct ls_extirq_data *priv, u32 mask,
u32 value)
{
u32 intpcr;
/*
* Serialize concurrent calls to ls_extirq_set_type() from multiple
* IRQ descriptors, making sure the read-modify-write is atomic.
*/
raw_spin_lock(&priv->lock);
if (priv->big_endian)
intpcr = ioread32be(priv->intpcr);
else
intpcr = ioread32(priv->intpcr);
intpcr &= ~mask;
intpcr |= value;
if (priv->big_endian)
iowrite32be(intpcr, priv->intpcr);
else
iowrite32(intpcr, priv->intpcr);
raw_spin_unlock(&priv->lock);
}
static int static int
ls_extirq_set_type(struct irq_data *data, unsigned int type) ls_extirq_set_type(struct irq_data *data, unsigned int type)
{ {
...@@ -51,7 +78,8 @@ ls_extirq_set_type(struct irq_data *data, unsigned int type) ...@@ -51,7 +78,8 @@ ls_extirq_set_type(struct irq_data *data, unsigned int type)
default: default:
return -EINVAL; return -EINVAL;
} }
regmap_update_bits(priv->syscon, priv->intpcr, mask, value);
ls_extirq_intpcr_rmw(priv, mask, value);
return irq_chip_set_type_parent(data, type); return irq_chip_set_type_parent(data, type);
} }
...@@ -143,7 +171,6 @@ ls_extirq_parse_map(struct ls_extirq_data *priv, struct device_node *node) ...@@ -143,7 +171,6 @@ ls_extirq_parse_map(struct ls_extirq_data *priv, struct device_node *node)
static int __init static int __init
ls_extirq_of_init(struct device_node *node, struct device_node *parent) ls_extirq_of_init(struct device_node *node, struct device_node *parent)
{ {
struct irq_domain *domain, *parent_domain; struct irq_domain *domain, *parent_domain;
struct ls_extirq_data *priv; struct ls_extirq_data *priv;
int ret; int ret;
...@@ -151,40 +178,52 @@ ls_extirq_of_init(struct device_node *node, struct device_node *parent) ...@@ -151,40 +178,52 @@ ls_extirq_of_init(struct device_node *node, struct device_node *parent)
parent_domain = irq_find_host(parent); parent_domain = irq_find_host(parent);
if (!parent_domain) { if (!parent_domain) {
pr_err("Cannot find parent domain\n"); pr_err("Cannot find parent domain\n");
return -ENODEV; ret = -ENODEV;
goto err_irq_find_host;
} }
priv = kzalloc(sizeof(*priv), GFP_KERNEL); priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) if (!priv) {
return -ENOMEM; ret = -ENOMEM;
goto err_alloc_priv;
priv->syscon = syscon_node_to_regmap(node->parent);
if (IS_ERR(priv->syscon)) {
ret = PTR_ERR(priv->syscon);
pr_err("Failed to lookup parent regmap\n");
goto out;
} }
ret = of_property_read_u32(node, "reg", &priv->intpcr);
if (ret) { /*
pr_err("Missing INTPCR offset value\n"); * All extirq OF nodes are under a scfg/syscon node with
goto out; * the 'ranges' property
*/
priv->intpcr = of_iomap(node, 0);
if (!priv->intpcr) {
pr_err("Cannot ioremap OF node %pOF\n", node);
ret = -ENOMEM;
goto err_iomap;
} }
ret = ls_extirq_parse_map(priv, node); ret = ls_extirq_parse_map(priv, node);
if (ret) if (ret)
goto out; goto err_parse_map;
priv->big_endian = of_device_is_big_endian(parent);
priv->is_ls1021a_or_ls1043a = of_device_is_compatible(node, "fsl,ls1021a-extirq") || priv->is_ls1021a_or_ls1043a = of_device_is_compatible(node, "fsl,ls1021a-extirq") ||
of_device_is_compatible(node, "fsl,ls1043a-extirq"); of_device_is_compatible(node, "fsl,ls1043a-extirq");
raw_spin_lock_init(&priv->lock);
domain = irq_domain_add_hierarchy(parent_domain, 0, priv->nirq, node, domain = irq_domain_add_hierarchy(parent_domain, 0, priv->nirq, node,
&extirq_domain_ops, priv); &extirq_domain_ops, priv);
if (!domain) if (!domain) {
ret = -ENOMEM; ret = -ENOMEM;
goto err_add_hierarchy;
}
out: return 0;
if (ret)
kfree(priv); err_add_hierarchy:
err_parse_map:
iounmap(priv->intpcr);
err_iomap:
kfree(priv);
err_alloc_priv:
err_irq_find_host:
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment