powerpc/powernv: Add PCI error injection debugfs entry
authorMike Qiu <qiudayu@linux.vnet.ibm.com>
Tue, 30 Sep 2014 02:38:57 +0000 (12:38 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Tue, 30 Sep 2014 07:15:10 +0000 (17:15 +1000)
The patch adds debugfs file (/sys/kernel/debug/powerpc/PCIxxxx/
err_injct), which accepts following formated string, to support
error injection. It will be used to support userland utility
"errinjct" in future.

  "pe_no:0:function:address:mask" - 32-bits PCI errors
  "pe_no:1:function:address:mask" - 64-bits PCI errors

Signed-off-by: Mike Qiu <qiudayu@linux.vnet.ibm.com>
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/platforms/powernv/eeh-ioda.c

index 1ac80db1489bbfa0ffaa198174d77f28ca3ff1b4..22609f23f4556eb5adfa5d5f13cb50a0b031eec9 100644 (file)
@@ -66,6 +66,54 @@ static struct notifier_block ioda_eeh_nb = {
 };
 
 #ifdef CONFIG_DEBUG_FS
+static ssize_t ioda_eeh_ei_write(struct file *filp,
+                                const char __user *user_buf,
+                                size_t count, loff_t *ppos)
+{
+       struct pci_controller *hose = filp->private_data;
+       struct pnv_phb *phb = hose->private_data;
+       struct eeh_dev *edev;
+       struct eeh_pe *pe;
+       int pe_no, type, func;
+       unsigned long addr, mask;
+       char buf[50];
+       int ret;
+
+       if (!phb->eeh_ops || !phb->eeh_ops->err_inject)
+               return -ENXIO;
+
+       ret = simple_write_to_buffer(buf, sizeof(buf), ppos, user_buf, count);
+       if (!ret)
+               return -EFAULT;
+
+       /* Retrieve parameters */
+       ret = sscanf(buf, "%x:%x:%x:%lx:%lx",
+                    &pe_no, &type, &func, &addr, &mask);
+       if (ret != 5)
+               return -EINVAL;
+
+       /* Retrieve PE */
+       edev = kzalloc(sizeof(*edev), GFP_KERNEL);
+       if (!edev)
+               return -ENOMEM;
+       edev->phb = hose;
+       edev->pe_config_addr = pe_no;
+       pe = eeh_pe_get(edev);
+       kfree(edev);
+       if (!pe)
+               return -ENODEV;
+
+       /* Do error injection */
+       ret = phb->eeh_ops->err_inject(pe, type, func, addr, mask);
+       return ret < 0 ? ret : count;
+}
+
+static const struct file_operations ioda_eeh_ei_fops = {
+       .open   = simple_open,
+       .llseek = no_llseek,
+       .write  = ioda_eeh_ei_write,
+};
+
 static int ioda_eeh_dbgfs_set(void *data, int offset, u64 val)
 {
        struct pci_controller *hose = data;
@@ -152,6 +200,10 @@ static int ioda_eeh_post_init(struct pci_controller *hose)
        if (!phb->has_dbgfs && phb->dbgfs) {
                phb->has_dbgfs = 1;
 
+               debugfs_create_file("err_injct", 0200,
+                                   phb->dbgfs, hose,
+                                   &ioda_eeh_ei_fops);
+
                debugfs_create_file("err_injct_outbound", 0600,
                                    phb->dbgfs, hose,
                                    &ioda_eeh_outb_dbgfs_ops);