aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Skeggs2015-11-23 17:17:52 -0600
committerBen Skeggs2015-12-21 21:21:56 -0600
commit4a3cbf5c0a38adf41d637c5d7273480336df39d0 (patch)
treebb07ba39db1d77bf2c86c1d9d76dbe0474f575d6 /nouveau
parentd1ec093e4c5b08c3825fe07e287aa3d023e9c9ae (diff)
downloadexternal-libgbm-4a3cbf5c0a38adf41d637c5d7273480336df39d0.tar.gz
external-libgbm-4a3cbf5c0a38adf41d637c5d7273480336df39d0.tar.xz
external-libgbm-4a3cbf5c0a38adf41d637c5d7273480336df39d0.zip
nouveau: move more abi16-specific logic into abi16.c
v2. - add a comment about the (ab)use of nouveau_object::length - add a comment about abi16_object() return values v3. - handle new client + old kernel for sw classes 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>
Diffstat (limited to 'nouveau')
-rw-r--r--nouveau/abi16.c88
-rw-r--r--nouveau/nouveau.c56
-rw-r--r--nouveau/private.h7
3 files changed, 93 insertions, 58 deletions
diff --git a/nouveau/abi16.c b/nouveau/abi16.c
index 59bc4360..44fda645 100644
--- a/nouveau/abi16.c
+++ b/nouveau/abi16.c
@@ -32,8 +32,10 @@
32 32
33#include "private.h" 33#include "private.h"
34 34
35#include "nvif/class.h"
35 36
36drm_private int 37
38static int
37abi16_chan_nv04(struct nouveau_object *obj) 39abi16_chan_nv04(struct nouveau_object *obj)
38{ 40{
39 struct nouveau_device *dev = (struct nouveau_device *)obj->parent; 41 struct nouveau_device *dev = (struct nouveau_device *)obj->parent;
@@ -57,7 +59,7 @@ abi16_chan_nv04(struct nouveau_object *obj)
57 return 0; 59 return 0;
58} 60}
59 61
60drm_private int 62static int
61abi16_chan_nvc0(struct nouveau_object *obj) 63abi16_chan_nvc0(struct nouveau_object *obj)
62{ 64{
63 struct nouveau_device *dev = (struct nouveau_device *)obj->parent; 65 struct nouveau_device *dev = (struct nouveau_device *)obj->parent;
@@ -78,7 +80,7 @@ abi16_chan_nvc0(struct nouveau_object *obj)
78 return 0; 80 return 0;
79} 81}
80 82
81drm_private int 83static int
82abi16_chan_nve0(struct nouveau_object *obj) 84abi16_chan_nve0(struct nouveau_object *obj)
83{ 85{
84 struct nouveau_device *dev = (struct nouveau_device *)obj->parent; 86 struct nouveau_device *dev = (struct nouveau_device *)obj->parent;
@@ -104,7 +106,7 @@ abi16_chan_nve0(struct nouveau_object *obj)
104 return 0; 106 return 0;
105} 107}
106 108
107drm_private int 109static int
108abi16_engobj(struct nouveau_object *obj) 110abi16_engobj(struct nouveau_object *obj)
109{ 111{
110 struct drm_nouveau_grobj_alloc req = { 112 struct drm_nouveau_grobj_alloc req = {
@@ -115,6 +117,27 @@ abi16_engobj(struct nouveau_object *obj)
115 struct nouveau_device *dev; 117 struct nouveau_device *dev;
116 int ret; 118 int ret;
117 119
120 /* Older kernel versions did not have the concept of nouveau-
121 * specific classes and abused some NVIDIA-assigned ones for
122 * a SW class. The ABI16 layer has compatibility in place to
123 * translate these older identifiers to the newer ones.
124 *
125 * Clients that have been updated to use NVIF are required to
126 * use the newer class identifiers, which means that they'll
127 * break if running on an older kernel.
128 *
129 * To handle this case, when using ABI16, we translate to the
130 * older values which work on any kernel.
131 */
132 switch (req.class) {
133 case NVIF_CLASS_SW_NV04 : req.class = 0x006e; break;
134 case NVIF_CLASS_SW_NV10 : req.class = 0x016e; break;
135 case NVIF_CLASS_SW_NV50 : req.class = 0x506e; break;
136 case NVIF_CLASS_SW_GF100: req.class = 0x906e; break;
137 default:
138 break;
139 }
140
118 dev = nouveau_object_find(obj, NOUVEAU_DEVICE_CLASS); 141 dev = nouveau_object_find(obj, NOUVEAU_DEVICE_CLASS);
119 ret = drmCommandWrite(dev->fd, DRM_NOUVEAU_GROBJ_ALLOC, 142 ret = drmCommandWrite(dev->fd, DRM_NOUVEAU_GROBJ_ALLOC,
120 &req, sizeof(req)); 143 &req, sizeof(req));
@@ -125,7 +148,7 @@ abi16_engobj(struct nouveau_object *obj)
125 return 0; 148 return 0;
126} 149}
127 150
128drm_private int 151static int
129abi16_ntfy(struct nouveau_object *obj) 152abi16_ntfy(struct nouveau_object *obj)
130{ 153{
131 struct nv04_notify *ntfy = obj->data; 154 struct nv04_notify *ntfy = obj->data;
@@ -149,6 +172,61 @@ abi16_ntfy(struct nouveau_object *obj)
149} 172}
150 173
151drm_private void 174drm_private void
175abi16_delete(struct nouveau_object *obj)
176{
177 struct nouveau_device *dev =
178 nouveau_object_find(obj, NOUVEAU_DEVICE_CLASS);
179 if (obj->oclass == NOUVEAU_FIFO_CHANNEL_CLASS) {
180 struct drm_nouveau_channel_free req;
181 req.channel = obj->handle;
182 drmCommandWrite(dev->fd, DRM_NOUVEAU_CHANNEL_FREE,
183 &req, sizeof(req));
184 } else {
185 struct drm_nouveau_gpuobj_free req;
186 req.channel = obj->parent->handle;
187 req.handle = obj->handle;
188 drmCommandWrite(dev->fd, DRM_NOUVEAU_GPUOBJ_FREE,
189 &req, sizeof(req));
190 }
191}
192
193drm_private bool
194abi16_object(struct nouveau_object *obj, int (**func)(struct nouveau_object *))
195{
196 struct nouveau_object *parent = obj->parent;
197
198 /* nouveau_object::length is (ab)used to determine whether the
199 * object is a legacy object (!=0), or a real NVIF object.
200 */
201 if ((parent->length != 0 && parent->oclass == NOUVEAU_DEVICE_CLASS)) {
202 if (obj->oclass == NOUVEAU_FIFO_CHANNEL_CLASS) {
203 struct nouveau_device *dev = (void *)parent;
204 if (dev->chipset < 0xc0)
205 *func = abi16_chan_nv04;
206 else
207 if (dev->chipset < 0xe0)
208 *func = abi16_chan_nvc0;
209 else
210 *func = abi16_chan_nve0;
211 return true;
212 }
213 } else
214 if ((parent->length != 0 &&
215 parent->oclass == NOUVEAU_FIFO_CHANNEL_CLASS)) {
216 if (obj->oclass == NOUVEAU_NOTIFIER_CLASS) {
217 *func = abi16_ntfy;
218 return true;
219 }
220
221 *func = abi16_engobj;
222 return false; /* try NVIF, if supported, before calling func */
223 }
224
225 *func = NULL;
226 return false;
227}
228
229drm_private void
152abi16_bo_info(struct nouveau_bo *bo, struct drm_nouveau_gem_info *info) 230abi16_bo_info(struct nouveau_bo *bo, struct drm_nouveau_gem_info *info)
153{ 231{
154 struct nouveau_bo_priv *nvbo = nouveau_bo(bo); 232 struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
diff --git a/nouveau/nouveau.c b/nouveau/nouveau.c
index 97fd77b9..8a0be2fa 100644
--- a/nouveau/nouveau.c
+++ b/nouveau/nouveau.c
@@ -135,6 +135,7 @@ nouveau_device_wrap(int fd, int close, struct nouveau_device **pdev)
135 nvdev->gart_limit_percent = 80; 135 nvdev->gart_limit_percent = 80;
136 DRMINITLISTHEAD(&nvdev->bo_list); 136 DRMINITLISTHEAD(&nvdev->bo_list);
137 nvdev->base.object.oclass = NOUVEAU_DEVICE_CLASS; 137 nvdev->base.object.oclass = NOUVEAU_DEVICE_CLASS;
138 nvdev->base.object.length = ~0;
138 nvdev->base.lib_version = 0x01000000; 139 nvdev->base.lib_version = 0x01000000;
139 nvdev->base.chipset = chipset; 140 nvdev->base.chipset = chipset;
140 nvdev->base.vram_size = vram; 141 nvdev->base.vram_size = vram;
@@ -251,8 +252,8 @@ nouveau_object_new(struct nouveau_object *parent, uint64_t handle,
251 uint32_t oclass, void *data, uint32_t length, 252 uint32_t oclass, void *data, uint32_t length,
252 struct nouveau_object **pobj) 253 struct nouveau_object **pobj)
253{ 254{
254 struct nouveau_device *dev;
255 struct nouveau_object *obj; 255 struct nouveau_object *obj;
256 int (*func)(struct nouveau_object *);
256 int ret = -EINVAL; 257 int ret = -EINVAL;
257 258
258 if (length == 0) 259 if (length == 0)
@@ -267,37 +268,9 @@ nouveau_object_new(struct nouveau_object *parent, uint64_t handle,
267 memcpy(obj->data, data, length); 268 memcpy(obj->data, data, length);
268 *(struct nouveau_object **)obj->data = obj; 269 *(struct nouveau_object **)obj->data = obj;
269 270
270 dev = nouveau_object_find(obj, NOUVEAU_DEVICE_CLASS); 271 abi16_object(obj, &func);
271 switch (parent->oclass) { 272 if (func)
272 case NOUVEAU_DEVICE_CLASS: 273 ret = func(obj);
273 switch (obj->oclass) {
274 case NOUVEAU_FIFO_CHANNEL_CLASS:
275 {
276 if (dev->chipset < 0xc0)
277 ret = abi16_chan_nv04(obj);
278 else
279 if (dev->chipset < 0xe0)
280 ret = abi16_chan_nvc0(obj);
281 else
282 ret = abi16_chan_nve0(obj);
283 }
284 break;
285 default:
286 break;
287 }
288 break;
289 case NOUVEAU_FIFO_CHANNEL_CLASS:
290 switch (obj->oclass) {
291 case NOUVEAU_NOTIFIER_CLASS:
292 ret = abi16_ntfy(obj);
293 break;
294 default:
295 ret = abi16_engobj(obj);
296 break;
297 }
298 default:
299 break;
300 }
301 274
302 if (ret) { 275 if (ret) {
303 free(obj); 276 free(obj);
@@ -312,24 +285,11 @@ void
312nouveau_object_del(struct nouveau_object **pobj) 285nouveau_object_del(struct nouveau_object **pobj)
313{ 286{
314 struct nouveau_object *obj = *pobj; 287 struct nouveau_object *obj = *pobj;
315 struct nouveau_device *dev;
316 if (obj) { 288 if (obj) {
317 dev = nouveau_object_find(obj, NOUVEAU_DEVICE_CLASS); 289 abi16_delete(obj);
318 if (obj->oclass == NOUVEAU_FIFO_CHANNEL_CLASS) { 290 free(obj);
319 struct drm_nouveau_channel_free req; 291 *pobj = NULL;
320 req.channel = obj->handle;
321 drmCommandWrite(dev->fd, DRM_NOUVEAU_CHANNEL_FREE,
322 &req, sizeof(req));
323 } else {
324 struct drm_nouveau_gpuobj_free req;
325 req.channel = obj->parent->handle;
326 req.handle = obj->handle;
327 drmCommandWrite(dev->fd, DRM_NOUVEAU_GPUOBJ_FREE,
328 &req, sizeof(req));
329 }
330 } 292 }
331 free(obj);
332 *pobj = NULL;
333} 293}
334 294
335void * 295void *
diff --git a/nouveau/private.h b/nouveau/private.h
index e9439f30..5f352a49 100644
--- a/nouveau/private.h
+++ b/nouveau/private.h
@@ -114,11 +114,8 @@ int
114nouveau_device_open_existing(struct nouveau_device **, int, int, drm_context_t); 114nouveau_device_open_existing(struct nouveau_device **, int, int, drm_context_t);
115 115
116/* abi16.c */ 116/* abi16.c */
117drm_private int abi16_chan_nv04(struct nouveau_object *); 117drm_private bool abi16_object(struct nouveau_object *, int (**)(struct nouveau_object *));
118drm_private int abi16_chan_nvc0(struct nouveau_object *); 118drm_private void abi16_delete(struct nouveau_object *);
119drm_private int abi16_chan_nve0(struct nouveau_object *);
120drm_private int abi16_engobj(struct nouveau_object *);
121drm_private int abi16_ntfy(struct nouveau_object *);
122drm_private void abi16_bo_info(struct nouveau_bo *, struct drm_nouveau_gem_info *); 119drm_private void abi16_bo_info(struct nouveau_bo *, struct drm_nouveau_gem_info *);
123drm_private int abi16_bo_init(struct nouveau_bo *, uint32_t alignment, 120drm_private int abi16_bo_init(struct nouveau_bo *, uint32_t alignment,
124 union nouveau_bo_config *); 121 union nouveau_bo_config *);