ghes.h 2.8 KB
Newer Older
1
/* SPDX-License-Identifier: GPL-2.0 */
2 3 4
#ifndef GHES_H
#define GHES_H

5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#include <acpi/apei.h>
#include <acpi/hed.h>

/*
 * One struct ghes is created for each generic hardware error source.
 * It provides the context for APEI hardware error timer/IRQ/SCI/NMI
 * handler.
 *
 * estatus: memory buffer for error status block, allocated during
 * HEST parsing.
 */
#define GHES_TO_CLEAR		0x0001
#define GHES_EXITING		0x0002

struct ghes {
20 21 22 23
	union {
		struct acpi_hest_generic *generic;
		struct acpi_hest_generic_v2 *generic_v2;
	};
24
	struct acpi_hest_generic_status *estatus;
25 26 27 28 29 30 31 32 33 34 35 36
	u64 buffer_paddr;
	unsigned long flags;
	union {
		struct list_head list;
		struct timer_list timer;
		unsigned int irq;
	};
};

struct ghes_estatus_node {
	struct llist_node llnode;
	struct acpi_hest_generic *generic;
37
	struct ghes *ghes;
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
};

struct ghes_estatus_cache {
	u32 estatus_len;
	atomic_t count;
	struct acpi_hest_generic *generic;
	unsigned long long time_in;
	struct rcu_head rcu;
};

enum {
	GHES_SEV_NO = 0x0,
	GHES_SEV_CORRECTED = 0x1,
	GHES_SEV_RECOVERABLE = 0x2,
	GHES_SEV_PANIC = 0x3,
};
54 55 56 57

/* From drivers/edac/ghes_edac.c */

#ifdef CONFIG_EDAC_GHES
58
void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err);
59 60 61 62 63 64

int ghes_edac_register(struct ghes *ghes, struct device *dev);

void ghes_edac_unregister(struct ghes *ghes);

#else
65
static inline void ghes_edac_report_mem_error(int sev,
66 67 68 69 70 71
				       struct cper_sec_mem_err *mem_err)
{
}

static inline int ghes_edac_register(struct ghes *ghes, struct device *dev)
{
72
	return -ENODEV;
73 74 75 76 77 78
}

static inline void ghes_edac_unregister(struct ghes *ghes)
{
}
#endif
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114

static inline int acpi_hest_get_version(struct acpi_hest_generic_data *gdata)
{
	return gdata->revision >> 8;
}

static inline void *acpi_hest_get_payload(struct acpi_hest_generic_data *gdata)
{
	if (acpi_hest_get_version(gdata) >= 3)
		return (void *)(((struct acpi_hest_generic_data_v300 *)(gdata)) + 1);

	return gdata + 1;
}

static inline int acpi_hest_get_error_length(struct acpi_hest_generic_data *gdata)
{
	return ((struct acpi_hest_generic_data *)(gdata))->error_data_length;
}

static inline int acpi_hest_get_size(struct acpi_hest_generic_data *gdata)
{
	if (acpi_hest_get_version(gdata) >= 3)
		return sizeof(struct acpi_hest_generic_data_v300);

	return sizeof(struct acpi_hest_generic_data);
}

static inline int acpi_hest_get_record_size(struct acpi_hest_generic_data *gdata)
{
	return (acpi_hest_get_size(gdata) + acpi_hest_get_error_length(gdata));
}

static inline void *acpi_hest_get_next(struct acpi_hest_generic_data *gdata)
{
	return (void *)(gdata) + acpi_hest_get_record_size(gdata);
}
115

116 117 118 119 120
#define apei_estatus_for_each_section(estatus, section)			\
	for (section = (struct acpi_hest_generic_data *)(estatus + 1);	\
	     (void *)section - (void *)(estatus + 1) < estatus->data_length; \
	     section = acpi_hest_get_next(section))

121
int ghes_notify_sea(void);
122 123

#endif /* GHES_H */