/* <:copyright-BRCM:2007:DUAL/GPL:standard Copyright (c) 2007 Broadcom All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as published by the Free Software Foundation (the "GPL"). This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php, or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. :> */ /*************************************************************************** * File Name : sputest.c * * Description: This file contains SPU test code * ***************************************************************************/ /* Includes. */ #include #include #include #include #include #include #include #include #include #include #include #include "bcm_map_part.h" #include "bcm_intr.h" #include "bcmspudrv.h" #include "../spudrv.h" #include "spudrv_data.h" #include #include #include "../spu.h" #if defined(CONFIG_BCM_SPU_TEST) /* Prototypes. */ static int encrypt_decrypt_verify (uint16 test_pkt_id, uint16 rx_index); unsigned long spu_get_cycle_count(void); void spu_assign_output_desc (unsigned char *buf, uint16 len); extern void spu_dump_array(char *msg, unsigned char *buf, uint16 len); /* * Performance variables */ extern unsigned long start; extern unsigned long end; extern unsigned long proc_time; int xmit_pkt_len = 0; int recv_pkt_len = 0; /* DMA buffers */ unsigned char *tx_data = NULL; unsigned char *rx_data = NULL; unsigned char *tx_hdr = NULL; extern unsigned long spu_cycle_per_us; /* Device control structure */ extern pspu_dev_ctrl_t pdev_ctrl; int num_tests_passed = 0; int num_tests_failed = 0; /*************************************************************************** * Function Name: ipsec_setup_tx_rx * Description : Setup Tx and Rx buffers for test. * Returns : rx_index ***************************************************************************/ static int ipsec_setup_tx_rx (uint32 test_pkt_id, int *done) { int i = 0; unsigned char *p; unsigned char *p8; unsigned char *palign; unsigned char *ptx; unsigned char *ptx_tmpl; unsigned char *tx_pkt; uint16 rx_index; uint16 tx_pkt_size = tx_pkt_len[test_pkt_id]; uint16 rx_pkt_size = rx_pkt_len[test_pkt_id]; unsigned long irq_flags; /* * Setup the Rx Buffer first */ if ((p = kmalloc ((rx_pkt_size + BUF_ALIGN), GFP_KERNEL)) == NULL) { printk (KERN_ERR "IPSEC SPU: Error no memory for Rx buffer\n"); *done = 0; return -ENOMEM; } rx_data = p; rx_index = pdev_ctrl->rx_tail; memset (p, 0, rx_pkt_size); cache_flush_len(p, rx_pkt_size + BUF_ALIGN); p8 = (unsigned char *) IPSEC_SPU_ALIGN (p, BUF_ALIGN); spin_lock_irqsave (&pdev_ctrl->spin_lock, irq_flags); pdev_ctrl->rx_bds[pdev_ctrl->rx_tail].address = (uint32) VIRT_TO_PHY (p8); pdev_ctrl->rx_bds[pdev_ctrl->rx_tail].length = rx_pkt_size; recv_pkt_len = rx_pkt_size; if (pdev_ctrl->rx_tail == (NR_RX_BDS - 1)) { pdev_ctrl->rx_bds[pdev_ctrl->rx_tail].status = DMA_OWN | DMA_WRAP; #ifdef SPU_DEBUG printk (KERN_ERR "IPSEC SPU: Rx BD %p addr %lx len %x sts %x\n", &pdev_ctrl->rx_bds[pdev_ctrl->rx_tail], pdev_ctrl->rx_bds[pdev_ctrl->rx_tail].address, pdev_ctrl->rx_bds[pdev_ctrl->rx_tail].length, pdev_ctrl->rx_bds[pdev_ctrl->rx_tail].status); #endif pdev_ctrl->rx_tail = 0; } else { pdev_ctrl->rx_bds[pdev_ctrl->rx_tail].status = DMA_OWN; #ifdef SPU_DEBUG printk (KERN_ERR "IPSEC SPU: ** Rx BD %p addr %lx len %x sts %x\n", &pdev_ctrl->rx_bds[pdev_ctrl->rx_tail], pdev_ctrl->rx_bds[pdev_ctrl->rx_tail].address, pdev_ctrl->rx_bds[pdev_ctrl->rx_tail].length, pdev_ctrl->rx_bds[pdev_ctrl->rx_tail].status); #endif pdev_ctrl->rx_tail++; } spin_unlock_irqrestore(&pdev_ctrl->spin_lock, irq_flags); /* * Now setup the Tx buffer. */ if ((tx_pkt = kmalloc (tx_pkt_size + BUF_ALIGN, GFP_KERNEL)) == NULL) { printk (KERN_ERR "IPSEC SPU: Error INPUT PKT OUT OF MEMORY\n"); *done = 0; return -ENOMEM; } tx_data = tx_pkt; p8 = (unsigned char *) IPSEC_SPU_ALIGN (tx_pkt, BUF_ALIGN); p = (uint8 *) CACHE_TO_NONCACHE ((uint32) p8); memset (p, 0, tx_pkt_size); ptx_tmpl = (unsigned char *) tx_test_pkts[test_pkt_id]; ptx = (unsigned char *) p; #ifdef SPU_DEBUG printk (KERN_ERR "IPSEC SPU: tx_data %p p %p\n", ptx, p); #endif while (i < tx_pkt_size) { *ptx = *ptx_tmpl; ptx++; ptx_tmpl++; i++; } palign = (unsigned char *) IPSEC_SPU_ALIGN (tx_pkt, BUF_ALIGN); #ifdef SPU_DEBUG printk (KERN_ERR "IPSEC SPU: Setting Up Tx BD tx_pkt %p p %p phy addr 0x%lx\n", ptx, p, (uint32) VIRT_TO_PHY (palign)); #endif spin_lock_irqsave(&pdev_ctrl->spin_lock, irq_flags); pdev_ctrl->tx_bds[pdev_ctrl->tx_tail].address = (uint32) VIRT_TO_PHY (palign); pdev_ctrl->tx_bds[pdev_ctrl->tx_tail].length = tx_pkt_size; xmit_pkt_len = tx_pkt_size; if (pdev_ctrl->tx_tail == (NR_XMIT_BDS - 1)) { pdev_ctrl->tx_bds[pdev_ctrl->tx_tail].status = DMA_OWN | DMA_SOP | DMA_EOP | DMA_WRAP; #ifdef SPU_DEBUG printk (KERN_ERR "IPSEC SPU: Tx BD %p addr %lx len %x sts %x\n", &pdev_ctrl->tx_bds[pdev_ctrl->tx_tail], pdev_ctrl->tx_bds[pdev_ctrl->tx_tail].address, pdev_ctrl->tx_bds[pdev_ctrl->tx_tail].length, pdev_ctrl->tx_bds[pdev_ctrl->tx_tail].status); #endif pdev_ctrl->tx_tail = 0; pdev_ctrl->tx_free_bds = NR_XMIT_BDS; } else { pdev_ctrl->tx_bds[pdev_ctrl->tx_tail].status = DMA_OWN | DMA_SOP | DMA_EOP; #ifdef SPU_DEBUG printk (KERN_ERR "IPSEC SPU: ** Tx BD %p addr %lx len %x sts %x\n", &pdev_ctrl->tx_bds[pdev_ctrl->tx_tail], pdev_ctrl->tx_bds[pdev_ctrl->tx_tail].address, pdev_ctrl->tx_bds[pdev_ctrl->tx_tail].length, pdev_ctrl->tx_bds[pdev_ctrl->tx_tail].status); #endif pdev_ctrl->tx_free_bds--; pdev_ctrl->tx_tail++; } spin_unlock_irqrestore(&pdev_ctrl->spin_lock, irq_flags); return rx_index; } /*************************************************************************** * Function Name: encrypt_decrypt_verify * Description : Verify the result of encryption or decryption operation. * Returns : 0 success ***************************************************************************/ static int encrypt_decrypt_verify (uint16 test_pkt_id, uint16 rx_index) { int ret = 1; //unsigned char *p; unsigned char *ptx = NULL; unsigned char *prx = NULL; unsigned char *ptmpl = NULL; unsigned char *rxdata = NULL; //unsigned char *tx_data = tx_test_pkts[test_pkt_id]; unsigned char *rx_tmpl = rx_templates[test_pkt_id]; uint16 rx_len = pdev_ctrl->rx_bds[rx_index].length; #ifdef SPU_DEBUG int i = 0; uint16 tx_len = tx_pkt_len[test_pkt_id]; #endif uint16 dma_status = pdev_ctrl->rx_bds[rx_index].status; if (dma_status & DMA_OWN) { printk (KERN_ERR "IPSEC SPU: Nothing to process\n"); goto clean_up; return ret; } rxdata = (unsigned char *) pdev_ctrl->rx_bds[rx_index].address; prx = (unsigned char *) IPSEC_SPU_ALIGN (rxdata, BUF_ALIGN); #ifdef SPU_DEBUG printk (KERN_ERR "IPSEC SPU: Rx Buffer pres addr %p rx addr %p\n", prx, rxdata); #endif prx = (uint8 *) CACHE_TO_NONCACHE (prx); #ifdef SPU_DEBUG printk (KERN_ERR "IPSEC SPU: Rx Buffer pres addr %p rx addr %p\n", prx, rxdata); #endif ptmpl = (unsigned char *) IPSEC_SPU_ALIGN (rx_tmpl, BUF_ALIGN); ptx = (unsigned char *) IPSEC_SPU_ALIGN (tx_data, BUF_ALIGN); ptx = (uint8 *) CACHE_TO_NONCACHE (ptx); if (memcmp (prx, rx_tmpl, rx_len) == 0) { num_tests_passed++; printk (KERN_ERR "IPSEC SPU: Packet [%d] Test Passed Tx Len %d " "Rx Len %d Time %lx\n", test_pkt_id, xmit_pkt_len, recv_pkt_len, proc_time); } else { num_tests_failed++; printk (KERN_ERR "IPSEC SPU: Packet [%d] Test Failed Tx Len %d " "Rx Len %d Time %lx\n", test_pkt_id, xmit_pkt_len, recv_pkt_len, proc_time); #ifdef SPU_DEBUG for (i = 0; i < tx_len; i += 4) { printk ("Tx Pkt %p 0x%02x%02x%02x%02x\n", (ptx + i), *(ptx + i), *(ptx + i + 1), *(ptx + i + 2), *(ptx + i + 3)); } for (i = 0; i < rx_len; i += 4) { printk ("Rx Pkt %p 0x%02x%02x%02x%02x \t Rx Exp %p 0x%02x%02x%02x%02x\n", (prx + i), *(prx + i), *(prx + i + 1), *(prx + i + 2), *(prx + i + 3), (ptmpl + i), *(ptmpl + i), *(ptmpl + i + 1), *(ptmpl + i + 2), *(ptmpl + i + 3)); } #endif } ret = 0; clean_up: /* * Clean up the buffers allocated for tx and rx * before leaving. */ kfree (rx_data); kfree (tx_data); kfree (tx_hdr); return ret; } static int dump_output (uint16 rx_index) { int ret = 1; #ifdef SPU_DEBUG int i = 0; #endif unsigned char *rxdata = NULL; unsigned char *prx; uint16 dma_status = pdev_ctrl->rx_bds[rx_index].status; if (dma_status & DMA_OWN) { printk (KERN_ERR "IPSEC SPU: Nothing to process\n"); return ret; } rxdata = (unsigned char *) pdev_ctrl->rx_bds[rx_index].address; //prx = (unsigned char *)IPSEC_SPU_ALIGN(rxdata, BUF_ALIGN); prx = (uint8 *) CACHE_TO_NONCACHE (rxdata); #ifdef SPU_DEBUG printk ("BD len %d status %0x address %lx\n", pdev_ctrl->rx_bds[rx_index].length, pdev_ctrl->rx_bds[rx_index].status, pdev_ctrl->rx_bds[rx_index].address); printk ("********** Received Data **********\n"); for (i = 0; i < pdev_ctrl->rx_bds[rx_index].length; i++) { printk ("%02x ", *(prx + i)); if (!((i + 1) % 4)) { printk ("\n"); } } #endif return 0; } /*************************************************************************** * Function Name: spu_perform_test * Description : Tests for the hardware to do encrypt * or decrypt operation * Returns : N/A ***************************************************************************/ void spu_perform_test(uint32 tx_pkt_id, uint32 num_pkts) { int ntries = 0; #ifdef DISABLE_ENGINES unsigned long aes_enable; #endif uint16 rx_index; int done = 1; printk (KERN_ERR "IPSEC SPU: do_encrypt\n"); #if AES_MD5 printk (KERN_ERR "IPSEC SPU: AES MD5 TEST\n"); #endif #if AES_SHA1 printk (KERN_ERR "IPSEC SPU: AES SHA1 TEST\n"); #endif #if DES_MD5 printk (KERN_ERR "IPSEC SPU: DES MD5 TEST\n"); #endif #if DES_SHA1 printk (KERN_ERR "IPSEC SPU: DES SHA1 TEST\n"); #endif #if DES3_MD5 printk (KERN_ERR "IPSEC SPU: DES3 MD5 TEST\n"); #endif #if DES3_SHA1 printk (KERN_ERR "IPSEC SPU: DES3 SHA1 TEST\n"); #endif if (tx_pkt_id > MAX_PKT_ID || num_pkts > MAX_PKTS_PER_TEST) { return; } #ifdef DISABLE_ENGINES printk (KERN_ERR "IPSEC SPU: Disabling AES, DES, HASH engines 0x%08x\n", SPU_CTRL); aes_enable = SPU_CTRL; /* Disable AES, DES/3DES and HASH */ //aes_enable = (1 << 8) | (1 << 9) | (1 << 10); /* Disable DES/3DES and HASH */ aes_enable = (1 << 9) | (1 << 10); SPU_CTRL = aes_enable; printk (KERN_ERR "IPSEC SPU: AES, DES, HASH Disabled 0x%08x\n", SPU_CTRL); #endif num_tests_failed = num_tests_passed = 0; do { /* * Setup the rx and tx buffer. */ rx_index = ipsec_setup_tx_rx (tx_pkt_id, &done); /* * Enable the DMA. */ //retry: pdev_ctrl->rx_dma->cfg |= DMA_ENABLE; pdev_ctrl->tx_dma->cfg |= DMA_ENABLE; BcmHalInterruptEnable (pdev_ctrl->rx_irq); #ifdef SPU_DEBUG printk (KERN_ERR "IPSEC SPU: Done Enabling Tx %p %lx and Rx %p %lx DMA\n", &(pdev_ctrl->tx_dma->cfg), pdev_ctrl->tx_dma->cfg, &(pdev_ctrl->rx_dma->cfg), pdev_ctrl->rx_dma->cfg); printk (KERN_ERR "IPSEC SPU: Tx Chn BaseDesc %lx st data %lx " "len status %lx bufptr %lx\n", pdev_ctrl->dma_ctrl->stram.s[1].baseDescPtr, pdev_ctrl->dma_ctrl->stram.s[1].state_data, pdev_ctrl->dma_ctrl->stram.s[1].desc_len_status, pdev_ctrl->dma_ctrl->stram.s[1].desc_base_bufptr); printk (KERN_ERR "IPSEC SPU: Rx Chn BaseDesc %lx st data %lx " "len status %lx bufptr %lx\n", pdev_ctrl->dma_ctrl->stram.s[0].baseDescPtr, pdev_ctrl->dma_ctrl->stram.s[0].state_data, pdev_ctrl->dma_ctrl->stram.s[0].desc_len_status, pdev_ctrl->dma_ctrl->stram.s[0].desc_base_bufptr); printk (KERN_ERR "IPSEC SPU: DMA CTRL Global Interrupt Status %lx " "Mask %lx\n", pdev_ctrl->dma_ctrl->ctrl_global_interrupt_status, pdev_ctrl->dma_ctrl->ctrl_global_interrupt_mask); #endif start = spu_get_cycle_count(); /* * Unblocked so check the Rx with the template and * print the verdict. But first compute the elapsed * time in usecs. */ if (end < start) { proc_time = (0xFFFFFFFF - start) + end; } else { proc_time = end - start; } proc_time = proc_time / spu_cycle_per_us; encrypt_decrypt_verify(tx_pkt_id, rx_index); dump_output (rx_index); start = end = proc_time = 0; xmit_pkt_len = recv_pkt_len = 0; ntries = 0; num_pkts--; tx_pkt_id++; } while (done && num_pkts); printk("Num Tests %d Failed %d Passed %d\n", (num_tests_passed + num_tests_failed), num_tests_failed, num_tests_passed); } #endif /* CONFIG_BCM_SPU_TEST */ MODULE_LICENSE("GPL");