| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright (c) 2021-2022, NVIDIA CORPORATION. All rights reserved
- *
- * The driver handles Error's from Control Backbone(CBB) version 2.0.
- * generated due to illegal accesses. The driver prints debug information
- * about failed transaction on receiving interrupt from Error Notifier.
- * Error types supported by CBB2.0 are:
- * UNSUPPORTED_ERR, PWRDOWN_ERR, TIMEOUT_ERR, FIREWALL_ERR, DECODE_ERR,
- * SLAVE_ERR
- */
- #include <linux/acpi.h>
- #include <linux/clk.h>
- #include <linux/cpufeature.h>
- #include <linux/debugfs.h>
- #include <linux/module.h>
- #include <linux/of.h>
- #include <linux/platform_device.h>
- #include <linux/device.h>
- #include <linux/io.h>
- #include <linux/interrupt.h>
- #include <linux/ioport.h>
- #include <soc/tegra/fuse.h>
- #include <soc/tegra/tegra-cbb.h>
- #define FABRIC_EN_CFG_INTERRUPT_ENABLE_0_0 0x0
- #define FABRIC_EN_CFG_STATUS_0_0 0x40
- #define FABRIC_EN_CFG_ADDR_INDEX_0_0 0x60
- #define FABRIC_EN_CFG_ADDR_LOW_0 0x80
- #define FABRIC_EN_CFG_ADDR_HI_0 0x84
- #define FABRIC_MN_MASTER_ERR_EN_0 0x200
- #define FABRIC_MN_MASTER_ERR_FORCE_0 0x204
- #define FABRIC_MN_MASTER_ERR_STATUS_0 0x208
- #define FABRIC_MN_MASTER_ERR_OVERFLOW_STATUS_0 0x20c
- #define FABRIC_MN_MASTER_LOG_ERR_STATUS_0 0x300
- #define FABRIC_MN_MASTER_LOG_ADDR_LOW_0 0x304
- #define FABRIC_MN_MASTER_LOG_ADDR_HIGH_0 0x308
- #define FABRIC_MN_MASTER_LOG_ATTRIBUTES0_0 0x30c
- #define FABRIC_MN_MASTER_LOG_ATTRIBUTES1_0 0x310
- #define FABRIC_MN_MASTER_LOG_ATTRIBUTES2_0 0x314
- #define FABRIC_MN_MASTER_LOG_USER_BITS0_0 0x318
- #define AXI_SLV_TIMEOUT_STATUS_0_0 0x8
- #define APB_BLOCK_TMO_STATUS_0 0xc00
- #define APB_BLOCK_NUM_TMO_OFFSET 0x20
- #define FAB_EM_EL_MSTRID GENMASK(29, 24)
- #define FAB_EM_EL_VQC GENMASK(17, 16)
- #define FAB_EM_EL_GRPSEC GENMASK(14, 8)
- #define FAB_EM_EL_FALCONSEC GENMASK(1, 0)
- #define FAB_EM_EL_FABID GENMASK(20, 16)
- #define FAB_EM_EL_SLAVEID GENMASK(7, 0)
- #define FAB_EM_EL_ACCESSID GENMASK(7, 0)
- #define FAB_EM_EL_AXCACHE GENMASK(27, 24)
- #define FAB_EM_EL_AXPROT GENMASK(22, 20)
- #define FAB_EM_EL_BURSTLENGTH GENMASK(19, 12)
- #define FAB_EM_EL_BURSTTYPE GENMASK(9, 8)
- #define FAB_EM_EL_BEATSIZE GENMASK(6, 4)
- #define FAB_EM_EL_ACCESSTYPE GENMASK(0, 0)
- #define USRBITS_MSTR_ID GENMASK(29, 24)
- #define REQ_SOCKET_ID GENMASK(27, 24)
- #define CCPLEX_MSTRID 0x1
- #define FIREWALL_APERTURE_SZ 0x10000
- /* Write firewall check enable */
- #define WEN 0x20000
- enum tegra234_cbb_fabric_ids {
- CBB_FAB_ID,
- SCE_FAB_ID,
- RCE_FAB_ID,
- DCE_FAB_ID,
- AON_FAB_ID,
- PSC_FAB_ID,
- BPMP_FAB_ID,
- FSI_FAB_ID,
- MAX_FAB_ID,
- };
- struct tegra234_slave_lookup {
- const char *name;
- unsigned int offset;
- };
- struct tegra234_cbb_fabric {
- const char *name;
- phys_addr_t off_mask_erd;
- phys_addr_t firewall_base;
- unsigned int firewall_ctl;
- unsigned int firewall_wr_ctl;
- const char * const *master_id;
- unsigned int notifier_offset;
- const struct tegra_cbb_error *errors;
- const int max_errors;
- const struct tegra234_slave_lookup *slave_map;
- const int max_slaves;
- };
- struct tegra234_cbb {
- struct tegra_cbb base;
- const struct tegra234_cbb_fabric *fabric;
- struct resource *res;
- void __iomem *regs;
- int num_intr;
- int sec_irq;
- /* record */
- void __iomem *mon;
- unsigned int type;
- u32 mask;
- u64 access;
- u32 mn_attr0;
- u32 mn_attr1;
- u32 mn_attr2;
- u32 mn_user_bits;
- };
- static inline struct tegra234_cbb *to_tegra234_cbb(struct tegra_cbb *cbb)
- {
- return container_of(cbb, struct tegra234_cbb, base);
- }
- static LIST_HEAD(cbb_list);
- static DEFINE_SPINLOCK(cbb_lock);
- static bool
- tegra234_cbb_write_access_allowed(struct platform_device *pdev, struct tegra234_cbb *cbb)
- {
- u32 val;
- if (!cbb->fabric->firewall_base ||
- !cbb->fabric->firewall_ctl ||
- !cbb->fabric->firewall_wr_ctl) {
- dev_info(&pdev->dev, "SoC data missing for firewall\n");
- return false;
- }
- if ((cbb->fabric->firewall_ctl > FIREWALL_APERTURE_SZ) ||
- (cbb->fabric->firewall_wr_ctl > FIREWALL_APERTURE_SZ)) {
- dev_err(&pdev->dev, "wrong firewall offset value\n");
- return false;
- }
- val = readl(cbb->regs + cbb->fabric->firewall_base + cbb->fabric->firewall_ctl);
- /*
- * If the firewall check feature for allowing or blocking the
- * write accesses through the firewall of a fabric is disabled
- * then CCPLEX can write to the registers of that fabric.
- */
- if (!(val & WEN))
- return true;
- /*
- * If the firewall check is enabled then check whether CCPLEX
- * has write access to the fabric's error notifier registers
- */
- val = readl(cbb->regs + cbb->fabric->firewall_base + cbb->fabric->firewall_wr_ctl);
- if (val & (BIT(CCPLEX_MSTRID)))
- return true;
- return false;
- }
- static void tegra234_cbb_fault_enable(struct tegra_cbb *cbb)
- {
- struct tegra234_cbb *priv = to_tegra234_cbb(cbb);
- void __iomem *addr;
- addr = priv->regs + priv->fabric->notifier_offset;
- writel(0x1ff, addr + FABRIC_EN_CFG_INTERRUPT_ENABLE_0_0);
- dsb(sy);
- }
- static void tegra234_cbb_error_clear(struct tegra_cbb *cbb)
- {
- struct tegra234_cbb *priv = to_tegra234_cbb(cbb);
- writel(0, priv->mon + FABRIC_MN_MASTER_ERR_FORCE_0);
- writel(0x3f, priv->mon + FABRIC_MN_MASTER_ERR_STATUS_0);
- dsb(sy);
- }
- static u32 tegra234_cbb_get_status(struct tegra_cbb *cbb)
- {
- struct tegra234_cbb *priv = to_tegra234_cbb(cbb);
- void __iomem *addr;
- u32 value;
- addr = priv->regs + priv->fabric->notifier_offset;
- value = readl(addr + FABRIC_EN_CFG_STATUS_0_0);
- dsb(sy);
- return value;
- }
- static void tegra234_cbb_mask_serror(struct tegra234_cbb *cbb)
- {
- writel(0x1, cbb->regs + cbb->fabric->off_mask_erd);
- dsb(sy);
- }
- static u32 tegra234_cbb_get_tmo_slv(void __iomem *addr)
- {
- u32 timeout;
- timeout = readl(addr);
- return timeout;
- }
- static void tegra234_cbb_tmo_slv(struct seq_file *file, const char *slave, void __iomem *addr,
- u32 status)
- {
- tegra_cbb_print_err(file, "\t %s : %#x\n", slave, status);
- }
- static void tegra234_cbb_lookup_apbslv(struct seq_file *file, const char *slave,
- void __iomem *base)
- {
- unsigned int block = 0;
- void __iomem *addr;
- char name[64];
- u32 status;
- status = tegra234_cbb_get_tmo_slv(base);
- if (status)
- tegra_cbb_print_err(file, "\t %s_BLOCK_TMO_STATUS : %#x\n", slave, status);
- while (status) {
- if (status & BIT(0)) {
- u32 timeout, clients, client = 0;
- addr = base + APB_BLOCK_NUM_TMO_OFFSET + (block * 4);
- timeout = tegra234_cbb_get_tmo_slv(addr);
- clients = timeout;
- while (timeout) {
- if (timeout & BIT(0)) {
- if (clients != 0xffffffff)
- clients &= BIT(client);
- sprintf(name, "%s_BLOCK%d_TMO", slave, block);
- tegra234_cbb_tmo_slv(file, name, addr, clients);
- }
- timeout >>= 1;
- client++;
- }
- }
- status >>= 1;
- block++;
- }
- }
- static void tegra234_lookup_slave_timeout(struct seq_file *file, struct tegra234_cbb *cbb,
- u8 slave_id, u8 fab_id)
- {
- const struct tegra234_slave_lookup *map = cbb->fabric->slave_map;
- void __iomem *addr;
- /*
- * 1) Get slave node name and address mapping using slave_id.
- * 2) Check if the timed out slave node is APB or AXI.
- * 3) If AXI, then print timeout register and reset axi slave
- * using <FABRIC>_SN_<>_SLV_TIMEOUT_STATUS_0_0 register.
- * 4) If APB, then perform an additional lookup to find the client
- * which timed out.
- * a) Get block number from the index of set bit in
- * <FABRIC>_SN_AXI2APB_<>_BLOCK_TMO_STATUS_0 register.
- * b) Get address of register repective to block number i.e.
- * <FABRIC>_SN_AXI2APB_<>_BLOCK<index-set-bit>_TMO_0.
- * c) Read the register in above step to get client_id which
- * timed out as per the set bits.
- * d) Reset the timedout client and print details.
- * e) Goto step-a till all bits are set.
- */
- addr = cbb->regs + map[slave_id].offset;
- if (strstr(map[slave_id].name, "AXI2APB")) {
- addr += APB_BLOCK_TMO_STATUS_0;
- tegra234_cbb_lookup_apbslv(file, map[slave_id].name, addr);
- } else {
- char name[64];
- u32 status;
- addr += AXI_SLV_TIMEOUT_STATUS_0_0;
- status = tegra234_cbb_get_tmo_slv(addr);
- if (status) {
- sprintf(name, "%s_SLV_TIMEOUT_STATUS", map[slave_id].name);
- tegra234_cbb_tmo_slv(file, name, addr, status);
- }
- }
- }
- static void tegra234_cbb_print_error(struct seq_file *file, struct tegra234_cbb *cbb, u32 status,
- u32 overflow)
- {
- unsigned int type = 0;
- if (status & (status - 1))
- tegra_cbb_print_err(file, "\t Multiple type of errors reported\n");
- while (status) {
- if (type >= cbb->fabric->max_errors) {
- tegra_cbb_print_err(file, "\t Wrong type index:%u, status:%u\n",
- type, status);
- return;
- }
- if (status & 0x1)
- tegra_cbb_print_err(file, "\t Error Code\t\t: %s\n",
- cbb->fabric->errors[type].code);
- status >>= 1;
- type++;
- }
- type = 0;
- while (overflow) {
- if (type >= cbb->fabric->max_errors) {
- tegra_cbb_print_err(file, "\t Wrong type index:%u, overflow:%u\n",
- type, overflow);
- return;
- }
- if (overflow & 0x1)
- tegra_cbb_print_err(file, "\t Overflow\t\t: Multiple %s\n",
- cbb->fabric->errors[type].code);
- overflow >>= 1;
- type++;
- }
- }
- static void print_errlog_err(struct seq_file *file, struct tegra234_cbb *cbb)
- {
- u8 cache_type, prot_type, burst_length, mstr_id, grpsec, vqc, falconsec, beat_size;
- u8 access_type, access_id, requester_socket_id, local_socket_id, slave_id, fab_id;
- char fabric_name[20];
- bool is_numa = false;
- u8 burst_type;
- if (num_possible_nodes() > 1)
- is_numa = true;
- mstr_id = FIELD_GET(FAB_EM_EL_MSTRID, cbb->mn_user_bits);
- vqc = FIELD_GET(FAB_EM_EL_VQC, cbb->mn_user_bits);
- grpsec = FIELD_GET(FAB_EM_EL_GRPSEC, cbb->mn_user_bits);
- falconsec = FIELD_GET(FAB_EM_EL_FALCONSEC, cbb->mn_user_bits);
- /*
- * For SOC with multiple NUMA nodes, print cross socket access
- * errors only if initiator/master_id is CCPLEX, CPMU or GPU.
- */
- if (is_numa) {
- local_socket_id = numa_node_id();
- requester_socket_id = FIELD_GET(REQ_SOCKET_ID, cbb->mn_attr2);
- if (requester_socket_id != local_socket_id) {
- if ((mstr_id != 0x1) && (mstr_id != 0x2) && (mstr_id != 0xB))
- return;
- }
- }
- fab_id = FIELD_GET(FAB_EM_EL_FABID, cbb->mn_attr2);
- slave_id = FIELD_GET(FAB_EM_EL_SLAVEID, cbb->mn_attr2);
- access_id = FIELD_GET(FAB_EM_EL_ACCESSID, cbb->mn_attr1);
- cache_type = FIELD_GET(FAB_EM_EL_AXCACHE, cbb->mn_attr0);
- prot_type = FIELD_GET(FAB_EM_EL_AXPROT, cbb->mn_attr0);
- burst_length = FIELD_GET(FAB_EM_EL_BURSTLENGTH, cbb->mn_attr0);
- burst_type = FIELD_GET(FAB_EM_EL_BURSTTYPE, cbb->mn_attr0);
- beat_size = FIELD_GET(FAB_EM_EL_BEATSIZE, cbb->mn_attr0);
- access_type = FIELD_GET(FAB_EM_EL_ACCESSTYPE, cbb->mn_attr0);
- tegra_cbb_print_err(file, "\n");
- if (cbb->type < cbb->fabric->max_errors)
- tegra_cbb_print_err(file, "\t Error Code\t\t: %s\n",
- cbb->fabric->errors[cbb->type].code);
- else
- tegra_cbb_print_err(file, "\t Wrong type index:%u\n", cbb->type);
- tegra_cbb_print_err(file, "\t MASTER_ID\t\t: %s\n", cbb->fabric->master_id[mstr_id]);
- tegra_cbb_print_err(file, "\t Address\t\t: %#llx\n", cbb->access);
- tegra_cbb_print_cache(file, cache_type);
- tegra_cbb_print_prot(file, prot_type);
- tegra_cbb_print_err(file, "\t Access_Type\t\t: %s", (access_type) ? "Write\n" : "Read\n");
- tegra_cbb_print_err(file, "\t Access_ID\t\t: %#x", access_id);
- if (fab_id == PSC_FAB_ID)
- strcpy(fabric_name, "psc-fabric");
- else if (fab_id == FSI_FAB_ID)
- strcpy(fabric_name, "fsi-fabric");
- else
- strcpy(fabric_name, cbb->fabric->name);
- if (is_numa) {
- tegra_cbb_print_err(file, "\t Requester_Socket_Id\t: %#x\n",
- requester_socket_id);
- tegra_cbb_print_err(file, "\t Local_Socket_Id\t: %#x\n",
- local_socket_id);
- tegra_cbb_print_err(file, "\t No. of NUMA_NODES\t: %#x\n",
- num_possible_nodes());
- }
- tegra_cbb_print_err(file, "\t Fabric\t\t: %s\n", fabric_name);
- tegra_cbb_print_err(file, "\t Slave_Id\t\t: %#x\n", slave_id);
- tegra_cbb_print_err(file, "\t Burst_length\t\t: %#x\n", burst_length);
- tegra_cbb_print_err(file, "\t Burst_type\t\t: %#x\n", burst_type);
- tegra_cbb_print_err(file, "\t Beat_size\t\t: %#x\n", beat_size);
- tegra_cbb_print_err(file, "\t VQC\t\t\t: %#x\n", vqc);
- tegra_cbb_print_err(file, "\t GRPSEC\t\t: %#x\n", grpsec);
- tegra_cbb_print_err(file, "\t FALCONSEC\t\t: %#x\n", falconsec);
- if ((fab_id == PSC_FAB_ID) || (fab_id == FSI_FAB_ID))
- return;
- if (slave_id >= cbb->fabric->max_slaves) {
- tegra_cbb_print_err(file, "\t Invalid slave_id:%d\n", slave_id);
- return;
- }
- if (!strcmp(cbb->fabric->errors[cbb->type].code, "TIMEOUT_ERR")) {
- tegra234_lookup_slave_timeout(file, cbb, slave_id, fab_id);
- return;
- }
- tegra_cbb_print_err(file, "\t Slave\t\t\t: %s\n", cbb->fabric->slave_map[slave_id].name);
- }
- static int print_errmonX_info(struct seq_file *file, struct tegra234_cbb *cbb)
- {
- u32 overflow, status, error;
- status = readl(cbb->mon + FABRIC_MN_MASTER_ERR_STATUS_0);
- if (!status) {
- pr_err("Error Notifier received a spurious notification\n");
- return -ENODATA;
- }
- if (status == 0xffffffff) {
- pr_err("CBB registers returning all 1's which is invalid\n");
- return -EINVAL;
- }
- overflow = readl(cbb->mon + FABRIC_MN_MASTER_ERR_OVERFLOW_STATUS_0);
- tegra234_cbb_print_error(file, cbb, status, overflow);
- error = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ERR_STATUS_0);
- if (!error) {
- pr_info("Error Monitor doesn't have Error Logger\n");
- return -EINVAL;
- }
- cbb->type = 0;
- while (error) {
- if (error & BIT(0)) {
- u32 hi, lo;
- hi = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ADDR_HIGH_0);
- lo = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ADDR_LOW_0);
- cbb->access = (u64)hi << 32 | lo;
- cbb->mn_attr0 = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ATTRIBUTES0_0);
- cbb->mn_attr1 = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ATTRIBUTES1_0);
- cbb->mn_attr2 = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ATTRIBUTES2_0);
- cbb->mn_user_bits = readl(cbb->mon + FABRIC_MN_MASTER_LOG_USER_BITS0_0);
- print_errlog_err(file, cbb);
- }
- cbb->type++;
- error >>= 1;
- }
- return 0;
- }
- static int print_err_notifier(struct seq_file *file, struct tegra234_cbb *cbb, u32 status)
- {
- unsigned int index = 0;
- int err;
- pr_crit("**************************************\n");
- pr_crit("CPU:%d, Error:%s, Errmon:%d\n", smp_processor_id(),
- cbb->fabric->name, status);
- while (status) {
- if (status & BIT(0)) {
- unsigned int notifier = cbb->fabric->notifier_offset;
- u32 hi, lo, mask = BIT(index);
- phys_addr_t addr;
- u64 offset;
- writel(mask, cbb->regs + notifier + FABRIC_EN_CFG_ADDR_INDEX_0_0);
- hi = readl(cbb->regs + notifier + FABRIC_EN_CFG_ADDR_HI_0);
- lo = readl(cbb->regs + notifier + FABRIC_EN_CFG_ADDR_LOW_0);
- addr = (u64)hi << 32 | lo;
- offset = addr - cbb->res->start;
- cbb->mon = cbb->regs + offset;
- cbb->mask = BIT(index);
- err = print_errmonX_info(file, cbb);
- tegra234_cbb_error_clear(&cbb->base);
- if (err)
- return err;
- }
- status >>= 1;
- index++;
- }
- tegra_cbb_print_err(file, "\t**************************************\n");
- return 0;
- }
- #ifdef CONFIG_DEBUG_FS
- static DEFINE_MUTEX(cbb_debugfs_mutex);
- static int tegra234_cbb_debugfs_show(struct tegra_cbb *cbb, struct seq_file *file, void *data)
- {
- int err = 0;
- mutex_lock(&cbb_debugfs_mutex);
- list_for_each_entry(cbb, &cbb_list, node) {
- struct tegra234_cbb *priv = to_tegra234_cbb(cbb);
- u32 status;
- status = tegra_cbb_get_status(&priv->base);
- if (status) {
- err = print_err_notifier(file, priv, status);
- if (err)
- break;
- }
- }
- mutex_unlock(&cbb_debugfs_mutex);
- return err;
- }
- #endif
- /*
- * Handler for CBB errors
- */
- static irqreturn_t tegra234_cbb_isr(int irq, void *data)
- {
- bool is_inband_err = false;
- struct tegra_cbb *cbb;
- unsigned long flags;
- u8 mstr_id;
- int err;
- spin_lock_irqsave(&cbb_lock, flags);
- list_for_each_entry(cbb, &cbb_list, node) {
- struct tegra234_cbb *priv = to_tegra234_cbb(cbb);
- u32 status = tegra_cbb_get_status(cbb);
- if (status && (irq == priv->sec_irq)) {
- tegra_cbb_print_err(NULL, "CPU:%d, Error: %s@0x%llx, irq=%d\n",
- smp_processor_id(), priv->fabric->name,
- priv->res->start, irq);
- err = print_err_notifier(NULL, priv, status);
- if (err)
- goto unlock;
- /*
- * If illegal request is from CCPLEX(id:0x1) master then call WARN()
- */
- if (priv->fabric->off_mask_erd) {
- mstr_id = FIELD_GET(USRBITS_MSTR_ID, priv->mn_user_bits);
- if (mstr_id == CCPLEX_MSTRID)
- is_inband_err = 1;
- }
- }
- }
- unlock:
- spin_unlock_irqrestore(&cbb_lock, flags);
- WARN_ON(is_inband_err);
- return IRQ_HANDLED;
- }
- /*
- * Register handler for CBB_SECURE interrupt for reporting errors
- */
- static int tegra234_cbb_interrupt_enable(struct tegra_cbb *cbb)
- {
- struct tegra234_cbb *priv = to_tegra234_cbb(cbb);
- if (priv->sec_irq) {
- int err = devm_request_irq(cbb->dev, priv->sec_irq, tegra234_cbb_isr, 0,
- dev_name(cbb->dev), priv);
- if (err) {
- dev_err(cbb->dev, "failed to register interrupt %u: %d\n", priv->sec_irq,
- err);
- return err;
- }
- }
- return 0;
- }
- static void tegra234_cbb_error_enable(struct tegra_cbb *cbb)
- {
- tegra_cbb_fault_enable(cbb);
- }
- static const struct tegra_cbb_ops tegra234_cbb_ops = {
- .get_status = tegra234_cbb_get_status,
- .error_clear = tegra234_cbb_error_clear,
- .fault_enable = tegra234_cbb_fault_enable,
- .error_enable = tegra234_cbb_error_enable,
- .interrupt_enable = tegra234_cbb_interrupt_enable,
- #ifdef CONFIG_DEBUG_FS
- .debugfs_show = tegra234_cbb_debugfs_show,
- #endif
- };
- static const char * const tegra234_master_id[] = {
- [0x00] = "TZ",
- [0x01] = "CCPLEX",
- [0x02] = "CCPMU",
- [0x03] = "BPMP_FW",
- [0x04] = "AON",
- [0x05] = "SCE",
- [0x06] = "GPCDMA_P",
- [0x07] = "TSECA_NONSECURE",
- [0x08] = "TSECA_LIGHTSECURE",
- [0x09] = "TSECA_HEAVYSECURE",
- [0x0a] = "CORESIGHT",
- [0x0b] = "APE",
- [0x0c] = "PEATRANS",
- [0x0d] = "JTAGM_DFT",
- [0x0e] = "RCE",
- [0x0f] = "DCE",
- [0x10] = "PSC_FW_USER",
- [0x11] = "PSC_FW_SUPERVISOR",
- [0x12] = "PSC_FW_MACHINE",
- [0x13] = "PSC_BOOT",
- [0x14] = "BPMP_BOOT",
- [0x15] = "NVDEC_NONSECURE",
- [0x16] = "NVDEC_LIGHTSECURE",
- [0x17] = "NVDEC_HEAVYSECURE",
- [0x18] = "CBB_INTERNAL",
- [0x19] = "RSVD"
- };
- static const struct tegra_cbb_error tegra234_cbb_errors[] = {
- {
- .code = "SLAVE_ERR",
- .desc = "Slave being accessed responded with an error"
- }, {
- .code = "DECODE_ERR",
- .desc = "Attempt to access an address hole"
- }, {
- .code = "FIREWALL_ERR",
- .desc = "Attempt to access a region which is firewall protected"
- }, {
- .code = "TIMEOUT_ERR",
- .desc = "No response returned by slave"
- }, {
- .code = "PWRDOWN_ERR",
- .desc = "Attempt to access a portion of fabric that is powered down"
- }, {
- .code = "UNSUPPORTED_ERR",
- .desc = "Attempt to access a slave through an unsupported access"
- }
- };
- static const struct tegra234_slave_lookup tegra234_aon_slave_map[] = {
- { "AXI2APB", 0x00000 },
- { "AST", 0x14000 },
- { "CBB", 0x15000 },
- { "CPU", 0x16000 },
- };
- static const struct tegra234_cbb_fabric tegra234_aon_fabric = {
- .name = "aon-fabric",
- .master_id = tegra234_master_id,
- .slave_map = tegra234_aon_slave_map,
- .max_slaves = ARRAY_SIZE(tegra234_aon_slave_map),
- .errors = tegra234_cbb_errors,
- .max_errors = ARRAY_SIZE(tegra234_cbb_errors),
- .notifier_offset = 0x17000,
- .firewall_base = 0x30000,
- .firewall_ctl = 0x8d0,
- .firewall_wr_ctl = 0x8c8,
- };
- static const struct tegra234_slave_lookup tegra234_bpmp_slave_map[] = {
- { "AXI2APB", 0x00000 },
- { "AST0", 0x15000 },
- { "AST1", 0x16000 },
- { "CBB", 0x17000 },
- { "CPU", 0x18000 },
- };
- static const struct tegra234_cbb_fabric tegra234_bpmp_fabric = {
- .name = "bpmp-fabric",
- .master_id = tegra234_master_id,
- .slave_map = tegra234_bpmp_slave_map,
- .max_slaves = ARRAY_SIZE(tegra234_bpmp_slave_map),
- .errors = tegra234_cbb_errors,
- .max_errors = ARRAY_SIZE(tegra234_cbb_errors),
- .notifier_offset = 0x19000,
- .firewall_base = 0x30000,
- .firewall_ctl = 0x8f0,
- .firewall_wr_ctl = 0x8e8,
- };
- static const struct tegra234_slave_lookup tegra234_cbb_slave_map[] = {
- { "AON", 0x40000 },
- { "BPMP", 0x41000 },
- { "CBB", 0x42000 },
- { "HOST1X", 0x43000 },
- { "STM", 0x44000 },
- { "FSI", 0x45000 },
- { "PSC", 0x46000 },
- { "PCIE_C1", 0x47000 },
- { "PCIE_C2", 0x48000 },
- { "PCIE_C3", 0x49000 },
- { "PCIE_C0", 0x4a000 },
- { "PCIE_C4", 0x4b000 },
- { "GPU", 0x4c000 },
- { "SMMU0", 0x4d000 },
- { "SMMU1", 0x4e000 },
- { "SMMU2", 0x4f000 },
- { "SMMU3", 0x50000 },
- { "SMMU4", 0x51000 },
- { "PCIE_C10", 0x52000 },
- { "PCIE_C7", 0x53000 },
- { "PCIE_C8", 0x54000 },
- { "PCIE_C9", 0x55000 },
- { "PCIE_C5", 0x56000 },
- { "PCIE_C6", 0x57000 },
- { "DCE", 0x58000 },
- { "RCE", 0x59000 },
- { "SCE", 0x5a000 },
- { "AXI2APB_1", 0x70000 },
- { "AXI2APB_10", 0x71000 },
- { "AXI2APB_11", 0x72000 },
- { "AXI2APB_12", 0x73000 },
- { "AXI2APB_13", 0x74000 },
- { "AXI2APB_14", 0x75000 },
- { "AXI2APB_15", 0x76000 },
- { "AXI2APB_16", 0x77000 },
- { "AXI2APB_17", 0x78000 },
- { "AXI2APB_18", 0x79000 },
- { "AXI2APB_19", 0x7a000 },
- { "AXI2APB_2", 0x7b000 },
- { "AXI2APB_20", 0x7c000 },
- { "AXI2APB_21", 0x7d000 },
- { "AXI2APB_22", 0x7e000 },
- { "AXI2APB_23", 0x7f000 },
- { "AXI2APB_25", 0x80000 },
- { "AXI2APB_26", 0x81000 },
- { "AXI2APB_27", 0x82000 },
- { "AXI2APB_28", 0x83000 },
- { "AXI2APB_29", 0x84000 },
- { "AXI2APB_30", 0x85000 },
- { "AXI2APB_31", 0x86000 },
- { "AXI2APB_32", 0x87000 },
- { "AXI2APB_33", 0x88000 },
- { "AXI2APB_34", 0x89000 },
- { "AXI2APB_35", 0x92000 },
- { "AXI2APB_4", 0x8b000 },
- { "AXI2APB_5", 0x8c000 },
- { "AXI2APB_6", 0x8d000 },
- { "AXI2APB_7", 0x8e000 },
- { "AXI2APB_8", 0x8f000 },
- { "AXI2APB_9", 0x90000 },
- { "AXI2APB_3", 0x91000 },
- };
- static const struct tegra234_cbb_fabric tegra234_cbb_fabric = {
- .name = "cbb-fabric",
- .master_id = tegra234_master_id,
- .slave_map = tegra234_cbb_slave_map,
- .max_slaves = ARRAY_SIZE(tegra234_cbb_slave_map),
- .errors = tegra234_cbb_errors,
- .max_errors = ARRAY_SIZE(tegra234_cbb_errors),
- .notifier_offset = 0x60000,
- .off_mask_erd = 0x3a004,
- .firewall_base = 0x10000,
- .firewall_ctl = 0x23f0,
- .firewall_wr_ctl = 0x23e8,
- };
- static const struct tegra234_slave_lookup tegra234_common_slave_map[] = {
- { "AXI2APB", 0x00000 },
- { "AST0", 0x15000 },
- { "AST1", 0x16000 },
- { "CBB", 0x17000 },
- { "RSVD", 0x00000 },
- { "CPU", 0x18000 },
- };
- static const struct tegra234_cbb_fabric tegra234_dce_fabric = {
- .name = "dce-fabric",
- .master_id = tegra234_master_id,
- .slave_map = tegra234_common_slave_map,
- .max_slaves = ARRAY_SIZE(tegra234_common_slave_map),
- .errors = tegra234_cbb_errors,
- .max_errors = ARRAY_SIZE(tegra234_cbb_errors),
- .notifier_offset = 0x19000,
- .firewall_base = 0x30000,
- .firewall_ctl = 0x290,
- .firewall_wr_ctl = 0x288,
- };
- static const struct tegra234_cbb_fabric tegra234_rce_fabric = {
- .name = "rce-fabric",
- .master_id = tegra234_master_id,
- .slave_map = tegra234_common_slave_map,
- .max_slaves = ARRAY_SIZE(tegra234_common_slave_map),
- .errors = tegra234_cbb_errors,
- .max_errors = ARRAY_SIZE(tegra234_cbb_errors),
- .notifier_offset = 0x19000,
- .firewall_base = 0x30000,
- .firewall_ctl = 0x290,
- .firewall_wr_ctl = 0x288,
- };
- static const struct tegra234_cbb_fabric tegra234_sce_fabric = {
- .name = "sce-fabric",
- .master_id = tegra234_master_id,
- .slave_map = tegra234_common_slave_map,
- .max_slaves = ARRAY_SIZE(tegra234_common_slave_map),
- .errors = tegra234_cbb_errors,
- .max_errors = ARRAY_SIZE(tegra234_cbb_errors),
- .notifier_offset = 0x19000,
- .firewall_base = 0x30000,
- .firewall_ctl = 0x290,
- .firewall_wr_ctl = 0x288,
- };
- static const char * const tegra241_master_id[] = {
- [0x0] = "TZ",
- [0x1] = "CCPLEX",
- [0x2] = "CCPMU",
- [0x3] = "BPMP_FW",
- [0x4] = "PSC_FW_USER",
- [0x5] = "PSC_FW_SUPERVISOR",
- [0x6] = "PSC_FW_MACHINE",
- [0x7] = "PSC_BOOT",
- [0x8] = "BPMP_BOOT",
- [0x9] = "JTAGM_DFT",
- [0xa] = "CORESIGHT",
- [0xb] = "GPU",
- [0xc] = "PEATRANS",
- [0xd ... 0x3f] = "RSVD"
- };
- /*
- * Possible causes for Slave and Timeout errors.
- * SLAVE_ERR:
- * Slave being accessed responded with an error. Slave could return
- * an error for various cases :
- * Unsupported access, clamp setting when power gated, register
- * level firewall(SCR), address hole within the slave, etc
- *
- * TIMEOUT_ERR:
- * No response returned by slave. Can be due to slave being clock
- * gated, under reset, powered down or slave inability to respond
- * for an internal slave issue
- */
- static const struct tegra_cbb_error tegra241_cbb_errors[] = {
- {
- .code = "SLAVE_ERR",
- .desc = "Slave being accessed responded with an error."
- }, {
- .code = "DECODE_ERR",
- .desc = "Attempt to access an address hole or Reserved region of memory."
- }, {
- .code = "FIREWALL_ERR",
- .desc = "Attempt to access a region which is firewalled."
- }, {
- .code = "TIMEOUT_ERR",
- .desc = "No response returned by slave."
- }, {
- .code = "PWRDOWN_ERR",
- .desc = "Attempt to access a portion of the fabric that is powered down."
- }, {
- .code = "UNSUPPORTED_ERR",
- .desc = "Attempt to access a slave through an unsupported access."
- }, {
- .code = "POISON_ERR",
- .desc = "Slave responds with poison error to indicate error in data."
- }, {
- .code = "RSVD"
- }, {
- .code = "RSVD"
- }, {
- .code = "RSVD"
- }, {
- .code = "RSVD"
- }, {
- .code = "RSVD"
- }, {
- .code = "RSVD"
- }, {
- .code = "RSVD"
- }, {
- .code = "RSVD"
- }, {
- .code = "RSVD"
- }, {
- .code = "NO_SUCH_ADDRESS_ERR",
- .desc = "The address belongs to the pri_target range but there is no register "
- "implemented at the address."
- }, {
- .code = "TASK_ERR",
- .desc = "Attempt to update a PRI task when the current task has still not "
- "completed."
- }, {
- .code = "EXTERNAL_ERR",
- .desc = "Indicates that an external PRI register access met with an error due to "
- "any issue in the unit."
- }, {
- .code = "INDEX_ERR",
- .desc = "Applicable to PRI index aperture pair, when the programmed index is "
- "outside the range defined in the manual."
- }, {
- .code = "RESET_ERR",
- .desc = "Target in Reset Error: Attempt to access a SubPri or external PRI "
- "register but they are in reset."
- }, {
- .code = "REGISTER_RST_ERR",
- .desc = "Attempt to access a PRI register but the register is partial or "
- "completely in reset."
- }, {
- .code = "POWER_GATED_ERR",
- .desc = "Returned by external PRI client when the external access goes to a power "
- "gated domain."
- }, {
- .code = "SUBPRI_FS_ERR",
- .desc = "Subpri is floorswept: Attempt to access a subpri through the main pri "
- "target but subPri logic is floorswept."
- }, {
- .code = "SUBPRI_CLK_OFF_ERR",
- .desc = "Subpri clock is off: Attempt to access a subpri through the main pri "
- "target but subPris clock is gated/off."
- },
- };
- static const struct tegra234_slave_lookup tegra241_cbb_slave_map[] = {
- { "RSVD", 0x00000 },
- { "PCIE_C8", 0x51000 },
- { "PCIE_C9", 0x52000 },
- { "RSVD", 0x00000 },
- { "RSVD", 0x00000 },
- { "RSVD", 0x00000 },
- { "RSVD", 0x00000 },
- { "RSVD", 0x00000 },
- { "RSVD", 0x00000 },
- { "RSVD", 0x00000 },
- { "RSVD", 0x00000 },
- { "AON", 0x5b000 },
- { "BPMP", 0x5c000 },
- { "RSVD", 0x00000 },
- { "RSVD", 0x00000 },
- { "PSC", 0x5d000 },
- { "STM", 0x5e000 },
- { "AXI2APB_1", 0x70000 },
- { "AXI2APB_10", 0x71000 },
- { "AXI2APB_11", 0x72000 },
- { "AXI2APB_12", 0x73000 },
- { "AXI2APB_13", 0x74000 },
- { "AXI2APB_14", 0x75000 },
- { "AXI2APB_15", 0x76000 },
- { "AXI2APB_16", 0x77000 },
- { "AXI2APB_17", 0x78000 },
- { "AXI2APB_18", 0x79000 },
- { "AXI2APB_19", 0x7a000 },
- { "AXI2APB_2", 0x7b000 },
- { "AXI2APB_20", 0x7c000 },
- { "AXI2APB_4", 0x87000 },
- { "AXI2APB_5", 0x88000 },
- { "AXI2APB_6", 0x89000 },
- { "AXI2APB_7", 0x8a000 },
- { "AXI2APB_8", 0x8b000 },
- { "AXI2APB_9", 0x8c000 },
- { "AXI2APB_3", 0x8d000 },
- { "AXI2APB_21", 0x7d000 },
- { "AXI2APB_22", 0x7e000 },
- { "AXI2APB_23", 0x7f000 },
- { "AXI2APB_24", 0x80000 },
- { "AXI2APB_25", 0x81000 },
- { "AXI2APB_26", 0x82000 },
- { "AXI2APB_27", 0x83000 },
- { "AXI2APB_28", 0x84000 },
- { "PCIE_C4", 0x53000 },
- { "PCIE_C5", 0x54000 },
- { "PCIE_C6", 0x55000 },
- { "PCIE_C7", 0x56000 },
- { "PCIE_C2", 0x57000 },
- { "PCIE_C3", 0x58000 },
- { "PCIE_C0", 0x59000 },
- { "PCIE_C1", 0x5a000 },
- { "CCPLEX", 0x50000 },
- { "AXI2APB_29", 0x85000 },
- { "AXI2APB_30", 0x86000 },
- { "CBB_CENTRAL", 0x00000 },
- { "AXI2APB_31", 0x8E000 },
- { "AXI2APB_32", 0x8F000 },
- };
- static const struct tegra234_cbb_fabric tegra241_cbb_fabric = {
- .name = "cbb-fabric",
- .master_id = tegra241_master_id,
- .slave_map = tegra241_cbb_slave_map,
- .max_slaves = ARRAY_SIZE(tegra241_cbb_slave_map),
- .errors = tegra241_cbb_errors,
- .max_errors = ARRAY_SIZE(tegra241_cbb_errors),
- .notifier_offset = 0x60000,
- .off_mask_erd = 0x40004,
- .firewall_base = 0x20000,
- .firewall_ctl = 0x2370,
- .firewall_wr_ctl = 0x2368,
- };
- static const struct tegra234_slave_lookup tegra241_bpmp_slave_map[] = {
- { "RSVD", 0x00000 },
- { "RSVD", 0x00000 },
- { "RSVD", 0x00000 },
- { "CBB", 0x15000 },
- { "CPU", 0x16000 },
- { "AXI2APB", 0x00000 },
- { "DBB0", 0x17000 },
- { "DBB1", 0x18000 },
- };
- static const struct tegra234_cbb_fabric tegra241_bpmp_fabric = {
- .name = "bpmp-fabric",
- .master_id = tegra241_master_id,
- .slave_map = tegra241_bpmp_slave_map,
- .max_slaves = ARRAY_SIZE(tegra241_bpmp_slave_map),
- .errors = tegra241_cbb_errors,
- .max_errors = ARRAY_SIZE(tegra241_cbb_errors),
- .notifier_offset = 0x19000,
- .firewall_base = 0x30000,
- .firewall_ctl = 0x8f0,
- .firewall_wr_ctl = 0x8e8,
- };
- static const struct of_device_id tegra234_cbb_dt_ids[] = {
- { .compatible = "nvidia,tegra234-cbb-fabric", .data = &tegra234_cbb_fabric },
- { .compatible = "nvidia,tegra234-aon-fabric", .data = &tegra234_aon_fabric },
- { .compatible = "nvidia,tegra234-bpmp-fabric", .data = &tegra234_bpmp_fabric },
- { .compatible = "nvidia,tegra234-dce-fabric", .data = &tegra234_dce_fabric },
- { .compatible = "nvidia,tegra234-rce-fabric", .data = &tegra234_rce_fabric },
- { .compatible = "nvidia,tegra234-sce-fabric", .data = &tegra234_sce_fabric },
- { /* sentinel */ },
- };
- MODULE_DEVICE_TABLE(of, tegra234_cbb_dt_ids);
- struct tegra234_cbb_acpi_uid {
- const char *hid;
- const char *uid;
- const struct tegra234_cbb_fabric *fabric;
- };
- static const struct tegra234_cbb_acpi_uid tegra234_cbb_acpi_uids[] = {
- { "NVDA1070", "1", &tegra241_cbb_fabric },
- { "NVDA1070", "2", &tegra241_bpmp_fabric },
- { },
- };
- static const struct
- tegra234_cbb_fabric *tegra234_cbb_acpi_get_fabric(struct acpi_device *adev)
- {
- const struct tegra234_cbb_acpi_uid *entry;
- for (entry = tegra234_cbb_acpi_uids; entry->hid; entry++) {
- if (acpi_dev_hid_uid_match(adev, entry->hid, entry->uid))
- return entry->fabric;
- }
- return NULL;
- }
- static const struct acpi_device_id tegra241_cbb_acpi_ids[] = {
- { "NVDA1070" },
- { },
- };
- MODULE_DEVICE_TABLE(acpi, tegra241_cbb_acpi_ids);
- static int tegra234_cbb_probe(struct platform_device *pdev)
- {
- const struct tegra234_cbb_fabric *fabric;
- struct tegra234_cbb *cbb;
- unsigned long flags = 0;
- int err;
- if (pdev->dev.of_node) {
- fabric = of_device_get_match_data(&pdev->dev);
- } else {
- struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
- if (!device)
- return -ENODEV;
- fabric = tegra234_cbb_acpi_get_fabric(device);
- if (!fabric) {
- dev_err(&pdev->dev, "no device match found\n");
- return -ENODEV;
- }
- }
- cbb = devm_kzalloc(&pdev->dev, sizeof(*cbb), GFP_KERNEL);
- if (!cbb)
- return -ENOMEM;
- INIT_LIST_HEAD(&cbb->base.node);
- cbb->base.ops = &tegra234_cbb_ops;
- cbb->base.dev = &pdev->dev;
- cbb->fabric = fabric;
- cbb->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &cbb->res);
- if (IS_ERR(cbb->regs))
- return PTR_ERR(cbb->regs);
- err = tegra_cbb_get_irq(pdev, NULL, &cbb->sec_irq);
- if (err)
- return err;
- platform_set_drvdata(pdev, cbb);
- /*
- * Don't enable error reporting for a Fabric if write to it's registers
- * is blocked by CBB firewall.
- */
- if (!tegra234_cbb_write_access_allowed(pdev, cbb)) {
- dev_info(&pdev->dev, "error reporting not enabled due to firewall\n");
- return 0;
- }
- spin_lock_irqsave(&cbb_lock, flags);
- list_add(&cbb->base.node, &cbb_list);
- spin_unlock_irqrestore(&cbb_lock, flags);
- /* set ERD bit to mask SError and generate interrupt to report error */
- if (cbb->fabric->off_mask_erd)
- tegra234_cbb_mask_serror(cbb);
- return tegra_cbb_register(&cbb->base);
- }
- static int __maybe_unused tegra234_cbb_resume_noirq(struct device *dev)
- {
- struct tegra234_cbb *cbb = dev_get_drvdata(dev);
- tegra234_cbb_error_enable(&cbb->base);
- dev_dbg(dev, "%s resumed\n", cbb->fabric->name);
- return 0;
- }
- static const struct dev_pm_ops tegra234_cbb_pm = {
- SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, tegra234_cbb_resume_noirq)
- };
- static struct platform_driver tegra234_cbb_driver = {
- .probe = tegra234_cbb_probe,
- .driver = {
- .name = "tegra234-cbb",
- .of_match_table = tegra234_cbb_dt_ids,
- .acpi_match_table = tegra241_cbb_acpi_ids,
- .pm = &tegra234_cbb_pm,
- },
- };
- static int __init tegra234_cbb_init(void)
- {
- return platform_driver_register(&tegra234_cbb_driver);
- }
- pure_initcall(tegra234_cbb_init);
- static void __exit tegra234_cbb_exit(void)
- {
- platform_driver_unregister(&tegra234_cbb_driver);
- }
- module_exit(tegra234_cbb_exit);
- MODULE_DESCRIPTION("Control Backbone 2.0 error handling driver for Tegra234");
|