Fix a refcounting mistake with first_swap_fence.
[mesa.git] / src / mesa / drivers / dri / i915tex / server / intel_dri.c
1 /**
2 * \file server/intel_dri.c
3 * \brief File to perform the device-specific initialization tasks typically
4 * done in the X server.
5 *
6 * Here they are converted to run in the client (or perhaps a standalone
7 * process), and to work with the frame buffer device rather than the X
8 * server infrastructure.
9 *
10 * Copyright (C) 2006 Dave Airlie (airlied@linux.ie)
11
12 Permission is hereby granted, free of charge, to any person obtaining a
13 copy of this software and associated documentation files (the
14 "Software"), to deal in the Software without restriction, including
15 without limitation the rights to use, copy, modify, merge, publish,
16 distribute, sub license, and/or sell copies of the Software, and to
17 permit persons to whom the Software is furnished to do so, subject to
18 the following conditions:
19
20 The above copyright notice and this permission notice (including the
21 next paragraph) shall be included in all copies or substantial portions
22 of the Software.
23
24 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
27 IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR
28 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
29 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
30 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <errno.h>
37 #include <unistd.h>
38
39 #include "driver.h"
40 #include "drm.h"
41
42 #include "intel.h"
43 #include "i830_dri.h"
44
45 #include "memops.h"
46 #include "pciaccess.h"
47
48 static size_t drm_page_size;
49 static int nextTile = 0;
50 #define xf86DrvMsg(...) do {} while(0)
51
52 static const int pitches[] = {
53 128 * 8,
54 128 * 16,
55 128 * 32,
56 128 * 64,
57 0
58 };
59
60 static Bool I830DRIDoMappings(DRIDriverContext *ctx, I830Rec *pI830, drmI830Sarea *sarea);
61
62 static unsigned long
63 GetBestTileAlignment(unsigned long size)
64 {
65 unsigned long i;
66
67 for (i = KB(512); i < size; i <<= 1)
68 ;
69
70 if (i > MB(64))
71 i = MB(64);
72
73 return i;
74 }
75
76 static void SetFenceRegs(const DRIDriverContext *ctx, I830Rec *pI830)
77 {
78 int i;
79 unsigned char *MMIO = ctx->MMIOAddress;
80
81 for (i = 0; i < 8; i++) {
82 OUTREG(FENCE + i * 4, pI830->Fence[i]);
83 // if (I810_DEBUG & DEBUG_VERBOSE_VGA)
84 fprintf(stderr,"Fence Register : %x\n", pI830->Fence[i]);
85 }
86 }
87
88 /* Tiled memory is good... really, really good...
89 *
90 * Need to make it less likely that we miss out on this - probably
91 * need to move the frontbuffer away from the 'guarenteed' alignment
92 * of the first memory segment, or perhaps allocate a discontigous
93 * framebuffer to get more alignment 'sweet spots'.
94 */
95 static void
96 SetFence(const DRIDriverContext *ctx, I830Rec *pI830,
97 int nr, unsigned int start, unsigned int pitch,
98 unsigned int size)
99 {
100 unsigned int val;
101 unsigned int fence_mask = 0;
102 unsigned int fence_pitch;
103
104 if (nr < 0 || nr > 7) {
105 fprintf(stderr,
106 "SetFence: fence %d out of range\n",nr);
107 return;
108 }
109
110 pI830->Fence[nr] = 0;
111
112 if (IS_I9XX(pI830))
113 fence_mask = ~I915G_FENCE_START_MASK;
114 else
115 fence_mask = ~I830_FENCE_START_MASK;
116
117 if (start & fence_mask) {
118 fprintf(stderr,
119 "SetFence: %d: start (0x%08x) is not %s aligned\n",
120 nr, start, (IS_I9XX(pI830)) ? "1MB" : "512k");
121 return;
122 }
123
124 if (start % size) {
125 fprintf(stderr,
126 "SetFence: %d: start (0x%08x) is not size (%dk) aligned\n",
127 nr, start, size / 1024);
128 return;
129 }
130
131 if (pitch & 127) {
132 fprintf(stderr,
133 "SetFence: %d: pitch (%d) not a multiple of 128 bytes\n",
134 nr, pitch);
135 return;
136 }
137
138 val = (start | FENCE_X_MAJOR | FENCE_VALID);
139
140 if (IS_I9XX(pI830)) {
141 switch (size) {
142 case MB(1):
143 val |= I915G_FENCE_SIZE_1M;
144 break;
145 case MB(2):
146 val |= I915G_FENCE_SIZE_2M;
147 break;
148 case MB(4):
149 val |= I915G_FENCE_SIZE_4M;
150 break;
151 case MB(8):
152 val |= I915G_FENCE_SIZE_8M;
153 break;
154 case MB(16):
155 val |= I915G_FENCE_SIZE_16M;
156 break;
157 case MB(32):
158 val |= I915G_FENCE_SIZE_32M;
159 break;
160 case MB(64):
161 val |= I915G_FENCE_SIZE_64M;
162 break;
163 default:
164 fprintf(stderr,
165 "SetFence: %d: illegal size (%d kByte)\n", nr, size / 1024);
166 return;
167 }
168 } else {
169 switch (size) {
170 case KB(512):
171 val |= FENCE_SIZE_512K;
172 break;
173 case MB(1):
174 val |= FENCE_SIZE_1M;
175 break;
176 case MB(2):
177 val |= FENCE_SIZE_2M;
178 break;
179 case MB(4):
180 val |= FENCE_SIZE_4M;
181 break;
182 case MB(8):
183 val |= FENCE_SIZE_8M;
184 break;
185 case MB(16):
186 val |= FENCE_SIZE_16M;
187 break;
188 case MB(32):
189 val |= FENCE_SIZE_32M;
190 break;
191 case MB(64):
192 val |= FENCE_SIZE_64M;
193 break;
194 default:
195 fprintf(stderr,
196 "SetFence: %d: illegal size (%d kByte)\n", nr, size / 1024);
197 return;
198 }
199 }
200
201 if (IS_I9XX(pI830))
202 fence_pitch = pitch / 512;
203 else
204 fence_pitch = pitch / 128;
205
206 switch (fence_pitch) {
207 case 1:
208 val |= FENCE_PITCH_1;
209 break;
210 case 2:
211 val |= FENCE_PITCH_2;
212 break;
213 case 4:
214 val |= FENCE_PITCH_4;
215 break;
216 case 8:
217 val |= FENCE_PITCH_8;
218 break;
219 case 16:
220 val |= FENCE_PITCH_16;
221 break;
222 case 32:
223 val |= FENCE_PITCH_32;
224 break;
225 case 64:
226 val |= FENCE_PITCH_64;
227 break;
228 default:
229 fprintf(stderr,
230 "SetFence: %d: illegal pitch (%d)\n", nr, pitch);
231 return;
232 }
233
234 pI830->Fence[nr] = val;
235 }
236
237 static Bool
238 MakeTiles(const DRIDriverContext *ctx, I830Rec *pI830, I830MemRange *pMem)
239 {
240 int pitch, ntiles, i;
241
242 pitch = pMem->Pitch * ctx->cpp;
243 /*
244 * Simply try to break the region up into at most four pieces of size
245 * equal to the alignment.
246 */
247 ntiles = ROUND_TO(pMem->Size, pMem->Alignment) / pMem->Alignment;
248 if (ntiles >= 4) {
249 return FALSE;
250 }
251
252 for (i = 0; i < ntiles; i++, nextTile++) {
253 SetFence(ctx, pI830, nextTile, pMem->Start + i * pMem->Alignment,
254 pitch, pMem->Alignment);
255 }
256 return TRUE;
257 }
258
259 static void I830SetupMemoryTiling(const DRIDriverContext *ctx, I830Rec *pI830)
260 {
261 int i;
262
263 /* Clear out */
264 for (i = 0; i < 8; i++)
265 pI830->Fence[i] = 0;
266
267 nextTile = 0;
268
269 if (pI830->BackBuffer.Alignment >= KB(512)) {
270 if (MakeTiles(ctx, pI830, &(pI830->BackBuffer))) {
271 fprintf(stderr,
272 "Activating tiled memory for the back buffer.\n");
273 } else {
274 fprintf(stderr,
275 "MakeTiles failed for the back buffer.\n");
276 pI830->allowPageFlip = FALSE;
277 }
278 }
279
280 if (pI830->DepthBuffer.Alignment >= KB(512)) {
281 if (MakeTiles(ctx, pI830, &(pI830->DepthBuffer))) {
282 fprintf(stderr,
283 "Activating tiled memory for the depth buffer.\n");
284 } else {
285 fprintf(stderr,
286 "MakeTiles failed for the depth buffer.\n");
287 }
288 }
289
290 return;
291 }
292
293 static int I830DetectMemory(const DRIDriverContext *ctx, I830Rec *pI830)
294 {
295 struct pci_device host_bridge, ig_dev;
296 uint32_t gmch_ctrl;
297 int memsize = 0;
298 int range;
299 uint32_t aper_size;
300 uint32_t membase2 = 0;
301
302 memset(&host_bridge, 0, sizeof(host_bridge));
303 memset(&ig_dev, 0, sizeof(ig_dev));
304
305 ig_dev.dev = 2;
306
307 pci_device_cfg_read_u32(&host_bridge, &gmch_ctrl, I830_GMCH_CTRL);
308
309 if (IS_I830(pI830) || IS_845G(pI830)) {
310 if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) {
311 aper_size = 0x80000000;
312 } else {
313 aper_size = 0x40000000;
314 }
315 } else {
316 if (IS_I9XX(pI830)) {
317 int ret;
318 ret = pci_device_cfg_read_u32(&ig_dev, &membase2, 0x18);
319 if (membase2 & 0x08000000)
320 aper_size = 0x8000000;
321 else
322 aper_size = 0x10000000;
323
324 fprintf(stderr,"aper size is %08X %08x %d\n", aper_size, membase2, ret);
325 } else
326 aper_size = 0x8000000;
327 }
328
329 pI830->aper_size = aper_size;
330
331
332 /* We need to reduce the stolen size, by the GTT and the popup.
333 * The GTT varying according the the FbMapSize and the popup is 4KB */
334 range = (ctx->shared.fbSize / (1024*1024)) + 4;
335
336 if (IS_I85X(pI830) || IS_I865G(pI830) || IS_I9XX(pI830)) {
337 switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
338 case I855_GMCH_GMS_STOLEN_1M:
339 memsize = MB(1) - KB(range);
340 break;
341 case I855_GMCH_GMS_STOLEN_4M:
342 memsize = MB(4) - KB(range);
343 break;
344 case I855_GMCH_GMS_STOLEN_8M:
345 memsize = MB(8) - KB(range);
346 break;
347 case I855_GMCH_GMS_STOLEN_16M:
348 memsize = MB(16) - KB(range);
349 break;
350 case I855_GMCH_GMS_STOLEN_32M:
351 memsize = MB(32) - KB(range);
352 break;
353 case I915G_GMCH_GMS_STOLEN_48M:
354 if (IS_I9XX(pI830))
355 memsize = MB(48) - KB(range);
356 break;
357 case I915G_GMCH_GMS_STOLEN_64M:
358 if (IS_I9XX(pI830))
359 memsize = MB(64) - KB(range);
360 break;
361 }
362 } else {
363 switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
364 case I830_GMCH_GMS_STOLEN_512:
365 memsize = KB(512) - KB(range);
366 break;
367 case I830_GMCH_GMS_STOLEN_1024:
368 memsize = MB(1) - KB(range);
369 break;
370 case I830_GMCH_GMS_STOLEN_8192:
371 memsize = MB(8) - KB(range);
372 break;
373 case I830_GMCH_GMS_LOCAL:
374 memsize = 0;
375 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
376 "Local memory found, but won't be used.\n");
377 break;
378 }
379 }
380 if (memsize > 0) {
381 fprintf(stderr,
382 "detected %d kB stolen memory.\n", memsize / 1024);
383 } else {
384 fprintf(stderr,
385 "no video memory detected.\n");
386 }
387 return memsize;
388 }
389
390 static int AgpInit(const DRIDriverContext *ctx, I830Rec *info)
391 {
392 unsigned long mode = 0x4;
393
394 if (drmAgpAcquire(ctx->drmFD) < 0) {
395 fprintf(stderr, "[gart] AGP not available\n");
396 return 0;
397 }
398
399 if (drmAgpEnable(ctx->drmFD, mode) < 0) {
400 fprintf(stderr, "[gart] AGP not enabled\n");
401 drmAgpRelease(ctx->drmFD);
402 return 0;
403 }
404 else
405 fprintf(stderr, "[gart] AGP enabled at %dx\n", ctx->agpmode);
406
407 return 1;
408 }
409
410 /*
411 * Allocate memory from the given pool. Grow the pool if needed and if
412 * possible.
413 */
414 static unsigned long
415 AllocFromPool(const DRIDriverContext *ctx, I830Rec *pI830,
416 I830MemRange *result, I830MemPool *pool,
417 long size, unsigned long alignment, int flags)
418 {
419 long needed, start, end;
420
421 if (!result || !pool || !size)
422 return 0;
423
424 /* Calculate how much space is needed. */
425 if (alignment <= GTT_PAGE_SIZE)
426 needed = size;
427 else {
428 start = ROUND_TO(pool->Free.Start, alignment);
429 end = ROUND_TO(start + size, alignment);
430 needed = end - pool->Free.Start;
431 }
432 if (needed > pool->Free.Size) {
433 return 0;
434 }
435
436 result->Start = ROUND_TO(pool->Free.Start, alignment);
437 pool->Free.Start += needed;
438 result->End = pool->Free.Start;
439
440 pool->Free.Size = pool->Free.End - pool->Free.Start;
441 result->Size = result->End - result->Start;
442 result->Pool = pool;
443 result->Alignment = alignment;
444 return needed;
445 }
446
447 static unsigned long AllocFromAGP(const DRIDriverContext *ctx, I830Rec *pI830, long size, unsigned long alignment, I830MemRange *result)
448 {
449 unsigned long start, end;
450 unsigned long newApStart, newApEnd;
451 int ret;
452 if (!result || !size)
453 return 0;
454
455 if (!alignment)
456 alignment = 4;
457
458 start = ROUND_TO(pI830->MemoryAperture.Start, alignment);
459 end = ROUND_TO(start + size, alignment);
460 newApStart = end;
461 newApEnd = pI830->MemoryAperture.End;
462
463 ret=drmAgpAlloc(ctx->drmFD, size, 0, &(result->Physical), (drm_handle_t *)&(result->Key));
464
465 if (ret)
466 {
467 fprintf(stderr,"drmAgpAlloc failed %d\n", ret);
468 return 0;
469 }
470 pI830->allocatedMemory += size;
471 pI830->MemoryAperture.Start = newApStart;
472 pI830->MemoryAperture.End = newApEnd;
473 pI830->MemoryAperture.Size = newApEnd - newApStart;
474 // pI830->FreeMemory -= size;
475 result->Start = start;
476 result->End = start + size;
477 result->Size = size;
478 result->Offset = start;
479 result->Alignment = alignment;
480 result->Pool = NULL;
481
482 return size;
483 }
484
485 unsigned long
486 I830AllocVidMem(const DRIDriverContext *ctx, I830Rec *pI830, I830MemRange *result, I830MemPool *pool, long size, unsigned long alignment, int flags)
487 {
488 int ret;
489
490 if (!result)
491 return 0;
492
493 /* Make sure these are initialised. */
494 result->Size = 0;
495 result->Key = -1;
496
497 if (!size) {
498 return 0;
499 }
500
501 if (pool->Free.Size < size)
502 return AllocFromAGP(ctx, pI830, size, alignment, result);
503 else
504 {
505 ret = AllocFromPool(ctx, pI830, result, pool, size, alignment, flags);
506
507 if (ret==0)
508 return AllocFromAGP(ctx, pI830, size, alignment, result);
509 return ret;
510 }
511 }
512
513 static Bool BindAgpRange(const DRIDriverContext *ctx, I830MemRange *mem)
514 {
515 if (!mem)
516 return FALSE;
517
518 if (mem->Key == -1)
519 return TRUE;
520
521 return !drmAgpBind(ctx->drmFD, mem->Key, mem->Offset);
522 }
523
524 /* simple memory allocation routines needed */
525 /* put ring buffer in low memory */
526 /* need to allocate front, back, depth buffers aligned correctly,
527 allocate ring buffer,
528 */
529
530 /* */
531 static Bool
532 I830AllocateMemory(const DRIDriverContext *ctx, I830Rec *pI830)
533 {
534 unsigned long size, ret;
535 unsigned long lines, lineSize, align;
536
537 /* allocate ring buffer */
538 memset(pI830->LpRing, 0, sizeof(I830RingBuffer));
539 pI830->LpRing->mem.Key = -1;
540
541 size = PRIMARY_RINGBUFFER_SIZE;
542
543 ret = I830AllocVidMem(ctx, pI830, &pI830->LpRing->mem, &pI830->StolenPool, size, 0x1000, 0);
544
545 if (ret != size)
546 {
547 fprintf(stderr,"unable to allocate ring buffer %ld\n", ret);
548 return FALSE;
549 }
550
551 pI830->LpRing->tail_mask = pI830->LpRing->mem.Size - 1;
552
553
554 /* allocate front buffer */
555 memset(&(pI830->FrontBuffer), 0, sizeof(pI830->FrontBuffer));
556 pI830->FrontBuffer.Key = -1;
557 pI830->FrontBuffer.Pitch = ctx->shared.virtualWidth;
558
559 align = KB(512);
560
561 lineSize = ctx->shared.virtualWidth * ctx->cpp;
562 lines = (ctx->shared.virtualHeight + 15) / 16 * 16;
563 size = lineSize * lines;
564 size = ROUND_TO_PAGE(size);
565
566 align = GetBestTileAlignment(size);
567
568 ret = I830AllocVidMem(ctx, pI830, &pI830->FrontBuffer, &pI830->StolenPool, size, align, 0);
569 if (ret < size)
570 {
571 fprintf(stderr,"unable to allocate front buffer %ld\n", ret);
572 return FALSE;
573 }
574
575 memset(&(pI830->BackBuffer), 0, sizeof(pI830->BackBuffer));
576 pI830->BackBuffer.Key = -1;
577 pI830->BackBuffer.Pitch = ctx->shared.virtualWidth;
578
579 ret = I830AllocVidMem(ctx, pI830, &pI830->BackBuffer, &pI830->StolenPool, size, align, 0);
580 if (ret < size)
581 {
582 fprintf(stderr,"unable to allocate back buffer %ld\n", ret);
583 return FALSE;
584 }
585
586 memset(&(pI830->DepthBuffer), 0, sizeof(pI830->DepthBuffer));
587 pI830->DepthBuffer.Key = -1;
588 pI830->DepthBuffer.Pitch = ctx->shared.virtualWidth;
589
590 ret = I830AllocVidMem(ctx, pI830, &pI830->DepthBuffer, &pI830->StolenPool, size, align, 0);
591 if (ret < size)
592 {
593 fprintf(stderr,"unable to allocate depth buffer %ld\n", ret);
594 return FALSE;
595 }
596
597 memset(&(pI830->ContextMem), 0, sizeof(pI830->ContextMem));
598 pI830->ContextMem.Key = -1;
599 size = KB(32);
600
601 ret = I830AllocVidMem(ctx, pI830, &pI830->ContextMem, &pI830->StolenPool, size, align, 0);
602 if (ret < size)
603 {
604 fprintf(stderr,"unable to allocate context buffer %ld\n", ret);
605 return FALSE;
606 }
607
608 #if 0
609 memset(&(pI830->TexMem), 0, sizeof(pI830->TexMem));
610 pI830->TexMem.Key = -1;
611
612 size = 32768 * 1024;
613 ret = AllocFromAGP(ctx, pI830, size, align, &pI830->TexMem);
614 if (ret < size)
615 {
616 fprintf(stderr,"unable to allocate texture memory %ld\n", ret);
617 return FALSE;
618 }
619 #endif
620
621 return TRUE;
622 }
623
624 static Bool
625 I830BindMemory(const DRIDriverContext *ctx, I830Rec *pI830)
626 {
627 if (!BindAgpRange(ctx, &pI830->LpRing->mem))
628 return FALSE;
629 if (!BindAgpRange(ctx, &pI830->FrontBuffer))
630 return FALSE;
631 if (!BindAgpRange(ctx, &pI830->BackBuffer))
632 return FALSE;
633 if (!BindAgpRange(ctx, &pI830->DepthBuffer))
634 return FALSE;
635 if (!BindAgpRange(ctx, &pI830->ContextMem))
636 return FALSE;
637 #if 0
638 if (!BindAgpRange(ctx, &pI830->TexMem))
639 return FALSE;
640 #endif
641 return TRUE;
642 }
643
644 static void SetupDRIMM(const DRIDriverContext *ctx, I830Rec *pI830)
645 {
646 unsigned long aperEnd = ROUND_DOWN_TO(pI830->aper_size, GTT_PAGE_SIZE) / GTT_PAGE_SIZE;
647 unsigned long aperStart = ROUND_TO(pI830->aper_size - KB(32768), GTT_PAGE_SIZE) / GTT_PAGE_SIZE;
648
649 fprintf(stderr, "aper size is %08X\n", ctx->shared.fbSize);
650 if (drmMMInit(ctx->drmFD, aperStart, aperEnd - aperStart, DRM_BO_MEM_TT)) {
651 fprintf(stderr,
652 "DRM MM Initialization Failed\n");
653 } else {
654 fprintf(stderr,
655 "DRM MM Initialized at offset 0x%lx length %d page\n", aperStart, aperEnd-aperStart);
656 }
657
658 }
659
660 static Bool
661 I830CleanupDma(const DRIDriverContext *ctx)
662 {
663 drmI830Init info;
664
665 memset(&info, 0, sizeof(drmI830Init));
666 info.func = I830_CLEANUP_DMA;
667
668 if (drmCommandWrite(ctx->drmFD, DRM_I830_INIT,
669 &info, sizeof(drmI830Init))) {
670 fprintf(stderr, "I830 Dma Cleanup Failed\n");
671 return FALSE;
672 }
673
674 return TRUE;
675 }
676
677 static Bool
678 I830InitDma(const DRIDriverContext *ctx, I830Rec *pI830)
679 {
680 I830RingBuffer *ring = pI830->LpRing;
681 drmI830Init info;
682
683 memset(&info, 0, sizeof(drmI830Init));
684 info.func = I830_INIT_DMA;
685
686 info.ring_start = ring->mem.Start + pI830->LinearAddr;
687 info.ring_end = ring->mem.End + pI830->LinearAddr;
688 info.ring_size = ring->mem.Size;
689
690 info.mmio_offset = (unsigned int)ctx->MMIOStart;
691
692 info.sarea_priv_offset = sizeof(drm_sarea_t);
693
694 info.front_offset = pI830->FrontBuffer.Start;
695 info.back_offset = pI830->BackBuffer.Start;
696 info.depth_offset = pI830->DepthBuffer.Start;
697 info.w = ctx->shared.virtualWidth;
698 info.h = ctx->shared.virtualHeight;
699 info.pitch = ctx->shared.virtualWidth;
700 info.back_pitch = pI830->BackBuffer.Pitch;
701 info.depth_pitch = pI830->DepthBuffer.Pitch;
702 info.cpp = ctx->cpp;
703
704 if (drmCommandWrite(ctx->drmFD, DRM_I830_INIT,
705 &info, sizeof(drmI830Init))) {
706 fprintf(stderr,
707 "I830 Dma Initialization Failed\n");
708 return FALSE;
709 }
710
711 return TRUE;
712 }
713
714 static int I830CheckDRMVersion( const DRIDriverContext *ctx,
715 I830Rec *pI830 )
716 {
717 drmVersionPtr version;
718
719 version = drmGetVersion(ctx->drmFD);
720
721 if (version) {
722 int req_minor, req_patch;
723
724 req_minor = 4;
725 req_patch = 0;
726
727 if (version->version_major != 1 ||
728 version->version_minor < req_minor ||
729 (version->version_minor == req_minor &&
730 version->version_patchlevel < req_patch)) {
731 /* Incompatible drm version */
732 fprintf(stderr,
733 "[dri] I830DRIScreenInit failed because of a version "
734 "mismatch.\n"
735 "[dri] i915.o kernel module version is %d.%d.%d "
736 "but version 1.%d.%d or newer is needed.\n"
737 "[dri] Disabling DRI.\n",
738 version->version_major,
739 version->version_minor,
740 version->version_patchlevel,
741 req_minor,
742 req_patch);
743 drmFreeVersion(version);
744 return 0;
745 }
746
747 pI830->drmMinor = version->version_minor;
748 drmFreeVersion(version);
749 }
750 return 1;
751 }
752
753 static void
754 I830SetRingRegs(const DRIDriverContext *ctx, I830Rec *pI830)
755 {
756 unsigned int itemp;
757 unsigned char *MMIO = ctx->MMIOAddress;
758
759 OUTREG(LP_RING + RING_LEN, 0);
760 OUTREG(LP_RING + RING_TAIL, 0);
761 OUTREG(LP_RING + RING_HEAD, 0);
762
763 if ((long)(pI830->LpRing->mem.Start & I830_RING_START_MASK) !=
764 pI830->LpRing->mem.Start) {
765 fprintf(stderr,
766 "I830SetRingRegs: Ring buffer start (%lx) violates its "
767 "mask (%x)\n", pI830->LpRing->mem.Start, I830_RING_START_MASK);
768 }
769 /* Don't care about the old value. Reserved bits must be zero anyway. */
770 itemp = pI830->LpRing->mem.Start & I830_RING_START_MASK;
771 OUTREG(LP_RING + RING_START, itemp);
772
773 if (((pI830->LpRing->mem.Size - 4096) & I830_RING_NR_PAGES) !=
774 pI830->LpRing->mem.Size - 4096) {
775 fprintf(stderr,
776 "I830SetRingRegs: Ring buffer size - 4096 (%lx) violates its "
777 "mask (%x)\n", pI830->LpRing->mem.Size - 4096,
778 I830_RING_NR_PAGES);
779 }
780 /* Don't care about the old value. Reserved bits must be zero anyway. */
781 itemp = (pI830->LpRing->mem.Size - 4096) & I830_RING_NR_PAGES;
782 itemp |= (RING_NO_REPORT | RING_VALID);
783 OUTREG(LP_RING + RING_LEN, itemp);
784
785 pI830->LpRing->head = INREG(LP_RING + RING_HEAD) & I830_HEAD_MASK;
786 pI830->LpRing->tail = INREG(LP_RING + RING_TAIL);
787 pI830->LpRing->space = pI830->LpRing->head - (pI830->LpRing->tail + 8);
788 if (pI830->LpRing->space < 0)
789 pI830->LpRing->space += pI830->LpRing->mem.Size;
790
791 SetFenceRegs(ctx, pI830);
792
793 /* RESET THE DISPLAY PIPE TO POINT TO THE FRONTBUFFER - hacky
794 hacky hacky */
795 OUTREG(DSPABASE, pI830->FrontBuffer.Start + pI830->LinearAddr);
796
797 }
798
799 static Bool
800 I830SetParam(const DRIDriverContext *ctx, int param, int value)
801 {
802 drmI830SetParam sp;
803
804 memset(&sp, 0, sizeof(sp));
805 sp.param = param;
806 sp.value = value;
807
808 if (drmCommandWrite(ctx->drmFD, DRM_I830_SETPARAM, &sp, sizeof(sp))) {
809 fprintf(stderr, "I830 SetParam Failed\n");
810 return FALSE;
811 }
812
813 return TRUE;
814 }
815
816 static Bool
817 I830DRIMapScreenRegions(DRIDriverContext *ctx, I830Rec *pI830, drmI830Sarea *sarea)
818 {
819 fprintf(stderr,
820 "[drm] Mapping front buffer\n");
821
822 if (drmAddMap(ctx->drmFD,
823 (drm_handle_t)(sarea->front_offset + pI830->LinearAddr),
824 sarea->front_size,
825 DRM_FRAME_BUFFER, /*DRM_AGP,*/
826 0,
827 &sarea->front_handle) < 0) {
828 fprintf(stderr,
829 "[drm] drmAddMap(front_handle) failed. Disabling DRI\n");
830 return FALSE;
831 }
832 ctx->shared.hFrameBuffer = sarea->front_handle;
833 ctx->shared.fbSize = sarea->front_size;
834 fprintf(stderr, "[drm] Front Buffer = 0x%08x\n",
835 sarea->front_handle);
836
837 if (drmAddMap(ctx->drmFD,
838 (drm_handle_t)(sarea->back_offset),
839 sarea->back_size, DRM_AGP, 0,
840 &sarea->back_handle) < 0) {
841 fprintf(stderr,
842 "[drm] drmAddMap(back_handle) failed. Disabling DRI\n");
843 return FALSE;
844 }
845 fprintf(stderr, "[drm] Back Buffer = 0x%08x\n",
846 sarea->back_handle);
847
848 if (drmAddMap(ctx->drmFD,
849 (drm_handle_t)sarea->depth_offset,
850 sarea->depth_size, DRM_AGP, 0,
851 &sarea->depth_handle) < 0) {
852 fprintf(stderr,
853 "[drm] drmAddMap(depth_handle) failed. Disabling DRI\n");
854 return FALSE;
855 }
856 fprintf(stderr, "[drm] Depth Buffer = 0x%08x\n",
857 sarea->depth_handle);
858
859 #if 0
860 if (drmAddMap(ctx->drmFD,
861 (drm_handle_t)sarea->tex_offset,
862 sarea->tex_size, DRM_AGP, 0,
863 &sarea->tex_handle) < 0) {
864 fprintf(stderr,
865 "[drm] drmAddMap(tex_handle) failed. Disabling DRI\n");
866 return FALSE;
867 }
868 fprintf(stderr, "[drm] textures = 0x%08x\n",
869 sarea->tex_handle);
870 #endif
871 return TRUE;
872 }
873
874
875 static void
876 I830DRIUnmapScreenRegions(const DRIDriverContext *ctx, I830Rec *pI830, drmI830Sarea *sarea)
877 {
878 #if 1
879 if (sarea->front_handle) {
880 drmRmMap(ctx->drmFD, sarea->front_handle);
881 sarea->front_handle = 0;
882 }
883 #endif
884 if (sarea->back_handle) {
885 drmRmMap(ctx->drmFD, sarea->back_handle);
886 sarea->back_handle = 0;
887 }
888 if (sarea->depth_handle) {
889 drmRmMap(ctx->drmFD, sarea->depth_handle);
890 sarea->depth_handle = 0;
891 }
892 if (sarea->tex_handle) {
893 drmRmMap(ctx->drmFD, sarea->tex_handle);
894 sarea->tex_handle = 0;
895 }
896 }
897
898 #if 0
899 static void
900 I830InitTextureHeap(const DRIDriverContext *ctx, I830Rec *pI830, drmI830Sarea *sarea)
901 {
902 /* Start up the simple memory manager for agp space */
903 drmI830MemInitHeap drmHeap;
904 drmHeap.region = I830_MEM_REGION_AGP;
905 drmHeap.start = 0;
906 drmHeap.size = sarea->tex_size;
907
908 if (drmCommandWrite(ctx->drmFD, DRM_I830_INIT_HEAP,
909 &drmHeap, sizeof(drmHeap))) {
910 fprintf(stderr,
911 "[drm] Failed to initialized agp heap manager\n");
912 } else {
913 fprintf(stderr,
914 "[drm] Initialized kernel agp heap manager, %d\n",
915 sarea->tex_size);
916
917 I830SetParam(ctx, I830_SETPARAM_TEX_LRU_LOG_GRANULARITY,
918 sarea->log_tex_granularity);
919 }
920 }
921 #endif
922
923 static Bool
924 I830DRIDoMappings(DRIDriverContext *ctx, I830Rec *pI830, drmI830Sarea *sarea)
925 {
926 if (drmAddMap(ctx->drmFD,
927 (drm_handle_t)pI830->LpRing->mem.Start,
928 pI830->LpRing->mem.Size, DRM_AGP, 0,
929 &pI830->ring_map) < 0) {
930 fprintf(stderr,
931 "[drm] drmAddMap(ring_map) failed. Disabling DRI\n");
932 return FALSE;
933 }
934 fprintf(stderr, "[drm] ring buffer = 0x%08x\n",
935 pI830->ring_map);
936
937 if (I830InitDma(ctx, pI830) == FALSE) {
938 return FALSE;
939 }
940
941 /* init to zero to be safe */
942
943 I830DRIMapScreenRegions(ctx, pI830, sarea);
944 SetupDRIMM(ctx, pI830);
945
946 #if 0
947 I830InitTextureHeap(ctx, pI830, sarea);
948 #endif
949 if (ctx->pciDevice != PCI_CHIP_845_G &&
950 ctx->pciDevice != PCI_CHIP_I830_M) {
951 I830SetParam(ctx, I830_SETPARAM_USE_MI_BATCHBUFFER_START, 1 );
952 }
953
954 /* Okay now initialize the dma engine */
955 {
956 pI830->irq = drmGetInterruptFromBusID(ctx->drmFD,
957 ctx->pciBus,
958 ctx->pciDevice,
959 ctx->pciFunc);
960
961 if (drmCtlInstHandler(ctx->drmFD, pI830->irq)) {
962 fprintf(stderr,
963 "[drm] failure adding irq handler\n");
964 pI830->irq = 0;
965 return FALSE;
966 }
967 else
968 fprintf(stderr,
969 "[drm] dma control initialized, using IRQ %d\n",
970 pI830->irq);
971 }
972
973 fprintf(stderr, "[dri] visual configs initialized\n");
974
975 return TRUE;
976 }
977
978 static Bool
979 I830ClearScreen(DRIDriverContext *ctx, I830Rec *pI830, drmI830Sarea *sarea)
980 {
981 /* need to drmMap front and back buffers and zero them */
982 drmAddress map_addr;
983 int ret;
984
985 ret = drmMap(ctx->drmFD,
986 sarea->front_handle,
987 sarea->front_size,
988 &map_addr);
989
990 if (ret)
991 {
992 fprintf(stderr, "Unable to map front buffer\n");
993 return FALSE;
994 }
995
996 drimemsetio((char *)map_addr,
997 0,
998 sarea->front_size);
999 drmUnmap(map_addr, sarea->front_size);
1000
1001
1002 ret = drmMap(ctx->drmFD,
1003 sarea->back_handle,
1004 sarea->back_size,
1005 &map_addr);
1006
1007 if (ret)
1008 {
1009 fprintf(stderr, "Unable to map back buffer\n");
1010 return FALSE;
1011 }
1012
1013 drimemsetio((char *)map_addr,
1014 0,
1015 sarea->back_size);
1016 drmUnmap(map_addr, sarea->back_size);
1017
1018 return TRUE;
1019 }
1020
1021 static Bool
1022 I830ScreenInit(DRIDriverContext *ctx, I830Rec *pI830)
1023
1024 {
1025 I830DRIPtr pI830DRI;
1026 drmI830Sarea *pSAREAPriv;
1027 int err;
1028
1029 drm_page_size = getpagesize();
1030
1031 pI830->registerSize = ctx->MMIOSize;
1032 /* This is a hack for now. We have to have more than a 4k page here
1033 * because of the size of the state. However, the state should be
1034 * in a per-context mapping. This will be added in the Mesa 3.5 port
1035 * of the I830 driver.
1036 */
1037 ctx->shared.SAREASize = SAREA_MAX;
1038
1039 /* Note that drmOpen will try to load the kernel module, if needed. */
1040 ctx->drmFD = drmOpen("i915", NULL );
1041 if (ctx->drmFD < 0) {
1042 fprintf(stderr, "[drm] drmOpen failed\n");
1043 return 0;
1044 }
1045
1046 if ((err = drmSetBusid(ctx->drmFD, ctx->pciBusID)) < 0) {
1047 fprintf(stderr, "[drm] drmSetBusid failed (%d, %s), %s\n",
1048 ctx->drmFD, ctx->pciBusID, strerror(-err));
1049 return 0;
1050 }
1051
1052 if (drmAddMap( ctx->drmFD,
1053 0,
1054 ctx->shared.SAREASize,
1055 DRM_SHM,
1056 DRM_CONTAINS_LOCK,
1057 &ctx->shared.hSAREA) < 0)
1058 {
1059 fprintf(stderr, "[drm] drmAddMap failed\n");
1060 return 0;
1061 }
1062
1063 fprintf(stderr, "[drm] added %d byte SAREA at 0x%08x\n",
1064 ctx->shared.SAREASize, ctx->shared.hSAREA);
1065
1066 if (drmMap( ctx->drmFD,
1067 ctx->shared.hSAREA,
1068 ctx->shared.SAREASize,
1069 (drmAddressPtr)(&ctx->pSAREA)) < 0)
1070 {
1071 fprintf(stderr, "[drm] drmMap failed\n");
1072 return 0;
1073
1074 }
1075
1076 memset(ctx->pSAREA, 0, ctx->shared.SAREASize);
1077 fprintf(stderr, "[drm] mapped SAREA 0x%08x to %p, size %d\n",
1078 ctx->shared.hSAREA, ctx->pSAREA, ctx->shared.SAREASize);
1079
1080
1081 if (drmAddMap(ctx->drmFD,
1082 ctx->MMIOStart,
1083 ctx->MMIOSize,
1084 DRM_REGISTERS,
1085 DRM_READ_ONLY,
1086 &pI830->registerHandle) < 0) {
1087 fprintf(stderr, "[drm] drmAddMap mmio failed\n");
1088 return 0;
1089 }
1090 fprintf(stderr,
1091 "[drm] register handle = 0x%08x\n", pI830->registerHandle);
1092
1093
1094 if (!I830CheckDRMVersion(ctx, pI830)) {
1095 return FALSE;
1096 }
1097
1098 /* Create a 'server' context so we can grab the lock for
1099 * initialization ioctls.
1100 */
1101 if ((err = drmCreateContext(ctx->drmFD, &ctx->serverContext)) != 0) {
1102 fprintf(stderr, "%s: drmCreateContext failed %d\n", __FUNCTION__, err);
1103 return 0;
1104 }
1105
1106 DRM_LOCK(ctx->drmFD, ctx->pSAREA, ctx->serverContext, 0);
1107
1108 /* Initialize the SAREA private data structure */
1109 pSAREAPriv = (drmI830Sarea *)(((char*)ctx->pSAREA) +
1110 sizeof(drm_sarea_t));
1111 memset(pSAREAPriv, 0, sizeof(*pSAREAPriv));
1112
1113 pI830->StolenMemory.Size = I830DetectMemory(ctx, pI830);
1114 pI830->StolenMemory.Start = 0;
1115 pI830->StolenMemory.End = pI830->StolenMemory.Size;
1116
1117 pI830->MemoryAperture.Start = pI830->StolenMemory.End;
1118 pI830->MemoryAperture.End = KB(40000);
1119 pI830->MemoryAperture.Size = pI830->MemoryAperture.End - pI830->MemoryAperture.Start;
1120
1121 pI830->StolenPool.Fixed = pI830->StolenMemory;
1122 pI830->StolenPool.Total = pI830->StolenMemory;
1123 pI830->StolenPool.Free = pI830->StolenPool.Total;
1124 pI830->FreeMemory = pI830->StolenPool.Total.Size;
1125
1126 if (!AgpInit(ctx, pI830))
1127 return FALSE;
1128
1129 if (I830AllocateMemory(ctx, pI830) == FALSE)
1130 {
1131 return FALSE;
1132 }
1133
1134 if (I830BindMemory(ctx, pI830) == FALSE)
1135 {
1136 return FALSE;
1137 }
1138
1139 pSAREAPriv->rotated_offset = -1;
1140 pSAREAPriv->rotated_size = 0;
1141 pSAREAPriv->rotated_pitch = ctx->shared.virtualWidth;
1142
1143 pSAREAPriv->front_offset = pI830->FrontBuffer.Start;
1144 pSAREAPriv->front_size = pI830->FrontBuffer.Size;
1145 pSAREAPriv->width = ctx->shared.virtualWidth;
1146 pSAREAPriv->height = ctx->shared.virtualHeight;
1147 pSAREAPriv->pitch = ctx->shared.virtualWidth;
1148 pSAREAPriv->virtualX = ctx->shared.virtualWidth;
1149 pSAREAPriv->virtualY = ctx->shared.virtualHeight;
1150 pSAREAPriv->back_offset = pI830->BackBuffer.Start;
1151 pSAREAPriv->back_size = pI830->BackBuffer.Size;
1152 pSAREAPriv->depth_offset = pI830->DepthBuffer.Start;
1153 pSAREAPriv->depth_size = pI830->DepthBuffer.Size;
1154 #if 0
1155 pSAREAPriv->tex_offset = pI830->TexMem.Start;
1156 pSAREAPriv->tex_size = pI830->TexMem.Size;
1157 #endif
1158 pSAREAPriv->log_tex_granularity = pI830->TexGranularity;
1159
1160 ctx->driverClientMsg = malloc(sizeof(I830DRIRec));
1161 ctx->driverClientMsgSize = sizeof(I830DRIRec);
1162 pI830DRI = (I830DRIPtr)ctx->driverClientMsg;
1163 pI830DRI->deviceID = pI830->Chipset;
1164 pI830DRI->regsSize = I830_REG_SIZE;
1165 pI830DRI->width = ctx->shared.virtualWidth;
1166 pI830DRI->height = ctx->shared.virtualHeight;
1167 pI830DRI->mem = ctx->shared.fbSize;
1168 pI830DRI->cpp = ctx->cpp;
1169
1170 pI830DRI->bitsPerPixel = ctx->bpp;
1171 pI830DRI->sarea_priv_offset = sizeof(drm_sarea_t);
1172
1173 err = I830DRIDoMappings(ctx, pI830, pSAREAPriv);
1174 if (err == FALSE)
1175 return FALSE;
1176
1177 I830SetupMemoryTiling(ctx, pI830);
1178
1179 /* Quick hack to clear the front & back buffers. Could also use
1180 * the clear ioctl to do this, but would need to setup hw state
1181 * first.
1182 */
1183 I830ClearScreen(ctx, pI830, pSAREAPriv);
1184
1185 I830SetRingRegs(ctx, pI830);
1186
1187 return TRUE;
1188 }
1189
1190
1191 /**
1192 * \brief Validate the fbdev mode.
1193 *
1194 * \param ctx display handle.
1195 *
1196 * \return one on success, or zero on failure.
1197 *
1198 * Saves some registers and returns 1.
1199 *
1200 * \sa radeonValidateMode().
1201 */
1202 static int i830ValidateMode( const DRIDriverContext *ctx )
1203 {
1204 return 1;
1205 }
1206
1207 /**
1208 * \brief Examine mode returned by fbdev.
1209 *
1210 * \param ctx display handle.
1211 *
1212 * \return one on success, or zero on failure.
1213 *
1214 * Restores registers that fbdev has clobbered and returns 1.
1215 *
1216 * \sa i810ValidateMode().
1217 */
1218 static int i830PostValidateMode( const DRIDriverContext *ctx )
1219 {
1220 I830Rec *pI830 = ctx->driverPrivate;
1221
1222 I830SetRingRegs(ctx, pI830);
1223 return 1;
1224 }
1225
1226
1227 /**
1228 * \brief Initialize the framebuffer device mode
1229 *
1230 * \param ctx display handle.
1231 *
1232 * \return one on success, or zero on failure.
1233 *
1234 * Fills in \p info with some default values and some information from \p ctx
1235 * and then calls I810ScreenInit() for the screen initialization.
1236 *
1237 * Before exiting clears the framebuffer memory accessing it directly.
1238 */
1239 static int i830InitFBDev( DRIDriverContext *ctx )
1240 {
1241 I830Rec *pI830 = calloc(1, sizeof(I830Rec));
1242 int i;
1243
1244 {
1245 int dummy = ctx->shared.virtualWidth;
1246
1247 switch (ctx->bpp / 8) {
1248 case 1: dummy = (ctx->shared.virtualWidth + 127) & ~127; break;
1249 case 2: dummy = (ctx->shared.virtualWidth + 31) & ~31; break;
1250 case 3:
1251 case 4: dummy = (ctx->shared.virtualWidth + 15) & ~15; break;
1252 }
1253
1254 ctx->shared.virtualWidth = dummy;
1255 ctx->shared.Width = ctx->shared.virtualWidth;
1256 }
1257
1258
1259 for (i = 0; pitches[i] != 0; i++) {
1260 if (pitches[i] >= ctx->shared.virtualWidth) {
1261 ctx->shared.virtualWidth = pitches[i];
1262 break;
1263 }
1264 }
1265
1266 ctx->driverPrivate = (void *)pI830;
1267
1268 pI830->LpRing = calloc(1, sizeof(I830RingBuffer));
1269 pI830->Chipset = ctx->chipset;
1270 pI830->LinearAddr = ctx->FBStart;
1271
1272 if (!I830ScreenInit( ctx, pI830 ))
1273 return 0;
1274
1275
1276 return 1;
1277 }
1278
1279
1280 /**
1281 * \brief The screen is being closed, so clean up any state and free any
1282 * resources used by the DRI.
1283 *
1284 * \param ctx display handle.
1285 *
1286 * Unmaps the SAREA, closes the DRM device file descriptor and frees the driver
1287 * private data.
1288 */
1289 static void i830HaltFBDev( DRIDriverContext *ctx )
1290 {
1291 drmI830Sarea *pSAREAPriv;
1292 I830Rec *pI830 = ctx->driverPrivate;
1293
1294 if (pI830->irq) {
1295 drmCtlUninstHandler(ctx->drmFD);
1296 pI830->irq = 0; }
1297
1298 I830CleanupDma(ctx);
1299
1300 pSAREAPriv = (drmI830Sarea *)(((char*)ctx->pSAREA) +
1301 sizeof(drm_sarea_t));
1302
1303 I830DRIUnmapScreenRegions(ctx, pI830, pSAREAPriv);
1304 drmUnmap( ctx->pSAREA, ctx->shared.SAREASize );
1305 drmClose(ctx->drmFD);
1306
1307 if (ctx->driverPrivate) {
1308 free(ctx->driverPrivate);
1309 ctx->driverPrivate = 0;
1310 }
1311 }
1312
1313
1314 extern void i810NotifyFocus( int );
1315
1316 /**
1317 * \brief Exported driver interface for Mini GLX.
1318 *
1319 * \sa DRIDriverRec.
1320 */
1321 const struct DRIDriverRec __driDriver = {
1322 i830ValidateMode,
1323 i830PostValidateMode,
1324 i830InitFBDev,
1325 i830HaltFBDev,
1326 NULL,//I830EngineShutdown,
1327 NULL, //I830EngineRestore,
1328 #ifndef _EMBEDDED
1329 0,
1330 #else
1331 i810NotifyFocus,
1332 #endif
1333 };