DMA for PCIe
by drakonof from LinuxQuestions.org on (#52QN7)
Hi all!
Could you say please, what I am doing wrong?
Debian 10.
I am trying send data through PCIe + DMA. But I cannot fill sending array correctly. The data which I send from a host are received not which that I expect.
Code:#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
// cdma regs
#define CDMACR 0x00
#define CDMASR 0x04
#define CURDESC_PNTR 0x08
#define CURDESC_PNTR_MSB 0x0C
#define TAILDESC_PNTR 0x10
#define TAILDESC_PNTR_MSB 0x14
#define SA 0x18
#define SA_MSB 0x1C
#define DA 0x20
#define DA_MSB 0x24
#define BTT 0x28
#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;
}
// filling test array by const
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);
// filling device pcie regs by phys host memory
pci_reg_mem[0x208/4]=(dma_handle >> 32);
pci_reg_mem[0x20c/4]=(dma_handle & 0xFFFFFFFF);
// filling cdma regs
cdma_reg_mem[0x18/4]=0x30000000;
cdma_reg_mem[0x20/4]=0x80000000;
cdma_reg_mem[0x28/4]=256;
// checking received data
for(i = 0; i < 240; i++)
{
printk(KERN_INFO "%d. DDR %X vs ADDR %X\n",i,ddr_mem[i], *(u8*) (dmabuf + i));
}
printk(KERN_INFO "dma %llX\n",dma_handle);
printk(KERN_INFO "AXIU %X\n",pci_reg_mem[0x208/4]);
printk(KERN_INFO "AXIL %X\n",pci_reg_mem[0x20C/4]);
printk(KERN_INFO "SA %X\n",cdma_reg_mem[0x18/4]);
printk(KERN_INFO "DA %X\n",cdma_reg_mem[0x20/4]);
printk(KERN_INFO "SR %X\n",cdma_reg_mem[0x4/4]);
cdma_reg_mem[0x4/4] = 0x1000;
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;
}Thank you in advance!


Could you say please, what I am doing wrong?
Debian 10.
I am trying send data through PCIe + DMA. But I cannot fill sending array correctly. The data which I send from a host are received not which that I expect.
Code:#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
// cdma regs
#define CDMACR 0x00
#define CDMASR 0x04
#define CURDESC_PNTR 0x08
#define CURDESC_PNTR_MSB 0x0C
#define TAILDESC_PNTR 0x10
#define TAILDESC_PNTR_MSB 0x14
#define SA 0x18
#define SA_MSB 0x1C
#define DA 0x20
#define DA_MSB 0x24
#define BTT 0x28
#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;
}
// filling test array by const
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);
// filling device pcie regs by phys host memory
pci_reg_mem[0x208/4]=(dma_handle >> 32);
pci_reg_mem[0x20c/4]=(dma_handle & 0xFFFFFFFF);
// filling cdma regs
cdma_reg_mem[0x18/4]=0x30000000;
cdma_reg_mem[0x20/4]=0x80000000;
cdma_reg_mem[0x28/4]=256;
// checking received data
for(i = 0; i < 240; i++)
{
printk(KERN_INFO "%d. DDR %X vs ADDR %X\n",i,ddr_mem[i], *(u8*) (dmabuf + i));
}
printk(KERN_INFO "dma %llX\n",dma_handle);
printk(KERN_INFO "AXIU %X\n",pci_reg_mem[0x208/4]);
printk(KERN_INFO "AXIL %X\n",pci_reg_mem[0x20C/4]);
printk(KERN_INFO "SA %X\n",cdma_reg_mem[0x18/4]);
printk(KERN_INFO "DA %X\n",cdma_reg_mem[0x20/4]);
printk(KERN_INFO "SR %X\n",cdma_reg_mem[0x4/4]);
cdma_reg_mem[0x4/4] = 0x1000;
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;
}Thank you in advance!