1. 简介

Regmap 机制是在 Linux 3.1 加入进来的特性。主要目的是减少慢速 I/O 驱动上的重复逻辑,提供一种通用的接口来操作底层硬件上的寄存器。其实这就是内核做的一次重构。Regmap 除了能做到统一的 I/O 接口,还可以在驱动和硬件 IC 之间做一层缓存,从而能减少底层 I/O 的操作次数。

2. 使用对比

在了解 Regmap 的实现细节前,我们先来对比一下,传统操作寄存器的方式,与 Regmap 之间的差异。

2.1 传统方式

我们以一个 I2C 设备为例。读写一个寄存器,肯定需要用到 i2c_transfer 这样的 I2C 函数。为了方便,一般的驱动中,会在这之上再写一个 Wrapper,然后通过调用这个 Wrapper 来读写寄存器。比如如下这个读取寄存器的函数:

static int xxx_i2c_read_reg(struct i2c_client *client, u8 reg, u8 *val)
{
struct i2c_msg msg[] = {
{
.addr = client->addr,
.flags = 0,
.len = 1,
.buf = &reg,
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = 1,
.buf = val,
},
}; return i2c_transfer(client->adapter, msg, 2);
}

2.2 Regmap方式

如果 regmap 的方式来实现,对于上面这种读寄存器操作,其实现如下:

// first step: define regmap_config
static const struct regmap_config xxx_regmap_config = {
.reg_bits = 10,
.val_bits = 14, .max_register = 40,
.cache_type = REGCACHE_RBTREE, .volatile_reg = false,
.readable_reg = false,
}; // second step: initialize regmap in driver loading
regmap = regmap_init_i2c(i2c_client, &xxx_regmap_config); // third step: register operations
regmap_read(regmap, XXX_REG, &value);

代码中,做的第一步就是定义 IC 的一些寄存器信息。比如:位宽,地址位宽,寄存器总数等。然后在驱动加载的时候,初始化 Regmap,这样就可以正常调用 Regmap 的 API 了。

可以看到,为了让慢速 I/O 能够专注于自身的逻辑,内核把 SPI, I2C 等总线操作方式全部封装在 Regmap 里,这样驱动若要做 I/O 操作,直接调用 Regmap 的函数就可以了。

3. 实现细节

整个 Regmap 是分为 3 层,其拓扑结构如下:

这里通过其中 3 个核心结构体来分别说明。

3.1 regmap_config

struct regmap_config构体代表一个设备的寄存器配置信息,在做 Regmap 初始化时,驱动就需要把这个结构体传给 Regmap。这个结构体的定义在 include/linux/regmap.h,其中包含该设备的寄存器数量,寄存器位宽,缓存类型,读写属性等。

这一层是直接和驱动对接的。Regmap 根据传进来的 regmap_config 初始化对应的缓存和总线操作接口,驱动就可以正常调用 regmap_writeregmap_read 函数。

3.2 regmap_ops

struct regmap_ops是用来定义一个缓存类型的,具体定义如下:

struct regcache_ops {
const char *name;
enum regcache_type type;
int (*init)(struct regmap *map);
int (*exit)(struct regmap *map);
#ifdef CONFIG_DEBUG_FS
void (*debugfs_init)(struct regmap *map);
#endif
int (*read)(struct regmap *map, unsigned int reg, unsigned int *value);
int (*write)(struct regmap *map, unsigned int reg, unsigned int value);
int (*sync)(struct regmap *map, unsigned int min, unsigned int max);
int (*drop)(struct regmap *map, unsigned int min, unsigned int max);
};

在最新 Linux 4.0 版本中,已经有 3 种缓存类型,分别是数组(flat)、LZO 压缩和红黑树(rbtree)。数组好理解,是最简单的缓存类型,当设备寄存器很少时,可以用这种类型来缓存寄存器值。LZO(Lempel–Ziv–Oberhumer) 是 Linux 中经常用到的一种压缩算法,Linux 编译后就会用这个算法来压缩。这个算法有 3 个特性:压缩快,解压不需要额外内存,压缩比可以自动调节。在这里,你可以理解为一个数组缓存,套了一层压缩,来节约内存。当设备寄存器数量中等时,可以考虑这种缓存类型。而最后一类红黑树,它的特性就是索引快,所以当设备寄存器数量比较大,或者对寄存器操作延时要求低时,就可以用这种缓存类型。

缓存的类型是在 Regmap 初始化时,由.cache_type = REGCACHE_RBTREE来指定的。对于regmap_read获取值,若需要从硬件上读取,则调用具体协议的读写函数,若是 I2C,调用i2c_transfer。写的过程也是大同小异。

3.3 regmap_bus

前面说的都是 Regmap 所做的封装,而真正进行 I/O 操作就是这最后一层。struct regmap_bus 定义了一个总线上的读写函数,这一层就像之前对 i2c_transfer 所做的封装一样。其定义如下:

struct regmap_bus {
bool fast_io;
regmap_hw_write write;
regmap_hw_gather_write gather_write;
regmap_hw_async_write async_write;
regmap_hw_reg_write reg_write;
regmap_hw_read read;
regmap_hw_reg_read reg_read;
regmap_hw_free_context free_context;
regmap_hw_async_alloc async_alloc;
u8 read_flag_mask;
enum regmap_endian reg_format_endian_default;
enum regmap_endian val_format_endian_default;
};

在 Lernel 4.0 中,已经支持了 I2C、SPI、AC97、MMIO 和 SPMI 五种总线类型。相信在未来,有更多的总线会加进来。其实添加一个总线也不是很难,只需 4 个函数就可以了:xxx_readxxx_writexxx_initxxx_deinit。具体可以看源码,这里就不多说了,留个任务在这吧。

Regmap 框架:简化慢速IO接口优化性能【转】的更多相关文章

  1. 多线程IO通过并发IO来优化性能

    1.通过多线程IO,并发的IO形式来减少顺序IO达到提升性能的目的. 2.具体线程使用方式可以参见  http://www.cnblogs.com/freedommovie/p/7155260.htm ...

  2. SSH框架简化

    通过对ssh框架有了基础性的学习,本文主要是使用注解的方式来简化ssh框架的代码编写. 注意事项: 1.运行环境:Windows 8-64位,Eclipse(开发工具),jdk1.8.0_91,Tom ...

  3. Linux硬件IO的优化简介

    Linux硬件IO的优化简介 首先简单介绍下有哪些硬件设备如下(由于硬件种类厂家等各种因素我就不在此多做介绍有兴趣的可以自行学习): 1.CPU:中央处理器,是计算机运算控制的核心部件之一,相当于人的 ...

  4. 提升网速的路由器优化方法(UPnP、QoS、MTU、交换机模式、无线中继)

    在上一篇<为什么房间的 Wi-Fi 信号这么差>中,猫哥从微波炉.相对论.人存原理出发,介绍了影响 Wi-Fi 信号强弱的几大因素,接下来猫哥再给大家介绍几种不用升级带宽套餐也能提升网速的 ...

  5. 【linux草鞋应用编程系列】_1_ 开篇_系统调用IO接口与标准IO接口

    最近学习linux系统下的应用编程,参考书籍是那本称为神书的<Unix环境高级编程>,个人感觉神书不是写给草鞋看的,而是 写给大神看的,如果没有一定的基础那么看这本书可能会感到有些头重脚轻 ...

  6. [经验] Win7减肥攻略(删文件不删功能、简化优化系统不简优化性能)

    [经验] Win7减肥攻略(删文件不删功能.简化优化系统不简优化性能) ☆心梦无痕☆ 发表于 2014-1-24 11:15:04 https://www.itsk.com/thread-316471 ...

  7. 用 Python 测试框架简化测试

    用 Python 测试框架简化测试 摘要:本文将向您介绍了三种流行 Python 测试框架(zope.testing,py.test,nose)的基本特性,并讨论新一代的测试风格. 最近出现了行业级的 ...

  8. STM32W108无线射频模块通用IO接口应用实例

    STM32W108无线射频模块通用IO接口应用实例 本实例编写STM32W108的GPIO測试程序,通过控制GPIO引脚,实现对LED灯的控制. 开发环境与硬件说明 硬件:STM32W108无线开发板 ...

  9. 用ladon框架封装Python为Webservice接口以及调用接口的方法

    一.用ladon框架封装Python为Webservice接口 功能实现的同时,希望将接口开放给别人,而封装python接口的一个再简单不过的框架Ladon,而且提供不同的协议,包括SOAP和Json ...

随机推荐

  1. spring boot实现ssm(2)功能

    spring 和 mybatis 整合的那篇: ssm(2) . 配置文件比ssm(1) 更多, 在做项目的时候, 配置文件是一个让人头大的事情. 那么在spring boot中, 实现相同功能, 需 ...

  2. smarty安装与配置

    smarty是一个 PHP 模板引擎,也就是一个类库, 可以到官网下载,也可以到其GitHub地址去下载: 鄙人下载的是 3.1.32版本,解压后的目录结构如下: 最重要的是 libs 目录,demo ...

  3. VS2017 IIS 部署.net core web项目

    1.点击IIS,查看模块 查看是否安装了 AspNetCoreModule 模块,如果没有安装可下载:https://dotnet.microsoft.com/download 下载安装后,即可部署项 ...

  4. git 撤销add和commit

    有时候改完代码发现改错分支了,而这个时候已经add或者commit了,怎么办,有办法: 1.若果已经add .  了这个时候可以使用git stash命令,具体操作命令如下: (1) > git ...

  5. 畅通工程再续(hdu1875) 并查集

    畅通工程再续 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Sub ...

  6. Dagger2 单例

    解锁Dagger2使用姿势(二) 之带你理解@Scope Dagger2从0基础使用,到单例注入的正确姿势 Android之dagger2的简单运用和详细解读(入门)

  7. C#生成二维码,裁切边框

    使用google zxing生成的二维码带有白色边框,显示在报告(使用Crystal Report 水晶报表)上时,由于空间有限造成二维码过小难以扫描识别. 通过将白色边框裁切掉,可以在有限的空间内最 ...

  8. 理解Java反射

    一.反射简介 Java让我们在运行时识别对象和类的信息,主要有2种方式:一种是传统的RTTI,它假定我们在编译时已经知道了所有的类型信息:另一种是反射机制,它允许我们在运行时发现和使用类的信息. 1. ...

  9. JDBC流程

    最近要学习Mybatis的源码,因此对JDBC的使用进行总结. 一.JDBC概述 JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java ...

  10. BZOJ2337: [HNOI2011]XOR和路径(期望 高斯消元)

    题意 题目链接 Sol 期望的线性性对xor运算是不成立的,但是我们可以每位分开算 设\(f[i]\)表示从\(i\)到\(n\)边权为1的概率,统计答案的时候乘一下权值 转移方程为 \[f[i] = ...