繁体   English   中英

读取内存映射的 IO 寄存器如何(来自数据表)并在 mmap 中使用它们

[英]reading Memory-Mapped IO registers How to (from datasheet) and using them in mmap

我有带有Ethernet controller: Intel Corporation 82579LM Gigabit Network Connection (Lewisville) (rev 04)的英特尔系统。 我已下载数据表,例如Intel ® 82579 Gigabit Ethernet PHY的数据表

现在我正在读取 pci 以太网设备的 resource0,例如

    if((fd = open("/sys/bus/pci/devices/0000:00:19.0/resource1", O_RDWR | O_SYNC)) == -1) {
        perror("Error: open error");
    }

    int map_size = 4096UL;
    ...
    map_base = mmap(0,4096UL , PROT_READ, MAP_SHARED, fd, Register_Values_From_Datasheet);

我有 x86-64 位系统。 卡利 linux 5.7。 所以我用数据表中的寄存器偏移值代替上面的Register_Values_From_Datasheet ,例如0x00008STATUS:Device Status Register =from datasheet

但是 mmap() 的 errno 在 mmap 调用后具有值22:EINVAL 表示无效的论点。 也许我从数据表中读取的偏移值可能必须以其他方式解释。

我在以太网设备的 sys/bus/pci/devices/0000:00:19.0 中的资源文件是这样的

        0x00000000fe400000 0x00000000fe41ffff 0x0000000000040200
        0x00000000fe427000 0x00000000fe427fff 0x0000000000040200
        0x000000000000f060 0x000000000000f07f 0x0000000000040101
        0x0000000000000000 0x0000000000000000 0x0000000000000000
        0x0000000000000000 0x0000000000000000 0x0000000000000000
        0x0000000000000000 0x0000000000000000 0x0000000000000000
        0x0000000000000000 0x0000000000000000 0x0000000000000000
        0x0000000000000000 0x0000000000000000 0x0000000000000000
        0x0000000000000000 0x0000000000000000 0x0000000000000000
        0x0000000000000000 0x0000000000000000 0x0000000000000000
        0x0000000000000000 0x0000000000000000 0x0000000000000000
        0x0000000000000000 0x0000000000000000 0x0000000000000000
        0x0000000000000000 0x0000000000000000 0x0000000000000000

从上面的资源文本文件(resource0)转储显示我的内存映射 IO 从 0x00000000fe400000 开始。 所以我认为应该是 mmap 的返回地址 (return (void*)=&0x00000000fe400000)= 但我得到类似0xffffffff和 errno 是 22。任何人都可以指导我正确的方向如何偏移量需要是从数据表解释。 此外,通常需要访问哪些寄存器才能获取 pci 以太网设备的数据包。 因为我是设备编程的新手。

Resource0 是资源列表,剩余的 Resource1.. ResourceN 是寄存器所在的实际 memory 区域。 (参考: https://techpubs.jurassic.nl/manuals/linux/developer/REACTLINUX_PG/sgi_html/ch07.html

偏移量是区域内的偏移量,而不是区域的偏移量。

所以你通常会 map region1 的整个空间 - 在你的情况下是 128KB 因为: 0x00000000fe41ffff - 0x00000000fe400000 (您也可以检查 /proc/iomem 进行确认)

map_base = mmap(0,32*4096UL , PROT_READ, MAP_SHARED, fd, 0); 

编辑:mmap 的签名是:

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

如果您指定超过文件大小的长度或偏移量,您会得到 EINVAL:来自 Linux 手册页:

EINVAL We don't like addr, length, or offset (e.g., they are too large, or not aligned on a page boundary).

您可能最终会将 map_base 转换为 uint32_t 数组(如果所有寄存器都是 32 位)并使用: map_base_as_int[8/4]来索引寄存器空间。

第一个障碍是获取只读数据(例如,MAC 地址等)。

一旦您真正想要发送和接收数据包,您将需要物理地址 - DPDK 代码处理这个(以相当复杂的方式),但您可以使用 GRUB 参数切出物理 memory 并安全使用它......


另一种方法是在 '/dev/mem' 上使用 mmap 使用fe400000上方的偏移量)无论如何,您将需要这个用于物理 memory 访问(并且您需要确保您的 kernel 已编译用于访问 - 一些锁定的内核不是)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM