]> git.karo-electronics.de Git - linux-beck.git/commitdiff
greybus: firmware: Add runtime PM support
authorViresh Kumar <viresh.kumar@linaro.org>
Tue, 26 Jul 2016 20:41:02 +0000 (13:41 -0700)
committerGreg Kroah-Hartman <gregkh@google.com>
Tue, 26 Jul 2016 22:29:00 +0000 (15:29 -0700)
This patch implements runtime PM support for firmware management bundle.
This guarantees that the bundle will be active, while the AP or the
Module is trying to exchange any operations over any of the CPorts.

- Firmware Management CPort:

  Runtime PM get/put calls are placed around the ioctl calls, which are
  all implemented as blocking ioctls.

- Component Authentication CPort:

  Runtime PM get/put calls are placed around the ioctl calls, which are
  all implemented as blocking ioctls.

- SPI:

  Uses the interface provided by spilib.c and runtime PM get/put are
  called around connection usage.

- firmware-download:

  This is the most tricky one. All operations on this CPort are
  initiated from the Module and not from the AP. And the AP needs to do
  runtime_pm_get() before any request is received over this CPort.

  The module doesn't send any request over this connection, unless the
  AP has requested the module over firmware management CPort to download
  a firmware package over firmware download CPort.

  And so the runtime PM get/put calls around the ioctls in
  fw-management.c are sufficient to handle the firmware management CPort
  as well.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/authentication.c
drivers/staging/greybus/fw-core.c
drivers/staging/greybus/fw-management.c

index a4ac3bbdcb86dbcdc35735c5ad7452a8de6072b8..168626ba0c03601ea7247601d459d75fda70a3c2 100644 (file)
@@ -265,6 +265,7 @@ static long cap_ioctl_unlocked(struct file *file, unsigned int cmd,
                               unsigned long arg)
 {
        struct gb_cap *cap = file->private_data;
+       struct gb_bundle *bundle = cap->connection->bundle;
        int ret = -ENODEV;
 
        /*
@@ -278,8 +279,13 @@ static long cap_ioctl_unlocked(struct file *file, unsigned int cmd,
         * new operations.
         */
        mutex_lock(&cap->mutex);
-       if (!cap->disabled)
-               ret = cap_ioctl(cap, cmd, (void __user *)arg);
+       if (!cap->disabled) {
+               ret = gb_pm_runtime_get_sync(bundle);
+               if (!ret) {
+                       ret = cap_ioctl(cap, cmd, (void __user *)arg);
+                       gb_pm_runtime_put_autosuspend(bundle);
+               }
+       }
        mutex_unlock(&cap->mutex);
 
        return ret;
index 19f92fb0331b6138a3a51a5b871a6720e7f23daf..56296db0b509fbbd4e084935ee380abeae17afb1 100644 (file)
@@ -20,6 +20,27 @@ struct gb_fw_core {
        struct gb_connection    *cap_connection;
 };
 
+#ifndef SPI_CORE_SUPPORT_PM
+static int fw_spi_prepare_transfer_hardware(struct device *dev)
+{
+       return gb_pm_runtime_get_sync(to_gb_bundle(dev));
+}
+
+static void fw_spi_unprepare_transfer_hardware(struct device *dev)
+{
+       gb_pm_runtime_put_autosuspend(to_gb_bundle(dev));
+}
+
+static struct spilib_ops __spilib_ops = {
+       .prepare_transfer_hardware = fw_spi_prepare_transfer_hardware,
+       .unprepare_transfer_hardware = fw_spi_unprepare_transfer_hardware,
+};
+
+static struct spilib_ops *spilib_ops = &__spilib_ops;
+#else
+static struct spilib_ops *spilib_ops = NULL;
+#endif
+
 struct gb_connection *to_fw_mgmt_connection(struct device *dev)
 {
        struct gb_fw_core *fw_core = dev_get_drvdata(dev);
@@ -38,7 +59,8 @@ static int gb_fw_spi_connection_init(struct gb_connection *connection)
        if (ret)
                return ret;
 
-       ret = gb_spilib_master_init(connection, &connection->bundle->dev, NULL);
+       ret = gb_spilib_master_init(connection, &connection->bundle->dev,
+                                   spilib_ops);
        if (ret) {
                gb_connection_disable(connection);
                return ret;
@@ -206,6 +228,8 @@ static int gb_fw_core_probe(struct gb_bundle *bundle,
 
        greybus_set_drvdata(bundle, fw_core);
 
+       gb_pm_runtime_put_autosuspend(bundle);
+
        return 0;
 
 err_exit_connections:
@@ -225,6 +249,11 @@ err_destroy_connections:
 static void gb_fw_core_disconnect(struct gb_bundle *bundle)
 {
        struct gb_fw_core *fw_core = greybus_get_drvdata(bundle);
+       int ret;
+
+       ret = gb_pm_runtime_get_sync(bundle);
+       if (ret)
+               gb_pm_runtime_get_noresume(bundle);
 
        gb_fw_mgmt_connection_exit(fw_core->mgmt_connection);
        gb_cap_connection_exit(fw_core->cap_connection);
index ccd9d7c9141628dee1f6d2309f7084abd9389002..2efe65cfd612a096f2c150932c5add66b7549951 100644 (file)
@@ -507,6 +507,7 @@ static long fw_mgmt_ioctl_unlocked(struct file *file, unsigned int cmd,
                                   unsigned long arg)
 {
        struct fw_mgmt *fw_mgmt = file->private_data;
+       struct gb_bundle *bundle = fw_mgmt->connection->bundle;
        int ret = -ENODEV;
 
        /*
@@ -522,8 +523,13 @@ static long fw_mgmt_ioctl_unlocked(struct file *file, unsigned int cmd,
         * new operations.
         */
        mutex_lock(&fw_mgmt->mutex);
-       if (!fw_mgmt->disabled)
-               ret = fw_mgmt_ioctl(fw_mgmt, cmd, (void __user *)arg);
+       if (!fw_mgmt->disabled) {
+               ret = gb_pm_runtime_get_sync(bundle);
+               if (!ret) {
+                       ret = fw_mgmt_ioctl(fw_mgmt, cmd, (void __user *)arg);
+                       gb_pm_runtime_put_autosuspend(bundle);
+               }
+       }
        mutex_unlock(&fw_mgmt->mutex);
 
        return ret;