11

我正在为一个简单的测试设备编写 PCI 驱动程序。

使用 lspci 可以正确识别硬件(您可以看到我的驱动程序vabs已注册):

04:02.0 Non-VGA unclassified device: Device bace:55aa
    Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
    Status: Cap- 66MHz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
    Latency: 0
    Region 0: Memory at f0000000 (32-bit, prefetchable) [size=16M]
    Kernel driver in use: vabs

驱动程序和 PCI 子系统的初始化和取消初始化工作正常。我得到了一个设备号,并且 udev 创建了一个设备文件。

从设备文件读取时,我收到以下错误消息:

BUG: unable to handle kernel paging request at 00000000f0000000

我在初始化中成功请求 PCI 资源。这将为 memstart0 返回 00000000f0000000,这是我的 PCI 基地址 0。

memstart0 = pci_resource_start( pdev, 0 );
memlen = pci_resource_len( pdev, 0 );
if( request_mem_region(memstart0,memlen,pdev->dev.kobj.name)==NULL ) {
    dev_err(&pdev->dev,"Memory address conflict for device\n");
    goto cleanup_mem;
}

尝试使用以下代码从该 memio 地址读取会出现上述错误:

ssize_t driver_read(struct file *instance, char __user *buffer, size_t max_bytes_to_read, loff_t *offset) {
    u32 test;

    dev_dbg(vabs_dev,"copying from %p\n", (void *) memstart0);
    test = readl((void *) memstart0);

    return max_bytes_to_read;
}

我还尝试了其他访问函数,如 memcpy_fromio、ioread32 和直接指针访问,结果相同。

硬件在 Windows 机器上工作。唯一显着的区别是,Windows 将基地址 0 保留为 00000000f d 000000,而 Linux 将其保留为 00000000f 0 000000。

这是用于公立学校的非营利教育目的。谢谢你的帮助!

4

1 回答 1

19

阅读Documentation/IO-mapping.txt(搜索“iomap”)和/或LDD3 的第 15 章

request_mem_region只是确保没有其他驱动程序已经占用了该内存区域。您仍然需要将其映射到内核的 VM 空间,iomap然后才能读取/写入它。

请注意,整个pci_resource_startetc. 舞蹈在某种程度上已被弃用。我相信这些天推荐的方法是:

pci_request_regions(pdev, "myname");  /* to request regions for all BARs */

然后:

void __iomem *base = pci_iomap(pdev, 0, pci_resources_len(pdev,0)); /* to map BAR 0 */

然后:

ioread32(base + offset);  /* Or readl(base + offset), but this is more generic */

最后,最后:

pci_iounmap(pdev, base);  /* Release kernel VM mapping (undoes pci_iomap) */
pci_release_regions(pdev); /* Release all regions (undoes pci_request_regions) */

您可以通过组合pci_resource_startpci_resource_lenrequest_mem_region和手动执行前两个操作iomap。但以上是 (a) 更短且 (b) 内存映射设备和使用旧 x86 I/O 空间的设备之间的通用性。(并不是说周围有很多这样的人了。)

于 2012-12-10T17:08:03.320 回答