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_realloc_gpu(struct nouveau_bo_priv
*nvbo
, uint32_t flags
, int size
)
87 if (nvbo
->drm
.size
&& nvbo
->drm
.size
!= size
) {
88 nouveau_mem_free(nvbo
->base
.device
, &nvbo
->drm
, &nvbo
->map
);
91 if (size
&& !nvbo
->drm
.size
) {
94 if (flags
& NOUVEAU_BO_VRAM
)
95 nvbo
->drm
.flags
|= NOUVEAU_MEM_FB
;
96 if (flags
& NOUVEAU_BO_GART
)
97 nvbo
->drm
.flags
|= (NOUVEAU_MEM_AGP
|
99 nvbo
->drm
.flags
|= NOUVEAU_MEM_MAPPED
;
102 ret
= nouveau_mem_alloc(nvbo
->base
.device
, size
,
103 nvbo
->drm
.alignment
, nvbo
->drm
.flags
,
104 &nvbo
->drm
, &nvbo
->map
);
114 nouveau_bo_tmp_del(void *priv
)
116 struct nouveau_resource
*r
= priv
;
118 nouveau_fence_ref(NULL
, (struct nouveau_fence
**)&r
->priv
);
119 nouveau_resource_free(&r
);
122 static struct nouveau_resource
*
123 nouveau_bo_tmp(struct nouveau_channel
*chan
, unsigned size
,
124 struct nouveau_fence
*fence
)
126 struct nouveau_device_priv
*nvdev
= nouveau_device(chan
->device
);
127 struct nouveau_resource
*r
= NULL
;
128 struct nouveau_fence
*ref
= NULL
;
131 nouveau_fence_ref(fence
, &ref
);
133 nouveau_fence_new(chan
, &ref
);
136 while (nouveau_resource_alloc(nvdev
->sa_heap
, size
, ref
, &r
)) {
137 nouveau_fence_flush(chan
);
139 nouveau_fence_signal_cb(ref
, nouveau_bo_tmp_del
, r
);
145 nouveau_bo_init(struct nouveau_device
*dev
)
147 struct nouveau_device_priv
*nvdev
= nouveau_device(dev
);
150 ret
= nouveau_mem_alloc(dev
, 128*1024, 0, NOUVEAU_MEM_AGP
|
151 NOUVEAU_MEM_PCI
, &nvdev
->sa
, &nvdev
->sa_map
);
155 ret
= nouveau_resource_init(&nvdev
->sa_heap
, 0, nvdev
->sa
.size
);
157 nouveau_mem_free(dev
, &nvdev
->sa
, &nvdev
->sa_map
);
165 nouveau_bo_takedown(struct nouveau_device
*dev
)
167 struct nouveau_device_priv
*nvdev
= nouveau_device(dev
);
169 nouveau_mem_free(dev
, &nvdev
->sa
, &nvdev
->sa_map
);
173 nouveau_bo_new(struct nouveau_device
*dev
, uint32_t flags
, int align
,
174 int size
, struct nouveau_bo
**bo
)
176 struct nouveau_bo_priv
*nvbo
;
179 if (!dev
|| !bo
|| *bo
)
182 nvbo
= calloc(1, sizeof(struct nouveau_bo_priv
));
185 nvbo
->base
.device
= dev
;
186 nvbo
->drm
.alignment
= align
;
188 if (flags
& NOUVEAU_BO_PIN
) {
189 ret
= nouveau_bo_realloc_gpu(nvbo
, flags
, size
);
195 nvbo
->sysmem
= malloc(size
);
202 nvbo
->base
.size
= size
;
203 nvbo
->base
.offset
= nvbo
->drm
.offset
;
204 nvbo
->base
.handle
= bo_to_ptr(nvbo
);
211 nouveau_bo_user(struct nouveau_device
*dev
, void *ptr
, int size
,
212 struct nouveau_bo
**bo
)
214 struct nouveau_bo_priv
*nvbo
;
216 if (!dev
|| !bo
|| *bo
)
219 nvbo
= calloc(1, sizeof(*nvbo
));
222 nvbo
->base
.device
= dev
;
227 nvbo
->base
.size
= size
;
228 nvbo
->base
.offset
= nvbo
->drm
.offset
;
229 nvbo
->base
.handle
= bo_to_ptr(nvbo
);
236 nouveau_bo_ref(struct nouveau_device
*dev
, uint64_t handle
,
237 struct nouveau_bo
**bo
)
239 struct nouveau_bo_priv
*nvbo
= ptr_to_bo(handle
);
241 if (!dev
|| !bo
|| *bo
)
250 nouveau_bo_resize(struct nouveau_bo
*bo
, int size
)
252 struct nouveau_bo_priv
*nvbo
= nouveau_bo(bo
);
255 if (!nvbo
|| nvbo
->user
)
259 nvbo
->sysmem
= realloc(nvbo
->sysmem
, size
);
263 ret
= nouveau_bo_realloc_gpu(nvbo
, 0, size
);
268 nvbo
->base
.size
= size
;
273 nouveau_bo_del(struct nouveau_bo
**bo
)
275 struct nouveau_bo_priv
*nvbo
;
279 nvbo
= nouveau_bo(*bo
);
282 if (--nvbo
->refcount
)
286 nouveau_fence_wait(&nvbo
->fence
);
288 nouveau_bo_realloc_gpu(nvbo
, 0, 0);
289 if (nvbo
->sysmem
&& !nvbo
->user
)
295 nouveau_bo_map(struct nouveau_bo
*bo
, uint32_t flags
)
297 struct nouveau_bo_priv
*nvbo
= nouveau_bo(bo
);
302 if (flags
& NOUVEAU_BO_WR
)
303 nouveau_fence_wait(&nvbo
->fence
);
305 nouveau_fence_wait(&nvbo
->wr_fence
);
308 bo
->map
= nvbo
->sysmem
;
315 nouveau_bo_unmap(struct nouveau_bo
*bo
)
321 nouveau_bo_upload(struct nouveau_bo_priv
*nvbo
)
324 nouveau_fence_wait(&nvbo
->fence
);
325 memcpy(nvbo
->map
, nvbo
->sysmem
, nvbo
->drm
.size
);
330 nouveau_bo_validate_user(struct nouveau_channel
*chan
, struct nouveau_bo
*bo
,
331 struct nouveau_fence
*fence
, uint32_t flags
)
333 struct nouveau_channel_priv
*nvchan
= nouveau_channel(chan
);
334 struct nouveau_device_priv
*nvdev
= nouveau_device(chan
->device
);
335 struct nouveau_bo_priv
*nvbo
= nouveau_bo(bo
);
336 struct nouveau_resource
*r
;
338 if (nvchan
->user_charge
+ bo
->size
> nvdev
->sa
.size
)
340 nvchan
->user_charge
+= bo
->size
;
342 if (!(flags
& NOUVEAU_BO_GART
))
345 r
= nouveau_bo_tmp(chan
, bo
->size
, fence
);
349 memcpy(nvdev
->sa_map
+ r
->start
, nvbo
->sysmem
, bo
->size
);
351 nvbo
->offset
= nvdev
->sa
.offset
+ r
->start
;
352 nvbo
->flags
= NOUVEAU_BO_GART
;
357 nouveau_bo_validate_bo(struct nouveau_channel
*chan
, struct nouveau_bo
*bo
,
358 struct nouveau_fence
*fence
, uint32_t flags
)
360 struct nouveau_bo_priv
*nvbo
= nouveau_bo(bo
);
362 if (!nvbo
->drm
.size
) {
363 nouveau_bo_realloc_gpu(nvbo
, flags
, nvbo
->base
.size
);
364 nouveau_bo_upload(nvbo
);
371 nouveau_bo_upload(nvbo
);
374 nvbo
->offset
= nvbo
->drm
.offset
;
375 if (nvbo
->drm
.flags
& (NOUVEAU_MEM_AGP
| NOUVEAU_MEM_PCI
))
376 nvbo
->flags
= NOUVEAU_BO_GART
;
378 nvbo
->flags
= NOUVEAU_BO_VRAM
;
384 nouveau_bo_validate(struct nouveau_channel
*chan
, struct nouveau_bo
*bo
,
385 struct nouveau_fence
*fence
, uint32_t flags
)
387 struct nouveau_bo_priv
*nvbo
= nouveau_bo(bo
);
390 assert(bo
->map
== NULL
);
393 ret
= nouveau_bo_validate_user(chan
, bo
, fence
, flags
);
395 ret
= nouveau_bo_validate_bo(chan
, bo
, fence
, flags
);
400 ret
= nouveau_bo_validate_bo(chan
, bo
, fence
, flags
);
405 if (flags
& NOUVEAU_BO_WR
)
406 nouveau_fence_ref(fence
, &nvbo
->wr_fence
);
407 nouveau_fence_ref(fence
, &nvbo
->fence
);