diff options
author | Jason Wright <jason@cvs.openbsd.org> | 2002-05-09 19:13:10 +0000 |
---|---|---|
committer | Jason Wright <jason@cvs.openbsd.org> | 2002-05-09 19:13:10 +0000 |
commit | 6549b122e58382c8b7d14256ac2703be3fa9097f (patch) | |
tree | ffd3ef2ca77a18e101c77c95d2444f484fbaddc4 /sys/dev/pci | |
parent | a58ac6b9916fc64d49516fc50e9133c04064cbc2 (diff) |
Rework to process requests from a queue/interrupt handler instead of busy
waiting.
Diffstat (limited to 'sys/dev/pci')
-rw-r--r-- | sys/dev/pci/lofn.c | 162 | ||||
-rw-r--r-- | sys/dev/pci/lofnreg.h | 4 | ||||
-rw-r--r-- | sys/dev/pci/lofnvar.h | 15 |
3 files changed, 133 insertions, 48 deletions
diff --git a/sys/dev/pci/lofn.c b/sys/dev/pci/lofn.c index b8acae80c58..923460b520d 100644 --- a/sys/dev/pci/lofn.c +++ b/sys/dev/pci/lofn.c @@ -1,7 +1,7 @@ -/* $OpenBSD: lofn.c,v 1.14 2002/05/08 19:09:25 jason Exp $ */ +/* $OpenBSD: lofn.c,v 1.15 2002/05/09 19:13:09 jason Exp $ */ /* - * Copyright (c) 2001 Jason L. Wright (jason@thought.net) + * Copyright (c) 2001-2002 Jason L. Wright (jason@thought.net) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -83,7 +83,10 @@ void lofn_read_reg(struct lofn_softc *, int, union lofn_reg *); void lofn_write_reg(struct lofn_softc *, int, union lofn_reg *); int lofn_kprocess(struct cryptkop *); struct lofn_softc *lofn_kfind(struct cryptkop *); -int lofn_kprocess_modexp(struct lofn_softc *, struct cryptkop *); +int lofn_modexp_start(struct lofn_softc *, struct lofn_q *); +void lofn_modexp_finish(struct lofn_softc *, struct lofn_q *); + +void lofn_feed(struct lofn_softc *); int lofn_probe(parent, match, aux) @@ -148,15 +151,17 @@ lofn_attach(parent, self, aux) WRITE_REG_0(sc, LOFN_REL_RNC, LOFN_RNG_SCALAR); /* Enable RNG */ - WRITE_REG_0(sc, LOFN_REL_IER, - READ_REG_0(sc, LOFN_REL_IER) | LOFN_IER_RDY); WRITE_REG_0(sc, LOFN_REL_CFG2, READ_REG_0(sc, LOFN_REL_CFG2) | LOFN_CFG2_RNGENA); + sc->sc_ier |= LOFN_REL_IER; + WRITE_REG(sc, LOFN_REL_IER, sc->sc_ier); /* Enable ALU */ WRITE_REG_0(sc, LOFN_REL_CFG2, READ_REG_0(sc, LOFN_REL_CFG2) | LOFN_CFG2_PRCENA); + SIMPLEQ_INIT(&sc->sc_queue); + sc->sc_cid = crypto_get_driverid(0); if (sc->sc_cid < 0) { printf(": failed to register cid\n"); @@ -165,7 +170,7 @@ lofn_attach(parent, self, aux) crypto_kregister(sc->sc_cid, CRK_MOD_EXP, 0, lofn_kprocess); - printf(": %s\n", intrstr, sc->sc_sh); + printf(": %s\n", intrstr); return; @@ -178,25 +183,41 @@ lofn_intr(vsc) void *vsc; { struct lofn_softc *sc = vsc; + struct lofn_q *q; u_int32_t sr; int r = 0, i; sr = READ_REG_0(sc, LOFN_REL_SR); - if (sr & LOFN_SR_RNG_UF) { - r = 1; - printf("%s: rng underflow (disabling)\n", sc->sc_dv.dv_xname); - WRITE_REG_0(sc, LOFN_REL_CFG2, - READ_REG_0(sc, LOFN_REL_CFG2) & (~LOFN_CFG2_RNGENA)); - WRITE_REG_0(sc, LOFN_REL_IER, - READ_REG_0(sc, LOFN_REL_IER) & (~LOFN_IER_RDY)); - } else if (sr & LOFN_SR_RNG_RDY) { - r = 1; + if (sc->sc_ier & LOFN_IER_RDY) { + if (sr & LOFN_SR_RNG_UF) { + r = 1; + printf("%s: rng underflow (disabling)\n", + sc->sc_dv.dv_xname); + WRITE_REG_0(sc, LOFN_REL_CFG2, + READ_REG_0(sc, LOFN_REL_CFG2) & + (~LOFN_CFG2_RNGENA)); + sc->sc_ier &= ~LOFN_IER_RDY; + WRITE_REG_0(sc, LOFN_REL_IER, sc->sc_ier); + } else if (sr & LOFN_SR_RNG_RDY) { + r = 1; + + bus_space_read_region_4(sc->sc_st, sc->sc_sh, + LOFN_REL_RNG, sc->sc_rngbuf, LOFN_RNGBUF_SIZE); + for (i = 0; i < LOFN_RNGBUF_SIZE; i++) + add_true_randomness(sc->sc_rngbuf[i]); + } + } - bus_space_read_region_4(sc->sc_st, sc->sc_sh, LOFN_REL_RNG, - sc->sc_rngbuf, LOFN_RNGBUF_SIZE); - for (i = 0; i < LOFN_RNGBUF_SIZE; i++) - add_true_randomness(sc->sc_rngbuf[i]); + if (sc->sc_ier & LOFN_IER_DONE) { + r = 1; + if (sr & LOFN_SR_DONE && sc->sc_current != NULL) { + q = sc->sc_current; + sc->sc_current = NULL; + q->q_finish(sc, q); + free(q, M_DEVBUF); + lofn_feed(sc); + } } return (r); @@ -268,32 +289,50 @@ lofn_kprocess(krp) struct cryptkop *krp; { struct lofn_softc *sc; + struct lofn_q *q; + int s; if (krp == NULL || krp->krp_callback == NULL) return (EINVAL); - if ((sc = lofn_kfind(krp)) == NULL) - return (EINVAL); + if ((sc = lofn_kfind(krp)) == NULL) { + krp->krp_status = EINVAL; + crypto_kdone(krp); + return (0); + } + + q = (struct lofn_q *)malloc(sizeof(*q), M_DEVBUF, M_NOWAIT); + if (q == NULL) { + krp->krp_status = ENOMEM; + crypto_kdone(krp); + return (0); + } switch (krp->krp_op) { case CRK_MOD_EXP: - return (lofn_kprocess_modexp(sc, krp)); + q->q_start = lofn_modexp_start; + q->q_finish = lofn_modexp_finish; + q->q_krp = krp; + s = splnet(); + SIMPLEQ_INSERT_TAIL(&sc->sc_queue, q, q_next); + lofn_feed(sc); + splx(s); + return (0); default: printf("%s: kprocess: invalid op 0x%x\n", sc->sc_dv.dv_xname, krp->krp_op); krp->krp_status = EOPNOTSUPP; crypto_kdone(krp); + free(q, M_DEVBUF); return (0); } } -/* - * Start computation of cr[C] = (cr[M] ^ cr[E]) mod cr[N] - */ int -lofn_kprocess_modexp(sc, krp) +lofn_modexp_start(sc, q) struct lofn_softc *sc; - struct cryptkop *krp; + struct lofn_q *q; { + struct cryptkop *krp = q->q_krp; int ip = 0, bits, err = 0; int mshift, eshift, nshift; @@ -302,12 +341,6 @@ lofn_kprocess_modexp(sc, krp) goto errout; } - /* Poll until done... */ - while (1) { - if (READ_REG(sc, LOFN_REL_SR) & LOFN_SR_DONE) - break; - } - /* Zero out registers. */ lofn_zero_reg(sc, 0); lofn_zero_reg(sc, 1); @@ -408,17 +441,9 @@ lofn_kprocess_modexp(sc, krp) ip += 4; } + /* Start microprogram */ WRITE_REG(sc, LOFN_REL_CR, 0); - while (1) { - if (READ_REG(sc, LOFN_REL_SR) & LOFN_SR_DONE) - break; - } - - lofn_read_reg(sc, 3, &sc->sc_tmp); - bcopy(sc->sc_tmp.b, krp->krp_param[LOFN_MODEXP_PAR_C].crp_p, - (krp->krp_param[LOFN_MODEXP_PAR_C].crp_nbits + 7) / 8); - crypto_kdone(krp); return (0); errout: @@ -429,7 +454,25 @@ errout: lofn_zero_reg(sc, 3); krp->krp_status = err; crypto_kdone(krp); - return (0); + return (1); +} + +void +lofn_modexp_finish(sc, q) + struct lofn_softc *sc; + struct lofn_q *q; +{ + struct cryptkop *krp = q->q_krp; + + lofn_read_reg(sc, 3, &sc->sc_tmp); + bcopy(sc->sc_tmp.b, krp->krp_param[LOFN_MODEXP_PAR_C].crp_p, + (krp->krp_param[LOFN_MODEXP_PAR_C].crp_nbits + 7) / 8); + bzero(&sc->sc_tmp, sizeof(sc->sc_tmp)); + lofn_zero_reg(sc, 0); + lofn_zero_reg(sc, 1); + lofn_zero_reg(sc, 2); + lofn_zero_reg(sc, 3); + crypto_kdone(krp); } /* @@ -455,3 +498,36 @@ lofn_norm_sigbits(const u_int8_t *p, u_int pbits) } return (sig); } + +void +lofn_feed(sc) + struct lofn_softc *sc; +{ + struct lofn_q *q; + + /* Queue is empty and nothing being processed, turn off interrupt */ + if (SIMPLEQ_EMPTY(&sc->sc_queue) && + sc->sc_current == NULL) { + sc->sc_ier &= ~LOFN_IER_DONE; + WRITE_REG(sc, LOFN_REL_IER, sc->sc_ier); + return; + } + + /* Operation already pending, wait. */ + if (sc->sc_current != NULL) + return; + + while (!SIMPLEQ_EMPTY(&sc->sc_queue)) { + q = SIMPLEQ_FIRST(&sc->sc_queue); + if (q->q_start(sc, q) == 0) { + sc->sc_current = q; + SIMPLEQ_REMOVE_HEAD(&sc->sc_queue, q, q_next); + sc->sc_ier |= LOFN_IER_DONE; + WRITE_REG(sc, LOFN_REL_IER, sc->sc_ier); + break; + } else { + SIMPLEQ_REMOVE_HEAD(&sc->sc_queue, q, q_next); + free(q, M_DEVBUF); + } + } +} diff --git a/sys/dev/pci/lofnreg.h b/sys/dev/pci/lofnreg.h index 07035be92ad..eb0daa39314 100644 --- a/sys/dev/pci/lofnreg.h +++ b/sys/dev/pci/lofnreg.h @@ -1,7 +1,7 @@ -/* $OpenBSD: lofnreg.h,v 1.13 2002/05/08 19:09:25 jason Exp $ */ +/* $OpenBSD: lofnreg.h,v 1.14 2002/05/09 19:13:09 jason Exp $ */ /* - * Copyright (c) 2001 Jason L. Wright (jason@thought.net) + * Copyright (c) 2001-2002 Jason L. Wright (jason@thought.net) * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/sys/dev/pci/lofnvar.h b/sys/dev/pci/lofnvar.h index 7fcd024dea3..25d0df00ed7 100644 --- a/sys/dev/pci/lofnvar.h +++ b/sys/dev/pci/lofnvar.h @@ -1,7 +1,7 @@ -/* $OpenBSD: lofnvar.h,v 1.6 2002/05/08 19:09:25 jason Exp $ */ +/* $OpenBSD: lofnvar.h,v 1.7 2002/05/09 19:13:09 jason Exp $ */ /* - * Copyright (c) 2001 Jason L. Wright (jason@thought.net) + * Copyright (c) 2001-2002 Jason L. Wright (jason@thought.net) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -44,10 +44,19 @@ struct lofn_softc { bus_space_handle_t sc_sh; bus_space_tag_t sc_st; bus_dma_tag_t sc_dmat; - u_int32_t sc_rngbuf[LOFN_RNGBUF_SIZE]; + u_int32_t sc_rngbuf[LOFN_RNGBUF_SIZE], sc_ier; int32_t sc_cid; union lofn_reg sc_tmp; union lofn_reg sc_zero; + SIMPLEQ_HEAD(,lofn_q) sc_queue; + struct lofn_q *sc_current; +}; + +struct lofn_q { + SIMPLEQ_ENTRY(lofn_q) q_next; + int (*q_start)(struct lofn_softc *, struct lofn_q *); + void (*q_finish)(struct lofn_softc *, struct lofn_q *); + struct cryptkop *q_krp; }; #define READ_REG(sc,r) \ |