Please comment on the following patch for HW accelerated kasumi + f8 and f8 encryption engine.
Regards,
Marri
------------------------------------- patch ---------------------------------
--- may03_denx/drivers/crypto/Kconfig 2007-05-03 08:39: 15.000000000 -0700
+++ 0323_denx/drivers/crypto/Kconfig 2007-05-15 13:40:56.789633768 -0700
@@ -37,6 +37,13 @@
If unsure say M. The compiled module will be
called padlock-aes.ko
+config CRYPTO_KASUMI
+ bool "Support for Kasumi driver"
+ depends on 440EPX
+ default N
+ help
+ Used in encrypting and decrypting data.
+
config CRYPTO_DEV_PADLOCK_SHA
tristate "PadLock driver for SHA1 and SHA256 algorithms"
depends on CRYPTO_DEV_PADLOCK
--- may03_denx/drivers/crypto/Makefile 2007-05-03 08:39:15.000000000 -0700
+++ 0323_denx/drivers/crypto/Makefile 2007-04-25 13:39:52.000000000 -0700
@@ -2,3 +2,4 @@
obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o
obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o
obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o
+obj-$(CONFIG_KASUMI_CRYPTO) +=kasumi.o
--- may03_denx/drivers/crypto/kasumi.h 1969-12-31 16:00: 00.000000000 -0800
+++ 0323_denx/drivers/crypto/kasumi.h 2007-05-15 15:16:27.046502312 -0700
@@ -0,0 +1,122 @@
+/**********************************************************************
+ *
+ * kasumi.h
+ * Cryptographic Driver APIs.
+ *
+ * Support for Kasumi F8 and F9 hardware crypto engine.
+ * author: tmarri@xxxxxxxx
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ *
+ *
+ * DISCLAIMER
+ *
+ * This software is provided 'as is' with no explicit or implied warranties
+ * in respect of its properties, including, but not limited to, correctness
+ * and/or fitness for purpose.
+ * ---------------------------------------------------------------------------
+ */
+#define MULTIPLE_DATA_ENC 1
+
+#define KASUMI_TEST 0
+
+/* Dynamic major number */
+#define KASUMI_MAJOR 0
+
+/* IOCTL numbers */
+#define KASUMI_IOCTL_ENCRYPT 0x100
+#define KASUMI_IOCTL_DECRYPT 0x101
+#define KASUMI_IOCTL_F8_MODE 0x102
+#define KASUMI_IOCTL_F9_MODE 0x103
+
+#define SDR0_SRST1 0x201
+#define DCR_PLB4A0 0x81
+#define DCR_UIC0_SR 0xC0
+#define DCR_UIC0_ER 0xC2
+
+/* Need to disable READ pipeline to avoid hang on PLB bus */
+#define DISABLE_RD_PIPE_LINE 0xf9ffffff
+#define KASUMI_RESET_MSK 0x00002000
+#define KASU0_BASE 0x0E0180000ULL
+
+#define KASU0_DATA_IN0 0x0
+#define KASU0_DATA_OUT0 0x0
+#define KASU0_DATA_IN1 0x4
+#define KASU0_DATA_OUT1 0x4
+#define KASU0_CTRL 0x8
+#define KASU0_STATUS 0x8
+#define KASU0_MODE 0xc
+#define KASU0_KEY0 0x10
+#define KASU0_KEY1 0x14
+#define KASU0_KEY2 0x18
+#define KASU0_KEY3 0x1c
+#define KASU0_COUNT 0x20
+#define KASU0_CONFIG 0x24
+#define KASU0_FRESH 0x28
+
+#define KASUMI_DEC_MODE 0x02000000
+#define KASUMI_ENC_MODE 0x03000000
+#define KASUMI_F8_ENC_MODE 0x05000000
+#define KASUMI_F8_DEC_MODE 0x04000000
+#define KASUMI_F9_ENC_MODE 0x09000000
+#define KASUMI_F9_DEC_MODE 0x08000000
+
+#define KASUMI_DATA_READY 0x01000000
+
+#define KASUMI_VAL_KEYS 0x04000000
+#define KASUMI_VAL_MODE 0x02000000
+#define KASUMI_VAL_DATA 0x08000000
+#define KASUMI_VAL_CFG 0x10000000
+#define KASUMI_VAL_COUNT 0x20000000
+#define KASUMI_VAL_FRESH 0x40000000
+
+#define kasumi_byte_swap(x) ((((uint)x & 0xff000000) >> 24) | \
+ (((uint)x & 0x00ff0000) >> 8) | \
+ (((uint)x & 0x0000ff00) << 8) | \
+ (((uint)x & 0x000000ff) << 24))
+
+struct kasumi_desc {
+ uint mode;
+ uint count;
+ uint config;
+ uint fresh;
+ uint key0;
+ uint key1;
+ uint key2;
+ uint key3;
+ uint *data_in;
+ uint *data_out;
+};
+struct kasumi_regs{
+ uint *ctrl;
+ uint *status;
+ uint *mode;
+ uint *key0;
+ uint *key1;
+ uint *key2;
+ uint *key3;
+ uint *data_in0;
+ uint *data_in1;
+ uint *data_out0;
+ uint *data_out1;
+ uint *count;
+ uint *config;
+ uint *fresh;
+};
+
+struct kasumi_f8_f9_desc {
+ struct kasumi_desc kd;
+ uint len;
+ uint bearer;
+ uint direction;
+};
+int kasumi_f9_encrypt(struct kasumi_desc *test, uint len, uint direction);
+int kasumi_f8_encrypt(struct kasumi_desc *test, uint len, uint bearer,
+ uint direction);
+int kasumi_decrypt(struct kasumi_desc *test);
+int kasumi_encrypt(struct kasumi_desc *test);
--- may03_denx/drivers/crypto/kasumi.c 1969-12-31 16:00:00.000000000 -0800
+++ 0323_denx/drivers/crypto/kasumi.c 2007-05-15 15:16: 27.045502464 -0700
@@ -0,0 +1,898 @@
+/*
+ * Cryptographic Driver APIs.
+ *
+ * Support for Kasumi F8 and F9 hardware crypto engine.
+ * author: tmarri@xxxxxxxx
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ *
+ *
+ * DISCLAIMER
+ *
+ * This software is provided 'as is' with no explicit or implied warranties
+ * in respect of its properties, including, but not limited to, correctness
+ * and/or fitness for purpose.
+ * ---------------------------------------------------------------------------
+ */
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <asm/io.h>
+#include <linux/fcntl.h>
+#include <linux/cdev.h>
+#include <linux/seq_file.h>
+#include <linux/fs.h> /* everything... */
+
+#include <asm/system.h>
+#include <asm/uaccess.h> /* copy_*_user */
+
+#include <asm/ibm44x.h>
+#include "kasumi.h "
+
+static int kasumi_major = KASUMI_MAJOR;
+static uint data_in[512], data_out[512];
+static uint *kasumi_base;
+static struct kasumi_regs kreg;
+
+#ifdef KASUMI_TEST
+/*
+** Function to test KASUMI encrypt and decrypt modes
+*/
+static int kasumi_test(void)
+{
+ struct kasumi_desc test_in, test_out;
+ uint data_in0[2], data_in1[2], data_out0[2], data_out1[2];
+
+ test_in.key0 = 0x9F45D62B;
+ test_in.key1 = 0x00B3C582;
+ test_in.key2 = 0x10492C95;
+ test_in.key3 = 0x48FF8148;
+ data_in0[0] = 0xEA024714;
+ data_in0[1] = 0xAD5C4D84;
+ test_in.data_in = &data_in0[0];
+ test_in.data_out = &data_out0[0];
+
+ printk(KERN_INFO "Encryption test\n");
+ kasumi_encrypt(&test_in);
+
+ test_out.key0 = 0x9F45D62B;
+ test_out.key1 = 0x00B3C582;
+ test_out.key2 = 0x10492C95;
+ test_out.key3 = 0x48FF8148;
+ test_out.data_in = &data_in1[0];
+ test_out.data_out = &data_out1[0];
+ test_out.data_in[0] = data_out0[0];
+ test_out.data_in[1] = data_out0[1];
+
+ printk(KERN_INFO "Decryption test\n");
+ kasumi_decrypt(&test_out);
+ printk(KERN_INFO "data_out0[0]=0x%x\n", data_out0[0]);
+ printk(KERN_INFO "data_out0[1]=0x%x\n", data_out0[1]);
+ printk(KERN_INFO "data_out1[0]=0x%x\n", data_out1[0]);
+ printk(KERN_INFO "data_out1[1]=0x%x\n", data_out1[1]);
+
+ if (data_in0[0] == data_out1[0])
+ printk(KERN_INFO " Data 0 matched\n");
+ else
+ printk(KERN_INFO " Data 0 NOT matched\n");
+ if (data_in0[1] == data_out1[1])
+ printk(KERN_INFO " Data 1 matched\n");
+ else
+ printk(KERN_INFO " Data 1 NOT matched\n");
+ return 0;
+}
+
+/*
+** Function to test F* mode of encryption
+*/
+static void kasumi_test_f8_1(void)
+{
+ int len = 0x31E, bearer = 0xc, direction = 1;
+ struct kasumi_desc test_in;
+ struct kasumi_desc test_out;
+ int i = 0;
+ uint data_in[32] = {
+ 0x7EC61272, 0x743BF161, 0x4726446A, 0x6C38CED1,
+ 0x66F6CA76, 0xEB543004, 0x4286346C, 0xEF130F92,
+ 0x922B0345, 0x0D3A9975, 0xE5BD2EA0, 0xEB55AD8E,
+ 0x1B199E3E, 0xC4316020, 0xE9A1B285, 0xE7627953,
+ 0x59B7BDFD, 0x39BEF4B2, 0x484583D5, 0xAFE082AE,
+ 0xE638BF5F, 0xD5A60619, 0x3901A08F, 0x4AB41AAB, 0x9B134880
+ };
+ uint data_cmp[32] = {
+ 0xD1E2DE70, 0xEEF86C69, 0x64FB542B, 0xC2D460AA,
+ 0xBFAA10A4, 0xA093262B, 0x7D199E70, 0x6FC2D489,
+ 0x15532969, 0x10F3A973, 0x012682E4, 0x1C4E2B02,
+ 0xBE2017B7, 0x253BBF93, 0x09DE5819, 0xCB42E819,
+ 0x56F4C99B, 0xC9765CAF, 0x53B1D0BB, 0x8279826A,
+ 0xDBBC5522, 0xE915C120, 0xA618A5A7, 0xF5E89708, 0x9339650F
+ };
+ uint data_out0[32];
+ uint data_out1[32];
+
+ test_in.key0 = 0x2BD6459F;
+ test_in.key1 = 0x82C5B300;
+ test_in.key2 = 0x952C4910;
+ test_in.key3 = 0x4881FF48;
+
+ test_in.count = 0x72A4F20F;
+
+ printk(KERN_INFO "in CFG=0x%x\n", test_in.config);
+ test_in.data_in = &data_in[0];
+ test_in.data_out = &data_out0[0];
+ kasumi_f8_encrypt(&test_in, len, bearer, direction);
+
+ i = 0;
+ for (i = 0; i < 32; i++) {
+ if (data_out0[i] != data_cmp[i])
+ printk(KERN_INFO
+ "data MISS match data recieved=0x%x expected =0x%x\n\nn",
+ data_out0[i], data_cmp[i]);
+ else
+ printk(KERN_INFO "data MATCHED\n");
+
+ }
+}
+
+/*
+** Function to test F9 mode of encryption
+*/
+static void kasumi_test_f9(void)
+{
+ struct kasumi_desc test_in;
+ int i = 0;
+ uint direction = 0, len = 189;
+ uint data_in[6] = {
+ 0x6B227737,
+ 0x296F393C,
+ 0x8079353E,
+ 0xDC87E2E8,
+ 0x05D2EC49,
+ 0xA4F2D8E0
+ };
+ uint data_out[2];
+
+ test_in.key0 = 0x2BD6459F;
+ test_in.key1 = 0x82C5B300;
+ test_in.key2 = 0x952C4910;
+ test_in.key3 = 0x4881FF48;
+ test_in.fresh = 0x05D2EC49;
+ test_in.count = 0x38A6F056;
+
+ for (i = 0; i < 6; i++)
+ data_in[i] = kasumi_byte_swap(data_in[i]);
+ test_in.data_in = &data_in[0];
+ test_in.data_out = &data_out[0];
+ kasumi_f9_encrypt(&test_in, len, direction);
+ if (data_out[0] == 0xf63bd72c)
+ printk(KERN_INFO
+ " F9 test passed Expected data = 0x%x data recieved=0x%x\n",
+ 0xf63bd72c, data_out[0]);
+ else
+ printk(KERN_INFO
+ " \n F9 test Failed Expected data = 0x%x data recieved=0x%x\n",
+ 0xf63bd72c, data_out[0]);
+
+}
+#endif
+
+/*
+**FUNCTION:kasumi_encrypt_decrypt()
+** args: kd is kasumi descriptor which holds all the requred data to do kasumi
+** mode encryption and decryption
+** Description: This function follows the kasumi algorithm to encrypt and decrypt.
+** 1. Check for interrupt bit KDA(Kasumi Data Availability)
+** 2. check for data availability bit in CTRL register and write 1 to clear it
+** 3. Set keys
+** 4. set mode
+** 5. set inputdata
+** 6. validate keys , mode and data
+** 7. wait for the data availability and then read the data.
+** This function can only do 64bit data encryption at given time
+** Please check the test() in the comment section.
+*/
+static int kasumi_encrypt_decrypt(struct kasumi_desc *kd)
+{
+ uint time_out = 100;
+
+ /*
+ * CTRL_STATUS[0] to reset the DATA out mechanism
+ */
+ printk(KERN_WARNING "kreg.ctrl 0x%x\n", kreg.ctrl);
+ out_be32(kreg.ctrl, in_be32(kreg.ctrl) | KASUMI_DATA_READY);
+ /*
+ * Check for interrupt bit for data availability bit set .
+ * if set clear it
+ */
+ if (mfdcr(DCR_UIC0_SR) & 0x08000000) {
+ mtdcr(DCR_UIC0_SR, (mfdcr(DCR_UIC0_SR) & ~0x08000000));
+ }
+
+ /*
+ * Check if KASUMI is ready for data input
+ */
+ if (!mfdcr(DCR_UIC0_SR) & 0x10000000)
+ printk(KERN_INFO "KASUMI is ready for data\n");
+
+ /*
+ * need keys
+ */
+ out_be32(kreg.key0, kd->key0);
+ out_be32(kreg.key1, kd->key1);
+ out_be32(kreg.key2, kd->key2);
+ out_be32(kreg.key3, kd->key3);
+ /*
+ * Check for correct mode
+ */
+ if ((kd->mode != KASUMI_ENC_MODE) && (kd->mode != KASUMI_DEC_MODE)) {
+ printk(KERN_INFO "KASUMI ERROR: invalid mode\n\n");
+ return -1;
+ }
+
+ /*
+ * set mode
+ */
+ out_be32(kreg.mode, kd->mode);
+ /*
+ * write data
+ */
+ if ((kd->data_in != NULL) && (kd->data_in)) {
+ out_be32(kreg.data_in0 , kd->data_in[0]);
+ out_be32(kreg.data_in1, kd->data_in[1]);
+ } else {
+ printk(KERN_INFO "No data passed\n");
+ return -1;
+ }
+
+ /*
+ * validate data CTRL_STAT[4]
+ * Validate mode CTRL_STA[1] = 1
+ * vlaidatkeys keys CTRL_STAT[2] = 1
+ */
+ out_be32(kreg.ctrl, in_be32(kreg.ctrl) | (KASUMI_VAL_DATA |
+ KASUMI_VAL_KEYS |
+ KASUMI_VAL_MODE));
+ /*
+ * Just in case DATA validation not finished
+ */
+ time_out = 100;
+ while (in_be32(kreg.ctrl) & KASUMI_VAL_DATA) {
+ time_out--;
+ mdelay(1);
+ if (time_out <= 0) {
+ printk(KERN_INFO
+ "ERROR: at line %d Timed out KASU0_CTRL=0x%x\n",
+ __LINE__, in_be32(kreg.ctrl));
+ break;
+ }
+ }
+
+ /*
+ * Check if data available bit is set
+ */
+ if (!mfdcr(DCR_UIC0_SR) & 0x08000000)
+ printk(KERN_WARNING
+ "KASUMI data NOT available and NO KDA interrupt occured\n");
+
+ /*
+ * Is data avaialbel
+ */
+ time_out = 100;
+ while (!(in_be32(kreg.status) & KASUMI_DATA_READY)) {
+ time_out--;
+ mdelay(1);
+ if (time_out <= 0) {
+ printk(KERN_INFO "line %d Timed out KASU0_CTRL=0x%x\n",
+ __LINE__, in_be32(kreg.ctrl));
+ break;
+ }
+ }
+
+ if (!(in_be32(kreg.status ) & KASUMI_DATA_READY))
+ printk(KERN_WARNING "Data is not ready\n");
+
+ kd->data_out[0] = in_be32(kreg.data_out0);
+ kd->data_out[1] = in_be32(kreg.data_out1);
+ return 0;
+}
+
+/*
+** Kasumi encryption function calls the kasumi_encrypt_decrypt()
+**
+*/
+int kasumi_encrypt(struct kasumi_desc *test)
+{
+ test->mode = KASUMI_ENC_MODE;
+ if (kasumi_encrypt_decrypt(test) != 0) {
+ printk(KERN_INFO "kasumi_encrypt_decrypt returned error");
+ return -1;
+ } else
+ return 0;
+
+}
+
+/*
+** Kasumi encryption function calls the kasumi_encrypt_decrypt()
+**
+*/
+int kasumi_decrypt(struct kasumi_desc *test)
+{
+ test->mode = KASUMI_DEC_MODE;
+ if (kasumi_encrypt_decrypt(test) != 0) {
+ printk(KERN_INFO "kasumi_encrypt_decrypt returned error");
+ return -1;
+ } else
+ return 0;
+
+}
+
+/*
+**
+**FUNCTION:kasumi_encrypt_decrypt()
+**args: kd is kasumi descriptor which holds all the requred data to do kasumi mode encryption and decryption
+**Description: This function follows the kasumi algorithm to encrypt and decrypt.
+** 1. Check for interrupt bit KDA(Kasumi Data Availability)
+** 2. check for data availability bit in CTRL register and write 1 to clear it
+** 3. Set keys
+** 4. set mode
+** 5. set config
+** 6. set count
+** 7. set inputdata
+** 8. validate keys , mode , config , count and data
+** 9. wait for the data availability and then read the data.
+** This function can encrypt block data
+** Please check the test_f8_1() in the comment section.
+*/
+static int kasumi_f8_encrypt_decrypt(struct kasumi_desc *kd)
+{
+ int time_out = 10000;
+ int len = 0;
+ int i = 0;
+
+ len = ((kd->config & 0xff) << 8) | ((kd->config & 0xff00) >> 8);
+ /*Reset data out mechanism */
+ /*CTRL_STATUS[0] to reset the DATA out mechanism */
+ out_be32(kreg.ctrl, in_be32(kreg.ctrl) | KASUMI_DATA_READY);
+
+ if (mfdcr(DCR_UIC0_SR) & 0x08000000)
+ mtdcr(DCR_UIC0_SR, (mfdcr(DCR_UIC0_SR) & ~0x08000000));
+
+ if (!mfdcr(DCR_UIC0_SR) & 0x10000000)
+ printk(KERN_INFO "KASUMI is NOT ready for data\n");
+
+ /*need keys */
+
+ out_be32(kreg.key0, kd->key0);
+ out_be32(kreg.key1, kd->key1);
+ out_be32(kreg.key2, kd->key2);
+ out_be32(kreg.key3, kd->key3);
+ /*write config */
+ out_be32(kreg.config, kd->config);
+ /* Write count */
+ out_be32(kreg.count, kd->count);
+ /*set mode */
+ if (kd->mode != KASUMI_F8_ENC_MODE) {
+ printk(KERN_INFO "KASUMI Invalid mode\n");
+ return -1;
+ }
+
+ out_be32(kreg.mode, kd->mode);
+
+ /*
+ * write data
+ * validate data CTRL_STAT[4]
+ * Validate mode CTRL_STA[1] = 1
+ * vlaidatkeys keys CTRL_STAT[2] = 1
+ * vlaidatkeys count and config
+ */
+ out_be32(kreg.ctrl, in_be32(kreg.ctrl) | (KASUMI_VAL_CFG |
+ KASUMI_VAL_COUNT |
+ KASUMI_VAL_KEYS |
+ KASUMI_VAL_MODE));
+ time_out = 100;
+ /*
+ ** Just in case DATA validation is not finished
+ */
+ while (in_be32( kreg.ctrl) & (KASUMI_VAL_CFG | KASUMI_VAL_COUNT |
+ KASUMI_VAL_KEYS | KASUMI_VAL_MODE)) {
+ time_out--;
+ mdelay(1);
+ if (time_out <= 0) {
+ printk(KERN_INFO
+ " KASUMI:line %d Timed out KASU0_CTRL=0x%x\n",
+ __LINE__, in_be32(kreg.ctrl));
+ break;
+ }
+
+ }
+
+ if (in_be32(kreg.ctrl )
+ & (KASUMI_VAL_CFG | KASUMI_VAL_COUNT |
+ KASUMI_VAL_KEYS | KASUMI_VAL_MODE))
+ printk(KERN_WARNING
+ " CFG COUNT KEYS MODE validation NOT complete\n");
+ /*
+ ** Here we encode 64bits a time till whole block is encrypted
+ */
+ while (len > 0) {
+ if ((&kd->data_in[i] != NULL) && (&kd->data_in[i + 1] != NULL)) {
+ out_be32(kreg.data_in0, kd->data_in[i]);
+ out_be32(kreg.data_in1, kd->data_in[i + 1]);
+ } else {
+ printk(KERN_INFO "No data passed\n");
+ break;
+ }
+
+ out_be32(kreg.ctrl, in_be32(kreg.ctrl) | KASUMI_VAL_DATA);
+ time_out = 100;
+ while (in_be32(kreg.ctrl) & (KASUMI_VAL_DATA)) {
+ time_out--;
+ if (time_out <= 0) {
+ printk(KERN_INFO
+ "KASUMI: line %d Timed out KASU0_CTRL=0x%x\n",
+ __LINE__, in_be32(kreg.ctrl));
+ break;
+ }
+ }
+
+ if (in_be32(kreg.ctrl) & (KASUMI_VAL_DATA))
+ printk(KERN_WARNING "Data validation NOT complete\n");
+
+ time_out = 100;
+ while (!(in_be32( kreg.status) & KASUMI_DATA_READY)) {
+ mdelay(1);
+ time_out--;
+ if (time_out <= 0) {
+ printk(KERN_INFO
+ "line %d Timed out KASU0_CTRL=0x%x\n",
+ __LINE__, in_be32(kreg.ctrl));
+ break;
+ }
+
+ }
+
+ if (!(in_be32(kreg.status) & KASUMI_DATA_READY)) {
+ printk(KERN_WARNING "Data is not ready\n");
+ break;
+ }
+
+ kd->data_out[i] = kasumi_byte_swap(in_be32(kreg.data_out0));
+ kd->data_out[i + 1] = kasumi_byte_swap(in_be32(kreg.data_out1));
+ /*
+ ** CTRL_STATUS[0] to reset the DATA out mechanism
+ */
+ out_be32(kreg.ctrl, KASUMI_DATA_READY);
+ if (!mfdcr(DCR_UIC0_SR) & 0x10000000)
+ printk(KERN_WARNING "KASUMI is NOT ready for data\n");
+
+ i += 2;
+ len = len - 64;
+ }
+
+ return 0;
+}
+
+/*
+** arg1: hte filled kasumi_desc structure pointer
+** arg2: len
+** arg3: bearer
+** arg4: direction
+*/
+int kasumi_f8_encrypt(struct kasumi_desc *test, uint len, uint bearer,
+ uint direction)
+{
+ int i = 0;
+
+ test->config = (len << 16 | bearer << 1 | direction);
+ test->mode = KASUMI_F8_ENC_MODE;
+ test->key0 = kasumi_byte_swap(test->key0);
+ test->key1 = kasumi_byte_swap(test->key1);
+ test->key2 = kasumi_byte_swap(test->key2);
+ test->key3 = kasumi_byte_swap(test->key3);
+ test->count = kasumi_byte_swap(test->count);
+ test->config = kasumi_byte_swap(test->config);
+ len = len / (32);
+
+ for (i = 0; i <= len; i++)
+ test->data_in[i] = kasumi_byte_swap(test->data_in[i]);
+
+ if (kasumi_f8_encrypt_decrypt(test) != 0) {
+ printk(KERN_INFO
+ "kasumi_f8_encrypt_decrypt() returned error\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+**
+**FUNCTION:kasumi_encrypt_decrypt()
+**args: kd is kasumi descriptor which holds all the requred data to do kasumi mode encryption and decryption
+**Description: This function follows the kasumi algorithm to encrypt and decrypt.
+** 1. Check for interrupt bit KDA(Kasumi Data Availability)
+** 2. check for data availability bit in CTRL register and write 1 to clear it
+** 3. Set keys
+** 4. set mode
+** 5. set config
+** 6. set count
+** 7. set inputdata
+** 8. validate keys , mode , config , count and data
+** 9. wait for the data availability and then read the data.
+** This function can encrypt block data
+** Please check the test_f9_1() in the comment section.
+*/
+int kasumi_f9(struct kasumi_desc *kd)
+{
+ int time_out = 10000;
+ int len = 0;
+ int i = 0;
+
+ /*
+ ** Get the lenght of the block we are going to encode
+ */
+ len = ((kd->config & 0xff) << 8) | ((kd->config & 0xff00) >> 8);
+
+ /*
+ ** CTRL_STATUS[0] to reset the DATA out mechanism
+ */
+ out_be32(kreg.ctrl, in_be32(kreg.ctrl) | KASUMI_DATA_READY);
+ if (mfdcr(DCR_UIC0_SR) & 0x08000000)
+ mtdcr(DCR_UIC0_SR, (mfdcr(DCR_UIC0_SR) & ~0x08000000));
+
+ if (!(mfdcr(DCR_UIC0_SR) & 0x10000000))
+ printk(KERN_INFO "KASUMI is ready for data\n");
+
+ /*
+ ** need keys
+ */
+ out_be32(kreg.key0, kd->key0);
+ out_be32(kreg.key1, kd->key1);
+ out_be32(kreg.key2, kd->key2);
+ out_be32(kreg.key3, kd->key3);
+ /*
+ ** write config
+ */
+ out_be32(kreg.config, kd->config);
+ /*
+ ** Write count
+ */
+ out_be32(kreg.count, kd->count);
+ /*
+ ** set fresh
+ */
+ out_be32(kreg.fresh, kd->fresh);
+ /*
+ ** set mode
+ */
+ if (kd->mode != KASUMI_F9_ENC_MODE) {
+ printk(KERN_INFO "KASUMI Invalid mode\n");
+ return -1;
+ }
+
+ out_be32(kreg.mode, kd->mode);
+ /*
+ * write data
+ * validate data CTRL_STAT[4]
+ * Validate mode CTRL_STA[1] = 1
+ * vlaidatkeys keys CTRL_STAT[2] = 1
+ * vlaidatkeys count and config
+ */
+ out_be32(kreg.ctrl,
+ in_be32(kreg.ctrl) |
+ (KASUMI_VAL_CFG | KASUMI_VAL_COUNT | KASUMI_VAL_KEYS |
+ KASUMI_VAL_MODE | KASUMI_VAL_FRESH));
+ time_out = 100;
+ /*
+ ** Just in case validation is not complete.
+ */
+ while (in_be32(kreg.ctrl) & (KASUMI_VAL_CFG |
+ KASUMI_VAL_COUNT | KASUMI_VAL_KEYS
+ | KASUMI_VAL_MODE | KASUMI_VAL_FRESH)) {
+ time_out--;
+ mdelay(1);
+ if (time_out <= 0) {
+ printk(KERN_INFO "line %d Timed out KASU0_CTRL=0x%x\n",
+ __LINE__, in_be32(kreg.ctrl));
+ break;
+ }
+ }
+
+ if (in_be32(kreg.ctrl) & (KASUMI_VAL_CFG |
+ KASUMI_VAL_COUNT | KASUMI_VAL_KEYS
+ | KASUMI_VAL_MODE | KASUMI_VAL_FRESH))
+ printk(KERN_WARNING
+ " CFG COUNT KEYS MODE validation NOT complete\n");
+
+ /*
+ ** Loop around this code till we encode all 64bit data blocks
+ */
+ while (len > 0) {
+
+ if ((&kd->data_in[i] != NULL) && (&kd->data_in[i + 1] != NULL)) {
+ out_be32(kreg.data_in0, kd->data_in[i]);
+ out_be32( kreg.data_in1, kd->data_in[i + 1]);
+ } else {
+ printk(KERN_INFO "No data passed\n");
+ return -1;
+ }
+
+ out_be32(kreg.ctrl, in_be32(kreg.ctrl) | KASUMI_VAL_DATA);
+ time_out = 100;
+
+ while (in_be32(kreg.ctrl) & (KASUMI_VAL_DATA)) {
+ time_out--;
+ mdelay(1);
+ if (time_out <= 0) {
+ printk(KERN_INFO
+ "line %d Timed out KASU0_CTRL=0x%x\n",
+ __LINE__, in_be32(kreg.ctrl));
+ break;
+ }
+ }
+
+ if (in_be32( kreg.ctrl) & (KASUMI_VAL_DATA)) {
+ printk(KERN_INFO "Data validation NOT complete\n");
+ }
+
+ if (!(mfdcr(DCR_UIC0_SR) & 0x10000000))
+ printk(KERN_INFO "KASUMI is NOT ready for data\n");
+
+ i += 2;
+ len = len - 64;
+ }
+
+ if (!(mfdcr(DCR_UIC0_SR) & 0x08000000))
+ printk(KERN_INFO
+ "KASUMI data NOT available and NO KDA interrupt occured\n");
+
+ /*
+ ** Is data avaialbel
+ */
+ time_out = 100;
+ while (!(in_be32(kreg.status) & KASUMI_DATA_READY)) {
+ time_out--;
+ mdelay(1);
+ if (time_out <= 0) {
+ printk(KERN_INFO "line %d Timed out KASU0_CTRL=0x%x\n",
+ __LINE__, in_be32(kreg.ctrl));
+ }
+
+ }
+
+ if (!(in_be32(kreg.status) & KASUMI_DATA_READY))
+ printk(KERN_WARNING "Data is not ready\n");
+ kd->data_out[0] = kasumi_byte_swap(in_be32(kreg.data_out0));
+ kd->data_out[1] = kasumi_byte_swap(in_be32(kreg.data_out1));
+ out_be32( kreg.ctrl, KASUMI_DATA_READY);
+ return 0;
+}
+
+/*
+** arg1: kasumi_desc structure
+** arg2: len
+** arg3: direction
+*/
+int kasumi_f9_encrypt(struct kasumi_desc *test, uint len, uint direction)
+{
+ test->config = (len << 16 | direction);
+ test->config = (0x00BD0000);
+ test->mode = KASUMI_F9_ENC_MODE;
+ test->key0 = kasumi_byte_swap(test->key0);
+ test->key1 = kasumi_byte_swap(test->key1);
+ test->key2 = kasumi_byte_swap(test->key2);
+ test->key3 = kasumi_byte_swap(test->key3);
+ test->count = kasumi_byte_swap(test->count);
+ test->config = kasumi_byte_swap(test->config);
+ test->fresh = kasumi_byte_swap(test->fresh);
+
+ if (kasumi_f9(test) != 0) {
+ printk(KERN_INFO
+ "kasumi_f8_encrypt_decrypt() returned error\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+**IOCTL function to let this driver usaed from user space.
+**
+*/
+static int kasumi_ioctl(struct inode *inode, struct file *filep,
+ unsigned int cmd, unsigned long arg)
+{
+ int kerr = 0;
+ struct kasumi_f8_f9_desc kd_f89;
+
+ kd_f89.kd.data_in = &data_in[0];
+ kd_f89.kd.data_out = &data_out[0];
+
+ switch (cmd) {
+ case KASUMI_IOCTL_ENCRYPT:
+ {
+ copy_from_user(&kd_f89,
+ (struct kasumi_f8_f9_desc __user *)arg,
+ sizeof(struct kasumi_f8_f9_desc));
+ kerr = kasumi_encrypt(&kd_f89.kd);
+ copy_to_user(&kd_f89,
+ (struct kasumi_f8_f9_desc __user *)arg,
+ sizeof(struct kasumi_f8_f9_desc));
+
+ if (kerr < 0)
+ return kerr;
+ return 0;
+ break;
+ }
+ case KASUMI_IOCTL_DECRYPT:
+ {
+ printk(KERN_INFO "kd_f89.kd.data_in[0]=0x%x\n",
+ kd_f89.kd.data_in[0]);
+ printk(KERN_INFO "kd_f89.kd.data_in[1]=0x%x\n",
+ kd_f89.kd.data_in[1]);
+ copy_from_user(&kd_f89,
+ (struct kasumi_f8_f9_desc __user *)arg,
+ sizeof(struct kasumi_f8_f9_desc));
+ kerr = kasumi_decrypt(&kd_f89.kd);
+ copy_to_user(&kd_f89,
+ (struct kasumi_f8_f9_desc __user *)arg,
+ sizeof(struct kasumi_f8_f9_desc));
+ if (kerr < 0)
+ return kerr;
+ break;
+ }
+ case KASUMI_IOCTL_F8_MODE:
+ {
+ copy_from_user(&kd_f89,
+ (struct kasumi_f8_f9_desc __user *)arg,
+ sizeof(struct kasumi_f8_f9_desc));
+ kerr =
+ kasumi_f8_encrypt(&kd_f89.kd, kd_f89.len,
+ kd_f89.bearer, kd_f89.direction);
+ copy_to_user(&kd_f89,
+ (struct kasumi_f8_f9_desc __user *)arg,
+ sizeof(struct kasumi_f8_f9_desc));
+ if (kerr < 0)
+ return kerr;
+ break;
+ }
+ case KASUMI_IOCTL_F9_MODE:
+ {
+ copy_from_user(&kd_f89,
+ (struct kasumi_f8_f9_desc __user *)arg,
+ sizeof(struct kasumi_f8_f9_desc));
+ kerr =
+ kasumi_f9_encrypt(&kd_f89.kd, kd_f89.len,
+ kd_f89.direction);
+ copy_to_user(&kd_f89,
+ (struct kasumi_f8_f9_desc __user *)arg,
+ sizeof(struct kasumi_f8_f9_desc));
+ if (kerr < 0)
+ return kerr;
+ break;
+ }
+ default:
+ return -ENOTTY;
+ }
+
+ return 0;
+}
+
+/*
+** file operations
+*/
+struct file_operations kasumi_fops = {
+ .ioctl = kasumi_ioctl,
+};
+
+/*
+** Moudle initialization
+**/
+int kasumi_init_module(void)
+{
+ int kerr = 0;
+ dev_t dev = MKDEV(kasumi_major, 0);
+ struct cdev *k_cdev = cdev_alloc();
+
+ printk(KERN_INFO "Loading Kasumi Driver\n");
+ if (kasumi_major)
+ kerr = register_chrdev_region(dev, 1, "kasumi");
+ else {
+ kerr = alloc_chrdev_region(&dev, 0, 1, "kasumi");
+ kasumi_major = MAJOR(dev);
+ }
+
+ if (kerr < 0) {
+ printk(KERN_ERR "KASUMI:Failed to get major number");
+ return kerr;
+ }
+
+ cdev_init(k_cdev, &kasumi_fops);
+ k_cdev->owner = THIS_MODULE;
+ k_cdev->ops = &kasumi_fops;
+ kerr = cdev_add(k_cdev, MKDEV(kasumi_major, 0), 1);
+ if (kerr < 0)
+ return kerr;
+
+ /*
+ * setup register base address
+ */
+ kasumi_base = ioremap64(0x0E0180000ULL, 0x80);
+ if (!kasumi_base) {
+ printk(KERN_INFO "ioremap falied for address 0xE0180000\n");
+ return -1;
+ }
+
+ /*
+ **Register address assignments
+ **
+ */
+ kreg.ctrl = ((uint *) ((u8 *) kasumi_base + KASU0_CTRL));
+ kreg.status = ((uint *) ((u8 *) kasumi_base + KASU0_STATUS));
+ kreg.mode = ((uint *) ((u8 *) kasumi_base + KASU0_MODE));
+ kreg.key0 = ((uint *) ((u8 *) kasumi_base + KASU0_KEY0));
+ kreg.key1 = ((uint *) ((u8 *) kasumi_base + KASU0_KEY1));
+ kreg.key2 = ((uint *) ((u8 *) kasumi_base + KASU0_KEY2));
+ kreg.key3 = ((uint *) ((u8 *) kasumi_base + KASU0_KEY3));
+ kreg.count = ((uint *) ((u8 *) kasumi_base + KASU0_COUNT));
+ kreg.config = ((uint *) ((u8 *) kasumi_base + KASU0_CONFIG));
+ kreg.fresh = ((uint *) ((u8 *) kasumi_base + KASU0_FRESH));
+ kreg.data_in0 = ((uint *) ((u8 *) kasumi_base + KASU0_DATA_IN0));
+ kreg.data_in1 = ((uint *) ((u8 *) kasumi_base + KASU0_DATA_IN1));
+ kreg.data_out0 = ((uint *) ((u8 *) kasumi_base + KASU0_DATA_OUT0));
+ kreg.data_out1 = ((uint *) ((u8 *) kasumi_base + KASU0_DATA_OUT1));
+
+ /*
+ ** reset KASUMI core
+ */
+ SDR_WRITE(SDR0_SRST1, SDR_READ(SDR0_SRST1) | KASUMI_RESET_MSK);
+ SDR_WRITE(SDR0_SRST1, SDR_READ(SDR0_SRST1) & (~KASUMI_RESET_MSK));
+ /*
+ ** Disable the read pipe line. Otherwise it may cause hang on PLB
+ */
+ mtdcr(DCR_PLB4A0, mfdcr(DCR_PLB4A0) & DISABLE_RD_PIPE_LINE);
+ mtdcr(DCR_UIC0_ER, (mfdcr(DCR_UIC0_ER) | 0x18000000));
+
+ /*
+ ** Kasumi test
+ */
+#ifdef KASUMI_TEST
+ kasumi_test();
+ /*
+ ** f8 mode
+ */
+ kasumi_test_f8_1();
+ /*
+ ** f9 mode
+ */
+ kasumi_test_f9();
+#endif
+ return 0;
+}
+
+/*
+ * Cleanup module
+ */
+void kasumi_cleanup_module(void)
+{
+ iounmap(kasumi_base);
+ printk(KERN_INFO "Exiting Kasumi Driver\n");
+}
+
+EXPORT_SYMBOL(kasumi_f9_encrypt);
+EXPORT_SYMBOL(kasumi_f8_encrypt);
+EXPORT_SYMBOL(kasumi_encrypt);
+EXPORT_SYMBOL(kasumi_decrypt);
+module_init(kasumi_init_module);
+module_exit(kasumi_cleanup_module);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tirumala Marri <tmarri@xxxxxxxx>");
+MODULE_DESCRIPTION("Kasumi security engine driver");
--
Marri T Reddy
San Jose,CA
No day but today