提交 67510cca 编写于 作者: R Robert Richter 提交者: Thomas Gleixner

irqchip/gicv3-its: Add HW revision detection and configuration

Some GIC revisions require an individual configuration to esp. add
workarounds for HW bugs. This patch implements generic code to parse
the hw revision provided by an IIDR register value and runs specific
code if hw matches. A function is added that reads the IIDR registers
for ITS (GITS_IIDR) and then goes through a list of init functions to
be called for specific versions. Same could be done for GICV3
(GICD_IIDR), but there are no users yet for it.

The patch is needed to implement workarounds for HW errata in Cavium's
ThunderX GICV3 ITS.
Signed-off-by: NRobert Richter <rrichter@cavium.com>
Reviewed-by: NMarc Zygnier <marc.zyngier@arm.com>
Acked-by: NCatalin Marinas <catalin.marinas@arm.com>
Cc: Tirumalesh Chalamarla <tchalamarla@cavium.com>
Cc: linux-arm-kernel@lists.infradead.org
Cc: Jason Cooper <jason@lakedaemon.net>
Link: http://lkml.kernel.org/r/1442869119-1814-5-git-send-email-rric@kernel.orgSigned-off-by: NThomas Gleixner <tglx@linutronix.de>
上级 c14e3673
...@@ -21,6 +21,17 @@ ...@@ -21,6 +21,17 @@
#include "irq-gic-common.h" #include "irq-gic-common.h"
void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks,
void *data)
{
for (; quirks->desc; quirks++) {
if (quirks->iidr != (quirks->mask & iidr))
continue;
quirks->init(data);
pr_info("GIC: enabling workaround for %s\n", quirks->desc);
}
}
int gic_configure_irq(unsigned int irq, unsigned int type, int gic_configure_irq(unsigned int irq, unsigned int type,
void __iomem *base, void (*sync_access)(void)) void __iomem *base, void (*sync_access)(void))
{ {
......
...@@ -20,10 +20,19 @@ ...@@ -20,10 +20,19 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
struct gic_quirk {
const char *desc;
void (*init)(void *data);
u32 iidr;
u32 mask;
};
int gic_configure_irq(unsigned int irq, unsigned int type, int gic_configure_irq(unsigned int irq, unsigned int type,
void __iomem *base, void (*sync_access)(void)); void __iomem *base, void (*sync_access)(void));
void gic_dist_config(void __iomem *base, int gic_irqs, void gic_dist_config(void __iomem *base, int gic_irqs,
void (*sync_access)(void)); void (*sync_access)(void));
void gic_cpu_config(void __iomem *base, void (*sync_access)(void)); void gic_cpu_config(void __iomem *base, void (*sync_access)(void));
void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks,
void *data);
#endif /* _IRQ_GIC_COMMON_H */ #endif /* _IRQ_GIC_COMMON_H */
...@@ -37,6 +37,8 @@ ...@@ -37,6 +37,8 @@
#include <asm/cputype.h> #include <asm/cputype.h>
#include <asm/exception.h> #include <asm/exception.h>
#include "irq-gic-common.h"
#define ITS_FLAGS_CMDQ_NEEDS_FLUSHING (1 << 0) #define ITS_FLAGS_CMDQ_NEEDS_FLUSHING (1 << 0)
#define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0) #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0)
...@@ -1375,6 +1377,18 @@ static int its_force_quiescent(void __iomem *base) ...@@ -1375,6 +1377,18 @@ static int its_force_quiescent(void __iomem *base)
} }
} }
static const struct gic_quirk its_quirks[] = {
{
}
};
static void its_enable_quirks(struct its_node *its)
{
u32 iidr = readl_relaxed(its->base + GITS_IIDR);
gic_enable_quirks(iidr, its_quirks, its);
}
static int its_probe(struct device_node *node, struct irq_domain *parent) static int its_probe(struct device_node *node, struct irq_domain *parent)
{ {
struct resource res; struct resource res;
...@@ -1433,6 +1447,8 @@ static int its_probe(struct device_node *node, struct irq_domain *parent) ...@@ -1433,6 +1447,8 @@ static int its_probe(struct device_node *node, struct irq_domain *parent)
} }
its->cmd_write = its->cmd_base; its->cmd_write = its->cmd_base;
its_enable_quirks(its);
err = its_alloc_tables(node->full_name, its); err = its_alloc_tables(node->full_name, its);
if (err) if (err)
goto out_free_cmd; goto out_free_cmd;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册