xref: /minix/minix/kernel/arch/i386/arch_clock.c (revision 2a404668)
1 /* i386-specific clock functions. */
2 
3 #include <machine/ports.h>
4 
5 #include "kernel/clock.h"
6 #include "kernel/interrupt.h"
7 #include <minix/u64.h>
8 
9 #include <sys/sched.h> /* for CP_*, CPUSTATES */
10 #if CPUSTATES != MINIX_CPUSTATES
11 /* If this breaks, the code in this file may have to be adapted accordingly. */
12 #error "MINIX_CPUSTATES value is out of sync with NetBSD's!"
13 #endif
14 
15 #ifdef USE_APIC
16 #include "apic.h"
17 #endif
18 
19 #include "kernel/spinlock.h"
20 
21 #ifdef CONFIG_SMP
22 #include "kernel/smp.h"
23 #endif
24 
25 #define CLOCK_ACK_BIT   0x80    /* PS/2 clock interrupt acknowledge bit */
26 
27 /* Clock parameters. */
28 #define COUNTER_FREQ (2*TIMER_FREQ) /* counter frequency using square wave */
29 #define LATCH_COUNT     0x00    /* cc00xxxx, c = channel, x = any */
30 #define SQUARE_WAVE     0x36    /* ccaammmb, a = access, m = mode, b = BCD */
31                                 /*   11x11, 11 = LSB then MSB, x11 = sq wave */
32 #define TIMER_FREQ  1193182    /* clock frequency for timer in PC and AT */
33 #define TIMER_COUNT(freq) (TIMER_FREQ/(freq)) /* initial value for counter*/
34 
35 static irq_hook_t pic_timer_hook;		/* interrupt handler hook */
36 
37 static unsigned probe_ticks;
38 static u64_t tsc0, tsc1;
39 #define PROBE_TICKS	(system_hz / 10)
40 
41 static unsigned tsc_per_ms[CONFIG_MAX_CPUS];
42 static unsigned tsc_per_tick[CONFIG_MAX_CPUS];
43 static uint64_t tsc_per_state[CONFIG_MAX_CPUS][CPUSTATES];
44 
45 /*===========================================================================*
46  *				init_8235A_timer			     *
47  *===========================================================================*/
48 int init_8253A_timer(const unsigned freq)
49 {
50 	/* Initialize channel 0 of the 8253A timer to, e.g., 60 Hz,
51 	 * and register the CLOCK task's interrupt handler to be run
52 	 * on every clock tick.
53 	 */
54 	outb(TIMER_MODE, SQUARE_WAVE);  /* run continuously */
55 	outb(TIMER0, (TIMER_COUNT(freq) & 0xff)); /* timer low byte */
56 	outb(TIMER0, TIMER_COUNT(freq) >> 8); /* timer high byte */
57 
58 	return OK;
59 }
60 
61 /*===========================================================================*
62  *				stop_8235A_timer			     *
63  *===========================================================================*/
64 void stop_8253A_timer(void)
65 {
66 	/* Reset the clock to the BIOS rate. (For rebooting.) */
67 	outb(TIMER_MODE, 0x36);
68 	outb(TIMER0, 0);
69 	outb(TIMER0, 0);
70 }
71 
72 void arch_timer_int_handler(void)
73 {
74 }
75 
76 static int calib_cpu_handler(irq_hook_t * UNUSED(hook))
77 {
78 	u64_t tsc;
79 
80 	probe_ticks++;
81 	read_tsc_64(&tsc);
82 
83 
84 	if (probe_ticks == 1) {
85 		tsc0 = tsc;
86 	}
87 	else if (probe_ticks == PROBE_TICKS) {
88 		tsc1 = tsc;
89 	}
90 
91 	/* just in case we are in an SMP single cpu fallback mode */
92 	BKL_UNLOCK();
93 	return 1;
94 }
95 
96 static void estimate_cpu_freq(void)
97 {
98 	u64_t tsc_delta;
99 	u64_t cpu_freq;
100 
101 	irq_hook_t calib_cpu;
102 
103 	/* set the probe, we use the legacy timer, IRQ 0 */
104 	put_irq_handler(&calib_cpu, CLOCK_IRQ, calib_cpu_handler);
105 
106 	/* just in case we are in an SMP single cpu fallback mode */
107 	BKL_UNLOCK();
108 	/* set the PIC timer to get some time */
109 	intr_enable();
110 
111 	/* loop for some time to get a sample */
112 	while(probe_ticks < PROBE_TICKS) {
113 		intr_enable();
114 	}
115 
116 	intr_disable();
117 	/* just in case we are in an SMP single cpu fallback mode */
118 	BKL_LOCK();
119 
120 	/* remove the probe */
121 	rm_irq_handler(&calib_cpu);
122 
123 	tsc_delta = tsc1 - tsc0;
124 
125 	cpu_freq = (tsc_delta / (PROBE_TICKS - 1)) * system_hz;
126 	cpu_set_freq(cpuid, cpu_freq);
127 	cpu_info[cpuid].freq = (unsigned long)(cpu_freq / 1000000);
128 	BOOT_VERBOSE(cpu_print_freq(cpuid));
129 }
130 
131 int init_local_timer(unsigned freq)
132 {
133 #ifdef USE_APIC
134 	/* if we know the address, lapic is enabled and we should use it */
135 	if (lapic_addr) {
136 		unsigned cpu = cpuid;
137 		tsc_per_ms[cpu] = (unsigned)(cpu_get_freq(cpu) / 1000);
138 		tsc_per_tick[cpu] = (unsigned)(cpu_get_freq(cpu) / system_hz);
139 		lapic_set_timer_one_shot(1000000 / system_hz);
140 	} else {
141 		DEBUGBASIC(("Initiating legacy i8253 timer\n"));
142 #else
143 	{
144 #endif
145 		init_8253A_timer(freq);
146 		estimate_cpu_freq();
147 		/* always only 1 cpu in the system */
148 		tsc_per_ms[0] = (unsigned long)(cpu_get_freq(0) / 1000);
149 		tsc_per_tick[0] = (unsigned)(cpu_get_freq(0) / system_hz);
150 	}
151 
152 	return 0;
153 }
154 
155 void stop_local_timer(void)
156 {
157 #ifdef USE_APIC
158 	if (lapic_addr) {
159 		lapic_stop_timer();
160 		apic_eoi();
161 	} else
162 #endif
163 	{
164 		stop_8253A_timer();
165 	}
166 }
167 
168 void restart_local_timer(void)
169 {
170 #ifdef USE_APIC
171 	if (lapic_addr) {
172 		lapic_restart_timer();
173 	}
174 #endif
175 }
176 
177 int register_local_timer_handler(const irq_handler_t handler)
178 {
179 #ifdef USE_APIC
180 	if (lapic_addr) {
181 		/* Using APIC, it is configured in apic_idt_init() */
182 		BOOT_VERBOSE(printf("Using LAPIC timer as tick source\n"));
183 	} else
184 #endif
185 	{
186 		/* Using PIC, Initialize the CLOCK's interrupt hook. */
187 		pic_timer_hook.proc_nr_e = NONE;
188 		pic_timer_hook.irq = CLOCK_IRQ;
189 
190 		put_irq_handler(&pic_timer_hook, CLOCK_IRQ, handler);
191 	}
192 
193 	return 0;
194 }
195 
196 void cycles_accounting_init(void)
197 {
198 #ifdef CONFIG_SMP
199 	unsigned cpu = cpuid;
200 #endif
201 
202 	read_tsc_64(get_cpu_var_ptr(cpu, tsc_ctr_switch));
203 
204 	get_cpu_var(cpu, cpu_last_tsc) = 0;
205 	get_cpu_var(cpu, cpu_last_idle) = 0;
206 }
207 
208 void context_stop(struct proc * p)
209 {
210 	u64_t tsc, tsc_delta;
211 	u64_t * __tsc_ctr_switch = get_cpulocal_var_ptr(tsc_ctr_switch);
212 	unsigned int cpu, tpt, counter;
213 #ifdef CONFIG_SMP
214 	int must_bkl_unlock = 0;
215 
216 	cpu = cpuid;
217 
218 	/*
219 	 * This function is called only if we switch from kernel to user or idle
220 	 * or back. Therefore this is a perfect location to place the big kernel
221 	 * lock which will hopefully disappear soon.
222 	 *
223 	 * If we stop accounting for KERNEL we must unlock the BKL. If account
224 	 * for IDLE we must not hold the lock
225 	 */
226 	if (p == proc_addr(KERNEL)) {
227 		u64_t tmp;
228 
229 		read_tsc_64(&tsc);
230 		tmp = tsc - *__tsc_ctr_switch;
231 		kernel_ticks[cpu] = kernel_ticks[cpu] + tmp;
232 		p->p_cycles = p->p_cycles + tmp;
233 		must_bkl_unlock = 1;
234 	} else {
235 		u64_t bkl_tsc;
236 		atomic_t succ;
237 
238 		read_tsc_64(&bkl_tsc);
239 		/* this only gives a good estimate */
240 		succ = big_kernel_lock.val;
241 
242 		BKL_LOCK();
243 
244 		read_tsc_64(&tsc);
245 
246 		bkl_ticks[cpu] = bkl_ticks[cpu] + tsc - bkl_tsc;
247 		bkl_tries[cpu]++;
248 		bkl_succ[cpu] += !(!(succ == 0));
249 
250 		p->p_cycles = p->p_cycles + tsc - *__tsc_ctr_switch;
251 
252 #ifdef CONFIG_SMP
253 		/*
254 		 * Since at the time we got a scheduling IPI we might have been
255 		 * waiting for BKL already, we may miss it due to a similar IPI to
256 		 * the cpu which is already waiting for us to handle its. This
257 		 * results in a live-lock of these two cpus.
258 		 *
259 		 * Therefore we always check if there is one pending and if so,
260 		 * we handle it straight away so the other cpu can continue and
261 		 * we do not deadlock.
262 		 */
263 		smp_sched_handler();
264 #endif
265 	}
266 #else
267 	read_tsc_64(&tsc);
268 	p->p_cycles = p->p_cycles + tsc - *__tsc_ctr_switch;
269 	cpu = 0;
270 #endif
271 
272 	tsc_delta = tsc - *__tsc_ctr_switch;
273 
274 	if (kbill_ipc) {
275 		kbill_ipc->p_kipc_cycles += tsc_delta;
276 		kbill_ipc = NULL;
277 	}
278 
279 	if (kbill_kcall) {
280 		kbill_kcall->p_kcall_cycles += tsc_delta;
281 		kbill_kcall = NULL;
282 	}
283 
284 	/*
285 	 * Perform CPU average accounting here, rather than in the generic
286 	 * clock handler.  Doing it here offers two advantages: 1) we can
287 	 * account for time spent in the kernel, and 2) we properly account for
288 	 * CPU time spent by a process that has a lot of short-lasting activity
289 	 * such that it spends serious CPU time but never actually runs when a
290 	 * clock tick triggers.  Note that clock speed inaccuracy requires that
291 	 * the code below is a loop, but the loop will in by far most cases not
292 	 * be executed more than once, and often be skipped at all.
293 	 */
294 	tpt = tsc_per_tick[cpu];
295 
296 	p->p_tick_cycles += tsc_delta;
297 	while (tpt > 0 && p->p_tick_cycles >= tpt) {
298 		p->p_tick_cycles -= tpt;
299 
300 		/*
301 		 * The process has spent roughly a whole clock tick worth of
302 		 * CPU cycles.  Update its per-process CPU utilization counter.
303 		 * Some of the cycles may actually have been spent in a
304 		 * previous second, but that is not a problem.
305 		 */
306 		cpuavg_increment(&p->p_cpuavg, kclockinfo.uptime, system_hz);
307 	}
308 
309 	/*
310 	 * deduct the just consumed cpu cycles from the cpu time left for this
311 	 * process during its current quantum. Skip IDLE and other pseudo kernel
312 	 * tasks, except for global accounting purposes.
313 	 */
314 	if (p->p_endpoint >= 0) {
315 		/* On MINIX3, the "system" counter covers system processes. */
316 		if (p->p_priv != priv_addr(USER_PRIV_ID))
317 			counter = CP_SYS;
318 		else if (p->p_misc_flags & MF_NICED)
319 			counter = CP_NICE;
320 		else
321 			counter = CP_USER;
322 
323 #if DEBUG_RACE
324 		p->p_cpu_time_left = 0;
325 #else
326 		if (tsc_delta < p->p_cpu_time_left) {
327 			p->p_cpu_time_left -= tsc_delta;
328 		} else {
329 			p->p_cpu_time_left = 0;
330 		}
331 #endif
332 	} else {
333 		/* On MINIX3, the "interrupts" counter covers the kernel. */
334 		if (p->p_endpoint == IDLE)
335 			counter = CP_IDLE;
336 		else
337 			counter = CP_INTR;
338 	}
339 
340 	tsc_per_state[cpu][counter] += tsc_delta;
341 
342 	*__tsc_ctr_switch = tsc;
343 
344 #ifdef CONFIG_SMP
345 	if(must_bkl_unlock) {
346 		BKL_UNLOCK();
347 	}
348 #endif
349 }
350 
351 void context_stop_idle(void)
352 {
353 	int is_idle;
354 #ifdef CONFIG_SMP
355 	unsigned cpu = cpuid;
356 #endif
357 
358 	is_idle = get_cpu_var(cpu, cpu_is_idle);
359 	get_cpu_var(cpu, cpu_is_idle) = 0;
360 
361 	context_stop(get_cpulocal_var_ptr(idle_proc));
362 
363 	if (is_idle)
364 		restart_local_timer();
365 #if SPROFILE
366 	if (sprofiling)
367 		get_cpulocal_var(idle_interrupted) = 1;
368 #endif
369 }
370 
371 u64_t ms_2_cpu_time(unsigned ms)
372 {
373 	return (u64_t)tsc_per_ms[cpuid] * ms;
374 }
375 
376 unsigned cpu_time_2_ms(u64_t cpu_time)
377 {
378 	return (unsigned long)(cpu_time / tsc_per_ms[cpuid]);
379 }
380 
381 short cpu_load(void)
382 {
383 	u64_t current_tsc, *current_idle;
384 	u64_t tsc_delta, idle_delta, busy;
385 	struct proc *idle;
386 	short load;
387 #ifdef CONFIG_SMP
388 	unsigned cpu = cpuid;
389 #endif
390 
391 	u64_t *last_tsc, *last_idle;
392 
393 	last_tsc = get_cpu_var_ptr(cpu, cpu_last_tsc);
394 	last_idle = get_cpu_var_ptr(cpu, cpu_last_idle);
395 
396 	idle = get_cpu_var_ptr(cpu, idle_proc);;
397 	read_tsc_64(&current_tsc);
398 	current_idle = &idle->p_cycles; /* ptr to idle proc */
399 
400 	/* calculate load since last cpu_load invocation */
401 	if (*last_tsc) {
402 		tsc_delta = current_tsc - *last_tsc;
403 		idle_delta = *current_idle - *last_idle;
404 
405 		busy = tsc_delta - idle_delta;
406 		busy = busy * 100;
407 		load = ex64lo(busy / tsc_delta);
408 
409 		if (load > 100)
410 			load = 100;
411 	} else
412 		load = 0;
413 
414 	*last_tsc = current_tsc;
415 	*last_idle = *current_idle;
416 	return load;
417 }
418 
419 void busy_delay_ms(int ms)
420 {
421 	u64_t cycles = ms_2_cpu_time(ms), tsc0, tsc, tsc1;
422 	read_tsc_64(&tsc0);
423 	tsc1 = tsc0 + cycles;
424 	do { read_tsc_64(&tsc); } while(tsc < tsc1);
425 	return;
426 }
427 
428 /*
429  * Return the number of clock ticks spent in each of a predefined number of
430  * CPU states.
431  */
432 void
433 get_cpu_ticks(unsigned int cpu, uint64_t ticks[CPUSTATES])
434 {
435 	int i;
436 
437 	/* TODO: make this inter-CPU safe! */
438 	for (i = 0; i < CPUSTATES; i++)
439 		ticks[i] = tsc_per_state[cpu][i] / tsc_per_tick[cpu];
440 }
441