nvdla: kmd: synchronize PING across many clients

[1] When the multiple clients try to ping at the same time, the
    KMD errors out for all clients except one. This behavior
    is expected since there is only one command memory and the
    KMD errors out when that memory is busy.
[2] This commit fixes the issue by synchronizing the ping operations
    across all the clients by introducing a lock.
[3] Alternatively Increasing MAX_COMMANDS_PER_DEVICE will work but
    not optimal since,
    - the ping is an INIT mode operation.
    - the ping operation is inexpensive => the memory is immediately
      available even if locked.
    - the overall memory allocation will increase.

Considering the use case is rare, the synchronization of ping across
multiple clients is preferred.

Change-Id: I012efd18554a85bb31b79b98bf83386b37251d32
Signed-off-by: Arvind M <am@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2813197
Reviewed-by: svcacv <svcacv@nvidia.com>
Reviewed-by: svc_kernel_abi <svc_kernel_abi@nvidia.com>
Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com>
Reviewed-by: svc-mobile-cert <svc-mobile-cert@nvidia.com>
Reviewed-by: Amit Sharma (SW-TEGRA) <amisharma@nvidia.com>
Reviewed-by: Ken Adams <kadams@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
Arvind M
2022-11-21 12:15:04 +00:00
committed by Laxman Dewangan
parent c7726fd7d3
commit 103da69059
3 changed files with 17 additions and 1 deletions

View File

@@ -838,6 +838,7 @@ static int nvdla_probe(struct platform_device *pdev)
mutex_init(&pdata->lock);
mutex_init(&nvdla_dev->cmd_lock);
init_completion(&nvdla_dev->cmd_completion);
mutex_init(&nvdla_dev->ping_lock);
pdata->private_data = nvdla_dev;
platform_set_drvdata(pdev, pdata);
nvdla_dev->dbg_mask = debug_err;
@@ -900,6 +901,7 @@ err_client_device_init:
nvhost_module_deinit(pdev);
err_module_init:
err_get_resources:
mutex_destroy(&nvdla_dev->ping_lock);
devm_kfree(dev, nvdla_dev);
err_alloc_nvdla:
err_no_ip:
@@ -928,7 +930,7 @@ static int __exit nvdla_remove(struct platform_device *pdev)
nvdla_queue_deinit(nvdla_dev->pool);
nvhost_client_device_release(pdev);
nvhost_module_deinit(pdev);
mutex_destroy(&nvdla_dev->ping_lock);
nvdla_free_gcov_region(pdev, false);
if (nvdla_dev->trace_dump_pa) {

View File

@@ -243,6 +243,7 @@ enum nvdla_submit_mode {
* @gcov_dump_pa physical address of fw gcov buffer
* @gcov_dump_va virtual address of fw gcovbuffer
* @is_suspended flag to check if module is in suspend state.
* @ping_lock lock to synchronize the ping operation requests.
*/
struct nvdla_device {
struct platform_device *pdev;
@@ -269,6 +270,7 @@ struct nvdla_device {
#ifdef CONFIG_PM
bool is_suspended;
#endif
struct mutex ping_lock;
};
/**

View File

@@ -258,6 +258,8 @@ static int nvdla_ping(struct platform_device *pdev,
{
struct nvdla_cmd_mem_info ping_cmd_mem_info;
struct nvdla_cmd_data cmd_data;
struct nvhost_device_data *pdata = platform_get_drvdata(pdev);
struct nvdla_device *nvdla_dev = pdata->private_data;
u32 *ping_va;
int err = 0;
@@ -275,6 +277,14 @@ static int nvdla_ping(struct platform_device *pdev,
goto fail_to_on;
}
if (nvdla_dev == NULL) {
nvdla_dbg_err(pdev, "Invalid nvdla device\n");
err = -EINVAL;
goto fail_to_get_nvdla_dev;
}
mutex_lock(&nvdla_dev->ping_lock);
/* assign ping cmd buffer */
err = nvdla_get_cmd_memory(pdev, &ping_cmd_mem_info);
if (err) {
@@ -313,6 +323,8 @@ static int nvdla_ping(struct platform_device *pdev,
fail_cmd:
nvdla_put_cmd_memory(pdev, ping_cmd_mem_info.index);
fail_to_alloc:
mutex_unlock(&nvdla_dev->ping_lock);
fail_to_get_nvdla_dev:
nvhost_module_idle(pdev);
fail_to_on:
fail_to_get_val_arg: