/**************************** MC Err device ***************************/
/* * Taken from table 8-55 in the MPC8641 User's Manual and/or 9-61 in the * MPC8572 User's Manual. Each line represents a syndrome bit column as a * 64-bit value, but split into an upper and lower 32-bit chunk. The labels * below correspond to Freescale's manuals.
*/ staticunsignedint ecc_table[16] = { /* MSB LSB */ /* [0:31] [32:63] */
0xf00fe11e, 0xc33c0ff7, /* Syndrome bit 7 */
0x00ff00ff, 0x00fff0ff,
0x0f0f0f0f, 0x0f0fff00,
0x11113333, 0x7777000f,
0x22224444, 0x8888222f,
0x44448888, 0xffff4441,
0x8888ffff, 0x11118882,
0xffff1111, 0x22221114, /* Syndrome bit 0 */
};
/* * Calculate the correct ECC value for a 64-bit value specified by high:low
*/ static u8 calculate_ecc(u32 high, u32 low)
{
u32 mask_low;
u32 mask_high; int bit_cnt;
u8 ecc = 0; int i; int j;
for (i = 0; i < 8; i++) {
mask_high = ecc_table[i * 2];
mask_low = ecc_table[i * 2 + 1];
bit_cnt = 0;
/* * Create the syndrome code which is generated if the data line specified by * 'bit' failed. Eg generate an 8-bit codes seen in Table 8-55 in the MPC8641 * User's Manual and 9-61 in the MPC8572 User's Manual.
*/ static u8 syndrome_from_bit(unsignedint bit) { int i;
u8 syndrome = 0;
/* * Cycle through the upper or lower 32-bit portion of each value in * ecc_table depending on if 'bit' is in the upper or lower half of * 64-bit data.
*/ for (i = bit < 32; i < 16; i += 2)
syndrome |= ((ecc_table[i] >> (bit % 32)) & 1) << (i / 2);
return syndrome;
}
/* * Decode data and ecc syndrome to determine what went wrong * Note: This can only decode single-bit errors
*/ staticvoid sbe_ecc_decode(u32 cap_high, u32 cap_low, u32 cap_ecc, int *bad_data_bit, int *bad_ecc_bit)
{ int i;
u8 syndrome;
*bad_data_bit = -1;
*bad_ecc_bit = -1;
/* * Calculate the ECC of the captured data and XOR it with the captured * ECC to find an ECC syndrome value we can search for
*/
syndrome = calculate_ecc(cap_high, cap_low) ^ cap_ecc;
/* Check if a data line is stuck... */ for (i = 0; i < 64; i++) { if (syndrome == syndrome_from_bit(i)) {
*bad_data_bit = i; return;
}
}
/* If data is correct, check ECC bits for errors... */ for (i = 0; i < 8; i++) { if ((syndrome >> i) & 0x1) {
*bad_ecc_bit = i; return;
}
}
}
/* no more processing if not ECC bit errors */ if (!(err_detect & (DDR_EDE_SBE | DDR_EDE_MBE))) {
ddr_out32(pdata, FSL_MC_ERR_DETECT, err_detect); return;
}
syndrome = ddr_in32(pdata, FSL_MC_CAPTURE_ECC);
/* Mask off appropriate bits of syndrome based on bus width */
bus_width = (ddr_in32(pdata, FSL_MC_DDR_SDRAM_CFG) &
DSC_DBW_MASK) ? 32 : 64; if (bus_width == 64)
syndrome &= 0xff; else
syndrome &= 0xffff;
/* * Get the endianness of DDR controller registers. * Default is big endian.
*/
pdata->little_endian = of_property_read_bool(op->dev.of_node, "little-endian");
res = of_address_to_resource(op->dev.of_node, 0, &r); if (res) {
pr_err("%s: Unable to get resource for MC err regs\n",
__func__); goto err;
}
if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r),
pdata->name)) {
pr_err("%s: Error while requesting mem region\n",
__func__);
res = -EBUSY; goto err;
}
pdata->mc_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r)); if (!pdata->mc_vbase) {
pr_err("%s: Unable to setup MC err regs\n", __func__);
res = -ENOMEM; goto err;
}
if (pdata->flag == TYPE_IMX9) {
pdata->inject_vbase = devm_platform_ioremap_resource_byname(op, "inject"); if (IS_ERR(pdata->inject_vbase)) {
res = -ENOMEM; goto err;
}
}
if (edac_op_state == EDAC_OPSTATE_POLL)
mci->edac_check = fsl_mc_check;
mci->ctl_page_to_phys = NULL;
mci->scrub_mode = SCRUB_SW_SRC;
fsl_ddr_init_csrows(mci);
/* store the original error disable bits */
pdata->orig_ddr_err_disable = ddr_in32(pdata, FSL_MC_ERR_DISABLE);
ddr_out32(pdata, FSL_MC_ERR_DISABLE, 0);
/* clear all error bits */
ddr_out32(pdata, FSL_MC_ERR_DETECT, ~0);
res = edac_mc_add_mc_with_groups(mci, fsl_ddr_dev_groups); if (res) {
edac_dbg(3, "failed edac_mc_add_mc()\n"); goto err;
}
if (edac_op_state == EDAC_OPSTATE_INT) {
ddr_out32(pdata, FSL_MC_ERR_INT_EN,
DDR_EIE_MBEE | DDR_EIE_SBEE);
/* store the original error management threshold */
pdata->orig_ddr_err_sbe = ddr_in32(pdata,
FSL_MC_ERR_SBE) & 0xff0000;
/* set threshold to 1 error per interrupt */
ddr_out32(pdata, FSL_MC_ERR_SBE, 0x10000);
/* register interrupts */
pdata->irq = platform_get_irq(op, 0);
res = devm_request_irq(&op->dev, pdata->irq,
fsl_mc_isr,
IRQF_SHARED, "[EDAC] MC err", mci); if (res < 0) {
pr_err("%s: Unable to request irq %d for FSL DDR DRAM ERR\n",
__func__, pdata->irq);
res = -ENODEV; goto err2;
}
pr_info(EDAC_MOD_STR " acquired irq %d for MC\n",
pdata->irq);
}
devres_remove_group(&op->dev, fsl_mc_err_probe);
edac_dbg(3, "success\n");
pr_info(EDAC_MOD_STR " MC err registered\n");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.