当前位置: 首页 > news >正文

IO Virtualization with Virtio.part 1 [十二]

久等了各位!

本篇开始讲解 IO 虚拟化中的 virtio,我会以 Linux 的 IIC 驱动为例,从 IIC 驱动的非虚拟化实现,到 IIC 驱动的半虚拟化实现,再到最后 X-Hyper 中如何通过 virtio 来实现前后端联系,一步步把 virtio 讲清楚。所以我一共会分为4个子篇幅来介绍virtio,内容有点多,需要一点点消化。

本篇我们以 RK 板的 IIC 控制器为例,先讲解 Linux 下的 IIC 驱动框架。

设备树创建 i2c 设备的节点,在设备树遍历时会创建一个 i2c 的 platform 设备出来:

    i2c@fdd40000 {compatible = "rockchip,rk3399-i2c";reg = <0x00 0xfdd40000 0x00 0x1000>;clocks = <0x32 0x07 0x32 0x2d>;clock-names = "i2c\0pclk";interrupts = <0x00 0x2e 0x04>;pinctrl-names = "default";pinctrl-0 = <0x35>;#address-cells = <0x01>;#size-cells = <0x00>;status = "okay";phandle = <0x17a>;}

设备包含如下信息:

  • compatible:兼容性,用于匹配可以用于该设备的驱动;
  • reg:该设备的寄存器基地址和范围;
  • interrupts:i2c 中断控制器使用的中断配置;

这个 platform device 在被放入平台总线时,会匹配对应的 platform driver,那么先来看一下 platform bus 是什么:

struct bus_type platform_bus_type = {.name		= "platform",.dev_groups	= platform_dev_groups,.match		= platform_match,.uevent		= platform_uevent,.dma_configure	= platform_dma_configure,.pm		= &platform_dev_pm_ops,
};

我们只关注其中的 match 函数,它是当一个新的设备或者一个新的驱动被添加到该总线时会被调用的匹配函数,当一个新的设备被加入时,使用 match 来匹配对应的驱动,当一个新的驱动被添加到该总线时,也会使用这个 match 来匹配设备。

我们以 rk 板的 i2c 平台总线驱动为例,首先我们找到 rk 板的 i2c 平台总线驱动:

static struct platform_driver rk3x_i2c_driver = {.probe   = rk3x_i2c_probe,.remove  = rk3x_i2c_remove,.driver  = {.name  = "rk3x-i2c",.of_match_table = rk3x_i2c_match,.pm = &rk3x_i2c_pm_ops,},
};

使用of_match_table 来匹配对应的的设备,使用probe 来初始化设备。

整体流程如下:

在深入分析 IIC 的驱动代码前,先简单看一下 IIC 的整个数据发送和接受流程,这里不会涉及底层硬件的时序,需要读者自己去学习。

IIC 主机向从机写数据:

IIC 主机向从机读数据:

当然IIC的发送接收不止上述两种模式,这里只讨论常用的两种发送和接收数据的方法。

然后我们开始分析 IIC platform driver 的代码了:

我们以 RK board 为例,其总线驱动代码在:drivers\i2c\busses\i2c-rk3x.c 中,具体实现可以参考我之前的文章,这里只给出一个整体框图。最终 i2c 的控制器也会以字符设备节点暴露给用户态,我们可以通过 i2c 控制器的字符设备给相应的 i2c 外设通信。

然后看一下用户层打开一个 i2c 控制器对应的字符设备节点的整体流程图:

整个流程如下:

当应用程序打开一个设备文件时,通过系统调用 sys_open 进入内核,在内核空间中由 do_sys_open 负责发起整个设备文件的打开操作,首先获得该设备文件所对应的 inode,然后调用其中的 i_fop 函数,对字符设备而言,i_fop 函数就是 chrdev_open,后者通过 inode 中的 i_rdev 成员在 cdev_map 中查找该设备所对应的设备对象 cdev,在成功找到了该设备对象后,将 inode 的 cdev 成员指向该字符设备对象,这样下次再对该设备文件节点进行打开操作时,就可以直接通过 i_cdev 成员得到设备节点所对应的字符设备对象了。内核在每次打开一个设备文件时,会产生一个整形的文件描述符 fd 和一个新的 struct file 对象 filp 来跟踪对该文件的这一次操作,在打开设备文件时,内核会将 filp 和 fd 关联起来,同时会将 cdev 中的 ops 赋值给 filp->f_op,同时创建 i2c_client,关联 i2c_adapter,并将 filp 的 private_data 和 i2_client 关联起来。最后 sys_open 系统调用将设备文件描述符 fd 返回到用户空间。

接下来用一个实际的例子去理解一下 IIC 的完成一次 Combined R/W 的流程:

用户侧示例代码如下:

int main(void)
{int fd = 0;int ret = 0;const char *path_name ="/dev/i2c-0";uint8_t buf[8] = {0};uint8_t start_reg = 0x0;struct i2c_msg read_msg[2] = {{0x20,               /* slave addr */0,                  /* operate flags */1,                  /* data len */&start_reg          /* data buf */},{0x20,               /* slave addr */I2C_M_RD,           /* operate flags */8,                  /* data len */&buf[0]   			/* data buf */},};struct i2c_rdwr_ioctl_data rdwr = {.msgs = read_msg,.nmsgs = 2};fd  = open(path_name, O_RDWR);ret = ioctl(fd, I2C_SLAVE_FORCE, 0x20);ret = ioctl(fd, I2C_RDWR, (unsigned long)&rdwr);return 0;
}

这是一次 Combined 的从机数据读取操作,由两部分i2c_msg 组成,第一个 msg 向从机写设备寄存器地址,表示要读取的设备寄存器,然后再发送读数据请求,向从机请求 8 个字节的 data。

对应整个 IIC 的协议段如下:

然后我们通过 ioctl 进入内核,并最终调用 i2cdev_fops->i2cdev_ioctl。

static const struct file_operations i2cdev_fops = {....compat_ioctl	= compat_i2cdev_ioctl,...
};static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{struct i2c_client *client = file->private_data;...switch (cmd) {...case I2C_RDWR: {...return i2cdev_ioctl_rdwr(client, rdwr_arg.nmsgs, rdwr_pa);}...return 0;
}static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client,unsigned nmsgs, struct i2c_msg *msgs)
{...res = i2c_transfer(client->adapter, msgs, nmsgs);...return res;
}int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{...ret = __i2c_transfer(adap, msgs, num);return ret;
}int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{...ret = adap->algo->master_xfer(adap, msgs, num);...return ret;
}

可以看到最后就是调用了i2c_adapter 中的master_xfer。

static int rk3x_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msgs, int num)
{struct rk3x_i2c *i2c = (struct rk3x_i2c *)adap->algo_data;...for (i = 0; i < num; i += ret) {ret = rk3x_i2c_setup(i2c, msgs + i, num - i);...rk3x_i2c_start(i2c);...}...
}

rk3x_i2c_xfer 中初始化MRXADDR 和 MRXRADDR 寄存器并初始化 i2c 的初始化状态机状态。然后通过rk3x_i2c_start 发送 start 信号开始 i2c 的整个流程,并在rk3x_i2c_irq 中维护整个 i2c 数据发送和接受的状态机:

static irqreturn_t rk3x_i2c_irq(int irqno, void *dev_id)
{...switch (i2c->state) {case STATE_START:rk3x_i2c_handle_start(i2c, ipd);break;case STATE_WRITE:rk3x_i2c_handle_write(i2c, ipd);break;case STATE_READ:rk3x_i2c_handle_read(i2c, ipd);break;case STATE_STOP:rk3x_i2c_handle_stop(i2c, ipd);break;case STATE_IDLE:break;}...
}

在 Combined W/R 模式下的流程图和状态机如下所示:

流程图:

IIC 驱动状态机:

到这里我们简单的介绍了Linux下的IIC驱动框架和其工作流程,如果要深入理解还需自己阅读驱动代码,下一篇幅将介绍IIC半虚拟化的Virtio前端驱动。

相关文章:

IO Virtualization with Virtio.part 1 [十二]

久等了各位&#xff01; 本篇开始讲解 IO 虚拟化中的 virtio&#xff0c;我会以 Linux 的 IIC 驱动为例&#xff0c;从 IIC 驱动的非虚拟化实现&#xff0c;到 IIC 驱动的半虚拟化实现&#xff0c;再到最后 X-Hyper 中如何通过 virtio 来实现前后端联系&#xff0c;一步步把 v…...

ShardingSphere-Proxy分表场景:go测试案例

接续上篇文章《ShardingSphere-Proxy分表场景测试案例》 go测试用例&#xff1a; package mainimport ("fmt""math/rand""time""github.com/bwmarrin/snowflake""gorm.io/driver/mysql""gorm.io/gorm""gor…...

OpenStack系列第四篇:云平台基础功能与操作(Dashboard)

文章目录 1. 镜像&#xff08;Image&#xff09;添加镜像查看镜像删除镜像 2. 卷&#xff08;Volume&#xff09;创建卷查看卷删除卷 3. 网络&#xff08;虚拟网络&#xff09;创建网络查看网络删除网络 4. 实例类型创建实例类型查看实例类型删除实例类型 4. 密钥对&#xff08…...

ESP32 I2S音频总线学习笔记(一):初识I2S通信与配置基础

文章目录 简介为什么需要I2S&#xff1f;关于音频信号采样率分辨率音频声道 怎样使用I2S传输音频&#xff1f;位时钟BCLK字时钟WS串行数据SD I2S传输模型I2S通信格式I2S格式左对齐格式右对齐格式 i2s基本配置i2s 底层API加载I2S驱动设置I2S使用的引脚I2S读取数据I2S发送数据卸载…...

25上半年软考高级系统分析师易混淆知识点

第1章 系统工程与信息系统基础 易混淆点1&#xff1a;系统工程生命周期与信息系统的生命周期 1、系统工程生命周期阶段 探索性研究→概念阶段→开发阶段→生产阶段→使用阶段→保障阶段→退役阶段 2、信息系统的生命周期 产生阶段→开发阶段&#xff08;单个系统开发&…...

采集JSON解析错误的修复

两段采集来的JSON格式&#xff1a; 一&#xff1a; {"hwgOnlineId":"554312", "jiwuChatId":"", "phoneCategoryId":"20006", "cuxiaoSeq":{voucherTitle:1,lh 二&#xff1a; {"pic":&q…...

Java中实现对象的深拷贝(Deep Copy)

在Java中实现对象的深拷贝&#xff08;Deep Copy&#xff09;意味着创建一个对象的副本&#xff0c;使得原对象和副本对象完全分离&#xff0c;对副本对象的任何修改都不会影响到原对象。以下是几种实现深拷贝的方法&#xff1a; 1. 手动实现深拷贝 对于自定义类&#xff0c;…...

位置编码-APE

Transformer 中的绝对位置编码 &#xff08;以下由gpt 生成&#xff09; Transformer 的绝对位置编码&#xff08;Absolute Position Encoding, APE&#xff09;是用于对序列数据中的位置信息进行建模的一种方法。在 Transformer 的架构中&#xff0c;输入数据&#xff08;如句…...

MySQL有哪些锁?

1.MySQL有哪些锁&#xff1f; 全局锁表级锁 表锁元数据锁意向锁 行级锁 记录锁间隙锁临键锁临时意向锁 我了解的是MySQL的锁可以分为全局锁、表级锁、行级锁。 我比较熟悉的是表级锁和行级锁&#xff0c;如果我们对表结构进行修改时&#xff0c;MySQL就会对这个表结构加一个…...

Everything实现,快速搜索文件

最近编写NTFS文件实时搜索工具, 类似 Everything 这样, 翻阅了很多博客, 结果大致如下: 1.分析比较肤浅, 采用USN日志枚举来获取文件记录 速度一言难尽, 因为日志枚举的是全盘所有文件的所有日志, 记录比文件记录还多, 速度当然很慢, 还有的甚至于是 使用 DeviceIoControl 函数…...

[硬件] DELL BIOS 相关注意事项

前言 前段时间重装系统. DELL BIOS属实资料少, 又难用. 这里给出相关的注意事项, 并且配上图片. BIOS相关注意事项 进入BIOS ESC/F2/ F12. 都可以进入BIOS, 当进U盘的入Win PE系统时, 使用F12 效果更佳. 关闭安全模式 切换到Boot Configuration选项,将Secure Boot选项off选…...

Rocky Linux 下安装Liboffice

Rocky Linux下安装Liboffice。 Step1: 在桌面&#xff0c;单击击键盘的Window键&#xff0c;点击出现的白色software按钮图标&#xff1b; Step2: 输入lib&#xff0c;即可自动跳出libre Office, 进行安装&#xff1b; Step3: Have fun with Rocky Linux....

【每日学点鸿蒙知识】长时任务、HarmonyAppProvision申请、preferences、Testing工具、应用保活

1、HarmonyOS 如何解决语音聊天、通信app退后台系统采集播放回调就会停止&#xff0c;回前台未恢复&#xff1f; 关于应用切到后台系统采集播放回调停止的问题原因如下&#xff1a;为了降低设备耗电速度、保障用户使用流畅度&#xff0c;系统会对退至后台的应用进行管控&#…...

步进电机驱动算法——S形加减速算法原理

1. 前言&#xff1a; 最近项目又用到了步进电机&#xff0c;为了在运动中加减速更加平稳决定研究一下S型加减速&#xff0c;原来用过野火的s型加减速程序&#xff0c;云里雾里的移植成功了&#xff0c;今天再翻来程序看一脸懵逼&#xff0c;重新学习了一下发现所有公式都能看懂…...

【图像去噪】论文复现:大道至简!ZS-N2N的Pytorch源码复现,跑通源码,获得指标计算结果,补充保存去噪结果图像代码,代码实现与论文理论对应!

请先看【专栏介绍文章】:【图像去噪(Image Denoising)】关于【图像去噪】专栏的相关说明,包含适配人群、专栏简介、专栏亮点、阅读方法、定价理由、品质承诺、关于更新、去噪概述、文章目录、资料汇总、问题汇总(更新中) 完整代码和训练好的模型权重文件下载链接见本文底…...

2024年中国新能源汽车用车发展怎么样 PaperGPT(一)

概述 在国家政策的强力扶持下&#xff0c;2024年中国新能源汽车市场迎来了新的发展机遇。本文将基于《中国新能源汽车用车报告&#xff08;2024年&#xff09;》的数据&#xff0c;对新能源汽车的市场发展和用车趋势概述。 新能源汽车市场发展 政策推动&#xff1a;国家和地…...

数据结构-排序思想

直接插入排序 将后面的无序区中的元素挨个向前面的有序区中插入。 1.将顺序表中R[0]用作哨兵&#xff0c;按索引i2...n的次序&#xff0c;将R[i]向有序区R[1...i-1]中执行插入操作。 2.插入操作可采取在有序区中从后向前的查找比较和移动的方法。 3.此操作中比较的次数与原序列…...

python 快速排序(Quick Sort)

快速排序&#xff08;Quick Sort&#xff09; 快速排序是一种高效的排序算法&#xff0c;采用分治法&#xff08;Divide and Conquer&#xff09;策略。它的基本思想是&#xff1a;选择一个基准元素&#xff08;pivot&#xff09;&#xff0c;将数组分为两部分&#xff0c;使得…...

MySQL数据库——常见慢查询优化方式

本文详细介绍MySQL的慢查询相关概念&#xff0c;分析步骤及其优化方案等。 文章目录 什么是慢查询日志&#xff1f;慢查询日志的相关参数如何启用慢查询日志&#xff1f;方式一&#xff1a;修改配置文件方式二&#xff1a;通过命令动态启用 分析慢查询日志方式一&#xff1a;直…...

【AIGC篇】AIGC 引擎:点燃创作自动化的未来之火

&#xff1a;羑悻的小杀马特.-CSDN博客 未来都是惊喜。你生来本应为高山。并非草芥。 引言&#xff1a; 在当今数字化的时代&#xff0c;人工智能生成内容&#xff08;AIGC&#xff09;正以一种前所未有的力量改变着我们的创作领域。它就像一个神秘而强大的魔法师&#xff0c;…...

Linux简单的操作

ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

汽车生产虚拟实训中的技能提升与生产优化​

在制造业蓬勃发展的大背景下&#xff0c;虚拟教学实训宛如一颗璀璨的新星&#xff0c;正发挥着不可或缺且日益凸显的关键作用&#xff0c;源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例&#xff0c;汽车生产线上各类…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

QT3D学习笔记——圆台、圆锥

类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体&#xff08;对象或容器&#xff09;QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质&#xff08;定义颜色、反光等&#xff09;QFirstPersonC…...

Java求职者面试指南:计算机基础与源码原理深度解析

Java求职者面试指南&#xff1a;计算机基础与源码原理深度解析 第一轮提问&#xff1a;基础概念问题 1. 请解释什么是进程和线程的区别&#xff1f; 面试官&#xff1a;进程是程序的一次执行过程&#xff0c;是系统进行资源分配和调度的基本单位&#xff1b;而线程是进程中的…...

MySQL 8.0 事务全面讲解

以下是一个结合两次回答的 MySQL 8.0 事务全面讲解&#xff0c;涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容&#xff0c;并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念&#xff08;ACID&#xff09; 事务是…...

LRU 缓存机制详解与实现(Java版) + 力扣解决

&#x1f4cc; LRU 缓存机制详解与实现&#xff08;Java版&#xff09; 一、&#x1f4d6; 问题背景 在日常开发中&#xff0c;我们经常会使用 缓存&#xff08;Cache&#xff09; 来提升性能。但由于内存有限&#xff0c;缓存不可能无限增长&#xff0c;于是需要策略决定&am…...

Rust 开发环境搭建

环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行&#xff1a; rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu ​ 2、Hello World fn main() { println…...

系统掌握PyTorch:图解张量、Autograd、DataLoader、nn.Module与实战模型

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文通过代码驱动的方式&#xff0c;系统讲解PyTorch核心概念和实战技巧&#xff0c;涵盖张量操作、自动微分、数据加载、模型构建和训练全流程&#…...

LangChain 中的文档加载器(Loader)与文本切分器(Splitter)详解《二》

&#x1f9e0; LangChain 中 TextSplitter 的使用详解&#xff1a;从基础到进阶&#xff08;附代码&#xff09; 一、前言 在处理大规模文本数据时&#xff0c;特别是在构建知识库或进行大模型训练与推理时&#xff0c;文本切分&#xff08;Text Splitting&#xff09; 是一个…...