aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/crypto/omap-aes.c
diff options
context:
space:
mode:
authorJoel Fernandes <joelf@ti.com>2013-08-17 22:42:29 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2013-08-21 07:28:03 -0400
commit1bf95cca8f407cc0d6f21708fdbb17d1dd531bec (patch)
treebca048f64a8a120b79e2eefd1c58420b87628f66 /drivers/crypto/omap-aes.c
parent67216756ea8b9bfa738e0f0a263094f459ab1a12 (diff)
crypto: omap-aes - PIO mode: Add IRQ handler and walk SGs
We add an IRQ handler that implements a state-machine for PIO-mode and data structures for walking the scatter-gather list. The IRQ handler is called in succession both when data is available to read or next data can be sent for processing. This process continues till the entire in/out SG lists have been walked. Once the SG-list has been completely walked, the IRQ handler schedules the done_task tasklet. Also add a useful macro that is used through out the IRQ code for a common pattern of calculating how much an SG list has been walked. This improves code readability and avoids checkpatch errors. Signed-off-by: Joel Fernandes <joelf@ti.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'drivers/crypto/omap-aes.c')
-rw-r--r--drivers/crypto/omap-aes.c90
1 files changed, 90 insertions, 0 deletions
diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c
index 68c44253137d..9909f93255b4 100644
--- a/drivers/crypto/omap-aes.c
+++ b/drivers/crypto/omap-aes.c
@@ -40,6 +40,8 @@
40#define DST_MAXBURST 4 40#define DST_MAXBURST 4
41#define DMA_MIN (DST_MAXBURST * sizeof(u32)) 41#define DMA_MIN (DST_MAXBURST * sizeof(u32))
42 42
43#define _calc_walked(inout) (dd->inout##_walk.offset - dd->inout##_sg->offset)
44
43/* OMAP TRM gives bitfields as start:end, where start is the higher bit 45/* OMAP TRM gives bitfields as start:end, where start is the higher bit
44 number. For example 7:0 */ 46 number. For example 7:0 */
45#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end)) 47#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end))
@@ -92,6 +94,8 @@
92#define FLAGS_FAST BIT(5) 94#define FLAGS_FAST BIT(5)
93#define FLAGS_BUSY BIT(6) 95#define FLAGS_BUSY BIT(6)
94 96
97#define AES_BLOCK_WORDS (AES_BLOCK_SIZE >> 2)
98
95struct omap_aes_ctx { 99struct omap_aes_ctx {
96 struct omap_aes_dev *dd; 100 struct omap_aes_dev *dd;
97 101
@@ -157,6 +161,8 @@ struct omap_aes_dev {
157 size_t total; 161 size_t total;
158 struct scatterlist *in_sg; 162 struct scatterlist *in_sg;
159 struct scatterlist *out_sg; 163 struct scatterlist *out_sg;
164 struct scatter_walk in_walk;
165 struct scatter_walk out_walk;
160 int dma_in; 166 int dma_in;
161 struct dma_chan *dma_lch_in; 167 struct dma_chan *dma_lch_in;
162 int dma_out; 168 int dma_out;
@@ -863,6 +869,90 @@ static const struct omap_aes_pdata omap_aes_pdata_omap4 = {
863 .minor_shift = 0, 869 .minor_shift = 0,
864}; 870};
865 871
872static irqreturn_t omap_aes_irq(int irq, void *dev_id)
873{
874 struct omap_aes_dev *dd = dev_id;
875 u32 status, i;
876 u32 *src, *dst;
877
878 status = omap_aes_read(dd, AES_REG_IRQ_STATUS(dd));
879 if (status & AES_REG_IRQ_DATA_IN) {
880 omap_aes_write(dd, AES_REG_IRQ_ENABLE(dd), 0x0);
881
882 BUG_ON(!dd->in_sg);
883
884 BUG_ON(_calc_walked(in) > dd->in_sg->length);
885
886 src = sg_virt(dd->in_sg) + _calc_walked(in);
887
888 for (i = 0; i < AES_BLOCK_WORDS; i++) {
889 omap_aes_write(dd, AES_REG_DATA_N(dd, i), *src);
890
891 scatterwalk_advance(&dd->in_walk, 4);
892 if (dd->in_sg->length == _calc_walked(in)) {
893 dd->in_sg = scatterwalk_sg_next(dd->in_sg);
894 if (dd->in_sg) {
895 scatterwalk_start(&dd->in_walk,
896 dd->in_sg);
897 src = sg_virt(dd->in_sg) +
898 _calc_walked(in);
899 }
900 } else {
901 src++;
902 }
903 }
904
905 /* Clear IRQ status */
906 status &= ~AES_REG_IRQ_DATA_IN;
907 omap_aes_write(dd, AES_REG_IRQ_STATUS(dd), status);
908
909 /* Enable DATA_OUT interrupt */
910 omap_aes_write(dd, AES_REG_IRQ_ENABLE(dd), 0x4);
911
912 } else if (status & AES_REG_IRQ_DATA_OUT) {
913 omap_aes_write(dd, AES_REG_IRQ_ENABLE(dd), 0x0);
914
915 BUG_ON(!dd->out_sg);
916
917 BUG_ON(_calc_walked(out) > dd->out_sg->length);
918
919 dst = sg_virt(dd->out_sg) + _calc_walked(out);
920
921 for (i = 0; i < AES_BLOCK_WORDS; i++) {
922 *dst = omap_aes_read(dd, AES_REG_DATA_N(dd, i));
923 scatterwalk_advance(&dd->out_walk, 4);
924 if (dd->out_sg->length == _calc_walked(out)) {
925 dd->out_sg = scatterwalk_sg_next(dd->out_sg);
926 if (dd->out_sg) {
927 scatterwalk_start(&dd->out_walk,
928 dd->out_sg);
929 dst = sg_virt(dd->out_sg) +
930 _calc_walked(out);
931 }
932 } else {
933 dst++;
934 }
935 }
936
937 dd->total -= AES_BLOCK_SIZE;
938
939 BUG_ON(dd->total < 0);
940
941 /* Clear IRQ status */
942 status &= ~AES_REG_IRQ_DATA_OUT;
943 omap_aes_write(dd, AES_REG_IRQ_STATUS(dd), status);
944
945 if (!dd->total)
946 /* All bytes read! */
947 tasklet_schedule(&dd->done_task);
948 else
949 /* Enable DATA_IN interrupt for next block */
950 omap_aes_write(dd, AES_REG_IRQ_ENABLE(dd), 0x2);
951 }
952
953 return IRQ_HANDLED;
954}
955
866static const struct of_device_id omap_aes_of_match[] = { 956static const struct of_device_id omap_aes_of_match[] = {
867 { 957 {
868 .compatible = "ti,omap2-aes", 958 .compatible = "ti,omap2-aes",