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 的管理方式