没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
驱动层ioremap创建页表流程
在编写linux设备驱动程序时经常使用ioremap接口将外设的物理地址转换成虚拟地址,继而通过访问内存的方式来访问外设物理地址
空间的内容。下来就详细看下ioremap的具体流程。在ARM上,ioremap相关的操作api如下:
#define ioremap(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE)
#define ioremap_nocache(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE)
#define ioremap_cached(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE_CACHED)
#define ioremap_wc(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE_WC)
#define iounmap __arm_iounmap
其中__arm_ioremap的定义如下:
void __iomem *
__arm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
{
return arch_ioremap_caller(phys_addr, size, mtype,
__builtin_return_address(0));
}
查看arch_ioremap_caller后发现其是一个函数指针,具体指向的函数如下:
void __iomem * (*arch_ioremap_caller)(unsigned long, size_t, unsigned int, void *) = __arm_ioremap_caller;
void __iomem *__arm_ioremap_caller(unsigned long phys_addr, size_t size, unsigned int mtype, void *caller)
{
unsigned long last_addr;
unsigned long offset = phys_addr & ~PAGE_MASK;
unsigned long pfn = __phys_to_pfn(phys_addr);
/*
* Don't allow wraparound or zero size
*/
last_addr = phys_addr + size - 1;
if (!size || last_addr < phys_addr)
return NULL;
return __arm_ioremap_pfn_caller(pfn, offset, size, mtype, caller);
}
上述函数首先根据物理地址计算出offset(物理地址的低12位地址),再计算出pfn,然后调用__arm_ioremap_pfn_caller,如下:
void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn, unsigned long offset, size_t size, unsigned int mtype, void *caller)
{
const struct mem_type *type;
int err;
unsigned long addr;
struct vm_struct * area;
type = get_mem_type(mtype);
if (!type)
return NULL;
/*
* Page align the mapping size, taking account of any offset.
*/
size = PAGE_ALIGN(offset + size);
/*
* Try to reuse one of the static mapping whenever possible.
*/
read_lock(&vmlist_lock);
for (area = vmlist; area; area = area->next) {
if (!size || (sizeof(phys_addr_t) == 4 && pfn >= 0x100000))
break;
if (!(area->flags & VM_ARM_STATIC_MAPPING))
continue;
if ((area->flags & VM_ARM_MTYPE_MASK) != VM_ARM_MTYPE(mtype))
continue;
if (__phys_to_pfn(area->phys_addr) > pfn ||
__pfn_to_phys(pfn) + size-1 > area->phys_addr + area->size-1)
continue;
/* we can drop the lock here as we know *area is static */
read_unlock(&vmlist_lock);
addr = (unsigned long)area->addr;
addr += __pfn_to_phys(pfn) - area->phys_addr;
return (void __iomem *) (offset + addr);
}
read_unlock(&vmlist_lock);
/*
* Don't allow RAM to be mapped - this causes problems with ARMv6+
*/
if (WARN_ON(pfn_valid(pfn)))
return NULL;
资源评论
chenbeixin
- 粉丝: 20
- 资源: 43
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功