SylixOS中AHCI驱动框架分析
1、概述
本文档介绍SATA和AHCI相关协议,以IMX6Q实验平台为基础,分析SylixOS中AHCI驱动框架的具体实现。
2、SATA简介
2.1 SATA硬盘
串口硬盘SATA(Serial ATA)与以往的并口硬盘PATA(Parallel ATA)相比,数据传输速度更加快捷,并支持热插拔;同时,SATA总线使用了嵌入式时钟频率信号,具备了比以往更强的纠错能力,能对传输指令进行检查,如果发现错误会自动矫正,提高了数据传输的可靠性。
目前SATA接口主要有SATA1.0、SATA2.0、SATA3.0这三个版本,三种主流规范的带宽与传输速度的对比如图 2.1所示。
图 2.1 SATA传输速度对比
2.2 拓扑结构
SATA的拓扑结构是点对点式的,主机可以通过多个链接支持多个设备,每个设备百分百占用总线带宽,并且一个设备的链接出错不会影响其他设备的链接,其链接方式如图 2.2所示。
图 2.2 SATA拓扑结构
2.3 接口结构
SATA接口使用4根电缆传输数据,其结构图如图 2.3所示。Tx+、Tx-表示输出差分数据线,对应的,Rx+、Rx-表示输入差分数据线。
图 2.3 SATA接口结构
2.4 协议模型
SATA协议借鉴TCP/IP模型,分为四个层次来实现,包括物理层、链路层、传输层、应用层,其体系结构如图 2.4所示。
图 2.4 SATA协议模型
物理层采用全双工串行传输方式,主要功能是进行信号的串并及并串转化。
链路层的主要功能是通过控制原语的传递来控制信息帧的整个传输过程,保证帧信息能够正确的发送与接收,并能进行流量的控制,防止数据发送过快或接收过多。
传输层主要负责FIS帧信息结构的封装与解封。
应用层能够接收来自主机端的命令,根据命令的要求将自身的信息发送给主机端,或是接收来自主机端的以PIO或DMA方式传输的数据,同时写入闪存中,也能从闪存中以PIO或DMA的方式读出数据,传送给主机端。在应用层采用两个FIFO对数据进行缓冲,一个为读FIFO,一个为写FIFO。应用层能接收来自传输层的数据帧送入写FIFO中或将来自设备内部总线的数据保存在读FIFO中,然后通知传输层构造数据帧。
3、AHCI简介
3.1 AHCI系统结构
AHCI是SATA设备对应的协议标准(逻辑设备接口标准),在系统内存总线和SATA设备内部逻辑间扮演通用接口的角色,我们可以将其视为SATA的一种优化驱动,其本质就是SATA协议模型各层次的具体实现。它以AHCI HBA(Host Bus Adapter)的形式呈现,其系统结构如图 3.1所示。
图 3.1 AHCI系统结构
3.2 AHCI HBA结构
每个HBA上最多可以支持32个端口,HBA的内部逻辑结构如图 3.2所示,图中从左往右,可以按照SATA协议四层模型划分。
图 3.2 HBA内部结构
4、AHCI驱动框架分析
在IMX6Q实验平台上,HBA是集成在芯片组内部,并且仅使用了端口0。
在SylixOS集成开发环境base工程libsylixos/SylixOS/system/device/ahci路径下,提供了ahci驱动框架,其结构如图 4.1所示。
图 4.1 AHCI驱动框架
4.1 AHCI驱动管理
在ahcidrv.c中,主要实现了如下函数:
API_AhciDrvInit
该函数主要负责AHCI驱动注册的初始化工作,如:初始化驱动数量统计的全局变量、初始化驱动管理链表等,同时给shell命令"ahcidrv"关联操作函数。该函数需要在进行驱动注册前调用。
API_AhciDrvRegister
该函数主要负责注册指定类型的驱动,通过创建驱动控制块,将bsp层实现的AHCI相关驱动链入管理链表,以便AHCI控制器调用。
API_AhciDrvHandleGet
该函数为AHCI控制器提供调用AHCI驱动句柄的接口。
__tshellAhciDrvCmd
shell命令"ahcidrv"的关联函数实现,提供AHCI设备驱动列表的显示功能。
4.2 AHCI设备管理
在ahcidev.c中,主要实现了如下函数:
API_AhciDevInit
该函数主要负责AHCI设备管理的初始化,如:初始化设备数量统计的全局变量、初始化设备管理链表等,同时给shell命令"ahcidev"关联操作函数。该函数在进行驱动注册前被调用。
API_AhciDevCountGet
该函数保存当前设备链表中存在的设备数量。
API_AhciDevHandleGet
该函数提供了根据控制器句柄和驱动器编号获取AHCI设备句柄的接口,在创建设备前可以判断当前设备链表中是否已存在同类型的设备。
API_AhciDevAdd
该函数用于向AHCI设备管理链表中添加一个设备。
API_AhciDevDelete
该函数用于从AHCI设备管理链表中删除一个设备。
API_AhciDevIoctl
该函数提供AHCI设备控制接口,用于获取/设置设备的cache回写功能
__tshellAhciDevCmd
Shell命令"ahcidev"的关联函数实现,提供AHCI设备列表显示和cache回写设置功能。
4.3 AHCI控制器管理
在ahciCtrl.c中,主要实现了如下函数:
API_AhciCtrlInit
该函数主要负责AHCI控制器管理初始化,如:初始化控制器数量统计的全局变量、初始化控制器管理链表等,同时给shell命令"ahcictrl"关联操作函数。该函数在进行驱动注册前被调用。
API_AhciCtrlCountGet
该函数用来获取当前AHCI控制器总数。
API_AhciCtrlIndexGet
该函数用来给新创建的控制器分配索引号。
API_AhciCtrlHandleGetFromIndex
该函数可通过索引号获取AHCI控制器的句柄。
API_AhciCtrlHandleGetFromName
该函数可通过控制器名字获取AHCI控制器的句柄。
API_AhciCtrlHandleGetFromPciArg
该函数可通过PCI设备句柄来获取AHCI控制器的句柄。
API_AhciCtrlAdd
该函数用于向AHCI控制器链表中添加一个新的控制器。
API_AhciCtrlDelete
该函数用于向AHCI控制器链表中删除一个控制器。
__tshellAhciCtrlCmd
Shell命令"ahcictrl"的关联函数实现,提供AHCI控制器列表显示功能。
4.4 AHCI驱动库
在ahciLib.c中,提供了一些AHCI驱动器和控制器的相关操作库函数,如驱动器扇区信息、工作模式、中断处理、控制器复位、控制器信息打印等功能。
4. 5AHCI电源管理
在ahciPm.c中,提供了使能/禁能设备电源管理功能,用于块设备中的电源控制管理。
4.6 AHCI驱动实现
在ahci.c中,是AHCI控制器逻辑功能的具体实现。
创建AHCI控制器,并加入控制器管理链表进行管理。
初始化AHCI驱动,包括创建设备热插拔监测线程、控制器和驱动器内存结构的分配和初始化、命令序列和FIS信息帧的初始化、磁盘控制器和驱动器的初始化等。
设备热插拔监测线程可以监测设备接入、设备移除、设备异常等信息,并进行相关处理。
当监测到设备接入时,进行控制器和驱动器的初始化,然后创建一个块设备,块设备中提供了块设备的读写和控制等功能,为上层提供操作接口,最后加入设备管理链表进行管理。其具体实现流程如程序清单 4.1所示。
程序清单 4.1
case AHCI_MSG_ATTACH: /* 设备接入 */AHCI_LOG(AHCI_LOG_PRT, "recv attach msg ctrl %d drive %d.\r\n",hCtrl->AHCICTRL_uiIndex, iDrive);if (hDrive->AHCIDRIVE_ucState != AHCI_DEV_NONE) {AHCI_LOG(AHCI_LOG_PRT, "ctrl %d drive %d state none.\r\n",hCtrl->AHCICTRL_uiIndex, iDrive);continue;}hDrive->AHCIDRIVE_ucState = AHCI_DEV_INIT;AHCI_LOG(AHCI_LOG_PRT, "init ctrl %d drive %d.\r\n", hCtrl->AHCICTRL_uiIndex, iDrive);/** 判断当前驱动器是否处于忙状态,因为机械硬盘从上电到正常工作需要一段时间*/iRet = __ahciDriveNoBusyWait(hDrive);if (iRet != ERROR_NONE) {break;}iRetry = 0;/** 磁盘控制器初始化*/iRet = __ahciDiskCtrlInit(hCtrl, iDrive);while (iRet != ERROR_NONE) {AHCI_LOG(AHCI_LOG_ERR, "ctrl init err ctrl %d drive %d retry %d.\r\n",hCtrl->AHCICTRL_uiIndex, iDrive, iRetry);iRetry += 1;if (iRetry >= AHCI_RETRY_NUM) {break;}iRet = __ahciDiskCtrlInit(hCtrl, iDrive);}iRetry = 0;/** 磁盘驱动器初始化*/iRet = __ahciDiskDriveInit(hCtrl, iDrive);while (iRet != ERROR_NONE) {AHCI_LOG(AHCI_LOG_ERR, "drive init err ctrl %d drive %d retry %d.\r\n",hCtrl->AHCICTRL_uiIndex, iDrive, iRetry);iRetry += 1;if (iRetry >= AHCI_RETRY_NUM) {break;}iRet = __ahciDiskDriveInit(hCtrl, iDrive);}/** 块设备创建,根据设备类型提供读写和控制接口*/hBlkDev = __ahciBlkDevCreate(hCtrl, iDrive, hDrive->AHCIDRIVE_ulStartSector, 0);if (!hBlkDev) {AHCI_LOG(AHCI_LOG_ERR, "create blk dev error %s.\r\n", hDrive->AHCIDRIVE_cDevName);break;}/** 加入块设备管理链表*/API_AhciDevAdd(hCtrl, iDrive);break;
2.当监测到设备移除时,进行块设备的移除操作,具体实现如程序清单 4.2所示。
程序清单 4.2
case AHCI_MSG_REMOVE: /* 设备移除 */AHCI_LOG(AHCI_LOG_PRT, "remove ctrl %d drive %d.\r\n", hCtrl->AHCICTRL_uiIndex, iDrive);if (hDrive->AHCIDRIVE_hDev != LW_NULL) {__ahciBlkDevRemove(hCtrl, iDrive);}break;
5、BSP中的具体实现
在IMX6Q实验平台上,BSP中具体实现如程序清单 5.1所示。主要进行注册驱动前的初始化、驱动函数的实现、驱动函数的注册、AHCI控制器的创建。
程序清单 5.1
/******************************************************************************************************** ** 函数名称: imxAhciDevInit ** 功能描述: IMX 类型控制器驱动相关初始化 ** 输 入 : NONE ** 输 出 : ERROR or OK ** 全局变量: ** 调用模块:API 函数 ********************************************************************************************************/ LW_API INT imxAhciDevInit (VOID) {AHCI_DRV_CB tDrvReg;AHCI_DRV_HANDLE hDrvReg = &tDrvReg;/** AHCI驱动注册初始化,在驱动注册前进行*/API_AhciDrvInit();lib_strlcpy(&hDrvReg->AHCIDRV_cDrvName[0], AHCI_IMX_DRV_NAME, AHCI_DRV_NAME_MAX);/** 驱动函数具体实现*/hDrvReg->AHCIDRV_uiDrvVer = AHCI_IMX_DRV_VER_NUM;hDrvReg->AHCIDRV_pfuncOptCtrl = imxAhciCtrlOpt;hDrvReg->AHCIDRV_pfuncVendorDriveInfoShow = imxAhciVendorDriveInfoShow;hDrvReg->AHCIDRV_pfuncVendorDriveRegNameGet = imxAhciVendorDriveRegNameGet;hDrvReg->AHCIDRV_pfuncVendorDriveInit = imxAhciVendorDriveInit;hDrvReg->AHCIDRV_pfuncVendorCtrlInfoShow = imxAhciVendorCtrlInfoShow;hDrvReg->AHCIDRV_pfuncVendorCtrlRegNameGet = imxAhciVendorCtrlRegNameGet;hDrvReg->AHCIDRV_pfuncVendorCtrlTypeNameGet = imxAhciVendorCtrlTypeNameGet;hDrvReg->AHCIDRV_pfuncVendorCtrlIntEnable = imxAhciVendorCtrlIntEnable;hDrvReg->AHCIDRV_pfuncVendorCtrlIntConnect = imxAhciVendorCtrlIntConnect;hDrvReg->AHCIDRV_pfuncVendorCtrlInit = imxAhciVendorCtrlInit;hDrvReg->AHCIDRV_pfuncVendorCtrlReadyWork = imxAhciVendorCtrlReadyWork;hDrvReg->AHCIDRV_pfuncVendorPlatformInit = imxAhciVendorPlatformInit;hDrvReg->AHCIDRV_pfuncVendorDrvReadyWork = imxAhciVendorDrvReadyWork;/** 注册驱动函数*/API_AhciDrvRegister(hDrvReg);/** 创建AHCI控制器*/API_AhciCtrlCreate(AHCI_IMX_DRV_NAME, 0, LW_NULL);return (ERROR_NONE); }
这样,创建完AHCI控制器后,在AHCI控制器管理驱动中进行一系列初始化,创建热插拔监测线程进行设备状态监测,根据设备状态进行块设备的相关处理。
注:本文档着重介绍AHCI驱动的框架结构,关于AHCI协议中命令槽、命令序列、FIS信息帧等细节的相关处理,还待后续深入学习整理。
6、参考资料
1、《serial ATA Revision 3.0》
2、《serial-ata-ahci-spec-rev1-3-1》
转载于:https://my.oschina.net/u/3248430/blog/900104
SylixOS中AHCI驱动框架分析相关推荐
- Linux USB驱动框架分析 【转】
转自:http://blog.chinaunix.net/uid-11848011-id-96188.html 初次接触与OS相关的设备驱动编写,感觉还挺有意思的,为了不至于忘掉看过的东西,笔记跟总结 ...
- framebuffer驱动详解2——framebuffer驱动框架分析
以下内容源于朱有鹏嵌入式课程的学习,如有侵权,请告知删除. 一.framebuffer驱动框架总览 1.驱动框架部分 (1)drivers/video/fbmem.c(主要的文件) 创建graphic ...
- LCD 设备驱动框架分析及核心结构
Linux 下很多东西都是和结构体相关,举个例子,时钟大家都知道吧,Linux 下对应时钟的东西就有好几个结构体,所以你要是想明白Linux 下那些东西,对结构体要有所了解,LCD 是基础的驱动设备, ...
- Linux PCI驱动框架分析:(Peripheral Component Interconnect,外部设备互联)
<DPDK 20.05 | rte_pci_bus思维导图 | 第一版> <linux系统下:IO端口,内存,PCI总线 的 读写(I/O)操作> <Linux指令:ls ...
- Linux PCIe驱动框架分析(第二章)
目录 项目背景 1. 概述 2. 数据结构 3. 流程分析 3.1 设备驱动模型 3.2 初始化 3.2.1 pci_bus_match 3.2.2 pci_device_probe 3.3 枚举 项 ...
- I2C驱动框架分析(3):DW_I2C驱动分析
I2C驱动框架分析(1):I2C重要概念与数据结构 I2C驱动框架分析(2):I2C框架源码分析 I2C驱动框架分析(3):DW_I2C驱动分析 第三章:DW_I2C驱动 其驱动文件在drivers/ ...
- linux内核usb驱动框架,基于S3C2440平台的linux2.6.22内核版本的USB驱动框架分析
基于S3C2440平台的linux2.6.22内核版本的USB驱动框架分析 发布时间:2014-07-18 16:47:31来源:红联作者:linux08071151 driver/usb/host/ ...
- OS相关驱动 Linux USB驱动框架分析
初次接触与OS相关的设备驱动编写,感觉还挺有意思的,为了不至于忘掉看过的东西,笔记跟总结当然不可缺,更何况我决定为嵌入式卖命了.好,言归正传,我说一说这段时间的收获,跟大家分享一下Linux的驱动开发 ...
- rt-thread SDIO驱动框架分析(SD卡驱动\SD Nand驱动)
rt-thread SDIO驱动框架分析之SD卡驱动 文章目录 rt-thread SDIO驱动框架分析之SD卡驱动 1. 前言 2. SDIO通用驱动框架介绍 3. 文件架构分析 4. SDIO设备 ...
- 深入分析Linux PCI驱动框架分析(二)
说明: Kernel版本:4.14 ARM64处理器 使用工具:Source Insight 3.5, Visio 1. 概述 本文将分析Linux PCI子系统的框架,主要围绕Linux PCI子系 ...
最新文章
- mysql can_***MySQL错误:Can't connect to MySQL server (10060)
- EXCEL怎么打20位以上的数字?
- tinyid 教程_tinyid
- IE(=8)版本不支持getElementsByClassName()
- Python Cookbook 3rd Edition Documentation
- method java_解析Java中的Field类和Method类
- oracle数据库插入多表,在Oracle数据库中插入嵌套表
- “OSPF” Router-ID
- 信息搜集 - 二层发现 arping
- 使用phpStudy搭建74cms(详)
- 添加nginx作为系统服务
- linux双线路由,linux双线路由配置方法介绍
- android inflate 参数,Android inflate方法总结
- matlab 函数输出 向量,matlab中的函数返回向量
- codeforces 69A(Young Physicist) Java
- 传销?花生日记罚款7456万元这个微信社群营销分钱模式要知道
- 复旦女神陈果:孤独是一个人的狂欢,在你寂寞时请关注这些公众号充实自己
- 获得拼多多商品详情(商品主图、sku)
- Linux 内存管理中的 RSS 、VSZ等的含义
- Keras : 训练minst数据集并加载模型对本地手写图片进行预测