1*4a4a4e9eSQuan Nguyen // SPDX-License-Identifier: GPL-2.0-only 2*4a4a4e9eSQuan Nguyen /* 3*4a4a4e9eSQuan Nguyen * Ampere Computing SoC's SMpro Error Monitoring Driver 4*4a4a4e9eSQuan Nguyen * 5*4a4a4e9eSQuan Nguyen * Copyright (c) 2022, Ampere Computing LLC 6*4a4a4e9eSQuan Nguyen * 7*4a4a4e9eSQuan Nguyen */ 8*4a4a4e9eSQuan Nguyen 9*4a4a4e9eSQuan Nguyen #include <linux/i2c.h> 10*4a4a4e9eSQuan Nguyen #include <linux/mod_devicetable.h> 11*4a4a4e9eSQuan Nguyen #include <linux/module.h> 12*4a4a4e9eSQuan Nguyen #include <linux/platform_device.h> 13*4a4a4e9eSQuan Nguyen #include <linux/regmap.h> 14*4a4a4e9eSQuan Nguyen 15*4a4a4e9eSQuan Nguyen /* GPI RAS Error Registers */ 16*4a4a4e9eSQuan Nguyen #define GPI_RAS_ERR 0x7E 17*4a4a4e9eSQuan Nguyen 18*4a4a4e9eSQuan Nguyen /* Core and L2C Error Registers */ 19*4a4a4e9eSQuan Nguyen #define CORE_CE_ERR_CNT 0x80 20*4a4a4e9eSQuan Nguyen #define CORE_CE_ERR_LEN 0x81 21*4a4a4e9eSQuan Nguyen #define CORE_CE_ERR_DATA 0x82 22*4a4a4e9eSQuan Nguyen #define CORE_UE_ERR_CNT 0x83 23*4a4a4e9eSQuan Nguyen #define CORE_UE_ERR_LEN 0x84 24*4a4a4e9eSQuan Nguyen #define CORE_UE_ERR_DATA 0x85 25*4a4a4e9eSQuan Nguyen 26*4a4a4e9eSQuan Nguyen /* Memory Error Registers */ 27*4a4a4e9eSQuan Nguyen #define MEM_CE_ERR_CNT 0x90 28*4a4a4e9eSQuan Nguyen #define MEM_CE_ERR_LEN 0x91 29*4a4a4e9eSQuan Nguyen #define MEM_CE_ERR_DATA 0x92 30*4a4a4e9eSQuan Nguyen #define MEM_UE_ERR_CNT 0x93 31*4a4a4e9eSQuan Nguyen #define MEM_UE_ERR_LEN 0x94 32*4a4a4e9eSQuan Nguyen #define MEM_UE_ERR_DATA 0x95 33*4a4a4e9eSQuan Nguyen 34*4a4a4e9eSQuan Nguyen /* RAS Error/Warning Registers */ 35*4a4a4e9eSQuan Nguyen #define ERR_SMPRO_TYPE 0xA0 36*4a4a4e9eSQuan Nguyen #define ERR_PMPRO_TYPE 0xA1 37*4a4a4e9eSQuan Nguyen #define ERR_SMPRO_INFO_LO 0xA2 38*4a4a4e9eSQuan Nguyen #define ERR_SMPRO_INFO_HI 0xA3 39*4a4a4e9eSQuan Nguyen #define ERR_SMPRO_DATA_LO 0xA4 40*4a4a4e9eSQuan Nguyen #define ERR_SMPRO_DATA_HI 0xA5 41*4a4a4e9eSQuan Nguyen #define WARN_SMPRO_INFO_LO 0xAA 42*4a4a4e9eSQuan Nguyen #define WARN_SMPRO_INFO_HI 0xAB 43*4a4a4e9eSQuan Nguyen #define ERR_PMPRO_INFO_LO 0xA6 44*4a4a4e9eSQuan Nguyen #define ERR_PMPRO_INFO_HI 0xA7 45*4a4a4e9eSQuan Nguyen #define ERR_PMPRO_DATA_LO 0xA8 46*4a4a4e9eSQuan Nguyen #define ERR_PMPRO_DATA_HI 0xA9 47*4a4a4e9eSQuan Nguyen #define WARN_PMPRO_INFO_LO 0xAC 48*4a4a4e9eSQuan Nguyen #define WARN_PMPRO_INFO_HI 0xAD 49*4a4a4e9eSQuan Nguyen 50*4a4a4e9eSQuan Nguyen /* PCIE Error Registers */ 51*4a4a4e9eSQuan Nguyen #define PCIE_CE_ERR_CNT 0xC0 52*4a4a4e9eSQuan Nguyen #define PCIE_CE_ERR_LEN 0xC1 53*4a4a4e9eSQuan Nguyen #define PCIE_CE_ERR_DATA 0xC2 54*4a4a4e9eSQuan Nguyen #define PCIE_UE_ERR_CNT 0xC3 55*4a4a4e9eSQuan Nguyen #define PCIE_UE_ERR_LEN 0xC4 56*4a4a4e9eSQuan Nguyen #define PCIE_UE_ERR_DATA 0xC5 57*4a4a4e9eSQuan Nguyen 58*4a4a4e9eSQuan Nguyen /* Other Error Registers */ 59*4a4a4e9eSQuan Nguyen #define OTHER_CE_ERR_CNT 0xD0 60*4a4a4e9eSQuan Nguyen #define OTHER_CE_ERR_LEN 0xD1 61*4a4a4e9eSQuan Nguyen #define OTHER_CE_ERR_DATA 0xD2 62*4a4a4e9eSQuan Nguyen #define OTHER_UE_ERR_CNT 0xD8 63*4a4a4e9eSQuan Nguyen #define OTHER_UE_ERR_LEN 0xD9 64*4a4a4e9eSQuan Nguyen #define OTHER_UE_ERR_DATA 0xDA 65*4a4a4e9eSQuan Nguyen 66*4a4a4e9eSQuan Nguyen /* Event Data Registers */ 67*4a4a4e9eSQuan Nguyen #define VRD_WARN_FAULT_EVENT_DATA 0x78 68*4a4a4e9eSQuan Nguyen #define VRD_HOT_EVENT_DATA 0x79 69*4a4a4e9eSQuan Nguyen #define DIMM_HOT_EVENT_DATA 0x7A 70*4a4a4e9eSQuan Nguyen 71*4a4a4e9eSQuan Nguyen #define MAX_READ_BLOCK_LENGTH 48 72*4a4a4e9eSQuan Nguyen 73*4a4a4e9eSQuan Nguyen #define RAS_SMPRO_ERR 0 74*4a4a4e9eSQuan Nguyen #define RAS_PMPRO_ERR 1 75*4a4a4e9eSQuan Nguyen 76*4a4a4e9eSQuan Nguyen enum RAS_48BYTES_ERR_TYPES { 77*4a4a4e9eSQuan Nguyen CORE_CE_ERR, 78*4a4a4e9eSQuan Nguyen CORE_UE_ERR, 79*4a4a4e9eSQuan Nguyen MEM_CE_ERR, 80*4a4a4e9eSQuan Nguyen MEM_UE_ERR, 81*4a4a4e9eSQuan Nguyen PCIE_CE_ERR, 82*4a4a4e9eSQuan Nguyen PCIE_UE_ERR, 83*4a4a4e9eSQuan Nguyen OTHER_CE_ERR, 84*4a4a4e9eSQuan Nguyen OTHER_UE_ERR, 85*4a4a4e9eSQuan Nguyen NUM_48BYTES_ERR_TYPE, 86*4a4a4e9eSQuan Nguyen }; 87*4a4a4e9eSQuan Nguyen 88*4a4a4e9eSQuan Nguyen struct smpro_error_hdr { 89*4a4a4e9eSQuan Nguyen u8 count; /* Number of the RAS errors */ 90*4a4a4e9eSQuan Nguyen u8 len; /* Number of data bytes */ 91*4a4a4e9eSQuan Nguyen u8 data; /* Start of 48-byte data */ 92*4a4a4e9eSQuan Nguyen u8 max_cnt; /* Max num of errors */ 93*4a4a4e9eSQuan Nguyen }; 94*4a4a4e9eSQuan Nguyen 95*4a4a4e9eSQuan Nguyen /* 96*4a4a4e9eSQuan Nguyen * Included Address of registers to get Count, Length of data and Data 97*4a4a4e9eSQuan Nguyen * of the 48 bytes error data 98*4a4a4e9eSQuan Nguyen */ 99*4a4a4e9eSQuan Nguyen static struct smpro_error_hdr smpro_error_table[] = { 100*4a4a4e9eSQuan Nguyen [CORE_CE_ERR] = { 101*4a4a4e9eSQuan Nguyen .count = CORE_CE_ERR_CNT, 102*4a4a4e9eSQuan Nguyen .len = CORE_CE_ERR_LEN, 103*4a4a4e9eSQuan Nguyen .data = CORE_CE_ERR_DATA, 104*4a4a4e9eSQuan Nguyen .max_cnt = 32 105*4a4a4e9eSQuan Nguyen }, 106*4a4a4e9eSQuan Nguyen [CORE_UE_ERR] = { 107*4a4a4e9eSQuan Nguyen .count = CORE_UE_ERR_CNT, 108*4a4a4e9eSQuan Nguyen .len = CORE_UE_ERR_LEN, 109*4a4a4e9eSQuan Nguyen .data = CORE_UE_ERR_DATA, 110*4a4a4e9eSQuan Nguyen .max_cnt = 32 111*4a4a4e9eSQuan Nguyen }, 112*4a4a4e9eSQuan Nguyen [MEM_CE_ERR] = { 113*4a4a4e9eSQuan Nguyen .count = MEM_CE_ERR_CNT, 114*4a4a4e9eSQuan Nguyen .len = MEM_CE_ERR_LEN, 115*4a4a4e9eSQuan Nguyen .data = MEM_CE_ERR_DATA, 116*4a4a4e9eSQuan Nguyen .max_cnt = 16 117*4a4a4e9eSQuan Nguyen }, 118*4a4a4e9eSQuan Nguyen [MEM_UE_ERR] = { 119*4a4a4e9eSQuan Nguyen .count = MEM_UE_ERR_CNT, 120*4a4a4e9eSQuan Nguyen .len = MEM_UE_ERR_LEN, 121*4a4a4e9eSQuan Nguyen .data = MEM_UE_ERR_DATA, 122*4a4a4e9eSQuan Nguyen .max_cnt = 16 123*4a4a4e9eSQuan Nguyen }, 124*4a4a4e9eSQuan Nguyen [PCIE_CE_ERR] = { 125*4a4a4e9eSQuan Nguyen .count = PCIE_CE_ERR_CNT, 126*4a4a4e9eSQuan Nguyen .len = PCIE_CE_ERR_LEN, 127*4a4a4e9eSQuan Nguyen .data = PCIE_CE_ERR_DATA, 128*4a4a4e9eSQuan Nguyen .max_cnt = 96 129*4a4a4e9eSQuan Nguyen }, 130*4a4a4e9eSQuan Nguyen [PCIE_UE_ERR] = { 131*4a4a4e9eSQuan Nguyen .count = PCIE_UE_ERR_CNT, 132*4a4a4e9eSQuan Nguyen .len = PCIE_UE_ERR_LEN, 133*4a4a4e9eSQuan Nguyen .data = PCIE_UE_ERR_DATA, 134*4a4a4e9eSQuan Nguyen .max_cnt = 96 135*4a4a4e9eSQuan Nguyen }, 136*4a4a4e9eSQuan Nguyen [OTHER_CE_ERR] = { 137*4a4a4e9eSQuan Nguyen .count = OTHER_CE_ERR_CNT, 138*4a4a4e9eSQuan Nguyen .len = OTHER_CE_ERR_LEN, 139*4a4a4e9eSQuan Nguyen .data = OTHER_CE_ERR_DATA, 140*4a4a4e9eSQuan Nguyen .max_cnt = 8 141*4a4a4e9eSQuan Nguyen }, 142*4a4a4e9eSQuan Nguyen [OTHER_UE_ERR] = { 143*4a4a4e9eSQuan Nguyen .count = OTHER_UE_ERR_CNT, 144*4a4a4e9eSQuan Nguyen .len = OTHER_UE_ERR_LEN, 145*4a4a4e9eSQuan Nguyen .data = OTHER_UE_ERR_DATA, 146*4a4a4e9eSQuan Nguyen .max_cnt = 8 147*4a4a4e9eSQuan Nguyen }, 148*4a4a4e9eSQuan Nguyen }; 149*4a4a4e9eSQuan Nguyen 150*4a4a4e9eSQuan Nguyen /* 151*4a4a4e9eSQuan Nguyen * List of SCP registers which are used to get 152*4a4a4e9eSQuan Nguyen * one type of RAS Internal errors. 153*4a4a4e9eSQuan Nguyen */ 154*4a4a4e9eSQuan Nguyen struct smpro_int_error_hdr { 155*4a4a4e9eSQuan Nguyen u8 type; 156*4a4a4e9eSQuan Nguyen u8 info_l; 157*4a4a4e9eSQuan Nguyen u8 info_h; 158*4a4a4e9eSQuan Nguyen u8 data_l; 159*4a4a4e9eSQuan Nguyen u8 data_h; 160*4a4a4e9eSQuan Nguyen u8 warn_l; 161*4a4a4e9eSQuan Nguyen u8 warn_h; 162*4a4a4e9eSQuan Nguyen }; 163*4a4a4e9eSQuan Nguyen 164*4a4a4e9eSQuan Nguyen static struct smpro_int_error_hdr list_smpro_int_error_hdr[] = { 165*4a4a4e9eSQuan Nguyen [RAS_SMPRO_ERR] = { 166*4a4a4e9eSQuan Nguyen .type = ERR_SMPRO_TYPE, 167*4a4a4e9eSQuan Nguyen .info_l = ERR_SMPRO_INFO_LO, 168*4a4a4e9eSQuan Nguyen .info_h = ERR_SMPRO_INFO_HI, 169*4a4a4e9eSQuan Nguyen .data_l = ERR_SMPRO_DATA_LO, 170*4a4a4e9eSQuan Nguyen .data_h = ERR_SMPRO_DATA_HI, 171*4a4a4e9eSQuan Nguyen .warn_l = WARN_SMPRO_INFO_LO, 172*4a4a4e9eSQuan Nguyen .warn_h = WARN_SMPRO_INFO_HI, 173*4a4a4e9eSQuan Nguyen }, 174*4a4a4e9eSQuan Nguyen [RAS_PMPRO_ERR] = { 175*4a4a4e9eSQuan Nguyen .type = ERR_PMPRO_TYPE, 176*4a4a4e9eSQuan Nguyen .info_l = ERR_PMPRO_INFO_LO, 177*4a4a4e9eSQuan Nguyen .info_h = ERR_PMPRO_INFO_HI, 178*4a4a4e9eSQuan Nguyen .data_l = ERR_PMPRO_DATA_LO, 179*4a4a4e9eSQuan Nguyen .data_h = ERR_PMPRO_DATA_HI, 180*4a4a4e9eSQuan Nguyen .warn_l = WARN_PMPRO_INFO_LO, 181*4a4a4e9eSQuan Nguyen .warn_h = WARN_PMPRO_INFO_HI, 182*4a4a4e9eSQuan Nguyen }, 183*4a4a4e9eSQuan Nguyen }; 184*4a4a4e9eSQuan Nguyen 185*4a4a4e9eSQuan Nguyen struct smpro_errmon { 186*4a4a4e9eSQuan Nguyen struct regmap *regmap; 187*4a4a4e9eSQuan Nguyen }; 188*4a4a4e9eSQuan Nguyen 189*4a4a4e9eSQuan Nguyen enum EVENT_TYPES { 190*4a4a4e9eSQuan Nguyen VRD_WARN_FAULT_EVENT, 191*4a4a4e9eSQuan Nguyen VRD_HOT_EVENT, 192*4a4a4e9eSQuan Nguyen DIMM_HOT_EVENT, 193*4a4a4e9eSQuan Nguyen NUM_EVENTS_TYPE, 194*4a4a4e9eSQuan Nguyen }; 195*4a4a4e9eSQuan Nguyen 196*4a4a4e9eSQuan Nguyen /* Included Address of event source and data registers */ 197*4a4a4e9eSQuan Nguyen static u8 smpro_event_table[NUM_EVENTS_TYPE] = { 198*4a4a4e9eSQuan Nguyen VRD_WARN_FAULT_EVENT_DATA, 199*4a4a4e9eSQuan Nguyen VRD_HOT_EVENT_DATA, 200*4a4a4e9eSQuan Nguyen DIMM_HOT_EVENT_DATA, 201*4a4a4e9eSQuan Nguyen }; 202*4a4a4e9eSQuan Nguyen 203*4a4a4e9eSQuan Nguyen static ssize_t smpro_event_data_read(struct device *dev, 204*4a4a4e9eSQuan Nguyen struct device_attribute *da, char *buf, 205*4a4a4e9eSQuan Nguyen int channel) 206*4a4a4e9eSQuan Nguyen { 207*4a4a4e9eSQuan Nguyen struct smpro_errmon *errmon = dev_get_drvdata(dev); 208*4a4a4e9eSQuan Nguyen s32 event_data; 209*4a4a4e9eSQuan Nguyen int ret; 210*4a4a4e9eSQuan Nguyen 211*4a4a4e9eSQuan Nguyen ret = regmap_read(errmon->regmap, smpro_event_table[channel], &event_data); 212*4a4a4e9eSQuan Nguyen if (ret) 213*4a4a4e9eSQuan Nguyen return ret; 214*4a4a4e9eSQuan Nguyen /* Clear event after read */ 215*4a4a4e9eSQuan Nguyen if (event_data != 0) 216*4a4a4e9eSQuan Nguyen regmap_write(errmon->regmap, smpro_event_table[channel], event_data); 217*4a4a4e9eSQuan Nguyen 218*4a4a4e9eSQuan Nguyen return sysfs_emit(buf, "%04x\n", event_data); 219*4a4a4e9eSQuan Nguyen } 220*4a4a4e9eSQuan Nguyen 221*4a4a4e9eSQuan Nguyen static ssize_t smpro_overflow_data_read(struct device *dev, struct device_attribute *da, 222*4a4a4e9eSQuan Nguyen char *buf, int channel) 223*4a4a4e9eSQuan Nguyen { 224*4a4a4e9eSQuan Nguyen struct smpro_errmon *errmon = dev_get_drvdata(dev); 225*4a4a4e9eSQuan Nguyen struct smpro_error_hdr *err_info; 226*4a4a4e9eSQuan Nguyen s32 err_count; 227*4a4a4e9eSQuan Nguyen int ret; 228*4a4a4e9eSQuan Nguyen 229*4a4a4e9eSQuan Nguyen err_info = &smpro_error_table[channel]; 230*4a4a4e9eSQuan Nguyen 231*4a4a4e9eSQuan Nguyen ret = regmap_read(errmon->regmap, err_info->count, &err_count); 232*4a4a4e9eSQuan Nguyen if (ret) 233*4a4a4e9eSQuan Nguyen return ret; 234*4a4a4e9eSQuan Nguyen 235*4a4a4e9eSQuan Nguyen /* Bit 8 indicates the overflow status */ 236*4a4a4e9eSQuan Nguyen return sysfs_emit(buf, "%d\n", (err_count & BIT(8)) ? 1 : 0); 237*4a4a4e9eSQuan Nguyen } 238*4a4a4e9eSQuan Nguyen 239*4a4a4e9eSQuan Nguyen static ssize_t smpro_error_data_read(struct device *dev, struct device_attribute *da, 240*4a4a4e9eSQuan Nguyen char *buf, int channel) 241*4a4a4e9eSQuan Nguyen { 242*4a4a4e9eSQuan Nguyen struct smpro_errmon *errmon = dev_get_drvdata(dev); 243*4a4a4e9eSQuan Nguyen unsigned char err_data[MAX_READ_BLOCK_LENGTH]; 244*4a4a4e9eSQuan Nguyen struct smpro_error_hdr *err_info; 245*4a4a4e9eSQuan Nguyen s32 err_count, err_length; 246*4a4a4e9eSQuan Nguyen int ret; 247*4a4a4e9eSQuan Nguyen 248*4a4a4e9eSQuan Nguyen err_info = &smpro_error_table[channel]; 249*4a4a4e9eSQuan Nguyen 250*4a4a4e9eSQuan Nguyen ret = regmap_read(errmon->regmap, err_info->count, &err_count); 251*4a4a4e9eSQuan Nguyen /* Error count is the low byte */ 252*4a4a4e9eSQuan Nguyen err_count &= 0xff; 253*4a4a4e9eSQuan Nguyen if (ret || !err_count || err_count > err_info->max_cnt) 254*4a4a4e9eSQuan Nguyen return ret; 255*4a4a4e9eSQuan Nguyen 256*4a4a4e9eSQuan Nguyen ret = regmap_read(errmon->regmap, err_info->len, &err_length); 257*4a4a4e9eSQuan Nguyen if (ret || err_length <= 0) 258*4a4a4e9eSQuan Nguyen return ret; 259*4a4a4e9eSQuan Nguyen 260*4a4a4e9eSQuan Nguyen if (err_length > MAX_READ_BLOCK_LENGTH) 261*4a4a4e9eSQuan Nguyen err_length = MAX_READ_BLOCK_LENGTH; 262*4a4a4e9eSQuan Nguyen 263*4a4a4e9eSQuan Nguyen memset(err_data, 0x00, MAX_READ_BLOCK_LENGTH); 264*4a4a4e9eSQuan Nguyen ret = regmap_noinc_read(errmon->regmap, err_info->data, err_data, err_length); 265*4a4a4e9eSQuan Nguyen if (ret < 0) 266*4a4a4e9eSQuan Nguyen return ret; 267*4a4a4e9eSQuan Nguyen 268*4a4a4e9eSQuan Nguyen /* clear the error */ 269*4a4a4e9eSQuan Nguyen ret = regmap_write(errmon->regmap, err_info->count, 0x100); 270*4a4a4e9eSQuan Nguyen if (ret) 271*4a4a4e9eSQuan Nguyen return ret; 272*4a4a4e9eSQuan Nguyen /* 273*4a4a4e9eSQuan Nguyen * The output of Core/Memory/PCIe/Others UE/CE errors follows the format 274*4a4a4e9eSQuan Nguyen * specified in section 5.8.1 CE/UE Error Data record in 275*4a4a4e9eSQuan Nguyen * Altra SOC BMC Interface specification. 276*4a4a4e9eSQuan Nguyen */ 277*4a4a4e9eSQuan Nguyen return sysfs_emit(buf, "%*phN\n", MAX_READ_BLOCK_LENGTH, err_data); 278*4a4a4e9eSQuan Nguyen } 279*4a4a4e9eSQuan Nguyen 280*4a4a4e9eSQuan Nguyen /* 281*4a4a4e9eSQuan Nguyen * Output format: 282*4a4a4e9eSQuan Nguyen * <4-byte hex value of error info><4-byte hex value of error extensive data> 283*4a4a4e9eSQuan Nguyen * Where: 284*4a4a4e9eSQuan Nguyen * + error info : The error information 285*4a4a4e9eSQuan Nguyen * + error data : Extensive data (32 bits) 286*4a4a4e9eSQuan Nguyen * Reference to section 5.10 RAS Internal Error Register Definition in 287*4a4a4e9eSQuan Nguyen * Altra SOC BMC Interface specification 288*4a4a4e9eSQuan Nguyen */ 289*4a4a4e9eSQuan Nguyen static ssize_t smpro_internal_err_read(struct device *dev, struct device_attribute *da, 290*4a4a4e9eSQuan Nguyen char *buf, int channel) 291*4a4a4e9eSQuan Nguyen { 292*4a4a4e9eSQuan Nguyen struct smpro_errmon *errmon = dev_get_drvdata(dev); 293*4a4a4e9eSQuan Nguyen struct smpro_int_error_hdr *err_info; 294*4a4a4e9eSQuan Nguyen unsigned int err[4] = { 0 }; 295*4a4a4e9eSQuan Nguyen unsigned int err_type; 296*4a4a4e9eSQuan Nguyen unsigned int val; 297*4a4a4e9eSQuan Nguyen int ret; 298*4a4a4e9eSQuan Nguyen 299*4a4a4e9eSQuan Nguyen /* read error status */ 300*4a4a4e9eSQuan Nguyen ret = regmap_read(errmon->regmap, GPI_RAS_ERR, &val); 301*4a4a4e9eSQuan Nguyen if (ret) 302*4a4a4e9eSQuan Nguyen return ret; 303*4a4a4e9eSQuan Nguyen 304*4a4a4e9eSQuan Nguyen if ((channel == RAS_SMPRO_ERR && !(val & BIT(0))) || 305*4a4a4e9eSQuan Nguyen (channel == RAS_PMPRO_ERR && !(val & BIT(1)))) 306*4a4a4e9eSQuan Nguyen return 0; 307*4a4a4e9eSQuan Nguyen 308*4a4a4e9eSQuan Nguyen err_info = &list_smpro_int_error_hdr[channel]; 309*4a4a4e9eSQuan Nguyen ret = regmap_read(errmon->regmap, err_info->type, &val); 310*4a4a4e9eSQuan Nguyen if (ret) 311*4a4a4e9eSQuan Nguyen return ret; 312*4a4a4e9eSQuan Nguyen 313*4a4a4e9eSQuan Nguyen err_type = (val & BIT(1)) ? BIT(1) : 314*4a4a4e9eSQuan Nguyen (val & BIT(2)) ? BIT(2) : 0; 315*4a4a4e9eSQuan Nguyen 316*4a4a4e9eSQuan Nguyen if (!err_type) 317*4a4a4e9eSQuan Nguyen return 0; 318*4a4a4e9eSQuan Nguyen 319*4a4a4e9eSQuan Nguyen ret = regmap_read(errmon->regmap, err_info->info_l, err + 1); 320*4a4a4e9eSQuan Nguyen if (ret) 321*4a4a4e9eSQuan Nguyen return ret; 322*4a4a4e9eSQuan Nguyen 323*4a4a4e9eSQuan Nguyen ret = regmap_read(errmon->regmap, err_info->info_h, err); 324*4a4a4e9eSQuan Nguyen if (ret) 325*4a4a4e9eSQuan Nguyen return ret; 326*4a4a4e9eSQuan Nguyen 327*4a4a4e9eSQuan Nguyen if (err_type & BIT(2)) { 328*4a4a4e9eSQuan Nguyen /* Error with data type */ 329*4a4a4e9eSQuan Nguyen ret = regmap_read(errmon->regmap, err_info->data_l, err + 3); 330*4a4a4e9eSQuan Nguyen if (ret) 331*4a4a4e9eSQuan Nguyen return ret; 332*4a4a4e9eSQuan Nguyen 333*4a4a4e9eSQuan Nguyen ret = regmap_read(errmon->regmap, err_info->data_h, err + 2); 334*4a4a4e9eSQuan Nguyen if (ret) 335*4a4a4e9eSQuan Nguyen return ret; 336*4a4a4e9eSQuan Nguyen } 337*4a4a4e9eSQuan Nguyen 338*4a4a4e9eSQuan Nguyen /* clear the read errors */ 339*4a4a4e9eSQuan Nguyen ret = regmap_write(errmon->regmap, err_info->type, err_type); 340*4a4a4e9eSQuan Nguyen if (ret) 341*4a4a4e9eSQuan Nguyen return ret; 342*4a4a4e9eSQuan Nguyen 343*4a4a4e9eSQuan Nguyen return sysfs_emit(buf, "%*phN\n", (int)sizeof(err), err); 344*4a4a4e9eSQuan Nguyen } 345*4a4a4e9eSQuan Nguyen 346*4a4a4e9eSQuan Nguyen /* 347*4a4a4e9eSQuan Nguyen * Output format: 348*4a4a4e9eSQuan Nguyen * <4-byte hex value of warining info> 349*4a4a4e9eSQuan Nguyen * Reference to section 5.10 RAS Internal Error Register Definition in 350*4a4a4e9eSQuan Nguyen * Altra SOC BMC Interface specification 351*4a4a4e9eSQuan Nguyen */ 352*4a4a4e9eSQuan Nguyen static ssize_t smpro_internal_warn_read(struct device *dev, struct device_attribute *da, 353*4a4a4e9eSQuan Nguyen char *buf, int channel) 354*4a4a4e9eSQuan Nguyen { 355*4a4a4e9eSQuan Nguyen struct smpro_errmon *errmon = dev_get_drvdata(dev); 356*4a4a4e9eSQuan Nguyen struct smpro_int_error_hdr *err_info; 357*4a4a4e9eSQuan Nguyen unsigned int warn[2] = { 0 }; 358*4a4a4e9eSQuan Nguyen unsigned int val; 359*4a4a4e9eSQuan Nguyen int ret; 360*4a4a4e9eSQuan Nguyen 361*4a4a4e9eSQuan Nguyen /* read error status */ 362*4a4a4e9eSQuan Nguyen ret = regmap_read(errmon->regmap, GPI_RAS_ERR, &val); 363*4a4a4e9eSQuan Nguyen if (ret) 364*4a4a4e9eSQuan Nguyen return ret; 365*4a4a4e9eSQuan Nguyen 366*4a4a4e9eSQuan Nguyen if ((channel == RAS_SMPRO_ERR && !(val & BIT(0))) || 367*4a4a4e9eSQuan Nguyen (channel == RAS_PMPRO_ERR && !(val & BIT(1)))) 368*4a4a4e9eSQuan Nguyen return 0; 369*4a4a4e9eSQuan Nguyen 370*4a4a4e9eSQuan Nguyen err_info = &list_smpro_int_error_hdr[channel]; 371*4a4a4e9eSQuan Nguyen ret = regmap_read(errmon->regmap, err_info->type, &val); 372*4a4a4e9eSQuan Nguyen if (ret) 373*4a4a4e9eSQuan Nguyen return ret; 374*4a4a4e9eSQuan Nguyen 375*4a4a4e9eSQuan Nguyen if (!(val & BIT(0))) 376*4a4a4e9eSQuan Nguyen return 0; 377*4a4a4e9eSQuan Nguyen 378*4a4a4e9eSQuan Nguyen ret = regmap_read(errmon->regmap, err_info->warn_l, warn + 1); 379*4a4a4e9eSQuan Nguyen if (ret) 380*4a4a4e9eSQuan Nguyen return ret; 381*4a4a4e9eSQuan Nguyen 382*4a4a4e9eSQuan Nguyen ret = regmap_read(errmon->regmap, err_info->warn_h, warn); 383*4a4a4e9eSQuan Nguyen if (ret) 384*4a4a4e9eSQuan Nguyen return ret; 385*4a4a4e9eSQuan Nguyen 386*4a4a4e9eSQuan Nguyen /* clear the warning */ 387*4a4a4e9eSQuan Nguyen ret = regmap_write(errmon->regmap, err_info->type, BIT(0)); 388*4a4a4e9eSQuan Nguyen if (ret) 389*4a4a4e9eSQuan Nguyen return ret; 390*4a4a4e9eSQuan Nguyen 391*4a4a4e9eSQuan Nguyen return sysfs_emit(buf, "%*phN\n", (int)sizeof(warn), warn); 392*4a4a4e9eSQuan Nguyen } 393*4a4a4e9eSQuan Nguyen 394*4a4a4e9eSQuan Nguyen #define ERROR_OVERFLOW_RO(_error, _index) \ 395*4a4a4e9eSQuan Nguyen static ssize_t overflow_##_error##_show(struct device *dev, \ 396*4a4a4e9eSQuan Nguyen struct device_attribute *da, \ 397*4a4a4e9eSQuan Nguyen char *buf) \ 398*4a4a4e9eSQuan Nguyen { \ 399*4a4a4e9eSQuan Nguyen return smpro_overflow_data_read(dev, da, buf, _index); \ 400*4a4a4e9eSQuan Nguyen } \ 401*4a4a4e9eSQuan Nguyen static DEVICE_ATTR_RO(overflow_##_error) 402*4a4a4e9eSQuan Nguyen 403*4a4a4e9eSQuan Nguyen ERROR_OVERFLOW_RO(core_ce, CORE_CE_ERR); 404*4a4a4e9eSQuan Nguyen ERROR_OVERFLOW_RO(core_ue, CORE_UE_ERR); 405*4a4a4e9eSQuan Nguyen ERROR_OVERFLOW_RO(mem_ce, MEM_CE_ERR); 406*4a4a4e9eSQuan Nguyen ERROR_OVERFLOW_RO(mem_ue, MEM_UE_ERR); 407*4a4a4e9eSQuan Nguyen ERROR_OVERFLOW_RO(pcie_ce, PCIE_CE_ERR); 408*4a4a4e9eSQuan Nguyen ERROR_OVERFLOW_RO(pcie_ue, PCIE_UE_ERR); 409*4a4a4e9eSQuan Nguyen ERROR_OVERFLOW_RO(other_ce, OTHER_CE_ERR); 410*4a4a4e9eSQuan Nguyen ERROR_OVERFLOW_RO(other_ue, OTHER_UE_ERR); 411*4a4a4e9eSQuan Nguyen 412*4a4a4e9eSQuan Nguyen #define ERROR_RO(_error, _index) \ 413*4a4a4e9eSQuan Nguyen static ssize_t error_##_error##_show(struct device *dev, \ 414*4a4a4e9eSQuan Nguyen struct device_attribute *da, \ 415*4a4a4e9eSQuan Nguyen char *buf) \ 416*4a4a4e9eSQuan Nguyen { \ 417*4a4a4e9eSQuan Nguyen return smpro_error_data_read(dev, da, buf, _index); \ 418*4a4a4e9eSQuan Nguyen } \ 419*4a4a4e9eSQuan Nguyen static DEVICE_ATTR_RO(error_##_error) 420*4a4a4e9eSQuan Nguyen 421*4a4a4e9eSQuan Nguyen ERROR_RO(core_ce, CORE_CE_ERR); 422*4a4a4e9eSQuan Nguyen ERROR_RO(core_ue, CORE_UE_ERR); 423*4a4a4e9eSQuan Nguyen ERROR_RO(mem_ce, MEM_CE_ERR); 424*4a4a4e9eSQuan Nguyen ERROR_RO(mem_ue, MEM_UE_ERR); 425*4a4a4e9eSQuan Nguyen ERROR_RO(pcie_ce, PCIE_CE_ERR); 426*4a4a4e9eSQuan Nguyen ERROR_RO(pcie_ue, PCIE_UE_ERR); 427*4a4a4e9eSQuan Nguyen ERROR_RO(other_ce, OTHER_CE_ERR); 428*4a4a4e9eSQuan Nguyen ERROR_RO(other_ue, OTHER_UE_ERR); 429*4a4a4e9eSQuan Nguyen 430*4a4a4e9eSQuan Nguyen static ssize_t error_smpro_show(struct device *dev, struct device_attribute *da, char *buf) 431*4a4a4e9eSQuan Nguyen { 432*4a4a4e9eSQuan Nguyen return smpro_internal_err_read(dev, da, buf, RAS_SMPRO_ERR); 433*4a4a4e9eSQuan Nguyen } 434*4a4a4e9eSQuan Nguyen static DEVICE_ATTR_RO(error_smpro); 435*4a4a4e9eSQuan Nguyen 436*4a4a4e9eSQuan Nguyen static ssize_t error_pmpro_show(struct device *dev, struct device_attribute *da, char *buf) 437*4a4a4e9eSQuan Nguyen { 438*4a4a4e9eSQuan Nguyen return smpro_internal_err_read(dev, da, buf, RAS_PMPRO_ERR); 439*4a4a4e9eSQuan Nguyen } 440*4a4a4e9eSQuan Nguyen static DEVICE_ATTR_RO(error_pmpro); 441*4a4a4e9eSQuan Nguyen 442*4a4a4e9eSQuan Nguyen static ssize_t warn_smpro_show(struct device *dev, struct device_attribute *da, char *buf) 443*4a4a4e9eSQuan Nguyen { 444*4a4a4e9eSQuan Nguyen return smpro_internal_warn_read(dev, da, buf, RAS_SMPRO_ERR); 445*4a4a4e9eSQuan Nguyen } 446*4a4a4e9eSQuan Nguyen static DEVICE_ATTR_RO(warn_smpro); 447*4a4a4e9eSQuan Nguyen 448*4a4a4e9eSQuan Nguyen static ssize_t warn_pmpro_show(struct device *dev, struct device_attribute *da, char *buf) 449*4a4a4e9eSQuan Nguyen { 450*4a4a4e9eSQuan Nguyen return smpro_internal_warn_read(dev, da, buf, RAS_PMPRO_ERR); 451*4a4a4e9eSQuan Nguyen } 452*4a4a4e9eSQuan Nguyen static DEVICE_ATTR_RO(warn_pmpro); 453*4a4a4e9eSQuan Nguyen 454*4a4a4e9eSQuan Nguyen #define EVENT_RO(_event, _index) \ 455*4a4a4e9eSQuan Nguyen static ssize_t event_##_event##_show(struct device *dev, \ 456*4a4a4e9eSQuan Nguyen struct device_attribute *da, \ 457*4a4a4e9eSQuan Nguyen char *buf) \ 458*4a4a4e9eSQuan Nguyen { \ 459*4a4a4e9eSQuan Nguyen return smpro_event_data_read(dev, da, buf, _index); \ 460*4a4a4e9eSQuan Nguyen } \ 461*4a4a4e9eSQuan Nguyen static DEVICE_ATTR_RO(event_##_event) 462*4a4a4e9eSQuan Nguyen 463*4a4a4e9eSQuan Nguyen EVENT_RO(vrd_warn_fault, VRD_WARN_FAULT_EVENT); 464*4a4a4e9eSQuan Nguyen EVENT_RO(vrd_hot, VRD_HOT_EVENT); 465*4a4a4e9eSQuan Nguyen EVENT_RO(dimm_hot, DIMM_HOT_EVENT); 466*4a4a4e9eSQuan Nguyen 467*4a4a4e9eSQuan Nguyen static struct attribute *smpro_errmon_attrs[] = { 468*4a4a4e9eSQuan Nguyen &dev_attr_overflow_core_ce.attr, 469*4a4a4e9eSQuan Nguyen &dev_attr_overflow_core_ue.attr, 470*4a4a4e9eSQuan Nguyen &dev_attr_overflow_mem_ce.attr, 471*4a4a4e9eSQuan Nguyen &dev_attr_overflow_mem_ue.attr, 472*4a4a4e9eSQuan Nguyen &dev_attr_overflow_pcie_ce.attr, 473*4a4a4e9eSQuan Nguyen &dev_attr_overflow_pcie_ue.attr, 474*4a4a4e9eSQuan Nguyen &dev_attr_overflow_other_ce.attr, 475*4a4a4e9eSQuan Nguyen &dev_attr_overflow_other_ue.attr, 476*4a4a4e9eSQuan Nguyen &dev_attr_error_core_ce.attr, 477*4a4a4e9eSQuan Nguyen &dev_attr_error_core_ue.attr, 478*4a4a4e9eSQuan Nguyen &dev_attr_error_mem_ce.attr, 479*4a4a4e9eSQuan Nguyen &dev_attr_error_mem_ue.attr, 480*4a4a4e9eSQuan Nguyen &dev_attr_error_pcie_ce.attr, 481*4a4a4e9eSQuan Nguyen &dev_attr_error_pcie_ue.attr, 482*4a4a4e9eSQuan Nguyen &dev_attr_error_other_ce.attr, 483*4a4a4e9eSQuan Nguyen &dev_attr_error_other_ue.attr, 484*4a4a4e9eSQuan Nguyen &dev_attr_error_smpro.attr, 485*4a4a4e9eSQuan Nguyen &dev_attr_error_pmpro.attr, 486*4a4a4e9eSQuan Nguyen &dev_attr_warn_smpro.attr, 487*4a4a4e9eSQuan Nguyen &dev_attr_warn_pmpro.attr, 488*4a4a4e9eSQuan Nguyen &dev_attr_event_vrd_warn_fault.attr, 489*4a4a4e9eSQuan Nguyen &dev_attr_event_vrd_hot.attr, 490*4a4a4e9eSQuan Nguyen &dev_attr_event_dimm_hot.attr, 491*4a4a4e9eSQuan Nguyen NULL 492*4a4a4e9eSQuan Nguyen }; 493*4a4a4e9eSQuan Nguyen 494*4a4a4e9eSQuan Nguyen ATTRIBUTE_GROUPS(smpro_errmon); 495*4a4a4e9eSQuan Nguyen 496*4a4a4e9eSQuan Nguyen static int smpro_errmon_probe(struct platform_device *pdev) 497*4a4a4e9eSQuan Nguyen { 498*4a4a4e9eSQuan Nguyen struct smpro_errmon *errmon; 499*4a4a4e9eSQuan Nguyen 500*4a4a4e9eSQuan Nguyen errmon = devm_kzalloc(&pdev->dev, sizeof(struct smpro_errmon), GFP_KERNEL); 501*4a4a4e9eSQuan Nguyen if (!errmon) 502*4a4a4e9eSQuan Nguyen return -ENOMEM; 503*4a4a4e9eSQuan Nguyen 504*4a4a4e9eSQuan Nguyen platform_set_drvdata(pdev, errmon); 505*4a4a4e9eSQuan Nguyen 506*4a4a4e9eSQuan Nguyen errmon->regmap = dev_get_regmap(pdev->dev.parent, NULL); 507*4a4a4e9eSQuan Nguyen if (!errmon->regmap) 508*4a4a4e9eSQuan Nguyen return -ENODEV; 509*4a4a4e9eSQuan Nguyen 510*4a4a4e9eSQuan Nguyen return 0; 511*4a4a4e9eSQuan Nguyen } 512*4a4a4e9eSQuan Nguyen 513*4a4a4e9eSQuan Nguyen static struct platform_driver smpro_errmon_driver = { 514*4a4a4e9eSQuan Nguyen .probe = smpro_errmon_probe, 515*4a4a4e9eSQuan Nguyen .driver = { 516*4a4a4e9eSQuan Nguyen .name = "smpro-errmon", 517*4a4a4e9eSQuan Nguyen .dev_groups = smpro_errmon_groups, 518*4a4a4e9eSQuan Nguyen }, 519*4a4a4e9eSQuan Nguyen }; 520*4a4a4e9eSQuan Nguyen 521*4a4a4e9eSQuan Nguyen module_platform_driver(smpro_errmon_driver); 522*4a4a4e9eSQuan Nguyen 523*4a4a4e9eSQuan Nguyen MODULE_AUTHOR("Tung Nguyen <tung.nguyen@amperecomputing.com>"); 524*4a4a4e9eSQuan Nguyen MODULE_AUTHOR("Thinh Pham <thinh.pham@amperecomputing.com>"); 525*4a4a4e9eSQuan Nguyen MODULE_AUTHOR("Hoang Nguyen <hnguyen@amperecomputing.com>"); 526*4a4a4e9eSQuan Nguyen MODULE_AUTHOR("Thu Nguyen <thu@os.amperecomputing.com>"); 527*4a4a4e9eSQuan Nguyen MODULE_AUTHOR("Quan Nguyen <quan@os.amperecomputing.com>"); 528*4a4a4e9eSQuan Nguyen MODULE_DESCRIPTION("Ampere Altra SMpro driver"); 529*4a4a4e9eSQuan Nguyen MODULE_LICENSE("GPL"); 530