int dma_alloc_descriptor_ring(DMA_DescriptorRing_t *ring, /* */ int numDescriptors /* */ ) { size_t bytesToAlloc = dmacHw_descriptorLen(numDescriptors); if ((ring == NULL) || (numDescriptors <= 0)) { return -EINVAL; } ring->physAddr = 0; ring->descriptorsAllocated = 0; ring->bytesAllocated = 0; ring->virtAddr = dma_alloc_writecombine(NULL, bytesToAlloc, &ring->physAddr, GFP_KERNEL); if (ring->virtAddr == NULL) { return -ENOMEM; } ring->bytesAllocated = bytesToAlloc; ring->descriptorsAllocated = numDescriptors; return dma_init_descriptor_ring(ring, numDescriptors); }
int dmacHw_initDescriptor(void *pDescriptorVirt, /* [ IN ] Virtual address of uncahced buffer allocated to form descriptor ring */ uint32_t descriptorPhyAddr, /* [ IN ] Physical address of pDescriptorVirt (descriptor buffer) */ uint32_t len, /* [ IN ] Size of the pBuf */ uint32_t num /* [ IN ] Number of descriptor in the ring */ ) { uint32_t i; dmacHw_DESC_RING_t *pRing; dmacHw_DESC_t *pDesc; /* Check the alignment of the descriptor */ if ((uint32_t) pDescriptorVirt & 0x00000003) { dmacHw_ASSERT(0); return -1; } /* Check if enough space has been allocated for descriptor ring */ if (len < dmacHw_descriptorLen(num)) { return -1; } pRing = dmacHw_GET_DESC_RING(pDescriptorVirt); pRing->pHead = (dmacHw_DESC_t *) ((uint32_t) pRing + sizeof(dmacHw_DESC_RING_t)); pRing->pFree = pRing->pTail = pRing->pEnd = pRing->pHead; pRing->pProg = dmacHw_DESC_INIT; /* Initialize link item chain, starting from the head */ pDesc = pRing->pHead; /* Find the offset between virtual to physical address */ pRing->virt2PhyOffset = (uint32_t) pDescriptorVirt - descriptorPhyAddr; /* Form the descriptor ring */ for (i = 0; i < num - 1; i++) { /* Clear link list item */ memset((void *)pDesc, 0, sizeof(dmacHw_DESC_t)); /* Point to the next item in the physical address */ pDesc->llpPhy = (uint32_t) (pDesc + 1) - pRing->virt2PhyOffset; /* Point to the next item in the virtual address */ pDesc->llp = (uint32_t) (pDesc + 1); /* Mark descriptor is ready to use */ pDesc->ctl.hi = dmacHw_DESC_FREE; /* Look into next link list item */ pDesc++; } /* Clear last link list item */ memset((void *)pDesc, 0, sizeof(dmacHw_DESC_t)); /* Last item pointing to the first item in the physical address to complete the ring */ pDesc->llpPhy = (uint32_t) pRing->pHead - pRing->virt2PhyOffset; /* Last item pointing to the first item in the virtual address to complete the ring */ pDesc->llp = (uint32_t) pRing->pHead; /* Mark descriptor is ready to use */ pDesc->ctl.hi = dmacHw_DESC_FREE; /* Set the number of descriptors in the ring */ pRing->num = num; return 0; }
int dmacHw_initDescriptor(void *pDescriptorVirt, uint32_t descriptorPhyAddr, uint32_t len, uint32_t num ) { uint32_t i; dmacHw_DESC_RING_t *pRing; dmacHw_DESC_t *pDesc; if ((uint32_t) pDescriptorVirt & 0x00000003) { dmacHw_ASSERT(0); return -1; } if (len < dmacHw_descriptorLen(num)) { return -1; } pRing = dmacHw_GET_DESC_RING(pDescriptorVirt); pRing->pHead = (dmacHw_DESC_t *) ((uint32_t) pRing + sizeof(dmacHw_DESC_RING_t)); pRing->pFree = pRing->pTail = pRing->pEnd = pRing->pHead; pRing->pProg = dmacHw_DESC_INIT; pDesc = pRing->pHead; pRing->virt2PhyOffset = (uint32_t) pDescriptorVirt - descriptorPhyAddr; for (i = 0; i < num - 1; i++) { memset((void *)pDesc, 0, sizeof(dmacHw_DESC_t)); pDesc->llpPhy = (uint32_t) (pDesc + 1) - pRing->virt2PhyOffset; pDesc->llp = (uint32_t) (pDesc + 1); pDesc->ctl.hi = dmacHw_DESC_FREE; pDesc++; } memset((void *)pDesc, 0, sizeof(dmacHw_DESC_t)); pDesc->llpPhy = (uint32_t) pRing->pHead - pRing->virt2PhyOffset; pDesc->llp = (uint32_t) pRing->pHead; pDesc->ctl.hi = dmacHw_DESC_FREE; pRing->num = num; return 0; }
int dma_alloc_double_dst_descriptors(DMA_Handle_t handle, /* */ dma_addr_t srcData, /* */ dma_addr_t dstData1, /* */ dma_addr_t dstData2, /* */ size_t numBytes /* */ ) { DMA_Channel_t *channel; DMA_DeviceAttribute_t *devAttr; int numDst1Descriptors; int numDst2Descriptors; int numDescriptors; size_t ringBytesRequired; int rc = 0; channel = HandleToChannel(handle); if (channel == NULL) { return -ENODEV; } devAttr = &DMA_gDeviceAttribute[channel->devType]; /* */ /* */ /* */ numDst1Descriptors = dmacHw_calculateDescriptorCount(&devAttr->config, (void *)srcData, (void *)dstData1, numBytes); if (numDst1Descriptors < 0) { return -EINVAL; } numDst2Descriptors = dmacHw_calculateDescriptorCount(&devAttr->config, (void *)srcData, (void *)dstData2, numBytes); if (numDst2Descriptors < 0) { return -EINVAL; } numDescriptors = numDst1Descriptors + numDst2Descriptors; /* */ /* */ /* */ ringBytesRequired = dmacHw_descriptorLen(numDescriptors); /* */ if (ringBytesRequired > devAttr->ring.bytesAllocated) { /* */ /* */ /* */ might_sleep(); /* */ dma_free_descriptor_ring(&devAttr->ring); /* */ rc = dma_alloc_descriptor_ring(&devAttr->ring, numDescriptors); if (rc < 0) { printk(KERN_ERR "%s: dma_alloc_descriptor_ring(%d) failed\n", __func__, ringBytesRequired); return rc; } } /* */ /* */ /* */ if (dmacHw_initDescriptor(devAttr->ring.virtAddr, devAttr->ring.physAddr, devAttr->ring.bytesAllocated, numDescriptors) < 0) { printk(KERN_ERR "%s: dmacHw_initDescriptor failed\n", __func__); return -EINVAL; } /* */ /* */ if (dmacHw_setDataDescriptor(&devAttr->config, devAttr->ring.virtAddr, (void *)srcData, (void *)dstData1, numBytes) < 0) { printk(KERN_ERR "%s: dmacHw_setDataDescriptor 1 failed\n", __func__); return -EINVAL; } if (dmacHw_setDataDescriptor(&devAttr->config, devAttr->ring.virtAddr, (void *)srcData, (void *)dstData2, numBytes) < 0) { printk(KERN_ERR "%s: dmacHw_setDataDescriptor 2 failed\n", __func__); return -EINVAL; } /* */ /* */ devAttr->prevSrcData = 0; devAttr->prevDstData = 0; devAttr->prevNumBytes = 0; return numDescriptors; }
int dma_alloc_descriptors(DMA_Handle_t handle, /* */ dmacHw_TRANSFER_TYPE_e transferType, /* */ dma_addr_t srcData, /* */ dma_addr_t dstData, /* */ size_t numBytes /* */ ) { DMA_Channel_t *channel; DMA_DeviceAttribute_t *devAttr; int numDescriptors; size_t ringBytesRequired; int rc = 0; channel = HandleToChannel(handle); if (channel == NULL) { return -ENODEV; } devAttr = &DMA_gDeviceAttribute[channel->devType]; if (devAttr->config.transferType != transferType) { return -EINVAL; } /* */ /* */ /* */ numDescriptors = dmacHw_calculateDescriptorCount(&devAttr->config, (void *)srcData, (void *)dstData, numBytes); if (numDescriptors < 0) { printk(KERN_ERR "%s: dmacHw_calculateDescriptorCount failed\n", __func__); return -EINVAL; } /* */ /* */ ringBytesRequired = dmacHw_descriptorLen(numDescriptors); /* */ if (ringBytesRequired > devAttr->ring.bytesAllocated) { /* */ /* */ /* */ might_sleep(); /* */ dma_free_descriptor_ring(&devAttr->ring); /* */ rc = dma_alloc_descriptor_ring(&devAttr->ring, numDescriptors); if (rc < 0) { printk(KERN_ERR "%s: dma_alloc_descriptor_ring(%d) failed\n", __func__, numDescriptors); return rc; } /* */ if (dmacHw_initDescriptor(devAttr->ring.virtAddr, devAttr->ring.physAddr, devAttr->ring.bytesAllocated, numDescriptors) < 0) { printk(KERN_ERR "%s: dmacHw_initDescriptor failed\n", __func__); return -EINVAL; } } else { /* */ /* */ dmacHw_resetDescriptorControl(devAttr->ring.virtAddr); } /* */ /* */ if (dmacHw_setDataDescriptor(&devAttr->config, devAttr->ring.virtAddr, (void *)srcData, (void *)dstData, numBytes) < 0) { printk(KERN_ERR "%s: dmacHw_setDataDescriptor failed\n", __func__); return -EINVAL; } /* */ /* */ devAttr->prevSrcData = srcData; devAttr->prevDstData = dstData; devAttr->prevNumBytes = numBytes; return 0; }
int dma_alloc_double_dst_descriptors(DMA_Handle_t handle, /* DMA Handle */ dma_addr_t srcData, /* Physical address of source data */ dma_addr_t dstData1, /* Physical address of first destination buffer */ dma_addr_t dstData2, /* Physical address of second destination buffer */ size_t numBytes /* Number of bytes in each destination buffer */ ) { DMA_Channel_t *channel; DMA_DeviceAttribute_t *devAttr; int numDst1Descriptors; int numDst2Descriptors; int numDescriptors; size_t ringBytesRequired; int rc = 0; channel = HandleToChannel(handle); if (channel == NULL) { return -ENODEV; } devAttr = &DMA_gDeviceAttribute[channel->devType]; /* Figure out how many descriptors we need. */ /* printk("srcData: 0x%08x dstData: 0x%08x, numBytes: %d\n", */ /* srcData, dstData, numBytes); */ numDst1Descriptors = dmacHw_calculateDescriptorCount(&devAttr->config, (void *)srcData, (void *)dstData1, numBytes); if (numDst1Descriptors < 0) { return -EINVAL; } numDst2Descriptors = dmacHw_calculateDescriptorCount(&devAttr->config, (void *)srcData, (void *)dstData2, numBytes); if (numDst2Descriptors < 0) { return -EINVAL; } numDescriptors = numDst1Descriptors + numDst2Descriptors; /* printk("numDescriptors: %d\n", numDescriptors); */ /* Check to see if we can reuse the existing descriptor ring, or if we need to allocate */ /* a new one. */ ringBytesRequired = dmacHw_descriptorLen(numDescriptors); /* printk("ringBytesRequired: %d\n", ringBytesRequired); */ if (ringBytesRequired > devAttr->ring.bytesAllocated) { /* Make sure that this code path is never taken from interrupt context. */ /* It's OK for an interrupt to initiate a DMA transfer, but the descriptor */ /* allocation needs to have already been done. */ might_sleep(); /* Free the old descriptor ring and allocate a new one. */ dma_free_descriptor_ring(&devAttr->ring); /* And allocate a new one. */ rc = dma_alloc_descriptor_ring(&devAttr->ring, numDescriptors); if (rc < 0) { printk(KERN_ERR "%s: dma_alloc_descriptor_ring(%d) failed\n", __func__, ringBytesRequired); return rc; } } /* Setup the descriptor for this transfer. Since this function is used with */ /* CONTINUOUS DMA operations, we need to reinitialize every time, otherwise */ /* setDataDescriptor will keep trying to append onto the end. */ if (dmacHw_initDescriptor(devAttr->ring.virtAddr, devAttr->ring.physAddr, devAttr->ring.bytesAllocated, numDescriptors) < 0) { printk(KERN_ERR "%s: dmacHw_initDescriptor failed\n", __func__); return -EINVAL; } /* dma_alloc/free both set the prevSrc/DstData to 0. If they happen to be the same */ /* as last time, then we don't need to call setDataDescriptor again. */ if (dmacHw_setDataDescriptor(&devAttr->config, devAttr->ring.virtAddr, (void *)srcData, (void *)dstData1, numBytes) < 0) { printk(KERN_ERR "%s: dmacHw_setDataDescriptor 1 failed\n", __func__); return -EINVAL; } if (dmacHw_setDataDescriptor(&devAttr->config, devAttr->ring.virtAddr, (void *)srcData, (void *)dstData2, numBytes) < 0) { printk(KERN_ERR "%s: dmacHw_setDataDescriptor 2 failed\n", __func__); return -EINVAL; } /* You should use dma_start_transfer rather than dma_transfer_xxx so we don't */ /* try to make the 'prev' variables right. */ devAttr->prevSrcData = 0; devAttr->prevDstData = 0; devAttr->prevNumBytes = 0; return numDescriptors; }
int dma_alloc_descriptors(DMA_Handle_t handle, /* DMA Handle */ dmacHw_TRANSFER_TYPE_e transferType, /* Type of transfer being performed */ dma_addr_t srcData, /* Place to get data to write to device */ dma_addr_t dstData, /* Pointer to device data address */ size_t numBytes /* Number of bytes to transfer to the device */ ) { DMA_Channel_t *channel; DMA_DeviceAttribute_t *devAttr; int numDescriptors; size_t ringBytesRequired; int rc = 0; channel = HandleToChannel(handle); if (channel == NULL) { return -ENODEV; } devAttr = &DMA_gDeviceAttribute[channel->devType]; if (devAttr->config.transferType != transferType) { return -EINVAL; } /* Figure out how many descriptors we need. */ /* printk("srcData: 0x%08x dstData: 0x%08x, numBytes: %d\n", */ /* srcData, dstData, numBytes); */ numDescriptors = dmacHw_calculateDescriptorCount(&devAttr->config, (void *)srcData, (void *)dstData, numBytes); if (numDescriptors < 0) { printk(KERN_ERR "%s: dmacHw_calculateDescriptorCount failed\n", __func__); return -EINVAL; } /* Check to see if we can reuse the existing descriptor ring, or if we need to allocate */ /* a new one. */ ringBytesRequired = dmacHw_descriptorLen(numDescriptors); /* printk("ringBytesRequired: %d\n", ringBytesRequired); */ if (ringBytesRequired > devAttr->ring.bytesAllocated) { /* Make sure that this code path is never taken from interrupt context. */ /* It's OK for an interrupt to initiate a DMA transfer, but the descriptor */ /* allocation needs to have already been done. */ might_sleep(); /* Free the old descriptor ring and allocate a new one. */ dma_free_descriptor_ring(&devAttr->ring); /* And allocate a new one. */ rc = dma_alloc_descriptor_ring(&devAttr->ring, numDescriptors); if (rc < 0) { printk(KERN_ERR "%s: dma_alloc_descriptor_ring(%d) failed\n", __func__, numDescriptors); return rc; } /* Setup the descriptor for this transfer */ if (dmacHw_initDescriptor(devAttr->ring.virtAddr, devAttr->ring.physAddr, devAttr->ring.bytesAllocated, numDescriptors) < 0) { printk(KERN_ERR "%s: dmacHw_initDescriptor failed\n", __func__); return -EINVAL; } } else { /* We've already got enough ring buffer allocated. All we need to do is reset */ /* any control information, just in case the previous DMA was stopped. */ dmacHw_resetDescriptorControl(devAttr->ring.virtAddr); } /* dma_alloc/free both set the prevSrc/DstData to 0. If they happen to be the same */ /* as last time, then we don't need to call setDataDescriptor again. */ if (dmacHw_setDataDescriptor(&devAttr->config, devAttr->ring.virtAddr, (void *)srcData, (void *)dstData, numBytes) < 0) { printk(KERN_ERR "%s: dmacHw_setDataDescriptor failed\n", __func__); return -EINVAL; } /* Remember the critical information for this transfer so that we can eliminate */ /* another call to dma_alloc_descriptors if the caller reuses the same buffers */ devAttr->prevSrcData = srcData; devAttr->prevDstData = dstData; devAttr->prevNumBytes = numBytes; return 0; }