summaryrefslogtreecommitdiff
path: root/sys/dev/pci
diff options
context:
space:
mode:
authorJason Wright <jason@cvs.openbsd.org>2002-05-09 19:13:10 +0000
committerJason Wright <jason@cvs.openbsd.org>2002-05-09 19:13:10 +0000
commit6549b122e58382c8b7d14256ac2703be3fa9097f (patch)
treeffd3ef2ca77a18e101c77c95d2444f484fbaddc4 /sys/dev/pci
parenta58ac6b9916fc64d49516fc50e9133c04064cbc2 (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.c162
-rw-r--r--sys/dev/pci/lofnreg.h4
-rw-r--r--sys/dev/pci/lofnvar.h15
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) \