Merge "drivers: edac: Enable and use per-cpu variable for l1/l2 IRQ" into msm-4.8
diff --git a/drivers/edac/kryo3xx_arm64_edac.c b/drivers/edac/kryo3xx_arm64_edac.c
index a19ccae..7e2aadc 100644
--- a/drivers/edac/kryo3xx_arm64_edac.c
+++ b/drivers/edac/kryo3xx_arm64_edac.c
@@ -55,7 +55,7 @@
static inline void set_errxctlr_el1(void)
{
- u64 val = 0x8f;
+ u64 val = 0x10f;
asm volatile("msr s3_0_c5_c4_1, %0" : : "r" (val));
}
@@ -116,25 +116,35 @@
struct erp_drvdata {
struct edac_device_ctl_info *edev_ctl;
+ struct erp_drvdata __percpu **erp_cpu_drvdata;
+ int ppi;
};
static struct erp_drvdata *panic_handler_drvdata;
static DEFINE_SPINLOCK(local_handler_lock);
+static void l1_l2_irq_enable(void *info)
+{
+ int irq = *(int *)info;
+
+ enable_percpu_irq(irq, IRQ_TYPE_LEVEL_HIGH);
+}
+
static int request_erp_irq(struct platform_device *pdev, const char *propname,
const char *desc, irq_handler_t handler,
void *ed, int percpu)
{
int rc;
struct resource *r;
+ struct erp_drvdata *drv = ed;
r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, propname);
if (!r) {
pr_err("ARM64 CPU ERP: Could not find <%s> IRQ property. Proceeding anyway.\n",
propname);
- return -EINVAL;
+ goto out;
}
if (!percpu) {
@@ -143,17 +153,41 @@
IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
desc,
ed);
- } else {
- rc = request_percpu_irq(r->start, handler, desc, ed);
- }
- if (rc) {
- pr_err("ARM64 CPU ERP: Failed to request IRQ %d: %d (%s / %s). Proceeding anyway.\n",
- (int) r->start, rc, propname, desc);
- return -EINVAL;
+ if (rc) {
+ pr_err("ARM64 CPU ERP: Failed to request IRQ %d: %d (%s / %s). Proceeding anyway.\n",
+ (int) r->start, rc, propname, desc);
+ goto out;
+ }
+
+ } else {
+ drv->erp_cpu_drvdata = alloc_percpu(struct erp_drvdata *);
+ if (!drv->erp_cpu_drvdata) {
+ pr_err("Failed to allocate percpu erp data\n");
+ goto out;
+ }
+
+ *raw_cpu_ptr(drv->erp_cpu_drvdata) = drv;
+ rc = request_percpu_irq(r->start, handler, desc,
+ drv->erp_cpu_drvdata);
+
+ if (rc) {
+ pr_err("ARM64 CPU ERP: Failed to request IRQ %d: %d (%s / %s). Proceeding anyway.\n",
+ (int) r->start, rc, propname, desc);
+ goto out_free;
+ }
+
+ drv->ppi = r->start;
+ on_each_cpu(l1_l2_irq_enable, &(r->start), 1);
}
return 0;
+
+out_free:
+ free_percpu(drv->erp_cpu_drvdata);
+ drv->erp_cpu_drvdata = NULL;
+out:
+ return -EINVAL;
}
static void dump_err_reg(int errorcode, int level, u64 errxstatus, u64 errxmisc,
@@ -285,10 +319,9 @@
static irqreturn_t kryo3xx_l1_l2_handler(int irq, void *drvdata)
{
- struct erp_drvdata *drv = drvdata;
- struct edac_device_ctl_info *edev_ctl = drv->edev_ctl;
+ struct erp_drvdata *drv = *(struct erp_drvdata **)(drvdata);
- kryo3xx_check_l1_l2_ecc(edev_ctl);
+ kryo3xx_check_l1_l2_ecc(drv->edev_ctl);
return IRQ_HANDLED;
}
@@ -371,6 +404,12 @@
struct erp_drvdata *drv = dev_get_drvdata(&pdev->dev);
struct edac_device_ctl_info *edac_ctl = drv->edev_ctl;
+
+ if (drv->erp_cpu_drvdata != NULL) {
+ free_percpu_irq(drv->ppi, drv->erp_cpu_drvdata);
+ free_percpu(drv->erp_cpu_drvdata);
+ }
+
edac_device_del_device(edac_ctl->dev);
edac_device_free_ctl_info(edac_ctl);