Linux将基于I/O映射方式的I/O端口和基于内存映射方式的I/O端口资源统称为“I/O区域”(I/O Region)。I/O Region仍然是一种I/O资源,因此他仍然能够用resource结构类型来描述。下面我们就来看看Linux是如何管理I/O Region的。
3.3.1 I/O Region的分配
在函数__request_resource()的基础上,Linux实现了用于分配I/O区域的函数__request_region(),如下:
struct resource * __request_region(struct resource *parent,
unsigned long start, unsigned long n, const char *name)
{
struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
if (res) {
memset(res, 0, sizeof(*res));
res->name = name;
res->start = start;
res->end = start n - 1;
res->flags = IORESOURCE_BUSY;
write_lock(&resource_lock);
for (;;) {
struct resource *conflict;
conflict = __request_resource(parent, res);
if (!conflict)
break;
if (conflict != parent) {
parent = conflict;
if (!(conflict->flags & IORESOURCE_BUSY))
continue;
}
/* Uhhuh, that didn't work out.. */
kfree(res);
res = NULL;
break;
}
write_unlock(&resource_lock);
}
return res;
}
NOTE:
①首先,调用kmalloc()函数在SLAB分配器缓存中分配一个resource结构。
②然后,相应的根据参数?**跏蓟峙涞膔esource结构。注意!flags成员被初始化为IORESOURCE_BUSY。
③接下来,用一个for循环开始进行资源分配,循环体的步骤如下:
l 首先,调用__request_resource()函数进行资源分配。假如返回NULL,说明分配成功,因此就执行break语句推出for循环,返回所分配的resource结构的指针,函数成功地结束。
l 假如__request_resource()函数分配不成功,则进一步判断所返回的冲突资源节点是否就是父资源节点parent。假如不是,则将分配行为下降一个层次,即试图在当前冲突的资源节点中进行分配(只有在冲突的资源节点没有配置IORESOURCE_BUSY的情况下才能够),于是让 parent指针等于conflict,并在conflict->flags&IORESOURCE_BUSY为0的情况下执行 continue语句继续for循环。
l 否则假如相冲突的资源节点就是父节点parent,或相冲突资源节点配置了IORESOURCE_BUSY标志位,则宣告分配失败。于是调用kfree ()函数释放所分配的resource结构,并将res指针置为NULL,最后用break语句推出for循环。
④最后,返回所分配的resource结构的指针。
3.3.2 I/O Region的释放
函数__release_region()实现在一个父资源节点parent中释放给定范围的I/O Region。实际上该函数的实现思想和__release_resource()相类似。其源代码如下:
void __release_region(struct resource *parent,
unsigned long start, unsigned long n)
{
struct resource **p;
unsigned long end;
p = &parent->child;
end = start n - 1;
for (;;) {
struct resource *res = *p;
if (!res)
break;
if (res->start <= start && res->end >= end) {
if (!(res->flags & IORESOURCE_BUSY)) {
p = &res->child;
continue;
}
if (res->start != start' 'res->end != end)
break;
*p = res->sibling;
kfree(res);
return;
}
p = &res->sibling;
}
printk(Trying to free nonexistent resource <lx-lx>
, start, end);
}
类似地,该函数也是通过一个for循环来遍历父资源parent的child链表。为此,他让指针res指向当前正被扫描的子资源节点,指针p指向前一个子资源节点的sibling成员变量,p的初始值为指向parent->child。For循环体的步骤如下:
①让res指针指向当前被扫描的子资源节点(res=*p)。
②假如res指针为NULL,说明已扫描完整个child链表,所以退出for循环。
③假如res指针不为NULL,则继续看看所指定的I/O区域范围是否完全包含在当前资源节点中,也即看看[start,start n-1]是否包含在res->[start,end]中。假如不属于,则让p指向当前资源节点的sibling成员,然后继续for循环。假如属于,则执行下列步骤:
l 先看看当前资源节点是否配置了IORESOURCE_BUSY标志位。假如没有配置该标志位,则说明该资源节点下面可能还会有子节点,因此将扫描过程下降一个层次,于是修改p指针,使他指向res->child,然后执行continue语句继续for循环。
l 假如配置了IORESOURCE_BUSY标志位。则一定要确保当前资源节点就是所指定的I/O区域,然后将当前资源节点从其父资源的child链表中去除。这能够通过让前一个兄弟资源节点的sibling指针指向当前资源节点的下一个兄弟资源节点来实现(即让*p=res->sibling),最后调用kfree()函数释放当前资源节点的resource结构。然后函数就能够成功返回了。
文章整理:西部数码--专业提供域名注册、虚拟主机服务
http://www.west263.com
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!




