- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我正在编写一个 linux 设备驱动程序以允许 FPGA(当前通过 PCI express 连接到 PC)将 DMA 数据直接写入 CPU RAM。这需要在没有任何交互的情况下发生,并且用户空间需要能够访问数据。一些细节:- 运行 64 位 Fedora 14- 系统有 8GB 内存- FPGA (Cyclone IV) 在 PCIe 卡上
为了实现这一目标,我执行了以下操作:- 在 grub 中保留 RAM 的上部 2GB,内存映射为 6GB$2GB(如果我添加 mem=2GB,将无法启动)。我可以看到/proc/meminfo 中保留了 2GB 的 RAM- 映射 BAR0 以允许读取和写入 FPGA 寄存器(这非常有效)- 在我的驱动程序中使用 remap_pfn_range() 实现了一个 mmap 函数- 使用ioremap获取缓冲区的虚拟地址- 添加了 ioctl 调用(用于测试)以将数据写入缓冲区- 通过调用 ioctl 将数据写入缓冲区并验证数据位于用户空间的缓冲区中来测试 mmap
我面临的问题是当 FPGA 开始将数据 DMA 到我提供的缓冲区地址时。我经常收到 PTE 错误(来自 DMAR:) 或使用下面的代码我收到以下错误:DMAR: [DMA Write] 请求设备 [01:00.0] 故障地址 186dc5000
DMAR:[故障原因 01] 根条目中的当前位已清除DRHD:处理故障状态 reg 3
第一行地址根据FPGA的DMA每次递增0x1000
这是我的 init() 代码:
#define IMG_BUF_OFFSET 0x180000000UL // Location in RAM (6GB)
#define IMG_BUF_SIZE 0x80000000UL // Size of the Buffer (2GB)
#define pci_dma_h(addr) ((addr >> 16) >> 16)
#define pci_dma_l(addr) (addr & 0xffffffffUL)
if((pdev = pci_get_device(FPGA_VEN_ID, FPGA_DEV_ID, NULL)))
{
printk("FPGA Found on the PCIe Bus\n");
// Enable the device
if(pci_enable_device(pdev))
{
printk("Failed to enable PCI device\n");
return(-1);
}
// Enable bus master
pci_set_master(pdev);
pci_read_config_word(pdev, PCI_VENDOR_ID, &id);
printk("Vendor id: %x\n", id);
pci_read_config_word(pdev, PCI_DEVICE_ID, &id);
printk("Device id: %x\n", id);
pci_read_config_word(pdev, PCI_STATUS, &id);
printk("Device Status: %x\n", id);
pci_read_config_dword(pdev, PCI_COMMAND, &temp);
printk("Command Register : : %x\n", temp);
printk("Resources Allocated :\n");
pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &temp);
printk("BAR0 : %x\n", temp);
// Get the starting address of BAR0
bar0_ptr = (unsigned int*)pcim_iomap(pdev, 0, FPGA_CONFIG_SIZE);
if(!bar0_ptr)
{
printk("Error mapping Bar0\n");
return -1;
}
printk("Remapped BAR0\n");
// Set DMA Masking
if(!pci_set_dma_mask(pdev, DMA_BIT_MASK(64)))
{
pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
printk("Device setup for 64bit DMA\n");
}
else if(!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))
{
pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
printk("Device setup for 32bit DMA\n");
}
else
{
printk(KERN_WARNING"No suitable DMA available.\n");
return -1;
}
// Get a pointer to reserved lower RAM in kernel address space (virtual address)
virt_addr = ioremap(IMG_BUF_OFFSET, IMG_BUF_SIZE);
kernel_image_buffer_ptr = (unsigned char*)virt_addr;
memset(kernel_image_buffer_ptr, 0, IMG_BUF_SIZE);
printk("Remapped image buffer: 0x%p\n", (void*)virt_addr);
这是我的 mmap 代码:
unsigned long image_buffer;
unsigned int low;
unsigned int high;
if(remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
vma->vm_end - vma->vm_start,
vma->vm_page_prot))
{
return(-EAGAIN);
}
image_buffer = (vma->vm_pgoff << PAGE_SHIFT);
if(0 > check_mem_region(IMG_BUF_OFFSET, IMG_BUF_SIZE))
{
printk("Failed to check region...memory in use\n");
return -1;
}
request_mem_region(IMG_BUF_OFFSET, IMG_BUF_SIZE, DRV_NAME);
// Get the bus address from the virtual address above
//dma_page = virt_to_page(addr);
//dma_offset = ((unsigned long)addr & ~PAGE_MASK);
//dma_addr = pci_map_page(pdev, dma_page, dma_offset, IMG_BUF_SIZE, PCI_DMA_FROMDEVICE);
//dma_addr = pci_map_single(pdev, image_buffer, IMG_BUF_SIZE, PCI_DMA_FROMDEVICE);
//dma_addr = IMG_BUF_OFFSET;
//printk("DMA Address: 0x%p\n", (void*)dma_addr);
// Write start or image buffer address to the FPGA
low = pci_dma_l(image_buffer);
low &= 0xfffffffc;
high = pci_dma_h(image_buffer);
if(high != 0)
low |= 0x00000001;
*(bar0_ptr + (17024/4)) = 0;
//printk("DMA Address LOW : 0x%x\n", cpu_to_le32(low));
//printk("DMA Address HIGH: 0x%x\n", cpu_to_le32(high));
*(bar0_ptr + (4096/4)) = cpu_to_le32(low); //2147483649;
*(bar0_ptr + (4100/4)) = cpu_to_le32(high);
*(bar0_ptr + (17052/4)) = cpu_to_le32(low & 0xfffffffe);//2147483648;
printk("Process Read Command: Addr:0x%x Ret:0x%x\n", 4096, *(bar0_ptr + (4096/4)));
printk("Process Read Command: Addr:0x%x Ret:0x%x\n", 4100, *(bar0_ptr + (4100/4)));
printk("Process Read Command: Addr:0x%x Ret:0x%x\n", 17052, *(bar0_ptr + (17052/4)));
return(0);
感谢您提供的任何帮助。
最佳答案
您是自己控制写入 TLP 数据包的 RTL 代码,还是可以命名您正在使用的 DMA 引擎和 PCIe BFM(总线功能模型)?您的数据包在模拟器中是什么样子的?大多数体面的 BFM 应该捕获它,而不是让你在部署后使用 PCIe 硬件捕获系统找到它。
要定位上部 2GB RAM,您需要从设备发送 2DW(64 位)地址。您的 Fmt/Type 中的位是否设置为执行此操作?故障地址看起来像一个屏蔽的 32 位总线地址,因此这个级别的某些内容可能不正确。还要记住,因为 PCIe 是大端模式,所以在将目标地址写入 PCIe 设备端点时要小心。如果 Fmt 不正确,您可能会将目标地址的较低字节放入有效负载中 - 同样,体面的 BFM 应该会发现生成的数据包长度不匹配。
如果你有最新的主板/现代 CPU,PCIe 端点应该执行 PCIe AER(高级错误报告),所以如果运行最近的 Centos/RHEL 6.3,你应该得到端点的 dmesg
报告故障。这非常有用,因为报告将数据包的第一批 DW 捕获到特殊捕获寄存器,因此您可以查看收到的 TLP。
在您的内核驱动程序中,我看到您设置了 DMA 掩码,这还不够,因为您没有对 mmu 进行编程以允许从设备写入页面。查看 pci_alloc_consistent()
的实现,看看您还应该调用什么来实现这一点。
关于Linux 设备驱动程序允许 FPGA 直接通过 DMA 访问 CPU RAM,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11250739/
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我相信在大学时我用从 C 派生的语言为 FPGA 编写了一个程序。我了解 VHDL 和 verilog 等语言。但是,我不明白的是程序员在使用哪个方面有多少选择?它依赖于FPGA吗?我将使用 Xili
在设计 FPGA 系统时,我如何粗略估计给定任务所需的逻辑 block 数量? 有人对我对这些常见设备的期望有一个粗略的数量级吗? 串口 使用 CRC32 的数据包解帧器 8 微核 我看过 www.o
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我是编程和 FPGA 的新手。我喜欢在我的 Windows 10 PC 上运行一个程序,并喜欢将输入发送到 FPGA,当处理完成后,我喜欢接收输出到同一个程序。是否可能以及如何实现。我需要一些指导才能
我有一个基本问题。我为一些媒体应用程序制作了一些 FPGA 图像和 现在我想在性能和面积方面将我的结果与相同算法的 ASIC 实现的结果进行比较。我听说这样的比较没有意义,因为它有点比较苹果和橘子。但
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我正在用一个小算法修改固件文件 (.jic) JTAG 间接配置文件,但更改文件内的数据使其无法使用,因为文件中某处有一个校验和必须更新。 我需要找到 .jic 文件中的校验和在哪里,并破译使用的算法
我想通过 Xilinx FPGA 的 MGT channel 发送信号(不管是什么类型的信号,只是随机二进制)。这是用于测试 PCB 上的 MGT 走线。我可以实现这一目标的最简单方法是什么?对于常规
我正在使用 Xilinx ISE 14.7 合成器。我能够使用 .coe 文件初始化我的 BRAM 并访问它。我也可以使用 data2mem 工具用新的 .mem 文件更新它并更新我的位文件。这里我已
我在使用 Lattice ICE5LP4K 的内部振荡器时遇到问题。根据 iCE40 振荡器使用指南附录,verilog 中的代码应如下所示: SB_HFOSC OSCInst0 (
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 12 个月
我正在尝试在 FPGA 和 x86_64 Linux 机器之间进行 DMA 传输。 在 PC 端,我正在做这个初始化: //driver probe ... pci_set_master(dev);
Xilinx FPGA 中的“切片寄存器”和“切片 LUT”有什么区别? 为什么在 Vertix 5 中切片寄存器的数量等于切片 LUT 的数量,但在 Vertix 6 和 Vertix 7 中切片寄
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 想改进这个问题?将问题更新为 on-topic对于堆栈溢出。 5年前关闭。 Improve this qu
这是平行线: http://anycpu.org/forum/viewtopic.php?f=13&t=66 它有 64 个内核、1GB RAM、运行 Linux、以太网——每个人都在为它大喊大叫..
我正在设计一个基于 xilinx fpga 上的 microblaze 微处理器的微 Controller 。大部分硬件设置已完成。此时我正在更新的是要在 microblaze 上运行的 c 代码。在
在进行时钟域转换(速率匹配)时,我们通常将数据翻倍以避免亚稳态。双翻牌只会降低亚稳的概率。三重翻牌将进一步减少它。 如何计算亚稳定性和使用的时钟域触发器数量之间的概率/关系? 最佳答案 亚稳定性查询的
我知道在使用这些输入之前需要将所有输入同步到 FPGA 以避免亚稳态。我还意识到需要在单个 FPGA 中同步跨时钟域的信号。这个问题与跨越时钟域无关。 我的问题是定期注册 是否是个好主意?全部 的输入
我是一名优秀的程序员,十分优秀!