xref: /plan9-contrib/sys/src/9k/k10/archk10.c (revision 5ae61b61c8015e599b904d2af12b5be472f0d43e)
19ef1f84bSDavid du Colombier #include "u.h"
29ef1f84bSDavid du Colombier #include "../port/lib.h"
39ef1f84bSDavid du Colombier #include "mem.h"
49ef1f84bSDavid du Colombier #include "dat.h"
59ef1f84bSDavid du Colombier #include "fns.h"
69ef1f84bSDavid du Colombier 
79ef1f84bSDavid du Colombier static int
portwaitfor(int * vp,int val)89ef1f84bSDavid du Colombier portwaitfor(int *vp, int val)
99ef1f84bSDavid du Colombier {
109ef1f84bSDavid du Colombier 	int i;
119ef1f84bSDavid du Colombier 
129ef1f84bSDavid du Colombier 	/*
139ef1f84bSDavid du Colombier 	 * How many times round this loop?
149ef1f84bSDavid du Colombier 	 */
159ef1f84bSDavid du Colombier 	for(i = 0; *vp == val && i < 10000; i++)
169ef1f84bSDavid du Colombier 		;
179ef1f84bSDavid du Colombier 
189ef1f84bSDavid du Colombier 	return *vp;
199ef1f84bSDavid du Colombier }
209ef1f84bSDavid du Colombier 
219ef1f84bSDavid du Colombier int (*waitfor)(int*, int) = portwaitfor;
229ef1f84bSDavid du Colombier 
239ef1f84bSDavid du Colombier extern int k10waitfor(int*, int);
249ef1f84bSDavid du Colombier 
259ef1f84bSDavid du Colombier static int
cpuidinit(void)269ef1f84bSDavid du Colombier cpuidinit(void)
279ef1f84bSDavid du Colombier {
289ef1f84bSDavid du Colombier 	u32int eax, info[4];
299ef1f84bSDavid du Colombier 
309ef1f84bSDavid du Colombier 	/*
319ef1f84bSDavid du Colombier 	 * Standard CPUID functions.
329ef1f84bSDavid du Colombier 	 * Functions 0 and 1 will be needed multiple times
339ef1f84bSDavid du Colombier 	 * so cache the info now.
349ef1f84bSDavid du Colombier 	 */
359ef1f84bSDavid du Colombier 	if((m->ncpuinfos = cpuid(0, 0, m->cpuinfo[0])) == 0)
369ef1f84bSDavid du Colombier 		return 0;
379ef1f84bSDavid du Colombier 	m->ncpuinfos++;
389ef1f84bSDavid du Colombier 
399ef1f84bSDavid du Colombier 	if(memcmp(&m->cpuinfo[0][1], "GenuntelineI", 12) == 0)
409ef1f84bSDavid du Colombier 		m->isintelcpu = 1;
419ef1f84bSDavid du Colombier 	cpuid(1, 0, m->cpuinfo[1]);
429ef1f84bSDavid du Colombier 
439ef1f84bSDavid du Colombier 	/*
449ef1f84bSDavid du Colombier 	 * Extended CPUID functions.
459ef1f84bSDavid du Colombier 	 */
469ef1f84bSDavid du Colombier 	if((eax = cpuid(0x80000000, 0, info)) >= 0x80000000)
479ef1f84bSDavid du Colombier 		m->ncpuinfoe = (eax & ~0x80000000) + 1;
489ef1f84bSDavid du Colombier 
499ef1f84bSDavid du Colombier 	/*
509ef1f84bSDavid du Colombier 	 * Is MONITOR/MWAIT supported?
519ef1f84bSDavid du Colombier 	 */
529ef1f84bSDavid du Colombier 	if(m->cpuinfo[1][2] & 8){
539ef1f84bSDavid du Colombier 		/*
549ef1f84bSDavid du Colombier 		 * Will be interested in parameters,
559ef1f84bSDavid du Colombier 		 * extensions, and hints later; they can be retrieved
569ef1f84bSDavid du Colombier 		 * with standard CPUID function 5.
579ef1f84bSDavid du Colombier 		 */
589ef1f84bSDavid du Colombier 		waitfor = k10waitfor;
599ef1f84bSDavid du Colombier 	}
609ef1f84bSDavid du Colombier 
619ef1f84bSDavid du Colombier 	return 1;
629ef1f84bSDavid du Colombier }
639ef1f84bSDavid du Colombier 
649ef1f84bSDavid du Colombier static int
cpuidinfo(u32int eax,u32int ecx,u32int info[4])659ef1f84bSDavid du Colombier cpuidinfo(u32int eax, u32int ecx, u32int info[4])
669ef1f84bSDavid du Colombier {
679ef1f84bSDavid du Colombier 	if(m->ncpuinfos == 0 && cpuidinit() == 0)
689ef1f84bSDavid du Colombier 		return 0;
699ef1f84bSDavid du Colombier 
709ef1f84bSDavid du Colombier 	if(!(eax & 0x80000000)){
719ef1f84bSDavid du Colombier 		if(eax >= m->ncpuinfos)
729ef1f84bSDavid du Colombier 			return 0;
739ef1f84bSDavid du Colombier 	}
749ef1f84bSDavid du Colombier 	else if(eax >= (0x80000000|m->ncpuinfoe))
759ef1f84bSDavid du Colombier 		return 0;
769ef1f84bSDavid du Colombier 
779ef1f84bSDavid du Colombier 	cpuid(eax, ecx, info);
789ef1f84bSDavid du Colombier 
799ef1f84bSDavid du Colombier 	return 1;
809ef1f84bSDavid du Colombier }
819ef1f84bSDavid du Colombier 
829ef1f84bSDavid du Colombier static vlong
cpuidhz(u32int info[2][4])839ef1f84bSDavid du Colombier cpuidhz(u32int info[2][4])
849ef1f84bSDavid du Colombier {
859ef1f84bSDavid du Colombier 	int f, r;
869ef1f84bSDavid du Colombier 	vlong hz;
879ef1f84bSDavid du Colombier 	u64int msr;
889ef1f84bSDavid du Colombier 
899ef1f84bSDavid du Colombier 	if(memcmp(&info[0][1], "GenuntelineI", 12) == 0){
909ef1f84bSDavid du Colombier 		switch(info[1][0] & 0x0fff3ff0){
919ef1f84bSDavid du Colombier 		default:
929ef1f84bSDavid du Colombier 			return 0;
939ef1f84bSDavid du Colombier 		case 0x00000f30:		/* Xeon (MP), Pentium [4D] */
949ef1f84bSDavid du Colombier 		case 0x00000f40:		/* Xeon (MP), Pentium [4D] */
959ef1f84bSDavid du Colombier 		case 0x00000f60:		/* Xeon 7100, 5000 or above */
969ef1f84bSDavid du Colombier 			msr = rdmsr(0x2c);
979ef1f84bSDavid du Colombier 			r = (msr>>16) & 0x07;
989ef1f84bSDavid du Colombier 			switch(r){
999ef1f84bSDavid du Colombier 			default:
1009ef1f84bSDavid du Colombier 				return 0;
1019ef1f84bSDavid du Colombier 			case 0:
1029ef1f84bSDavid du Colombier 				hz = 266666666666ll;
1039ef1f84bSDavid du Colombier 				break;
1049ef1f84bSDavid du Colombier 			case 1:
1059ef1f84bSDavid du Colombier 				hz = 133333333333ll;
1069ef1f84bSDavid du Colombier 				break;
1079ef1f84bSDavid du Colombier 			case 2:
1089ef1f84bSDavid du Colombier 				hz = 200000000000ll;
1099ef1f84bSDavid du Colombier 				break;
1109ef1f84bSDavid du Colombier 			case 3:
1119ef1f84bSDavid du Colombier 				hz = 166666666666ll;
1129ef1f84bSDavid du Colombier 				break;
1139ef1f84bSDavid du Colombier 			case 4:
1149ef1f84bSDavid du Colombier 				hz = 333333333333ll;
1159ef1f84bSDavid du Colombier 				break;
1169ef1f84bSDavid du Colombier 			}
1179ef1f84bSDavid du Colombier 
1189ef1f84bSDavid du Colombier 			/*
1199ef1f84bSDavid du Colombier 			 * Hz is *1000 at this point.
1209ef1f84bSDavid du Colombier 			 * Do the scaling then round it.
1219ef1f84bSDavid du Colombier 			 * The manual is conflicting about
1229ef1f84bSDavid du Colombier 			 * the size of the msr field.
1239ef1f84bSDavid du Colombier 			 */
1249ef1f84bSDavid du Colombier 			hz = (((hz*(msr>>24))/100)+5)/10;
1259ef1f84bSDavid du Colombier 			break;
1269ef1f84bSDavid du Colombier 		case 0x00000690:		/* Pentium M, Celeron M */
1279ef1f84bSDavid du Colombier 		case 0x000006d0:		/* Pentium M, Celeron M */
1289ef1f84bSDavid du Colombier 			hz = ((rdmsr(0x2a)>>22) & 0x1f)*100 * 1000000ll;
1299ef1f84bSDavid du Colombier 			break;
1309ef1f84bSDavid du Colombier 		case 0x000006e0:		/* Core Duo */
1319ef1f84bSDavid du Colombier 		case 0x000006f0:		/* Core 2 Duo/Quad/Extreme */
1329ef1f84bSDavid du Colombier 		case 0x00010670:		/* Core 2 Extreme */
1339ef1f84bSDavid du Colombier 			/*
1349ef1f84bSDavid du Colombier 			 * Get the FSB frequemcy.
1359ef1f84bSDavid du Colombier 			 * If processor has Enhanced Intel Speedstep Technology
1369ef1f84bSDavid du Colombier 			 * then non-integer bus frequency ratios are possible.
1379ef1f84bSDavid du Colombier 			 */
1389ef1f84bSDavid du Colombier 			if(info[1][2] & 0x00000080){
1399ef1f84bSDavid du Colombier 				msr = rdmsr(0x198);
1409ef1f84bSDavid du Colombier 				r = (msr>>40) & 0x1f;
1419ef1f84bSDavid du Colombier 			}
1429ef1f84bSDavid du Colombier 			else{
1439ef1f84bSDavid du Colombier 				msr = 0;
1449ef1f84bSDavid du Colombier 				r = rdmsr(0x2a) & 0x1f;
1459ef1f84bSDavid du Colombier 			}
1469ef1f84bSDavid du Colombier 			f = rdmsr(0xcd) & 0x07;
1479ef1f84bSDavid du Colombier 			switch(f){
1489ef1f84bSDavid du Colombier 			default:
1499ef1f84bSDavid du Colombier 				return 0;
1509ef1f84bSDavid du Colombier 			case 5:
1519ef1f84bSDavid du Colombier 				hz = 100000000000ll;
1529ef1f84bSDavid du Colombier 				break;
1539ef1f84bSDavid du Colombier 			case 1:
1549ef1f84bSDavid du Colombier 				hz = 133333333333ll;
1559ef1f84bSDavid du Colombier 				break;
1569ef1f84bSDavid du Colombier 			case 3:
1579ef1f84bSDavid du Colombier 				hz = 166666666666ll;
1589ef1f84bSDavid du Colombier 				break;
1599ef1f84bSDavid du Colombier 			case 2:
1609ef1f84bSDavid du Colombier 				hz = 200000000000ll;
1619ef1f84bSDavid du Colombier 				break;
1629ef1f84bSDavid du Colombier 			case 0:
1639ef1f84bSDavid du Colombier 				hz = 266666666666ll;
1649ef1f84bSDavid du Colombier 				break;
1659ef1f84bSDavid du Colombier 			case 4:
1669ef1f84bSDavid du Colombier 				hz = 333333333333ll;
1679ef1f84bSDavid du Colombier 				break;
1689ef1f84bSDavid du Colombier 			case 6:
1699ef1f84bSDavid du Colombier 				hz = 400000000000ll;
1709ef1f84bSDavid du Colombier 				break;
1719ef1f84bSDavid du Colombier 			}
1729ef1f84bSDavid du Colombier 
1739ef1f84bSDavid du Colombier 			/*
1749ef1f84bSDavid du Colombier 			 * Hz is *1000 at this point.
1759ef1f84bSDavid du Colombier 			 * Do the scaling then round it.
1769ef1f84bSDavid du Colombier 			 */
1779ef1f84bSDavid du Colombier 			if(msr & 0x0000400000000000ll)
1789ef1f84bSDavid du Colombier 				hz = hz*r + hz/2;
1799ef1f84bSDavid du Colombier 			else
1809ef1f84bSDavid du Colombier 				hz = hz*r;
1819ef1f84bSDavid du Colombier 			hz = ((hz/100)+5)/10;
1829ef1f84bSDavid du Colombier 			break;
1839ef1f84bSDavid du Colombier 		}
1849ef1f84bSDavid du Colombier 		DBG("cpuidhz: 0x2a: %#llux hz %lld\n", rdmsr(0x2a), hz);
1859ef1f84bSDavid du Colombier 	}
1869ef1f84bSDavid du Colombier 	else if(memcmp(&info[0][1], "AuthcAMDenti", 12) == 0){
1879ef1f84bSDavid du Colombier 		switch(info[1][0] & 0x0fff0ff0){
1889ef1f84bSDavid du Colombier 		default:
1899ef1f84bSDavid du Colombier 			return 0;
1909ef1f84bSDavid du Colombier 		case 0x00000f50:		/* K8 */
1919ef1f84bSDavid du Colombier 			msr = rdmsr(0xc0010042);
1929ef1f84bSDavid du Colombier 			if(msr == 0)
1939ef1f84bSDavid du Colombier 				return 0;
1949ef1f84bSDavid du Colombier 			hz = (800 + 200*((msr>>1) & 0x1f)) * 1000000ll;
1959ef1f84bSDavid du Colombier 			break;
1969ef1f84bSDavid du Colombier 		case 0x00100f90:		/* K10 */
1979ef1f84bSDavid du Colombier 		case 0x00000620:		/* QEMU64 */
1989ef1f84bSDavid du Colombier 			msr = rdmsr(0xc0010064);
1999ef1f84bSDavid du Colombier 			r = (msr>>6) & 0x07;
2009ef1f84bSDavid du Colombier 			hz = (((msr & 0x3f)+0x10)*100000000ll)/(1<<r);
2019ef1f84bSDavid du Colombier 			break;
2029ef1f84bSDavid du Colombier 		}
2039ef1f84bSDavid du Colombier 		DBG("cpuidhz: %#llux hz %lld\n", msr, hz);
2049ef1f84bSDavid du Colombier 	}
2059ef1f84bSDavid du Colombier 	else
2069ef1f84bSDavid du Colombier 		return 0;
2079ef1f84bSDavid du Colombier 
2089ef1f84bSDavid du Colombier 	return hz;
2099ef1f84bSDavid du Colombier }
2109ef1f84bSDavid du Colombier 
2119ef1f84bSDavid du Colombier void
cpuiddump(void)2129ef1f84bSDavid du Colombier cpuiddump(void)
2139ef1f84bSDavid du Colombier {
2149ef1f84bSDavid du Colombier 	int i;
2159ef1f84bSDavid du Colombier 	u32int info[4];
2169ef1f84bSDavid du Colombier 
2179ef1f84bSDavid du Colombier 	if(!DBGFLG)
2189ef1f84bSDavid du Colombier 		return;
2199ef1f84bSDavid du Colombier 
2209ef1f84bSDavid du Colombier 	if(m->ncpuinfos == 0 && cpuidinit() == 0)
2219ef1f84bSDavid du Colombier 		return;
2229ef1f84bSDavid du Colombier 
2239ef1f84bSDavid du Colombier 	for(i = 0; i < m->ncpuinfos; i++){
2249ef1f84bSDavid du Colombier 		cpuid(i, 0, info);
2259ef1f84bSDavid du Colombier 		DBG("eax = %#8.8ux: %8.8ux %8.8ux %8.8ux %8.8ux\n",
2269ef1f84bSDavid du Colombier 			i, info[0], info[1], info[2], info[3]);
2279ef1f84bSDavid du Colombier 	}
2289ef1f84bSDavid du Colombier 	for(i = 0; i < m->ncpuinfoe; i++){
2299ef1f84bSDavid du Colombier 		cpuid(0x80000000|i, 0, info);
2309ef1f84bSDavid du Colombier 		DBG("eax = %#8.8ux: %8.8ux %8.8ux %8.8ux %8.8ux\n",
2319ef1f84bSDavid du Colombier 			0x80000000|i, info[0], info[1], info[2], info[3]);
2329ef1f84bSDavid du Colombier 	}
2339ef1f84bSDavid du Colombier }
2349ef1f84bSDavid du Colombier 
2359ef1f84bSDavid du Colombier vlong
archhz(void)2369ef1f84bSDavid du Colombier archhz(void)
2379ef1f84bSDavid du Colombier {
2389ef1f84bSDavid du Colombier 	vlong hz;
2399ef1f84bSDavid du Colombier 	u32int info[2][4];
2409ef1f84bSDavid du Colombier 
2419ef1f84bSDavid du Colombier 	if(DBGFLG && m->machno == 0)
2429ef1f84bSDavid du Colombier 		cpuiddump();
2439ef1f84bSDavid du Colombier 	if(!cpuidinfo(0, 0, info[0]) || !cpuidinfo(1, 0, info[1]))
2449ef1f84bSDavid du Colombier 		return 0;
2459ef1f84bSDavid du Colombier 
2469ef1f84bSDavid du Colombier 	hz = cpuidhz(info);
2479ef1f84bSDavid du Colombier 	if(hz != 0)
2489ef1f84bSDavid du Colombier 		return hz;
2499ef1f84bSDavid du Colombier 	else if(m->machno != 0)
2509ef1f84bSDavid du Colombier 		return sys->machptr[0]->cpuhz;
2519ef1f84bSDavid du Colombier 
2529ef1f84bSDavid du Colombier 	return i8254hz(info);
2539ef1f84bSDavid du Colombier }
2549ef1f84bSDavid du Colombier 
2559ef1f84bSDavid du Colombier int
archmmu(void)2569ef1f84bSDavid du Colombier archmmu(void)
2579ef1f84bSDavid du Colombier {
2589ef1f84bSDavid du Colombier 	u32int info[4];
2599ef1f84bSDavid du Colombier 
2609ef1f84bSDavid du Colombier 	/*
2619ef1f84bSDavid du Colombier 	 * Should the check for m->machno != 0 be here
2629ef1f84bSDavid du Colombier 	 * or in the caller (mmuinit)?
2639ef1f84bSDavid du Colombier 	 *
2649ef1f84bSDavid du Colombier 	 * To do here:
2659ef1f84bSDavid du Colombier 	 * check and enable Pse;
2669ef1f84bSDavid du Colombier 	 * Pge; Nxe.
2679ef1f84bSDavid du Colombier 	 */
2689ef1f84bSDavid du Colombier 
2699ef1f84bSDavid du Colombier 	/*
2709ef1f84bSDavid du Colombier 	 * How many page sizes are there?
2719ef1f84bSDavid du Colombier 	 * Always have 4*KiB, but need to check
2729ef1f84bSDavid du Colombier 	 * configured correctly.
2739ef1f84bSDavid du Colombier 	 */
2749ef1f84bSDavid du Colombier 	assert(PGSZ == 4*KiB);
2759ef1f84bSDavid du Colombier 
2769ef1f84bSDavid du Colombier 	m->pgszlg2[0] = 12;
2779ef1f84bSDavid du Colombier 	m->pgszmask[0] = (1<<12)-1;
2789ef1f84bSDavid du Colombier 	m->npgsz = 1;
2799ef1f84bSDavid du Colombier 	if(m->ncpuinfos == 0 && cpuidinit() == 0)
2809ef1f84bSDavid du Colombier 		return 1;
2819ef1f84bSDavid du Colombier 
2829ef1f84bSDavid du Colombier 	/*
2839ef1f84bSDavid du Colombier 	 * Check the Pse bit in function 1 DX for 2*MiB support;
2849ef1f84bSDavid du Colombier 	 * if false, only 4*KiB is available.
2859ef1f84bSDavid du Colombier 	 */
2869ef1f84bSDavid du Colombier 	if(!(m->cpuinfo[1][3] & 0x00000008))
2879ef1f84bSDavid du Colombier 		return 1;
2889ef1f84bSDavid du Colombier 	m->pgszlg2[1] = 21;
2899ef1f84bSDavid du Colombier 	m->pgszmask[1] = (1<<21)-1;
2909ef1f84bSDavid du Colombier 	m->npgsz = 2;
2919ef1f84bSDavid du Colombier 
2929ef1f84bSDavid du Colombier 	/*
2939ef1f84bSDavid du Colombier 	 * Check the Page1GB bit in function 0x80000001 DX for 1*GiB support.
2949ef1f84bSDavid du Colombier 	 */
2959ef1f84bSDavid du Colombier 	if(cpuidinfo(0x80000001, 0, info) && (info[3] & 0x04000000)){
2969ef1f84bSDavid du Colombier 		m->pgszlg2[2] = 30;
2979ef1f84bSDavid du Colombier 		m->pgszmask[2] = (1<<30)-1;
2989ef1f84bSDavid du Colombier 		m->npgsz = 3;
2999ef1f84bSDavid du Colombier 	}
3009ef1f84bSDavid du Colombier 
3019ef1f84bSDavid du Colombier 	return m->npgsz;
3029ef1f84bSDavid du Colombier }
3039ef1f84bSDavid du Colombier 
3049ef1f84bSDavid du Colombier static int
fmtP(Fmt * f)3059ef1f84bSDavid du Colombier fmtP(Fmt* f)
3069ef1f84bSDavid du Colombier {
3079ef1f84bSDavid du Colombier 	uintmem pa;
3089ef1f84bSDavid du Colombier 
3099ef1f84bSDavid du Colombier 	pa = va_arg(f->args, uintmem);
3109ef1f84bSDavid du Colombier 
3119ef1f84bSDavid du Colombier 	if(f->flags & FmtSharp)
3129ef1f84bSDavid du Colombier 		return fmtprint(f, "%#16.16llux", pa);
3139ef1f84bSDavid du Colombier 
3149ef1f84bSDavid du Colombier 	return fmtprint(f, "%llud", pa);
3159ef1f84bSDavid du Colombier }
3169ef1f84bSDavid du Colombier 
3179ef1f84bSDavid du Colombier static int
fmtL(Fmt * f)3189ef1f84bSDavid du Colombier fmtL(Fmt* f)
3199ef1f84bSDavid du Colombier {
3209ef1f84bSDavid du Colombier 	Mpl pl;
3219ef1f84bSDavid du Colombier 
3229ef1f84bSDavid du Colombier 	pl = va_arg(f->args, Mpl);
3239ef1f84bSDavid du Colombier 
3249ef1f84bSDavid du Colombier 	return fmtprint(f, "%#16.16llux", pl);
3259ef1f84bSDavid du Colombier }
3269ef1f84bSDavid du Colombier 
3279ef1f84bSDavid du Colombier static int
fmtR(Fmt * f)3289ef1f84bSDavid du Colombier fmtR(Fmt* f)
3299ef1f84bSDavid du Colombier {
3309ef1f84bSDavid du Colombier 	u64int r;
3319ef1f84bSDavid du Colombier 
3329ef1f84bSDavid du Colombier 	r = va_arg(f->args, u64int);
3339ef1f84bSDavid du Colombier 
3349ef1f84bSDavid du Colombier 	return fmtprint(f, "%#16.16llux", r);
3359ef1f84bSDavid du Colombier }
3369ef1f84bSDavid du Colombier 
3379ef1f84bSDavid du Colombier void
archfmtinstall(void)3389ef1f84bSDavid du Colombier archfmtinstall(void)
3399ef1f84bSDavid du Colombier {
3409ef1f84bSDavid du Colombier 	/*
3419ef1f84bSDavid du Colombier 	 * Architecture-specific formatting. Not as neat as they
3429ef1f84bSDavid du Colombier 	 * could be (e.g. there's no defined type for a 'register':
3439ef1f84bSDavid du Colombier 	 *	L - Mpl, mach priority level
3449ef1f84bSDavid du Colombier 	 *	P - uintmem, physical address
3459ef1f84bSDavid du Colombier 	 *	R - register
3469ef1f84bSDavid du Colombier 	 * With a little effort these routines could be written
3479ef1f84bSDavid du Colombier 	 * in a fairly architecturally-independent manner, relying
3489ef1f84bSDavid du Colombier 	 * on the compiler to optimise-away impossible conditions,
3499ef1f84bSDavid du Colombier 	 * and/or by exploiting the innards of the fmt library.
3509ef1f84bSDavid du Colombier 	 */
3519ef1f84bSDavid du Colombier 	fmtinstall('P', fmtP);
3529ef1f84bSDavid du Colombier 
3539ef1f84bSDavid du Colombier 	fmtinstall('L', fmtL);
3549ef1f84bSDavid du Colombier 	fmtinstall('R', fmtR);
3559ef1f84bSDavid du Colombier }
3569ef1f84bSDavid du Colombier 
3579ef1f84bSDavid du Colombier void
microdelay(int microsecs)3589ef1f84bSDavid du Colombier microdelay(int microsecs)
3599ef1f84bSDavid du Colombier {
3609ef1f84bSDavid du Colombier 	u64int r, t;
3619ef1f84bSDavid du Colombier 
3629ef1f84bSDavid du Colombier 	r = rdtsc();
3639ef1f84bSDavid du Colombier 	for(t = r + m->cpumhz*microsecs; r < t; r = rdtsc())
3646c88371cSDavid du Colombier 		pause();
3659ef1f84bSDavid du Colombier }
3669ef1f84bSDavid du Colombier 
3679ef1f84bSDavid du Colombier void
millidelay(int millisecs)3689ef1f84bSDavid du Colombier millidelay(int millisecs)
3699ef1f84bSDavid du Colombier {
3709ef1f84bSDavid du Colombier 	u64int r, t;
3719ef1f84bSDavid du Colombier 
3729ef1f84bSDavid du Colombier 	r = rdtsc();
3739ef1f84bSDavid du Colombier 	for(t = r + m->cpumhz*1000ull*millisecs; r < t; r = rdtsc())
3746c88371cSDavid du Colombier 		pause();
3759ef1f84bSDavid du Colombier }
376*5ae61b61SDavid du Colombier 
377*5ae61b61SDavid du Colombier int
isdmaok(void * a,usize len,int range)378*5ae61b61SDavid du Colombier isdmaok(void *a, usize len, int range)
379*5ae61b61SDavid du Colombier {
380*5ae61b61SDavid du Colombier 	uintmem pa;
381*5ae61b61SDavid du Colombier 
382*5ae61b61SDavid du Colombier 	if(!iskaddr(a) || (char*)a < etext)
383*5ae61b61SDavid du Colombier 		return 0;
384*5ae61b61SDavid du Colombier 	pa = mmuphysaddr(PTR2UINT(a));
385*5ae61b61SDavid du Colombier 	if(pa == 0 || pa == ~(uintmem)0)
386*5ae61b61SDavid du Colombier 		return 0;
387*5ae61b61SDavid du Colombier 	return range > 32 || pa+len <= 0xFFFFFFFFULL;
388*5ae61b61SDavid du Colombier }
389