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