From b7aed08e65c495a5c76e7160efbaed6774d0e02f Mon Sep 17 00:00:00 2001 From: Tomas Hruby Date: Wed, 15 Sep 2010 14:10:09 +0000 Subject: [PATCH] SMP - Only a single APIC timer handler - bsp_timer_int_handler() and ap_timer_int_handler() unified into timer_int_handler() - global realtime updated only on BSP --- kernel/arch/i386/apic.c | 17 ++- kernel/arch/i386/apic_asm.S | 7 +- kernel/arch/i386/apic_asm.h | 3 +- kernel/arch/i386/include/arch_clock.h | 2 + kernel/clock.c | 182 ++++++++++++-------------- kernel/clock.h | 4 +- 6 files changed, 100 insertions(+), 115 deletions(-) diff --git a/kernel/arch/i386/apic.c b/kernel/arch/i386/apic.c index ed6f48e03..979325be2 100644 --- a/kernel/arch/i386/apic.c +++ b/kernel/arch/i386/apic.c @@ -484,6 +484,7 @@ PRIVATE void apic_calibrate_clocks(unsigned cpu) } intr_disable(); + BKL_LOCK(); /* remove the probe */ rm_irq_handler(&calib_clk); @@ -613,6 +614,8 @@ PRIVATE int lapic_enable_in_msr(void) ia32_msr_read(IA32_APIC_BASE, &msr.hi, &msr.lo); +#if 0 + /*FIXME this is a problem on AP */ /* * FIXME if the location is different (unlikely) then the one we expect, * update it @@ -625,6 +628,7 @@ PRIVATE int lapic_enable_in_msr(void) } lapic_addr = phys2vir(msr.lo & ~((1 << 12) - 1)); } +#endif msr.lo |= (1 << IA32_APIC_BASE_ENABLE_BIT); ia32_msr_write(IA32_APIC_BASE, msr.hi, msr.lo); @@ -825,7 +829,6 @@ PUBLIC void apic_idt_init(const int reset) /* Set up idt tables for smp mode. */ - vir_bytes local_timer_intr_handler; int is_bsp = is_boot_apic(apicid()); if (reset) { @@ -861,16 +864,12 @@ PUBLIC void apic_idt_init(const int reset) /* configure the timer interupt handler */ if (is_bsp) { - local_timer_intr_handler = (vir_bytes) lapic_bsp_timer_int_handler; - BOOT_VERBOSE(printf("Initiating BSP timer handler\n")); - } else { - local_timer_intr_handler = (vir_bytes) lapic_ap_timer_int_handler; - BOOT_VERBOSE(printf("Initiating AP timer handler\n")); + BOOT_VERBOSE(printf("Initiating APIC timer handler\n")); + /* register the timer interrupt handler for this CPU */ + int_gate(APIC_TIMER_INT_VECTOR, (vir_bytes) lapic_timer_int_handler, + PRESENT | INT_GATE_TYPE | (INTR_PRIVILEGE << DPL_SHIFT)); } - /* register the timer interrupt handler for this CPU */ - int_gate(APIC_TIMER_INT_VECTOR, (vir_bytes) local_timer_intr_handler, - PRESENT | INT_GATE_TYPE | (INTR_PRIVILEGE << DPL_SHIFT)); } PRIVATE int acpi_get_ioapics(struct io_apic * ioa, unsigned * nioa, unsigned max) diff --git a/kernel/arch/i386/apic_asm.S b/kernel/arch/i386/apic_asm.S index 8faa33963..34c651baf 100644 --- a/kernel/arch/i386/apic_asm.S +++ b/kernel/arch/i386/apic_asm.S @@ -64,11 +64,8 @@ ENTRY(apic_hwint##irq) \ iret ; /* apic timer tick handlers */ -ENTRY(lapic_bsp_timer_int_handler) - lapic_intr(_C_LABEL(bsp_timer_int_handler)) - -ENTRY(lapic_ap_timer_int_handler) - lapic_intr(_C_LABEL(ap_timer_int_handler)) +ENTRY(lapic_timer_int_handler) + lapic_intr(_C_LABEL(timer_int_handler)) #ifdef CONFIG_SMP #include "arch_smp.h" diff --git a/kernel/arch/i386/apic_asm.h b/kernel/arch/i386/apic_asm.h index 8086100d9..cf398e629 100644 --- a/kernel/arch/i386/apic_asm.h +++ b/kernel/arch/i386/apic_asm.h @@ -71,8 +71,7 @@ _PROTOTYPE( void apic_hwint62, (void) ); _PROTOTYPE( void apic_hwint63, (void) ); /* The local APIC timer tick handlers */ -_PROTOTYPE(void lapic_bsp_timer_int_handler, (void)); -_PROTOTYPE(void lapic_ap_timer_int_handler, (void)); +_PROTOTYPE(void lapic_timer_int_handler, (void)); #endif diff --git a/kernel/arch/i386/include/arch_clock.h b/kernel/arch/i386/include/arch_clock.h index 61586474f..f9dd03ec0 100644 --- a/kernel/arch/i386/include/arch_clock.h +++ b/kernel/arch/i386/include/arch_clock.h @@ -1,6 +1,8 @@ #ifndef __CLOCK_X86_H__ #define __CLOCK_X86_H__ +#include "../apic_asm.h" + _PROTOTYPE(int init_8253A_timer, (unsigned freq)); _PROTOTYPE(void stop_8253A_timer, (void)); diff --git a/kernel/clock.c b/kernel/clock.c index 6963451fd..3f848b3cb 100644 --- a/kernel/clock.c +++ b/kernel/clock.c @@ -35,7 +35,6 @@ #include #include "clock.h" -#include "debug.h" #ifdef CONFIG_WATCHDOG #include "watchdog.h" @@ -63,30 +62,87 @@ PRIVATE clock_t realtime = 0; /* real time clock */ * The boot processos timer interrupt handler. In addition to non-boot cpus it * keeps real time and notifies the clock task if need be */ -extern unsigned ooq_msg; -PUBLIC int bsp_timer_int_handler(void) +PUBLIC int timer_int_handler(void) { - unsigned ticks; + /* Update user and system accounting times. Charge the current process + * for user time. If the current process is not billable, that is, if a + * non-user process is running, charge the billable process for system + * time as well. Thus the unbillable process' user time is the billable + * user's system time. + */ - if(minix_panicing) - return 0; + struct proc * p, * billp; - /* Get number of ticks and update realtime. */ - ticks = lost_ticks + 1; - lost_ticks = 0; - realtime += ticks; + /* FIXME watchdog for slave cpus! */ +#ifdef CONFIG_WATCHDOG + /* + * we need to know whether local timer ticks are happening or whether + * the kernel is locked up. We don't care about overflows as we only + * need to know that it's still ticking or not + */ + watchdog_local_timer_ticks++; +#endif - ap_timer_int_handler(); + if (cpu_is_bsp(cpuid)) + realtime++; - /* if a timer expired, notify the clock task */ - if ((next_timeout <= realtime)) { - tmrs_exptimers(&clock_timers, realtime, NULL); - next_timeout = (clock_timers == NULL) ? - TMR_NEVER : clock_timers->tmr_exp_time; + /* Update user and system accounting times. Charge the current process + * for user time. If the current process is not billable, that is, if a + * non-user process is running, charge the billable process for system + * time as well. Thus the unbillable process' user time is the billable + * user's system time. + */ + + p = get_cpulocal_var(proc_ptr); + billp = get_cpulocal_var(bill_ptr); + + p->p_user_time++; + + if (! (priv(p)->s_flags & BILLABLE)) { + billp->p_sys_time++; } - if (do_serial_debug) - do_ser_debug(); + /* Decrement virtual timers, if applicable. We decrement both the + * virtual and the profile timer of the current process, and if the + * current process is not billable, the timer of the billed process as + * well. If any of the timers expire, do_clocktick() will send out + * signals. + */ + if ((p->p_misc_flags & MF_VIRT_TIMER)){ + p->p_virt_left--; + } + if ((p->p_misc_flags & MF_PROF_TIMER)){ + p->p_prof_left--; + } + if (! (priv(p)->s_flags & BILLABLE) && + (billp->p_misc_flags & MF_PROF_TIMER)){ + billp->p_prof_left--; + } + + /* + * Check if a process-virtual timer expired. Check current process, but + * also bill_ptr - one process's user time is another's system time, and + * the profile timer decreases for both! + */ + vtimer_check(p); + + if (p != billp) + vtimer_check(billp); + + /* Update load average. */ + load_update(); + + if (cpu_is_bsp(cpuid)) { + /* if a timer expired, notify the clock task */ + if ((next_timeout <= realtime)) { + tmrs_exptimers(&clock_timers, realtime, NULL); + next_timeout = (clock_timers == NULL) ? + TMR_NEVER : clock_timers->tmr_exp_time; + } + + if (do_serial_debug) + do_ser_debug(); + } return(1); /* reenable interrupts */ } @@ -152,9 +208,11 @@ PRIVATE void load_update(void) } /* Cumulation. How many processes are ready now? */ - for(q = 0; q < NR_SCHED_QUEUES; q++) - for(p = rdy_head[q]; p; p = p->p_nextready) + for(q = 0; q < NR_SCHED_QUEUES; q++) { + for(p = rdy_head[q]; p != NULL; p = p->p_nextready) { enqueued++; + } + } kloadinfo.proc_load_history[slot] += enqueued; @@ -162,90 +220,20 @@ PRIVATE void load_update(void) kloadinfo.last_clock = realtime; } -/* - * Timer interupt handler. This is the only thing executed on non boot - * processors. It is called by bsp_timer_int_handler() on the boot processor - */ -PUBLIC int ap_timer_int_handler(void) -{ - - /* Update user and system accounting times. Charge the current process - * for user time. If the current process is not billable, that is, if a - * non-user process is running, charge the billable process for system - * time as well. Thus the unbillable process' user time is the billable - * user's system time. - */ - - const unsigned ticks = 1; - struct proc * p, * billp; - -#ifdef CONFIG_WATCHDOG - /* - * we need to know whether local timer ticks are happening or whether - * the kernel is locked up. We don't care about overflows as we only - * need to know that it's still ticking or not - */ - watchdog_local_timer_ticks++; -#endif - - /* Update user and system accounting times. Charge the current process - * for user time. If the current process is not billable, that is, if a - * non-user process is running, charge the billable process for system - * time as well. Thus the unbillable process' user time is the billable - * user's system time. - */ - - p = get_cpulocal_var(proc_ptr); - billp = get_cpulocal_var(bill_ptr); - - p->p_user_time += ticks; - - /* FIXME make this ms too */ - if (! (priv(p)->s_flags & BILLABLE)) { - billp->p_sys_time += ticks; - } - - /* Decrement virtual timers, if applicable. We decrement both the - * virtual and the profile timer of the current process, and if the - * current process is not billable, the timer of the billed process as - * well. If any of the timers expire, do_clocktick() will send out - * signals. - */ - if ((p->p_misc_flags & MF_VIRT_TIMER)){ - p->p_virt_left -= ticks; - } - if ((p->p_misc_flags & MF_PROF_TIMER)){ - p->p_prof_left -= ticks; - } - if (! (priv(p)->s_flags & BILLABLE) && - (billp->p_misc_flags & MF_PROF_TIMER)){ - billp->p_prof_left -= ticks; - } - - /* - * Check if a process-virtual timer expired. Check current process, but - * also bill_ptr - one process's user time is another's system time, and - * the profile timer decreases for both! - */ - vtimer_check(p); - - if (p != billp) - vtimer_check(billp); - - /* Update load average. */ - load_update(); - - return 1; -} - PUBLIC int boot_cpu_init_timer(unsigned freq) { if (arch_init_local_timer(freq)) return -1; if (arch_register_local_timer_handler( - (irq_handler_t) bsp_timer_int_handler)) + (irq_handler_t) timer_int_handler)) return -1; return 0; } + +PUBLIC int app_cpu_init_timer(unsigned freq) +{ + if (arch_init_local_timer(freq)) + return -1; +} diff --git a/kernel/clock.h b/kernel/clock.h index 5a9c70868..ebd53fa92 100644 --- a/kernel/clock.h +++ b/kernel/clock.h @@ -5,9 +5,9 @@ #include "arch_clock.h" _PROTOTYPE(int boot_cpu_init_timer, (unsigned freq)); +_PROTOTYPE(int app_cpu_init_timer, (unsigned freq)); -_PROTOTYPE(int bsp_timer_int_handler, (void)); -_PROTOTYPE(int ap_timer_int_handler, (void)); +_PROTOTYPE(int timer_int_handler, (void)); _PROTOTYPE(int arch_init_local_timer, (unsigned freq)); _PROTOTYPE(void arch_stop_local_timer, (void));