2 * OMAP Crypto driver common support routines.
4 * Copyright (c) 2017 Texas Instruments Incorporated
5 * Tero Kristo <t-kristo@ti.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as published
9 * by the Free Software Foundation.
12 #include <linux/module.h>
13 #include <linux/kernel.h>
14 #include <linux/scatterlist.h>
15 #include <crypto/scatterwalk.h>
17 #include "omap-crypto.h"
19 static int omap_crypto_copy_sg_lists(int total
, int bs
,
20 struct scatterlist
**sg
,
21 struct scatterlist
*new_sg
, u16 flags
)
23 int n
= sg_nents(*sg
);
24 struct scatterlist
*tmp
;
26 if (!(flags
& OMAP_CRYPTO_FORCE_SINGLE_ENTRY
)) {
27 new_sg
= kmalloc_array(n
, sizeof(*sg
), GFP_KERNEL
);
31 sg_init_table(new_sg
, n
);
36 while (*sg
&& total
) {
37 int len
= (*sg
)->length
;
44 sg_set_page(tmp
, sg_page(*sg
), len
, (*sg
)->offset
);
58 static int omap_crypto_copy_sgs(int total
, int bs
, struct scatterlist
**sg
,
59 struct scatterlist
*new_sg
, u16 flags
)
65 new_len
= ALIGN(total
, bs
);
66 pages
= get_order(new_len
);
68 buf
= (void *)__get_free_pages(GFP_ATOMIC
, pages
);
70 pr_err("%s: Couldn't allocate pages for unaligned cases.\n",
75 if (flags
& OMAP_CRYPTO_COPY_DATA
) {
76 scatterwalk_map_and_copy(buf
, *sg
, 0, total
, 0);
77 if (flags
& OMAP_CRYPTO_ZERO_BUF
)
78 memset(buf
+ total
, 0, new_len
- total
);
81 if (!(flags
& OMAP_CRYPTO_FORCE_SINGLE_ENTRY
))
82 sg_init_table(new_sg
, 1);
84 sg_set_buf(new_sg
, buf
, new_len
);
91 static int omap_crypto_check_sg(struct scatterlist
*sg
, int total
, int bs
,
97 if (!IS_ALIGNED(total
, bs
))
98 return OMAP_CRYPTO_NOT_ALIGNED
;
103 if (!IS_ALIGNED(sg
->offset
, 4))
104 return OMAP_CRYPTO_NOT_ALIGNED
;
105 if (!IS_ALIGNED(sg
->length
, bs
))
106 return OMAP_CRYPTO_NOT_ALIGNED
;
115 if ((flags
& OMAP_CRYPTO_FORCE_SINGLE_ENTRY
) && num_sg
> 1)
116 return OMAP_CRYPTO_NOT_ALIGNED
;
119 return OMAP_CRYPTO_BAD_DATA_LENGTH
;
124 int omap_crypto_align_sg(struct scatterlist
**sg
, int total
, int bs
,
125 struct scatterlist
*new_sg
, u16 flags
,
126 u8 flags_shift
, unsigned long *dd_flags
)
130 *dd_flags
&= ~(OMAP_CRYPTO_COPY_MASK
<< flags_shift
);
132 if (flags
& OMAP_CRYPTO_FORCE_COPY
)
133 ret
= OMAP_CRYPTO_NOT_ALIGNED
;
135 ret
= omap_crypto_check_sg(*sg
, total
, bs
, flags
);
137 if (ret
== OMAP_CRYPTO_NOT_ALIGNED
) {
138 ret
= omap_crypto_copy_sgs(total
, bs
, sg
, new_sg
, flags
);
141 *dd_flags
|= OMAP_CRYPTO_DATA_COPIED
<< flags_shift
;
142 } else if (ret
== OMAP_CRYPTO_BAD_DATA_LENGTH
) {
143 ret
= omap_crypto_copy_sg_lists(total
, bs
, sg
, new_sg
, flags
);
146 if (!(flags
& OMAP_CRYPTO_FORCE_SINGLE_ENTRY
))
147 *dd_flags
|= OMAP_CRYPTO_SG_COPIED
<< flags_shift
;
148 } else if (flags
& OMAP_CRYPTO_FORCE_SINGLE_ENTRY
) {
149 sg_set_buf(new_sg
, sg_virt(*sg
), (*sg
)->length
);
154 EXPORT_SYMBOL_GPL(omap_crypto_align_sg
);
156 void omap_crypto_cleanup(struct scatterlist
*sg
, struct scatterlist
*orig
,
157 int offset
, int len
, u8 flags_shift
,
163 flags
>>= flags_shift
;
164 flags
&= OMAP_CRYPTO_COPY_MASK
;
170 pages
= get_order(len
);
172 if (orig
&& (flags
& OMAP_CRYPTO_COPY_MASK
))
173 scatterwalk_map_and_copy(buf
, orig
, offset
, len
, 1);
175 if (flags
& OMAP_CRYPTO_DATA_COPIED
)
176 free_pages((unsigned long)buf
, pages
);
177 else if (flags
& OMAP_CRYPTO_SG_COPIED
)
180 EXPORT_SYMBOL_GPL(omap_crypto_cleanup
);
182 MODULE_DESCRIPTION("OMAP crypto support library.");
183 MODULE_LICENSE("GPL v2");
184 MODULE_AUTHOR("Tero Kristo <t-kristo@ti.com>");