Re: [PATCH v2 2/2] clk: aspeed: Prevent reset if clock is enabled

From: Joel Stanley
Date: Fri Mar 09 2018 - 00:03:16 EST


Hi Lei,

On Fri, Mar 9, 2018 at 1:49 PM, Lei YU <mine260309@xxxxxxxxx> wrote:
>
>
>
>> static int aspeed_clk_enable(struct clk_hw *hw)
>> {
>> struct aspeed_clk_gate *gate = to_aspeed_clk_gate(hw);
>> @@ -215,6 +227,11 @@ static int aspeed_clk_enable(struct clk_hw *hw)
>>
>> spin_lock_irqsave(gate->lock, flags);
>>
>> + if (aspeed_clk_is_enabled(hw)) {
>> + spin_unlock_irqrestore(gate->lock, flags);
>> + return 0;
>> + }
>> +
>
> I think this piece of code can be run before spin_lock_irqsave(), so it is
> able to just return without spin_unlock_irqrestore()?

As far as I understand, we are not running under any kind of lock when
calling into the clock framework.

Consider two clock consumer (any old driver) attempting an operation
to change the state of a clock. The first consumer calls
aspeed_clk_enable, and run the aspeed_clk_is_enabled function. This
consumer is then preempted, and the second consume calls
aspeed_clk_disable, taking the lock, they then disable the clock. They
return out of aspeed_clk_disable and the first consumer can run again.

The first consumer has already checked that the clock was disabled, so
they execute the 'return 0', without enabling it. However, their
information is out of date, so they are now in a state where the clock
hardware is disabled, but the clock framework and the consumer think
it is enabled.

By doing the check under a lock, the second consumer won't be able to
perform it's operation until after the first has finished (and as we
disable IRQs, the first bit of code will run to completion without
being preempted).

I might have missed something, so if you're confident we don't need to
check the value under a lock then please let me know :)

Cheers,

Joel