![]() |
RT-Thread RTOS
An open source embedded real-time operating system
|
RT-Thread hwspinlock (components/drivers/hwspinlock/) models SoC hardware mutex registers shared across heterogeneous CPUs (AMP), remote processors, or firmware—not the same as a single-OS **rt_spinlock**. A bank (one controller IP) exports many **rt_hwspinlock** instances; consumers acquire through **rt_hwspin_*** or device-tree **hwlocks**.
Public API: **components/drivers/include/drivers/hwspinlock.h**. DM types: **components/drivers/hwspinlock/hwspinlock_dm.h**. Core: **components/drivers/hwspinlock/hwspinlock.c**.
SoC-specific controllers are added under **SOC_DM_HWSPINLOCK_DIR** in the BSP Kconfig.
| Option | Role |
|---|---|
**RT_USING_DM** | Required parent |
**RT_USING_OFW** | Required — phandle parsing for **hwlocks** |
**RT_USING_HWSPINLOCK** | Build **hwspinlock.c**; selects **RT_USING_ADT** / **RT_USING_ADT_REF** |
**SOC_DM_HWSPINLOCK_DIR** | BSP adds platform drivers (e.g. mailbox companion lock IP) |
| Object | Role |
|---|---|
**struct rt_hwspinlock_bank** | One controller: **dev**, **ops**, **base_id**, **locks[]** |
**struct rt_hwspinlock** | One hardware lock index; per-lock software **rt_spinlock** guards metadata |
**struct rt_hwspinlock_ops** | **trylock**, **unlock**, optional **relax** (WFE / yield in busy-wait) |
Two layers of locking:
hwlock->lock** — protects the bank’s bookkeeping while calling ops (optional irqsave via **out_irq_level**).ops->trylock/unlock** — the actual cross-core exclusion in silicon.**rt_hw_dmb()** is issued after acquire and before release for visibility ordering.
**rt_hwspinlock_bank_register** requirements:
bank**, **bank->dev**, **bank->ops**, **locks_nr > 0**locks[i].bank**, **used = false**, software spinlockrt_dm_dev_bind_fwdata(dev, NULL, bank)** for OFW lookup**rt_hwspinlock_bank_unregister**: succeeds only when **rt_ref_read(&bank->ref) == 1** (no outstanding **get** references)—else **-RT_EBUSY**.
| API | IRQ save | Behavior |
|---|---|---|
**rt_hwspin_trylock_raw** | optional **out_irq_level** | One try; **-RT_EBUSY** if hardware busy |
**rt_hwspin_lock_timeout_raw** | optional | Retries until success or **timeout_ms** → **-RT_ETIMEOUT**; calls **ops->relax** while waiting |
**rt_hwspin_unlock_raw** | restore if provided | **ops->unlock** then release software lock |
Convenience inlines: **rt_hwspin_trylock**, **rt_hwspin_trylock_irqsave**, **rt_hwspin_lock_timeout**, **rt_hwspin_lock_timeout_irqsave**, matching **unlock** variants.
Rules:
unlock does not clear used** — allocation is separate from locking.| API | Role |
|---|---|
**rt_hwspinlock_get()** | First free lock in any registered bank |
**rt_hwspinlock_get_by_index(dev, index)** | Via consumer’s OFW node |
**rt_hwspinlock_get_by_name(dev, name)** | Match **hwlock-names** |
**rt_ofw_get_hwspinlock_by_index(np, index)** | Parse **hwlocks** + **#hwlock-cells** |
**rt_ofw_get_hwspinlock_by_name(np, name)** | Index from **hwlock-names** |
**rt_hwspinlock_put(hwlock)** | Clear **used**, **rt_ref_put** on bank — does not unlock |
OFW parse (hwspinlock.c):
rt_ofw_parse_phandle_cells(np, "hwlocks", "#hwlock-cells", index, &args)**rt_platform_ofw_request(bank_np)** if provider not probedbank = rt_ofw_data(bank_np)**; lock id = **bank->base_id + args.args[0]** (requires **args_count == 1**)hwlock->used** and **rt_ref_get(&bank->ref)**| Use hwspinlock when… | Use **rt_spinlock** when… |
|---|---|
| Another CPU / DSP / M-core can touch the same resource without sharing RT-Thread. | Only RT-Thread SMP CPUs coordinate, all under one OS. |
| TRM or firmware defines hardware lock index before mailbox/shared SRAM access. | Exclusion inside one kernel with IRQ disable or SMP spinlock is enough. |
| Mailbox / rpmsg handshake doc lists lock IDs. | Short critical section on local driver private data. |
Typical scenarios: AMP, heterogeneous multicore, CPU ↔ remoteproc register blocks, shared message SRAM between Linux and RT-Thread.
Agree on a fixed lock index map in DTS and in remote firmware (e.g. lock 0 = mailbox header, lock 1 = virtio queue). See Mailbox subsystem and RPMsg.
Suggested lock order (document in BSP): acquire hwspinlock before ringing doorbell / sending mailbox, release after MMIO writes visible—avoid holding hwlock while waiting on a blocking IPC call from the other side.
hwspinlock_bank_alloc**, implement **trylock/unlock/relax**, set **base_id** consistently with DT indices, **rt_hwspinlock_bank_register**.rt_ofw_get_hwspinlock_by_name** in **probe**; **put** in **remove**.lock_timeout_irqsave** → short MMIO → **unlock_irqrestore**.put** before **bank_unregister**.rt_hwspinlock_put without unlock** — next **get** may see hardware still owned by this or another core.#hwlock-cells or index — **rt_ofw_get_*** returns **RT_ENOSYS** or wrong slot → silent corruption.relax** busy-wait assumptions.unregister with active refs** — **-RT_EBUSY**; remote side may still hold hardware lock even if ref count looks idle.components/drivers/include/drivers/hwspinlock.hcomponents/drivers/hwspinlock/hwspinlock_dm.h, hwspinlock.crt_dm_dev_bind_fwdata**, **rt_platform_ofw_request**#hwlock-cells**