Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * CompactPCI Hot Plug Driver
0004  *
0005  * Copyright (C) 2002,2005 SOMA Networks, Inc.
0006  * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
0007  * Copyright (C) 2001 IBM Corp.
0008  *
0009  * All rights reserved.
0010  *
0011  * Send feedback to <scottm@somanetworks.com>
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 /* local variables */
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     /* Unconfigure device */
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     /* Clear EXT (by setting it) */
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      * Create a structure for each slot, and register that slot
0202      * with the pci_hotplug subsystem.
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         /* Add slot to our internal list */
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 /* This is the interrupt mode interrupt handler */
0269 static irqreturn_t
0270 cpci_hp_intr(int irq, void *data)
0271 {
0272     dbg("entered cpci_hp_intr");
0273 
0274     /* Check to see if it was our interrupt */
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     /* Disable ENUM interrupt */
0282     controller->ops->disable_irq();
0283 
0284     /* Trigger processing by the event thread */
0285     wake_up_process(cpci_thread);
0286     return IRQ_HANDLED;
0287 }
0288 
0289 /*
0290  * According to PICMG 2.1 R2.0, section 6.3.2, upon
0291  * initialization, the system driver shall clear the
0292  * INS bits of the cold-inserted devices.
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              * Some broken hardware (e.g. PLX 9054AB) asserts
0343              * ENUM# twice...
0344              */
0345             if (slot->dev) {
0346                 warn("slot %s already inserted",
0347                      slot_name(slot));
0348                 inserted++;
0349                 continue;
0350             }
0351 
0352             /* Process insertion */
0353             dbg("%s - slot %s inserted", __func__, slot_name(slot));
0354 
0355             /* GSM, debug */
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             /* Configure device */
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             /* GSM, debug */
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             /* GSM, debug */
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             /* Process extraction request */
0389             dbg("%s - slot %s extracted",
0390                 __func__, slot_name(slot));
0391 
0392             /* GSM, debug */
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                  * Hmmm, we're likely hosed at this point, should we
0408                  * bother trying to tell the driver or not?
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 /* This is the interrupt mode worker thread body */
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                 /* Give userspace a chance to handle extraction */
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         /* Re-enable ENUM# interrupt */
0458         dbg("%s - re-enabling irq", __func__);
0459         controller->ops->enable_irq();
0460     }
0461  out:
0462     return 0;
0463 }
0464 
0465 /* This is the polling mode worker thread body */
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                     /* Give userspace a chance to handle extraction */
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      * Unregister all of our slots with the pci_hotplug subsystem,
0554      * and free up all memory that we had allocated.
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         /* Start enum interrupt processing */
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         /* Stop enum interrupt processing */
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 }