diff options
author | Lee Nipper <lee.nipper@freescale.com> | 2008-07-30 04:26:57 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2008-08-13 06:08:33 -0400 |
commit | f3c85bc1bc72b4cc8d58664a490a9d42bdb6565a (patch) | |
tree | e3582146af658bd9828b137013615b86199fbbd6 | |
parent | b0e0c9e7f6d5764633e93944dafd896dd6097318 (diff) |
crypto: talitos - Add handling for SEC 3.x treatment of link table
Later SEC revision requires the link table (used for scatter/gather)
to have an extra entry to account for the total length in descriptor [4],
which contains cipher Input and ICV.
This only applies to decrypt, not encrypt.
Without this change, on 837x, a gather return/length error results
when a decryption uses a link table to gather the fragments.
This is observed by doing a ping with size of 1447 or larger with AES,
or a ping with size 1455 or larger with 3des.
So, add check for SEC compatible "fsl,3.0" for using extra link table entry.
Signed-off-by: Lee Nipper <lee.nipper@freescale.com>
Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r-- | drivers/crypto/talitos.c | 54 |
1 files changed, 39 insertions, 15 deletions
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 681c15f42083..ee827a7f7c6a 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c | |||
@@ -96,6 +96,9 @@ struct talitos_private { | |||
96 | unsigned int exec_units; | 96 | unsigned int exec_units; |
97 | unsigned int desc_types; | 97 | unsigned int desc_types; |
98 | 98 | ||
99 | /* SEC Compatibility info */ | ||
100 | unsigned long features; | ||
101 | |||
99 | /* next channel to be assigned next incoming descriptor */ | 102 | /* next channel to be assigned next incoming descriptor */ |
100 | atomic_t last_chan; | 103 | atomic_t last_chan; |
101 | 104 | ||
@@ -133,6 +136,9 @@ struct talitos_private { | |||
133 | struct hwrng rng; | 136 | struct hwrng rng; |
134 | }; | 137 | }; |
135 | 138 | ||
139 | /* .features flag */ | ||
140 | #define TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT 0x00000001 | ||
141 | |||
136 | /* | 142 | /* |
137 | * map virtual single (contiguous) pointer to h/w descriptor pointer | 143 | * map virtual single (contiguous) pointer to h/w descriptor pointer |
138 | */ | 144 | */ |
@@ -785,7 +791,7 @@ static void ipsec_esp_encrypt_done(struct device *dev, | |||
785 | /* copy the generated ICV to dst */ | 791 | /* copy the generated ICV to dst */ |
786 | if (edesc->dma_len) { | 792 | if (edesc->dma_len) { |
787 | icvdata = &edesc->link_tbl[edesc->src_nents + | 793 | icvdata = &edesc->link_tbl[edesc->src_nents + |
788 | edesc->dst_nents + 1]; | 794 | edesc->dst_nents + 2]; |
789 | sg = sg_last(areq->dst, edesc->dst_nents); | 795 | sg = sg_last(areq->dst, edesc->dst_nents); |
790 | memcpy((char *)sg_virt(sg) + sg->length - ctx->authsize, | 796 | memcpy((char *)sg_virt(sg) + sg->length - ctx->authsize, |
791 | icvdata, ctx->authsize); | 797 | icvdata, ctx->authsize); |
@@ -814,7 +820,7 @@ static void ipsec_esp_decrypt_done(struct device *dev, | |||
814 | /* auth check */ | 820 | /* auth check */ |
815 | if (edesc->dma_len) | 821 | if (edesc->dma_len) |
816 | icvdata = &edesc->link_tbl[edesc->src_nents + | 822 | icvdata = &edesc->link_tbl[edesc->src_nents + |
817 | edesc->dst_nents + 1]; | 823 | edesc->dst_nents + 2]; |
818 | else | 824 | else |
819 | icvdata = &edesc->link_tbl[0]; | 825 | icvdata = &edesc->link_tbl[0]; |
820 | 826 | ||
@@ -921,10 +927,30 @@ static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq, | |||
921 | sg_count = sg_to_link_tbl(areq->src, sg_count, cryptlen, | 927 | sg_count = sg_to_link_tbl(areq->src, sg_count, cryptlen, |
922 | &edesc->link_tbl[0]); | 928 | &edesc->link_tbl[0]); |
923 | if (sg_count > 1) { | 929 | if (sg_count > 1) { |
930 | struct talitos_ptr *link_tbl_ptr = | ||
931 | &edesc->link_tbl[sg_count-1]; | ||
932 | struct scatterlist *sg; | ||
933 | struct talitos_private *priv = dev_get_drvdata(dev); | ||
934 | |||
924 | desc->ptr[4].j_extent |= DESC_PTR_LNKTBL_JUMP; | 935 | desc->ptr[4].j_extent |= DESC_PTR_LNKTBL_JUMP; |
925 | desc->ptr[4].ptr = cpu_to_be32(edesc->dma_link_tbl); | 936 | desc->ptr[4].ptr = cpu_to_be32(edesc->dma_link_tbl); |
926 | dma_sync_single_for_device(ctx->dev, edesc->dma_link_tbl, | 937 | dma_sync_single_for_device(ctx->dev, edesc->dma_link_tbl, |
927 | edesc->dma_len, DMA_BIDIRECTIONAL); | 938 | edesc->dma_len, DMA_BIDIRECTIONAL); |
939 | /* If necessary for this SEC revision, | ||
940 | * add a link table entry for ICV. | ||
941 | */ | ||
942 | if ((priv->features & | ||
943 | TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT) && | ||
944 | (edesc->desc.hdr & DESC_HDR_MODE0_ENCRYPT) == 0) { | ||
945 | link_tbl_ptr->j_extent = 0; | ||
946 | link_tbl_ptr++; | ||
947 | link_tbl_ptr->j_extent = DESC_PTR_LNKTBL_RETURN; | ||
948 | link_tbl_ptr->len = cpu_to_be16(authsize); | ||
949 | sg = sg_last(areq->src, edesc->src_nents ? : 1); | ||
950 | link_tbl_ptr->ptr = cpu_to_be32( | ||
951 | (char *)sg_dma_address(sg) | ||
952 | + sg->length - authsize); | ||
953 | } | ||
928 | } else { | 954 | } else { |
929 | /* Only one segment now, so no link tbl needed */ | 955 | /* Only one segment now, so no link tbl needed */ |
930 | desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq->src)); | 956 | desc->ptr[4].ptr = cpu_to_be32(sg_dma_address(areq->src)); |
@@ -944,12 +970,11 @@ static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq, | |||
944 | desc->ptr[5].ptr = cpu_to_be32(sg_dma_address(areq->dst)); | 970 | desc->ptr[5].ptr = cpu_to_be32(sg_dma_address(areq->dst)); |
945 | } else { | 971 | } else { |
946 | struct talitos_ptr *link_tbl_ptr = | 972 | struct talitos_ptr *link_tbl_ptr = |
947 | &edesc->link_tbl[edesc->src_nents]; | 973 | &edesc->link_tbl[edesc->src_nents + 1]; |
948 | struct scatterlist *sg; | ||
949 | 974 | ||
950 | desc->ptr[5].ptr = cpu_to_be32((struct talitos_ptr *) | 975 | desc->ptr[5].ptr = cpu_to_be32((struct talitos_ptr *) |
951 | edesc->dma_link_tbl + | 976 | edesc->dma_link_tbl + |
952 | edesc->src_nents); | 977 | edesc->src_nents + 1); |
953 | if (areq->src == areq->dst) { | 978 | if (areq->src == areq->dst) { |
954 | memcpy(link_tbl_ptr, &edesc->link_tbl[0], | 979 | memcpy(link_tbl_ptr, &edesc->link_tbl[0], |
955 | edesc->src_nents * sizeof(struct talitos_ptr)); | 980 | edesc->src_nents * sizeof(struct talitos_ptr)); |
@@ -957,14 +982,10 @@ static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq, | |||
957 | sg_count = sg_to_link_tbl(areq->dst, sg_count, cryptlen, | 982 | sg_count = sg_to_link_tbl(areq->dst, sg_count, cryptlen, |
958 | link_tbl_ptr); | 983 | link_tbl_ptr); |
959 | } | 984 | } |
985 | /* Add an entry to the link table for ICV data */ | ||
960 | link_tbl_ptr += sg_count - 1; | 986 | link_tbl_ptr += sg_count - 1; |
961 | |||
962 | /* handle case where sg_last contains the ICV exclusively */ | ||
963 | sg = sg_last(areq->dst, edesc->dst_nents); | ||
964 | if (sg->length == ctx->authsize) | ||
965 | link_tbl_ptr--; | ||
966 | |||
967 | link_tbl_ptr->j_extent = 0; | 987 | link_tbl_ptr->j_extent = 0; |
988 | sg_count++; | ||
968 | link_tbl_ptr++; | 989 | link_tbl_ptr++; |
969 | link_tbl_ptr->j_extent = DESC_PTR_LNKTBL_RETURN; | 990 | link_tbl_ptr->j_extent = DESC_PTR_LNKTBL_RETURN; |
970 | link_tbl_ptr->len = cpu_to_be16(authsize); | 991 | link_tbl_ptr->len = cpu_to_be16(authsize); |
@@ -973,7 +994,7 @@ static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq, | |||
973 | link_tbl_ptr->ptr = cpu_to_be32((struct talitos_ptr *) | 994 | link_tbl_ptr->ptr = cpu_to_be32((struct talitos_ptr *) |
974 | edesc->dma_link_tbl + | 995 | edesc->dma_link_tbl + |
975 | edesc->src_nents + | 996 | edesc->src_nents + |
976 | edesc->dst_nents + 1); | 997 | edesc->dst_nents + 2); |
977 | 998 | ||
978 | desc->ptr[5].j_extent |= DESC_PTR_LNKTBL_JUMP; | 999 | desc->ptr[5].j_extent |= DESC_PTR_LNKTBL_JUMP; |
979 | dma_sync_single_for_device(ctx->dev, edesc->dma_link_tbl, | 1000 | dma_sync_single_for_device(ctx->dev, edesc->dma_link_tbl, |
@@ -1040,12 +1061,12 @@ static struct ipsec_esp_edesc *ipsec_esp_edesc_alloc(struct aead_request *areq, | |||
1040 | 1061 | ||
1041 | /* | 1062 | /* |
1042 | * allocate space for base edesc plus the link tables, | 1063 | * allocate space for base edesc plus the link tables, |
1043 | * allowing for a separate entry for the generated ICV (+ 1), | 1064 | * allowing for two separate entries for ICV and generated ICV (+ 2), |
1044 | * and the ICV data itself | 1065 | * and the ICV data itself |
1045 | */ | 1066 | */ |
1046 | alloc_len = sizeof(struct ipsec_esp_edesc); | 1067 | alloc_len = sizeof(struct ipsec_esp_edesc); |
1047 | if (src_nents || dst_nents) { | 1068 | if (src_nents || dst_nents) { |
1048 | dma_len = (src_nents + dst_nents + 1) * | 1069 | dma_len = (src_nents + dst_nents + 2) * |
1049 | sizeof(struct talitos_ptr) + ctx->authsize; | 1070 | sizeof(struct talitos_ptr) + ctx->authsize; |
1050 | alloc_len += dma_len; | 1071 | alloc_len += dma_len; |
1051 | } else { | 1072 | } else { |
@@ -1104,7 +1125,7 @@ static int aead_authenc_decrypt(struct aead_request *req) | |||
1104 | /* stash incoming ICV for later cmp with ICV generated by the h/w */ | 1125 | /* stash incoming ICV for later cmp with ICV generated by the h/w */ |
1105 | if (edesc->dma_len) | 1126 | if (edesc->dma_len) |
1106 | icvdata = &edesc->link_tbl[edesc->src_nents + | 1127 | icvdata = &edesc->link_tbl[edesc->src_nents + |
1107 | edesc->dst_nents + 1]; | 1128 | edesc->dst_nents + 2]; |
1108 | else | 1129 | else |
1109 | icvdata = &edesc->link_tbl[0]; | 1130 | icvdata = &edesc->link_tbl[0]; |
1110 | 1131 | ||
@@ -1480,6 +1501,9 @@ static int talitos_probe(struct of_device *ofdev, | |||
1480 | goto err_out; | 1501 | goto err_out; |
1481 | } | 1502 | } |
1482 | 1503 | ||
1504 | if (of_device_is_compatible(np, "fsl,sec3.0")) | ||
1505 | priv->features |= TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT; | ||
1506 | |||
1483 | priv->head_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels, | 1507 | priv->head_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels, |
1484 | GFP_KERNEL); | 1508 | GFP_KERNEL); |
1485 | priv->tail_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels, | 1509 | priv->tail_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels, |