aerdrv.c revision e167bfcaa4cd44b4c66206a3c06b2aafb3f1260e
16c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin/* 26c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * drivers/pci/pcie/aer/aerdrv.c 36c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * 46c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * This file is subject to the terms and conditions of the GNU General Public 56c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * License. See the file "COPYING" in the main directory of this archive 66c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * for more details. 76c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * 86c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * This file implements the AER root port service driver. The driver will 96c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * register an irq handler. When root port triggers an AER interrupt, the irq 106c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * handler will collect root port status and schedule a work. 116c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * 126c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Copyright (C) 2006 Intel Corp. 136c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Tom Long Nguyen (tom.l.nguyen@intel.com) 146c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Zhang Yanmin (yanmin.zhang@intel.com) 156c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * 166c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin */ 176c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 186c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin#include <linux/module.h> 196c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin#include <linux/pci.h> 20d43c36dc6b357fa1806800f18aa30123c747a6d1Alexey Dobriyan#include <linux/sched.h> 216c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin#include <linux/kernel.h> 226c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin#include <linux/errno.h> 236c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin#include <linux/pm.h> 246c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin#include <linux/init.h> 256c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin#include <linux/interrupt.h> 266c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin#include <linux/delay.h> 276c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin#include <linux/pcieport_if.h> 285a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 296c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 306c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin#include "aerdrv.h" 315d9526d07a8dc87460c13c277b3edcc26b0e662fAlex Chiang#include "../../pci.h" 326c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 336c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin/* 346c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Version Information 356c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin */ 366c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin#define DRIVER_VERSION "v1.0" 376c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin#define DRIVER_AUTHOR "tom.l.nguyen@intel.com" 386c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin#define DRIVER_DESC "Root Port Advanced Error Reporting Driver" 396c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, YanminMODULE_AUTHOR(DRIVER_AUTHOR); 406c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, YanminMODULE_DESCRIPTION(DRIVER_DESC); 416c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, YanminMODULE_LICENSE("GPL"); 426c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 43c9a918838c07cbef934c8ef818d8f0e719015c3aHidetoshi Setostatic int __devinit aer_probe(struct pcie_device *dev); 446c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanminstatic void aer_remove(struct pcie_device *dev); 456c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanminstatic pci_ers_result_t aer_error_detected(struct pci_dev *dev, 466c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin enum pci_channel_state error); 476c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanminstatic void aer_error_resume(struct pci_dev *dev); 486c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanminstatic pci_ers_result_t aer_root_reset(struct pci_dev *dev); 496c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 506c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanminstatic struct pci_error_handlers aer_error_handlers = { 516c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin .error_detected = aer_error_detected, 52c9a918838c07cbef934c8ef818d8f0e719015c3aHidetoshi Seto .resume = aer_error_resume, 536c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin}; 546c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 55c1996c2778e90f80cb9fc6a52508068f10d39611Sam Ravnborgstatic struct pcie_port_service_driver aerdriver = { 566c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin .name = "aer", 57694f88ef7ada0d99e304f687ba92e268a594358bKenji Kaneshige .port_type = PCI_EXP_TYPE_ROOT_PORT, 5822106368c999246c414610dcaacd485e741605b1Rafael J. Wysocki .service = PCIE_PORT_SERVICE_AER, 596c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 606c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin .probe = aer_probe, 616c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin .remove = aer_remove, 626c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 636c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin .err_handler = &aer_error_handlers, 646c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 656c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin .reset_link = aer_root_reset, 666c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin}; 676c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 687f785763660e75c9eddaddea3d618696af4ae3a2Randy Dunlapstatic int pcie_aer_disable; 697f785763660e75c9eddaddea3d618696af4ae3a2Randy Dunlap 707f785763660e75c9eddaddea3d618696af4ae3a2Randy Dunlapvoid pci_no_aer(void) 717f785763660e75c9eddaddea3d618696af4ae3a2Randy Dunlap{ 727f785763660e75c9eddaddea3d618696af4ae3a2Randy Dunlap pcie_aer_disable = 1; /* has priority over 'forceload' */ 737f785763660e75c9eddaddea3d618696af4ae3a2Randy Dunlap} 747f785763660e75c9eddaddea3d618696af4ae3a2Randy Dunlap 75843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Setostatic int set_device_error_reporting(struct pci_dev *dev, void *data) 76843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto{ 77843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto bool enable = *((bool *)data); 78843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 79843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto if ((dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) || 80843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto (dev->pcie_type == PCI_EXP_TYPE_UPSTREAM) || 81843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto (dev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM)) { 82843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto if (enable) 83843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_enable_pcie_error_reporting(dev); 84843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto else 85843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_disable_pcie_error_reporting(dev); 86843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto } 87843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 88843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto if (enable) 89843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pcie_set_ecrc_checking(dev); 90843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 91843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto return 0; 92843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto} 93843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 94843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto/** 95843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * set_downstream_devices_error_reporting - enable/disable the error reporting bits on the root port and its downstream ports. 96843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * @dev: pointer to root port's pci_dev data structure 97843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * @enable: true = enable error reporting, false = disable error reporting. 98843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto */ 99843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Setostatic void set_downstream_devices_error_reporting(struct pci_dev *dev, 100843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto bool enable) 101843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto{ 102843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto set_device_error_reporting(dev, &enable); 103843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 104843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto if (!dev->subordinate) 105843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto return; 106843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_walk_bus(dev->subordinate, set_device_error_reporting, &enable); 107843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto} 108843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 109843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto/** 110843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * aer_enable_rootport - enable Root Port's interrupts when receiving messages 111843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * @rpc: pointer to a Root Port data structure 112843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * 113843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * Invoked when PCIe bus loads AER service driver. 114843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto */ 115843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Setostatic void aer_enable_rootport(struct aer_rpc *rpc) 116843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto{ 117843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto struct pci_dev *pdev = rpc->rpd->port; 118843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto int pos, aer_pos; 119843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto u16 reg16; 120843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto u32 reg32; 121843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 122843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pos = pci_pcie_cap(pdev); 123843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto /* Clear PCIe Capability's Device Status */ 124843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_read_config_word(pdev, pos+PCI_EXP_DEVSTA, ®16); 125843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_write_config_word(pdev, pos+PCI_EXP_DEVSTA, reg16); 126843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 127843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto /* Disable system error generation in response to error messages */ 128843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_read_config_word(pdev, pos + PCI_EXP_RTCTL, ®16); 129843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto reg16 &= ~(SYSTEM_ERROR_INTR_ON_MESG_MASK); 130843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_write_config_word(pdev, pos + PCI_EXP_RTCTL, reg16); 131843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 132843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto aer_pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR); 133843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto /* Clear error status */ 134843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, ®32); 135843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, reg32); 136843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_read_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, ®32); 137843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_write_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, reg32); 138843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_read_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, ®32); 139843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_write_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, reg32); 140843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 141843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto /* 142843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * Enable error reporting for the root port device and downstream port 143843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * devices. 144843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto */ 145843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto set_downstream_devices_error_reporting(pdev, true); 146843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 147843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto /* Enable Root Port's interrupt in response to error messages */ 148843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_COMMAND, ®32); 149843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto reg32 |= ROOT_PORT_INTR_ON_MESG_MASK; 150843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_COMMAND, reg32); 151843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto} 152843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 153843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto/** 154843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * aer_disable_rootport - disable Root Port's interrupts when receiving messages 155843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * @rpc: pointer to a Root Port data structure 156843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * 157843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * Invoked when PCIe bus unloads AER service driver. 158843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto */ 159843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Setostatic void aer_disable_rootport(struct aer_rpc *rpc) 160843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto{ 161843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto struct pci_dev *pdev = rpc->rpd->port; 162843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto u32 reg32; 163843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto int pos; 164843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 165843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto /* 166843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * Disable error reporting for the root port device and downstream port 167843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * devices. 168843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto */ 169843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto set_downstream_devices_error_reporting(pdev, false); 170843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 171843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR); 172843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto /* Disable Root's interrupt in response to error messages */ 173843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, ®32); 174843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK; 175843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, reg32); 176843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 177843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto /* Clear Root's error status reg */ 178843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, ®32); 179843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, reg32); 180843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto} 181843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 1826c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin/** 1836c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * aer_irq - Root Port's ISR 1846c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * @irq: IRQ assigned to Root Port 1856c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * @context: pointer to Root Port data structure 1866c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * 1876c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Invoked when Root Port detects AER messages. 1886c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin **/ 189634deb028c9188b4144863ea87dde5457fb93e92Huang Yingirqreturn_t aer_irq(int irq, void *context) 1906c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin{ 1916c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin unsigned int status, id; 1926c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin struct pcie_device *pdev = (struct pcie_device *)context; 1936c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin struct aer_rpc *rpc = get_service_data(pdev); 1946c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin int next_prod_idx; 1956c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin unsigned long flags; 1966c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin int pos; 1976c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 1980927678f55c9a50c296f7e6dae85e87b8236e155Jesse Barnes pos = pci_find_ext_capability(pdev->port, PCI_EXT_CAP_ID_ERR); 1996c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* 2006c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Must lock access to Root Error Status Reg, Root Error ID Reg, 2016c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * and Root error producer/consumer index 2026c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin */ 2036c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin spin_lock_irqsave(&rpc->e_lock, flags); 2046c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 2056c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* Read error status */ 2066c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, &status); 207e167bfcaa4cd44b4c66206a3c06b2aafb3f1260eHidetoshi Seto if (!(status & (PCI_ERR_ROOT_UNCOR_RCV|PCI_ERR_ROOT_COR_RCV))) { 2086c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin spin_unlock_irqrestore(&rpc->e_lock, flags); 2096c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin return IRQ_NONE; 2106c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin } 2116c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 2126c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* Read error source and clear error status */ 213f647a44f5725b0e6c8211096f4b49900164123eeHidetoshi Seto pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_ERR_SRC, &id); 2146c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin pci_write_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, status); 2156c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 2166c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* Store error source for later DPC handler */ 2176c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin next_prod_idx = rpc->prod_idx + 1; 2186c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin if (next_prod_idx == AER_ERROR_SOURCES_MAX) 2196c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin next_prod_idx = 0; 2206c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin if (next_prod_idx == rpc->cons_idx) { 2216c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* 2226c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Error Storm Condition - possibly the same error occurred. 2236c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Drop the error. 2246c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin */ 2256c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin spin_unlock_irqrestore(&rpc->e_lock, flags); 2266c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin return IRQ_HANDLED; 2276c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin } 2286c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin rpc->e_sources[rpc->prod_idx].status = status; 2296c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin rpc->e_sources[rpc->prod_idx].id = id; 2306c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin rpc->prod_idx = next_prod_idx; 2316c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin spin_unlock_irqrestore(&rpc->e_lock, flags); 2326c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 2336c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* Invoke DPC handler */ 2346c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin schedule_work(&rpc->dpc_handler); 2356c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 2366c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin return IRQ_HANDLED; 2376c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin} 238634deb028c9188b4144863ea87dde5457fb93e92Huang YingEXPORT_SYMBOL_GPL(aer_irq); 2396c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 2406c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin/** 2416c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * aer_alloc_rpc - allocate Root Port data structure 2426c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * @dev: pointer to the pcie_dev data structure 2436c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * 2446c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Invoked when Root Port's AER service is loaded. 2456c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin **/ 246c9a918838c07cbef934c8ef818d8f0e719015c3aHidetoshi Setostatic struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev) 2476c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin{ 2486c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin struct aer_rpc *rpc; 2496c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 250c9a918838c07cbef934c8ef818d8f0e719015c3aHidetoshi Seto rpc = kzalloc(sizeof(struct aer_rpc), GFP_KERNEL); 251c9a918838c07cbef934c8ef818d8f0e719015c3aHidetoshi Seto if (!rpc) 2526c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin return NULL; 2536c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 2546c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* 2556c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Initialize Root lock access, e_lock, to Root Error Status Reg, 2566c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Root Error ID Reg, and Root error producer/consumer index. 2576c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin */ 258f5609d7e679db3f29433f56e1f2e397a2f815288Milind Arun Choudhary spin_lock_init(&rpc->e_lock); 2596c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 2606c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin rpc->rpd = dev; 26165f27f38446e1976cc98fd3004b110fedcddd189David Howells INIT_WORK(&rpc->dpc_handler, aer_isr); 2626c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin rpc->prod_idx = rpc->cons_idx = 0; 2636c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin mutex_init(&rpc->rpc_mutex); 2646c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin init_waitqueue_head(&rpc->wait_release); 2656c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 26645e829ea412760d2404d7dfc42528df46aedbf62Stefan Assmann /* Use PCIe bus function to store rpc into PCIe device */ 2676c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin set_service_data(dev, rpc); 2686c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 2696c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin return rpc; 2706c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin} 2716c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 2726c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin/** 2736c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * aer_remove - clean up resources 2746c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * @dev: pointer to the pcie_dev data structure 2756c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * 2766c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Invoked when PCI Express bus unloads or AER probe fails. 2776c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin **/ 2786c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanminstatic void aer_remove(struct pcie_device *dev) 2796c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin{ 2806c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin struct aer_rpc *rpc = get_service_data(dev); 2816c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 2826c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin if (rpc) { 2836c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* If register interrupt service, it must be free. */ 2846c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin if (rpc->isr) 2856c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin free_irq(dev->irq, dev); 2866c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 2876c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin wait_event(rpc->wait_release, rpc->prod_idx == rpc->cons_idx); 2886c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 289460d298d521910483dcdc09920ca4c4a63b16730Hidetoshi Seto aer_disable_rootport(rpc); 290460d298d521910483dcdc09920ca4c4a63b16730Hidetoshi Seto kfree(rpc); 2916c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin set_service_data(dev, NULL); 2926c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin } 2936c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin} 2946c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 2956c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin/** 2966c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * aer_probe - initialize resources 2976c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * @dev: pointer to the pcie_dev data structure 2986c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * @id: pointer to the service id data structure 2996c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * 3006c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Invoked when PCI Express bus loads AER service driver. 3016c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin **/ 302c9a918838c07cbef934c8ef818d8f0e719015c3aHidetoshi Setostatic int __devinit aer_probe(struct pcie_device *dev) 3036c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin{ 3046c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin int status; 3056c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin struct aer_rpc *rpc; 3066c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin struct device *device = &dev->device; 3076c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 3086c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* Init */ 309c9a918838c07cbef934c8ef818d8f0e719015c3aHidetoshi Seto status = aer_init(dev); 310c9a918838c07cbef934c8ef818d8f0e719015c3aHidetoshi Seto if (status) 3116c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin return status; 3126c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 3136c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* Alloc rpc data structure */ 314c9a918838c07cbef934c8ef818d8f0e719015c3aHidetoshi Seto rpc = aer_alloc_rpc(dev); 315c9a918838c07cbef934c8ef818d8f0e719015c3aHidetoshi Seto if (!rpc) { 316531f254e5cdadb894f04ed27107cdb34c15817eaBjorn Helgaas dev_printk(KERN_DEBUG, device, "alloc rpc failed\n"); 3176c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin aer_remove(dev); 3186c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin return -ENOMEM; 3196c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin } 3206c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 3216c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* Request IRQ ISR */ 322c9a918838c07cbef934c8ef818d8f0e719015c3aHidetoshi Seto status = request_irq(dev->irq, aer_irq, IRQF_SHARED, "aerdrv", dev); 323c9a918838c07cbef934c8ef818d8f0e719015c3aHidetoshi Seto if (status) { 324531f254e5cdadb894f04ed27107cdb34c15817eaBjorn Helgaas dev_printk(KERN_DEBUG, device, "request IRQ failed\n"); 3256c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin aer_remove(dev); 3266c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin return status; 3276c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin } 3286c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 3296c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin rpc->isr = 1; 3306c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 3316c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin aer_enable_rootport(rpc); 3326c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 3336c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin return status; 3346c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin} 3356c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 3366c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin/** 3376c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * aer_root_reset - reset link on Root Port 3386c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * @dev: pointer to Root Port's pci_dev data structure 3396c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * 3406c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Invoked by Port Bus driver when performing link reset at Root Port. 3416c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin **/ 3426c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanminstatic pci_ers_result_t aer_root_reset(struct pci_dev *dev) 3436c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin{ 3446c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin u16 p2p_ctrl; 345c6d34eddecb34fd84f9fb2ea26a63cfde5662f49Hidetoshi Seto u32 reg32; 3466c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin int pos; 3476c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 3480927678f55c9a50c296f7e6dae85e87b8236e155Jesse Barnes pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); 3496c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 3506c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* Disable Root's interrupt in response to error messages */ 351c6d34eddecb34fd84f9fb2ea26a63cfde5662f49Hidetoshi Seto pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, ®32); 352c6d34eddecb34fd84f9fb2ea26a63cfde5662f49Hidetoshi Seto reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK; 353c6d34eddecb34fd84f9fb2ea26a63cfde5662f49Hidetoshi Seto pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32); 3546c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 3556c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* Assert Secondary Bus Reset */ 3566c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &p2p_ctrl); 3574352aa5bbf1d0080c2dcf904ce1e4be0a1cb5937Alexander Duyck p2p_ctrl |= PCI_BRIDGE_CTL_BUS_RESET; 3586c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl); 3596c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 3604352aa5bbf1d0080c2dcf904ce1e4be0a1cb5937Alexander Duyck /* 3614352aa5bbf1d0080c2dcf904ce1e4be0a1cb5937Alexander Duyck * we should send hot reset message for 2ms to allow it time to 3624352aa5bbf1d0080c2dcf904ce1e4be0a1cb5937Alexander Duyck * propogate to all downstream ports 3634352aa5bbf1d0080c2dcf904ce1e4be0a1cb5937Alexander Duyck */ 3644352aa5bbf1d0080c2dcf904ce1e4be0a1cb5937Alexander Duyck msleep(2); 3654352aa5bbf1d0080c2dcf904ce1e4be0a1cb5937Alexander Duyck 3666c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* De-assert Secondary Bus Reset */ 3674352aa5bbf1d0080c2dcf904ce1e4be0a1cb5937Alexander Duyck p2p_ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET; 3686c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl); 3696c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 3706c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* 3716c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * System software must wait for at least 100ms from the end 3726c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * of a reset of one or more device before it is permitted 3736c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * to issue Configuration Requests to those devices. 3746c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin */ 3756c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin msleep(200); 376531f254e5cdadb894f04ed27107cdb34c15817eaBjorn Helgaas dev_printk(KERN_DEBUG, &dev->dev, "Root Port link has been reset\n"); 3776c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 378c6d34eddecb34fd84f9fb2ea26a63cfde5662f49Hidetoshi Seto /* Clear Root Error Status */ 379c6d34eddecb34fd84f9fb2ea26a63cfde5662f49Hidetoshi Seto pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, ®32); 380c6d34eddecb34fd84f9fb2ea26a63cfde5662f49Hidetoshi Seto pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, reg32); 381c6d34eddecb34fd84f9fb2ea26a63cfde5662f49Hidetoshi Seto 3826c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* Enable Root Port's interrupt in response to error messages */ 383c6d34eddecb34fd84f9fb2ea26a63cfde5662f49Hidetoshi Seto pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, ®32); 384c6d34eddecb34fd84f9fb2ea26a63cfde5662f49Hidetoshi Seto reg32 |= ROOT_PORT_INTR_ON_MESG_MASK; 385c6d34eddecb34fd84f9fb2ea26a63cfde5662f49Hidetoshi Seto pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32); 3866c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 3876c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin return PCI_ERS_RESULT_RECOVERED; 3886c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin} 3896c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 3906c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin/** 3916c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * aer_error_detected - update severity status 3926c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * @dev: pointer to Root Port's pci_dev data structure 3936c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * @error: error severity being notified by port bus 3946c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * 3956c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Invoked by Port Bus driver during error recovery. 3966c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin **/ 3976c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanminstatic pci_ers_result_t aer_error_detected(struct pci_dev *dev, 3986c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin enum pci_channel_state error) 3996c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin{ 4006c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* Root Port has no impact. Always recovers. */ 4016c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin return PCI_ERS_RESULT_CAN_RECOVER; 4026c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin} 4036c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 4046c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin/** 4056c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * aer_error_resume - clean up corresponding error status bits 4066c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * @dev: pointer to Root Port's pci_dev data structure 4076c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * 4086c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Invoked by Port Bus driver during nonfatal recovery. 4096c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin **/ 4106c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanminstatic void aer_error_resume(struct pci_dev *dev) 4116c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin{ 4126c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin int pos; 4136c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin u32 status, mask; 4146c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin u16 reg16; 4156c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 4166c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* Clean up Root device status */ 41739a53062cb5b2ceca6035f3ed67317672f0bcf3bKenji Kaneshige pos = pci_pcie_cap(dev); 4186c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, ®16); 4196c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin pci_write_config_word(dev, pos + PCI_EXP_DEVSTA, reg16); 4206c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 4216c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* Clean AER Root Error Status */ 4220927678f55c9a50c296f7e6dae85e87b8236e155Jesse Barnes pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); 4236c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status); 4246c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask); 4256c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin if (dev->error_state == pci_channel_io_normal) 4266c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin status &= ~mask; /* Clear corresponding nonfatal bits */ 4276c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin else 4286c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin status &= mask; /* Clear corresponding fatal bits */ 4296c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status); 4306c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin} 4316c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 4326c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin/** 4336c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * aer_service_init - register AER root service driver 4346c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * 4356c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Invoked when AER root service driver is loaded. 4366c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin **/ 4376c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanminstatic int __init aer_service_init(void) 4386c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin{ 4397f785763660e75c9eddaddea3d618696af4ae3a2Randy Dunlap if (pcie_aer_disable) 4407f785763660e75c9eddaddea3d618696af4ae3a2Randy Dunlap return -ENXIO; 4413e77a3f7895e9c20756dc250282afa12f6d259a3Andi Kleen if (!pci_msi_enabled()) 4423e77a3f7895e9c20756dc250282afa12f6d259a3Andi Kleen return -ENXIO; 443c1996c2778e90f80cb9fc6a52508068f10d39611Sam Ravnborg return pcie_port_service_register(&aerdriver); 4446c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin} 4456c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 4466c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin/** 4476c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * aer_service_exit - unregister AER root service driver 4486c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * 4496c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Invoked when AER root service driver is unloaded. 4506c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin **/ 4516c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanminstatic void __exit aer_service_exit(void) 4526c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin{ 453c1996c2778e90f80cb9fc6a52508068f10d39611Sam Ravnborg pcie_port_service_unregister(&aerdriver); 4546c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin} 4556c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 4566c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanminmodule_init(aer_service_init); 4576c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanminmodule_exit(aer_service_exit); 458