0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <linux/module.h>
0015 #include <linux/kernel.h>
0016 #include <linux/sched/signal.h>
0017 #include <linux/slab.h>
0018 #include <linux/pci.h>
0019 #include <linux/pci_hotplug.h>
0020 #include <linux/init.h>
0021 #include <linux/interrupt.h>
0022 #include <linux/atomic.h>
0023 #include <linux/delay.h>
0024 #include <linux/kthread.h>
0025 #include "cpci_hotplug.h"
0026
0027 #define DRIVER_AUTHOR "Scott Murray <scottm@somanetworks.com>"
0028 #define DRIVER_DESC "CompactPCI Hot Plug Core"
0029
0030 #define MY_NAME "cpci_hotplug"
0031
0032 #define dbg(format, arg...) \
0033 do { \
0034 if (cpci_debug) \
0035 printk(KERN_DEBUG "%s: " format "\n", \
0036 MY_NAME, ## arg); \
0037 } while (0)
0038 #define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME, ## arg)
0039 #define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME, ## arg)
0040 #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME, ## arg)
0041
0042
0043 static DECLARE_RWSEM(list_rwsem);
0044 static LIST_HEAD(slot_list);
0045 static int slots;
0046 static atomic_t extracting;
0047 int cpci_debug;
0048 static struct cpci_hp_controller *controller;
0049 static struct task_struct *cpci_thread;
0050 static int thread_finished;
0051
0052 static int enable_slot(struct hotplug_slot *slot);
0053 static int disable_slot(struct hotplug_slot *slot);
0054 static int set_attention_status(struct hotplug_slot *slot, u8 value);
0055 static int get_power_status(struct hotplug_slot *slot, u8 *value);
0056 static int get_attention_status(struct hotplug_slot *slot, u8 *value);
0057 static int get_adapter_status(struct hotplug_slot *slot, u8 *value);
0058 static int get_latch_status(struct hotplug_slot *slot, u8 *value);
0059
0060 static const struct hotplug_slot_ops cpci_hotplug_slot_ops = {
0061 .enable_slot = enable_slot,
0062 .disable_slot = disable_slot,
0063 .set_attention_status = set_attention_status,
0064 .get_power_status = get_power_status,
0065 .get_attention_status = get_attention_status,
0066 .get_adapter_status = get_adapter_status,
0067 .get_latch_status = get_latch_status,
0068 };
0069
0070 static int
0071 enable_slot(struct hotplug_slot *hotplug_slot)
0072 {
0073 struct slot *slot = to_slot(hotplug_slot);
0074 int retval = 0;
0075
0076 dbg("%s - physical_slot = %s", __func__, slot_name(slot));
0077
0078 if (controller->ops->set_power)
0079 retval = controller->ops->set_power(slot, 1);
0080 return retval;
0081 }
0082
0083 static int
0084 disable_slot(struct hotplug_slot *hotplug_slot)
0085 {
0086 struct slot *slot = to_slot(hotplug_slot);
0087 int retval = 0;
0088
0089 dbg("%s - physical_slot = %s", __func__, slot_name(slot));
0090
0091 down_write(&list_rwsem);
0092
0093
0094 dbg("%s - unconfiguring slot %s", __func__, slot_name(slot));
0095 retval = cpci_unconfigure_slot(slot);
0096 if (retval) {
0097 err("%s - could not unconfigure slot %s",
0098 __func__, slot_name(slot));
0099 goto disable_error;
0100 }
0101 dbg("%s - finished unconfiguring slot %s", __func__, slot_name(slot));
0102
0103
0104 if (cpci_clear_ext(slot)) {
0105 err("%s - could not clear EXT for slot %s",
0106 __func__, slot_name(slot));
0107 retval = -ENODEV;
0108 goto disable_error;
0109 }
0110 cpci_led_on(slot);
0111
0112 if (controller->ops->set_power) {
0113 retval = controller->ops->set_power(slot, 0);
0114 if (retval)
0115 goto disable_error;
0116 }
0117
0118 slot->adapter_status = 0;
0119
0120 if (slot->extracting) {
0121 slot->extracting = 0;
0122 atomic_dec(&extracting);
0123 }
0124 disable_error:
0125 up_write(&list_rwsem);
0126 return retval;
0127 }
0128
0129 static u8
0130 cpci_get_power_status(struct slot *slot)
0131 {
0132 u8 power = 1;
0133
0134 if (controller->ops->get_power)
0135 power = controller->ops->get_power(slot);
0136 return power;
0137 }
0138
0139 static int
0140 get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
0141 {
0142 struct slot *slot = to_slot(hotplug_slot);
0143
0144 *value = cpci_get_power_status(slot);
0145 return 0;
0146 }
0147
0148 static int
0149 get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
0150 {
0151 struct slot *slot = to_slot(hotplug_slot);
0152
0153 *value = cpci_get_attention_status(slot);
0154 return 0;
0155 }
0156
0157 static int
0158 set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
0159 {
0160 return cpci_set_attention_status(to_slot(hotplug_slot), status);
0161 }
0162
0163 static int
0164 get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
0165 {
0166 struct slot *slot = to_slot(hotplug_slot);
0167
0168 *value = slot->adapter_status;
0169 return 0;
0170 }
0171
0172 static int
0173 get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
0174 {
0175 struct slot *slot = to_slot(hotplug_slot);
0176
0177 *value = slot->latch_status;
0178 return 0;
0179 }
0180
0181 static void release_slot(struct slot *slot)
0182 {
0183 pci_dev_put(slot->dev);
0184 kfree(slot);
0185 }
0186
0187 #define SLOT_NAME_SIZE 6
0188
0189 int
0190 cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
0191 {
0192 struct slot *slot;
0193 char name[SLOT_NAME_SIZE];
0194 int status;
0195 int i;
0196
0197 if (!(controller && bus))
0198 return -ENODEV;
0199
0200
0201
0202
0203
0204 for (i = first; i <= last; ++i) {
0205 slot = kzalloc(sizeof(struct slot), GFP_KERNEL);
0206 if (!slot) {
0207 status = -ENOMEM;
0208 goto error;
0209 }
0210
0211 slot->bus = bus;
0212 slot->number = i;
0213 slot->devfn = PCI_DEVFN(i, 0);
0214
0215 snprintf(name, SLOT_NAME_SIZE, "%02x:%02x", bus->number, i);
0216
0217 slot->hotplug_slot.ops = &cpci_hotplug_slot_ops;
0218
0219 dbg("registering slot %s", name);
0220 status = pci_hp_register(&slot->hotplug_slot, bus, i, name);
0221 if (status) {
0222 err("pci_hp_register failed with error %d", status);
0223 goto error_slot;
0224 }
0225 dbg("slot registered with name: %s", slot_name(slot));
0226
0227
0228 down_write(&list_rwsem);
0229 list_add(&slot->slot_list, &slot_list);
0230 slots++;
0231 up_write(&list_rwsem);
0232 }
0233 return 0;
0234 error_slot:
0235 kfree(slot);
0236 error:
0237 return status;
0238 }
0239 EXPORT_SYMBOL_GPL(cpci_hp_register_bus);
0240
0241 int
0242 cpci_hp_unregister_bus(struct pci_bus *bus)
0243 {
0244 struct slot *slot;
0245 struct slot *tmp;
0246 int status = 0;
0247
0248 down_write(&list_rwsem);
0249 if (!slots) {
0250 up_write(&list_rwsem);
0251 return -1;
0252 }
0253 list_for_each_entry_safe(slot, tmp, &slot_list, slot_list) {
0254 if (slot->bus == bus) {
0255 list_del(&slot->slot_list);
0256 slots--;
0257
0258 dbg("deregistering slot %s", slot_name(slot));
0259 pci_hp_deregister(&slot->hotplug_slot);
0260 release_slot(slot);
0261 }
0262 }
0263 up_write(&list_rwsem);
0264 return status;
0265 }
0266 EXPORT_SYMBOL_GPL(cpci_hp_unregister_bus);
0267
0268
0269 static irqreturn_t
0270 cpci_hp_intr(int irq, void *data)
0271 {
0272 dbg("entered cpci_hp_intr");
0273
0274
0275 if ((controller->irq_flags & IRQF_SHARED) &&
0276 !controller->ops->check_irq(controller->dev_id)) {
0277 dbg("exited cpci_hp_intr, not our interrupt");
0278 return IRQ_NONE;
0279 }
0280
0281
0282 controller->ops->disable_irq();
0283
0284
0285 wake_up_process(cpci_thread);
0286 return IRQ_HANDLED;
0287 }
0288
0289
0290
0291
0292
0293
0294 static int
0295 init_slots(int clear_ins)
0296 {
0297 struct slot *slot;
0298 struct pci_dev *dev;
0299
0300 dbg("%s - enter", __func__);
0301 down_read(&list_rwsem);
0302 if (!slots) {
0303 up_read(&list_rwsem);
0304 return -1;
0305 }
0306 list_for_each_entry(slot, &slot_list, slot_list) {
0307 dbg("%s - looking at slot %s", __func__, slot_name(slot));
0308 if (clear_ins && cpci_check_and_clear_ins(slot))
0309 dbg("%s - cleared INS for slot %s",
0310 __func__, slot_name(slot));
0311 dev = pci_get_slot(slot->bus, PCI_DEVFN(slot->number, 0));
0312 if (dev) {
0313 slot->adapter_status = 1;
0314 slot->latch_status = 1;
0315 slot->dev = dev;
0316 }
0317 }
0318 up_read(&list_rwsem);
0319 dbg("%s - exit", __func__);
0320 return 0;
0321 }
0322
0323 static int
0324 check_slots(void)
0325 {
0326 struct slot *slot;
0327 int extracted;
0328 int inserted;
0329 u16 hs_csr;
0330
0331 down_read(&list_rwsem);
0332 if (!slots) {
0333 up_read(&list_rwsem);
0334 err("no slots registered, shutting down");
0335 return -1;
0336 }
0337 extracted = inserted = 0;
0338 list_for_each_entry(slot, &slot_list, slot_list) {
0339 dbg("%s - looking at slot %s", __func__, slot_name(slot));
0340 if (cpci_check_and_clear_ins(slot)) {
0341
0342
0343
0344
0345 if (slot->dev) {
0346 warn("slot %s already inserted",
0347 slot_name(slot));
0348 inserted++;
0349 continue;
0350 }
0351
0352
0353 dbg("%s - slot %s inserted", __func__, slot_name(slot));
0354
0355
0356 hs_csr = cpci_get_hs_csr(slot);
0357 dbg("%s - slot %s HS_CSR (1) = %04x",
0358 __func__, slot_name(slot), hs_csr);
0359
0360
0361 dbg("%s - configuring slot %s",
0362 __func__, slot_name(slot));
0363 if (cpci_configure_slot(slot)) {
0364 err("%s - could not configure slot %s",
0365 __func__, slot_name(slot));
0366 continue;
0367 }
0368 dbg("%s - finished configuring slot %s",
0369 __func__, slot_name(slot));
0370
0371
0372 hs_csr = cpci_get_hs_csr(slot);
0373 dbg("%s - slot %s HS_CSR (2) = %04x",
0374 __func__, slot_name(slot), hs_csr);
0375
0376 slot->latch_status = 1;
0377 slot->adapter_status = 1;
0378
0379 cpci_led_off(slot);
0380
0381
0382 hs_csr = cpci_get_hs_csr(slot);
0383 dbg("%s - slot %s HS_CSR (3) = %04x",
0384 __func__, slot_name(slot), hs_csr);
0385
0386 inserted++;
0387 } else if (cpci_check_ext(slot)) {
0388
0389 dbg("%s - slot %s extracted",
0390 __func__, slot_name(slot));
0391
0392
0393 hs_csr = cpci_get_hs_csr(slot);
0394 dbg("%s - slot %s HS_CSR = %04x",
0395 __func__, slot_name(slot), hs_csr);
0396
0397 if (!slot->extracting) {
0398 slot->latch_status = 0;
0399 slot->extracting = 1;
0400 atomic_inc(&extracting);
0401 }
0402 extracted++;
0403 } else if (slot->extracting) {
0404 hs_csr = cpci_get_hs_csr(slot);
0405 if (hs_csr == 0xffff) {
0406
0407
0408
0409
0410 err("card in slot %s was improperly removed",
0411 slot_name(slot));
0412 slot->adapter_status = 0;
0413 slot->extracting = 0;
0414 atomic_dec(&extracting);
0415 }
0416 }
0417 }
0418 up_read(&list_rwsem);
0419 dbg("inserted=%d, extracted=%d, extracting=%d",
0420 inserted, extracted, atomic_read(&extracting));
0421 if (inserted || extracted)
0422 return extracted;
0423 else if (!atomic_read(&extracting)) {
0424 err("cannot find ENUM# source, shutting down");
0425 return -1;
0426 }
0427 return 0;
0428 }
0429
0430
0431 static int
0432 event_thread(void *data)
0433 {
0434 int rc;
0435
0436 dbg("%s - event thread started", __func__);
0437 while (1) {
0438 dbg("event thread sleeping");
0439 set_current_state(TASK_INTERRUPTIBLE);
0440 schedule();
0441 if (kthread_should_stop())
0442 break;
0443 do {
0444 rc = check_slots();
0445 if (rc > 0) {
0446
0447 msleep(500);
0448 } else if (rc < 0) {
0449 dbg("%s - error checking slots", __func__);
0450 thread_finished = 1;
0451 goto out;
0452 }
0453 } while (atomic_read(&extracting) && !kthread_should_stop());
0454 if (kthread_should_stop())
0455 break;
0456
0457
0458 dbg("%s - re-enabling irq", __func__);
0459 controller->ops->enable_irq();
0460 }
0461 out:
0462 return 0;
0463 }
0464
0465
0466 static int
0467 poll_thread(void *data)
0468 {
0469 int rc;
0470
0471 while (1) {
0472 if (kthread_should_stop() || signal_pending(current))
0473 break;
0474 if (controller->ops->query_enum()) {
0475 do {
0476 rc = check_slots();
0477 if (rc > 0) {
0478
0479 msleep(500);
0480 } else if (rc < 0) {
0481 dbg("%s - error checking slots", __func__);
0482 thread_finished = 1;
0483 goto out;
0484 }
0485 } while (atomic_read(&extracting) && !kthread_should_stop());
0486 }
0487 msleep(100);
0488 }
0489 out:
0490 return 0;
0491 }
0492
0493 static int
0494 cpci_start_thread(void)
0495 {
0496 if (controller->irq)
0497 cpci_thread = kthread_run(event_thread, NULL, "cpci_hp_eventd");
0498 else
0499 cpci_thread = kthread_run(poll_thread, NULL, "cpci_hp_polld");
0500 if (IS_ERR(cpci_thread)) {
0501 err("Can't start up our thread");
0502 return PTR_ERR(cpci_thread);
0503 }
0504 thread_finished = 0;
0505 return 0;
0506 }
0507
0508 static void
0509 cpci_stop_thread(void)
0510 {
0511 kthread_stop(cpci_thread);
0512 thread_finished = 1;
0513 }
0514
0515 int
0516 cpci_hp_register_controller(struct cpci_hp_controller *new_controller)
0517 {
0518 int status = 0;
0519
0520 if (controller)
0521 return -1;
0522 if (!(new_controller && new_controller->ops))
0523 return -EINVAL;
0524 if (new_controller->irq) {
0525 if (!(new_controller->ops->enable_irq &&
0526 new_controller->ops->disable_irq))
0527 status = -EINVAL;
0528 if (request_irq(new_controller->irq,
0529 cpci_hp_intr,
0530 new_controller->irq_flags,
0531 MY_NAME,
0532 new_controller->dev_id)) {
0533 err("Can't get irq %d for the hotplug cPCI controller",
0534 new_controller->irq);
0535 status = -ENODEV;
0536 }
0537 dbg("%s - acquired controller irq %d",
0538 __func__, new_controller->irq);
0539 }
0540 if (!status)
0541 controller = new_controller;
0542 return status;
0543 }
0544 EXPORT_SYMBOL_GPL(cpci_hp_register_controller);
0545
0546 static void
0547 cleanup_slots(void)
0548 {
0549 struct slot *slot;
0550 struct slot *tmp;
0551
0552
0553
0554
0555
0556 down_write(&list_rwsem);
0557 if (!slots)
0558 goto cleanup_null;
0559 list_for_each_entry_safe(slot, tmp, &slot_list, slot_list) {
0560 list_del(&slot->slot_list);
0561 pci_hp_deregister(&slot->hotplug_slot);
0562 release_slot(slot);
0563 }
0564 cleanup_null:
0565 up_write(&list_rwsem);
0566 }
0567
0568 int
0569 cpci_hp_unregister_controller(struct cpci_hp_controller *old_controller)
0570 {
0571 int status = 0;
0572
0573 if (controller) {
0574 if (!thread_finished)
0575 cpci_stop_thread();
0576 if (controller->irq)
0577 free_irq(controller->irq, controller->dev_id);
0578 controller = NULL;
0579 cleanup_slots();
0580 } else
0581 status = -ENODEV;
0582 return status;
0583 }
0584 EXPORT_SYMBOL_GPL(cpci_hp_unregister_controller);
0585
0586 int
0587 cpci_hp_start(void)
0588 {
0589 static int first = 1;
0590 int status;
0591
0592 dbg("%s - enter", __func__);
0593 if (!controller)
0594 return -ENODEV;
0595
0596 down_read(&list_rwsem);
0597 if (list_empty(&slot_list)) {
0598 up_read(&list_rwsem);
0599 return -ENODEV;
0600 }
0601 up_read(&list_rwsem);
0602
0603 status = init_slots(first);
0604 if (first)
0605 first = 0;
0606 if (status)
0607 return status;
0608
0609 status = cpci_start_thread();
0610 if (status)
0611 return status;
0612 dbg("%s - thread started", __func__);
0613
0614 if (controller->irq) {
0615
0616 dbg("%s - enabling irq", __func__);
0617 controller->ops->enable_irq();
0618 }
0619 dbg("%s - exit", __func__);
0620 return 0;
0621 }
0622 EXPORT_SYMBOL_GPL(cpci_hp_start);
0623
0624 int
0625 cpci_hp_stop(void)
0626 {
0627 if (!controller)
0628 return -ENODEV;
0629 if (controller->irq) {
0630
0631 dbg("%s - disabling irq", __func__);
0632 controller->ops->disable_irq();
0633 }
0634 cpci_stop_thread();
0635 return 0;
0636 }
0637 EXPORT_SYMBOL_GPL(cpci_hp_stop);
0638
0639 int __init
0640 cpci_hotplug_init(int debug)
0641 {
0642 cpci_debug = debug;
0643 return 0;
0644 }