arm中的request_mem_region

在s3c2410_wdt.c中
有一行
request_mem_region(res->start, size, pdev->name)

在devs.c中
static struct resource s3c_wdt_resource[] = {
[0] = {
.start = S3C24XX_PA_WATCHDOG,
.end   = S3C24XX_PA_WATCHDOG + S3C24XX_SZ_WATCHDOG - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_WDT,
.end   = IRQ_WDT,
.flags = IORESOURCE_IRQ,
}

}
在arch/arm/mach-s3c2410/include/mach/map.h
#define S3C24XX_PA_WATCHDOG S3C2410_PA_WATCHDOG
在/arch/arm/plat-s3c24xx/include/mach/map.h
#define S3C2410_PA_WATCHDOG (0x53000000)

即上面行代码要申请0x53000000开始的一段size大小的内存地址空间以访问watchdog

从s3c2440/s3c2410手册上获知
watchdog的寄存器地址本来就是从0x53000000开始的一段内存区域
比如WTCON  0x53000000,WTDAwatchdog  0x53000004,WTCNT  0x53000008等,就是说这些io内存的物理地址都是已经被cpu定义好的了,即使不去request_mem_region,watchdog那些寄存器的物理地址也是从这里开始的,即在驱动程序中访问watchdog就必须去访问这部分物理地址(的ioremap之后的虚拟地址)。
难道内核会把0x53000000这个地址空间分配给别的寄存器吗?
不知道request_mem_region用意为何?

s3c2440的地址空间中,从4千8百万到5b00001c这段地址都是已经分配好的了,用于特殊寄存器的寻址,
访问某个地址就是访问一个已定的寄存器。

不知道我的理解哪有问题


对于上述问题,有以下解释:


对于48000000--5b00001c的那些特殊寄存器,在访问前应先按照cpu说明书上的地址在linux中申请同样的地址空间,成为io内存,再去访问----------因为
寄存器的地址对cpu而言是不变、既定的,但linux并不知道这些,比如他不知道WTCON寄存器的地址是0x53000000,所以要访问硬件WTCON的时候驱动程序必须先向linux申请从0x53000000开始的一段地址,用的便是request_mem_region(res->start, size, pdev->name),然后再将申请到的地址控件用ioremap转化成虚拟地址再去访问........当然如果你访问WTCON的时候却向内核申请了比如0x54000000(在0x54000000还未被申请的情况下,应该可以申请成功),这样访问到的寄存器便不是WTCON了

request_mem_region仅仅是linux对IO内存的管理,意思指这块内存我已经占用了,别人就不要动了,也不能被swap出去。使用这些寄存器时,可以不调用request_mem_region,但这样的话就不能阻止别人对他的访问了。

是的,后来看了一下request_mem_region源码,里面有个死循环在保护已被申请过的资源不被其他代码再request_mem_region成功。
在__request_region里面会再次分配一个struct resource *res,内核使用write_lock使这个res被独占的写,但是内核并没有保护那个驱动中可以接触的比如上面的static struct resource s3c_wdt_resource,所以
如果第二个驱动不去request_mem_region还是可以访问第一个驱动中request_mem_region过的资源的,但这样就可能两者都访问到不正确的结果。所以在每个驱动模块在使用io内存之前最好都要先使request_mem_region申请一下,这样就利用到了内核提供的锁保护机制,不用在自己的驱动中再写代码去防止已经申请到的资源被其他驱动有意无意的伤害到。目前的理解。
#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name), 0)

struct resource * __request_region(struct resource *parent,
   resource_size_t start, resource_size_t n,
   const char *name, int flags)
{
struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);

if (!res)
return NULL;

res->name = name;
res->start = start;
res->end = start + n - 1;
res->flags = IORESOURCE_BUSY;
res->flags |= flags;

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;
}


static struct resource * __request_resource(struct resource *root, struct resource *new)
{
resource_size_t start = new->start;
resource_size_t 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;
for (;;) {
tmp = *p;
if (!tmp || tmp->start > end) {
new->sibling = tmp;
*p = new;
new->parent = root;
return NULL;
}
p = &tmp->sibling;
if (tmp->end < start)
continue;
return tmp;
}
}


最终结论:在对统一编址的arm平台的寄存器进行访问时,其实在cpu上已经固定把该块内存分配给了这些寄存器,只不过linux不知道,应该使用request_mem_region对该内存区域进行内存保护,也就是linux对其进行内存保护,但是如果直接使用该段内存也是可以的,但是可能会出现错误,所以任何内核代码在使用寄存器时都应该使用request_mem_region,以避免由于争夺该资源而导致错误的发生。


对于独立编址的平台,必须使用该函数了,呵呵,想一下也应该是这个样子,需要把一些寄存器映射到内存空间,再进行操作,不申请也不行啊~~~~


http://bbs.csdn.net/topics/370071947

你可能感兴趣的:(内存,kernel,内核,内存分配)