linux devm_xxx接口相关的iomem_resource管理

struct resource {
resource_size_t start;
resource_size_t end;
const char *name;
unsigned long flags;
struct resource *parent, *sibling, *child;

};

//resource资源树,会先找sibling节点然后再找子节点,sibling代表的所有子节点的region加起来等于sibling的本身的region

struct resource iomem_resource = {
.name = "PCI mem",
.start = 0,
.end = -1,
.flags = IORESOURCE_MEM,
};
EXPORT_SYMBOL(iomem_resource);

可见iomem_resource 代表了整个系统的所有物理地址范围

void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res)
{
resource_size_t size;
const char *name;
void __iomem *dest_ptr;


BUG_ON(!dev);


if (!res || resource_type(res) != IORESOURCE_MEM) {
dev_err(dev, "invalid resource\n");
return IOMEM_ERR_PTR(-EINVAL);
}


size = resource_size(res);
name = res->name ?: dev_name(dev);

//获取一块memory region
if (!devm_request_mem_region(dev, res->start, size, name)) {
dev_err(dev, "can't request region for resource %pR\n", res);
return IOMEM_ERR_PTR(-EBUSY);
}

//注册mem region成功后会进行  ioremap
if (res->flags & IORESOURCE_CACHEABLE)
dest_ptr = devm_ioremap(dev, res->start, size);
else
dest_ptr = devm_ioremap_nocache(dev, res->start, size);


if (!dest_ptr) {
dev_err(dev, "ioremap failed for resource %pR\n", res);
devm_release_mem_region(dev, res->start, size);
dest_ptr = IOMEM_ERR_PTR(-ENOMEM);
}


return dest_ptr;
}
EXPORT_SYMBOL(devm_ioremap_resource);


struct resource * __devm_request_region(struct device *dev,
struct resource *parent, resource_size_t start,
resource_size_t n, const char *name)
{
struct region_devres *dr = NULL;
struct resource *res;


dr = devres_alloc(devm_region_release, sizeof(struct region_devres),
 GFP_KERNEL);//注册该资源的释放函数
if (!dr)
return NULL;

dr->parent = parent;
dr->start = start;
dr->n = n;

//注册到iomem_resource树中
res = __request_region(parent, start, n, name, 0);
if (res)
devres_add(dev, dr);
else
devres_free(dr);


return res;
}
EXPORT_SYMBOL(__devm_request_region);


struct resource * __request_region(struct resource *parent,
  resource_size_t start, resource_size_t n,
  const char *name, int flags)
{
DECLARE_WAITQUEUE(wait, current);
struct resource *res = alloc_resource(GFP_KERNEL);


if (!res)
return NULL;


res->name = name;
res->start = start;
res->end = start + n - 1;
res->flags = resource_type(parent);
res->flags |= IORESOURCE_BUSY | 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;
}//如果一时拿不到资源的话会休眠,等待释放函数wakeup 等待队列muxed_resource_wait
if (conflict->flags & flags & IORESOURCE_MUXED) {
add_wait_queue(&muxed_resource_wait, &wait);
write_unlock(&resource_lock);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule();
remove_wait_queue(&muxed_resource_wait, &wait);
write_lock(&resource_lock);
continue;
}
/* Uhhuh, that didn't work out.. */
free_resource(res);
res = NULL;
break;
}
write_unlock(&resource_lock);
return res;
}
EXPORT_SYMBOL(__request_region);

=============================================================================================

自己在使用devm_ioremap_resource接口的时候kernel ooops提示can not request region

追踪是该接口是会去一个全局唯一的管理所有region的资源树中查找是否有满足的region,如果已经有人占用了这块region会返回conflict 

换用接口devm_ioremap


void __iomem *devm_ioremap(struct device *dev, resource_size_t offset,
  unsigned long size)
{
void __iomem **ptr, *addr;


ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return NULL;

//可以比较明显的看出这其中是没有mem region的申请操作的
addr = ioremap(offset, size);
if (addr) {
*ptr = addr;
devres_add(dev, ptr);
} else
devres_free(ptr);


return addr;
}
EXPORT_SYMBOL(devm_ioremap);


 cat /proc/iomem 可以查看系统当前的通过devm_request_mem_region申请的mem region内存资源的占用情况

mem  resource 的管理方式


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值