cpci_hotplug_pci.c 6.3 KB

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