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> 20415e12b2379239973feab91850b0dce985c6058aRafael J. Wysocki#include <linux/pci-acpi.h> 21d43c36dc6b357fa1806800f18aa30123c747a6d1Alexey Dobriyan#include <linux/sched.h> 226c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin#include <linux/kernel.h> 236c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin#include <linux/errno.h> 246c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin#include <linux/pm.h> 256c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin#include <linux/init.h> 266c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin#include <linux/interrupt.h> 276c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin#include <linux/delay.h> 286c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin#include <linux/pcieport_if.h> 295a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 306c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 316c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin#include "aerdrv.h" 325d9526d07a8dc87460c13c277b3edcc26b0e662fAlex Chiang#include "../../pci.h" 336c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 346c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin/* 356c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Version Information 366c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin */ 376c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin#define DRIVER_VERSION "v1.0" 386c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin#define DRIVER_AUTHOR "tom.l.nguyen@intel.com" 396c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin#define DRIVER_DESC "Root Port Advanced Error Reporting Driver" 406c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, YanminMODULE_AUTHOR(DRIVER_AUTHOR); 416c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, YanminMODULE_DESCRIPTION(DRIVER_DESC); 426c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, YanminMODULE_LICENSE("GPL"); 436c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 4415856ad50bf5ea02a5ee22399c036d49e7e1124dBill Pembertonstatic int aer_probe(struct pcie_device *dev); 456c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanminstatic void aer_remove(struct pcie_device *dev); 466c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanminstatic pci_ers_result_t aer_error_detected(struct pci_dev *dev, 476c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin enum pci_channel_state error); 486c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanminstatic void aer_error_resume(struct pci_dev *dev); 496c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanminstatic pci_ers_result_t aer_root_reset(struct pci_dev *dev); 506c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 51494530284f16298050ab99f54b7b12dd7d1418a1Stephen Hemmingerstatic const struct pci_error_handlers aer_error_handlers = { 526c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin .error_detected = aer_error_detected, 53c9a918838c07cbef934c8ef818d8f0e719015c3aHidetoshi Seto .resume = aer_error_resume, 546c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin}; 556c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 56c1996c2778e90f80cb9fc6a52508068f10d39611Sam Ravnborgstatic struct pcie_port_service_driver aerdriver = { 576c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin .name = "aer", 58694f88ef7ada0d99e304f687ba92e268a594358bKenji Kaneshige .port_type = PCI_EXP_TYPE_ROOT_PORT, 5922106368c999246c414610dcaacd485e741605b1Rafael J. Wysocki .service = PCIE_PORT_SERVICE_AER, 606c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 616c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin .probe = aer_probe, 626c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin .remove = aer_remove, 636c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 646c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin .err_handler = &aer_error_handlers, 656c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 666c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin .reset_link = aer_root_reset, 676c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin}; 686c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 697f785763660e75c9eddaddea3d618696af4ae3a2Randy Dunlapstatic int pcie_aer_disable; 707f785763660e75c9eddaddea3d618696af4ae3a2Randy Dunlap 717f785763660e75c9eddaddea3d618696af4ae3a2Randy Dunlapvoid pci_no_aer(void) 727f785763660e75c9eddaddea3d618696af4ae3a2Randy Dunlap{ 737f785763660e75c9eddaddea3d618696af4ae3a2Randy Dunlap pcie_aer_disable = 1; /* has priority over 'forceload' */ 747f785763660e75c9eddaddea3d618696af4ae3a2Randy Dunlap} 757f785763660e75c9eddaddea3d618696af4ae3a2Randy Dunlap 76f1a7bfaf6bb9cb195577e674c0ab2fd0a55d9014Rafael J. Wysockibool pci_aer_available(void) 77f1a7bfaf6bb9cb195577e674c0ab2fd0a55d9014Rafael J. Wysocki{ 78f1a7bfaf6bb9cb195577e674c0ab2fd0a55d9014Rafael J. Wysocki return !pcie_aer_disable && pci_msi_enabled(); 79f1a7bfaf6bb9cb195577e674c0ab2fd0a55d9014Rafael J. Wysocki} 80f1a7bfaf6bb9cb195577e674c0ab2fd0a55d9014Rafael J. Wysocki 81843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Setostatic int set_device_error_reporting(struct pci_dev *dev, void *data) 82843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto{ 83843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto bool enable = *((bool *)data); 8462f87c0e31d646d5501edf4f7feb07d0ad689d80Yijing Wang int type = pci_pcie_type(dev); 85843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 8662f87c0e31d646d5501edf4f7feb07d0ad689d80Yijing Wang if ((type == PCI_EXP_TYPE_ROOT_PORT) || 8762f87c0e31d646d5501edf4f7feb07d0ad689d80Yijing Wang (type == PCI_EXP_TYPE_UPSTREAM) || 8862f87c0e31d646d5501edf4f7feb07d0ad689d80Yijing Wang (type == PCI_EXP_TYPE_DOWNSTREAM)) { 89843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto if (enable) 90843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_enable_pcie_error_reporting(dev); 91843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto else 92843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_disable_pcie_error_reporting(dev); 93843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto } 94843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 95843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto if (enable) 96843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pcie_set_ecrc_checking(dev); 97843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 98843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto return 0; 99843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto} 100843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 101843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto/** 102843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * set_downstream_devices_error_reporting - enable/disable the error reporting bits on the root port and its downstream ports. 103843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * @dev: pointer to root port's pci_dev data structure 104843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * @enable: true = enable error reporting, false = disable error reporting. 105843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto */ 106843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Setostatic void set_downstream_devices_error_reporting(struct pci_dev *dev, 107843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto bool enable) 108843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto{ 109843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto set_device_error_reporting(dev, &enable); 110843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 111843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto if (!dev->subordinate) 112843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto return; 113843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_walk_bus(dev->subordinate, set_device_error_reporting, &enable); 114843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto} 115843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 116843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto/** 117843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * aer_enable_rootport - enable Root Port's interrupts when receiving messages 118843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * @rpc: pointer to a Root Port data structure 119843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * 120843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * Invoked when PCIe bus loads AER service driver. 121843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto */ 122843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Setostatic void aer_enable_rootport(struct aer_rpc *rpc) 123843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto{ 124843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto struct pci_dev *pdev = rpc->rpd->port; 12543bd4ee89f748111d2a0443e6ef58f08ceb359aaJiang Liu int aer_pos; 126843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto u16 reg16; 127843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto u32 reg32; 128843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 129843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto /* Clear PCIe Capability's Device Status */ 13043bd4ee89f748111d2a0443e6ef58f08ceb359aaJiang Liu pcie_capability_read_word(pdev, PCI_EXP_DEVSTA, ®16); 13143bd4ee89f748111d2a0443e6ef58f08ceb359aaJiang Liu pcie_capability_write_word(pdev, PCI_EXP_DEVSTA, reg16); 132843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 133843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto /* Disable system error generation in response to error messages */ 13443bd4ee89f748111d2a0443e6ef58f08ceb359aaJiang Liu pcie_capability_clear_word(pdev, PCI_EXP_RTCTL, 13543bd4ee89f748111d2a0443e6ef58f08ceb359aaJiang Liu SYSTEM_ERROR_INTR_ON_MESG_MASK); 136843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 137843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto aer_pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR); 138843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto /* Clear error status */ 139843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, ®32); 140843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, reg32); 141843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_read_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, ®32); 142843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_write_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, reg32); 143843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_read_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, ®32); 144843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_write_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, reg32); 145843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 146843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto /* 147843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * Enable error reporting for the root port device and downstream port 148843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * devices. 149843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto */ 150843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto set_downstream_devices_error_reporting(pdev, true); 151843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 152843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto /* Enable Root Port's interrupt in response to error messages */ 153843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_COMMAND, ®32); 154843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto reg32 |= ROOT_PORT_INTR_ON_MESG_MASK; 155843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_COMMAND, reg32); 156843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto} 157843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 158843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto/** 159843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * aer_disable_rootport - disable Root Port's interrupts when receiving messages 160843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * @rpc: pointer to a Root Port data structure 161843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * 162843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * Invoked when PCIe bus unloads AER service driver. 163843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto */ 164843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Setostatic void aer_disable_rootport(struct aer_rpc *rpc) 165843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto{ 166843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto struct pci_dev *pdev = rpc->rpd->port; 167843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto u32 reg32; 168843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto int pos; 169843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 170843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto /* 171843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * Disable error reporting for the root port device and downstream port 172843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto * devices. 173843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto */ 174843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto set_downstream_devices_error_reporting(pdev, false); 175843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 176843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR); 177843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto /* Disable Root's interrupt in response to error messages */ 178843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, ®32); 179843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK; 180843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, reg32); 181843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 182843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto /* Clear Root's error status reg */ 183843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, ®32); 184843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, reg32); 185843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto} 186843f4697eea576c24f057bbdb199115bbb6b10bcHidetoshi Seto 1876c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin/** 1886c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * aer_irq - Root Port's ISR 1896c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * @irq: IRQ assigned to Root Port 1906c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * @context: pointer to Root Port data structure 1916c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * 1926c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Invoked when Root Port detects AER messages. 193f6d3780061283039de33b402c35c3bf9322afe14Hidetoshi Seto */ 194634deb028c9188b4144863ea87dde5457fb93e92Huang Yingirqreturn_t aer_irq(int irq, void *context) 1956c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin{ 1966c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin unsigned int status, id; 1976c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin struct pcie_device *pdev = (struct pcie_device *)context; 1986c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin struct aer_rpc *rpc = get_service_data(pdev); 1996c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin int next_prod_idx; 2006c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin unsigned long flags; 2016c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin int pos; 2026c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 2030927678f55c9a50c296f7e6dae85e87b8236e155Jesse Barnes pos = pci_find_ext_capability(pdev->port, PCI_EXT_CAP_ID_ERR); 2046c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* 2056c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Must lock access to Root Error Status Reg, Root Error ID Reg, 2066c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * and Root error producer/consumer index 2076c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin */ 2086c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin spin_lock_irqsave(&rpc->e_lock, flags); 2096c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 2106c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* Read error status */ 2116c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, &status); 212e167bfcaa4cd44b4c66206a3c06b2aafb3f1260eHidetoshi Seto if (!(status & (PCI_ERR_ROOT_UNCOR_RCV|PCI_ERR_ROOT_COR_RCV))) { 2136c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin spin_unlock_irqrestore(&rpc->e_lock, flags); 2146c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin return IRQ_NONE; 2156c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin } 2166c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 2176c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* Read error source and clear error status */ 218f647a44f5725b0e6c8211096f4b49900164123eeHidetoshi Seto pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_ERR_SRC, &id); 2196c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin pci_write_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, status); 2206c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 2216c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* Store error source for later DPC handler */ 2226c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin next_prod_idx = rpc->prod_idx + 1; 2236c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin if (next_prod_idx == AER_ERROR_SOURCES_MAX) 2246c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin next_prod_idx = 0; 2256c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin if (next_prod_idx == rpc->cons_idx) { 2266c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* 2276c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Error Storm Condition - possibly the same error occurred. 2286c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Drop the error. 2296c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin */ 2306c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin spin_unlock_irqrestore(&rpc->e_lock, flags); 2316c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin return IRQ_HANDLED; 2326c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin } 2336c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin rpc->e_sources[rpc->prod_idx].status = status; 2346c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin rpc->e_sources[rpc->prod_idx].id = id; 2356c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin rpc->prod_idx = next_prod_idx; 2366c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin spin_unlock_irqrestore(&rpc->e_lock, flags); 2376c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 2386c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* Invoke DPC handler */ 2396c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin schedule_work(&rpc->dpc_handler); 2406c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 2416c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin return IRQ_HANDLED; 2426c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin} 243634deb028c9188b4144863ea87dde5457fb93e92Huang YingEXPORT_SYMBOL_GPL(aer_irq); 2446c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 2456c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin/** 2466c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * aer_alloc_rpc - allocate Root Port data structure 2476c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * @dev: pointer to the pcie_dev data structure 2486c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * 2496c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Invoked when Root Port's AER service is loaded. 250f6d3780061283039de33b402c35c3bf9322afe14Hidetoshi Seto */ 251c9a918838c07cbef934c8ef818d8f0e719015c3aHidetoshi Setostatic struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev) 2526c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin{ 2536c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin struct aer_rpc *rpc; 2546c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 255c9a918838c07cbef934c8ef818d8f0e719015c3aHidetoshi Seto rpc = kzalloc(sizeof(struct aer_rpc), GFP_KERNEL); 256c9a918838c07cbef934c8ef818d8f0e719015c3aHidetoshi Seto if (!rpc) 2576c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin return NULL; 2586c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 259f6d3780061283039de33b402c35c3bf9322afe14Hidetoshi Seto /* Initialize Root lock access, e_lock, to Root Error Status Reg */ 260f5609d7e679db3f29433f56e1f2e397a2f815288Milind Arun Choudhary spin_lock_init(&rpc->e_lock); 2616c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 2626c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin rpc->rpd = dev; 26365f27f38446e1976cc98fd3004b110fedcddd189David Howells INIT_WORK(&rpc->dpc_handler, aer_isr); 2646c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin mutex_init(&rpc->rpc_mutex); 2656c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin init_waitqueue_head(&rpc->wait_release); 2666c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 26745e829ea412760d2404d7dfc42528df46aedbf62Stefan Assmann /* Use PCIe bus function to store rpc into PCIe device */ 2686c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin set_service_data(dev, rpc); 2696c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 2706c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin return rpc; 2716c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin} 2726c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 2736c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin/** 2746c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * aer_remove - clean up resources 2756c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * @dev: pointer to the pcie_dev data structure 2766c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * 2776c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Invoked when PCI Express bus unloads or AER probe fails. 278f6d3780061283039de33b402c35c3bf9322afe14Hidetoshi Seto */ 2796c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanminstatic void aer_remove(struct pcie_device *dev) 2806c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin{ 2816c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin struct aer_rpc *rpc = get_service_data(dev); 2826c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 2836c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin if (rpc) { 2846c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* If register interrupt service, it must be free. */ 2856c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin if (rpc->isr) 2866c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin free_irq(dev->irq, dev); 2876c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 2886c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin wait_event(rpc->wait_release, rpc->prod_idx == rpc->cons_idx); 2896c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 290460d298d521910483dcdc09920ca4c4a63b16730Hidetoshi Seto aer_disable_rootport(rpc); 291460d298d521910483dcdc09920ca4c4a63b16730Hidetoshi Seto kfree(rpc); 2926c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin set_service_data(dev, NULL); 2936c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin } 2946c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin} 2956c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 2966c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin/** 2976c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * aer_probe - initialize resources 2986c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * @dev: pointer to the pcie_dev data structure 2996c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * @id: pointer to the service id data structure 3006c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * 3016c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Invoked when PCI Express bus loads AER service driver. 302f6d3780061283039de33b402c35c3bf9322afe14Hidetoshi Seto */ 30315856ad50bf5ea02a5ee22399c036d49e7e1124dBill Pembertonstatic int aer_probe(struct pcie_device *dev) 3046c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin{ 3056c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin int status; 3066c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin struct aer_rpc *rpc; 3076c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin struct device *device = &dev->device; 3086c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 3096c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* Init */ 310c9a918838c07cbef934c8ef818d8f0e719015c3aHidetoshi Seto status = aer_init(dev); 311c9a918838c07cbef934c8ef818d8f0e719015c3aHidetoshi Seto if (status) 3126c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin return status; 3136c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 3146c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* Alloc rpc data structure */ 315c9a918838c07cbef934c8ef818d8f0e719015c3aHidetoshi Seto rpc = aer_alloc_rpc(dev); 316c9a918838c07cbef934c8ef818d8f0e719015c3aHidetoshi Seto if (!rpc) { 317531f254e5cdadb894f04ed27107cdb34c15817eaBjorn Helgaas dev_printk(KERN_DEBUG, device, "alloc rpc failed\n"); 3186c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin aer_remove(dev); 3196c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin return -ENOMEM; 3206c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin } 3216c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 3226c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* Request IRQ ISR */ 323c9a918838c07cbef934c8ef818d8f0e719015c3aHidetoshi Seto status = request_irq(dev->irq, aer_irq, IRQF_SHARED, "aerdrv", dev); 324c9a918838c07cbef934c8ef818d8f0e719015c3aHidetoshi Seto if (status) { 325531f254e5cdadb894f04ed27107cdb34c15817eaBjorn Helgaas dev_printk(KERN_DEBUG, device, "request IRQ failed\n"); 3266c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin aer_remove(dev); 3276c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin return status; 3286c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin } 3296c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 3306c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin rpc->isr = 1; 3316c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 3326c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin aer_enable_rootport(rpc); 3336c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 3346c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin return status; 3356c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin} 3366c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 3376c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin/** 3386c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * aer_root_reset - reset link on Root Port 3396c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * @dev: pointer to Root Port's pci_dev data structure 3406c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * 3416c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Invoked by Port Bus driver when performing link reset at Root Port. 342f6d3780061283039de33b402c35c3bf9322afe14Hidetoshi Seto */ 3436c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanminstatic pci_ers_result_t aer_root_reset(struct pci_dev *dev) 3446c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin{ 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 3551b95ce8fc9c12fdb60047f2f9950f29e76e7c66dAlex Williamson pci_reset_bridge_secondary_bus(dev); 356531f254e5cdadb894f04ed27107cdb34c15817eaBjorn Helgaas dev_printk(KERN_DEBUG, &dev->dev, "Root Port link has been reset\n"); 3576c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 358c6d34eddecb34fd84f9fb2ea26a63cfde5662f49Hidetoshi Seto /* Clear Root Error Status */ 359c6d34eddecb34fd84f9fb2ea26a63cfde5662f49Hidetoshi Seto pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, ®32); 360c6d34eddecb34fd84f9fb2ea26a63cfde5662f49Hidetoshi Seto pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, reg32); 361c6d34eddecb34fd84f9fb2ea26a63cfde5662f49Hidetoshi Seto 3626c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* Enable Root Port's interrupt in response to error messages */ 363c6d34eddecb34fd84f9fb2ea26a63cfde5662f49Hidetoshi Seto pci_read_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, ®32); 364c6d34eddecb34fd84f9fb2ea26a63cfde5662f49Hidetoshi Seto reg32 |= ROOT_PORT_INTR_ON_MESG_MASK; 365c6d34eddecb34fd84f9fb2ea26a63cfde5662f49Hidetoshi Seto pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32); 3666c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 3676c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin return PCI_ERS_RESULT_RECOVERED; 3686c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin} 3696c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 3706c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin/** 3716c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * aer_error_detected - update severity status 3726c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * @dev: pointer to Root Port's pci_dev data structure 3736c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * @error: error severity being notified by port bus 3746c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * 3756c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Invoked by Port Bus driver during error recovery. 376f6d3780061283039de33b402c35c3bf9322afe14Hidetoshi Seto */ 3776c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanminstatic pci_ers_result_t aer_error_detected(struct pci_dev *dev, 3786c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin enum pci_channel_state error) 3796c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin{ 3806c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* Root Port has no impact. Always recovers. */ 3816c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin return PCI_ERS_RESULT_CAN_RECOVER; 3826c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin} 3836c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 3846c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin/** 3856c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * aer_error_resume - clean up corresponding error status bits 3866c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * @dev: pointer to Root Port's pci_dev data structure 3876c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * 3886c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Invoked by Port Bus driver during nonfatal recovery. 389f6d3780061283039de33b402c35c3bf9322afe14Hidetoshi Seto */ 3906c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanminstatic void aer_error_resume(struct pci_dev *dev) 3916c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin{ 3926c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin int pos; 3936c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin u32 status, mask; 3946c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin u16 reg16; 3956c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 3966c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* Clean up Root device status */ 39743bd4ee89f748111d2a0443e6ef58f08ceb359aaJiang Liu pcie_capability_read_word(dev, PCI_EXP_DEVSTA, ®16); 39843bd4ee89f748111d2a0443e6ef58f08ceb359aaJiang Liu pcie_capability_write_word(dev, PCI_EXP_DEVSTA, reg16); 3996c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 4006c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin /* Clean AER Root Error Status */ 4010927678f55c9a50c296f7e6dae85e87b8236e155Jesse Barnes pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); 4026c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status); 4036c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask); 4046c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin if (dev->error_state == pci_channel_io_normal) 4056c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin status &= ~mask; /* Clear corresponding nonfatal bits */ 4066c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin else 4076c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin status &= mask; /* Clear corresponding fatal bits */ 4086c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status); 4096c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin} 4106c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 4116c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin/** 4126c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * aer_service_init - register AER root service driver 4136c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * 4146c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Invoked when AER root service driver is loaded. 415f6d3780061283039de33b402c35c3bf9322afe14Hidetoshi Seto */ 4166c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanminstatic int __init aer_service_init(void) 4176c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin{ 418b22c3d82757109fa107ce17ba9484d45273eed05Rafael J. Wysocki if (!pci_aer_available() || aer_acpi_firmware_first()) 4193e77a3f7895e9c20756dc250282afa12f6d259a3Andi Kleen return -ENXIO; 420c1996c2778e90f80cb9fc6a52508068f10d39611Sam Ravnborg return pcie_port_service_register(&aerdriver); 4216c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin} 4226c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 4236c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin/** 4246c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * aer_service_exit - unregister AER root service driver 4256c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * 4266c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin * Invoked when AER root service driver is unloaded. 427f6d3780061283039de33b402c35c3bf9322afe14Hidetoshi Seto */ 4286c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanminstatic void __exit aer_service_exit(void) 4296c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin{ 430c1996c2778e90f80cb9fc6a52508068f10d39611Sam Ravnborg pcie_port_service_unregister(&aerdriver); 4316c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin} 4326c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanmin 4336c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanminmodule_init(aer_service_init); 4346c2b374d74857e892080ee726184ec1d15e7d4e4Zhang, Yanminmodule_exit(aer_service_exit); 435