首页 > 其他分享 >硬件自旋锁框架 【ChatGPT】

硬件自旋锁框架 【ChatGPT】

时间:2023-12-10 12:55:38浏览次数:39  
标签:返回 hwspinlock struct int hwspin 硬件 自旋 hwlock ChatGPT

硬件自旋锁框架

简介

硬件自旋锁模块为异构处理器和不在单一共享操作系统下运行的处理器之间的同步和互斥提供硬件辅助。

例如,OMAP4具有双核Cortex-A9、双核Cortex-M3和一个C64x+ DSP,每个处理器运行不同的操作系统(主处理器A9通常运行Linux,从处理器M3和DSP运行某种RTOS)。

通用的硬件自旋锁框架允许平台无关的驱动程序使用硬件自旋锁设备来访问在远程处理器之间共享的数据结构,否则没有其他机制可以实现同步和互斥操作。

例如,在OMAP4上,CPU密集型多媒体任务通过IPC子系统Syslink从主机卸载到远程M3和/或C64x+从处理器。

为了实现基于消息的快速通信,需要最小的内核支持,以便将从远程处理器到达的消息传递给适当的用户进程。

这种通信基于远程处理器之间共享的简单数据结构,并且使用硬件自旋锁模块进行同步(远程处理器直接将新消息放入这个共享数据结构)。

通用的硬件自旋锁接口使得可以拥有通用的、平台无关的驱动程序。

用户API

struct hwspinlock *hwspin_lock_request(void);

动态分配一个硬件自旋锁并返回其地址,如果没有未使用的硬件自旋锁可用,则返回NULL。使用此API的用户通常希望在可以用于实现同步之前将锁的ID通知给远程核心。

应该在进程上下文中调用(可能会休眠)。

struct hwspinlock *hwspin_lock_request_specific(unsigned int id);

分配特定的硬件自旋锁ID并返回其地址,如果该硬件自旋锁已在使用中,则返回NULL。通常,板级代码将调用此函数以预留特定的硬件自旋锁ID以供预定义目的使用。

应该在进程上下文中调用(可能会休眠)。

int of_hwspin_lock_get_id(struct device_node *np, int index);

检索基于OF phandle的特定锁的全局锁ID。此函数为hwspinlock模块的DT用户提供了一种获取特定hwspinlock的全局锁ID的方法,以便可以使用常规的hwspin_lock_request_specific() API进行请求。

该函数在成功时返回锁ID号,如果hwspinlock设备尚未向核心注册,则返回-EPROBE_DEFER,或其他错误值。

应该在进程上下文中调用(可能会休眠)。

int hwspin_lock_free(struct hwspinlock *hwlock);

释放先前分配的硬件自旋锁;成功时返回0,失败时返回适当的错误代码(例如,如果硬件自旋锁已释放,则返回-EINVAL)。

应该在进程上下文中调用(可能会休眠)。

int hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int timeout);

使用超时限制(以毫秒为单位)锁定先前分配的硬件自旋锁。如果硬件自旋锁已被占用,函数将忙等待直到其被释放,但在超时后放弃。从此函数成功返回后,抢占将被禁用,因此调用者不能休眠,并建议尽快释放硬件自旋锁,以最小化远程核心对硬件互连的轮询。

成功时返回0,否则返回适当的错误代码(尤其是如果硬件自旋锁在超时后仍然忙碌,则返回-ETIMEDOUT)。该函数永远不会休眠。

int hwspin_lock_timeout_irq(struct hwspinlock *hwlock, unsigned int timeout);

锁定先前分配的 hwspinlock,并设置超时限制(以毫秒为单位)。如果 hwspinlock 已被占用,函数将忙等待直到其释放,但在超时时间到达时放弃等待。成功返回后,禁用抢占和本地中断,因此调用者不能睡眠,并建议尽快释放 hwspinlock。

成功返回 0,否则返回适当的错误代码(特别是如果 hwspinlock 在超时时间后仍然忙碌,则返回 -ETIMEDOUT)。该函数不会睡眠。

int hwspin_lock_timeout_irqsave(struct hwspinlock *hwlock, unsigned int to,
                                unsigned long *flags);

锁定先前分配的 hwspinlock,并设置超时限制(以毫秒为单位)。如果 hwspinlock 已被占用,函数将忙等待直到其释放,但在超时时间到达时放弃等待。成功返回后,禁用抢占,禁用本地中断,并将其先前状态保存在给定的 flags 占位符中。调用者不能睡眠,并建议尽快释放 hwspinlock。

成功返回 0,否则返回适当的错误代码(特别是如果 hwspinlock 在超时时间后仍然忙碌,则返回 -ETIMEDOUT)。

该函数不会睡眠。

int hwspin_lock_timeout_raw(struct hwspinlock *hwlock, unsigned int timeout);

锁定先前分配的 hwspinlock,并设置超时限制(以毫秒为单位)。如果 hwspinlock 已被占用,函数将忙等待直到其释放,但在超时时间到达时放弃等待。

注意:用户必须使用互斥锁或自旋锁保护获取硬件锁的例程,以避免死锁,这将允许用户在硬件锁下执行一些耗时或可睡眠的操作。

成功返回 0,否则返回适当的错误代码(特别是如果 hwspinlock 在超时时间后仍然忙碌,则返回 -ETIMEDOUT)。

该函数不会睡眠。

int hwspin_lock_timeout_in_atomic(struct hwspinlock *hwlock, unsigned int to);

锁定先前分配的 hwspinlock,并设置超时限制(以毫秒为单位)。如果 hwspinlock 已被占用,函数将忙等待直到其释放,但在超时时间到达时放弃等待。

此函数只能从原子上下文中调用,超时值不得超过几毫秒。

成功返回 0,否则返回适当的错误代码(特别是如果 hwspinlock 在超时时间后仍然忙碌,则返回 -ETIMEDOUT)。

该函数不会睡眠。

int hwspin_trylock(struct hwspinlock *hwlock);

尝试锁定先前分配的 hwspinlock,如果已被占用则立即失败。

成功返回 0,否则返回适当的错误代码(特别是如果 hwspinlock 已被占用,则返回 -EBUSY)。该函数不会睡眠。

int hwspin_trylock_irq(struct hwspinlock *hwlock);

尝试锁定先前分配的 hwspinlock,如果已被占用则立即失败。

成功返回 0,否则返回适当的错误代码(特别是如果 hwspinlock 已被占用,则返回 -EBUSY)。

该函数不会睡眠。

int hwspin_trylock_irqsave(struct hwspinlock *hwlock, unsigned long *flags);

尝试锁定先前分配的 hwspinlock,如果已被占用则立即失败。

成功返回 0,否则返回适当的错误代码(特别是如果 hwspinlock 已被占用,则返回 -EBUSY)。禁用抢占,禁用本地中断,并将其先前状态保存在给定的 flags 占位符中。调用者不能睡眠,并建议尽快释放 hwspinlock。

该函数不会睡眠。

int hwspin_trylock_raw(struct hwspinlock *hwlock);

尝试锁定先前分配的 hwspinlock,如果已被占用则立即失败。

注意:用户必须使用互斥锁或自旋锁保护获取硬件锁的例程,以避免死锁,这将允许用户在硬件锁下执行一些耗时或可睡眠的操作。

成功返回 0,否则返回适当的错误代码(特别是如果 hwspinlock 已被占用,则返回 -EBUSY)。该函数不会睡眠。

int hwspin_trylock_in_atomic(struct hwspinlock *hwlock);

尝试锁定先前分配的 hwspinlock,如果已被占用则立即失败。

此函数只能从原子上下文中调用。

成功返回 0,否则返回适当的错误代码(特别是如果 hwspinlock 已被占用,则返回 -EBUSY)。该函数不会睡眠。

void hwspin_unlock(struct hwspinlock *hwlock);

解锁先前锁定的 hwspinlock。始终成功,并且可以从任何上下文中调用(该函数不会睡眠)。

注意:代码不应解锁已解锁的 hwspinlock(没有对此进行保护)。

void hwspin_unlock_irq(struct hwspinlock *hwlock);

解锁先前锁定的 hwspinlock,并启用本地中断。调用者不应解锁已解锁的 hwspinlock。

这样做被视为错误(没有对此进行保护)。成功返回后,启用抢占和本地中断。该函数不会睡眠。

void hwspin_unlock_irqrestore(struct hwspinlock *hwlock, unsigned long *flags);

解锁先前锁定的 hwspinlock。

调用者不应解锁已解锁的 hwspinlock。这样做被视为错误(没有对此进行保护)。成功返回后,重新启用抢占,并将本地中断的状态恢复为在给定的 flags 中保存的状态。该函数不会睡眠。

void hwspin_unlock_raw(struct hwspinlock *hwlock);

解锁先前锁定的 hwspinlock。

调用者不应解锁已解锁的 hwspinlock。这样做被视为错误(没有对此进行保护)。该函数不会睡眠。

void hwspin_unlock_in_atomic(struct hwspinlock *hwlock);

解锁先前锁定的 hwspinlock。

调用者不应解锁已解锁的 hwspinlock。这样做被视为错误(没有对此进行保护)。该函数不会睡眠。

int hwspin_lock_get_id(struct hwspinlock *hwlock);

检索给定 hwspinlock 的 id 号码。当 hwspinlock 被动态分配时,需要此信息:在与要同步的远程任务实现互斥之前,应将 id 号码传递给远程任务。

返回 hwspinlock 的 id 号码,如果 hwlock 为 null,则返回 -EINVAL。

典型用法

#include <linux/hwspinlock.h>
#include <linux/err.h>

int hwspinlock_example1(void)
{
        struct hwspinlock *hwlock;
        int ret;

        /* 动态分配一个硬件自旋锁 */
        hwlock = hwspin_lock_request();
        if (!hwlock)
                ...

        id = hwspin_lock_get_id(hwlock);
        /* 可能需要将id传递给远程处理器 */

        /* 获取锁,如果已经被占用则自旋1秒钟 */
        ret = hwspin_lock_timeout(hwlock, 1000);
        if (ret)
                ...

        /*
        * 获取到锁后,进行相应操作,但不要睡眠
        */

        /* 释放锁 */
        hwspin_unlock(hwlock);

        /* 释放锁资源 */
        ret = hwspin_lock_free(hwlock);
        if (ret)
                ...

        return ret;
}

int hwspinlock_example2(void)
{
        struct hwspinlock *hwlock;
        int ret;

        /*
        * 分配一个特定的硬件自旋锁id - 这应该在板级初始化代码中尽早调用。
        */
        hwlock = hwspin_lock_request_specific(PREDEFINED_LOCK_ID);
        if (!hwlock)
                ...

        /* 尝试获取锁,但不要自旋 */
        ret = hwspin_trylock(hwlock);
        if (!ret) {
                pr_info("锁已经被占用\n");
                return -EBUSY;
        }

        /*
        * 获取到锁后,进行相应操作,但不要睡眠
        */

        /* 释放锁 */
        hwspin_unlock(hwlock);

        /* 释放锁资源 */
        ret = hwspin_lock_free(hwlock);
        if (ret)
                ...

        return ret;
}

## 实现者的API

int hwspin_lock_register(struct hwspinlock_device *bank, struct device *dev,
              const struct hwspinlock_ops *ops, int base_id, int num_locks);

从底层特定平台的实现中调用,以注册一个新的硬件自旋锁设备(通常是多个锁的集合)。应该在进程上下文中调用(此函数可能会睡眠)。

成功返回0,失败返回适当的错误代码。

int hwspin_lock_unregister(struct hwspinlock_device *bank);

从底层特定供应商的实现中调用,以注销一个硬件自旋锁设备(通常是多个锁的集合)。

应该在进程上下文中调用(此函数可能会睡眠)。

成功返回hwspinlock的地址,错误返回NULL(例如,如果hwspinlock仍在使用中)。

## 重要的结构体

struct hwspinlock_device是一个通常包含多个硬件锁的设备。它由底层的hwspinlock实现使用hwspin_lock_register() API进行注册。

```c
/**
* struct hwspinlock_device - 通常包含多个hwspinlock的设备
* @dev: 底层设备,将用于调用运行时PM API
* @ops: 特定平台的hwspinlock处理程序
* @base_id: 此设备中第一个锁的id索引
* @num_locks: 此设备中的锁数量
* @lock: 动态分配的 'struct hwspinlock' 数组
*/
struct hwspinlock_device {
        struct device *dev;
        const struct hwspinlock_ops *ops;
        int base_id;
        int num_locks;
        struct hwspinlock lock[0];
};

struct hwspinlock_device包含一个hwspinlock结构的数组,每个结构表示一个单独的硬件锁:

/**
* struct hwspinlock - 此结构表示一个单独的hwspinlock实例
* @bank: 拥有此锁的hwspinlock_device结构
* @lock: 由hwspinlock核心初始化和使用
* @priv: 由底层特定平台的hwspinlock驱动程序拥有的私有数据
*/
struct hwspinlock {
        struct hwspinlock_device *bank;
        spinlock_t lock;
        void *priv;
};

在注册一组锁时,hwspinlock驱动程序只需要设置锁的priv成员。其余成员由hwspinlock核心自行设置和初始化。

实现回调函数

在'struct hwspinlock_ops'中定义了三个可能的回调函数:

struct hwspinlock_ops {
        int (*trylock)(struct hwspinlock *lock);
        void (*unlock)(struct hwspinlock *lock);
        void (*relax)(struct hwspinlock *lock);
};

前两个回调函数是必需的:

->trylock()回调函数应该尝试一次获取锁,并在失败时返回0,在成功时返回1。此回调函数不得睡眠。

->unlock()回调函数释放锁。它总是成功的,它也不得睡眠。

->relax()回调函数是可选的。在自旋等待锁时,hwspinlock核心会调用它,底层实现可以使用它来在两次连续调用->trylock()之间强制延迟。它不得睡眠。

标签:返回,hwspinlock,struct,int,hwspin,硬件,自旋,hwlock,ChatGPT
From: https://www.cnblogs.com/pengdonglin137/p/17892412.html

相关文章

  • 驱动模型 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/driver-api/driver-model/index.htmlDriverModel(驱动程序模型)DriverBinding(驱动绑定)BusTypes(总线类型)DeviceDriverDesignPatterns(设备驱动程序设计模式)TheBasicDeviceStructure(基本设备结构)Devres-ManagedDeviceResou......
  • percpu 读写信号量 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/locking/percpu-rw-semaphore.html"Percpurwsemaphores"是一种新的读写信号量设计,针对读取操作进行了优化。传统的读写信号量存在一个问题,即当多个核心获取读取锁时,包含信号量的缓存行在各个核心的L1缓存之间反复传输,导致性能下降......
  • 计算机组成与设计: 硬件软件接口中的基址寻址
    基址寻址是计算机组成与设计中的重要概念,它指的是通过将一个基址与一个偏移量相加来确定内存中的特定位置。在硬件软件接口中,基址寻址问题是指如何在编程过程中使用基址寄存器来访问内存中的数据和指令。基址寄存器存储了一个起始地址,而偏移寄存器存储了与该基址的偏移量。通过将这......
  • 保持内核代码的可抢占安全 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/locking/preempt-locking.html在可抢占内核下的适当锁定:保持内核代码的可抢占安全作者[email protected]介绍可抢占内核会引发新的锁定问题。这些问题与SMP下的问题相同:并发性和可重入性。幸运的是,Linux可抢占内核模型利......
  • 序列计数器和顺序锁 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/locking/seqlock.html#序列计数器和顺序锁介绍序列计数器是一种具有无锁读取器(只读重试循环)和无写入者饥饿的读者-写者一致性机制。它们用于很少写入数据的情况(例如系统时间),其中读者希望获得一致的信息集,并且愿意在信息发生变化时重试......
  • 锁定课程 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/locking/spinlocks.html锁定课程课程1:自旋锁用于锁定的最基本原语是自旋锁:staticDEFINE_SPINLOCK(xxx_lock);unsignedlongflags;spin_lock_irqsave(&xxx_lock,flags);...临界区域...spin_unlock_irqrestore(&xxx_lock,fl......
  • RT-mutex 实现设计【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/locking/rt-mutex-design.htmlRT-mutex实现设计版权所有(c)2006StevenRostedt根据GNU自由文档许可证第1.2版许可本文档试图描述rtmutex.c实现的设计。它并不描述rtmutex.c存在的原因。有关此内容,请参阅带PI支持的RT-m......
  • 通用互斥子系统 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/locking/mutex-design.html通用互斥子系统由[email protected]发起由[email protected]更新互斥锁是什么?在Linux内核中,互斥锁指的是一种特定的锁原语,它在共享内存系统上强制进行串行化,而不仅仅是指学术界......
  • 锁统计 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/locking/lockstat.html锁统计什么顾名思义,它提供了有关锁的统计信息。为什么因为诸如锁争用之类的问题会严重影响性能。如何Lockdep已经在锁函数中设置了钩子,并将锁实例映射到锁类上。我们在此基础上构建(参见运行时锁正确性验证器)......
  • 运行时锁定正确性验证器 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/locking/lockdep-design.html锁类该验证器操作的基本对象是“锁”的“类”。“锁”的“类”是一组逻辑上相同的锁,即使这些锁可能有多个(可能有成千上万个)实例化。例如,inode结构中的锁是一个类,而每个inode都有自己的该锁类的实例化。验......