GNU Linux-libre 4.9.288-gnu1
[releases.git] / drivers / gpu / drm / nouveau / nvkm / engine / device / user.c
1 /*
2  * Copyright 2012 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
23  */
24 #define nvkm_udevice(p) container_of((p), struct nvkm_udevice, object)
25 #include "priv.h"
26 #include "ctrl.h"
27
28 #include <core/client.h>
29 #include <subdev/fb.h>
30 #include <subdev/instmem.h>
31 #include <subdev/timer.h>
32
33 #include <nvif/class.h>
34 #include <nvif/cl0080.h>
35 #include <nvif/unpack.h>
36
37 struct nvkm_udevice {
38         struct nvkm_object object;
39         struct nvkm_device *device;
40 };
41
42 static int
43 nvkm_udevice_info(struct nvkm_udevice *udev, void *data, u32 size)
44 {
45         struct nvkm_object *object = &udev->object;
46         struct nvkm_device *device = udev->device;
47         struct nvkm_fb *fb = device->fb;
48         struct nvkm_instmem *imem = device->imem;
49         union {
50                 struct nv_device_info_v0 v0;
51         } *args = data;
52         int ret = -ENOSYS;
53
54         nvif_ioctl(object, "device info size %d\n", size);
55         if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
56                 nvif_ioctl(object, "device info vers %d\n", args->v0.version);
57         } else
58                 return ret;
59
60         switch (device->chipset) {
61         case 0x01a:
62         case 0x01f:
63         case 0x04c:
64         case 0x04e:
65         case 0x063:
66         case 0x067:
67         case 0x068:
68         case 0x0aa:
69         case 0x0ac:
70         case 0x0af:
71                 args->v0.platform = NV_DEVICE_INFO_V0_IGP;
72                 break;
73         default:
74                 switch (device->type) {
75                 case NVKM_DEVICE_PCI:
76                         args->v0.platform = NV_DEVICE_INFO_V0_PCI;
77                         break;
78                 case NVKM_DEVICE_AGP:
79                         args->v0.platform = NV_DEVICE_INFO_V0_AGP;
80                         break;
81                 case NVKM_DEVICE_PCIE:
82                         args->v0.platform = NV_DEVICE_INFO_V0_PCIE;
83                         break;
84                 case NVKM_DEVICE_TEGRA:
85                         args->v0.platform = NV_DEVICE_INFO_V0_SOC;
86                         break;
87                 default:
88                         WARN_ON(1);
89                         break;
90                 }
91                 break;
92         }
93
94         switch (device->card_type) {
95         case NV_04: args->v0.family = NV_DEVICE_INFO_V0_TNT; break;
96         case NV_10:
97         case NV_11: args->v0.family = NV_DEVICE_INFO_V0_CELSIUS; break;
98         case NV_20: args->v0.family = NV_DEVICE_INFO_V0_KELVIN; break;
99         case NV_30: args->v0.family = NV_DEVICE_INFO_V0_RANKINE; break;
100         case NV_40: args->v0.family = NV_DEVICE_INFO_V0_CURIE; break;
101         case NV_50: args->v0.family = NV_DEVICE_INFO_V0_TESLA; break;
102         case NV_C0: args->v0.family = NV_DEVICE_INFO_V0_FERMI; break;
103         case NV_E0: args->v0.family = NV_DEVICE_INFO_V0_KEPLER; break;
104         case GM100: args->v0.family = NV_DEVICE_INFO_V0_MAXWELL; break;
105         case GP100: args->v0.family = NV_DEVICE_INFO_V0_PASCAL; break;
106         default:
107                 args->v0.family = 0;
108                 break;
109         }
110
111         args->v0.chipset  = device->chipset;
112         args->v0.revision = device->chiprev;
113         if (fb && fb->ram)
114                 args->v0.ram_size = args->v0.ram_user = fb->ram->size;
115         else
116                 args->v0.ram_size = args->v0.ram_user = 0;
117         if (imem && args->v0.ram_size > 0)
118                 args->v0.ram_user = args->v0.ram_user - imem->reserved;
119
120         strncpy(args->v0.chip, device->chip->name, sizeof(args->v0.chip));
121         strncpy(args->v0.name, device->name, sizeof(args->v0.name));
122         return 0;
123 }
124
125 static int
126 nvkm_udevice_time(struct nvkm_udevice *udev, void *data, u32 size)
127 {
128         struct nvkm_object *object = &udev->object;
129         struct nvkm_device *device = udev->device;
130         union {
131                 struct nv_device_time_v0 v0;
132         } *args = data;
133         int ret = -ENOSYS;
134
135         nvif_ioctl(object, "device time size %d\n", size);
136         if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
137                 nvif_ioctl(object, "device time vers %d\n", args->v0.version);
138                 args->v0.time = nvkm_timer_read(device->timer);
139         }
140
141         return ret;
142 }
143
144 static int
145 nvkm_udevice_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
146 {
147         struct nvkm_udevice *udev = nvkm_udevice(object);
148         nvif_ioctl(object, "device mthd %08x\n", mthd);
149         switch (mthd) {
150         case NV_DEVICE_V0_INFO:
151                 return nvkm_udevice_info(udev, data, size);
152         case NV_DEVICE_V0_TIME:
153                 return nvkm_udevice_time(udev, data, size);
154         default:
155                 break;
156         }
157         return -EINVAL;
158 }
159
160 static int
161 nvkm_udevice_rd08(struct nvkm_object *object, u64 addr, u8 *data)
162 {
163         struct nvkm_udevice *udev = nvkm_udevice(object);
164         *data = nvkm_rd08(udev->device, addr);
165         return 0;
166 }
167
168 static int
169 nvkm_udevice_rd16(struct nvkm_object *object, u64 addr, u16 *data)
170 {
171         struct nvkm_udevice *udev = nvkm_udevice(object);
172         *data = nvkm_rd16(udev->device, addr);
173         return 0;
174 }
175
176 static int
177 nvkm_udevice_rd32(struct nvkm_object *object, u64 addr, u32 *data)
178 {
179         struct nvkm_udevice *udev = nvkm_udevice(object);
180         *data = nvkm_rd32(udev->device, addr);
181         return 0;
182 }
183
184 static int
185 nvkm_udevice_wr08(struct nvkm_object *object, u64 addr, u8 data)
186 {
187         struct nvkm_udevice *udev = nvkm_udevice(object);
188         nvkm_wr08(udev->device, addr, data);
189         return 0;
190 }
191
192 static int
193 nvkm_udevice_wr16(struct nvkm_object *object, u64 addr, u16 data)
194 {
195         struct nvkm_udevice *udev = nvkm_udevice(object);
196         nvkm_wr16(udev->device, addr, data);
197         return 0;
198 }
199
200 static int
201 nvkm_udevice_wr32(struct nvkm_object *object, u64 addr, u32 data)
202 {
203         struct nvkm_udevice *udev = nvkm_udevice(object);
204         nvkm_wr32(udev->device, addr, data);
205         return 0;
206 }
207
208 static int
209 nvkm_udevice_map(struct nvkm_object *object, u64 *addr, u32 *size)
210 {
211         struct nvkm_udevice *udev = nvkm_udevice(object);
212         struct nvkm_device *device = udev->device;
213         *addr = device->func->resource_addr(device, 0);
214         *size = device->func->resource_size(device, 0);
215         return 0;
216 }
217
218 static int
219 nvkm_udevice_fini(struct nvkm_object *object, bool suspend)
220 {
221         struct nvkm_udevice *udev = nvkm_udevice(object);
222         struct nvkm_device *device = udev->device;
223         int ret = 0;
224
225         mutex_lock(&device->mutex);
226         if (!--device->refcount) {
227                 ret = nvkm_device_fini(device, suspend);
228                 if (ret && suspend) {
229                         device->refcount++;
230                         goto done;
231                 }
232         }
233
234 done:
235         mutex_unlock(&device->mutex);
236         return ret;
237 }
238
239 static int
240 nvkm_udevice_init(struct nvkm_object *object)
241 {
242         struct nvkm_udevice *udev = nvkm_udevice(object);
243         struct nvkm_device *device = udev->device;
244         int ret = 0;
245
246         mutex_lock(&device->mutex);
247         if (!device->refcount++) {
248                 ret = nvkm_device_init(device);
249                 if (ret) {
250                         device->refcount--;
251                         goto done;
252                 }
253         }
254
255 done:
256         mutex_unlock(&device->mutex);
257         return ret;
258 }
259
260 static int
261 nvkm_udevice_child_new(const struct nvkm_oclass *oclass,
262                        void *data, u32 size, struct nvkm_object **pobject)
263 {
264         struct nvkm_udevice *udev = nvkm_udevice(oclass->parent);
265         const struct nvkm_device_oclass *sclass = oclass->priv;
266         return sclass->ctor(udev->device, oclass, data, size, pobject);
267 }
268
269 static int
270 nvkm_udevice_child_get(struct nvkm_object *object, int index,
271                        struct nvkm_oclass *oclass)
272 {
273         struct nvkm_udevice *udev = nvkm_udevice(object);
274         struct nvkm_device *device = udev->device;
275         struct nvkm_engine *engine;
276         u64 mask = (1ULL << NVKM_ENGINE_DMAOBJ) |
277                    (1ULL << NVKM_ENGINE_FIFO) |
278                    (1ULL << NVKM_ENGINE_DISP) |
279                    (1ULL << NVKM_ENGINE_PM);
280         const struct nvkm_device_oclass *sclass = NULL;
281         int i;
282
283         for (; i = __ffs64(mask), mask && !sclass; mask &= ~(1ULL << i)) {
284                 if (!(engine = nvkm_device_engine(device, i)) ||
285                     !(engine->func->base.sclass))
286                         continue;
287                 oclass->engine = engine;
288
289                 index -= engine->func->base.sclass(oclass, index, &sclass);
290         }
291
292         if (!sclass) {
293                 switch (index) {
294                 case 0: sclass = &nvkm_control_oclass; break;
295                 default:
296                         return -EINVAL;
297                 }
298                 oclass->base = sclass->base;
299         }
300
301         oclass->ctor = nvkm_udevice_child_new;
302         oclass->priv = sclass;
303         return 0;
304 }
305
306 static const struct nvkm_object_func
307 nvkm_udevice_super = {
308         .init = nvkm_udevice_init,
309         .fini = nvkm_udevice_fini,
310         .mthd = nvkm_udevice_mthd,
311         .map = nvkm_udevice_map,
312         .rd08 = nvkm_udevice_rd08,
313         .rd16 = nvkm_udevice_rd16,
314         .rd32 = nvkm_udevice_rd32,
315         .wr08 = nvkm_udevice_wr08,
316         .wr16 = nvkm_udevice_wr16,
317         .wr32 = nvkm_udevice_wr32,
318         .sclass = nvkm_udevice_child_get,
319 };
320
321 static const struct nvkm_object_func
322 nvkm_udevice = {
323         .init = nvkm_udevice_init,
324         .fini = nvkm_udevice_fini,
325         .mthd = nvkm_udevice_mthd,
326         .sclass = nvkm_udevice_child_get,
327 };
328
329 int
330 nvkm_udevice_new(const struct nvkm_oclass *oclass, void *data, u32 size,
331                  struct nvkm_object **pobject)
332 {
333         union {
334                 struct nv_device_v0 v0;
335         } *args = data;
336         struct nvkm_client *client = oclass->client;
337         struct nvkm_object *parent = &client->object;
338         const struct nvkm_object_func *func;
339         struct nvkm_udevice *udev;
340         int ret = -ENOSYS;
341
342         nvif_ioctl(parent, "create device size %d\n", size);
343         if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
344                 nvif_ioctl(parent, "create device v%d device %016llx\n",
345                            args->v0.version, args->v0.device);
346         } else
347                 return ret;
348
349         /* give priviledged clients register access */
350         if (client->super)
351                 func = &nvkm_udevice_super;
352         else
353                 func = &nvkm_udevice;
354
355         if (!(udev = kzalloc(sizeof(*udev), GFP_KERNEL)))
356                 return -ENOMEM;
357         nvkm_object_ctor(func, oclass, &udev->object);
358         *pobject = &udev->object;
359
360         /* find the device that matches what the client requested */
361         if (args->v0.device != ~0)
362                 udev->device = nvkm_device_find(args->v0.device);
363         else
364                 udev->device = nvkm_device_find(client->device);
365         if (!udev->device)
366                 return -ENODEV;
367
368         return 0;
369 }
370
371 const struct nvkm_sclass
372 nvkm_udevice_sclass = {
373         .oclass = NV_DEVICE,
374         .minver = 0,
375         .maxver = 0,
376         .ctor = nvkm_udevice_new,
377 };