cpcihp_generic.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * cpcihp_generic.c
  4. *
  5. * Generic port I/O CompactPCI driver
  6. *
  7. * Copyright 2002 SOMA Networks, Inc.
  8. * Copyright 2001 Intel San Luis Obispo
  9. * Copyright 2000,2001 MontaVista Software Inc.
  10. *
  11. * This generic CompactPCI hotplug driver should allow using the PCI hotplug
  12. * mechanism on any CompactPCI board that exposes the #ENUM signal as a bit
  13. * in a system register that can be read through standard port I/O.
  14. *
  15. * Send feedback to <[email protected]>
  16. */
  17. #include <linux/module.h>
  18. #include <linux/init.h>
  19. #include <linux/errno.h>
  20. #include <linux/pci.h>
  21. #include <linux/string.h>
  22. #include "cpci_hotplug.h"
  23. #define DRIVER_VERSION "0.1"
  24. #define DRIVER_AUTHOR "Scott Murray <[email protected]>"
  25. #define DRIVER_DESC "Generic port I/O CompactPCI Hot Plug Driver"
  26. #if !defined(MODULE)
  27. #define MY_NAME "cpcihp_generic"
  28. #else
  29. #define MY_NAME THIS_MODULE->name
  30. #endif
  31. #define dbg(format, arg...) \
  32. do { \
  33. if (debug) \
  34. printk(KERN_DEBUG "%s: " format "\n", \
  35. MY_NAME, ## arg); \
  36. } while (0)
  37. #define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME, ## arg)
  38. #define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME, ## arg)
  39. #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME, ## arg)
  40. /* local variables */
  41. static bool debug;
  42. static char *bridge;
  43. static u8 bridge_busnr;
  44. static u8 bridge_slot;
  45. static struct pci_bus *bus;
  46. static u8 first_slot;
  47. static u8 last_slot;
  48. static u16 port;
  49. static unsigned int enum_bit;
  50. static u8 enum_mask;
  51. static struct cpci_hp_controller_ops generic_hpc_ops;
  52. static struct cpci_hp_controller generic_hpc;
  53. static int __init validate_parameters(void)
  54. {
  55. char *str;
  56. char *p;
  57. unsigned long tmp;
  58. if (!bridge) {
  59. info("not configured, disabling.");
  60. return -EINVAL;
  61. }
  62. str = bridge;
  63. if (!*str)
  64. return -EINVAL;
  65. tmp = simple_strtoul(str, &p, 16);
  66. if (p == str || tmp > 0xff) {
  67. err("Invalid hotplug bus bridge device bus number");
  68. return -EINVAL;
  69. }
  70. bridge_busnr = (u8) tmp;
  71. dbg("bridge_busnr = 0x%02x", bridge_busnr);
  72. if (*p != ':') {
  73. err("Invalid hotplug bus bridge device");
  74. return -EINVAL;
  75. }
  76. str = p + 1;
  77. tmp = simple_strtoul(str, &p, 16);
  78. if (p == str || tmp > 0x1f) {
  79. err("Invalid hotplug bus bridge device slot number");
  80. return -EINVAL;
  81. }
  82. bridge_slot = (u8) tmp;
  83. dbg("bridge_slot = 0x%02x", bridge_slot);
  84. dbg("first_slot = 0x%02x", first_slot);
  85. dbg("last_slot = 0x%02x", last_slot);
  86. if (!(first_slot && last_slot)) {
  87. err("Need to specify first_slot and last_slot");
  88. return -EINVAL;
  89. }
  90. if (last_slot < first_slot) {
  91. err("first_slot must be less than last_slot");
  92. return -EINVAL;
  93. }
  94. dbg("port = 0x%04x", port);
  95. dbg("enum_bit = 0x%02x", enum_bit);
  96. if (enum_bit > 7) {
  97. err("Invalid #ENUM bit");
  98. return -EINVAL;
  99. }
  100. enum_mask = 1 << enum_bit;
  101. return 0;
  102. }
  103. static int query_enum(void)
  104. {
  105. u8 value;
  106. value = inb_p(port);
  107. return ((value & enum_mask) == enum_mask);
  108. }
  109. static int __init cpcihp_generic_init(void)
  110. {
  111. int status;
  112. struct resource *r;
  113. struct pci_dev *dev;
  114. info(DRIVER_DESC " version: " DRIVER_VERSION);
  115. status = validate_parameters();
  116. if (status)
  117. return status;
  118. r = request_region(port, 1, "#ENUM hotswap signal register");
  119. if (!r)
  120. return -EBUSY;
  121. dev = pci_get_domain_bus_and_slot(0, bridge_busnr,
  122. PCI_DEVFN(bridge_slot, 0));
  123. if (!dev || dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
  124. err("Invalid bridge device %s", bridge);
  125. pci_dev_put(dev);
  126. return -EINVAL;
  127. }
  128. bus = dev->subordinate;
  129. pci_dev_put(dev);
  130. memset(&generic_hpc, 0, sizeof(struct cpci_hp_controller));
  131. generic_hpc_ops.query_enum = query_enum;
  132. generic_hpc.ops = &generic_hpc_ops;
  133. status = cpci_hp_register_controller(&generic_hpc);
  134. if (status != 0) {
  135. err("Could not register cPCI hotplug controller");
  136. return -ENODEV;
  137. }
  138. dbg("registered controller");
  139. status = cpci_hp_register_bus(bus, first_slot, last_slot);
  140. if (status != 0) {
  141. err("Could not register cPCI hotplug bus");
  142. goto init_bus_register_error;
  143. }
  144. dbg("registered bus");
  145. status = cpci_hp_start();
  146. if (status != 0) {
  147. err("Could not started cPCI hotplug system");
  148. goto init_start_error;
  149. }
  150. dbg("started cpci hp system");
  151. return 0;
  152. init_start_error:
  153. cpci_hp_unregister_bus(bus);
  154. init_bus_register_error:
  155. cpci_hp_unregister_controller(&generic_hpc);
  156. err("status = %d", status);
  157. return status;
  158. }
  159. static void __exit cpcihp_generic_exit(void)
  160. {
  161. cpci_hp_stop();
  162. cpci_hp_unregister_bus(bus);
  163. cpci_hp_unregister_controller(&generic_hpc);
  164. release_region(port, 1);
  165. }
  166. module_init(cpcihp_generic_init);
  167. module_exit(cpcihp_generic_exit);
  168. MODULE_AUTHOR(DRIVER_AUTHOR);
  169. MODULE_DESCRIPTION(DRIVER_DESC);
  170. MODULE_LICENSE("GPL");
  171. module_param(debug, bool, S_IRUGO | S_IWUSR);
  172. MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
  173. module_param(bridge, charp, 0);
  174. MODULE_PARM_DESC(bridge, "Hotswap bus bridge device, <bus>:<slot> (bus and slot are in hexadecimal)");
  175. module_param(first_slot, byte, 0);
  176. MODULE_PARM_DESC(first_slot, "Hotswap bus first slot number");
  177. module_param(last_slot, byte, 0);
  178. MODULE_PARM_DESC(last_slot, "Hotswap bus last slot number");
  179. module_param_hw(port, ushort, ioport, 0);
  180. MODULE_PARM_DESC(port, "#ENUM signal I/O port");
  181. module_param(enum_bit, uint, 0);
  182. MODULE_PARM_DESC(enum_bit, "#ENUM signal bit (0-7)");