12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355 |
- /*
- * crypto/ocf/talitos/talitos.c
- *
- * An OCF-Linux module that uses Freescale's SEC to do the crypto.
- * Based on crypto/ocf/hifn and crypto/ocf/safe OCF drivers
- *
- * Copyright (c) 2006 Freescale Semiconductor, Inc.
- *
- * This code written by Kim A. B. Phillips <kim.phillips@freescale.com>
- * some code copied from files with the following:
- * Copyright (C) 2004-2007 David McCullough <david_mccullough@mcafee.com>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * ---------------------------------------------------------------------------
- *
- * NOTES:
- *
- * The Freescale SEC (also known as 'talitos') resides on the
- * internal bus, and runs asynchronous to the processor core. It has
- * a wide gamut of cryptographic acceleration features, including single-
- * pass IPsec (also known as algorithm chaining). To properly utilize
- * all of the SEC's performance enhancing features, further reworking
- * of higher level code (framework, applications) will be necessary.
- *
- * The following table shows which SEC version is present in which devices:
- *
- * Devices SEC version
- *
- * 8272, 8248 SEC 1.0
- * 885, 875 SEC 1.2
- * 8555E, 8541E SEC 2.0
- * 8349E SEC 2.01
- * 8548E SEC 2.1
- *
- * The following table shows the features offered by each SEC version:
- *
- * Max. chan-
- * version Bus I/F Clock nels DEU AESU AFEU MDEU PKEU RNG KEU
- *
- * SEC 1.0 internal 64b 100MHz 4 1 1 1 1 1 1 0
- * SEC 1.2 internal 32b 66MHz 1 1 1 0 1 0 0 0
- * SEC 2.0 internal 64b 166MHz 4 1 1 1 1 1 1 0
- * SEC 2.01 internal 64b 166MHz 4 1 1 1 1 1 1 0
- * SEC 2.1 internal 64b 333MHz 4 1 1 1 1 1 1 1
- *
- * Each execution unit in the SEC has two modes of execution; channel and
- * slave/debug. This driver employs the channel infrastructure in the
- * device for convenience. Only the RNG is directly accessed due to the
- * convenience of its random fifo pool. The relationship between the
- * channels and execution units is depicted in the following diagram:
- *
- * ------- ------------
- * ---| ch0 |---| |
- * ------- | |
- * | |------+-------+-------+-------+------------
- * ------- | | | | | | |
- * ---| ch1 |---| | | | | | |
- * ------- | | ------ ------ ------ ------ ------
- * |controller| |DEU | |AESU| |MDEU| |PKEU| ... |RNG |
- * ------- | | ------ ------ ------ ------ ------
- * ---| ch2 |---| | | | | | |
- * ------- | | | | | | |
- * | |------+-------+-------+-------+------------
- * ------- | |
- * ---| ch3 |---| |
- * ------- ------------
- *
- * Channel ch0 may drive an aes operation to the aes unit (AESU),
- * and, at the same time, ch1 may drive a message digest operation
- * to the mdeu. Each channel has an input descriptor FIFO, and the
- * FIFO can contain, e.g. on the 8541E, up to 24 entries, before a
- * a buffer overrun error is triggered. The controller is responsible
- * for fetching the data from descriptor pointers, and passing the
- * data to the appropriate EUs. The controller also writes the
- * cryptographic operation's result to memory. The SEC notifies
- * completion by triggering an interrupt and/or setting the 1st byte
- * of the hdr field to 0xff.
- *
- * TODO:
- * o support more algorithms
- * o support more versions of the SEC
- * o add support for linux 2.4
- * o scatter-gather (sg) support
- * o add support for public key ops (PKEU)
- * o add statistics
- */
- #include <linux/version.h>
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED)
- #include <linux/config.h>
- #endif
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/interrupt.h>
- #include <linux/spinlock.h>
- #include <linux/random.h>
- #include <linux/skbuff.h>
- #include <asm/scatterlist.h>
- #include <linux/dma-mapping.h> /* dma_map_single() */
- #include <linux/moduleparam.h>
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
- #include <linux/platform_device.h>
- #endif
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
- #include <linux/of_platform.h>
- #endif
- #include <cryptodev.h>
- #include <uio.h>
- #define DRV_NAME "talitos"
- #include "talitos_dev.h"
- #include "talitos_soft.h"
- #define read_random(p,l) get_random_bytes(p,l)
- const char talitos_driver_name[] = "Talitos OCF";
- const char talitos_driver_version[] = "0.2";
- static int talitos_newsession(device_t dev, u_int32_t *sidp,
- struct cryptoini *cri);
- static int talitos_freesession(device_t dev, u_int64_t tid);
- static int talitos_process(device_t dev, struct cryptop *crp, int hint);
- static void dump_talitos_status(struct talitos_softc *sc);
- static int talitos_submit(struct talitos_softc *sc, struct talitos_desc *td,
- int chsel);
- static void talitos_doneprocessing(struct talitos_softc *sc);
- static void talitos_init_device(struct talitos_softc *sc);
- static void talitos_reset_device_master(struct talitos_softc *sc);
- static void talitos_reset_device(struct talitos_softc *sc);
- static void talitos_errorprocessing(struct talitos_softc *sc);
- #ifdef CONFIG_PPC_MERGE
- static int talitos_probe(struct of_device *ofdev, const struct of_device_id *match);
- static int talitos_remove(struct of_device *ofdev);
- #else
- static int talitos_probe(struct platform_device *pdev);
- static int talitos_remove(struct platform_device *pdev);
- #endif
- #ifdef CONFIG_OCF_RANDOMHARVEST
- static int talitos_read_random(void *arg, u_int32_t *buf, int maxwords);
- static void talitos_rng_init(struct talitos_softc *sc);
- #endif
- static device_method_t talitos_methods = {
- /* crypto device methods */
- DEVMETHOD(cryptodev_newsession, talitos_newsession),
- DEVMETHOD(cryptodev_freesession,talitos_freesession),
- DEVMETHOD(cryptodev_process, talitos_process),
- };
- #define debug talitos_debug
- int talitos_debug = 0;
- module_param(talitos_debug, int, 0644);
- MODULE_PARM_DESC(talitos_debug, "Enable debug");
- static inline void talitos_write(volatile unsigned *addr, u32 val)
- {
- out_be32(addr, val);
- }
- static inline u32 talitos_read(volatile unsigned *addr)
- {
- u32 val;
- val = in_be32(addr);
- return val;
- }
- static void dump_talitos_status(struct talitos_softc *sc)
- {
- unsigned int v, v_hi, i, *ptr;
- v = talitos_read(sc->sc_base_addr + TALITOS_MCR);
- v_hi = talitos_read(sc->sc_base_addr + TALITOS_MCR_HI);
- printk(KERN_INFO "%s: MCR 0x%08x_%08x\n",
- device_get_nameunit(sc->sc_cdev), v, v_hi);
- v = talitos_read(sc->sc_base_addr + TALITOS_IMR);
- v_hi = talitos_read(sc->sc_base_addr + TALITOS_IMR_HI);
- printk(KERN_INFO "%s: IMR 0x%08x_%08x\n",
- device_get_nameunit(sc->sc_cdev), v, v_hi);
- v = talitos_read(sc->sc_base_addr + TALITOS_ISR);
- v_hi = talitos_read(sc->sc_base_addr + TALITOS_ISR_HI);
- printk(KERN_INFO "%s: ISR 0x%08x_%08x\n",
- device_get_nameunit(sc->sc_cdev), v, v_hi);
- for (i = 0; i < sc->sc_num_channels; i++) {
- v = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET +
- TALITOS_CH_CDPR);
- v_hi = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET +
- TALITOS_CH_CDPR_HI);
- printk(KERN_INFO "%s: CDPR ch%d 0x%08x_%08x\n",
- device_get_nameunit(sc->sc_cdev), i, v, v_hi);
- }
- for (i = 0; i < sc->sc_num_channels; i++) {
- v = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET +
- TALITOS_CH_CCPSR);
- v_hi = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET +
- TALITOS_CH_CCPSR_HI);
- printk(KERN_INFO "%s: CCPSR ch%d 0x%08x_%08x\n",
- device_get_nameunit(sc->sc_cdev), i, v, v_hi);
- }
- ptr = sc->sc_base_addr + TALITOS_CH_DESCBUF;
- for (i = 0; i < 16; i++) {
- v = talitos_read(ptr++); v_hi = talitos_read(ptr++);
- printk(KERN_INFO "%s: DESCBUF ch0 0x%08x_%08x (tdp%02d)\n",
- device_get_nameunit(sc->sc_cdev), v, v_hi, i);
- }
- return;
- }
- #ifdef CONFIG_OCF_RANDOMHARVEST
- /*
- * pull random numbers off the RNG FIFO, not exceeding amount available
- */
- static int
- talitos_read_random(void *arg, u_int32_t *buf, int maxwords)
- {
- struct talitos_softc *sc = (struct talitos_softc *) arg;
- int rc;
- u_int32_t v;
- DPRINTF("%s()\n", __FUNCTION__);
- /* check for things like FIFO underflow */
- v = talitos_read(sc->sc_base_addr + TALITOS_RNGISR_HI);
- if (unlikely(v)) {
- printk(KERN_ERR "%s: RNGISR_HI error %08x\n",
- device_get_nameunit(sc->sc_cdev), v);
- return 0;
- }
- /*
- * OFL is number of available 64-bit words,
- * shift and convert to a 32-bit word count
- */
- v = talitos_read(sc->sc_base_addr + TALITOS_RNGSR_HI);
- v = (v & TALITOS_RNGSR_HI_OFL) >> (16 - 1);
- if (maxwords > v)
- maxwords = v;
- for (rc = 0; rc < maxwords; rc++) {
- buf[rc] = talitos_read(sc->sc_base_addr +
- TALITOS_RNG_FIFO + rc*sizeof(u_int32_t));
- }
- if (maxwords & 1) {
- /*
- * RNG will complain with an AE in the RNGISR
- * if we don't complete the pairs of 32-bit reads
- * to its 64-bit register based FIFO
- */
- v = talitos_read(sc->sc_base_addr +
- TALITOS_RNG_FIFO + rc*sizeof(u_int32_t));
- }
- return rc;
- }
- static void
- talitos_rng_init(struct talitos_softc *sc)
- {
- u_int32_t v;
- DPRINTF("%s()\n", __FUNCTION__);
- /* reset RNG EU */
- v = talitos_read(sc->sc_base_addr + TALITOS_RNGRCR_HI);
- v |= TALITOS_RNGRCR_HI_SR;
- talitos_write(sc->sc_base_addr + TALITOS_RNGRCR_HI, v);
- while ((talitos_read(sc->sc_base_addr + TALITOS_RNGSR_HI)
- & TALITOS_RNGSR_HI_RD) == 0)
- cpu_relax();
- /*
- * we tell the RNG to start filling the RNG FIFO
- * by writing the RNGDSR
- */
- v = talitos_read(sc->sc_base_addr + TALITOS_RNGDSR_HI);
- talitos_write(sc->sc_base_addr + TALITOS_RNGDSR_HI, v);
- /*
- * 64 bits of data will be pushed onto the FIFO every
- * 256 SEC cycles until the FIFO is full. The RNG then
- * attempts to keep the FIFO full.
- */
- v = talitos_read(sc->sc_base_addr + TALITOS_RNGISR_HI);
- if (v) {
- printk(KERN_ERR "%s: RNGISR_HI error %08x\n",
- device_get_nameunit(sc->sc_cdev), v);
- return;
- }
- /*
- * n.b. we need to add a FIPS test here - if the RNG is going
- * to fail, it's going to fail at reset time
- */
- return;
- }
- #endif /* CONFIG_OCF_RANDOMHARVEST */
- /*
- * Generate a new software session.
- */
- static int
- talitos_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri)
- {
- struct cryptoini *c, *encini = NULL, *macini = NULL;
- struct talitos_softc *sc = device_get_softc(dev);
- struct talitos_session *ses = NULL;
- int sesn;
- DPRINTF("%s()\n", __FUNCTION__);
- if (sidp == NULL || cri == NULL || sc == NULL) {
- DPRINTF("%s,%d - EINVAL\n", __FILE__, __LINE__);
- return EINVAL;
- }
- for (c = cri; c != NULL; c = c->cri_next) {
- if (c->cri_alg == CRYPTO_MD5 ||
- c->cri_alg == CRYPTO_MD5_HMAC ||
- c->cri_alg == CRYPTO_SHA1 ||
- c->cri_alg == CRYPTO_SHA1_HMAC ||
- c->cri_alg == CRYPTO_NULL_HMAC) {
- if (macini)
- return EINVAL;
- macini = c;
- } else if (c->cri_alg == CRYPTO_DES_CBC ||
- c->cri_alg == CRYPTO_3DES_CBC ||
- c->cri_alg == CRYPTO_AES_CBC ||
- c->cri_alg == CRYPTO_NULL_CBC) {
- if (encini)
- return EINVAL;
- encini = c;
- } else {
- DPRINTF("UNKNOWN c->cri_alg %d\n", encini->cri_alg);
- return EINVAL;
- }
- }
- if (encini == NULL && macini == NULL)
- return EINVAL;
- if (encini) {
- /* validate key length */
- switch (encini->cri_alg) {
- case CRYPTO_DES_CBC:
- if (encini->cri_klen != 64)
- return EINVAL;
- break;
- case CRYPTO_3DES_CBC:
- if (encini->cri_klen != 192) {
- return EINVAL;
- }
- break;
- case CRYPTO_AES_CBC:
- if (encini->cri_klen != 128 &&
- encini->cri_klen != 192 &&
- encini->cri_klen != 256)
- return EINVAL;
- break;
- default:
- DPRINTF("UNKNOWN encini->cri_alg %d\n",
- encini->cri_alg);
- return EINVAL;
- }
- }
- if (sc->sc_sessions == NULL) {
- ses = sc->sc_sessions = (struct talitos_session *)
- kmalloc(sizeof(struct talitos_session), SLAB_ATOMIC);
- if (ses == NULL)
- return ENOMEM;
- memset(ses, 0, sizeof(struct talitos_session));
- sesn = 0;
- sc->sc_nsessions = 1;
- } else {
- for (sesn = 0; sesn < sc->sc_nsessions; sesn++) {
- if (sc->sc_sessions[sesn].ses_used == 0) {
- ses = &sc->sc_sessions[sesn];
- break;
- }
- }
- if (ses == NULL) {
- /* allocating session */
- sesn = sc->sc_nsessions;
- ses = (struct talitos_session *) kmalloc(
- (sesn + 1) * sizeof(struct talitos_session),
- SLAB_ATOMIC);
- if (ses == NULL)
- return ENOMEM;
- memset(ses, 0,
- (sesn + 1) * sizeof(struct talitos_session));
- memcpy(ses, sc->sc_sessions,
- sesn * sizeof(struct talitos_session));
- memset(sc->sc_sessions, 0,
- sesn * sizeof(struct talitos_session));
- kfree(sc->sc_sessions);
- sc->sc_sessions = ses;
- ses = &sc->sc_sessions[sesn];
- sc->sc_nsessions++;
- }
- }
- ses->ses_used = 1;
- if (encini) {
- ses->ses_klen = (encini->cri_klen + 7) / 8;
- memcpy(ses->ses_key, encini->cri_key, ses->ses_klen);
- if (macini) {
- /* doing hash on top of cipher */
- ses->ses_hmac_len = (macini->cri_klen + 7) / 8;
- memcpy(ses->ses_hmac, macini->cri_key,
- ses->ses_hmac_len);
- }
- } else if (macini) {
- /* doing hash */
- ses->ses_klen = (macini->cri_klen + 7) / 8;
- memcpy(ses->ses_key, macini->cri_key, ses->ses_klen);
- }
- /* back compat way of determining MSC result len */
- if (macini) {
- ses->ses_mlen = macini->cri_mlen;
- if (ses->ses_mlen == 0) {
- if (macini->cri_alg == CRYPTO_MD5_HMAC)
- ses->ses_mlen = MD5_HASH_LEN;
- else
- ses->ses_mlen = SHA1_HASH_LEN;
- }
- }
- /* really should make up a template td here,
- * and only fill things like i/o and direction in process() */
- /* assign session ID */
- *sidp = TALITOS_SID(sc->sc_num, sesn);
- return 0;
- }
- /*
- * Deallocate a session.
- */
- static int
- talitos_freesession(device_t dev, u_int64_t tid)
- {
- struct talitos_softc *sc = device_get_softc(dev);
- int session, ret;
- u_int32_t sid = ((u_int32_t) tid) & 0xffffffff;
- if (sc == NULL)
- return EINVAL;
- session = TALITOS_SESSION(sid);
- if (session < sc->sc_nsessions) {
- memset(&sc->sc_sessions[session], 0,
- sizeof(sc->sc_sessions[session]));
- ret = 0;
- } else
- ret = EINVAL;
- return ret;
- }
- /*
- * launch device processing - it will come back with done notification
- * in the form of an interrupt and/or HDR_DONE_BITS in header
- */
- static int
- talitos_submit(
- struct talitos_softc *sc,
- struct talitos_desc *td,
- int chsel)
- {
- u_int32_t v;
- v = dma_map_single(NULL, td, sizeof(*td), DMA_TO_DEVICE);
- talitos_write(sc->sc_base_addr +
- chsel*TALITOS_CH_OFFSET + TALITOS_CH_FF, 0);
- talitos_write(sc->sc_base_addr +
- chsel*TALITOS_CH_OFFSET + TALITOS_CH_FF_HI, v);
- return 0;
- }
- static int
- talitos_process(device_t dev, struct cryptop *crp, int hint)
- {
- int i, err = 0, ivsize;
- struct talitos_softc *sc = device_get_softc(dev);
- struct cryptodesc *crd1, *crd2, *maccrd, *enccrd;
- caddr_t iv;
- struct talitos_session *ses;
- struct talitos_desc *td;
- unsigned long flags;
- /* descriptor mappings */
- int hmac_key, hmac_data, cipher_iv, cipher_key,
- in_fifo, out_fifo, cipher_iv_out;
- static int chsel = -1;
- u_int32_t rand_iv[4];
- DPRINTF("%s()\n", __FUNCTION__);
- if (crp == NULL || crp->crp_callback == NULL || sc == NULL) {
- return EINVAL;
- }
- crp->crp_etype = 0;
- if (TALITOS_SESSION(crp->crp_sid) >= sc->sc_nsessions) {
- return EINVAL;
- }
- ses = &sc->sc_sessions[TALITOS_SESSION(crp->crp_sid)];
- /* enter the channel scheduler */
- spin_lock_irqsave(&sc->sc_chnfifolock[sc->sc_num_channels], flags);
- /* reuse channel that already had/has requests for the required EU */
- for (i = 0; i < sc->sc_num_channels; i++) {
- if (sc->sc_chnlastalg[i] == crp->crp_desc->crd_alg)
- break;
- }
- if (i == sc->sc_num_channels) {
- /*
- * haven't seen this algo the last sc_num_channels or more
- * use round robin in this case
- * nb: sc->sc_num_channels must be power of 2
- */
- chsel = (chsel + 1) & (sc->sc_num_channels - 1);
- } else {
- /*
- * matches channel with same target execution unit;
- * use same channel in this case
- */
- chsel = i;
- }
- sc->sc_chnlastalg[chsel] = crp->crp_desc->crd_alg;
- /* release the channel scheduler lock */
- spin_unlock_irqrestore(&sc->sc_chnfifolock[sc->sc_num_channels], flags);
- /* acquire the selected channel fifo lock */
- spin_lock_irqsave(&sc->sc_chnfifolock[chsel], flags);
- /* find and reserve next available descriptor-cryptop pair */
- for (i = 0; i < sc->sc_chfifo_len; i++) {
- if (sc->sc_chnfifo[chsel][i].cf_desc.hdr == 0) {
- /*
- * ensure correct descriptor formation by
- * avoiding inadvertently setting "optional" entries
- * e.g. not using "optional" dptr2 for MD/HMAC descs
- */
- memset(&sc->sc_chnfifo[chsel][i].cf_desc,
- 0, sizeof(*td));
- /* reserve it with done notification request bit */
- sc->sc_chnfifo[chsel][i].cf_desc.hdr |=
- TALITOS_DONE_NOTIFY;
- break;
- }
- }
- spin_unlock_irqrestore(&sc->sc_chnfifolock[chsel], flags);
- if (i == sc->sc_chfifo_len) {
- /* fifo full */
- err = ERESTART;
- goto errout;
- }
-
- td = &sc->sc_chnfifo[chsel][i].cf_desc;
- sc->sc_chnfifo[chsel][i].cf_crp = crp;
- crd1 = crp->crp_desc;
- if (crd1 == NULL) {
- err = EINVAL;
- goto errout;
- }
- crd2 = crd1->crd_next;
- /* prevent compiler warning */
- hmac_key = 0;
- hmac_data = 0;
- if (crd2 == NULL) {
- td->hdr |= TD_TYPE_COMMON_NONSNOOP_NO_AFEU;
- /* assign descriptor dword ptr mappings for this desc. type */
- cipher_iv = 1;
- cipher_key = 2;
- in_fifo = 3;
- cipher_iv_out = 5;
- if (crd1->crd_alg == CRYPTO_MD5_HMAC ||
- crd1->crd_alg == CRYPTO_SHA1_HMAC ||
- crd1->crd_alg == CRYPTO_SHA1 ||
- crd1->crd_alg == CRYPTO_MD5) {
- out_fifo = 5;
- maccrd = crd1;
- enccrd = NULL;
- } else if (crd1->crd_alg == CRYPTO_DES_CBC ||
- crd1->crd_alg == CRYPTO_3DES_CBC ||
- crd1->crd_alg == CRYPTO_AES_CBC ||
- crd1->crd_alg == CRYPTO_ARC4) {
- out_fifo = 4;
- maccrd = NULL;
- enccrd = crd1;
- } else {
- DPRINTF("UNKNOWN crd1->crd_alg %d\n", crd1->crd_alg);
- err = EINVAL;
- goto errout;
- }
- } else {
- if (sc->sc_desc_types & TALITOS_HAS_DT_IPSEC_ESP) {
- td->hdr |= TD_TYPE_IPSEC_ESP;
- } else {
- DPRINTF("unimplemented: multiple descriptor ipsec\n");
- err = EINVAL;
- goto errout;
- }
- /* assign descriptor dword ptr mappings for this desc. type */
- hmac_key = 0;
- hmac_data = 1;
- cipher_iv = 2;
- cipher_key = 3;
- in_fifo = 4;
- out_fifo = 5;
- cipher_iv_out = 6;
- if ((crd1->crd_alg == CRYPTO_MD5_HMAC ||
- crd1->crd_alg == CRYPTO_SHA1_HMAC ||
- crd1->crd_alg == CRYPTO_MD5 ||
- crd1->crd_alg == CRYPTO_SHA1) &&
- (crd2->crd_alg == CRYPTO_DES_CBC ||
- crd2->crd_alg == CRYPTO_3DES_CBC ||
- crd2->crd_alg == CRYPTO_AES_CBC ||
- crd2->crd_alg == CRYPTO_ARC4) &&
- ((crd2->crd_flags & CRD_F_ENCRYPT) == 0)) {
- maccrd = crd1;
- enccrd = crd2;
- } else if ((crd1->crd_alg == CRYPTO_DES_CBC ||
- crd1->crd_alg == CRYPTO_ARC4 ||
- crd1->crd_alg == CRYPTO_3DES_CBC ||
- crd1->crd_alg == CRYPTO_AES_CBC) &&
- (crd2->crd_alg == CRYPTO_MD5_HMAC ||
- crd2->crd_alg == CRYPTO_SHA1_HMAC ||
- crd2->crd_alg == CRYPTO_MD5 ||
- crd2->crd_alg == CRYPTO_SHA1) &&
- (crd1->crd_flags & CRD_F_ENCRYPT)) {
- enccrd = crd1;
- maccrd = crd2;
- } else {
- /* We cannot order the SEC as requested */
- printk("%s: cannot do the order\n",
- device_get_nameunit(sc->sc_cdev));
- err = EINVAL;
- goto errout;
- }
- }
- /* assign in_fifo and out_fifo based on input/output struct type */
- if (crp->crp_flags & CRYPTO_F_SKBUF) {
- /* using SKB buffers */
- struct sk_buff *skb = (struct sk_buff *)crp->crp_buf;
- if (skb_shinfo(skb)->nr_frags) {
- printk("%s: skb frags unimplemented\n",
- device_get_nameunit(sc->sc_cdev));
- err = EINVAL;
- goto errout;
- }
- td->ptr[in_fifo].ptr = dma_map_single(NULL, skb->data,
- skb->len, DMA_TO_DEVICE);
- td->ptr[in_fifo].len = skb->len;
- td->ptr[out_fifo].ptr = dma_map_single(NULL, skb->data,
- skb->len, DMA_TO_DEVICE);
- td->ptr[out_fifo].len = skb->len;
- td->ptr[hmac_data].ptr = dma_map_single(NULL, skb->data,
- skb->len, DMA_TO_DEVICE);
- } else if (crp->crp_flags & CRYPTO_F_IOV) {
- /* using IOV buffers */
- struct uio *uiop = (struct uio *)crp->crp_buf;
- if (uiop->uio_iovcnt > 1) {
- printk("%s: iov frags unimplemented\n",
- device_get_nameunit(sc->sc_cdev));
- err = EINVAL;
- goto errout;
- }
- td->ptr[in_fifo].ptr = dma_map_single(NULL,
- uiop->uio_iov->iov_base, crp->crp_ilen, DMA_TO_DEVICE);
- td->ptr[in_fifo].len = crp->crp_ilen;
- /* crp_olen is never set; always use crp_ilen */
- td->ptr[out_fifo].ptr = dma_map_single(NULL,
- uiop->uio_iov->iov_base,
- crp->crp_ilen, DMA_TO_DEVICE);
- td->ptr[out_fifo].len = crp->crp_ilen;
- } else {
- /* using contig buffers */
- td->ptr[in_fifo].ptr = dma_map_single(NULL,
- crp->crp_buf, crp->crp_ilen, DMA_TO_DEVICE);
- td->ptr[in_fifo].len = crp->crp_ilen;
- td->ptr[out_fifo].ptr = dma_map_single(NULL,
- crp->crp_buf, crp->crp_ilen, DMA_TO_DEVICE);
- td->ptr[out_fifo].len = crp->crp_ilen;
- }
- if (enccrd) {
- switch (enccrd->crd_alg) {
- case CRYPTO_3DES_CBC:
- td->hdr |= TALITOS_MODE0_DEU_3DES;
- /* FALLTHROUGH */
- case CRYPTO_DES_CBC:
- td->hdr |= TALITOS_SEL0_DEU
- | TALITOS_MODE0_DEU_CBC;
- if (enccrd->crd_flags & CRD_F_ENCRYPT)
- td->hdr |= TALITOS_MODE0_DEU_ENC;
- ivsize = 2*sizeof(u_int32_t);
- DPRINTF("%cDES ses %d ch %d len %d\n",
- (td->hdr & TALITOS_MODE0_DEU_3DES)?'3':'1',
- (u32)TALITOS_SESSION(crp->crp_sid),
- chsel, td->ptr[in_fifo].len);
- break;
- case CRYPTO_AES_CBC:
- td->hdr |= TALITOS_SEL0_AESU
- | TALITOS_MODE0_AESU_CBC;
- if (enccrd->crd_flags & CRD_F_ENCRYPT)
- td->hdr |= TALITOS_MODE0_AESU_ENC;
- ivsize = 4*sizeof(u_int32_t);
- DPRINTF("AES ses %d ch %d len %d\n",
- (u32)TALITOS_SESSION(crp->crp_sid),
- chsel, td->ptr[in_fifo].len);
- break;
- default:
- printk("%s: unimplemented enccrd->crd_alg %d\n",
- device_get_nameunit(sc->sc_cdev), enccrd->crd_alg);
- err = EINVAL;
- goto errout;
- }
- /*
- * Setup encrypt/decrypt state. When using basic ops
- * we can't use an inline IV because hash/crypt offset
- * must be from the end of the IV to the start of the
- * crypt data and this leaves out the preceding header
- * from the hash calculation. Instead we place the IV
- * in the state record and set the hash/crypt offset to
- * copy both the header+IV.
- */
- if (enccrd->crd_flags & CRD_F_ENCRYPT) {
- td->hdr |= TALITOS_DIR_OUTBOUND;
- if (enccrd->crd_flags & CRD_F_IV_EXPLICIT)
- iv = enccrd->crd_iv;
- else
- read_random((iv = (caddr_t) rand_iv), sizeof(rand_iv));
- if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0) {
- crypto_copyback(crp->crp_flags, crp->crp_buf,
- enccrd->crd_inject, ivsize, iv);
- }
- } else {
- td->hdr |= TALITOS_DIR_INBOUND;
- if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) {
- iv = enccrd->crd_iv;
- } else {
- iv = (caddr_t) rand_iv;
- crypto_copydata(crp->crp_flags, crp->crp_buf,
- enccrd->crd_inject, ivsize, iv);
- }
- }
- td->ptr[cipher_iv].ptr = dma_map_single(NULL, iv, ivsize,
- DMA_TO_DEVICE);
- td->ptr[cipher_iv].len = ivsize;
- /*
- * we don't need the cipher iv out length/pointer
- * field to do ESP IPsec. Therefore we set the len field as 0,
- * which tells the SEC not to do anything with this len/ptr
- * field. Previously, when length/pointer as pointing to iv,
- * it gave us corruption of packets.
- */
- td->ptr[cipher_iv_out].len = 0;
- }
- if (enccrd && maccrd) {
- /* this is ipsec only for now */
- td->hdr |= TALITOS_SEL1_MDEU
- | TALITOS_MODE1_MDEU_INIT
- | TALITOS_MODE1_MDEU_PAD;
- switch (maccrd->crd_alg) {
- case CRYPTO_MD5:
- td->hdr |= TALITOS_MODE1_MDEU_MD5;
- break;
- case CRYPTO_MD5_HMAC:
- td->hdr |= TALITOS_MODE1_MDEU_MD5_HMAC;
- break;
- case CRYPTO_SHA1:
- td->hdr |= TALITOS_MODE1_MDEU_SHA1;
- break;
- case CRYPTO_SHA1_HMAC:
- td->hdr |= TALITOS_MODE1_MDEU_SHA1_HMAC;
- break;
- default:
- /* We cannot order the SEC as requested */
- printk("%s: cannot do the order\n",
- device_get_nameunit(sc->sc_cdev));
- err = EINVAL;
- goto errout;
- }
- if ((maccrd->crd_alg == CRYPTO_MD5_HMAC) ||
- (maccrd->crd_alg == CRYPTO_SHA1_HMAC)) {
- /*
- * The offset from hash data to the start of
- * crypt data is the difference in the skips.
- */
- /* ipsec only for now */
- td->ptr[hmac_key].ptr = dma_map_single(NULL,
- ses->ses_hmac, ses->ses_hmac_len, DMA_TO_DEVICE);
- td->ptr[hmac_key].len = ses->ses_hmac_len;
- td->ptr[in_fifo].ptr += enccrd->crd_skip;
- td->ptr[in_fifo].len = enccrd->crd_len;
- td->ptr[out_fifo].ptr += enccrd->crd_skip;
- td->ptr[out_fifo].len = enccrd->crd_len;
- /* bytes of HMAC to postpend to ciphertext */
- td->ptr[out_fifo].extent = ses->ses_mlen;
- td->ptr[hmac_data].ptr += maccrd->crd_skip;
- td->ptr[hmac_data].len = enccrd->crd_skip - maccrd->crd_skip;
- }
- if (enccrd->crd_flags & CRD_F_KEY_EXPLICIT) {
- printk("%s: CRD_F_KEY_EXPLICIT unimplemented\n",
- device_get_nameunit(sc->sc_cdev));
- }
- }
- if (!enccrd && maccrd) {
- /* single MD5 or SHA */
- td->hdr |= TALITOS_SEL0_MDEU
- | TALITOS_MODE0_MDEU_INIT
- | TALITOS_MODE0_MDEU_PAD;
- switch (maccrd->crd_alg) {
- case CRYPTO_MD5:
- td->hdr |= TALITOS_MODE0_MDEU_MD5;
- DPRINTF("MD5 ses %d ch %d len %d\n",
- (u32)TALITOS_SESSION(crp->crp_sid),
- chsel, td->ptr[in_fifo].len);
- break;
- case CRYPTO_MD5_HMAC:
- td->hdr |= TALITOS_MODE0_MDEU_MD5_HMAC;
- break;
- case CRYPTO_SHA1:
- td->hdr |= TALITOS_MODE0_MDEU_SHA1;
- DPRINTF("SHA1 ses %d ch %d len %d\n",
- (u32)TALITOS_SESSION(crp->crp_sid),
- chsel, td->ptr[in_fifo].len);
- break;
- case CRYPTO_SHA1_HMAC:
- td->hdr |= TALITOS_MODE0_MDEU_SHA1_HMAC;
- break;
- default:
- /* We cannot order the SEC as requested */
- DPRINTF("cannot do the order\n");
- err = EINVAL;
- goto errout;
- }
- if (crp->crp_flags & CRYPTO_F_IOV)
- td->ptr[out_fifo].ptr += maccrd->crd_inject;
- if ((maccrd->crd_alg == CRYPTO_MD5_HMAC) ||
- (maccrd->crd_alg == CRYPTO_SHA1_HMAC)) {
- td->ptr[hmac_key].ptr = dma_map_single(NULL,
- ses->ses_hmac, ses->ses_hmac_len,
- DMA_TO_DEVICE);
- td->ptr[hmac_key].len = ses->ses_hmac_len;
- }
- }
- else {
- /* using process key (session data has duplicate) */
- td->ptr[cipher_key].ptr = dma_map_single(NULL,
- enccrd->crd_key, (enccrd->crd_klen + 7) / 8,
- DMA_TO_DEVICE);
- td->ptr[cipher_key].len = (enccrd->crd_klen + 7) / 8;
- }
- /* descriptor complete - GO! */
- return talitos_submit(sc, td, chsel);
- errout:
- if (err != ERESTART) {
- crp->crp_etype = err;
- crypto_done(crp);
- }
- return err;
- }
- /* go through all channels descriptors, notifying OCF what has
- * _and_hasn't_ successfully completed and reset the device
- * (otherwise it's up to decoding desc hdrs!)
- */
- static void talitos_errorprocessing(struct talitos_softc *sc)
- {
- unsigned long flags;
- int i, j;
- /* disable further scheduling until under control */
- spin_lock_irqsave(&sc->sc_chnfifolock[sc->sc_num_channels], flags);
- if (debug) dump_talitos_status(sc);
- /* go through descriptors, try and salvage those successfully done,
- * and EIO those that weren't
- */
- for (i = 0; i < sc->sc_num_channels; i++) {
- spin_lock_irqsave(&sc->sc_chnfifolock[i], flags);
- for (j = 0; j < sc->sc_chfifo_len; j++) {
- if (sc->sc_chnfifo[i][j].cf_desc.hdr) {
- if ((sc->sc_chnfifo[i][j].cf_desc.hdr
- & TALITOS_HDR_DONE_BITS)
- != TALITOS_HDR_DONE_BITS) {
- /* this one didn't finish */
- /* signify in crp->etype */
- sc->sc_chnfifo[i][j].cf_crp->crp_etype
- = EIO;
- }
- } else
- continue; /* free entry */
- /* either way, notify ocf */
- crypto_done(sc->sc_chnfifo[i][j].cf_crp);
- /* and tag it available again
- *
- * memset to ensure correct descriptor formation by
- * avoiding inadvertently setting "optional" entries
- * e.g. not using "optional" dptr2 MD/HMAC processing
- */
- memset(&sc->sc_chnfifo[i][j].cf_desc,
- 0, sizeof(struct talitos_desc));
- }
- spin_unlock_irqrestore(&sc->sc_chnfifolock[i], flags);
- }
- /* reset and initialize the SEC h/w device */
- talitos_reset_device(sc);
- talitos_init_device(sc);
- #ifdef CONFIG_OCF_RANDOMHARVEST
- if (sc->sc_exec_units & TALITOS_HAS_EU_RNG)
- talitos_rng_init(sc);
- #endif
- /* Okay. Stand by. */
- spin_unlock_irqrestore(&sc->sc_chnfifolock[sc->sc_num_channels], flags);
- return;
- }
- /* go through all channels descriptors, notifying OCF what's been done */
- static void talitos_doneprocessing(struct talitos_softc *sc)
- {
- unsigned long flags;
- int i, j;
- /* go through descriptors looking for done bits */
- for (i = 0; i < sc->sc_num_channels; i++) {
- spin_lock_irqsave(&sc->sc_chnfifolock[i], flags);
- for (j = 0; j < sc->sc_chfifo_len; j++) {
- /* descriptor has done bits set? */
- if ((sc->sc_chnfifo[i][j].cf_desc.hdr
- & TALITOS_HDR_DONE_BITS)
- == TALITOS_HDR_DONE_BITS) {
- /* notify ocf */
- crypto_done(sc->sc_chnfifo[i][j].cf_crp);
- /* and tag it available again
- *
- * memset to ensure correct descriptor formation by
- * avoiding inadvertently setting "optional" entries
- * e.g. not using "optional" dptr2 MD/HMAC processing
- */
- memset(&sc->sc_chnfifo[i][j].cf_desc,
- 0, sizeof(struct talitos_desc));
- }
- }
- spin_unlock_irqrestore(&sc->sc_chnfifolock[i], flags);
- }
- return;
- }
- static irqreturn_t
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
- talitos_intr(int irq, void *arg)
- #else
- talitos_intr(int irq, void *arg, struct pt_regs *regs)
- #endif
- {
- struct talitos_softc *sc = arg;
- u_int32_t v, v_hi;
-
- /* ack */
- v = talitos_read(sc->sc_base_addr + TALITOS_ISR);
- v_hi = talitos_read(sc->sc_base_addr + TALITOS_ISR_HI);
- talitos_write(sc->sc_base_addr + TALITOS_ICR, v);
- talitos_write(sc->sc_base_addr + TALITOS_ICR_HI, v_hi);
- if (unlikely(v & TALITOS_ISR_ERROR)) {
- /* Okay, Houston, we've had a problem here. */
- printk(KERN_DEBUG "%s: got error interrupt - ISR 0x%08x_%08x\n",
- device_get_nameunit(sc->sc_cdev), v, v_hi);
- talitos_errorprocessing(sc);
- } else
- if (likely(v & TALITOS_ISR_DONE)) {
- talitos_doneprocessing(sc);
- }
- return IRQ_HANDLED;
- }
- /*
- * Initialize registers we need to touch only once.
- */
- static void
- talitos_init_device(struct talitos_softc *sc)
- {
- u_int32_t v;
- int i;
- DPRINTF("%s()\n", __FUNCTION__);
- /* init all channels */
- for (i = 0; i < sc->sc_num_channels; i++) {
- v = talitos_read(sc->sc_base_addr +
- i*TALITOS_CH_OFFSET + TALITOS_CH_CCCR_HI);
- v |= TALITOS_CH_CCCR_HI_CDWE
- | TALITOS_CH_CCCR_HI_CDIE; /* invoke interrupt if done */
- talitos_write(sc->sc_base_addr +
- i*TALITOS_CH_OFFSET + TALITOS_CH_CCCR_HI, v);
- }
- /* enable all interrupts */
- v = talitos_read(sc->sc_base_addr + TALITOS_IMR);
- v |= TALITOS_IMR_ALL;
- talitos_write(sc->sc_base_addr + TALITOS_IMR, v);
- v = talitos_read(sc->sc_base_addr + TALITOS_IMR_HI);
- v |= TALITOS_IMR_HI_ERRONLY;
- talitos_write(sc->sc_base_addr + TALITOS_IMR_HI, v);
- return;
- }
- /*
- * set the master reset bit on the device.
- */
- static void
- talitos_reset_device_master(struct talitos_softc *sc)
- {
- u_int32_t v;
- /* Reset the device by writing 1 to MCR:SWR and waiting 'til cleared */
- v = talitos_read(sc->sc_base_addr + TALITOS_MCR);
- talitos_write(sc->sc_base_addr + TALITOS_MCR, v | TALITOS_MCR_SWR);
- while (talitos_read(sc->sc_base_addr + TALITOS_MCR) & TALITOS_MCR_SWR)
- cpu_relax();
- return;
- }
- /*
- * Resets the device. Values in the registers are left as is
- * from the reset (i.e. initial values are assigned elsewhere).
- */
- static void
- talitos_reset_device(struct talitos_softc *sc)
- {
- u_int32_t v;
- int i;
- DPRINTF("%s()\n", __FUNCTION__);
- /*
- * Master reset
- * errata documentation: warning: certain SEC interrupts
- * are not fully cleared by writing the MCR:SWR bit,
- * set bit twice to completely reset
- */
- talitos_reset_device_master(sc); /* once */
- talitos_reset_device_master(sc); /* and once again */
-
- /* reset all channels */
- for (i = 0; i < sc->sc_num_channels; i++) {
- v = talitos_read(sc->sc_base_addr + i*TALITOS_CH_OFFSET +
- TALITOS_CH_CCCR);
- talitos_write(sc->sc_base_addr + i*TALITOS_CH_OFFSET +
- TALITOS_CH_CCCR, v | TALITOS_CH_CCCR_RESET);
- }
- }
- /* Set up the crypto device structure, private data,
- * and anything else we need before we start */
- #ifdef CONFIG_PPC_MERGE
- static int talitos_probe(struct of_device *ofdev, const struct of_device_id *match)
- #else
- static int talitos_probe(struct platform_device *pdev)
- #endif
- {
- struct talitos_softc *sc = NULL;
- struct resource *r;
- #ifdef CONFIG_PPC_MERGE
- struct device *device = &ofdev->dev;
- struct device_node *np = ofdev->node;
- const unsigned int *prop;
- int err;
- struct resource res;
- #endif
- static int num_chips = 0;
- int rc;
- int i;
- DPRINTF("%s()\n", __FUNCTION__);
- sc = (struct talitos_softc *) kmalloc(sizeof(*sc), GFP_KERNEL);
- if (!sc)
- return -ENOMEM;
- memset(sc, 0, sizeof(*sc));
- softc_device_init(sc, DRV_NAME, num_chips, talitos_methods);
- sc->sc_irq = -1;
- sc->sc_cid = -1;
- #ifndef CONFIG_PPC_MERGE
- sc->sc_dev = pdev;
- #endif
- sc->sc_num = num_chips++;
- #ifdef CONFIG_PPC_MERGE
- dev_set_drvdata(device, sc);
- #else
- platform_set_drvdata(sc->sc_dev, sc);
- #endif
- /* get the irq line */
- #ifdef CONFIG_PPC_MERGE
- err = of_address_to_resource(np, 0, &res);
- if (err)
- return -EINVAL;
- r = &res;
- sc->sc_irq = irq_of_parse_and_map(np, 0);
- #else
- /* get a pointer to the register memory */
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- sc->sc_irq = platform_get_irq(pdev, 0);
- #endif
- rc = request_irq(sc->sc_irq, talitos_intr, 0,
- device_get_nameunit(sc->sc_cdev), sc);
- if (rc) {
- printk(KERN_ERR "%s: failed to hook irq %d\n",
- device_get_nameunit(sc->sc_cdev), sc->sc_irq);
- sc->sc_irq = -1;
- goto out;
- }
- sc->sc_base_addr = (ocf_iomem_t) ioremap(r->start, (r->end - r->start));
- if (!sc->sc_base_addr) {
- printk(KERN_ERR "%s: failed to ioremap\n",
- device_get_nameunit(sc->sc_cdev));
- goto out;
- }
- /* figure out our SEC's properties and capabilities */
- sc->sc_chiprev = (u64)talitos_read(sc->sc_base_addr + TALITOS_ID) << 32
- | talitos_read(sc->sc_base_addr + TALITOS_ID_HI);
- DPRINTF("sec id 0x%llx\n", sc->sc_chiprev);
- #ifdef CONFIG_PPC_MERGE
- /* get SEC properties from device tree, defaulting to SEC 2.0 */
- prop = of_get_property(np, "num-channels", NULL);
- sc->sc_num_channels = prop ? *prop : TALITOS_NCHANNELS_SEC_2_0;
- prop = of_get_property(np, "channel-fifo-len", NULL);
- sc->sc_chfifo_len = prop ? *prop : TALITOS_CHFIFOLEN_SEC_2_0;
- prop = of_get_property(np, "exec-units-mask", NULL);
- sc->sc_exec_units = prop ? *prop : TALITOS_HAS_EUS_SEC_2_0;
- prop = of_get_property(np, "descriptor-types-mask", NULL);
- sc->sc_desc_types = prop ? *prop : TALITOS_HAS_DESCTYPES_SEC_2_0;
- #else
- /* bulk should go away with openfirmware flat device tree support */
- if (sc->sc_chiprev & TALITOS_ID_SEC_2_0) {
- sc->sc_num_channels = TALITOS_NCHANNELS_SEC_2_0;
- sc->sc_chfifo_len = TALITOS_CHFIFOLEN_SEC_2_0;
- sc->sc_exec_units = TALITOS_HAS_EUS_SEC_2_0;
- sc->sc_desc_types = TALITOS_HAS_DESCTYPES_SEC_2_0;
- } else {
- printk(KERN_ERR "%s: failed to id device\n",
- device_get_nameunit(sc->sc_cdev));
- goto out;
- }
- #endif
- /* + 1 is for the meta-channel lock used by the channel scheduler */
- sc->sc_chnfifolock = (spinlock_t *) kmalloc(
- (sc->sc_num_channels + 1) * sizeof(spinlock_t), GFP_KERNEL);
- if (!sc->sc_chnfifolock)
- goto out;
- for (i = 0; i < sc->sc_num_channels + 1; i++) {
- spin_lock_init(&sc->sc_chnfifolock[i]);
- }
- sc->sc_chnlastalg = (int *) kmalloc(
- sc->sc_num_channels * sizeof(int), GFP_KERNEL);
- if (!sc->sc_chnlastalg)
- goto out;
- memset(sc->sc_chnlastalg, 0, sc->sc_num_channels * sizeof(int));
- sc->sc_chnfifo = (struct desc_cryptop_pair **) kmalloc(
- sc->sc_num_channels * sizeof(struct desc_cryptop_pair *),
- GFP_KERNEL);
- if (!sc->sc_chnfifo)
- goto out;
- for (i = 0; i < sc->sc_num_channels; i++) {
- sc->sc_chnfifo[i] = (struct desc_cryptop_pair *) kmalloc(
- sc->sc_chfifo_len * sizeof(struct desc_cryptop_pair),
- GFP_KERNEL);
- if (!sc->sc_chnfifo[i])
- goto out;
- memset(sc->sc_chnfifo[i], 0,
- sc->sc_chfifo_len * sizeof(struct desc_cryptop_pair));
- }
- /* reset and initialize the SEC h/w device */
- talitos_reset_device(sc);
- talitos_init_device(sc);
- sc->sc_cid = crypto_get_driverid(softc_get_device(sc),CRYPTOCAP_F_HARDWARE);
- if (sc->sc_cid < 0) {
- printk(KERN_ERR "%s: could not get crypto driver id\n",
- device_get_nameunit(sc->sc_cdev));
- goto out;
- }
- /* register algorithms with the framework */
- printk("%s:", device_get_nameunit(sc->sc_cdev));
- if (sc->sc_exec_units & TALITOS_HAS_EU_RNG) {
- printk(" rng");
- #ifdef CONFIG_OCF_RANDOMHARVEST
- talitos_rng_init(sc);
- crypto_rregister(sc->sc_cid, talitos_read_random, sc);
- #endif
- }
- if (sc->sc_exec_units & TALITOS_HAS_EU_DEU) {
- printk(" des/3des");
- crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0);
- crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0);
- }
- if (sc->sc_exec_units & TALITOS_HAS_EU_AESU) {
- printk(" aes");
- crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0);
- }
- if (sc->sc_exec_units & TALITOS_HAS_EU_MDEU) {
- printk(" md5");
- crypto_register(sc->sc_cid, CRYPTO_MD5, 0, 0);
- /* HMAC support only with IPsec for now */
- crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0);
- printk(" sha1");
- crypto_register(sc->sc_cid, CRYPTO_SHA1, 0, 0);
- /* HMAC support only with IPsec for now */
- crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0);
- }
- printk("\n");
- return 0;
- out:
- #ifndef CONFIG_PPC_MERGE
- talitos_remove(pdev);
- #endif
- return -ENOMEM;
- }
- #ifdef CONFIG_PPC_MERGE
- static int talitos_remove(struct of_device *ofdev)
- #else
- static int talitos_remove(struct platform_device *pdev)
- #endif
- {
- #ifdef CONFIG_PPC_MERGE
- struct talitos_softc *sc = dev_get_drvdata(&ofdev->dev);
- #else
- struct talitos_softc *sc = platform_get_drvdata(pdev);
- #endif
- int i;
- DPRINTF("%s()\n", __FUNCTION__);
- if (sc->sc_cid >= 0)
- crypto_unregister_all(sc->sc_cid);
- if (sc->sc_chnfifo) {
- for (i = 0; i < sc->sc_num_channels; i++)
- if (sc->sc_chnfifo[i])
- kfree(sc->sc_chnfifo[i]);
- kfree(sc->sc_chnfifo);
- }
- if (sc->sc_chnlastalg)
- kfree(sc->sc_chnlastalg);
- if (sc->sc_chnfifolock)
- kfree(sc->sc_chnfifolock);
- if (sc->sc_irq != -1)
- free_irq(sc->sc_irq, sc);
- if (sc->sc_base_addr)
- iounmap((void *) sc->sc_base_addr);
- kfree(sc);
- return 0;
- }
- #ifdef CONFIG_PPC_MERGE
- static struct of_device_id talitos_match[] = {
- {
- .type = "crypto",
- .compatible = "talitos",
- },
- {},
- };
- MODULE_DEVICE_TABLE(of, talitos_match);
- static struct of_platform_driver talitos_driver = {
- .name = DRV_NAME,
- .match_table = talitos_match,
- .probe = talitos_probe,
- .remove = talitos_remove,
- };
- static int __init talitos_init(void)
- {
- return of_register_platform_driver(&talitos_driver);
- }
- static void __exit talitos_exit(void)
- {
- of_unregister_platform_driver(&talitos_driver);
- }
- #else
- /* Structure for a platform device driver */
- static struct platform_driver talitos_driver = {
- .probe = talitos_probe,
- .remove = talitos_remove,
- .driver = {
- .name = "fsl-sec2",
- }
- };
- static int __init talitos_init(void)
- {
- return platform_driver_register(&talitos_driver);
- }
- static void __exit talitos_exit(void)
- {
- platform_driver_unregister(&talitos_driver);
- }
- #endif
- module_init(talitos_init);
- module_exit(talitos_exit);
- MODULE_LICENSE("Dual BSD/GPL");
- MODULE_AUTHOR("kim.phillips@freescale.com");
- MODULE_DESCRIPTION("OCF driver for Freescale SEC (talitos)");
|