gpu: host1x: Memory context stealing

Currently, each process holding an open TegraDRM channel reserves
for itself one of the limited number of hardware memory contexts.
Attempting to allocate a channel when all contexts are in use
results in failure.

While we cannot have more contexts than the hardware supports in
active use, idle channels don't necessarily need to have a backing
memory context. As such, in this patch, we add another layer
to allow hardware memory contexts to be "stolen away" by channels
that are in active use, from idle processes.

The way this is implemented, is by keeping track of memory
mappings on each abstracted memory context. If we need to
steal that memory context's backing hardware context, we unmap
everything from it and give it away. When that abstracted
memory context is needed again (re-activated), we attempt
to allocate or steal another hardware context and re-map
the previously unmapped buffers.

Unfortunately, this means additional overhead and unpredictability
at submit time. Submit can fail if we cannot re-allocate a
backing memory context. Future work includes a provision for
un-stealable backing hardware memory contexts for processes
requiring more determinism, as well as optimization and cosmetic
improvements.

Bug 4403250
Bug 4399310

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
Change-Id: I3d13e3476f1bff3c4757152254496cddaaafd76a
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3058905
Reviewed-by: Santosh BS <santoshb@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
Mikko Perttunen
2024-01-16 04:20:04 +02:00
committed by mobile promotions
parent 7e85d429e7
commit e062e9d49c
8 changed files with 318 additions and 45 deletions

View File

@@ -240,9 +240,14 @@ static int submit_write_reloc(struct tegra_drm_context *context, struct gather_b
struct drm_tegra_submit_buf *buf, struct tegra_drm_mapping *mapping)
{
/* TODO check that target_offset is within bounds */
dma_addr_t iova = mapping->iova + buf->reloc.target_offset;
dma_addr_t iova = buf->reloc.target_offset;
u32 written_ptr;
if (mapping->bo_map)
iova += mapping->iova;
else
iova += mapping->ctx_map->mapping->phys;
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
if (buf->flags & DRM_TEGRA_SUBMIT_RELOC_SECTOR_LAYOUT)
iova |= BIT_ULL(39);
@@ -526,9 +531,6 @@ static void release_job(struct host1x_job *job)
struct tegra_drm_submit_data *job_data = job->user_data;
u32 i;
if (job->memory_context)
host1x_memory_context_put(job->memory_context);
if (IS_ENABLED(CONFIG_TRACING) && job_data->timestamps.virt) {
u64 *timestamps = job_data->timestamps.virt;
@@ -542,6 +544,11 @@ static void release_job(struct host1x_job *job)
for (i = 0; i < job_data->num_used_mappings; i++)
tegra_drm_mapping_put(job_data->used_mappings[i].mapping);
if (job->memory_context) {
host1x_memory_context_inactive(job->memory_context);
host1x_memory_context_put(job->memory_context);
}
kfree(job_data->used_mappings);
kfree(job_data);
@@ -581,6 +588,7 @@ static int submit_init_profiling(struct tegra_drm_context *context,
int tegra_drm_ioctl_channel_submit(struct drm_device *drm, void *data,
struct drm_file *file)
{
struct host1x_memory_context *active_memctx = NULL;
struct tegra_drm_file *fpriv = file->driver_priv;
struct drm_tegra_channel_submit *args = data;
static atomic_t next_job_id = ATOMIC_INIT(1);
@@ -604,6 +612,17 @@ int tegra_drm_ioctl_channel_submit(struct drm_device *drm, void *data,
return -EINVAL;
}
if (context->memory_context) {
err = host1x_memory_context_active(context->memory_context);
if (err) {
mutex_unlock(&fpriv->lock);
SUBMIT_ERR(context, "failed to activate memory context");
return err;
}
active_memctx = context->memory_context;
}
if (args->flags & ~(DRM_TEGRA_SUBMIT_SECONDARY_SYNCPT)) {
SUBMIT_ERR(context, "invalid flags '%#x'", args->flags);
goto unlock;
@@ -704,7 +723,8 @@ int tegra_drm_ioctl_channel_submit(struct drm_device *drm, void *data,
}
if (supported) {
job->memory_context = context->memory_context;
job->memory_context = active_memctx;
active_memctx = NULL;
host1x_memory_context_get(job->memory_context);
}
} else if (context->client->ops->get_streamid_offset) {
@@ -825,6 +845,8 @@ put_bo:
unlock:
if (syncobj)
drm_syncobj_put(syncobj);
if (active_memctx)
host1x_memory_context_inactive(active_memctx);
mutex_unlock(&fpriv->lock);
return err;