1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2021-2022, NVIDIA CORPORATION. All rights reserved 4 * 5 * The driver handles Error's from Control Backbone(CBB) version 2.0. 6 * generated due to illegal accesses. The driver prints debug information 7 * about failed transaction on receiving interrupt from Error Notifier. 8 * Error types supported by CBB2.0 are: 9 * UNSUPPORTED_ERR, PWRDOWN_ERR, TIMEOUT_ERR, FIREWALL_ERR, DECODE_ERR, 10 * SLAVE_ERR 11 */ 12 13 #include <linux/acpi.h> 14 #include <linux/clk.h> 15 #include <linux/cpufeature.h> 16 #include <linux/debugfs.h> 17 #include <linux/module.h> 18 #include <linux/of.h> 19 #include <linux/of_device.h> 20 #include <linux/platform_device.h> 21 #include <linux/device.h> 22 #include <linux/io.h> 23 #include <linux/of_irq.h> 24 #include <linux/of_address.h> 25 #include <linux/interrupt.h> 26 #include <linux/ioport.h> 27 #include <linux/version.h> 28 #include <soc/tegra/fuse.h> 29 #include <soc/tegra/tegra-cbb.h> 30 31 #define FABRIC_EN_CFG_INTERRUPT_ENABLE_0_0 0x0 32 #define FABRIC_EN_CFG_STATUS_0_0 0x40 33 #define FABRIC_EN_CFG_ADDR_INDEX_0_0 0x60 34 #define FABRIC_EN_CFG_ADDR_LOW_0 0x80 35 #define FABRIC_EN_CFG_ADDR_HI_0 0x84 36 37 #define FABRIC_MN_MASTER_ERR_EN_0 0x200 38 #define FABRIC_MN_MASTER_ERR_FORCE_0 0x204 39 #define FABRIC_MN_MASTER_ERR_STATUS_0 0x208 40 #define FABRIC_MN_MASTER_ERR_OVERFLOW_STATUS_0 0x20c 41 42 #define FABRIC_MN_MASTER_LOG_ERR_STATUS_0 0x300 43 #define FABRIC_MN_MASTER_LOG_ADDR_LOW_0 0x304 44 #define FABRIC_MN_MASTER_LOG_ADDR_HIGH_0 0x308 45 #define FABRIC_MN_MASTER_LOG_ATTRIBUTES0_0 0x30c 46 #define FABRIC_MN_MASTER_LOG_ATTRIBUTES1_0 0x310 47 #define FABRIC_MN_MASTER_LOG_ATTRIBUTES2_0 0x314 48 #define FABRIC_MN_MASTER_LOG_USER_BITS0_0 0x318 49 50 #define AXI_SLV_TIMEOUT_STATUS_0_0 0x8 51 #define APB_BLOCK_TMO_STATUS_0 0xc00 52 #define APB_BLOCK_NUM_TMO_OFFSET 0x20 53 54 #define FAB_EM_EL_MSTRID GENMASK(29, 24) 55 #define FAB_EM_EL_VQC GENMASK(17, 16) 56 #define FAB_EM_EL_GRPSEC GENMASK(14, 8) 57 #define FAB_EM_EL_FALCONSEC GENMASK(1, 0) 58 59 #define FAB_EM_EL_FABID GENMASK(20, 16) 60 #define FAB_EM_EL_SLAVEID GENMASK(7, 0) 61 62 #define FAB_EM_EL_ACCESSID GENMASK(7, 0) 63 64 #define FAB_EM_EL_AXCACHE GENMASK(27, 24) 65 #define FAB_EM_EL_AXPROT GENMASK(22, 20) 66 #define FAB_EM_EL_BURSTLENGTH GENMASK(19, 12) 67 #define FAB_EM_EL_BURSTTYPE GENMASK(9, 8) 68 #define FAB_EM_EL_BEATSIZE GENMASK(6, 4) 69 #define FAB_EM_EL_ACCESSTYPE GENMASK(0, 0) 70 71 #define USRBITS_MSTR_ID GENMASK(29, 24) 72 73 #define REQ_SOCKET_ID GENMASK(27, 24) 74 75 enum tegra234_cbb_fabric_ids { 76 CBB_FAB_ID, 77 SCE_FAB_ID, 78 RCE_FAB_ID, 79 DCE_FAB_ID, 80 AON_FAB_ID, 81 PSC_FAB_ID, 82 BPMP_FAB_ID, 83 FSI_FAB_ID, 84 MAX_FAB_ID, 85 }; 86 87 struct tegra234_slave_lookup { 88 const char *name; 89 unsigned int offset; 90 }; 91 92 struct tegra234_cbb_fabric { 93 const char *name; 94 phys_addr_t off_mask_erd; 95 bool erd_mask_inband_err; 96 const char * const *master_id; 97 unsigned int notifier_offset; 98 const struct tegra_cbb_error *errors; 99 const struct tegra234_slave_lookup *slave_map; 100 }; 101 102 struct tegra234_cbb { 103 struct tegra_cbb base; 104 105 const struct tegra234_cbb_fabric *fabric; 106 struct resource *res; 107 void __iomem *regs; 108 109 int num_intr; 110 int sec_irq; 111 112 /* record */ 113 void __iomem *mon; 114 unsigned int type; 115 u32 mask; 116 u64 access; 117 u32 mn_attr0; 118 u32 mn_attr1; 119 u32 mn_attr2; 120 u32 mn_user_bits; 121 }; 122 123 static inline struct tegra234_cbb *to_tegra234_cbb(struct tegra_cbb *cbb) 124 { 125 return container_of(cbb, struct tegra234_cbb, base); 126 } 127 128 static LIST_HEAD(cbb_list); 129 static DEFINE_SPINLOCK(cbb_lock); 130 131 static void tegra234_cbb_fault_enable(struct tegra_cbb *cbb) 132 { 133 struct tegra234_cbb *priv = to_tegra234_cbb(cbb); 134 void __iomem *addr; 135 136 addr = priv->regs + priv->fabric->notifier_offset; 137 writel(0x1ff, addr + FABRIC_EN_CFG_INTERRUPT_ENABLE_0_0); 138 dsb(sy); 139 } 140 141 static void tegra234_cbb_error_clear(struct tegra_cbb *cbb) 142 { 143 struct tegra234_cbb *priv = to_tegra234_cbb(cbb); 144 145 writel(0x3f, priv->mon + FABRIC_MN_MASTER_ERR_STATUS_0); 146 dsb(sy); 147 } 148 149 static u32 tegra234_cbb_get_status(struct tegra_cbb *cbb) 150 { 151 struct tegra234_cbb *priv = to_tegra234_cbb(cbb); 152 void __iomem *addr; 153 u32 value; 154 155 addr = priv->regs + priv->fabric->notifier_offset; 156 value = readl(addr + FABRIC_EN_CFG_STATUS_0_0); 157 dsb(sy); 158 159 return value; 160 } 161 162 static void tegra234_cbb_mask_serror(struct tegra234_cbb *cbb) 163 { 164 writel(0x1, cbb->regs + cbb->fabric->off_mask_erd); 165 dsb(sy); 166 } 167 168 static u32 tegra234_cbb_get_tmo_slv(void __iomem *addr) 169 { 170 u32 timeout; 171 172 timeout = readl(addr); 173 return timeout; 174 } 175 176 static void tegra234_cbb_tmo_slv(struct seq_file *file, const char *slave, void __iomem *addr, 177 u32 status) 178 { 179 tegra_cbb_print_err(file, "\t %s : %#x\n", slave, status); 180 } 181 182 static void tegra234_cbb_lookup_apbslv(struct seq_file *file, const char *slave, 183 void __iomem *base) 184 { 185 unsigned int block = 0; 186 void __iomem *addr; 187 char name[64]; 188 u32 status; 189 190 status = tegra234_cbb_get_tmo_slv(base); 191 if (status) 192 tegra_cbb_print_err(file, "\t %s_BLOCK_TMO_STATUS : %#x\n", slave, status); 193 194 while (status) { 195 if (status & BIT(0)) { 196 u32 timeout, clients, client = 0; 197 198 addr = base + APB_BLOCK_NUM_TMO_OFFSET + (block * 4); 199 timeout = tegra234_cbb_get_tmo_slv(addr); 200 clients = timeout; 201 202 while (timeout) { 203 if (timeout & BIT(0)) { 204 if (clients != 0xffffffff) 205 clients &= BIT(client); 206 207 sprintf(name, "%s_BLOCK%d_TMO", slave, block); 208 209 tegra234_cbb_tmo_slv(file, name, addr, clients); 210 } 211 212 timeout >>= 1; 213 client++; 214 } 215 } 216 217 status >>= 1; 218 block++; 219 } 220 } 221 222 static void tegra234_lookup_slave_timeout(struct seq_file *file, struct tegra234_cbb *cbb, 223 u8 slave_id, u8 fab_id) 224 { 225 const struct tegra234_slave_lookup *map = cbb->fabric->slave_map; 226 void __iomem *addr; 227 228 /* 229 * 1) Get slave node name and address mapping using slave_id. 230 * 2) Check if the timed out slave node is APB or AXI. 231 * 3) If AXI, then print timeout register and reset axi slave 232 * using <FABRIC>_SN_<>_SLV_TIMEOUT_STATUS_0_0 register. 233 * 4) If APB, then perform an additional lookup to find the client 234 * which timed out. 235 * a) Get block number from the index of set bit in 236 * <FABRIC>_SN_AXI2APB_<>_BLOCK_TMO_STATUS_0 register. 237 * b) Get address of register repective to block number i.e. 238 * <FABRIC>_SN_AXI2APB_<>_BLOCK<index-set-bit>_TMO_0. 239 * c) Read the register in above step to get client_id which 240 * timed out as per the set bits. 241 * d) Reset the timedout client and print details. 242 * e) Goto step-a till all bits are set. 243 */ 244 245 addr = cbb->regs + map[slave_id].offset; 246 247 if (strstr(map[slave_id].name, "AXI2APB")) { 248 addr += APB_BLOCK_TMO_STATUS_0; 249 250 tegra234_cbb_lookup_apbslv(file, map[slave_id].name, addr); 251 } else { 252 char name[64]; 253 u32 status; 254 255 addr += AXI_SLV_TIMEOUT_STATUS_0_0; 256 257 status = tegra234_cbb_get_tmo_slv(addr); 258 if (status) { 259 sprintf(name, "%s_SLV_TIMEOUT_STATUS", map[slave_id].name); 260 tegra234_cbb_tmo_slv(file, name, addr, status); 261 } 262 } 263 } 264 265 static void tegra234_cbb_print_error(struct seq_file *file, struct tegra234_cbb *cbb, u32 status, 266 u32 overflow) 267 { 268 unsigned int type = 0; 269 270 if (status & (status - 1)) 271 tegra_cbb_print_err(file, "\t Multiple type of errors reported\n"); 272 273 while (status) { 274 if (status & 0x1) 275 tegra_cbb_print_err(file, "\t Error Code\t\t: %s\n", 276 cbb->fabric->errors[type].code); 277 278 status >>= 1; 279 type++; 280 } 281 282 type = 0; 283 284 while (overflow) { 285 if (overflow & 0x1) 286 tegra_cbb_print_err(file, "\t Overflow\t\t: Multiple %s\n", 287 cbb->fabric->errors[type].code); 288 289 overflow >>= 1; 290 type++; 291 } 292 } 293 294 static void print_errlog_err(struct seq_file *file, struct tegra234_cbb *cbb) 295 { 296 u8 cache_type, prot_type, burst_length, mstr_id, grpsec, vqc, falconsec, beat_size; 297 u8 access_type, access_id, requester_socket_id, local_socket_id, slave_id, fab_id; 298 char fabric_name[20]; 299 bool is_numa = false; 300 u8 burst_type; 301 302 if (num_possible_nodes() > 1) 303 is_numa = true; 304 305 mstr_id = FIELD_GET(FAB_EM_EL_MSTRID, cbb->mn_user_bits); 306 vqc = FIELD_GET(FAB_EM_EL_VQC, cbb->mn_user_bits); 307 grpsec = FIELD_GET(FAB_EM_EL_GRPSEC, cbb->mn_user_bits); 308 falconsec = FIELD_GET(FAB_EM_EL_FALCONSEC, cbb->mn_user_bits); 309 310 /* 311 * For SOC with multiple NUMA nodes, print cross socket access 312 * errors only if initiator/master_id is CCPLEX, CPMU or GPU. 313 */ 314 if (is_numa) { 315 local_socket_id = numa_node_id(); 316 requester_socket_id = FIELD_GET(REQ_SOCKET_ID, cbb->mn_attr2); 317 318 if (requester_socket_id != local_socket_id) { 319 if ((mstr_id != 0x1) && (mstr_id != 0x2) && (mstr_id != 0xB)) 320 return; 321 } 322 } 323 324 fab_id = FIELD_GET(FAB_EM_EL_FABID, cbb->mn_attr2); 325 slave_id = FIELD_GET(FAB_EM_EL_SLAVEID, cbb->mn_attr2); 326 327 access_id = FIELD_GET(FAB_EM_EL_ACCESSID, cbb->mn_attr1); 328 329 cache_type = FIELD_GET(FAB_EM_EL_AXCACHE, cbb->mn_attr0); 330 prot_type = FIELD_GET(FAB_EM_EL_AXPROT, cbb->mn_attr0); 331 burst_length = FIELD_GET(FAB_EM_EL_BURSTLENGTH, cbb->mn_attr0); 332 burst_type = FIELD_GET(FAB_EM_EL_BURSTTYPE, cbb->mn_attr0); 333 beat_size = FIELD_GET(FAB_EM_EL_BEATSIZE, cbb->mn_attr0); 334 access_type = FIELD_GET(FAB_EM_EL_ACCESSTYPE, cbb->mn_attr0); 335 336 tegra_cbb_print_err(file, "\n"); 337 tegra_cbb_print_err(file, "\t Error Code\t\t: %s\n", 338 cbb->fabric->errors[cbb->type].code); 339 340 tegra_cbb_print_err(file, "\t MASTER_ID\t\t: %s\n", cbb->fabric->master_id[mstr_id]); 341 tegra_cbb_print_err(file, "\t Address\t\t: %#llx\n", cbb->access); 342 343 tegra_cbb_print_cache(file, cache_type); 344 tegra_cbb_print_prot(file, prot_type); 345 346 tegra_cbb_print_err(file, "\t Access_Type\t\t: %s", (access_type) ? "Write\n" : "Read\n"); 347 tegra_cbb_print_err(file, "\t Access_ID\t\t: %#x", access_id); 348 349 if (fab_id == PSC_FAB_ID) 350 strcpy(fabric_name, "psc-fabric"); 351 else if (fab_id == FSI_FAB_ID) 352 strcpy(fabric_name, "fsi-fabric"); 353 else 354 strcpy(fabric_name, cbb->fabric->name); 355 356 if (is_numa) { 357 tegra_cbb_print_err(file, "\t Requester_Socket_Id\t: %#x\n", 358 requester_socket_id); 359 tegra_cbb_print_err(file, "\t Local_Socket_Id\t: %#x\n", 360 local_socket_id); 361 tegra_cbb_print_err(file, "\t No. of NUMA_NODES\t: %#x\n", 362 num_possible_nodes()); 363 } 364 365 tegra_cbb_print_err(file, "\t Fabric\t\t: %s\n", fabric_name); 366 tegra_cbb_print_err(file, "\t Slave_Id\t\t: %#x\n", slave_id); 367 tegra_cbb_print_err(file, "\t Burst_length\t\t: %#x\n", burst_length); 368 tegra_cbb_print_err(file, "\t Burst_type\t\t: %#x\n", burst_type); 369 tegra_cbb_print_err(file, "\t Beat_size\t\t: %#x\n", beat_size); 370 tegra_cbb_print_err(file, "\t VQC\t\t\t: %#x\n", vqc); 371 tegra_cbb_print_err(file, "\t GRPSEC\t\t: %#x\n", grpsec); 372 tegra_cbb_print_err(file, "\t FALCONSEC\t\t: %#x\n", falconsec); 373 374 if ((fab_id == PSC_FAB_ID) || (fab_id == FSI_FAB_ID)) 375 return; 376 377 if (!strcmp(cbb->fabric->errors[cbb->type].code, "TIMEOUT_ERR")) { 378 tegra234_lookup_slave_timeout(file, cbb, slave_id, fab_id); 379 return; 380 } 381 382 tegra_cbb_print_err(file, "\t Slave\t\t\t: %s\n", cbb->fabric->slave_map[slave_id].name); 383 } 384 385 static int print_errmonX_info(struct seq_file *file, struct tegra234_cbb *cbb) 386 { 387 u32 overflow, status, error; 388 389 status = readl(cbb->mon + FABRIC_MN_MASTER_ERR_STATUS_0); 390 if (!status) { 391 pr_err("Error Notifier received a spurious notification\n"); 392 return -ENODATA; 393 } 394 395 if (status == 0xffffffff) { 396 pr_err("CBB registers returning all 1's which is invalid\n"); 397 return -EINVAL; 398 } 399 400 overflow = readl(cbb->mon + FABRIC_MN_MASTER_ERR_OVERFLOW_STATUS_0); 401 402 tegra234_cbb_print_error(file, cbb, status, overflow); 403 404 error = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ERR_STATUS_0); 405 if (!error) { 406 pr_info("Error Monitor doesn't have Error Logger\n"); 407 return -EINVAL; 408 } 409 410 cbb->type = 0; 411 412 while (error) { 413 if (error & BIT(0)) { 414 u32 hi, lo; 415 416 hi = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ADDR_HIGH_0); 417 lo = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ADDR_LOW_0); 418 419 cbb->access = (u64)hi << 32 | lo; 420 421 cbb->mn_attr0 = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ATTRIBUTES0_0); 422 cbb->mn_attr1 = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ATTRIBUTES1_0); 423 cbb->mn_attr2 = readl(cbb->mon + FABRIC_MN_MASTER_LOG_ATTRIBUTES2_0); 424 cbb->mn_user_bits = readl(cbb->mon + FABRIC_MN_MASTER_LOG_USER_BITS0_0); 425 426 print_errlog_err(file, cbb); 427 } 428 429 cbb->type++; 430 error >>= 1; 431 } 432 433 return 0; 434 } 435 436 static int print_err_notifier(struct seq_file *file, struct tegra234_cbb *cbb, u32 status) 437 { 438 unsigned int index = 0; 439 int err; 440 441 pr_crit("**************************************\n"); 442 pr_crit("CPU:%d, Error:%s, Errmon:%d\n", smp_processor_id(), 443 cbb->fabric->name, status); 444 445 while (status) { 446 if (status & BIT(0)) { 447 unsigned int notifier = cbb->fabric->notifier_offset; 448 u32 hi, lo, mask = BIT(index); 449 phys_addr_t addr; 450 u64 offset; 451 452 writel(mask, cbb->regs + notifier + FABRIC_EN_CFG_ADDR_INDEX_0_0); 453 hi = readl(cbb->regs + notifier + FABRIC_EN_CFG_ADDR_HI_0); 454 lo = readl(cbb->regs + notifier + FABRIC_EN_CFG_ADDR_LOW_0); 455 456 addr = (u64)hi << 32 | lo; 457 458 offset = addr - cbb->res->start; 459 cbb->mon = cbb->regs + offset; 460 cbb->mask = BIT(index); 461 462 err = print_errmonX_info(file, cbb); 463 tegra234_cbb_error_clear(&cbb->base); 464 if (err) 465 return err; 466 } 467 468 status >>= 1; 469 index++; 470 } 471 472 tegra_cbb_print_err(file, "\t**************************************\n"); 473 return 0; 474 } 475 476 #ifdef CONFIG_DEBUG_FS 477 static DEFINE_MUTEX(cbb_debugfs_mutex); 478 479 static int tegra234_cbb_debugfs_show(struct tegra_cbb *cbb, struct seq_file *file, void *data) 480 { 481 int err = 0; 482 483 mutex_lock(&cbb_debugfs_mutex); 484 485 list_for_each_entry(cbb, &cbb_list, node) { 486 struct tegra234_cbb *priv = to_tegra234_cbb(cbb); 487 u32 status; 488 489 status = tegra_cbb_get_status(&priv->base); 490 if (status) { 491 err = print_err_notifier(file, priv, status); 492 if (err) 493 break; 494 } 495 } 496 497 mutex_unlock(&cbb_debugfs_mutex); 498 return err; 499 } 500 #endif 501 502 /* 503 * Handler for CBB errors 504 */ 505 static irqreturn_t tegra234_cbb_isr(int irq, void *data) 506 { 507 bool is_inband_err = false; 508 struct tegra_cbb *cbb; 509 unsigned long flags; 510 u8 mstr_id; 511 int err; 512 513 spin_lock_irqsave(&cbb_lock, flags); 514 515 list_for_each_entry(cbb, &cbb_list, node) { 516 struct tegra234_cbb *priv = to_tegra234_cbb(cbb); 517 u32 status = tegra_cbb_get_status(cbb); 518 519 if (status && (irq == priv->sec_irq)) { 520 tegra_cbb_print_err(NULL, "CPU:%d, Error: %s@%llx, irq=%d\n", 521 smp_processor_id(), priv->fabric->name, 522 priv->res->start, irq); 523 524 err = print_err_notifier(NULL, priv, status); 525 if (err) 526 goto unlock; 527 528 mstr_id = FIELD_GET(USRBITS_MSTR_ID, priv->mn_user_bits); 529 530 /* 531 * If illegal request is from CCPLEX(id:0x1) master then call BUG() to 532 * crash system. 533 */ 534 if ((mstr_id == 0x1) && priv->fabric->off_mask_erd) 535 is_inband_err = 1; 536 } 537 } 538 539 unlock: 540 spin_unlock_irqrestore(&cbb_lock, flags); 541 WARN_ON(is_inband_err); 542 return IRQ_HANDLED; 543 } 544 545 /* 546 * Register handler for CBB_SECURE interrupt for reporting errors 547 */ 548 static int tegra234_cbb_interrupt_enable(struct tegra_cbb *cbb) 549 { 550 struct tegra234_cbb *priv = to_tegra234_cbb(cbb); 551 552 if (priv->sec_irq) { 553 int err = devm_request_irq(cbb->dev, priv->sec_irq, tegra234_cbb_isr, 0, 554 dev_name(cbb->dev), priv); 555 if (err) { 556 dev_err(cbb->dev, "failed to register interrupt %u: %d\n", priv->sec_irq, 557 err); 558 return err; 559 } 560 } 561 562 return 0; 563 } 564 565 static void tegra234_cbb_error_enable(struct tegra_cbb *cbb) 566 { 567 tegra_cbb_fault_enable(cbb); 568 } 569 570 static const struct tegra_cbb_ops tegra234_cbb_ops = { 571 .get_status = tegra234_cbb_get_status, 572 .error_clear = tegra234_cbb_error_clear, 573 .fault_enable = tegra234_cbb_fault_enable, 574 .error_enable = tegra234_cbb_error_enable, 575 .interrupt_enable = tegra234_cbb_interrupt_enable, 576 #ifdef CONFIG_DEBUG_FS 577 .debugfs_show = tegra234_cbb_debugfs_show, 578 #endif 579 }; 580 581 static const char * const tegra234_master_id[] = { 582 [0x00] = "TZ", 583 [0x01] = "CCPLEX", 584 [0x02] = "CCPMU", 585 [0x03] = "BPMP_FW", 586 [0x04] = "AON", 587 [0x05] = "SCE", 588 [0x06] = "GPCDMA_P", 589 [0x07] = "TSECA_NONSECURE", 590 [0x08] = "TSECA_LIGHTSECURE", 591 [0x09] = "TSECA_HEAVYSECURE", 592 [0x0a] = "CORESIGHT", 593 [0x0b] = "APE", 594 [0x0c] = "PEATRANS", 595 [0x0d] = "JTAGM_DFT", 596 [0x0e] = "RCE", 597 [0x0f] = "DCE", 598 [0x10] = "PSC_FW_USER", 599 [0x11] = "PSC_FW_SUPERVISOR", 600 [0x12] = "PSC_FW_MACHINE", 601 [0x13] = "PSC_BOOT", 602 [0x14] = "BPMP_BOOT", 603 [0x15] = "NVDEC_NONSECURE", 604 [0x16] = "NVDEC_LIGHTSECURE", 605 [0x17] = "NVDEC_HEAVYSECURE", 606 [0x18] = "CBB_INTERNAL", 607 [0x19] = "RSVD" 608 }; 609 610 static const struct tegra_cbb_error tegra234_cbb_errors[] = { 611 { 612 .code = "SLAVE_ERR", 613 .desc = "Slave being accessed responded with an error" 614 }, { 615 .code = "DECODE_ERR", 616 .desc = "Attempt to access an address hole" 617 }, { 618 .code = "FIREWALL_ERR", 619 .desc = "Attempt to access a region which is firewall protected" 620 }, { 621 .code = "TIMEOUT_ERR", 622 .desc = "No response returned by slave" 623 }, { 624 .code = "PWRDOWN_ERR", 625 .desc = "Attempt to access a portion of fabric that is powered down" 626 }, { 627 .code = "UNSUPPORTED_ERR", 628 .desc = "Attempt to access a slave through an unsupported access" 629 } 630 }; 631 632 static const struct tegra234_slave_lookup tegra234_aon_slave_map[] = { 633 { "AXI2APB", 0x00000 }, 634 { "AST", 0x14000 }, 635 { "CBB", 0x15000 }, 636 { "CPU", 0x16000 }, 637 }; 638 639 static const struct tegra234_cbb_fabric tegra234_aon_fabric = { 640 .name = "aon-fabric", 641 .master_id = tegra234_master_id, 642 .slave_map = tegra234_aon_slave_map, 643 .errors = tegra234_cbb_errors, 644 .notifier_offset = 0x17000, 645 }; 646 647 static const struct tegra234_slave_lookup tegra234_bpmp_slave_map[] = { 648 { "AXI2APB", 0x00000 }, 649 { "AST0", 0x15000 }, 650 { "AST1", 0x16000 }, 651 { "CBB", 0x17000 }, 652 { "CPU", 0x18000 }, 653 }; 654 655 static const struct tegra234_cbb_fabric tegra234_bpmp_fabric = { 656 .name = "bpmp-fabric", 657 .master_id = tegra234_master_id, 658 .slave_map = tegra234_bpmp_slave_map, 659 .errors = tegra234_cbb_errors, 660 .notifier_offset = 0x19000, 661 }; 662 663 static const struct tegra234_slave_lookup tegra234_cbb_slave_map[] = { 664 { "AON", 0x40000 }, 665 { "BPMP", 0x41000 }, 666 { "CBB", 0x42000 }, 667 { "HOST1X", 0x43000 }, 668 { "STM", 0x44000 }, 669 { "FSI", 0x45000 }, 670 { "PSC", 0x46000 }, 671 { "PCIE_C1", 0x47000 }, 672 { "PCIE_C2", 0x48000 }, 673 { "PCIE_C3", 0x49000 }, 674 { "PCIE_C0", 0x4a000 }, 675 { "PCIE_C4", 0x4b000 }, 676 { "GPU", 0x4c000 }, 677 { "SMMU0", 0x4d000 }, 678 { "SMMU1", 0x4e000 }, 679 { "SMMU2", 0x4f000 }, 680 { "SMMU3", 0x50000 }, 681 { "SMMU4", 0x51000 }, 682 { "PCIE_C10", 0x52000 }, 683 { "PCIE_C7", 0x53000 }, 684 { "PCIE_C8", 0x54000 }, 685 { "PCIE_C9", 0x55000 }, 686 { "PCIE_C5", 0x56000 }, 687 { "PCIE_C6", 0x57000 }, 688 { "DCE", 0x58000 }, 689 { "RCE", 0x59000 }, 690 { "SCE", 0x5a000 }, 691 { "AXI2APB_1", 0x70000 }, 692 { "AXI2APB_10", 0x71000 }, 693 { "AXI2APB_11", 0x72000 }, 694 { "AXI2APB_12", 0x73000 }, 695 { "AXI2APB_13", 0x74000 }, 696 { "AXI2APB_14", 0x75000 }, 697 { "AXI2APB_15", 0x76000 }, 698 { "AXI2APB_16", 0x77000 }, 699 { "AXI2APB_17", 0x78000 }, 700 { "AXI2APB_18", 0x79000 }, 701 { "AXI2APB_19", 0x7a000 }, 702 { "AXI2APB_2", 0x7b000 }, 703 { "AXI2APB_20", 0x7c000 }, 704 { "AXI2APB_21", 0x7d000 }, 705 { "AXI2APB_22", 0x7e000 }, 706 { "AXI2APB_23", 0x7f000 }, 707 { "AXI2APB_25", 0x80000 }, 708 { "AXI2APB_26", 0x81000 }, 709 { "AXI2APB_27", 0x82000 }, 710 { "AXI2APB_28", 0x83000 }, 711 { "AXI2APB_29", 0x84000 }, 712 { "AXI2APB_30", 0x85000 }, 713 { "AXI2APB_31", 0x86000 }, 714 { "AXI2APB_32", 0x87000 }, 715 { "AXI2APB_33", 0x88000 }, 716 { "AXI2APB_34", 0x89000 }, 717 { "AXI2APB_35", 0x92000 }, 718 { "AXI2APB_4", 0x8b000 }, 719 { "AXI2APB_5", 0x8c000 }, 720 { "AXI2APB_6", 0x8d000 }, 721 { "AXI2APB_7", 0x8e000 }, 722 { "AXI2APB_8", 0x8f000 }, 723 { "AXI2APB_9", 0x90000 }, 724 { "AXI2APB_3", 0x91000 }, 725 }; 726 727 static const struct tegra234_cbb_fabric tegra234_cbb_fabric = { 728 .name = "cbb-fabric", 729 .master_id = tegra234_master_id, 730 .slave_map = tegra234_cbb_slave_map, 731 .errors = tegra234_cbb_errors, 732 .notifier_offset = 0x60000, 733 .off_mask_erd = 0x3a004 734 }; 735 736 static const struct tegra234_slave_lookup tegra234_dce_slave_map[] = { 737 { "AXI2APB", 0x00000 }, 738 { "AST0", 0x15000 }, 739 { "AST1", 0x16000 }, 740 { "CPU", 0x18000 }, 741 }; 742 743 static const struct tegra234_cbb_fabric tegra234_dce_fabric = { 744 .name = "dce-fabric", 745 .master_id = tegra234_master_id, 746 .slave_map = tegra234_dce_slave_map, 747 .errors = tegra234_cbb_errors, 748 .notifier_offset = 0x19000, 749 }; 750 751 static const struct tegra234_slave_lookup tegra234_rce_slave_map[] = { 752 { "AXI2APB", 0x00000 }, 753 { "AST0", 0x15000 }, 754 { "AST1", 0x16000 }, 755 { "CPU", 0x18000 }, 756 }; 757 758 static const struct tegra234_cbb_fabric tegra234_rce_fabric = { 759 .name = "rce-fabric", 760 .master_id = tegra234_master_id, 761 .slave_map = tegra234_rce_slave_map, 762 .errors = tegra234_cbb_errors, 763 .notifier_offset = 0x19000, 764 }; 765 766 static const struct tegra234_slave_lookup tegra234_sce_slave_map[] = { 767 { "AXI2APB", 0x00000 }, 768 { "AST0", 0x15000 }, 769 { "AST1", 0x16000 }, 770 { "CBB", 0x17000 }, 771 { "CPU", 0x18000 }, 772 }; 773 774 static const struct tegra234_cbb_fabric tegra234_sce_fabric = { 775 .name = "sce-fabric", 776 .master_id = tegra234_master_id, 777 .slave_map = tegra234_sce_slave_map, 778 .errors = tegra234_cbb_errors, 779 .notifier_offset = 0x19000, 780 }; 781 782 static const char * const tegra241_master_id[] = { 783 [0x0] = "TZ", 784 [0x1] = "CCPLEX", 785 [0x2] = "CCPMU", 786 [0x3] = "BPMP_FW", 787 [0x4] = "PSC_FW_USER", 788 [0x5] = "PSC_FW_SUPERVISOR", 789 [0x6] = "PSC_FW_MACHINE", 790 [0x7] = "PSC_BOOT", 791 [0x8] = "BPMP_BOOT", 792 [0x9] = "JTAGM_DFT", 793 [0xa] = "CORESIGHT", 794 [0xb] = "GPU", 795 [0xc] = "PEATRANS", 796 [0xd ... 0x3f] = "RSVD" 797 }; 798 799 /* 800 * Possible causes for Slave and Timeout errors. 801 * SLAVE_ERR: 802 * Slave being accessed responded with an error. Slave could return 803 * an error for various cases : 804 * Unsupported access, clamp setting when power gated, register 805 * level firewall(SCR), address hole within the slave, etc 806 * 807 * TIMEOUT_ERR: 808 * No response returned by slave. Can be due to slave being clock 809 * gated, under reset, powered down or slave inability to respond 810 * for an internal slave issue 811 */ 812 static const struct tegra_cbb_error tegra241_cbb_errors[] = { 813 { 814 .code = "SLAVE_ERR", 815 .desc = "Slave being accessed responded with an error." 816 }, { 817 .code = "DECODE_ERR", 818 .desc = "Attempt to access an address hole or Reserved region of memory." 819 }, { 820 .code = "FIREWALL_ERR", 821 .desc = "Attempt to access a region which is firewalled." 822 }, { 823 .code = "TIMEOUT_ERR", 824 .desc = "No response returned by slave." 825 }, { 826 .code = "PWRDOWN_ERR", 827 .desc = "Attempt to access a portion of the fabric that is powered down." 828 }, { 829 .code = "UNSUPPORTED_ERR", 830 .desc = "Attempt to access a slave through an unsupported access." 831 }, { 832 .code = "POISON_ERR", 833 .desc = "Slave responds with poison error to indicate error in data." 834 }, { 835 .code = "RSVD" 836 }, { 837 .code = "RSVD" 838 }, { 839 .code = "RSVD" 840 }, { 841 .code = "RSVD" 842 }, { 843 .code = "RSVD" 844 }, { 845 .code = "RSVD" 846 }, { 847 .code = "RSVD" 848 }, { 849 .code = "RSVD" 850 }, { 851 .code = "RSVD" 852 }, { 853 .code = "NO_SUCH_ADDRESS_ERR", 854 .desc = "The address belongs to the pri_target range but there is no register " 855 "implemented at the address." 856 }, { 857 .code = "TASK_ERR", 858 .desc = "Attempt to update a PRI task when the current task has still not " 859 "completed." 860 }, { 861 .code = "EXTERNAL_ERR", 862 .desc = "Indicates that an external PRI register access met with an error due to " 863 "any issue in the unit." 864 }, { 865 .code = "INDEX_ERR", 866 .desc = "Applicable to PRI index aperture pair, when the programmed index is " 867 "outside the range defined in the manual." 868 }, { 869 .code = "RESET_ERR", 870 .desc = "Target in Reset Error: Attempt to access a SubPri or external PRI " 871 "register but they are in reset." 872 }, { 873 .code = "REGISTER_RST_ERR", 874 .desc = "Attempt to access a PRI register but the register is partial or " 875 "completely in reset." 876 }, { 877 .code = "POWER_GATED_ERR", 878 .desc = "Returned by external PRI client when the external access goes to a power " 879 "gated domain." 880 }, { 881 .code = "SUBPRI_FS_ERR", 882 .desc = "Subpri is floorswept: Attempt to access a subpri through the main pri " 883 "target but subPri logic is floorswept." 884 }, { 885 .code = "SUBPRI_CLK_OFF_ERR", 886 .desc = "Subpri clock is off: Attempt to access a subpri through the main pri " 887 "target but subPris clock is gated/off." 888 }, 889 }; 890 891 static const struct tegra234_slave_lookup tegra241_cbb_slave_map[] = { 892 { "CCPLEX", 0x50000 }, 893 { "PCIE_C8", 0x51000 }, 894 { "PCIE_C9", 0x52000 }, 895 { "RSVD", 0x00000 }, 896 { "RSVD", 0x00000 }, 897 { "RSVD", 0x00000 }, 898 { "RSVD", 0x00000 }, 899 { "RSVD", 0x00000 }, 900 { "RSVD", 0x00000 }, 901 { "RSVD", 0x00000 }, 902 { "RSVD", 0x00000 }, 903 { "AON", 0x5b000 }, 904 { "BPMP", 0x5c000 }, 905 { "RSVD", 0x00000 }, 906 { "RSVD", 0x00000 }, 907 { "PSC", 0x5d000 }, 908 { "STM", 0x5e000 }, 909 { "AXI2APB_1", 0x70000 }, 910 { "AXI2APB_10", 0x71000 }, 911 { "AXI2APB_11", 0x72000 }, 912 { "AXI2APB_12", 0x73000 }, 913 { "AXI2APB_13", 0x74000 }, 914 { "AXI2APB_14", 0x75000 }, 915 { "AXI2APB_15", 0x76000 }, 916 { "AXI2APB_16", 0x77000 }, 917 { "AXI2APB_17", 0x78000 }, 918 { "AXI2APB_18", 0x79000 }, 919 { "AXI2APB_19", 0x7a000 }, 920 { "AXI2APB_2", 0x7b000 }, 921 { "AXI2APB_20", 0x7c000 }, 922 { "AXI2APB_4", 0x87000 }, 923 { "AXI2APB_5", 0x88000 }, 924 { "AXI2APB_6", 0x89000 }, 925 { "AXI2APB_7", 0x8a000 }, 926 { "AXI2APB_8", 0x8b000 }, 927 { "AXI2APB_9", 0x8c000 }, 928 { "AXI2APB_3", 0x8d000 }, 929 { "AXI2APB_21", 0x7d000 }, 930 { "AXI2APB_22", 0x7e000 }, 931 { "AXI2APB_23", 0x7f000 }, 932 { "AXI2APB_24", 0x80000 }, 933 { "AXI2APB_25", 0x81000 }, 934 { "AXI2APB_26", 0x82000 }, 935 { "AXI2APB_27", 0x83000 }, 936 { "AXI2APB_28", 0x84000 }, 937 { "PCIE_C4", 0x53000 }, 938 { "PCIE_C5", 0x54000 }, 939 { "PCIE_C6", 0x55000 }, 940 { "PCIE_C7", 0x56000 }, 941 { "PCIE_C2", 0x57000 }, 942 { "PCIE_C3", 0x58000 }, 943 { "PCIE_C0", 0x59000 }, 944 { "PCIE_C1", 0x5a000 }, 945 { "AXI2APB_29", 0x85000 }, 946 { "AXI2APB_30", 0x86000 }, 947 }; 948 949 static const struct tegra234_cbb_fabric tegra241_cbb_fabric = { 950 .name = "cbb-fabric", 951 .master_id = tegra241_master_id, 952 .slave_map = tegra241_cbb_slave_map, 953 .errors = tegra241_cbb_errors, 954 .notifier_offset = 0x60000, 955 .off_mask_erd = 0x40004, 956 }; 957 958 static const struct tegra234_slave_lookup tegra241_bpmp_slave_map[] = { 959 { "RSVD", 0x00000 }, 960 { "RSVD", 0x00000 }, 961 { "CBB", 0x15000 }, 962 { "CPU", 0x16000 }, 963 { "AXI2APB", 0x00000 }, 964 { "DBB0", 0x17000 }, 965 { "DBB1", 0x18000 }, 966 }; 967 968 static const struct tegra234_cbb_fabric tegra241_bpmp_fabric = { 969 .name = "bpmp-fabric", 970 .master_id = tegra241_master_id, 971 .slave_map = tegra241_bpmp_slave_map, 972 .errors = tegra241_cbb_errors, 973 .notifier_offset = 0x19000, 974 }; 975 976 static const struct of_device_id tegra234_cbb_dt_ids[] = { 977 { .compatible = "nvidia,tegra234-cbb-fabric", .data = &tegra234_cbb_fabric }, 978 { .compatible = "nvidia,tegra234-aon-fabric", .data = &tegra234_aon_fabric }, 979 { .compatible = "nvidia,tegra234-bpmp-fabric", .data = &tegra234_bpmp_fabric }, 980 { .compatible = "nvidia,tegra234-dce-fabric", .data = &tegra234_dce_fabric }, 981 { .compatible = "nvidia,tegra234-rce-fabric", .data = &tegra234_rce_fabric }, 982 { .compatible = "nvidia,tegra234-sce-fabric", .data = &tegra234_sce_fabric }, 983 { /* sentinel */ }, 984 }; 985 MODULE_DEVICE_TABLE(of, tegra234_cbb_dt_ids); 986 987 struct tegra234_cbb_acpi_uid { 988 const char *hid; 989 const char *uid; 990 const struct tegra234_cbb_fabric *fabric; 991 }; 992 993 static const struct tegra234_cbb_acpi_uid tegra234_cbb_acpi_uids[] = { 994 { "NVDA1070", "1", &tegra241_cbb_fabric }, 995 { "NVDA1070", "2", &tegra241_bpmp_fabric }, 996 { }, 997 }; 998 999 static const struct 1000 tegra234_cbb_fabric *tegra234_cbb_acpi_get_fabric(struct acpi_device *adev) 1001 { 1002 const struct tegra234_cbb_acpi_uid *entry; 1003 1004 for (entry = tegra234_cbb_acpi_uids; entry->hid; entry++) { 1005 if (acpi_dev_hid_uid_match(adev, entry->hid, entry->uid)) 1006 return entry->fabric; 1007 } 1008 1009 return NULL; 1010 } 1011 1012 static const struct acpi_device_id tegra241_cbb_acpi_ids[] = { 1013 { "NVDA1070" }, 1014 { }, 1015 }; 1016 MODULE_DEVICE_TABLE(acpi, tegra241_cbb_acpi_ids); 1017 1018 static int tegra234_cbb_probe(struct platform_device *pdev) 1019 { 1020 const struct tegra234_cbb_fabric *fabric; 1021 struct tegra234_cbb *cbb; 1022 unsigned long flags = 0; 1023 int err; 1024 1025 if (pdev->dev.of_node) { 1026 fabric = of_device_get_match_data(&pdev->dev); 1027 } else { 1028 struct acpi_device *device = ACPI_COMPANION(&pdev->dev); 1029 if (!device) 1030 return -ENODEV; 1031 1032 fabric = tegra234_cbb_acpi_get_fabric(device); 1033 if (!fabric) { 1034 dev_err(&pdev->dev, "no device match found\n"); 1035 return -ENODEV; 1036 } 1037 } 1038 1039 cbb = devm_kzalloc(&pdev->dev, sizeof(*cbb), GFP_KERNEL); 1040 if (!cbb) 1041 return -ENOMEM; 1042 1043 INIT_LIST_HEAD(&cbb->base.node); 1044 cbb->base.ops = &tegra234_cbb_ops; 1045 cbb->base.dev = &pdev->dev; 1046 cbb->fabric = fabric; 1047 1048 cbb->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &cbb->res); 1049 if (IS_ERR(cbb->regs)) 1050 return PTR_ERR(cbb->regs); 1051 1052 err = tegra_cbb_get_irq(pdev, NULL, &cbb->sec_irq); 1053 if (err) 1054 return err; 1055 1056 platform_set_drvdata(pdev, cbb); 1057 1058 spin_lock_irqsave(&cbb_lock, flags); 1059 list_add(&cbb->base.node, &cbb_list); 1060 spin_unlock_irqrestore(&cbb_lock, flags); 1061 1062 /* set ERD bit to mask SError and generate interrupt to report error */ 1063 if (cbb->fabric->off_mask_erd) 1064 tegra234_cbb_mask_serror(cbb); 1065 1066 return tegra_cbb_register(&cbb->base); 1067 } 1068 1069 static int tegra234_cbb_remove(struct platform_device *pdev) 1070 { 1071 return 0; 1072 } 1073 1074 static int __maybe_unused tegra234_cbb_resume_noirq(struct device *dev) 1075 { 1076 struct tegra234_cbb *cbb = dev_get_drvdata(dev); 1077 1078 tegra234_cbb_error_enable(&cbb->base); 1079 1080 dev_dbg(dev, "%s resumed\n", cbb->fabric->name); 1081 1082 return 0; 1083 } 1084 1085 static const struct dev_pm_ops tegra234_cbb_pm = { 1086 SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, tegra234_cbb_resume_noirq) 1087 }; 1088 1089 static struct platform_driver tegra234_cbb_driver = { 1090 .probe = tegra234_cbb_probe, 1091 .remove = tegra234_cbb_remove, 1092 .driver = { 1093 .name = "tegra234-cbb", 1094 .of_match_table = tegra234_cbb_dt_ids, 1095 .acpi_match_table = tegra241_cbb_acpi_ids, 1096 .pm = &tegra234_cbb_pm, 1097 }, 1098 }; 1099 1100 static int __init tegra234_cbb_init(void) 1101 { 1102 return platform_driver_register(&tegra234_cbb_driver); 1103 } 1104 pure_initcall(tegra234_cbb_init); 1105 1106 static void __exit tegra234_cbb_exit(void) 1107 { 1108 platform_driver_unregister(&tegra234_cbb_driver); 1109 } 1110 module_exit(tegra234_cbb_exit); 1111 1112 MODULE_DESCRIPTION("Control Backbone 2.0 error handling driver for Tegra234"); 1113 MODULE_LICENSE("GPL"); 1114