aer_inject.c revision c9a918838c07cbef934c8ef818d8f0e719015c3a
1/* 2 * PCIE AER software error injection support. 3 * 4 * Debuging PCIE AER code is quite difficult because it is hard to 5 * trigger various real hardware errors. Software based error 6 * injection can fake almost all kinds of errors with the help of a 7 * user space helper tool aer-inject, which can be gotten from: 8 * http://www.kernel.org/pub/linux/utils/pci/aer-inject/ 9 * 10 * Copyright 2009 Intel Corporation. 11 * Huang Ying <ying.huang@intel.com> 12 * 13 * This program is free software; you can redistribute it and/or 14 * modify it under the terms of the GNU General Public License 15 * as published by the Free Software Foundation; version 2 16 * of the License. 17 * 18 */ 19 20#include <linux/module.h> 21#include <linux/init.h> 22#include <linux/miscdevice.h> 23#include <linux/pci.h> 24#include <linux/fs.h> 25#include <linux/uaccess.h> 26#include "aerdrv.h" 27 28struct aer_error_inj { 29 u8 bus; 30 u8 dev; 31 u8 fn; 32 u32 uncor_status; 33 u32 cor_status; 34 u32 header_log0; 35 u32 header_log1; 36 u32 header_log2; 37 u32 header_log3; 38}; 39 40struct aer_error { 41 struct list_head list; 42 unsigned int bus; 43 unsigned int devfn; 44 int pos_cap_err; 45 46 u32 uncor_status; 47 u32 cor_status; 48 u32 header_log0; 49 u32 header_log1; 50 u32 header_log2; 51 u32 header_log3; 52 u32 root_status; 53 u32 source_id; 54}; 55 56struct pci_bus_ops { 57 struct list_head list; 58 struct pci_bus *bus; 59 struct pci_ops *ops; 60}; 61 62static LIST_HEAD(einjected); 63 64static LIST_HEAD(pci_bus_ops_list); 65 66/* Protect einjected and pci_bus_ops_list */ 67static DEFINE_SPINLOCK(inject_lock); 68 69static void aer_error_init(struct aer_error *err, unsigned int bus, 70 unsigned int devfn, int pos_cap_err) 71{ 72 INIT_LIST_HEAD(&err->list); 73 err->bus = bus; 74 err->devfn = devfn; 75 err->pos_cap_err = pos_cap_err; 76} 77 78/* inject_lock must be held before calling */ 79static struct aer_error *__find_aer_error(unsigned int bus, unsigned int devfn) 80{ 81 struct aer_error *err; 82 83 list_for_each_entry(err, &einjected, list) { 84 if (bus == err->bus && devfn == err->devfn) 85 return err; 86 } 87 return NULL; 88} 89 90/* inject_lock must be held before calling */ 91static struct aer_error *__find_aer_error_by_dev(struct pci_dev *dev) 92{ 93 return __find_aer_error(dev->bus->number, dev->devfn); 94} 95 96/* inject_lock must be held before calling */ 97static struct pci_ops *__find_pci_bus_ops(struct pci_bus *bus) 98{ 99 struct pci_bus_ops *bus_ops; 100 101 list_for_each_entry(bus_ops, &pci_bus_ops_list, list) { 102 if (bus_ops->bus == bus) 103 return bus_ops->ops; 104 } 105 return NULL; 106} 107 108static struct pci_bus_ops *pci_bus_ops_pop(void) 109{ 110 unsigned long flags; 111 struct pci_bus_ops *bus_ops = NULL; 112 113 spin_lock_irqsave(&inject_lock, flags); 114 if (list_empty(&pci_bus_ops_list)) 115 bus_ops = NULL; 116 else { 117 struct list_head *lh = pci_bus_ops_list.next; 118 list_del(lh); 119 bus_ops = list_entry(lh, struct pci_bus_ops, list); 120 } 121 spin_unlock_irqrestore(&inject_lock, flags); 122 return bus_ops; 123} 124 125static u32 *find_pci_config_dword(struct aer_error *err, int where, 126 int *prw1cs) 127{ 128 int rw1cs = 0; 129 u32 *target = NULL; 130 131 if (err->pos_cap_err == -1) 132 return NULL; 133 134 switch (where - err->pos_cap_err) { 135 case PCI_ERR_UNCOR_STATUS: 136 target = &err->uncor_status; 137 rw1cs = 1; 138 break; 139 case PCI_ERR_COR_STATUS: 140 target = &err->cor_status; 141 rw1cs = 1; 142 break; 143 case PCI_ERR_HEADER_LOG: 144 target = &err->header_log0; 145 break; 146 case PCI_ERR_HEADER_LOG+4: 147 target = &err->header_log1; 148 break; 149 case PCI_ERR_HEADER_LOG+8: 150 target = &err->header_log2; 151 break; 152 case PCI_ERR_HEADER_LOG+12: 153 target = &err->header_log3; 154 break; 155 case PCI_ERR_ROOT_STATUS: 156 target = &err->root_status; 157 rw1cs = 1; 158 break; 159 case PCI_ERR_ROOT_COR_SRC: 160 target = &err->source_id; 161 break; 162 } 163 if (prw1cs) 164 *prw1cs = rw1cs; 165 return target; 166} 167 168static int pci_read_aer(struct pci_bus *bus, unsigned int devfn, int where, 169 int size, u32 *val) 170{ 171 u32 *sim; 172 struct aer_error *err; 173 unsigned long flags; 174 struct pci_ops *ops; 175 176 spin_lock_irqsave(&inject_lock, flags); 177 if (size != sizeof(u32)) 178 goto out; 179 err = __find_aer_error(bus->number, devfn); 180 if (!err) 181 goto out; 182 183 sim = find_pci_config_dword(err, where, NULL); 184 if (sim) { 185 *val = *sim; 186 spin_unlock_irqrestore(&inject_lock, flags); 187 return 0; 188 } 189out: 190 ops = __find_pci_bus_ops(bus); 191 spin_unlock_irqrestore(&inject_lock, flags); 192 return ops->read(bus, devfn, where, size, val); 193} 194 195int pci_write_aer(struct pci_bus *bus, unsigned int devfn, int where, int size, 196 u32 val) 197{ 198 u32 *sim; 199 struct aer_error *err; 200 unsigned long flags; 201 int rw1cs; 202 struct pci_ops *ops; 203 204 spin_lock_irqsave(&inject_lock, flags); 205 if (size != sizeof(u32)) 206 goto out; 207 err = __find_aer_error(bus->number, devfn); 208 if (!err) 209 goto out; 210 211 sim = find_pci_config_dword(err, where, &rw1cs); 212 if (sim) { 213 if (rw1cs) 214 *sim ^= val; 215 else 216 *sim = val; 217 spin_unlock_irqrestore(&inject_lock, flags); 218 return 0; 219 } 220out: 221 ops = __find_pci_bus_ops(bus); 222 spin_unlock_irqrestore(&inject_lock, flags); 223 return ops->write(bus, devfn, where, size, val); 224} 225 226static struct pci_ops pci_ops_aer = { 227 .read = pci_read_aer, 228 .write = pci_write_aer, 229}; 230 231static void pci_bus_ops_init(struct pci_bus_ops *bus_ops, 232 struct pci_bus *bus, 233 struct pci_ops *ops) 234{ 235 INIT_LIST_HEAD(&bus_ops->list); 236 bus_ops->bus = bus; 237 bus_ops->ops = ops; 238} 239 240static int pci_bus_set_aer_ops(struct pci_bus *bus) 241{ 242 struct pci_ops *ops; 243 struct pci_bus_ops *bus_ops; 244 unsigned long flags; 245 246 bus_ops = kmalloc(sizeof(*bus_ops), GFP_KERNEL); 247 if (!bus_ops) 248 return -ENOMEM; 249 ops = pci_bus_set_ops(bus, &pci_ops_aer); 250 spin_lock_irqsave(&inject_lock, flags); 251 if (ops == &pci_ops_aer) 252 goto out; 253 pci_bus_ops_init(bus_ops, bus, ops); 254 list_add(&bus_ops->list, &pci_bus_ops_list); 255 bus_ops = NULL; 256out: 257 spin_unlock_irqrestore(&inject_lock, flags); 258 kfree(bus_ops); 259 return 0; 260} 261 262static struct pci_dev *pcie_find_root_port(struct pci_dev *dev) 263{ 264 while (1) { 265 if (!dev->is_pcie) 266 break; 267 if (dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) 268 return dev; 269 if (!dev->bus->self) 270 break; 271 dev = dev->bus->self; 272 } 273 return NULL; 274} 275 276static int find_aer_device_iter(struct device *device, void *data) 277{ 278 struct pcie_device **result = data; 279 struct pcie_device *pcie_dev; 280 281 if (device->bus == &pcie_port_bus_type) { 282 pcie_dev = to_pcie_device(device); 283 if (pcie_dev->service & PCIE_PORT_SERVICE_AER) { 284 *result = pcie_dev; 285 return 1; 286 } 287 } 288 return 0; 289} 290 291static int find_aer_device(struct pci_dev *dev, struct pcie_device **result) 292{ 293 return device_for_each_child(&dev->dev, result, find_aer_device_iter); 294} 295 296static int aer_inject(struct aer_error_inj *einj) 297{ 298 struct aer_error *err, *rperr; 299 struct aer_error *err_alloc = NULL, *rperr_alloc = NULL; 300 struct pci_dev *dev, *rpdev; 301 struct pcie_device *edev; 302 unsigned long flags; 303 unsigned int devfn = PCI_DEVFN(einj->dev, einj->fn); 304 int pos_cap_err, rp_pos_cap_err; 305 u32 sever; 306 int ret = 0; 307 308 dev = pci_get_bus_and_slot(einj->bus, devfn); 309 if (!dev) 310 return -EINVAL; 311 rpdev = pcie_find_root_port(dev); 312 if (!rpdev) { 313 ret = -EINVAL; 314 goto out_put; 315 } 316 317 pos_cap_err = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); 318 if (!pos_cap_err) { 319 ret = -EIO; 320 goto out_put; 321 } 322 pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_SEVER, &sever); 323 324 rp_pos_cap_err = pci_find_ext_capability(rpdev, PCI_EXT_CAP_ID_ERR); 325 if (!rp_pos_cap_err) { 326 ret = -EIO; 327 goto out_put; 328 } 329 330 err_alloc = kzalloc(sizeof(struct aer_error), GFP_KERNEL); 331 if (!err_alloc) { 332 ret = -ENOMEM; 333 goto out_put; 334 } 335 rperr_alloc = kzalloc(sizeof(struct aer_error), GFP_KERNEL); 336 if (!rperr_alloc) { 337 ret = -ENOMEM; 338 goto out_put; 339 } 340 341 spin_lock_irqsave(&inject_lock, flags); 342 343 err = __find_aer_error_by_dev(dev); 344 if (!err) { 345 err = err_alloc; 346 err_alloc = NULL; 347 aer_error_init(err, einj->bus, devfn, pos_cap_err); 348 list_add(&err->list, &einjected); 349 } 350 err->uncor_status |= einj->uncor_status; 351 err->cor_status |= einj->cor_status; 352 err->header_log0 = einj->header_log0; 353 err->header_log1 = einj->header_log1; 354 err->header_log2 = einj->header_log2; 355 err->header_log3 = einj->header_log3; 356 357 rperr = __find_aer_error_by_dev(rpdev); 358 if (!rperr) { 359 rperr = rperr_alloc; 360 rperr_alloc = NULL; 361 aer_error_init(rperr, rpdev->bus->number, rpdev->devfn, 362 rp_pos_cap_err); 363 list_add(&rperr->list, &einjected); 364 } 365 if (einj->cor_status) { 366 if (rperr->root_status & PCI_ERR_ROOT_COR_RCV) 367 rperr->root_status |= PCI_ERR_ROOT_MULTI_COR_RCV; 368 else 369 rperr->root_status |= PCI_ERR_ROOT_COR_RCV; 370 rperr->source_id &= 0xffff0000; 371 rperr->source_id |= (einj->bus << 8) | devfn; 372 } 373 if (einj->uncor_status) { 374 if (rperr->root_status & PCI_ERR_ROOT_UNCOR_RCV) 375 rperr->root_status |= PCI_ERR_ROOT_MULTI_UNCOR_RCV; 376 if (sever & einj->uncor_status) { 377 rperr->root_status |= PCI_ERR_ROOT_FATAL_RCV; 378 if (!(rperr->root_status & PCI_ERR_ROOT_UNCOR_RCV)) 379 rperr->root_status |= PCI_ERR_ROOT_FIRST_FATAL; 380 } else 381 rperr->root_status |= PCI_ERR_ROOT_NONFATAL_RCV; 382 rperr->root_status |= PCI_ERR_ROOT_UNCOR_RCV; 383 rperr->source_id &= 0x0000ffff; 384 rperr->source_id |= ((einj->bus << 8) | devfn) << 16; 385 } 386 spin_unlock_irqrestore(&inject_lock, flags); 387 388 ret = pci_bus_set_aer_ops(dev->bus); 389 if (ret) 390 goto out_put; 391 ret = pci_bus_set_aer_ops(rpdev->bus); 392 if (ret) 393 goto out_put; 394 395 if (find_aer_device(rpdev, &edev)) 396 aer_irq(-1, edev); 397 else 398 ret = -EINVAL; 399out_put: 400 kfree(err_alloc); 401 kfree(rperr_alloc); 402 pci_dev_put(dev); 403 return ret; 404} 405 406static ssize_t aer_inject_write(struct file *filp, const char __user *ubuf, 407 size_t usize, loff_t *off) 408{ 409 struct aer_error_inj einj; 410 int ret; 411 412 if (!capable(CAP_SYS_ADMIN)) 413 return -EPERM; 414 415 if (usize != sizeof(struct aer_error_inj)) 416 return -EINVAL; 417 418 if (copy_from_user(&einj, ubuf, usize)) 419 return -EFAULT; 420 421 ret = aer_inject(&einj); 422 return ret ? ret : usize; 423} 424 425static const struct file_operations aer_inject_fops = { 426 .write = aer_inject_write, 427 .owner = THIS_MODULE, 428}; 429 430static struct miscdevice aer_inject_device = { 431 .minor = MISC_DYNAMIC_MINOR, 432 .name = "aer_inject", 433 .fops = &aer_inject_fops, 434}; 435 436static int __init aer_inject_init(void) 437{ 438 return misc_register(&aer_inject_device); 439} 440 441static void __exit aer_inject_exit(void) 442{ 443 struct aer_error *err, *err_next; 444 unsigned long flags; 445 struct pci_bus_ops *bus_ops; 446 447 misc_deregister(&aer_inject_device); 448 449 while ((bus_ops = pci_bus_ops_pop())) { 450 pci_bus_set_ops(bus_ops->bus, bus_ops->ops); 451 kfree(bus_ops); 452 } 453 454 spin_lock_irqsave(&inject_lock, flags); 455 list_for_each_entry_safe(err, err_next, &pci_bus_ops_list, list) { 456 list_del(&err->list); 457 kfree(err); 458 } 459 spin_unlock_irqrestore(&inject_lock, flags); 460} 461 462module_init(aer_inject_init); 463module_exit(aer_inject_exit); 464 465MODULE_DESCRIPTION("PCIE AER software error injector"); 466MODULE_LICENSE("GPL"); 467