Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 84146868 authored by Kyle Yan's avatar Kyle Yan Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drivers: edac: Update the register offsets" into msm-4.8

parents 0063796b 5c9de9a2
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -462,7 +462,7 @@ config EDAC_XGENE
	  APM X-Gene family of SOCs.

config EDAC_QCOM_LLCC
	depends on EDAC_MM_EDAC
	depends on EDAC_MM_EDAC && QCOM_LLCC
	tristate "QCOM LLCC Caches"
	help
	  Support for error detection and correction on the
+50 −50
Original line number Diff line number Diff line
@@ -39,27 +39,27 @@
#define DRP_SYN_REG_CNT	8

/* single & Double Bit syndrome register offsets */
#define TRP_ECC_SB_ERR_SYN0		0x0002334c
#define TRP_ECC_DB_ERR_SYN0		0x00023370
#define DRP_ECC_SB_ERR_SYN0		0x000400A8
#define DRP_ECC_DB_ERR_SYN0		0x000400D0
#define TRP_ECC_SB_ERR_SYN0		0x0002304C
#define TRP_ECC_DB_ERR_SYN0		0x00020370
#define DRP_ECC_SB_ERR_SYN0		0x0004204C
#define DRP_ECC_DB_ERR_SYN0		0x00042070

/* Error register offsets */
#define TRP_ECC_ERROR_STATUS1		0x00023348
#define TRP_ECC_ERROR_STATUS0		0x00023344
#define DRP_ECC_ERROR_STATUS1		0x000400A4
#define DRP_ECC_ERROR_STATUS0		0x000400A0
#define TRP_ECC_ERROR_STATUS1		0x00020348
#define TRP_ECC_ERROR_STATUS0		0x00020344
#define DRP_ECC_ERROR_STATUS1		0x00042048
#define DRP_ECC_ERROR_STATUS0		0x00042044

/* TRP, DRP interrupt register offsets */
#define DRP_INTERRUPT_STATUS		0x00040060
#define TRP_INTERRUPT_0_STATUS		0x00024380
#define DRP_INTERRUPT_CLEAR		0x00040058
#define DRP_ECC_ERROR_CNTR_CLEAR	0x00040044
#define TRP_INTERRUPT_0_CLEAR		0x00024384
#define TRP_ECC_ERROR_CNTR_CLEAR	0x00023440
#define DRP_INTERRUPT_STATUS		0x00041000
#define TRP_INTERRUPT_0_STATUS		0x00020480
#define DRP_INTERRUPT_CLEAR		0x00041008
#define DRP_ECC_ERROR_CNTR_CLEAR	0x00040004
#define TRP_INTERRUPT_0_CLEAR		0x00020484
#define TRP_ECC_ERROR_CNTR_CLEAR	0x00020440

/* Mask and shift macros */
#define ECC_DB_ERR_COUNT_MASK	0x0000003f
#define ECC_DB_ERR_COUNT_MASK	0x0000001f
#define ECC_DB_ERR_WAYS_MASK	0xffff0000
#define ECC_DB_ERR_WAYS_SHIFT	16

@@ -90,7 +90,6 @@ struct errors_edac {
};

struct erp_drvdata {
	struct edac_device_ctl_info *edev_ctl;
	struct regmap *llcc_map;
};

@@ -107,9 +106,11 @@ static void qcom_llcc_clear_errors(int err_type, struct regmap *llcc_map)
	switch (err_type) {
	case LLCC_DRAM_CE:
	case LLCC_DRAM_UE:
		/* Clear the interrupt */
		regmap_write(llcc_map, DRP_INTERRUPT_CLEAR, DRP_TRP_INT_CLEAR);
		regmap_write(llcc_map, TRP_INTERRUPT_CLEAR,
			     DRP_ECC_ERROR_CNTR_CLEAR);
		/* Clear the counters */
		regmap_write(llcc_map, DRP_ECC_ERROR_CNTR_CLEAR,
			DRP_TRP_CNT_CLEAR);
		break;
	case LLCC_TRAM_CE:
	case LLCC_TRAM_UE:
@@ -190,7 +191,7 @@ static void dump_drp_db_syn_reg(struct regmap *llcc_map)

	for (i = 0; i < DRP_SYN_REG_CNT; i++) {
		synd_reg = DRP_ECC_DB_ERR_SYN0 + (i * 4);
		regmap_read(llcc_map, synd_red, &synd_val);
		regmap_read(llcc_map, synd_reg, &synd_val);
		edac_printk(KERN_CRIT, EDAC_LLCC, "DRP_ECC_SYN%d: 0x%8x\n",
			i, synd_val);
	}
@@ -215,6 +216,7 @@ static void dump_drp_sb_syn_reg(struct regmap *llcc_map)
	int sb_err_ways;
	u32 synd_reg;
	u32 synd_val;
	u32 synd_reg_offset;

	for (i = 0; i < DRP_SYN_REG_CNT; i++) {
		synd_reg_offset = DRP_ECC_SB_ERR_SYN0 + (i * 4);
@@ -237,7 +239,8 @@ static void dump_drp_sb_syn_reg(struct regmap *llcc_map)
}


static void dump_syn_reg(int err_type, struct regmap *llcc_map)
static void dump_syn_reg(struct edac_device_ctl_info *edev_ctl,
			 int err_type, struct regmap *llcc_map)
{
	switch (err_type) {
	case LLCC_DRAM_CE:
@@ -256,7 +259,7 @@ static void dump_syn_reg(int err_type, struct regmap *llcc_map)

	qcom_llcc_clear_errors(err_type, llcc_map);

	errors[err_type].func(edev_ctl, 1, 0, errors[err_type].msg);
	errors[err_type].func(edev_ctl, 0, 0, errors[err_type].msg);
}

static void qcom_llcc_poll_cache_errors
@@ -264,9 +267,7 @@ static void qcom_llcc_poll_cache_errors
{
	u32 drp_error;
	u32 trp_error;
	struct erp_drvdata *drv;

	drv = container_of(edev_ctl, struct erp_drvdata, edev_ctl);
	struct erp_drvdata *drv = edev_ctl->pvt_info;

	/* Look for Data RAM errors */
	regmap_read(drv->llcc_map, DRP_INTERRUPT_STATUS, &drp_error);
@@ -274,11 +275,11 @@ static void qcom_llcc_poll_cache_errors
	if (drp_error & SB_ECC_ERROR) {
		edac_printk(KERN_CRIT, EDAC_LLCC,
			"Single Bit Error detected in Data Ram\n");
		dump_syn_reg(LLCC_DRAM_CE, drv->llcc_map);
		dump_syn_reg(edev_ctl, LLCC_DRAM_CE, drv->llcc_map);
	} else if (drp_error & DB_ECC_ERROR) {
		edac_printk(KERN_CRIT, EDAC_LLCC,
			"Double Bit Error detected in Data Ram\n");
		dump_syn_reg(LLCC_DRAM_UE, drv->llcc_map);
		dump_syn_reg(edev_ctl, LLCC_DRAM_UE, drv->llcc_map);
	}

	/* Look for Tag RAM errors */
@@ -286,11 +287,11 @@ static void qcom_llcc_poll_cache_errors
	if (trp_error & SB_ECC_ERROR) {
		edac_printk(KERN_CRIT, EDAC_LLCC,
			"Single Bit Error detected in Tag Ram\n");
		dump_syn_reg(LLCC_TRAM_CE, drv->llcc_map);
		dump_syn_reg(edev_ctl, LLCC_TRAM_CE, drv->llcc_map);
	} else if (trp_error & DB_ECC_ERROR) {
		edac_printk(KERN_CRIT, EDAC_LLCC,
			"Double Bit Error detected in Tag Ram\n");
		dump_syn_reg(LLCC_TRAM_UE, drv->llcc_map);
		dump_syn_reg(edev_ctl, LLCC_TRAM_UE, drv->llcc_map);
	}
}

@@ -298,11 +299,24 @@ static int qcom_llcc_erp_probe(struct platform_device *pdev)
{
	int rc = 0;
	struct erp_drvdata *drv;
	struct edac_device_ctl_info *edev_ctl;
	struct device *dev = &pdev->dev;

	drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);
	if (!drv)
		return -ENOMEM;
	/* Allocate edac control info */
	edev_ctl = edac_device_alloc_ctl_info(sizeof(*drv), "qcom-llcc", 1,
			NULL, 1, 1, NULL, 0, edac_device_alloc_index());

	edev_ctl->dev = dev;
	edev_ctl->mod_name = dev_name(dev);
	edev_ctl->dev_name = dev_name(dev);
	edev_ctl->ctl_name = "llcc";
	edev_ctl->poll_msec = poll_msec;
	edev_ctl->edac_check = qcom_llcc_poll_cache_errors;
	edev_ctl->defer_work = 1;
	edev_ctl->panic_on_ce = LLCC_ERP_PANIC_ON_CE;
	edev_ctl->panic_on_ue = LLCC_ERP_PANIC_ON_UE;

	drv = edev_ctl->pvt_info;

	drv->llcc_map = syscon_node_to_regmap(dev->parent->of_node);
	if (IS_ERR(drv->llcc_map)) {
@@ -310,32 +324,18 @@ static int qcom_llcc_erp_probe(struct platform_device *pdev)
		return -ENOMEM;
	}

	/* Allocate edac control info */
	drv->edev_ctl = edac_device_alloc_ctl_info(0, "qcom-llcc", 1, NULL, 1,
				1, NULL, 0, edac_device_alloc_index());

	drv->edev_ctl->dev = dev;
	drv->edev_ctl->mod_name = dev_name(dev);
	drv->edev_ctl->dev_name = dev_name(dev);
	drv->edev_ctl->ctl_name = "llcc";
	drv->edev_ctl->poll_msec = poll_msec;
	drv->edev_ctl->edac_check = qcom_llcc_poll_cache_errors;
	drv->edev_ctl->defer_work = 1;
	drv->edev_ctl->panic_on_ce = LLCC_ERP_PANIC_ON_CE;
	drv->edev_ctl->panic_on_ue = LLCC_ERP_PANIC_ON_UE;
	platform_set_drvdata(pdev, drv);

	rc = edac_device_add_device(drv->edev_ctl);
	platform_set_drvdata(pdev, edev_ctl);

	rc = edac_device_add_device(edev_ctl);
	if (rc)
		edac_device_free_ctl_info(drv->edev_ctl);
		edac_device_free_ctl_info(edev_ctl);

	return rc;
}

static int qcom_llcc_erp_remove(struct platform_device *pdev)
{
	struct erp_drvdata *drv = dev_get_drvdata(&pdev->dev);
	struct edac_device_ctl_info *edev_ctl = drv->edev_ctl;
	struct edac_device_ctl_info *edev_ctl = dev_get_drvdata(&pdev->dev);

	edac_device_del_device(edev_ctl->dev);
	edac_device_free_ctl_info(edev_ctl);