linux/drivers/pci/pcie/aer/aerdrv.c
<<
>>
Prefs
   1/*
   2 * drivers/pci/pcie/aer/aerdrv.c
   3 *
   4 * This file is subject to the terms and conditions of the GNU General Public
   5 * License.  See the file "COPYING" in the main directory of this archive
   6 * for more details.
   7 *
   8 * This file implements the AER root port service driver. The driver will
   9 * register an irq handler. When root port triggers an AER interrupt, the irq
  10 * handler will collect root port status and schedule a work.
  11 *
  12 * Copyright (C) 2006 Intel Corp.
  13 *      Tom Long Nguyen (tom.l.nguyen@intel.com)
  14 *      Zhang Yanmin (yanmin.zhang@intel.com)
  15 *
  16 */
  17
  18#include <linux/module.h>
  19#include <linux/pci.h>
  20#include <linux/pci-acpi.h>
  21#include <linux/sched.h>
  22#include <linux/kernel.h>
  23#include <linux/errno.h>
  24#include <linux/pm.h>
  25#include <linux/init.h>
  26#include <linux/interrupt.h>
  27#include <linux/delay.h>
  28#include <linux/pcieport_if.h>
  29#include <linux/slab.h>
  30
  31#include "aerdrv.h"
  32#include "../../pci.h"
  33
  34/*
  35 * Version Information
  36 */
  37#define DRIVER_VERSION "v1.0"
  38#define DRIVER_AUTHOR "tom.l.nguyen@intel.com"
  39#define DRIVER_DESC "Root Port Advanced Error Reporting Driver"
  40MODULE_AUTHOR(DRIVER_AUTHOR);
  41MODULE_DESCRIPTION(DRIVER_DESC);
  42MODULE_LICENSE("GPL");
  43
  44static int aer_probe(struct pcie_device *dev);
  45static void aer_remove(struct pcie_device *dev);
  46static pci_ers_result_t aer_error_detected(struct pci_dev *dev,
  47        enum pci_channel_state error);
  48static void aer_error_resume(struct pci_dev *dev);
  49static pci_ers_result_t aer_root_reset(struct pci_dev *dev);
  50
  51static const struct pci_error_handlers aer_error_handlers = {
  52        .error_detected = aer_error_detected,
  53        .resume         = aer_error_resume,
  54};
  55
  56static struct pcie_port_service_driver aerdriver = {
  57        .name           = "aer",
  58        .port_type      = PCI_EXP_TYPE_ROOT_PORT,
  59        .service        = PCIE_PORT_SERVICE_AER,
  60
  61        .probe          = aer_probe,
  62        .remove         = aer_remove,
  63
  64        .err_handler    = &aer_error_handlers,
  65
  66        .reset_link     = aer_root_reset,
  67};
  68
  69static int pcie_aer_disable;
  70
  71void pci_no_aer(void)
  72{
  73        pcie_aer_disable = 1;   /* has priority over 'forceload' */
  74}
  75
  76bool pci_aer_available(void)
  77{
  78        return !pcie_aer_disable && pci_msi_enabled();
  79}
  80
  81static int set_device_error_reporting(struct pci_dev *dev, void *data)
  82{
  83        bool enable = *((bool *)data);
  84        int type = pci_pcie_type(dev);
  85
  86        if ((type == PCI_EXP_TYPE_ROOT_PORT) ||
  87            (type == PCI_EXP_TYPE_UPSTREAM) ||
  88            (type == PCI_EXP_TYPE_DOWNSTREAM)) {
  89                if (enable)
  90                        pci_enable_pcie_error_reporting(dev);
  91                else
  92                        pci_disable_pcie_error_reporting(dev);
  93        }
  94
  95        if (enable)
  96                pcie_set_ecrc_checking(dev);
  97
  98        return 0;
  99}
 100
 101/**
 102 * set_downstream_devices_error_reporting - enable/disable the error reporting  bits on the root port and its downstream ports.
 103 * @dev: pointer to root port's pci_dev data structure
 104 * @enable: true = enable error reporting, false = disable error reporting.
 105 */
 106static void set_downstream_devices_error_reporting(struct pci_dev *dev,
 107                                                   bool enable)
 108{
 109        set_device_error_reporting(dev, &enable);
 110
 111        if (!dev->subordinate)
 112                return;
 113        pci_walk_bus(dev->subordinate, set_device_error_reporting, &enable);
 114}
 115
 116/**
 117 * aer_enable_rootport - enable Root Port's interrupts when receiving messages
 118 * @rpc: pointer to a Root Port data structure
 119 *
 120 * Invoked when PCIe bus loads AER service driver.
 121 */
 122static void aer_enable_rootport(struct aer_rpc *rpc)
 123{
 124        struct pci_dev *pdev = rpc->rpd->port;
 125        int aer_pos;
 126        u16 reg16;
 127        u32 reg32;
 128
 129        /* Clear PCIe Capability's Device Status */
 130        pcie_capability_read_word(pdev, PCI_EXP_DEVSTA, &reg16);
 131        pcie_capability_write_word(pdev, PCI_EXP_DEVSTA, reg16);
 132
 133        /* Disable system error generation in response to error messages */
 134        pcie_capability_clear_word(pdev, PCI_EXP_RTCTL,
 135                                   SYSTEM_ERROR_INTR_ON_MESG_MASK);
 136
 137        aer_pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
 138        /* Clear error status */
 139        pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, &reg32);
 140        pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, reg32);
 141        pci_read_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, &reg32);
 142        pci_write_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, reg32);
 143        pci_read_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, &reg32);
 144        pci_write_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, reg32);
 145
 146        /*
 147         * Enable error reporting for the root port device and downstream port
 148         * devices.
 149         */
 150        set_downstream_devices_error_reporting(pdev, true);
 151
 152        /* Enable Root Port's interrupt in response to error messages */
 153        pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_COMMAND, &reg32);
 154        reg32 |= ROOT_PORT_INTR_ON_MESG_MASK;
 155        pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_COMMAND, reg32);
 156}
 157
 158/**
 159 * aer_disable_rootport - disable Root Port's interrupts when receiving messages
 160 * @rpc: pointer to a Root Port data structure
 161 *
 162 * Invoked when PCIe bus unloads AER service driver.
 163 */
 164static void aer_disable_rootport(struct aer_rpc *rpc)
 165{
 166        struct pci_dev *pdev = rpc->rpd->port;
 167        u32 reg32;
 168        int pos;
 169
 170        /*
 171         * Disable error reporting for the root port device and downstream port
 172         * devices.
 173         */
 174        set_downstream_devices_error_reporting(pdev, false);
 175
 176        pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
 177        /* Disable Root's interrupt in response to error messages */
 178        pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, &reg32);
 179        reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK;
 180        pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, reg32);
 181
 182        /* Clear Root's error status reg */
 183        pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, &reg32);
 184        pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, reg32);
 185}
 186
 187/**
 188 * aer_irq - Root Port's ISR
 189 * @irq: IRQ assigned to Root Port
 190 * @context: pointer to Root Port data structure
 191 *
 192 * Invoked when Root Port detects AER messages.
 193 */
 194irqreturn_t aer_irq(int irq, void *context)
 195{
 196        unsigned int status, id;
 197        struct pcie_device *pdev = (struct pcie_device *)context;
 198        struct aer_rpc *rpc = get_service_data(pdev);
 199        int next_prod_idx;
 200        unsigned long flags;
 201        int pos;
 202
 203        pos = pci_find_ext_capability(pdev->port, PCI_EXT_CAP_ID_ERR);
 204        /*
 205         * Must lock access to Root Error Status Reg, Root Error ID Reg,
 206         * and Root error producer/consumer index
 207         */
 208        spin_lock_irqsave(&rpc->e_lock, flags);
 209
 210        /* Read error status */
 211        pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, &status);
 212        if (!(status & (PCI_ERR_ROOT_UNCOR_RCV|PCI_ERR_ROOT_COR_RCV))) {
 213                spin_unlock_irqrestore(&rpc->e_lock, flags);
 214                return IRQ_NONE;
 215        }
 216
 217        /* Read error source and clear error status */
 218        pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_ERR_SRC, &id);
 219        pci_write_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, status);
 220
 221        /* Store error source for later DPC handler */
 222        next_prod_idx = rpc->prod_idx + 1;
 223        if (next_prod_idx == AER_ERROR_SOURCES_MAX)
 224                next_prod_idx = 0;
 225        if (next_prod_idx == rpc->cons_idx) {
 226                /*
 227                 * Error Storm Condition - possibly the same error occurred.
 228                 * Drop the error.
 229                 */
 230                spin_unlock_irqrestore(&rpc->e_lock, flags);
 231                return IRQ_HANDLED;
 232        }
 233        rpc->e_sources[rpc->prod_idx].status =  status;
 234        rpc->e_sources[rpc->prod_idx].id = id;
 235        rpc->prod_idx = next_prod_idx;
 236        spin_unlock_irqrestore(&rpc->e_lock, flags);
 237
 238        /*  Invoke DPC handler */
 239        schedule_work(&rpc->dpc_handler);
 240
 241        return IRQ_HANDLED;
 242}
 243EXPORT_SYMBOL_GPL(aer_irq);
 244
 245/**
 246 * aer_alloc_rpc - allocate Root Port data structure
 247 * @dev: pointer to the pcie_dev data structure
 248 *
 249 * Invoked when Root Port's AER service is loaded.
 250 */
 251static struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev)
 252{
 253        struct aer_rpc *rpc;
 254
 255        rpc = kzalloc(sizeof(struct aer_rpc), GFP_KERNEL);
 256        if (!rpc)
 257                return NULL;
 258
 259        /* Initialize Root lock access, e_lock, to Root Error Status Reg */
 260        spin_lock_init(&rpc->e_lock);
 261
 262        rpc->rpd = dev;
 263        INIT_WORK(&rpc->dpc_handler, aer_isr);
 264        mutex_init(&rpc->rpc_mutex);
 265
 266        /* Use PCIe bus function to store rpc into PCIe device */
 267        set_service_data(dev, rpc);
 268
 269        return rpc;
 270}
 271
 272/**
 273 * aer_remove - clean up resources
 274 * @dev: pointer to the pcie_dev data structure
 275 *
 276 * Invoked when PCI Express bus unloads or AER probe fails.
 277 */
 278static void aer_remove(struct pcie_device *dev)
 279{
 280        struct aer_rpc *rpc = get_service_data(dev);
 281
 282        if (rpc) {
 283                /* If register interrupt service, it must be free. */
 284                if (rpc->isr)
 285                        free_irq(dev->irq, dev);
 286
 287                flush_work(&rpc->dpc_handler);
 288                aer_disable_rootport(rpc);
 289                kfree(rpc);
 290                set_service_data(dev, NULL);
 291        }
 292}
 293
 294/**
 295 * aer_probe - initialize resources
 296 * @dev: pointer to the pcie_dev data structure
 297 * @id: pointer to the service id data structure
 298 *
 299 * Invoked when PCI Express bus loads AER service driver.
 300 */
 301static int aer_probe(struct pcie_device *dev)
 302{
 303        int status;
 304        struct aer_rpc *rpc;
 305        struct device *device = &dev->device;
 306
 307        /* Init */
 308        status = aer_init(dev);
 309        if (status)
 310                return status;
 311
 312        /* Alloc rpc data structure */
 313        rpc = aer_alloc_rpc(dev);
 314        if (!rpc) {
 315                dev_printk(KERN_DEBUG, device, "alloc rpc failed\n");
 316                aer_remove(dev);
 317                return -ENOMEM;
 318        }
 319
 320        /* Request IRQ ISR */
 321        status = request_irq(dev->irq, aer_irq, IRQF_SHARED, "aerdrv", dev);
 322        if (status) {
 323                dev_printk(KERN_DEBUG, device, "request IRQ failed\n");
 324                aer_remove(dev);
 325                return status;
 326        }
 327
 328        rpc->isr = 1;
 329
 330        aer_enable_rootport(rpc);
 331
 332        return status;
 333}
 334
 335/**
 336 * aer_root_reset - reset link on Root Port
 337 * @dev: pointer to Root Port's pci_dev data structure
 338 *
 339 * Invoked by Port Bus driver when performing link reset at Root Port.
 340 */
 341static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
 342{
 343        u32 reg32;
 344        int pos;
 345
 346        pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
 347
 348        /* Disable Root's interrupt in response to error messages */
 349        pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, &reg32);
 350        reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK;
 351        pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32);
 352
 353        pci_reset_bridge_secondary_bus(dev);
 354        dev_printk(KERN_DEBUG, &dev->dev, "Root Port link has been reset\n");
 355
 356        /* Clear Root Error Status */
 357        pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &reg32);
 358        pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, reg32);
 359
 360        /* Enable Root Port's interrupt in response to error messages */
 361        pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, &reg32);
 362        reg32 |= ROOT_PORT_INTR_ON_MESG_MASK;
 363        pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32);
 364
 365        return PCI_ERS_RESULT_RECOVERED;
 366}
 367
 368/**
 369 * aer_error_detected - update severity status
 370 * @dev: pointer to Root Port's pci_dev data structure
 371 * @error: error severity being notified by port bus
 372 *
 373 * Invoked by Port Bus driver during error recovery.
 374 */
 375static pci_ers_result_t aer_error_detected(struct pci_dev *dev,
 376                        enum pci_channel_state error)
 377{
 378        /* Root Port has no impact. Always recovers. */
 379        return PCI_ERS_RESULT_CAN_RECOVER;
 380}
 381
 382/**
 383 * aer_error_resume - clean up corresponding error status bits
 384 * @dev: pointer to Root Port's pci_dev data structure
 385 *
 386 * Invoked by Port Bus driver during nonfatal recovery.
 387 */
 388static void aer_error_resume(struct pci_dev *dev)
 389{
 390        int pos;
 391        u32 status, mask;
 392        u16 reg16;
 393
 394        /* Clean up Root device status */
 395        pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &reg16);
 396        pcie_capability_write_word(dev, PCI_EXP_DEVSTA, reg16);
 397
 398        /* Clean AER Root Error Status */
 399        pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
 400        pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
 401        pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask);
 402        if (dev->error_state == pci_channel_io_normal)
 403                status &= ~mask; /* Clear corresponding nonfatal bits */
 404        else
 405                status &= mask; /* Clear corresponding fatal bits */
 406        pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status);
 407}
 408
 409/**
 410 * aer_service_init - register AER root service driver
 411 *
 412 * Invoked when AER root service driver is loaded.
 413 */
 414static int __init aer_service_init(void)
 415{
 416        if (!pci_aer_available() || aer_acpi_firmware_first())
 417                return -ENXIO;
 418        return pcie_port_service_register(&aerdriver);
 419}
 420
 421/**
 422 * aer_service_exit - unregister AER root service driver
 423 *
 424 * Invoked when AER root service driver is unloaded.
 425 */
 426static void __exit aer_service_exit(void)
 427{
 428        pcie_port_service_unregister(&aerdriver);
 429}
 430
 431module_init(aer_service_init);
 432module_exit(aer_service_exit);
 433