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#define pr_fmt(fmt) "pciehp: " fmt
  21#define dev_fmt pr_fmt
  22
  23#include <linux/moduleparam.h>
  24#include <linux/kernel.h>
  25#include <linux/slab.h>
  26#include <linux/types.h>
  27#include <linux/pci.h>
  28#include "pciehp.h"
  29
  30#include "../pci.h"
  31
  32/* Global variables */
  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_poll_mode, bool, 0644);
  41module_param(pciehp_poll_time, int, 0644);
  42MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not");
  43MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds");
  44
  45static int set_attention_status(struct hotplug_slot *slot, u8 value);
  46static int get_power_status(struct hotplug_slot *slot, u8 *value);
  47static int get_latch_status(struct hotplug_slot *slot, u8 *value);
  48static int get_adapter_status(struct hotplug_slot *slot, u8 *value);
  49
  50static int init_slot(struct controller *ctrl)
  51{
  52        struct hotplug_slot_ops *ops;
  53        char name[SLOT_NAME_SIZE];
  54        int retval;
  55
  56        /* Setup hotplug slot ops */
  57        ops = kzalloc(sizeof(*ops), GFP_KERNEL);
  58        if (!ops)
  59                return -ENOMEM;
  60
  61        ops->enable_slot = pciehp_sysfs_enable_slot;
  62        ops->disable_slot = pciehp_sysfs_disable_slot;
  63        ops->get_power_status = get_power_status;
  64        ops->get_adapter_status = get_adapter_status;
  65        ops->reset_slot = pciehp_reset_slot;
  66        if (MRL_SENS(ctrl))
  67                ops->get_latch_status = get_latch_status;
  68        if (ATTN_LED(ctrl)) {
  69                ops->get_attention_status = pciehp_get_attention_status;
  70                ops->set_attention_status = set_attention_status;
  71        } else if (ctrl->pcie->port->hotplug_user_indicators) {
  72                ops->get_attention_status = pciehp_get_raw_indicator_status;
  73                ops->set_attention_status = pciehp_set_raw_indicator_status;
  74        }
  75
  76        /* register this slot with the hotplug pci core */
  77        ctrl->hotplug_slot.ops = ops;
  78        snprintf(name, SLOT_NAME_SIZE, "%u", PSN(ctrl));
  79
  80        retval = pci_hp_initialize(&ctrl->hotplug_slot,
  81                                   ctrl->pcie->port->subordinate, 0, name);
  82        if (retval) {
  83                ctrl_err(ctrl, "pci_hp_initialize failed: error %d\n", retval);
  84                kfree(ops);
  85        }
  86        return retval;
  87}
  88
  89static void cleanup_slot(struct controller *ctrl)
  90{
  91        struct hotplug_slot *hotplug_slot = &ctrl->hotplug_slot;
  92
  93        pci_hp_destroy(hotplug_slot);
  94        kfree(hotplug_slot->ops);
  95}
  96
  97/*
  98 * set_attention_status - Turns the Attention Indicator on, off or blinking
  99 */
 100static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
 101{
 102        struct controller *ctrl = to_ctrl(hotplug_slot);
 103        struct pci_dev *pdev = ctrl->pcie->port;
 104
 105        if (status)
 106                status <<= PCI_EXP_SLTCTL_ATTN_IND_SHIFT;
 107        else
 108                status = PCI_EXP_SLTCTL_ATTN_IND_OFF;
 109
 110        pci_config_pm_runtime_get(pdev);
 111        pciehp_set_indicators(ctrl, INDICATOR_NOOP, status);
 112        pci_config_pm_runtime_put(pdev);
 113        return 0;
 114}
 115
 116static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
 117{
 118        struct controller *ctrl = to_ctrl(hotplug_slot);
 119        struct pci_dev *pdev = ctrl->pcie->port;
 120
 121        pci_config_pm_runtime_get(pdev);
 122        pciehp_get_power_status(ctrl, value);
 123        pci_config_pm_runtime_put(pdev);
 124        return 0;
 125}
 126
 127static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
 128{
 129        struct controller *ctrl = to_ctrl(hotplug_slot);
 130        struct pci_dev *pdev = ctrl->pcie->port;
 131
 132        pci_config_pm_runtime_get(pdev);
 133        pciehp_get_latch_status(ctrl, value);
 134        pci_config_pm_runtime_put(pdev);
 135        return 0;
 136}
 137
 138static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
 139{
 140        struct controller *ctrl = to_ctrl(hotplug_slot);
 141        struct pci_dev *pdev = ctrl->pcie->port;
 142        int ret;
 143
 144        pci_config_pm_runtime_get(pdev);
 145        ret = pciehp_card_present_or_link_active(ctrl);
 146        pci_config_pm_runtime_put(pdev);
 147        if (ret < 0)
 148                return ret;
 149
 150        *value = ret;
 151        return 0;
 152}
 153
 154/**
 155 * pciehp_check_presence() - synthesize event if presence has changed
 156 * @ctrl: controller to check
 157 *
 158 * On probe and resume, an explicit presence check is necessary to bring up an
 159 * occupied slot or bring down an unoccupied slot.  This can't be triggered by
 160 * events in the Slot Status register, they may be stale and are therefore
 161 * cleared.  Secondly, sending an interrupt for "events that occur while
 162 * interrupt generation is disabled [when] interrupt generation is subsequently
 163 * enabled" is optional per PCIe r4.0, sec 6.7.3.4.
 164 */
 165static void pciehp_check_presence(struct controller *ctrl)
 166{
 167        int occupied;
 168
 169        down_read(&ctrl->reset_lock);
 170        mutex_lock(&ctrl->state_lock);
 171
 172        occupied = pciehp_card_present_or_link_active(ctrl);
 173        if ((occupied > 0 && (ctrl->state == OFF_STATE ||
 174                          ctrl->state == BLINKINGON_STATE)) ||
 175            (!occupied && (ctrl->state == ON_STATE ||
 176                           ctrl->state == BLINKINGOFF_STATE)))
 177                pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC);
 178
 179        mutex_unlock(&ctrl->state_lock);
 180        up_read(&ctrl->reset_lock);
 181}
 182
 183static int pciehp_probe(struct pcie_device *dev)
 184{
 185        int rc;
 186        struct controller *ctrl;
 187
 188        /* If this is not a "hotplug" service, we have no business here. */
 189        if (dev->service != PCIE_PORT_SERVICE_HP)
 190                return -ENODEV;
 191
 192        if (!dev->port->subordinate) {
 193                /* Can happen if we run out of bus numbers during probe */
 194                pci_err(dev->port,
 195                        "Hotplug bridge without secondary bus, ignoring\n");
 196                return -ENODEV;
 197        }
 198
 199        ctrl = pcie_init(dev);
 200        if (!ctrl) {
 201                pci_err(dev->port, "Controller initialization failed\n");
 202                return -ENODEV;
 203        }
 204        set_service_data(dev, ctrl);
 205
 206        /* Setup the slot information structures */
 207        rc = init_slot(ctrl);
 208        if (rc) {
 209                if (rc == -EBUSY)
 210                        ctrl_warn(ctrl, "Slot already registered by another hotplug driver\n");
 211                else
 212                        ctrl_err(ctrl, "Slot initialization failed (%d)\n", rc);
 213                goto err_out_release_ctlr;
 214        }
 215
 216        /* Enable events after we have setup the data structures */
 217        rc = pcie_init_notification(ctrl);
 218        if (rc) {
 219                ctrl_err(ctrl, "Notification initialization failed (%d)\n", rc);
 220                goto err_out_free_ctrl_slot;
 221        }
 222
 223        /* Publish to user space */
 224        rc = pci_hp_add(&ctrl->hotplug_slot);
 225        if (rc) {
 226                ctrl_err(ctrl, "Publication to user space failed (%d)\n", rc);
 227                goto err_out_shutdown_notification;
 228        }
 229
 230        pciehp_check_presence(ctrl);
 231
 232        return 0;
 233
 234err_out_shutdown_notification:
 235        pcie_shutdown_notification(ctrl);
 236err_out_free_ctrl_slot:
 237        cleanup_slot(ctrl);
 238err_out_release_ctlr:
 239        pciehp_release_ctrl(ctrl);
 240        return -ENODEV;
 241}
 242
 243static void pciehp_remove(struct pcie_device *dev)
 244{
 245        struct controller *ctrl = get_service_data(dev);
 246
 247        pci_hp_del(&ctrl->hotplug_slot);
 248        pcie_shutdown_notification(ctrl);
 249        cleanup_slot(ctrl);
 250        pciehp_release_ctrl(ctrl);
 251}
 252
 253#ifdef CONFIG_PM
 254static bool pme_is_native(struct pcie_device *dev)
 255{
 256        const struct pci_host_bridge *host;
 257
 258        host = pci_find_host_bridge(dev->port->bus);
 259        return pcie_ports_native || host->native_pme;
 260}
 261
 262static void pciehp_disable_interrupt(struct pcie_device *dev)
 263{
 264        /*
 265         * Disable hotplug interrupt so that it does not trigger
 266         * immediately when the downstream link goes down.
 267         */
 268        if (pme_is_native(dev))
 269                pcie_disable_interrupt(get_service_data(dev));
 270}
 271
 272#ifdef CONFIG_PM_SLEEP
 273static int pciehp_suspend(struct pcie_device *dev)
 274{
 275        /*
 276         * If the port is already runtime suspended we can keep it that
 277         * way.
 278         */
 279        if (dev_pm_skip_suspend(&dev->port->dev))
 280                return 0;
 281
 282        pciehp_disable_interrupt(dev);
 283        return 0;
 284}
 285
 286static int pciehp_resume_noirq(struct pcie_device *dev)
 287{
 288        struct controller *ctrl = get_service_data(dev);
 289
 290        /* pci_restore_state() just wrote to the Slot Control register */
 291        ctrl->cmd_started = jiffies;
 292        ctrl->cmd_busy = true;
 293
 294        /* clear spurious events from rediscovery of inserted card */
 295        if (ctrl->state == ON_STATE || ctrl->state == BLINKINGOFF_STATE)
 296                pcie_clear_hotplug_events(ctrl);
 297
 298        return 0;
 299}
 300#endif
 301
 302static int pciehp_resume(struct pcie_device *dev)
 303{
 304        struct controller *ctrl = get_service_data(dev);
 305
 306        if (pme_is_native(dev))
 307                pcie_enable_interrupt(ctrl);
 308
 309        pciehp_check_presence(ctrl);
 310
 311        return 0;
 312}
 313
 314static int pciehp_runtime_suspend(struct pcie_device *dev)
 315{
 316        pciehp_disable_interrupt(dev);
 317        return 0;
 318}
 319
 320static int pciehp_runtime_resume(struct pcie_device *dev)
 321{
 322        struct controller *ctrl = get_service_data(dev);
 323
 324        /* pci_restore_state() just wrote to the Slot Control register */
 325        ctrl->cmd_started = jiffies;
 326        ctrl->cmd_busy = true;
 327
 328        /* clear spurious events from rediscovery of inserted card */
 329        if ((ctrl->state == ON_STATE || ctrl->state == BLINKINGOFF_STATE) &&
 330             pme_is_native(dev))
 331                pcie_clear_hotplug_events(ctrl);
 332
 333        return pciehp_resume(dev);
 334}
 335#endif /* PM */
 336
 337static struct pcie_port_service_driver hpdriver_portdrv = {
 338        .name           = "pciehp",
 339        .port_type      = PCIE_ANY_PORT,
 340        .service        = PCIE_PORT_SERVICE_HP,
 341
 342        .probe          = pciehp_probe,
 343        .remove         = pciehp_remove,
 344
 345#ifdef  CONFIG_PM
 346#ifdef  CONFIG_PM_SLEEP
 347        .suspend        = pciehp_suspend,
 348        .resume_noirq   = pciehp_resume_noirq,
 349        .resume         = pciehp_resume,
 350#endif
 351        .runtime_suspend = pciehp_runtime_suspend,
 352        .runtime_resume = pciehp_runtime_resume,
 353#endif  /* PM */
 354};
 355
 356int __init pcie_hp_init(void)
 357{
 358        int retval = 0;
 359
 360        retval = pcie_port_service_register(&hpdriver_portdrv);
 361        pr_debug("pcie_port_service_register = %d\n", retval);
 362        if (retval)
 363                pr_debug("Failure to register service\n");
 364
 365        return retval;
 366}
 367