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
;
107 #ifdef CONFIG_ZONE_DMA
108 if (page_zonenum(sg_page(sg
)) != ZONE_DMA
)
109 return OMAP_CRYPTO_NOT_ALIGNED
;
119 if ((flags
& OMAP_CRYPTO_FORCE_SINGLE_ENTRY
) && num_sg
> 1)
120 return OMAP_CRYPTO_NOT_ALIGNED
;
123 return OMAP_CRYPTO_BAD_DATA_LENGTH
;
128 int omap_crypto_align_sg(struct scatterlist
**sg
, int total
, int bs
,
129 struct scatterlist
*new_sg
, u16 flags
,
130 u8 flags_shift
, unsigned long *dd_flags
)
134 *dd_flags
&= ~(OMAP_CRYPTO_COPY_MASK
<< flags_shift
);
136 if (flags
& OMAP_CRYPTO_FORCE_COPY
)
137 ret
= OMAP_CRYPTO_NOT_ALIGNED
;
139 ret
= omap_crypto_check_sg(*sg
, total
, bs
, flags
);
141 if (ret
== OMAP_CRYPTO_NOT_ALIGNED
) {
142 ret
= omap_crypto_copy_sgs(total
, bs
, sg
, new_sg
, flags
);
145 *dd_flags
|= OMAP_CRYPTO_DATA_COPIED
<< flags_shift
;
146 } else if (ret
== OMAP_CRYPTO_BAD_DATA_LENGTH
) {
147 ret
= omap_crypto_copy_sg_lists(total
, bs
, sg
, new_sg
, flags
);
150 if (!(flags
& OMAP_CRYPTO_FORCE_SINGLE_ENTRY
))
151 *dd_flags
|= OMAP_CRYPTO_SG_COPIED
<< flags_shift
;
152 } else if (flags
& OMAP_CRYPTO_FORCE_SINGLE_ENTRY
) {
153 sg_set_buf(new_sg
, sg_virt(*sg
), (*sg
)->length
);
158 EXPORT_SYMBOL_GPL(omap_crypto_align_sg
);
160 void omap_crypto_cleanup(struct scatterlist
*sg
, struct scatterlist
*orig
,
161 int offset
, int len
, u8 flags_shift
,
167 flags
>>= flags_shift
;
168 flags
&= OMAP_CRYPTO_COPY_MASK
;
174 pages
= get_order(len
);
176 if (orig
&& (flags
& OMAP_CRYPTO_COPY_MASK
))
177 scatterwalk_map_and_copy(buf
, orig
, offset
, len
, 1);
179 if (flags
& OMAP_CRYPTO_DATA_COPIED
)
180 free_pages((unsigned long)buf
, pages
);
181 else if (flags
& OMAP_CRYPTO_SG_COPIED
)
184 EXPORT_SYMBOL_GPL(omap_crypto_cleanup
);
186 MODULE_DESCRIPTION("OMAP crypto support library.");
187 MODULE_LICENSE("GPL v2");
188 MODULE_AUTHOR("Tero Kristo <t-kristo@ti.com>");