cpci_hotplug_pci.c 7.1 KB

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