Common clock and dvfs

Saravana Kannan skannan at codeaurora.org
Fri Apr 22 21:21:26 EDT 2011


On 04/22/2011 12:37 PM, Thomas Gleixner wrote:
> On Fri, 22 Apr 2011, Colin Cross wrote:
>
>> Is the clock api the right place to do dvfs, or should the clock api
>> be kept simple, and more complicated operations like dvfs be kept
>> outside?
>
> I think it's an orthogonal issue which can be solved once we have
> generic implementations in place for clk_ functions which result in
> DFVS relevant changes.
>
> clk_prepare()
> {
> 	lock_tree();
> 	if (dvfs_validate())
> 		return -ECRAP;
> 	prepare();
> 	unlock_tree();
> }
>
> clk_unprepare()
> {
> 	lock_tree();
> 	unprepare();
> 	dvfs_recalc();
> 	unlock_tree();
> }
>
> clk_set_rate()
> {
> 	lock_tree();
>
> 	if (rate>  clk->rate&&  dvfs_prevalidate(rate))
> 		return -ECRAP;
>
> 	set_and_propagate_rate();
>
> 	if (rate<  old->rate)
> 	   dvfs_recalc();
>
> 	unlock_tree();
> }

I understand that this is just some example code, but I'm not sure how 
accurate you were trying to be. So, I will assume the worst.

I really don't like this lock the whole clock tree approach for DVFS. I 
think a better approach would be something like this:

struct dvfs_tuple {
	long	max_rate; /* Max rate for this DVFS level. */
	int	dvfs_level;
};

/* Yeah, bad name. pick what you like. */
struct dvfs_class {
	int 	*level_cnt;
	int 	num_levels;
	int (*dvfs_update) (int level);
	mutex	lock;
}

stuct clk {
	...
	/* Last entry would have {LONG_MAX, highest level in dvfs}, */
	struct	dvfs_tuple *dvfs_list;
	struct  dvfs_class *dvfs_class;
}

Then

clk_prepare() {
	for each dvfs tuple {
		if current_rate <= max_rate; {
			level = dvfs_level;
			break;
		}
	}

	lock(dvfs_class->mutex);

	clk->dvfs_class->level_cnt[level]++;
	/* Find highest level in this dvfs class with non-zero count */
	if(clk->dvfs_class->update(highest_level))
		return -ECRAP;
	/* Yes, I see locking err, but you get the point */
	unlock(dvfs_class->mutex);
	
	clk->ops->prepare(clk);
}

I did some crappy factorization of functions, returning -ECRAP without 
unlocking, etc, but you get the point.

Whether the "level" translates to controlling power supply A or B or A & 
B is upto the implementation of dvfs_class->dvfs_update() which is per 
SOC/mach/arch.

This will keep the dvfs data structure common for all clocks, remove the 
need to traverse the entire tree and keep the generic code agnostic of 
1-1 vs. many-1 vs many-many.

> We can put the dvfs functions into the propagation code as well and
> back out there when dvfs tells us. That probably works nicely for
> prepare and unprepare, but might be complex for set_rate in the actual
> set_rate propagation (except when the rate is less than the original
> one).

For set rate, you lock the dvfs class, increment the count for the new 
rate's dvfs_level, decrement it for the previous dvfs level, and then 
call dvfs_update() with the max level in that class, unlock dvfs_class.

Thanks,
Saravana

-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.



More information about the linux-arm-kernel mailing list