Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) 2021, NVIDIA Corporation.
  4 */
  5
  6#include <linux/device.h>
  7#include <linux/kref.h>
  8#include <linux/of.h>
  9#include <linux/of_device.h>
 10#include <linux/pid.h>
 11#include <linux/slab.h>
 12
 13#include "context.h"
 14#include "dev.h"
 15
 16static void host1x_memory_context_release(struct device *dev)
 17{
 18	/* context device is freed in host1x_memory_context_list_free() */
 19}
 20
 21int host1x_memory_context_list_init(struct host1x *host1x)
 22{
 23	struct host1x_memory_context_list *cdl = &host1x->context_list;
 24	struct device_node *node = host1x->dev->of_node;
 25	struct host1x_memory_context *ctx;
 26	unsigned int i;
 27	int err;
 28
 29	cdl->devs = NULL;
 30	cdl->len = 0;
 31	mutex_init(&cdl->lock);
 32
 33	err = of_property_count_u32_elems(node, "iommu-map");
 34	if (err < 0)
 35		return 0;
 36
 37	cdl->len = err / 4;
 38	cdl->devs = kcalloc(cdl->len, sizeof(*cdl->devs), GFP_KERNEL);
 39	if (!cdl->devs)
 40		return -ENOMEM;
 41
 42	for (i = 0; i < cdl->len; i++) {
 43		ctx = &cdl->devs[i];
 44
 45		ctx->host = host1x;
 46
 47		device_initialize(&ctx->dev);
 48
 49		/*
 50		 * Due to an issue with T194 NVENC, only 38 bits can be used.
 51		 * Anyway, 256GiB of IOVA ought to be enough for anyone.
 52		 */
 53		ctx->dma_mask = DMA_BIT_MASK(38);
 54		ctx->dev.dma_mask = &ctx->dma_mask;
 55		ctx->dev.coherent_dma_mask = ctx->dma_mask;
 56		dev_set_name(&ctx->dev, "host1x-ctx.%d", i);
 57		ctx->dev.bus = &host1x_context_device_bus_type;
 58		ctx->dev.parent = host1x->dev;
 59		ctx->dev.release = host1x_memory_context_release;
 60
 61		dma_set_max_seg_size(&ctx->dev, UINT_MAX);
 62
 63		err = device_add(&ctx->dev);
 64		if (err) {
 65			dev_err(host1x->dev, "could not add context device %d: %d\n", i, err);
 66			put_device(&ctx->dev);
 67			goto unreg_devices;
 68		}
 69
 70		err = of_dma_configure_id(&ctx->dev, node, true, &i);
 71		if (err) {
 72			dev_err(host1x->dev, "IOMMU configuration failed for context device %d: %d\n",
 73				i, err);
 74			device_unregister(&ctx->dev);
 75			goto unreg_devices;
 76		}
 77
 78		if (!tegra_dev_iommu_get_stream_id(&ctx->dev, &ctx->stream_id) ||
 79		    !device_iommu_mapped(&ctx->dev)) {
 80			dev_err(host1x->dev, "Context device %d has no IOMMU!\n", i);
 81			device_unregister(&ctx->dev);
 82
 83			/*
 84			 * This means that if IOMMU is disabled but context devices
 85			 * are defined in the device tree, Host1x will fail to probe.
 86			 * That's probably OK in this time and age.
 87			 */
 88			err = -EINVAL;
 89
 90			goto unreg_devices;
 91		}
 92	}
 93
 94	return 0;
 95
 96unreg_devices:
 97	while (i--)
 98		device_unregister(&cdl->devs[i].dev);
 99
100	kfree(cdl->devs);
101	cdl->devs = NULL;
102	cdl->len = 0;
103
104	return err;
105}
106
107void host1x_memory_context_list_free(struct host1x_memory_context_list *cdl)
108{
109	unsigned int i;
110
111	for (i = 0; i < cdl->len; i++)
112		device_unregister(&cdl->devs[i].dev);
113
114	kfree(cdl->devs);
115	cdl->len = 0;
116}
117
118struct host1x_memory_context *host1x_memory_context_alloc(struct host1x *host1x,
119							  struct device *dev,
120							  struct pid *pid)
121{
122	struct host1x_memory_context_list *cdl = &host1x->context_list;
123	struct host1x_memory_context *free = NULL;
124	int i;
125
126	if (!cdl->len)
127		return ERR_PTR(-EOPNOTSUPP);
128
129	mutex_lock(&cdl->lock);
130
131	for (i = 0; i < cdl->len; i++) {
132		struct host1x_memory_context *cd = &cdl->devs[i];
133
134		if (cd->dev.iommu->iommu_dev != dev->iommu->iommu_dev)
135			continue;
136
137		if (cd->owner == pid) {
138			refcount_inc(&cd->ref);
139			mutex_unlock(&cdl->lock);
140			return cd;
141		} else if (!cd->owner && !free) {
142			free = cd;
143		}
144	}
145
146	if (!free) {
147		mutex_unlock(&cdl->lock);
148		return ERR_PTR(-EBUSY);
149	}
150
151	refcount_set(&free->ref, 1);
152	free->owner = get_pid(pid);
153
154	mutex_unlock(&cdl->lock);
155
156	return free;
157}
158EXPORT_SYMBOL_GPL(host1x_memory_context_alloc);
159
160void host1x_memory_context_get(struct host1x_memory_context *cd)
161{
162	refcount_inc(&cd->ref);
163}
164EXPORT_SYMBOL_GPL(host1x_memory_context_get);
165
166void host1x_memory_context_put(struct host1x_memory_context *cd)
167{
168	struct host1x_memory_context_list *cdl = &cd->host->context_list;
169
170	if (refcount_dec_and_mutex_lock(&cd->ref, &cdl->lock)) {
171		put_pid(cd->owner);
172		cd->owner = NULL;
173		mutex_unlock(&cdl->lock);
174	}
175}
176EXPORT_SYMBOL_GPL(host1x_memory_context_put);