Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
14 years ago

Altera 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 = 8192
Then 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?