OSDN Git Service

drm/nouveau/nvif: replace path-based object identification
[uclinux-h8/linux.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, client->super,
48                                      data, size, hack);
49 }
50
51 int
52 nvif_object_sclass(struct nvif_object *object, u32 *oclass, int count)
53 {
54         struct {
55                 struct nvif_ioctl_v0 ioctl;
56                 struct nvif_ioctl_sclass_v0 sclass;
57         } *args;
58         u32 size = count * sizeof(args->sclass.oclass[0]);
59         int ret;
60
61         if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL)))
62                 return -ENOMEM;
63         args->ioctl.version = 0;
64         args->ioctl.type = NVIF_IOCTL_V0_SCLASS;
65         args->sclass.version = 0;
66         args->sclass.count = count;
67
68         memcpy(args->sclass.oclass, oclass, size);
69         ret = nvif_object_ioctl(object, args, sizeof(*args) + size, NULL);
70         ret = ret ? ret : args->sclass.count;
71         memcpy(oclass, args->sclass.oclass, size);
72         kfree(args);
73         return ret;
74 }
75
76 u32
77 nvif_object_rd(struct nvif_object *object, int size, u64 addr)
78 {
79         struct {
80                 struct nvif_ioctl_v0 ioctl;
81                 struct nvif_ioctl_rd_v0 rd;
82         } args = {
83                 .ioctl.type = NVIF_IOCTL_V0_RD,
84                 .rd.size = size,
85                 .rd.addr = addr,
86         };
87         int ret = nvif_object_ioctl(object, &args, sizeof(args), NULL);
88         if (ret) {
89                 /*XXX: warn? */
90                 return 0;
91         }
92         return args.rd.data;
93 }
94
95 void
96 nvif_object_wr(struct nvif_object *object, int size, u64 addr, u32 data)
97 {
98         struct {
99                 struct nvif_ioctl_v0 ioctl;
100                 struct nvif_ioctl_wr_v0 wr;
101         } args = {
102                 .ioctl.type = NVIF_IOCTL_V0_WR,
103                 .wr.size = size,
104                 .wr.addr = addr,
105                 .wr.data = data,
106         };
107         int ret = nvif_object_ioctl(object, &args, sizeof(args), NULL);
108         if (ret) {
109                 /*XXX: warn? */
110         }
111 }
112
113 int
114 nvif_object_mthd(struct nvif_object *object, u32 mthd, void *data, u32 size)
115 {
116         struct {
117                 struct nvif_ioctl_v0 ioctl;
118                 struct nvif_ioctl_mthd_v0 mthd;
119         } *args;
120         u8 stack[128];
121         int ret;
122
123         if (sizeof(*args) + size > sizeof(stack)) {
124                 if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL)))
125                         return -ENOMEM;
126         } else {
127                 args = (void *)stack;
128         }
129         args->ioctl.version = 0;
130         args->ioctl.type = NVIF_IOCTL_V0_MTHD;
131         args->mthd.version = 0;
132         args->mthd.method = mthd;
133
134         memcpy(args->mthd.data, data, size);
135         ret = nvif_object_ioctl(object, args, sizeof(*args) + size, NULL);
136         memcpy(data, args->mthd.data, size);
137         if (args != (void *)stack)
138                 kfree(args);
139         return ret;
140 }
141
142 void
143 nvif_object_unmap(struct nvif_object *object)
144 {
145         if (object->map.size) {
146                 struct nvif_client *client = object->client;
147                 struct {
148                         struct nvif_ioctl_v0 ioctl;
149                         struct nvif_ioctl_unmap unmap;
150                 } args = {
151                         .ioctl.type = NVIF_IOCTL_V0_UNMAP,
152                 };
153
154                 if (object->map.ptr) {
155                         client->driver->unmap(client, object->map.ptr,
156                                                       object->map.size);
157                         object->map.ptr = NULL;
158                 }
159
160                 nvif_object_ioctl(object, &args, sizeof(args), NULL);
161                 object->map.size = 0;
162         }
163 }
164
165 int
166 nvif_object_map(struct nvif_object *object)
167 {
168         struct nvif_client *client = object->client;
169         struct {
170                 struct nvif_ioctl_v0 ioctl;
171                 struct nvif_ioctl_map_v0 map;
172         } args = {
173                 .ioctl.type = NVIF_IOCTL_V0_MAP,
174         };
175         int ret = nvif_object_ioctl(object, &args, sizeof(args), NULL);
176         if (ret == 0) {
177                 object->map.size = args.map.length;
178                 object->map.ptr = client->driver->map(client, args.map.handle,
179                                                       object->map.size);
180                 if (ret = -ENOMEM, object->map.ptr)
181                         return 0;
182                 nvif_object_unmap(object);
183         }
184         return ret;
185 }
186
187 void
188 nvif_object_fini(struct nvif_object *object)
189 {
190         struct {
191                 struct nvif_ioctl_v0 ioctl;
192                 struct nvif_ioctl_del del;
193         } args = {
194                 .ioctl.type = NVIF_IOCTL_V0_DEL,
195         };
196
197         if (!object->client)
198                 return;
199
200         nvif_object_unmap(object);
201         nvif_object_ioctl(object, &args, sizeof(args), NULL);
202         object->client = NULL;
203 }
204
205 int
206 nvif_object_init(struct nvif_object *parent, u32 handle, u32 oclass,
207                  void *data, u32 size, struct nvif_object *object)
208 {
209         struct {
210                 struct nvif_ioctl_v0 ioctl;
211                 struct nvif_ioctl_new_v0 new;
212         } *args;
213         int ret = 0;
214
215         object->client = NULL;
216         object->handle = handle;
217         object->oclass = oclass;
218         object->map.ptr = NULL;
219         object->map.size = 0;
220
221         if (parent) {
222                 if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL))) {
223                         nvif_object_fini(object);
224                         return -ENOMEM;
225                 }
226
227                 args->ioctl.version = 0;
228                 args->ioctl.type = NVIF_IOCTL_V0_NEW;
229                 args->new.version = 0;
230                 args->new.route = parent->client->route;
231                 args->new.token = nvif_handle(object);
232                 args->new.object = nvif_handle(object);
233                 args->new.handle = handle;
234                 args->new.oclass = oclass;
235
236                 memcpy(args->new.data, data, size);
237                 ret = nvif_object_ioctl(parent, args, sizeof(*args) + size,
238                                         &object->priv);
239                 memcpy(data, args->new.data, size);
240                 kfree(args);
241                 if (ret == 0)
242                         object->client = parent->client;
243         }
244
245         if (ret)
246                 nvif_object_fini(object);
247         return ret;
248 }