From 0c103ec66e20ee097b021da036b735daa1fdf10d Mon Sep 17 00:00:00 2001 From: Ketan Patil Date: Fri, 30 Jun 2023 09:39:52 +0000 Subject: [PATCH] memory: tegra: Add support for mc-err driver Add support for mc-err driver on T264. Maintain driver similar to current upstream mc-err driver, so that upstreaming diff for T264 would be straight forward. Current IRQ handling logic is as follows: - Read MCF int status from MCB - Find out the MC channel responsible for generating error - Read address register from that MC channel block to get the address - Find out type of error from status register Current implementation is as per the information received so far, further updates will be made once HW team provide programming guidelines. Bug 3846055 Change-Id: I71508a88521e8b5c3d046b087efe4baf2769ceb3 Signed-off-by: Ketan Patil Reviewed-on: https://git-master.nvidia.com/r/c/linux-t264/+/2929112 Reviewed-by: Sachin Nikam Reviewed-by: Ashish Mhetre Reviewed-by: Pritesh Raithatha GVS: Gerrit_Virtual_Submit --- drivers/memory/tegra/private-soc/Makefile | 1 + .../tegra/private-soc/tegra264-mc-err.c | 954 ++++++++++++++++++ 2 files changed, 955 insertions(+) create mode 100644 drivers/memory/tegra/private-soc/tegra264-mc-err.c diff --git a/drivers/memory/tegra/private-soc/Makefile b/drivers/memory/tegra/private-soc/Makefile index 1b88c57d..dd1c5335 100644 --- a/drivers/memory/tegra/private-soc/Makefile +++ b/drivers/memory/tegra/private-soc/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 obj-m += mc-t26x.o obj-m += tegra264-mc-hwpm.o +obj-m += tegra264-mc-err.o diff --git a/drivers/memory/tegra/private-soc/tegra264-mc-err.c b/drivers/memory/tegra/private-soc/tegra264-mc-err.c new file mode 100644 index 00000000..ae792996 --- /dev/null +++ b/drivers/memory/tegra/private-soc/tegra264-mc-err.c @@ -0,0 +1,954 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved. + */ + +#define pr_fmt(fmt) "tegra264-mc-err: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MC_BROADCAST_CHANNEL ~0 + +#define MCF_INTSTATUS_0 0xce2c +#define MC_ERR_STATUS_0 0x8700 +#define MC_ERR_ADR_0 0x8704 +#define MC_ERR_ADR_HI_0 0x8708 +#define MC_ERR_VPR_STATUS_0 0x8720 +#define MC_ERR_VPR_ADR_0 0x8724 +#define MC_ERR_SEC_STATUS_0 0x873c +#define MC_ERR_SEC_ADR_0 0x8740 +#define MC_ERR_MTS_STATUS_0 0x875c +#define MC_ERR_MTS_ADR_0 0x8760 +#define MC_ERR_GENERALIZED_CARVEOUT_STATUS_0 0x8778 +#define MC_ERR_GENERALIZED_CARVEOUT_ADR_0 0x877c +#define MC_ERR_ROUTE_SANITY_STATUS_0 0x8764 +#define MC_ERR_ROUTE_SANITY_ADR_0 0x8768 +#define MCF_INTMASK_0 0xce30 +#define MCF_INTPRIORITY_0 0xce34 + + +#define MC_INT_DECERR_ROUTE_SANITY_GIC_MSI BIT(21) +#define MC_INT_DECERR_ROUTE_SANITY BIT(20) +#define MC_INT_SCRUB_ECC_WR_ACK BIT(18) +#define MC_INT_DECERR_GENERALIZED_CARVEOUT BIT(17) +#define MC_INT_DECERR_MTS BIT(16) +#define MC_INT_SECERR_SEC BIT(13) +#define MC_INT_DECERR_VPR BIT(12) +#define MC_INT_SECURITY_VIOLATION BIT(8) +#define MC_INT_DECERR_EMEM BIT(6) + +#define MC_ERR_STATUS_TYPE_MASK (0x3 << 28) +#define MC_ERR_STATUS_TYPE_SHIFT 28 +#define MC_ERR_STATUS_ADR_HI_SHIFT 20 +#define MC_ERR_STATUS_ADR_HI_MASK 0x3 +#define MC_ERR_STATUS_RW BIT(16) +#define MC_ERR_STATUS_SECURITY BIT(17) + +#define CLIENT_ID_MASK 0x1ff +#define MAX_MC_CHANNELS 16 + +struct tegra_mc_client { + unsigned int id; + const char *name; +}; + +static const struct tegra_mc_client clients[] = { + { + .id = TEGRA264_MEMORY_CLIENT_PTCR, + .name = "ptcr", + }, { + .id = TEGRA264_MEMORY_CLIENT_HOST1XR, + .name = "host1xr", + }, { + .id = TEGRA264_MEMORY_CLIENT_MPCORER, + .name = "mpcorer", + }, { + .id = TEGRA264_MEMORY_CLIENT_PSCR, + .name = "pscr", + }, { + .id = TEGRA264_MEMORY_CLIENT_PSCW, + .name = "pscw", + }, { + .id = TEGRA264_MEMORY_CLIENT_ISP0R, + .name = "isp0r", + }, { + .id = TEGRA264_MEMORY_CLIENT_MPCOREW, + .name = "mpcorew", + }, { + .id = TEGRA264_MEMORY_CLIENT_ISP0W, + .name = "isp0w", + }, { + .id = TEGRA264_MEMORY_CLIENT_ISP1W, + .name = "isp1w", + }, { + .id = TEGRA264_MEMORY_CLIENT_ISPFALCONR, + .name = "ispfalconr", + }, { + .id = TEGRA264_MEMORY_CLIENT_ISPFALCONW, + .name = "ispfalconw", + }, { + .id = TEGRA264_MEMORY_CLIENT_MGBE2R, + .name = "mgbe2r", + }, { + .id = TEGRA264_MEMORY_CLIENT_OFAR2MC, + .name = "ofar2mc", + }, { + .id = TEGRA264_MEMORY_CLIENT_OFAW2MC, + .name = "ofaw2mc", + }, { + .id = TEGRA264_MEMORY_CLIENT_MGBE2W, + .name = "mgbe2w", + }, { + .id = TEGRA264_MEMORY_CLIENT_MGBE3R, + .name = "mgbe3r", + }, { + .id = TEGRA264_MEMORY_CLIENT_MGBE3W, + .name = "mgbe3w", + }, { + .id = TEGRA264_MEMORY_CLIENT_SEU1RD, + .name = "seu1rd", + }, { + .id = TEGRA264_MEMORY_CLIENT_SEU1WR, + .name = "seu1wr", + }, { + .id = TEGRA264_MEMORY_CLIENT_VICR, + .name = "vicr", + }, { + .id = TEGRA264_MEMORY_CLIENT_VICW, + .name = "vicw", + }, { + .id = TEGRA264_MEMORY_CLIENT_VIW, + .name = "viw", + }, { + .id = TEGRA264_MEMORY_CLIENT_XSPI0R, + .name = "xspi0r", + }, { + .id = TEGRA264_MEMORY_CLIENT_XSPI0W, + .name = "xspi0w", + }, { + .id = TEGRA264_MEMORY_CLIENT_NVDECSRD2MC, + .name = "nvdecsrd2mc", + }, { + .id = TEGRA264_MEMORY_CLIENT_NVDECSWR2MC, + .name = "nvdecswr2mc", + }, { + .id = TEGRA264_MEMORY_CLIENT_APER, + .name = "aper", + }, { + .id = TEGRA264_MEMORY_CLIENT_APEW, + .name = "apew", + }, { + .id = TEGRA264_MEMORY_CLIENT_SER, + .name = "ser", + }, { + .id = TEGRA264_MEMORY_CLIENT_SEW, + .name = "sew", + }, { + .id = TEGRA264_MEMORY_CLIENT_AXIAPR, + .name = "axiapr", + }, { + .id = TEGRA264_MEMORY_CLIENT_AXIAPW, + .name = "axiapw", + }, { + .id = TEGRA264_MEMORY_CLIENT_ETRR, + .name = "etrr", + }, { + .id = TEGRA264_MEMORY_CLIENT_ETRW, + .name = "etrw", + }, { + .id = TEGRA264_MEMORY_CLIENT_TSECR, + .name = "tsecr", + }, { + .id = TEGRA264_MEMORY_CLIENT_TSECW, + .name = "tsecw", + }, { + .id = TEGRA264_MEMORY_CLIENT_BPMPR, + .name = "bpmpr", + }, { + .id = TEGRA264_MEMORY_CLIENT_BPMPW, + .name = "bpmpw", + }, { + .id = TEGRA264_MEMORY_CLIENT_AONR, + .name = "aonr", + }, { + .id = TEGRA264_MEMORY_CLIENT_AONW, + .name = "aonw", + }, { + .id = TEGRA264_MEMORY_CLIENT_GPCDMAR, + .name = "gpcdmar", + }, { + .id = TEGRA264_MEMORY_CLIENT_GPCDMAW, + .name = "gpcdmaw", + }, { + .id = TEGRA264_MEMORY_CLIENT_APEDMAR, + .name = "apedmar", + }, { + .id = TEGRA264_MEMORY_CLIENT_APEDMAW, + .name = "apedmaw", + }, { + .id = TEGRA264_MEMORY_CLIENT_MIU0R, + .name = "miu0r", + }, { + .id = TEGRA264_MEMORY_CLIENT_MIU0W, + .name = "miu0w", + }, { + .id = TEGRA264_MEMORY_CLIENT_MIU1R, + .name = "miu1r", + }, { + .id = TEGRA264_MEMORY_CLIENT_MIU1W, + .name = "miu1w", + }, { + .id = TEGRA264_MEMORY_CLIENT_MIU2R, + .name = "miu2r", + }, { + .id = TEGRA264_MEMORY_CLIENT_MIU2W, + .name = "miu2w", + }, { + .id = TEGRA264_MEMORY_CLIENT_MIU3R, + .name = "miu3r", + }, { + .id = TEGRA264_MEMORY_CLIENT_MIU3W, + .name = "miu3w", + }, { + .id = TEGRA264_MEMORY_CLIENT_MIU4R, + .name = "miu4r", + }, { + .id = TEGRA264_MEMORY_CLIENT_MIU4W, + .name = "miu4w", + }, { + .id = TEGRA264_MEMORY_CLIENT_GPUR02MC, + .name = "gpur02mc", + }, { + .id = TEGRA264_MEMORY_CLIENT_GPUW02MC, + .name = "gpuw02mc", + }, { + .id = TEGRA264_MEMORY_CLIENT_VIFALCONR, + .name = "vifalconr", + }, { + .id = TEGRA264_MEMORY_CLIENT_VIFALCONW, + .name = "vifalconw", + }, { + .id = TEGRA264_MEMORY_CLIENT_RCER, + .name = "rcer", + }, { + .id = TEGRA264_MEMORY_CLIENT_RCEW, + .name = "rcew", + }, { + .id = TEGRA264_MEMORY_CLIENT_NVENC1SRD2MC, + .name = "nvenc1srd2mc", + }, { + .id = TEGRA264_MEMORY_CLIENT_NVENC1SWR2MC, + .name = "nvenc1swr2mc", + }, { + .id = TEGRA264_MEMORY_CLIENT_PCIE0W, + .name = "pcie0w", + }, { + .id = TEGRA264_MEMORY_CLIENT_PCIE1R, + .name = "pcie1r", + }, { + .id = TEGRA264_MEMORY_CLIENT_PCIE1W, + .name = "pcie1w", + }, { + .id = TEGRA264_MEMORY_CLIENT_PCIE2AR, + .name = "pcie2ar", + }, { + .id = TEGRA264_MEMORY_CLIENT_PCIE2AW, + .name = "pcie2aw", + }, { + .id = TEGRA264_MEMORY_CLIENT_PCIE3R, + .name = "pcie3r", + }, { + .id = TEGRA264_MEMORY_CLIENT_PCIE3W, + .name = "pcie3w", + }, { + .id = TEGRA264_MEMORY_CLIENT_PCIE4R, + .name = "pcie4r", + }, { + .id = TEGRA264_MEMORY_CLIENT_PCIE4W, + .name = "pcie4w", + }, { + .id = TEGRA264_MEMORY_CLIENT_PCIE5R, + .name = "pcie5r", + }, { + .id = TEGRA264_MEMORY_CLIENT_PCIE5W, + .name = "pcie5w", + }, { + .id = TEGRA264_MEMORY_CLIENT_MIU5R, + .name = "miu5r", + }, { + .id = TEGRA264_MEMORY_CLIENT_MIU5W, + .name = "miu5w", + }, { + .id = TEGRA264_MEMORY_CLIENT_MIU6W, + .name = "miu6w", + }, { + .id = TEGRA264_MEMORY_CLIENT_RISTR, + .name = "ristr", + }, { + .id = TEGRA264_MEMORY_CLIENT_RISTW, + .name = "ristw", + }, { + .id = TEGRA264_MEMORY_CLIENT_OESPR, + .name = "oespr", + }, { + .id = TEGRA264_MEMORY_CLIENT_OESPW, + .name = "oespw", + }, { + .id = TEGRA264_MEMORY_CLIENT_MIU7W, + .name = "miu7w", + }, { + .id = TEGRA264_MEMORY_CLIENT_MIU8R, + .name = "miu8r", + }, { + .id = TEGRA264_MEMORY_CLIENT_MIU8W, + .name = "miu8w", + }, { + .id = TEGRA264_MEMORY_CLIENT_MIU9R, + .name = "miu9r", + }, { + .id = TEGRA264_MEMORY_CLIENT_MIU9W, + .name = "miu9w", + }, { + .id = TEGRA264_MEMORY_CLIENT_PMA0AWR, + .name = "pma0awr", + }, { + .id = TEGRA264_MEMORY_CLIENT_NVJPG1SRD2MC, + .name = "nvjpg1srd2mc", + }, { + .id = TEGRA264_MEMORY_CLIENT_NVJPG1SWR2MC, + .name = "nvjpg1swr2mc", + }, { + .id = TEGRA264_MEMORY_CLIENT_SMMU0CTWR, + .name = "smmu0ctwr", + }, { + .id = TEGRA264_MEMORY_CLIENT_SMMU0CMDQVR, + .name = "smmu0cmdqvr", + }, { + .id = TEGRA264_MEMORY_CLIENT_SMMU0CMDQVW, + .name = "smmu0cmdqvw", + }, { + .id = TEGRA264_MEMORY_CLIENT_SMMU0EVNTQW, + .name = "smmu0evntqw", + }, { + .id = TEGRA264_MEMORY_CLIENT_SMMU1PTWR, + .name = "smmu1ptwr", + }, { + .id = TEGRA264_MEMORY_CLIENT_SMMU1CTWR, + .name = "smmu1ctwr", + }, { + .id = TEGRA264_MEMORY_CLIENT_SMMU1CMDQVR, + .name = "smmu1cmdqvr", + }, { + .id = TEGRA264_MEMORY_CLIENT_SMMU1CMDQVW, + .name = "smmu1cmdqvw", + }, { + .id = TEGRA264_MEMORY_CLIENT_SMMU1EVNTQW, + .name = "smmu1evntqw", + }, { + .id = TEGRA264_MEMORY_CLIENT_SMMU2PTWR, + .name = "smmu2ptwr", + }, { + .id = TEGRA264_MEMORY_CLIENT_SMMU2CTWR, + .name = "smmu2ctwr", + }, { + .id = TEGRA264_MEMORY_CLIENT_SMMU2CMDQVR, + .name = "smmu2cmdqvr", + }, { + .id = TEGRA264_MEMORY_CLIENT_SMMU2CMDQVW, + .name = "smmu2cmdqvw", + }, { + .id = TEGRA264_MEMORY_CLIENT_SMMU2EVNTQW, + .name = "smmu2evntqw", + }, { + .id = TEGRA264_MEMORY_CLIENT_SMMU0CMDQR, + .name = "smmu0cmdqr", + }, { + .id = TEGRA264_MEMORY_CLIENT_SMMU1CMDQR, + .name = "smmu1cmdqr", + }, { + .id = TEGRA264_MEMORY_CLIENT_SMMU2CMDQR, + .name = "smmu2cmdqr", + }, { + .id = TEGRA264_MEMORY_CLIENT_APE1R, + .name = "ape1r", + }, { + .id = TEGRA264_MEMORY_CLIENT_APE1W, + .name = "ape1w", + }, { + .id = TEGRA264_MEMORY_CLIENT_UFSR, + .name = "ufsr", + }, { + .id = TEGRA264_MEMORY_CLIENT_UFSW, + .name = "ufsw", + }, { + .id = TEGRA264_MEMORY_CLIENT_XUSB_DEVR, + .name = "xusb_devr", + }, { + .id = TEGRA264_MEMORY_CLIENT_XUSB_DEVW, + .name = "xusb_devw", + }, { + .id = TEGRA264_MEMORY_CLIENT_XUSB_DEV1R, + .name = "xusb_dev1r", + }, { + .id = TEGRA264_MEMORY_CLIENT_XUSB_DEV2W, + .name = "xusb_dev2w", + }, { + .id = TEGRA264_MEMORY_CLIENT_XUSB_DEV3R, + .name = "xusb_dev3r", + }, { + .id = TEGRA264_MEMORY_CLIENT_XUSB_DEV3W, + .name = "xusb_dev3w", + }, { + .id = TEGRA264_MEMORY_CLIENT_XUSB_DEV4R, + .name = "xusb_dev4r", + }, { + .id = TEGRA264_MEMORY_CLIENT_XUSB_DEV4W, + .name = "xusb_dev4w", + }, { + .id = TEGRA264_MEMORY_CLIENT_XUSB_DEV5R, + .name = "xusb_dev5r", + }, { + .id = TEGRA264_MEMORY_CLIENT_XUSB_DEV5W, + .name = "xusb_dev5w", + }, { + .id = TEGRA264_MEMORY_CLIENT_DCER, + .name = "dcer", + }, { + .id = TEGRA264_MEMORY_CLIENT_DCEW, + .name = "dcew", + }, { + .id = TEGRA264_MEMORY_CLIENT_HDAR, + .name = "hdar", + }, { + .id = TEGRA264_MEMORY_CLIENT_HDAW, + .name = "hdaw", + }, { + .id = TEGRA264_MEMORY_CLIENT_DISPNISOR, + .name = "dispnisor", + }, { + .id = TEGRA264_MEMORY_CLIENT_DISPNISOW, + .name = "dispnisow", + }, { + .id = TEGRA264_MEMORY_CLIENT_XUSB_DEV1W, + .name = "xusb_dev1w", + }, { + .id = TEGRA264_MEMORY_CLIENT_XUSB_DEV2R, + .name = "xusb_dev2r", + }, { + .id = TEGRA264_MEMORY_CLIENT_DISPR, + .name = "dispr", + }, { + .id = TEGRA264_MEMORY_CLIENT_MSSSEQR, + .name = "mssseqr", + }, { + .id = TEGRA264_MEMORY_CLIENT_MSSSEQW, + .name = "mssseqw", + }, { + .id = TEGRA264_MEMORY_CLIENT_SMMU3PTWR, + .name = "smmu3ptwr", + }, { + .id = TEGRA264_MEMORY_CLIENT_SMMU3CTWR, + .name = "smmu3ctwr", + }, { + .id = TEGRA264_MEMORY_CLIENT_SMMU3CMDQVR, + .name = "smmu3cmdqvr", + }, { + .id = TEGRA264_MEMORY_CLIENT_SMMU3CMDQVW, + .name = "smmu3cmdqvw", + }, { + .id = TEGRA264_MEMORY_CLIENT_SMMU3EVNTQW, + .name = "smmu3evntqw", + }, { + .id = TEGRA264_MEMORY_CLIENT_SMMU3CMDQR, + .name = "smmu3cmdqr", + }, { + .id = TEGRA264_MEMORY_CLIENT_SMMU4PTWR, + .name = "smmu4ptwr", + }, { + .id = TEGRA264_MEMORY_CLIENT_SMMU4CTWR, + .name = "smmu4ctwr", + }, { + .id = TEGRA264_MEMORY_CLIENT_SMMU4CMDQVR, + .name = "smmu4cmdqvr", + }, { + .id = TEGRA264_MEMORY_CLIENT_SMMU4CMDQVW, + .name = "smmu4cmdqvw", + }, { + .id = TEGRA264_MEMORY_CLIENT_SMMU4EVNTQW, + .name = "smmu4evntqw", + }, { + .id = TEGRA264_MEMORY_CLIENT_SMMU4CMDQR, + .name = "smmu4cmdqr", + }, { + .id = TEGRA264_MEMORY_CLIENT_MGBE0R, + .name = "mgbe0r", + }, { + .id = TEGRA264_MEMORY_CLIENT_MGBE0W, + .name = "mgbe0w", + }, { + .id = TEGRA264_MEMORY_CLIENT_MGBE1R, + .name = "mgbe1r", + }, { + .id = TEGRA264_MEMORY_CLIENT_MGBE1W, + .name = "mgbe1w", + }, { + .id = TEGRA264_MEMORY_CLIENT_VI1W, + .name = "vi1w", + }, { + .id = TEGRA264_MEMORY_CLIENT_VIFALCON1R, + .name = "vifalcon1r", + }, { + .id = TEGRA264_MEMORY_CLIENT_VIFALCON1W, + .name = "vifalcon1w", + }, { + .id = TEGRA264_MEMORY_CLIENT_ISPFALCON1R, + .name = "ispfalcon1r", + }, { + .id = TEGRA264_MEMORY_CLIENT_ISPFALCON1W, + .name = "ispfalcon1w", + }, { + .id = TEGRA264_MEMORY_CLIENT_RCE1R, + .name = "rce1r", + }, { + .id = TEGRA264_MEMORY_CLIENT_RCE1W, + .name = "rce1w", + }, { + .id = TEGRA264_MEMORY_CLIENT_SEU2R, + .name = "seu2r", + }, { + .id = TEGRA264_MEMORY_CLIENT_SEU2W, + .name = "seu2w", + }, { + .id = TEGRA264_MEMORY_CLIENT_SEU3R, + .name = "seu3r", + }, { + .id = TEGRA264_MEMORY_CLIENT_SEU3W, + .name = "seu3w", + }, { + .id = TEGRA264_MEMORY_CLIENT_PVA0R, + .name = "pva0r", + }, { + .id = TEGRA264_MEMORY_CLIENT_PVA0W, + .name = "pva0w", + }, { + .id = TEGRA264_MEMORY_CLIENT_PVA1R, + .name = "pva1r", + }, { + .id = TEGRA264_MEMORY_CLIENT_PVA1W, + .name = "pva1w", + }, { + .id = TEGRA264_MEMORY_CLIENT_PVA2R, + .name = "pva2r", + }, { + .id = TEGRA264_MEMORY_CLIENT_PVA2W, + .name = "pva2w", + }, { + .id = TEGRA264_MEMORY_CLIENT_ISP3W, + .name = "isp3w", + }, { + .id = TEGRA264_MEMORY_CLIENT_ISP2R, + .name = "isp2r", + }, { + .id = TEGRA264_MEMORY_CLIENT_ISP2W, + .name = "isp2w", + }, { + .id = TEGRA264_MEMORY_CLIENT_EQOSR, + .name = "eqosr", + }, { + .id = TEGRA264_MEMORY_CLIENT_EQOSW, + .name = "eqosw", + }, { + .id = TEGRA264_MEMORY_CLIENT_FSI0R, + .name = "fsi0r", + }, { + .id = TEGRA264_MEMORY_CLIENT_FSI0W, + .name = "fsi0w", + }, { + .id = TEGRA264_MEMORY_CLIENT_FSI1R, + .name = "fsi1r", + }, { + .id = TEGRA264_MEMORY_CLIENT_FSI1W, + .name = "fsi1w", + }, { + .id = TEGRA264_MEMORY_CLIENT_SDMMC0R, + .name = "sdmmc0r", + }, { + .id = TEGRA264_MEMORY_CLIENT_SDMMC0W, + .name = "sdmmc0w", + }, { + .id = TEGRA264_MEMORY_CLIENT_SBR, + .name = "sbr", + }, { + .id = TEGRA264_MEMORY_CLIENT_SBW, + .name = "sbw", + }, { + .id = TEGRA264_MEMORY_CLIENT_HSS_MIU0R, + .name = "hss_miu0r", + }, { + .id = TEGRA264_MEMORY_CLIENT_HSS_MIU0W, + .name = "hss_miu0w", + }, { + .id = TEGRA264_MEMORY_CLIENT_HSS_MIU1R, + .name = "hss_miu1r", + }, { + .id = TEGRA264_MEMORY_CLIENT_HSS_MIU1W, + .name = "hss_miu1w", + }, { + .id = TEGRA264_MEMORY_CLIENT_HSS_MIU2R, + .name = "hss_miu2r", + }, { + .id = TEGRA264_MEMORY_CLIENT_HSS_MIU2W, + .name = "hss_miu2w", + }, { + .id = TEGRA264_MEMORY_CLIENT_HSS_MIU3R, + .name = "hss_miu3r", + }, { + .id = TEGRA264_MEMORY_CLIENT_HSS_MIU3W, + .name = "hss_miu3w", + }, { + .id = TEGRA264_MEMORY_CLIENT_HSS_MIU4R, + .name = "hss_miu4r", + }, { + .id = TEGRA264_MEMORY_CLIENT_HSS_MIU4W, + .name = "hss_miu4w", + }, { + .id = TEGRA264_MEMORY_CLIENT_HSS_MIU5R, + .name = "hss_miu5r", + }, { + .id = TEGRA264_MEMORY_CLIENT_HSS_MIU5W, + .name = "hss_miu5w", + }, { + .id = TEGRA264_MEMORY_CLIENT_HSS_MIU6R, + .name = "hss_miu6r", + }, { + .id = TEGRA264_MEMORY_CLIENT_HSS_MIU6W, + .name = "hss_miu6w", + }, { + .id = TEGRA264_MEMORY_CLIENT_HSS_MIU7R, + .name = "hss_miu7r", + }, { + .id = TEGRA264_MEMORY_CLIENT_HSS_MIU7W, + .name = "hss_miu7w", + }, { + .id = TEGRA264_MEMORY_CLIENT_GMMUR2MC, + .name = "gmmur2mc", + }, { + .id = TEGRA264_MEMORY_CLIENT_UCFELAR, + .name = "ucfelar", + }, { + .id = TEGRA264_MEMORY_CLIENT_UCFELAW, + .name = "ucfelaw", + }, { + .id = TEGRA264_MEMORY_CLIENT_SLCR, + .name = "slcr", + }, { + .id = TEGRA264_MEMORY_CLIENT_SLCW, + .name = "slcw", + }, { + .id = TEGRA264_MEMORY_CLIENT_REMOTER, + .name = "remoter", + }, { + .id = TEGRA264_MEMORY_CLIENT_REMOTEW, + .name = "remotew" + }, +}; + +static u32 num_clients = ARRAY_SIZE(clients); + +const char *const tegra_mc_status_names[32] = { + [ 6] = "EMEM address decode error", + [ 8] = "Security violation", + [12] = "VPR violation", + [13] = "Secure carveout violation", + [16] = "MTS carveout violation", + [17] = "Generalized carveout violation", + [20] = "Route Sanity error", + [21] = "GIC_MSI error", +}; + +const char *const tegra_mc_error_names[8] = { + [1] = "EMEM decode error", + [2] = "TrustZone violation", + [3] = "Carveout violation", +}; + +struct tegra_mcerr { + struct device *dev; + void __iomem *bcast_ch_regs; + void __iomem **ch_regs; + int channels; + int irq; + u32 mcf_int_mask; +}; + +static const struct of_device_id tegra_mcerr_of_ids[] = { + { .compatible = "nvidia,tegra-t264-mc-err"}, + {} +}; +MODULE_DEVICE_TABLE(of, tegra_mcerr_of_ids); + +static inline u32 mc_ch_readl(const struct tegra_mcerr *mc_err, int ch, + unsigned long offset) +{ + if (!mc_err->bcast_ch_regs) + return 0; + + if (ch == MC_BROADCAST_CHANNEL) + return readl_relaxed(mc_err->bcast_ch_regs + offset); + + return readl_relaxed(mc_err->ch_regs[ch] + offset); +} + +static inline void mc_ch_writel(const struct tegra_mcerr *mc_err, int ch, + u32 value, unsigned long offset) +{ + if (!mc_err->bcast_ch_regs) + return; + + if (ch == MC_BROADCAST_CHANNEL) + writel_relaxed(value, mc_err->bcast_ch_regs + offset); + else + writel_relaxed(value, mc_err->ch_regs[ch] + offset); +} + +void log_fault(struct tegra_mcerr *mc_err, u32 channel, unsigned long mcf_ch_intstatus) +{ + unsigned int bit; + + for_each_set_bit(bit, &mcf_ch_intstatus, 32) { + const char *error = tegra_mc_status_names[bit] ?: "unknown"; + u32 intmask = BIT(bit); + u32 status_reg, addr_reg, addr_hi_reg = 0; + u32 addr_val, value, client_id, i; + const char *direction, *secure; + const char *client = "unknown", *desc; + phys_addr_t addr = 0; + u8 type; + + switch (intmask) { + case MC_INT_DECERR_EMEM: + status_reg = MC_ERR_STATUS_0; + addr_reg = MC_ERR_ADR_0; + addr_hi_reg = MC_ERR_ADR_HI_0; + break; + case MC_INT_SECURITY_VIOLATION: + status_reg = MC_ERR_STATUS_0; + addr_reg = MC_ERR_ADR_0; + addr_hi_reg = MC_ERR_ADR_HI_0; + break; + case MC_INT_DECERR_VPR: + status_reg = MC_ERR_VPR_STATUS_0; + addr_reg = MC_ERR_VPR_ADR_0; + break; + case MC_INT_SECERR_SEC: + status_reg = MC_ERR_SEC_STATUS_0; + addr_reg = MC_ERR_SEC_ADR_0; + break; + case MC_INT_DECERR_MTS: + status_reg = MC_ERR_MTS_STATUS_0; + addr_reg = MC_ERR_MTS_ADR_0; + break; + case MC_INT_DECERR_GENERALIZED_CARVEOUT: + status_reg = MC_ERR_GENERALIZED_CARVEOUT_STATUS_0; + addr_reg = MC_ERR_GENERALIZED_CARVEOUT_ADR_0; + break; + case MC_INT_SCRUB_ECC_WR_ACK: + status_reg = MC_ERR_STATUS_0; + addr_reg = MC_ERR_ADR_0; + addr_hi_reg = MC_ERR_ADR_HI_0; + break; + case MC_INT_DECERR_ROUTE_SANITY: + status_reg = MC_ERR_ROUTE_SANITY_STATUS_0; + addr_reg = MC_ERR_ROUTE_SANITY_ADR_0; + break; + case MC_INT_DECERR_ROUTE_SANITY_GIC_MSI: + status_reg = MC_ERR_ROUTE_SANITY_STATUS_0; + addr_reg = MC_ERR_ROUTE_SANITY_ADR_0; + break; + } + + value = mc_ch_readl(mc_err, channel, status_reg); + if (addr_hi_reg) + addr = mc_ch_readl(mc_err, channel, addr_hi_reg); + else + addr = ((value >> MC_ERR_STATUS_ADR_HI_SHIFT) & + MC_ERR_STATUS_ADR_HI_MASK); + + addr <<= 32; + addr_val = mc_ch_readl(mc_err, channel, addr_reg); + addr |= addr_val; + + if (value & MC_ERR_STATUS_RW) + direction = "write"; + else + direction = "read"; + + if (value & MC_ERR_STATUS_SECURITY) + secure = "secure"; + else + secure = "non-secure"; + + client_id = value & CLIENT_ID_MASK; + for (i = 0; i < num_clients; i++) { + if (clients[i].id == client_id) { + client = clients[i].name; + break; + } + } + + type = (value & MC_ERR_STATUS_TYPE_MASK) >> + MC_ERR_STATUS_TYPE_SHIFT; + desc = tegra_mc_error_names[type]; + + dev_err_ratelimited(mc_err->dev, "%s: %s%s @%pa: %s (%s)\n", + client, secure, direction, &addr, error, + desc); + } +} + +/* Currently this function only handle MCF interrupts, will extend for other components */ +irqreturn_t handle_irq(int irq, void *data) +{ + struct tegra_mcerr *mc_err = data; + unsigned long mcf_intstatus, mcf_ch_intstatus; + u32 i; + + /* Read MCF_INSTATUS from MCB and if it is set then check for individual channels */ + mcf_intstatus = mc_ch_readl(mc_err, MC_BROADCAST_CHANNEL, MCF_INTSTATUS_0); + if (mcf_intstatus == 0) { + dev_err(mc_err->dev, "No interrupt in MCF\n"); + return IRQ_NONE; + } + + for(i = 0; i < mc_err->channels; i++) { + mcf_ch_intstatus = mc_ch_readl(mc_err, i, MCF_INTSTATUS_0) & (mc_err->mcf_int_mask); + if (mcf_ch_intstatus != 0) { + /* log fault */ + log_fault(mc_err, i, mcf_ch_intstatus); + + /* + * clear interrupts + * TODO: This code is taken from upstream mc-err driver but looks incorrect + * to me. Need to discuss and correct it. + */ + mc_ch_writel(mc_err, i, mcf_ch_intstatus, MCF_INTSTATUS_0); + mc_ch_writel(mc_err, MC_BROADCAST_CHANNEL, mcf_intstatus, MCF_INTSTATUS_0); + return IRQ_HANDLED; + } + } + + return IRQ_NONE; +} + +static int tegra_mcerr_probe(struct platform_device *pdev) +{ + struct tegra_mcerr *mc_err; + u32 i; + int err; + struct resource *res; + + mc_err = devm_kzalloc(&pdev->dev, sizeof(*mc_err), GFP_KERNEL); + if (!mc_err) + return -ENOMEM; + + platform_set_drvdata(pdev, mc_err); + mc_err->dev = &pdev->dev; + mc_err->channels = MAX_MC_CHANNELS; + mc_err->ch_regs = devm_kcalloc(&pdev->dev, mc_err->channels, sizeof(*mc_err->ch_regs), + GFP_KERNEL); + if(!mc_err->ch_regs) + return -ENOMEM; + + /* Map MCB */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(mc_err->dev, "Missing MCB resource\n"); + return -ENODEV; + } + + mc_err->bcast_ch_regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (IS_ERR(mc_err->bcast_ch_regs)) { + dev_err(mc_err->dev, "Ioremap failed for MCB\n"); + return PTR_ERR(mc_err->bcast_ch_regs); + } + + /* Map MC channels */ + for (i = 0; i < mc_err->channels; i++) { + res = platform_get_resource(pdev, IORESOURCE_MEM, i+1); + if (!res) { + dev_err(mc_err->dev, "Missing MC channel %u resource\n", i); + return -ENODEV; + } + + mc_err->ch_regs[i] = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (IS_ERR(mc_err->ch_regs[i])) { + dev_err(mc_err->dev, "Ioremap failed for MC channel %u\n", i); + return PTR_ERR(mc_err->ch_regs[i]); + } + } + + /* Set interrupt masks */ + mc_err->mcf_int_mask = MC_INT_DECERR_ROUTE_SANITY_GIC_MSI | + MC_INT_DECERR_ROUTE_SANITY | MC_INT_SCRUB_ECC_WR_ACK | + MC_INT_DECERR_GENERALIZED_CARVEOUT | MC_INT_DECERR_MTS | + MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | + MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM; + mc_ch_writel(mc_err, MC_BROADCAST_CHANNEL, mc_err->mcf_int_mask, MCF_INTMASK_0); + mc_ch_writel(mc_err, MC_BROADCAST_CHANNEL, mc_err->mcf_int_mask, MCF_INTPRIORITY_0); + + /* Request IRQ and register handler */ + mc_err->irq = platform_get_irq(pdev, 0); + if (mc_err->irq < 0) { + dev_err(mc_err->dev, "Unable to parse/map MC error interrupt\n"); + return -EINVAL; + } + + err = devm_request_irq(&pdev->dev, mc_err->irq, handle_irq, IRQF_SHARED, + dev_name(&pdev->dev), mc_err); + if (err) { + dev_err(mc_err->dev, "devm_request_irq failure\n"); + return err; + } + + return 0; +} + +static int tegra_mcerr_remove(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver mcerr_driver = { + .driver = { + .name = "nv-tegra-mcerr", + .of_match_table = tegra_mcerr_of_ids, + .owner = THIS_MODULE, + }, + .probe = tegra_mcerr_probe, + .remove = tegra_mcerr_remove, +}; + +static int __init tegra_mc_err_init(void) +{ + return platform_driver_register(&mcerr_driver); +} + +static void __exit tegra_mc_err_exit(void) +{ + platform_driver_unregister(&mcerr_driver); +} + +module_exit(tegra_mc_err_exit); +module_init(tegra_mc_err_init); + +MODULE_AUTHOR("Ketan Patil "); +MODULE_DESCRIPTION("Tegra264 MC-ERR driver"); +MODULE_LICENSE("GPL v2");