eeh-powernv.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. /*
  2. * The file intends to implement the platform dependent EEH operations on
  3. * powernv platform. Actually, the powernv was created in order to fully
  4. * hypervisor support.
  5. *
  6. * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2013.
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. */
  13. #include <linux/atomic.h>
  14. #include <linux/delay.h>
  15. #include <linux/export.h>
  16. #include <linux/init.h>
  17. #include <linux/list.h>
  18. #include <linux/msi.h>
  19. #include <linux/of.h>
  20. #include <linux/pci.h>
  21. #include <linux/proc_fs.h>
  22. #include <linux/rbtree.h>
  23. #include <linux/sched.h>
  24. #include <linux/seq_file.h>
  25. #include <linux/spinlock.h>
  26. #include <asm/eeh.h>
  27. #include <asm/eeh_event.h>
  28. #include <asm/firmware.h>
  29. #include <asm/io.h>
  30. #include <asm/iommu.h>
  31. #include <asm/machdep.h>
  32. #include <asm/msi_bitmap.h>
  33. #include <asm/opal.h>
  34. #include <asm/ppc-pci.h>
  35. #include "powernv.h"
  36. #include "pci.h"
  37. /**
  38. * powernv_eeh_init - EEH platform dependent initialization
  39. *
  40. * EEH platform dependent initialization on powernv
  41. */
  42. static int powernv_eeh_init(void)
  43. {
  44. /* We require OPALv3 */
  45. if (!firmware_has_feature(FW_FEATURE_OPALv3)) {
  46. pr_warning("%s: OPALv3 is required !\n", __func__);
  47. return -EINVAL;
  48. }
  49. /* Set EEH probe mode */
  50. eeh_probe_mode_set(EEH_PROBE_MODE_DEV);
  51. return 0;
  52. }
  53. /**
  54. * powernv_eeh_post_init - EEH platform dependent post initialization
  55. *
  56. * EEH platform dependent post initialization on powernv. When
  57. * the function is called, the EEH PEs and devices should have
  58. * been built. If the I/O cache staff has been built, EEH is
  59. * ready to supply service.
  60. */
  61. static int powernv_eeh_post_init(void)
  62. {
  63. struct pci_controller *hose;
  64. struct pnv_phb *phb;
  65. int ret = 0;
  66. list_for_each_entry(hose, &hose_list, list_node) {
  67. phb = hose->private_data;
  68. if (phb->eeh_ops && phb->eeh_ops->post_init) {
  69. ret = phb->eeh_ops->post_init(hose);
  70. if (ret)
  71. break;
  72. }
  73. }
  74. return ret;
  75. }
  76. /**
  77. * powernv_eeh_dev_probe - Do probe on PCI device
  78. * @dev: PCI device
  79. * @flag: unused
  80. *
  81. * When EEH module is installed during system boot, all PCI devices
  82. * are checked one by one to see if it supports EEH. The function
  83. * is introduced for the purpose. By default, EEH has been enabled
  84. * on all PCI devices. That's to say, we only need do necessary
  85. * initialization on the corresponding eeh device and create PE
  86. * accordingly.
  87. *
  88. * It's notable that's unsafe to retrieve the EEH device through
  89. * the corresponding PCI device. During the PCI device hotplug, which
  90. * was possiblly triggered by EEH core, the binding between EEH device
  91. * and the PCI device isn't built yet.
  92. */
  93. static int powernv_eeh_dev_probe(struct pci_dev *dev, void *flag)
  94. {
  95. struct pci_controller *hose = pci_bus_to_host(dev->bus);
  96. struct pnv_phb *phb = hose->private_data;
  97. struct device_node *dn = pci_device_to_OF_node(dev);
  98. struct eeh_dev *edev = of_node_to_eeh_dev(dn);
  99. /*
  100. * When probing the root bridge, which doesn't have any
  101. * subordinate PCI devices. We don't have OF node for
  102. * the root bridge. So it's not reasonable to continue
  103. * the probing.
  104. */
  105. if (!dn || !edev)
  106. return 0;
  107. /* Skip for PCI-ISA bridge */
  108. if ((dev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
  109. return 0;
  110. /* Initialize eeh device */
  111. edev->class_code = dev->class;
  112. edev->mode = 0;
  113. edev->config_addr = ((dev->bus->number << 8) | dev->devfn);
  114. edev->pe_config_addr = phb->bdfn_to_pe(phb, dev->bus, dev->devfn & 0xff);
  115. /* Create PE */
  116. eeh_add_to_parent_pe(edev);
  117. /*
  118. * Enable EEH explicitly so that we will do EEH check
  119. * while accessing I/O stuff
  120. *
  121. * FIXME: Enable that for PHB3 later
  122. */
  123. if (phb->type == PNV_PHB_IODA1)
  124. eeh_subsystem_enabled = 1;
  125. /* Save memory bars */
  126. eeh_save_bars(edev);
  127. return 0;
  128. }
  129. /**
  130. * powernv_eeh_set_option - Initialize EEH or MMIO/DMA reenable
  131. * @pe: EEH PE
  132. * @option: operation to be issued
  133. *
  134. * The function is used to control the EEH functionality globally.
  135. * Currently, following options are support according to PAPR:
  136. * Enable EEH, Disable EEH, Enable MMIO and Enable DMA
  137. */
  138. static int powernv_eeh_set_option(struct eeh_pe *pe, int option)
  139. {
  140. struct pci_controller *hose = pe->phb;
  141. struct pnv_phb *phb = hose->private_data;
  142. int ret = -EEXIST;
  143. /*
  144. * What we need do is pass it down for hardware
  145. * implementation to handle it.
  146. */
  147. if (phb->eeh_ops && phb->eeh_ops->set_option)
  148. ret = phb->eeh_ops->set_option(pe, option);
  149. return ret;
  150. }
  151. /**
  152. * powernv_eeh_get_pe_addr - Retrieve PE address
  153. * @pe: EEH PE
  154. *
  155. * Retrieve the PE address according to the given tranditional
  156. * PCI BDF (Bus/Device/Function) address.
  157. */
  158. static int powernv_eeh_get_pe_addr(struct eeh_pe *pe)
  159. {
  160. return pe->addr;
  161. }
  162. /**
  163. * powernv_eeh_get_state - Retrieve PE state
  164. * @pe: EEH PE
  165. * @delay: delay while PE state is temporarily unavailable
  166. *
  167. * Retrieve the state of the specified PE. For IODA-compitable
  168. * platform, it should be retrieved from IODA table. Therefore,
  169. * we prefer passing down to hardware implementation to handle
  170. * it.
  171. */
  172. static int powernv_eeh_get_state(struct eeh_pe *pe, int *delay)
  173. {
  174. struct pci_controller *hose = pe->phb;
  175. struct pnv_phb *phb = hose->private_data;
  176. int ret = EEH_STATE_NOT_SUPPORT;
  177. if (phb->eeh_ops && phb->eeh_ops->get_state) {
  178. ret = phb->eeh_ops->get_state(pe);
  179. /*
  180. * If the PE state is temporarily unavailable,
  181. * to inform the EEH core delay for default
  182. * period (1 second)
  183. */
  184. if (delay) {
  185. *delay = 0;
  186. if (ret & EEH_STATE_UNAVAILABLE)
  187. *delay = 1000;
  188. }
  189. }
  190. return ret;
  191. }
  192. /**
  193. * powernv_eeh_reset - Reset the specified PE
  194. * @pe: EEH PE
  195. * @option: reset option
  196. *
  197. * Reset the specified PE
  198. */
  199. static int powernv_eeh_reset(struct eeh_pe *pe, int option)
  200. {
  201. struct pci_controller *hose = pe->phb;
  202. struct pnv_phb *phb = hose->private_data;
  203. int ret = -EEXIST;
  204. if (phb->eeh_ops && phb->eeh_ops->reset)
  205. ret = phb->eeh_ops->reset(pe, option);
  206. return ret;
  207. }
  208. /**
  209. * powernv_eeh_wait_state - Wait for PE state
  210. * @pe: EEH PE
  211. * @max_wait: maximal period in microsecond
  212. *
  213. * Wait for the state of associated PE. It might take some time
  214. * to retrieve the PE's state.
  215. */
  216. static int powernv_eeh_wait_state(struct eeh_pe *pe, int max_wait)
  217. {
  218. int ret;
  219. int mwait;
  220. while (1) {
  221. ret = powernv_eeh_get_state(pe, &mwait);
  222. /*
  223. * If the PE's state is temporarily unavailable,
  224. * we have to wait for the specified time. Otherwise,
  225. * the PE's state will be returned immediately.
  226. */
  227. if (ret != EEH_STATE_UNAVAILABLE)
  228. return ret;
  229. max_wait -= mwait;
  230. if (max_wait <= 0) {
  231. pr_warning("%s: Timeout getting PE#%x's state (%d)\n",
  232. __func__, pe->addr, max_wait);
  233. return EEH_STATE_NOT_SUPPORT;
  234. }
  235. msleep(mwait);
  236. }
  237. return EEH_STATE_NOT_SUPPORT;
  238. }
  239. /**
  240. * powernv_eeh_get_log - Retrieve error log
  241. * @pe: EEH PE
  242. * @severity: temporary or permanent error log
  243. * @drv_log: driver log to be combined with retrieved error log
  244. * @len: length of driver log
  245. *
  246. * Retrieve the temporary or permanent error from the PE.
  247. */
  248. static int powernv_eeh_get_log(struct eeh_pe *pe, int severity,
  249. char *drv_log, unsigned long len)
  250. {
  251. struct pci_controller *hose = pe->phb;
  252. struct pnv_phb *phb = hose->private_data;
  253. int ret = -EEXIST;
  254. if (phb->eeh_ops && phb->eeh_ops->get_log)
  255. ret = phb->eeh_ops->get_log(pe, severity, drv_log, len);
  256. return ret;
  257. }
  258. /**
  259. * powernv_eeh_configure_bridge - Configure PCI bridges in the indicated PE
  260. * @pe: EEH PE
  261. *
  262. * The function will be called to reconfigure the bridges included
  263. * in the specified PE so that the mulfunctional PE would be recovered
  264. * again.
  265. */
  266. static int powernv_eeh_configure_bridge(struct eeh_pe *pe)
  267. {
  268. struct pci_controller *hose = pe->phb;
  269. struct pnv_phb *phb = hose->private_data;
  270. int ret = 0;
  271. if (phb->eeh_ops && phb->eeh_ops->configure_bridge)
  272. ret = phb->eeh_ops->configure_bridge(pe);
  273. return ret;
  274. }
  275. /**
  276. * powernv_eeh_next_error - Retrieve next EEH error to handle
  277. * @pe: Affected PE
  278. *
  279. * Using OPAL API, to retrieve next EEH error for EEH core to handle
  280. */
  281. static int powernv_eeh_next_error(struct eeh_pe **pe)
  282. {
  283. struct pci_controller *hose;
  284. struct pnv_phb *phb = NULL;
  285. list_for_each_entry(hose, &hose_list, list_node) {
  286. phb = hose->private_data;
  287. break;
  288. }
  289. if (phb && phb->eeh_ops->next_error)
  290. return phb->eeh_ops->next_error(pe);
  291. return -EEXIST;
  292. }
  293. static struct eeh_ops powernv_eeh_ops = {
  294. .name = "powernv",
  295. .init = powernv_eeh_init,
  296. .post_init = powernv_eeh_post_init,
  297. .of_probe = NULL,
  298. .dev_probe = powernv_eeh_dev_probe,
  299. .set_option = powernv_eeh_set_option,
  300. .get_pe_addr = powernv_eeh_get_pe_addr,
  301. .get_state = powernv_eeh_get_state,
  302. .reset = powernv_eeh_reset,
  303. .wait_state = powernv_eeh_wait_state,
  304. .get_log = powernv_eeh_get_log,
  305. .configure_bridge = powernv_eeh_configure_bridge,
  306. .read_config = pnv_pci_cfg_read,
  307. .write_config = pnv_pci_cfg_write,
  308. .next_error = powernv_eeh_next_error
  309. };
  310. /**
  311. * eeh_powernv_init - Register platform dependent EEH operations
  312. *
  313. * EEH initialization on powernv platform. This function should be
  314. * called before any EEH related functions.
  315. */
  316. static int __init eeh_powernv_init(void)
  317. {
  318. int ret = -EINVAL;
  319. if (!machine_is(powernv))
  320. return ret;
  321. ret = eeh_ops_register(&powernv_eeh_ops);
  322. if (!ret)
  323. pr_info("EEH: PowerNV platform initialized\n");
  324. else
  325. pr_info("EEH: Failed to initialize PowerNV platform (%d)\n", ret);
  326. return ret;
  327. }
  328. early_initcall(eeh_powernv_init);