1*29962197SMikko Perttunen // SPDX-License-Identifier: GPL-2.0-only
2*29962197SMikko Perttunen /*
3*29962197SMikko Perttunen * Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
4*29962197SMikko Perttunen */
5*29962197SMikko Perttunen
6*29962197SMikko Perttunen #include <linux/arm-smccc.h>
7*29962197SMikko Perttunen #include <linux/kernel.h>
8*29962197SMikko Perttunen #include <linux/of.h>
9*29962197SMikko Perttunen #include <linux/panic_notifier.h>
10*29962197SMikko Perttunen
11*29962197SMikko Perttunen #define SMC_SIP_INVOKE_MCE 0xc2ffff00
12*29962197SMikko Perttunen #define MCE_SMC_READ_MCA 12
13*29962197SMikko Perttunen
14*29962197SMikko Perttunen #define MCA_ARI_CMD_RD_SERR 1
15*29962197SMikko Perttunen
16*29962197SMikko Perttunen #define MCA_ARI_RW_SUBIDX_STAT 1
17*29962197SMikko Perttunen #define SERR_STATUS_VAL BIT_ULL(63)
18*29962197SMikko Perttunen
19*29962197SMikko Perttunen #define MCA_ARI_RW_SUBIDX_ADDR 2
20*29962197SMikko Perttunen #define MCA_ARI_RW_SUBIDX_MSC1 3
21*29962197SMikko Perttunen #define MCA_ARI_RW_SUBIDX_MSC2 4
22*29962197SMikko Perttunen
23*29962197SMikko Perttunen static const char * const bank_names[] = {
24*29962197SMikko Perttunen "SYS:DPMU", "ROC:IOB", "ROC:MCB", "ROC:CCE", "ROC:CQX", "ROC:CTU",
25*29962197SMikko Perttunen };
26*29962197SMikko Perttunen
read_uncore_mca(u8 cmd,u8 idx,u8 subidx,u8 inst,u64 * data)27*29962197SMikko Perttunen static void read_uncore_mca(u8 cmd, u8 idx, u8 subidx, u8 inst, u64 *data)
28*29962197SMikko Perttunen {
29*29962197SMikko Perttunen struct arm_smccc_res res;
30*29962197SMikko Perttunen
31*29962197SMikko Perttunen arm_smccc_smc(SMC_SIP_INVOKE_MCE | MCE_SMC_READ_MCA,
32*29962197SMikko Perttunen ((u64)inst << 24) | ((u64)idx << 16) |
33*29962197SMikko Perttunen ((u64)subidx << 8) | ((u64)cmd << 0),
34*29962197SMikko Perttunen 0, 0, 0, 0, 0, 0, &res);
35*29962197SMikko Perttunen
36*29962197SMikko Perttunen *data = res.a2;
37*29962197SMikko Perttunen }
38*29962197SMikko Perttunen
tegra186_ari_panic_handler(struct notifier_block * nb,unsigned long code,void * unused)39*29962197SMikko Perttunen static int tegra186_ari_panic_handler(struct notifier_block *nb,
40*29962197SMikko Perttunen unsigned long code, void *unused)
41*29962197SMikko Perttunen {
42*29962197SMikko Perttunen u64 status;
43*29962197SMikko Perttunen int i;
44*29962197SMikko Perttunen
45*29962197SMikko Perttunen for (i = 0; i < ARRAY_SIZE(bank_names); i++) {
46*29962197SMikko Perttunen read_uncore_mca(MCA_ARI_CMD_RD_SERR, i, MCA_ARI_RW_SUBIDX_STAT,
47*29962197SMikko Perttunen 0, &status);
48*29962197SMikko Perttunen
49*29962197SMikko Perttunen if (status & SERR_STATUS_VAL) {
50*29962197SMikko Perttunen u64 addr, misc1, misc2;
51*29962197SMikko Perttunen
52*29962197SMikko Perttunen read_uncore_mca(MCA_ARI_CMD_RD_SERR, i,
53*29962197SMikko Perttunen MCA_ARI_RW_SUBIDX_ADDR, 0, &addr);
54*29962197SMikko Perttunen read_uncore_mca(MCA_ARI_CMD_RD_SERR, i,
55*29962197SMikko Perttunen MCA_ARI_RW_SUBIDX_MSC1, 0, &misc1);
56*29962197SMikko Perttunen read_uncore_mca(MCA_ARI_CMD_RD_SERR, i,
57*29962197SMikko Perttunen MCA_ARI_RW_SUBIDX_MSC2, 0, &misc2);
58*29962197SMikko Perttunen
59*29962197SMikko Perttunen pr_crit("Machine Check Error in %s\n"
60*29962197SMikko Perttunen " status=0x%llx addr=0x%llx\n"
61*29962197SMikko Perttunen " msc1=0x%llx msc2=0x%llx\n",
62*29962197SMikko Perttunen bank_names[i], status, addr, misc1, misc2);
63*29962197SMikko Perttunen }
64*29962197SMikko Perttunen }
65*29962197SMikko Perttunen
66*29962197SMikko Perttunen return NOTIFY_DONE;
67*29962197SMikko Perttunen }
68*29962197SMikko Perttunen
69*29962197SMikko Perttunen static struct notifier_block tegra186_ari_panic_nb = {
70*29962197SMikko Perttunen .notifier_call = tegra186_ari_panic_handler,
71*29962197SMikko Perttunen };
72*29962197SMikko Perttunen
tegra186_ari_init(void)73*29962197SMikko Perttunen static int __init tegra186_ari_init(void)
74*29962197SMikko Perttunen {
75*29962197SMikko Perttunen if (of_machine_is_compatible("nvidia,tegra186"))
76*29962197SMikko Perttunen atomic_notifier_chain_register(&panic_notifier_list, &tegra186_ari_panic_nb);
77*29962197SMikko Perttunen
78*29962197SMikko Perttunen return 0;
79*29962197SMikko Perttunen }
80*29962197SMikko Perttunen early_initcall(tegra186_ari_init);
81