加入request_mem_region我的驱动程序后失败,“忙”消息每次第一次访问(After a

2019-09-22 16:21发布

OK,这是很奇怪我。 我有一个模拟的CAN总线驱动器,它是一个Linux内核模块。 然后我具有其中通过打开文件描述符和发送访问驱动程序用户空间中运行一个测试程序ioctl()消息。

现在,CAN总线驱动只是我一直在采取新的x86平台上运行(这是我们的嵌入式的Coldfire系统上运行)。 在嵌入式系统它必须使用request_mem_region() / ioremap()来获得I / O区访问,我并不要这样做的记忆,但我想保持尽可能多的通用代码,我可以。

下面是一些有用的定义:

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

随后的初始化过程中,我们正在做这样的:

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

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

现在,如果我理解正确的这一切......我们在这里所做的是请求范围内未分配的内存地址的保留,如果我们成功了,让他们通过我们的访问。

我检查通过当前映射地址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

它看起来像有什么期运用那段记忆,让我觉得我OK这里。 所以,我打开我的内核模块,成功,去跑我的测试程序,它失败,再次运行它和它的作品。 你运行它,它已经刚装入后每隔一日一次,它就会失败......第2,第3,第n次,它会工作:

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

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

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()从我的驱动程序代码一切正常,所以我觉得我只是在做一些愚蠢的事......但为什么它在它的方式失败?

Answer 1:

我有点惊讶,这对你的作品的。 所述request_mem_region()传递的值0x101C0000其是系统RAM,的物理地址范围内0x001000000x1ffeffff 。 我猜(初始)错误回报是,内核已经安装了这个物理内存区域到它的内存池的指标。 当驾驶员错误退出(或当模块卸载),它尝试做适当的清理和调用release_mem_region()这可能会使得成功request_mem_region()的下一个复飞?

通常你会提供request_mem_region()使用(即目前未知的内核)的地址范围,因为司机在作出该物理地址范围“可用”(即宣布进行映射的物理地址范围的过程到虚拟地址空间)。

相反,如果你使用像会发生什么

#define MCF_MBAR    0x90000000

假设该物理地址空间实在是不使用的?

顺便说一句,如果你的驱动程序调用release_mem_region()第一次使用后,则驱动程序有一个bug。 驱动程序应该只释放它实际上已经获得的资源。 如果request_mem_region()返回一个错误,那么内存资源是从未获得过。 因此没有理由调用release_mem_region()和驱动程序时总是会得到分配错误_init() 如果你检查一些正常经营的Linux设备驱动程序,你可能会发现精心错误退出方案(使用goto语句)放松在所分配的资源_init()在释放前常规和有效性检查_exit()的代码。



文章来源: After adding request_mem_region my driver fails every first access with “busy” message