hest.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /*
  2. * APEI Hardware Error Souce Table support
  3. *
  4. * HEST describes error sources in detail; communicates operational
  5. * parameters (i.e. severity levels, masking bits, and threshold
  6. * values) to Linux as necessary. It also allows the BIOS to report
  7. * non-standard error sources to Linux (for example, chipset-specific
  8. * error registers).
  9. *
  10. * For more information about HEST, please refer to ACPI Specification
  11. * version 4.0, section 17.3.2.
  12. *
  13. * Copyright 2009 Intel Corp.
  14. * Author: Huang Ying <ying.huang@intel.com>
  15. *
  16. * This program is free software; you can redistribute it and/or
  17. * modify it under the terms of the GNU General Public License version
  18. * 2 as published by the Free Software Foundation;
  19. *
  20. * This program is distributed in the hope that it will be useful,
  21. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23. * GNU General Public License for more details.
  24. *
  25. * You should have received a copy of the GNU General Public License
  26. * along with this program; if not, write to the Free Software
  27. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  28. */
  29. #include <linux/kernel.h>
  30. #include <linux/module.h>
  31. #include <linux/init.h>
  32. #include <linux/acpi.h>
  33. #include <linux/kdebug.h>
  34. #include <linux/highmem.h>
  35. #include <linux/io.h>
  36. #include <acpi/apei.h>
  37. #include "apei-internal.h"
  38. #define HEST_PFX "HEST: "
  39. int hest_disable;
  40. EXPORT_SYMBOL_GPL(hest_disable);
  41. /* HEST table parsing */
  42. static struct acpi_table_hest *hest_tab;
  43. static int hest_void_parse(struct acpi_hest_header *hest_hdr, void *data)
  44. {
  45. return 0;
  46. }
  47. static int hest_esrc_len_tab[ACPI_HEST_TYPE_RESERVED] = {
  48. [ACPI_HEST_TYPE_IA32_CHECK] = -1, /* need further calculation */
  49. [ACPI_HEST_TYPE_IA32_CORRECTED_CHECK] = -1,
  50. [ACPI_HEST_TYPE_IA32_NMI] = sizeof(struct acpi_hest_ia_nmi),
  51. [ACPI_HEST_TYPE_AER_ROOT_PORT] = sizeof(struct acpi_hest_aer_root),
  52. [ACPI_HEST_TYPE_AER_ENDPOINT] = sizeof(struct acpi_hest_aer),
  53. [ACPI_HEST_TYPE_AER_BRIDGE] = sizeof(struct acpi_hest_aer_bridge),
  54. [ACPI_HEST_TYPE_GENERIC_ERROR] = sizeof(struct acpi_hest_generic),
  55. };
  56. static int hest_esrc_len(struct acpi_hest_header *hest_hdr)
  57. {
  58. u16 hest_type = hest_hdr->type;
  59. int len;
  60. if (hest_type >= ACPI_HEST_TYPE_RESERVED)
  61. return 0;
  62. len = hest_esrc_len_tab[hest_type];
  63. if (hest_type == ACPI_HEST_TYPE_IA32_CORRECTED_CHECK) {
  64. struct acpi_hest_ia_corrected *cmc;
  65. cmc = (struct acpi_hest_ia_corrected *)hest_hdr;
  66. len = sizeof(*cmc) + cmc->num_hardware_banks *
  67. sizeof(struct acpi_hest_ia_error_bank);
  68. } else if (hest_type == ACPI_HEST_TYPE_IA32_CHECK) {
  69. struct acpi_hest_ia_machine_check *mc;
  70. mc = (struct acpi_hest_ia_machine_check *)hest_hdr;
  71. len = sizeof(*mc) + mc->num_hardware_banks *
  72. sizeof(struct acpi_hest_ia_error_bank);
  73. }
  74. BUG_ON(len == -1);
  75. return len;
  76. };
  77. int apei_hest_parse(apei_hest_func_t func, void *data)
  78. {
  79. struct acpi_hest_header *hest_hdr;
  80. int i, rc, len;
  81. if (hest_disable)
  82. return -EINVAL;
  83. hest_hdr = (struct acpi_hest_header *)(hest_tab + 1);
  84. for (i = 0; i < hest_tab->error_source_count; i++) {
  85. len = hest_esrc_len(hest_hdr);
  86. if (!len) {
  87. pr_warning(FW_WARN HEST_PFX
  88. "Unknown or unused hardware error source "
  89. "type: %d for hardware error source: %d.\n",
  90. hest_hdr->type, hest_hdr->source_id);
  91. return -EINVAL;
  92. }
  93. if ((void *)hest_hdr + len >
  94. (void *)hest_tab + hest_tab->header.length) {
  95. pr_warning(FW_BUG HEST_PFX
  96. "Table contents overflow for hardware error source: %d.\n",
  97. hest_hdr->source_id);
  98. return -EINVAL;
  99. }
  100. rc = func(hest_hdr, data);
  101. if (rc)
  102. return rc;
  103. hest_hdr = (void *)hest_hdr + len;
  104. }
  105. return 0;
  106. }
  107. EXPORT_SYMBOL_GPL(apei_hest_parse);
  108. static int __init setup_hest_disable(char *str)
  109. {
  110. hest_disable = 1;
  111. return 0;
  112. }
  113. __setup("hest_disable", setup_hest_disable);
  114. static int __init hest_init(void)
  115. {
  116. acpi_status status;
  117. int rc = -ENODEV;
  118. if (acpi_disabled)
  119. goto err;
  120. if (hest_disable) {
  121. pr_info(HEST_PFX "HEST tabling parsing is disabled.\n");
  122. goto err;
  123. }
  124. status = acpi_get_table(ACPI_SIG_HEST, 0,
  125. (struct acpi_table_header **)&hest_tab);
  126. if (status == AE_NOT_FOUND) {
  127. pr_info(HEST_PFX "Table is not found!\n");
  128. goto err;
  129. } else if (ACPI_FAILURE(status)) {
  130. const char *msg = acpi_format_exception(status);
  131. pr_err(HEST_PFX "Failed to get table, %s\n", msg);
  132. rc = -EINVAL;
  133. goto err;
  134. }
  135. rc = apei_hest_parse(hest_void_parse, NULL);
  136. if (rc)
  137. goto err;
  138. pr_info(HEST_PFX "HEST table parsing is initialized.\n");
  139. return 0;
  140. err:
  141. hest_disable = 1;
  142. return rc;
  143. }
  144. subsys_initcall(hest_init);