diff --git a/drivers/video/tegra/host/nvdla/dla_queue.c b/drivers/video/tegra/host/nvdla/dla_queue.c index 381120df..3a00b147 100644 --- a/drivers/video/tegra/host/nvdla/dla_queue.c +++ b/drivers/video/tegra/host/nvdla/dla_queue.c @@ -12,17 +12,89 @@ #include #include #include +#include +#include #include "port/nvdla_host_wrapper.h" - -#if IS_ENABLED(CONFIG_TEGRA_NVDLA_CHANNEL) -#include "nvhost_job.h" -#endif - #include "dla_channel.h" #include "dla_queue.h" #include "nvdla_debug.h" +#if IS_ENABLED(CONFIG_TEGRA_NVDLA_CHANNEL) +#include "nvhost_job.h" + +/* Add host1x host1x_cb structures and functions needed for handling callbacks */ +struct nvdla_host1x_cb { + struct dma_fence_cb cb; + struct work_struct work; + void (*notifier)(void *data); + void *notifier_data; +}; + +static void nvdla_host1x_cb_func(struct dma_fence *f, struct dma_fence_cb *cb) +{ + struct nvdla_host1x_cb *host1x_cb; + + host1x_cb = container_of(cb, struct nvdla_host1x_cb, cb); + schedule_work(&host1x_cb->work); + dma_fence_put(f); +} + +static void nvdla_intr_do_work(struct work_struct *work) +{ + struct nvdla_host1x_cb *host1x_cb; + + host1x_cb = container_of(work, struct nvdla_host1x_cb, work); + host1x_cb->notifier(host1x_cb->notifier_data); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 5, 0)) + kfree_rcu_mightsleep(host1x_cb); +#else + kfree_rcu(host1x_cb); +#endif +} + +static int nvdla_intr_register_notifier(struct platform_device *pdev, + u32 id, u32 thresh, + void (*callback)(void *data), + void *private_data) +{ + struct nvhost_device_data *pdata = platform_get_drvdata(pdev); + struct dma_fence *fence; + struct nvdla_host1x_cb *cb; + struct host1x_syncpt *sp; + int err; + + sp = host1x_syncpt_get_by_id_noref(pdata->host1x, id); + if (!sp) + return -EINVAL; + + fence = host1x_fence_create(sp, thresh, true); + if (IS_ERR(fence)) { + pr_err("error %d during construction of fence!", + (int)PTR_ERR(fence)); + return PTR_ERR(fence); + } + + cb = kzalloc(sizeof(*cb), GFP_KERNEL); + if (!cb) { + dma_fence_put(fence); + return -ENOMEM; + } + + INIT_WORK(&cb->work, nvdla_intr_do_work); + cb->notifier = callback; + cb->notifier_data = private_data; + + err = dma_fence_add_callback(fence, &cb->cb, nvdla_host1x_cb_func); + if (err < 0) { + dma_fence_put(fence); + kfree(cb); + } + + return err; +} +#endif + #define CMDBUF_SIZE 4096 /** @@ -553,7 +625,7 @@ int nvdla_queue_submit_to_host1x(struct nvdla_queue *queue, *task_syncpt_threshold = job->sp->fence; /* Register a callback function for releasing resources */ - err = nvhost_intr_register_notifier(host1x_pdev, + err = nvdla_intr_register_notifier(host1x_pdev, queue->syncpt_id, job->sp->fence, queue_task_update, task); diff --git a/drivers/video/tegra/host/nvdla/port/sync/nvdla_sync_syncpt.c b/drivers/video/tegra/host/nvdla/port/sync/nvdla_sync_syncpt.c index de1a73ad..fdf16b55 100644 --- a/drivers/video/tegra/host/nvdla/port/sync/nvdla_sync_syncpt.c +++ b/drivers/video/tegra/host/nvdla/port/sync/nvdla_sync_syncpt.c @@ -31,6 +31,14 @@ struct nvdla_sync_context { dma_addr_t address; }; +static dma_addr_t nvdla_syncpt_address(struct platform_device *pdev, u32 syncpt_id) +{ + struct nvhost_device_data *pdata = platform_get_drvdata(pdev); + struct nvhost_syncpt_interface *syncpt_if = pdata->syncpt_unit_interface; + + return syncpt_if->base + syncpt_if->page_size * syncpt_id; +} + struct nvdla_sync_device *nvdla_sync_device_create_syncpoint( struct platform_device *pdev) { @@ -52,7 +60,6 @@ struct nvdla_sync_device *nvdla_sync_device_create_syncpoint( goto fail; } - /* Replace nvhost_syncpt_unit_interface_init with host1x_syncpt_get_shim_info */ pdata = platform_get_drvdata(pdev); syncpt_if = devm_kzalloc(&pdev->dev, sizeof(*syncpt_if), GFP_KERNEL); if (!syncpt_if) { @@ -142,7 +149,7 @@ dma_addr_t nvdla_sync_get_address_by_syncptid( dma_addr_t address = 0ULL; if (device != NULL) - address = nvhost_syncpt_address(device->pdev, syncptid); + address = nvdla_syncpt_address(device->pdev, syncptid); return address; } @@ -150,6 +157,8 @@ dma_addr_t nvdla_sync_get_address_by_syncptid( struct nvdla_sync_context *nvdla_sync_create(struct nvdla_sync_device *device) { struct nvdla_sync_context *context = NULL; + struct host1x_syncpt *sp = NULL; + struct nvhost_device_data *pdata = NULL; if ((device == NULL) || (device->pdev == NULL)) goto fail; @@ -162,15 +171,23 @@ struct nvdla_sync_context *nvdla_sync_create(struct nvdla_sync_device *device) goto fail; } - context->syncptid = - nvhost_get_syncpt_host_managed(device->pdev, 0U, NULL); - if (context->syncptid == 0) { - nvdla_dbg_err(device->pdev, "Failed to get syncpoint ID\n"); + pdata = platform_get_drvdata(device->pdev); + sp = host1x_syncpt_alloc(pdata->host1x, + 0U, /* Not client managed */ + dev_name(&device->pdev->dev)); + if (!sp) { + nvdla_dbg_err(device->pdev, "Failed to allocate syncpoint\n"); goto free_context; } - context->address = - nvhost_syncpt_address(device->pdev, context->syncptid); + context->syncptid = host1x_syncpt_id(sp); + if (context->syncptid == 0) { + nvdla_dbg_err(device->pdev, "Failed to get syncpoint ID\n"); + host1x_syncpt_put(sp); /* Release the allocated syncpoint */ + goto free_context; + } + + context->address = nvdla_syncpt_address(device->pdev, context->syncptid); context->device = device; return context; @@ -183,14 +200,21 @@ fail: void nvdla_sync_destroy(struct nvdla_sync_context *context) { + struct host1x_syncpt *sp = NULL; + struct nvhost_device_data *pdata; + if (context == NULL) goto done; if ((context->device == NULL) || (context->device->pdev == NULL)) goto free_context; - /* Release the syncpoint ID */ - nvhost_syncpt_put_ref_ext(context->device->pdev, context->syncptid); + pdata = platform_get_drvdata(context->device->pdev); + sp = host1x_syncpt_get_by_id_noref(pdata->host1x, context->syncptid); + if (WARN_ON(!sp)) + goto free_context; + + host1x_syncpt_put(sp); free_context: context->device = NULL; @@ -213,13 +237,18 @@ uint32_t nvdla_sync_increment_max_value(struct nvdla_sync_context *context, uint32_t increment) { uint32_t maxval = 0U; + struct nvhost_device_data *pdata; + struct host1x_syncpt *sp; if ((context == NULL) || (context->device == NULL)) goto fail; - maxval = nvhost_syncpt_incr_max_ext(context->device->pdev, - context->syncptid, - increment); + pdata = platform_get_drvdata(context->device->pdev); + sp = host1x_syncpt_get_by_id_noref(pdata->host1x, context->syncptid); + if (WARN_ON(!sp)) + goto fail; + + maxval = host1x_syncpt_incr_max(sp, increment); fail: return maxval; @@ -228,12 +257,18 @@ fail: uint32_t nvdla_sync_get_max_value(struct nvdla_sync_context *context) { int32_t maxval = 0U; + struct nvhost_device_data *pdata; + struct host1x_syncpt *sp; if ((context == NULL) || (context->device == NULL)) goto fail; - maxval = nvhost_syncpt_read_maxval(context->device->pdev, - context->syncptid); + pdata = platform_get_drvdata(context->device->pdev); + sp = host1x_syncpt_get_by_id_noref(pdata->host1x, context->syncptid); + if (WARN_ON(!sp)) + goto fail; + + maxval = host1x_syncpt_read_max(sp); fail: return maxval; @@ -246,6 +281,8 @@ int32_t nvdla_sync_wait(struct nvdla_sync_context *context, int32_t err = 0; int wait_complete; struct nvdla_sync_device *device; + struct nvhost_device_data *pdata; + struct host1x_syncpt *sp; if ((context == NULL) || (context->device == NULL)) { err = -EINVAL; @@ -254,10 +291,15 @@ int32_t nvdla_sync_wait(struct nvdla_sync_context *context, device = context->device; if (timeout == 0ULL) { - wait_complete = nvhost_syncpt_is_expired_ext(device->pdev, - context->syncptid, - threshold); - if (wait_complete == 0) { + pdata = platform_get_drvdata(device->pdev); + sp = host1x_syncpt_get_by_id_noref(pdata->host1x, context->syncptid); + if (WARN_ON(!sp)) { + err = -EINVAL; + goto fail; + } + + wait_complete = (host1x_syncpt_wait(sp, threshold, 0, NULL) == 0); + if (!wait_complete) { nvdla_dbg_err(device->pdev, "Wait on sp[%u] for threshold[%u] timedout\n", context->syncptid, threshold); @@ -280,15 +322,28 @@ int32_t nvdla_sync_signal(struct nvdla_sync_context *context, uint32_t signal_value) { int err = 0; + struct nvhost_device_data *pdata; + struct host1x_syncpt *sp; + uint32_t cur; if ((context == NULL) || (context->device == NULL)) { err = -EINVAL; goto fail; } - nvhost_syncpt_set_min_update(context->device->pdev, - context->syncptid, - signal_value); + pdata = platform_get_drvdata(context->device->pdev); + sp = host1x_syncpt_get_by_id_noref(pdata->host1x, context->syncptid); + if (WARN_ON(!sp)) { + err = -EINVAL; + goto fail; + } + + cur = host1x_syncpt_read(sp); + while (cur++ != signal_value) + host1x_syncpt_incr(sp); + + /* Read back to ensure the value has been updated */ + host1x_syncpt_read(sp); fail: return err;