hed.c 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * ACPI Hardware Error Device (PNP0C33) Driver
  4. *
  5. * Copyright (C) 2010, Intel Corp.
  6. * Author: Huang Ying <ying.huang@intel.com>
  7. *
  8. * ACPI Hardware Error Device is used to report some hardware errors
  9. * notified via SCI, mainly the corrected errors.
  10. */
  11. #include <linux/kernel.h>
  12. #include <linux/module.h>
  13. #include <linux/init.h>
  14. #include <linux/acpi.h>
  15. #include <linux/platform_device.h>
  16. #include <acpi/hed.h>
  17. static const struct acpi_device_id acpi_hed_ids[] = {
  18. {"PNP0C33", 0},
  19. {"", 0},
  20. };
  21. MODULE_DEVICE_TABLE(acpi, acpi_hed_ids);
  22. static acpi_handle hed_handle;
  23. static BLOCKING_NOTIFIER_HEAD(acpi_hed_notify_list);
  24. int register_acpi_hed_notifier(struct notifier_block *nb)
  25. {
  26. return blocking_notifier_chain_register(&acpi_hed_notify_list, nb);
  27. }
  28. EXPORT_SYMBOL_GPL(register_acpi_hed_notifier);
  29. void unregister_acpi_hed_notifier(struct notifier_block *nb)
  30. {
  31. blocking_notifier_chain_unregister(&acpi_hed_notify_list, nb);
  32. }
  33. EXPORT_SYMBOL_GPL(unregister_acpi_hed_notifier);
  34. /*
  35. * SCI to report hardware error is forwarded to the listeners of HED,
  36. * it is used by HEST Generic Hardware Error Source with notify type
  37. * SCI.
  38. */
  39. static void acpi_hed_notify(acpi_handle handle, u32 event, void *data)
  40. {
  41. blocking_notifier_call_chain(&acpi_hed_notify_list, 0, NULL);
  42. }
  43. static int acpi_hed_probe(struct platform_device *pdev)
  44. {
  45. struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
  46. int err;
  47. /* Only one hardware error device */
  48. if (hed_handle)
  49. return -EINVAL;
  50. hed_handle = device->handle;
  51. err = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY,
  52. acpi_hed_notify, device);
  53. if (err)
  54. hed_handle = NULL;
  55. return err;
  56. }
  57. static void acpi_hed_remove(struct platform_device *pdev)
  58. {
  59. struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
  60. acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY,
  61. acpi_hed_notify);
  62. hed_handle = NULL;
  63. }
  64. static struct platform_driver acpi_hed_driver = {
  65. .probe = acpi_hed_probe,
  66. .remove = acpi_hed_remove,
  67. .driver = {
  68. .name = "acpi-hardware-error-device",
  69. .acpi_match_table = acpi_hed_ids,
  70. },
  71. };
  72. static int __init acpi_hed_driver_init(void)
  73. {
  74. return platform_driver_register(&acpi_hed_driver);
  75. }
  76. subsys_initcall(acpi_hed_driver_init);
  77. MODULE_AUTHOR("Huang Ying");
  78. MODULE_DESCRIPTION("ACPI Hardware Error Device Driver");
  79. MODULE_LICENSE("GPL");