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
27 #include "nouveau_private.h"
30 nouveau_channel_alloc(struct nouveau_device
*dev
, uint32_t fb_ctxdma
,
31 uint32_t tt_ctxdma
, struct nouveau_channel
**chan
)
33 struct nouveau_device_priv
*nvdev
= nouveau_device(dev
);
34 struct nouveau_channel_priv
*nvchan
;
38 if (!nvdev
|| !chan
|| *chan
)
41 nvchan
= calloc(1, sizeof(struct nouveau_channel_priv
));
44 nvchan
->base
.device
= dev
;
46 nvchan
->drm
.fb_ctxdma_handle
= fb_ctxdma
;
47 nvchan
->drm
.tt_ctxdma_handle
= tt_ctxdma
;
48 ret
= drmCommandWriteRead(nvdev
->fd
, DRM_NOUVEAU_CHANNEL_ALLOC
,
49 &nvchan
->drm
, sizeof(nvchan
->drm
));
55 nvchan
->base
.id
= nvchan
->drm
.channel
;
56 if (nouveau_grobj_ref(&nvchan
->base
, nvchan
->drm
.fb_ctxdma_handle
,
57 &nvchan
->base
.vram
) ||
58 nouveau_grobj_ref(&nvchan
->base
, nvchan
->drm
.tt_ctxdma_handle
,
59 &nvchan
->base
.gart
)) {
60 nouveau_channel_free((void *)&nvchan
);
64 /* Mark all DRM-assigned subchannels as in-use */
65 for (i
= 0; i
< nvchan
->drm
.nr_subchan
; i
++) {
66 struct nouveau_grobj_priv
*gr
= calloc(1, sizeof(*gr
));
68 gr
->base
.bound
= NOUVEAU_GROBJ_BOUND_EXPLICIT
;
70 gr
->base
.handle
= nvchan
->drm
.subchan
[i
].handle
;
71 gr
->base
.grclass
= nvchan
->drm
.subchan
[i
].grclass
;
72 gr
->base
.channel
= &nvchan
->base
;
74 nvchan
->base
.subc
[i
].gr
= &gr
->base
;
77 ret
= drmMap(nvdev
->fd
, nvchan
->drm
.notifier
, nvchan
->drm
.notifier_size
,
78 (drmAddressPtr
)&nvchan
->notifier_block
);
80 nouveau_channel_free((void *)&nvchan
);
84 ret
= nouveau_grobj_alloc(&nvchan
->base
, 0x00000000, 0x0030,
85 &nvchan
->base
.nullobj
);
87 nouveau_channel_free((void *)&nvchan
);
91 if (!nvdev
->mm_enabled
) {
92 ret
= drmMap(nvdev
->fd
, nvchan
->drm
.ctrl
, nvchan
->drm
.ctrl_size
,
93 (void*)&nvchan
->user
);
95 nouveau_channel_free((void *)&nvchan
);
98 nvchan
->put
= &nvchan
->user
[0x40/4];
99 nvchan
->get
= &nvchan
->user
[0x44/4];
100 nvchan
->ref_cnt
= &nvchan
->user
[0x48/4];
102 ret
= drmMap(nvdev
->fd
, nvchan
->drm
.cmdbuf
,
103 nvchan
->drm
.cmdbuf_size
, (void*)&nvchan
->pushbuf
);
105 nouveau_channel_free((void *)&nvchan
);
109 nouveau_dma_channel_init(&nvchan
->base
);
112 nouveau_pushbuf_init(&nvchan
->base
);
114 if (!nvdev
->mm_enabled
&& dev
->chipset
< 0x10) {
115 ret
= nouveau_grobj_alloc(&nvchan
->base
, 0xbeef3904, 0x5039,
116 &nvchan
->fence_grobj
);
118 nouveau_channel_free((void *)&nvchan
);
122 ret
= nouveau_notifier_alloc(&nvchan
->base
, 0xbeef3905, 1,
123 &nvchan
->fence_ntfy
);
125 nouveau_channel_free((void *)&nvchan
);
129 BEGIN_RING(&nvchan
->base
, nvchan
->fence_grobj
, 0x0180, 1);
130 OUT_RING (&nvchan
->base
, nvchan
->fence_ntfy
->handle
);
131 nvchan
->fence_grobj
->bound
= NOUVEAU_GROBJ_BOUND_EXPLICIT
;
134 *chan
= &nvchan
->base
;
139 nouveau_channel_free(struct nouveau_channel
**chan
)
141 struct nouveau_channel_priv
*nvchan
;
142 struct nouveau_device_priv
*nvdev
;
143 struct drm_nouveau_channel_free cf
;
147 nvchan
= nouveau_channel(*chan
);
149 nvdev
= nouveau_device(nvchan
->base
.device
);
151 FIRE_RING(&nvchan
->base
);
153 if (!nvdev
->mm_enabled
) {
154 struct nouveau_fence
*fence
= NULL
;
156 /* Make sure all buffer objects on delayed delete queue
157 * actually get freed.
159 nouveau_fence_new(&nvchan
->base
, &fence
);
160 nouveau_fence_emit(fence
);
161 nouveau_fence_wait(&fence
);
164 if (nvchan
->notifier_block
)
165 drmUnmap(nvchan
->notifier_block
, nvchan
->drm
.notifier_size
);
167 nouveau_grobj_free(&nvchan
->base
.vram
);
168 nouveau_grobj_free(&nvchan
->base
.gart
);
169 nouveau_grobj_free(&nvchan
->base
.nullobj
);
170 nouveau_grobj_free(&nvchan
->fence_grobj
);
171 nouveau_notifier_free(&nvchan
->fence_ntfy
);
173 cf
.channel
= nvchan
->drm
.channel
;
174 drmCommandWrite(nvdev
->fd
, DRM_NOUVEAU_CHANNEL_FREE
, &cf
, sizeof(cf
));