您的位置:首页 > 运维架构 > Linux

linux下request_mem_region的粗略理解

2008-02-25 14:00 260 查看
linux
下request_mem_region的粗略理解


文章来源
:
http
:
//gliethttp.cublog.cn

Linux
把基于I/O映射方式的I/O端口和基于内存映射方式的I/O端口资源统称为“I/O区域”(I/ORegion)。I/ORegion仍然是一种I/O资源,因此它仍然可以用resource结构类型来描述。

Linux
是以一种倒置的树形结构来管理每一类I/O资源(如:I/O端口、外设内存、DMA和IRQ)的。每一类I/O资源都对应有一颗倒置的资源树,树中的每一个节点都是一个resource结构,而树的根结点root则描述了该类资源的整个资源空间。


1
.
结构体

1
.
1
>
struct
resourceiomem_resource
=
{
"PCImem"
,
0x00000000
,
0xffffffff
,
IORESOURCE_MEM
};

1
.
2
>
struct
resource
{

const
char
*
name
;

unsigned
long
start
,
end
;

unsigned
long
flags
;

struct
resource
*
parent
,
*
sibling
,
*
child
;

};

2
.
调用函数

request_mem_region
(
S1D_PHYSICAL_REG_ADDR
,
S1D_PHYSICAL_REG_SIZE
,
"EpsonFB_RG"
)

#
define
request_mem_region
(
start
,
n
,
name
)
__request_region
(&
iomem_resource
,
(
start
),
(
n
),
(
name
))

__request_region
检查是否可以安全占用起始物理地址S1D_PHYSICAL_REG_ADDR之后的连续S1D_PHYSICAL_REG_SIZE字节大小空间


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
);
//siblingparent
下的所有单元,检测申请部分是否存在交叠冲突

if
(!
conflict
)
//conflict=0;
申请成功,正常安置了[start,end]到相应位置

break
;

if
(
conflict
!=
parent
)
{

parent
=
conflict
;

if
(!(
conflict
->
flags
&
IORESOURCE_BUSY
))

continue
;

}

kfree
(
res
);
//
检测到了资源交叠冲突,kfree归还kmalloc申请的内存

res
=
NULL
;

break
;

}

write_unlock
(&
resource_lock
);

}

return
res
;

}


static
struct
resource
*
__request_resource
(
struct
resource
*
root
,
struct
resource
*
new
)

{

unsigned
long
start
=
new
->
start
;

unsigned
long
end
=
new
->
end
;

struct
resource
*
tmp
,
**
p
;


if
(
end
<
start
)

return
root
;

if
(
start
<
root
->
start
)

return
root
;

if
(
end
>
root
->
end
)

return
root
;

p
=
&
root
->
child
;
//root
下的第一个链表元素*p.[child链表是以I/O资源物理地址从低到高的顺序排列的]

for
(;;)
{

tmp
=
*
p
;

if
(!
tmp
||
tmp
->
start
>
end
)
{

new
->
sibling
=
tmp
;

*
p
=
new
;

//
可以从root->child=null开始我们的分析考虑,此时tmp=null,那么第一个申请将以!tmp条件满足而进入

//
这时root->child的值为new指针,new->sibling=tmp=null;当第二次申请发生时:如果tmp->start>end成立,

//
那么,root->child的值为new指针,new->sibling=tmp;这样就链接上了,空间分布图如:

//child=[start,end]-->[tmp->start,tmp->end](1);
如果条件tmp->start>end不成立,那么只能是!tmp条件进入

//
那么,root->child的值不变,tmp->sibling=new;new->sibling=tmp=null这样就链接上了,空间分布图如:

//child=[child->start,child->end]-->[start,end](2);

//
当第三次申请发生时:如果start在(2)中的[child->end,end]之间,那么tmp->end<start将成立,继而continue,

//
此时tmp=(2)中的[start,end],因为tmp->start<end,所以继续执行p=&tmp->slibing=null,

//
因为tmp->end>start,所以资源冲突,返回(2)中的[start,end]域

//
综上的两个边界值情况和一个中间值情况的分析,可以知道代码实现了一个从地地址到高地址的顺序链表

//
模型图:childe=[a,b]-->[c,d]-->[e,f],此时有一个[x,y]需要插入进去,tmp作为sibling指针游动

//tmp
指向child=[a,b],

//tmp
指向[a,b],当tmp->start>y时,插入后的链接图为:child=[x,y]-->[a,b]-->[c,d]-->[e,f]-->null;当tmp->end>=x时,冲突返回tmp

//tmp
指向[c,d],当tmp->start>y时,插入后的链接图为:child=[a,b]-->[x,y]-->[c,d]-->[e,f]-->null;当tmp->end>=x时,冲突返回tmp

//tmp
指向[e,f],当tmp->start>y时,插入后的链接图为:child=[a,b]-->[c,d]-->[x,y]-->[e,f]-->null;当tmp->end>=x时,冲突返回tmp

//tmp
指向null,插入后的链接图为:child=[a,b]-->[c,d]-->[e,f]-->[x,y]-->null;

//
顺利的达到了检测冲突,顺序链接的目的

new
->
parent
=
root
;

return
NULL
;

}

p
=
&
tmp
->
sibling
;

if
(
tmp
->
end
<
start
)

continue
;

return
tmp
;

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: