161f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij/*
261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij * driver/dma/coh901318_lli.c
361f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij *
461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij * Copyright (C) 2007-2009 ST-Ericsson
561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij * License terms: GNU General Public License (GPL) version 2
661f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij * Support functions for handling lli for dma
761f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij * Author: Per Friden <per.friden@stericsson.com>
861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij */
961f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
1061f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij#include <linux/spinlock.h>
1161f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij#include <linux/memory.h>
125a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h>
13db8196df4bb6f117caa163aa73b0f16fd62290bdVinod Koul#include <linux/dmapool.h>
1461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij#include <mach/coh901318.h>
1561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
1661f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij#include "coh901318_lli.h"
1761f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
1861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij#if (defined(CONFIG_DEBUG_FS) && defined(CONFIG_U300_DEBUG))
1961f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij#define DEBUGFS_POOL_COUNTER_RESET(pool) (pool->debugfs_pool_counter = 0)
2061f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij#define DEBUGFS_POOL_COUNTER_ADD(pool, add) (pool->debugfs_pool_counter += add)
2161f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij#else
2261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij#define DEBUGFS_POOL_COUNTER_RESET(pool)
2361f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij#define DEBUGFS_POOL_COUNTER_ADD(pool, add)
2461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij#endif
2561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
2661f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleijstatic struct coh901318_lli *
2761f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleijcoh901318_lli_next(struct coh901318_lli *data)
2861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij{
2961f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	if (data == NULL || data->link_addr == 0)
3061f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		return NULL;
3161f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
3261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	return (struct coh901318_lli *) data->virt_link_addr;
3361f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij}
3461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
3561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleijint coh901318_pool_create(struct coh901318_pool *pool,
3661f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			  struct device *dev,
3761f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			  size_t size, size_t align)
3861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij{
3961f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	spin_lock_init(&pool->lock);
4061f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	pool->dev = dev;
4161f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	pool->dmapool = dma_pool_create("lli_pool", dev, size, align, 0);
4261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
4361f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	DEBUGFS_POOL_COUNTER_RESET(pool);
4461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	return 0;
4561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij}
4661f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
4761f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleijint coh901318_pool_destroy(struct coh901318_pool *pool)
4861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij{
4961f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
5061f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	dma_pool_destroy(pool->dmapool);
5161f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	return 0;
5261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij}
5361f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
5461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleijstruct coh901318_lli *
5561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleijcoh901318_lli_alloc(struct coh901318_pool *pool, unsigned int len)
5661f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij{
5761f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	int i;
5861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	struct coh901318_lli *head;
5961f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	struct coh901318_lli *lli;
6061f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	struct coh901318_lli *lli_prev;
6161f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	dma_addr_t phy;
6261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
6361f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	if (len == 0)
6461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		goto err;
6561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
6661f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	spin_lock(&pool->lock);
6761f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
6861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	head = dma_pool_alloc(pool->dmapool, GFP_NOWAIT, &phy);
6961f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
7061f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	if (head == NULL)
7161f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		goto err;
7261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
7361f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	DEBUGFS_POOL_COUNTER_ADD(pool, 1);
7461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
7561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	lli = head;
7661f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	lli->phy_this = phy;
7756a5d3cf21c71963c8fc506e9b9d3f71641d9c71Linus Walleij	lli->link_addr = 0x00000000;
7856a5d3cf21c71963c8fc506e9b9d3f71641d9c71Linus Walleij	lli->virt_link_addr = 0x00000000U;
7961f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
8061f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	for (i = 1; i < len; i++) {
8161f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		lli_prev = lli;
8261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
8361f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		lli = dma_pool_alloc(pool->dmapool, GFP_NOWAIT, &phy);
8461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
8561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		if (lli == NULL)
8661f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			goto err_clean_up;
8761f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
8861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		DEBUGFS_POOL_COUNTER_ADD(pool, 1);
8961f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		lli->phy_this = phy;
9056a5d3cf21c71963c8fc506e9b9d3f71641d9c71Linus Walleij		lli->link_addr = 0x00000000;
9156a5d3cf21c71963c8fc506e9b9d3f71641d9c71Linus Walleij		lli->virt_link_addr = 0x00000000U;
9261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
9361f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		lli_prev->link_addr = phy;
9461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		lli_prev->virt_link_addr = lli;
9561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	}
9661f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
9761f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	spin_unlock(&pool->lock);
9861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
9961f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	return head;
10061f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
10161f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij err:
10261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	spin_unlock(&pool->lock);
10361f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	return NULL;
10461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
10561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij err_clean_up:
10661f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	lli_prev->link_addr = 0x00000000U;
10761f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	spin_unlock(&pool->lock);
10861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	coh901318_lli_free(pool, &head);
10961f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	return NULL;
11061f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij}
11161f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
11261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleijvoid coh901318_lli_free(struct coh901318_pool *pool,
11361f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			struct coh901318_lli **lli)
11461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij{
11561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	struct coh901318_lli *l;
11661f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	struct coh901318_lli *next;
11761f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
11861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	if (lli == NULL)
11961f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		return;
12061f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
12161f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	l = *lli;
12261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
12361f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	if (l == NULL)
12461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		return;
12561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
12661f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	spin_lock(&pool->lock);
12761f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
12861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	while (l->link_addr) {
12961f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		next = l->virt_link_addr;
13061f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		dma_pool_free(pool->dmapool, l, l->phy_this);
13161f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		DEBUGFS_POOL_COUNTER_ADD(pool, -1);
13261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		l = next;
13361f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	}
13461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	dma_pool_free(pool->dmapool, l, l->phy_this);
13561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	DEBUGFS_POOL_COUNTER_ADD(pool, -1);
13661f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
13761f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	spin_unlock(&pool->lock);
13861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	*lli = NULL;
13961f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij}
14061f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
14161f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleijint
14261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleijcoh901318_lli_fill_memcpy(struct coh901318_pool *pool,
14361f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			  struct coh901318_lli *lli,
14461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			  dma_addr_t source, unsigned int size,
14561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			  dma_addr_t destination, u32 ctrl_chained,
14661f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			  u32 ctrl_eom)
14761f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij{
14861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	int s = size;
14961f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	dma_addr_t src = source;
15061f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	dma_addr_t dst = destination;
15161f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
15261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	lli->src_addr = src;
15361f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	lli->dst_addr = dst;
15461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
15561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	while (lli->link_addr) {
15661f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		lli->control = ctrl_chained | MAX_DMA_PACKET_SIZE;
15761f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		lli->src_addr = src;
15861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		lli->dst_addr = dst;
15961f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
16061f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		s -= MAX_DMA_PACKET_SIZE;
16161f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		lli = coh901318_lli_next(lli);
16261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
16361f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		src += MAX_DMA_PACKET_SIZE;
16461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		dst += MAX_DMA_PACKET_SIZE;
16561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	}
16661f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
16761f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	lli->control = ctrl_eom | s;
16861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	lli->src_addr = src;
16961f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	lli->dst_addr = dst;
17061f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
1710b58828c923e57f1bfbbd2c4277ceb60666314faLinus Walleij	return 0;
17261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij}
17361f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
17461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleijint
17561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleijcoh901318_lli_fill_single(struct coh901318_pool *pool,
17661f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			  struct coh901318_lli *lli,
17761f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			  dma_addr_t buf, unsigned int size,
17861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			  dma_addr_t dev_addr, u32 ctrl_chained, u32 ctrl_eom,
179db8196df4bb6f117caa163aa73b0f16fd62290bdVinod Koul			  enum dma_transfer_direction dir)
18061f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij{
18161f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	int s = size;
18261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	dma_addr_t src;
18361f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	dma_addr_t dst;
18461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
18561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
186db8196df4bb6f117caa163aa73b0f16fd62290bdVinod Koul	if (dir == DMA_MEM_TO_DEV) {
18761f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		src = buf;
18861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		dst = dev_addr;
18961f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
190db8196df4bb6f117caa163aa73b0f16fd62290bdVinod Koul	} else if (dir == DMA_DEV_TO_MEM) {
19161f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
19261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		src = dev_addr;
19361f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		dst = buf;
19461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	} else {
19561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		return -EINVAL;
19661f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	}
19761f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
19861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	while (lli->link_addr) {
19961f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		size_t block_size = MAX_DMA_PACKET_SIZE;
20061f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		lli->control = ctrl_chained | MAX_DMA_PACKET_SIZE;
20161f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
20261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		/* If we are on the next-to-final block and there will
20361f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		 * be less than half a DMA packet left for the last
20461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		 * block, then we want to make this block a little
20561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		 * smaller to balance the sizes. This is meant to
20661f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		 * avoid too small transfers if the buffer size is
20761f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		 * (MAX_DMA_PACKET_SIZE*N + 1) */
20861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		if (s < (MAX_DMA_PACKET_SIZE + MAX_DMA_PACKET_SIZE/2))
20961f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			block_size = MAX_DMA_PACKET_SIZE/2;
21061f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
21161f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		s -= block_size;
21261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		lli->src_addr = src;
21361f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		lli->dst_addr = dst;
21461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
21561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		lli = coh901318_lli_next(lli);
21661f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
217db8196df4bb6f117caa163aa73b0f16fd62290bdVinod Koul		if (dir == DMA_MEM_TO_DEV)
21861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			src += block_size;
219db8196df4bb6f117caa163aa73b0f16fd62290bdVinod Koul		else if (dir == DMA_DEV_TO_MEM)
22061f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			dst += block_size;
22161f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	}
22261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
22361f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	lli->control = ctrl_eom | s;
22461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	lli->src_addr = src;
22561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	lli->dst_addr = dst;
22661f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
2270b58828c923e57f1bfbbd2c4277ceb60666314faLinus Walleij	return 0;
22861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij}
22961f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
23061f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleijint
23161f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleijcoh901318_lli_fill_sg(struct coh901318_pool *pool,
23261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		      struct coh901318_lli *lli,
23361f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		      struct scatterlist *sgl, unsigned int nents,
23461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		      dma_addr_t dev_addr, u32 ctrl_chained, u32 ctrl,
23561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		      u32 ctrl_last,
236db8196df4bb6f117caa163aa73b0f16fd62290bdVinod Koul		      enum dma_transfer_direction dir, u32 ctrl_irq_mask)
23761f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij{
23861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	int i;
23961f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	struct scatterlist *sg;
24061f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	u32 ctrl_sg;
24161f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	dma_addr_t src = 0;
24261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	dma_addr_t dst = 0;
24361f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	u32 bytes_to_transfer;
24461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	u32 elem_size;
24561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
24661f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	if (lli == NULL)
24761f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		goto err;
24861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
24961f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	spin_lock(&pool->lock);
25061f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
251db8196df4bb6f117caa163aa73b0f16fd62290bdVinod Koul	if (dir == DMA_MEM_TO_DEV)
25261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		dst = dev_addr;
253db8196df4bb6f117caa163aa73b0f16fd62290bdVinod Koul	else if (dir == DMA_DEV_TO_MEM)
25461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		src = dev_addr;
25561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	else
25661f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		goto err;
25761f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
25861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	for_each_sg(sgl, sg, nents, i) {
25961f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		if (sg_is_chain(sg)) {
26061f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			/* sg continues to the next sg-element don't
26161f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			 * send ctrl_finish until the last
26261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			 * sg-element in the chain
26361f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			 */
26461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			ctrl_sg = ctrl_chained;
26561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		} else if (i == nents - 1)
26661f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			ctrl_sg = ctrl_last;
26761f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		else
26861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			ctrl_sg = ctrl ? ctrl : ctrl_last;
26961f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
27061f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
271db8196df4bb6f117caa163aa73b0f16fd62290bdVinod Koul		if (dir == DMA_MEM_TO_DEV)
27261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			/* increment source address */
27356a5d3cf21c71963c8fc506e9b9d3f71641d9c71Linus Walleij			src = sg_phys(sg);
27461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		else
27561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			/* increment destination address */
27656a5d3cf21c71963c8fc506e9b9d3f71641d9c71Linus Walleij			dst =  sg_phys(sg);
27761f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
27861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		bytes_to_transfer = sg_dma_len(sg);
27961f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
28061f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		while (bytes_to_transfer) {
28161f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			u32 val;
28261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
28361f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			if (bytes_to_transfer > MAX_DMA_PACKET_SIZE) {
28461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij				elem_size = MAX_DMA_PACKET_SIZE;
28561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij				val = ctrl_chained;
28661f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			} else {
28761f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij				elem_size = bytes_to_transfer;
28861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij				val = ctrl_sg;
28961f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			}
29061f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
29161f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			lli->control = val | elem_size;
29261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			lli->src_addr = src;
29361f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			lli->dst_addr = dst;
29461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
295db8196df4bb6f117caa163aa73b0f16fd62290bdVinod Koul			if (dir == DMA_DEV_TO_MEM)
29661f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij				dst += elem_size;
29761f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			else
29861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij				src += elem_size;
29961f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
30061f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			BUG_ON(lli->link_addr & 3);
30161f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
30261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			bytes_to_transfer -= elem_size;
30361f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij			lli = coh901318_lli_next(lli);
30461f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij		}
30561f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
30661f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	}
30761f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	spin_unlock(&pool->lock);
30861f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij
3090b58828c923e57f1bfbbd2c4277ceb60666314faLinus Walleij	return 0;
31061f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij err:
31161f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	spin_unlock(&pool->lock);
31261f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij	return -EINVAL;
31361f135b92f4758bc4d4767cd0a5d2da954e27f14Linus Walleij}
314