drm/nouveau: rip out nvkm_client.super
[linux-2.6-microblaze.git] / drivers / gpu / drm / nouveau / nvif / object.c
1 /*
2  * Copyright 2014 Red Hat Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Authors: Ben Skeggs <bskeggs@redhat.com>
23  */
24
25 #include <nvif/object.h>
26 #include <nvif/client.h>
27 #include <nvif/driver.h>
28 #include <nvif/ioctl.h>
29
30 int
31 nvif_object_ioctl(struct nvif_object *object, void *data, u32 size, void **hack)
32 {
33         struct nvif_client *client = object->client;
34         union {
35                 struct nvif_ioctl_v0 v0;
36         } *args = data;
37
38         if (size >= sizeof(*args) && args->v0.version == 0) {
39                 if (object != &client->object)
40                         args->v0.object = nvif_handle(object);
41                 else
42                         args->v0.object = 0;
43                 args->v0.owner = NVIF_IOCTL_V0_OWNER_ANY;
44         } else
45                 return -ENOSYS;
46
47         return client->driver->ioctl(client->object.priv, data, size, hack);
48 }
49
50 void
51 nvif_object_sclass_put(struct nvif_sclass **psclass)
52 {
53         kfree(*psclass);
54         *psclass = NULL;
55 }
56
57 int
58 nvif_object_sclass_get(struct nvif_object *object, struct nvif_sclass **psclass)
59 {
60         struct {
61                 struct nvif_ioctl_v0 ioctl;
62                 struct nvif_ioctl_sclass_v0 sclass;
63         } *args = NULL;
64         int ret, cnt = 0, i;
65         u32 size;
66
67         while (1) {
68                 size = sizeof(*args) + cnt * sizeof(args->sclass.oclass[0]);
69                 if (!(args = kmalloc(size, GFP_KERNEL)))
70                         return -ENOMEM;
71                 args->ioctl.version = 0;
72                 args->ioctl.type = NVIF_IOCTL_V0_SCLASS;
73                 args->sclass.version = 0;
74                 args->sclass.count = cnt;
75
76                 ret = nvif_object_ioctl(object, args, size, NULL);
77                 if (ret == 0 && args->sclass.count <= cnt)
78                         break;
79                 cnt = args->sclass.count;
80                 kfree(args);
81                 if (ret != 0)
82                         return ret;
83         }
84
85         *psclass = kcalloc(args->sclass.count, sizeof(**psclass), GFP_KERNEL);
86         if (*psclass) {
87                 for (i = 0; i < args->sclass.count; i++) {
88                         (*psclass)[i].oclass = args->sclass.oclass[i].oclass;
89                         (*psclass)[i].minver = args->sclass.oclass[i].minver;
90                         (*psclass)[i].maxver = args->sclass.oclass[i].maxver;
91                 }
92                 ret = args->sclass.count;
93         } else {
94                 ret = -ENOMEM;
95         }
96
97         kfree(args);
98         return ret;
99 }
100
101 u32
102 nvif_object_rd(struct nvif_object *object, int size, u64 addr)
103 {
104         struct {
105                 struct nvif_ioctl_v0 ioctl;
106                 struct nvif_ioctl_rd_v0 rd;
107         } args = {
108                 .ioctl.type = NVIF_IOCTL_V0_RD,
109                 .rd.size = size,
110                 .rd.addr = addr,
111         };
112         int ret = nvif_object_ioctl(object, &args, sizeof(args), NULL);
113         if (ret) {
114                 /*XXX: warn? */
115                 return 0;
116         }
117         return args.rd.data;
118 }
119
120 void
121 nvif_object_wr(struct nvif_object *object, int size, u64 addr, u32 data)
122 {
123         struct {
124                 struct nvif_ioctl_v0 ioctl;
125                 struct nvif_ioctl_wr_v0 wr;
126         } args = {
127                 .ioctl.type = NVIF_IOCTL_V0_WR,
128                 .wr.size = size,
129                 .wr.addr = addr,
130                 .wr.data = data,
131         };
132         int ret = nvif_object_ioctl(object, &args, sizeof(args), NULL);
133         if (ret) {
134                 /*XXX: warn? */
135         }
136 }
137
138 int
139 nvif_object_mthd(struct nvif_object *object, u32 mthd, void *data, u32 size)
140 {
141         struct {
142                 struct nvif_ioctl_v0 ioctl;
143                 struct nvif_ioctl_mthd_v0 mthd;
144         } *args;
145         u8 stack[128];
146         int ret;
147
148         if (sizeof(*args) + size > sizeof(stack)) {
149                 if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL)))
150                         return -ENOMEM;
151         } else {
152                 args = (void *)stack;
153         }
154         args->ioctl.version = 0;
155         args->ioctl.type = NVIF_IOCTL_V0_MTHD;
156         args->mthd.version = 0;
157         args->mthd.method = mthd;
158
159         memcpy(args->mthd.data, data, size);
160         ret = nvif_object_ioctl(object, args, sizeof(*args) + size, NULL);
161         memcpy(data, args->mthd.data, size);
162         if (args != (void *)stack)
163                 kfree(args);
164         return ret;
165 }
166
167 void
168 nvif_object_unmap_handle(struct nvif_object *object)
169 {
170         struct {
171                 struct nvif_ioctl_v0 ioctl;
172                 struct nvif_ioctl_unmap unmap;
173         } args = {
174                 .ioctl.type = NVIF_IOCTL_V0_UNMAP,
175         };
176
177         nvif_object_ioctl(object, &args, sizeof(args), NULL);
178 }
179
180 int
181 nvif_object_map_handle(struct nvif_object *object, void *argv, u32 argc,
182                        u64 *handle, u64 *length)
183 {
184         struct {
185                 struct nvif_ioctl_v0 ioctl;
186                 struct nvif_ioctl_map_v0 map;
187         } *args;
188         u32 argn = sizeof(*args) + argc;
189         int ret, maptype;
190
191         if (!(args = kzalloc(argn, GFP_KERNEL)))
192                 return -ENOMEM;
193         args->ioctl.type = NVIF_IOCTL_V0_MAP;
194         memcpy(args->map.data, argv, argc);
195
196         ret = nvif_object_ioctl(object, args, argn, NULL);
197         *handle = args->map.handle;
198         *length = args->map.length;
199         maptype = args->map.type;
200         kfree(args);
201         return ret ? ret : (maptype == NVIF_IOCTL_MAP_V0_IO);
202 }
203
204 void
205 nvif_object_unmap(struct nvif_object *object)
206 {
207         struct nvif_client *client = object->client;
208         if (object->map.ptr) {
209                 if (object->map.size) {
210                         client->driver->unmap(client, object->map.ptr,
211                                                       object->map.size);
212                         object->map.size = 0;
213                 }
214                 object->map.ptr = NULL;
215                 nvif_object_unmap_handle(object);
216         }
217 }
218
219 int
220 nvif_object_map(struct nvif_object *object, void *argv, u32 argc)
221 {
222         struct nvif_client *client = object->client;
223         u64 handle, length;
224         int ret = nvif_object_map_handle(object, argv, argc, &handle, &length);
225         if (ret >= 0) {
226                 if (ret) {
227                         object->map.ptr = client->driver->map(client,
228                                                               handle,
229                                                               length);
230                         if (ret = -ENOMEM, object->map.ptr) {
231                                 object->map.size = length;
232                                 return 0;
233                         }
234                 } else {
235                         object->map.ptr = (void *)(unsigned long)handle;
236                         return 0;
237                 }
238                 nvif_object_unmap_handle(object);
239         }
240         return ret;
241 }
242
243 void
244 nvif_object_dtor(struct nvif_object *object)
245 {
246         struct {
247                 struct nvif_ioctl_v0 ioctl;
248                 struct nvif_ioctl_del del;
249         } args = {
250                 .ioctl.type = NVIF_IOCTL_V0_DEL,
251         };
252
253         if (!object->client)
254                 return;
255
256         nvif_object_unmap(object);
257         nvif_object_ioctl(object, &args, sizeof(args), NULL);
258         object->client = NULL;
259 }
260
261 int
262 nvif_object_ctor(struct nvif_object *parent, const char *name, u32 handle,
263                  s32 oclass, void *data, u32 size, struct nvif_object *object)
264 {
265         struct {
266                 struct nvif_ioctl_v0 ioctl;
267                 struct nvif_ioctl_new_v0 new;
268         } *args;
269         int ret = 0;
270
271         object->client = NULL;
272         object->name = name ? name : "nvifObject";
273         object->handle = handle;
274         object->oclass = oclass;
275         object->map.ptr = NULL;
276         object->map.size = 0;
277
278         if (parent) {
279                 if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL))) {
280                         nvif_object_dtor(object);
281                         return -ENOMEM;
282                 }
283
284                 object->parent = parent->parent;
285
286                 args->ioctl.version = 0;
287                 args->ioctl.type = NVIF_IOCTL_V0_NEW;
288                 args->new.version = 0;
289                 args->new.route = parent->client->route;
290                 args->new.token = nvif_handle(object);
291                 args->new.object = nvif_handle(object);
292                 args->new.handle = handle;
293                 args->new.oclass = oclass;
294
295                 memcpy(args->new.data, data, size);
296                 ret = nvif_object_ioctl(parent, args, sizeof(*args) + size,
297                                         &object->priv);
298                 memcpy(data, args->new.data, size);
299                 kfree(args);
300                 if (ret == 0)
301                         object->client = parent->client;
302         }
303
304         if (ret)
305                 nvif_object_dtor(object);
306         return ret;
307 }