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

Commit 6935406b authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge changes...

Merge changes If8baae37,I52d9824c,I70f941af,I53900813,Ifbc6b712,I96354945,I14332ea7,Ida9202a3,I4dd40be4,Iaae6fd42,I9787da64,I2ef80558 into msm-next

* changes:
  soc: qcom: amon: Activity monitor driver for LLCC
  drivers: llcc: Update llcc driver based on broadcast behavior
  soc: qcom: llcc: Initialize index before using it
  soc: qcom: llcc: Update the active/deactive status check
  drivers: soc: Update the max capacity programming
  soc: qcom: llcc: Fix to read LLCC status register
  drivers: Fix compiler warnings
  drivers: edac: Enable llcc ecc interrupt handling
  drivers: llcc: Remove access to unwanted registers
  soc: qcom: llcc: Do not explicitly write enable to tag ram ecc
  soc: qcom: llcc: Change register offsets as per new updates
  drivers: soc: Add LLCC driver
parents d66a43ec c409a1a3
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -65,6 +65,12 @@ Optional Properties:
	Value type: <string>
	Definition: Property to enable or disable the driver

== llcc amon device ==

Optional Properties:
-qcom,fg-cnt : The value of fine grained counter of activity monitor
	        block.

Example:

	qcom,llcc@01300000 {
@@ -85,6 +91,7 @@ Example:

		qcom,llcc-amon {
			compatible = "qcom,llcc-amon";
			qcom,fg-cnt = <0x7>;
		};
	};

+159 −55
Original line number Diff line number Diff line
/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -18,6 +18,7 @@
#include <linux/spinlock.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/interrupt.h>
#include "edac_core.h"

#ifdef CONFIG_EDAC_QCOM_LLCC_PANIC_ON_CE
@@ -38,6 +39,10 @@

#define DRP_SYN_REG_CNT	8

#define LLCC_COMMON_STATUS0		0x0003000C
#define LLCC_LB_CNT_MASK		0xf0000000
#define LLCC_LB_CNT_SHIFT		28

/* single & Double Bit syndrome register offsets */
#define TRP_ECC_SB_ERR_SYN0		0x0002304C
#define TRP_ECC_DB_ERR_SYN0		0x00020370
@@ -76,6 +81,11 @@
static int poll_msec = 5000;
module_param(poll_msec, int, 0444);

static int interrupt_mode;
module_param(interrupt_mode, int, 0444);
MODULE_PARM_DESC(interrupt_mode,
		 "Controls whether to use interrupt or poll mode");

enum {
	LLCC_DRAM_CE = 0,
	LLCC_DRAM_UE,
@@ -91,6 +101,10 @@ struct errors_edac {

struct erp_drvdata {
	struct regmap *llcc_map;
	phys_addr_t *llcc_banks;
	u32 ecc_irq;
	u32 num_banks;
	u32 b_off;
};

static const struct errors_edac errors[] = {
@@ -101,29 +115,32 @@ static const struct errors_edac errors[] = {
};

/* Clear the error interrupt and counter registers */
static void qcom_llcc_clear_errors(int err_type, struct regmap *llcc_map)
static void qcom_llcc_clear_errors(int err_type, struct erp_drvdata *drv)
{
	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(drv->llcc_map, drv->b_off + DRP_INTERRUPT_CLEAR,
			DRP_TRP_INT_CLEAR);
		/* Clear the counters */
		regmap_write(llcc_map, DRP_ECC_ERROR_CNTR_CLEAR,
		regmap_write(drv->llcc_map,
			drv->b_off + DRP_ECC_ERROR_CNTR_CLEAR,
			DRP_TRP_CNT_CLEAR);
		break;
	case LLCC_TRAM_CE:
	case LLCC_TRAM_UE:
		regmap_write(llcc_map, TRP_INTERRUPT_0_CLEAR,
		regmap_write(drv->llcc_map, drv->b_off + TRP_INTERRUPT_0_CLEAR,
			     DRP_TRP_INT_CLEAR);
		regmap_write(llcc_map, TRP_ECC_ERROR_CNTR_CLEAR,
		regmap_write(drv->llcc_map,
			drv->b_off + TRP_ECC_ERROR_CNTR_CLEAR,
			DRP_TRP_CNT_CLEAR);
		break;
	}
}

/* Dump syndrome registers for tag Ram Double bit errors */
static void dump_trp_db_syn_reg(struct regmap *llcc_map)
static void dump_trp_db_syn_reg(struct erp_drvdata *drv, u32 bank)
{
	int i;
	int db_err_cnt;
@@ -133,17 +150,20 @@ static void dump_trp_db_syn_reg(struct regmap *llcc_map)

	for (i = 0; i < TRP_SYN_REG_CNT; i++) {
		synd_reg = TRP_ECC_DB_ERR_SYN0 + (i * 4);
		regmap_read(llcc_map, synd_reg, &synd_val);
		regmap_read(drv->llcc_map, drv->llcc_banks[bank] + synd_reg,
			&synd_val);
		edac_printk(KERN_CRIT, EDAC_LLCC, "TRP_ECC_SYN%d: 0x%8x\n",
			i, synd_val);
	}

	regmap_read(llcc_map, TRP_ECC_ERROR_STATUS1, &db_err_cnt);
	regmap_read(drv->llcc_map,
		drv->llcc_banks[bank] + TRP_ECC_ERROR_STATUS1, &db_err_cnt);
	db_err_cnt = (db_err_cnt & ECC_DB_ERR_COUNT_MASK);
	edac_printk(KERN_CRIT, EDAC_LLCC, "Double-Bit error count: 0x%4x\n",
		db_err_cnt);

	regmap_read(llcc_map, TRP_ECC_ERROR_STATUS0, &db_err_ways);
	regmap_read(drv->llcc_map,
		drv->llcc_banks[bank] + TRP_ECC_ERROR_STATUS0, &db_err_ways);
	db_err_ways = (db_err_ways & ECC_DB_ERR_WAYS_MASK);
	db_err_ways >>= ECC_DB_ERR_WAYS_SHIFT;

@@ -152,7 +172,7 @@ static void dump_trp_db_syn_reg(struct regmap *llcc_map)
}

/* Dump syndrome register for tag Ram Single Bit Errors */
static void dump_trp_sb_syn_reg(struct regmap *llcc_map)
static void dump_trp_sb_syn_reg(struct erp_drvdata *drv, u32 bank)
{
	int i;
	int sb_err_cnt;
@@ -162,18 +182,21 @@ static void dump_trp_sb_syn_reg(struct regmap *llcc_map)

	for (i = 0; i < TRP_SYN_REG_CNT; i++) {
		synd_reg = TRP_ECC_SB_ERR_SYN0 + (i * 4);
		regmap_read(llcc_map, synd_reg, &synd_val);
		regmap_read(drv->llcc_map, drv->llcc_banks[bank] + synd_reg,
			&synd_val);
		edac_printk(KERN_CRIT, EDAC_LLCC, "TRP_ECC_SYN%d: 0x%8x\n",
			i, synd_val);
	}

	regmap_read(llcc_map, TRP_ECC_ERROR_STATUS1, &sb_err_cnt);
	regmap_read(drv->llcc_map,
		drv->llcc_banks[bank] + TRP_ECC_ERROR_STATUS1, &sb_err_cnt);
	sb_err_cnt = (sb_err_cnt & ECC_SB_ERR_COUNT_MASK);
	sb_err_cnt >>= ECC_SB_ERR_COUNT_SHIFT;
	edac_printk(KERN_CRIT, EDAC_LLCC, "Single-Bit error count: 0x%4x\n",
		sb_err_cnt);

	regmap_read(llcc_map, TRP_ECC_ERROR_STATUS0, &sb_err_ways);
	regmap_read(drv->llcc_map,
		drv->llcc_banks[bank] + TRP_ECC_ERROR_STATUS0, &sb_err_ways);
	sb_err_ways = sb_err_ways & ECC_SB_ERR_WAYS_MASK;

	edac_printk(KERN_CRIT, EDAC_LLCC, "Single-Bit error ways: 0x%4x\n",
@@ -181,7 +204,7 @@ static void dump_trp_sb_syn_reg(struct regmap *llcc_map)
}

/* Dump syndrome registers for Data Ram Double bit errors */
static void dump_drp_db_syn_reg(struct regmap *llcc_map)
static void dump_drp_db_syn_reg(struct erp_drvdata *drv, u32 bank)
{
	int i;
	int db_err_cnt;
@@ -191,17 +214,20 @@ 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_reg, &synd_val);
		regmap_read(drv->llcc_map, drv->llcc_banks[bank] + synd_reg,
			&synd_val);
		edac_printk(KERN_CRIT, EDAC_LLCC, "DRP_ECC_SYN%d: 0x%8x\n",
			i, synd_val);
	}

	regmap_read(llcc_map, DRP_ECC_ERROR_STATUS1, &db_err_cnt);
	regmap_read(drv->llcc_map,
		drv->llcc_banks[bank] + DRP_ECC_ERROR_STATUS1, &db_err_cnt);
	db_err_cnt = (db_err_cnt & ECC_DB_ERR_COUNT_MASK);
	edac_printk(KERN_CRIT, EDAC_LLCC, "Double-Bit error count: 0x%4x\n",
		db_err_cnt);

	regmap_read(llcc_map, DRP_ECC_ERROR_STATUS0, &db_err_ways);
	regmap_read(drv->llcc_map,
		drv->llcc_banks[bank] + DRP_ECC_ERROR_STATUS0, &db_err_ways);
	db_err_ways &= ECC_DB_ERR_WAYS_MASK;
	db_err_ways >>= ECC_DB_ERR_WAYS_SHIFT;
	edac_printk(KERN_CRIT, EDAC_LLCC, "Double-Bit error ways: 0x%4x\n",
@@ -209,29 +235,31 @@ static void dump_drp_db_syn_reg(struct regmap *llcc_map)
}

/* Dump Syndrome registers for Data Ram Single bit errors*/
static void dump_drp_sb_syn_reg(struct regmap *llcc_map)
static void dump_drp_sb_syn_reg(struct erp_drvdata *drv, u32 bank)
{
	int i;
	int sb_err_cnt;
	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);
		regmap_read(llcc_map, synd_reg, &synd_val);
		synd_reg = DRP_ECC_SB_ERR_SYN0 + (i * 4);
		regmap_read(drv->llcc_map, drv->llcc_banks[bank] + synd_reg,
			&synd_val);
		edac_printk(KERN_CRIT, EDAC_LLCC, "DRP_ECC_SYN%d: 0x%8x\n",
			i, synd_val);
	}

	regmap_read(llcc_map, DRP_ECC_ERROR_STATUS1, &sb_err_cnt);
	regmap_read(drv->llcc_map,
		drv->llcc_banks[bank] + DRP_ECC_ERROR_STATUS1, &sb_err_cnt);
	sb_err_cnt &= ECC_SB_ERR_COUNT_MASK;
	sb_err_cnt >>= ECC_SB_ERR_COUNT_SHIFT;
	edac_printk(KERN_CRIT, EDAC_LLCC, "Single-Bit error count: 0x%4x\n",
		sb_err_cnt);

	regmap_read(llcc_map, DRP_ECC_ERROR_STATUS0, &sb_err_ways);
	regmap_read(drv->llcc_map,
		drv->llcc_banks[bank] + DRP_ECC_ERROR_STATUS0, &sb_err_ways);
	sb_err_ways = sb_err_ways & ECC_SB_ERR_WAYS_MASK;

	edac_printk(KERN_CRIT, EDAC_LLCC, "Single-Bit error ways: 0x%4x\n",
@@ -240,67 +268,89 @@ static void dump_drp_sb_syn_reg(struct regmap *llcc_map)


static void dump_syn_reg(struct edac_device_ctl_info *edev_ctl,
			 int err_type, struct regmap *llcc_map)
			 int err_type, u32 bank)
{
	struct erp_drvdata *drv = edev_ctl->pvt_info;

	switch (err_type) {
	case LLCC_DRAM_CE:
		dump_drp_sb_syn_reg(llcc_map);
		dump_drp_sb_syn_reg(drv, bank);
		break;
	case LLCC_DRAM_UE:
		dump_drp_db_syn_reg(llcc_map);
		dump_drp_db_syn_reg(drv, bank);
		break;
	case LLCC_TRAM_CE:
		dump_trp_sb_syn_reg(llcc_map);
		dump_trp_sb_syn_reg(drv, bank);
		break;
	case LLCC_TRAM_UE:
		dump_trp_db_syn_reg(llcc_map);
		dump_trp_db_syn_reg(drv, bank);
		break;
	}

	qcom_llcc_clear_errors(err_type, llcc_map);
	qcom_llcc_clear_errors(err_type, drv);

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

static void qcom_llcc_poll_cache_errors
static void qcom_llcc_check_cache_errors
		(struct edac_device_ctl_info *edev_ctl)
{
	u32 drp_error;
	u32 trp_error;
	struct erp_drvdata *drv = edev_ctl->pvt_info;
	u32 i;

	for (i = 0; i < drv->num_banks; i++) {
		/* Look for Data RAM errors */
	regmap_read(drv->llcc_map, DRP_INTERRUPT_STATUS, &drp_error);
		regmap_read(drv->llcc_map,
			drv->llcc_banks[i] + DRP_INTERRUPT_STATUS, &drp_error);

		if (drp_error & SB_ECC_ERROR) {
			edac_printk(KERN_CRIT, EDAC_LLCC,
				"Single Bit Error detected in Data Ram\n");
		dump_syn_reg(edev_ctl, LLCC_DRAM_CE, drv->llcc_map);
			dump_syn_reg(edev_ctl, LLCC_DRAM_CE, i);
		} else if (drp_error & DB_ECC_ERROR) {
			edac_printk(KERN_CRIT, EDAC_LLCC,
				"Double Bit Error detected in Data Ram\n");
		dump_syn_reg(edev_ctl, LLCC_DRAM_UE, drv->llcc_map);
			dump_syn_reg(edev_ctl, LLCC_DRAM_UE, i);
		}

		/* Look for Tag RAM errors */
	regmap_read(drv->llcc_map, TRP_INTERRUPT_0_STATUS, &trp_error);
		regmap_read(drv->llcc_map,
			drv->llcc_banks[i] + TRP_INTERRUPT_0_STATUS,
			&trp_error);
		if (trp_error & SB_ECC_ERROR) {
			edac_printk(KERN_CRIT, EDAC_LLCC,
				"Single Bit Error detected in Tag Ram\n");
		dump_syn_reg(edev_ctl, LLCC_TRAM_CE, drv->llcc_map);
			dump_syn_reg(edev_ctl, LLCC_TRAM_CE, i);
		} else if (trp_error & DB_ECC_ERROR) {
			edac_printk(KERN_CRIT, EDAC_LLCC,
				"Double Bit Error detected in Tag Ram\n");
		dump_syn_reg(edev_ctl, LLCC_TRAM_UE, drv->llcc_map);
			dump_syn_reg(edev_ctl, LLCC_TRAM_UE, i);
		}
	}
}

static void qcom_llcc_poll_cache_errors(struct edac_device_ctl_info *edev_ctl)
{
	qcom_llcc_check_cache_errors(edev_ctl);
}

static irqreturn_t llcc_ecc_irq_handler
			(int irq, void *edev_ctl)
{
	qcom_llcc_check_cache_errors(edev_ctl);
	return IRQ_HANDLED;
}

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;
	u32 *banks;
	u32 i;

	/* Allocate edac control info */
	edev_ctl = edac_device_alloc_ctl_info(sizeof(*drv), "qcom-llcc", 1,
@@ -321,12 +371,66 @@ static int qcom_llcc_erp_probe(struct platform_device *pdev)
	drv->llcc_map = syscon_node_to_regmap(dev->parent->of_node);
	if (IS_ERR(drv->llcc_map)) {
		dev_err(dev, "no regmap for syscon llcc parent\n");
		rc = -ENOMEM;
		goto out;
	}

	if (interrupt_mode) {
		drv->ecc_irq = platform_get_irq_byname(pdev, "ecc_irq");
		if (!drv->ecc_irq) {
			rc = -ENODEV;
			goto out;
		}

		rc = devm_request_irq(dev, drv->ecc_irq, llcc_ecc_irq_handler,
				IRQF_TRIGGER_RISING, "llcc_ecc", edev_ctl);
		if (rc) {
			dev_err(dev, "failed to request ecc irq\n");
			goto out;
		}
	}

	/* Find the number of LLC banks supported */
	regmap_read(drv->llcc_map, LLCC_COMMON_STATUS0,
		    &drv->num_banks);

	drv->num_banks &= LLCC_LB_CNT_MASK;
	drv->num_banks >>= LLCC_LB_CNT_SHIFT;

	drv->llcc_banks = devm_kzalloc(&pdev->dev,
		sizeof(phys_addr_t) * drv->num_banks, GFP_KERNEL);

	if (!drv->num_banks) {
		dev_err(dev, "Cannot allocate memory for llcc_banks\n");
		return -ENOMEM;
	}

	banks = devm_kzalloc(&pdev->dev,
		sizeof(u32) * drv->num_banks, GFP_KERNEL);
	if (!banks)
		return -ENOMEM;

	rc = of_property_read_u32_array(dev->parent->of_node,
			"qcom,llcc-banks-off", banks, drv->num_banks);
	if (rc) {
		dev_err(dev, "Cannot read llcc-banks-off property\n");
		return -EINVAL;
	}

	rc = of_property_read_u32(dev->parent->of_node,
			"qcom,llcc-broadcast-off", &drv->b_off);
	if (rc) {
		dev_err(dev, "Cannot read llcc-broadcast-off property\n");
		return -EINVAL;
	}

	for (i = 0; i < drv->num_banks; i++)
		drv->llcc_banks[i] = banks[i];

	platform_set_drvdata(pdev, edev_ctl);

	rc = edac_device_add_device(edev_ctl);
out:
	if (rc)
		edac_device_free_ctl_info(edev_ctl);

+26 −0
Original line number Diff line number Diff line
@@ -23,6 +23,32 @@ config QCOM_MDT_LOADER
	tristate
	select QCOM_SCM

config QCOM_LLCC
	tristate "Qualcomm Technologies, Inc. LLCC driver"
	depends on ARCH_QCOM
	help
	  Qualcomm Technologies, Inc. platform specific LLCC driver for Last
	  Level Cache. This provides interfaces to client's that use the LLCC.
	  Say yes here to enable LLCC slice driver.

config QCOM_LLCC_AMON
	tristate "Qualcomm Technologies, Inc. LLCC Activity Monitor(AMON) driver"
	depends on QCOM_LLCC
	help
	  This option enables a activity monitor driver for last level cache
	  controller. This driver configures the activity monitor as
	  deadlock detector and dumps the AMON registers upon detection of
	  deadlock.

config QCOM_LLCC_AMON_PANIC
	tristate "Panic on detecting LLCC Activity Monitor(AMON) error"
	depends on QCOM_LLCC_AMON
	help
	  This option enables panic upon detection of LLCC Activity Monitor(AMON)
	  errors. Say yes here to enable deadlock detection mode of AMON. In
	  deadlock detection mode AMON will trigger an interrupt if some LLCC request
	  ages out.

config QCOM_PM
	bool "Qualcomm Power Management"
	depends on ARCH_QCOM && !ARM64
+2 −0
Original line number Diff line number Diff line
obj-$(CONFIG_QCOM_CPUSS_DUMP) += cpuss_dump.o
obj-$(CONFIG_QCOM_GSBI)	+=	qcom_gsbi.o
obj-$(CONFIG_QCOM_MDT_LOADER)	+= mdt_loader.o
obj-$(CONFIG_QCOM_LLCC) += llcc-core.o llcc-slice.o
obj-$(CONFIG_QCOM_LLCC_AMON) += llcc-amon.o
obj-$(CONFIG_QCOM_PM)	+=	spm.o
obj-$(CONFIG_QCOM_SMD_RPM)	+= smd-rpm.o
obj-$(CONFIG_QCOM_SMEM) +=	smem.o
+536 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading