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