Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

greybus: firmware: Add runtime PM support

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>

authored by

Viresh Kumar and committed by
Greg Kroah-Hartman
c57fbb40 2321f049

+46 -5
+8 -2
drivers/staging/greybus/authentication.c
··· 265 265 unsigned long arg) 266 266 { 267 267 struct gb_cap *cap = file->private_data; 268 + struct gb_bundle *bundle = cap->connection->bundle; 268 269 int ret = -ENODEV; 269 270 270 271 /* ··· 279 278 * new operations. 280 279 */ 281 280 mutex_lock(&cap->mutex); 282 - if (!cap->disabled) 283 - ret = cap_ioctl(cap, cmd, (void __user *)arg); 281 + if (!cap->disabled) { 282 + ret = gb_pm_runtime_get_sync(bundle); 283 + if (!ret) { 284 + ret = cap_ioctl(cap, cmd, (void __user *)arg); 285 + gb_pm_runtime_put_autosuspend(bundle); 286 + } 287 + } 284 288 mutex_unlock(&cap->mutex); 285 289 286 290 return ret;
+30 -1
drivers/staging/greybus/fw-core.c
··· 20 20 struct gb_connection *cap_connection; 21 21 }; 22 22 23 + #ifndef SPI_CORE_SUPPORT_PM 24 + static int fw_spi_prepare_transfer_hardware(struct device *dev) 25 + { 26 + return gb_pm_runtime_get_sync(to_gb_bundle(dev)); 27 + } 28 + 29 + static void fw_spi_unprepare_transfer_hardware(struct device *dev) 30 + { 31 + gb_pm_runtime_put_autosuspend(to_gb_bundle(dev)); 32 + } 33 + 34 + static struct spilib_ops __spilib_ops = { 35 + .prepare_transfer_hardware = fw_spi_prepare_transfer_hardware, 36 + .unprepare_transfer_hardware = fw_spi_unprepare_transfer_hardware, 37 + }; 38 + 39 + static struct spilib_ops *spilib_ops = &__spilib_ops; 40 + #else 41 + static struct spilib_ops *spilib_ops = NULL; 42 + #endif 43 + 23 44 struct gb_connection *to_fw_mgmt_connection(struct device *dev) 24 45 { 25 46 struct gb_fw_core *fw_core = dev_get_drvdata(dev); ··· 59 38 if (ret) 60 39 return ret; 61 40 62 - ret = gb_spilib_master_init(connection, &connection->bundle->dev, NULL); 41 + ret = gb_spilib_master_init(connection, &connection->bundle->dev, 42 + spilib_ops); 63 43 if (ret) { 64 44 gb_connection_disable(connection); 65 45 return ret; ··· 228 206 229 207 greybus_set_drvdata(bundle, fw_core); 230 208 209 + gb_pm_runtime_put_autosuspend(bundle); 210 + 231 211 return 0; 232 212 233 213 err_exit_connections: ··· 249 225 static void gb_fw_core_disconnect(struct gb_bundle *bundle) 250 226 { 251 227 struct gb_fw_core *fw_core = greybus_get_drvdata(bundle); 228 + int ret; 229 + 230 + ret = gb_pm_runtime_get_sync(bundle); 231 + if (ret) 232 + gb_pm_runtime_get_noresume(bundle); 252 233 253 234 gb_fw_mgmt_connection_exit(fw_core->mgmt_connection); 254 235 gb_cap_connection_exit(fw_core->cap_connection);
+8 -2
drivers/staging/greybus/fw-management.c
··· 507 507 unsigned long arg) 508 508 { 509 509 struct fw_mgmt *fw_mgmt = file->private_data; 510 + struct gb_bundle *bundle = fw_mgmt->connection->bundle; 510 511 int ret = -ENODEV; 511 512 512 513 /* ··· 523 522 * new operations. 524 523 */ 525 524 mutex_lock(&fw_mgmt->mutex); 526 - if (!fw_mgmt->disabled) 527 - ret = fw_mgmt_ioctl(fw_mgmt, cmd, (void __user *)arg); 525 + if (!fw_mgmt->disabled) { 526 + ret = gb_pm_runtime_get_sync(bundle); 527 + if (!ret) { 528 + ret = fw_mgmt_ioctl(fw_mgmt, cmd, (void __user *)arg); 529 + gb_pm_runtime_put_autosuspend(bundle); 530 + } 531 + } 528 532 mutex_unlock(&fw_mgmt->mutex); 529 533 530 534 return ret;