diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/char/drm/mga_dma.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/char/drm/mga_dma.c')
-rw-r--r-- | drivers/char/drm/mga_dma.c | 754 |
1 files changed, 754 insertions, 0 deletions
diff --git a/drivers/char/drm/mga_dma.c b/drivers/char/drm/mga_dma.c new file mode 100644 index 000000000000..832eaf8a5068 --- /dev/null +++ b/drivers/char/drm/mga_dma.c | |||
@@ -0,0 +1,754 @@ | |||
1 | /* mga_dma.c -- DMA support for mga g200/g400 -*- linux-c -*- | ||
2 | * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com | ||
3 | * | ||
4 | * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. | ||
5 | * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. | ||
6 | * All Rights Reserved. | ||
7 | * | ||
8 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
9 | * copy of this software and associated documentation files (the "Software"), | ||
10 | * to deal in the Software without restriction, including without limitation | ||
11 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
12 | * and/or sell copies of the Software, and to permit persons to whom the | ||
13 | * Software is furnished to do so, subject to the following conditions: | ||
14 | * | ||
15 | * The above copyright notice and this permission notice (including the next | ||
16 | * paragraph) shall be included in all copies or substantial portions of the | ||
17 | * Software. | ||
18 | * | ||
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
22 | * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
23 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
24 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
25 | * DEALINGS IN THE SOFTWARE. | ||
26 | * | ||
27 | * Authors: | ||
28 | * Rickard E. (Rik) Faith <faith@valinux.com> | ||
29 | * Jeff Hartmann <jhartmann@valinux.com> | ||
30 | * Keith Whitwell <keith@tungstengraphics.com> | ||
31 | * | ||
32 | * Rewritten by: | ||
33 | * Gareth Hughes <gareth@valinux.com> | ||
34 | */ | ||
35 | |||
36 | #include "drmP.h" | ||
37 | #include "drm.h" | ||
38 | #include "mga_drm.h" | ||
39 | #include "mga_drv.h" | ||
40 | |||
41 | #define MGA_DEFAULT_USEC_TIMEOUT 10000 | ||
42 | #define MGA_FREELIST_DEBUG 0 | ||
43 | |||
44 | static int mga_do_cleanup_dma( drm_device_t *dev ); | ||
45 | |||
46 | /* ================================================================ | ||
47 | * Engine control | ||
48 | */ | ||
49 | |||
50 | int mga_do_wait_for_idle( drm_mga_private_t *dev_priv ) | ||
51 | { | ||
52 | u32 status = 0; | ||
53 | int i; | ||
54 | DRM_DEBUG( "\n" ); | ||
55 | |||
56 | for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { | ||
57 | status = MGA_READ( MGA_STATUS ) & MGA_ENGINE_IDLE_MASK; | ||
58 | if ( status == MGA_ENDPRDMASTS ) { | ||
59 | MGA_WRITE8( MGA_CRTC_INDEX, 0 ); | ||
60 | return 0; | ||
61 | } | ||
62 | DRM_UDELAY( 1 ); | ||
63 | } | ||
64 | |||
65 | #if MGA_DMA_DEBUG | ||
66 | DRM_ERROR( "failed!\n" ); | ||
67 | DRM_INFO( " status=0x%08x\n", status ); | ||
68 | #endif | ||
69 | return DRM_ERR(EBUSY); | ||
70 | } | ||
71 | |||
72 | static int mga_do_dma_reset( drm_mga_private_t *dev_priv ) | ||
73 | { | ||
74 | drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; | ||
75 | drm_mga_primary_buffer_t *primary = &dev_priv->prim; | ||
76 | |||
77 | DRM_DEBUG( "\n" ); | ||
78 | |||
79 | /* The primary DMA stream should look like new right about now. | ||
80 | */ | ||
81 | primary->tail = 0; | ||
82 | primary->space = primary->size; | ||
83 | primary->last_flush = 0; | ||
84 | |||
85 | sarea_priv->last_wrap = 0; | ||
86 | |||
87 | /* FIXME: Reset counters, buffer ages etc... | ||
88 | */ | ||
89 | |||
90 | /* FIXME: What else do we need to reinitialize? WARP stuff? | ||
91 | */ | ||
92 | |||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | /* ================================================================ | ||
97 | * Primary DMA stream | ||
98 | */ | ||
99 | |||
100 | void mga_do_dma_flush( drm_mga_private_t *dev_priv ) | ||
101 | { | ||
102 | drm_mga_primary_buffer_t *primary = &dev_priv->prim; | ||
103 | u32 head, tail; | ||
104 | u32 status = 0; | ||
105 | int i; | ||
106 | DMA_LOCALS; | ||
107 | DRM_DEBUG( "\n" ); | ||
108 | |||
109 | /* We need to wait so that we can do an safe flush */ | ||
110 | for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { | ||
111 | status = MGA_READ( MGA_STATUS ) & MGA_ENGINE_IDLE_MASK; | ||
112 | if ( status == MGA_ENDPRDMASTS ) break; | ||
113 | DRM_UDELAY( 1 ); | ||
114 | } | ||
115 | |||
116 | if ( primary->tail == primary->last_flush ) { | ||
117 | DRM_DEBUG( " bailing out...\n" ); | ||
118 | return; | ||
119 | } | ||
120 | |||
121 | tail = primary->tail + dev_priv->primary->offset; | ||
122 | |||
123 | /* We need to pad the stream between flushes, as the card | ||
124 | * actually (partially?) reads the first of these commands. | ||
125 | * See page 4-16 in the G400 manual, middle of the page or so. | ||
126 | */ | ||
127 | BEGIN_DMA( 1 ); | ||
128 | |||
129 | DMA_BLOCK( MGA_DMAPAD, 0x00000000, | ||
130 | MGA_DMAPAD, 0x00000000, | ||
131 | MGA_DMAPAD, 0x00000000, | ||
132 | MGA_DMAPAD, 0x00000000 ); | ||
133 | |||
134 | ADVANCE_DMA(); | ||
135 | |||
136 | primary->last_flush = primary->tail; | ||
137 | |||
138 | head = MGA_READ( MGA_PRIMADDRESS ); | ||
139 | |||
140 | if ( head <= tail ) { | ||
141 | primary->space = primary->size - primary->tail; | ||
142 | } else { | ||
143 | primary->space = head - tail; | ||
144 | } | ||
145 | |||
146 | DRM_DEBUG( " head = 0x%06lx\n", head - dev_priv->primary->offset ); | ||
147 | DRM_DEBUG( " tail = 0x%06lx\n", tail - dev_priv->primary->offset ); | ||
148 | DRM_DEBUG( " space = 0x%06x\n", primary->space ); | ||
149 | |||
150 | mga_flush_write_combine(); | ||
151 | MGA_WRITE( MGA_PRIMEND, tail | MGA_PAGPXFER ); | ||
152 | |||
153 | DRM_DEBUG( "done.\n" ); | ||
154 | } | ||
155 | |||
156 | void mga_do_dma_wrap_start( drm_mga_private_t *dev_priv ) | ||
157 | { | ||
158 | drm_mga_primary_buffer_t *primary = &dev_priv->prim; | ||
159 | u32 head, tail; | ||
160 | DMA_LOCALS; | ||
161 | DRM_DEBUG( "\n" ); | ||
162 | |||
163 | BEGIN_DMA_WRAP(); | ||
164 | |||
165 | DMA_BLOCK( MGA_DMAPAD, 0x00000000, | ||
166 | MGA_DMAPAD, 0x00000000, | ||
167 | MGA_DMAPAD, 0x00000000, | ||
168 | MGA_DMAPAD, 0x00000000 ); | ||
169 | |||
170 | ADVANCE_DMA(); | ||
171 | |||
172 | tail = primary->tail + dev_priv->primary->offset; | ||
173 | |||
174 | primary->tail = 0; | ||
175 | primary->last_flush = 0; | ||
176 | primary->last_wrap++; | ||
177 | |||
178 | head = MGA_READ( MGA_PRIMADDRESS ); | ||
179 | |||
180 | if ( head == dev_priv->primary->offset ) { | ||
181 | primary->space = primary->size; | ||
182 | } else { | ||
183 | primary->space = head - dev_priv->primary->offset; | ||
184 | } | ||
185 | |||
186 | DRM_DEBUG( " head = 0x%06lx\n", | ||
187 | head - dev_priv->primary->offset ); | ||
188 | DRM_DEBUG( " tail = 0x%06x\n", primary->tail ); | ||
189 | DRM_DEBUG( " wrap = %d\n", primary->last_wrap ); | ||
190 | DRM_DEBUG( " space = 0x%06x\n", primary->space ); | ||
191 | |||
192 | mga_flush_write_combine(); | ||
193 | MGA_WRITE( MGA_PRIMEND, tail | MGA_PAGPXFER ); | ||
194 | |||
195 | set_bit( 0, &primary->wrapped ); | ||
196 | DRM_DEBUG( "done.\n" ); | ||
197 | } | ||
198 | |||
199 | void mga_do_dma_wrap_end( drm_mga_private_t *dev_priv ) | ||
200 | { | ||
201 | drm_mga_primary_buffer_t *primary = &dev_priv->prim; | ||
202 | drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; | ||
203 | u32 head = dev_priv->primary->offset; | ||
204 | DRM_DEBUG( "\n" ); | ||
205 | |||
206 | sarea_priv->last_wrap++; | ||
207 | DRM_DEBUG( " wrap = %d\n", sarea_priv->last_wrap ); | ||
208 | |||
209 | mga_flush_write_combine(); | ||
210 | MGA_WRITE( MGA_PRIMADDRESS, head | MGA_DMA_GENERAL ); | ||
211 | |||
212 | clear_bit( 0, &primary->wrapped ); | ||
213 | DRM_DEBUG( "done.\n" ); | ||
214 | } | ||
215 | |||
216 | |||
217 | /* ================================================================ | ||
218 | * Freelist management | ||
219 | */ | ||
220 | |||
221 | #define MGA_BUFFER_USED ~0 | ||
222 | #define MGA_BUFFER_FREE 0 | ||
223 | |||
224 | #if MGA_FREELIST_DEBUG | ||
225 | static void mga_freelist_print( drm_device_t *dev ) | ||
226 | { | ||
227 | drm_mga_private_t *dev_priv = dev->dev_private; | ||
228 | drm_mga_freelist_t *entry; | ||
229 | |||
230 | DRM_INFO( "\n" ); | ||
231 | DRM_INFO( "current dispatch: last=0x%x done=0x%x\n", | ||
232 | dev_priv->sarea_priv->last_dispatch, | ||
233 | (unsigned int)(MGA_READ( MGA_PRIMADDRESS ) - | ||
234 | dev_priv->primary->offset) ); | ||
235 | DRM_INFO( "current freelist:\n" ); | ||
236 | |||
237 | for ( entry = dev_priv->head->next ; entry ; entry = entry->next ) { | ||
238 | DRM_INFO( " %p idx=%2d age=0x%x 0x%06lx\n", | ||
239 | entry, entry->buf->idx, entry->age.head, | ||
240 | entry->age.head - dev_priv->primary->offset ); | ||
241 | } | ||
242 | DRM_INFO( "\n" ); | ||
243 | } | ||
244 | #endif | ||
245 | |||
246 | static int mga_freelist_init( drm_device_t *dev, drm_mga_private_t *dev_priv ) | ||
247 | { | ||
248 | drm_device_dma_t *dma = dev->dma; | ||
249 | drm_buf_t *buf; | ||
250 | drm_mga_buf_priv_t *buf_priv; | ||
251 | drm_mga_freelist_t *entry; | ||
252 | int i; | ||
253 | DRM_DEBUG( "count=%d\n", dma->buf_count ); | ||
254 | |||
255 | dev_priv->head = drm_alloc( sizeof(drm_mga_freelist_t), | ||
256 | DRM_MEM_DRIVER ); | ||
257 | if ( dev_priv->head == NULL ) | ||
258 | return DRM_ERR(ENOMEM); | ||
259 | |||
260 | memset( dev_priv->head, 0, sizeof(drm_mga_freelist_t) ); | ||
261 | SET_AGE( &dev_priv->head->age, MGA_BUFFER_USED, 0 ); | ||
262 | |||
263 | for ( i = 0 ; i < dma->buf_count ; i++ ) { | ||
264 | buf = dma->buflist[i]; | ||
265 | buf_priv = buf->dev_private; | ||
266 | |||
267 | entry = drm_alloc( sizeof(drm_mga_freelist_t), | ||
268 | DRM_MEM_DRIVER ); | ||
269 | if ( entry == NULL ) | ||
270 | return DRM_ERR(ENOMEM); | ||
271 | |||
272 | memset( entry, 0, sizeof(drm_mga_freelist_t) ); | ||
273 | |||
274 | entry->next = dev_priv->head->next; | ||
275 | entry->prev = dev_priv->head; | ||
276 | SET_AGE( &entry->age, MGA_BUFFER_FREE, 0 ); | ||
277 | entry->buf = buf; | ||
278 | |||
279 | if ( dev_priv->head->next != NULL ) | ||
280 | dev_priv->head->next->prev = entry; | ||
281 | if ( entry->next == NULL ) | ||
282 | dev_priv->tail = entry; | ||
283 | |||
284 | buf_priv->list_entry = entry; | ||
285 | buf_priv->discard = 0; | ||
286 | buf_priv->dispatched = 0; | ||
287 | |||
288 | dev_priv->head->next = entry; | ||
289 | } | ||
290 | |||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | static void mga_freelist_cleanup( drm_device_t *dev ) | ||
295 | { | ||
296 | drm_mga_private_t *dev_priv = dev->dev_private; | ||
297 | drm_mga_freelist_t *entry; | ||
298 | drm_mga_freelist_t *next; | ||
299 | DRM_DEBUG( "\n" ); | ||
300 | |||
301 | entry = dev_priv->head; | ||
302 | while ( entry ) { | ||
303 | next = entry->next; | ||
304 | drm_free( entry, sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER ); | ||
305 | entry = next; | ||
306 | } | ||
307 | |||
308 | dev_priv->head = dev_priv->tail = NULL; | ||
309 | } | ||
310 | |||
311 | #if 0 | ||
312 | /* FIXME: Still needed? | ||
313 | */ | ||
314 | static void mga_freelist_reset( drm_device_t *dev ) | ||
315 | { | ||
316 | drm_device_dma_t *dma = dev->dma; | ||
317 | drm_buf_t *buf; | ||
318 | drm_mga_buf_priv_t *buf_priv; | ||
319 | int i; | ||
320 | |||
321 | for ( i = 0 ; i < dma->buf_count ; i++ ) { | ||
322 | buf = dma->buflist[i]; | ||
323 | buf_priv = buf->dev_private; | ||
324 | SET_AGE( &buf_priv->list_entry->age, | ||
325 | MGA_BUFFER_FREE, 0 ); | ||
326 | } | ||
327 | } | ||
328 | #endif | ||
329 | |||
330 | static drm_buf_t *mga_freelist_get( drm_device_t *dev ) | ||
331 | { | ||
332 | drm_mga_private_t *dev_priv = dev->dev_private; | ||
333 | drm_mga_freelist_t *next; | ||
334 | drm_mga_freelist_t *prev; | ||
335 | drm_mga_freelist_t *tail = dev_priv->tail; | ||
336 | u32 head, wrap; | ||
337 | DRM_DEBUG( "\n" ); | ||
338 | |||
339 | head = MGA_READ( MGA_PRIMADDRESS ); | ||
340 | wrap = dev_priv->sarea_priv->last_wrap; | ||
341 | |||
342 | DRM_DEBUG( " tail=0x%06lx %d\n", | ||
343 | tail->age.head ? | ||
344 | tail->age.head - dev_priv->primary->offset : 0, | ||
345 | tail->age.wrap ); | ||
346 | DRM_DEBUG( " head=0x%06lx %d\n", | ||
347 | head - dev_priv->primary->offset, wrap ); | ||
348 | |||
349 | if ( TEST_AGE( &tail->age, head, wrap ) ) { | ||
350 | prev = dev_priv->tail->prev; | ||
351 | next = dev_priv->tail; | ||
352 | prev->next = NULL; | ||
353 | next->prev = next->next = NULL; | ||
354 | dev_priv->tail = prev; | ||
355 | SET_AGE( &next->age, MGA_BUFFER_USED, 0 ); | ||
356 | return next->buf; | ||
357 | } | ||
358 | |||
359 | DRM_DEBUG( "returning NULL!\n" ); | ||
360 | return NULL; | ||
361 | } | ||
362 | |||
363 | int mga_freelist_put( drm_device_t *dev, drm_buf_t *buf ) | ||
364 | { | ||
365 | drm_mga_private_t *dev_priv = dev->dev_private; | ||
366 | drm_mga_buf_priv_t *buf_priv = buf->dev_private; | ||
367 | drm_mga_freelist_t *head, *entry, *prev; | ||
368 | |||
369 | DRM_DEBUG( "age=0x%06lx wrap=%d\n", | ||
370 | buf_priv->list_entry->age.head - | ||
371 | dev_priv->primary->offset, | ||
372 | buf_priv->list_entry->age.wrap ); | ||
373 | |||
374 | entry = buf_priv->list_entry; | ||
375 | head = dev_priv->head; | ||
376 | |||
377 | if ( buf_priv->list_entry->age.head == MGA_BUFFER_USED ) { | ||
378 | SET_AGE( &entry->age, MGA_BUFFER_FREE, 0 ); | ||
379 | prev = dev_priv->tail; | ||
380 | prev->next = entry; | ||
381 | entry->prev = prev; | ||
382 | entry->next = NULL; | ||
383 | } else { | ||
384 | prev = head->next; | ||
385 | head->next = entry; | ||
386 | prev->prev = entry; | ||
387 | entry->prev = head; | ||
388 | entry->next = prev; | ||
389 | } | ||
390 | |||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | |||
395 | /* ================================================================ | ||
396 | * DMA initialization, cleanup | ||
397 | */ | ||
398 | |||
399 | static int mga_do_init_dma( drm_device_t *dev, drm_mga_init_t *init ) | ||
400 | { | ||
401 | drm_mga_private_t *dev_priv; | ||
402 | int ret; | ||
403 | DRM_DEBUG( "\n" ); | ||
404 | |||
405 | dev_priv = drm_alloc( sizeof(drm_mga_private_t), DRM_MEM_DRIVER ); | ||
406 | if ( !dev_priv ) | ||
407 | return DRM_ERR(ENOMEM); | ||
408 | |||
409 | memset( dev_priv, 0, sizeof(drm_mga_private_t) ); | ||
410 | |||
411 | dev_priv->chipset = init->chipset; | ||
412 | |||
413 | dev_priv->usec_timeout = MGA_DEFAULT_USEC_TIMEOUT; | ||
414 | |||
415 | if ( init->sgram ) { | ||
416 | dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_BLK; | ||
417 | } else { | ||
418 | dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_RSTR; | ||
419 | } | ||
420 | dev_priv->maccess = init->maccess; | ||
421 | |||
422 | dev_priv->fb_cpp = init->fb_cpp; | ||
423 | dev_priv->front_offset = init->front_offset; | ||
424 | dev_priv->front_pitch = init->front_pitch; | ||
425 | dev_priv->back_offset = init->back_offset; | ||
426 | dev_priv->back_pitch = init->back_pitch; | ||
427 | |||
428 | dev_priv->depth_cpp = init->depth_cpp; | ||
429 | dev_priv->depth_offset = init->depth_offset; | ||
430 | dev_priv->depth_pitch = init->depth_pitch; | ||
431 | |||
432 | /* FIXME: Need to support AGP textures... | ||
433 | */ | ||
434 | dev_priv->texture_offset = init->texture_offset[0]; | ||
435 | dev_priv->texture_size = init->texture_size[0]; | ||
436 | |||
437 | DRM_GETSAREA(); | ||
438 | |||
439 | if(!dev_priv->sarea) { | ||
440 | DRM_ERROR( "failed to find sarea!\n" ); | ||
441 | /* Assign dev_private so we can do cleanup. */ | ||
442 | dev->dev_private = (void *)dev_priv; | ||
443 | mga_do_cleanup_dma( dev ); | ||
444 | return DRM_ERR(EINVAL); | ||
445 | } | ||
446 | |||
447 | dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset); | ||
448 | if(!dev_priv->mmio) { | ||
449 | DRM_ERROR( "failed to find mmio region!\n" ); | ||
450 | /* Assign dev_private so we can do cleanup. */ | ||
451 | dev->dev_private = (void *)dev_priv; | ||
452 | mga_do_cleanup_dma( dev ); | ||
453 | return DRM_ERR(EINVAL); | ||
454 | } | ||
455 | dev_priv->status = drm_core_findmap(dev, init->status_offset); | ||
456 | if(!dev_priv->status) { | ||
457 | DRM_ERROR( "failed to find status page!\n" ); | ||
458 | /* Assign dev_private so we can do cleanup. */ | ||
459 | dev->dev_private = (void *)dev_priv; | ||
460 | mga_do_cleanup_dma( dev ); | ||
461 | return DRM_ERR(EINVAL); | ||
462 | } | ||
463 | dev_priv->warp = drm_core_findmap(dev, init->warp_offset); | ||
464 | if(!dev_priv->warp) { | ||
465 | DRM_ERROR( "failed to find warp microcode region!\n" ); | ||
466 | /* Assign dev_private so we can do cleanup. */ | ||
467 | dev->dev_private = (void *)dev_priv; | ||
468 | mga_do_cleanup_dma( dev ); | ||
469 | return DRM_ERR(EINVAL); | ||
470 | } | ||
471 | dev_priv->primary = drm_core_findmap(dev, init->primary_offset); | ||
472 | if(!dev_priv->primary) { | ||
473 | DRM_ERROR( "failed to find primary dma region!\n" ); | ||
474 | /* Assign dev_private so we can do cleanup. */ | ||
475 | dev->dev_private = (void *)dev_priv; | ||
476 | mga_do_cleanup_dma( dev ); | ||
477 | return DRM_ERR(EINVAL); | ||
478 | } | ||
479 | dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); | ||
480 | if(!dev->agp_buffer_map) { | ||
481 | DRM_ERROR( "failed to find dma buffer region!\n" ); | ||
482 | /* Assign dev_private so we can do cleanup. */ | ||
483 | dev->dev_private = (void *)dev_priv; | ||
484 | mga_do_cleanup_dma( dev ); | ||
485 | return DRM_ERR(EINVAL); | ||
486 | } | ||
487 | |||
488 | dev_priv->sarea_priv = | ||
489 | (drm_mga_sarea_t *)((u8 *)dev_priv->sarea->handle + | ||
490 | init->sarea_priv_offset); | ||
491 | |||
492 | drm_core_ioremap( dev_priv->warp, dev ); | ||
493 | drm_core_ioremap( dev_priv->primary, dev ); | ||
494 | drm_core_ioremap( dev->agp_buffer_map, dev ); | ||
495 | |||
496 | if(!dev_priv->warp->handle || | ||
497 | !dev_priv->primary->handle || | ||
498 | !dev->agp_buffer_map->handle ) { | ||
499 | DRM_ERROR( "failed to ioremap agp regions!\n" ); | ||
500 | /* Assign dev_private so we can do cleanup. */ | ||
501 | dev->dev_private = (void *)dev_priv; | ||
502 | mga_do_cleanup_dma( dev ); | ||
503 | return DRM_ERR(ENOMEM); | ||
504 | } | ||
505 | |||
506 | ret = mga_warp_install_microcode( dev_priv ); | ||
507 | if ( ret < 0 ) { | ||
508 | DRM_ERROR( "failed to install WARP ucode!\n" ); | ||
509 | /* Assign dev_private so we can do cleanup. */ | ||
510 | dev->dev_private = (void *)dev_priv; | ||
511 | mga_do_cleanup_dma( dev ); | ||
512 | return ret; | ||
513 | } | ||
514 | |||
515 | ret = mga_warp_init( dev_priv ); | ||
516 | if ( ret < 0 ) { | ||
517 | DRM_ERROR( "failed to init WARP engine!\n" ); | ||
518 | /* Assign dev_private so we can do cleanup. */ | ||
519 | dev->dev_private = (void *)dev_priv; | ||
520 | mga_do_cleanup_dma( dev ); | ||
521 | return ret; | ||
522 | } | ||
523 | |||
524 | dev_priv->prim.status = (u32 *)dev_priv->status->handle; | ||
525 | |||
526 | mga_do_wait_for_idle( dev_priv ); | ||
527 | |||
528 | /* Init the primary DMA registers. | ||
529 | */ | ||
530 | MGA_WRITE( MGA_PRIMADDRESS, | ||
531 | dev_priv->primary->offset | MGA_DMA_GENERAL ); | ||
532 | #if 0 | ||
533 | MGA_WRITE( MGA_PRIMPTR, | ||
534 | virt_to_bus((void *)dev_priv->prim.status) | | ||
535 | MGA_PRIMPTREN0 | /* Soft trap, SECEND, SETUPEND */ | ||
536 | MGA_PRIMPTREN1 ); /* DWGSYNC */ | ||
537 | #endif | ||
538 | |||
539 | dev_priv->prim.start = (u8 *)dev_priv->primary->handle; | ||
540 | dev_priv->prim.end = ((u8 *)dev_priv->primary->handle | ||
541 | + dev_priv->primary->size); | ||
542 | dev_priv->prim.size = dev_priv->primary->size; | ||
543 | |||
544 | dev_priv->prim.tail = 0; | ||
545 | dev_priv->prim.space = dev_priv->prim.size; | ||
546 | dev_priv->prim.wrapped = 0; | ||
547 | |||
548 | dev_priv->prim.last_flush = 0; | ||
549 | dev_priv->prim.last_wrap = 0; | ||
550 | |||
551 | dev_priv->prim.high_mark = 256 * DMA_BLOCK_SIZE; | ||
552 | |||
553 | dev_priv->prim.status[0] = dev_priv->primary->offset; | ||
554 | dev_priv->prim.status[1] = 0; | ||
555 | |||
556 | dev_priv->sarea_priv->last_wrap = 0; | ||
557 | dev_priv->sarea_priv->last_frame.head = 0; | ||
558 | dev_priv->sarea_priv->last_frame.wrap = 0; | ||
559 | |||
560 | if ( mga_freelist_init( dev, dev_priv ) < 0 ) { | ||
561 | DRM_ERROR( "could not initialize freelist\n" ); | ||
562 | /* Assign dev_private so we can do cleanup. */ | ||
563 | dev->dev_private = (void *)dev_priv; | ||
564 | mga_do_cleanup_dma( dev ); | ||
565 | return DRM_ERR(ENOMEM); | ||
566 | } | ||
567 | |||
568 | /* Make dev_private visable to others. */ | ||
569 | dev->dev_private = (void *)dev_priv; | ||
570 | return 0; | ||
571 | } | ||
572 | |||
573 | static int mga_do_cleanup_dma( drm_device_t *dev ) | ||
574 | { | ||
575 | DRM_DEBUG( "\n" ); | ||
576 | |||
577 | /* Make sure interrupts are disabled here because the uninstall ioctl | ||
578 | * may not have been called from userspace and after dev_private | ||
579 | * is freed, it's too late. | ||
580 | */ | ||
581 | if ( dev->irq_enabled ) drm_irq_uninstall(dev); | ||
582 | |||
583 | if ( dev->dev_private ) { | ||
584 | drm_mga_private_t *dev_priv = dev->dev_private; | ||
585 | |||
586 | if ( dev_priv->warp != NULL ) | ||
587 | drm_core_ioremapfree( dev_priv->warp, dev ); | ||
588 | if ( dev_priv->primary != NULL ) | ||
589 | drm_core_ioremapfree( dev_priv->primary, dev ); | ||
590 | if ( dev->agp_buffer_map != NULL ) | ||
591 | drm_core_ioremapfree( dev->agp_buffer_map, dev ); | ||
592 | |||
593 | if ( dev_priv->head != NULL ) { | ||
594 | mga_freelist_cleanup( dev ); | ||
595 | } | ||
596 | |||
597 | drm_free( dev->dev_private, sizeof(drm_mga_private_t), | ||
598 | DRM_MEM_DRIVER ); | ||
599 | dev->dev_private = NULL; | ||
600 | } | ||
601 | |||
602 | return 0; | ||
603 | } | ||
604 | |||
605 | int mga_dma_init( DRM_IOCTL_ARGS ) | ||
606 | { | ||
607 | DRM_DEVICE; | ||
608 | drm_mga_init_t init; | ||
609 | |||
610 | LOCK_TEST_WITH_RETURN( dev, filp ); | ||
611 | |||
612 | DRM_COPY_FROM_USER_IOCTL( init, (drm_mga_init_t __user *)data, sizeof(init) ); | ||
613 | |||
614 | switch ( init.func ) { | ||
615 | case MGA_INIT_DMA: | ||
616 | return mga_do_init_dma( dev, &init ); | ||
617 | case MGA_CLEANUP_DMA: | ||
618 | return mga_do_cleanup_dma( dev ); | ||
619 | } | ||
620 | |||
621 | return DRM_ERR(EINVAL); | ||
622 | } | ||
623 | |||
624 | |||
625 | /* ================================================================ | ||
626 | * Primary DMA stream management | ||
627 | */ | ||
628 | |||
629 | int mga_dma_flush( DRM_IOCTL_ARGS ) | ||
630 | { | ||
631 | DRM_DEVICE; | ||
632 | drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; | ||
633 | drm_lock_t lock; | ||
634 | |||
635 | LOCK_TEST_WITH_RETURN( dev, filp ); | ||
636 | |||
637 | DRM_COPY_FROM_USER_IOCTL( lock, (drm_lock_t __user *)data, sizeof(lock) ); | ||
638 | |||
639 | DRM_DEBUG( "%s%s%s\n", | ||
640 | (lock.flags & _DRM_LOCK_FLUSH) ? "flush, " : "", | ||
641 | (lock.flags & _DRM_LOCK_FLUSH_ALL) ? "flush all, " : "", | ||
642 | (lock.flags & _DRM_LOCK_QUIESCENT) ? "idle, " : "" ); | ||
643 | |||
644 | WRAP_WAIT_WITH_RETURN( dev_priv ); | ||
645 | |||
646 | if ( lock.flags & (_DRM_LOCK_FLUSH | _DRM_LOCK_FLUSH_ALL) ) { | ||
647 | mga_do_dma_flush( dev_priv ); | ||
648 | } | ||
649 | |||
650 | if ( lock.flags & _DRM_LOCK_QUIESCENT ) { | ||
651 | #if MGA_DMA_DEBUG | ||
652 | int ret = mga_do_wait_for_idle( dev_priv ); | ||
653 | if ( ret < 0 ) | ||
654 | DRM_INFO( "%s: -EBUSY\n", __FUNCTION__ ); | ||
655 | return ret; | ||
656 | #else | ||
657 | return mga_do_wait_for_idle( dev_priv ); | ||
658 | #endif | ||
659 | } else { | ||
660 | return 0; | ||
661 | } | ||
662 | } | ||
663 | |||
664 | int mga_dma_reset( DRM_IOCTL_ARGS ) | ||
665 | { | ||
666 | DRM_DEVICE; | ||
667 | drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; | ||
668 | |||
669 | LOCK_TEST_WITH_RETURN( dev, filp ); | ||
670 | |||
671 | return mga_do_dma_reset( dev_priv ); | ||
672 | } | ||
673 | |||
674 | |||
675 | /* ================================================================ | ||
676 | * DMA buffer management | ||
677 | */ | ||
678 | |||
679 | static int mga_dma_get_buffers( DRMFILE filp, | ||
680 | drm_device_t *dev, drm_dma_t *d ) | ||
681 | { | ||
682 | drm_buf_t *buf; | ||
683 | int i; | ||
684 | |||
685 | for ( i = d->granted_count ; i < d->request_count ; i++ ) { | ||
686 | buf = mga_freelist_get( dev ); | ||
687 | if ( !buf ) return DRM_ERR(EAGAIN); | ||
688 | |||
689 | buf->filp = filp; | ||
690 | |||
691 | if ( DRM_COPY_TO_USER( &d->request_indices[i], | ||
692 | &buf->idx, sizeof(buf->idx) ) ) | ||
693 | return DRM_ERR(EFAULT); | ||
694 | if ( DRM_COPY_TO_USER( &d->request_sizes[i], | ||
695 | &buf->total, sizeof(buf->total) ) ) | ||
696 | return DRM_ERR(EFAULT); | ||
697 | |||
698 | d->granted_count++; | ||
699 | } | ||
700 | return 0; | ||
701 | } | ||
702 | |||
703 | int mga_dma_buffers( DRM_IOCTL_ARGS ) | ||
704 | { | ||
705 | DRM_DEVICE; | ||
706 | drm_device_dma_t *dma = dev->dma; | ||
707 | drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; | ||
708 | drm_dma_t __user *argp = (void __user *)data; | ||
709 | drm_dma_t d; | ||
710 | int ret = 0; | ||
711 | |||
712 | LOCK_TEST_WITH_RETURN( dev, filp ); | ||
713 | |||
714 | DRM_COPY_FROM_USER_IOCTL( d, argp, sizeof(d) ); | ||
715 | |||
716 | /* Please don't send us buffers. | ||
717 | */ | ||
718 | if ( d.send_count != 0 ) { | ||
719 | DRM_ERROR( "Process %d trying to send %d buffers via drmDMA\n", | ||
720 | DRM_CURRENTPID, d.send_count ); | ||
721 | return DRM_ERR(EINVAL); | ||
722 | } | ||
723 | |||
724 | /* We'll send you buffers. | ||
725 | */ | ||
726 | if ( d.request_count < 0 || d.request_count > dma->buf_count ) { | ||
727 | DRM_ERROR( "Process %d trying to get %d buffers (of %d max)\n", | ||
728 | DRM_CURRENTPID, d.request_count, dma->buf_count ); | ||
729 | return DRM_ERR(EINVAL); | ||
730 | } | ||
731 | |||
732 | WRAP_TEST_WITH_RETURN( dev_priv ); | ||
733 | |||
734 | d.granted_count = 0; | ||
735 | |||
736 | if ( d.request_count ) { | ||
737 | ret = mga_dma_get_buffers( filp, dev, &d ); | ||
738 | } | ||
739 | |||
740 | DRM_COPY_TO_USER_IOCTL( argp, d, sizeof(d) ); | ||
741 | |||
742 | return ret; | ||
743 | } | ||
744 | |||
745 | void mga_driver_pretakedown(drm_device_t *dev) | ||
746 | { | ||
747 | mga_do_cleanup_dma( dev ); | ||
748 | } | ||
749 | |||
750 | int mga_driver_dma_quiescent(drm_device_t *dev) | ||
751 | { | ||
752 | drm_mga_private_t *dev_priv = dev->dev_private; | ||
753 | return mga_do_wait_for_idle( dev_priv ); | ||
754 | } | ||