// SPDX-License-Identifier: GPL-2.0-only /* * GHES/EDAC Linux driver * * Copyright (c) 2013 by Mauro Carvalho Chehab * * Red Hat Inc. https://www.redhat.com
*/
/* * Access to ghes_pvt must be protected by ghes_lock. The spinlock * also provides the necessary (implicit) memory barrier for the SMP * case to make the pointer visible on another CPU.
*/ staticstruct ghes_pvt *ghes_pvt;
/* * This driver's representation of the system hardware, as collected * from DMI.
*/ staticstruct ghes_hw_desc { int num_dimms; struct dimm_info *dimms;
} ghes_hw;
/* * Sync with other, potentially concurrent callers of * ghes_edac_report_mem_error(). We don't know what the * "inventive" firmware would do.
*/ static DEFINE_SPINLOCK(ghes_lock);
/* * Set to a NULL string when both bank and device are zero. In this case, * the label assigned by default will be preserved.
*/
snprintf(dimm->label, sizeof(dimm->label), "%s%s%s",
(bank && *bank) ? bank : "",
(bank && *bank && device && *device) ? " " : "",
(device && *device) ? device : "");
}
/* * Actually, we can only detect if the memory has bits for * checksum or not
*/ if (entry->total_width == entry->data_width)
dimm->edac_mode = EDAC_NONE; else
dimm->edac_mode = EDAC_SECDED;
n += scnprintf(msg + n, len - n, "APEI location: %s ", location);
if (!(mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS)) goto out;
n += scnprintf(msg + n, len - n, "status(0x%016llx): ", mem->error_status);
n += scnprintf(msg + n, len - n, "%s ", cper_mem_err_status_str(mem->error_status));
/* * We can do the locking below because GHES defers error processing * from NMI to IRQ context. Whenever that changes, we'd at least * know.
*/ if (WARN_ON_ONCE(in_nmi())) return NOTIFY_OK;
/* Memory error location, mapped on e->location */
p = e->location;
cper_mem_err_pack(mem_err, &cmem);
p += cper_mem_err_location(&cmem, p);
if (mem_err->validation_bits & CPER_MEM_VALID_MODULE_HANDLE) { struct dimm_info *dimm;
p += cper_dimm_err_location(&cmem, p);
dimm = find_dimm_by_handle(mci, mem_err->mem_dev_handle); if (dimm) {
e->top_layer = dimm->idx;
strcpy(e->label, dimm->label);
}
} if (p > e->location)
*(p - 1) = '\0';
if (!*e->label)
strcpy(e->label, "unknown memory");
/* All other fields are mapped on e->other_detail */
p = pvt->other_detail;
p += print_mem_error_other_detail(mem_err, p, e->location, OTHER_DETAIL_LEN); if (p > pvt->other_detail)
*(p - 1) = '\0';
if (fake) {
pr_info("This system has a very crappy BIOS: It doesn't even list the DIMMS.\n");
pr_info("Its SMBIOS info is wrong. It is doubtful that the error report would\n");
pr_info("work on such system. Use this driver with caution\n");
}
pr_info("This system has %d DIMM sockets.\n", ghes_hw.num_dimms);
if (!fake) { struct dimm_info *src, *dst; int i = 0;
/* * If no src->label, preserve default label assigned * from EDAC core.
*/ if (strlen(src->label))
memcpy(dst->label, src->label, sizeof(src->label));
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.