18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * ACPI Hardware Error Device (PNP0C33) Driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2010, Intel Corp.
68c2ecf20Sopenharmony_ci *	Author: Huang Ying <ying.huang@intel.com>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * ACPI Hardware Error Device is used to report some hardware errors
98c2ecf20Sopenharmony_ci * notified via SCI, mainly the corrected errors.
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/kernel.h>
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/init.h>
158c2ecf20Sopenharmony_ci#include <linux/acpi.h>
168c2ecf20Sopenharmony_ci#include <acpi/hed.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistatic const struct acpi_device_id acpi_hed_ids[] = {
198c2ecf20Sopenharmony_ci	{"PNP0C33", 0},
208c2ecf20Sopenharmony_ci	{"", 0},
218c2ecf20Sopenharmony_ci};
228c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, acpi_hed_ids);
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistatic acpi_handle hed_handle;
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic BLOCKING_NOTIFIER_HEAD(acpi_hed_notify_list);
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ciint register_acpi_hed_notifier(struct notifier_block *nb)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	return blocking_notifier_chain_register(&acpi_hed_notify_list, nb);
318c2ecf20Sopenharmony_ci}
328c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(register_acpi_hed_notifier);
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_civoid unregister_acpi_hed_notifier(struct notifier_block *nb)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	blocking_notifier_chain_unregister(&acpi_hed_notify_list, nb);
378c2ecf20Sopenharmony_ci}
388c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(unregister_acpi_hed_notifier);
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci/*
418c2ecf20Sopenharmony_ci * SCI to report hardware error is forwarded to the listeners of HED,
428c2ecf20Sopenharmony_ci * it is used by HEST Generic Hardware Error Source with notify type
438c2ecf20Sopenharmony_ci * SCI.
448c2ecf20Sopenharmony_ci */
458c2ecf20Sopenharmony_cistatic void acpi_hed_notify(struct acpi_device *device, u32 event)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	blocking_notifier_call_chain(&acpi_hed_notify_list, 0, NULL);
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic int acpi_hed_add(struct acpi_device *device)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	/* Only one hardware error device */
538c2ecf20Sopenharmony_ci	if (hed_handle)
548c2ecf20Sopenharmony_ci		return -EINVAL;
558c2ecf20Sopenharmony_ci	hed_handle = device->handle;
568c2ecf20Sopenharmony_ci	return 0;
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic int acpi_hed_remove(struct acpi_device *device)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	hed_handle = NULL;
628c2ecf20Sopenharmony_ci	return 0;
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic struct acpi_driver acpi_hed_driver = {
668c2ecf20Sopenharmony_ci	.name = "hardware_error_device",
678c2ecf20Sopenharmony_ci	.class = "hardware_error",
688c2ecf20Sopenharmony_ci	.ids = acpi_hed_ids,
698c2ecf20Sopenharmony_ci	.ops = {
708c2ecf20Sopenharmony_ci		.add = acpi_hed_add,
718c2ecf20Sopenharmony_ci		.remove = acpi_hed_remove,
728c2ecf20Sopenharmony_ci		.notify = acpi_hed_notify,
738c2ecf20Sopenharmony_ci	},
748c2ecf20Sopenharmony_ci};
758c2ecf20Sopenharmony_cimodule_acpi_driver(acpi_hed_driver);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ciACPI_MODULE_NAME("hed");
788c2ecf20Sopenharmony_ciMODULE_AUTHOR("Huang Ying");
798c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ACPI Hardware Error Device Driver");
808c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
81