2 * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
3 * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sub license,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
25 #include <X11/Xlibint.h>
27 #include "savageioctl.h"
28 #include "savagedma.h"
29 #include "savage_bci.h"
33 /* Commit does not depend on whether we use real DMA or fake it via the BCI */
34 void savageDMACommit (savageContextPtr imesa
, void *endPtr
) {
35 DMABufferPtr dmaBuff
= &imesa
->DMABuf
;
36 GLuint end
= (GLuint
)endPtr
;
38 /* make sure that enough space was allocated */
39 assert (end
<= dmaBuff
->allocEnd
);
41 dmaBuff
->allocEnd
= dmaBuff
->end
= end
;
43 /* TODO: check commands, either here or in flush */
48 0 return -1 if no available page
49 1 wait until a page be available */
50 static GLuint
getDMAPage (savageContextPtr imesa
, int flag
) {
51 DMABufferPtr dmaBuff
= &imesa
->DMABuf
;
55 if (dmaBuff
->kickFlag
== GL_FALSE
)
56 return dmaBuff
->usingPage
;
58 page
= dmaBuff
->usingPage
+ 1;
61 if (page
>= (dmaBuff
->buf
->size
* dmaBuff
->buf
->type
)/DMA_PAGE_SIZE
)
64 eventTag1
= GET_EVENTTAG
;
65 if ( eventTag1
== page
) { /* is kicking off */
67 while (GET_EVENTTAG
== page
); /* FIXME: add a max loop count? */
73 dmaBuff
->usingPage
= page
;
74 dmaBuff
->start
= dmaBuff
->end
= dmaBuff
->allocEnd
=
75 (dmaBuff
->buf
->linear
+ DMA_PAGE_SIZE
* page
);
76 dmaBuff
->kickFlag
= GL_FALSE
;
81 /* Allocate space in a real DMA buffer */
82 void *savageDMAAlloc (savageContextPtr imesa
, GLuint size
) {
83 DMABufferPtr dmaBuff
= &imesa
->DMABuf
;
85 /* make sure that everything has been filled in and committed */
86 assert (dmaBuff
->end
== dmaBuff
->allocEnd
);
88 size
*= sizeof (uint32_t); /* size in bytes */
89 if (dmaBuff
->kickFlag
== GL_TRUE
) {
90 if (size
> DMA_PAGE_SIZE
)
92 getDMAPage (imesa
, 1);
93 } else if (dmaBuff
->end
+ size
>=
94 dmaBuff
->buf
->linear
+ DMA_PAGE_SIZE
*(dmaBuff
->usingPage
+1)) {
96 savageDMAFlush (imesa
);
97 getDMAPage (imesa
, 1);
99 dmaBuff
->allocEnd
= dmaBuff
->end
+ size
;
100 return (void *)dmaBuff
->end
;
103 /* Flush DMA buffer via DMA */
104 void savageDMAFlush (savageContextPtr imesa
) {
105 volatile uint32_t* BCIbase
;
106 DMABufferPtr dmaBuff
= &imesa
->DMABuf
;
108 GLuint dmaCount
, dmaCount1
, remain
;
111 /* make sure that everything has been filled in and committed */
112 assert (dmaBuff
->allocEnd
== dmaBuff
->end
);
114 if (dmaBuff
->kickFlag
== GL_TRUE
) /* has been kicked off? */
116 if (dmaBuff
->start
== dmaBuff
->end
) /* no command? */
120 BCIbase
= (volatile uint32_t *)SAVAGE_GET_BCI_POINTER(imesa
,4);
122 /* set the eventtag */
123 *BCIbase
= (dmaBuff
->usingPage
& 0xffffL
) | (CMD_UpdateShadowStat
<< 27)
125 *BCIbase
= 0x96010051; /* set register x51*/
126 /* set the DMA buffer address */
127 phyAddress
= (dmaBuff
->buf
->phyaddress
+ dmaBuff
->usingPage
*DMA_PAGE_SIZE
)
128 & MDT_SRCADD_ALIGMENT
;
129 if (dmaBuff
->buf
->location
== DRM_SAVAGE_MEM_LOCATION_AGP
)
130 *BCIbase
= (phyAddress
) | MDT_SRC_AGP
;
132 *BCIbase
= (phyAddress
) | MDT_SRC_PCI
;
134 /* pad with noops to multiple of 32 bytes */
135 dmaCount
= (GLuint
)(dmaBuff
->end
- dmaBuff
->start
);
136 dmaCount1
= (dmaCount
+ 31UL) & ~31UL;
137 remain
= (dmaCount1
- dmaCount
) >> 2;
138 for (i
= 0; i
< remain
; i
++) {
139 *((uint32_t *)dmaBuff
->end
) = 0x40000000L
;
142 dmaCount
= (dmaCount1
>> 3) - 1;
143 dmaBuff
->allocEnd
= dmaBuff
->end
;
146 *BCIbase
= (0xA8000000L
)|dmaCount
;
147 dmaBuff
->kickFlag
= GL_TRUE
;
151 int savageDMAInit (savageContextPtr imesa
)
153 DMABufferPtr dmaBuff
= &imesa
->DMABuf
;
154 drm_savage_alloc_cont_mem_t
* req
;
158 req
= (drm_savage_alloc_cont_mem_t
*)
159 malloc (sizeof(drm_savage_alloc_cont_mem_t
));
163 req
->type
= DRM_SAVAGE_MEM_PAGE
;
167 req
->phyaddress
= imesa
->sarea
->agp_offset
;
168 if (req
->phyaddress
) {
169 if (drmMap (imesa
->driFd
,
171 DRM_SAVAGE_DMA_AGP_SIZE
,
172 (drmAddressPtr
)&req
->linear
) < 0) {
173 fprintf (stderr
, "AGP map error.\n");
176 if (0) fprintf (stderr
,"Using AGP dma|\n");
177 req
->location
= DRM_SAVAGE_MEM_LOCATION_AGP
;
178 req
->size
= DRM_SAVAGE_DMA_AGP_SIZE
/DRM_SAVAGE_MEM_PAGE
;
183 req
->size
= DMA_BUFFER_SIZE
/DRM_SAVAGE_MEM_PAGE
;
184 for (i
= 0; i
< DMA_TRY_COUNT
; i
++) {
185 if ((ret
= savageAllocDMABuffer (imesa
, req
)) != 0)
187 req
->size
= req
->size
/2;
191 fprintf(stderr
, "Can't alloc DMA memory(system and agp)\n");
194 req
->location
= DRM_SAVAGE_MEM_LOCATION_PCI
;
199 dmaBuff
->start
= dmaBuff
->end
= dmaBuff
->allocEnd
= req
->linear
;
200 dmaBuff
->usingPage
= 0;
201 dmaBuff
->kickFlag
= GL_FALSE
;
207 int savageDMAClose (savageContextPtr imesa
)
209 DMABufferPtr dmaBuff
= &imesa
->DMABuf
;
210 drm_savage_alloc_cont_mem_t
* req
= dmaBuff
->buf
;
212 if(req
->location
== DRM_SAVAGE_MEM_LOCATION_PCI
)
213 savageFreeDMABuffer (imesa
, req
);
214 else { /* AGP memory */
215 drmUnmap ((drmAddress
)req
->linear
, req
->size
*req
->type
);
216 drmRmMap (imesa
->driFd
, req
->phyaddress
);
223 /* Allocate space in faked DMA buffer */
224 void *savageDMAAlloc (savageContextPtr imesa
, GLuint size
) {
225 DMABufferPtr dmaBuff
= &imesa
->DMABuf
;
227 /* make sure that everything has been filled in and committed */
228 assert (dmaBuff
->end
== dmaBuff
->allocEnd
);
230 size
*= sizeof (uint32_t); /* size in bytes */
231 if (dmaBuff
->end
+ size
>= dmaBuff
->buf
->linear
+ DMA_PAGE_SIZE
) {
233 savageDMAFlush (imesa
);
235 dmaBuff
->allocEnd
= dmaBuff
->end
+ size
;
236 return (void *)dmaBuff
->end
;
239 /* Flush DMA buffer via BCI (faked DMA) */
240 void savageDMAFlush(savageContextPtr imesa
) {
241 volatile uint32_t* BCIbase
;
242 DMABufferPtr dmaBuff
= &imesa
->DMABuf
;
245 /* make sure that everything has been filled in and committed */
246 assert (dmaBuff
->allocEnd
== dmaBuff
->end
);
248 if (dmaBuff
->start
== dmaBuff
->end
) /* no command? */
252 BCIbase
= (volatile uint32_t *)SAVAGE_GET_BCI_POINTER(
253 imesa
, (dmaBuff
->end
- dmaBuff
->start
) / sizeof (uint32_t));
255 for (entry
= (uint32_t *)dmaBuff
->start
;
256 entry
< (uint32_t *)dmaBuff
->end
; ++entry
)
259 dmaBuff
->end
= dmaBuff
->allocEnd
= dmaBuff
->start
;
263 int savageDMAInit (savageContextPtr imesa
) {
264 DMABufferPtr dmaBuff
= &imesa
->DMABuf
;
265 drm_savage_alloc_cont_mem_t
* req
;
267 req
= (drm_savage_alloc_cont_mem_t
*)
268 malloc (sizeof(drm_savage_alloc_cont_mem_t
));
272 req
->linear
= (GLuint
)malloc (DMA_PAGE_SIZE
);
280 dmaBuff
->start
= dmaBuff
->end
= dmaBuff
->allocEnd
= req
->linear
;
281 dmaBuff
->usingPage
= 0;
282 dmaBuff
->kickFlag
= GL_FALSE
;
287 /* Close faked DMA */
288 int savageDMAClose (savageContextPtr imesa
) {
289 DMABufferPtr dmaBuff
= &imesa
->DMABuf
;
290 drm_savage_alloc_cont_mem_t
* req
= dmaBuff
->buf
;
292 free ((void *)req
->linear
);
300 /* Faked vertex buffers
302 * This is a dirty hack, knowing that it will go away soon when real
303 * vertex DMA is implemented and eventually moved to the DRM.
306 static uint32_t vertex_data
[16384]; /* 64KB */
307 static drmBuf vertex_buffer
= {
309 65536, /* total = 64KB */
311 (drmAddress
)vertex_data
/* address */
314 void savageFakeVertices (savageContextPtr imesa
, drmBufPtr buffer
) {
315 GLuint vertexStride
= imesa
->vertex_size
; /* stride in dwords */
316 GLuint vertexSize
= imesa
->vertex_size
; /* the real vertex size in dwords */
317 GLuint nVertices
= buffer
->used
/ (vertexStride
*4);
318 uint32_t *data
= (uint32_t*)buffer
->address
;
319 uint32_t vertexFormat
= imesa
->DrawPrimitiveCmd
& SAVAGE_HW_SKIPFLAGS
;
322 /* we have the monopoly on vertex buffers ;-) */
323 assert (buffer
== &vertex_buffer
);
324 assert (buffer
->used
% (vertexStride
*4) == 0); /* whole vertices */
325 assert (nVertices
% 3 == 0); /* triangle lists */
327 /* Flush (pseodo) DMA before accessing the BCI directly. */
328 savageDMAFlush(imesa
);
332 /* Can emit up to 255 vertices (85 triangles) with one command. */
333 GLuint count
= left
> 255 ? 255 : left
;
334 /* Don't go through another buffering mechanism, copy to BCI
336 volatile uint32_t *vb
= SAVAGE_GET_BCI_POINTER(imesa
,
337 count
*vertexSize
+ 1);
339 WRITE_CMD (vb
, SAVAGE_DRAW_PRIMITIVE(
340 count
, SAVAGE_HW_TRIANGLE_LIST
| vertexFormat
, 0),
342 for (i
= 0; i
< count
; ++i
) {
343 for (j
= 0; j
< vertexSize
; ++j
)
344 WRITE_CMD (vb
, data
[j
], uint32_t);
345 data
+= vertexStride
;
350 /* clear the vertex buffer for the next set of vertices */
351 vertex_buffer
.used
= 0;
354 drmBufPtr
savageFakeGetBuffer (savageContextPtr imesa
) {
355 assert (vertex_buffer
.used
== 0); /* has been flushed */
356 return &vertex_buffer
;