Commit c36e3e77 authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab

sb_edac: convert driver to use the new edac ABI

The legacy edac ABI is going to be removed. Port the driver to use
and benefit from the new API functionality.
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 63b5d1d9
...@@ -314,8 +314,6 @@ struct sbridge_pvt { ...@@ -314,8 +314,6 @@ struct sbridge_pvt {
struct sbridge_info info; struct sbridge_info info;
struct sbridge_channel channel[NUM_CHANNELS]; struct sbridge_channel channel[NUM_CHANNELS];
int csrow_map[NUM_CHANNELS][MAX_DIMMS];
/* Memory type detection */ /* Memory type detection */
bool is_mirrored, is_lockstep, is_close_pg; bool is_mirrored, is_lockstep, is_close_pg;
...@@ -487,29 +485,14 @@ static struct pci_dev *get_pdev_slot_func(u8 bus, unsigned slot, ...@@ -487,29 +485,14 @@ static struct pci_dev *get_pdev_slot_func(u8 bus, unsigned slot,
} }
/** /**
* sbridge_get_active_channels() - gets the number of channels and csrows * check_if_ecc_is_active() - Checks if ECC is active
* bus: Device bus * bus: Device bus
* @channels: Number of channels that will be returned
* @csrows: Number of csrows found
*
* Since EDAC core needs to know in advance the number of available channels
* and csrows, in order to allocate memory for csrows/channels, it is needed
* to run two similar steps. At the first step, implemented on this function,
* it checks the number of csrows/channels present at one socket, identified
* by the associated PCI bus.
* this is used in order to properly allocate the size of mci components.
* Note: one csrow is one dimm.
*/ */
static int sbridge_get_active_channels(const u8 bus, unsigned *channels, static int check_if_ecc_is_active(const u8 bus)
unsigned *csrows)
{ {
struct pci_dev *pdev = NULL; struct pci_dev *pdev = NULL;
int i, j;
u32 mcmtr; u32 mcmtr;
*channels = 0;
*csrows = 0;
pdev = get_pdev_slot_func(bus, 15, 0); pdev = get_pdev_slot_func(bus, 15, 0);
if (!pdev) { if (!pdev) {
sbridge_printk(KERN_ERR, "Couldn't find PCI device " sbridge_printk(KERN_ERR, "Couldn't find PCI device "
...@@ -523,41 +506,14 @@ static int sbridge_get_active_channels(const u8 bus, unsigned *channels, ...@@ -523,41 +506,14 @@ static int sbridge_get_active_channels(const u8 bus, unsigned *channels,
sbridge_printk(KERN_ERR, "ECC is disabled. Aborting\n"); sbridge_printk(KERN_ERR, "ECC is disabled. Aborting\n");
return -ENODEV; return -ENODEV;
} }
for (i = 0; i < NUM_CHANNELS; i++) {
u32 mtr;
/* Device 15 functions 2 - 5 */
pdev = get_pdev_slot_func(bus, 15, 2 + i);
if (!pdev) {
sbridge_printk(KERN_ERR, "Couldn't find PCI device "
"%2x.%02d.%d!!!\n",
bus, 15, 2 + i);
return -ENODEV;
}
(*channels)++;
for (j = 0; j < ARRAY_SIZE(mtr_regs); j++) {
pci_read_config_dword(pdev, mtr_regs[j], &mtr);
debugf1("Bus#%02x channel #%d MTR%d = %x\n", bus, i, j, mtr);
if (IS_DIMM_PRESENT(mtr))
(*csrows)++;
}
}
debugf0("Number of active channels: %d, number of active dimms: %d\n",
*channels, *csrows);
return 0; return 0;
} }
static int get_dimm_config(struct mem_ctl_info *mci) static int get_dimm_config(struct mem_ctl_info *mci)
{ {
struct sbridge_pvt *pvt = mci->pvt_info; struct sbridge_pvt *pvt = mci->pvt_info;
struct csrow_info *csr; struct dimm_info *dimm;
int i, j, banks, ranks, rows, cols, size, npages; int i, j, banks, ranks, rows, cols, size, npages;
int csrow = 0;
unsigned long last_page = 0;
u32 reg; u32 reg;
enum edac_type mode; enum edac_type mode;
enum mem_type mtype; enum mem_type mtype;
...@@ -616,7 +572,8 @@ static int get_dimm_config(struct mem_ctl_info *mci) ...@@ -616,7 +572,8 @@ static int get_dimm_config(struct mem_ctl_info *mci)
u32 mtr; u32 mtr;
for (j = 0; j < ARRAY_SIZE(mtr_regs); j++) { for (j = 0; j < ARRAY_SIZE(mtr_regs); j++) {
struct dimm_info *dimm = &mci->dimms[j]; dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms, mci->n_layers,
i, j, 0);
pci_read_config_dword(pvt->pci_tad[i], pci_read_config_dword(pvt->pci_tad[i],
mtr_regs[j], &mtr); mtr_regs[j], &mtr);
debugf4("Channel #%d MTR%d = %x\n", i, j, mtr); debugf4("Channel #%d MTR%d = %x\n", i, j, mtr);
...@@ -636,16 +593,6 @@ static int get_dimm_config(struct mem_ctl_info *mci) ...@@ -636,16 +593,6 @@ static int get_dimm_config(struct mem_ctl_info *mci)
size, npages, size, npages,
banks, ranks, rows, cols); banks, ranks, rows, cols);
/*
* Fake stuff. This controller doesn't see
* csrows.
*/
csr = &mci->csrows[csrow];
pvt->csrow_map[i][j] = csrow;
last_page += npages;
csrow++;
csr->channels[0].dimm = dimm;
dimm->nr_pages = npages; dimm->nr_pages = npages;
dimm->grain = 32; dimm->grain = 32;
dimm->dtype = (banks == 8) ? DEV_X8 : DEV_X4; dimm->dtype = (banks == 8) ? DEV_X8 : DEV_X4;
...@@ -841,11 +788,10 @@ static int get_memory_error_data(struct mem_ctl_info *mci, ...@@ -841,11 +788,10 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
u8 *socket, u8 *socket,
long *channel_mask, long *channel_mask,
u8 *rank, u8 *rank,
char *area_type) char *area_type, char *msg)
{ {
struct mem_ctl_info *new_mci; struct mem_ctl_info *new_mci;
struct sbridge_pvt *pvt = mci->pvt_info; struct sbridge_pvt *pvt = mci->pvt_info;
char msg[256];
int n_rir, n_sads, n_tads, sad_way, sck_xch; int n_rir, n_sads, n_tads, sad_way, sck_xch;
int sad_interl, idx, base_ch; int sad_interl, idx, base_ch;
int interleave_mode; int interleave_mode;
...@@ -867,12 +813,10 @@ static int get_memory_error_data(struct mem_ctl_info *mci, ...@@ -867,12 +813,10 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
*/ */
if ((addr > (u64) pvt->tolm) && (addr < (1LL << 32))) { if ((addr > (u64) pvt->tolm) && (addr < (1LL << 32))) {
sprintf(msg, "Error at TOLM area, on addr 0x%08Lx", addr); sprintf(msg, "Error at TOLM area, on addr 0x%08Lx", addr);
edac_mc_handle_ce_no_info(mci, msg);
return -EINVAL; return -EINVAL;
} }
if (addr >= (u64)pvt->tohm) { if (addr >= (u64)pvt->tohm) {
sprintf(msg, "Error at MMIOH area, on addr 0x%016Lx", addr); sprintf(msg, "Error at MMIOH area, on addr 0x%016Lx", addr);
edac_mc_handle_ce_no_info(mci, msg);
return -EINVAL; return -EINVAL;
} }
...@@ -889,7 +833,6 @@ static int get_memory_error_data(struct mem_ctl_info *mci, ...@@ -889,7 +833,6 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
limit = SAD_LIMIT(reg); limit = SAD_LIMIT(reg);
if (limit <= prv) { if (limit <= prv) {
sprintf(msg, "Can't discover the memory socket"); sprintf(msg, "Can't discover the memory socket");
edac_mc_handle_ce_no_info(mci, msg);
return -EINVAL; return -EINVAL;
} }
if (addr <= limit) if (addr <= limit)
...@@ -898,7 +841,6 @@ static int get_memory_error_data(struct mem_ctl_info *mci, ...@@ -898,7 +841,6 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
} }
if (n_sads == MAX_SAD) { if (n_sads == MAX_SAD) {
sprintf(msg, "Can't discover the memory socket"); sprintf(msg, "Can't discover the memory socket");
edac_mc_handle_ce_no_info(mci, msg);
return -EINVAL; return -EINVAL;
} }
area_type = get_dram_attr(reg); area_type = get_dram_attr(reg);
...@@ -939,7 +881,6 @@ static int get_memory_error_data(struct mem_ctl_info *mci, ...@@ -939,7 +881,6 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
break; break;
default: default:
sprintf(msg, "Can't discover socket interleave"); sprintf(msg, "Can't discover socket interleave");
edac_mc_handle_ce_no_info(mci, msg);
return -EINVAL; return -EINVAL;
} }
*socket = sad_interleave[idx]; *socket = sad_interleave[idx];
...@@ -954,7 +895,6 @@ static int get_memory_error_data(struct mem_ctl_info *mci, ...@@ -954,7 +895,6 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
if (!new_mci) { if (!new_mci) {
sprintf(msg, "Struct for socket #%u wasn't initialized", sprintf(msg, "Struct for socket #%u wasn't initialized",
*socket); *socket);
edac_mc_handle_ce_no_info(mci, msg);
return -EINVAL; return -EINVAL;
} }
mci = new_mci; mci = new_mci;
...@@ -970,7 +910,6 @@ static int get_memory_error_data(struct mem_ctl_info *mci, ...@@ -970,7 +910,6 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
limit = TAD_LIMIT(reg); limit = TAD_LIMIT(reg);
if (limit <= prv) { if (limit <= prv) {
sprintf(msg, "Can't discover the memory channel"); sprintf(msg, "Can't discover the memory channel");
edac_mc_handle_ce_no_info(mci, msg);
return -EINVAL; return -EINVAL;
} }
if (addr <= limit) if (addr <= limit)
...@@ -1010,7 +949,6 @@ static int get_memory_error_data(struct mem_ctl_info *mci, ...@@ -1010,7 +949,6 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
break; break;
default: default:
sprintf(msg, "Can't discover the TAD target"); sprintf(msg, "Can't discover the TAD target");
edac_mc_handle_ce_no_info(mci, msg);
return -EINVAL; return -EINVAL;
} }
*channel_mask = 1 << base_ch; *channel_mask = 1 << base_ch;
...@@ -1024,7 +962,6 @@ static int get_memory_error_data(struct mem_ctl_info *mci, ...@@ -1024,7 +962,6 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
break; break;
default: default:
sprintf(msg, "Invalid mirror set. Can't decode addr"); sprintf(msg, "Invalid mirror set. Can't decode addr");
edac_mc_handle_ce_no_info(mci, msg);
return -EINVAL; return -EINVAL;
} }
} else } else
...@@ -1052,7 +989,6 @@ static int get_memory_error_data(struct mem_ctl_info *mci, ...@@ -1052,7 +989,6 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
if (offset > addr) { if (offset > addr) {
sprintf(msg, "Can't calculate ch addr: TAD offset 0x%08Lx is too high for addr 0x%08Lx!", sprintf(msg, "Can't calculate ch addr: TAD offset 0x%08Lx is too high for addr 0x%08Lx!",
offset, addr); offset, addr);
edac_mc_handle_ce_no_info(mci, msg);
return -EINVAL; return -EINVAL;
} }
addr -= offset; addr -= offset;
...@@ -1092,7 +1028,6 @@ static int get_memory_error_data(struct mem_ctl_info *mci, ...@@ -1092,7 +1028,6 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
if (n_rir == MAX_RIR_RANGES) { if (n_rir == MAX_RIR_RANGES) {
sprintf(msg, "Can't discover the memory rank for ch addr 0x%08Lx", sprintf(msg, "Can't discover the memory rank for ch addr 0x%08Lx",
ch_addr); ch_addr);
edac_mc_handle_ce_no_info(mci, msg);
return -EINVAL; return -EINVAL;
} }
rir_way = RIR_WAY(reg); rir_way = RIR_WAY(reg);
...@@ -1406,7 +1341,8 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci, ...@@ -1406,7 +1341,8 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
{ {
struct mem_ctl_info *new_mci; struct mem_ctl_info *new_mci;
struct sbridge_pvt *pvt = mci->pvt_info; struct sbridge_pvt *pvt = mci->pvt_info;
char *type, *optype, *msg, *recoverable_msg; enum hw_event_mc_err_type tp_event;
char *type, *optype, msg[256], *recoverable_msg;
bool ripv = GET_BITFIELD(m->mcgstatus, 0, 0); bool ripv = GET_BITFIELD(m->mcgstatus, 0, 0);
bool overflow = GET_BITFIELD(m->status, 62, 62); bool overflow = GET_BITFIELD(m->status, 62, 62);
bool uncorrected_error = GET_BITFIELD(m->status, 61, 61); bool uncorrected_error = GET_BITFIELD(m->status, 61, 61);
...@@ -1418,13 +1354,21 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci, ...@@ -1418,13 +1354,21 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
u32 optypenum = GET_BITFIELD(m->status, 4, 6); u32 optypenum = GET_BITFIELD(m->status, 4, 6);
long channel_mask, first_channel; long channel_mask, first_channel;
u8 rank, socket; u8 rank, socket;
int csrow, rc, dimm; int rc, dimm;
char *area_type = "Unknown"; char *area_type = "Unknown";
if (ripv) if (uncorrected_error) {
type = "NON_FATAL"; if (ripv) {
else type = "FATAL";
type = "FATAL"; tp_event = HW_EVENT_ERR_FATAL;
} else {
type = "NON_FATAL";
tp_event = HW_EVENT_ERR_UNCORRECTED;
}
} else {
type = "CORRECTED";
tp_event = HW_EVENT_ERR_CORRECTED;
}
/* /*
* According with Table 15-9 of the Intel Archictecture spec vol 3A, * According with Table 15-9 of the Intel Archictecture spec vol 3A,
...@@ -1442,19 +1386,19 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci, ...@@ -1442,19 +1386,19 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
} else { } else {
switch (optypenum) { switch (optypenum) {
case 0: case 0:
optype = "generic undef request"; optype = "generic undef request error";
break; break;
case 1: case 1:
optype = "memory read"; optype = "memory read error";
break; break;
case 2: case 2:
optype = "memory write"; optype = "memory write error";
break; break;
case 3: case 3:
optype = "addr/cmd"; optype = "addr/cmd error";
break; break;
case 4: case 4:
optype = "memory scrubbing"; optype = "memory scrubbing error";
break; break;
default: default:
optype = "reserved"; optype = "reserved";
...@@ -1463,13 +1407,13 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci, ...@@ -1463,13 +1407,13 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
} }
rc = get_memory_error_data(mci, m->addr, &socket, rc = get_memory_error_data(mci, m->addr, &socket,
&channel_mask, &rank, area_type); &channel_mask, &rank, area_type, msg);
if (rc < 0) if (rc < 0)
return; goto err_parsing;
new_mci = get_mci_for_node_id(socket); new_mci = get_mci_for_node_id(socket);
if (!new_mci) { if (!new_mci) {
edac_mc_handle_ce_no_info(mci, "Error: socket got corrupted!"); strcpy(msg, "Error: socket got corrupted!");
return; goto err_parsing;
} }
mci = new_mci; mci = new_mci;
pvt = mci->pvt_info; pvt = mci->pvt_info;
...@@ -1483,8 +1427,6 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci, ...@@ -1483,8 +1427,6 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
else else
dimm = 2; dimm = 2;
csrow = pvt->csrow_map[first_channel][dimm];
if (uncorrected_error && recoverable) if (uncorrected_error && recoverable)
recoverable_msg = " recoverable"; recoverable_msg = " recoverable";
else else
...@@ -1495,18 +1437,14 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci, ...@@ -1495,18 +1437,14 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
* Probably, we can just discard it, as the channel information * Probably, we can just discard it, as the channel information
* comes from the get_memory_error_data() address decoding * comes from the get_memory_error_data() address decoding
*/ */
msg = kasprintf(GFP_ATOMIC, snprintf(msg, sizeof(msg),
"%d %s error(s): %s on %s area %s%s: cpu=%d Err=%04x:%04x (ch=%d), " "%d error(s)%s: %s%s: cpu=%d Err=%04x:%04x addr = 0x%08llx socket=%d Channel=%ld(mask=%ld), rank=%d\n",
"addr = 0x%08llx => socket=%d, Channel=%ld(mask=%ld), rank=%d\n",
core_err_cnt, core_err_cnt,
overflow ? " OVERFLOW" : "",
area_type, area_type,
optype,
type,
recoverable_msg, recoverable_msg,
overflow ? "OVERFLOW" : "",
m->cpu, m->cpu,
mscod, errcode, mscod, errcode,
channel, /* 1111b means not specified */
(long long) m->addr, (long long) m->addr,
socket, socket,
first_channel, /* This is the real channel on SB */ first_channel, /* This is the real channel on SB */
...@@ -1515,13 +1453,19 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci, ...@@ -1515,13 +1453,19 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
debugf0("%s", msg); debugf0("%s", msg);
/* FIXME: need support for channel mask */
/* Call the helper to output message */ /* Call the helper to output message */
if (uncorrected_error) edac_mc_handle_error(tp_event, mci,
edac_mc_handle_fbd_ue(mci, csrow, 0, 0, msg); m->addr >> PAGE_SHIFT, m->addr & ~PAGE_MASK, 0,
else channel, dimm, -1,
edac_mc_handle_fbd_ce(mci, csrow, 0, msg); optype, msg, m);
return;
err_parsing:
edac_mc_handle_error(tp_event, mci, 0, 0, 0,
-1, -1, -1,
msg, "", m);
kfree(msg);
} }
/* /*
...@@ -1680,16 +1624,25 @@ static void sbridge_unregister_mci(struct sbridge_dev *sbridge_dev) ...@@ -1680,16 +1624,25 @@ static void sbridge_unregister_mci(struct sbridge_dev *sbridge_dev)
static int sbridge_register_mci(struct sbridge_dev *sbridge_dev) static int sbridge_register_mci(struct sbridge_dev *sbridge_dev)
{ {
struct mem_ctl_info *mci; struct mem_ctl_info *mci;
struct edac_mc_layer layers[2];
struct sbridge_pvt *pvt; struct sbridge_pvt *pvt;
int rc, channels, csrows; int rc;
/* Check the number of active and not disabled channels */ /* Check the number of active and not disabled channels */
rc = sbridge_get_active_channels(sbridge_dev->bus, &channels, &csrows); rc = check_if_ecc_is_active(sbridge_dev->bus);
if (unlikely(rc < 0)) if (unlikely(rc < 0))
return rc; return rc;
/* allocate a new MC control structure */ /* allocate a new MC control structure */
mci = edac_mc_alloc(sizeof(*pvt), csrows, channels, sbridge_dev->mc); layers[0].type = EDAC_MC_LAYER_CHANNEL;
layers[0].size = NUM_CHANNELS;
layers[0].is_virt_csrow = false;
layers[1].type = EDAC_MC_LAYER_SLOT;
layers[1].size = MAX_DIMMS;
layers[1].is_virt_csrow = true;
mci = new_edac_mc_alloc(sbridge_dev->mc, ARRAY_SIZE(layers), layers,
sizeof(*pvt));
if (unlikely(!mci)) if (unlikely(!mci))
return -ENOMEM; return -ENOMEM;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment