aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/crypto/talitos.c
diff options
context:
space:
mode:
authorKim Phillips <kim.phillips@freescale.com>2008-10-12 08:33:14 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2008-12-24 19:01:12 -0500
commitfe5720e2b7c1e8ff95d4bf18329517cf64ad1d70 (patch)
tree7c9eb9005a4810a9bd9c9a1dcd580a66e7d28b34 /drivers/crypto/talitos.c
parent1c2e8811eea5f0c5da3213ea206c2864fa4614fd (diff)
crypto: talitos - Perform auth check in h/w if on sec 2.1 and above
SEC version 2.1 and above adds the capability to do the IPSec ICV memcmp in h/w. Results of the cmp are written back in the descriptor header, along with the done status. A new callback is added that checks these ICCR bits instead of performing the memcmp on the core, and is enabled by h/w capability. Signed-off-by: Kim Phillips <kim.phillips@freescale.com> After testing on different parts, another condition was added before using h/w auth check because different SEC revisions require different handling. The SEC 3.0 allows a more flexible link table where the auth data can span separate link table entries. The SEC 2.4/2.1 does not support this case. So a test was added in the decrypt routine for a fragmented case; the h/w auth check is disallowed for revisions not having the extent in the link table; in this case the hw auth check is done by software. A portion of a previous change for SEC 3.0 link table handling was removed since it became dead code with the hw auth check supported. This seems to be the best compromise for using hw auth check on supporting SEC revisions; it keeps the link table logic simpler for the fragmented cases. Signed-off-by: Lee Nipper <lee.nipper@freescale.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'drivers/crypto/talitos.c')
-rw-r--r--drivers/crypto/talitos.c127
1 files changed, 83 insertions, 44 deletions
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index b5c2c9340a9c..16c97caa17ac 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -137,6 +137,7 @@ struct talitos_private {
137 137
138/* .features flag */ 138/* .features flag */
139#define TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT 0x00000001 139#define TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT 0x00000001
140#define TALITOS_FTR_HW_AUTH_CHECK 0x00000002
140 141
141/* 142/*
142 * map virtual single (contiguous) pointer to h/w descriptor pointer 143 * map virtual single (contiguous) pointer to h/w descriptor pointer
@@ -183,6 +184,11 @@ static int reset_channel(struct device *dev, int ch)
183 setbits32(priv->reg + TALITOS_CCCR_LO(ch), TALITOS_CCCR_LO_CDWE | 184 setbits32(priv->reg + TALITOS_CCCR_LO(ch), TALITOS_CCCR_LO_CDWE |
184 TALITOS_CCCR_LO_CDIE); 185 TALITOS_CCCR_LO_CDIE);
185 186
187 /* and ICCR writeback, if available */
188 if (priv->features & TALITOS_FTR_HW_AUTH_CHECK)
189 setbits32(priv->reg + TALITOS_CCCR_LO(ch),
190 TALITOS_CCCR_LO_IWSE);
191
186 return 0; 192 return 0;
187} 193}
188 194
@@ -238,6 +244,11 @@ static int init_device(struct device *dev)
238 setbits32(priv->reg + TALITOS_IMR, TALITOS_IMR_INIT); 244 setbits32(priv->reg + TALITOS_IMR, TALITOS_IMR_INIT);
239 setbits32(priv->reg + TALITOS_IMR_LO, TALITOS_IMR_LO_INIT); 245 setbits32(priv->reg + TALITOS_IMR_LO, TALITOS_IMR_LO_INIT);
240 246
247 /* disable integrity check error interrupts (use writeback instead) */
248 if (priv->features & TALITOS_FTR_HW_AUTH_CHECK)
249 setbits32(priv->reg + TALITOS_MDEUICR_LO,
250 TALITOS_MDEUICR_LO_ICE);
251
241 return 0; 252 return 0;
242} 253}
243 254
@@ -375,7 +386,8 @@ static void talitos_done(unsigned long data)
375 /* At this point, all completed channels have been processed. 386 /* At this point, all completed channels have been processed.
376 * Unmask done interrupts for channels completed later on. 387 * Unmask done interrupts for channels completed later on.
377 */ 388 */
378 setbits32(priv->reg + TALITOS_IMR, TALITOS_IMR_DONE); 389 setbits32(priv->reg + TALITOS_IMR, TALITOS_IMR_INIT);
390 setbits32(priv->reg + TALITOS_IMR_LO, TALITOS_IMR_LO_INIT);
379} 391}
380 392
381/* 393/*
@@ -812,7 +824,7 @@ static void ipsec_esp_encrypt_done(struct device *dev,
812 aead_request_complete(areq, err); 824 aead_request_complete(areq, err);
813} 825}
814 826
815static void ipsec_esp_decrypt_done(struct device *dev, 827static void ipsec_esp_decrypt_swauth_done(struct device *dev,
816 struct talitos_desc *desc, void *context, 828 struct talitos_desc *desc, void *context,
817 int err) 829 int err)
818{ 830{
@@ -844,6 +856,27 @@ static void ipsec_esp_decrypt_done(struct device *dev,
844 aead_request_complete(req, err); 856 aead_request_complete(req, err);
845} 857}
846 858
859static void ipsec_esp_decrypt_hwauth_done(struct device *dev,
860 struct talitos_desc *desc, void *context,
861 int err)
862{
863 struct aead_request *req = context;
864 struct ipsec_esp_edesc *edesc =
865 container_of(desc, struct ipsec_esp_edesc, desc);
866
867 ipsec_esp_unmap(dev, edesc, req);
868
869 /* check ICV auth status */
870 if (!err)
871 if ((desc->hdr_lo & DESC_HDR_LO_ICCR1_MASK) !=
872 DESC_HDR_LO_ICCR1_PASS)
873 err = -EBADMSG;
874
875 kfree(edesc);
876
877 aead_request_complete(req, err);
878}
879
847/* 880/*
848 * convert scatterlist to SEC h/w link table format 881 * convert scatterlist to SEC h/w link table format
849 * stop at cryptlen bytes 882 * stop at cryptlen bytes
@@ -897,6 +930,7 @@ static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq,
897 unsigned int authsize = ctx->authsize; 930 unsigned int authsize = ctx->authsize;
898 unsigned int ivsize; 931 unsigned int ivsize;
899 int sg_count, ret; 932 int sg_count, ret;
933 int sg_link_tbl_len;
900 934
901 /* hmac key */ 935 /* hmac key */
902 map_single_talitos_ptr(dev, &desc->ptr[0], ctx->authkeylen, &ctx->key, 936 map_single_talitos_ptr(dev, &desc->ptr[0], ctx->authkeylen, &ctx->key,
@@ -934,33 +968,19 @@ static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq,
934 if (sg_count == 1) { 968 if (sg_count == 1) {
935 desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq->src)); 969 desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq->src));
936 } else { 970 } else {
937 sg_count = sg_to_link_tbl(areq->src, sg_count, cryptlen, 971 sg_link_tbl_len = cryptlen;
972
973 if ((edesc->desc.hdr & DESC_HDR_MODE1_MDEU_CICV) &&
974 (edesc->desc.hdr & DESC_HDR_MODE0_ENCRYPT) == 0) {
975 sg_link_tbl_len = cryptlen + authsize;
976 }
977 sg_count = sg_to_link_tbl(areq->src, sg_count, sg_link_tbl_len,
938 &edesc->link_tbl[0]); 978 &edesc->link_tbl[0]);
939 if (sg_count > 1) { 979 if (sg_count > 1) {
940 struct talitos_ptr *link_tbl_ptr =
941 &edesc->link_tbl[sg_count-1];
942 struct scatterlist *sg;
943 struct talitos_private *priv = dev_get_drvdata(dev);
944
945 desc->ptr[4].j_extent |= DESC_PTR_LNKTBL_JUMP; 980 desc->ptr[4].j_extent |= DESC_PTR_LNKTBL_JUMP;
946 desc->ptr[4].ptr = cpu_to_be32(edesc->dma_link_tbl); 981 desc->ptr[4].ptr = cpu_to_be32(edesc->dma_link_tbl);
947 dma_sync_single_for_device(ctx->dev, edesc->dma_link_tbl, 982 dma_sync_single_for_device(ctx->dev, edesc->dma_link_tbl,
948 edesc->dma_len, DMA_BIDIRECTIONAL); 983 edesc->dma_len, DMA_BIDIRECTIONAL);
949 /* If necessary for this SEC revision,
950 * add a link table entry for ICV.
951 */
952 if ((priv->features &
953 TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT) &&
954 (edesc->desc.hdr & DESC_HDR_MODE0_ENCRYPT) == 0) {
955 link_tbl_ptr->j_extent = 0;
956 link_tbl_ptr++;
957 link_tbl_ptr->j_extent = DESC_PTR_LNKTBL_RETURN;
958 link_tbl_ptr->len = cpu_to_be16(authsize);
959 sg = sg_last(areq->src, edesc->src_nents ? : 1);
960 link_tbl_ptr->ptr = cpu_to_be32(
961 (char *)sg_dma_address(sg)
962 + sg->length - authsize);
963 }
964 } else { 984 } else {
965 /* Only one segment now, so no link tbl needed */ 985 /* Only one segment now, so no link tbl needed */
966 desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq->src)); 986 desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq->src));
@@ -985,13 +1005,9 @@ static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq,
985 desc->ptr[5].ptr = cpu_to_be32((struct talitos_ptr *) 1005 desc->ptr[5].ptr = cpu_to_be32((struct talitos_ptr *)
986 edesc->dma_link_tbl + 1006 edesc->dma_link_tbl +
987 edesc->src_nents + 1); 1007 edesc->src_nents + 1);
988 if (areq->src == areq->dst) { 1008 sg_count = sg_to_link_tbl(areq->dst, sg_count, cryptlen,
989 memcpy(link_tbl_ptr, &edesc->link_tbl[0], 1009 link_tbl_ptr);
990 edesc->src_nents * sizeof(struct talitos_ptr)); 1010
991 } else {
992 sg_count = sg_to_link_tbl(areq->dst, sg_count, cryptlen,
993 link_tbl_ptr);
994 }
995 /* Add an entry to the link table for ICV data */ 1011 /* Add an entry to the link table for ICV data */
996 link_tbl_ptr += sg_count - 1; 1012 link_tbl_ptr += sg_count - 1;
997 link_tbl_ptr->j_extent = 0; 1013 link_tbl_ptr->j_extent = 0;
@@ -1116,11 +1132,14 @@ static int aead_authenc_encrypt(struct aead_request *req)
1116 return ipsec_esp(edesc, req, NULL, 0, ipsec_esp_encrypt_done); 1132 return ipsec_esp(edesc, req, NULL, 0, ipsec_esp_encrypt_done);
1117} 1133}
1118 1134
1135
1136
1119static int aead_authenc_decrypt(struct aead_request *req) 1137static int aead_authenc_decrypt(struct aead_request *req)
1120{ 1138{
1121 struct crypto_aead *authenc = crypto_aead_reqtfm(req); 1139 struct crypto_aead *authenc = crypto_aead_reqtfm(req);
1122 struct talitos_ctx *ctx = crypto_aead_ctx(authenc); 1140 struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
1123 unsigned int authsize = ctx->authsize; 1141 unsigned int authsize = ctx->authsize;
1142 struct talitos_private *priv = dev_get_drvdata(ctx->dev);
1124 struct ipsec_esp_edesc *edesc; 1143 struct ipsec_esp_edesc *edesc;
1125 struct scatterlist *sg; 1144 struct scatterlist *sg;
1126 void *icvdata; 1145 void *icvdata;
@@ -1132,22 +1151,39 @@ static int aead_authenc_decrypt(struct aead_request *req)
1132 if (IS_ERR(edesc)) 1151 if (IS_ERR(edesc))
1133 return PTR_ERR(edesc); 1152 return PTR_ERR(edesc);
1134 1153
1135 /* stash incoming ICV for later cmp with ICV generated by the h/w */ 1154 if ((priv->features & TALITOS_FTR_HW_AUTH_CHECK) &&
1136 if (edesc->dma_len) 1155 (((!edesc->src_nents && !edesc->dst_nents) ||
1137 icvdata = &edesc->link_tbl[edesc->src_nents + 1156 priv->features & TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT))) {
1138 edesc->dst_nents + 2];
1139 else
1140 icvdata = &edesc->link_tbl[0];
1141 1157
1142 sg = sg_last(req->src, edesc->src_nents ? : 1); 1158 /* decrypt and check the ICV */
1159 edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_DIR_INBOUND |
1160 DESC_HDR_MODE1_MDEU_CICV;
1143 1161
1144 memcpy(icvdata, (char *)sg_virt(sg) + sg->length - ctx->authsize, 1162 /* reset integrity check result bits */
1145 ctx->authsize); 1163 edesc->desc.hdr_lo = 0;
1146 1164
1147 /* decrypt */ 1165 return ipsec_esp(edesc, req, NULL, 0, ipsec_esp_decrypt_hwauth_done);
1148 edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_DIR_INBOUND;
1149 1166
1150 return ipsec_esp(edesc, req, NULL, 0, ipsec_esp_decrypt_done); 1167 } else {
1168
1169 /* Have to check the ICV with software */
1170
1171 edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_DIR_INBOUND;
1172
1173 /* stash incoming ICV for later cmp with ICV generated by the h/w */
1174 if (edesc->dma_len)
1175 icvdata = &edesc->link_tbl[edesc->src_nents +
1176 edesc->dst_nents + 2];
1177 else
1178 icvdata = &edesc->link_tbl[0];
1179
1180 sg = sg_last(req->src, edesc->src_nents ? : 1);
1181
1182 memcpy(icvdata, (char *)sg_virt(sg) + sg->length - ctx->authsize,
1183 ctx->authsize);
1184
1185 return ipsec_esp(edesc, req, NULL, 0, ipsec_esp_decrypt_swauth_done);
1186 }
1151} 1187}
1152 1188
1153static int aead_authenc_givencrypt( 1189static int aead_authenc_givencrypt(
@@ -1460,10 +1496,10 @@ static int talitos_probe(struct of_device *ofdev,
1460 1496
1461 priv->ofdev = ofdev; 1497 priv->ofdev = ofdev;
1462 1498
1463 INIT_LIST_HEAD(&priv->alg_list);
1464
1465 tasklet_init(&priv->done_task, talitos_done, (unsigned long)dev); 1499 tasklet_init(&priv->done_task, talitos_done, (unsigned long)dev);
1466 1500
1501 INIT_LIST_HEAD(&priv->alg_list);
1502
1467 priv->irq = irq_of_parse_and_map(np, 0); 1503 priv->irq = irq_of_parse_and_map(np, 0);
1468 1504
1469 if (priv->irq == NO_IRQ) { 1505 if (priv->irq == NO_IRQ) {
@@ -1516,6 +1552,9 @@ static int talitos_probe(struct of_device *ofdev,
1516 if (of_device_is_compatible(np, "fsl,sec3.0")) 1552 if (of_device_is_compatible(np, "fsl,sec3.0"))
1517 priv->features |= TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT; 1553 priv->features |= TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT;
1518 1554
1555 if (of_device_is_compatible(np, "fsl,sec2.1"))
1556 priv->features |= TALITOS_FTR_HW_AUTH_CHECK;
1557
1519 priv->head_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels, 1558 priv->head_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels,
1520 GFP_KERNEL); 1559 GFP_KERNEL);
1521 priv->tail_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels, 1560 priv->tail_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels,