PageRenderTime 25ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/drivers/pci/hotplug/rpadlpar_core.c

https://bitbucket.org/codefirex/kernel_samsung_jf
C | 472 lines | 306 code | 78 blank | 88 comment | 50 complexity | dfd577c035a29926a767dc5a121cf555 MD5 | raw file
  1. /*
  2. * Interface for Dynamic Logical Partitioning of I/O Slots on
  3. * RPA-compliant PPC64 platform.
  4. *
  5. * John Rose <johnrose@austin.ibm.com>
  6. * Linda Xie <lxie@us.ibm.com>
  7. *
  8. * October 2003
  9. *
  10. * Copyright (C) 2003 IBM.
  11. *
  12. * This program is free software; you can redistribute it and/or
  13. * modify it under the terms of the GNU General Public License
  14. * as published by the Free Software Foundation; either version
  15. * 2 of the License, or (at your option) any later version.
  16. */
  17. #undef DEBUG
  18. #include <linux/init.h>
  19. #include <linux/module.h>
  20. #include <linux/pci.h>
  21. #include <linux/string.h>
  22. #include <linux/vmalloc.h>
  23. #include <asm/pci-bridge.h>
  24. #include <linux/mutex.h>
  25. #include <asm/rtas.h>
  26. #include <asm/vio.h>
  27. #include "../pci.h"
  28. #include "rpaphp.h"
  29. #include "rpadlpar.h"
  30. static DEFINE_MUTEX(rpadlpar_mutex);
  31. #define DLPAR_MODULE_NAME "rpadlpar_io"
  32. #define NODE_TYPE_VIO 1
  33. #define NODE_TYPE_SLOT 2
  34. #define NODE_TYPE_PHB 3
  35. static struct device_node *find_vio_slot_node(char *drc_name)
  36. {
  37. struct device_node *parent = of_find_node_by_name(NULL, "vdevice");
  38. struct device_node *dn = NULL;
  39. char *name;
  40. int rc;
  41. if (!parent)
  42. return NULL;
  43. while ((dn = of_get_next_child(parent, dn))) {
  44. rc = rpaphp_get_drc_props(dn, NULL, &name, NULL, NULL);
  45. if ((rc == 0) && (!strcmp(drc_name, name)))
  46. break;
  47. }
  48. return dn;
  49. }
  50. /* Find dlpar-capable pci node that contains the specified name and type */
  51. static struct device_node *find_php_slot_pci_node(char *drc_name,
  52. char *drc_type)
  53. {
  54. struct device_node *np = NULL;
  55. char *name;
  56. char *type;
  57. int rc;
  58. while ((np = of_find_node_by_name(np, "pci"))) {
  59. rc = rpaphp_get_drc_props(np, NULL, &name, &type, NULL);
  60. if (rc == 0)
  61. if (!strcmp(drc_name, name) && !strcmp(drc_type, type))
  62. break;
  63. }
  64. return np;
  65. }
  66. static struct device_node *find_dlpar_node(char *drc_name, int *node_type)
  67. {
  68. struct device_node *dn;
  69. dn = find_php_slot_pci_node(drc_name, "SLOT");
  70. if (dn) {
  71. *node_type = NODE_TYPE_SLOT;
  72. return dn;
  73. }
  74. dn = find_php_slot_pci_node(drc_name, "PHB");
  75. if (dn) {
  76. *node_type = NODE_TYPE_PHB;
  77. return dn;
  78. }
  79. dn = find_vio_slot_node(drc_name);
  80. if (dn) {
  81. *node_type = NODE_TYPE_VIO;
  82. return dn;
  83. }
  84. return NULL;
  85. }
  86. /**
  87. * find_php_slot - return hotplug slot structure for device node
  88. * @dn: target &device_node
  89. *
  90. * This routine will return the hotplug slot structure
  91. * for a given device node. Note that built-in PCI slots
  92. * may be dlpar-able, but not hot-pluggable, so this routine
  93. * will return NULL for built-in PCI slots.
  94. */
  95. static struct slot *find_php_slot(struct device_node *dn)
  96. {
  97. struct list_head *tmp, *n;
  98. struct slot *slot;
  99. list_for_each_safe(tmp, n, &rpaphp_slot_head) {
  100. slot = list_entry(tmp, struct slot, rpaphp_slot_list);
  101. if (slot->dn == dn)
  102. return slot;
  103. }
  104. return NULL;
  105. }
  106. static struct pci_dev *dlpar_find_new_dev(struct pci_bus *parent,
  107. struct device_node *dev_dn)
  108. {
  109. struct pci_dev *tmp = NULL;
  110. struct device_node *child_dn;
  111. list_for_each_entry(tmp, &parent->devices, bus_list) {
  112. child_dn = pci_device_to_OF_node(tmp);
  113. if (child_dn == dev_dn)
  114. return tmp;
  115. }
  116. return NULL;
  117. }
  118. static void dlpar_pci_add_bus(struct device_node *dn)
  119. {
  120. struct pci_dn *pdn = PCI_DN(dn);
  121. struct pci_controller *phb = pdn->phb;
  122. struct pci_dev *dev = NULL;
  123. eeh_add_device_tree_early(dn);
  124. /* Add EADS device to PHB bus, adding new entry to bus->devices */
  125. dev = of_create_pci_dev(dn, phb->bus, pdn->devfn);
  126. if (!dev) {
  127. printk(KERN_ERR "%s: failed to create pci dev for %s\n",
  128. __func__, dn->full_name);
  129. return;
  130. }
  131. /* Scan below the new bridge */
  132. if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
  133. dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
  134. of_scan_pci_bridge(dev);
  135. /* Map IO space for child bus, which may or may not succeed */
  136. pcibios_map_io_space(dev->subordinate);
  137. /* Finish adding it : resource allocation, adding devices, etc...
  138. * Note that we need to perform the finish pass on the -parent-
  139. * bus of the EADS bridge so the bridge device itself gets
  140. * properly added
  141. */
  142. pcibios_finish_adding_to_bus(phb->bus);
  143. }
  144. static int dlpar_add_pci_slot(char *drc_name, struct device_node *dn)
  145. {
  146. struct pci_dev *dev;
  147. struct pci_controller *phb;
  148. if (pcibios_find_pci_bus(dn))
  149. return -EINVAL;
  150. /* Add pci bus */
  151. dlpar_pci_add_bus(dn);
  152. /* Confirm new bridge dev was created */
  153. phb = PCI_DN(dn)->phb;
  154. dev = dlpar_find_new_dev(phb->bus, dn);
  155. if (!dev) {
  156. printk(KERN_ERR "%s: unable to add bus %s\n", __func__,
  157. drc_name);
  158. return -EIO;
  159. }
  160. if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
  161. printk(KERN_ERR "%s: unexpected header type %d, unable to add bus %s\n",
  162. __func__, dev->hdr_type, drc_name);
  163. return -EIO;
  164. }
  165. /* Add hotplug slot */
  166. if (rpaphp_add_slot(dn)) {
  167. printk(KERN_ERR "%s: unable to add hotplug slot %s\n",
  168. __func__, drc_name);
  169. return -EIO;
  170. }
  171. return 0;
  172. }
  173. static int dlpar_remove_phb(char *drc_name, struct device_node *dn)
  174. {
  175. struct slot *slot;
  176. struct pci_dn *pdn;
  177. int rc = 0;
  178. if (!pcibios_find_pci_bus(dn))
  179. return -EINVAL;
  180. /* If pci slot is hotplugable, use hotplug to remove it */
  181. slot = find_php_slot(dn);
  182. if (slot && rpaphp_deregister_slot(slot)) {
  183. printk(KERN_ERR "%s: unable to remove hotplug slot %s\n",
  184. __func__, drc_name);
  185. return -EIO;
  186. }
  187. pdn = dn->data;
  188. BUG_ON(!pdn || !pdn->phb);
  189. rc = remove_phb_dynamic(pdn->phb);
  190. if (rc < 0)
  191. return rc;
  192. pdn->phb = NULL;
  193. return 0;
  194. }
  195. static int dlpar_add_phb(char *drc_name, struct device_node *dn)
  196. {
  197. struct pci_controller *phb;
  198. if (PCI_DN(dn) && PCI_DN(dn)->phb) {
  199. /* PHB already exists */
  200. return -EINVAL;
  201. }
  202. phb = init_phb_dynamic(dn);
  203. if (!phb)
  204. return -EIO;
  205. if (rpaphp_add_slot(dn)) {
  206. printk(KERN_ERR "%s: unable to add hotplug slot %s\n",
  207. __func__, drc_name);
  208. return -EIO;
  209. }
  210. return 0;
  211. }
  212. static int dlpar_add_vio_slot(char *drc_name, struct device_node *dn)
  213. {
  214. if (vio_find_node(dn))
  215. return -EINVAL;
  216. if (!vio_register_device_node(dn)) {
  217. printk(KERN_ERR
  218. "%s: failed to register vio node %s\n",
  219. __func__, drc_name);
  220. return -EIO;
  221. }
  222. return 0;
  223. }
  224. /**
  225. * dlpar_add_slot - DLPAR add an I/O Slot
  226. * @drc_name: drc-name of newly added slot
  227. *
  228. * Make the hotplug module and the kernel aware of a newly added I/O Slot.
  229. * Return Codes:
  230. * 0 Success
  231. * -ENODEV Not a valid drc_name
  232. * -EINVAL Slot already added
  233. * -ERESTARTSYS Signalled before obtaining lock
  234. * -EIO Internal PCI Error
  235. */
  236. int dlpar_add_slot(char *drc_name)
  237. {
  238. struct device_node *dn = NULL;
  239. int node_type;
  240. int rc = -EIO;
  241. if (mutex_lock_interruptible(&rpadlpar_mutex))
  242. return -ERESTARTSYS;
  243. /* Find newly added node */
  244. dn = find_dlpar_node(drc_name, &node_type);
  245. if (!dn) {
  246. rc = -ENODEV;
  247. goto exit;
  248. }
  249. switch (node_type) {
  250. case NODE_TYPE_VIO:
  251. rc = dlpar_add_vio_slot(drc_name, dn);
  252. break;
  253. case NODE_TYPE_SLOT:
  254. rc = dlpar_add_pci_slot(drc_name, dn);
  255. break;
  256. case NODE_TYPE_PHB:
  257. rc = dlpar_add_phb(drc_name, dn);
  258. break;
  259. }
  260. printk(KERN_INFO "%s: slot %s added\n", DLPAR_MODULE_NAME, drc_name);
  261. exit:
  262. mutex_unlock(&rpadlpar_mutex);
  263. return rc;
  264. }
  265. /**
  266. * dlpar_remove_vio_slot - DLPAR remove a virtual I/O Slot
  267. * @drc_name: drc-name of newly added slot
  268. * @dn: &device_node
  269. *
  270. * Remove the kernel and hotplug representations of an I/O Slot.
  271. * Return Codes:
  272. * 0 Success
  273. * -EINVAL Vio dev doesn't exist
  274. */
  275. static int dlpar_remove_vio_slot(char *drc_name, struct device_node *dn)
  276. {
  277. struct vio_dev *vio_dev;
  278. vio_dev = vio_find_node(dn);
  279. if (!vio_dev)
  280. return -EINVAL;
  281. vio_unregister_device(vio_dev);
  282. return 0;
  283. }
  284. /**
  285. * dlpar_remove_pci_slot - DLPAR remove a PCI I/O Slot
  286. * @drc_name: drc-name of newly added slot
  287. * @dn: &device_node
  288. *
  289. * Remove the kernel and hotplug representations of a PCI I/O Slot.
  290. * Return Codes:
  291. * 0 Success
  292. * -ENODEV Not a valid drc_name
  293. * -EIO Internal PCI Error
  294. */
  295. int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
  296. {
  297. struct pci_bus *bus;
  298. struct slot *slot;
  299. bus = pcibios_find_pci_bus(dn);
  300. if (!bus)
  301. return -EINVAL;
  302. pr_debug("PCI: Removing PCI slot below EADS bridge %s\n",
  303. bus->self ? pci_name(bus->self) : "<!PHB!>");
  304. slot = find_php_slot(dn);
  305. if (slot) {
  306. pr_debug("PCI: Removing hotplug slot for %04x:%02x...\n",
  307. pci_domain_nr(bus), bus->number);
  308. if (rpaphp_deregister_slot(slot)) {
  309. printk(KERN_ERR
  310. "%s: unable to remove hotplug slot %s\n",
  311. __func__, drc_name);
  312. return -EIO;
  313. }
  314. }
  315. /* Remove all devices below slot */
  316. pcibios_remove_pci_devices(bus);
  317. /* Unmap PCI IO space */
  318. if (pcibios_unmap_io_space(bus)) {
  319. printk(KERN_ERR "%s: failed to unmap bus range\n",
  320. __func__);
  321. return -ERANGE;
  322. }
  323. /* Remove the EADS bridge device itself */
  324. BUG_ON(!bus->self);
  325. pr_debug("PCI: Now removing bridge device %s\n", pci_name(bus->self));
  326. eeh_remove_bus_device(bus->self);
  327. pci_stop_and_remove_bus_device(bus->self);
  328. return 0;
  329. }
  330. /**
  331. * dlpar_remove_slot - DLPAR remove an I/O Slot
  332. * @drc_name: drc-name of newly added slot
  333. *
  334. * Remove the kernel and hotplug representations of an I/O Slot.
  335. * Return Codes:
  336. * 0 Success
  337. * -ENODEV Not a valid drc_name
  338. * -EINVAL Slot already removed
  339. * -ERESTARTSYS Signalled before obtaining lock
  340. * -EIO Internal Error
  341. */
  342. int dlpar_remove_slot(char *drc_name)
  343. {
  344. struct device_node *dn;
  345. int node_type;
  346. int rc = 0;
  347. if (mutex_lock_interruptible(&rpadlpar_mutex))
  348. return -ERESTARTSYS;
  349. dn = find_dlpar_node(drc_name, &node_type);
  350. if (!dn) {
  351. rc = -ENODEV;
  352. goto exit;
  353. }
  354. switch (node_type) {
  355. case NODE_TYPE_VIO:
  356. rc = dlpar_remove_vio_slot(drc_name, dn);
  357. break;
  358. case NODE_TYPE_PHB:
  359. rc = dlpar_remove_phb(drc_name, dn);
  360. break;
  361. case NODE_TYPE_SLOT:
  362. rc = dlpar_remove_pci_slot(drc_name, dn);
  363. break;
  364. }
  365. vm_unmap_aliases();
  366. printk(KERN_INFO "%s: slot %s removed\n", DLPAR_MODULE_NAME, drc_name);
  367. exit:
  368. mutex_unlock(&rpadlpar_mutex);
  369. return rc;
  370. }
  371. static inline int is_dlpar_capable(void)
  372. {
  373. int rc = rtas_token("ibm,configure-connector");
  374. return (int) (rc != RTAS_UNKNOWN_SERVICE);
  375. }
  376. int __init rpadlpar_io_init(void)
  377. {
  378. int rc = 0;
  379. if (!is_dlpar_capable()) {
  380. printk(KERN_WARNING "%s: partition not DLPAR capable\n",
  381. __func__);
  382. return -EPERM;
  383. }
  384. rc = dlpar_sysfs_init();
  385. return rc;
  386. }
  387. void rpadlpar_io_exit(void)
  388. {
  389. dlpar_sysfs_exit();
  390. return;
  391. }
  392. module_init(rpadlpar_io_init);
  393. module_exit(rpadlpar_io_exit);
  394. MODULE_LICENSE("GPL");