Kar*_*hik 6 io arm virtual-memory
我有一个 Terasic-SoCKIT(fpga 和 arm cortex a9),我在 HPS 上运行 Linux。我正在尝试访问内存映射 I/O,编写了一个带有函数“request_mem_region”和“ioremap”的简单字符驱动程序。
内存映射 IO 是 AXI 总线,我可以使用它向 FPGA 传输数据。我看到每次写入大约需要 6us,对于我的应用程序,我需要它小于 1us。此外,驱动程序在几次写入后停止写入映射的 IO(看不到 fpga 中的数据正在更改;驱动程序中的缓冲区是否已满??)。
问题是我是否遗漏了什么,或者因为写入是从虚拟地址到物理地址发生的,所以它不能再快了?如果从虚拟地址写入速度变慢,有没有办法加快速度?我知道,ARM 有一个 DMAC,但我还没有探索它。
谢谢你,卡西克
对不起,我没说我正在测量用户空间代码中的时间。后来查了一下驱动写入的时间,是纳秒级。所以,我认为大部分时间是从用户空间写入内核。
所以,我做了一些进一步的阅读并了解到 ioremap() 将物理地址映射到内核虚拟地址,而 remap_pfn_range() 将物理地址/IO 内存映射到用户虚拟空间(这就是我需要的;从用户写入 IO 内存空间)。我使用了简单的 mmap 示例 - http://web.cecs.pdx.edu/~jrb/ui/linux/examples.dir/simple/simple.c作为内核驱动程序。以下代码是我的用户空间代码:
using namespace std;
#include <iostream>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <ctime>
#define PAGE_SIZE 4096
#define HPS2FPGA_BRIDGE_BASE 0xc0000000
#define BLINK_OFFSET 0x0
volatile unsigned char *blink_mem;
void *bridge_map;
int main()
{
int fd, ret = EXIT_FAILURE;
unsigned int i;
unsigned char value;
int dummy;
off_t blink_base = HPS2FPGA_BRIDGE_BASE;
clock_t start, stop;
double duration;
/* open the memory device file */
fd = open("/dev/HPS2FPGA", O_RDWR|O_SYNC);
if (fd < 0) {
perror("open");
exit(EXIT_FAILURE);
}
/* map the LWHPS2FPGA bridge into process memory */
bridge_map = mmap(NULL, PAGE_SIZE, PROT_WRITE|PROT_READ|PROT_EXEC, MAP_SHARED,
fd, blink_base);
if (bridge_map == MAP_FAILED) {
perror("mmap");
goto cleanup;
}
/* get the delay_ctrl peripheral's base address */
blink_mem = (unsigned char *) (bridge_map + BLINK_OFFSET);
start = clock();
/* write the value */
for(i = 0; i < 1000000; i++)
{
*blink_mem = i;
dummy = *blink_mem;
}
stop = clock();
duration = ( stop - start ) / (double) CLOCKS_PER_SEC;
printf("%f", duration);
if (munmap(bridge_map, PAGE_SIZE) < 0) {
perror("munmap");
goto cleanup;
}
ret = 0;
cleanup:
close(fd);
return ret;
}
Run Code Online (Sandbox Code Playgroud)
我正在写入虚拟地址空间 mmap 返回,我可以通过读取该地址的值来验证写入,但我没有看到该值在 FPGA 中得到更新。
当我写入用户虚拟空间时,物理地址如何写入?有没有办法调试并查看物理地址空间是否真正被写入?
好吧,看起来这个问题的主题是一个毛皮......内存映射 I/O(正确完成)将与处理器为正在访问的硬件执行此操作一样快,并且执行此操作不会产生任何开销用户模式与内核模式相反(即没有“从用户空间写入内核”)。
但是,您仍然必须考虑当您对地址进行读取或写入时会发生什么(这就是问题所在)。在大多数架构中,有两种映射 - 虚拟到物理,以及物理到设备。第一个是在虚拟内存硬件中设置的,第二个是在内存控制器中设置的。
除了映射之外,所有访问通常都通过缓存硬件进行,因此您必须决定是否要缓存访问。如果正在访问的底层设备是某种 RAM,那么您通常希望缓存访问。对于其他类型的设备,通常不需要。
可能还有很多其他事情需要考虑(例如,VM 映射是否驻留在 VM 硬件中、访问的宽度和时间、优先级、权限等),但缓存是第一位的。
在@Karthik的情况下,因为他没有在映射中关闭缓存,所以根据缓存的类型,当他写入地址(直写)时,整个缓存行正在被写入,或者写入被延迟(回写)(如果您想了解有关缓存的一些细节,请尝试这个)。
为了回答特定的(后续)问题,一旦虚拟地址映射完成并且缓存完成其工作,访问就会进入内存控制器 - 该硬件决定正在访问哪个总线和/或设备并执行“正确的操作”。该硬件的“东西”,通常涉及断言芯片选择和/或写使能信号,可能将部分或全部物理地址复制到地址线上,可能是一些设置时序等。
...调试这些东西的最佳方法是将某种分析器连接到您的设备或总线,或者如果这太困难/昂贵,则内存控制器中可能有一些调试支持。
blink_mem另一个次要但重要的一点...请注意上面代码中的声明-易失性类型限定符非常重要。它告诉编译器不要破坏对地址的访问。除此之外,您应该了解与内存访问有关的任何特殊管道指令(查看powerpc 中的eieio指令 - 有人有幽默感:-)
最后,只是为了重申评论中所说的内容,这实际上是问题的真正答案,当调用remap_pfn_range()时,您可以通过使用以下命令修改最后一个参数(prot)中指定的页面保护来关闭缓存pgprot_noncached()宏。另请阅读此和此,特别是此。干杯!
| 归档时间: |
|
| 查看次数: |
4800 次 |
| 最近记录: |