HID: amd_sfh: Improve boot time when SFH is available
authorBasavaraj Natikar <Basavaraj.Natikar@amd.com>
Wed, 14 Feb 2024 14:41:43 +0000 (20:11 +0530)
committerJiri Kosina <jkosina@suse.com>
Tue, 27 Feb 2024 14:13:55 +0000 (15:13 +0100)
AMD SFH load takes longer time in initialization. Hence split and defer
initialization code to improve SFH module load time and boot time of the
system when SFH is available.

Signed-off-by: Basavaraj Natikar <Basavaraj.Natikar@amd.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
drivers/hid/amd-sfh-hid/amd_sfh_common.h
drivers/hid/amd-sfh-hid/amd_sfh_pcie.c

index a1950bc6e6cefee4ca1dcdc5cc2ceaf4216c9065..ef5551c1eec5d3b17291b1dc3bbd9f9625868d64 100644 (file)
@@ -53,6 +53,8 @@ struct amd_mp2_dev {
        /* mp2 active control status */
        u32 mp2_acs;
        struct sfh_dev_status dev_en;
+       struct work_struct work;
+       u8 init_done;
 };
 
 struct amd_mp2_ops {
index 8c1809c7d1f7357148e7a8d2aba82273181e65d0..495ec1179ee5bf8190117e193827d542b03296aa 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);