From fc1cd99cfeb396cc9bf03c228a4e66446c526abe Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 12 May 2016 18:38:51 +0200 Subject: kernel: remove ocf support, cryptodev-linux should be used instead Signed-off-by: Felix Fietkau Signed-off-by: Ralph Sennhauser --- .../files/crypto/ocf/kirkwood/cesa_ocf_drv.c | 1302 -------------------- 1 file changed, 1302 deletions(-) delete mode 100644 target/linux/generic/files/crypto/ocf/kirkwood/cesa_ocf_drv.c (limited to 'target/linux/generic/files/crypto/ocf/kirkwood/cesa_ocf_drv.c') diff --git a/target/linux/generic/files/crypto/ocf/kirkwood/cesa_ocf_drv.c b/target/linux/generic/files/crypto/ocf/kirkwood/cesa_ocf_drv.c deleted file mode 100644 index 6fb9e09238..0000000000 --- a/target/linux/generic/files/crypto/ocf/kirkwood/cesa_ocf_drv.c +++ /dev/null @@ -1,1302 +0,0 @@ -/******************************************************************************* -Copyright (C) Marvell International Ltd. and its affiliates - -This software file (the "File") is owned and distributed by Marvell -International Ltd. and/or its affiliates ("Marvell") under the following -alternative licensing terms. Once you have made an election to distribute the -File under one of the following license alternatives, please (i) delete this -introductory statement regarding license alternatives, (ii) delete the two -license alternatives that you have not elected to use and (iii) preserve the -Marvell copyright notice above. - - -******************************************************************************** -Marvell GPL License Option - -If you received this File from Marvell, you may opt to use, redistribute and/or -modify this File in accordance with the terms and conditions of the General -Public License Version 2, June 1991 (the "GPL License"), a copy of which is -available along with the File in the license.txt file or by writing to the Free -Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or -on the worldwide web at http://www.gnu.org/licenses/gpl.txt. - -THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED -WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY -DISCLAIMED. The GPL License provides additional details about this warranty -disclaimer. -*******************************************************************************/ - -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED) -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ctrlEnv/sys/mvSysCesa.h" -#include "cesa/mvCesa.h" /* moved here before cryptodev.h due to include dependencies */ -#include -#include -#include -#include -#include "mvDebug.h" - -#include "cesa/mvMD5.h" -#include "cesa/mvSHA1.h" - -#include "cesa/mvCesaRegs.h" -#include "cesa/AES/mvAes.h" -#include "cesa/mvLru.h" - -#undef RT_DEBUG -#ifdef RT_DEBUG -static int debug = 1; -module_param(debug, int, 1); -MODULE_PARM_DESC(debug, "Enable debug"); -#undef dprintk -#define dprintk(a...) if (debug) { printk(a); } else -#else -static int debug = 0; -#undef dprintk -#define dprintk(a...) -#endif - - -/* TDMA Regs */ -#define WINDOW_BASE(i) 0xA00 + (i << 3) -#define WINDOW_CTRL(i) 0xA04 + (i << 3) - -/* interrupt handling */ -#undef CESA_OCF_POLLING -#undef CESA_OCF_TASKLET - -#if defined(CESA_OCF_POLLING) && defined(CESA_OCF_TASKLET) -#error "don't use both tasklet and polling mode" -#endif - -extern int cesaReqResources; -/* support for spliting action into 2 actions */ -#define CESA_OCF_SPLIT - -/* general defines */ -#define CESA_OCF_MAX_SES 128 -#define CESA_Q_SIZE 64 - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0) -#define FRAG_PAGE(f) (f).p -#else -#define FRAG_PAGE(f) (f) -#endif - -/* data structures */ -struct cesa_ocf_data { - int cipher_alg; - int auth_alg; - int encrypt_tn_auth; -#define auth_tn_decrypt encrypt_tn_auth - int ivlen; - int digestlen; - short sid_encrypt; - short sid_decrypt; - /* fragment workaround sessions */ - short frag_wa_encrypt; - short frag_wa_decrypt; - short frag_wa_auth; -}; - -/* CESA device data */ -struct cesa_dev { - void __iomem *sram; - void __iomem *reg; - struct mv_cesa_platform_data *plat_data; - int irq; -}; - -#define DIGEST_BUF_SIZE 32 -struct cesa_ocf_process { - MV_CESA_COMMAND cesa_cmd; - MV_CESA_MBUF cesa_mbuf; - MV_BUF_INFO cesa_bufs[MV_CESA_MAX_MBUF_FRAGS]; - char digest[DIGEST_BUF_SIZE]; - int digest_len; - struct cryptop *crp; - int need_cb; -}; - -/* global variables */ -static int32_t cesa_ocf_id = -1; -static struct cesa_ocf_data *cesa_ocf_sessions[CESA_OCF_MAX_SES]; -static spinlock_t cesa_lock; -static struct cesa_dev cesa_device; - -/* static APIs */ -static int cesa_ocf_process (device_t, struct cryptop *, int); -static int cesa_ocf_newsession (device_t, u_int32_t *, struct cryptoini *); -static int cesa_ocf_freesession (device_t, u_int64_t); -static void cesa_callback (unsigned long); -static irqreturn_t cesa_interrupt_handler (int, void *); -#ifdef CESA_OCF_POLLING -static void cesa_interrupt_polling(void); -#endif -#ifdef CESA_OCF_TASKLET -static struct tasklet_struct cesa_ocf_tasklet; -#endif - -static struct timeval tt_start; -static struct timeval tt_end; - -/* - * dummy device structure - */ - -static struct { - softc_device_decl sc_dev; -} mv_cesa_dev; - -static device_method_t mv_cesa_methods = { - /* crypto device methods */ - DEVMETHOD(cryptodev_newsession, cesa_ocf_newsession), - DEVMETHOD(cryptodev_freesession,cesa_ocf_freesession), - DEVMETHOD(cryptodev_process, cesa_ocf_process), - DEVMETHOD(cryptodev_kprocess, NULL), -}; - - - -/* Add debug Trace */ -#undef CESA_OCF_TRACE_DEBUG -#ifdef CESA_OCF_TRACE_DEBUG - -#define MV_CESA_USE_TIMER_ID 0 - -typedef struct -{ - int type; /* 0 - isrEmpty, 1 - cesaReadyGet, 2 - cesaAction */ - MV_U32 timeStamp; - MV_U32 cause; - MV_U32 realCause; - MV_U32 dmaCause; - int resources; - MV_CESA_REQ* pReqReady; - MV_CESA_REQ* pReqEmpty; - MV_CESA_REQ* pReqProcess; -} MV_CESA_TEST_TRACE; - -#define MV_CESA_TEST_TRACE_SIZE 50 - -static int cesaTestTraceIdx = 0; -static MV_CESA_TEST_TRACE cesaTestTrace[MV_CESA_TEST_TRACE_SIZE]; - -static void cesaTestTraceAdd(int type) -{ - cesaTestTrace[cesaTestTraceIdx].type = type; - cesaTestTrace[cesaTestTraceIdx].realCause = MV_REG_READ(MV_CESA_ISR_CAUSE_REG); - //cesaTestTrace[cesaTestTraceIdx].idmaCause = MV_REG_READ(IDMA_CAUSE_REG); - cesaTestTrace[cesaTestTraceIdx].resources = cesaReqResources; - cesaTestTrace[cesaTestTraceIdx].pReqReady = pCesaReqReady; - cesaTestTrace[cesaTestTraceIdx].pReqEmpty = pCesaReqEmpty; - cesaTestTrace[cesaTestTraceIdx].pReqProcess = pCesaReqProcess; - cesaTestTrace[cesaTestTraceIdx].timeStamp = mvCntmrRead(MV_CESA_USE_TIMER_ID); - cesaTestTraceIdx++; - if(cesaTestTraceIdx == MV_CESA_TEST_TRACE_SIZE) - cesaTestTraceIdx = 0; -} - -#else /* CESA_OCF_TRACE_DEBUG */ - -#define cesaTestTraceAdd(x) - -#endif /* CESA_OCF_TRACE_DEBUG */ - -unsigned int -get_usec(unsigned int start) -{ - if(start) { - do_gettimeofday (&tt_start); - return 0; - } - else { - do_gettimeofday (&tt_end); - tt_end.tv_sec -= tt_start.tv_sec; - tt_end.tv_usec -= tt_start.tv_usec; - if (tt_end.tv_usec < 0) { - tt_end.tv_usec += 1000 * 1000; - tt_end.tv_sec -= 1; - } - } - printk("time taken is %d\n", (unsigned int)(tt_end.tv_usec + tt_end.tv_sec * 1000000)); - return (tt_end.tv_usec + tt_end.tv_sec * 1000000); -} - -#ifdef RT_DEBUG -/* - * check that the crp action match the current session - */ -static int -ocf_check_action(struct cryptop *crp, struct cesa_ocf_data *cesa_ocf_cur_ses) { - int count = 0; - int encrypt = 0, decrypt = 0, auth = 0; - struct cryptodesc *crd; - - /* Go through crypto descriptors, processing as we go */ - for (crd = crp->crp_desc; crd; crd = crd->crd_next, count++) { - if(count > 2) { - printk("%s,%d: session mode is not supported.\n", __FILE__, __LINE__); - return 1; - } - - /* Encryption /Decryption */ - if(crd->crd_alg == cesa_ocf_cur_ses->cipher_alg) { - /* check that the action is compatible with session */ - if(encrypt || decrypt) { - printk("%s,%d: session mode is not supported.\n", __FILE__, __LINE__); - return 1; - } - - if(crd->crd_flags & CRD_F_ENCRYPT) { /* encrypt */ - if( (count == 2) && (cesa_ocf_cur_ses->encrypt_tn_auth) ) { - printk("%s,%d: sequence isn't supported by this session.\n", __FILE__, __LINE__); - return 1; - } - encrypt++; - } - else { /* decrypt */ - if( (count == 2) && !(cesa_ocf_cur_ses->auth_tn_decrypt) ) { - printk("%s,%d: sequence isn't supported by this session.\n", __FILE__, __LINE__); - return 1; - } - decrypt++; - } - - } - /* Authentication */ - else if(crd->crd_alg == cesa_ocf_cur_ses->auth_alg) { - /* check that the action is compatible with session */ - if(auth) { - printk("%s,%d: session mode is not supported.\n", __FILE__, __LINE__); - return 1; - } - if( (count == 2) && (decrypt) && (cesa_ocf_cur_ses->auth_tn_decrypt)) { - printk("%s,%d: sequence isn't supported by this session.\n", __FILE__, __LINE__); - return 1; - } - if( (count == 2) && (encrypt) && !(cesa_ocf_cur_ses->encrypt_tn_auth)) { - printk("%s,%d: sequence isn't supported by this session.\n", __FILE__, __LINE__); - return 1; - } - auth++; - } - else { - printk("%s,%d: Alg isn't supported by this session.\n", __FILE__, __LINE__); - return 1; - } - } - return 0; - -} -#endif - -/* - * Process a request. - */ -static int -cesa_ocf_process(device_t dev, struct cryptop *crp, int hint) -{ - struct cesa_ocf_process *cesa_ocf_cmd = NULL; - struct cesa_ocf_process *cesa_ocf_cmd_wa = NULL; - MV_CESA_COMMAND *cesa_cmd; - struct cryptodesc *crd; - struct cesa_ocf_data *cesa_ocf_cur_ses; - int sid = 0, temp_len = 0, i; - int encrypt = 0, decrypt = 0, auth = 0; - int status; - struct sk_buff *skb = NULL; - struct uio *uiop = NULL; - unsigned char *ivp; - MV_BUF_INFO *p_buf_info; - MV_CESA_MBUF *p_mbuf_info; - unsigned long flags; - - dprintk("%s()\n", __FUNCTION__); - - if( cesaReqResources <= 1 ) { - dprintk("%s,%d: ERESTART\n", __FILE__, __LINE__); - return ERESTART; - } - -#ifdef RT_DEBUG - /* Sanity check */ - if (crp == NULL) { - printk("%s,%d: EINVAL\n", __FILE__, __LINE__); - return EINVAL; - } - - if (crp->crp_desc == NULL || crp->crp_buf == NULL ) { - printk("%s,%d: EINVAL\n", __FILE__, __LINE__); - crp->crp_etype = EINVAL; - return EINVAL; - } - - sid = crp->crp_sid & 0xffffffff; - if ((sid >= CESA_OCF_MAX_SES) || (cesa_ocf_sessions[sid] == NULL)) { - crp->crp_etype = ENOENT; - printk("%s,%d: ENOENT session %d \n", __FILE__, __LINE__, sid); - return EINVAL; - } -#endif - - sid = crp->crp_sid & 0xffffffff; - crp->crp_etype = 0; - cesa_ocf_cur_ses = cesa_ocf_sessions[sid]; - -#ifdef RT_DEBUG - if(ocf_check_action(crp, cesa_ocf_cur_ses)){ - goto p_error; - } -#endif - - /* malloc a new cesa process */ - cesa_ocf_cmd = kmalloc(sizeof(struct cesa_ocf_process), GFP_ATOMIC); - - if (cesa_ocf_cmd == NULL) { - printk("%s,%d: ENOBUFS \n", __FILE__, __LINE__); - goto p_error; - } - memset(cesa_ocf_cmd, 0, sizeof(struct cesa_ocf_process)); - - /* init cesa_process */ - cesa_ocf_cmd->crp = crp; - /* always call callback */ - cesa_ocf_cmd->need_cb = 1; - - /* init cesa_cmd for usage of the HALs */ - cesa_cmd = &cesa_ocf_cmd->cesa_cmd; - cesa_cmd->pReqPrv = (void *)cesa_ocf_cmd; - cesa_cmd->sessionId = cesa_ocf_cur_ses->sid_encrypt; /* defualt use encrypt */ - - /* prepare src buffer */ - /* we send the entire buffer to the HAL, even if only part of it should be encrypt/auth. */ - /* if not using seesions for both encrypt and auth, then it will be wiser to to copy only */ - /* from skip to crd_len. */ - p_buf_info = cesa_ocf_cmd->cesa_bufs; - p_mbuf_info = &cesa_ocf_cmd->cesa_mbuf; - - p_buf_info += 2; /* save 2 first buffers for IV and digest - - we won't append them to the end since, they - might be places in an unaligned addresses. */ - - p_mbuf_info->pFrags = p_buf_info; - temp_len = 0; - - /* handle SKB */ - if (crp->crp_flags & CRYPTO_F_SKBUF) { - - dprintk("%s,%d: handle SKB.\n", __FILE__, __LINE__); - skb = (struct sk_buff *) crp->crp_buf; - - if (skb_shinfo(skb)->nr_frags >= (MV_CESA_MAX_MBUF_FRAGS - 1)) { - printk("%s,%d: %d nr_frags > MV_CESA_MAX_MBUF_FRAGS", __FILE__, __LINE__, skb_shinfo(skb)->nr_frags); - goto p_error; - } - - p_mbuf_info->mbufSize = skb->len; - temp_len = skb->len; - /* first skb fragment */ - p_buf_info->bufSize = skb_headlen(skb); - p_buf_info->bufVirtPtr = skb->data; - p_buf_info++; - - /* now handle all other skb fragments */ - for ( i = 0; i < skb_shinfo(skb)->nr_frags; i++ ) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - p_buf_info->bufSize = frag->size; - p_buf_info->bufVirtPtr = page_address(FRAG_PAGE(frag->page)) + frag->page_offset; - p_buf_info++; - } - p_mbuf_info->numFrags = skb_shinfo(skb)->nr_frags + 1; - } - /* handle UIO */ - else if(crp->crp_flags & CRYPTO_F_IOV) { - - dprintk("%s,%d: handle UIO.\n", __FILE__, __LINE__); - uiop = (struct uio *) crp->crp_buf; - - if (uiop->uio_iovcnt > (MV_CESA_MAX_MBUF_FRAGS - 1)) { - printk("%s,%d: %d uio_iovcnt > MV_CESA_MAX_MBUF_FRAGS \n", __FILE__, __LINE__, uiop->uio_iovcnt); - goto p_error; - } - - p_mbuf_info->mbufSize = crp->crp_ilen; - p_mbuf_info->numFrags = uiop->uio_iovcnt; - for(i = 0; i < uiop->uio_iovcnt; i++) { - p_buf_info->bufVirtPtr = uiop->uio_iov[i].iov_base; - p_buf_info->bufSize = uiop->uio_iov[i].iov_len; - temp_len += p_buf_info->bufSize; - dprintk("%s,%d: buf %x-> addr %x, size %x \n" - , __FILE__, __LINE__, i, (unsigned int)p_buf_info->bufVirtPtr, p_buf_info->bufSize); - p_buf_info++; - } - - } - /* handle CONTIG */ - else { - dprintk("%s,%d: handle CONTIG.\n", __FILE__, __LINE__); - p_mbuf_info->numFrags = 1; - p_mbuf_info->mbufSize = crp->crp_ilen; - p_buf_info->bufVirtPtr = crp->crp_buf; - p_buf_info->bufSize = crp->crp_ilen; - temp_len = crp->crp_ilen; - p_buf_info++; - } - - /* Support up to 64K why? cause! */ - if(crp->crp_ilen > 64*1024) { - printk("%s,%d: buf too big %x \n", __FILE__, __LINE__, crp->crp_ilen); - goto p_error; - } - - if( temp_len != crp->crp_ilen ) { - printk("%s,%d: warning size don't match.(%x %x) \n", __FILE__, __LINE__, temp_len, crp->crp_ilen); - } - - cesa_cmd->pSrc = p_mbuf_info; - cesa_cmd->pDst = p_mbuf_info; - - /* restore p_buf_info to point to first available buf */ - p_buf_info = cesa_ocf_cmd->cesa_bufs; - p_buf_info += 1; - - - /* Go through crypto descriptors, processing as we go */ - for (crd = crp->crp_desc; crd; crd = crd->crd_next) { - - /* Encryption /Decryption */ - if(crd->crd_alg == cesa_ocf_cur_ses->cipher_alg) { - - dprintk("%s,%d: cipher", __FILE__, __LINE__); - - cesa_cmd->cryptoOffset = crd->crd_skip; - cesa_cmd->cryptoLength = crd->crd_len; - - if(crd->crd_flags & CRD_F_ENCRYPT) { /* encrypt */ - dprintk(" encrypt \n"); - encrypt++; - - /* handle IV */ - if (crd->crd_flags & CRD_F_IV_EXPLICIT) { /* IV from USER */ - dprintk("%s,%d: IV from USER (offset %x) \n", __FILE__, __LINE__, crd->crd_inject); - cesa_cmd->ivFromUser = 1; - ivp = crd->crd_iv; - - /* - * do we have to copy the IV back to the buffer ? - */ - if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) { - dprintk("%s,%d: copy the IV back to the buffer\n", __FILE__, __LINE__); - cesa_cmd->ivOffset = crd->crd_inject; - crypto_copyback(crp->crp_flags, crp->crp_buf, crd->crd_inject, cesa_ocf_cur_ses->ivlen, ivp); - } - else { - dprintk("%s,%d: don't copy the IV back to the buffer \n", __FILE__, __LINE__); - p_mbuf_info->numFrags++; - p_mbuf_info->mbufSize += cesa_ocf_cur_ses->ivlen; - p_mbuf_info->pFrags = p_buf_info; - - p_buf_info->bufVirtPtr = ivp; - p_buf_info->bufSize = cesa_ocf_cur_ses->ivlen; - p_buf_info--; - - /* offsets */ - cesa_cmd->ivOffset = 0; - cesa_cmd->cryptoOffset += cesa_ocf_cur_ses->ivlen; - if(auth) { - cesa_cmd->macOffset += cesa_ocf_cur_ses->ivlen; - cesa_cmd->digestOffset += cesa_ocf_cur_ses->ivlen; - } - } - } - else { /* random IV */ - dprintk("%s,%d: random IV \n", __FILE__, __LINE__); - cesa_cmd->ivFromUser = 0; - - /* - * do we have to copy the IV back to the buffer ? - */ - /* in this mode the HAL will always copy the IV */ - /* given by the session to the ivOffset */ - if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) { - cesa_cmd->ivOffset = crd->crd_inject; - } - else { - /* if IV isn't copy, then how will the user know which IV did we use??? */ - printk("%s,%d: EINVAL\n", __FILE__, __LINE__); - goto p_error; - } - } - } - else { /* decrypt */ - dprintk(" decrypt \n"); - decrypt++; - cesa_cmd->sessionId = cesa_ocf_cur_ses->sid_decrypt; - - /* handle IV */ - if (crd->crd_flags & CRD_F_IV_EXPLICIT) { - dprintk("%s,%d: IV from USER \n", __FILE__, __LINE__); - /* append the IV buf to the mbuf */ - cesa_cmd->ivFromUser = 1; - p_mbuf_info->numFrags++; - p_mbuf_info->mbufSize += cesa_ocf_cur_ses->ivlen; - p_mbuf_info->pFrags = p_buf_info; - - p_buf_info->bufVirtPtr = crd->crd_iv; - p_buf_info->bufSize = cesa_ocf_cur_ses->ivlen; - p_buf_info--; - - /* offsets */ - cesa_cmd->ivOffset = 0; - cesa_cmd->cryptoOffset += cesa_ocf_cur_ses->ivlen; - if(auth) { - cesa_cmd->macOffset += cesa_ocf_cur_ses->ivlen; - cesa_cmd->digestOffset += cesa_ocf_cur_ses->ivlen; - } - } - else { - dprintk("%s,%d: IV inside the buffer \n", __FILE__, __LINE__); - cesa_cmd->ivFromUser = 0; - cesa_cmd->ivOffset = crd->crd_inject; - } - } - - } - /* Authentication */ - else if(crd->crd_alg == cesa_ocf_cur_ses->auth_alg) { - dprintk("%s,%d: Authentication \n", __FILE__, __LINE__); - auth++; - cesa_cmd->macOffset = crd->crd_skip; - cesa_cmd->macLength = crd->crd_len; - - /* digest + mac */ - cesa_cmd->digestOffset = crd->crd_inject; - } - else { - printk("%s,%d: Alg isn't supported by this session.\n", __FILE__, __LINE__); - goto p_error; - } - } - - dprintk("\n"); - dprintk("%s,%d: Sending Action: \n", __FILE__, __LINE__); - dprintk("%s,%d: IV from user: %d. IV offset %x \n", __FILE__, __LINE__, cesa_cmd->ivFromUser, cesa_cmd->ivOffset); - dprintk("%s,%d: crypt offset %x len %x \n", __FILE__, __LINE__, cesa_cmd->cryptoOffset, cesa_cmd->cryptoLength); - dprintk("%s,%d: Auth offset %x len %x \n", __FILE__, __LINE__, cesa_cmd->macOffset, cesa_cmd->macLength); - dprintk("%s,%d: set digest in offset %x . \n", __FILE__, __LINE__, cesa_cmd->digestOffset); - if(debug) { - mvCesaDebugMbuf("SRC BUFFER", cesa_cmd->pSrc, 0, cesa_cmd->pSrc->mbufSize); - } - - - /* send action to HAL */ - spin_lock_irqsave(&cesa_lock, flags); - status = mvCesaAction(cesa_cmd); - spin_unlock_irqrestore(&cesa_lock, flags); - - /* action not allowed */ - if(status == MV_NOT_ALLOWED) { -#ifdef CESA_OCF_SPLIT - /* if both encrypt and auth try to split */ - if(auth && (encrypt || decrypt)) { - MV_CESA_COMMAND *cesa_cmd_wa; - - /* malloc a new cesa process and init it */ - cesa_ocf_cmd_wa = kmalloc(sizeof(struct cesa_ocf_process), GFP_ATOMIC); - - if (cesa_ocf_cmd_wa == NULL) { - printk("%s,%d: ENOBUFS \n", __FILE__, __LINE__); - goto p_error; - } - memcpy(cesa_ocf_cmd_wa, cesa_ocf_cmd, sizeof(struct cesa_ocf_process)); - cesa_cmd_wa = &cesa_ocf_cmd_wa->cesa_cmd; - cesa_cmd_wa->pReqPrv = (void *)cesa_ocf_cmd_wa; - cesa_ocf_cmd_wa->need_cb = 0; - - /* break requests to two operation, first operation completion won't call callback */ - if((decrypt) && (cesa_ocf_cur_ses->auth_tn_decrypt)) { - cesa_cmd_wa->sessionId = cesa_ocf_cur_ses->frag_wa_auth; - cesa_cmd->sessionId = cesa_ocf_cur_ses->frag_wa_decrypt; - } - else if((decrypt) && !(cesa_ocf_cur_ses->auth_tn_decrypt)) { - cesa_cmd_wa->sessionId = cesa_ocf_cur_ses->frag_wa_decrypt; - cesa_cmd->sessionId = cesa_ocf_cur_ses->frag_wa_auth; - } - else if((encrypt) && (cesa_ocf_cur_ses->encrypt_tn_auth)) { - cesa_cmd_wa->sessionId = cesa_ocf_cur_ses->frag_wa_encrypt; - cesa_cmd->sessionId = cesa_ocf_cur_ses->frag_wa_auth; - } - else if((encrypt) && !(cesa_ocf_cur_ses->encrypt_tn_auth)){ - cesa_cmd_wa->sessionId = cesa_ocf_cur_ses->frag_wa_auth; - cesa_cmd->sessionId = cesa_ocf_cur_ses->frag_wa_encrypt; - } - else { - printk("%s,%d: Unsupporterd fragment wa mode \n", __FILE__, __LINE__); - goto p_error; - } - - /* send the 2 actions to the HAL */ - spin_lock_irqsave(&cesa_lock, flags); - status = mvCesaAction(cesa_cmd_wa); - spin_unlock_irqrestore(&cesa_lock, flags); - - if((status != MV_NO_MORE) && (status != MV_OK)) { - printk("%s,%d: cesa action failed, status = 0x%x\n", __FILE__, __LINE__, status); - goto p_error; - } - spin_lock_irqsave(&cesa_lock, flags); - status = mvCesaAction(cesa_cmd); - spin_unlock_irqrestore(&cesa_lock, flags); - - } - /* action not allowed and can't split */ - else -#endif - { - goto p_error; - } - } - - /* Hal Q is full, send again. This should never happen */ - if(status == MV_NO_RESOURCE) { - printk("%s,%d: cesa no more resources \n", __FILE__, __LINE__); - if(cesa_ocf_cmd) - kfree(cesa_ocf_cmd); - if(cesa_ocf_cmd_wa) - kfree(cesa_ocf_cmd_wa); - return ERESTART; - } - else if((status != MV_NO_MORE) && (status != MV_OK)) { - printk("%s,%d: cesa action failed, status = 0x%x\n", __FILE__, __LINE__, status); - goto p_error; - } - - -#ifdef CESA_OCF_POLLING - cesa_interrupt_polling(); -#endif - cesaTestTraceAdd(5); - - return 0; -p_error: - crp->crp_etype = EINVAL; - if(cesa_ocf_cmd) - kfree(cesa_ocf_cmd); - if(cesa_ocf_cmd_wa) - kfree(cesa_ocf_cmd_wa); - return EINVAL; -} - -/* - * cesa callback. - */ -static void -cesa_callback(unsigned long dummy) -{ - struct cesa_ocf_process *cesa_ocf_cmd = NULL; - struct cryptop *crp = NULL; - MV_CESA_RESULT result[MV_CESA_MAX_CHAN]; - int res_idx = 0,i; - MV_STATUS status; - - dprintk("%s()\n", __FUNCTION__); - -#ifdef CESA_OCF_TASKLET - disable_irq(cesa_device.irq); -#endif - while(MV_TRUE) { - - /* Get Ready requests */ - spin_lock(&cesa_lock); - status = mvCesaReadyGet(&result[res_idx]); - spin_unlock(&cesa_lock); - - cesaTestTraceAdd(2); - - if(status != MV_OK) { -#ifdef CESA_OCF_POLLING - if(status == MV_BUSY) { /* Fragment */ - cesa_interrupt_polling(); - return; - } -#endif - break; - } - res_idx++; - break; - } - - for(i = 0; i < res_idx; i++) { - - if(!result[i].pReqPrv) { - printk("%s,%d: warning private is NULL\n", __FILE__, __LINE__); - break; - } - - cesa_ocf_cmd = result[i].pReqPrv; - crp = cesa_ocf_cmd->crp; - - // ignore HMAC error. - //if(result->retCode) - // crp->crp_etype = EIO; - -#if defined(CESA_OCF_POLLING) - if(!cesa_ocf_cmd->need_cb){ - cesa_interrupt_polling(); - } -#endif - if(cesa_ocf_cmd->need_cb) { - if(debug) { - mvCesaDebugMbuf("DST BUFFER", cesa_ocf_cmd->cesa_cmd.pDst, 0, cesa_ocf_cmd->cesa_cmd.pDst->mbufSize); - } - crypto_done(crp); - } - kfree(cesa_ocf_cmd); - } -#ifdef CESA_OCF_TASKLET - enable_irq(cesa_device.irq); -#endif - - cesaTestTraceAdd(3); - - return; -} - -#ifdef CESA_OCF_POLLING -static void -cesa_interrupt_polling(void) -{ - u32 cause; - - dprintk("%s()\n", __FUNCTION__); - - /* Read cause register */ - do { - cause = MV_REG_READ(MV_CESA_ISR_CAUSE_REG); - cause &= MV_CESA_CAUSE_ACC_DMA_ALL_MASK; - - } while (cause == 0); - - /* clear interrupts */ - MV_REG_WRITE(MV_CESA_ISR_CAUSE_REG, 0); - - cesa_callback(0); - - return; -} - -#endif - -/* - * cesa Interrupt polling routine. - */ -static irqreturn_t -cesa_interrupt_handler(int irq, void *arg) -{ - u32 cause; - - dprintk("%s()\n", __FUNCTION__); - - cesaTestTraceAdd(0); - - /* Read cause register */ - cause = MV_REG_READ(MV_CESA_ISR_CAUSE_REG); - - if( (cause & MV_CESA_CAUSE_ACC_DMA_ALL_MASK) == 0) - { - /* Empty interrupt */ - dprintk("%s,%d: cesaTestReadyIsr: cause=0x%x\n", __FILE__, __LINE__, cause); - return IRQ_HANDLED; - } - - /* clear interrupts */ - MV_REG_WRITE(MV_CESA_ISR_CAUSE_REG, 0); - - cesaTestTraceAdd(1); -#ifdef CESA_OCF_TASKLET - tasklet_hi_schedule(&cesa_ocf_tasklet); -#else - cesa_callback(0); -#endif - return IRQ_HANDLED; -} - -/* - * Open a session. - */ -static int -/*cesa_ocf_newsession(void *arg, u_int32_t *sid, struct cryptoini *cri)*/ -cesa_ocf_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri) -{ - u32 status = 0, i; - u32 count = 0, auth = 0, encrypt =0; - struct cesa_ocf_data *cesa_ocf_cur_ses; - MV_CESA_OPEN_SESSION cesa_session; - MV_CESA_OPEN_SESSION *cesa_ses = &cesa_session; - - - dprintk("%s()\n", __FUNCTION__); - if (sid == NULL || cri == NULL) { - printk("%s,%d: EINVAL\n", __FILE__, __LINE__); - return EINVAL; - } - - /* leave first empty like in other implementations */ - for (i = 1; i < CESA_OCF_MAX_SES; i++) { - if (cesa_ocf_sessions[i] == NULL) - break; - } - - if(i >= CESA_OCF_MAX_SES) { - printk("%s,%d: no more sessions \n", __FILE__, __LINE__); - return EINVAL; - } - - cesa_ocf_sessions[i] = (struct cesa_ocf_data *) kmalloc(sizeof(struct cesa_ocf_data), GFP_ATOMIC); - if (cesa_ocf_sessions[i] == NULL) { - cesa_ocf_freesession(NULL, i); - printk("%s,%d: ENOBUFS \n", __FILE__, __LINE__); - return ENOBUFS; - } - dprintk("%s,%d: new session %d \n", __FILE__, __LINE__, i); - - *sid = i; - cesa_ocf_cur_ses = cesa_ocf_sessions[i]; - memset(cesa_ocf_cur_ses, 0, sizeof(struct cesa_ocf_data)); - cesa_ocf_cur_ses->sid_encrypt = -1; - cesa_ocf_cur_ses->sid_decrypt = -1; - cesa_ocf_cur_ses->frag_wa_encrypt = -1; - cesa_ocf_cur_ses->frag_wa_decrypt = -1; - cesa_ocf_cur_ses->frag_wa_auth = -1; - - /* init the session */ - memset(cesa_ses, 0, sizeof(MV_CESA_OPEN_SESSION)); - count = 1; - while (cri) { - if(count > 2) { - printk("%s,%d: don't support more then 2 operations\n", __FILE__, __LINE__); - goto error; - } - switch (cri->cri_alg) { - case CRYPTO_AES_CBC: - dprintk("%s,%d: (%d) AES CBC \n", __FILE__, __LINE__, count); - cesa_ocf_cur_ses->cipher_alg = cri->cri_alg; - cesa_ocf_cur_ses->ivlen = MV_CESA_AES_BLOCK_SIZE; - cesa_ses->cryptoAlgorithm = MV_CESA_CRYPTO_AES; - cesa_ses->cryptoMode = MV_CESA_CRYPTO_CBC; - if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) { - printk("%s,%d: CRYPTO key too long.\n", __FILE__, __LINE__); - goto error; - } - memcpy(cesa_ses->cryptoKey, cri->cri_key, cri->cri_klen/8); - dprintk("%s,%d: key length %d \n", __FILE__, __LINE__, cri->cri_klen/8); - cesa_ses->cryptoKeyLength = cri->cri_klen/8; - encrypt += count; - break; - case CRYPTO_3DES_CBC: - dprintk("%s,%d: (%d) 3DES CBC \n", __FILE__, __LINE__, count); - cesa_ocf_cur_ses->cipher_alg = cri->cri_alg; - cesa_ocf_cur_ses->ivlen = MV_CESA_3DES_BLOCK_SIZE; - cesa_ses->cryptoAlgorithm = MV_CESA_CRYPTO_3DES; - cesa_ses->cryptoMode = MV_CESA_CRYPTO_CBC; - if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) { - printk("%s,%d: CRYPTO key too long.\n", __FILE__, __LINE__); - goto error; - } - memcpy(cesa_ses->cryptoKey, cri->cri_key, cri->cri_klen/8); - cesa_ses->cryptoKeyLength = cri->cri_klen/8; - encrypt += count; - break; - case CRYPTO_DES_CBC: - dprintk("%s,%d: (%d) DES CBC \n", __FILE__, __LINE__, count); - cesa_ocf_cur_ses->cipher_alg = cri->cri_alg; - cesa_ocf_cur_ses->ivlen = MV_CESA_DES_BLOCK_SIZE; - cesa_ses->cryptoAlgorithm = MV_CESA_CRYPTO_DES; - cesa_ses->cryptoMode = MV_CESA_CRYPTO_CBC; - if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) { - printk("%s,%d: CRYPTO key too long.\n", __FILE__, __LINE__); - goto error; - } - memcpy(cesa_ses->cryptoKey, cri->cri_key, cri->cri_klen/8); - cesa_ses->cryptoKeyLength = cri->cri_klen/8; - encrypt += count; - break; - case CRYPTO_MD5: - case CRYPTO_MD5_HMAC: - dprintk("%s,%d: (%d) %sMD5 CBC \n", __FILE__, __LINE__, count, (cri->cri_alg != CRYPTO_MD5)? "H-":" "); - cesa_ocf_cur_ses->auth_alg = cri->cri_alg; - cesa_ocf_cur_ses->digestlen = (cri->cri_alg == CRYPTO_MD5)? MV_CESA_MD5_DIGEST_SIZE : 12; - cesa_ses->macMode = (cri->cri_alg == CRYPTO_MD5)? MV_CESA_MAC_MD5 : MV_CESA_MAC_HMAC_MD5; - if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) { - printk("%s,%d: MAC key too long. \n", __FILE__, __LINE__); - goto error; - } - cesa_ses->macKeyLength = cri->cri_klen/8; - memcpy(cesa_ses->macKey, cri->cri_key, cri->cri_klen/8); - cesa_ses->digestSize = cesa_ocf_cur_ses->digestlen; - auth += count; - break; - case CRYPTO_SHA1: - case CRYPTO_SHA1_HMAC: - dprintk("%s,%d: (%d) %sSHA1 CBC \n", __FILE__, __LINE__, count, (cri->cri_alg != CRYPTO_SHA1)? "H-":" "); - cesa_ocf_cur_ses->auth_alg = cri->cri_alg; - cesa_ocf_cur_ses->digestlen = (cri->cri_alg == CRYPTO_SHA1)? MV_CESA_SHA1_DIGEST_SIZE : 12; - cesa_ses->macMode = (cri->cri_alg == CRYPTO_SHA1)? MV_CESA_MAC_SHA1 : MV_CESA_MAC_HMAC_SHA1; - if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) { - printk("%s,%d: MAC key too long. \n", __FILE__, __LINE__); - goto error; - } - cesa_ses->macKeyLength = cri->cri_klen/8; - memcpy(cesa_ses->macKey, cri->cri_key, cri->cri_klen/8); - cesa_ses->digestSize = cesa_ocf_cur_ses->digestlen; - auth += count; - break; - default: - printk("%s,%d: unknown algo 0x%x\n", __FILE__, __LINE__, cri->cri_alg); - goto error; - } - cri = cri->cri_next; - count++; - } - - if((encrypt > 2) || (auth > 2)) { - printk("%s,%d: session mode is not supported.\n", __FILE__, __LINE__); - goto error; - } - /* create new sessions in HAL */ - if(encrypt) { - cesa_ses->operation = MV_CESA_CRYPTO_ONLY; - /* encrypt session */ - if(auth == 1) { - cesa_ses->operation = MV_CESA_MAC_THEN_CRYPTO; - } - else if(auth == 2) { - cesa_ses->operation = MV_CESA_CRYPTO_THEN_MAC; - cesa_ocf_cur_ses->encrypt_tn_auth = 1; - } - else { - cesa_ses->operation = MV_CESA_CRYPTO_ONLY; - } - cesa_ses->direction = MV_CESA_DIR_ENCODE; - status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->sid_encrypt); - if(status != MV_OK) { - printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status); - goto error; - } - /* decrypt session */ - if( cesa_ses->operation == MV_CESA_MAC_THEN_CRYPTO ) { - cesa_ses->operation = MV_CESA_CRYPTO_THEN_MAC; - } - else if( cesa_ses->operation == MV_CESA_CRYPTO_THEN_MAC ) { - cesa_ses->operation = MV_CESA_MAC_THEN_CRYPTO; - } - cesa_ses->direction = MV_CESA_DIR_DECODE; - status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->sid_decrypt); - if(status != MV_OK) { - printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status); - goto error; - } - - /* preapre one action sessions for case we will need to split an action */ -#ifdef CESA_OCF_SPLIT - if(( cesa_ses->operation == MV_CESA_MAC_THEN_CRYPTO ) || - ( cesa_ses->operation == MV_CESA_CRYPTO_THEN_MAC )) { - /* open one session for encode and one for decode */ - cesa_ses->operation = MV_CESA_CRYPTO_ONLY; - cesa_ses->direction = MV_CESA_DIR_ENCODE; - status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->frag_wa_encrypt); - if(status != MV_OK) { - printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status); - goto error; - } - - cesa_ses->direction = MV_CESA_DIR_DECODE; - status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->frag_wa_decrypt); - if(status != MV_OK) { - printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status); - goto error; - } - /* open one session for auth */ - cesa_ses->operation = MV_CESA_MAC_ONLY; - cesa_ses->direction = MV_CESA_DIR_ENCODE; - status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->frag_wa_auth); - if(status != MV_OK) { - printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status); - goto error; - } - } -#endif - } - else { /* only auth */ - cesa_ses->operation = MV_CESA_MAC_ONLY; - cesa_ses->direction = MV_CESA_DIR_ENCODE; - status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->sid_encrypt); - if(status != MV_OK) { - printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status); - goto error; - } - } - - return 0; -error: - cesa_ocf_freesession(NULL, *sid); - return EINVAL; - -} - - -/* - * Free a session. - */ -static int -cesa_ocf_freesession(device_t dev, u_int64_t tid) -{ - struct cesa_ocf_data *cesa_ocf_cur_ses; - u_int32_t sid = CRYPTO_SESID2LID(tid); - //unsigned long flags; - - dprintk("%s() %d \n", __FUNCTION__, sid); - if ( (sid >= CESA_OCF_MAX_SES) || (cesa_ocf_sessions[sid] == NULL) ) { - printk("%s,%d: EINVAL can't free session %d \n", __FILE__, __LINE__, sid); - return(EINVAL); - } - - /* Silently accept and return */ - if (sid == 0) - return(0); - - /* release session from HAL */ - cesa_ocf_cur_ses = cesa_ocf_sessions[sid]; - if (cesa_ocf_cur_ses->sid_encrypt != -1) { - mvCesaSessionClose(cesa_ocf_cur_ses->sid_encrypt); - } - if (cesa_ocf_cur_ses->sid_decrypt != -1) { - mvCesaSessionClose(cesa_ocf_cur_ses->sid_decrypt); - } - if (cesa_ocf_cur_ses->frag_wa_encrypt != -1) { - mvCesaSessionClose(cesa_ocf_cur_ses->frag_wa_encrypt); - } - if (cesa_ocf_cur_ses->frag_wa_decrypt != -1) { - mvCesaSessionClose(cesa_ocf_cur_ses->frag_wa_decrypt); - } - if (cesa_ocf_cur_ses->frag_wa_auth != -1) { - mvCesaSessionClose(cesa_ocf_cur_ses->frag_wa_auth); - } - - kfree(cesa_ocf_cur_ses); - cesa_ocf_sessions[sid] = NULL; - - return 0; -} - - -/* TDMA Window setup */ - -static void __init -setup_tdma_mbus_windows(struct cesa_dev *dev) -{ - int i; - - for (i = 0; i < 4; i++) { - writel(0, dev->reg + WINDOW_BASE(i)); - writel(0, dev->reg + WINDOW_CTRL(i)); - } - - for (i = 0; i < dev->plat_data->dram->num_cs; i++) { - struct mbus_dram_window *cs = dev->plat_data->dram->cs + i; - writel( - ((cs->size - 1) & 0xffff0000) | - (cs->mbus_attr << 8) | - (dev->plat_data->dram->mbus_dram_target_id << 4) | 1, - dev->reg + WINDOW_CTRL(i) - ); - writel(cs->base, dev->reg + WINDOW_BASE(i)); - } -} - -/* - * our driver startup and shutdown routines - */ -static int -mv_cesa_ocf_init(struct platform_device *pdev) -{ -#if defined(CONFIG_MV78200) || defined(CONFIG_MV632X) - if (MV_FALSE == mvSocUnitIsMappedToThisCpu(CESA)) - { - dprintk("CESA is not mapped to this CPU\n"); - return -ENODEV; - } -#endif - - dprintk("%s\n", __FUNCTION__); - memset(&mv_cesa_dev, 0, sizeof(mv_cesa_dev)); - softc_device_init(&mv_cesa_dev, "MV CESA", 0, mv_cesa_methods); - cesa_ocf_id = crypto_get_driverid(softc_get_device(&mv_cesa_dev),CRYPTOCAP_F_HARDWARE); - - if (cesa_ocf_id < 0) - panic("MV CESA crypto device cannot initialize!"); - - dprintk("%s,%d: cesa ocf device id is %d \n", __FILE__, __LINE__, cesa_ocf_id); - - /* CESA unit is auto power on off */ -#if 0 - if (MV_FALSE == mvCtrlPwrClckGet(CESA_UNIT_ID,0)) - { - printk("\nWarning CESA %d is Powered Off\n",0); - return EINVAL; - } -#endif - - memset(&cesa_device, 0, sizeof(struct cesa_dev)); - /* Get the IRQ, and crypto memory regions */ - { - struct resource *res; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram"); - - if (!res) - return -ENXIO; - - cesa_device.sram = ioremap(res->start, res->end - res->start + 1); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); - - if (!res) { - iounmap(cesa_device.sram); - return -ENXIO; - } - cesa_device.reg = ioremap(res->start, res->end - res->start + 1); - cesa_device.irq = platform_get_irq(pdev, 0); - cesa_device.plat_data = pdev->dev.platform_data; - setup_tdma_mbus_windows(&cesa_device); - - } - - - if( MV_OK != mvCesaInit(CESA_OCF_MAX_SES*5, CESA_Q_SIZE, cesa_device.reg, - NULL) ) { - printk("%s,%d: mvCesaInit Failed. \n", __FILE__, __LINE__); - return EINVAL; - } - - /* clear and unmask Int */ - MV_REG_WRITE( MV_CESA_ISR_CAUSE_REG, 0); -#ifndef CESA_OCF_POLLING - MV_REG_WRITE( MV_CESA_ISR_MASK_REG, MV_CESA_CAUSE_ACC_DMA_MASK); -#endif -#ifdef CESA_OCF_TASKLET - tasklet_init(&cesa_ocf_tasklet, cesa_callback, (unsigned int) 0); -#endif - /* register interrupt */ - if( request_irq( cesa_device.irq, cesa_interrupt_handler, - 0, "cesa", &cesa_ocf_id) < 0) { - printk("%s,%d: cannot assign irq %x\n", __FILE__, __LINE__, cesa_device.reg); - return EINVAL; - } - - - memset(cesa_ocf_sessions, 0, sizeof(struct cesa_ocf_data *) * CESA_OCF_MAX_SES); - -#define REGISTER(alg) \ - crypto_register(cesa_ocf_id, alg, 0,0) - REGISTER(CRYPTO_AES_CBC); - REGISTER(CRYPTO_DES_CBC); - REGISTER(CRYPTO_3DES_CBC); - REGISTER(CRYPTO_MD5); - REGISTER(CRYPTO_MD5_HMAC); - REGISTER(CRYPTO_SHA1); - REGISTER(CRYPTO_SHA1_HMAC); -#undef REGISTER - - return 0; -} - -static void -mv_cesa_ocf_exit(struct platform_device *pdev) -{ - dprintk("%s()\n", __FUNCTION__); - - crypto_unregister_all(cesa_ocf_id); - cesa_ocf_id = -1; - iounmap(cesa_device.reg); - iounmap(cesa_device.sram); - free_irq(cesa_device.irq, NULL); - - /* mask and clear Int */ - MV_REG_WRITE( MV_CESA_ISR_MASK_REG, 0); - MV_REG_WRITE( MV_CESA_ISR_CAUSE_REG, 0); - - - if( MV_OK != mvCesaFinish() ) { - printk("%s,%d: mvCesaFinish Failed. \n", __FILE__, __LINE__); - return; - } -} - - -void cesa_ocf_debug(void) -{ - -#ifdef CESA_OCF_TRACE_DEBUG - { - int i, j; - j = cesaTestTraceIdx; - mvOsPrintf("No Type rCause iCause Proc Isr Res Time pReady pProc pEmpty\n"); - for(i=0; i