mirror of
https://github.com/torvalds/linux.git
synced 2025-12-01 07:26:02 +07:00
Merge tag 'edac_urgent_for_v6.18_rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/ras/ras
Pull EDAC fixes from Borislav Petkov: - In Versalnet, handle the reporting of non-standard hw errors whose information can come in more than one remote processor message. - Explicitly reenable ECC checking after a warm reset in Altera OCRAM as those registers are reset to default otherwise - Fix single-bit error injection in Altera EDAC to not inject errors directly in ECC RAM and thus lead to false double-bit errors due to same ECC RAM being in concurrent use * tag 'edac_urgent_for_v6.18_rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/ras/ras: EDAC/altera: Use INTTEST register for Ethernet and USB SBE injection EDAC/altera: Handle OCRAM ECC enable after warm reset EDAC/versalnet: Handle split messages for non-standard errors
This commit is contained in:
@@ -1184,10 +1184,22 @@ altr_check_ocram_deps_init(struct altr_edac_device_dev *device)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* Verify OCRAM has been initialized */
|
/*
|
||||||
|
* Verify that OCRAM has been initialized.
|
||||||
|
* During a warm reset, OCRAM contents are retained, but the control
|
||||||
|
* and status registers are reset to their default values. Therefore,
|
||||||
|
* ECC must be explicitly re-enabled in the control register.
|
||||||
|
* Error condition: if INITCOMPLETEA is clear and ECC_EN is already set.
|
||||||
|
*/
|
||||||
if (!ecc_test_bits(ALTR_A10_ECC_INITCOMPLETEA,
|
if (!ecc_test_bits(ALTR_A10_ECC_INITCOMPLETEA,
|
||||||
(base + ALTR_A10_ECC_INITSTAT_OFST)))
|
(base + ALTR_A10_ECC_INITSTAT_OFST))) {
|
||||||
return -ENODEV;
|
if (!ecc_test_bits(ALTR_A10_ECC_EN,
|
||||||
|
(base + ALTR_A10_ECC_CTRL_OFST)))
|
||||||
|
ecc_set_bits(ALTR_A10_ECC_EN,
|
||||||
|
(base + ALTR_A10_ECC_CTRL_OFST));
|
||||||
|
else
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
/* Enable IRQ on Single Bit Error */
|
/* Enable IRQ on Single Bit Error */
|
||||||
writel(ALTR_A10_ECC_SERRINTEN, (base + ALTR_A10_ECC_ERRINTENS_OFST));
|
writel(ALTR_A10_ECC_SERRINTEN, (base + ALTR_A10_ECC_ERRINTENS_OFST));
|
||||||
@@ -1357,7 +1369,7 @@ static const struct edac_device_prv_data a10_enetecc_data = {
|
|||||||
.ue_set_mask = ALTR_A10_ECC_TDERRA,
|
.ue_set_mask = ALTR_A10_ECC_TDERRA,
|
||||||
.set_err_ofst = ALTR_A10_ECC_INTTEST_OFST,
|
.set_err_ofst = ALTR_A10_ECC_INTTEST_OFST,
|
||||||
.ecc_irq_handler = altr_edac_a10_ecc_irq,
|
.ecc_irq_handler = altr_edac_a10_ecc_irq,
|
||||||
.inject_fops = &altr_edac_a10_device_inject2_fops,
|
.inject_fops = &altr_edac_a10_device_inject_fops,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* CONFIG_EDAC_ALTERA_ETHERNET */
|
#endif /* CONFIG_EDAC_ALTERA_ETHERNET */
|
||||||
@@ -1447,7 +1459,7 @@ static const struct edac_device_prv_data a10_usbecc_data = {
|
|||||||
.ue_set_mask = ALTR_A10_ECC_TDERRA,
|
.ue_set_mask = ALTR_A10_ECC_TDERRA,
|
||||||
.set_err_ofst = ALTR_A10_ECC_INTTEST_OFST,
|
.set_err_ofst = ALTR_A10_ECC_INTTEST_OFST,
|
||||||
.ecc_irq_handler = altr_edac_a10_ecc_irq,
|
.ecc_irq_handler = altr_edac_a10_ecc_irq,
|
||||||
.inject_fops = &altr_edac_a10_device_inject2_fops,
|
.inject_fops = &altr_edac_a10_device_inject_fops,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* CONFIG_EDAC_ALTERA_USB */
|
#endif /* CONFIG_EDAC_ALTERA_USB */
|
||||||
|
|||||||
@@ -605,21 +605,23 @@ static int rpmsg_cb(struct rpmsg_device *rpdev, void *data,
|
|||||||
length = result[MSG_ERR_LENGTH];
|
length = result[MSG_ERR_LENGTH];
|
||||||
offset = result[MSG_ERR_OFFSET];
|
offset = result[MSG_ERR_OFFSET];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The data can come in two stretches. Construct the regs from two
|
||||||
|
* messages. The offset indicates the offset from which the data is to
|
||||||
|
* be taken.
|
||||||
|
*/
|
||||||
|
for (i = 0 ; i < length; i++) {
|
||||||
|
k = offset + i;
|
||||||
|
j = ERROR_DATA + i;
|
||||||
|
mc_priv->regs[k] = result[j];
|
||||||
|
}
|
||||||
|
|
||||||
if (result[TOTAL_ERR_LENGTH] > length) {
|
if (result[TOTAL_ERR_LENGTH] > length) {
|
||||||
if (!mc_priv->part_len)
|
if (!mc_priv->part_len)
|
||||||
mc_priv->part_len = length;
|
mc_priv->part_len = length;
|
||||||
else
|
else
|
||||||
mc_priv->part_len += length;
|
mc_priv->part_len += length;
|
||||||
/*
|
|
||||||
* The data can come in 2 stretches. Construct the regs from 2
|
|
||||||
* messages the offset indicates the offset from which the data is to
|
|
||||||
* be taken
|
|
||||||
*/
|
|
||||||
for (i = 0 ; i < length; i++) {
|
|
||||||
k = offset + i;
|
|
||||||
j = ERROR_DATA + i;
|
|
||||||
mc_priv->regs[k] = result[j];
|
|
||||||
}
|
|
||||||
if (mc_priv->part_len < result[TOTAL_ERR_LENGTH])
|
if (mc_priv->part_len < result[TOTAL_ERR_LENGTH])
|
||||||
return 0;
|
return 0;
|
||||||
mc_priv->part_len = 0;
|
mc_priv->part_len = 0;
|
||||||
@@ -705,7 +707,7 @@ static int rpmsg_cb(struct rpmsg_device *rpdev, void *data,
|
|||||||
/* Convert to bytes */
|
/* Convert to bytes */
|
||||||
length = result[TOTAL_ERR_LENGTH] * 4;
|
length = result[TOTAL_ERR_LENGTH] * 4;
|
||||||
log_non_standard_event(sec_type, &amd_versalnet_guid, mc_priv->message,
|
log_non_standard_event(sec_type, &amd_versalnet_guid, mc_priv->message,
|
||||||
sec_sev, (void *)&result[ERROR_DATA], length);
|
sec_sev, (void *)&mc_priv->regs, length);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user