After adding request_mem_region my driver fails every first access with “busy” message

对着背影说爱祢 提交于 2020-01-02 05:24:11

问题


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.

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.

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

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;
}

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?


回答1:


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?

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).

What happens if instead you use something like

#define MCF_MBAR    0x90000000

assuming that that physical address space is really unused?

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.



来源:https://stackoverflow.com/questions/12516603/after-adding-request-mem-region-my-driver-fails-every-first-access-with-busy-m

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!