summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2016-12-17 16:35:26 +0100
committercinap_lenrek <cinap_lenrek@felloff.net>2016-12-17 16:35:26 +0100
commitea30cf94a5f247dd00c32c01325b8a47ad5f105a (patch)
treef9fbad860ac9499b11ad56778069b23ce826ca96
parentd48a0894865e810f46e1ef2f07476c4f3101698a (diff)
pat write combinding support for 386 kernel, honor cpuid bits
-rw-r--r--sys/src/9/pc/dat.h1
-rw-r--r--sys/src/9/pc/mmu.c45
-rw-r--r--sys/src/9/pc64/dat.h1
-rw-r--r--sys/src/9/pc64/mmu.c21
4 files changed, 61 insertions, 7 deletions
diff --git a/sys/src/9/pc/dat.h b/sys/src/9/pc/dat.h
index 581bdf73e..f0157652d 100644
--- a/sys/src/9/pc/dat.h
+++ b/sys/src/9/pc/dat.h
@@ -316,6 +316,7 @@ enum {
Mtrr = 1<<12, /* memory-type range regs. */
Pge = 1<<13, /* page global extension */
Mca = 1<<14, /* machine-check architecture */
+ Pat = 1<<16, /* page attribute table */
Pse2 = 1<<17, /* more page size extensions */
Clflush = 1<<19,
Acpif = 1<<22, /* therm control msr */
diff --git a/sys/src/9/pc/mmu.c b/sys/src/9/pc/mmu.c
index d97c9a5b5..3c79f90a3 100644
--- a/sys/src/9/pc/mmu.c
+++ b/sys/src/9/pc/mmu.c
@@ -66,11 +66,17 @@ static void memglobal(void);
#define VPTX(va) (((ulong)(va))>>12)
#define vpd (vpt+VPTX(VPT))
+enum {
+ /* PAT entry used for write combining */
+ PATWC = 7,
+};
+
void
mmuinit(void)
{
ulong x, *p;
ushort ptr[3];
+ vlong v;
if(0) print("vpt=%#.8ux vpd=%#p kmap=%#.8ux\n",
VPT, vpd, KMAP);
@@ -119,6 +125,14 @@ mmuinit(void)
taskswitch(PADDR(m->pdb), (ulong)m + BY2PG);
ltr(TSSSEL);
+
+ /* IA32_PAT write combining */
+ if((MACHP(0)->cpuiddx & Pat) != 0
+ && rdmsr(0x277, &v) != -1){
+ v &= ~(255LL<<(PATWC*8));
+ v |= 1LL<<(PATWC*8); /* WC */
+ wrmsr(0x277, v);
+ }
}
/*
@@ -1065,7 +1079,36 @@ cankaddr(ulong pa)
return -KZERO - pa;
}
+/*
+ * mark pages as write combining (used for framebuffer)
+ */
void
-patwc(void *, int)
+patwc(void *a, int n)
{
+ ulong *pte, mask, attr, va;
+ vlong v;
+ int z;
+
+ /* check if pat is usable */
+ if((MACHP(0)->cpuiddx & Pat) == 0
+ || rdmsr(0x277, &v) == -1
+ || ((v >> PATWC*8) & 7) != 1)
+ return;
+
+ /* set the bits for all pages in range */
+ for(va = (ulong)a; n > 0; n -= z, va += z){
+ pte = mmuwalk(m->pdb, va, 1, 0);
+ if(pte && (*pte & (PTEVALID|PTESIZE)) == (PTEVALID|PTESIZE)){
+ z = 4*MB - (va & (4*MB-1));
+ mask = 3<<3 | 1<<12;
+ } else {
+ pte = mmuwalk(m->pdb, va, 2, 0);
+ if(pte == 0 || (*pte & PTEVALID) == 0)
+ panic("patwc: va=%#p", va);
+ z = BY2PG - (va & (BY2PG-1));
+ mask = 3<<3 | 1<<7;
+ }
+ attr = (((PATWC&3)<<3) | ((PATWC&4)<<5) | ((PATWC&4)<<10));
+ *pte = (*pte & ~mask) | (attr & mask);
+ }
}
diff --git a/sys/src/9/pc64/dat.h b/sys/src/9/pc64/dat.h
index b6333c5ff..e3554a1be 100644
--- a/sys/src/9/pc64/dat.h
+++ b/sys/src/9/pc64/dat.h
@@ -279,6 +279,7 @@ enum {
Mtrr = 1<<12, /* memory-type range regs. */
Pge = 1<<13, /* page global extension */
Mca = 1<<14, /* machine-check architecture */
+ Pat = 1<<16, /* page attribute table */
Pse2 = 1<<17, /* more page size extensions */
Clflush = 1<<19,
Acpif = 1<<22, /* therm control msr */
diff --git a/sys/src/9/pc64/mmu.c b/sys/src/9/pc64/mmu.c
index ffd077e31..6f27ac25e 100644
--- a/sys/src/9/pc64/mmu.c
+++ b/sys/src/9/pc64/mmu.c
@@ -135,10 +135,12 @@ mmuinit(void)
wrmsr(0xc0000084, 0x200);
/* IA32_PAT write combining */
- rdmsr(0x277, &v);
- v &= ~(255LL<<(PATWC*8));
- v |= 1LL<<(PATWC*8); /* WC */
- wrmsr(0x277, v);
+ if((MACHP(0)->cpuiddx & Pat) != 0
+ && rdmsr(0x277, &v) != -1){
+ v &= ~(255LL<<(PATWC*8));
+ v |= 1LL<<(PATWC*8); /* WC */
+ wrmsr(0x277, v);
+ }
}
/*
@@ -549,13 +551,20 @@ vunmap(void *v, int)
* mark pages as write combining (used for framebuffer)
*/
void
-patwc(void *v, int n)
+patwc(void *a, int n)
{
uintptr *pte, mask, attr, va;
int z, l;
+ vlong v;
+
+ /* check if pat is usable */
+ if((MACHP(0)->cpuiddx & Pat) == 0
+ || rdmsr(0x277, &v) == -1
+ || ((v >> PATWC*8) & 7) != 1)
+ return;
/* set the bits for all pages in range */
- for(va = (uintptr)v; n > 0; n -= z, va += z){
+ for(va = (uintptr)a; n > 0; n -= z, va += z){
l = 0;
pte = mmuwalk(m->pml4, va, l, 0);
if(pte == 0)