#include <linux/arm_sdei.h>
#include <linux/kernel.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/acpi.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <linux/cper.h>
#include <linux/cleanup.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/ratelimit.h>
#include <linux/vmalloc.h>
#include <linux/irq_work.h>
#include <linux/llist.h>
#include <linux/genalloc.h>
#include <linux/kfifo.h>
#include <linux/pci.h>
#include <linux/pfn.h>
#include <linux/aer.h>
#include <linux/nmi.h>
#include <linux/sched/clock.h>
#include <linux/uuid.h>
#include <linux/ras.h>
#include <linux/task_work.h>
#include <acpi/actbl1.h>
#include <acpi/ghes.h>
#include <acpi/apei.h>
#include <asm/fixmap.h>
#include <asm/tlbflush.h>
#include <cxl/event.h>
#include <ras/ras_event.h>
#include "apei-internal.h"
#define GHES_PFX …
#define GHES_ESTATUS_MAX_SIZE …
#define GHES_ESOURCE_PREALLOC_MAX_SIZE …
#define GHES_ESTATUS_POOL_MIN_ALLOC_ORDER …
#define GHES_ESTATUS_CACHE_AVG_SIZE …
#define GHES_ESTATUS_CACHES_SIZE …
#define GHES_ESTATUS_IN_CACHE_MAX_NSEC …
#define GHES_ESTATUS_CACHE_ALLOCED_MAX …
#define GHES_ESTATUS_CACHE_LEN(estatus_len) …
#define GHES_ESTATUS_FROM_CACHE(estatus_cache) …
#define GHES_ESTATUS_NODE_LEN(estatus_len) …
#define GHES_ESTATUS_FROM_NODE(estatus_node) …
#define GHES_VENDOR_ENTRY_LEN(gdata_len) …
#define GHES_GDATA_FROM_VENDOR_ENTRY(vendor_entry) …
#ifndef CONFIG_ARM_SDE_INTERFACE
#define FIX_APEI_GHES_SDEI_NORMAL …
#define FIX_APEI_GHES_SDEI_CRITICAL …
#endif
static ATOMIC_NOTIFIER_HEAD(ghes_report_chain);
static inline bool is_hest_type_generic_v2(struct ghes *ghes)
{ … }
static inline bool is_hest_sync_notify(struct ghes *ghes)
{ … }
bool ghes_disable;
module_param_named(disable, ghes_disable, bool, 0);
static bool ghes_edac_force_enable;
module_param_named(edac_force_enable, ghes_edac_force_enable, bool, 0);
static LIST_HEAD(ghes_hed);
static DEFINE_MUTEX(ghes_list_mutex);
static LIST_HEAD(ghes_devs);
static DEFINE_MUTEX(ghes_devs_mutex);
static DEFINE_SPINLOCK(ghes_notify_lock_irq);
struct ghes_vendor_record_entry { … };
static struct gen_pool *ghes_estatus_pool;
static struct ghes_estatus_cache __rcu *ghes_estatus_caches[GHES_ESTATUS_CACHES_SIZE];
static atomic_t ghes_estatus_cache_alloced;
static int ghes_panic_timeout __read_mostly = …;
static void __iomem *ghes_map(u64 pfn, enum fixed_addresses fixmap_idx)
{ … }
static void ghes_unmap(void __iomem *vaddr, enum fixed_addresses fixmap_idx)
{ … }
int ghes_estatus_pool_init(unsigned int num_ghes)
{ … }
void ghes_estatus_pool_region_free(unsigned long addr, u32 size)
{ … }
EXPORT_SYMBOL_GPL(…);
static int map_gen_v2(struct ghes *ghes)
{ … }
static void unmap_gen_v2(struct ghes *ghes)
{ … }
static void ghes_ack_error(struct acpi_hest_generic_v2 *gv2)
{ … }
static struct ghes *ghes_new(struct acpi_hest_generic *generic)
{ … }
static void ghes_fini(struct ghes *ghes)
{ … }
static inline int ghes_severity(int severity)
{ … }
static void ghes_copy_tofrom_phys(void *buffer, u64 paddr, u32 len,
int from_phys,
enum fixed_addresses fixmap_idx)
{ … }
static int __ghes_check_estatus(struct ghes *ghes,
struct acpi_hest_generic_status *estatus)
{ … }
static int __ghes_peek_estatus(struct ghes *ghes,
struct acpi_hest_generic_status *estatus,
u64 *buf_paddr, enum fixed_addresses fixmap_idx)
{ … }
static int __ghes_read_estatus(struct acpi_hest_generic_status *estatus,
u64 buf_paddr, enum fixed_addresses fixmap_idx,
size_t buf_len)
{ … }
static int ghes_read_estatus(struct ghes *ghes,
struct acpi_hest_generic_status *estatus,
u64 *buf_paddr, enum fixed_addresses fixmap_idx)
{ … }
static void ghes_clear_estatus(struct ghes *ghes,
struct acpi_hest_generic_status *estatus,
u64 buf_paddr, enum fixed_addresses fixmap_idx)
{ … }
static void ghes_kick_task_work(struct callback_head *head)
{ … }
static bool ghes_do_memory_failure(u64 physical_addr, int flags)
{ … }
static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata,
int sev, bool sync)
{ … }
static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata,
int sev, bool sync)
{ … }
static void ghes_handle_aer(struct acpi_hest_generic_data *gdata)
{ … }
static BLOCKING_NOTIFIER_HEAD(vendor_record_notify_list);
int ghes_register_vendor_record_notifier(struct notifier_block *nb)
{ … }
EXPORT_SYMBOL_GPL(…);
void ghes_unregister_vendor_record_notifier(struct notifier_block *nb)
{ … }
EXPORT_SYMBOL_GPL(…);
static void ghes_vendor_record_work_func(struct work_struct *work)
{ … }
static void ghes_defer_non_standard_event(struct acpi_hest_generic_data *gdata,
int sev)
{ … }
#define CXL_CPER_FIFO_DEPTH …
DEFINE_KFIFO(cxl_cper_fifo, … } ;
static DEFINE_SPINLOCK(cxl_cper_work_lock);
struct work_struct *cxl_cper_work;
static void cxl_cper_post_event(enum cxl_event_type event_type,
struct cxl_cper_event_rec *rec)
{ … }
int cxl_cper_register_work(struct work_struct *work)
{ … }
EXPORT_SYMBOL_NS_GPL(…);
int cxl_cper_unregister_work(struct work_struct *work)
{ … }
EXPORT_SYMBOL_NS_GPL(…);
int cxl_cper_kfifo_get(struct cxl_cper_work_data *wd)
{ … }
EXPORT_SYMBOL_NS_GPL(…);
static bool ghes_do_proc(struct ghes *ghes,
const struct acpi_hest_generic_status *estatus)
{ … }
static void __ghes_print_estatus(const char *pfx,
const struct acpi_hest_generic *generic,
const struct acpi_hest_generic_status *estatus)
{ … }
static int ghes_print_estatus(const char *pfx,
const struct acpi_hest_generic *generic,
const struct acpi_hest_generic_status *estatus)
{ … }
static int ghes_estatus_cached(struct acpi_hest_generic_status *estatus)
{ … }
static struct ghes_estatus_cache *ghes_estatus_cache_alloc(
struct acpi_hest_generic *generic,
struct acpi_hest_generic_status *estatus)
{ … }
static void ghes_estatus_cache_rcu_free(struct rcu_head *head)
{ … }
static void
ghes_estatus_cache_add(struct acpi_hest_generic *generic,
struct acpi_hest_generic_status *estatus)
{ … }
static void __ghes_panic(struct ghes *ghes,
struct acpi_hest_generic_status *estatus,
u64 buf_paddr, enum fixed_addresses fixmap_idx)
{ … }
static int ghes_proc(struct ghes *ghes)
{ … }
static void ghes_add_timer(struct ghes *ghes)
{ … }
static void ghes_poll_func(struct timer_list *t)
{ … }
static irqreturn_t ghes_irq_func(int irq, void *data)
{ … }
static int ghes_notify_hed(struct notifier_block *this, unsigned long event,
void *data)
{ … }
static struct notifier_block ghes_notifier_hed = …;
static struct llist_head ghes_estatus_llist;
static struct irq_work ghes_proc_irq_work;
static void ghes_proc_in_irq(struct irq_work *irq_work)
{ … }
static void ghes_print_queued_estatus(void)
{ … }
static int ghes_in_nmi_queue_one_entry(struct ghes *ghes,
enum fixed_addresses fixmap_idx)
{ … }
static int ghes_in_nmi_spool_from_list(struct list_head *rcu_list,
enum fixed_addresses fixmap_idx)
{ … }
#ifdef CONFIG_ACPI_APEI_SEA
static LIST_HEAD(ghes_sea);
int ghes_notify_sea(void)
{
static DEFINE_RAW_SPINLOCK(ghes_notify_lock_sea);
int rv;
raw_spin_lock(&ghes_notify_lock_sea);
rv = ghes_in_nmi_spool_from_list(&ghes_sea, FIX_APEI_GHES_SEA);
raw_spin_unlock(&ghes_notify_lock_sea);
return rv;
}
static void ghes_sea_add(struct ghes *ghes)
{
mutex_lock(&ghes_list_mutex);
list_add_rcu(&ghes->list, &ghes_sea);
mutex_unlock(&ghes_list_mutex);
}
static void ghes_sea_remove(struct ghes *ghes)
{
mutex_lock(&ghes_list_mutex);
list_del_rcu(&ghes->list);
mutex_unlock(&ghes_list_mutex);
synchronize_rcu();
}
#else
static inline void ghes_sea_add(struct ghes *ghes) { … }
static inline void ghes_sea_remove(struct ghes *ghes) { … }
#endif
#ifdef CONFIG_HAVE_ACPI_APEI_NMI
static atomic_t ghes_in_nmi = …;
static LIST_HEAD(ghes_nmi);
static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs)
{ … }
static void ghes_nmi_add(struct ghes *ghes)
{ … }
static void ghes_nmi_remove(struct ghes *ghes)
{ … }
#else
static inline void ghes_nmi_add(struct ghes *ghes) { }
static inline void ghes_nmi_remove(struct ghes *ghes) { }
#endif
static void ghes_nmi_init_cxt(void)
{ … }
static int __ghes_sdei_callback(struct ghes *ghes,
enum fixed_addresses fixmap_idx)
{ … }
static int ghes_sdei_normal_callback(u32 event_num, struct pt_regs *regs,
void *arg)
{ … }
static int ghes_sdei_critical_callback(u32 event_num, struct pt_regs *regs,
void *arg)
{ … }
static int apei_sdei_register_ghes(struct ghes *ghes)
{ … }
static int apei_sdei_unregister_ghes(struct ghes *ghes)
{ … }
static int ghes_probe(struct platform_device *ghes_dev)
{ … }
static void ghes_remove(struct platform_device *ghes_dev)
{ … }
static struct platform_driver ghes_platform_driver = …;
void __init acpi_ghes_init(void)
{ … }
static struct acpi_platform_list plat_list[] = …;
struct list_head *ghes_get_devices(void)
{ … }
EXPORT_SYMBOL_GPL(…);
void ghes_register_report_chain(struct notifier_block *nb)
{ … }
EXPORT_SYMBOL_GPL(…);
void ghes_unregister_report_chain(struct notifier_block *nb)
{ … }
EXPORT_SYMBOL_GPL(…);