Altera_Forum
Honored Contributor
14 years agoAltera kernel module
Hello, I write kernel module for board Altera Arria 2 gx. I had problems with the table of descriptors,please help advice.
I use operating system OpenSuse 11.3 64 bit (x86_64 architecture),processor Intel Xeon. For access to a board I make mapping bar0.pcie_Altera_dev->bar=pci_iomap(dev, BAR,pcie_Altera_dev->length);//length = 8192Then I create dma buffers
pcie_Altera_dev->dma_bufs = kzalloc(sizeof(void *) * pcie_Altera_dev->dma_nrbufs, GFP_KERNEL);
if (pcie_Altera_dev->dma_bufs == NULL) goto err;
pcie_Altera_dev->dma_addrs = kzalloc(sizeof(dma_addr_t) * pcie_Altera_dev->dma_nrbufs, GFP_KERNEL);
if (pcie_Altera_dev->dma_addrs == NULL)
goto err;
for (i = 0; i < pcie_Altera_dev->dma_nrbufs; i++)
{
pcie_Altera_dev->dma_bufs = pci_alloc_consistent(pcie_Altera_dev->pci_dev,
pcie_Altera_dev->dma_buflen,
pcie_Altera_dev->dma_addrs + i);
if (pcie_Altera_dev->dma_bufs == NULL) {
ERR("can not allocate coherent DMA buffer number %d",i);
goto err;
enable msi
//enable msi
ret = pci_enable_msi(dev);
if (ret) {
MSG("Could not enable MSI interrupting");
}
//request irq
ret = request_irq(dev->irq,
pcie_Altera_interrupt,
IRQF_SHARED,
DEVICE_NAME,
pcie_Altera_dev);
static irqreturn_t pcie_Altera_interrupt(int irq, void *dev_id)
{
struct pcie_Altera *Altera_dev = (struct pcie_Altera *)dev_id;
if (!Altera_dev)
return IRQ_NONE;
Altera_dev->irqCount++;
MSG("detected irq, count = %d",Altera_dev->irqCount);
return IRQ_HANDLED;
}
I use structure which is presented in Altera Embedded Peripherals IP User Guide struct alt_avalon_sgdma_packed{ unsigned int *read_addr; unsigned int read_addr_pad; unsigned int *write_addr; unsigned int write_addr_pad; unsigned int *next; unsigned int next_pad; unsigned short bytes_to_transfer; unsigned char read_burst; /* Reserved field. Set to 0. */ unsigned char write_burst;/* Reserved field. Set to 0. */ unsigned short actual_bytes_transferred; unsigned char status; unsigned char control; }; In user guide writen: Chapter 25: Scatter-Gather DMA Controller Core Building and Updating Descriptor List Altera recommends the following method of building and updating the descriptor list: 1. Build the descriptor list and terminate the list with a non-hardware owned descriptor (OWNED_BY_HW = 0). The list can be arbitrarily long.
struct alt_avalon_sgdma_packed* desc,desc2;
desc=kcalloc(1,sizeof(struct alt_avalon_sgdma_packed), GFP_KERNEL);
desc2=kcalloc(1,sizeof(struct alt_avalon_sgdma_packed), GFP_KERNEL);
desc->read_addr=Altera_dev->dma_addrs;
desc->write_addr=Altera_dev->dma_addrs;
desc->next=virt_to_bus(desc2);//get bus address structure
desc->bytes_to_transfer=1024;
desc->read_burst=0;
desc->write_burst=0;
desc->actual_bytes_transferred=0;
desc->status=0;
desc->control=128;
desc2->read_addr=NULL;
desc2->write_addr=NULL;
desc2->next=NULL;
desc2->bytes_to_transfer=0;
desc2->read_burst=0;
desc2->write_burst=0;/* Reserved field. Set to 0. */
desc2->actual_bytes_transferred=0;
desc2->status=0;
desc2->control=0;
2. Set the interrupt IE_CHAIN_COMPLETED.
pd.Address=0x10;
pd.Value=0x8
iowrite32(pd.Value,(void*)Altera_dev->bar + pd.Address);3. Write the address of the first descriptor in the first list to the next_descriptor_pointer register and set the RUN bit to 1 to initiate transfers.
pd.Address=0x20;
pd.Value=virt_to_bus(desc);
iowrite32(pd.Value,(void*)Altera_dev->bar + pd.Address);
pd.Address=0x10;
pd.Value=0x28;
iowrite32(pd.Value,(void*)Altera_dev->bar + pd.Address);
5. When the SD-DMA controller core finishes processing the first list, an interrupt is generated. Update the next_descriptor_pointer register with the address of the first descriptor in the second list. Clear the RUN bit and the status register. Set the RUN bit back to 1 to resume transfers. But I do not get interrupted. And actual_bytes_transferred, status,other value do not change and buffers are empty. What is my mistake?