A common clock framework (from LWN)

One of the big problem areas that has been identified in the ARM kerneltrees is the diversity of implementations for various things that could beshared—either within the ARM tree or more widely with the rest of thekernel. That problem has led to a large amount of duplicated code in theARM tree, both via cut-and-paste and code that is conceptually similar butuses different data structures and APIs. The latter makes the creation ofa single kernel image that can boot on multiple ARM platforms impossible, sothere are efforts to consolidate these implementations. The common clockframework is one such effort.

In a typical ARM system-on-chip (SoC), there can be dozens of differentclocks for use by various I/O and other devices in the SoC. Typicallythose clocks are hooked together into elaborate tree-like structures. Inthose trees, child clocks can sometimes only change their frequency if the parent(and any other children) are correspondingly changed; disabling certainclocks will affect other clocks in the system and so on. Each ARMplatform/SoC has its own way of encapsulating that information andpresenting it to other parts of the system (like power and thermalmanagement controllers), which makes it difficult to createplatform-independent solutions.

The first problem that a common clock framework faces is the sheer numberof different struct clk definitions scattered throughout the ARMtree. There are more than two dozen definitions in arch/armcurrently, but the proposal for a commonframework not surprisingly reduces that number to one. Implementations canwrap the struct clk in another structure that holdshardware-specific data, but the common structure looks like:

    struct clk {
	const char                  *name;
	const struct clk_hw_ops     *ops;
	struct clk                  *parent;
	unsigned long               rate;
	unsigned long               flags;
	unsigned int                enable_count;
	unsigned int                prepare_count;
	struct hlist_head           children;
	struct hlist_node           child_node;
    };

The parent and children/child_node fields allowthe clocks to be arrangedinto trees, while the rate field tracks the current clock frequency (in Hz). Theflags field is used to describe the clocktype (e.g. whether a rate change needs to be done on the parent clock, orthat the clock must be disabled before changing the rate). The two *_count fields are for tracking calls to the enableand prepare operations, while the bulk of the "work" is done within thestruct clk_hw_ops field (ops).

Each of the entries in the clk_hw_ops structure correspond to afunction in the driver-facing API for the clock framework. That API doessome sanity checking before calling the corresponding operation fromclk_hw_ops:

    struct clk_hw_ops {
	int             (*prepare)(struct clk *clk);
	void            (*unprepare)(struct clk *clk);
	int             (*enable)(struct clk *clk);
	void            (*disable)(struct clk *clk);
	unsigned long   (*recalc_rate)(struct clk *clk);
	long            (*round_rate)(struct clk *clk, unsigned long,
				      unsigned long *);
	int             (*set_parent)(struct clk *clk, struct clk *);
	struct clk *    (*get_parent)(struct clk *clk);
	int             (*set_rate)(struct clk *clk, unsigned long);
    };
clk_prepare() is used to initializethe clock to a state where it could be enabled, and that call must be madebefore clk_enable(), which actually starts the clock running. clk_disable() and clk_unprepare() do the reverse andshould be called in that order. The difference is that clk_prepare() can sleep, while clk_enable() must not, sohaving two separate calls allows the clock initialization to be split intoatomic and non-atomic pieces.

clk_get_parent() and clk_set_parent() do what the namesimply, simply returning or changing the parentfield, though setting the parent only succeeds if the clock is not alreadyin use (otherwise -EBUSY is returned). clk_recalc_rate() queriesthe hardware, rather than the cached rate field, for the current frequency of theclock. clk_round_rate() rounds a frequency in Hz to a rate thatthe clock can actually use, and can also be used to determine the correctfrequency for the parent clock when changing rates. All of those are more or less helper functionsfor clk_set_rate().

clk_set_rate() changes the frequency of a clock, but it must takeinto account some other factors. If the CLK_PARENT_SET_RATE flagvalue is set for the clock, clk_set_rate() needs to propagate thechange to the parent clock (which may also have that flag set,necessitating a recursive traversal of the tree, attempting to set the rateat each level).

Drivers can also register their interest in being notified of rate changeswith the clk_notifier_register() function. Three different typesof notification can be requested: before the clock's ratechanges, after it has been changed, or if the change gets aborted after thepre-change notifications have been called (i.e. PRE_RATE_CHANGE,POST_RATE_CHANGE, and ABORT_RATE_CHANGE). In each case,both the old and new values for the rate get passed as part of thenotification callback. The patch to add notificationscreates another operation in clk_hw_ops calledspeculate_rate(), which notes potential rate changes and sends any needed pre-changenotifications as it walks the sub-tree.

The patch set also exports the clock hierarchy into debugfs. Eachtop-level clock gets a directory in ../debug/clk that containsread-only files to report the clock's rate, flags, prepare and enablecounts, and the number of notifiers registered. Subdirectories are createdfor each child clock containing the same information.

The common clock framework has been around for some time in various forms.The current incarnation is being shepherded by Mike Turquette, but he notesthat it is based on work originally done by Jeremy Kerr and BenHerrenschmidt. Beyond that: "Many others contributed to thosepatches and promptly had their work stolen by me". Turquette has also posted a patch set withan examplethat replaces the OMAP4 clocks using the framework.

The comments onthe most recent iteration have been fairly light, but still substantive, sowe are clearly a ways off from seeing a version in the mainline. It'sclearly on the radar of ARM developers, and would clean up a fair amount ofcode duplication within that tree, so we should see something in themainline soon—hopefully in one of the next few kernel releases.


( Log in to post comments)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值