150437bff7f7374f86837986f66e15e73a364f894Russell King/* 250437bff7f7374f86837986f66e15e73a364f894Russell King * Virtual DMA channel support for DMAengine 350437bff7f7374f86837986f66e15e73a364f894Russell King * 450437bff7f7374f86837986f66e15e73a364f894Russell King * Copyright (C) 2012 Russell King 550437bff7f7374f86837986f66e15e73a364f894Russell King * 650437bff7f7374f86837986f66e15e73a364f894Russell King * This program is free software; you can redistribute it and/or modify 750437bff7f7374f86837986f66e15e73a364f894Russell King * it under the terms of the GNU General Public License version 2 as 850437bff7f7374f86837986f66e15e73a364f894Russell King * published by the Free Software Foundation. 950437bff7f7374f86837986f66e15e73a364f894Russell King */ 1050437bff7f7374f86837986f66e15e73a364f894Russell King#include <linux/device.h> 1150437bff7f7374f86837986f66e15e73a364f894Russell King#include <linux/dmaengine.h> 1250437bff7f7374f86837986f66e15e73a364f894Russell King#include <linux/module.h> 1350437bff7f7374f86837986f66e15e73a364f894Russell King#include <linux/spinlock.h> 1450437bff7f7374f86837986f66e15e73a364f894Russell King 1550437bff7f7374f86837986f66e15e73a364f894Russell King#include "virt-dma.h" 1650437bff7f7374f86837986f66e15e73a364f894Russell King 1750437bff7f7374f86837986f66e15e73a364f894Russell Kingstatic struct virt_dma_desc *to_virt_desc(struct dma_async_tx_descriptor *tx) 1850437bff7f7374f86837986f66e15e73a364f894Russell King{ 1950437bff7f7374f86837986f66e15e73a364f894Russell King return container_of(tx, struct virt_dma_desc, tx); 2050437bff7f7374f86837986f66e15e73a364f894Russell King} 2150437bff7f7374f86837986f66e15e73a364f894Russell King 2250437bff7f7374f86837986f66e15e73a364f894Russell Kingdma_cookie_t vchan_tx_submit(struct dma_async_tx_descriptor *tx) 2350437bff7f7374f86837986f66e15e73a364f894Russell King{ 2450437bff7f7374f86837986f66e15e73a364f894Russell King struct virt_dma_chan *vc = to_virt_chan(tx->chan); 2550437bff7f7374f86837986f66e15e73a364f894Russell King struct virt_dma_desc *vd = to_virt_desc(tx); 2650437bff7f7374f86837986f66e15e73a364f894Russell King unsigned long flags; 2750437bff7f7374f86837986f66e15e73a364f894Russell King dma_cookie_t cookie; 2850437bff7f7374f86837986f66e15e73a364f894Russell King 2950437bff7f7374f86837986f66e15e73a364f894Russell King spin_lock_irqsave(&vc->lock, flags); 3050437bff7f7374f86837986f66e15e73a364f894Russell King cookie = dma_cookie_assign(tx); 3150437bff7f7374f86837986f66e15e73a364f894Russell King 3250437bff7f7374f86837986f66e15e73a364f894Russell King list_add_tail(&vd->node, &vc->desc_submitted); 3350437bff7f7374f86837986f66e15e73a364f894Russell King spin_unlock_irqrestore(&vc->lock, flags); 3450437bff7f7374f86837986f66e15e73a364f894Russell King 3550437bff7f7374f86837986f66e15e73a364f894Russell King dev_dbg(vc->chan.device->dev, "vchan %p: txd %p[%x]: submitted\n", 3650437bff7f7374f86837986f66e15e73a364f894Russell King vc, vd, cookie); 3750437bff7f7374f86837986f66e15e73a364f894Russell King 3850437bff7f7374f86837986f66e15e73a364f894Russell King return cookie; 3950437bff7f7374f86837986f66e15e73a364f894Russell King} 4050437bff7f7374f86837986f66e15e73a364f894Russell KingEXPORT_SYMBOL_GPL(vchan_tx_submit); 4150437bff7f7374f86837986f66e15e73a364f894Russell King 42fe045874aaf4480386c65baf1acae82af4c5e21fRussell Kingstruct virt_dma_desc *vchan_find_desc(struct virt_dma_chan *vc, 43fe045874aaf4480386c65baf1acae82af4c5e21fRussell King dma_cookie_t cookie) 44fe045874aaf4480386c65baf1acae82af4c5e21fRussell King{ 45fe045874aaf4480386c65baf1acae82af4c5e21fRussell King struct virt_dma_desc *vd; 46fe045874aaf4480386c65baf1acae82af4c5e21fRussell King 47fe045874aaf4480386c65baf1acae82af4c5e21fRussell King list_for_each_entry(vd, &vc->desc_issued, node) 48fe045874aaf4480386c65baf1acae82af4c5e21fRussell King if (vd->tx.cookie == cookie) 49fe045874aaf4480386c65baf1acae82af4c5e21fRussell King return vd; 50fe045874aaf4480386c65baf1acae82af4c5e21fRussell King 51fe045874aaf4480386c65baf1acae82af4c5e21fRussell King return NULL; 52fe045874aaf4480386c65baf1acae82af4c5e21fRussell King} 53fe045874aaf4480386c65baf1acae82af4c5e21fRussell KingEXPORT_SYMBOL_GPL(vchan_find_desc); 54fe045874aaf4480386c65baf1acae82af4c5e21fRussell King 5550437bff7f7374f86837986f66e15e73a364f894Russell King/* 5650437bff7f7374f86837986f66e15e73a364f894Russell King * This tasklet handles the completion of a DMA descriptor by 5750437bff7f7374f86837986f66e15e73a364f894Russell King * calling its callback and freeing it. 5850437bff7f7374f86837986f66e15e73a364f894Russell King */ 5950437bff7f7374f86837986f66e15e73a364f894Russell Kingstatic void vchan_complete(unsigned long arg) 6050437bff7f7374f86837986f66e15e73a364f894Russell King{ 6150437bff7f7374f86837986f66e15e73a364f894Russell King struct virt_dma_chan *vc = (struct virt_dma_chan *)arg; 62571fa74034701391b1be2ad193f684acfdeb75d1Russell King struct virt_dma_desc *vd; 63571fa74034701391b1be2ad193f684acfdeb75d1Russell King dma_async_tx_callback cb = NULL; 64571fa74034701391b1be2ad193f684acfdeb75d1Russell King void *cb_data = NULL; 6550437bff7f7374f86837986f66e15e73a364f894Russell King LIST_HEAD(head); 6650437bff7f7374f86837986f66e15e73a364f894Russell King 6750437bff7f7374f86837986f66e15e73a364f894Russell King spin_lock_irq(&vc->lock); 6850437bff7f7374f86837986f66e15e73a364f894Russell King list_splice_tail_init(&vc->desc_completed, &head); 69571fa74034701391b1be2ad193f684acfdeb75d1Russell King vd = vc->cyclic; 70571fa74034701391b1be2ad193f684acfdeb75d1Russell King if (vd) { 71571fa74034701391b1be2ad193f684acfdeb75d1Russell King vc->cyclic = NULL; 72571fa74034701391b1be2ad193f684acfdeb75d1Russell King cb = vd->tx.callback; 73571fa74034701391b1be2ad193f684acfdeb75d1Russell King cb_data = vd->tx.callback_param; 74571fa74034701391b1be2ad193f684acfdeb75d1Russell King } 7550437bff7f7374f86837986f66e15e73a364f894Russell King spin_unlock_irq(&vc->lock); 7650437bff7f7374f86837986f66e15e73a364f894Russell King 77571fa74034701391b1be2ad193f684acfdeb75d1Russell King if (cb) 78571fa74034701391b1be2ad193f684acfdeb75d1Russell King cb(cb_data); 79571fa74034701391b1be2ad193f684acfdeb75d1Russell King 8050437bff7f7374f86837986f66e15e73a364f894Russell King while (!list_empty(&head)) { 81571fa74034701391b1be2ad193f684acfdeb75d1Russell King vd = list_first_entry(&head, struct virt_dma_desc, node); 82571fa74034701391b1be2ad193f684acfdeb75d1Russell King cb = vd->tx.callback; 83571fa74034701391b1be2ad193f684acfdeb75d1Russell King cb_data = vd->tx.callback_param; 8450437bff7f7374f86837986f66e15e73a364f894Russell King 8550437bff7f7374f86837986f66e15e73a364f894Russell King list_del(&vd->node); 8650437bff7f7374f86837986f66e15e73a364f894Russell King 8750437bff7f7374f86837986f66e15e73a364f894Russell King vc->desc_free(vd); 8850437bff7f7374f86837986f66e15e73a364f894Russell King 8950437bff7f7374f86837986f66e15e73a364f894Russell King if (cb) 9050437bff7f7374f86837986f66e15e73a364f894Russell King cb(cb_data); 9150437bff7f7374f86837986f66e15e73a364f894Russell King } 9250437bff7f7374f86837986f66e15e73a364f894Russell King} 9350437bff7f7374f86837986f66e15e73a364f894Russell King 9450437bff7f7374f86837986f66e15e73a364f894Russell Kingvoid vchan_dma_desc_free_list(struct virt_dma_chan *vc, struct list_head *head) 9550437bff7f7374f86837986f66e15e73a364f894Russell King{ 9650437bff7f7374f86837986f66e15e73a364f894Russell King while (!list_empty(head)) { 9750437bff7f7374f86837986f66e15e73a364f894Russell King struct virt_dma_desc *vd = list_first_entry(head, 9850437bff7f7374f86837986f66e15e73a364f894Russell King struct virt_dma_desc, node); 9950437bff7f7374f86837986f66e15e73a364f894Russell King list_del(&vd->node); 10050437bff7f7374f86837986f66e15e73a364f894Russell King dev_dbg(vc->chan.device->dev, "txd %p: freeing\n", vd); 10150437bff7f7374f86837986f66e15e73a364f894Russell King vc->desc_free(vd); 10250437bff7f7374f86837986f66e15e73a364f894Russell King } 10350437bff7f7374f86837986f66e15e73a364f894Russell King} 10450437bff7f7374f86837986f66e15e73a364f894Russell KingEXPORT_SYMBOL_GPL(vchan_dma_desc_free_list); 10550437bff7f7374f86837986f66e15e73a364f894Russell King 10650437bff7f7374f86837986f66e15e73a364f894Russell Kingvoid vchan_init(struct virt_dma_chan *vc, struct dma_device *dmadev) 10750437bff7f7374f86837986f66e15e73a364f894Russell King{ 10850437bff7f7374f86837986f66e15e73a364f894Russell King dma_cookie_init(&vc->chan); 10950437bff7f7374f86837986f66e15e73a364f894Russell King 11050437bff7f7374f86837986f66e15e73a364f894Russell King spin_lock_init(&vc->lock); 11150437bff7f7374f86837986f66e15e73a364f894Russell King INIT_LIST_HEAD(&vc->desc_submitted); 11250437bff7f7374f86837986f66e15e73a364f894Russell King INIT_LIST_HEAD(&vc->desc_issued); 11350437bff7f7374f86837986f66e15e73a364f894Russell King INIT_LIST_HEAD(&vc->desc_completed); 11450437bff7f7374f86837986f66e15e73a364f894Russell King 11550437bff7f7374f86837986f66e15e73a364f894Russell King tasklet_init(&vc->task, vchan_complete, (unsigned long)vc); 11650437bff7f7374f86837986f66e15e73a364f894Russell King 11750437bff7f7374f86837986f66e15e73a364f894Russell King vc->chan.device = dmadev; 11850437bff7f7374f86837986f66e15e73a364f894Russell King list_add_tail(&vc->chan.device_node, &dmadev->channels); 11950437bff7f7374f86837986f66e15e73a364f894Russell King} 12050437bff7f7374f86837986f66e15e73a364f894Russell KingEXPORT_SYMBOL_GPL(vchan_init); 12150437bff7f7374f86837986f66e15e73a364f894Russell King 12250437bff7f7374f86837986f66e15e73a364f894Russell KingMODULE_AUTHOR("Russell King"); 12350437bff7f7374f86837986f66e15e73a364f894Russell KingMODULE_LICENSE("GPL"); 124