if (priv->svc_sreg_support)
err = secure_writel(addr, data, priv->sreg_tbl); else
writel(data, addr);
return err;
}
/* * Gather the ECC information from the External Memory Interface registers * and report it to the edac handler.
*/ staticvoid bluefield_gather_report_ecc(struct mem_ctl_info *mci, int error_cnt, int is_single_ecc)
{ struct bluefield_edac_priv *priv = mci->pvt_info;
u32 dram_additional_info, err_prank, edea0, edea1;
u32 ecc_latch_select, dram_syndrom, serr, derr, syndrom; enum hw_event_mc_err_type ecc_type;
u64 ecc_dimm_addr; int ecc_dimm, err;
/* * Tell the External Memory Interface to populate the relevant * registers with information about the last ECC error occurrence.
*/
ecc_latch_select = MLXBF_ECC_LATCH_SEL__START;
err = bluefield_edac_writel(priv, MLXBF_ECC_LATCH_SEL, ecc_latch_select); if (err)
dev_err(priv->dev, "ECC latch select write failed.\n");
/* * Verify that the ECC reported info in the registers is of the * same type as the one asked to report. If not, just report the * error without the detailed information.
*/
err = bluefield_edac_readl(priv, MLXBF_SYNDROM, &dram_syndrom); if (err) {
dev_err(priv->dev, "DRAM syndrom read failed.\n"); return;
}
/* * The memory controller might not be initialized by the firmware * when there isn't memory, which may lead to bad register readings.
*/ if (mci->edac_cap == EDAC_FLAG_NONE) return;
/* Read the MSS (Memory SubSystem) index from ACPI table. */ if (device_property_read_u32(dev, "mss_number", &mc_idx)) {
dev_warn(dev, "bf_edac: MSS number unknown\n"); return -EINVAL;
}
/* Read the DIMMs per MC from ACPI table. */ if (device_property_read_u32(dev, "dimm_per_mc", &dimm_count)) {
dev_warn(dev, "bf_edac: DIMMs per MC unknown\n"); return -EINVAL;
}
if (dimm_count > MLXBF_EDAC_MAX_DIMM_PER_MC) {
dev_warn(dev, "bf_edac: DIMMs per MC not valid\n"); return -EINVAL;
}
emi_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!emi_res) return -EINVAL;
mci = edac_mc_alloc(mc_idx, ARRAY_SIZE(layers), layers, sizeof(*priv)); if (!mci) return -ENOMEM;
priv = mci->pvt_info;
priv->dev = dev;
/* * The "sec_reg_block" property in the ACPI table determines the method * the driver uses to access the EMI registers: * a) property is not present - directly access registers via readl/writel * b) property is present - indirectly access registers via SMC calls * (assuming required Silicon Provider service version found)
*/ if (device_property_read_u32(dev, "sec_reg_block", &priv->sreg_tbl)) {
priv->svc_sreg_support = false;
} else { /* * Check for minimum required Arm Silicon Provider (SiP) service * version, ensuring support of required SMC function IDs.
*/
arm_smccc_smc(MLXBF_SIP_SVC_VERSION, 0, 0, 0, 0, 0, 0, 0, &res); if (res.a0 == MLXBF_SVC_REQ_MAJOR &&
res.a1 >= MLXBF_SVC_REQ_MINOR) {
priv->svc_sreg_support = true;
} else {
dev_err(dev, "Required SMCs are not supported.\n");
ret = -EINVAL; goto err;
}
}
priv->dimm_per_mc = dimm_count; if (!priv->svc_sreg_support) {
priv->emi_base = devm_ioremap_resource(dev, emi_res); if (IS_ERR(priv->emi_base)) {
dev_err(dev, "failed to map EMI IO resource\n");
ret = PTR_ERR(priv->emi_base); goto err;
}
} else {
priv->emi_base = (void __iomem *)emi_res->start;
}
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.