linux/drivers/pci/pcie/portdrv_pci.c
<<
>>
Prefs
   1/*
   2 * File:        portdrv_pci.c
   3 * Purpose:     PCI Express Port Bus Driver
   4 *
   5 * Copyright (C) 2004 Intel
   6 * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
   7 */
   8
   9#include <linux/module.h>
  10#include <linux/pci.h>
  11#include <linux/kernel.h>
  12#include <linux/errno.h>
  13#include <linux/pm.h>
  14#include <linux/pm_runtime.h>
  15#include <linux/init.h>
  16#include <linux/pcieport_if.h>
  17#include <linux/aer.h>
  18#include <linux/dmi.h>
  19#include <linux/pci-aspm.h>
  20
  21#include "portdrv.h"
  22#include "aer/aerdrv.h"
  23
  24/*
  25 * Version Information
  26 */
  27#define DRIVER_VERSION "v1.0"
  28#define DRIVER_AUTHOR "tom.l.nguyen@intel.com"
  29#define DRIVER_DESC "PCIe Port Bus Driver"
  30MODULE_AUTHOR(DRIVER_AUTHOR);
  31MODULE_DESCRIPTION(DRIVER_DESC);
  32MODULE_LICENSE("GPL");
  33
  34/* If this switch is set, PCIe port native services should not be enabled. */
  35bool pcie_ports_disabled;
  36
  37/*
  38 * If this switch is set, ACPI _OSC will be used to determine whether or not to
  39 * enable PCIe port native services.
  40 */
  41bool pcie_ports_auto = true;
  42
  43static int __init pcie_port_setup(char *str)
  44{
  45        if (!strncmp(str, "compat", 6)) {
  46                pcie_ports_disabled = true;
  47        } else if (!strncmp(str, "native", 6)) {
  48                pcie_ports_disabled = false;
  49                pcie_ports_auto = false;
  50        } else if (!strncmp(str, "auto", 4)) {
  51                pcie_ports_disabled = false;
  52                pcie_ports_auto = true;
  53        }
  54
  55        return 1;
  56}
  57__setup("pcie_ports=", pcie_port_setup);
  58
  59/* global data */
  60
  61/**
  62 * pcie_clear_root_pme_status - Clear root port PME interrupt status.
  63 * @dev: PCIe root port or event collector.
  64 */
  65void pcie_clear_root_pme_status(struct pci_dev *dev)
  66{
  67        pcie_capability_set_dword(dev, PCI_EXP_RTSTA, PCI_EXP_RTSTA_PME);
  68}
  69
  70static int pcie_portdrv_restore_config(struct pci_dev *dev)
  71{
  72        int retval;
  73
  74        retval = pci_enable_device(dev);
  75        if (retval)
  76                return retval;
  77        pci_set_master(dev);
  78        return 0;
  79}
  80
  81#ifdef CONFIG_PM
  82static int pcie_port_resume_noirq(struct device *dev)
  83{
  84        struct pci_dev *pdev = to_pci_dev(dev);
  85
  86        /*
  87         * Some BIOSes forget to clear Root PME Status bits after system wakeup
  88         * which breaks ACPI-based runtime wakeup on PCI Express, so clear those
  89         * bits now just in case (shouldn't hurt).
  90         */
  91        if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT)
  92                pcie_clear_root_pme_status(pdev);
  93        return 0;
  94}
  95
  96static const struct dev_pm_ops pcie_portdrv_pm_ops = {
  97        .suspend        = pcie_port_device_suspend,
  98        .resume         = pcie_port_device_resume,
  99        .freeze         = pcie_port_device_suspend,
 100        .thaw           = pcie_port_device_resume,
 101        .poweroff       = pcie_port_device_suspend,
 102        .restore        = pcie_port_device_resume,
 103        .resume_noirq   = pcie_port_resume_noirq,
 104};
 105
 106#define PCIE_PORTDRV_PM_OPS     (&pcie_portdrv_pm_ops)
 107
 108#else /* !PM */
 109
 110#define PCIE_PORTDRV_PM_OPS     NULL
 111#endif /* !PM */
 112
 113/*
 114 * pcie_portdrv_probe - Probe PCI-Express port devices
 115 * @dev: PCI-Express port device being probed
 116 *
 117 * If detected invokes the pcie_port_device_register() method for
 118 * this port device.
 119 *
 120 */
 121static int pcie_portdrv_probe(struct pci_dev *dev,
 122                                        const struct pci_device_id *id)
 123{
 124        int status;
 125
 126        if (!pci_is_pcie(dev) ||
 127            ((pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT) &&
 128             (pci_pcie_type(dev) != PCI_EXP_TYPE_UPSTREAM) &&
 129             (pci_pcie_type(dev) != PCI_EXP_TYPE_DOWNSTREAM)))
 130                return -ENODEV;
 131
 132        status = pcie_port_device_register(dev);
 133        if (status)
 134                return status;
 135
 136        pci_save_state(dev);
 137        /*
 138         * D3cold may not work properly on some PCIe port, so disable
 139         * it by default.
 140         */
 141        dev->d3cold_allowed = false;
 142        return 0;
 143}
 144
 145static void pcie_portdrv_remove(struct pci_dev *dev)
 146{
 147        pcie_port_device_remove(dev);
 148}
 149
 150static int error_detected_iter(struct device *device, void *data)
 151{
 152        struct pcie_device *pcie_device;
 153        struct pcie_port_service_driver *driver;
 154        struct aer_broadcast_data *result_data;
 155        pci_ers_result_t status;
 156
 157        result_data = (struct aer_broadcast_data *) data;
 158
 159        if (device->bus == &pcie_port_bus_type && device->driver) {
 160                driver = to_service_driver(device->driver);
 161                if (!driver ||
 162                        !driver->err_handler ||
 163                        !driver->err_handler->error_detected)
 164                        return 0;
 165
 166                pcie_device = to_pcie_device(device);
 167
 168                /* Forward error detected message to service drivers */
 169                status = driver->err_handler->error_detected(
 170                        pcie_device->port,
 171                        result_data->state);
 172                result_data->result =
 173                        merge_result(result_data->result, status);
 174        }
 175
 176        return 0;
 177}
 178
 179static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev *dev,
 180                                        enum pci_channel_state error)
 181{
 182        struct aer_broadcast_data data = {error, PCI_ERS_RESULT_CAN_RECOVER};
 183
 184        /* get true return value from &data */
 185        device_for_each_child(&dev->dev, &data, error_detected_iter);
 186        return data.result;
 187}
 188
 189static int mmio_enabled_iter(struct device *device, void *data)
 190{
 191        struct pcie_device *pcie_device;
 192        struct pcie_port_service_driver *driver;
 193        pci_ers_result_t status, *result;
 194
 195        result = (pci_ers_result_t *) data;
 196
 197        if (device->bus == &pcie_port_bus_type && device->driver) {
 198                driver = to_service_driver(device->driver);
 199                if (driver &&
 200                        driver->err_handler &&
 201                        driver->err_handler->mmio_enabled) {
 202                        pcie_device = to_pcie_device(device);
 203
 204                        /* Forward error message to service drivers */
 205                        status = driver->err_handler->mmio_enabled(
 206                                        pcie_device->port);
 207                        *result = merge_result(*result, status);
 208                }
 209        }
 210
 211        return 0;
 212}
 213
 214static pci_ers_result_t pcie_portdrv_mmio_enabled(struct pci_dev *dev)
 215{
 216        pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED;
 217
 218        /* get true return value from &status */
 219        device_for_each_child(&dev->dev, &status, mmio_enabled_iter);
 220        return status;
 221}
 222
 223static int slot_reset_iter(struct device *device, void *data)
 224{
 225        struct pcie_device *pcie_device;
 226        struct pcie_port_service_driver *driver;
 227        pci_ers_result_t status, *result;
 228
 229        result = (pci_ers_result_t *) data;
 230
 231        if (device->bus == &pcie_port_bus_type && device->driver) {
 232                driver = to_service_driver(device->driver);
 233                if (driver &&
 234                        driver->err_handler &&
 235                        driver->err_handler->slot_reset) {
 236                        pcie_device = to_pcie_device(device);
 237
 238                        /* Forward error message to service drivers */
 239                        status = driver->err_handler->slot_reset(
 240                                        pcie_device->port);
 241                        *result = merge_result(*result, status);
 242                }
 243        }
 244
 245        return 0;
 246}
 247
 248static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev)
 249{
 250        pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED;
 251
 252        /* If fatal, restore cfg space for possible link reset at upstream */
 253        if (dev->error_state == pci_channel_io_frozen) {
 254                dev->state_saved = true;
 255                pci_restore_state(dev);
 256                pcie_portdrv_restore_config(dev);
 257                pci_enable_pcie_error_reporting(dev);
 258        }
 259
 260        /* get true return value from &status */
 261        device_for_each_child(&dev->dev, &status, slot_reset_iter);
 262        return status;
 263}
 264
 265static int resume_iter(struct device *device, void *data)
 266{
 267        struct pcie_device *pcie_device;
 268        struct pcie_port_service_driver *driver;
 269
 270        if (device->bus == &pcie_port_bus_type && device->driver) {
 271                driver = to_service_driver(device->driver);
 272                if (driver &&
 273                        driver->err_handler &&
 274                        driver->err_handler->resume) {
 275                        pcie_device = to_pcie_device(device);
 276
 277                        /* Forward error message to service drivers */
 278                        driver->err_handler->resume(pcie_device->port);
 279                }
 280        }
 281
 282        return 0;
 283}
 284
 285static void pcie_portdrv_err_resume(struct pci_dev *dev)
 286{
 287        device_for_each_child(&dev->dev, NULL, resume_iter);
 288}
 289
 290/*
 291 * LINUX Device Driver Model
 292 */
 293static const struct pci_device_id port_pci_ids[] = { {
 294        /* handle any PCI-Express port */
 295        PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_PCI << 8) | 0x00), ~0),
 296        }, { /* end: all zeroes */ }
 297};
 298MODULE_DEVICE_TABLE(pci, port_pci_ids);
 299
 300static const struct pci_error_handlers pcie_portdrv_err_handler = {
 301        .error_detected = pcie_portdrv_error_detected,
 302        .mmio_enabled = pcie_portdrv_mmio_enabled,
 303        .slot_reset = pcie_portdrv_slot_reset,
 304        .resume = pcie_portdrv_err_resume,
 305};
 306
 307static struct pci_driver pcie_portdriver = {
 308        .name           = "pcieport",
 309        .id_table       = &port_pci_ids[0],
 310
 311        .probe          = pcie_portdrv_probe,
 312        .remove         = pcie_portdrv_remove,
 313
 314        .err_handler    = &pcie_portdrv_err_handler,
 315
 316        .driver.pm      = PCIE_PORTDRV_PM_OPS,
 317};
 318
 319static int __init dmi_pcie_pme_disable_msi(const struct dmi_system_id *d)
 320{
 321        pr_notice("%s detected: will not use MSI for PCIe PME signaling\n",
 322                  d->ident);
 323        pcie_pme_disable_msi();
 324        return 0;
 325}
 326
 327static struct dmi_system_id __initdata pcie_portdrv_dmi_table[] = {
 328        /*
 329         * Boxes that should not use MSI for PCIe PME signaling.
 330         */
 331        {
 332         .callback = dmi_pcie_pme_disable_msi,
 333         .ident = "MSI Wind U-100",
 334         .matches = {
 335                     DMI_MATCH(DMI_SYS_VENDOR,
 336                                "MICRO-STAR INTERNATIONAL CO., LTD"),
 337                     DMI_MATCH(DMI_PRODUCT_NAME, "U-100"),
 338                     },
 339         },
 340         {}
 341};
 342
 343static int __init pcie_portdrv_init(void)
 344{
 345        int retval;
 346
 347        if (pcie_ports_disabled)
 348                return pci_register_driver(&pcie_portdriver);
 349
 350        dmi_check_system(pcie_portdrv_dmi_table);
 351
 352        retval = pcie_port_bus_register();
 353        if (retval) {
 354                printk(KERN_WARNING "PCIE: bus_register error: %d\n", retval);
 355                goto out;
 356        }
 357        retval = pci_register_driver(&pcie_portdriver);
 358        if (retval)
 359                pcie_port_bus_unregister();
 360 out:
 361        return retval;
 362}
 363
 364module_init(pcie_portdrv_init);
 365