ref: f4880742fd204d538168c8bae11ba2935b2b13d6
parent: 3356e0e731bb8e0f4c82caebe358fae2c8fc9113
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Nov 12 19:48:46 EST 2017
igfx: allocate backing memory for framebuffer and hw cursor when not done by bios (from qu7uux) new approach to graphics memory management: the kernel driver never really cared about the size of stolen memory directly. that was only to figure out the maximum allocation to place the hardware cursor image somewhere at the end of the allocation done by bios. qu7uux's gm965 bios however wont steal enougth memory for his native resolution so we have todo it manually. the userspace igfx driver will figure out how much the bios allocated by looking at the gtt only. then extend the memory by creating a "fixed" physical segment. the kernel driver allocates the memory for the cursor image from normal kernel memory, and just maps it into the gtt at the end of the virtual kernel framebuffer aperture. thanks to qu7uux for the patch.
--- a/sys/src/9/pc/vgaigfx.c
+++ b/sys/src/9/pc/vgaigfx.c
@@ -12,72 +12,24 @@
#include <cursor.h>
#include "screen.h"
-static ulong
-stolenmb(Pcidev *p)
-{
- switch(p->did){
- case 0x0412: /* Haswell HD Graphics 4600 */
- case 0x0a16: /* Haswell HD Graphics 4400 */
- case 0x0126: /* Sandy Bridge HD Graphics 3000 */
- case 0x0166: /* Ivy Bridge */
- case 0x0102: /* Core-5 Sandy Bridge */
- case 0x0152: /* Core-i3 */
- switch((pcicfgr16(p, 0x50) >> 3) & 0x1f){
- case 0x01: return 32 - 2;
- case 0x02: return 64 - 2; /* 0102 Dell machine here */
- case 0x03: return 96 - 2;
- case 0x04: return 128 - 2;
- case 0x05: return 32 - 2;
- case 0x06: return 48 - 2;
- case 0x07: return 64 - 2;
- case 0x08: return 128 - 2;
- case 0x09: return 256 - 2;
- case 0x0A: return 96 - 2;
- case 0x0B: return 160 - 2;
- case 0x0C: return 224 - 2;
- case 0x0D: return 352 - 2;
- case 0x0E: return 448 - 2;
- case 0x0F: return 480 - 2;
- case 0x10: return 512 - 2;
- }
- break;
- case 0x2a42: /* X200 */
- case 0x29a2: /* 82P965/G965 HECI desktop */
- case 0x2a02: /* CF-R7 */
- switch((pcicfgr16(p, 0x52) >> 4) & 7){
- case 0x01: return 1;
- case 0x02: return 4;
- case 0x03: return 8;
- case 0x04: return 16;
- case 0x05: return 32;
- case 0x06: return 48;
- case 0x07: return 64;
- }
- break;
- }
- return 0;
-}
-
static uintptr
-gmsize(Pcidev *pci, void *mmio)
+igfxcuralloc(Pcidev *pci, void *mmio, int apsize)
{
- u32int x, i, npg, *gtt;
+ int n;
+ u32int pa, *buf, *p, *e;
- npg = stolenmb(pci)<<(20-12);
- if(npg == 0)
+ buf = mallocalign(64*64*4, BY2PG, 0, 0);
+ if(buf == nil){
+ print("igfx: no memory for cursor image\n");
return 0;
- gtt = (u32int*)((uchar*)mmio + pci->mem[0].size/2);
- if((gtt[0]&1) == 0)
- return 0;
- x = (gtt[0]>>12)+1;
- for(i=1; i<npg; i++){
- if((gtt[i]&1) == 0 || (gtt[i]>>12) != x)
- break;
- x++;
}
- if(0) print("igfx: graphics memory at %p-%p (%ud MB)\n",
- (uintptr)(x-i)<<12, (uintptr)x<<12, (i>>(20-12)));
- return (uintptr)i<<12;
+ n = (apsize > 128*MB ? 128*1024 : apsize/1024) / 4 - 4;
+ p = (u32int*)((uchar*)mmio + pci->mem[0].size/2) + n;
+ *(u32int*)((uchar*)mmio + 0x2170) = 0; /* flush write buffers */
+ for(e=p+4, pa=PADDR(buf); p<e; p++, pa+=1<<12)
+ *p = pa | 1;
+ *(u32int*)((uchar*)mmio + 0x2170) = 0; /* flush write buffers */
+ return (uintptr)n << 12;
}
static void
@@ -98,13 +50,7 @@
vgalinearpci(scr);
if(scr->apsize){
addvgaseg("igfxscreen", scr->paddr, scr->apsize);
- scr->storage = gmsize(p, scr->mmio);
- if(scr->storage < MB)
- scr->storage = 0;
- else if(scr->storage > scr->apsize)
- scr->storage = scr->apsize;
- if(scr->storage != 0)
- scr->storage -= PGROUND(64*64*4);
+ scr->storage = igfxcuralloc(p, scr->mmio, scr->apsize);
}
scr->softscreen = 1;
}
--- a/sys/src/cmd/aux/vga/igfx.c
+++ b/sys/src/cmd/aux/vga/igfx.c
@@ -1593,6 +1593,76 @@
csr(igfx, igfx->dpllsel[0].a, 8<<(x*4), 0);
}
+void
+checkgtt(Igfx *igfx, Mode *m)
+{
+ int fd, c;
+ ulong n;
+ char buf[64], *fl[5];
+ u32int i, j, pa, nilpte, *gtt;
+
+ if(igfx->mmio == nil)
+ return;
+ gtt = (u32int*)((uchar*)igfx->mmio + igfx->pci->mem[0].size/2);
+ pa = (gtt[0] & ~((1<<12)-1)) + (1<<12) | 1;
+ for(i=1; i<64*1024/4-4; i++, pa+=1<<12)
+ if((gtt[i] & ~((1<<11)-1<<1)) != pa)
+ break;
+ n = m->x * m->y * m->z / 8;
+ if(i<<12 >= n)
+ return;
+
+ /* unmap pages past stolen memory */
+ nilpte = gtt[64*1024/4-5];
+ wr(igfx, 0x2170, 0); /* flush write buffers */
+ for(j=i; j<64*1024/4-5; j++){
+ if((gtt[j] & 1) == 0 || (gtt[j] & ~((1<<11)-1<<1)) == pa)
+ break;
+ pa = gtt[j];
+ gtt[j] = nilpte;
+ }
+ wr(igfx, 0x2170, 0); /* flush write buffers */
+
+ trace("%s: mapping %lud additional bytes for requested mode\n", igfx->ctlr->name, n - (i<<12));
+ snprint(buf, sizeof buf, "#g/igfxtra");
+ if((fd = open(buf, OREAD)) >= 0){
+ close(fd);
+ if(remove(buf) < 0)
+ goto err;
+ }
+ if((fd = create(buf, OREAD, DMDIR|0777)) < 0)
+ goto err;
+ close(fd);
+ strncat(buf, "/ctl", sizeof(buf)-strlen("/ctl"));
+ if((fd = open(buf, ORDWR|OTRUNC)) < 0)
+ goto err;
+ snprint(buf, sizeof buf, "va 0x10000000 %#lux fixed", n - (i<<12));
+ if(write(fd, buf, strlen(buf)) < 0){
+ close(fd);
+ goto err;
+ }
+ seek(fd, 0, 0);
+ if((c = read(fd, buf, sizeof buf)) <= 0){
+ close(fd);
+ goto err;
+ }
+ close(fd);
+ buf[c-1] = 0;
+ if(getfields(buf, fl, nelem(fl), 0, " ") != nelem(fl)
+ || (pa = strtoul(fl[4], nil, 16)) == 0){
+ werrstr("invalid physical base address");
+ goto err;
+ }
+ n >>= 12;
+ wr(igfx, 0x2170, 0); /* flush write buffers */
+ for(; i<n; i++, pa+=1<<12)
+ gtt[i] = pa | 1;
+ wr(igfx, 0x2170, 0); /* flush write buffers */
+ return;
+err:
+ trace("%s: checkgtt: %r\n", igfx->ctlr->name);
+}
+
static void
load(Vga* vga, Ctlr* ctlr)
{
@@ -1637,6 +1707,9 @@
/* turn off all pipes */
for(x = 0; x < igfx->npipe; x++)
disablepipe(igfx, x);
+
+ /* check if enough memory has been mapped for requested mode */
+ checkgtt(igfx, vga->mode);
if(igfx->type == TypeG45){
/* toggle dsp a on and off (from enable sequence) */