sg_sw_sec4.h 3.9 KB
Newer Older
Y
Yuan Kang 已提交
1 2 3 4 5 6 7
/*
 * CAAM/SEC 4.x functions for using scatterlists in caam driver
 *
 * Copyright 2008-2011 Freescale Semiconductor, Inc.
 *
 */

Y
Yuan Kang 已提交
8
struct sec4_sg_entry;
Y
Yuan Kang 已提交
9 10 11 12

/*
 * convert single dma address to h/w link table format
 */
Y
Yuan Kang 已提交
13
static inline void dma_to_sec4_sg_one(struct sec4_sg_entry *sec4_sg_ptr,
Y
Yuan Kang 已提交
14 15
				      dma_addr_t dma, u32 len, u32 offset)
{
Y
Yuan Kang 已提交
16 17 18 19 20
	sec4_sg_ptr->ptr = dma;
	sec4_sg_ptr->len = len;
	sec4_sg_ptr->reserved = 0;
	sec4_sg_ptr->buf_pool_id = 0;
	sec4_sg_ptr->offset = offset;
Y
Yuan Kang 已提交
21
#ifdef DEBUG
Y
Yuan Kang 已提交
22 23 24
	print_hex_dump(KERN_ERR, "sec4_sg_ptr@: ",
		       DUMP_PREFIX_ADDRESS, 16, 4, sec4_sg_ptr,
		       sizeof(struct sec4_sg_entry), 1);
Y
Yuan Kang 已提交
25 26 27 28 29 30 31
#endif
}

/*
 * convert scatterlist to h/w link table format
 * but does not have final bit; instead, returns last entry
 */
Y
Yuan Kang 已提交
32 33 34
static inline struct sec4_sg_entry *
sg_to_sec4_sg(struct scatterlist *sg, int sg_count,
	      struct sec4_sg_entry *sec4_sg_ptr, u32 offset)
Y
Yuan Kang 已提交
35 36
{
	while (sg_count) {
Y
Yuan Kang 已提交
37
		dma_to_sec4_sg_one(sec4_sg_ptr, sg_dma_address(sg),
Y
Yuan Kang 已提交
38
				   sg_dma_len(sg), offset);
Y
Yuan Kang 已提交
39
		sec4_sg_ptr++;
Y
Yuan Kang 已提交
40
		sg = scatterwalk_sg_next(sg);
Y
Yuan Kang 已提交
41 42
		sg_count--;
	}
Y
Yuan Kang 已提交
43
	return sec4_sg_ptr - 1;
Y
Yuan Kang 已提交
44 45 46 47 48 49
}

/*
 * convert scatterlist to h/w link table format
 * scatterlist must have been previously dma mapped
 */
Y
Yuan Kang 已提交
50 51 52
static inline void sg_to_sec4_sg_last(struct scatterlist *sg, int sg_count,
				      struct sec4_sg_entry *sec4_sg_ptr,
				      u32 offset)
Y
Yuan Kang 已提交
53
{
Y
Yuan Kang 已提交
54 55
	sec4_sg_ptr = sg_to_sec4_sg(sg, sg_count, sec4_sg_ptr, offset);
	sec4_sg_ptr->len |= SEC4_SG_LEN_FIN;
Y
Yuan Kang 已提交
56 57 58
}

/* count number of elements in scatterlist */
Y
Yuan Kang 已提交
59 60
static inline int __sg_count(struct scatterlist *sg_list, int nbytes,
			     bool *chained)
Y
Yuan Kang 已提交
61 62 63 64 65 66 67 68
{
	struct scatterlist *sg = sg_list;
	int sg_nents = 0;

	while (nbytes > 0) {
		sg_nents++;
		nbytes -= sg->length;
		if (!sg_is_last(sg) && (sg + 1)->length == 0)
Y
Yuan Kang 已提交
69
			*chained = true;
Y
Yuan Kang 已提交
70 71 72 73 74 75 76
		sg = scatterwalk_sg_next(sg);
	}

	return sg_nents;
}

/* derive number of elements in scatterlist, but return 0 for 1 */
Y
Yuan Kang 已提交
77 78
static inline int sg_count(struct scatterlist *sg_list, int nbytes,
			     bool *chained)
Y
Yuan Kang 已提交
79
{
Y
Yuan Kang 已提交
80
	int sg_nents = __sg_count(sg_list, nbytes, chained);
Y
Yuan Kang 已提交
81 82 83 84 85 86

	if (likely(sg_nents == 1))
		return 0;

	return sg_nents;
}
Y
Yuan Kang 已提交
87

Y
Yuan Kang 已提交
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
static int dma_map_sg_chained(struct device *dev, struct scatterlist *sg,
			      unsigned int nents, enum dma_data_direction dir,
			      bool chained)
{
	if (unlikely(chained)) {
		int i;
		for (i = 0; i < nents; i++) {
			dma_map_sg(dev, sg, 1, dir);
			sg = scatterwalk_sg_next(sg);
		}
	} else {
		dma_map_sg(dev, sg, nents, dir);
	}
	return nents;
}

static int dma_unmap_sg_chained(struct device *dev, struct scatterlist *sg,
				unsigned int nents, enum dma_data_direction dir,
				bool chained)
{
	if (unlikely(chained)) {
		int i;
		for (i = 0; i < nents; i++) {
			dma_unmap_sg(dev, sg, 1, dir);
			sg = scatterwalk_sg_next(sg);
		}
	} else {
		dma_unmap_sg(dev, sg, nents, dir);
	}
	return nents;
}

Y
Yuan Kang 已提交
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
/* Copy from len bytes of sg to dest, starting from beginning */
static inline void sg_copy(u8 *dest, struct scatterlist *sg, unsigned int len)
{
	struct scatterlist *current_sg = sg;
	int cpy_index = 0, next_cpy_index = current_sg->length;

	while (next_cpy_index < len) {
		memcpy(dest + cpy_index, (u8 *) sg_virt(current_sg),
		       current_sg->length);
		current_sg = scatterwalk_sg_next(current_sg);
		cpy_index = next_cpy_index;
		next_cpy_index += current_sg->length;
	}
	if (cpy_index < len)
		memcpy(dest + cpy_index, (u8 *) sg_virt(current_sg),
		       len - cpy_index);
}

/* Copy sg data, from to_skip to end, to dest */
static inline void sg_copy_part(u8 *dest, struct scatterlist *sg,
				      int to_skip, unsigned int end)
{
	struct scatterlist *current_sg = sg;
	int sg_index, cpy_index;

	sg_index = current_sg->length;
	while (sg_index <= to_skip) {
		current_sg = scatterwalk_sg_next(current_sg);
		sg_index += current_sg->length;
	}
	cpy_index = sg_index - to_skip;
	memcpy(dest, (u8 *) sg_virt(current_sg) +
	       current_sg->length - cpy_index, cpy_index);
	current_sg = scatterwalk_sg_next(current_sg);
	if (end - sg_index)
		sg_copy(dest + cpy_index, current_sg, end - sg_index);
}