linux/drivers/pci/hotplug/pciehp_core.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * PCI Express Hot Plug Controller Driver
   4 *
   5 * Copyright (C) 1995,2001 Compaq Computer Corporation
   6 * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
   7 * Copyright (C) 2001 IBM Corp.
   8 * Copyright (C) 2003-2004 Intel Corporation
   9 *
  10 * All rights reserved.
  11 *
  12 * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com>
  13 *
  14 * Authors:
  15 *   Dan Zink <dan.zink@compaq.com>
  16 *   Greg Kroah-Hartman <greg@kroah.com>
  17 *   Dely Sy <dely.l.sy@intel.com>"
  18 */
  19
  20#include <linux/moduleparam.h>
  21#include <linux/kernel.h>
  22#include <linux/slab.h>
  23#include <linux/types.h>
  24#include <linux/pci.h>
  25#include "pciehp.h"
  26#include <linux/interrupt.h>
  27#include <linux/time.h>
  28
  29#include "../pci.h"
  30
  31/* Global variables */
  32bool pciehp_debug;
  33bool pciehp_poll_mode;
  34int pciehp_poll_time;
  35
  36/*
  37 * not really modular, but the easiest way to keep compat with existing
  38 * bootargs behaviour is to continue using module_param here.
  39 */
  40module_param(pciehp_debug, bool, 0644);
  41module_param(pciehp_poll_mode, bool, 0644);
  42module_param(pciehp_poll_time, int, 0644);
  43MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not");
  44MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not");
  45MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds");
  46
  47#define PCIE_MODULE_NAME "pciehp"
  48
  49static int set_attention_status(struct hotplug_slot *slot, u8 value);
  50static int enable_slot(struct hotplug_slot *slot);
  51static int disable_slot(struct hotplug_slot *slot);
  52static int get_power_status(struct hotplug_slot *slot, u8 *value);
  53static int get_attention_status(struct hotplug_slot *slot, u8 *value);
  54static int get_latch_status(struct hotplug_slot *slot, u8 *value);
  55static int get_adapter_status(struct hotplug_slot *slot, u8 *value);
  56static int reset_slot(struct hotplug_slot *slot, int probe);
  57
  58static int init_slot(struct controller *ctrl)
  59{
  60        struct slot *slot = ctrl->slot;
  61        struct hotplug_slot *hotplug = NULL;
  62        struct hotplug_slot_info *info = NULL;
  63        struct hotplug_slot_ops *ops = NULL;
  64        char name[SLOT_NAME_SIZE];
  65        int retval = -ENOMEM;
  66
  67        hotplug = kzalloc(sizeof(*hotplug), GFP_KERNEL);
  68        if (!hotplug)
  69                goto out;
  70
  71        info = kzalloc(sizeof(*info), GFP_KERNEL);
  72        if (!info)
  73                goto out;
  74
  75        /* Setup hotplug slot ops */
  76        ops = kzalloc(sizeof(*ops), GFP_KERNEL);
  77        if (!ops)
  78                goto out;
  79
  80        ops->enable_slot = enable_slot;
  81        ops->disable_slot = disable_slot;
  82        ops->get_power_status = get_power_status;
  83        ops->get_adapter_status = get_adapter_status;
  84        ops->reset_slot = reset_slot;
  85        if (MRL_SENS(ctrl))
  86                ops->get_latch_status = get_latch_status;
  87        if (ATTN_LED(ctrl)) {
  88                ops->get_attention_status = get_attention_status;
  89                ops->set_attention_status = set_attention_status;
  90        } else if (ctrl->pcie->port->hotplug_user_indicators) {
  91                ops->get_attention_status = pciehp_get_raw_indicator_status;
  92                ops->set_attention_status = pciehp_set_raw_indicator_status;
  93        }
  94
  95        /* register this slot with the hotplug pci core */
  96        hotplug->info = info;
  97        hotplug->private = slot;
  98        hotplug->ops = ops;
  99        slot->hotplug_slot = hotplug;
 100        snprintf(name, SLOT_NAME_SIZE, "%u", PSN(ctrl));
 101
 102        retval = pci_hp_initialize(hotplug,
 103                                   ctrl->pcie->port->subordinate, 0, name);
 104        if (retval)
 105                ctrl_err(ctrl, "pci_hp_initialize failed: error %d\n", retval);
 106out:
 107        if (retval) {
 108                kfree(ops);
 109                kfree(info);
 110                kfree(hotplug);
 111        }
 112        return retval;
 113}
 114
 115static void cleanup_slot(struct controller *ctrl)
 116{
 117        struct hotplug_slot *hotplug_slot = ctrl->slot->hotplug_slot;
 118
 119        pci_hp_destroy(hotplug_slot);
 120        kfree(hotplug_slot->ops);
 121        kfree(hotplug_slot->info);
 122        kfree(hotplug_slot);
 123}
 124
 125/*
 126 * set_attention_status - Turns the Amber LED for a slot on, off or blink
 127 */
 128static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
 129{
 130        struct slot *slot = hotplug_slot->private;
 131        struct pci_dev *pdev = slot->ctrl->pcie->port;
 132
 133        pci_config_pm_runtime_get(pdev);
 134        pciehp_set_attention_status(slot, status);
 135        pci_config_pm_runtime_put(pdev);
 136        return 0;
 137}
 138
 139
 140static int enable_slot(struct hotplug_slot *hotplug_slot)
 141{
 142        struct slot *slot = hotplug_slot->private;
 143
 144        return pciehp_sysfs_enable_slot(slot);
 145}
 146
 147
 148static int disable_slot(struct hotplug_slot *hotplug_slot)
 149{
 150        struct slot *slot = hotplug_slot->private;
 151
 152        return pciehp_sysfs_disable_slot(slot);
 153}
 154
 155static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
 156{
 157        struct slot *slot = hotplug_slot->private;
 158        struct pci_dev *pdev = slot->ctrl->pcie->port;
 159
 160        pci_config_pm_runtime_get(pdev);
 161        pciehp_get_power_status(slot, value);
 162        pci_config_pm_runtime_put(pdev);
 163        return 0;
 164}
 165
 166static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
 167{
 168        struct slot *slot = hotplug_slot->private;
 169
 170        pciehp_get_attention_status(slot, value);
 171        return 0;
 172}
 173
 174static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
 175{
 176        struct slot *slot = hotplug_slot->private;
 177        struct pci_dev *pdev = slot->ctrl->pcie->port;
 178
 179        pci_config_pm_runtime_get(pdev);
 180        pciehp_get_latch_status(slot, value);
 181        pci_config_pm_runtime_put(pdev);
 182        return 0;
 183}
 184
 185static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
 186{
 187        struct slot *slot = hotplug_slot->private;
 188        struct pci_dev *pdev = slot->ctrl->pcie->port;
 189
 190        pci_config_pm_runtime_get(pdev);
 191        pciehp_get_adapter_status(slot, value);
 192        pci_config_pm_runtime_put(pdev);
 193        return 0;
 194}
 195
 196static int reset_slot(struct hotplug_slot *hotplug_slot, int probe)
 197{
 198        struct slot *slot = hotplug_slot->private;
 199
 200        return pciehp_reset_slot(slot, probe);
 201}
 202
 203/**
 204 * pciehp_check_presence() - synthesize event if presence has changed
 205 *
 206 * On probe and resume, an explicit presence check is necessary to bring up an
 207 * occupied slot or bring down an unoccupied slot.  This can't be triggered by
 208 * events in the Slot Status register, they may be stale and are therefore
 209 * cleared.  Secondly, sending an interrupt for "events that occur while
 210 * interrupt generation is disabled [when] interrupt generation is subsequently
 211 * enabled" is optional per PCIe r4.0, sec 6.7.3.4.
 212 */
 213static void pciehp_check_presence(struct controller *ctrl)
 214{
 215        struct slot *slot = ctrl->slot;
 216        u8 occupied;
 217
 218        down_read(&ctrl->reset_lock);
 219        mutex_lock(&slot->lock);
 220
 221        pciehp_get_adapter_status(slot, &occupied);
 222        if ((occupied && (slot->state == OFF_STATE ||
 223                          slot->state == BLINKINGON_STATE)) ||
 224            (!occupied && (slot->state == ON_STATE ||
 225                           slot->state == BLINKINGOFF_STATE)))
 226                pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC);
 227
 228        mutex_unlock(&slot->lock);
 229        up_read(&ctrl->reset_lock);
 230}
 231
 232static int pciehp_probe(struct pcie_device *dev)
 233{
 234        int rc;
 235        struct controller *ctrl;
 236        struct slot *slot;
 237
 238        /* If this is not a "hotplug" service, we have no business here. */
 239        if (dev->service != PCIE_PORT_SERVICE_HP)
 240                return -ENODEV;
 241
 242        if (!dev->port->subordinate) {
 243                /* Can happen if we run out of bus numbers during probe */
 244                dev_err(&dev->device,
 245                        "Hotplug bridge without secondary bus, ignoring\n");
 246                return -ENODEV;
 247        }
 248
 249        ctrl = pcie_init(dev);
 250        if (!ctrl) {
 251                dev_err(&dev->device, "Controller initialization failed\n");
 252                return -ENODEV;
 253        }
 254        set_service_data(dev, ctrl);
 255
 256        /* Setup the slot information structures */
 257        rc = init_slot(ctrl);
 258        if (rc) {
 259                if (rc == -EBUSY)
 260                        ctrl_warn(ctrl, "Slot already registered by another hotplug driver\n");
 261                else
 262                        ctrl_err(ctrl, "Slot initialization failed (%d)\n", rc);
 263                goto err_out_release_ctlr;
 264        }
 265
 266        /* Enable events after we have setup the data structures */
 267        rc = pcie_init_notification(ctrl);
 268        if (rc) {
 269                ctrl_err(ctrl, "Notification initialization failed (%d)\n", rc);
 270                goto err_out_free_ctrl_slot;
 271        }
 272
 273        /* Publish to user space */
 274        slot = ctrl->slot;
 275        rc = pci_hp_add(slot->hotplug_slot);
 276        if (rc) {
 277                ctrl_err(ctrl, "Publication to user space failed (%d)\n", rc);
 278                goto err_out_shutdown_notification;
 279        }
 280
 281        pciehp_check_presence(ctrl);
 282
 283        return 0;
 284
 285err_out_shutdown_notification:
 286        pcie_shutdown_notification(ctrl);
 287err_out_free_ctrl_slot:
 288        cleanup_slot(ctrl);
 289err_out_release_ctlr:
 290        pciehp_release_ctrl(ctrl);
 291        return -ENODEV;
 292}
 293
 294static void pciehp_remove(struct pcie_device *dev)
 295{
 296        struct controller *ctrl = get_service_data(dev);
 297
 298        pci_hp_del(ctrl->slot->hotplug_slot);
 299        pcie_shutdown_notification(ctrl);
 300        cleanup_slot(ctrl);
 301        pciehp_release_ctrl(ctrl);
 302}
 303
 304#ifdef CONFIG_PM
 305static int pciehp_suspend(struct pcie_device *dev)
 306{
 307        return 0;
 308}
 309
 310static int pciehp_resume_noirq(struct pcie_device *dev)
 311{
 312        struct controller *ctrl = get_service_data(dev);
 313        struct slot *slot = ctrl->slot;
 314
 315        /* pci_restore_state() just wrote to the Slot Control register */
 316        ctrl->cmd_started = jiffies;
 317        ctrl->cmd_busy = true;
 318
 319        /* clear spurious events from rediscovery of inserted card */
 320        if (slot->state == ON_STATE || slot->state == BLINKINGOFF_STATE)
 321                pcie_clear_hotplug_events(ctrl);
 322
 323        return 0;
 324}
 325
 326static int pciehp_resume(struct pcie_device *dev)
 327{
 328        struct controller *ctrl = get_service_data(dev);
 329
 330        pciehp_check_presence(ctrl);
 331
 332        return 0;
 333}
 334#endif /* PM */
 335
 336static struct pcie_port_service_driver hpdriver_portdrv = {
 337        .name           = PCIE_MODULE_NAME,
 338        .port_type      = PCIE_ANY_PORT,
 339        .service        = PCIE_PORT_SERVICE_HP,
 340
 341        .probe          = pciehp_probe,
 342        .remove         = pciehp_remove,
 343
 344#ifdef  CONFIG_PM
 345        .suspend        = pciehp_suspend,
 346        .resume_noirq   = pciehp_resume_noirq,
 347        .resume         = pciehp_resume,
 348#endif  /* PM */
 349};
 350
 351static int __init pcied_init(void)
 352{
 353        int retval = 0;
 354
 355        retval = pcie_port_service_register(&hpdriver_portdrv);
 356        dbg("pcie_port_service_register = %d\n", retval);
 357        if (retval)
 358                dbg("Failure to register service\n");
 359
 360        return retval;
 361}
 362device_initcall(pcied_init);
 363