Всем привет.
Подскажите пожалуйста, что я делаю не так.
Задача: передать массив данных в ПЛИС через PCIe и DMA.
Пока данные могу слать и читать с помощью ioread и iowrite, так же можно переслать через memcry, это говорит что девайс на pci жив и с ним можно работать, dma в пределах ПЛИСА так же отлично работает.
Вот теперь пытаюсь выделить кусок физической памяти в хосте, проинитеть его тестовыми данными (я просто решил её полностью заполнить константным значением), затем передать адрес этой памяти в pcie ПЛИСА и забрать от туда данные через dma (те pcie заберет по адресу данные, положит их к себе в выделенный бар (axi bar) и даст команду dma что можно забирать и складывать в ddr.
регистры ddr и pcie ПЛИСА так же пишутся, проверял. По всей видимости, косяк в коде.
Изначально область BAR0 (axi bar) со стороны ПЛИС обнулена, область для тестовых данных в DDR я тоже зануляю по включению питания. Когда шлю данные из хоста в BAR0 (axi bar) появляются странные, но достаточно не хаотичные цифры, но отличные от тех что шлю. Это говорит о том что что-то всётаки приходит из хоста.
Посмотрите пожалуйста код и подскажите что исправить.
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include "vi_cntr.h"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Drakonof");
MODULE_DESCRIPTION("PCI");
MODULE_VERSION("0.1");
#define CDMA_BAR 0
#define PCI_BAR 1
#define DDR_BAR 2
#define DEVICE_NAME "drakonof_pci"
static dma_addr_t dma_handle = 0;
static void * dmabuf = NULL;
static volatile uint32_t *pci_reg_mem = NULL, *cdma_reg_mem = NULL;
static volatile uint32_t *ddr_mem = NULL;
static resource_size_t cdma_start,cdma_len,pci_start,pci_len,ddr_start,ddr_len;
static struct pci_device_id vi_cntr_pci_id[] = {
{ PCI_DEVICE(VI_CNTR_VENDOR, VI_CNTR_ID), },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, vi_cntr_pci_id);
static int vi_cntr_probe(struct pci_dev *pDev, const struct pci_device_id *id);
static void vi_cntr_remove(struct pci_dev *pDev);
static struct pci_driver vi_cntr_pci = {
.name = DEVICE_NAME,
.id_table = vi_cntr_pci_id,
.probe = vi_cntr_probe,
.remove = vi_cntr_remove
};
static int __init pci_init(void)
{
struct pci_dev *p_pci_dev = NULL;
if((p_pci_dev = pci_get_device(VI_CNTR_VENDOR,VI_CNTR_ID, p_pci_dev)) == NULL)
{
printk(KERN_NOTICE "PCI device not finded\n");
}
return pci_register_driver(&vi_cntr_pci);
}
static void __exit pci_exit(void)
{
pci_unregister_driver(&vi_cntr_pci);
}
static int vi_cntr_probe(struct pci_dev *p_pci_dev, const struct pci_device_id *pId)
{
u16 vendor = 0,
id = 0;
u32 i = 0;
if(pci_enable_device(p_pci_dev))
{
printk(KERN_INFO "pci_enable_device error\n");
}
pci_read_config_word(p_pci_dev, PCI_VENDOR_ID, &vendor);
pci_read_config_word(p_pci_dev, PCI_DEVICE_ID, &id);
printk(KERN_INFO "\n----------------------------------\n");
printk(KERN_INFO "Device vendor: 0x%X\nDevice id: 0x%X\n", vendor, id);
cdma_start = pci_resource_start(p_pci_dev,CDMA_BAR);
cdma_len = pci_resource_len(p_pci_dev,CDMA_BAR);
pci_start = pci_resource_start(p_pci_dev,PCI_BAR);
pci_len = pci_resource_len(p_pci_dev,PCI_BAR);
ddr_start = pci_resource_start(p_pci_dev,DDR_BAR);
ddr_len = pci_resource_len(p_pci_dev,DDR_BAR);
if(pci_set_dma_mask(p_pci_dev, DMA_BIT_MASK(64)))
{
printk(KERN_INFO "pci_set_dma_mask error.\n");
return -1;
}
if((dmabuf=dma_alloc_coherent(&p_pci_dev->dev,8192,&dma_handle,GFP_USER)) == NULL)
{
printk(KERN_INFO "dma_alloc_coherent error.\n");
return -1;
}
if(pci_request_regions(p_pci_dev, DEVICE_NAME))
{
printk(KERN_INFO "pci_request_regions error.\n");
return -1;
}
pci_set_master(p_pci_dev);
if((cdma_reg_mem = ioremap(cdma_start,cdma_len)) == NULL)
{
printk(KERN_INFO "ioremap pci_reg_mem error.\n");
return -1;
}
if((pci_reg_mem = ioremap(pci_start,pci_len)) == NULL)
{
printk(KERN_INFO "ioremap pci_reg_mem error.\n");
return -1;
}
if((ddr_mem = ioremap(ddr_start,ddr_len)) == NULL)
{
printk(KERN_INFO "ioremap pci_reg_mem error.\n");
return -1;
}
// здесь я заполняю массив для передачи константой
dma_sync_single_for_cpu(&p_pci_dev->dev, dma_handle, 8192, DMA_TO_DEVICE);
for(i = 0; i < 256; i++)
{
*(u32*)(dmabuf + i)= 0xABCDEF89;
}
dma_sync_single_for_device(&p_pci_dev->dev, dma_handle, 8192, DMA_TO_DEVICE);
// передаю адрес выделенной физической памяти в pcie ПЛИСА
pci_reg_mem[0x208/4]=(dma_handle >> 32);
pci_reg_mem[0x20c/4]=(dma_handle & 0xFFFFFFFF);
// заполняю регистры cdma ПЛИС
cdma_reg_mem[0x18/4]=0x30000000; // из BAR0 (axi bar)
cdma_reg_mem[0x20/4]=0x80000000; // в ddr
// передать 256 байт, это так же запускает копирование
// данных из BAR0 (axi bar) в ddr
cdma_reg_mem[0x28/4]=256;
// жду статуса конца передачи от cdma
i = 0;
while(!(cdma_reg_mem[0x4/4] & 0x2))
{
if(i == 100000)
{
printk(KERN_INFO "SR ERR %X\n",cdma_reg_mem[0x4/4]);
break;
}
else i++;
}
iounmap(pci_reg_mem);
iounmap(cdma_reg_mem);
iounmap(ddr_mem);
pci_release_regions(p_pci_dev);
pci_disable_device(p_pci_dev);
dma_free_coherent(&p_pci_dev->dev, 8192, dmabuf, dma_handle);
return 0;
}
Спасибо!