0%

周谈(57)- 根据CPU类型实现驱动平台适配

背景

本周收到一个客户需求,他们希望在系统里集成我们的驱动,希望驱动能够自动根据硬件来确定是否加载,最好就是只提供一份驱动,在不同机型下能自适应处理。

由于历史原因,我们的这些硬件从设计上就是不兼容的,且分别开发了不同的驱动,并没有一个统一的驱动架构。一般驱动是可以根据设备树或者ACPI表的描述,自动和硬件匹配的。只要硬件的描述不一样,那么加载了驱动后,也只有相应的驱动会匹配生效。

又由于各种原因,有些机型根本就不存在硬件描述,因此在驱动代码里是通过ioremap直接传入固定的地址来获取硬件的寄存器基址。所以平常的设备树和ACPI表机制用不了了。

鉴于不同平台的CPU类型是不一样的,跟客户讨论了一下,得到了一种方案。系统里同时集成多个驱动,在驱动模块加载时通过CPU类型判断当前机型是否有相关的硬件,没有的话,模块初始化时返回-ENODEV,否则正常初始化。

另外,就是驱动会通过字符文件向用户态提供接口,相应的用户态库打开对应的文件来实现功能。当存在多个驱动及对应用户态lib时,不同的硬件的字符文件需要不同,否则就有导致接口不匹配都不能用了。

CPU type

在ARM架构里,有一个MIDR_EL1的系统寄存器,这个寄存器提供了关于CPU的实现信息,包括CPU的类型和型号。

MIDR_EL1 寄存器包含以下字段:

1
2
3
4
5
Implementer: 表示实现CPU的公司或组织的代码。
Variant: 表示CPU变体的代码。
Architecture: 表示CPU架构的代码。
Part Number: 表示CPU部件编号的代码。
Revision: 表示CPU修订版本的代码。

在ARMv8架构中,MIDR_EL1 的布局如下:

1
2
3
4
5
6
Bits 31:24 - Revision
Bits 23:20 - Part Number bottom 4 bits
Bits 19:16 - Part Number top 4 bits
Bits 15:12 - Architecture
Bits 11:7 - Variant
Bits 6:0 - Implementer

具体在驱动的module_init函数中,只要根据Implementer和Part Number判断机型,确定是否存在具体的硬件作不同处理就好了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <asm/cputype.h>

int my_init(void) {

int ret = 0;
if (read_cpuid_implementor() == CPU_PRODUCTOR && read_cpuid_part_number()== CPU_TYPE_X) {
// do xxx
} else {
ret = -ENODEV;
}


return ret;
}

更多

对于不同硬件相互不兼容的情况,今年已经开始进行统一驱动的架构设计的工作了,定义了统一的对外接口,适配了不同的硬件,在一套代码里囊括了多个硬件的驱动。但由于各种紧急任务的插入,只完成了部分硬件的适配,没有形成一个稳定的版本。

究其原因,还是人的问题,团队没有形成战斗力,分配下去的任务没能及时的完成,完成的质量不过关。另外部门管理相对宽松,员工没有紧迫感,对任务没有责任感,进度推进缓慢,遇到问题不去推就阻塞住了。没有学习的氛围,缺乏知识沉淀和学习的主动性。

今年以来,对接的客户也越来越多,好多历史债务暴露出来,没有几个能打的同事,自个儿瞎忙活~,着实有些累。而且做这些活体现不了啥业绩,又没创新,纯粹的工作量,升职加薪无望,哎!只能自个儿业余加强自我提升了,尽量不让自己太落后。


行动,才不会被动!

欢迎关注个人公众号 微信 -> 搜索 -> fishmwei,沟通交流。

欢迎关注

博客地址: https://fishmwei.github.io

掘金主页: https://juejin.cn/user/2084329776486919