ghes.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  1. /*
  2. * APEI Generic Hardware Error Source support
  3. *
  4. * Generic Hardware Error Source provides a way to report platform
  5. * hardware errors (such as that from chipset). It works in so called
  6. * "Firmware First" mode, that is, hardware errors are reported to
  7. * firmware firstly, then reported to Linux by firmware. This way,
  8. * some non-standard hardware error registers or non-standard hardware
  9. * link can be checked by firmware to produce more hardware error
  10. * information for Linux.
  11. *
  12. * For more information about Generic Hardware Error Source, please
  13. * refer to ACPI Specification version 4.0, section 17.3.2.6
  14. *
  15. * Copyright 2010 Intel Corp.
  16. * Author: Huang Ying <ying.huang@intel.com>
  17. *
  18. * This program is free software; you can redistribute it and/or
  19. * modify it under the terms of the GNU General Public License version
  20. * 2 as published by the Free Software Foundation;
  21. *
  22. * This program is distributed in the hope that it will be useful,
  23. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  25. * GNU General Public License for more details.
  26. *
  27. * You should have received a copy of the GNU General Public License
  28. * along with this program; if not, write to the Free Software
  29. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  30. */
  31. #include <linux/kernel.h>
  32. #include <linux/module.h>
  33. #include <linux/init.h>
  34. #include <linux/acpi.h>
  35. #include <linux/io.h>
  36. #include <linux/interrupt.h>
  37. #include <linux/timer.h>
  38. #include <linux/cper.h>
  39. #include <linux/kdebug.h>
  40. #include <linux/platform_device.h>
  41. #include <linux/mutex.h>
  42. #include <linux/ratelimit.h>
  43. #include <linux/vmalloc.h>
  44. #include <acpi/apei.h>
  45. #include <acpi/atomicio.h>
  46. #include <acpi/hed.h>
  47. #include <asm/mce.h>
  48. #include <asm/tlbflush.h>
  49. #include "apei-internal.h"
  50. #define GHES_PFX "GHES: "
  51. #define GHES_ESTATUS_MAX_SIZE 65536
  52. /*
  53. * One struct ghes is created for each generic hardware error source.
  54. * It provides the context for APEI hardware error timer/IRQ/SCI/NMI
  55. * handler.
  56. *
  57. * estatus: memory buffer for error status block, allocated during
  58. * HEST parsing.
  59. */
  60. #define GHES_TO_CLEAR 0x0001
  61. #define GHES_EXITING 0x0002
  62. struct ghes {
  63. struct acpi_hest_generic *generic;
  64. struct acpi_hest_generic_status *estatus;
  65. u64 buffer_paddr;
  66. unsigned long flags;
  67. union {
  68. struct list_head list;
  69. struct timer_list timer;
  70. unsigned int irq;
  71. };
  72. };
  73. int ghes_disable;
  74. module_param_named(disable, ghes_disable, bool, 0);
  75. static int ghes_panic_timeout __read_mostly = 30;
  76. /*
  77. * All error sources notified with SCI shares one notifier function,
  78. * so they need to be linked and checked one by one. This is applied
  79. * to NMI too.
  80. *
  81. * RCU is used for these lists, so ghes_list_mutex is only used for
  82. * list changing, not for traversing.
  83. */
  84. static LIST_HEAD(ghes_sci);
  85. static LIST_HEAD(ghes_nmi);
  86. static DEFINE_MUTEX(ghes_list_mutex);
  87. /*
  88. * NMI may be triggered on any CPU, so ghes_nmi_lock is used for
  89. * mutual exclusion.
  90. */
  91. static DEFINE_RAW_SPINLOCK(ghes_nmi_lock);
  92. /*
  93. * Because the memory area used to transfer hardware error information
  94. * from BIOS to Linux can be determined only in NMI, IRQ or timer
  95. * handler, but general ioremap can not be used in atomic context, so
  96. * a special version of atomic ioremap is implemented for that.
  97. */
  98. /*
  99. * Two virtual pages are used, one for NMI context, the other for
  100. * IRQ/PROCESS context
  101. */
  102. #define GHES_IOREMAP_PAGES 2
  103. #define GHES_IOREMAP_NMI_PAGE(base) (base)
  104. #define GHES_IOREMAP_IRQ_PAGE(base) ((base) + PAGE_SIZE)
  105. /* virtual memory area for atomic ioremap */
  106. static struct vm_struct *ghes_ioremap_area;
  107. /*
  108. * These 2 spinlock is used to prevent atomic ioremap virtual memory
  109. * area from being mapped simultaneously.
  110. */
  111. static DEFINE_RAW_SPINLOCK(ghes_ioremap_lock_nmi);
  112. static DEFINE_SPINLOCK(ghes_ioremap_lock_irq);
  113. static int ghes_ioremap_init(void)
  114. {
  115. ghes_ioremap_area = __get_vm_area(PAGE_SIZE * GHES_IOREMAP_PAGES,
  116. VM_IOREMAP, VMALLOC_START, VMALLOC_END);
  117. if (!ghes_ioremap_area) {
  118. pr_err(GHES_PFX "Failed to allocate virtual memory area for atomic ioremap.\n");
  119. return -ENOMEM;
  120. }
  121. return 0;
  122. }
  123. static void ghes_ioremap_exit(void)
  124. {
  125. free_vm_area(ghes_ioremap_area);
  126. }
  127. static void __iomem *ghes_ioremap_pfn_nmi(u64 pfn)
  128. {
  129. unsigned long vaddr;
  130. vaddr = (unsigned long)GHES_IOREMAP_NMI_PAGE(ghes_ioremap_area->addr);
  131. ioremap_page_range(vaddr, vaddr + PAGE_SIZE,
  132. pfn << PAGE_SHIFT, PAGE_KERNEL);
  133. return (void __iomem *)vaddr;
  134. }
  135. static void __iomem *ghes_ioremap_pfn_irq(u64 pfn)
  136. {
  137. unsigned long vaddr;
  138. vaddr = (unsigned long)GHES_IOREMAP_IRQ_PAGE(ghes_ioremap_area->addr);
  139. ioremap_page_range(vaddr, vaddr + PAGE_SIZE,
  140. pfn << PAGE_SHIFT, PAGE_KERNEL);
  141. return (void __iomem *)vaddr;
  142. }
  143. static void ghes_iounmap_nmi(void __iomem *vaddr_ptr)
  144. {
  145. unsigned long vaddr = (unsigned long __force)vaddr_ptr;
  146. void *base = ghes_ioremap_area->addr;
  147. BUG_ON(vaddr != (unsigned long)GHES_IOREMAP_NMI_PAGE(base));
  148. unmap_kernel_range_noflush(vaddr, PAGE_SIZE);
  149. __flush_tlb_one(vaddr);
  150. }
  151. static void ghes_iounmap_irq(void __iomem *vaddr_ptr)
  152. {
  153. unsigned long vaddr = (unsigned long __force)vaddr_ptr;
  154. void *base = ghes_ioremap_area->addr;
  155. BUG_ON(vaddr != (unsigned long)GHES_IOREMAP_IRQ_PAGE(base));
  156. unmap_kernel_range_noflush(vaddr, PAGE_SIZE);
  157. __flush_tlb_one(vaddr);
  158. }
  159. static struct ghes *ghes_new(struct acpi_hest_generic *generic)
  160. {
  161. struct ghes *ghes;
  162. unsigned int error_block_length;
  163. int rc;
  164. ghes = kzalloc(sizeof(*ghes), GFP_KERNEL);
  165. if (!ghes)
  166. return ERR_PTR(-ENOMEM);
  167. ghes->generic = generic;
  168. rc = acpi_pre_map_gar(&generic->error_status_address);
  169. if (rc)
  170. goto err_free;
  171. error_block_length = generic->error_block_length;
  172. if (error_block_length > GHES_ESTATUS_MAX_SIZE) {
  173. pr_warning(FW_WARN GHES_PFX
  174. "Error status block length is too long: %u for "
  175. "generic hardware error source: %d.\n",
  176. error_block_length, generic->header.source_id);
  177. error_block_length = GHES_ESTATUS_MAX_SIZE;
  178. }
  179. ghes->estatus = kmalloc(error_block_length, GFP_KERNEL);
  180. if (!ghes->estatus) {
  181. rc = -ENOMEM;
  182. goto err_unmap;
  183. }
  184. return ghes;
  185. err_unmap:
  186. acpi_post_unmap_gar(&generic->error_status_address);
  187. err_free:
  188. kfree(ghes);
  189. return ERR_PTR(rc);
  190. }
  191. static void ghes_fini(struct ghes *ghes)
  192. {
  193. kfree(ghes->estatus);
  194. acpi_post_unmap_gar(&ghes->generic->error_status_address);
  195. }
  196. enum {
  197. GHES_SEV_NO = 0x0,
  198. GHES_SEV_CORRECTED = 0x1,
  199. GHES_SEV_RECOVERABLE = 0x2,
  200. GHES_SEV_PANIC = 0x3,
  201. };
  202. static inline int ghes_severity(int severity)
  203. {
  204. switch (severity) {
  205. case CPER_SEV_INFORMATIONAL:
  206. return GHES_SEV_NO;
  207. case CPER_SEV_CORRECTED:
  208. return GHES_SEV_CORRECTED;
  209. case CPER_SEV_RECOVERABLE:
  210. return GHES_SEV_RECOVERABLE;
  211. case CPER_SEV_FATAL:
  212. return GHES_SEV_PANIC;
  213. default:
  214. /* Unknown, go panic */
  215. return GHES_SEV_PANIC;
  216. }
  217. }
  218. static void ghes_copy_tofrom_phys(void *buffer, u64 paddr, u32 len,
  219. int from_phys)
  220. {
  221. void __iomem *vaddr;
  222. unsigned long flags = 0;
  223. int in_nmi = in_nmi();
  224. u64 offset;
  225. u32 trunk;
  226. while (len > 0) {
  227. offset = paddr - (paddr & PAGE_MASK);
  228. if (in_nmi) {
  229. raw_spin_lock(&ghes_ioremap_lock_nmi);
  230. vaddr = ghes_ioremap_pfn_nmi(paddr >> PAGE_SHIFT);
  231. } else {
  232. spin_lock_irqsave(&ghes_ioremap_lock_irq, flags);
  233. vaddr = ghes_ioremap_pfn_irq(paddr >> PAGE_SHIFT);
  234. }
  235. trunk = PAGE_SIZE - offset;
  236. trunk = min(trunk, len);
  237. if (from_phys)
  238. memcpy_fromio(buffer, vaddr + offset, trunk);
  239. else
  240. memcpy_toio(vaddr + offset, buffer, trunk);
  241. len -= trunk;
  242. paddr += trunk;
  243. buffer += trunk;
  244. if (in_nmi) {
  245. ghes_iounmap_nmi(vaddr);
  246. raw_spin_unlock(&ghes_ioremap_lock_nmi);
  247. } else {
  248. ghes_iounmap_irq(vaddr);
  249. spin_unlock_irqrestore(&ghes_ioremap_lock_irq, flags);
  250. }
  251. }
  252. }
  253. static int ghes_read_estatus(struct ghes *ghes, int silent)
  254. {
  255. struct acpi_hest_generic *g = ghes->generic;
  256. u64 buf_paddr;
  257. u32 len;
  258. int rc;
  259. rc = acpi_atomic_read(&buf_paddr, &g->error_status_address);
  260. if (rc) {
  261. if (!silent && printk_ratelimit())
  262. pr_warning(FW_WARN GHES_PFX
  263. "Failed to read error status block address for hardware error source: %d.\n",
  264. g->header.source_id);
  265. return -EIO;
  266. }
  267. if (!buf_paddr)
  268. return -ENOENT;
  269. ghes_copy_tofrom_phys(ghes->estatus, buf_paddr,
  270. sizeof(*ghes->estatus), 1);
  271. if (!ghes->estatus->block_status)
  272. return -ENOENT;
  273. ghes->buffer_paddr = buf_paddr;
  274. ghes->flags |= GHES_TO_CLEAR;
  275. rc = -EIO;
  276. len = apei_estatus_len(ghes->estatus);
  277. if (len < sizeof(*ghes->estatus))
  278. goto err_read_block;
  279. if (len > ghes->generic->error_block_length)
  280. goto err_read_block;
  281. if (apei_estatus_check_header(ghes->estatus))
  282. goto err_read_block;
  283. ghes_copy_tofrom_phys(ghes->estatus + 1,
  284. buf_paddr + sizeof(*ghes->estatus),
  285. len - sizeof(*ghes->estatus), 1);
  286. if (apei_estatus_check(ghes->estatus))
  287. goto err_read_block;
  288. rc = 0;
  289. err_read_block:
  290. if (rc && !silent && printk_ratelimit())
  291. pr_warning(FW_WARN GHES_PFX
  292. "Failed to read error status block!\n");
  293. return rc;
  294. }
  295. static void ghes_clear_estatus(struct ghes *ghes)
  296. {
  297. ghes->estatus->block_status = 0;
  298. if (!(ghes->flags & GHES_TO_CLEAR))
  299. return;
  300. ghes_copy_tofrom_phys(ghes->estatus, ghes->buffer_paddr,
  301. sizeof(ghes->estatus->block_status), 0);
  302. ghes->flags &= ~GHES_TO_CLEAR;
  303. }
  304. static void ghes_do_proc(struct ghes *ghes)
  305. {
  306. int sev, processed = 0;
  307. struct acpi_hest_generic_data *gdata;
  308. sev = ghes_severity(ghes->estatus->error_severity);
  309. apei_estatus_for_each_section(ghes->estatus, gdata) {
  310. #ifdef CONFIG_X86_MCE
  311. if (!uuid_le_cmp(*(uuid_le *)gdata->section_type,
  312. CPER_SEC_PLATFORM_MEM)) {
  313. apei_mce_report_mem_error(
  314. sev == GHES_SEV_CORRECTED,
  315. (struct cper_sec_mem_err *)(gdata+1));
  316. processed = 1;
  317. }
  318. #endif
  319. }
  320. }
  321. static void __ghes_print_estatus(const char *pfx, struct ghes *ghes)
  322. {
  323. if (pfx == NULL) {
  324. if (ghes_severity(ghes->estatus->error_severity) <=
  325. GHES_SEV_CORRECTED)
  326. pfx = KERN_WARNING HW_ERR;
  327. else
  328. pfx = KERN_ERR HW_ERR;
  329. }
  330. printk("%s""Hardware error from APEI Generic Hardware Error Source: %d\n",
  331. pfx, ghes->generic->header.source_id);
  332. apei_estatus_print(pfx, ghes->estatus);
  333. }
  334. static void ghes_print_estatus(const char *pfx, struct ghes *ghes)
  335. {
  336. /* Not more than 2 messages every 5 seconds */
  337. static DEFINE_RATELIMIT_STATE(ratelimit, 5*HZ, 2);
  338. if (__ratelimit(&ratelimit))
  339. __ghes_print_estatus(pfx, ghes);
  340. }
  341. static int ghes_proc(struct ghes *ghes)
  342. {
  343. int rc;
  344. rc = ghes_read_estatus(ghes, 0);
  345. if (rc)
  346. goto out;
  347. ghes_print_estatus(NULL, ghes);
  348. ghes_do_proc(ghes);
  349. out:
  350. ghes_clear_estatus(ghes);
  351. return 0;
  352. }
  353. static void ghes_add_timer(struct ghes *ghes)
  354. {
  355. struct acpi_hest_generic *g = ghes->generic;
  356. unsigned long expire;
  357. if (!g->notify.poll_interval) {
  358. pr_warning(FW_WARN GHES_PFX "Poll interval is 0 for generic hardware error source: %d, disabled.\n",
  359. g->header.source_id);
  360. return;
  361. }
  362. expire = jiffies + msecs_to_jiffies(g->notify.poll_interval);
  363. ghes->timer.expires = round_jiffies_relative(expire);
  364. add_timer(&ghes->timer);
  365. }
  366. static void ghes_poll_func(unsigned long data)
  367. {
  368. struct ghes *ghes = (void *)data;
  369. ghes_proc(ghes);
  370. if (!(ghes->flags & GHES_EXITING))
  371. ghes_add_timer(ghes);
  372. }
  373. static irqreturn_t ghes_irq_func(int irq, void *data)
  374. {
  375. struct ghes *ghes = data;
  376. int rc;
  377. rc = ghes_proc(ghes);
  378. if (rc)
  379. return IRQ_NONE;
  380. return IRQ_HANDLED;
  381. }
  382. static int ghes_notify_sci(struct notifier_block *this,
  383. unsigned long event, void *data)
  384. {
  385. struct ghes *ghes;
  386. int ret = NOTIFY_DONE;
  387. rcu_read_lock();
  388. list_for_each_entry_rcu(ghes, &ghes_sci, list) {
  389. if (!ghes_proc(ghes))
  390. ret = NOTIFY_OK;
  391. }
  392. rcu_read_unlock();
  393. return ret;
  394. }
  395. static int ghes_notify_nmi(struct notifier_block *this,
  396. unsigned long cmd, void *data)
  397. {
  398. struct ghes *ghes, *ghes_global = NULL;
  399. int sev, sev_global = -1;
  400. int ret = NOTIFY_DONE;
  401. if (cmd != DIE_NMI)
  402. return ret;
  403. raw_spin_lock(&ghes_nmi_lock);
  404. list_for_each_entry_rcu(ghes, &ghes_nmi, list) {
  405. if (ghes_read_estatus(ghes, 1)) {
  406. ghes_clear_estatus(ghes);
  407. continue;
  408. }
  409. sev = ghes_severity(ghes->estatus->error_severity);
  410. if (sev > sev_global) {
  411. sev_global = sev;
  412. ghes_global = ghes;
  413. }
  414. ret = NOTIFY_STOP;
  415. }
  416. if (ret == NOTIFY_DONE)
  417. goto out;
  418. if (sev_global >= GHES_SEV_PANIC) {
  419. oops_begin();
  420. __ghes_print_estatus(KERN_EMERG HW_ERR, ghes_global);
  421. /* reboot to log the error! */
  422. if (panic_timeout == 0)
  423. panic_timeout = ghes_panic_timeout;
  424. panic("Fatal hardware error!");
  425. }
  426. list_for_each_entry_rcu(ghes, &ghes_nmi, list) {
  427. if (!(ghes->flags & GHES_TO_CLEAR))
  428. continue;
  429. /* Do not print estatus because printk is not NMI safe */
  430. ghes_do_proc(ghes);
  431. ghes_clear_estatus(ghes);
  432. }
  433. out:
  434. raw_spin_unlock(&ghes_nmi_lock);
  435. return ret;
  436. }
  437. static struct notifier_block ghes_notifier_sci = {
  438. .notifier_call = ghes_notify_sci,
  439. };
  440. static struct notifier_block ghes_notifier_nmi = {
  441. .notifier_call = ghes_notify_nmi,
  442. };
  443. static int __devinit ghes_probe(struct platform_device *ghes_dev)
  444. {
  445. struct acpi_hest_generic *generic;
  446. struct ghes *ghes = NULL;
  447. int rc = -EINVAL;
  448. generic = *(struct acpi_hest_generic **)ghes_dev->dev.platform_data;
  449. if (!generic->enabled)
  450. return -ENODEV;
  451. switch (generic->notify.type) {
  452. case ACPI_HEST_NOTIFY_POLLED:
  453. case ACPI_HEST_NOTIFY_EXTERNAL:
  454. case ACPI_HEST_NOTIFY_SCI:
  455. case ACPI_HEST_NOTIFY_NMI:
  456. break;
  457. case ACPI_HEST_NOTIFY_LOCAL:
  458. pr_warning(GHES_PFX "Generic hardware error source: %d notified via local interrupt is not supported!\n",
  459. generic->header.source_id);
  460. goto err;
  461. default:
  462. pr_warning(FW_WARN GHES_PFX "Unknown notification type: %u for generic hardware error source: %d\n",
  463. generic->notify.type, generic->header.source_id);
  464. goto err;
  465. }
  466. rc = -EIO;
  467. if (generic->error_block_length <
  468. sizeof(struct acpi_hest_generic_status)) {
  469. pr_warning(FW_BUG GHES_PFX "Invalid error block length: %u for generic hardware error source: %d\n",
  470. generic->error_block_length,
  471. generic->header.source_id);
  472. goto err;
  473. }
  474. ghes = ghes_new(generic);
  475. if (IS_ERR(ghes)) {
  476. rc = PTR_ERR(ghes);
  477. ghes = NULL;
  478. goto err;
  479. }
  480. switch (generic->notify.type) {
  481. case ACPI_HEST_NOTIFY_POLLED:
  482. ghes->timer.function = ghes_poll_func;
  483. ghes->timer.data = (unsigned long)ghes;
  484. init_timer_deferrable(&ghes->timer);
  485. ghes_add_timer(ghes);
  486. break;
  487. case ACPI_HEST_NOTIFY_EXTERNAL:
  488. /* External interrupt vector is GSI */
  489. if (acpi_gsi_to_irq(generic->notify.vector, &ghes->irq)) {
  490. pr_err(GHES_PFX "Failed to map GSI to IRQ for generic hardware error source: %d\n",
  491. generic->header.source_id);
  492. goto err;
  493. }
  494. if (request_irq(ghes->irq, ghes_irq_func,
  495. 0, "GHES IRQ", ghes)) {
  496. pr_err(GHES_PFX "Failed to register IRQ for generic hardware error source: %d\n",
  497. generic->header.source_id);
  498. goto err;
  499. }
  500. break;
  501. case ACPI_HEST_NOTIFY_SCI:
  502. mutex_lock(&ghes_list_mutex);
  503. if (list_empty(&ghes_sci))
  504. register_acpi_hed_notifier(&ghes_notifier_sci);
  505. list_add_rcu(&ghes->list, &ghes_sci);
  506. mutex_unlock(&ghes_list_mutex);
  507. break;
  508. case ACPI_HEST_NOTIFY_NMI:
  509. mutex_lock(&ghes_list_mutex);
  510. if (list_empty(&ghes_nmi))
  511. register_die_notifier(&ghes_notifier_nmi);
  512. list_add_rcu(&ghes->list, &ghes_nmi);
  513. mutex_unlock(&ghes_list_mutex);
  514. break;
  515. default:
  516. BUG();
  517. }
  518. platform_set_drvdata(ghes_dev, ghes);
  519. return 0;
  520. err:
  521. if (ghes) {
  522. ghes_fini(ghes);
  523. kfree(ghes);
  524. }
  525. return rc;
  526. }
  527. static int __devexit ghes_remove(struct platform_device *ghes_dev)
  528. {
  529. struct ghes *ghes;
  530. struct acpi_hest_generic *generic;
  531. ghes = platform_get_drvdata(ghes_dev);
  532. generic = ghes->generic;
  533. ghes->flags |= GHES_EXITING;
  534. switch (generic->notify.type) {
  535. case ACPI_HEST_NOTIFY_POLLED:
  536. del_timer_sync(&ghes->timer);
  537. break;
  538. case ACPI_HEST_NOTIFY_EXTERNAL:
  539. free_irq(ghes->irq, ghes);
  540. break;
  541. case ACPI_HEST_NOTIFY_SCI:
  542. mutex_lock(&ghes_list_mutex);
  543. list_del_rcu(&ghes->list);
  544. if (list_empty(&ghes_sci))
  545. unregister_acpi_hed_notifier(&ghes_notifier_sci);
  546. mutex_unlock(&ghes_list_mutex);
  547. break;
  548. case ACPI_HEST_NOTIFY_NMI:
  549. mutex_lock(&ghes_list_mutex);
  550. list_del_rcu(&ghes->list);
  551. if (list_empty(&ghes_nmi))
  552. unregister_die_notifier(&ghes_notifier_nmi);
  553. mutex_unlock(&ghes_list_mutex);
  554. /*
  555. * To synchronize with NMI handler, ghes can only be
  556. * freed after NMI handler finishes.
  557. */
  558. synchronize_rcu();
  559. break;
  560. default:
  561. BUG();
  562. break;
  563. }
  564. ghes_fini(ghes);
  565. kfree(ghes);
  566. platform_set_drvdata(ghes_dev, NULL);
  567. return 0;
  568. }
  569. static struct platform_driver ghes_platform_driver = {
  570. .driver = {
  571. .name = "GHES",
  572. .owner = THIS_MODULE,
  573. },
  574. .probe = ghes_probe,
  575. .remove = ghes_remove,
  576. };
  577. static int __init ghes_init(void)
  578. {
  579. int rc;
  580. if (acpi_disabled)
  581. return -ENODEV;
  582. if (hest_disable) {
  583. pr_info(GHES_PFX "HEST is not enabled!\n");
  584. return -EINVAL;
  585. }
  586. if (ghes_disable) {
  587. pr_info(GHES_PFX "GHES is not enabled!\n");
  588. return -EINVAL;
  589. }
  590. rc = ghes_ioremap_init();
  591. if (rc)
  592. goto err;
  593. rc = platform_driver_register(&ghes_platform_driver);
  594. if (rc)
  595. goto err_ioremap_exit;
  596. return 0;
  597. err_ioremap_exit:
  598. ghes_ioremap_exit();
  599. err:
  600. return rc;
  601. }
  602. static void __exit ghes_exit(void)
  603. {
  604. platform_driver_unregister(&ghes_platform_driver);
  605. ghes_ioremap_exit();
  606. }
  607. module_init(ghes_init);
  608. module_exit(ghes_exit);
  609. MODULE_AUTHOR("Huang Ying");
  610. MODULE_DESCRIPTION("APEI Generic Hardware Error Source support");
  611. MODULE_LICENSE("GPL");
  612. MODULE_ALIAS("platform:GHES");