aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/pcie/aer/aer_inject.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/pcie/aer/aer_inject.c')
-rw-r--r--drivers/pci/pcie/aer/aer_inject.c93
1 files changed, 70 insertions, 23 deletions
diff --git a/drivers/pci/pcie/aer/aer_inject.c b/drivers/pci/pcie/aer/aer_inject.c
index 62d15f652bb6..f8f425b8731d 100644
--- a/drivers/pci/pcie/aer/aer_inject.c
+++ b/drivers/pci/pcie/aer/aer_inject.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * PCIE AER software error injection support. 2 * PCIe AER software error injection support.
3 * 3 *
4 * Debuging PCIE AER code is quite difficult because it is hard to 4 * Debuging PCIe AER code is quite difficult because it is hard to
5 * trigger various real hardware errors. Software based error 5 * trigger various real hardware errors. Software based error
6 * injection can fake almost all kinds of errors with the help of a 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: 7 * user space helper tool aer-inject, which can be gotten from:
@@ -21,8 +21,10 @@
21#include <linux/init.h> 21#include <linux/init.h>
22#include <linux/miscdevice.h> 22#include <linux/miscdevice.h>
23#include <linux/pci.h> 23#include <linux/pci.h>
24#include <linux/slab.h>
24#include <linux/fs.h> 25#include <linux/fs.h>
25#include <linux/uaccess.h> 26#include <linux/uaccess.h>
27#include <linux/stddef.h>
26#include "aerdrv.h" 28#include "aerdrv.h"
27 29
28struct aer_error_inj { 30struct aer_error_inj {
@@ -35,10 +37,12 @@ struct aer_error_inj {
35 u32 header_log1; 37 u32 header_log1;
36 u32 header_log2; 38 u32 header_log2;
37 u32 header_log3; 39 u32 header_log3;
40 u16 domain;
38}; 41};
39 42
40struct aer_error { 43struct aer_error {
41 struct list_head list; 44 struct list_head list;
45 u16 domain;
42 unsigned int bus; 46 unsigned int bus;
43 unsigned int devfn; 47 unsigned int devfn;
44 int pos_cap_err; 48 int pos_cap_err;
@@ -66,22 +70,27 @@ static LIST_HEAD(pci_bus_ops_list);
66/* Protect einjected and pci_bus_ops_list */ 70/* Protect einjected and pci_bus_ops_list */
67static DEFINE_SPINLOCK(inject_lock); 71static DEFINE_SPINLOCK(inject_lock);
68 72
69static void aer_error_init(struct aer_error *err, unsigned int bus, 73static void aer_error_init(struct aer_error *err, u16 domain,
70 unsigned int devfn, int pos_cap_err) 74 unsigned int bus, unsigned int devfn,
75 int pos_cap_err)
71{ 76{
72 INIT_LIST_HEAD(&err->list); 77 INIT_LIST_HEAD(&err->list);
78 err->domain = domain;
73 err->bus = bus; 79 err->bus = bus;
74 err->devfn = devfn; 80 err->devfn = devfn;
75 err->pos_cap_err = pos_cap_err; 81 err->pos_cap_err = pos_cap_err;
76} 82}
77 83
78/* inject_lock must be held before calling */ 84/* inject_lock must be held before calling */
79static struct aer_error *__find_aer_error(unsigned int bus, unsigned int devfn) 85static struct aer_error *__find_aer_error(u16 domain, unsigned int bus,
86 unsigned int devfn)
80{ 87{
81 struct aer_error *err; 88 struct aer_error *err;
82 89
83 list_for_each_entry(err, &einjected, list) { 90 list_for_each_entry(err, &einjected, list) {
84 if (bus == err->bus && devfn == err->devfn) 91 if (domain == err->domain &&
92 bus == err->bus &&
93 devfn == err->devfn)
85 return err; 94 return err;
86 } 95 }
87 return NULL; 96 return NULL;
@@ -90,7 +99,10 @@ static struct aer_error *__find_aer_error(unsigned int bus, unsigned int devfn)
90/* inject_lock must be held before calling */ 99/* inject_lock must be held before calling */
91static struct aer_error *__find_aer_error_by_dev(struct pci_dev *dev) 100static struct aer_error *__find_aer_error_by_dev(struct pci_dev *dev)
92{ 101{
93 return __find_aer_error(dev->bus->number, dev->devfn); 102 int domain = pci_domain_nr(dev->bus);
103 if (domain < 0)
104 return NULL;
105 return __find_aer_error((u16)domain, dev->bus->number, dev->devfn);
94} 106}
95 107
96/* inject_lock must be held before calling */ 108/* inject_lock must be held before calling */
@@ -172,11 +184,15 @@ static int pci_read_aer(struct pci_bus *bus, unsigned int devfn, int where,
172 struct aer_error *err; 184 struct aer_error *err;
173 unsigned long flags; 185 unsigned long flags;
174 struct pci_ops *ops; 186 struct pci_ops *ops;
187 int domain;
175 188
176 spin_lock_irqsave(&inject_lock, flags); 189 spin_lock_irqsave(&inject_lock, flags);
177 if (size != sizeof(u32)) 190 if (size != sizeof(u32))
178 goto out; 191 goto out;
179 err = __find_aer_error(bus->number, devfn); 192 domain = pci_domain_nr(bus);
193 if (domain < 0)
194 goto out;
195 err = __find_aer_error((u16)domain, bus->number, devfn);
180 if (!err) 196 if (!err)
181 goto out; 197 goto out;
182 198
@@ -200,11 +216,15 @@ int pci_write_aer(struct pci_bus *bus, unsigned int devfn, int where, int size,
200 unsigned long flags; 216 unsigned long flags;
201 int rw1cs; 217 int rw1cs;
202 struct pci_ops *ops; 218 struct pci_ops *ops;
219 int domain;
203 220
204 spin_lock_irqsave(&inject_lock, flags); 221 spin_lock_irqsave(&inject_lock, flags);
205 if (size != sizeof(u32)) 222 if (size != sizeof(u32))
206 goto out; 223 goto out;
207 err = __find_aer_error(bus->number, devfn); 224 domain = pci_domain_nr(bus);
225 if (domain < 0)
226 goto out;
227 err = __find_aer_error((u16)domain, bus->number, devfn);
208 if (!err) 228 if (!err)
209 goto out; 229 goto out;
210 230
@@ -262,7 +282,7 @@ out:
262static struct pci_dev *pcie_find_root_port(struct pci_dev *dev) 282static struct pci_dev *pcie_find_root_port(struct pci_dev *dev)
263{ 283{
264 while (1) { 284 while (1) {
265 if (!dev->is_pcie) 285 if (!pci_is_pcie(dev))
266 break; 286 break;
267 if (dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) 287 if (dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT)
268 return dev; 288 return dev;
@@ -302,28 +322,31 @@ static int aer_inject(struct aer_error_inj *einj)
302 unsigned long flags; 322 unsigned long flags;
303 unsigned int devfn = PCI_DEVFN(einj->dev, einj->fn); 323 unsigned int devfn = PCI_DEVFN(einj->dev, einj->fn);
304 int pos_cap_err, rp_pos_cap_err; 324 int pos_cap_err, rp_pos_cap_err;
305 u32 sever; 325 u32 sever, cor_mask, uncor_mask;
306 int ret = 0; 326 int ret = 0;
307 327
308 dev = pci_get_bus_and_slot(einj->bus, devfn); 328 dev = pci_get_domain_bus_and_slot((int)einj->domain, einj->bus, devfn);
309 if (!dev) 329 if (!dev)
310 return -EINVAL; 330 return -ENODEV;
311 rpdev = pcie_find_root_port(dev); 331 rpdev = pcie_find_root_port(dev);
312 if (!rpdev) { 332 if (!rpdev) {
313 ret = -EINVAL; 333 ret = -ENOTTY;
314 goto out_put; 334 goto out_put;
315 } 335 }
316 336
317 pos_cap_err = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); 337 pos_cap_err = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
318 if (!pos_cap_err) { 338 if (!pos_cap_err) {
319 ret = -EIO; 339 ret = -ENOTTY;
320 goto out_put; 340 goto out_put;
321 } 341 }
322 pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_SEVER, &sever); 342 pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_SEVER, &sever);
343 pci_read_config_dword(dev, pos_cap_err + PCI_ERR_COR_MASK, &cor_mask);
344 pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_MASK,
345 &uncor_mask);
323 346
324 rp_pos_cap_err = pci_find_ext_capability(rpdev, PCI_EXT_CAP_ID_ERR); 347 rp_pos_cap_err = pci_find_ext_capability(rpdev, PCI_EXT_CAP_ID_ERR);
325 if (!rp_pos_cap_err) { 348 if (!rp_pos_cap_err) {
326 ret = -EIO; 349 ret = -ENOTTY;
327 goto out_put; 350 goto out_put;
328 } 351 }
329 352
@@ -344,7 +367,8 @@ static int aer_inject(struct aer_error_inj *einj)
344 if (!err) { 367 if (!err) {
345 err = err_alloc; 368 err = err_alloc;
346 err_alloc = NULL; 369 err_alloc = NULL;
347 aer_error_init(err, einj->bus, devfn, pos_cap_err); 370 aer_error_init(err, einj->domain, einj->bus, devfn,
371 pos_cap_err);
348 list_add(&err->list, &einjected); 372 list_add(&err->list, &einjected);
349 } 373 }
350 err->uncor_status |= einj->uncor_status; 374 err->uncor_status |= einj->uncor_status;
@@ -354,11 +378,27 @@ static int aer_inject(struct aer_error_inj *einj)
354 err->header_log2 = einj->header_log2; 378 err->header_log2 = einj->header_log2;
355 err->header_log3 = einj->header_log3; 379 err->header_log3 = einj->header_log3;
356 380
381 if (einj->cor_status && !(einj->cor_status & ~cor_mask)) {
382 ret = -EINVAL;
383 printk(KERN_WARNING "The correctable error(s) is masked "
384 "by device\n");
385 spin_unlock_irqrestore(&inject_lock, flags);
386 goto out_put;
387 }
388 if (einj->uncor_status && !(einj->uncor_status & ~uncor_mask)) {
389 ret = -EINVAL;
390 printk(KERN_WARNING "The uncorrectable error(s) is masked "
391 "by device\n");
392 spin_unlock_irqrestore(&inject_lock, flags);
393 goto out_put;
394 }
395
357 rperr = __find_aer_error_by_dev(rpdev); 396 rperr = __find_aer_error_by_dev(rpdev);
358 if (!rperr) { 397 if (!rperr) {
359 rperr = rperr_alloc; 398 rperr = rperr_alloc;
360 rperr_alloc = NULL; 399 rperr_alloc = NULL;
361 aer_error_init(rperr, rpdev->bus->number, rpdev->devfn, 400 aer_error_init(rperr, pci_domain_nr(rpdev->bus),
401 rpdev->bus->number, rpdev->devfn,
362 rp_pos_cap_err); 402 rp_pos_cap_err);
363 list_add(&rperr->list, &einjected); 403 list_add(&rperr->list, &einjected);
364 } 404 }
@@ -392,8 +432,14 @@ static int aer_inject(struct aer_error_inj *einj)
392 if (ret) 432 if (ret)
393 goto out_put; 433 goto out_put;
394 434
395 if (find_aer_device(rpdev, &edev)) 435 if (find_aer_device(rpdev, &edev)) {
436 if (!get_service_data(edev)) {
437 printk(KERN_WARNING "AER service is not initialized\n");
438 ret = -EINVAL;
439 goto out_put;
440 }
396 aer_irq(-1, edev); 441 aer_irq(-1, edev);
442 }
397 else 443 else
398 ret = -EINVAL; 444 ret = -EINVAL;
399out_put: 445out_put:
@@ -411,10 +457,11 @@ static ssize_t aer_inject_write(struct file *filp, const char __user *ubuf,
411 457
412 if (!capable(CAP_SYS_ADMIN)) 458 if (!capable(CAP_SYS_ADMIN))
413 return -EPERM; 459 return -EPERM;
414 460 if (usize < offsetof(struct aer_error_inj, domain) ||
415 if (usize != sizeof(struct aer_error_inj)) 461 usize > sizeof(einj))
416 return -EINVAL; 462 return -EINVAL;
417 463
464 memset(&einj, 0, sizeof(einj));
418 if (copy_from_user(&einj, ubuf, usize)) 465 if (copy_from_user(&einj, ubuf, usize))
419 return -EFAULT; 466 return -EFAULT;
420 467
@@ -452,7 +499,7 @@ static void __exit aer_inject_exit(void)
452 } 499 }
453 500
454 spin_lock_irqsave(&inject_lock, flags); 501 spin_lock_irqsave(&inject_lock, flags);
455 list_for_each_entry_safe(err, err_next, &pci_bus_ops_list, list) { 502 list_for_each_entry_safe(err, err_next, &einjected, list) {
456 list_del(&err->list); 503 list_del(&err->list);
457 kfree(err); 504 kfree(err);
458 } 505 }
@@ -462,5 +509,5 @@ static void __exit aer_inject_exit(void)
462module_init(aer_inject_init); 509module_init(aer_inject_init);
463module_exit(aer_inject_exit); 510module_exit(aer_inject_exit);
464 511
465MODULE_DESCRIPTION("PCIE AER software error injector"); 512MODULE_DESCRIPTION("PCIe AER software error injector");
466MODULE_LICENSE("GPL"); 513MODULE_LICENSE("GPL");