Linux Clock Rate Exclusivity: Hold a Timing Contract Without Blocking Unrelated Consumers Forever
Use Linux clock-rate exclusivity to protect a bounded interval in which another consumer must not change the relevant clock rate. Balance every acquired claim and distinguish a genuinely blocked rate change from a successful no-op. This API is counted rate protection, not a mutex that makes a second acquisition wait until the first owner leaves.
Applicability: the contract below is pinned to Linux v6.12 with CONFIG_COMMON_CLK enabled and valid clock consumer handles. NULL optional handles and disabled-framework stubs are not protection demonstrations. The proposed fixtures use a controlled test provider with two known supported rates; no clock operation or hardware measurement was executed.

1. Define the protected interval and clock dependency
Identify which device operation depends on a stable rate and when that dependency ends. Examples include an acquisition interval or an active transport operation, but the driver must establish its own start, completion, cancellation, and failure boundaries. Hold protection only while the timing requirement actually needs it.
Map the selected provider and ancestors that could affect its rate. Include peer consumers and their legitimate rate-change needs. A long-lived protection claim can prevent useful power or performance changes elsewhere in the tree, so make the intended lifetime explicit before placing acquisition in probe.
The Common Clock Framework overview describes the provider/consumer organization and framework locking. Rate protection does not replace clock preparation or enablement. It also does not establish oscillator accuracy, a measured waveform, or control over firmware that bypasses the framework.
2. Choose preserve-current-rate or set-and-protect
The v6.12 consumer header defines clk_rate_exclusive_get and the matching clk_rate_exclusive_put. These operations may sleep and must not be called from atomic context. The get protects the existing rate; it does not by itself select the rate your device needs.
When the operation needs a new rate and immediate protection, clk_set_rate_exclusive combines setting and acquisition within one framework critical section. A separate set-rate call followed later by a get leaves an interval in which another consumer could intervene. Check the result of the combined call before declaring the protected operation ready.
The v6.12 implementation adds protection only if its set-rate step succeeds. A failed set-and-acquire call does not earn a matching put. Keep a clear software record of acquired claims so cleanup does not release something it never obtained.
3. Understand what “exclusive” does not mean
In v6.12, clk_rate_exclusive_get increments protection and consumer counts; another get can also succeed. Multiple claims can make the rate effectively fixed. The function does not identify a single winning task and block all other callers from acquiring a claim.
A consumer holding one claim can use ordinary clk_set_rate through that same consumer handle: the implementation temporarily removes one protection contribution while evaluating the request, then restores it. Another outstanding claim, including a nested claim by the same consumer, can leave the provider protected against a real rate change.
Do not use the set-and-acquire helper repeatedly as if it were ordinary rate adjustment under an existing claim. It has different acquisition semantics and intentionally does not remove existing protection first. Name wrapper operations according to whether they acquire, change, or release state.
Protection propagates through ancestors. That can constrain a peer whose requested rate requires an upstream change, but it does not imply that every sibling operation is forbidden. A sibling adjustment that does not alter the protected path can have a different outcome. Review the actual tree and provider behavior.
4. Build a fixture that really requests a change
Use separate consumer handles A and B referring to the same test provider. Before adding protection, establish two supported rates, f0 and f1, whose realized values differ. Avoid a fixed-rate provider or a request that rounds back to f0, since neither can demonstrate rejection of a real transition.
In v6.12, the core returns success early when the rounded requested rate already equals the current rate. That check precedes the protected-provider rejection. Consequently, B requesting f0 while A protects f0 can succeed without violating the contract.
| Proposed operation | Expected boundary |
|---|---|
| A sets f0 and acquires protection successfully | A owes one put; the protected interval can begin. |
| B requests unchanged f0 | A no-op success does not prove protection failed. |
| B requests supported, genuinely different f1 | A direct protected-provider change is rejected with EBUSY. |
| B acquires another protection claim | Acquisition can succeed; both claims now require balancing. |
| All claims are released after quiescence | A rate change becomes eligible, subject to other provider constraints. |
Verify returned status and current rate after each step. “Eligible” is not a promise that every requested rate must succeed: range constraints, notifier vetoes, provider limitations, and other state still matter. Preserve the baseline that proved f1 was feasible.
5. Test nesting, failure, and teardown separately
Add a nested-get case using A twice and show that releasing only one claim does not restore the single-owner adjustment behavior. Add a failed set-and-acquire case and confirm that its error path does not perform an unearned release. Keep each fixture isolated so a leaked claim from one case cannot contaminate the next.
For real device teardown, stop new dependent operations, complete or safely cancel the protected work, and only then release the claim. A timeout does not automatically mean the hardware no longer depends on the clock. Resolve that dependency before cleanup permits another consumer to change it.
The device-managed get variant ties cleanup to device-resource lifetime. That can suit a whole-device requirement, but it is broader than a single transaction. Do not mix automatic release with an untracked manual put or assume managed cleanup shortens a claim to the interval you intended.
6. Deliver ownership evidence rather than a rate screenshot
Keep the kernel configuration, provider tree, consumer-handle identities, supported baseline rates, acquired-claim ledger, and operation results together. Include cancellation and removal coverage. Distinguish framework model tests from board captures that establish actual timing under stated conditions.
No fixture was executed for this article. The deliverable is a balanced protection lifecycle and a test matrix that distinguishes acquisition, real-change rejection, no-op success, and restored eligibility. That is the mechanism missing from a generic “recalculate the divider” diagnosis: the driver must control when competing rate changes are allowed, then release that control deliberately.