cpci_hotplug_pci.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * CompactPCI Hot Plug Driver PCI functions
  4. *
  5. * Copyright (C) 2002,2005 by SOMA Networks, Inc.
  6. *
  7. * All rights reserved.
  8. *
  9. * Send feedback to <scottm@somanetworks.com>
  10. */
  11. #include <linux/module.h>
  12. #include <linux/kernel.h>
  13. #include <linux/pci.h>
  14. #include <linux/pci_hotplug.h>
  15. #include <linux/proc_fs.h>
  16. #include "../pci.h"
  17. #include "cpci_hotplug.h"
  18. #define MY_NAME "cpci_hotplug"
  19. extern int cpci_debug;
  20. #define dbg(format, arg...) \
  21. do { \
  22. if (cpci_debug) \
  23. printk(KERN_DEBUG "%s: " format "\n", \
  24. MY_NAME, ## arg); \
  25. } while (0)
  26. #define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME, ## arg)
  27. #define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME, ## arg)
  28. #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME, ## arg)
  29. u8 cpci_get_attention_status(struct slot *slot)
  30. {
  31. int hs_cap;
  32. u16 hs_csr;
  33. hs_cap = pci_bus_find_capability(slot->bus,
  34. slot->devfn,
  35. PCI_CAP_ID_CHSWP);
  36. if (!hs_cap)
  37. return 0;
  38. if (pci_bus_read_config_word(slot->bus,
  39. slot->devfn,
  40. hs_cap + 2,
  41. &hs_csr))
  42. return 0;
  43. return hs_csr & 0x0008 ? 1 : 0;
  44. }
  45. int cpci_set_attention_status(struct slot *slot, int status)
  46. {
  47. int hs_cap;
  48. u16 hs_csr;
  49. hs_cap = pci_bus_find_capability(slot->bus,
  50. slot->devfn,
  51. PCI_CAP_ID_CHSWP);
  52. if (!hs_cap)
  53. return 0;
  54. if (pci_bus_read_config_word(slot->bus,
  55. slot->devfn,
  56. hs_cap + 2,
  57. &hs_csr))
  58. return 0;
  59. if (status)
  60. hs_csr |= HS_CSR_LOO;
  61. else
  62. hs_csr &= ~HS_CSR_LOO;
  63. if (pci_bus_write_config_word(slot->bus,
  64. slot->devfn,
  65. hs_cap + 2,
  66. hs_csr))
  67. return 0;
  68. return 1;
  69. }
  70. u16 cpci_get_hs_csr(struct slot *slot)
  71. {
  72. int hs_cap;
  73. u16 hs_csr;
  74. hs_cap = pci_bus_find_capability(slot->bus,
  75. slot->devfn,
  76. PCI_CAP_ID_CHSWP);
  77. if (!hs_cap)
  78. return 0xFFFF;
  79. if (pci_bus_read_config_word(slot->bus,
  80. slot->devfn,
  81. hs_cap + 2,
  82. &hs_csr))
  83. return 0xFFFF;
  84. return hs_csr;
  85. }
  86. int cpci_check_and_clear_ins(struct slot *slot)
  87. {
  88. int hs_cap;
  89. u16 hs_csr;
  90. int ins = 0;
  91. hs_cap = pci_bus_find_capability(slot->bus,
  92. slot->devfn,
  93. PCI_CAP_ID_CHSWP);
  94. if (!hs_cap)
  95. return 0;
  96. if (pci_bus_read_config_word(slot->bus,
  97. slot->devfn,
  98. hs_cap + 2,
  99. &hs_csr))
  100. return 0;
  101. if (hs_csr & HS_CSR_INS) {
  102. /* Clear INS (by setting it) */
  103. if (pci_bus_write_config_word(slot->bus,
  104. slot->devfn,
  105. hs_cap + 2,
  106. hs_csr))
  107. ins = 0;
  108. else
  109. ins = 1;
  110. }
  111. return ins;
  112. }
  113. int cpci_check_ext(struct slot *slot)
  114. {
  115. int hs_cap;
  116. u16 hs_csr;
  117. int ext = 0;
  118. hs_cap = pci_bus_find_capability(slot->bus,
  119. slot->devfn,
  120. PCI_CAP_ID_CHSWP);
  121. if (!hs_cap)
  122. return 0;
  123. if (pci_bus_read_config_word(slot->bus,
  124. slot->devfn,
  125. hs_cap + 2,
  126. &hs_csr))
  127. return 0;
  128. if (hs_csr & HS_CSR_EXT)
  129. ext = 1;
  130. return ext;
  131. }
  132. int cpci_clear_ext(struct slot *slot)
  133. {
  134. int hs_cap;
  135. u16 hs_csr;
  136. hs_cap = pci_bus_find_capability(slot->bus,
  137. slot->devfn,
  138. PCI_CAP_ID_CHSWP);
  139. if (!hs_cap)
  140. return -ENODEV;
  141. if (pci_bus_read_config_word(slot->bus,
  142. slot->devfn,
  143. hs_cap + 2,
  144. &hs_csr))
  145. return -ENODEV;
  146. if (hs_csr & HS_CSR_EXT) {
  147. /* Clear EXT (by setting it) */
  148. if (pci_bus_write_config_word(slot->bus,
  149. slot->devfn,
  150. hs_cap + 2,
  151. hs_csr))
  152. return -ENODEV;
  153. }
  154. return 0;
  155. }
  156. int cpci_led_on(struct slot *slot)
  157. {
  158. int hs_cap;
  159. u16 hs_csr;
  160. hs_cap = pci_bus_find_capability(slot->bus,
  161. slot->devfn,
  162. PCI_CAP_ID_CHSWP);
  163. if (!hs_cap)
  164. return -ENODEV;
  165. if (pci_bus_read_config_word(slot->bus,
  166. slot->devfn,
  167. hs_cap + 2,
  168. &hs_csr))
  169. return -ENODEV;
  170. if ((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) {
  171. hs_csr |= HS_CSR_LOO;
  172. if (pci_bus_write_config_word(slot->bus,
  173. slot->devfn,
  174. hs_cap + 2,
  175. hs_csr)) {
  176. err("Could not set LOO for slot %s",
  177. hotplug_slot_name(slot->hotplug_slot));
  178. return -ENODEV;
  179. }
  180. }
  181. return 0;
  182. }
  183. int cpci_led_off(struct slot *slot)
  184. {
  185. int hs_cap;
  186. u16 hs_csr;
  187. hs_cap = pci_bus_find_capability(slot->bus,
  188. slot->devfn,
  189. PCI_CAP_ID_CHSWP);
  190. if (!hs_cap)
  191. return -ENODEV;
  192. if (pci_bus_read_config_word(slot->bus,
  193. slot->devfn,
  194. hs_cap + 2,
  195. &hs_csr))
  196. return -ENODEV;
  197. if (hs_csr & HS_CSR_LOO) {
  198. hs_csr &= ~HS_CSR_LOO;
  199. if (pci_bus_write_config_word(slot->bus,
  200. slot->devfn,
  201. hs_cap + 2,
  202. hs_csr)) {
  203. err("Could not clear LOO for slot %s",
  204. hotplug_slot_name(slot->hotplug_slot));
  205. return -ENODEV;
  206. }
  207. }
  208. return 0;
  209. }
  210. /*
  211. * Device configuration functions
  212. */
  213. int cpci_configure_slot(struct slot *slot)
  214. {
  215. struct pci_dev *dev;
  216. struct pci_bus *parent;
  217. int ret = 0;
  218. dbg("%s - enter", __func__);
  219. pci_lock_rescan_remove();
  220. if (slot->dev == NULL) {
  221. dbg("pci_dev null, finding %02x:%02x:%x",
  222. slot->bus->number, PCI_SLOT(slot->devfn), PCI_FUNC(slot->devfn));
  223. slot->dev = pci_get_slot(slot->bus, slot->devfn);
  224. }
  225. /* Still NULL? Well then scan for it! */
  226. if (slot->dev == NULL) {
  227. int n;
  228. dbg("pci_dev still null");
  229. /*
  230. * This will generate pci_dev structures for all functions, but
  231. * we will only call this case when lookup fails.
  232. */
  233. n = pci_scan_slot(slot->bus, slot->devfn);
  234. dbg("%s: pci_scan_slot returned %d", __func__, n);
  235. slot->dev = pci_get_slot(slot->bus, slot->devfn);
  236. if (slot->dev == NULL) {
  237. err("Could not find PCI device for slot %02x", slot->number);
  238. ret = -ENODEV;
  239. goto out;
  240. }
  241. }
  242. parent = slot->dev->bus;
  243. for_each_pci_bridge(dev, parent) {
  244. if (PCI_SLOT(dev->devfn) == PCI_SLOT(slot->devfn))
  245. pci_hp_add_bridge(dev);
  246. }
  247. pci_assign_unassigned_bridge_resources(parent->self);
  248. pci_bus_add_devices(parent);
  249. out:
  250. pci_unlock_rescan_remove();
  251. dbg("%s - exit", __func__);
  252. return ret;
  253. }
  254. int cpci_unconfigure_slot(struct slot *slot)
  255. {
  256. struct pci_dev *dev, *temp;
  257. dbg("%s - enter", __func__);
  258. if (!slot->dev) {
  259. err("No device for slot %02x\n", slot->number);
  260. return -ENODEV;
  261. }
  262. pci_lock_rescan_remove();
  263. list_for_each_entry_safe(dev, temp, &slot->bus->devices, bus_list) {
  264. if (PCI_SLOT(dev->devfn) != PCI_SLOT(slot->devfn))
  265. continue;
  266. pci_dev_get(dev);
  267. pci_stop_and_remove_bus_device(dev);
  268. pci_dev_put(dev);
  269. }
  270. pci_dev_put(slot->dev);
  271. slot->dev = NULL;
  272. pci_unlock_rescan_remove();
  273. dbg("%s - exit", __func__);
  274. return 0;
  275. }