linux/drivers/pci/hotplug/pciehp_core.c
<<
>>
Prefs
   1/*
   2 * PCI Express Hot Plug Controller Driver
   3 *
   4 * Copyright (C) 1995,2001 Compaq Computer Corporation
   5 * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
   6 * Copyright (C) 2001 IBM Corp.
   7 * Copyright (C) 2003-2004 Intel Corporation
   8 *
   9 * All rights reserved.
  10 *
  11 * This program is free software; you can redistribute it and/or modify
  12 * it under the terms of the GNU General Public License as published by
  13 * the Free Software Foundation; either version 2 of the License, or (at
  14 * your option) any later version.
  15 *
  16 * This program is distributed in the hope that it will be useful, but
  17 * WITHOUT ANY WARRANTY; without even the implied warranty of
  18 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  19 * NON INFRINGEMENT.  See the GNU General Public License for more
  20 * details.
  21 *
  22 * You should have received a copy of the GNU General Public License
  23 * along with this program; if not, write to the Free Software
  24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25 *
  26 * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com>
  27 *
  28 */
  29
  30#include <linux/moduleparam.h>
  31#include <linux/kernel.h>
  32#include <linux/slab.h>
  33#include <linux/types.h>
  34#include <linux/pci.h>
  35#include "pciehp.h"
  36#include <linux/interrupt.h>
  37#include <linux/time.h>
  38
  39/* Global variables */
  40bool pciehp_debug;
  41bool pciehp_poll_mode;
  42int pciehp_poll_time;
  43static bool pciehp_force;
  44
  45#define DRIVER_VERSION  "0.4"
  46#define DRIVER_AUTHOR   "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>"
  47#define DRIVER_DESC     "PCI Express Hot Plug Controller Driver"
  48
  49/*
  50 * not really modular, but the easiest way to keep compat with existing
  51 * bootargs behaviour is to continue using module_param here.
  52 */
  53module_param(pciehp_debug, bool, 0644);
  54module_param(pciehp_poll_mode, bool, 0644);
  55module_param(pciehp_poll_time, int, 0644);
  56module_param(pciehp_force, bool, 0644);
  57MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not");
  58MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not");
  59MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds");
  60MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if OSHP is missing");
  61
  62#define PCIE_MODULE_NAME "pciehp"
  63
  64static int set_attention_status(struct hotplug_slot *slot, u8 value);
  65static int enable_slot(struct hotplug_slot *slot);
  66static int disable_slot(struct hotplug_slot *slot);
  67static int get_power_status(struct hotplug_slot *slot, u8 *value);
  68static int get_attention_status(struct hotplug_slot *slot, u8 *value);
  69static int get_latch_status(struct hotplug_slot *slot, u8 *value);
  70static int get_adapter_status(struct hotplug_slot *slot, u8 *value);
  71static int reset_slot(struct hotplug_slot *slot, int probe);
  72
  73/**
  74 * release_slot - free up the memory used by a slot
  75 * @hotplug_slot: slot to free
  76 */
  77static void release_slot(struct hotplug_slot *hotplug_slot)
  78{
  79        kfree(hotplug_slot->ops);
  80        kfree(hotplug_slot->info);
  81        kfree(hotplug_slot);
  82}
  83
  84static int init_slot(struct controller *ctrl)
  85{
  86        struct slot *slot = ctrl->slot;
  87        struct hotplug_slot *hotplug = NULL;
  88        struct hotplug_slot_info *info = NULL;
  89        struct hotplug_slot_ops *ops = NULL;
  90        char name[SLOT_NAME_SIZE];
  91        int retval = -ENOMEM;
  92
  93        hotplug = kzalloc(sizeof(*hotplug), GFP_KERNEL);
  94        if (!hotplug)
  95                goto out;
  96
  97        info = kzalloc(sizeof(*info), GFP_KERNEL);
  98        if (!info)
  99                goto out;
 100
 101        /* Setup hotplug slot ops */
 102        ops = kzalloc(sizeof(*ops), GFP_KERNEL);
 103        if (!ops)
 104                goto out;
 105
 106        ops->enable_slot = enable_slot;
 107        ops->disable_slot = disable_slot;
 108        ops->get_power_status = get_power_status;
 109        ops->get_adapter_status = get_adapter_status;
 110        ops->reset_slot = reset_slot;
 111        if (MRL_SENS(ctrl))
 112                ops->get_latch_status = get_latch_status;
 113        if (ATTN_LED(ctrl)) {
 114                ops->get_attention_status = get_attention_status;
 115                ops->set_attention_status = set_attention_status;
 116        } else if (ctrl->pcie->port->hotplug_user_indicators) {
 117                ops->get_attention_status = pciehp_get_raw_indicator_status;
 118                ops->set_attention_status = pciehp_set_raw_indicator_status;
 119        }
 120
 121        /* register this slot with the hotplug pci core */
 122        hotplug->info = info;
 123        hotplug->private = slot;
 124        hotplug->release = &release_slot;
 125        hotplug->ops = ops;
 126        slot->hotplug_slot = hotplug;
 127        snprintf(name, SLOT_NAME_SIZE, "%u", PSN(ctrl));
 128
 129        retval = pci_hp_register(hotplug,
 130                                 ctrl->pcie->port->subordinate, 0, name);
 131        if (retval)
 132                ctrl_err(ctrl, "pci_hp_register failed: error %d\n", retval);
 133out:
 134        if (retval) {
 135                kfree(ops);
 136                kfree(info);
 137                kfree(hotplug);
 138        }
 139        return retval;
 140}
 141
 142static void cleanup_slot(struct controller *ctrl)
 143{
 144        pci_hp_deregister(ctrl->slot->hotplug_slot);
 145}
 146
 147/*
 148 * set_attention_status - Turns the Amber LED for a slot on, off or blink
 149 */
 150static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
 151{
 152        struct slot *slot = hotplug_slot->private;
 153
 154        pciehp_set_attention_status(slot, status);
 155        return 0;
 156}
 157
 158
 159static int enable_slot(struct hotplug_slot *hotplug_slot)
 160{
 161        struct slot *slot = hotplug_slot->private;
 162
 163        return pciehp_sysfs_enable_slot(slot);
 164}
 165
 166
 167static int disable_slot(struct hotplug_slot *hotplug_slot)
 168{
 169        struct slot *slot = hotplug_slot->private;
 170
 171        return pciehp_sysfs_disable_slot(slot);
 172}
 173
 174static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
 175{
 176        struct slot *slot = hotplug_slot->private;
 177
 178        pciehp_get_power_status(slot, value);
 179        return 0;
 180}
 181
 182static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
 183{
 184        struct slot *slot = hotplug_slot->private;
 185
 186        pciehp_get_attention_status(slot, value);
 187        return 0;
 188}
 189
 190static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
 191{
 192        struct slot *slot = hotplug_slot->private;
 193
 194        pciehp_get_latch_status(slot, value);
 195        return 0;
 196}
 197
 198static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
 199{
 200        struct slot *slot = hotplug_slot->private;
 201
 202        pciehp_get_adapter_status(slot, value);
 203        return 0;
 204}
 205
 206static int reset_slot(struct hotplug_slot *hotplug_slot, int probe)
 207{
 208        struct slot *slot = hotplug_slot->private;
 209
 210        return pciehp_reset_slot(slot, probe);
 211}
 212
 213static int pciehp_probe(struct pcie_device *dev)
 214{
 215        int rc;
 216        struct controller *ctrl;
 217        struct slot *slot;
 218        u8 occupied, poweron;
 219
 220        /* If this is not a "hotplug" service, we have no business here. */
 221        if (dev->service != PCIE_PORT_SERVICE_HP)
 222                return -ENODEV;
 223
 224        if (!dev->port->subordinate) {
 225                /* Can happen if we run out of bus numbers during probe */
 226                dev_err(&dev->device,
 227                        "Hotplug bridge without secondary bus, ignoring\n");
 228                return -ENODEV;
 229        }
 230
 231        ctrl = pcie_init(dev);
 232        if (!ctrl) {
 233                dev_err(&dev->device, "Controller initialization failed\n");
 234                return -ENODEV;
 235        }
 236        set_service_data(dev, ctrl);
 237
 238        /* Setup the slot information structures */
 239        rc = init_slot(ctrl);
 240        if (rc) {
 241                if (rc == -EBUSY)
 242                        ctrl_warn(ctrl, "Slot already registered by another hotplug driver\n");
 243                else
 244                        ctrl_err(ctrl, "Slot initialization failed (%d)\n", rc);
 245                goto err_out_release_ctlr;
 246        }
 247
 248        /* Enable events after we have setup the data structures */
 249        rc = pcie_init_notification(ctrl);
 250        if (rc) {
 251                ctrl_err(ctrl, "Notification initialization failed (%d)\n", rc);
 252                goto err_out_free_ctrl_slot;
 253        }
 254
 255        /* Check if slot is occupied */
 256        slot = ctrl->slot;
 257        pciehp_get_adapter_status(slot, &occupied);
 258        pciehp_get_power_status(slot, &poweron);
 259        if (occupied && pciehp_force) {
 260                mutex_lock(&slot->hotplug_lock);
 261                pciehp_enable_slot(slot);
 262                mutex_unlock(&slot->hotplug_lock);
 263        }
 264        /* If empty slot's power status is on, turn power off */
 265        if (!occupied && poweron && POWER_CTRL(ctrl))
 266                pciehp_power_off_slot(slot);
 267
 268        return 0;
 269
 270err_out_free_ctrl_slot:
 271        cleanup_slot(ctrl);
 272err_out_release_ctlr:
 273        pciehp_release_ctrl(ctrl);
 274        return -ENODEV;
 275}
 276
 277static void pciehp_remove(struct pcie_device *dev)
 278{
 279        struct controller *ctrl = get_service_data(dev);
 280
 281        cleanup_slot(ctrl);
 282        pciehp_release_ctrl(ctrl);
 283}
 284
 285#ifdef CONFIG_PM
 286static int pciehp_suspend(struct pcie_device *dev)
 287{
 288        return 0;
 289}
 290
 291static int pciehp_resume(struct pcie_device *dev)
 292{
 293        struct controller *ctrl;
 294        struct slot *slot;
 295        u8 status;
 296
 297        ctrl = get_service_data(dev);
 298
 299        /* reinitialize the chipset's event detection logic */
 300        pcie_enable_notification(ctrl);
 301
 302        slot = ctrl->slot;
 303
 304        /* Check if slot is occupied */
 305        pciehp_get_adapter_status(slot, &status);
 306        mutex_lock(&slot->hotplug_lock);
 307        if (status)
 308                pciehp_enable_slot(slot);
 309        else
 310                pciehp_disable_slot(slot);
 311        mutex_unlock(&slot->hotplug_lock);
 312        return 0;
 313}
 314#endif /* PM */
 315
 316static struct pcie_port_service_driver hpdriver_portdrv = {
 317        .name           = PCIE_MODULE_NAME,
 318        .port_type      = PCIE_ANY_PORT,
 319        .service        = PCIE_PORT_SERVICE_HP,
 320
 321        .probe          = pciehp_probe,
 322        .remove         = pciehp_remove,
 323
 324#ifdef  CONFIG_PM
 325        .suspend        = pciehp_suspend,
 326        .resume         = pciehp_resume,
 327#endif  /* PM */
 328};
 329
 330static int __init pcied_init(void)
 331{
 332        int retval = 0;
 333
 334        retval = pcie_port_service_register(&hpdriver_portdrv);
 335        dbg("pcie_port_service_register = %d\n", retval);
 336        info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
 337        if (retval)
 338                dbg("Failure to register service\n");
 339
 340        return retval;
 341}
 342device_initcall(pcied_init);
 343
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.