summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Skeggs2015-11-23 21:08:21 -0600
committerBen Skeggs2015-12-21 21:22:35 -0600
commit4291eea18fd81ca084935fb09a0e97a6661f4f85 (patch)
tree92023726dbce1d42a4fa03d75f987b382385255a
parent4c92a9d70725ec393899979bbfc21a37684e88d9 (diff)
downloadexternal-libdrm-4291eea18fd81ca084935fb09a0e97a6661f4f85.tar.gz
external-libdrm-4291eea18fd81ca084935fb09a0e97a6661f4f85.tar.xz
external-libdrm-4291eea18fd81ca084935fb09a0e97a6661f4f85.zip
nouveau: add support for newer kernel interfaces
v2. - leave client-provided pointer unmodified on sclass_get() failure Signed-off-by: Ben Skeggs <bskeggs@redhat.com> Tested-by: Samuel Pitoiset <samuel.pitoiset@gmail.com> Reviewed-by: Emil Velikov <emil.l.velikov@gmail.com>
-rw-r--r--nouveau/abi16.c3
-rw-r--r--nouveau/nouveau.c159
2 files changed, 155 insertions, 7 deletions
diff --git a/nouveau/abi16.c b/nouveau/abi16.c
index 46350b13..ee38c0cb 100644
--- a/nouveau/abi16.c
+++ b/nouveau/abi16.c
@@ -244,7 +244,8 @@ abi16_object(struct nouveau_object *obj, int (**func)(struct nouveau_object *))
244 /* nouveau_object::length is (ab)used to determine whether the 244 /* nouveau_object::length is (ab)used to determine whether the
245 * object is a legacy object (!=0), or a real NVIF object. 245 * object is a legacy object (!=0), or a real NVIF object.
246 */ 246 */
247 if ((parent->length != 0 && parent->oclass == NOUVEAU_DEVICE_CLASS)) { 247 if ((parent->length != 0 && parent->oclass == NOUVEAU_DEVICE_CLASS) ||
248 (parent->length == 0 && parent->oclass == NV_DEVICE)) {
248 if (obj->oclass == NOUVEAU_FIFO_CHANNEL_CLASS) { 249 if (obj->oclass == NOUVEAU_FIFO_CHANNEL_CLASS) {
249 struct nouveau_device *dev = (void *)parent; 250 struct nouveau_device *dev = (void *)parent;
250 if (dev->chipset < 0xc0) 251 if (dev->chipset < 0xc0)
diff --git a/nouveau/nouveau.c b/nouveau/nouveau.c
index fef338b6..e113a8fe 100644
--- a/nouveau/nouveau.c
+++ b/nouveau/nouveau.c
@@ -47,6 +47,7 @@
47 47
48#include "nvif/class.h" 48#include "nvif/class.h"
49#include "nvif/cl0080.h" 49#include "nvif/cl0080.h"
50#include "nvif/ioctl.h"
50#include "nvif/unpack.h" 51#include "nvif/unpack.h"
51 52
52#ifdef DEBUG 53#ifdef DEBUG
@@ -63,11 +64,67 @@ debug_init(char *args)
63} 64}
64#endif 65#endif
65 66
67static int
68nouveau_object_ioctl(struct nouveau_object *obj, void *data, uint32_t size)
69{
70 struct nouveau_drm *drm = nouveau_drm(obj);
71 union {
72 struct nvif_ioctl_v0 v0;
73 } *args = data;
74 uint32_t argc = size;
75 int ret = -ENOSYS;
76
77 if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
78 if (!obj->length) {
79 if (obj != &drm->client)
80 args->v0.object = (unsigned long)(void *)obj;
81 else
82 args->v0.object = 0;
83 args->v0.owner = NVIF_IOCTL_V0_OWNER_ANY;
84 args->v0.route = 0x00;
85 } else {
86 args->v0.route = 0xff;
87 args->v0.token = obj->handle;
88 }
89 } else
90 return ret;
91
92 return drmCommandWriteRead(drm->fd, DRM_NOUVEAU_NVIF, args, argc);
93}
94
66int 95int
67nouveau_object_mthd(struct nouveau_object *obj, 96nouveau_object_mthd(struct nouveau_object *obj,
68 uint32_t mthd, void *data, uint32_t size) 97 uint32_t mthd, void *data, uint32_t size)
69{ 98{
70 return -ENODEV; 99 struct nouveau_drm *drm = nouveau_drm(obj);
100 struct {
101 struct nvif_ioctl_v0 ioctl;
102 struct nvif_ioctl_mthd_v0 mthd;
103 } *args;
104 uint32_t argc = sizeof(*args) + size;
105 uint8_t stack[128];
106 int ret;
107
108 if (!drm->nvif)
109 return -ENOSYS;
110
111 if (argc > sizeof(stack)) {
112 if (!(args = malloc(argc)))
113 return -ENOMEM;
114 } else {
115 args = (void *)stack;
116 }
117 args->ioctl.version = 0;
118 args->ioctl.type = NVIF_IOCTL_V0_MTHD;
119 args->mthd.version = 0;
120 args->mthd.method = mthd;
121
122 memcpy(args->mthd.data, data, size);
123 ret = nouveau_object_ioctl(obj, args, argc);
124 memcpy(data, args->mthd.data, size);
125 if (args != (void *)stack)
126 free(args);
127 return ret;
71} 128}
72 129
73void 130void
@@ -81,7 +138,50 @@ int
81nouveau_object_sclass_get(struct nouveau_object *obj, 138nouveau_object_sclass_get(struct nouveau_object *obj,
82 struct nouveau_sclass **psclass) 139 struct nouveau_sclass **psclass)
83{ 140{
84 return abi16_sclass(obj, psclass); 141 struct nouveau_drm *drm = nouveau_drm(obj);
142 struct {
143 struct nvif_ioctl_v0 ioctl;
144 struct nvif_ioctl_sclass_v0 sclass;
145 } *args = NULL;
146 struct nouveau_sclass *sclass;
147 int ret, cnt = 0, i;
148 uint32_t size;
149
150 if (!drm->nvif)
151 return abi16_sclass(obj, psclass);
152
153 while (1) {
154 size = sizeof(*args) + cnt * sizeof(args->sclass.oclass[0]);
155 if (!(args = malloc(size)))
156 return -ENOMEM;
157 args->ioctl.version = 0;
158 args->ioctl.type = NVIF_IOCTL_V0_SCLASS;
159 args->sclass.version = 0;
160 args->sclass.count = cnt;
161
162 ret = nouveau_object_ioctl(obj, args, size);
163 if (ret == 0 && args->sclass.count <= cnt)
164 break;
165 cnt = args->sclass.count;
166 free(args);
167 if (ret != 0)
168 return ret;
169 }
170
171 if ((sclass = calloc(args->sclass.count, sizeof(*sclass)))) {
172 for (i = 0; i < args->sclass.count; i++) {
173 sclass[i].oclass = args->sclass.oclass[i].oclass;
174 sclass[i].minver = args->sclass.oclass[i].minver;
175 sclass[i].maxver = args->sclass.oclass[i].maxver;
176 }
177 *psclass = sclass;
178 ret = args->sclass.count;
179 } else {
180 ret = -ENOMEM;
181 }
182
183 free(args);
184 return ret;
85} 185}
86 186
87int 187int
@@ -114,12 +214,21 @@ nouveau_object_mclass(struct nouveau_object *obj,
114static void 214static void
115nouveau_object_fini(struct nouveau_object *obj) 215nouveau_object_fini(struct nouveau_object *obj)
116{ 216{
217 struct {
218 struct nvif_ioctl_v0 ioctl;
219 struct nvif_ioctl_del del;
220 } args = {
221 .ioctl.type = NVIF_IOCTL_V0_DEL,
222 };
223
117 if (obj->data) { 224 if (obj->data) {
118 abi16_delete(obj); 225 abi16_delete(obj);
119 free(obj->data); 226 free(obj->data);
120 obj->data = NULL; 227 obj->data = NULL;
121 return; 228 return;
122 } 229 }
230
231 nouveau_object_ioctl(obj, &args, sizeof(args));
123} 232}
124 233
125static int 234static int
@@ -127,6 +236,12 @@ nouveau_object_init(struct nouveau_object *parent, uint32_t handle,
127 int32_t oclass, void *data, uint32_t size, 236 int32_t oclass, void *data, uint32_t size,
128 struct nouveau_object *obj) 237 struct nouveau_object *obj)
129{ 238{
239 struct nouveau_drm *drm = nouveau_drm(parent);
240 struct {
241 struct nvif_ioctl_v0 ioctl;
242 struct nvif_ioctl_new_v0 new;
243 } *args;
244 uint32_t argc = sizeof(*args) + size;
130 int (*func)(struct nouveau_object *); 245 int (*func)(struct nouveau_object *);
131 int ret = -ENOSYS; 246 int ret = -ENOSYS;
132 247
@@ -136,7 +251,22 @@ nouveau_object_init(struct nouveau_object *parent, uint32_t handle,
136 obj->length = 0; 251 obj->length = 0;
137 obj->data = NULL; 252 obj->data = NULL;
138 253
139 abi16_object(obj, &func); 254 if (!abi16_object(obj, &func) && drm->nvif) {
255 if (!(args = malloc(argc)))
256 return -ENOMEM;
257 args->ioctl.version = 0;
258 args->ioctl.type = NVIF_IOCTL_V0_NEW;
259 args->new.version = 0;
260 args->new.route = NVIF_IOCTL_V0_ROUTE_NVIF;
261 args->new.token = (unsigned long)(void *)obj;
262 args->new.object = (unsigned long)(void *)obj;
263 args->new.handle = handle;
264 args->new.oclass = oclass;
265 memcpy(args->new.data, data, size);
266 ret = nouveau_object_ioctl(parent, args, argc);
267 memcpy(data, args->new.data, size);
268 free(args);
269 } else
140 if (func) { 270 if (func) {
141 obj->length = size ? size : sizeof(struct nouveau_object *); 271 obj->length = size ? size : sizeof(struct nouveau_object *);
142 if (!(obj->data = malloc(obj->length))) 272 if (!(obj->data = malloc(obj->length)))
@@ -218,7 +348,7 @@ nouveau_drm_new(int fd, struct nouveau_drm **pdrm)
218 drm->version = (ver->version_major << 24) | 348 drm->version = (ver->version_major << 24) |
219 (ver->version_minor << 8) | 349 (ver->version_minor << 8) |
220 ver->version_patchlevel; 350 ver->version_patchlevel;
221 drm->nvif = false; 351 drm->nvif = (drm->version >= 0x01000301);
222 drmFreeVersion(ver); 352 drmFreeVersion(ver);
223 return 0; 353 return 0;
224} 354}
@@ -238,9 +368,11 @@ int
238nouveau_device_new(struct nouveau_object *parent, int32_t oclass, 368nouveau_device_new(struct nouveau_object *parent, int32_t oclass,
239 void *data, uint32_t size, struct nouveau_device **pdev) 369 void *data, uint32_t size, struct nouveau_device **pdev)
240{ 370{
371 struct nv_device_info_v0 info = {};
241 union { 372 union {
242 struct nv_device_v0 v0; 373 struct nv_device_v0 v0;
243 } *args = data; 374 } *args = data;
375 uint32_t argc = size;
244 struct nouveau_drm *drm = nouveau_drm(parent); 376 struct nouveau_drm *drm = nouveau_drm(parent);
245 struct nouveau_device_priv *nvdev; 377 struct nouveau_device_priv *nvdev;
246 struct nouveau_device *dev; 378 struct nouveau_device *dev;
@@ -257,6 +389,22 @@ nouveau_device_new(struct nouveau_object *parent, int32_t oclass,
257 dev = *pdev = &nvdev->base; 389 dev = *pdev = &nvdev->base;
258 dev->fd = -1; 390 dev->fd = -1;
259 391
392 if (drm->nvif) {
393 ret = nouveau_object_init(parent, 0, oclass, args, argc,
394 &dev->object);
395 if (ret)
396 goto done;
397
398 info.version = 0;
399
400 ret = nouveau_object_mthd(&dev->object, NV_DEVICE_V0_INFO,
401 &info, sizeof(info));
402 if (ret)
403 goto done;
404
405 nvdev->base.chipset = info.chipset;
406 nvdev->have_bo_usage = true;
407 } else
260 if (args->v0.device == ~0ULL) { 408 if (args->v0.device == ~0ULL) {
261 nvdev->base.object.parent = &drm->client; 409 nvdev->base.object.parent = &drm->client;
262 nvdev->base.object.handle = ~0ULL; 410 nvdev->base.object.handle = ~0ULL;
@@ -333,8 +481,7 @@ nouveau_device_wrap(int fd, int close, struct nouveau_device **pdev)
333 481
334 nvdev = nouveau_device(*pdev); 482 nvdev = nouveau_device(*pdev);
335 nvdev->base.fd = drm->fd; 483 nvdev->base.fd = drm->fd;
336 nvdev->base.drm_version = drm->drm_version; 484 nvdev->base.drm_version = drm->version;
337 nvdev->base.lib_version = drm->lib_version;
338 nvdev->close = close; 485 nvdev->close = close;
339 return 0; 486 return 0;
340} 487}