我看linux对挂接在4G总线空间上的设备实体的管理方式-resource结构体
文章来源:http://gliethttp.cublog.cn
一个独立的挂接在cpu总线上的设备单元,一般都需要一段线性的地址空间来描述设备自身,linux是怎么管理所有的这些外部"物理地址范围段",进而给用户和linux自身一个比较好的观察4G总线上挂接的一个个设备实体的简洁、统一级联视图的呢? linux采用struct resource结构体来描述一个挂接在cpu总线上的设备实体(32位cpu的总线地址范围是0~4G),使用resource->name描述这个设备实体的名称,这个名字开发人员可以随意起,但最好贴切;[gliethttp] resource->start描述设备实体在cpu总线上的线性起始物理地址; resource->end描述设备实体在cpu总线上的线性结尾物理地址; resource->flag描述这个设备实体的一些共性和特性的标志位; 只需要了解一个设备实体的以上4项,linux就能够知晓这个挂接在cpu总线的上的设备实体的基本使用情况,也就是[resource->start,resource->end]这段物理地址现在是空闲着呢,还是被什么设备占用着呢? linux会坚决避免将一个已经被一个设备实体使用的总线物理地址区间段[resource->start,resource->end],再分配给另一个后来的也需要这个区间段或者区间段内部分地址的设备实体,进而避免设备之间出现对同一总线物理地址段的重复引用,而造成对唯一物理地址的设备实体二义性. 以上的4个属性仅仅用来描述一个设备实体自身,或者是设备实体可以用来自治的单元,但是这不是linux所想的,linux需要管理4G物理总线的所有空间,所以挂接到总线上的形形色色的各种设备实体,这就需要链在一起,因此resource结构体提供了另外3个成员, resource->parent描述管理本设备实体的父类resource指针 resource->sibling描述比本设备实体物理地址大的下一个设备实体的resource指针[这是一个单向链表] resource->child描述本设备实体可能还要更详细的描述本设备实体内部的一些物理地址区段, 来让linux能够更清楚本设备实体的内部的级联关系, 甚至可以将本设备实体内部的具有特色的区段的给它七个名字标示一下[gliethttp]. 有这样一个保证:[由来request_resource()函数提供这个保证的实现gliethttp] resource->child是所有resource->sibling里边地址最小的,resource->sibling大之,resource->sibling大大之,以此类推,所以resource->sibling永远链接着比resource自己的resource->end地址值大的下一个设备实体. 比如:request_resource(&iomem_resource, res);将res设备实体挂接到iomem_resource设备实体上,request_resource()函数会会在[iomem_resource.start,iomem_resource.end]之间找到[res->.start,res->end](对于request_resource()函数的具体实现,可以参见我的另一篇文章《linux下request_mem_region的粗略理解》)区间设备实体res是否可以占用,如果可以,那么将把res顺序加入到单向链表sibling的相应位置,如果已经被某个设备实体占用了,那么request_resource()将返回正在使用[res->.start,res->end]该段区间或部分区间的设备实体B的resource指针,进而res可以决定是否把自己作为B的孩子插到B的线性空间视图中. 通过request_resource()函数,我们可以将打算占用[start,end]总线地址空间的设备实体,登记到供linux内核观察4G总线上设备占用情况的单向观察链表resource中,进而避免对已经被占用的总线地址空间段,再分配给另一个新来的设备实体.
|