aerdrv.c revision d43c36dc6b357fa1806800f18aa30123c747a6d1
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_ANY_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, ®16); 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