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/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
  29#include "aerdrv.h"
  30#include "../../pci.h"
  31
  32/*
  33 * Version Information
  34 */
  35#define DRIVER_VERSION "v1.0"
  36#define DRIVER_AUTHOR "tom.l.nguyen@intel.com"
  37#define DRIVER_DESC "Root Port Advanced Error Reporting Driver"
  38MODULE_AUTHOR(DRIVER_AUTHOR);
  39MODULE_DESCRIPTION(DRIVER_DESC);
  40MODULE_LICENSE("GPL");
  41
  42static int __devinit aer_probe(struct pcie_device *dev);
  43static void aer_remove(struct pcie_device *dev);
  44static pci_ers_result_t aer_error_detected(struct pci_dev *dev,
  45        enum pci_channel_state error);
  46static void aer_error_resume(struct pci_dev *dev);
  47static pci_ers_result_t aer_root_reset(struct pci_dev *dev);
  48
  49static struct pci_error_handlers aer_error_handlers = {
  50        .error_detected = aer_error_detected,
  51        .resume         = aer_error_resume,
  52};
  53
  54static struct pcie_port_service_driver aerdriver = {
  55        .name           = "aer",
  56        .port_type      = PCIE_RC_PORT,
  57        .service        = PCIE_PORT_SERVICE_AER,
  58
  59        .probe          = aer_probe,
  60        .remove         = aer_remove,
  61
  62        .err_handler    = &aer_error_handlers,
  63
  64        .reset_link     = aer_root_reset,
  65};
  66
  67static int pcie_aer_disable;
  68
  69void pci_no_aer(void)
  70{
  71        pcie_aer_disable = 1;   /* has priority over 'forceload' */
  72}
  73
  74/**
  75 * aer_irq - Root Port's ISR
  76 * @irq: IRQ assigned to Root Port
  77 * @context: pointer to Root Port data structure
  78 *
  79 * Invoked when Root Port detects AER messages.
  80 **/
  81irqreturn_t aer_irq(int irq, void *context)
  82{
  83        unsigned int status, id;
  84        struct pcie_device *pdev = (struct pcie_device *)context;
  85        struct aer_rpc *rpc = get_service_data(pdev);
  86        int next_prod_idx;
  87        unsigned long flags;
  88        int pos;
  89
  90        pos = pci_find_ext_capability(pdev->port, PCI_EXT_CAP_ID_ERR);
  91        /*
  92         * Must lock access to Root Error Status Reg, Root Error ID Reg,
  93         * and Root error producer/consumer index
  94         */
  95        spin_lock_irqsave(&rpc->e_lock, flags);
  96
  97        /* Read error status */
  98        pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, &status);
  99        if (!(status & ROOT_ERR_STATUS_MASKS)) {
 100                spin_unlock_irqrestore(&rpc->e_lock, flags);
 101                return IRQ_NONE;
 102        }
 103
 104        /* Read error source and clear error status */
 105        pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_COR_SRC, &id);
 106        pci_write_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, status);
 107
 108        /* Store error source for later DPC handler */
 109        next_prod_idx = rpc->prod_idx + 1;
 110        if (next_prod_idx == AER_ERROR_SOURCES_MAX)
 111                next_prod_idx = 0;
 112        if (next_prod_idx == rpc->cons_idx) {
 113                /*
 114                 * Error Storm Condition - possibly the same error occurred.
 115                 * Drop the error.
 116                 */
 117                spin_unlock_irqrestore(&rpc->e_lock, flags);
 118                return IRQ_HANDLED;
 119        }
 120        rpc->e_sources[rpc->prod_idx].status =  status;
 121        rpc->e_sources[rpc->prod_idx].id = id;
 122        rpc->prod_idx = next_prod_idx;
 123        spin_unlock_irqrestore(&rpc->e_lock, flags);
 124
 125        /*  Invoke DPC handler */
 126        schedule_work(&rpc->dpc_handler);
 127
 128        return IRQ_HANDLED;
 129}
 130EXPORT_SYMBOL_GPL(aer_irq);
 131
 132/**
 133 * aer_alloc_rpc - allocate Root Port data structure
 134 * @dev: pointer to the pcie_dev data structure
 135 *
 136 * Invoked when Root Port's AER service is loaded.
 137 **/
 138static struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev)
 139{
 140        struct aer_rpc *rpc;
 141
 142        rpc = kzalloc(sizeof(struct aer_rpc), GFP_KERNEL);
 143        if (!rpc)
 144                return NULL;
 145
 146        /*
 147         * Initialize Root lock access, e_lock, to Root Error Status Reg,
 148         * Root Error ID Reg, and Root error producer/consumer index.
 149         */
 150        spin_lock_init(&rpc->e_lock);
 151
 152        rpc->rpd = dev;
 153        INIT_WORK(&rpc->dpc_handler, aer_isr);
 154        rpc->prod_idx = rpc->cons_idx = 0;
 155        mutex_init(&rpc->rpc_mutex);
 156        init_waitqueue_head(&rpc->wait_release);
 157
 158        /* Use PCIE bus function to store rpc into PCIE device */
 159        set_service_data(dev, rpc);
 160
 161        return rpc;
 162}
 163
 164/**
 165 * aer_remove - clean up resources
 166 * @dev: pointer to the pcie_dev data structure
 167 *
 168 * Invoked when PCI Express bus unloads or AER probe fails.
 169 **/
 170static void aer_remove(struct pcie_device *dev)
 171{
 172        struct aer_rpc *rpc = get_service_data(dev);
 173
 174        if (rpc) {
 175                /* If register interrupt service, it must be free. */
 176                if (rpc->isr)
 177                        free_irq(dev->irq, dev);
 178
 179                wait_event(rpc->wait_release, rpc->prod_idx == rpc->cons_idx);
 180
 181                aer_delete_rootport(rpc);
 182                set_service_data(dev, NULL);
 183        }
 184}
 185
 186/**
 187 * aer_probe - initialize resources
 188 * @dev: pointer to the pcie_dev data structure
 189 * @id: pointer to the service id data structure
 190 *
 191 * Invoked when PCI Express bus loads AER service driver.
 192 **/
 193static int __devinit aer_probe(struct pcie_device *dev)
 194{
 195        int status;
 196        struct aer_rpc *rpc;
 197        struct device *device = &dev->device;
 198
 199        /* Init */
 200        status = aer_init(dev);
 201        if (status)
 202                return status;
 203
 204        /* Alloc rpc data structure */
 205        rpc = aer_alloc_rpc(dev);
 206        if (!rpc) {
 207                dev_printk(KERN_DEBUG, device, "alloc rpc failed\n");
 208                aer_remove(dev);
 209                return -ENOMEM;
 210        }
 211
 212        /* Request IRQ ISR */
 213        status = request_irq(dev->irq, aer_irq, IRQF_SHARED, "aerdrv", dev);
 214        if (status) {
 215                dev_printk(KERN_DEBUG, device, "request IRQ failed\n");
 216                aer_remove(dev);
 217                return status;
 218        }
 219
 220        rpc->isr = 1;
 221
 222        aer_enable_rootport(rpc);
 223
 224        return status;
 225}
 226
 227/**
 228 * aer_root_reset - reset link on Root Port
 229 * @dev: pointer to Root Port's pci_dev data structure
 230 *
 231 * Invoked by Port Bus driver when performing link reset at Root Port.
 232 **/
 233static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
 234{
 235        u16 p2p_ctrl;
 236        u32 status;
 237        int pos;
 238
 239        pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
 240
 241        /* Disable Root's interrupt in response to error messages */
 242        pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, 0);
 243
 244        /* Assert Secondary Bus Reset */
 245        pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &p2p_ctrl);
 246        p2p_ctrl |= PCI_CB_BRIDGE_CTL_CB_RESET;
 247        pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
 248
 249        /* De-assert Secondary Bus Reset */
 250        p2p_ctrl &= ~PCI_CB_BRIDGE_CTL_CB_RESET;
 251        pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
 252
 253        /*
 254         * System software must wait for at least 100ms from the end
 255         * of a reset of one or more device before it is permitted
 256         * to issue Configuration Requests to those devices.
 257         */
 258        msleep(200);
 259        dev_printk(KERN_DEBUG, &dev->dev, "Root Port link has been reset\n");
 260
 261        /* Enable Root Port's interrupt in response to error messages */
 262        pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &status);
 263        pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, status);
 264        pci_write_config_dword(dev,
 265                pos + PCI_ERR_ROOT_COMMAND,
 266                ROOT_PORT_INTR_ON_MESG_MASK);
 267
 268        return PCI_ERS_RESULT_RECOVERED;
 269}
 270
 271/**
 272 * aer_error_detected - update severity status
 273 * @dev: pointer to Root Port's pci_dev data structure
 274 * @error: error severity being notified by port bus
 275 *
 276 * Invoked by Port Bus driver during error recovery.
 277 **/
 278static pci_ers_result_t aer_error_detected(struct pci_dev *dev,
 279                        enum pci_channel_state error)
 280{
 281        /* Root Port has no impact. Always recovers. */
 282        return PCI_ERS_RESULT_CAN_RECOVER;
 283}
 284
 285/**
 286 * aer_error_resume - clean up corresponding error status bits
 287 * @dev: pointer to Root Port's pci_dev data structure
 288 *
 289 * Invoked by Port Bus driver during nonfatal recovery.
 290 **/
 291static void aer_error_resume(struct pci_dev *dev)
 292{
 293        int pos;
 294        u32 status, mask;
 295        u16 reg16;
 296
 297        /* Clean up Root device status */
 298        pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
 299        pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, &reg16);
 300        pci_write_config_word(dev, pos + PCI_EXP_DEVSTA, reg16);
 301
 302        /* Clean AER Root Error Status */
 303        pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
 304        pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
 305        pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask);
 306        if (dev->error_state == pci_channel_io_normal)
 307                status &= ~mask; /* Clear corresponding nonfatal bits */
 308        else
 309                status &= mask; /* Clear corresponding fatal bits */
 310        pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status);
 311}
 312
 313/**
 314 * aer_service_init - register AER root service driver
 315 *
 316 * Invoked when AER root service driver is loaded.
 317 **/
 318static int __init aer_service_init(void)
 319{
 320        if (pcie_aer_disable)
 321                return -ENXIO;
 322        if (!pci_msi_enabled())
 323                return -ENXIO;
 324        return pcie_port_service_register(&aerdriver);
 325}
 326
 327/**
 328 * aer_service_exit - unregister AER root service driver
 329 *
 330 * Invoked when AER root service driver is unloaded.
 331 **/
 332static void __exit aer_service_exit(void)
 333{
 334        pcie_port_service_unregister(&aerdriver);
 335}
 336
 337module_init(aer_service_init);
 338module_exit(aer_service_exit);
 339