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 __devinit 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 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
  85        if ((dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) ||
  86            (dev->pcie_type == PCI_EXP_TYPE_UPSTREAM) ||
  87            (dev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM)) {
  88                if (enable)
  89                        pci_enable_pcie_error_reporting(dev);
  90                else
  91                        pci_disable_pcie_error_reporting(dev);
  92        }
  93
  94        if (enable)
  95                pcie_set_ecrc_checking(dev);
  96
  97        return 0;
  98}
  99
 100/**
 101 * set_downstream_devices_error_reporting - enable/disable the error reporting  bits on the root port and its downstream ports.
 102 * @dev: pointer to root port's pci_dev data structure
 103 * @enable: true = enable error reporting, false = disable error reporting.
 104 */
 105static void set_downstream_devices_error_reporting(struct pci_dev *dev,
 106                                                   bool enable)
 107{
 108        set_device_error_reporting(dev, &enable);
 109
 110        if (!dev->subordinate)
 111                return;
 112        pci_walk_bus(dev->subordinate, set_device_error_reporting, &enable);
 113}
 114
 115/**
 116 * aer_enable_rootport - enable Root Port's interrupts when receiving messages
 117 * @rpc: pointer to a Root Port data structure
 118 *
 119 * Invoked when PCIe bus loads AER service driver.
 120 */
 121static void aer_enable_rootport(struct aer_rpc *rpc)
 122{
 123        struct pci_dev *pdev = rpc->rpd->port;
 124        int pos, aer_pos;
 125        u16 reg16;
 126        u32 reg32;
 127
 128        pos = pci_pcie_cap(pdev);
 129        /* Clear PCIe Capability's Device Status */
 130        pci_read_config_word(pdev, pos+PCI_EXP_DEVSTA, &reg16);
 131        pci_write_config_word(pdev, pos+PCI_EXP_DEVSTA, reg16);
 132
 133        /* Disable system error generation in response to error messages */
 134        pci_read_config_word(pdev, pos + PCI_EXP_RTCTL, &reg16);
 135        reg16 &= ~(SYSTEM_ERROR_INTR_ON_MESG_MASK);
 136        pci_write_config_word(pdev, pos + PCI_EXP_RTCTL, reg16);
 137
 138        aer_pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
 139        /* Clear error status */
 140        pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, &reg32);
 141        pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, reg32);
 142        pci_read_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, &reg32);
 143        pci_write_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, reg32);
 144        pci_read_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, &reg32);
 145        pci_write_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, reg32);
 146
 147        /*
 148         * Enable error reporting for the root port device and downstream port
 149         * devices.
 150         */
 151        set_downstream_devices_error_reporting(pdev, true);
 152
 153        /* Enable Root Port's interrupt in response to error messages */
 154        pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_COMMAND, &reg32);
 155        reg32 |= ROOT_PORT_INTR_ON_MESG_MASK;
 156        pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_COMMAND, reg32);
 157}
 158
 159/**
 160 * aer_disable_rootport - disable Root Port's interrupts when receiving messages
 161 * @rpc: pointer to a Root Port data structure
 162 *
 163 * Invoked when PCIe bus unloads AER service driver.
 164 */
 165static void aer_disable_rootport(struct aer_rpc *rpc)
 166{
 167        struct pci_dev *pdev = rpc->rpd->port;
 168        u32 reg32;
 169        int pos;
 170
 171        /*
 172         * Disable error reporting for the root port device and downstream port
 173         * devices.
 174         */
 175        set_downstream_devices_error_reporting(pdev, false);
 176
 177        pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
 178        /* Disable Root's interrupt in response to error messages */
 179        pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, &reg32);
 180        reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK;
 181        pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, reg32);
 182
 183        /* Clear Root's error status reg */
 184        pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, &reg32);
 185        pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, reg32);
 186}
 187
 188/**
 189 * aer_irq - Root Port's ISR
 190 * @irq: IRQ assigned to Root Port
 191 * @context: pointer to Root Port data structure
 192 *
 193 * Invoked when Root Port detects AER messages.
 194 */
 195irqreturn_t aer_irq(int irq, void *context)
 196{
 197        unsigned int status, id;
 198        struct pcie_device *pdev = (struct pcie_device *)context;
 199        struct aer_rpc *rpc = get_service_data(pdev);
 200        int next_prod_idx;
 201        unsigned long flags;
 202        int pos;
 203
 204        pos = pci_find_ext_capability(pdev->port, PCI_EXT_CAP_ID_ERR);
 205        /*
 206         * Must lock access to Root Error Status Reg, Root Error ID Reg,
 207         * and Root error producer/consumer index
 208         */
 209        spin_lock_irqsave(&rpc->e_lock, flags);
 210
 211        /* Read error status */
 212        pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, &status);
 213        if (!(status & (PCI_ERR_ROOT_UNCOR_RCV|PCI_ERR_ROOT_COR_RCV))) {
 214                spin_unlock_irqrestore(&rpc->e_lock, flags);
 215                return IRQ_NONE;
 216        }
 217
 218        /* Read error source and clear error status */
 219        pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_ERR_SRC, &id);
 220        pci_write_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, status);
 221
 222        /* Store error source for later DPC handler */
 223        next_prod_idx = rpc->prod_idx + 1;
 224        if (next_prod_idx == AER_ERROR_SOURCES_MAX)
 225                next_prod_idx = 0;
 226        if (next_prod_idx == rpc->cons_idx) {
 227                /*
 228                 * Error Storm Condition - possibly the same error occurred.
 229                 * Drop the error.
 230                 */
 231                spin_unlock_irqrestore(&rpc->e_lock, flags);
 232                return IRQ_HANDLED;
 233        }
 234        rpc->e_sources[rpc->prod_idx].status =  status;
 235        rpc->e_sources[rpc->prod_idx].id = id;
 236        rpc->prod_idx = next_prod_idx;
 237        spin_unlock_irqrestore(&rpc->e_lock, flags);
 238
 239        /*  Invoke DPC handler */
 240        schedule_work(&rpc->dpc_handler);
 241
 242        return IRQ_HANDLED;
 243}
 244EXPORT_SYMBOL_GPL(aer_irq);
 245
 246/**
 247 * aer_alloc_rpc - allocate Root Port data structure
 248 * @dev: pointer to the pcie_dev data structure
 249 *
 250 * Invoked when Root Port's AER service is loaded.
 251 */
 252static struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev)
 253{
 254        struct aer_rpc *rpc;
 255
 256        rpc = kzalloc(sizeof(struct aer_rpc), GFP_KERNEL);
 257        if (!rpc)
 258                return NULL;
 259
 260        /* Initialize Root lock access, e_lock, to Root Error Status Reg */
 261        spin_lock_init(&rpc->e_lock);
 262
 263        rpc->rpd = dev;
 264        INIT_WORK(&rpc->dpc_handler, aer_isr);
 265        mutex_init(&rpc->rpc_mutex);
 266        init_waitqueue_head(&rpc->wait_release);
 267
 268        /* Use PCIe bus function to store rpc into PCIe device */
 269        set_service_data(dev, rpc);
 270
 271        return rpc;
 272}
 273
 274/**
 275 * aer_remove - clean up resources
 276 * @dev: pointer to the pcie_dev data structure
 277 *
 278 * Invoked when PCI Express bus unloads or AER probe fails.
 279 */
 280static void aer_remove(struct pcie_device *dev)
 281{
 282        struct aer_rpc *rpc = get_service_data(dev);
 283
 284        if (rpc) {
 285                /* If register interrupt service, it must be free. */
 286                if (rpc->isr)
 287                        free_irq(dev->irq, dev);
 288
 289                wait_event(rpc->wait_release, rpc->prod_idx == rpc->cons_idx);
 290
 291                aer_disable_rootport(rpc);
 292                kfree(rpc);
 293                set_service_data(dev, NULL);
 294        }
 295}
 296
 297/**
 298 * aer_probe - initialize resources
 299 * @dev: pointer to the pcie_dev data structure
 300 * @id: pointer to the service id data structure
 301 *
 302 * Invoked when PCI Express bus loads AER service driver.
 303 */
 304static int __devinit aer_probe(struct pcie_device *dev)
 305{
 306        int status;
 307        struct aer_rpc *rpc;
 308        struct device *device = &dev->device;
 309
 310        /* Init */
 311        status = aer_init(dev);
 312        if (status)
 313                return status;
 314
 315        /* Alloc rpc data structure */
 316        rpc = aer_alloc_rpc(dev);
 317        if (!rpc) {
 318                dev_printk(KERN_DEBUG, device, "alloc rpc failed\n");
 319                aer_remove(dev);
 320                return -ENOMEM;
 321        }
 322
 323        /* Request IRQ ISR */
 324        status = request_irq(dev->irq, aer_irq, IRQF_SHARED, "aerdrv", dev);
 325        if (status) {
 326                dev_printk(KERN_DEBUG, device, "request IRQ failed\n");
 327                aer_remove(dev);
 328                return status;
 329        }
 330
 331        rpc->isr = 1;
 332
 333        aer_enable_rootport(rpc);
 334
 335        return status;
 336}
 337
 338/**
 339 * aer_root_reset - reset link on Root Port
 340 * @dev: pointer to Root Port's pci_dev data structure
 341 *
 342 * Invoked by Port Bus driver when performing link reset at Root Port.
 343 */
 344static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
 345{
 346        u32 reg32;
 347        int pos;
 348
 349        pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
 350
 351        /* Disable Root's interrupt in response to error messages */
 352        pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, &reg32);
 353        reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK;
 354        pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32);
 355
 356        aer_do_secondary_bus_reset(dev);
 357        dev_printk(KERN_DEBUG, &dev->dev, "Root Port link has been reset\n");
 358
 359        /* Clear Root Error Status */
 360        pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &reg32);
 361        pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, reg32);
 362
 363        /* Enable Root Port's interrupt in response to error messages */
 364        pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, &reg32);
 365        reg32 |= ROOT_PORT_INTR_ON_MESG_MASK;
 366        pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32);
 367
 368        return PCI_ERS_RESULT_RECOVERED;
 369}
 370
 371/**
 372 * aer_error_detected - update severity status
 373 * @dev: pointer to Root Port's pci_dev data structure
 374 * @error: error severity being notified by port bus
 375 *
 376 * Invoked by Port Bus driver during error recovery.
 377 */
 378static pci_ers_result_t aer_error_detected(struct pci_dev *dev,
 379                        enum pci_channel_state error)
 380{
 381        /* Root Port has no impact. Always recovers. */
 382        return PCI_ERS_RESULT_CAN_RECOVER;
 383}
 384
 385/**
 386 * aer_error_resume - clean up corresponding error status bits
 387 * @dev: pointer to Root Port's pci_dev data structure
 388 *
 389 * Invoked by Port Bus driver during nonfatal recovery.
 390 */
 391static void aer_error_resume(struct pci_dev *dev)
 392{
 393        int pos;
 394        u32 status, mask;
 395        u16 reg16;
 396
 397        /* Clean up Root device status */
 398        pos = pci_pcie_cap(dev);
 399        pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, &reg16);
 400        pci_write_config_word(dev, pos + PCI_EXP_DEVSTA, reg16);
 401
 402        /* Clean AER Root Error Status */
 403        pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
 404        pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
 405        pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask);
 406        if (dev->error_state == pci_channel_io_normal)
 407                status &= ~mask; /* Clear corresponding nonfatal bits */
 408        else
 409                status &= mask; /* Clear corresponding fatal bits */
 410        pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status);
 411}
 412
 413/**
 414 * aer_service_init - register AER root service driver
 415 *
 416 * Invoked when AER root service driver is loaded.
 417 */
 418static int __init aer_service_init(void)
 419{
 420        if (!pci_aer_available() || aer_acpi_firmware_first())
 421                return -ENXIO;
 422        return pcie_port_service_register(&aerdriver);
 423}
 424
 425/**
 426 * aer_service_exit - unregister AER root service driver
 427 *
 428 * Invoked when AER root service driver is unloaded.
 429 */
 430static void __exit aer_service_exit(void)
 431{
 432        pcie_port_service_unregister(&aerdriver);
 433}
 434
 435module_init(aer_service_init);
 436module_exit(aer_service_exit);
 437