root/drivers/pci/hotplug/cpci_hotplug_core.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. enable_slot
  2. disable_slot
  3. cpci_get_power_status
  4. get_power_status
  5. get_attention_status
  6. set_attention_status
  7. get_adapter_status
  8. get_latch_status
  9. release_slot
  10. cpci_hp_register_bus
  11. cpci_hp_unregister_bus
  12. cpci_hp_intr
  13. init_slots
  14. check_slots
  15. event_thread
  16. poll_thread
  17. cpci_start_thread
  18. cpci_stop_thread
  19. cpci_hp_register_controller
  20. cleanup_slots
  21. cpci_hp_unregister_controller
  22. cpci_hp_start
  23. cpci_hp_stop
  24. cpci_hotplug_init

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

/* [<][>][^][v][top][bottom][index][help] */