C语言 request_mem_region() 实际做什么以及何时需要?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7682422/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 09:50:52  来源:igfitidea点击:

What does request_mem_region() actually do and when it is needed?

clinux-kernellinux-device-driverembedded-linux

提问by I'm a frog dragon

I'm studying on writing embedded linux driver, and decided to fire a few GPIOs to make sure I understand the book (LDD3, chap9.4.1)correctly.

我正在研究编写嵌入式 linux 驱动程序,并决定触发一些 GPIO 以确保我正确理解这本书(LDD3,第 9.4.1 章)

I am able to control the correct GPIO pins as intended (making it high and low, I probed with a multimeter); however, I tested 2 pieces of code, one with request_mem_region(), and one without. I'm expecting the one without will fail, but both is working just fine.

我能够按预期控制正确的 GPIO 引脚(使其高低,我用万用表探测);但是,我测试了 2 段代码,一段有request_mem_region(),另一段没有。我期待一个没有会失败,但两者都工作得很好。

Code with request_mem_region:

代码request_mem_region

if( request_mem_region( PIN3_CONF_PHYS, MAPPED_SIZE_GPIO_CONF,DEVICE_NAME ) == NULL )
  {
    printk( KERN_ALERT
            "GPIO_140_141_conf_phys error:%s: unable to obtain I/O memory address 0x%08llX\n",
            DEVICE_NAME, PIN3_CONF_PHYS );

    return -EBUSY;
  }

pin3_conf = (u32)ioremap( PIN3_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
pin4_conf = (u32)ioremap( PIN4_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
pin5_conf = (u32)ioremap( PIN5_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
pin6_conf = (u32)ioremap( PIN6_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
//-----------------------------------------------------------------
if( request_mem_region( GPIO_BANK5_PHYS, MAPPED_SIZE_GPIO_5,DEVICE_NAME ) == NULL )
  {
    printk( KERN_ALERT
            "error:%s: unable to obtain I/O memory address 0x%08llX\n",
            DEVICE_NAME, GPIO_BANK5_PHYS );

    return -EBUSY;
  }

gpio_virt = (u32)ioremap( GPIO_BANK5_PHYS, MAPPED_SIZE_GPIO_5 );

//some iowrite32() functions continue...

Code without request_mem_region():

没有的代码request_mem_region()

pin3_conf = (u32)ioremap( PIN3_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
pin4_conf = (u32)ioremap( PIN4_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
pin5_conf = (u32)ioremap( PIN5_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
pin6_conf = (u32)ioremap( PIN6_CONF_PHYS, MAPPED_SIZE_GPIO_CONF);
gpio_virt = (u32)ioremap( GPIO_BANK5_PHYS, MAPPED_SIZE_GPIO_5 );
//some iowrite32() functions continue...

The only difference I can observe from both cases is the result of doing a cat /proc/iomem, the one with request_mem_region()will display an additional line showing 49056000-49056097 : GPIO3.

我可以从这两种情况中观察到的唯一区别是执行 a 的结果cat /proc/iomem,其中request_mem_region()将显示额外的行显示49056000-49056097 : GPIO3.

My question is why request_mem_region()is needed since I can still communicate with the hardware address with only ioremap()? So when do we actually need to use request_mem_region()?

我的问题是为什么request_mem_region()需要,因为我仍然只能与硬件地址通信ioremap()?那么我们什么时候真正需要使用request_mem_region()

Thanks for any replies!

感谢您的回复!

回答by Thomas Petazzoni

request_mem_regiontells the kernel that your driver is going to use this range of I/O addresses, which will prevent other drivers to make any overlapping call to the same region through request_mem_region. This mechanism does not do any kind of mapping, it's a pure reservation mechanism, which relies on the fact that all kernel device drivers must be nice, and they must call request_mem_region, check the return value, and behave properly in case of error.

request_mem_region告诉内核你的驱动程序将使用这个范围的 I/O 地址,这将防止其他驱动程序通过request_mem_region. 这种机制不做任何类型的映射,它是一种纯粹的保留机制,它依赖于这样一个事实,即所有内核设备驱动程序都必须很好,并且它们必须调用request_mem_region、检查返回值并在出现错误时正确运行。

So it is completely logical that your code works without request_mem_region, it's just that it doesn't comply with the kernel coding rules.

所以你的代码在没有 的情况下工作是完全合乎逻辑的,request_mem_region只是它不符合内核编码规则。

However, your code doesn't comply with the kernel coding style. And additionnally, there is an existing infrastructure to handle GPIOs, named gpiolib, which you should use instead of manually remapping your GPIO bank registers. Which platform are you working on ?

但是,您的代码不符合内核编码风格。此外,还有一个现有的基础设施来处理 GPIO,名为 gpiolib,您应该使用它而不是手动重新映射您的 GPIO bank 寄存器。你在哪个平台上工作?

回答by jordi oliva

Using request_mem_region() and ioremap() in device drivers is now deprecated. You should use the below "managed" functions instead, which simplify driver coding and error handling:

现在不推荐在设备驱动程序中使用 request_mem_region() 和 ioremap()。您应该改用以下“托管”函数,以简化驱动程序编码和错误处理:

devm_ioremap()
devm_iounmap()
devm_ioremap_resource(), Takes care of both the request and remapping operations

https://bootlin.com/doc/training/linux-kernel/linux-kernel-slides.pdfslide 276

https://bootlin.com/doc/training/linux-kernel/linux-kernel-slides.pdf幻灯片 276