cpci_hotplug_core.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * CompactPCI Hot Plug Driver
  4. *
  5. * Copyright (C) 2002,2005 SOMA Networks, Inc.
  6. * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
  7. * Copyright (C) 2001 IBM Corp.
  8. *
  9. * All rights reserved.
  10. *
  11. * Send feedback to <scottm@somanetworks.com>
  12. */
  13. #include <linux/module.h>
  14. #include <linux/kernel.h>
  15. #include <linux/sched/signal.h>
  16. #include <linux/slab.h>
  17. #include <linux/pci.h>
  18. #include <linux/pci_hotplug.h>
  19. #include <linux/init.h>
  20. #include <linux/interrupt.h>
  21. #include <linux/atomic.h>
  22. #include <linux/delay.h>
  23. #include <linux/kthread.h>
  24. #include "cpci_hotplug.h"
  25. #define DRIVER_AUTHOR "Scott Murray <scottm@somanetworks.com>"
  26. #define DRIVER_DESC "CompactPCI Hot Plug Core"
  27. #define MY_NAME "cpci_hotplug"
  28. #define dbg(format, arg...) \
  29. do { \
  30. if (cpci_debug) \
  31. printk(KERN_DEBUG "%s: " format "\n", \
  32. MY_NAME, ## arg); \
  33. } while (0)
  34. #define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME, ## arg)
  35. #define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME, ## arg)
  36. #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME, ## arg)
  37. /* local variables */
  38. static DECLARE_RWSEM(list_rwsem);
  39. static LIST_HEAD(slot_list);
  40. static int slots;
  41. static atomic_t extracting;
  42. int cpci_debug;
  43. static struct cpci_hp_controller *controller;
  44. static struct task_struct *cpci_thread;
  45. static int thread_finished;
  46. static int enable_slot(struct hotplug_slot *slot);
  47. static int disable_slot(struct hotplug_slot *slot);
  48. static int set_attention_status(struct hotplug_slot *slot, u8 value);
  49. static int get_power_status(struct hotplug_slot *slot, u8 *value);
  50. static int get_attention_status(struct hotplug_slot *slot, u8 *value);
  51. static int get_adapter_status(struct hotplug_slot *slot, u8 *value);
  52. static int get_latch_status(struct hotplug_slot *slot, u8 *value);
  53. static const struct hotplug_slot_ops cpci_hotplug_slot_ops = {
  54. .enable_slot = enable_slot,
  55. .disable_slot = disable_slot,
  56. .set_attention_status = set_attention_status,
  57. .get_power_status = get_power_status,
  58. .get_attention_status = get_attention_status,
  59. .get_adapter_status = get_adapter_status,
  60. .get_latch_status = get_latch_status,
  61. };
  62. static int
  63. enable_slot(struct hotplug_slot *hotplug_slot)
  64. {
  65. struct slot *slot = to_slot(hotplug_slot);
  66. int retval = 0;
  67. dbg("%s - physical_slot = %s", __func__, slot_name(slot));
  68. if (controller->ops->set_power)
  69. retval = controller->ops->set_power(slot, 1);
  70. return retval;
  71. }
  72. static int
  73. disable_slot(struct hotplug_slot *hotplug_slot)
  74. {
  75. struct slot *slot = to_slot(hotplug_slot);
  76. int retval = 0;
  77. dbg("%s - physical_slot = %s", __func__, slot_name(slot));
  78. down_write(&list_rwsem);
  79. /* Unconfigure device */
  80. dbg("%s - unconfiguring slot %s", __func__, slot_name(slot));
  81. retval = cpci_unconfigure_slot(slot);
  82. if (retval) {
  83. err("%s - could not unconfigure slot %s",
  84. __func__, slot_name(slot));
  85. goto disable_error;
  86. }
  87. dbg("%s - finished unconfiguring slot %s", __func__, slot_name(slot));
  88. /* Clear EXT (by setting it) */
  89. if (cpci_clear_ext(slot)) {
  90. err("%s - could not clear EXT for slot %s",
  91. __func__, slot_name(slot));
  92. retval = -ENODEV;
  93. goto disable_error;
  94. }
  95. cpci_led_on(slot);
  96. if (controller->ops->set_power) {
  97. retval = controller->ops->set_power(slot, 0);
  98. if (retval)
  99. goto disable_error;
  100. }
  101. slot->adapter_status = 0;
  102. if (slot->extracting) {
  103. slot->extracting = 0;
  104. atomic_dec(&extracting);
  105. }
  106. disable_error:
  107. up_write(&list_rwsem);
  108. return retval;
  109. }
  110. static u8
  111. cpci_get_power_status(struct slot *slot)
  112. {
  113. u8 power = 1;
  114. if (controller->ops->get_power)
  115. power = controller->ops->get_power(slot);
  116. return power;
  117. }
  118. static int
  119. get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
  120. {
  121. struct slot *slot = to_slot(hotplug_slot);
  122. *value = cpci_get_power_status(slot);
  123. return 0;
  124. }
  125. static int
  126. get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
  127. {
  128. struct slot *slot = to_slot(hotplug_slot);
  129. *value = cpci_get_attention_status(slot);
  130. return 0;
  131. }
  132. static int
  133. set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
  134. {
  135. return cpci_set_attention_status(to_slot(hotplug_slot), status);
  136. }
  137. static int
  138. get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
  139. {
  140. struct slot *slot = to_slot(hotplug_slot);
  141. *value = slot->adapter_status;
  142. return 0;
  143. }
  144. static int
  145. get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
  146. {
  147. struct slot *slot = to_slot(hotplug_slot);
  148. *value = slot->latch_status;
  149. return 0;
  150. }
  151. static void release_slot(struct slot *slot)
  152. {
  153. pci_dev_put(slot->dev);
  154. kfree(slot);
  155. }
  156. #define SLOT_NAME_SIZE 6
  157. int
  158. cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
  159. {
  160. struct slot *slot;
  161. char name[SLOT_NAME_SIZE];
  162. int status;
  163. int i;
  164. if (!(controller && bus))
  165. return -ENODEV;
  166. /*
  167. * Create a structure for each slot, and register that slot
  168. * with the pci_hotplug subsystem.
  169. */
  170. for (i = first; i <= last; ++i) {
  171. slot = kzalloc(sizeof(struct slot), GFP_KERNEL);
  172. if (!slot) {
  173. status = -ENOMEM;
  174. goto error;
  175. }
  176. slot->bus = bus;
  177. slot->number = i;
  178. slot->devfn = PCI_DEVFN(i, 0);
  179. snprintf(name, SLOT_NAME_SIZE, "%02x:%02x", bus->number, i);
  180. slot->hotplug_slot.ops = &cpci_hotplug_slot_ops;
  181. dbg("registering slot %s", name);
  182. status = pci_hp_register(&slot->hotplug_slot, bus, i, name);
  183. if (status) {
  184. err("pci_hp_register failed with error %d", status);
  185. goto error_slot;
  186. }
  187. dbg("slot registered with name: %s", slot_name(slot));
  188. /* Add slot to our internal list */
  189. down_write(&list_rwsem);
  190. list_add(&slot->slot_list, &slot_list);
  191. slots++;
  192. up_write(&list_rwsem);
  193. }
  194. return 0;
  195. error_slot:
  196. kfree(slot);
  197. error:
  198. return status;
  199. }
  200. EXPORT_SYMBOL_GPL(cpci_hp_register_bus);
  201. int
  202. cpci_hp_unregister_bus(struct pci_bus *bus)
  203. {
  204. struct slot *slot;
  205. struct slot *tmp;
  206. int status = 0;
  207. down_write(&list_rwsem);
  208. if (!slots) {
  209. up_write(&list_rwsem);
  210. return -1;
  211. }
  212. list_for_each_entry_safe(slot, tmp, &slot_list, slot_list) {
  213. if (slot->bus == bus) {
  214. list_del(&slot->slot_list);
  215. slots--;
  216. dbg("deregistering slot %s", slot_name(slot));
  217. pci_hp_deregister(&slot->hotplug_slot);
  218. release_slot(slot);
  219. }
  220. }
  221. up_write(&list_rwsem);
  222. return status;
  223. }
  224. EXPORT_SYMBOL_GPL(cpci_hp_unregister_bus);
  225. /* This is the interrupt mode interrupt handler */
  226. static irqreturn_t
  227. cpci_hp_intr(int irq, void *data)
  228. {
  229. dbg("entered cpci_hp_intr");
  230. /* Check to see if it was our interrupt */
  231. if ((controller->irq_flags & IRQF_SHARED) &&
  232. !controller->ops->check_irq(controller->dev_id)) {
  233. dbg("exited cpci_hp_intr, not our interrupt");
  234. return IRQ_NONE;
  235. }
  236. /* Disable ENUM interrupt */
  237. controller->ops->disable_irq();
  238. /* Trigger processing by the event thread */
  239. wake_up_process(cpci_thread);
  240. return IRQ_HANDLED;
  241. }
  242. /*
  243. * According to PICMG 2.1 R2.0, section 6.3.2, upon
  244. * initialization, the system driver shall clear the
  245. * INS bits of the cold-inserted devices.
  246. */
  247. static int
  248. init_slots(int clear_ins)
  249. {
  250. struct slot *slot;
  251. struct pci_dev *dev;
  252. dbg("%s - enter", __func__);
  253. down_read(&list_rwsem);
  254. if (!slots) {
  255. up_read(&list_rwsem);
  256. return -1;
  257. }
  258. list_for_each_entry(slot, &slot_list, slot_list) {
  259. dbg("%s - looking at slot %s", __func__, slot_name(slot));
  260. if (clear_ins && cpci_check_and_clear_ins(slot))
  261. dbg("%s - cleared INS for slot %s",
  262. __func__, slot_name(slot));
  263. dev = pci_get_slot(slot->bus, PCI_DEVFN(slot->number, 0));
  264. if (dev) {
  265. slot->adapter_status = 1;
  266. slot->latch_status = 1;
  267. slot->dev = dev;
  268. }
  269. }
  270. up_read(&list_rwsem);
  271. dbg("%s - exit", __func__);
  272. return 0;
  273. }
  274. static int
  275. check_slots(void)
  276. {
  277. struct slot *slot;
  278. int extracted;
  279. int inserted;
  280. u16 hs_csr;
  281. down_read(&list_rwsem);
  282. if (!slots) {
  283. up_read(&list_rwsem);
  284. err("no slots registered, shutting down");
  285. return -1;
  286. }
  287. extracted = inserted = 0;
  288. list_for_each_entry(slot, &slot_list, slot_list) {
  289. dbg("%s - looking at slot %s", __func__, slot_name(slot));
  290. if (cpci_check_and_clear_ins(slot)) {
  291. /*
  292. * Some broken hardware (e.g. PLX 9054AB) asserts
  293. * ENUM# twice...
  294. */
  295. if (slot->dev) {
  296. warn("slot %s already inserted",
  297. slot_name(slot));
  298. inserted++;
  299. continue;
  300. }
  301. /* Process insertion */
  302. dbg("%s - slot %s inserted", __func__, slot_name(slot));
  303. /* GSM, debug */
  304. hs_csr = cpci_get_hs_csr(slot);
  305. dbg("%s - slot %s HS_CSR (1) = %04x",
  306. __func__, slot_name(slot), hs_csr);
  307. /* Configure device */
  308. dbg("%s - configuring slot %s",
  309. __func__, slot_name(slot));
  310. if (cpci_configure_slot(slot)) {
  311. err("%s - could not configure slot %s",
  312. __func__, slot_name(slot));
  313. continue;
  314. }
  315. dbg("%s - finished configuring slot %s",
  316. __func__, slot_name(slot));
  317. /* GSM, debug */
  318. hs_csr = cpci_get_hs_csr(slot);
  319. dbg("%s - slot %s HS_CSR (2) = %04x",
  320. __func__, slot_name(slot), hs_csr);
  321. slot->latch_status = 1;
  322. slot->adapter_status = 1;
  323. cpci_led_off(slot);
  324. /* GSM, debug */
  325. hs_csr = cpci_get_hs_csr(slot);
  326. dbg("%s - slot %s HS_CSR (3) = %04x",
  327. __func__, slot_name(slot), hs_csr);
  328. inserted++;
  329. } else if (cpci_check_ext(slot)) {
  330. /* Process extraction request */
  331. dbg("%s - slot %s extracted",
  332. __func__, slot_name(slot));
  333. /* GSM, debug */
  334. hs_csr = cpci_get_hs_csr(slot);
  335. dbg("%s - slot %s HS_CSR = %04x",
  336. __func__, slot_name(slot), hs_csr);
  337. if (!slot->extracting) {
  338. slot->latch_status = 0;
  339. slot->extracting = 1;
  340. atomic_inc(&extracting);
  341. }
  342. extracted++;
  343. } else if (slot->extracting) {
  344. hs_csr = cpci_get_hs_csr(slot);
  345. if (hs_csr == 0xffff) {
  346. /*
  347. * Hmmm, we're likely hosed at this point, should we
  348. * bother trying to tell the driver or not?
  349. */
  350. err("card in slot %s was improperly removed",
  351. slot_name(slot));
  352. slot->adapter_status = 0;
  353. slot->extracting = 0;
  354. atomic_dec(&extracting);
  355. }
  356. }
  357. }
  358. up_read(&list_rwsem);
  359. dbg("inserted=%d, extracted=%d, extracting=%d",
  360. inserted, extracted, atomic_read(&extracting));
  361. if (inserted || extracted)
  362. return extracted;
  363. else if (!atomic_read(&extracting)) {
  364. err("cannot find ENUM# source, shutting down");
  365. return -1;
  366. }
  367. return 0;
  368. }
  369. /* This is the interrupt mode worker thread body */
  370. static int
  371. event_thread(void *data)
  372. {
  373. int rc;
  374. dbg("%s - event thread started", __func__);
  375. while (1) {
  376. dbg("event thread sleeping");
  377. set_current_state(TASK_INTERRUPTIBLE);
  378. schedule();
  379. if (kthread_should_stop())
  380. break;
  381. do {
  382. rc = check_slots();
  383. if (rc > 0) {
  384. /* Give userspace a chance to handle extraction */
  385. msleep(500);
  386. } else if (rc < 0) {
  387. dbg("%s - error checking slots", __func__);
  388. thread_finished = 1;
  389. goto out;
  390. }
  391. } while (atomic_read(&extracting) && !kthread_should_stop());
  392. if (kthread_should_stop())
  393. break;
  394. /* Re-enable ENUM# interrupt */
  395. dbg("%s - re-enabling irq", __func__);
  396. controller->ops->enable_irq();
  397. }
  398. out:
  399. return 0;
  400. }
  401. /* This is the polling mode worker thread body */
  402. static int
  403. poll_thread(void *data)
  404. {
  405. int rc;
  406. while (1) {
  407. if (kthread_should_stop() || signal_pending(current))
  408. break;
  409. if (controller->ops->query_enum()) {
  410. do {
  411. rc = check_slots();
  412. if (rc > 0) {
  413. /* Give userspace a chance to handle extraction */
  414. msleep(500);
  415. } else if (rc < 0) {
  416. dbg("%s - error checking slots", __func__);
  417. thread_finished = 1;
  418. goto out;
  419. }
  420. } while (atomic_read(&extracting) && !kthread_should_stop());
  421. }
  422. msleep(100);
  423. }
  424. out:
  425. return 0;
  426. }
  427. static int
  428. cpci_start_thread(void)
  429. {
  430. if (controller->irq)
  431. cpci_thread = kthread_run(event_thread, NULL, "cpci_hp_eventd");
  432. else
  433. cpci_thread = kthread_run(poll_thread, NULL, "cpci_hp_polld");
  434. if (IS_ERR(cpci_thread)) {
  435. err("Can't start up our thread");
  436. return PTR_ERR(cpci_thread);
  437. }
  438. thread_finished = 0;
  439. return 0;
  440. }
  441. static void
  442. cpci_stop_thread(void)
  443. {
  444. kthread_stop(cpci_thread);
  445. thread_finished = 1;
  446. }
  447. int
  448. cpci_hp_register_controller(struct cpci_hp_controller *new_controller)
  449. {
  450. int status = 0;
  451. if (controller)
  452. return -1;
  453. if (!(new_controller && new_controller->ops))
  454. return -EINVAL;
  455. if (new_controller->irq) {
  456. if (!(new_controller->ops->enable_irq &&
  457. new_controller->ops->disable_irq))
  458. status = -EINVAL;
  459. if (request_irq(new_controller->irq,
  460. cpci_hp_intr,
  461. new_controller->irq_flags,
  462. MY_NAME,
  463. new_controller->dev_id)) {
  464. err("Can't get irq %d for the hotplug cPCI controller",
  465. new_controller->irq);
  466. status = -ENODEV;
  467. }
  468. dbg("%s - acquired controller irq %d",
  469. __func__, new_controller->irq);
  470. }
  471. if (!status)
  472. controller = new_controller;
  473. return status;
  474. }
  475. EXPORT_SYMBOL_GPL(cpci_hp_register_controller);
  476. static void
  477. cleanup_slots(void)
  478. {
  479. struct slot *slot;
  480. struct slot *tmp;
  481. /*
  482. * Unregister all of our slots with the pci_hotplug subsystem,
  483. * and free up all memory that we had allocated.
  484. */
  485. down_write(&list_rwsem);
  486. if (!slots)
  487. goto cleanup_null;
  488. list_for_each_entry_safe(slot, tmp, &slot_list, slot_list) {
  489. list_del(&slot->slot_list);
  490. pci_hp_deregister(&slot->hotplug_slot);
  491. release_slot(slot);
  492. }
  493. cleanup_null:
  494. up_write(&list_rwsem);
  495. return;
  496. }
  497. int
  498. cpci_hp_unregister_controller(struct cpci_hp_controller *old_controller)
  499. {
  500. int status = 0;
  501. if (controller) {
  502. if (!thread_finished)
  503. cpci_stop_thread();
  504. if (controller->irq)
  505. free_irq(controller->irq, controller->dev_id);
  506. controller = NULL;
  507. cleanup_slots();
  508. } else
  509. status = -ENODEV;
  510. return status;
  511. }
  512. EXPORT_SYMBOL_GPL(cpci_hp_unregister_controller);
  513. int
  514. cpci_hp_start(void)
  515. {
  516. static int first = 1;
  517. int status;
  518. dbg("%s - enter", __func__);
  519. if (!controller)
  520. return -ENODEV;
  521. down_read(&list_rwsem);
  522. if (list_empty(&slot_list)) {
  523. up_read(&list_rwsem);
  524. return -ENODEV;
  525. }
  526. up_read(&list_rwsem);
  527. status = init_slots(first);
  528. if (first)
  529. first = 0;
  530. if (status)
  531. return status;
  532. status = cpci_start_thread();
  533. if (status)
  534. return status;
  535. dbg("%s - thread started", __func__);
  536. if (controller->irq) {
  537. /* Start enum interrupt processing */
  538. dbg("%s - enabling irq", __func__);
  539. controller->ops->enable_irq();
  540. }
  541. dbg("%s - exit", __func__);
  542. return 0;
  543. }
  544. EXPORT_SYMBOL_GPL(cpci_hp_start);
  545. int
  546. cpci_hp_stop(void)
  547. {
  548. if (!controller)
  549. return -ENODEV;
  550. if (controller->irq) {
  551. /* Stop enum interrupt processing */
  552. dbg("%s - disabling irq", __func__);
  553. controller->ops->disable_irq();
  554. }
  555. cpci_stop_thread();
  556. return 0;
  557. }
  558. EXPORT_SYMBOL_GPL(cpci_hp_stop);
  559. int __init
  560. cpci_hotplug_init(int debug)
  561. {
  562. cpci_debug = debug;
  563. return 0;
  564. }