18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef GHES_H
38c2ecf20Sopenharmony_ci#define GHES_H
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#include <acpi/apei.h>
68c2ecf20Sopenharmony_ci#include <acpi/hed.h>
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci/*
98c2ecf20Sopenharmony_ci * One struct ghes is created for each generic hardware error source.
108c2ecf20Sopenharmony_ci * It provides the context for APEI hardware error timer/IRQ/SCI/NMI
118c2ecf20Sopenharmony_ci * handler.
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * estatus: memory buffer for error status block, allocated during
148c2ecf20Sopenharmony_ci * HEST parsing.
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_ci#define GHES_EXITING		0x0002
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistruct ghes {
198c2ecf20Sopenharmony_ci	union {
208c2ecf20Sopenharmony_ci		struct acpi_hest_generic *generic;
218c2ecf20Sopenharmony_ci		struct acpi_hest_generic_v2 *generic_v2;
228c2ecf20Sopenharmony_ci	};
238c2ecf20Sopenharmony_ci	struct acpi_hest_generic_status *estatus;
248c2ecf20Sopenharmony_ci	unsigned long flags;
258c2ecf20Sopenharmony_ci	union {
268c2ecf20Sopenharmony_ci		struct list_head list;
278c2ecf20Sopenharmony_ci		struct timer_list timer;
288c2ecf20Sopenharmony_ci		unsigned int irq;
298c2ecf20Sopenharmony_ci	};
308c2ecf20Sopenharmony_ci};
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistruct ghes_estatus_node {
338c2ecf20Sopenharmony_ci	struct llist_node llnode;
348c2ecf20Sopenharmony_ci	struct acpi_hest_generic *generic;
358c2ecf20Sopenharmony_ci	struct ghes *ghes;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	int task_work_cpu;
388c2ecf20Sopenharmony_ci	struct callback_head task_work;
398c2ecf20Sopenharmony_ci};
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistruct ghes_estatus_cache {
428c2ecf20Sopenharmony_ci	u32 estatus_len;
438c2ecf20Sopenharmony_ci	atomic_t count;
448c2ecf20Sopenharmony_ci	struct acpi_hest_generic *generic;
458c2ecf20Sopenharmony_ci	unsigned long long time_in;
468c2ecf20Sopenharmony_ci	struct rcu_head rcu;
478c2ecf20Sopenharmony_ci};
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cienum {
508c2ecf20Sopenharmony_ci	GHES_SEV_NO = 0x0,
518c2ecf20Sopenharmony_ci	GHES_SEV_CORRECTED = 0x1,
528c2ecf20Sopenharmony_ci	GHES_SEV_RECOVERABLE = 0x2,
538c2ecf20Sopenharmony_ci	GHES_SEV_PANIC = 0x3,
548c2ecf20Sopenharmony_ci};
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI_APEI_GHES
578c2ecf20Sopenharmony_ci/**
588c2ecf20Sopenharmony_ci * ghes_register_vendor_record_notifier - register a notifier for vendor
598c2ecf20Sopenharmony_ci * records that the kernel would otherwise ignore.
608c2ecf20Sopenharmony_ci * @nb: pointer to the notifier_block structure of the event handler.
618c2ecf20Sopenharmony_ci *
628c2ecf20Sopenharmony_ci * return 0 : SUCCESS, non-zero : FAIL
638c2ecf20Sopenharmony_ci */
648c2ecf20Sopenharmony_ciint ghes_register_vendor_record_notifier(struct notifier_block *nb);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci/**
678c2ecf20Sopenharmony_ci * ghes_unregister_vendor_record_notifier - unregister the previously
688c2ecf20Sopenharmony_ci * registered vendor record notifier.
698c2ecf20Sopenharmony_ci * @nb: pointer to the notifier_block structure of the vendor record handler.
708c2ecf20Sopenharmony_ci */
718c2ecf20Sopenharmony_civoid ghes_unregister_vendor_record_notifier(struct notifier_block *nb);
728c2ecf20Sopenharmony_ci#endif
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ciint ghes_estatus_pool_init(unsigned int num_ghes);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci/* From drivers/edac/ghes_edac.c */
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci#ifdef CONFIG_EDAC_GHES
798c2ecf20Sopenharmony_civoid ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ciint ghes_edac_register(struct ghes *ghes, struct device *dev);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_civoid ghes_edac_unregister(struct ghes *ghes);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci#else
868c2ecf20Sopenharmony_cistatic inline void ghes_edac_report_mem_error(int sev,
878c2ecf20Sopenharmony_ci				       struct cper_sec_mem_err *mem_err)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistatic inline int ghes_edac_register(struct ghes *ghes, struct device *dev)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	return -ENODEV;
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic inline void ghes_edac_unregister(struct ghes *ghes)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci#endif
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic inline int acpi_hest_get_version(struct acpi_hest_generic_data *gdata)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	return gdata->revision >> 8;
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic inline void *acpi_hest_get_payload(struct acpi_hest_generic_data *gdata)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	if (acpi_hest_get_version(gdata) >= 3)
1098c2ecf20Sopenharmony_ci		return (void *)(((struct acpi_hest_generic_data_v300 *)(gdata)) + 1);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	return gdata + 1;
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistatic inline int acpi_hest_get_error_length(struct acpi_hest_generic_data *gdata)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	return ((struct acpi_hest_generic_data *)(gdata))->error_data_length;
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic inline int acpi_hest_get_size(struct acpi_hest_generic_data *gdata)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	if (acpi_hest_get_version(gdata) >= 3)
1228c2ecf20Sopenharmony_ci		return sizeof(struct acpi_hest_generic_data_v300);
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	return sizeof(struct acpi_hest_generic_data);
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistatic inline int acpi_hest_get_record_size(struct acpi_hest_generic_data *gdata)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	return (acpi_hest_get_size(gdata) + acpi_hest_get_error_length(gdata));
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic inline void *acpi_hest_get_next(struct acpi_hest_generic_data *gdata)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	return (void *)(gdata) + acpi_hest_get_record_size(gdata);
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci#define apei_estatus_for_each_section(estatus, section)			\
1388c2ecf20Sopenharmony_ci	for (section = (struct acpi_hest_generic_data *)(estatus + 1);	\
1398c2ecf20Sopenharmony_ci	     (void *)section - (void *)(estatus + 1) < estatus->data_length; \
1408c2ecf20Sopenharmony_ci	     section = acpi_hest_get_next(section))
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI_APEI_SEA
1438c2ecf20Sopenharmony_ciint ghes_notify_sea(void);
1448c2ecf20Sopenharmony_ci#else
1458c2ecf20Sopenharmony_cistatic inline int ghes_notify_sea(void) { return -ENOENT; }
1468c2ecf20Sopenharmony_ci#endif
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci#endif /* GHES_H */
149