2 * Copyright 2007 Nouveau Project
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 #include "nouveau_drmif.h"
29 #include "nouveau_dma.h"
30 #include "nouveau_local.h"
33 nouveau_mem_free(struct nouveau_device
*dev
, struct drm_nouveau_mem_alloc
*ma
,
36 struct nouveau_device_priv
*nvdev
= nouveau_device(dev
);
37 struct drm_nouveau_mem_free mf
;
40 drmUnmap(*map
, ma
->size
);
45 mf
.offset
= ma
->offset
;
47 drmCommandWrite(nvdev
->fd
, DRM_NOUVEAU_MEM_FREE
,
54 nouveau_mem_alloc(struct nouveau_device
*dev
, unsigned size
, unsigned align
,
55 uint32_t flags
, struct drm_nouveau_mem_alloc
*ma
, void **map
)
57 struct nouveau_device_priv
*nvdev
= nouveau_device(dev
);
60 ma
->alignment
= align
;
64 ma
->flags
|= NOUVEAU_MEM_MAPPED
;
65 ret
= drmCommandWriteRead(nvdev
->fd
, DRM_NOUVEAU_MEM_ALLOC
, ma
,
66 sizeof(struct drm_nouveau_mem_alloc
));
71 ret
= drmMap(nvdev
->fd
, ma
->map_handle
, ma
->size
, map
);
74 nouveau_mem_free(dev
, ma
, map
);
83 nouveau_bo_tmp_del(void *priv
)
85 struct nouveau_resource
*r
= priv
;
87 nouveau_fence_ref(NULL
, (struct nouveau_fence
**)&r
->priv
);
88 nouveau_resource_free(&r
);
91 static struct nouveau_resource
*
92 nouveau_bo_tmp(struct nouveau_channel
*chan
, unsigned size
,
93 struct nouveau_fence
*fence
)
95 struct nouveau_device_priv
*nvdev
= nouveau_device(chan
->device
);
96 struct nouveau_resource
*r
= NULL
;
97 struct nouveau_fence
*ref
= NULL
;
100 nouveau_fence_ref(fence
, &ref
);
102 nouveau_fence_new(chan
, &ref
);
105 while (nouveau_resource_alloc(nvdev
->sa_heap
, size
, ref
, &r
)) {
106 nouveau_fence_flush(chan
);
108 nouveau_fence_signal_cb(ref
, nouveau_bo_tmp_del
, r
);
114 nouveau_bo_init(struct nouveau_device
*dev
)
116 struct nouveau_device_priv
*nvdev
= nouveau_device(dev
);
119 ret
= nouveau_mem_alloc(dev
, 128*1024, 0, NOUVEAU_MEM_AGP
|
120 NOUVEAU_MEM_PCI
, &nvdev
->sa
, &nvdev
->sa_map
);
124 ret
= nouveau_resource_init(&nvdev
->sa_heap
, 0, nvdev
->sa
.size
);
126 nouveau_mem_free(dev
, &nvdev
->sa
, &nvdev
->sa_map
);
134 nouveau_bo_takedown(struct nouveau_device
*dev
)
136 struct nouveau_device_priv
*nvdev
= nouveau_device(dev
);
138 nouveau_mem_free(dev
, &nvdev
->sa
, &nvdev
->sa_map
);
142 nouveau_bo_new(struct nouveau_device
*dev
, uint32_t flags
, int align
,
143 int size
, struct nouveau_bo
**bo
)
145 struct nouveau_bo_priv
*nvbo
;
148 if (!dev
|| !bo
|| *bo
)
151 nvbo
= calloc(1, sizeof(struct nouveau_bo_priv
));
154 nvbo
->base
.device
= dev
;
155 nvbo
->base
.size
= size
;
156 nvbo
->base
.handle
= bo_to_ptr(nvbo
);
157 nvbo
->drm
.alignment
= align
;
160 ret
= nouveau_bo_set_status(&nvbo
->base
, flags
);
171 nouveau_bo_user(struct nouveau_device
*dev
, void *ptr
, int size
,
172 struct nouveau_bo
**bo
)
174 struct nouveau_bo_priv
*nvbo
;
176 if (!dev
|| !bo
|| *bo
)
179 nvbo
= calloc(1, sizeof(*nvbo
));
182 nvbo
->base
.device
= dev
;
187 nvbo
->base
.size
= size
;
188 nvbo
->base
.offset
= nvbo
->drm
.offset
;
189 nvbo
->base
.handle
= bo_to_ptr(nvbo
);
196 nouveau_bo_ref(struct nouveau_device
*dev
, uint64_t handle
,
197 struct nouveau_bo
**bo
)
199 struct nouveau_bo_priv
*nvbo
= ptr_to_bo(handle
);
201 if (!dev
|| !bo
|| *bo
)
210 nouveau_bo_del(struct nouveau_bo
**bo
)
212 struct nouveau_bo_priv
*nvbo
;
216 nvbo
= nouveau_bo(*bo
);
219 if (--nvbo
->refcount
)
223 nouveau_fence_wait(&nvbo
->fence
);
224 nouveau_mem_free(nvbo
->base
.device
, &nvbo
->drm
, &nvbo
->map
);
225 if (nvbo
->sysmem
&& !nvbo
->user
)
231 nouveau_bo_map(struct nouveau_bo
*bo
, uint32_t flags
)
233 struct nouveau_bo_priv
*nvbo
= nouveau_bo(bo
);
238 if (flags
& NOUVEAU_BO_WR
)
239 nouveau_fence_wait(&nvbo
->fence
);
241 nouveau_fence_wait(&nvbo
->wr_fence
);
244 bo
->map
= nvbo
->sysmem
;
251 nouveau_bo_unmap(struct nouveau_bo
*bo
)
257 nouveau_bo_upload(struct nouveau_bo_priv
*nvbo
)
260 nouveau_fence_wait(&nvbo
->fence
);
261 memcpy(nvbo
->map
, nvbo
->sysmem
, nvbo
->drm
.size
);
266 nouveau_bo_set_status(struct nouveau_bo
*bo
, uint32_t flags
)
268 struct nouveau_bo_priv
*nvbo
= nouveau_bo(bo
);
269 struct drm_nouveau_mem_alloc
new;
270 void *new_map
= NULL
, *new_sysmem
= NULL
;
271 unsigned new_flags
= 0, ret
;
275 /* Check current memtype vs requested, if they match do nothing */
276 if ((nvbo
->drm
.flags
& NOUVEAU_MEM_FB
) && (flags
& NOUVEAU_BO_VRAM
))
278 if ((nvbo
->drm
.flags
& NOUVEAU_MEM_AGP
) && (flags
& NOUVEAU_BO_GART
))
280 if (nvbo
->drm
.size
== 0 && nvbo
->sysmem
&& (flags
& NOUVEAU_BO_LOCAL
))
283 memset(&new, 0x00, sizeof(new));
285 /* Allocate new memory */
286 if (flags
& NOUVEAU_BO_VRAM
)
287 new_flags
|= NOUVEAU_MEM_FB
;
289 if (flags
& NOUVEAU_BO_GART
)
290 new_flags
|= (NOUVEAU_MEM_AGP
| NOUVEAU_MEM_PCI
);
293 ret
= nouveau_mem_alloc(bo
->device
, bo
->size
,
294 nvbo
->drm
.alignment
, new_flags
,
299 new_sysmem
= malloc(bo
->size
);
302 /* Copy old -> new */
304 if (nvbo
->sysmem
|| nvbo
->map
) {
305 nouveau_bo_map(bo
, NOUVEAU_BO_RD
);
306 memcpy(new_map
, bo
->map
, bo
->size
);
307 nouveau_bo_unmap(bo
);
310 /* Free old memory */
312 nouveau_fence_wait(&nvbo
->fence
);
313 nouveau_mem_free(bo
->device
, &nvbo
->drm
, &nvbo
->map
);
319 nvbo
->sysmem
= new_sysmem
;
321 bo
->offset
= nvbo
->drm
.offset
;
326 nouveau_bo_validate_user(struct nouveau_channel
*chan
, struct nouveau_bo
*bo
,
327 struct nouveau_fence
*fence
, uint32_t flags
)
329 struct nouveau_channel_priv
*nvchan
= nouveau_channel(chan
);
330 struct nouveau_device_priv
*nvdev
= nouveau_device(chan
->device
);
331 struct nouveau_bo_priv
*nvbo
= nouveau_bo(bo
);
332 struct nouveau_resource
*r
;
334 if (nvchan
->user_charge
+ bo
->size
> nvdev
->sa
.size
)
336 nvchan
->user_charge
+= bo
->size
;
338 if (!(flags
& NOUVEAU_BO_GART
))
341 r
= nouveau_bo_tmp(chan
, bo
->size
, fence
);
345 memcpy(nvdev
->sa_map
+ r
->start
, nvbo
->sysmem
, bo
->size
);
347 nvbo
->offset
= nvdev
->sa
.offset
+ r
->start
;
348 nvbo
->flags
= NOUVEAU_BO_GART
;
353 nouveau_bo_validate_bo(struct nouveau_channel
*chan
, struct nouveau_bo
*bo
,
354 struct nouveau_fence
*fence
, uint32_t flags
)
356 struct nouveau_bo_priv
*nvbo
= nouveau_bo(bo
);
359 ret
= nouveau_bo_set_status(bo
, flags
);
364 nouveau_bo_upload(nvbo
);
366 nvbo
->offset
= nvbo
->drm
.offset
;
367 if (nvbo
->drm
.flags
& (NOUVEAU_MEM_AGP
| NOUVEAU_MEM_PCI
))
368 nvbo
->flags
= NOUVEAU_BO_GART
;
370 nvbo
->flags
= NOUVEAU_BO_VRAM
;
376 nouveau_bo_validate(struct nouveau_channel
*chan
, struct nouveau_bo
*bo
,
377 struct nouveau_fence
*fence
, uint32_t flags
)
379 struct nouveau_bo_priv
*nvbo
= nouveau_bo(bo
);
382 assert(bo
->map
== NULL
);
385 ret
= nouveau_bo_validate_user(chan
, bo
, fence
, flags
);
387 ret
= nouveau_bo_validate_bo(chan
, bo
, fence
, flags
);
392 ret
= nouveau_bo_validate_bo(chan
, bo
, fence
, flags
);
397 if (flags
& NOUVEAU_BO_WR
)
398 nouveau_fence_ref(fence
, &nvbo
->wr_fence
);
399 nouveau_fence_ref(fence
, &nvbo
->fence
);