linux下写设备驱动时__iomem有什么用? [英] What is the use of __iomem in linux while writing device drivers?

查看:23
本文介绍了linux下写设备驱动时__iomem有什么用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看到__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.

__iomemSparse 使用的 cookie,这是一个使用的工具找出内核中可能存在的编码错误.如果您没有在启用 Sparse 的情况下编译内核代码,__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.

首先安装 Sparse,然后将 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 定义如下:

# 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()(尽管现在最好使用更明确的宏 ioread32()/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.

此外,Sparse 使用 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
", *io);

Sparse 也不开心:

Sparse is not happy either:

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.

这让 Sparse 很高兴:

This makes Sparse happy:

void __iomem* io = ioremap(42, 4);
pr_info("%x
", 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 文章的精彩LWN 文章code>__iomem 和使用它的函数.

Edit: Here's a great LWN article about the inception of __iomem and functions using it.

这篇关于linux下写设备驱动时__iomem有什么用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆