These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / arch / s390 / pci / pci_event.c
index 460fdb2..369a3e0 100644 (file)
@@ -46,15 +46,13 @@ struct zpci_ccdf_avail {
 static void __zpci_event_error(struct zpci_ccdf_err *ccdf)
 {
        struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
+       struct pci_dev *pdev = zdev ? zdev->pdev : NULL;
 
        zpci_err("error CCDF:\n");
        zpci_err_hex(ccdf, sizeof(*ccdf));
 
-       if (!zdev)
-               return;
-
        pr_err("%s: Event 0x%x reports an error for PCI function 0x%x\n",
-              pci_name(zdev->pdev), ccdf->pec, ccdf->fid);
+              pdev ? pci_name(pdev) : "n/a", ccdf->pec, ccdf->fid);
 }
 
 void zpci_event_error(void *data)
@@ -75,7 +73,13 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
        zpci_err_hex(ccdf, sizeof(*ccdf));
 
        switch (ccdf->pec) {
-       case 0x0301: /* Standby -> Configured */
+       case 0x0301: /* Reserved|Standby -> Configured */
+               if (!zdev) {
+                       ret = clp_add_pci_device(ccdf->fid, ccdf->fh, 0);
+                       if (ret)
+                               break;
+                       zdev = get_zdev_by_fid(ccdf->fid);
+               }
                if (!zdev || zdev->state != ZPCI_FN_STATE_STANDBY)
                        break;
                zdev->state = ZPCI_FN_STATE_CONFIGURED;
@@ -83,7 +87,9 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
                ret = zpci_enable_device(zdev);
                if (ret)
                        break;
+               pci_lock_rescan_remove();
                pci_rescan_bus(zdev->bus);
+               pci_unlock_rescan_remove();
                break;
        case 0x0302: /* Reserved -> Standby */
                if (!zdev)
@@ -91,7 +97,7 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
                break;
        case 0x0303: /* Deconfiguration requested */
                if (pdev)
-                       pci_stop_and_remove_bus_device(pdev);
+                       pci_stop_and_remove_bus_device_locked(pdev);
 
                ret = zpci_disable_device(zdev);
                if (ret)
@@ -108,7 +114,7 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
                        /* Give the driver a hint that the function is
                         * already unusable. */
                        pdev->error_state = pci_channel_io_perm_failure;
-                       pci_stop_and_remove_bus_device(pdev);
+                       pci_stop_and_remove_bus_device_locked(pdev);
                }
 
                zdev->fh = ccdf->fh;