]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
powerpc/eeh: Add EEH operations to notify resume
authorBryant G. Ly <bryantly@linux.vnet.ibm.com>
Fri, 5 Jan 2018 16:45:49 +0000 (10:45 -0600)
committerMichael Ellerman <mpe@ellerman.id.au>
Sat, 27 Jan 2018 09:02:52 +0000 (20:02 +1100)
When pseries SR-IOV is enabled and after a PF driver has resumed from
EEH, platform has to be notified of the event so the child VFs can be
allowed to resume their normal recovery path.

This patch makes the EEH operation allow unfreeze platform dependent
code and adds the call to pseries EEH code.

Signed-off-by: Bryant G. Ly <bryantly@linux.vnet.ibm.com>
Signed-off-by: Juan J. Alvarez <jjalvare@linux.vnet.ibm.com>
Acked-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/include/asm/eeh.h
arch/powerpc/platforms/powernv/eeh-powernv.c
arch/powerpc/platforms/pseries/eeh_pseries.c

index 82829c65f31a70787df0b637387fc03448496003..fd37cc101f4f2f6fcba5fe1b5aecd7885d1da074 100644 (file)
@@ -214,6 +214,7 @@ struct eeh_ops {
        int (*write_config)(struct pci_dn *pdn, int where, int size, u32 val);
        int (*next_error)(struct eeh_pe **pe);
        int (*restore_config)(struct pci_dn *pdn);
+       int (*notify_resume)(struct pci_dn *pdn);
 };
 
 extern int eeh_subsystem_flags;
index 0665b6d03cb3588a69406a28013018a884ffc48b..33c86c1a17204445a231828c0b7467335a823098 100644 (file)
@@ -1704,7 +1704,8 @@ static struct eeh_ops pnv_eeh_ops = {
        .read_config            = pnv_eeh_read_config,
        .write_config           = pnv_eeh_write_config,
        .next_error             = pnv_eeh_next_error,
-       .restore_config         = pnv_eeh_restore_config
+       .restore_config         = pnv_eeh_restore_config,
+       .notify_resume          = NULL
 };
 
 #ifdef CONFIG_PCI_IOV
index 428bfd10bd5a13a7305910ef695a6a6e1d20048d..823cb27efa8b88a76f3fdd0d495fb7b6f6f0b0c2 100644 (file)
@@ -750,6 +750,97 @@ static int pseries_eeh_restore_config(struct pci_dn *pdn)
        return ret;
 }
 
+#ifdef CONFIG_PCI_IOV
+int pseries_send_allow_unfreeze(struct pci_dn *pdn,
+                               u16 *vf_pe_array, int cur_vfs)
+{
+       int rc;
+       int ibm_allow_unfreeze = rtas_token("ibm,open-sriov-allow-unfreeze");
+       unsigned long buid, addr;
+
+       addr = rtas_config_addr(pdn->busno, pdn->devfn, 0);
+       buid = pdn->phb->buid;
+       spin_lock(&rtas_data_buf_lock);
+       memcpy(rtas_data_buf, vf_pe_array, RTAS_DATA_BUF_SIZE);
+       rc = rtas_call(ibm_allow_unfreeze, 5, 1, NULL,
+                      addr,
+                      BUID_HI(buid),
+                      BUID_LO(buid),
+                      rtas_data_buf, cur_vfs * sizeof(u16));
+       spin_unlock(&rtas_data_buf_lock);
+       if (rc)
+               pr_warn("%s: Failed to allow unfreeze for PHB#%x-PE#%lx, rc=%x\n",
+                       __func__,
+                       pdn->phb->global_number, addr, rc);
+       return rc;
+}
+
+static int pseries_call_allow_unfreeze(struct eeh_dev *edev)
+{
+       struct pci_dn *pdn, *tmp, *parent, *physfn_pdn;
+       int cur_vfs = 0, rc = 0, vf_index, bus, devfn;
+       u16 *vf_pe_array;
+
+       vf_pe_array = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
+       if (!vf_pe_array)
+               return -ENOMEM;
+       if (pci_num_vf(edev->physfn ? edev->physfn : edev->pdev)) {
+               if (edev->pdev->is_physfn) {
+                       cur_vfs = pci_num_vf(edev->pdev);
+                       pdn = eeh_dev_to_pdn(edev);
+                       parent = pdn->parent;
+                       for (vf_index = 0; vf_index < cur_vfs; vf_index++)
+                               vf_pe_array[vf_index] =
+                                       cpu_to_be16(pdn->pe_num_map[vf_index]);
+                       rc = pseries_send_allow_unfreeze(pdn, vf_pe_array,
+                                                        cur_vfs);
+                       pdn->last_allow_rc = rc;
+                       for (vf_index = 0; vf_index < cur_vfs; vf_index++) {
+                               list_for_each_entry_safe(pdn, tmp,
+                                                        &parent->child_list,
+                                                        list) {
+                                       bus = pci_iov_virtfn_bus(edev->pdev,
+                                                                vf_index);
+                                       devfn = pci_iov_virtfn_devfn(edev->pdev,
+                                                                    vf_index);
+                                       if (pdn->busno != bus ||
+                                           pdn->devfn != devfn)
+                                               continue;
+                                       pdn->last_allow_rc = rc;
+                               }
+                       }
+               } else {
+                       pdn = pci_get_pdn(edev->pdev);
+                       vf_pe_array[0] = cpu_to_be16(pdn->pe_number);
+                       physfn_pdn = pci_get_pdn(edev->physfn);
+                       rc = pseries_send_allow_unfreeze(physfn_pdn,
+                                                        vf_pe_array, 1);
+                       pdn->last_allow_rc = rc;
+               }
+       }
+
+       kfree(vf_pe_array);
+       return rc;
+}
+
+static int pseries_notify_resume(struct pci_dn *pdn)
+{
+       struct eeh_dev *edev = pdn_to_eeh_dev(pdn);
+
+       if (!edev)
+               return -EEXIST;
+
+       if (rtas_token("ibm,open-sriov-allow-unfreeze")
+           == RTAS_UNKNOWN_SERVICE)
+               return -EINVAL;
+
+       if (edev->pdev->is_physfn || edev->pdev->is_virtfn)
+               return pseries_call_allow_unfreeze(edev);
+
+       return 0;
+}
+#endif
+
 static struct eeh_ops pseries_eeh_ops = {
        .name                   = "pseries",
        .init                   = pseries_eeh_init,
@@ -765,7 +856,10 @@ static struct eeh_ops pseries_eeh_ops = {
        .read_config            = pseries_eeh_read_config,
        .write_config           = pseries_eeh_write_config,
        .next_error             = NULL,
-       .restore_config         = pseries_eeh_restore_config
+       .restore_config         = pseries_eeh_restore_config,
+#ifdef CONFIG_PCI_IOV
+       .notify_resume          = pseries_notify_resume
+#endif
 };
 
 /**