Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DM/FEATURE] Support HWSpinlock fo AMP mode #9727

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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 "block/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')
311 changes: 311 additions & 0 deletions components/drivers/hwspinlock/hwspinlock.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,311 @@
/*
* 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 <cpuport.h>

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

#include "hwspinlock_dm.h"

static struct rt_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)
{
rt_spin_lock_init(&hwlock->lock);
hwlock->used = RT_FALSE;
}

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_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 (rt_unlikely(!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 (rt_unlikely(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 (rt_unlikely(!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)
{
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;
}

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 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_ref_put(&hwlock->bank->ref, &hwspinlock_release);
hwlock->used = RT_TRUE;
}
}

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