aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/crypto/picoxcell_crypto.c
diff options
context:
space:
mode:
authorJamie Iles <jamie@jamieiles.com>2011-03-26 22:48:29 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2011-03-26 22:48:29 -0400
commit40bfc14f3250691dca6fcb00f791727e180a7f79 (patch)
tree1b1306360019360b23b60c56b86a38a55284ea07 /drivers/crypto/picoxcell_crypto.c
parent0475add3c27a43a6599fe6338f8fffe919a13547 (diff)
crypto: picoxcell - fix possible status FIFO overflow
The SPAcc's have 2 equally sized FIFO's - a command FIFO and a status FIFO. The command FIFO takes the requests that are to be performed and the status FIFO reports the results. It is possible to get into the situation where there are more free spaces in the command FIFO than the status FIFO if we don't empty the status FIFO quickly enough resulting in a possible overflow of the status FIFO. This can result in incorrect status being reported in the status FIFO. Make sure that when we are submitting requests the number of requests that have been dispatched but not yet popped from the status FIFO does not exceed the size of a single FIFO. Signed-off-by: Jamie Iles <jamie@jamieiles.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'drivers/crypto/picoxcell_crypto.c')
-rw-r--r--drivers/crypto/picoxcell_crypto.c64
1 files changed, 35 insertions, 29 deletions
diff --git a/drivers/crypto/picoxcell_crypto.c b/drivers/crypto/picoxcell_crypto.c
index b092d0a65837..230b5b8cda1f 100644
--- a/drivers/crypto/picoxcell_crypto.c
+++ b/drivers/crypto/picoxcell_crypto.c
@@ -176,6 +176,8 @@ struct spacc_aead_ctx {
176 u8 salt[AES_BLOCK_SIZE]; 176 u8 salt[AES_BLOCK_SIZE];
177}; 177};
178 178
179static int spacc_ablk_submit(struct spacc_req *req);
180
179static inline struct spacc_alg *to_spacc_alg(struct crypto_alg *alg) 181static inline struct spacc_alg *to_spacc_alg(struct crypto_alg *alg)
180{ 182{
181 return alg ? container_of(alg, struct spacc_alg, alg) : NULL; 183 return alg ? container_of(alg, struct spacc_alg, alg) : NULL;
@@ -666,6 +668,24 @@ static int spacc_aead_submit(struct spacc_req *req)
666 return -EINPROGRESS; 668 return -EINPROGRESS;
667} 669}
668 670
671static int spacc_req_submit(struct spacc_req *req);
672
673static void spacc_push(struct spacc_engine *engine)
674{
675 struct spacc_req *req;
676
677 while (!list_empty(&engine->pending) &&
678 engine->in_flight + 1 <= engine->fifo_sz) {
679
680 ++engine->in_flight;
681 req = list_first_entry(&engine->pending, struct spacc_req,
682 list);
683 list_move_tail(&req->list, &engine->in_progress);
684
685 req->result = spacc_req_submit(req);
686 }
687}
688
669/* 689/*
670 * Setup an AEAD request for processing. This will configure the engine, load 690 * Setup an AEAD request for processing. This will configure the engine, load
671 * the context and then start the packet processing. 691 * the context and then start the packet processing.
@@ -698,7 +718,8 @@ static int spacc_aead_setup(struct aead_request *req, u8 *giv,
698 718
699 err = -EINPROGRESS; 719 err = -EINPROGRESS;
700 spin_lock_irqsave(&engine->hw_lock, flags); 720 spin_lock_irqsave(&engine->hw_lock, flags);
701 if (unlikely(spacc_fifo_cmd_full(engine))) { 721 if (unlikely(spacc_fifo_cmd_full(engine)) ||
722 engine->in_flight + 1 > engine->fifo_sz) {
702 if (!(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) { 723 if (!(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) {
703 err = -EBUSY; 724 err = -EBUSY;
704 spin_unlock_irqrestore(&engine->hw_lock, flags); 725 spin_unlock_irqrestore(&engine->hw_lock, flags);
@@ -706,9 +727,8 @@ static int spacc_aead_setup(struct aead_request *req, u8 *giv,
706 } 727 }
707 list_add_tail(&dev_req->list, &engine->pending); 728 list_add_tail(&dev_req->list, &engine->pending);
708 } else { 729 } else {
709 ++engine->in_flight; 730 list_add_tail(&dev_req->list, &engine->pending);
710 list_add_tail(&dev_req->list, &engine->in_progress); 731 spacc_push(engine);
711 spacc_aead_submit(dev_req);
712 } 732 }
713 spin_unlock_irqrestore(&engine->hw_lock, flags); 733 spin_unlock_irqrestore(&engine->hw_lock, flags);
714 734
@@ -1041,7 +1061,8 @@ static int spacc_ablk_setup(struct ablkcipher_request *req, unsigned alg_type,
1041 * we either stick it on the end of a pending list if we can backlog, 1061 * we either stick it on the end of a pending list if we can backlog,
1042 * or bailout with an error if not. 1062 * or bailout with an error if not.
1043 */ 1063 */
1044 if (unlikely(spacc_fifo_cmd_full(engine))) { 1064 if (unlikely(spacc_fifo_cmd_full(engine)) ||
1065 engine->in_flight + 1 > engine->fifo_sz) {
1045 if (!(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) { 1066 if (!(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) {
1046 err = -EBUSY; 1067 err = -EBUSY;
1047 spin_unlock_irqrestore(&engine->hw_lock, flags); 1068 spin_unlock_irqrestore(&engine->hw_lock, flags);
@@ -1049,9 +1070,8 @@ static int spacc_ablk_setup(struct ablkcipher_request *req, unsigned alg_type,
1049 } 1070 }
1050 list_add_tail(&dev_req->list, &engine->pending); 1071 list_add_tail(&dev_req->list, &engine->pending);
1051 } else { 1072 } else {
1052 ++engine->in_flight; 1073 list_add_tail(&dev_req->list, &engine->pending);
1053 list_add_tail(&dev_req->list, &engine->in_progress); 1074 spacc_push(engine);
1054 spacc_ablk_submit(dev_req);
1055 } 1075 }
1056 spin_unlock_irqrestore(&engine->hw_lock, flags); 1076 spin_unlock_irqrestore(&engine->hw_lock, flags);
1057 1077
@@ -1139,6 +1159,7 @@ static void spacc_process_done(struct spacc_engine *engine)
1139 req = list_first_entry(&engine->in_progress, struct spacc_req, 1159 req = list_first_entry(&engine->in_progress, struct spacc_req,
1140 list); 1160 list);
1141 list_move_tail(&req->list, &engine->completed); 1161 list_move_tail(&req->list, &engine->completed);
1162 --engine->in_flight;
1142 1163
1143 /* POP the status register. */ 1164 /* POP the status register. */
1144 writel(~0, engine->regs + SPA_STAT_POP_REG_OFFSET); 1165 writel(~0, engine->regs + SPA_STAT_POP_REG_OFFSET);
@@ -1208,36 +1229,21 @@ static void spacc_spacc_complete(unsigned long data)
1208 struct spacc_engine *engine = (struct spacc_engine *)data; 1229 struct spacc_engine *engine = (struct spacc_engine *)data;
1209 struct spacc_req *req, *tmp; 1230 struct spacc_req *req, *tmp;
1210 unsigned long flags; 1231 unsigned long flags;
1211 int num_removed = 0;
1212 LIST_HEAD(completed); 1232 LIST_HEAD(completed);
1213 1233
1214 spin_lock_irqsave(&engine->hw_lock, flags); 1234 spin_lock_irqsave(&engine->hw_lock, flags);
1235
1215 list_splice_init(&engine->completed, &completed); 1236 list_splice_init(&engine->completed, &completed);
1237 spacc_push(engine);
1238 if (engine->in_flight)
1239 mod_timer(&engine->packet_timeout, jiffies + PACKET_TIMEOUT);
1240
1216 spin_unlock_irqrestore(&engine->hw_lock, flags); 1241 spin_unlock_irqrestore(&engine->hw_lock, flags);
1217 1242
1218 list_for_each_entry_safe(req, tmp, &completed, list) { 1243 list_for_each_entry_safe(req, tmp, &completed, list) {
1219 ++num_removed;
1220 req->complete(req); 1244 req->complete(req);
1245 list_del(&req->list);
1221 } 1246 }
1222
1223 /* Try and fill the engine back up again. */
1224 spin_lock_irqsave(&engine->hw_lock, flags);
1225
1226 engine->in_flight -= num_removed;
1227
1228 list_for_each_entry_safe(req, tmp, &engine->pending, list) {
1229 if (spacc_fifo_cmd_full(engine))
1230 break;
1231
1232 list_move_tail(&req->list, &engine->in_progress);
1233 ++engine->in_flight;
1234 req->result = spacc_req_submit(req);
1235 }
1236
1237 if (engine->in_flight)
1238 mod_timer(&engine->packet_timeout, jiffies + PACKET_TIMEOUT);
1239
1240 spin_unlock_irqrestore(&engine->hw_lock, flags);
1241} 1247}
1242 1248
1243#ifdef CONFIG_PM 1249#ifdef CONFIG_PM