Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions components/drivers/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ rsource "hwcrypto/Kconfig"
rsource "wlan/Kconfig"
rsource "led/Kconfig"
rsource "mailbox/Kconfig"
rsource "hwspinlock/Kconfig"
rsource "phye/Kconfig"
rsource "ata/Kconfig"
rsource "nvme/Kconfig"
Expand Down
15 changes: 15 additions & 0 deletions components/drivers/hwspinlock/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
menuconfig RT_USING_HWSPINLOCK
bool "Using Hardware Spinlock device drivers"
depends on RT_USING_DM
depends on RT_USING_OFW
select RT_USING_ADT
select RT_USING_ADT_REF
default n
help
Hardware spinlock modules provide hardware assistance for
synchronization and mutual exclusion between heterogeneous processors
and those not operating under a single, shared operating system.

if RT_USING_HWSPINLOCK
osource "$(SOC_DM_HWSPINLOCK_DIR)/Kconfig"
endif
15 changes: 15 additions & 0 deletions components/drivers/hwspinlock/SConscript
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from building import *

group = []

if not GetDepend(['RT_USING_HWSPINLOCK']):
Return('group')

cwd = GetCurrentDir()
CPPPATH = [cwd + '/../include']

src = ['hwspinlock.c']

group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)

Return('group')
319 changes: 319 additions & 0 deletions components/drivers/hwspinlock/hwspinlock.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,319 @@
/*
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 [PR Title/PR 标题]: PR title needs improvement / PR 标题需要改进

English: The PR title [dm][hwspinlock] support hwspinlock follows the correct prefix format [module][subsystem], but the description "support hwspinlock" is too vague. It should be more specific about what is being added.

中文: PR 标题 [dm][hwspinlock] support hwspinlock 遵循了正确的前缀格式 [模块][子系统],但描述 "support hwspinlock" 过于模糊。应该更具体地说明正在添加什么。

Suggested title / 建议标题:
[dm][hwspinlock] Add hardware spinlock driver framework

or / 或

[dm][hwspinlock] Implement hwspinlock driver management

Note: This follows the RT-Thread guideline that titles should be specific and avoid vague terms like "support" or "add support for".

Copilot generated this review using guidance from repository custom instructions.
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-09-23 GuEe-GUI first version
*/

#include <rtthread.h>

#include <cpuport.h>

#define DBG_TAG "rtdm.hwspinlock"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>

#include "hwspinlock_dm.h"

static RT_DEFINE_SPINLOCK(hwspinlock_ops_lock);
static rt_list_t hwspinlock_bank_nodes = RT_LIST_OBJECT_INIT(hwspinlock_bank_nodes);

rt_err_t rt_hwspinlock_bank_register(struct rt_hwspinlock_bank *bank)
{
struct rt_hwspinlock *hwlock;

if (!bank || !bank->ops || bank->locks_nr <= 0 || !bank->dev)
{
return -RT_EINVAL;
}

rt_list_init(&bank->list);
rt_ref_init(&bank->ref);

hwlock = &bank->locks[0];

for (int i = 0; i < bank->locks_nr; ++i, ++hwlock)
{
hwlock->bank = bank;
hwlock->used = RT_FALSE;
rt_spin_lock_init(&hwlock->lock);
}

rt_spin_lock(&hwspinlock_ops_lock);
rt_list_insert_after(&hwspinlock_bank_nodes, &bank->list);
rt_spin_unlock(&hwspinlock_ops_lock);

rt_dm_dev_bind_fwdata(bank->dev, RT_NULL, bank);

return RT_EOK;
}

rt_err_t rt_hwspinlock_bank_unregister(struct rt_hwspinlock_bank *bank)
{
rt_err_t err;

if (!bank)
{
return -RT_EINVAL;
}

rt_spin_lock(&hwspinlock_ops_lock);

if (rt_ref_read(&bank->ref) == 1)
{
rt_list_remove(&bank->list);
rt_dm_dev_unbind_fwdata(bank->dev, RT_NULL);

err = RT_EOK;
}
else
{
err = -RT_EBUSY;
}

rt_spin_unlock(&hwspinlock_ops_lock);

return err;
}

rt_err_t rt_hwspin_trylock_raw(struct rt_hwspinlock *hwlock,
rt_ubase_t *out_irq_level)
{
rt_err_t err;

if (!hwlock)
{
return -RT_EINVAL;
}

if (out_irq_level)
{
*out_irq_level = rt_spin_lock_irqsave(&hwlock->lock);
}
else
{
rt_spin_lock(&hwlock->lock);
}

err = hwlock->bank->ops->trylock(hwlock);

if (err)
{
if (out_irq_level)
{
rt_spin_unlock_irqrestore(&hwlock->lock, *out_irq_level);
}
else
{
rt_spin_unlock(&hwlock->lock);
}
}

rt_hw_dmb();

return err;
}

rt_err_t rt_hwspin_lock_timeout_raw(struct rt_hwspinlock *hwlock,
rt_uint32_t timeout_ms, rt_ubase_t *out_irq_level)
{
rt_err_t err;
rt_tick_t timeout = rt_tick_get() + rt_tick_from_millisecond(timeout_ms);

for (;;)
{
err = rt_hwspin_trylock_raw(hwlock, out_irq_level);

if (err != -RT_EBUSY)
{
break;
}

if (timeout < rt_tick_get())
{
return -RT_ETIMEOUT;
}

if (hwlock->bank->ops->relax)
{
hwlock->bank->ops->relax(hwlock);
}
}

return err;
}

void rt_hwspin_unlock_raw(struct rt_hwspinlock *hwlock,
rt_ubase_t *out_irq_level)
{
if (!hwlock)
{
return;
}

rt_hw_dmb();

hwlock->bank->ops->unlock(hwlock);

if (out_irq_level)
{
rt_spin_unlock_irqrestore(&hwlock->lock, *out_irq_level);
}
else
{
rt_spin_unlock(&hwlock->lock);
}
}

static struct rt_hwspinlock *hwspinlock_get(struct rt_hwspinlock_bank *bank, int id)
{
struct rt_hwspinlock *hwlock = RT_NULL;

if (bank)
{
int offset = id - bank->base_id;

if (!bank->locks[offset].used)
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug/缺陷: Missing bounds check for array access / 缺少数组访问的边界检查

English: The offset is calculated from id - bank->base_id but there's no validation that offset is within valid bounds (0 to bank->locks_nr - 1) before accessing bank->locks[offset]. This can lead to out-of-bounds array access if an invalid id is provided.

中文: offset 是通过 id - bank->base_id 计算的,但在访问 bank->locks[offset] 之前没有验证 offset 是否在有效范围内(0 到 bank->locks_nr - 1)。如果提供了无效的 id,这可能导致数组越界访问。

Suggested fix / 建议修复:

if (bank)
{
    int offset = id - bank->base_id;
    
    if (offset >= 0 && offset < bank->locks_nr && !bank->locks[offset].used)
    {
        hwlock = &bank->locks[offset];
    }
}
Suggested change
if (!bank->locks[offset].used)
if (offset >= 0 && offset < bank->locks_nr && !bank->locks[offset].used)

Copilot uses AI. Check for mistakes.
{
hwlock = &bank->locks[offset];
}
}
else
{
rt_list_for_each_entry(bank, &hwspinlock_bank_nodes, list)
{
hwlock = rt_err_ptr(-RT_EBUSY);

for (int i = 0; i < bank->locks_nr; ++i)
{
if (!bank->locks[i].used)
{
hwlock = &bank->locks[i];
goto _found;
}
}
}
}

_found:
if (!rt_is_err_or_null(hwlock))
{
hwlock->used = RT_TRUE;
rt_ref_get(&hwlock->bank->ref);
}

return hwlock;
}

struct rt_hwspinlock *rt_hwspinlock_get(void)
{
struct rt_hwspinlock *lock;

rt_spin_lock(&hwspinlock_ops_lock);

lock = hwspinlock_get(RT_NULL, -1);

rt_spin_unlock(&hwspinlock_ops_lock);

return lock;
}

struct rt_hwspinlock *rt_hwspinlock_get_by_index(struct rt_device *dev, int index)
{
return rt_ofw_get_hwspinlock_by_index(dev->ofw_node, index);
}

struct rt_hwspinlock *rt_hwspinlock_get_by_name(struct rt_device *dev, const char *name)
{
return rt_ofw_get_hwspinlock_by_name(dev->ofw_node, name);
}

static void hwspinlock_release(struct rt_ref *r)
{
struct rt_hwspinlock_bank *bank = rt_container_of(r, struct rt_hwspinlock_bank, ref);

LOG_E("%s is release", rt_dm_dev_get_name(bank->dev));
(void)bank;

RT_ASSERT(0);
}

void rt_hwspinlock_put(struct rt_hwspinlock *hwlock)
{
if (hwlock)
{
rt_spin_lock(&hwspinlock_ops_lock);
hwlock->used = RT_FALSE;
rt_spin_unlock(&hwspinlock_ops_lock);

rt_ref_put(&hwlock->bank->ref, &hwspinlock_release);
}
}

struct rt_hwspinlock *rt_ofw_get_hwspinlock_by_index(struct rt_ofw_node *np, int index)
{
rt_err_t err;
struct rt_ofw_node *bank_np;
struct rt_ofw_cell_args args;
struct rt_hwspinlock *lock;
struct rt_hwspinlock_bank *bank;

if (!np || index < 0)
{
return rt_err_ptr(-RT_EINVAL);
}

err = rt_ofw_parse_phandle_cells(np, "hwlocks", "#hwlock-cells", index, &args);

if (err)
{
return rt_err_ptr(err);
}

bank_np = args.data;

if (!rt_ofw_data(bank_np))
{
rt_platform_ofw_request(bank_np);
}

rt_spin_lock(&hwspinlock_ops_lock);

bank = rt_ofw_data(bank_np);
rt_ofw_node_put(bank_np);

if (!bank || args.args_count != 1)
{
lock = rt_err_ptr(-RT_ENOSYS);
}
else
{
lock = hwspinlock_get(bank, bank->base_id + args.args[0]);
}

rt_spin_unlock(&hwspinlock_ops_lock);

return lock;
}

struct rt_hwspinlock *rt_ofw_get_hwspinlock_by_name(struct rt_ofw_node *np, const char *name)
{
int index;

if (!np || !name)
{
return rt_err_ptr(-RT_EINVAL);
}

index = rt_ofw_prop_index_of_string(np, "hwlock-names", name);

if (index < 0)
{
return rt_err_ptr(index);
}

return rt_ofw_get_hwspinlock_by_index(np, index);
}
Loading