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