Commit d5155217 authored by Sebastian Macke's avatar Sebastian Macke Committed by Jia Liu
Browse files

openrisc-timer: Reduce overhead, Separate clock update functions



The clock value is only evaluated when really necessary reducing
the overhead of the timer handling.

This also solves a problem in the way the Linux kernel
handles the timer and the expected accuracy.
The old version could lead to inaccurate timings.

Signed-off-by: default avatarSebastian Macke <sebastian@macke.de>
Reviewed-by: default avatarJia Liu <proljc@gmail.com>
Signed-off-by: default avatarJia Liu <proljc@gmail.com>
parent ae52bd96
Loading
Loading
Loading
Loading
+19 −10
Original line number Diff line number Diff line
@@ -30,19 +30,28 @@ static int is_counting;

void cpu_openrisc_count_update(OpenRISCCPU *cpu)
{
    uint64_t now, next;
    uint32_t wait;
    uint64_t now;

    now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
    if (!is_counting) {
        timer_del(cpu->env.timer);
        last_clk = now;
        return;
    }

    now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
    cpu->env.ttcr += (uint32_t)muldiv64(now - last_clk, TIMER_FREQ,
                                        get_ticks_per_sec());
    last_clk = now;
}

void cpu_openrisc_timer_update(OpenRISCCPU *cpu)
{
    uint32_t wait;
    uint64_t now, next;

    if (!is_counting) {
        return;
    }

    cpu_openrisc_count_update(cpu);
    now = last_clk;

    if ((cpu->env.ttmr & TTMR_TP) <= (cpu->env.ttcr & TTMR_TP)) {
        wait = TTMR_TP - (cpu->env.ttcr & TTMR_TP) + 1;
@@ -50,7 +59,6 @@ void cpu_openrisc_count_update(OpenRISCCPU *cpu)
    } else {
        wait = (cpu->env.ttmr & TTMR_TP) - (cpu->env.ttcr & TTMR_TP);
    }

    next = now + muldiv64(wait, get_ticks_per_sec(), TIMER_FREQ);
    timer_mod(cpu->env.timer, next);
}
@@ -63,8 +71,9 @@ void cpu_openrisc_count_start(OpenRISCCPU *cpu)

void cpu_openrisc_count_stop(OpenRISCCPU *cpu)
{
    is_counting = 0;
    timer_del(cpu->env.timer);
    cpu_openrisc_count_update(cpu);
    is_counting = 0;
}

static void openrisc_timer_cb(void *opaque)
@@ -84,15 +93,15 @@ static void openrisc_timer_cb(void *opaque)
        break;
    case TIMER_INTR:
        cpu->env.ttcr = 0;
        cpu_openrisc_count_start(cpu);
        break;
    case TIMER_SHOT:
        cpu_openrisc_count_stop(cpu);
        break;
    case TIMER_CONT:
        cpu_openrisc_count_start(cpu);
        break;
    }

    cpu_openrisc_timer_update(cpu);
}

void cpu_openrisc_clock_init(OpenRISCCPU *cpu)
+1 −0
Original line number Diff line number Diff line
@@ -373,6 +373,7 @@ void cpu_openrisc_pic_init(OpenRISCCPU *cpu);
/* hw/openrisc_timer.c */
void cpu_openrisc_clock_init(OpenRISCCPU *cpu);
void cpu_openrisc_count_update(OpenRISCCPU *cpu);
void cpu_openrisc_timer_update(OpenRISCCPU *cpu);
void cpu_openrisc_count_start(OpenRISCCPU *cpu);
void cpu_openrisc_count_stop(OpenRISCCPU *cpu);

+18 −20
Original line number Diff line number Diff line
@@ -127,27 +127,13 @@ void HELPER(mtspr)(CPUOpenRISCState *env,
        break;
    case TO_SPR(10, 0): /* TTMR */
        {
            int ip = env->ttmr & TTMR_IP;

            if (rb & TTMR_IP) {    /* Keep IP bit.  */
                env->ttmr = (rb & ~TTMR_IP) + ip;
            } else {    /* Clear IP bit.  */
                env->ttmr = rb & ~TTMR_IP;
                cs->interrupt_request &= ~CPU_INTERRUPT_TIMER;
            }

            cpu_openrisc_count_update(cpu);

            switch (env->ttmr & TTMR_M) {
            if ((env->ttmr & TTMR_M) ^ (rb & TTMR_M)) {
                switch (rb & TTMR_M) {
                case TIMER_NONE:
                    cpu_openrisc_count_stop(cpu);
                    break;
                case TIMER_INTR:
                cpu_openrisc_count_start(cpu);
                break;
                case TIMER_SHOT:
                cpu_openrisc_count_start(cpu);
                break;
                case TIMER_CONT:
                    cpu_openrisc_count_start(cpu);
                    break;
@@ -155,6 +141,18 @@ void HELPER(mtspr)(CPUOpenRISCState *env,
                    break;
                }
            }

            int ip = env->ttmr & TTMR_IP;

            if (rb & TTMR_IP) {    /* Keep IP bit.  */
                env->ttmr = (rb & ~TTMR_IP) | ip;
            } else {    /* Clear IP bit.  */
                env->ttmr = rb & ~TTMR_IP;
                cs->interrupt_request &= ~CPU_INTERRUPT_TIMER;
            }

            cpu_openrisc_timer_update(cpu);
        }
        break;

    case TO_SPR(10, 1): /* TTCR */
@@ -162,7 +160,7 @@ void HELPER(mtspr)(CPUOpenRISCState *env,
        if (env->ttmr & TIMER_NONE) {
            return;
        }
        cpu_openrisc_count_start(cpu);
        cpu_openrisc_timer_update(cpu);
        break;
    default: