static void localclockintr(Ureg *ureg, void *) { if(m->machno == 0) panic("cpu0: Unexpected local generic timer interrupt"); cpwrsc(0, CpTIMER, CpTIMERphys, CpTIMERphysctl, Imask|Enable); timerintr(ureg, 0); }
void timerset(uvlong next) { Systimers *tn; uvlong now; long period; now = fastticks(nil); period = next - now; if(period < MinPeriod) period = MinPeriod; else if(period > MaxPeriod) period = MaxPeriod; if(m->machno > 0){ cpwrsc(0, CpTIMER, CpTIMERphys, CpTIMERphysval, period); cpwrsc(0, CpTIMER, CpTIMERphys, CpTIMERphysctl, Enable); }else{ tn = (Systimers*)SYSTIMERS; tn->c3 = (ulong)(now + period); } }
static void errata(void) { ulong reg, r, p; /* apply cortex-a9 errata workarounds */ r = cpidget(); /* main id register */ assert((r >> 24) == 'A'); p = r & MASK(4); /* minor revision */ r >>= 20; r &= MASK(4); /* major revision */ /* this is an undocumented `diagnostic register' that linux knows */ reg = cprdsc(0, CpDTLB, 0, 1); if (r < 2 || r == 2 && p <= 2) reg |= 1<<4; /* 742230 */ if (r == 2 && p <= 2) reg |= 1<<6 | 1<<12 | 1<<22; /* 743622, 2×742231 */ if (r < 3) reg |= 1<<11; /* 751472 */ cpwrsc(0, CpDTLB, 0, 1, reg); }
void clockinit(void) { Systimers *tn; Armtimer *tm; u32int t0, t1, tstart, tend; if(((cprdsc(0, CpID, CpIDfeat, 1) >> 16) & 0xF) != 0) { /* generic timer supported */ if(m->machno == 0){ *(ulong*)(ARMLOCAL + Localctl) = 0; /* magic */ *(ulong*)(ARMLOCAL + Prescaler) = 0x06aaaaab; /* magic for 1 Mhz */ } cpwrsc(0, CpTIMER, CpTIMERphys, CpTIMERphysctl, Imask); } tn = (Systimers*)SYSTIMERS; tstart = tn->clo; do{ t0 = lcycles(); }while(tn->clo == tstart); tend = tstart + 10000; do{ t1 = lcycles(); }while(tn->clo != tend); t1 -= t0; m->cpuhz = 100 * t1; m->cpumhz = (m->cpuhz + Mhz/2 - 1) / Mhz; m->cyclefreq = m->cpuhz; if(m->machno == 0){ tn->c3 = tn->clo - 1; tm = (Armtimer*)ARMTIMER; tm->load = 0; tm->ctl = TmrPrescale1|CntEnable|CntWidth32; intrenable(IRQtimer3, clockintr, nil, 0, "clock"); }else intrenable(IRQcntpns, localclockintr, nil, 0, "clock"); }
void clockinit(void) { int i, s; Timerregs *tn; clockshutdown(); /* turn cycle counter on */ cpwrsc(0, CpCLD, CpCLDena, CpCLDenacyc, 1<<31); /* turn all counters on and clear the cycle counter */ cpwrsc(0, CpCLD, CpCLDena, CpCLDenapmnc, 1<<2 | 1); /* let users read the cycle counter directly */ cpwrsc(0, CpCLD, CpCLDena, CpCLDenapmnc, 1); ilock(&clklck); m->fastclock = 1; m->ticks = ticks = 0; /* * T0 is a freerunning timer (cycle counter); it wraps, * automatically reloads, and does not dispatch interrupts. */ tn = (Timerregs *)Tn0; tn->tcrr = Freebase; /* count up to 0 */ tn->tldr = Freebase; coherence(); tn->tclr = Ar | St; iunlock(&clklck); /* * T1 is the interrupting timer and does not participate * in measuring time. It is initially set to HZ. */ tn = (Timerregs *)Tn1; irqenable(Tn0irq+1, clockintr, tn, "clock"); ilock(&clklck); tn->tcrr = -Tcycles; /* approx.; count up to 0 */ tn->tldr = -Tcycles; coherence(); tn->tclr = Ar | St; coherence(); tn->tier = Ovf_it; coherence(); iunlock(&clklck); /* * verify sanity of timer1 */ s = spllo(); /* risky */ for (i = 0; i < 5 && ticks == 0; i++) { delay(10); cachedwbinvse(&ticks, sizeof ticks); } splx(s); if (ticks == 0) { if (tn->tcrr == 0) panic("clock not interrupting"); else if (tn->tcrr == tn->tldr) panic("clock not ticking at all"); #ifdef PARANOID else panic("clock running very slowly"); #endif } guessmips(issue1loop, "single"); if (Debug) iprint(", "); guessmips(issue2loop, "dual"); if (Debug) iprint("\n"); /* * m->delayloop should be the number of delay loop iterations * needed to consume 1 ms. 2 is min. instructions in the delay loop. */ m->delayloop = m->cpuhz / (1000 * 2); // iprint("m->delayloop = %lud\n", m->delayloop); /* * desynchronize the processor clocks so that they all don't * try to resched at the same time. */ delay(m->machno*2); }