diff options
author | Jason Wright <jason@cvs.openbsd.org> | 2002-07-16 03:59:18 +0000 |
---|---|---|
committer | Jason Wright <jason@cvs.openbsd.org> | 2002-07-16 03:59:18 +0000 |
commit | b6e36b04252a1652108aa2ee9a921b3a590ffa19 (patch) | |
tree | 5c348b26d2f0da558e80c7717dd1b62fef2cb421 /sys/dev | |
parent | 3e2511eb08acc841b6e77430b94ecdbecbf9bbca (diff) |
- Add a kthread for handling EA requests so that we have a context where we
can call bus_dmamem_{map/unmap} safely, this is because this chip has
(you'll love this...) NO support for scatter-gather
- implement enough of the crypto(9) api to support the simple/stateless
operations: SHA1 and MD5 simple hash
- remove debugging EA queue handling
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/noct.c | 345 | ||||
-rw-r--r-- | sys/dev/pci/noctvar.h | 26 |
2 files changed, 343 insertions, 28 deletions
diff --git a/sys/dev/pci/noct.c b/sys/dev/pci/noct.c index 0e7871afdfc..5791520fa0e 100644 --- a/sys/dev/pci/noct.c +++ b/sys/dev/pci/noct.c @@ -1,4 +1,4 @@ -/* $OpenBSD: noct.c,v 1.6 2002/06/28 18:34:13 jason Exp $ */ +/* $OpenBSD: noct.c,v 1.7 2002/07/16 03:59:17 jason Exp $ */ /* * Copyright (c) 2002 Jason L. Wright (jason@thought.net) @@ -49,6 +49,7 @@ #include <sys/mbuf.h> #include <sys/device.h> #include <sys/extent.h> +#include <sys/kthread.h> #include <uvm/uvm_extern.h> @@ -89,7 +90,12 @@ void noct_ea_enable(struct noct_softc *); void noct_ea_disable(struct noct_softc *); void noct_ea_init(struct noct_softc *); void noct_ea_intr(struct noct_softc *); -void noct_ea_tick(void *); +void noct_ea_create_thread(void *); +void noct_ea_thread(void *); +u_int32_t noct_ea_nfree(struct noct_softc *); +int noct_newsession(u_int32_t *, struct cryptoini *); +int noct_freesession(u_int64_t); +int noct_process(struct cryptop *); u_int64_t noct_read_8(struct noct_softc *, u_int32_t); void noct_write_8(struct noct_softc *, u_int32_t, u_int64_t); @@ -718,6 +724,17 @@ noct_rng_tick(vsc) timeout_add(&sc->sc_rngto, sc->sc_rngtick); } +u_int32_t +noct_ea_nfree(sc) + struct noct_softc *sc; +{ + if (sc->sc_eawp == sc->sc_earp) + return (NOCT_EA_ENTRIES); + if (sc->sc_eawp < sc->sc_earp) + return (sc->sc_earp - sc->sc_eawp - 1); + return (sc->sc_earp + NOCT_EA_ENTRIES - sc->sc_eawp - 1); +} + void noct_ea_disable(sc) struct noct_softc *sc; @@ -762,6 +779,7 @@ noct_ea_enable(sc) u_int64_t adr; sc->sc_eawp = 0; + sc->sc_earp = 0; adr = sc->sc_eamap->dm_segs[0].ds_addr; NOCT_WRITE_4(sc, NOCT_EA_Q_BASE_HI, (adr >> 32) & 0xffffffff); @@ -812,12 +830,15 @@ noct_ea_init(sc) noct_ea_disable(sc); noct_ea_enable(sc); - if (hz > 100) - sc->sc_eatick = hz/100; - else - sc->sc_eatick = 1; - timeout_set(&sc->sc_eato, noct_ea_tick, sc); - timeout_add(&sc->sc_eato, sc->sc_eatick); + SIMPLEQ_INIT(&sc->sc_inq); + SIMPLEQ_INIT(&sc->sc_chipq); + SIMPLEQ_INIT(&sc->sc_outq); + + crypto_register(sc->sc_cid, CRYPTO_MD5, 0, 0, + noct_newsession, noct_freesession, noct_process); + crypto_register(sc->sc_cid, CRYPTO_SHA1, 0, 0, NULL, NULL, NULL); + + kthread_create_deferred(noct_ea_create_thread, sc); return; @@ -834,31 +855,218 @@ fail: } void -noct_ea_tick(vsc) +noct_ea_create_thread(vsc) void *vsc; { struct noct_softc *sc = vsc; - struct noct_ea_cmd *nop; - int s, i; - s = splnet(); - nop = &sc->sc_eacmd[sc->sc_eawp]; - for (i = 0; i < EA_CMD_WORDS; i++) - nop->buf[i] = 0; - nop->buf[0] = htole32(EA_0_SI); - nop->buf[1] = htole32(EA_OP_NOP); - if (++sc->sc_eawp == NOCT_EA_ENTRIES) - sc->sc_eawp = 0; - NOCT_WRITE_4(sc, NOCT_EA_Q_PTR, sc->sc_eawp); - splx(s); - timeout_add(&sc->sc_eato, sc->sc_eatick); + if (kthread_create(noct_ea_thread, sc, NULL, + "%s", sc->sc_dv.dv_xname)) + panic("%s: unable to create ea thread", sc->sc_dv.dv_xname); +} + +void +noct_ea_thread(vsc) + void *vsc; +{ + struct noct_softc *sc = vsc; + struct noct_workq *q; + struct cryptop *crp; + struct cryptodesc *crd; + u_int64_t adr; + int s, err, rseg, i; + u_int32_t wp, len; + + for (;;) { + tsleep(&sc->sc_eawp, PWAIT, "noctea", 0); + + /* Handle output queue */ + s = splnet(); + while (!SIMPLEQ_EMPTY(&sc->sc_outq)) { + q = SIMPLEQ_FIRST(&sc->sc_outq); + SIMPLEQ_REMOVE_HEAD(&sc->sc_outq, q, q_next); + crp = q->q_crp; + crd = crp->crp_desc; + + if (crd->crd_alg == CRYPTO_MD5) + len = 16; + else if (crd->crd_alg == CRYPTO_SHA1) + len = 20; + else + len = 0; + + if (len != 0) { + if (crp->crp_flags & CRYPTO_F_IMBUF) + m_copyback((struct mbuf *)crp->crp_buf, + crd->crd_inject, len, + q->q_macbuf); + else if (crp->crp_flags & CRYPTO_F_IOV) + bcopy(q->q_macbuf, crp->crp_mac, len); + } + + splx(s); + + bus_dmamap_unload(sc->sc_dmat, q->q_dmamap); + bus_dmamap_destroy(sc->sc_dmat, q->q_dmamap); + bus_dmamem_unmap(sc->sc_dmat, q->q_buf, crd->crd_len); + bus_dmamem_free(sc->sc_dmat, &q->q_dmaseg, rseg); + crp->crp_etype = 0; + free(q, M_DEVBUF); + crypto_done(crp); + s = splnet(); + } + + /* Handle input queue */ + s = splnet(); + while (!SIMPLEQ_EMPTY(&sc->sc_inq)) { + q = SIMPLEQ_FIRST(&sc->sc_inq); + SIMPLEQ_REMOVE_HEAD(&sc->sc_inq, q, q_next); + splx(s); + + crp = q->q_crp; + crd = crp->crp_desc; + if (crd->crd_next != NULL) { + crp->crp_etype = EOPNOTSUPP; + crypto_done(crp); + free(q, M_DEVBUF); + goto next; + } + + if (crd->crd_alg != CRYPTO_MD5 && + crd->crd_alg != CRYPTO_SHA1) { + crp->crp_etype = EOPNOTSUPP; + crypto_done(crp); + free(q, M_DEVBUF); + goto next; + } + + if (crd->crd_len > 0x4800) { + crp->crp_etype = EOPNOTSUPP; + crypto_done(crp); + free(q, M_DEVBUF); + goto next; + } + + if ((err = bus_dmamem_alloc(sc->sc_dmat, crd->crd_len, + PAGE_SIZE, 0, &q->q_dmaseg, 1, &rseg, + BUS_DMA_WAITOK | BUS_DMA_STREAMING)) != 0) { + crp->crp_etype = err; + crypto_done(crp); + free(q, M_DEVBUF); + goto next; + } + + if ((err = bus_dmamem_map(sc->sc_dmat, &q->q_dmaseg, + rseg, crd->crd_len, (caddr_t *)&q->q_buf, + BUS_DMA_WAITOK)) != 0) { + crp->crp_etype = err; + bus_dmamem_free(sc->sc_dmat, + &q->q_dmaseg, rseg); + crypto_done(crp); + free(q, M_DEVBUF); + goto next; + } + + if ((err = bus_dmamap_create(sc->sc_dmat, crd->crd_len, + 1, crd->crd_len, 0, BUS_DMA_WAITOK, + &q->q_dmamap)) != 0) { + bus_dmamem_unmap(sc->sc_dmat, + q->q_buf, crd->crd_len); + bus_dmamem_free(sc->sc_dmat, + &q->q_dmaseg, rseg); + crp->crp_etype = err; + crypto_done(crp); + free(q, M_DEVBUF); + goto next; + } + + if ((err = bus_dmamap_load_raw(sc->sc_dmat, + q->q_dmamap, &q->q_dmaseg, rseg, crd->crd_len, + BUS_DMA_WAITOK)) != 0) { + bus_dmamap_destroy(sc->sc_dmat, q->q_dmamap); + bus_dmamem_unmap(sc->sc_dmat, + q->q_buf, crd->crd_len); + bus_dmamem_free(sc->sc_dmat, + &q->q_dmaseg, rseg); + crp->crp_etype = err; + crypto_done(crp); + free(q, M_DEVBUF); + goto next; + } + + if (crp->crp_flags & CRYPTO_F_IMBUF) + m_copydata((struct mbuf *)crp->crp_buf, + crd->crd_skip, crd->crd_len, q->q_buf); + else if (crp->crp_flags & CRYPTO_F_IOV) + cuio_copydata((struct uio *)crp->crp_buf, + crd->crd_skip, crd->crd_len, q->q_buf); + else { + /* XXX deal with this error. */ + } + + s = splnet(); + if (noct_ea_nfree(sc) < 1) { + bus_dmamap_unload(sc->sc_dmat, q->q_dmamap); + bus_dmamap_destroy(sc->sc_dmat, q->q_dmamap); + bus_dmamem_unmap(sc->sc_dmat, + q->q_buf, crd->crd_len); + bus_dmamem_free(sc->sc_dmat, + &q->q_dmaseg, rseg); + crp->crp_etype = ENOMEM; + crypto_done(crp); + splx(s); + free(q, M_DEVBUF); + goto next; + } + wp = sc->sc_eawp; + if (++sc->sc_eawp == NOCT_EA_ENTRIES) + sc->sc_eawp = 0; + for (i = 0; i < EA_CMD_WORDS; i++) + sc->sc_eacmd[wp].buf[i] = 0; + sc->sc_eacmd[wp].buf[0] = EA_0_SI; + switch (crd->crd_alg) { + case CRYPTO_MD5: + sc->sc_eacmd[wp].buf[1] = htole32(EA_OP_MD5); + break; + case CRYPTO_SHA1: + sc->sc_eacmd[wp].buf[1] = htole32(EA_OP_SHA1); + break; + } + + /* Source, new buffer just allocated */ + sc->sc_eacmd[wp].buf[1] |= htole32(crd->crd_len); + adr = q->q_dmamap->dm_segs[0].ds_addr; + sc->sc_eacmd[wp].buf[2] = htole32(adr >> 32); + sc->sc_eacmd[wp].buf[3] = htole32(adr & 0xffffffff); + + /* Dest, hide it in the descriptor */ + adr = sc->sc_eamap->dm_segs[0].ds_addr + + (wp * sizeof(struct noct_ea_cmd)) + + offsetof(struct noct_ea_cmd, buf[6]); + sc->sc_eacmd[wp].buf[4] = htole32(adr >> 32); + sc->sc_eacmd[wp].buf[5] = htole32(adr & 0xffffffff); + + if (++wp == NOCT_EA_ENTRIES) + wp = 0; + NOCT_WRITE_4(sc, NOCT_EA_Q_PTR, wp); + sc->sc_eawp = wp; + + SIMPLEQ_INSERT_TAIL(&sc->sc_chipq, q, q_next); + splx(s); + +next: + s = splnet(); + } + splx(s); + } } void noct_ea_intr(sc) struct noct_softc *sc; { - u_int32_t csr; + struct noct_workq *q; + u_int32_t csr, rp; csr = NOCT_READ_4(sc, NOCT_EA_CSR); NOCT_WRITE_4(sc, NOCT_EA_CSR, csr | @@ -867,9 +1075,21 @@ noct_ea_intr(sc) EACSR_INTRNLLEN | EACSR_EXTRNLLEN | EACSR_DESBLOCK | EACSR_DESKEY | EACSR_ILL); - if (csr & EACSR_CMDCMPL) { - /* command completed... */ + rp = (NOCT_READ_4(sc, NOCT_EA_Q_PTR) & EAQPTR_READ_M) >> + EAQPTR_READ_S; + while (sc->sc_earp != rp) { + if (SIMPLEQ_EMPTY(&sc->sc_chipq)) + panic("%s: empty chipq", sc->sc_dv.dv_xname); + q = SIMPLEQ_FIRST(&sc->sc_chipq); + SIMPLEQ_REMOVE_HEAD(&sc->sc_chipq, q, q_next); + SIMPLEQ_INSERT_TAIL(&sc->sc_outq, q, q_next); + bcopy((u_int8_t *)&sc->sc_eacmd[sc->sc_earp].buf[6], + q->q_macbuf, 20); + NOCT_WAKEUP(sc); + if (++sc->sc_earp == NOCT_EA_ENTRIES) + sc->sc_earp = 0; } + sc->sc_earp = rp; if (csr & EACSR_QALIGN) printf("%s: ea bad queue alignment\n", sc->sc_dv.dv_xname); @@ -1204,3 +1424,78 @@ out: krp->krp_status = err; crypto_kdone(krp); } + +int +noct_newsession(sidp, cri) + u_int32_t *sidp; + struct cryptoini *cri; +{ + struct noct_softc *sc; + int i; + + for (i = 0; i < noct_cd.cd_ndevs; i++) { + sc = noct_cd.cd_devs[i]; + if (sc == NULL || sc->sc_cid == (*sidp)) + break; + } + if (sc == NULL) + return (EINVAL); + + /* Can only handle single operations */ + if (cri->cri_next != NULL) + return (EINVAL); + + *sidp = NOCT_SID(sc->sc_dv.dv_unit, 0); + return (0); +} + +int +noct_freesession(tid) + u_int64_t tid; +{ + int card; + u_int32_t sid = ((u_int32_t)tid) & 0xffffffff; + + card = NOCT_CARD(sid); + if (card >= noct_cd.cd_ndevs || noct_cd.cd_devs[card] == NULL) + return (EINVAL); + return (0); +} + +int +noct_process(crp) + struct cryptop *crp; +{ + struct noct_softc *sc; + struct noct_workq *q = NULL; + int card, err, s; + + if (crp == NULL || crp->crp_callback == NULL) + return (EINVAL); + + card = NOCT_CARD(crp->crp_sid); + if (card >= noct_cd.cd_ndevs || noct_cd.cd_devs[card] == NULL) + return (EINVAL); + sc = noct_cd.cd_devs[card]; + + q = (struct noct_workq *)malloc(sizeof(struct noct_workq), + M_DEVBUF, M_NOWAIT); + if (q == NULL) { + err = ENOMEM; + goto errout; + } + q->q_crp = crp; + + s = splnet(); + SIMPLEQ_INSERT_TAIL(&sc->sc_inq, q, q_next); + splx(s); + NOCT_WAKEUP(sc); + return (0); + +errout: + if (q != NULL) + free(q, M_DEVBUF); + crp->crp_etype = err; + crypto_done(crp); + return (0); +} diff --git a/sys/dev/pci/noctvar.h b/sys/dev/pci/noctvar.h index e8cad8a9b4d..80832f6d670 100644 --- a/sys/dev/pci/noctvar.h +++ b/sys/dev/pci/noctvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: noctvar.h,v 1.4 2002/06/28 18:31:29 jason Exp $ */ +/* $OpenBSD: noctvar.h,v 1.5 2002/07/16 03:59:17 jason Exp $ */ /* * Copyright (c) 2002 Jason L. Wright (jason@thought.net) @@ -50,6 +50,15 @@ #define NOCT_BN_CACHE_SIZE ((256) * (128 / 8)) +struct noct_workq { + SIMPLEQ_ENTRY(noct_workq) q_next; + struct cryptop *q_crp; + bus_dmamap_t q_dmamap; + bus_dma_segment_t q_dmaseg; + caddr_t q_buf; + u_int8_t q_macbuf[20]; +}; + struct noct_softc; struct noct_bnc_sw { @@ -83,10 +92,13 @@ struct noct_softc { struct noct_bnc_sw sc_pkh_bnsw[NOCT_PKH_ENTRIES]; bus_dmamap_t sc_eamap; /* ea buffer map */ - struct timeout sc_eato; /* debug */ - int sc_eatick; /* debug */ u_int32_t sc_eawp; /* ea write pointer */ + u_int32_t sc_earp; /* ea read pointer */ struct noct_ea_cmd *sc_eacmd; /* ea command buffers */ + + SIMPLEQ_HEAD(,noct_workq) sc_inq; + SIMPLEQ_HEAD(,noct_workq) sc_chipq; + SIMPLEQ_HEAD(,noct_workq) sc_outq; }; #define NOCT_READ_4(sc,r) \ @@ -96,3 +108,11 @@ struct noct_softc { #define NOCT_READ_8(sc,r) noct_read_8(sc, r) #define NOCT_WRITE_8(sc,r,v) noct_write_8(sc, r, v) + +#define NOCT_CARD(sid) (((sid) & 0xf0000000) >> 28) +#define NOCT_SESSION(sid) ( (sid) & 0x0fffffff) +#define NOCT_SID(crd, sesn) (((crd) << 28) | ((sesn) & 0x0fffffff)) + +#define NOCT_WAKEUP(sc) wakeup(&(sc)->sc_eawp) +#define NOCT_SLEEP(sc) tsleep(&(sc)->sc_eawp, PWAIT, "noctea", 0) + |