brintos

brintos / linux-shallow public Read only

0
0
Text · 6.1 KiB · f47d05f Raw
260 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * CoreNet Coherency Fabric error reporting4 *5 * Copyright 2014 Freescale Semiconductor Inc.6 */7 8#include <linux/interrupt.h>9#include <linux/io.h>10#include <linux/irq.h>11#include <linux/module.h>12#include <linux/of.h>13#include <linux/platform_device.h>14#include <linux/property.h>15 16enum ccf_version {17	CCF1,18	CCF2,19};20 21struct ccf_info {22	enum ccf_version version;23	int err_reg_offs;24	bool has_brr;25};26 27static const struct ccf_info ccf1_info = {28	.version = CCF1,29	.err_reg_offs = 0xa00,30	.has_brr = false,31};32 33static const struct ccf_info ccf2_info = {34	.version = CCF2,35	.err_reg_offs = 0xe40,36	.has_brr = true,37};38 39/*40 * This register is present but not documented, with different values for41 * IP_ID, on other chips with fsl,corenet2-cf such as t4240 and b4860.42 */43#define CCF_BRR			0xbf844#define CCF_BRR_IPID		0xffff000045#define CCF_BRR_IPID_T1040	0x0931000046 47static const struct of_device_id ccf_matches[] = {48	{49		.compatible = "fsl,corenet1-cf",50		.data = &ccf1_info,51	},52	{53		.compatible = "fsl,corenet2-cf",54		.data = &ccf2_info,55	},56	{}57};58MODULE_DEVICE_TABLE(of, ccf_matches);59 60struct ccf_err_regs {61	u32 errdet;		/* 0x00 Error Detect Register */62	/* 0x04 Error Enable (ccf1)/Disable (ccf2) Register */63	u32 errdis;64	/* 0x08 Error Interrupt Enable Register (ccf2 only) */65	u32 errinten;66	u32 cecar;		/* 0x0c Error Capture Attribute Register */67	u32 cecaddrh;		/* 0x10 Error Capture Address High */68	u32 cecaddrl;		/* 0x14 Error Capture Address Low */69	u32 cecar2;		/* 0x18 Error Capture Attribute Register 2 */70};71 72/* LAE/CV also valid for errdis and errinten */73#define ERRDET_LAE		(1 << 0)  /* Local Access Error */74#define ERRDET_CV		(1 << 1)  /* Coherency Violation */75#define ERRDET_UTID		(1 << 2)  /* Unavailable Target ID (t1040) */76#define ERRDET_MCST		(1 << 3)  /* Multicast Stash (t1040) */77#define ERRDET_CTYPE_SHIFT	26	  /* Capture Type (ccf2 only) */78#define ERRDET_CTYPE_MASK	(0x1f << ERRDET_CTYPE_SHIFT)79#define ERRDET_CAP		(1 << 31) /* Capture Valid (ccf2 only) */80 81#define CECAR_VAL		(1 << 0)  /* Valid (ccf1 only) */82#define CECAR_UVT		(1 << 15) /* Unavailable target ID (ccf1) */83#define CECAR_SRCID_SHIFT_CCF1	2484#define CECAR_SRCID_MASK_CCF1	(0xff << CECAR_SRCID_SHIFT_CCF1)85#define CECAR_SRCID_SHIFT_CCF2	1886#define CECAR_SRCID_MASK_CCF2	(0xff << CECAR_SRCID_SHIFT_CCF2)87 88#define CECADDRH_ADDRH		0xff89 90struct ccf_private {91	const struct ccf_info *info;92	struct device *dev;93	void __iomem *regs;94	struct ccf_err_regs __iomem *err_regs;95	bool t1040;96};97 98static irqreturn_t ccf_irq(int irq, void *dev_id)99{100	struct ccf_private *ccf = dev_id;101	static DEFINE_RATELIMIT_STATE(ratelimit, DEFAULT_RATELIMIT_INTERVAL,102				      DEFAULT_RATELIMIT_BURST);103	u32 errdet, cecar, cecar2;104	u64 addr;105	u32 src_id;106	bool uvt = false;107	bool cap_valid = false;108 109	errdet = ioread32be(&ccf->err_regs->errdet);110	cecar = ioread32be(&ccf->err_regs->cecar);111	cecar2 = ioread32be(&ccf->err_regs->cecar2);112	addr = ioread32be(&ccf->err_regs->cecaddrl);113	addr |= ((u64)(ioread32be(&ccf->err_regs->cecaddrh) &114		       CECADDRH_ADDRH)) << 32;115 116	if (!__ratelimit(&ratelimit))117		goto out;118 119	switch (ccf->info->version) {120	case CCF1:121		if (cecar & CECAR_VAL) {122			if (cecar & CECAR_UVT)123				uvt = true;124 125			src_id = (cecar & CECAR_SRCID_MASK_CCF1) >>126				 CECAR_SRCID_SHIFT_CCF1;127			cap_valid = true;128		}129 130		break;131	case CCF2:132		if (errdet & ERRDET_CAP) {133			src_id = (cecar & CECAR_SRCID_MASK_CCF2) >>134				 CECAR_SRCID_SHIFT_CCF2;135			cap_valid = true;136		}137 138		break;139	}140 141	dev_crit(ccf->dev, "errdet 0x%08x cecar 0x%08x cecar2 0x%08x\n",142		 errdet, cecar, cecar2);143 144	if (errdet & ERRDET_LAE) {145		if (uvt)146			dev_crit(ccf->dev, "LAW Unavailable Target ID\n");147		else148			dev_crit(ccf->dev, "Local Access Window Error\n");149	}150 151	if (errdet & ERRDET_CV)152		dev_crit(ccf->dev, "Coherency Violation\n");153 154	if (errdet & ERRDET_UTID)155		dev_crit(ccf->dev, "Unavailable Target ID\n");156 157	if (errdet & ERRDET_MCST)158		dev_crit(ccf->dev, "Multicast Stash\n");159 160	if (cap_valid) {161		dev_crit(ccf->dev, "address 0x%09llx, src id 0x%x\n",162			 addr, src_id);163	}164 165out:166	iowrite32be(errdet, &ccf->err_regs->errdet);167	return errdet ? IRQ_HANDLED : IRQ_NONE;168}169 170static int ccf_probe(struct platform_device *pdev)171{172	struct ccf_private *ccf;173	u32 errinten;174	int ret, irq;175 176	ccf = devm_kzalloc(&pdev->dev, sizeof(*ccf), GFP_KERNEL);177	if (!ccf)178		return -ENOMEM;179 180	ccf->regs = devm_platform_ioremap_resource(pdev, 0);181	if (IS_ERR(ccf->regs))182		return PTR_ERR(ccf->regs);183 184	ccf->dev = &pdev->dev;185	ccf->info = device_get_match_data(&pdev->dev);186	ccf->err_regs = ccf->regs + ccf->info->err_reg_offs;187 188	if (ccf->info->has_brr) {189		u32 brr = ioread32be(ccf->regs + CCF_BRR);190 191		if ((brr & CCF_BRR_IPID) == CCF_BRR_IPID_T1040)192			ccf->t1040 = true;193	}194 195	dev_set_drvdata(&pdev->dev, ccf);196 197	irq = platform_get_irq(pdev, 0);198	if (irq < 0)199		return irq;200 201	ret = devm_request_irq(&pdev->dev, irq, ccf_irq, 0, pdev->name, ccf);202	if (ret) {203		dev_err(&pdev->dev, "%s: can't request irq\n", __func__);204		return ret;205	}206 207	errinten = ERRDET_LAE | ERRDET_CV;208	if (ccf->t1040)209		errinten |= ERRDET_UTID | ERRDET_MCST;210 211	switch (ccf->info->version) {212	case CCF1:213		/* On CCF1 this register enables rather than disables. */214		iowrite32be(errinten, &ccf->err_regs->errdis);215		break;216 217	case CCF2:218		iowrite32be(0, &ccf->err_regs->errdis);219		iowrite32be(errinten, &ccf->err_regs->errinten);220		break;221	}222 223	return 0;224}225 226static void ccf_remove(struct platform_device *pdev)227{228	struct ccf_private *ccf = dev_get_drvdata(&pdev->dev);229 230	switch (ccf->info->version) {231	case CCF1:232		iowrite32be(0, &ccf->err_regs->errdis);233		break;234 235	case CCF2:236		/*237		 * We clear errdis on ccf1 because that's the only way to238		 * disable interrupts, but on ccf2 there's no need to disable239		 * detection.240		 */241		iowrite32be(0, &ccf->err_regs->errinten);242		break;243	}244}245 246static struct platform_driver ccf_driver = {247	.driver = {248		.name = KBUILD_MODNAME,249		.of_match_table = ccf_matches,250	},251	.probe = ccf_probe,252	.remove_new = ccf_remove,253};254 255module_platform_driver(ccf_driver);256 257MODULE_LICENSE("GPL");258MODULE_AUTHOR("Freescale Semiconductor");259MODULE_DESCRIPTION("Freescale CoreNet Coherency Fabric error reporting");260