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