diff options
author | Ben Skeggs | 2015-11-23 21:08:21 -0600 |
---|---|---|
committer | Ben Skeggs | 2015-12-21 21:22:35 -0600 |
commit | 4291eea18fd81ca084935fb09a0e97a6661f4f85 (patch) | |
tree | 92023726dbce1d42a4fa03d75f987b382385255a | |
parent | 4c92a9d70725ec393899979bbfc21a37684e88d9 (diff) | |
download | external-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.c | 3 | ||||
-rw-r--r-- | nouveau/nouveau.c | 159 |
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 | ||
67 | static int | ||
68 | nouveau_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 | |||
66 | int | 95 | int |
67 | nouveau_object_mthd(struct nouveau_object *obj, | 96 | nouveau_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 | ||
73 | void | 130 | void |
@@ -81,7 +138,50 @@ int | |||
81 | nouveau_object_sclass_get(struct nouveau_object *obj, | 138 | nouveau_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 | ||
87 | int | 187 | int |
@@ -114,12 +214,21 @@ nouveau_object_mclass(struct nouveau_object *obj, | |||
114 | static void | 214 | static void |
115 | nouveau_object_fini(struct nouveau_object *obj) | 215 | nouveau_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 | ||
125 | static int | 234 | static 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 | |||
238 | nouveau_device_new(struct nouveau_object *parent, int32_t oclass, | 368 | nouveau_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 | } |