ghes.c 17 KB

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