| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- /*
- * 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)
- {
- 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);
- }
|