#include #include #include "fns.h" #include "reg.h" #include "ring.h" #include "pci.h" enum { KB = 1024UL, MB = KB*KB, BY2PG = 4096UL, SEGSIZE = BY2PG, }; char segname[] = "igfxring"; uintptr mkseg(void) { int fd, n; char buf[128], *fl[5]; uintptr pa; snprint(buf, sizeof(buf), "#g/%s", segname); if((fd = create(buf, OREAD|OEXCL, DMDIR|0755)) < 0) sysfatal("can't create segment: %r"); close(fd); snprint(buf, sizeof(buf), "#g/%s/ctl", segname); if((fd = open(buf, ORDWR|OTRUNC)) < 0) sysfatal("cant open segment ctl: %r"); snprint(buf, sizeof(buf), "va 0x20000000 %#lux fixed", SEGSIZE); if(write(fd, buf, strlen(buf)) < 0) sysfatal("write segment ctl: %r"); seek(fd, 0, 0); if((n = read(fd, buf, sizeof(buf))) <= 0) sysfatal("short read segment ctl: %r"); close(fd); buf[n-1] = '\0'; if(getfields(buf, fl, nelem(fl), 0, " ") != nelem(fl)) sysfatal("segment ctl contains wrong #args"); pa = strtoul(fl[4], nil, 16); if(pa == 0) sysfatal("segment ctl has bogus pa"); return pa; } void delseg(void) { char buf[128]; snprint(buf, sizeof(buf), "#g/%s", segname); if(remove(buf) < 0) sysfatal("unable to remove segment: %r"); } void* mapseg(void) { void *v; v = segattach(0, segname, 0, SEGSIZE); if(v == (void*)-1) sysfatal("segattach %s: %r", v); return v; } void unmapseg(void *v) { segdetach(v); } u32int* igfxmmio(void) { void *v, *v32; char *name; name = "igfxmmio"; v = segattach(0, name, 0, 4*MB); if(v == (void*)-1) sysfatal("segattach %s: %r", name); v32 = v; return v32; } static ulong gttsize(u32int *mmio) { u32int pgtbl; pgtbl = mmio[PGTBL_CTL/4]; pgtbl = (pgtbl>>1) & 7; if(pgtbl > 2) return 0; return (512*KB) >> pgtbl; } void gttflush(u32int *mmio) { mmio[GFX_FLSH_CNTL/4] = 0; } static void printpte(int fd, int idx, u32int pte) { u32int pn, pa, typ, valid; pn = pte >> 12; pa = pn << 12; typ = (pte >> 1) & 0x3; valid = pte & 0x1; fprint(fd, "0x%08x | 0x%08ux %01ux %01ux\n", idx*4*1024, pa, typ, valid); } void gttdump(u32int *mmio, void *gtt) { int i, entries, nvalid, fvalid, finvalid; u32int *ptep, pte, valid; entries = gttsize(mmio)/4; nvalid = 0; fvalid = 0; finvalid = 0; print("entries: %d\n", entries); ptep = gtt; print("magic pte:\n"); i = 64*1024/4-5; printpte(1, i, ptep[i]); //return; print("nr | address | type | valid\n"); for(i = 0; i < entries; i++){ pte = ptep[i]; valid = pte & 1; printpte(1, i, pte); if(valid == 1){ nvalid++; if(fvalid == 0) fvalid = i; } else { if(finvalid == 0) finvalid = i; } } print("%d valid entries, %d first invalid\n", nvalid, finvalid); } /* find first invalid entry */ int gttinvalid(u32int *mmio, void *gtt) { int i; ulong nentries; u32int *ptep, pte; nentries = gttsize(mmio); ptep = gtt; for(i = 8191; i < nentries/4; i++){ pte = ptep[i]; //print("gttinvalid: check %032ub\n", pte); if((pte & 1) == 0) return i; } return -1; } uintptr gttmap(u32int *mmio, void *gtt, u32int pa) { int idx; u32int *ptep; uintptr rp; ptep = gtt; idx = gttinvalid(mmio, gtt); if(idx < 0) sysfatal("no free gtt pte"); rp = (uintptr)idx << 12; fprint(2, "gttmap: "); printpte(2, idx, pa|1); gttflush(gtt); ptep[idx] = pa | 1; gttflush(gtt); return rp; } void gttunmap(void *gtt, uintptr gttva) { int idx; u32int *ptep; ptep = gtt; idx = gttva >> 12; fprint(2, "gttunmap: "); printpte(2, idx, ptep[idx]); gttflush(gtt); ptep[idx] = 0; gttflush(gtt); } void dumppci(void) { int i; Pcidev *p; u32int bsm; u64int gttmmadr; p = nil; while((p = pcimatch(p, 0x8086, 0)) != nil){ if(p->tbdf != MKBUS(BusPCI, 0, 2, 0)) continue; if(p->ccrb != 0x3 || p->ccru != 0x0) continue; bsm = pcicfgr32(p, 0x5C); print(" BSM = 0x%08ux\n", bsm); //gttaddr = (u32int)pcicfgr32(p, 0x10); //gttaddr = (gttaddr<<32) | (u32int)pcicfgr32(p, 0x14); gttmmadr = pcicfgr64(p, 0x10); print(" GTTMMADR = 0x%016llux\n", gttmmadr); gttmmadr = pcicfgr64(p, 0x18); print(" GMADR = 0x%016llux\n", gttmmadr); for(i = 0; i < nelem(p->mem); i++){ if(p->mem[i].size == 0) continue; print(" bar %d address 0x%08lux size %d\n", i, p->mem[i].bar, p->mem[i].size); } } } static int dflag = 0; static int pflag = 0; static int gflag = 0; static int wflag = 0; static void usage(void) { fprint(2, "usage: %s\n", argv0); exits("usage"); } void main(int argc, char *argv[]) { int i; char *p; uintptr pa, gttva; void *va, *mmio; Ring ring; pa = 0; gttva = 0; ARGBEGIN{ case 'd': dflag++; break; case 'p': pflag++; break; case 'g': gflag++; break; case 'w': wflag++; p = EARGF(usage()); gttva = (uintptr)strtoul(p, nil, 0); p = EARGF(usage()); pa = (uintptr)strtoul(p, nil, 0); break; default: usage(); }ARGEND /* get igfx mmio */ mmio = igfxmmio(); if(dflag){ dumpshit(mmio); goto putmmio; } if(pflag){ dumppci(); goto putmmio; } /* create ring segment */ void *gtt = ((uchar*)mmio)+(2*MB); if(gflag){ gttdump(mmio, gtt); goto putmmio; } if(wflag){ u32int *ptep = gtt; i = gttva>>12; print("old: "); printpte(1, i, ptep[gttva>>12]); gttflush(gtt); ptep[gttva>>12] = (u32int)pa; ptep[(0x85c000)>>12] = 0xbe85c000 | 1; gttflush(gtt); print("new: "); printpte(1, i, ptep[gttva>>12]); goto putmmio; } pa = mkseg(); print("pa %#p\n", (void*)pa); va = mapseg(); print("va %#p\n", va); gttva = gttmap(mmio, gtt, pa); print("gttva %#p\n", gttva); if(ringinit(&ring, mmio, va, gttva) < 0){ fprint(2, "ring init failed: %r\n"); goto putgtt; } dumpring(mmio); print("start ring\n"); if(ringstart(&ring) < 0){ fprint(2, "ring start failed: %r\n"); goto putgtt; } for(i = 0; i < 10; i++){ dumpring(mmio); if(ringbusy(&ring) == 0) break; sleep(100); } dumpring(mmio); print("stop ring\n"); ringstop(&ring); dumpring(mmio); putgtt: gttunmap(gtt, gttva); /* put ring segment */ unmapseg(va); delseg(); dumpring(mmio); dumpshit(mmio); putmmio: /* put igfx mmio */ unmapseg(mmio); exits(nil); }