编写设备驱动程序时linux中__iomem的用途是什么? [英] What is the use of __iomem in linux while writing device drivers?
问题描述
我已经看到__iomem
用于存储ioremap()
的返回类型,但是我在ARM体系结构中使用了u32
,并且效果很好.
I have seen that __iomem
is used to store the return type of ioremap()
, but I have used u32
in ARM architecture for it and it works well.
那么__iomem
在这里有什么不同?在什么情况下我应该使用它呢?
So what difference does __iomem
make here? And in which circumstances should I use it exactly?
推荐答案
很多类型转换都只是工作得很好".但是,这不是很严格.没有什么能阻止您将u32
强制转换为u32 *
并取消引用,但这不遵循内核API,并且容易出错.
Lots of type casts are going to just "work well". However, this is not very strict. Nothing stops you from casting a u32
to a u32 *
and dereference it, but this is not following the kernel API and is prone to errors.
__iomem
是 Sparse 使用的cookie,该工具用于查找可能的编码错误在内核中.如果您未在启用稀疏的情况下编译内核代码,则__iomem
仍将被忽略.
__iomem
is a cookie used by Sparse, a tool used to find possible coding faults in the kernel. If you don't compile your kernel code with Sparse enabled, __iomem
will be ignored anyway.
首先安装稀疏,然后将C=1
添加到您的make
调用中,以使用稀疏.例如,在构建模块时,请使用:
Use Sparse by first installing it, and then adding C=1
to your make
call. For example, when building a module, use:
make -C $KPATH M=$PWD C=1 modules
__iomem
的定义如下:
__iomem
is defined like this:
# define __iomem __attribute__((noderef, address_space(2)))
为所有I/O访问添加(并要求)像__iomem
这样的cookie是一种更严格的方法,可以避免编程错误.您不想使用具有绝对地址的I/O内存区域进行读写操作,因为您通常使用虚拟内存.因此,
Adding (and requiring) a cookie like __iomem
for all I/O accesses is a way to be stricter and avoid programming errors. You don't want to read/write from/to I/O memory regions with absolute addresses because you're usually using virtual memory. Thus,
void __iomem *ioremap(phys_addr_t offset, unsigned long size);
通常调用
以获得I/O物理地址offset
的虚拟地址,并以字节为单位指定长度size
. ioremap()
返回带有__iomem
cookie的指针,因此该现在可以与诸如readl()
/writel()
之类的内联函数一起使用(尽管现在最好使用更明确的宏iowrite32()
),它接受__iomem
地址.
is usually called to get the virtual address of an I/O physical address offset
, for a specified length size
in bytes. ioremap()
returns a pointer with an __iomem
cookie, so this may now be used with inline functions like readl()
/writel()
(although it's now preferable to use the more explicit macros ioread32()
/iowrite32()
, for example), which accept __iomem
addresses.
此外,稀疏使用noderef
属性来确保您不取消引用__iomem
指针.取消引用应该在某些I/O确实是内存映射的体系结构上起作用,但是其他体系结构使用特殊的指令来访问I/O,在这种情况下,取消引用将不起作用.
Also, the noderef
attribute is used by Sparse to make sure you don't dereference an __iomem
pointer. Dereferencing should work on some architecture where the I/O is really memory-mapped, but other architectures use special instructions for accessing I/Os and in this case, dereferencing won't work.
让我们看一个例子:
void *io = ioremap(42, 4);
稀疏不开心:
warning: incorrect type in initializer (different address spaces)
expected void *io
got void [noderef] <asn:2>*
或者:
u32 __iomem* io = ioremap(42, 4);
pr_info("%x\n", *io);
稀疏也不高兴:
warning: dereference of noderef expression
在最后一个示例中,第一行是正确的,因为ioremap()
将其值返回给__iomem
变量.但是后来,我们顺从了,我们不应该这样做.
In the last example, the first line is correct, because ioremap()
returns its value to an __iomem
variable. But then, we deference it, and we're not supposed to.
这使稀疏快乐:
void __iomem* io = ioremap(42, 4);
pr_info("%x\n", ioread32(io));
底线:请始终在需要时使用__iomem
(作为返回类型或参数类型),并使用Sparse来确保已这样做.另外:请勿取消引用__iomem
指针.
Bottom line: always use __iomem
where it's required (as a return type or as a parameter type), and use Sparse to make sure you did so. Also: do not dereference an __iomem
pointer.
编辑:这是关于 LWN文章的精彩文章. c0>并使用它.
Edit: Here's a great LWN article about the inception of __iomem
and functions using it.
这篇关于编写设备驱动程序时linux中__iomem的用途是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!