Dear coreboot folks,
since Linux 3.12+ graphics stolen memory seems to be used, which causes a regression with coreboot and native graphics init at least on the Intel 945 based Lenovo X60 [1].
This seems to be solved by properly setting register `PGETBL_CTL` [2], but the Linux kernel Intel graphics driver still reports a GTT (Graphics Translation Table) related error during start-up, but everything else seems to work.
[ 1.235640] [drm] GPU crash dump saved to /sys/class/drm/card0/error [ 1.236583] [drm] GPU hangs can indicate a bug anywhere in the entire gfx stack, including userspace. [ 1.236583] [drm] Please file a _new_ bug report on bugs.freedesktop.org against DRI -> DRM/Intel [ 1.236583] [drm] drm/i915 developers can then reassign to the right component if it's not a kernel issue. [ 1.236583] [drm] The gpu crash dump is required to analyze gpu hangs, so please always attach it. [ 1.236583] i915: render error detected, EIR: 0x00000010 [ 1.236583] i915: page table error [ 1.236583] i915: PGTBL_ER: 0x00000013 [ 1.236583] [drm:i915_report_and_clear_eir] *ERROR* EIR stuck: 0x00000010, masking [ 1.236583] i915: render error detected, EIR: 0x00000010 [ 1.236583] i915: page table error [ 1.236583] i915: PGTBL_ER: 0x00000013
Looking further into the native graphics init code for Intel IGDs, I wonder what `setgtt()` does.
Looking at Google Link, where this was introduced, there is the code below.
$ nl -ba src/mainboard/google/link/i915.c […] 95 void io_i915_WRITE32(unsigned long val, unsigned long addr) 96 { 97 if (verbose & vio) 98 printk(BIOS_SPEW, "%s: outl %08lx\n", regname(addr), val); 99 outl(addr, addrport); 100 outl(val, dataport); 101 } 102 103 104 /* 105 2560 106 4 words per 107 4 *p 108 10240 109 4k bytes per page 110 4096/p 111 2.50 112 1700 lines 113 1700 * p 114 4250.00 115 PTEs 116 */ 117 static void 118 setgtt(int start, int end, unsigned long base, int inc) 119 { 120 int i; 121 122 for(i = start; i < end; i++){ 123 u32 word = base + i*inc; 124 WRITE32(word|1,(i*4)|1); 125 } 126 } […] 349 /* GTT is the Global Translation Table for the graphics pipeline. 350 * It is used to translate graphics addresses to physical 351 * memory addresses. As in the CPU, GTTs map 4K pages. 352 * There are 32 bits per pixel, or 4 bytes, 353 * which means 1024 pixels per page. 354 * There are 4250 GTTs on Link: 355 * 2650 (X) * 1700 (Y) pixels / 1024 pixels per page. 356 * The setgtt function adds a further bit of flexibility: 357 * it allows you to set a range (the first two parameters) to point 358 * to a physical address (third parameter);the physical address is 359 * incremented by a count (fourth parameter) for each GTT in the 360 * range. 361 * Why do it this way? For ultrafast startup, 362 * we can point all the GTT entries to point to one page, 363 * and set that page to 0s: 364 * memset(physbase, 0, 4096); 365 * setgtt(0, 4250, physbase, 0); 366 * this takes about 2 ms, and is a win because zeroing 367 * the page takes a up to 200 ms. We will be exploiting this 368 * trick in a later rev of this code. 369 * This call sets the GTT to point to a linear range of pages 370 * starting at physbase. 371 */ 372 setgtt(0, FRAME_BUFFER_PAGES, physbase, 4096); 373 printk(BIOS_SPEW, "memset %p to 0 for %d bytes\n", 374 (void *)graphics, FRAME_BUFFER_BYTES); […] $ git grep FRAME_BUFFER src/mainboard/google/link/i915io.h src/mainboard/google/link/i915io.h:#define FRAME_BUFFER_PAGES ((2560*1700)/1024) src/mainboard/google/link/i915io.h:#define FRAME_BUFFER_BYTES (FRAME_BUFFER_PAGES*4096)
Looking at the code of the Lenovo X60 with the resolution of 1024×768, instead of `FRAME_BUFFER_PAGES` = 768 it is the higher number 800. Otherwise there are graphical corruptions on the GRUB screen.
Furthermore Vladimir’s native graphics patch up for review in Gerrit [3] uses the code below [3].
/* Setup GTT. */ for (i = 0; i < 0x2000; i++) { outl((i << 2) | 1, piobase); outl(pphysbase + (i << 12) + 1, piobase + 4); }
This is equivalent to `setgtt(0, 8192, physbase, 4096)`. As the code should be not hardcoded to one resolution (for example the Lenovo T60 has a different one than the Lenovo X60), the code should be dynamic.
Unfortunately, I did not find anything in the datasheet [4][5] explaining, why this `setgtt()` is needed at all. I guess this was figured out by tracing the Video BIOS? Ron, Denis, Peter, Vladimir, it’d be great if you could explain that to me?
At least on Intel 945, the GTT is 256 KB big and is placed below TOLUD into the graphics stolen memory, which is currently hardcoded to 8 MB. So how should the pages be setup then?
Thanks,
Paul
[1] https://bugs.freedesktop.org/show_bug.cgi?id=79038 [2] http://review.coreboot.org/5927 [3] http://review.coreboot.org/#/c/5320/9/src/northbridge/intel/i945/gma.c [4] http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/mobil... [5] https://01.org/linuxgraphics/sites/default/files/documentation/965_g35_vol_1...