📄 safe.c
字号:
sc->sc_front = sc->sc_ring; /* XXX honor batching */ safe_feed(sc, re); spin_unlock_irqrestore(&sc->sc_ringmtx, flags); return (0);errout: if (re->re_src.map != re->re_dst.map) pci_unmap_iov(sc, &re->re_dst); if (re->re_src.map) pci_unmap_iov(sc, &re->re_src); spin_unlock_irqrestore(&sc->sc_ringmtx, flags); if (err != ERESTART) { crp->crp_etype = err; crypto_done(crp); } else { sc->sc_needwakeup |= CRYPTO_SYMQ; } return (err);}static voidsafe_callback(struct safe_softc *sc, struct safe_ringentry *re){ struct cryptop *crp = (struct cryptop *)re->re_crp; struct cryptodesc *crd; DPRINTF("%s()\n", __FUNCTION__); safestats.st_opackets++; safestats.st_obytes += re->re_dst.mapsize; if (re->re_desc.d_csr & SAFE_PE_CSR_STATUS) { printk("safe: csr 0x%x cmd0 0x%x cmd1 0x%x\n", re->re_desc.d_csr, re->re_sa.sa_cmd0, re->re_sa.sa_cmd1); safestats.st_peoperr++; crp->crp_etype = EIO; /* something more meaningful? */ } if (re->re_dst.map != NULL && re->re_dst.map != re->re_src.map) pci_unmap_iov(sc, &re->re_dst); pci_unmap_iov(sc, &re->re_src);#if 0 /* * If result was written to a differet mbuf chain, swap * it in as the return value and reclaim the original. */ if ((crp->crp_flags & CRYPTO_F_IMBUF) && re->re_src_m != re->re_dst_m) { printk("safe: no CRYPTO_F_IMBUF support"); return; }#endif if (re->re_flags & SAFE_QFLAGS_COPYOUTIV) { /* copy out IV for future use */ for (crd = crp->crp_desc; crd; crd = crd->crd_next) { int ivsize; if (crd->crd_alg == CRYPTO_DES_CBC || crd->crd_alg == CRYPTO_3DES_CBC) { ivsize = 2*sizeof(u_int32_t); } else if (crd->crd_alg == CRYPTO_AES_CBC) { ivsize = 4*sizeof(u_int32_t); } else continue; if (crp->crp_flags & CRYPTO_F_IMBUF) { printk("safe: no CRYPTO_F_IMBUF support"); } else if (crp->crp_flags & CRYPTO_F_IOV) { int i; cuio_copydata((struct uio *)crp->crp_buf, crd->crd_skip + crd->crd_len - ivsize, ivsize, (caddr_t)sc->sc_sessions[re->re_sesn].ses_iv); for (i = 0; i < ivsize/sizeof(sc->sc_sessions[re->re_sesn].ses_iv[0]); i++) sc->sc_sessions[re->re_sesn].ses_iv[i] = cpu_to_le32(sc->sc_sessions[re->re_sesn].ses_iv[i]); } break; } } if (re->re_flags & SAFE_QFLAGS_COPYOUTICV) { /* copy out ICV result */ for (crd = crp->crp_desc; crd; crd = crd->crd_next) { if (!(crd->crd_alg == CRYPTO_MD5_HMAC || crd->crd_alg == CRYPTO_SHA1_HMAC || crd->crd_alg == CRYPTO_NULL_HMAC)) continue; if (crd->crd_alg == CRYPTO_SHA1_HMAC) { /* * SHA-1 ICV's are byte-swapped; fix 'em up * before copy them to their destination. */ bswap32(re->re_sastate.sa_saved_indigest[0]); bswap32(re->re_sastate.sa_saved_indigest[1]); bswap32(re->re_sastate.sa_saved_indigest[2]); } if (crp->crp_flags & CRYPTO_F_IMBUF) { printk("safe: no CRYPTO_F_IMBUF support"); } else if (crp->crp_flags & CRYPTO_F_IOV && crp->crp_mac) { bcopy((caddr_t)re->re_sastate.sa_saved_indigest, crp->crp_mac, 12); } break; } } crypto_done(crp);}#ifndef SAFE_NO_RNG#define SAFE_RNG_MAXWAIT 1000static voidsafe_rng_init(struct safe_softc *sc){ u_int32_t w, v; int i; DPRINTF("%s()\n", __FUNCTION__); WRITE_REG(sc, SAFE_RNG_CTRL, 0); /* use default value according to the manual */ WRITE_REG(sc, SAFE_RNG_CNFG, 0x834); /* magic from SafeNet */ WRITE_REG(sc, SAFE_RNG_ALM_CNT, 0); /* * There is a bug in rev 1.0 of the 1140 that when the RNG * is brought out of reset the ready status flag does not * work until the RNG has finished its internal initialization. * * So in order to determine the device is through its * initialization we must read the data register, using the * status reg in the read in case it is initialized. Then read * the data register until it changes from the first read. * Once it changes read the data register until it changes * again. At this time the RNG is considered initialized. * This could take between 750ms - 1000ms in time. */ i = 0; w = READ_REG(sc, SAFE_RNG_OUT); do { v = READ_REG(sc, SAFE_RNG_OUT); if (v != w) { w = v; break; } DELAY(10); } while (++i < SAFE_RNG_MAXWAIT); /* Wait Until data changes again */ i = 0; do { v = READ_REG(sc, SAFE_RNG_OUT); if (v != w) break; DELAY(10); } while (++i < SAFE_RNG_MAXWAIT);}static __inline voidsafe_rng_disable_short_cycle(struct safe_softc *sc){ DPRINTF("%s()\n", __FUNCTION__); WRITE_REG(sc, SAFE_RNG_CTRL, READ_REG(sc, SAFE_RNG_CTRL) &~ SAFE_RNG_CTRL_SHORTEN);}static __inline voidsafe_rng_enable_short_cycle(struct safe_softc *sc){ DPRINTF("%s()\n", __FUNCTION__); WRITE_REG(sc, SAFE_RNG_CTRL, READ_REG(sc, SAFE_RNG_CTRL) | SAFE_RNG_CTRL_SHORTEN);}static __inline u_int32_tsafe_rng_read(struct safe_softc *sc){ int i; DPRINTF("%s()\n", __FUNCTION__); i = 0; while (READ_REG(sc, SAFE_RNG_STAT) != 0 && ++i < SAFE_RNG_MAXWAIT) ; return READ_REG(sc, SAFE_RNG_OUT);}static voidsafe_rng(unsigned long arg){ struct safe_softc *sc = (struct safe_softc *) arg; u_int32_t buf[SAFE_RNG_MAXBUFSIZ]; /* NB: maybe move to softc */ u_int maxwords; int i; DPRINTF("%s()\n", __FUNCTION__); safestats.st_rng++; /* * Fetch the next block of data. */ maxwords = safe_rngbufsize; if (maxwords > SAFE_RNG_MAXBUFSIZ) maxwords = SAFE_RNG_MAXBUFSIZ;retry: for (i = 0; i < maxwords; i++) buf[i] = safe_rng_read(sc); /* * Check the comparator alarm count and reset the h/w if * it exceeds our threshold. This guards against the * hardware oscillators resonating with external signals. */ if (READ_REG(sc, SAFE_RNG_ALM_CNT) > safe_rngmaxalarm) { u_int32_t freq_inc, w; DPRINTF("%s: alarm count %u exceeds threshold %u\n", __func__, (unsigned)READ_REG(sc, SAFE_RNG_ALM_CNT), safe_rngmaxalarm); safestats.st_rngalarm++; safe_rng_enable_short_cycle(sc); freq_inc = 18; for (i = 0; i < 64; i++) { w = READ_REG(sc, SAFE_RNG_CNFG); freq_inc = ((w + freq_inc) & 0x3fL); w = ((w & ~0x3fL) | freq_inc); WRITE_REG(sc, SAFE_RNG_CNFG, w); WRITE_REG(sc, SAFE_RNG_ALM_CNT, 0); (void) safe_rng_read(sc); DELAY(25); if (READ_REG(sc, SAFE_RNG_ALM_CNT) == 0) { safe_rng_disable_short_cycle(sc); goto retry; } freq_inc = 1; } safe_rng_disable_short_cycle(sc); } else WRITE_REG(sc, SAFE_RNG_ALM_CNT, 0); mod_timer(&sc->sc_rngto, jiffies + (safe_rnginterval ? safe_rnginterval : 1) * HZ);}#endif /* SAFE_NO_RNG *//* * Resets the board. Values in the regesters are left as is * from the reset (i.e. initial values are assigned elsewhere). */static voidsafe_reset_board(struct safe_softc *sc){ u_int32_t v; /* * Reset the device. The manual says no delay * is needed between marking and clearing reset. */ DPRINTF("%s()\n", __FUNCTION__); v = READ_REG(sc, SAFE_PE_DMACFG) &~ (SAFE_PE_DMACFG_PERESET | SAFE_PE_DMACFG_PDRRESET | SAFE_PE_DMACFG_SGRESET); WRITE_REG(sc, SAFE_PE_DMACFG, v | SAFE_PE_DMACFG_PERESET | SAFE_PE_DMACFG_PDRRESET | SAFE_PE_DMACFG_SGRESET); WRITE_REG(sc, SAFE_PE_DMACFG, v);}/* * Initialize registers we need to touch only once. */static voidsafe_init_board(struct safe_softc *sc){ u_int32_t v, dwords; DPRINTF("%s()\n", __FUNCTION__); v = READ_REG(sc, SAFE_PE_DMACFG); v &=~ ( SAFE_PE_DMACFG_PEMODE | SAFE_PE_DMACFG_FSENA /* failsafe enable */ | SAFE_PE_DMACFG_GPRPCI /* gather ring on PCI */ | SAFE_PE_DMACFG_SPRPCI /* scatter ring on PCI */ | SAFE_PE_DMACFG_ESDESC /* endian-swap descriptors */ | SAFE_PE_DMACFG_ESPDESC /* endian-swap part. desc's */ | SAFE_PE_DMACFG_ESSA /* endian-swap SA's */ | SAFE_PE_DMACFG_ESPACKET /* swap the packet data */ ); v |= SAFE_PE_DMACFG_FSENA /* failsafe enable */ | SAFE_PE_DMACFG_GPRPCI /* gather ring on PCI */ | SAFE_PE_DMACFG_SPRPCI /* scatter ring on PCI */ | SAFE_PE_DMACFG_ESDESC /* endian-swap descriptors */ | SAFE_PE_DMACFG_ESPDESC /* endian-swap part. desc's */ | SAFE_PE_DMACFG_ESSA /* endian-swap SA's */#if 0 | SAFE_PE_DMACFG_ESPACKET /* swap the packet data */#endif ; WRITE_REG(sc, SAFE_PE_DMACFG, v);#ifdef __BIG_ENDIAN /* tell the safenet that we are 4321 and not 1234 */ WRITE_REG(sc, SAFE_ENDIAN, 0xe4e41b1b);#endif if (sc->sc_chiprev == SAFE_REV(1,0)) { /* * Avoid large PCI DMA transfers. Rev 1.0 has a bug where * "target mode transfers" done while the chip is DMA'ing * >1020 bytes cause the hardware to lockup. To avoid this * we reduce the max PCI transfer size and use small source * particle descriptors (<= 256 bytes). */ WRITE_REG(sc, SAFE_DMA_CFG, 256); printk("safe: Reduce max DMA size to %u words for rev %u.%u WAR\n", (unsigned) ((READ_REG(sc, SAFE_DMA_CFG)>>2) & 0xff), (unsigned) SAFE_REV_MAJ(sc->sc_chiprev), (unsigned) SAFE_REV_MIN(sc->sc_chiprev)); } /* NB: operands+results are overlaid */ WRITE_REG(sc, SAFE_PE_PDRBASE, sc->sc_ring_dma); WRITE_REG(sc, SAFE_PE_RDRBASE, sc->sc_ring_dma); /* * Configure ring entry size and number of items in the ring. */ KASSERT((sizeof(struct safe_ringentry) % sizeof(u_int32_t)) == 0, ("PE ring entry not 32-bit aligned!")); dwords = sizeof(struct safe_ringentry) / sizeof(u_int32_t); WRITE_REG(sc, SAFE_PE_RINGCFG, (dwords << SAFE_PE_RINGCFG_OFFSET_S) | SAFE_MAX_NQUEUE); WRITE_REG(sc, SAFE_PE_RINGPOLL, 0); /* disable polling */ WRITE_REG(sc, SAFE_PE_GRNGBASE, sc->sc_sp_dma); WRITE_REG(sc, SAFE_PE_SRNGBASE, sc->sc_dp_dma); WRITE_REG(sc, SAFE_PE_PARTSIZE, (SAFE_TOTAL_DPART<<16) | SAFE_TOTAL_SPART); /* * NB: destination particles are fixed size. We use * an mbuf cluster and require all results go to * clusters or smaller. */ WRITE_REG(sc, SAFE_PE_PARTCFG, SAFE_MAX_DSIZE); /* it's now safe to enable PE mode, do it */ WRITE_REG(sc, SAFE_PE_DMACFG, v | SAFE_PE_DMACFG_PEMODE); /* * Configure hardware to use level-triggered interrupts and * to interrupt after each descriptor is processed. */ WRITE_REG(sc, SAFE_HI_CFG, SAFE_HI_CFG_LEVEL); WRITE_REG(sc, SAFE_HI_DESC_CNT, 1); WRITE_REG(sc, SAFE_HI_MASK, SAFE_INT_PE_DDONE | SAFE_INT_PE_ERROR);}/* * Clean up after a chip crash. * It is assumed that the caller in splimp() */static voidsafe_cleanchip(struct safe_softc *sc){ DPRINTF("%s()\n", __FUNCTION__); if (sc->sc_nqchip != 0) { struct safe_ringentry *re = sc->sc_back; while (re != sc->sc_front) { if (re->re_desc.d_csr != 0) safe_free_entry(sc, re); if (++re == sc->sc_ringtop) re = sc->sc_ring; } sc->sc_back = re; sc->sc_nqchip = 0; }}/* * free a safe_q * It is assumed that the caller is within splimp(). */static intsafe_free_entry(struct safe_softc *sc, struct safe_ringentry *re){ struct cryptop *crp; DPRINTF("%s()\n", __FUNCTION__);#ifdef NOTYET /* * Free header MCR */ if ((re->re_dst_m != NULL) && (re->re_src_m != re->re_dst_m)) m_freem(re->re_dst_m);#endif crp = (struct cryptop *)re->re_crp; re->re_desc.d_csr = 0; crp->crp_etype = EFAULT; crypto_done(crp); return(0);}/* * Routine to reset the chip and clean up. * It is assumed that the caller is in splimp() */static voidsafe_totalreset(struct safe_softc *sc){ DPRINTF("%s()\n", __FUNCTION__); safe_reset_board(sc); safe_init_board(sc); safe_cleanchip(sc);}/* * Is the operand suitable aligned for direct DMA. Each * segment must be aligned on a 32-bit boundary and all * but the last segment must be a multiple of 4 bytes. */static intsafe_dmamap_aligned(const struct safe_operand *op){ int i; DPRINTF("%s()\n", __FUNCTION__); for (i = 0; i < op->nsegs; i++) { if (op->segs[i].ds_addr & 3) return (0); if (i != (op->nsegs - 1) && (op->segs[i].ds_len & 3)) return (0); } return (1);}/* * Is the operand suitable for direct DMA as the destination * of an operation. The hardware requires that each ``particle''
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -