qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [RESEND][PATCH] booke timers


From: Alexander Graf
Subject: Re: [Qemu-devel] [RESEND][PATCH] booke timers
Date: Fri, 9 Sep 2011 16:58:39 +0200

On 09.09.2011, at 16:22, Fabien Chouteau wrote:

> On 09/09/2011 15:46, Alexander Graf wrote:
>> 
>> On 09.09.2011, at 15:27, Fabien Chouteau wrote:
>> 
>>> On 09/09/2011 12:55, Alexander Graf wrote:
>>>> 
>>>> On 09.09.2011, at 12:36, Fabien Chouteau wrote:
>>>>>>> 
>>>>>>>> 
>>>>>>>>> +    }
>>>>>>>>> +
>>>>>>>>> +    qemu_mod_timer(timer, *next);
>>>>>>>>> +}
>>>>>>>>> +
>>>>>>>>> +static void booke_decr_cb(void *opaque)
>>>>>>>>> +{
>>>>>>>>> +    CPUState *env;
>>>>>>>>> +    ppc_tb_t *tb_env;
>>>>>>>>> +    booke_timer_t *booke_timer;
>>>>>>>>> +
>>>>>>>>> +    env = opaque;
>>>>>>>>> +    tb_env = env->tb_env;
>>>>>>>>> +    booke_timer = tb_env->opaque;
>>>>>>>>> +    env->spr[SPR_BOOKE_TSR] |= TSR_DIS;
>>>>>>>>> +    if (env->spr[SPR_BOOKE_TCR] & TCR_DIE) {
>>>>>>>>> +        ppc_set_irq(env, PPC_INTERRUPT_DECR, 1);
>>>>>>>>> +    }
>>>>>>>> 
>>>>>>>> You will need this more often - also for the TCR write case - so 
>>>>>>>> please put
>>>>>>>> the 3 lines above into a separate function and just call that here :)
>>>>>>> 
>>>>>>> Actually the checks are never exactly the same, here we test DIE in 
>>>>>>> TCR...
>>>>>> 
>>>>>> Sure, we have 3 different tests for the 3 different bits we can 
>>>>>> potentially set in TCR. The check always ends up being the same though:
>>>>>> 
>>>>>> if (TSR & bit && TCR & bit)
>>>>>>  set_irq(irq_for_bit);
>>>>>> 
>>>>>> Most device emulators have a simple function for this called 
>>>>>> "update_irq" that checks for all the bits and sets the respective irq 
>>>>>> lines.
>>>>>> 
>>>>> 
>>>>> I know but we have two cases:
>>>>> 
>>>>> - Timer hit: we check DIE in TCR
>>>>> - Rising edge of DIE in TCR (from user): check if DIS is set
>>>>> 
>>>>> I don't think we can have a good generic function for this, and I don't
>>>>> forecast any improvement in code readability.
>>>> 
>>>> update_decr_irq() {
>>>> if (TSR.DIS && TCR.DIE) {
>>>>   set_irq(DECR);
>>>> } else {
>>>>   unset_irq(DECR);
>>>> }
>>>> }
>>>> 
>>>> Timer hit:
>>>> 
>>>> TSR |= DIS;
>>>> update_decr_irq();
>>>> 
>>>> Setting TCR:
>>>> 
>>>> TCR |= DIE;
>>>> update_decr_irq();
>>>> 
>>>> Or am I misunderstanding the conditions under which the irq actually
>>>> triggers? TCR.DIE is only the interrupt enabled flag - the timer can still
>>>> hit nevertheless. The level of the interrupt is determined by TSR.DIR which
>>>> is what the timer sets when it hits. Unless I completely misread the spec, 
>>>> an
>>>> interrupt occurs when both of them are true. So all we need to do is have
>>>> that check and run it every time we change a value in TSR or TCR.
>>> 
>>> Well OK, this can work to trigger the interrupts, not to clear them though.
>>> And it will call ppc_set_irq when it's not required.
>> 
>> Calling ppc_set_irq shouldn't be an issue - at the end of the day it only
>> does a simple OR operation. Unsetting should be pretty obvious too though,
>> no? When either TSR.DIS or TCR.DIE are not set, the interrupt line is low.
>> 
> 
> if the interrupt is already set and you clear TCR.DIE, the interrupt has to
> remain set. The only way to unset an interrupt is to clear the corresponding
> bit in TSR (currently in store_booke_tsr).

Are you sure? I see several things in the 2.06 spec:

TSR.DIS:

0       A Decrementer event has not occurred.
1       A Decrementer event has occurred.

when MSR.EE=1 and TCR.DIE=1, a Decrementer interrupt is taken.

TCR.DIE:

0       Disable Decrementer interrupt
1       Enable Decrementer interrupt

Decrement to one and stop on zero

If TCR.ARE=0, TSR.DIS is set to 1, the value 0x0000_0000 is then placed into 
the DEC, and the Decrementer stops decrementing.
A Decrementer interrupt occurs when no higher priority interrupt exists, a 
Decrementer exception exists, and the exception is enabled.
The interrupt is enabled by TCR.DIE=1 and MSR.EE=1.

See     Section 7.6.12, “Decrementer Interrupt” on page 1021 for details of 
register behavior caused by the Decrementer inter- rupt.

7.6.12  Decrementer Interrupt
A Decrementer interrupt occurs when no higher priority interrupt exists (see 
Section 7.9 on page 1037), a Decrementer exception exists (TSR.DIS=1), and the 
exception is enabled. The interrupt is enabled by TCR.DIE=1 and MSR.EE=1. See 
Section 9.3 on page 1047.

Software is responsible for clearing the Decre- menter exception status prior 
to re-enabling the MSR.EE bit in order to avoid another redundant Decrementer 
interrupt. To clear the Decrementer exception, the interrupt handling routine 
must clear TSR.DIS. Clearing is done by writing a word to TSR using mtspr with 
a 1 in any bit position that is to be cleared and 0 in all other bit positions. 
The write-data to the TSR is not direct data, but a mask. A 1 causes the bit to 
be cleared, and a 0 has no effect.


To me that sounds as if the decrementer interrupt gets injected only when 
TSR.DIS=1, TCR.DIE=1 and MSR.EE=1. Unsetting any of these bits stops the 
interrupt from being delivered.

Scott, can you please check up with the hardware guys if this is correct?


Alex




reply via email to

[Prev in Thread] Current Thread [Next in Thread]