HID: amd_sfh: Improve boot time when SFH is available
[linux-2.6-microblaze.git] / drivers / hid / amd-sfh-hid / amd_sfh_pcie.c
index 8c1809c..495ec11 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/bitops.h>
 #include <linux/delay.h>
+#include <linux/devm-helpers.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmi.h>
 #include <linux/interrupt.h>
@@ -329,6 +330,48 @@ static const struct dmi_system_id dmi_nodevs[] = {
        { }
 };
 
+static void sfh1_1_init_work(struct work_struct *work)
+{
+       struct amd_mp2_dev *mp2 = container_of(work, struct amd_mp2_dev, work);
+       struct pci_dev *pdev = mp2->pdev;
+       int rc;
+
+       rc = mp2->sfh1_1_ops->init(mp2);
+       if (rc) {
+               dev_err(&pdev->dev, "sfh1_1_init failed err %d\n", rc);
+               return;
+       }
+
+       amd_sfh_clear_intr(mp2);
+       mp2->init_done = 1;
+}
+
+static void sfh_init_work(struct work_struct *work)
+{
+       struct amd_mp2_dev *mp2 = container_of(work, struct amd_mp2_dev, work);
+       struct pci_dev *pdev = mp2->pdev;
+       int rc;
+
+       rc = amd_sfh_hid_client_init(mp2);
+       if (rc) {
+               amd_sfh_clear_intr(mp2);
+               dev_err(&pdev->dev, "amd_sfh_hid_client_init failed err %d\n", rc);
+               return;
+       }
+
+       amd_sfh_clear_intr(mp2);
+       mp2->init_done = 1;
+}
+
+static void amd_sfh_remove(struct pci_dev *pdev)
+{
+       struct amd_mp2_dev *mp2 = pci_get_drvdata(pdev);
+
+       flush_work(&mp2->work);
+       if (mp2->init_done)
+               mp2->mp2_ops->remove(mp2);
+}
+
 static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct amd_mp2_dev *privdata;
@@ -367,10 +410,12 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
 
        privdata->sfh1_1_ops = (const struct amd_sfh1_1_ops *)id->driver_data;
        if (privdata->sfh1_1_ops) {
-               rc = privdata->sfh1_1_ops->init(privdata);
+               rc = devm_work_autocancel(&pdev->dev, &privdata->work, sfh1_1_init_work);
                if (rc)
                        return rc;
-               goto init_done;
+
+               schedule_work(&privdata->work);
+               return 0;
        }
 
        mp2_select_ops(privdata);
@@ -381,33 +426,34 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
                return rc;
        }
 
-       rc = amd_sfh_hid_client_init(privdata);
+       rc = devm_work_autocancel(&pdev->dev, &privdata->work, sfh_init_work);
        if (rc) {
                amd_sfh_clear_intr(privdata);
-               if (rc != -EOPNOTSUPP)
-                       dev_err(&pdev->dev, "amd_sfh_hid_client_init failed\n");
                return rc;
        }
 
-init_done:
-       amd_sfh_clear_intr(privdata);
-
-       return devm_add_action_or_reset(&pdev->dev, privdata->mp2_ops->remove, privdata);
+       schedule_work(&privdata->work);
+       return 0;
 }
 
 static void amd_sfh_shutdown(struct pci_dev *pdev)
 {
        struct amd_mp2_dev *mp2 = pci_get_drvdata(pdev);
 
-       if (mp2 && mp2->mp2_ops)
-               mp2->mp2_ops->stop_all(mp2);
+       if (mp2) {
+               flush_work(&mp2->work);
+               if (mp2->init_done)
+                       mp2->mp2_ops->stop_all(mp2);
+       }
 }
 
 static int __maybe_unused amd_mp2_pci_resume(struct device *dev)
 {
        struct amd_mp2_dev *mp2 = dev_get_drvdata(dev);
 
-       mp2->mp2_ops->resume(mp2);
+       flush_work(&mp2->work);
+       if (mp2->init_done)
+               mp2->mp2_ops->resume(mp2);
 
        return 0;
 }
@@ -416,7 +462,9 @@ static int __maybe_unused amd_mp2_pci_suspend(struct device *dev)
 {
        struct amd_mp2_dev *mp2 = dev_get_drvdata(dev);
 
-       mp2->mp2_ops->suspend(mp2);
+       flush_work(&mp2->work);
+       if (mp2->init_done)
+               mp2->mp2_ops->suspend(mp2);
 
        return 0;
 }
@@ -438,6 +486,7 @@ static struct pci_driver amd_mp2_pci_driver = {
        .probe          = amd_mp2_pci_probe,
        .driver.pm      = &amd_mp2_pm_ops,
        .shutdown       = amd_sfh_shutdown,
+       .remove         = amd_sfh_remove,
 };
 module_pci_driver(amd_mp2_pci_driver);