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