162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * AMD Passthrough DMA device driver 462306a36Sopenharmony_ci * -- Based on the CCP driver 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2016,2021 Advanced Micro Devices, Inc. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Author: Sanjay R Mehta <sanju.mehta@amd.com> 962306a36Sopenharmony_ci * Author: Gary R Hook <gary.hook@amd.com> 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "ptdma.h" 1362306a36Sopenharmony_ci#include "../dmaengine.h" 1462306a36Sopenharmony_ci#include "../virt-dma.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic inline struct pt_dma_chan *to_pt_chan(struct dma_chan *dma_chan) 1762306a36Sopenharmony_ci{ 1862306a36Sopenharmony_ci return container_of(dma_chan, struct pt_dma_chan, vc.chan); 1962306a36Sopenharmony_ci} 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic inline struct pt_dma_desc *to_pt_desc(struct virt_dma_desc *vd) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci return container_of(vd, struct pt_dma_desc, vd); 2462306a36Sopenharmony_ci} 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic void pt_free_chan_resources(struct dma_chan *dma_chan) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci struct pt_dma_chan *chan = to_pt_chan(dma_chan); 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci vchan_free_chan_resources(&chan->vc); 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic void pt_synchronize(struct dma_chan *dma_chan) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci struct pt_dma_chan *chan = to_pt_chan(dma_chan); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci vchan_synchronize(&chan->vc); 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic void pt_do_cleanup(struct virt_dma_desc *vd) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci struct pt_dma_desc *desc = to_pt_desc(vd); 4362306a36Sopenharmony_ci struct pt_device *pt = desc->pt; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci kmem_cache_free(pt->dma_desc_cache, desc); 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic int pt_dma_start_desc(struct pt_dma_desc *desc) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci struct pt_passthru_engine *pt_engine; 5162306a36Sopenharmony_ci struct pt_device *pt; 5262306a36Sopenharmony_ci struct pt_cmd *pt_cmd; 5362306a36Sopenharmony_ci struct pt_cmd_queue *cmd_q; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci desc->issued_to_hw = 1; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci pt_cmd = &desc->pt_cmd; 5862306a36Sopenharmony_ci pt = pt_cmd->pt; 5962306a36Sopenharmony_ci cmd_q = &pt->cmd_q; 6062306a36Sopenharmony_ci pt_engine = &pt_cmd->passthru; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci pt->tdata.cmd = pt_cmd; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci /* Execute the command */ 6562306a36Sopenharmony_ci pt_cmd->ret = pt_core_perform_passthru(cmd_q, pt_engine); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci return 0; 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic struct pt_dma_desc *pt_next_dma_desc(struct pt_dma_chan *chan) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci /* Get the next DMA descriptor on the active list */ 7362306a36Sopenharmony_ci struct virt_dma_desc *vd = vchan_next_desc(&chan->vc); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci return vd ? to_pt_desc(vd) : NULL; 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic struct pt_dma_desc *pt_handle_active_desc(struct pt_dma_chan *chan, 7962306a36Sopenharmony_ci struct pt_dma_desc *desc) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci struct dma_async_tx_descriptor *tx_desc; 8262306a36Sopenharmony_ci struct virt_dma_desc *vd; 8362306a36Sopenharmony_ci unsigned long flags; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* Loop over descriptors until one is found with commands */ 8662306a36Sopenharmony_ci do { 8762306a36Sopenharmony_ci if (desc) { 8862306a36Sopenharmony_ci if (!desc->issued_to_hw) { 8962306a36Sopenharmony_ci /* No errors, keep going */ 9062306a36Sopenharmony_ci if (desc->status != DMA_ERROR) 9162306a36Sopenharmony_ci return desc; 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci tx_desc = &desc->vd.tx; 9562306a36Sopenharmony_ci vd = &desc->vd; 9662306a36Sopenharmony_ci } else { 9762306a36Sopenharmony_ci tx_desc = NULL; 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci spin_lock_irqsave(&chan->vc.lock, flags); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci if (desc) { 10362306a36Sopenharmony_ci if (desc->status != DMA_COMPLETE) { 10462306a36Sopenharmony_ci if (desc->status != DMA_ERROR) 10562306a36Sopenharmony_ci desc->status = DMA_COMPLETE; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci dma_cookie_complete(tx_desc); 10862306a36Sopenharmony_ci dma_descriptor_unmap(tx_desc); 10962306a36Sopenharmony_ci list_del(&desc->vd.node); 11062306a36Sopenharmony_ci } else { 11162306a36Sopenharmony_ci /* Don't handle it twice */ 11262306a36Sopenharmony_ci tx_desc = NULL; 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci desc = pt_next_dma_desc(chan); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci spin_unlock_irqrestore(&chan->vc.lock, flags); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (tx_desc) { 12162306a36Sopenharmony_ci dmaengine_desc_get_callback_invoke(tx_desc, NULL); 12262306a36Sopenharmony_ci dma_run_dependencies(tx_desc); 12362306a36Sopenharmony_ci vchan_vdesc_fini(vd); 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci } while (desc); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci return NULL; 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic void pt_cmd_callback(void *data, int err) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci struct pt_dma_desc *desc = data; 13362306a36Sopenharmony_ci struct dma_chan *dma_chan; 13462306a36Sopenharmony_ci struct pt_dma_chan *chan; 13562306a36Sopenharmony_ci int ret; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci if (err == -EINPROGRESS) 13862306a36Sopenharmony_ci return; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci dma_chan = desc->vd.tx.chan; 14162306a36Sopenharmony_ci chan = to_pt_chan(dma_chan); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (err) 14462306a36Sopenharmony_ci desc->status = DMA_ERROR; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci while (true) { 14762306a36Sopenharmony_ci /* Check for DMA descriptor completion */ 14862306a36Sopenharmony_ci desc = pt_handle_active_desc(chan, desc); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* Don't submit cmd if no descriptor or DMA is paused */ 15162306a36Sopenharmony_ci if (!desc) 15262306a36Sopenharmony_ci break; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci ret = pt_dma_start_desc(desc); 15562306a36Sopenharmony_ci if (!ret) 15662306a36Sopenharmony_ci break; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci desc->status = DMA_ERROR; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic struct pt_dma_desc *pt_alloc_dma_desc(struct pt_dma_chan *chan, 16362306a36Sopenharmony_ci unsigned long flags) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci struct pt_dma_desc *desc; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci desc = kmem_cache_zalloc(chan->pt->dma_desc_cache, GFP_NOWAIT); 16862306a36Sopenharmony_ci if (!desc) 16962306a36Sopenharmony_ci return NULL; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci vchan_tx_prep(&chan->vc, &desc->vd, flags); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci desc->pt = chan->pt; 17462306a36Sopenharmony_ci desc->pt->cmd_q.int_en = !!(flags & DMA_PREP_INTERRUPT); 17562306a36Sopenharmony_ci desc->issued_to_hw = 0; 17662306a36Sopenharmony_ci desc->status = DMA_IN_PROGRESS; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci return desc; 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic struct pt_dma_desc *pt_create_desc(struct dma_chan *dma_chan, 18262306a36Sopenharmony_ci dma_addr_t dst, 18362306a36Sopenharmony_ci dma_addr_t src, 18462306a36Sopenharmony_ci unsigned int len, 18562306a36Sopenharmony_ci unsigned long flags) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct pt_dma_chan *chan = to_pt_chan(dma_chan); 18862306a36Sopenharmony_ci struct pt_passthru_engine *pt_engine; 18962306a36Sopenharmony_ci struct pt_dma_desc *desc; 19062306a36Sopenharmony_ci struct pt_cmd *pt_cmd; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci desc = pt_alloc_dma_desc(chan, flags); 19362306a36Sopenharmony_ci if (!desc) 19462306a36Sopenharmony_ci return NULL; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci pt_cmd = &desc->pt_cmd; 19762306a36Sopenharmony_ci pt_cmd->pt = chan->pt; 19862306a36Sopenharmony_ci pt_engine = &pt_cmd->passthru; 19962306a36Sopenharmony_ci pt_cmd->engine = PT_ENGINE_PASSTHRU; 20062306a36Sopenharmony_ci pt_engine->src_dma = src; 20162306a36Sopenharmony_ci pt_engine->dst_dma = dst; 20262306a36Sopenharmony_ci pt_engine->src_len = len; 20362306a36Sopenharmony_ci pt_cmd->pt_cmd_callback = pt_cmd_callback; 20462306a36Sopenharmony_ci pt_cmd->data = desc; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci desc->len = len; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci return desc; 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic struct dma_async_tx_descriptor * 21262306a36Sopenharmony_cipt_prep_dma_memcpy(struct dma_chan *dma_chan, dma_addr_t dst, 21362306a36Sopenharmony_ci dma_addr_t src, size_t len, unsigned long flags) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci struct pt_dma_desc *desc; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci desc = pt_create_desc(dma_chan, dst, src, len, flags); 21862306a36Sopenharmony_ci if (!desc) 21962306a36Sopenharmony_ci return NULL; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci return &desc->vd.tx; 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic struct dma_async_tx_descriptor * 22562306a36Sopenharmony_cipt_prep_dma_interrupt(struct dma_chan *dma_chan, unsigned long flags) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci struct pt_dma_chan *chan = to_pt_chan(dma_chan); 22862306a36Sopenharmony_ci struct pt_dma_desc *desc; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci desc = pt_alloc_dma_desc(chan, flags); 23162306a36Sopenharmony_ci if (!desc) 23262306a36Sopenharmony_ci return NULL; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci return &desc->vd.tx; 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic void pt_issue_pending(struct dma_chan *dma_chan) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci struct pt_dma_chan *chan = to_pt_chan(dma_chan); 24062306a36Sopenharmony_ci struct pt_dma_desc *desc; 24162306a36Sopenharmony_ci unsigned long flags; 24262306a36Sopenharmony_ci bool engine_is_idle = true; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci spin_lock_irqsave(&chan->vc.lock, flags); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci desc = pt_next_dma_desc(chan); 24762306a36Sopenharmony_ci if (desc) 24862306a36Sopenharmony_ci engine_is_idle = false; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci vchan_issue_pending(&chan->vc); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci desc = pt_next_dma_desc(chan); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci spin_unlock_irqrestore(&chan->vc.lock, flags); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci /* If there was nothing active, start processing */ 25762306a36Sopenharmony_ci if (engine_is_idle && desc) 25862306a36Sopenharmony_ci pt_cmd_callback(desc, 0); 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_cistatic enum dma_status 26262306a36Sopenharmony_cipt_tx_status(struct dma_chan *c, dma_cookie_t cookie, 26362306a36Sopenharmony_ci struct dma_tx_state *txstate) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci struct pt_device *pt = to_pt_chan(c)->pt; 26662306a36Sopenharmony_ci struct pt_cmd_queue *cmd_q = &pt->cmd_q; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci pt_check_status_trans(pt, cmd_q); 26962306a36Sopenharmony_ci return dma_cookie_status(c, cookie, txstate); 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic int pt_pause(struct dma_chan *dma_chan) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci struct pt_dma_chan *chan = to_pt_chan(dma_chan); 27562306a36Sopenharmony_ci unsigned long flags; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci spin_lock_irqsave(&chan->vc.lock, flags); 27862306a36Sopenharmony_ci pt_stop_queue(&chan->pt->cmd_q); 27962306a36Sopenharmony_ci spin_unlock_irqrestore(&chan->vc.lock, flags); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci return 0; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic int pt_resume(struct dma_chan *dma_chan) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci struct pt_dma_chan *chan = to_pt_chan(dma_chan); 28762306a36Sopenharmony_ci struct pt_dma_desc *desc = NULL; 28862306a36Sopenharmony_ci unsigned long flags; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci spin_lock_irqsave(&chan->vc.lock, flags); 29162306a36Sopenharmony_ci pt_start_queue(&chan->pt->cmd_q); 29262306a36Sopenharmony_ci desc = pt_next_dma_desc(chan); 29362306a36Sopenharmony_ci spin_unlock_irqrestore(&chan->vc.lock, flags); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* If there was something active, re-start */ 29662306a36Sopenharmony_ci if (desc) 29762306a36Sopenharmony_ci pt_cmd_callback(desc, 0); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci return 0; 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic int pt_terminate_all(struct dma_chan *dma_chan) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci struct pt_dma_chan *chan = to_pt_chan(dma_chan); 30562306a36Sopenharmony_ci unsigned long flags; 30662306a36Sopenharmony_ci struct pt_cmd_queue *cmd_q = &chan->pt->cmd_q; 30762306a36Sopenharmony_ci LIST_HEAD(head); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci iowrite32(SUPPORTED_INTERRUPTS, cmd_q->reg_control + 0x0010); 31062306a36Sopenharmony_ci spin_lock_irqsave(&chan->vc.lock, flags); 31162306a36Sopenharmony_ci vchan_get_all_descriptors(&chan->vc, &head); 31262306a36Sopenharmony_ci spin_unlock_irqrestore(&chan->vc.lock, flags); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci vchan_dma_desc_free_list(&chan->vc, &head); 31562306a36Sopenharmony_ci vchan_free_chan_resources(&chan->vc); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci return 0; 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ciint pt_dmaengine_register(struct pt_device *pt) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci struct pt_dma_chan *chan; 32362306a36Sopenharmony_ci struct dma_device *dma_dev = &pt->dma_dev; 32462306a36Sopenharmony_ci char *cmd_cache_name; 32562306a36Sopenharmony_ci char *desc_cache_name; 32662306a36Sopenharmony_ci int ret; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci pt->pt_dma_chan = devm_kzalloc(pt->dev, sizeof(*pt->pt_dma_chan), 32962306a36Sopenharmony_ci GFP_KERNEL); 33062306a36Sopenharmony_ci if (!pt->pt_dma_chan) 33162306a36Sopenharmony_ci return -ENOMEM; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci cmd_cache_name = devm_kasprintf(pt->dev, GFP_KERNEL, 33462306a36Sopenharmony_ci "%s-dmaengine-cmd-cache", 33562306a36Sopenharmony_ci dev_name(pt->dev)); 33662306a36Sopenharmony_ci if (!cmd_cache_name) 33762306a36Sopenharmony_ci return -ENOMEM; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci desc_cache_name = devm_kasprintf(pt->dev, GFP_KERNEL, 34062306a36Sopenharmony_ci "%s-dmaengine-desc-cache", 34162306a36Sopenharmony_ci dev_name(pt->dev)); 34262306a36Sopenharmony_ci if (!desc_cache_name) { 34362306a36Sopenharmony_ci ret = -ENOMEM; 34462306a36Sopenharmony_ci goto err_cache; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci pt->dma_desc_cache = kmem_cache_create(desc_cache_name, 34862306a36Sopenharmony_ci sizeof(struct pt_dma_desc), 0, 34962306a36Sopenharmony_ci SLAB_HWCACHE_ALIGN, NULL); 35062306a36Sopenharmony_ci if (!pt->dma_desc_cache) { 35162306a36Sopenharmony_ci ret = -ENOMEM; 35262306a36Sopenharmony_ci goto err_cache; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci dma_dev->dev = pt->dev; 35662306a36Sopenharmony_ci dma_dev->src_addr_widths = DMA_SLAVE_BUSWIDTH_64_BYTES; 35762306a36Sopenharmony_ci dma_dev->dst_addr_widths = DMA_SLAVE_BUSWIDTH_64_BYTES; 35862306a36Sopenharmony_ci dma_dev->directions = DMA_MEM_TO_MEM; 35962306a36Sopenharmony_ci dma_dev->residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR; 36062306a36Sopenharmony_ci dma_cap_set(DMA_MEMCPY, dma_dev->cap_mask); 36162306a36Sopenharmony_ci dma_cap_set(DMA_INTERRUPT, dma_dev->cap_mask); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci /* 36462306a36Sopenharmony_ci * PTDMA is intended to be used with the AMD NTB devices, hence 36562306a36Sopenharmony_ci * marking it as DMA_PRIVATE. 36662306a36Sopenharmony_ci */ 36762306a36Sopenharmony_ci dma_cap_set(DMA_PRIVATE, dma_dev->cap_mask); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci INIT_LIST_HEAD(&dma_dev->channels); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci chan = pt->pt_dma_chan; 37262306a36Sopenharmony_ci chan->pt = pt; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci /* Set base and prep routines */ 37562306a36Sopenharmony_ci dma_dev->device_free_chan_resources = pt_free_chan_resources; 37662306a36Sopenharmony_ci dma_dev->device_prep_dma_memcpy = pt_prep_dma_memcpy; 37762306a36Sopenharmony_ci dma_dev->device_prep_dma_interrupt = pt_prep_dma_interrupt; 37862306a36Sopenharmony_ci dma_dev->device_issue_pending = pt_issue_pending; 37962306a36Sopenharmony_ci dma_dev->device_tx_status = pt_tx_status; 38062306a36Sopenharmony_ci dma_dev->device_pause = pt_pause; 38162306a36Sopenharmony_ci dma_dev->device_resume = pt_resume; 38262306a36Sopenharmony_ci dma_dev->device_terminate_all = pt_terminate_all; 38362306a36Sopenharmony_ci dma_dev->device_synchronize = pt_synchronize; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci chan->vc.desc_free = pt_do_cleanup; 38662306a36Sopenharmony_ci vchan_init(&chan->vc, dma_dev); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci ret = dma_async_device_register(dma_dev); 38962306a36Sopenharmony_ci if (ret) 39062306a36Sopenharmony_ci goto err_reg; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci return 0; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cierr_reg: 39562306a36Sopenharmony_ci kmem_cache_destroy(pt->dma_desc_cache); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_cierr_cache: 39862306a36Sopenharmony_ci kmem_cache_destroy(pt->dma_cmd_cache); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci return ret; 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_civoid pt_dmaengine_unregister(struct pt_device *pt) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci struct dma_device *dma_dev = &pt->dma_dev; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci dma_async_device_unregister(dma_dev); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci kmem_cache_destroy(pt->dma_desc_cache); 41062306a36Sopenharmony_ci kmem_cache_destroy(pt->dma_cmd_cache); 41162306a36Sopenharmony_ci} 412