linux中ioremap与ioremap_cachable的区别(mips架构)

在arch/mips/include/asm/io.h
/*
* ioremap - map bus memory into CPU space
* @offset: bus address of the memory
* @size: size of the resource to map
*
* ioremap performs a platform specific sequence of operations to
* make bus memory CPU accessible via the readb/readw/readl/writeb/
* writew/writel functions and the other mmio helpers. The returned
* address is not guaranteed to be usable directly as a virtual
* address.
*/
#define ioremap(offset, size)\
__ioremap_mode((offset), (size), _CACHE_UNCACHED)

/*
* ioremap_cachable - map bus memory into CPU space
* @offset: bus address of the memory
* @size: size of the resource to map
*
* ioremap_nocache performs a platform specific sequence of operations to
* make bus memory CPU accessible via the readb/readw/readl/writeb/
* writew/writel functions and the other mmio helpers. The returned
* address is not guaranteed to be usable directly as a virtual
* address.
*
* This version of ioremap ensures that the memory is marked cachable by
* the CPU. Also enables full write-combining. Useful for some
* memory-like regions on I/O busses.
*/
#define ioremap_cachable(offset, size)\
__ioremap_mode((offset), (size), _page_cachable_default)
#define ioremap_cached(offset, size) ioremap_cachable(offset, size)


static inline void __iomem * __ioremap_mode(phys_t offset, unsigned long size,
unsigned long flags)
{
void __iomem *addr = plat_ioremap(offset, size, flags);

if (addr)
return addr;

#define __IS_LOW512(addr) (!((phys_t)(addr) & (phys_t) ~0x1fffffffULL))

if (cpu_has_64bit_addresses) {
u64 base = UNCAC_BASE;

/*
* R10000 supports a 2 bit uncached attribute therefore
* UNCAC_BASE may not equal IO_BASE.
*/
if (flags == _CACHE_UNCACHED)
base = (u64) IO_BASE;
return (void __iomem *) (unsigned long) (base + offset);
} else if (__builtin_constant_p(offset) &&
__builtin_constant_p(size) && __builtin_constant_p(flags)) {
phys_t phys_addr, last_addr;

phys_addr = fixup_bigphys_addr(offset, size);

/* Don't allow wraparound or zero size. */
last_addr = phys_addr + size - 1;
if (!size || last_addr < phys_addr)
return NULL;

/*
* Map uncached objects in the low 512MB of address
* space using KSEG1.
*/
if (__IS_LOW512(phys_addr) && __IS_LOW512(last_addr) &&
flags == _CACHE_UNCACHED)
return (void __iomem *)
(unsigned long)CKSEG1ADDR(phys_addr);
}

return __ioremap(offset, size, flags);

#undef __IS_LOW512
}

其中__builtin_constant_p(x)作用是用来确定一个值在编译时是否为常量(use to determine whether a value is a constant at compile-time)。
如果x在编译的时候就能获得常值,则为TRUE;如果是变量则为FALSE

在arch/mips/mm/ioremap.c中:
/*
* Remap an arbitrary physical address space into the kernel virtual
* address space. Needed when the kernel wants to access high addresses
* directly.
*
* NOTE! We need to allow non-page-aligned mappings too: we will obviously
* have to convert them into an offset in a page-aligned mapping, but the
* caller shouldn't need to know that small detail.
*/
void __iomem * __ioremap(phys_t phys_addr, phys_t size, unsigned long flags)
{
...
}
下面这段文字转自http://blog.csdn.net/bing_bing/article/details/5774294

void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
入口: phys_addr:要映射的起始的IO地址;

size:要映射的空间的大小;

flags:要映射的IO空间的和权限有关的标志;

功能: 将一个IO地址空间映射到内核的虚拟地址空间上去,便于访问;

实现:对要映射的IO地址空间进行判断,低PCI/ISA地址不需要重新映射,也不允许用户将IO地址空间映射到正在使用的RAM中,最后申请一个vm_area_struct结构,调用remap_area_pages填写页表,若填写过程不成功则释放申请的vm_area_struct空 间;

意义:
比如isa设备和pci设备,或者是fb,硬件的跳线或者是物理连接方式决定了硬件上的内存影射到的cpu物理地址。
在内核访问这些地址必须分配给这段内存以虚拟地址,这正是__ioremap的意义所在 ,需要注意的是,物理内存已经"存在"了,无需alloc page给这段地址了.

文件中的注释也是比较详尽的,并且只 暴露了__ioremap,iounmap两个函数供其他模
块调用,函数remap_area_pte,remap_area_pmd,remap_area_pages只为__ioremap所用.

--------
为了使软件访问I/O内存,必须为设备分配虚拟地址.这就是ioremap的工作.这个函数专门用来为I/O内存区域分配虚拟地址(空间).对于直接映射的I/O地址ioremap不做任何事情。有了ioremap(和iounmap),设备就可以访问任何I/O内存空间,不论它是否直接映射到虚拟地址空间.但是,这些地址永远不能直接使用(指物理地址),而要用readb这种函数.

根据计算机平台和所使用总线的不同,I/O 内存可能是,也可能不是通过页表访问的,通过页表访问的是统一编址(PowerPC),否则是独立编址(Intel)。如果访问是经由页表进行的,内核必须首先安排物理地址使其对设备驱动 程序可见(这通常意味着在进行任何 I/O 之前必须先调用 ioremap)。如果访问无需页表,那么 I/O 内存区域就很象 I/O 端口,可以使 用适当形式的函数读写它们。

不管访问 I/O 内存时是否需要调用 ioremap,都不鼓励直接使用指向 I/O 内存的指针。尽管(在“I/O 端口和 I/O 内存” 介绍过)I/O 内存在硬件一级是象普通 RAM 一样寻址的,但在“I/O 寄存器和常规内存”中描述过的那些需要额外小心的情况中已经建议不要使用普 通指针。相反,使用“包装的”函数访问 I/O 内存,一方面在所有平台上都是安全的,另一方面,在可以直接对指针指向的内存区域执行操作的时候,该函数 是经过优化的

-------
自己原以为当给显卡上的存储空间分配了总线地址A以后,它所对应的虚拟空间就随之确定了.也就是A+3G.可是事实上,在ioremap.c文件里面的实现并不是这样的.所用的函数是 __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)实现的时候是为从phys_addr开始的size大小的物理地址分配一块虚拟地址.注意这里是分配,而不是指定.我所认为的分配应该是指定即根据phys_addr得到其所对应的虚拟地址是phys_addr+3G. 本人认为一合理的解释是这样的:系统虚拟空间中映射的非IO卡上的地址空间满足3G差关系,而IO卡上的存储空间就不满足了.欢迎讨论

在X86体系下的,CPU的物理地址和PCI总线地址共用一个空间。linux内核将3G-4G的虚拟地址固定映射到了物理地址的0-1G的地方。但是如果外围设备上的地址高于1G,例如某块PCI卡分配到了一个高于1G的地址,就需要调用ioremap来重新建立该物理地址(总线地址)和虚拟地址之间的映射。这个映射过程是这样的:在ioremap.c文件的__ioremap函数中首先对将来映射的物理地址进行检查,也就是不能重新映射640K-1M地址(由于历史的原因,物理地址640k到1M空间被保留给了显卡),普通的ram地也不能重新被映射。之后调用get_vm_area获得可用的虚拟地址,然后根这虚拟地址和欲映射的物理地址修改页表,之后内核就可以用这个虚拟地址来访问映射的物理地址了。

http://bbs.chinaunix.net/thread-3554853-1-1.html

什么情况用cacheable,什么情况下必须non-cacheable?

CPU能帮你维护好 RAM的一致性, 也就是CPU或DMA该RAM时另一个会知道并做出相应动作,那就用cachable,因为性能好。
CPU和DMA各管各的,那就non-cachable,因为省得折腾。

for x86应该是cachable的, 因为体系结构已经保证了一致性

我觉得这里并不是一致性的问题。ioremap的memory是按指令顺序直接写到device上的。
如果是cacheable的话,假设我们
write reg1
write reg2
如果是cacheable的话,值就会被cache在cpu cache里,这两个值写到memeory的顺序就是不定的。
cache一致性只是保证cache和memory里的值的一致性,x86上由硬件保证。假如cache里的值是新的,memory里的是旧的。那么另外一个cpu,或者device想access这块memory的值,那么cache一致性就保证他们会独到最新的值。

更多相关文章

  1. Red Hat Linux下如何修改网卡MAC地址
  2. Linux内存管理 (10)缺页中断处理
  3. 进程实际内存占用: 私有驻留内存数(Private RSS)介绍
  4. 一些下载交叉编译环境的地址
  5. 如何使用SQL语句查到当前SQL SERVER 2000服务器的IP地址
  6. MediaPlayer源码存在的内存泄漏问题,释放资源的正确方式
  7. Android Studio 检测内存泄漏与解决方法
  8. APNS开源包的内存泄露问题
  9. 记一次java内存分析

随机推荐

  1. Win7(64-bit)系统下的【Python3.6.0+open
  2. 如何在python 3中将单词转换为数字(自己的
  3. 【Python】Python脚本实现抢券
  4. 如何使用不同的类python在一个类中的一个
  5. 安装numpy+scipy+matlotlib+scikit-learn
  6. Linux或Linux虚拟机桥接模式使用Python2
  7. [LeetCode][Python][C#]刷题记录 1. 两数
  8. Python3基础教程-廖雪峰[带标签完整版]
  9. wxPython 显示一张图片
  10. eclipse调用python模块是出错及解决