int dma_free_channel(DMA_Handle_t handle /* */ ) { int rc = 0; DMA_Channel_t *channel; DMA_DeviceAttribute_t *devAttr; if (down_interruptible(&gDMA.lock) < 0) { return -ERESTARTSYS; } channel = HandleToChannel(handle); if (channel == NULL) { rc = -EINVAL; goto out; } devAttr = &DMA_gDeviceAttribute[channel->devType]; if ((channel->flags & DMA_CHANNEL_FLAG_IS_DEDICATED) == 0) { channel->lastDevType = channel->devType; channel->devType = DMA_DEVICE_NONE; } channel->flags &= ~DMA_CHANNEL_FLAG_IN_USE; devAttr->flags &= ~DMA_DEVICE_FLAG_IN_USE; out: up(&gDMA.lock); wake_up_interruptible(&gDMA.freeChannelQ); return rc; }
static int ConfigChannel(DMA_Handle_t handle) { DMA_Channel_t *channel; DMA_DeviceAttribute_t *devAttr; int controllerIdx; channel = HandleToChannel(handle); if (channel == NULL) { return -ENODEV; } devAttr = &DMA_gDeviceAttribute[channel->devType]; controllerIdx = CONTROLLER_FROM_HANDLE(handle); if ((devAttr->flags & DMA_DEVICE_FLAG_PORT_PER_DMAC) != 0) { if (devAttr->config.transferType == dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL) { devAttr->config.dstPeripheralPort = devAttr->dmacPort[controllerIdx]; } else if (devAttr->config.transferType == dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM) { devAttr->config.srcPeripheralPort = devAttr->dmacPort[controllerIdx]; } } if (dmacHw_configChannel(channel->dmacHwHandle, &devAttr->config) != 0) { printk(KERN_ERR "ConfigChannel: dmacHw_configChannel failed\n"); return -EIO; } return 0; }
int dma_stop_transfer(DMA_Handle_t handle) { DMA_Channel_t *channel; channel = HandleToChannel(handle); if (channel == NULL) { return -ENODEV; } dmacHw_stopTransfer(channel->dmacHwHandle); return 0; }
int dma_transfer(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 rc = 0; channel = HandleToChannel(handle); if (channel == NULL) { return -ENODEV; } devAttr = &DMA_gDeviceAttribute[channel->devType]; if (devAttr->config.transferType != transferType) { return -EINVAL; } /* */ /* */ /* */ { rc = dma_alloc_descriptors(handle, transferType, srcData, dstData, numBytes); if (rc != 0) { return rc; } } /* */ devAttr->numBytes = numBytes; devAttr->transferStartTime = timer_get_tick_count(); dmacHw_initiateTransfer(channel->dmacHwHandle, &devAttr->config, devAttr->ring.virtAddr); /* */ return 0; }
int dma_transfer(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 rc = 0; channel = HandleToChannel(handle); if (channel == NULL) { return -ENODEV; } devAttr = &DMA_gDeviceAttribute[channel->devType]; if (devAttr->config.transferType != transferType) { return -EINVAL; } /* We keep track of the information about the previous request for this */ /* device, and if the attributes match, then we can use the descriptors we setup */ /* the last time, and not have to reinitialize everything. */ { rc = dma_alloc_descriptors(handle, transferType, srcData, dstData, numBytes); if (rc != 0) { return rc; } } /* And kick off the transfer */ devAttr->numBytes = numBytes; devAttr->transferStartTime = timer_get_tick_count(); dmacHw_initiateTransfer(channel->dmacHwHandle, &devAttr->config, devAttr->ring.virtAddr); /* Since we got this far, everything went successfully */ return 0; }
int dma_start_transfer(DMA_Handle_t handle) { DMA_Channel_t *channel; DMA_DeviceAttribute_t *devAttr; channel = HandleToChannel(handle); if (channel == NULL) { return -ENODEV; } devAttr = &DMA_gDeviceAttribute[channel->devType]; dmacHw_initiateTransfer(channel->dmacHwHandle, &devAttr->config, devAttr->ring.virtAddr); /* */ return 0; }
int dma_wait_transfer_done(DMA_Handle_t handle) { DMA_Channel_t *channel; dmacHw_TRANSFER_STATUS_e status; channel = HandleToChannel(handle); if (channel == NULL) { return -ENODEV; } while ((status = dmacHw_transferCompleted(channel->dmacHwHandle)) == dmacHw_TRANSFER_STATUS_BUSY) { ; } if (status == dmacHw_TRANSFER_STATUS_ERROR) { printk(KERN_ERR "%s: DMA transfer failed\n", __func__); return -EIO; } return 0; }
int dma_init(void) { int rc = 0; int controllerIdx; int channelIdx; DMA_Device_t devIdx; DMA_Channel_t *channel; DMA_Handle_t dedicatedHandle; memset(&gDMA, 0, sizeof(gDMA)); sema_init(&gDMA.lock, 0); init_waitqueue_head(&gDMA.freeChannelQ); /* */ dmacHw_initDma(); /* */ for (controllerIdx = 0; controllerIdx < DMA_NUM_CONTROLLERS; controllerIdx++) { for (channelIdx = 0; channelIdx < DMA_NUM_CHANNELS; channelIdx++) { channel = &gDMA.controller[controllerIdx].channel[channelIdx]; channel->flags = 0; channel->devType = DMA_DEVICE_NONE; channel->lastDevType = DMA_DEVICE_NONE; #if (DMA_DEBUG_TRACK_RESERVATION) channel->fileName = ""; channel->lineNum = 0; #endif channel->dmacHwHandle = dmacHw_getChannelHandle(dmacHw_MAKE_CHANNEL_ID (controllerIdx, channelIdx)); dmacHw_initChannel(channel->dmacHwHandle); } } /* */ gDMA.controller[0].channel[0].flags |= DMA_CHANNEL_FLAG_LARGE_FIFO; gDMA.controller[0].channel[1].flags |= DMA_CHANNEL_FLAG_LARGE_FIFO; gDMA.controller[1].channel[0].flags |= DMA_CHANNEL_FLAG_LARGE_FIFO; gDMA.controller[1].channel[1].flags |= DMA_CHANNEL_FLAG_LARGE_FIFO; /* */ for (devIdx = 0; devIdx < DMA_NUM_DEVICE_ENTRIES; devIdx++) { DMA_DeviceAttribute_t *devAttr = &DMA_gDeviceAttribute[devIdx]; if (((devAttr->flags & DMA_DEVICE_FLAG_NO_ISR) != 0) && ((devAttr->flags & DMA_DEVICE_FLAG_IS_DEDICATED) == 0)) { printk(KERN_ERR "DMA Device: %s Can only request NO_ISR for dedicated devices\n", devAttr->name); rc = -EINVAL; goto out; } if ((devAttr->flags & DMA_DEVICE_FLAG_IS_DEDICATED) != 0) { /* */ if (devAttr->dedicatedController >= DMA_NUM_CONTROLLERS) { printk(KERN_ERR "DMA Device: %s DMA Controller %d is out of range\n", devAttr->name, devAttr->dedicatedController); rc = -EINVAL; goto out; } if (devAttr->dedicatedChannel >= DMA_NUM_CHANNELS) { printk(KERN_ERR "DMA Device: %s DMA Channel %d is out of range\n", devAttr->name, devAttr->dedicatedChannel); rc = -EINVAL; goto out; } dedicatedHandle = MAKE_HANDLE(devAttr->dedicatedController, devAttr->dedicatedChannel); channel = HandleToChannel(dedicatedHandle); if ((channel->flags & DMA_CHANNEL_FLAG_IS_DEDICATED) != 0) { printk ("DMA Device: %s attempting to use same DMA Controller:Channel (%d:%d) as %s\n", devAttr->name, devAttr->dedicatedController, devAttr->dedicatedChannel, DMA_gDeviceAttribute[channel->devType]. name); rc = -EBUSY; goto out; } channel->flags |= DMA_CHANNEL_FLAG_IS_DEDICATED; channel->devType = devIdx; if (devAttr->flags & DMA_DEVICE_FLAG_NO_ISR) { channel->flags |= DMA_CHANNEL_FLAG_NO_ISR; } /* */ /* */ ConfigChannel(dedicatedHandle); } } /* */ for (controllerIdx = 0; controllerIdx < DMA_NUM_CONTROLLERS; controllerIdx++) { for (channelIdx = 0; channelIdx < DMA_NUM_CHANNELS; channelIdx++) { channel = &gDMA.controller[controllerIdx].channel[channelIdx]; if ((channel->flags & DMA_CHANNEL_FLAG_NO_ISR) == 0) { snprintf(channel->name, sizeof(channel->name), "dma %d:%d %s", controllerIdx, channelIdx, channel->devType == DMA_DEVICE_NONE ? "" : DMA_gDeviceAttribute[channel->devType]. name); rc = request_irq(IRQ_DMA0C0 + (controllerIdx * DMA_NUM_CHANNELS) + channelIdx, dma_interrupt_handler, IRQF_DISABLED, channel->name, channel); if (rc != 0) { printk(KERN_ERR "request_irq for IRQ_DMA%dC%d failed\n", controllerIdx, channelIdx); } } } } /* */ gDmaDir = proc_mkdir("dma", NULL); if (gDmaDir == NULL) { printk(KERN_ERR "Unable to create /proc/dma\n"); } else { create_proc_read_entry("channels", 0, gDmaDir, dma_proc_read_channels, NULL); create_proc_read_entry("devices", 0, gDmaDir, dma_proc_read_devices, NULL); } out: up(&gDMA.lock); return rc; }
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; }