1433d6423SLionel Sambuc 2433d6423SLionel Sambuc /* i386-specific clock functions. */ 3433d6423SLionel Sambuc 4433d6423SLionel Sambuc #include <machine/ports.h> 5433d6423SLionel Sambuc #include <minix/portio.h> 6433d6423SLionel Sambuc 7433d6423SLionel Sambuc #include "kernel/kernel.h" 8433d6423SLionel Sambuc 9433d6423SLionel Sambuc #include "kernel/clock.h" 10433d6423SLionel Sambuc #include "kernel/interrupt.h" 11433d6423SLionel Sambuc #include <minix/u64.h> 12433d6423SLionel Sambuc #include "glo.h" 13433d6423SLionel Sambuc #include "kernel/profile.h" 14433d6423SLionel Sambuc 15*366d18b2SDavid van Moolenbroek #include <sys/sched.h> /* for CP_*, CPUSTATES */ 16*366d18b2SDavid van Moolenbroek #if CPUSTATES != MINIX_CPUSTATES 17*366d18b2SDavid van Moolenbroek /* If this breaks, the code in this file may have to be adapted accordingly. */ 18*366d18b2SDavid van Moolenbroek #error "MINIX_CPUSTATES value is out of sync with NetBSD's!" 19*366d18b2SDavid van Moolenbroek #endif 20433d6423SLionel Sambuc 21433d6423SLionel Sambuc #ifdef USE_APIC 22433d6423SLionel Sambuc #include "apic.h" 23433d6423SLionel Sambuc #endif 24433d6423SLionel Sambuc 25433d6423SLionel Sambuc #include "kernel/spinlock.h" 26433d6423SLionel Sambuc 27433d6423SLionel Sambuc #ifdef CONFIG_SMP 28433d6423SLionel Sambuc #include "kernel/smp.h" 29433d6423SLionel Sambuc #endif 30433d6423SLionel Sambuc 31433d6423SLionel Sambuc #define CLOCK_ACK_BIT 0x80 /* PS/2 clock interrupt acknowledge bit */ 32433d6423SLionel Sambuc 33433d6423SLionel Sambuc /* Clock parameters. */ 34433d6423SLionel Sambuc #define COUNTER_FREQ (2*TIMER_FREQ) /* counter frequency using square wave */ 35433d6423SLionel Sambuc #define LATCH_COUNT 0x00 /* cc00xxxx, c = channel, x = any */ 36433d6423SLionel Sambuc #define SQUARE_WAVE 0x36 /* ccaammmb, a = access, m = mode, b = BCD */ 37433d6423SLionel Sambuc /* 11x11, 11 = LSB then MSB, x11 = sq wave */ 38433d6423SLionel Sambuc #define TIMER_FREQ 1193182 /* clock frequency for timer in PC and AT */ 39433d6423SLionel Sambuc #define TIMER_COUNT(freq) (TIMER_FREQ/(freq)) /* initial value for counter*/ 40433d6423SLionel Sambuc 41433d6423SLionel Sambuc static irq_hook_t pic_timer_hook; /* interrupt handler hook */ 42433d6423SLionel Sambuc 43433d6423SLionel Sambuc static unsigned probe_ticks; 44433d6423SLionel Sambuc static u64_t tsc0, tsc1; 45433d6423SLionel Sambuc #define PROBE_TICKS (system_hz / 10) 46433d6423SLionel Sambuc 47433d6423SLionel Sambuc static unsigned tsc_per_ms[CONFIG_MAX_CPUS]; 48*366d18b2SDavid van Moolenbroek static unsigned tsc_per_tick[CONFIG_MAX_CPUS]; 49*366d18b2SDavid van Moolenbroek static uint64_t tsc_per_state[CONFIG_MAX_CPUS][CPUSTATES]; 50433d6423SLionel Sambuc 51433d6423SLionel Sambuc /*===========================================================================* 52433d6423SLionel Sambuc * init_8235A_timer * 53433d6423SLionel Sambuc *===========================================================================*/ 54433d6423SLionel Sambuc int init_8253A_timer(const unsigned freq) 55433d6423SLionel Sambuc { 56433d6423SLionel Sambuc /* Initialize channel 0 of the 8253A timer to, e.g., 60 Hz, 57433d6423SLionel Sambuc * and register the CLOCK task's interrupt handler to be run 58433d6423SLionel Sambuc * on every clock tick. 59433d6423SLionel Sambuc */ 60433d6423SLionel Sambuc outb(TIMER_MODE, SQUARE_WAVE); /* run continuously */ 61433d6423SLionel Sambuc outb(TIMER0, (TIMER_COUNT(freq) & 0xff)); /* timer low byte */ 62433d6423SLionel Sambuc outb(TIMER0, TIMER_COUNT(freq) >> 8); /* timer high byte */ 63433d6423SLionel Sambuc 64433d6423SLionel Sambuc return OK; 65433d6423SLionel Sambuc } 66433d6423SLionel Sambuc 67433d6423SLionel Sambuc /*===========================================================================* 68433d6423SLionel Sambuc * stop_8235A_timer * 69433d6423SLionel Sambuc *===========================================================================*/ 70433d6423SLionel Sambuc void stop_8253A_timer(void) 71433d6423SLionel Sambuc { 72433d6423SLionel Sambuc /* Reset the clock to the BIOS rate. (For rebooting.) */ 73433d6423SLionel Sambuc outb(TIMER_MODE, 0x36); 74433d6423SLionel Sambuc outb(TIMER0, 0); 75433d6423SLionel Sambuc outb(TIMER0, 0); 76433d6423SLionel Sambuc } 77433d6423SLionel Sambuc 78433d6423SLionel Sambuc void arch_timer_int_handler(void) 79433d6423SLionel Sambuc { 80433d6423SLionel Sambuc } 81433d6423SLionel Sambuc 82433d6423SLionel Sambuc static int calib_cpu_handler(irq_hook_t * UNUSED(hook)) 83433d6423SLionel Sambuc { 84433d6423SLionel Sambuc u64_t tsc; 85433d6423SLionel Sambuc 86433d6423SLionel Sambuc probe_ticks++; 87433d6423SLionel Sambuc read_tsc_64(&tsc); 88433d6423SLionel Sambuc 89433d6423SLionel Sambuc 90433d6423SLionel Sambuc if (probe_ticks == 1) { 91433d6423SLionel Sambuc tsc0 = tsc; 92433d6423SLionel Sambuc } 93433d6423SLionel Sambuc else if (probe_ticks == PROBE_TICKS) { 94433d6423SLionel Sambuc tsc1 = tsc; 95433d6423SLionel Sambuc } 96433d6423SLionel Sambuc 97433d6423SLionel Sambuc /* just in case we are in an SMP single cpu fallback mode */ 98433d6423SLionel Sambuc BKL_UNLOCK(); 99433d6423SLionel Sambuc return 1; 100433d6423SLionel Sambuc } 101433d6423SLionel Sambuc 102433d6423SLionel Sambuc static void estimate_cpu_freq(void) 103433d6423SLionel Sambuc { 104433d6423SLionel Sambuc u64_t tsc_delta; 105433d6423SLionel Sambuc u64_t cpu_freq; 106433d6423SLionel Sambuc 107433d6423SLionel Sambuc irq_hook_t calib_cpu; 108433d6423SLionel Sambuc 109433d6423SLionel Sambuc /* set the probe, we use the legacy timer, IRQ 0 */ 110433d6423SLionel Sambuc put_irq_handler(&calib_cpu, CLOCK_IRQ, calib_cpu_handler); 111433d6423SLionel Sambuc 112433d6423SLionel Sambuc /* just in case we are in an SMP single cpu fallback mode */ 113433d6423SLionel Sambuc BKL_UNLOCK(); 114433d6423SLionel Sambuc /* set the PIC timer to get some time */ 115433d6423SLionel Sambuc intr_enable(); 116433d6423SLionel Sambuc 117433d6423SLionel Sambuc /* loop for some time to get a sample */ 118433d6423SLionel Sambuc while(probe_ticks < PROBE_TICKS) { 119433d6423SLionel Sambuc intr_enable(); 120433d6423SLionel Sambuc } 121433d6423SLionel Sambuc 122433d6423SLionel Sambuc intr_disable(); 123433d6423SLionel Sambuc /* just in case we are in an SMP single cpu fallback mode */ 124433d6423SLionel Sambuc BKL_LOCK(); 125433d6423SLionel Sambuc 126433d6423SLionel Sambuc /* remove the probe */ 127433d6423SLionel Sambuc rm_irq_handler(&calib_cpu); 128433d6423SLionel Sambuc 129433d6423SLionel Sambuc tsc_delta = tsc1 - tsc0; 130433d6423SLionel Sambuc 131433d6423SLionel Sambuc cpu_freq = (tsc_delta / (PROBE_TICKS - 1)) * system_hz; 132433d6423SLionel Sambuc cpu_set_freq(cpuid, cpu_freq); 133433d6423SLionel Sambuc cpu_info[cpuid].freq = (unsigned long)(cpu_freq / 1000000); 134433d6423SLionel Sambuc BOOT_VERBOSE(cpu_print_freq(cpuid)); 135433d6423SLionel Sambuc } 136433d6423SLionel Sambuc 137433d6423SLionel Sambuc int init_local_timer(unsigned freq) 138433d6423SLionel Sambuc { 139433d6423SLionel Sambuc #ifdef USE_APIC 140433d6423SLionel Sambuc /* if we know the address, lapic is enabled and we should use it */ 141433d6423SLionel Sambuc if (lapic_addr) { 142433d6423SLionel Sambuc unsigned cpu = cpuid; 143*366d18b2SDavid van Moolenbroek tsc_per_ms[cpu] = (unsigned)(cpu_get_freq(cpu) / 1000); 144*366d18b2SDavid van Moolenbroek tsc_per_tick[cpu] = (unsigned)(cpu_get_freq(cpu) / system_hz); 145433d6423SLionel Sambuc lapic_set_timer_one_shot(1000000 / system_hz); 146433d6423SLionel Sambuc } else { 147da9af514SLionel Sambuc DEBUGBASIC(("Initiating legacy i8253 timer\n")); 148433d6423SLionel Sambuc #else 149433d6423SLionel Sambuc { 150433d6423SLionel Sambuc #endif 151433d6423SLionel Sambuc init_8253A_timer(freq); 152433d6423SLionel Sambuc estimate_cpu_freq(); 153433d6423SLionel Sambuc /* always only 1 cpu in the system */ 154433d6423SLionel Sambuc tsc_per_ms[0] = (unsigned long)(cpu_get_freq(0) / 1000); 155*366d18b2SDavid van Moolenbroek tsc_per_tick[0] = (unsigned)(cpu_get_freq(0) / system_hz); 156433d6423SLionel Sambuc } 157433d6423SLionel Sambuc 158433d6423SLionel Sambuc return 0; 159433d6423SLionel Sambuc } 160433d6423SLionel Sambuc 161433d6423SLionel Sambuc void stop_local_timer(void) 162433d6423SLionel Sambuc { 163433d6423SLionel Sambuc #ifdef USE_APIC 164433d6423SLionel Sambuc if (lapic_addr) { 165433d6423SLionel Sambuc lapic_stop_timer(); 166433d6423SLionel Sambuc apic_eoi(); 167433d6423SLionel Sambuc } else 168433d6423SLionel Sambuc #endif 169433d6423SLionel Sambuc { 170433d6423SLionel Sambuc stop_8253A_timer(); 171433d6423SLionel Sambuc } 172433d6423SLionel Sambuc } 173433d6423SLionel Sambuc 174433d6423SLionel Sambuc void restart_local_timer(void) 175433d6423SLionel Sambuc { 176433d6423SLionel Sambuc #ifdef USE_APIC 177433d6423SLionel Sambuc if (lapic_addr) { 178433d6423SLionel Sambuc lapic_restart_timer(); 179433d6423SLionel Sambuc } 180433d6423SLionel Sambuc #endif 181433d6423SLionel Sambuc } 182433d6423SLionel Sambuc 183433d6423SLionel Sambuc int register_local_timer_handler(const irq_handler_t handler) 184433d6423SLionel Sambuc { 185433d6423SLionel Sambuc #ifdef USE_APIC 186433d6423SLionel Sambuc if (lapic_addr) { 187433d6423SLionel Sambuc /* Using APIC, it is configured in apic_idt_init() */ 188433d6423SLionel Sambuc BOOT_VERBOSE(printf("Using LAPIC timer as tick source\n")); 189433d6423SLionel Sambuc } else 190433d6423SLionel Sambuc #endif 191433d6423SLionel Sambuc { 192433d6423SLionel Sambuc /* Using PIC, Initialize the CLOCK's interrupt hook. */ 193433d6423SLionel Sambuc pic_timer_hook.proc_nr_e = NONE; 194433d6423SLionel Sambuc pic_timer_hook.irq = CLOCK_IRQ; 195433d6423SLionel Sambuc 196433d6423SLionel Sambuc put_irq_handler(&pic_timer_hook, CLOCK_IRQ, handler); 197433d6423SLionel Sambuc } 198433d6423SLionel Sambuc 199433d6423SLionel Sambuc return 0; 200433d6423SLionel Sambuc } 201433d6423SLionel Sambuc 202433d6423SLionel Sambuc void cycles_accounting_init(void) 203433d6423SLionel Sambuc { 204433d6423SLionel Sambuc #ifdef CONFIG_SMP 205433d6423SLionel Sambuc unsigned cpu = cpuid; 206433d6423SLionel Sambuc #endif 207433d6423SLionel Sambuc 208433d6423SLionel Sambuc read_tsc_64(get_cpu_var_ptr(cpu, tsc_ctr_switch)); 209433d6423SLionel Sambuc 210433d6423SLionel Sambuc get_cpu_var(cpu, cpu_last_tsc) = 0; 211433d6423SLionel Sambuc get_cpu_var(cpu, cpu_last_idle) = 0; 212433d6423SLionel Sambuc } 213433d6423SLionel Sambuc 214433d6423SLionel Sambuc void context_stop(struct proc * p) 215433d6423SLionel Sambuc { 216433d6423SLionel Sambuc u64_t tsc, tsc_delta; 217433d6423SLionel Sambuc u64_t * __tsc_ctr_switch = get_cpulocal_var_ptr(tsc_ctr_switch); 218*366d18b2SDavid van Moolenbroek unsigned int cpu, counter; 219433d6423SLionel Sambuc #ifdef CONFIG_SMP 220433d6423SLionel Sambuc int must_bkl_unlock = 0; 221433d6423SLionel Sambuc 222*366d18b2SDavid van Moolenbroek cpu = cpuid; 223*366d18b2SDavid van Moolenbroek 224433d6423SLionel Sambuc /* 225433d6423SLionel Sambuc * This function is called only if we switch from kernel to user or idle 226433d6423SLionel Sambuc * or back. Therefore this is a perfect location to place the big kernel 227433d6423SLionel Sambuc * lock which will hopefully disappear soon. 228433d6423SLionel Sambuc * 229433d6423SLionel Sambuc * If we stop accounting for KERNEL we must unlock the BKL. If account 230433d6423SLionel Sambuc * for IDLE we must not hold the lock 231433d6423SLionel Sambuc */ 232433d6423SLionel Sambuc if (p == proc_addr(KERNEL)) { 233433d6423SLionel Sambuc u64_t tmp; 234433d6423SLionel Sambuc 235433d6423SLionel Sambuc read_tsc_64(&tsc); 236433d6423SLionel Sambuc tmp = tsc - *__tsc_ctr_switch; 237433d6423SLionel Sambuc kernel_ticks[cpu] = kernel_ticks[cpu] + tmp; 238433d6423SLionel Sambuc p->p_cycles = p->p_cycles + tmp; 239433d6423SLionel Sambuc must_bkl_unlock = 1; 240433d6423SLionel Sambuc } else { 241433d6423SLionel Sambuc u64_t bkl_tsc; 242433d6423SLionel Sambuc atomic_t succ; 243433d6423SLionel Sambuc 244433d6423SLionel Sambuc read_tsc_64(&bkl_tsc); 245433d6423SLionel Sambuc /* this only gives a good estimate */ 246433d6423SLionel Sambuc succ = big_kernel_lock.val; 247433d6423SLionel Sambuc 248433d6423SLionel Sambuc BKL_LOCK(); 249433d6423SLionel Sambuc 250433d6423SLionel Sambuc read_tsc_64(&tsc); 251433d6423SLionel Sambuc 252433d6423SLionel Sambuc bkl_ticks[cpu] = bkl_ticks[cpu] + tsc - bkl_tsc; 253433d6423SLionel Sambuc bkl_tries[cpu]++; 254433d6423SLionel Sambuc bkl_succ[cpu] += !(!(succ == 0)); 255433d6423SLionel Sambuc 256433d6423SLionel Sambuc p->p_cycles = p->p_cycles + tsc - *__tsc_ctr_switch; 257433d6423SLionel Sambuc 258433d6423SLionel Sambuc #ifdef CONFIG_SMP 259433d6423SLionel Sambuc /* 260433d6423SLionel Sambuc * Since at the time we got a scheduling IPI we might have been 261433d6423SLionel Sambuc * waiting for BKL already, we may miss it due to a similar IPI to 262433d6423SLionel Sambuc * the cpu which is already waiting for us to handle its. This 263433d6423SLionel Sambuc * results in a live-lock of these two cpus. 264433d6423SLionel Sambuc * 265433d6423SLionel Sambuc * Therefore we always check if there is one pending and if so, 266433d6423SLionel Sambuc * we handle it straight away so the other cpu can continue and 267433d6423SLionel Sambuc * we do not deadlock. 268433d6423SLionel Sambuc */ 269433d6423SLionel Sambuc smp_sched_handler(); 270433d6423SLionel Sambuc #endif 271433d6423SLionel Sambuc } 272433d6423SLionel Sambuc #else 273433d6423SLionel Sambuc read_tsc_64(&tsc); 274433d6423SLionel Sambuc p->p_cycles = p->p_cycles + tsc - *__tsc_ctr_switch; 275*366d18b2SDavid van Moolenbroek cpu = 0; 276433d6423SLionel Sambuc #endif 277433d6423SLionel Sambuc 278433d6423SLionel Sambuc tsc_delta = tsc - *__tsc_ctr_switch; 279433d6423SLionel Sambuc 280433d6423SLionel Sambuc if (kbill_ipc) { 281433d6423SLionel Sambuc kbill_ipc->p_kipc_cycles = 282433d6423SLionel Sambuc kbill_ipc->p_kipc_cycles + tsc_delta; 283433d6423SLionel Sambuc kbill_ipc = NULL; 284433d6423SLionel Sambuc } 285433d6423SLionel Sambuc 286433d6423SLionel Sambuc if (kbill_kcall) { 287433d6423SLionel Sambuc kbill_kcall->p_kcall_cycles = 288433d6423SLionel Sambuc kbill_kcall->p_kcall_cycles + tsc_delta; 289433d6423SLionel Sambuc kbill_kcall = NULL; 290433d6423SLionel Sambuc } 291433d6423SLionel Sambuc 292433d6423SLionel Sambuc /* 293433d6423SLionel Sambuc * deduct the just consumed cpu cycles from the cpu time left for this 294433d6423SLionel Sambuc * process during its current quantum. Skip IDLE and other pseudo kernel 295*366d18b2SDavid van Moolenbroek * tasks, except for global accounting purposes. 296433d6423SLionel Sambuc */ 297433d6423SLionel Sambuc if (p->p_endpoint >= 0) { 298*366d18b2SDavid van Moolenbroek /* On MINIX3, the "system" counter covers system processes. */ 299*366d18b2SDavid van Moolenbroek if (p->p_priv != priv_addr(USER_PRIV_ID)) 300*366d18b2SDavid van Moolenbroek counter = CP_SYS; 301*366d18b2SDavid van Moolenbroek else if (p->p_misc_flags & MF_NICED) 302*366d18b2SDavid van Moolenbroek counter = CP_NICE; 303*366d18b2SDavid van Moolenbroek else 304*366d18b2SDavid van Moolenbroek counter = CP_USER; 305*366d18b2SDavid van Moolenbroek 306433d6423SLionel Sambuc #if DEBUG_RACE 307433d6423SLionel Sambuc p->p_cpu_time_left = 0; 308433d6423SLionel Sambuc #else 309433d6423SLionel Sambuc /* if (tsc_delta < p->p_cpu_time_left) in 64bit */ 310433d6423SLionel Sambuc if (ex64hi(tsc_delta) < ex64hi(p->p_cpu_time_left) || 311433d6423SLionel Sambuc (ex64hi(tsc_delta) == ex64hi(p->p_cpu_time_left) && 312433d6423SLionel Sambuc ex64lo(tsc_delta) < ex64lo(p->p_cpu_time_left))) 313433d6423SLionel Sambuc p->p_cpu_time_left = p->p_cpu_time_left - tsc_delta; 314433d6423SLionel Sambuc else { 315433d6423SLionel Sambuc p->p_cpu_time_left = 0; 316433d6423SLionel Sambuc } 317433d6423SLionel Sambuc #endif 318*366d18b2SDavid van Moolenbroek } else { 319*366d18b2SDavid van Moolenbroek /* On MINIX3, the "interrupts" counter covers the kernel. */ 320*366d18b2SDavid van Moolenbroek if (p->p_endpoint == IDLE) 321*366d18b2SDavid van Moolenbroek counter = CP_IDLE; 322*366d18b2SDavid van Moolenbroek else 323*366d18b2SDavid van Moolenbroek counter = CP_INTR; 324433d6423SLionel Sambuc } 325433d6423SLionel Sambuc 326*366d18b2SDavid van Moolenbroek tsc_per_state[cpu][counter] += tsc_delta; 327*366d18b2SDavid van Moolenbroek 328433d6423SLionel Sambuc *__tsc_ctr_switch = tsc; 329433d6423SLionel Sambuc 330433d6423SLionel Sambuc #ifdef CONFIG_SMP 331433d6423SLionel Sambuc if(must_bkl_unlock) { 332433d6423SLionel Sambuc BKL_UNLOCK(); 333433d6423SLionel Sambuc } 334433d6423SLionel Sambuc #endif 335433d6423SLionel Sambuc } 336433d6423SLionel Sambuc 337433d6423SLionel Sambuc void context_stop_idle(void) 338433d6423SLionel Sambuc { 339433d6423SLionel Sambuc int is_idle; 340433d6423SLionel Sambuc #ifdef CONFIG_SMP 341433d6423SLionel Sambuc unsigned cpu = cpuid; 342433d6423SLionel Sambuc #endif 343433d6423SLionel Sambuc 344433d6423SLionel Sambuc is_idle = get_cpu_var(cpu, cpu_is_idle); 345433d6423SLionel Sambuc get_cpu_var(cpu, cpu_is_idle) = 0; 346433d6423SLionel Sambuc 347433d6423SLionel Sambuc context_stop(get_cpulocal_var_ptr(idle_proc)); 348433d6423SLionel Sambuc 349433d6423SLionel Sambuc if (is_idle) 350433d6423SLionel Sambuc restart_local_timer(); 351433d6423SLionel Sambuc #if SPROFILE 352433d6423SLionel Sambuc if (sprofiling) 353433d6423SLionel Sambuc get_cpulocal_var(idle_interrupted) = 1; 354433d6423SLionel Sambuc #endif 355433d6423SLionel Sambuc } 356433d6423SLionel Sambuc 357433d6423SLionel Sambuc u64_t ms_2_cpu_time(unsigned ms) 358433d6423SLionel Sambuc { 359433d6423SLionel Sambuc return (u64_t)tsc_per_ms[cpuid] * ms; 360433d6423SLionel Sambuc } 361433d6423SLionel Sambuc 362433d6423SLionel Sambuc unsigned cpu_time_2_ms(u64_t cpu_time) 363433d6423SLionel Sambuc { 364433d6423SLionel Sambuc return (unsigned long)(cpu_time / tsc_per_ms[cpuid]); 365433d6423SLionel Sambuc } 366433d6423SLionel Sambuc 367433d6423SLionel Sambuc short cpu_load(void) 368433d6423SLionel Sambuc { 369433d6423SLionel Sambuc u64_t current_tsc, *current_idle; 370433d6423SLionel Sambuc u64_t tsc_delta, idle_delta, busy; 371433d6423SLionel Sambuc struct proc *idle; 372433d6423SLionel Sambuc short load; 373433d6423SLionel Sambuc #ifdef CONFIG_SMP 374433d6423SLionel Sambuc unsigned cpu = cpuid; 375433d6423SLionel Sambuc #endif 376433d6423SLionel Sambuc 377433d6423SLionel Sambuc u64_t *last_tsc, *last_idle; 378433d6423SLionel Sambuc 379433d6423SLionel Sambuc last_tsc = get_cpu_var_ptr(cpu, cpu_last_tsc); 380433d6423SLionel Sambuc last_idle = get_cpu_var_ptr(cpu, cpu_last_idle); 381433d6423SLionel Sambuc 382433d6423SLionel Sambuc idle = get_cpu_var_ptr(cpu, idle_proc);; 383433d6423SLionel Sambuc read_tsc_64(¤t_tsc); 384433d6423SLionel Sambuc current_idle = &idle->p_cycles; /* ptr to idle proc */ 385433d6423SLionel Sambuc 386433d6423SLionel Sambuc /* calculate load since last cpu_load invocation */ 387433d6423SLionel Sambuc if (*last_tsc) { 388433d6423SLionel Sambuc tsc_delta = current_tsc - *last_tsc; 389433d6423SLionel Sambuc idle_delta = *current_idle - *last_idle; 390433d6423SLionel Sambuc 391433d6423SLionel Sambuc busy = tsc_delta - idle_delta; 392433d6423SLionel Sambuc busy = busy * 100; 393433d6423SLionel Sambuc load = ex64lo(busy / tsc_delta); 394433d6423SLionel Sambuc 395433d6423SLionel Sambuc if (load > 100) 396433d6423SLionel Sambuc load = 100; 397433d6423SLionel Sambuc } else 398433d6423SLionel Sambuc load = 0; 399433d6423SLionel Sambuc 400433d6423SLionel Sambuc *last_tsc = current_tsc; 401433d6423SLionel Sambuc *last_idle = *current_idle; 402433d6423SLionel Sambuc return load; 403433d6423SLionel Sambuc } 404433d6423SLionel Sambuc 405433d6423SLionel Sambuc void busy_delay_ms(int ms) 406433d6423SLionel Sambuc { 407433d6423SLionel Sambuc u64_t cycles = ms_2_cpu_time(ms), tsc0, tsc, tsc1; 408433d6423SLionel Sambuc read_tsc_64(&tsc0); 409433d6423SLionel Sambuc tsc1 = tsc0 + cycles; 410433d6423SLionel Sambuc do { read_tsc_64(&tsc); } while(tsc < tsc1); 411433d6423SLionel Sambuc return; 412433d6423SLionel Sambuc } 413433d6423SLionel Sambuc 414*366d18b2SDavid van Moolenbroek /* 415*366d18b2SDavid van Moolenbroek * Return the number of clock ticks spent in each of a predefined number of 416*366d18b2SDavid van Moolenbroek * CPU states. 417*366d18b2SDavid van Moolenbroek */ 418*366d18b2SDavid van Moolenbroek void 419*366d18b2SDavid van Moolenbroek get_cpu_ticks(unsigned int cpu, uint64_t ticks[CPUSTATES]) 420*366d18b2SDavid van Moolenbroek { 421*366d18b2SDavid van Moolenbroek int i; 422*366d18b2SDavid van Moolenbroek 423*366d18b2SDavid van Moolenbroek /* TODO: make this inter-CPU safe! */ 424*366d18b2SDavid van Moolenbroek for (i = 0; i < CPUSTATES; i++) 425*366d18b2SDavid van Moolenbroek ticks[i] = tsc_per_state[cpu][i] / tsc_per_tick[cpu]; 426*366d18b2SDavid van Moolenbroek } 427