在添加request_mem_region之后,我的驱动程序在每次第一次访问时都失败,并显示“繁忙".信息 [英] After adding request_mem_region my driver fails every first access with "busy" message

查看:398
本文介绍了在添加request_mem_region之后,我的驱动程序在每次第一次访问时都失败,并显示“繁忙".信息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好的,这对我来说真的很奇怪.我有一个模拟的CAN总线驱动程序,它是一个Linux内核模块.然后,我在用户空间中运行了一个测试应用程序,该应用程序通过打开文件描述符并发送ioctl()消息来访问驱动程序.

OK, this is really weird to me. I've got a simulated CAN bus driver, it is a Linux Kernel module. Then I have a test application running in user space which accesses the driver via opening a file descriptor and sending ioctl() messages.

现在,CAN总线驱动程序只是我一直在x86平台上运行的东西(它已在我们的嵌入式Coldfire系统上运行).在嵌入式系统上,它必须使用request_mem_region()/ioremap()来访问内存I/O区域,我不需要执行此操作,但是我想保留尽可能多的尽可能通用的代码.

Now the CAN bus driver is just something I've been adopting to run on the x86 platform (it was running on our embedded Coldfire system). On the embedded system it had to use request_mem_region()/ioremap() to get the memory I/O area accessible, I don't need to do this, but I want to keep as much of the code common as I can.

以下是一些有用的定义:

Here are some useful defines:

#define MCF_MBAR    0x10000000

extern unsigned int Base[];
extern unsigned int can_range[];

  //This is the CAN registers on coldfire, just unused on my x86 desktop
Base[minor] = (MCF_MBAR + 0x1c0000); 
can_range[minor] = 0x180;

然后在初始化期间执行此操作:

Then during the init we were doing this:

if(NULL == request_mem_region(Base[minor], can_range[minor], "CAN-IO")) {
    return -EBUSY;
}

can_base[minor] = ioremap(Base[minor], can_range[minor]);

现在,如果我理解正确的话...我们在这里要做的只是请求保留一系列未分配的内存地址,如果成功,则可以让我们对其进行访问.

Now if I understand this correctly... all we're doing here is requesting a reservation of a range of non-assigned memory addresses and, if we're successful, making them accessible by us.

我通过cat /proc/iomem检查了当前映射的地址:

I checked the currently mapped addresses via cat /proc/iomem:

00000000-0000ffff : reserved
00010000-0009fbff : System RAM
0009fc00-0009ffff : reserved
000a0000-000bffff : Video RAM area
000c0000-000c8fff : Video ROM
000e2000-000e6fff : Adapter ROM
000f0000-000fffff : reserved
000f0000-000fffff : System ROM
00100000-1ffeffff : System RAM
00200000-0071038b : Kernel code
0071038c-00ad8a7f : Kernel data
00b58000-00c52fff : Kernel bss
                          <--  101C0000-101C0180 : This is where I'd be mapping memory
1fff0000-1fffffff : ACPI Tables
e0000000-e0ffffff : 0000:00:02.0
e0000000-e0bfffff : vesafb
f0000000-f001ffff : 0000:00:03.0
f0000000-f001ffff : e1000
f0400000-f07fffff : 0000:00:04.0
f0400000-f07fffff : vboxguest
f0800000-f0803fff : 0000:00:04.0
f0804000-f0804fff : 0000:00:06.0
f0804000-f0804fff : ohci_hcd
f0806000-f0807fff : 0000:00:0d.0
f0806000-f0807fff : ahci
fee00000-fee00fff : Local APIC
fffc0000-ffffffff : reserved

看起来没有任何使用该内存的空间,所以我觉得我还可以.因此,我成功加载了内核模块,然后运行我的测试程序,但是它失败了,再次运行它就可以了. 重新加载后,您在第一次运行它时,它将失败...在第二,第三,第n次运行时,它将运行:

It looks like there's nothing useing that memory, so I think I'm OK here. So I load my kernel module, successfully, go to run my test program and it fails, run it again and it works. Every 1st time you run it after it's been freshly loaded, it will fail... the 2nd, 3rd, nth time, it will work:

mike@linux-4puc:~> ./a.out 
  Starting driver test
  Error 'Device or resource busy' opening CAN device
mike@linux-4puc:~> ./a.out 
  Starting driver test
  We opened successfully

这是我非常简单的用户空间程序的一部分:

Here's part of my very simple userspace program:

int fd;
char* dev = "/dev/can0";

printf("Starting driver test\n");

if ((fd = open(dev, O_RDWR)) < 0) {
    printf("Error '%s' opening CAN device", strerror(errno));
    close(fd);
    return -1;
}

关于为什么发生这种情况的任何想法?如果我从驱动程序中删除了request_mem_region()代码,那么一切正常,那么我想我只是在做一些愚蠢的事情……但是为什么它会以失败的方式失败呢?

Any ideas on why this is happening? If I remove the request_mem_region() code from my driver everything works, so I think I'm just doing something stupid... but why does it fail in the manner that it does?

推荐答案

我对此感到有点惊讶. request_mem_region()传递的值0x101C0000处于系统RAM的物理地址范围0x00100000:0x1ffeffff中.我猜想,(初始)错误返回表明内核已经将该物理内存区域安装到其内存池中.当驱动程序错误退出时(或模块卸载时),它会尝试进行适当的清理并调用release_mem_region(),这可能会成功使request_mem_region()下一次复飞吗?

I'm a bit surprised that this works for you at all. The request_mem_region() is passed a value of 0x101C0000 which is within the physical address range of system RAM, 0x00100000:0x1ffeffff. I'd guess that the (initial) error return is an indicator that the kernel has already installed this physical memory region into its memory pools. When the driver error-exits (or when the module unloads) does it try to do the proper clean-up and call release_mem_region(), which might enable a successful request_mem_region() the next go-around?

通常,您会为request_mem_region()提供一个正在使用的 地址范围(即当前对于内核来说未知),因为驱动程序正在处理使该物理地址范围可用"(即声明要映射到虚拟地址空间的物理地址范围).

Normally you would provide request_mem_region() with an address range that is not in use (i.e. currently unknown to the kernel), because the driver is in the process of making that physical address range "usable" (i.e. declaring a physical address range for mapping to virtual address space).

如果您改用

#define MCF_MBAR    0x90000000

假定该物理地址空间确实未使用?

assuming that that physical address space is really unused?

顺便说一句,如果您的驱动程序在首次使用后调用release_mem_region(),则该驱动程序存在错误.驱动程序应仅释放其实际获取的资源.如果request_mem_region()返回错误,则永远不会获取内存资源.因此,没有理由调用release_mem_region()(驱动程序在_init()期间始终会出现分配错误).如果检查一些运行正常的Linux设备驱动程序,则可能会发现精心设计的错误退出方案(使用goto语句)在_init()例程中展开分配的资源,并在_exit()代码中进行释放之前进行有效性检查.

BTW if your driver is calling release_mem_region() after its first use, then the driver has a bug. A driver should only release the resources it has actually acquired. If request_mem_region() returned an error, then the memory resource was never acquired. Therefore there is no reason to call release_mem_region() (and the driver would always get the allocation error during _init()). If you inspect some properly-operating Linux device drivers, you will probably find elaborate error-exit schemes (using goto statements) to unwind the allocated resources in the _init() routine and validity checks before deallocation in the _exit() code.

这篇关于在添加request_mem_region之后,我的驱动程序在每次第一次访问时都失败,并显示“繁忙".信息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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