diff options
-rw-r--r-- | sys/dev/pci/aeon.c | 344 | ||||
-rw-r--r-- | sys/dev/pci/aeonreg.h | 7 | ||||
-rw-r--r-- | sys/dev/pci/aeonvar.h | 44 | ||||
-rw-r--r-- | sys/dev/pci/hifn7751.c | 344 | ||||
-rw-r--r-- | sys/dev/pci/hifn7751reg.h | 7 | ||||
-rw-r--r-- | sys/dev/pci/hifn7751var.h | 44 |
6 files changed, 416 insertions, 374 deletions
diff --git a/sys/dev/pci/aeon.c b/sys/dev/pci/aeon.c index 92de95e014c..93319eedb17 100644 --- a/sys/dev/pci/aeon.c +++ b/sys/dev/pci/aeon.c @@ -1,4 +1,4 @@ -/* $OpenBSD: aeon.c,v 1.2 1999/02/21 00:05:14 deraadt Exp $ */ +/* $OpenBSD: aeon.c,v 1.3 1999/02/24 06:09:45 deraadt Exp $ */ /* * Invertex AEON driver @@ -75,12 +75,12 @@ void aeon_init_dma __P((struct aeon_softc *)); void aeon_init_pci_registers __P((struct aeon_softc *)); int aeon_checkram __P((struct aeon_softc *)); int aeon_intr __P((void *)); -u_int32_t aeon_write_command __P((const struct aeon_command_buf_data *, - u_int8_t *)); -int aeon_build_command __P((const struct aeon_command * cmd, - struct aeon_command_buf_data *)); -void aeon_intr_process_ring __P((struct aeon_softc *, struct aeon_dma *)); - +u_int aeon_write_command __P((const struct aeon_command_buf_data *, + u_int8_t *)); +int aeon_build_command __P((const struct aeon_command * cmd, + struct aeon_command_buf_data *)); +int aeon_mbuf __P((struct mbuf *, int *np, long *pp, int *lp, int maxp, + int *nicealign)); /* * Used for round robin crypto requests @@ -406,21 +406,22 @@ aeon_init_dma(sc) int i; /* initialize static pointer values */ - for (i = 0; i < AEON_D_RSIZE; i++) { + for (i = 0; i < AEON_D_CMD_RSIZE; i++) dma->cmdr[i].p = vtophys(dma->command_bufs[i]); + for (i = 0; i < AEON_D_RES_RSIZE; i++) dma->resr[i].p = vtophys(dma->result_bufs[i]); - } - dma->cmdr[AEON_D_RSIZE].p = vtophys(dma->cmdr); - dma->srcr[AEON_D_RSIZE].p = vtophys(dma->srcr); - dma->dstr[AEON_D_RSIZE].p = vtophys(dma->dstr); - dma->resr[AEON_D_RSIZE].p = vtophys(dma->resr); + + dma->cmdr[AEON_D_CMD_RSIZE].p = vtophys(dma->cmdr); + dma->srcr[AEON_D_SRC_RSIZE].p = vtophys(dma->srcr); + dma->dstr[AEON_D_DST_RSIZE].p = vtophys(dma->dstr); + dma->resr[AEON_D_RES_RSIZE].p = vtophys(dma->resr); } /* * Writes out the raw command buffer space. Returns the * command buffer size. */ -u_int32_t +u_int aeon_write_command(const struct aeon_command_buf_data *cmd_data, u_int8_t *command_buf) { @@ -538,14 +539,14 @@ aeon_build_command(const struct aeon_command *cmd, * checks!!!! */ - if (cmd->source_length <= mac_length) { + if (cmd->src_npa <= mac_length) { printf("aeon: command source buffer has no data\n"); return -1; } dest_diff = (flags & AEON_ENCODE) ? mac_length : -mac_length; - if (cmd->dest_length < cmd->source_length + dest_diff) { + if (cmd->dst_npa < cmd->dst_npa + dest_diff) { printf("aeon: command dest length %u too short -- needed %u\n", - cmd->dest_length, cmd->source_length + dest_diff); + cmd->dst_npa, cmd->dst_npa + dest_diff); return -1; } #endif @@ -570,8 +571,8 @@ aeon_build_command(const struct aeon_command *cmd, * Set total source and dest counts. These values are the same as the * values set in the length field of the source and dest descriptor rings. */ - base_cmd->total_source_count = cmd->source_length; - base_cmd->total_dest_count = cmd->dest_length; + base_cmd->total_source_count = cmd->src_l; + base_cmd->total_dest_count = cmd->dst_l; /* * XXX -- We need session number range checking... @@ -612,7 +613,7 @@ aeon_build_command(const struct aeon_command *cmd, * Set the mac header skip and source count. */ mac_cmd->header_skip = cmd->mac_header_skip; - mac_cmd->source_count = cmd->source_length - cmd->mac_header_skip; + mac_cmd->source_count = cmd->src_npa - cmd->mac_header_skip; if (flags & AEON_DECODE) mac_cmd->source_count -= mac_length; } @@ -639,7 +640,7 @@ aeon_build_command(const struct aeon_command *cmd, * Set the encrypt header skip and source count. */ crypt_cmd->header_skip = cmd->crypt_header_skip; - crypt_cmd->source_count = cmd->source_length - cmd->crypt_header_skip; + crypt_cmd->source_count = cmd->src_npa - cmd->crypt_header_skip; if (flags & AEON_DECODE) crypt_cmd->source_count -= mac_length; @@ -671,51 +672,21 @@ aeon_build_command(const struct aeon_command *cmd, return 0; /* success */ } -int -aeon_crypto(struct aeon_command *cmd) +int +aeon_mbuf(m, np, pp, lp, maxp, nicep) + struct mbuf *m; + int *np; + long *pp; + int *lp; + int maxp; + int *nicep; { - u_int32_t cmdlen; - static u_int32_t current_device = 0; - struct aeon_softc *sc; - struct aeon_dma *dma; - struct aeon_command_buf_data cmd_buf_data; - int cmdi, srci, dsti, resi; - int error, s; -#define MAX_SCATTER 10 - long packp[MAX_SCATTER]; - int packl[MAX_SCATTER]; - struct mbuf *m0, *m = cmd->m; - int nchunks, i; - - if (aeon_build_command(cmd, &cmd_buf_data) != 0) - return AEON_CRYPTO_BAD_INPUT; - - s = splimp(); + struct mbuf *m0; + int npa = *np; + int tlen = 0; - /* Pick the aeon board to send the data to. Right now we use a round - * robin approach. */ - sc = aeon_devices[current_device++]; - if (current_device == aeon_num_devices) - current_device = 0; - dma = sc->sc_dma; - -#if 1 - printf("%s: Entering command" - " -- Status Reg 0x%08x" - " -- Interrupt Enable Reg 0x%08x" - " -- slots in use %u" - " -- source length %u" - " -- dest length %u\n", - sc->sc_dv.dv_xname, - READ_REG_1(sc, AEON_STATUS), READ_REG_1(sc, AEON_IRQEN), - dma->slots_in_use, cmd->source_length, cmd->dest_length); -#endif - - /* - * Generate a [pa,len] array from an mbuf. - * This is very broken - */ - nchunks = 0; + /* generate a [pa,len] array from an mbuf */ + npa = 0; for (m0 = m; m; m = m->m_next) { void *va; long pg, npg; @@ -723,101 +694,177 @@ aeon_crypto(struct aeon_command *cmd) va = m->m_data; len = m->m_len; + tlen += len; - packl[nchunks] = len; - packp[nchunks] = vtophys(va); - pg = packp[nchunks] & ~PAGE_MASK; + lp[npa] = len; + pp[npa] = vtophys(va); + pg = pp[npa] & ~PAGE_MASK; off = (long)va & PAGE_MASK; while (len + off > PAGE_SIZE) { va = va + PAGE_SIZE - off; npg = vtophys(va); if (npg != pg) { - nchunks++; - break; + /* FUCKED UP condition */ + npa++; + continue; } - packl[nchunks] = PAGE_SIZE - off; + lp[npa] = PAGE_SIZE - off; off = 0; - ++nchunks; - packl[nchunks] = len - (PAGE_SIZE - off); - len -= packl[nchunks]; - packp[nchunks] = vtophys(va); + ++npa; + if (npa > maxp) + return (0); + lp[npa] = len - (PAGE_SIZE - off); + len -= lp[npa]; + pp[npa] = vtophys(va); } } + if (nicep) { + int nice = 1; + int i; + + /* see if each [pa,len] entry is long-word aligned */ + for (i = 0; i < npa; i++) + if ((lp[i] & 3) || (pp[i] & 3)) + nice = 0; + *nicep = nice; + } + + *np = npa; + return (tlen); +} + +int +aeon_crypto(struct aeon_command *cmd) +{ + u_int32_t cmdlen; + static u_int32_t current_device = 0; + struct aeon_softc *sc; + struct aeon_dma *dma; + struct aeon_command_buf_data cmd_buf_data; + int cmdi, srci, dsti, resi, nicealign = 0; + int error, s, i; + + /* Pick the aeon board to send the data to. Right now we use a round + * robin approach. */ + sc = aeon_devices[current_device++]; + if (current_device == aeon_num_devices) + current_device = 0; + dma = sc->sc_dma; + + if (cmd->src_npa == 0 && cmd->src_m) + cmd->src_l = aeon_mbuf(cmd->src_m, &cmd->src_npa, + cmd->src_packp, cmd->src_packl, MAX_SCATTER, &nicealign); + if (cmd->src_l == 0) + return (-1); + + if (nicealign == 0) { + cmd->dst_l = cmd->src_l; + MGETHDR(cmd->dst_m, M_DONTWAIT, MT_DATA); + if (cmd->dst_m == NULL) + return (-1); + if (cmd->src_l > MHLEN) { + MCLGET(cmd->dst_m, M_DONTWAIT); + if ((cmd->dst_m->m_flags & M_EXT) == 0) { + m_freem(cmd->dst_m); + return (-1); + } + } + } else + cmd->dst_m = cmd->src_m; + + cmd->dst_l = aeon_mbuf(cmd->dst_m, &cmd->dst_npa, + cmd->dst_packp, cmd->dst_packl, MAX_SCATTER, NULL); + if (cmd->dst_l == 0) + return (-1); + + if (aeon_build_command(cmd, &cmd_buf_data) != 0) + return AEON_CRYPTO_BAD_INPUT; + + printf("%s: Entering cmd: stat %8x ien %8x u %d/%d/%d/%d n %d/%d\n", + sc->sc_dv.dv_xname, + READ_REG_1(sc, AEON_STATUS), READ_REG_1(sc, AEON_IRQEN), + dma->cmdu, dma->srcu, dma->dstu, dma->resu, cmd->src_npa, + cmd->dst_npa); + + s = splimp(); + /* * need 1 cmd, and 1 res * need N src, and N dst */ - while (dma->cmdu+1 == AEON_D_RSIZE || dma->srcu+nchunks == AEON_D_RSIZE || - dma->dstu+nchunks == AEON_D_RSIZE || dma->resu+1 == AEON_D_RSIZE) { - if (cmd->flags & AEON_DMA_FULL_NOBLOCK) + while (dma->cmdu+1 > AEON_D_CMD_RSIZE || + dma->srcu+cmd->src_npa > AEON_D_SRC_RSIZE || + dma->dstu+cmd->dst_npa > AEON_D_DST_RSIZE || + dma->resu+1 > AEON_D_RES_RSIZE) { + if (cmd->flags & AEON_DMA_FULL_NOBLOCK) { splx(s); return (AEON_CRYPTO_RINGS_FULL); + } tsleep((caddr_t) dma, PZERO, "aeonring", 1); } - dma->cmdu += 1; - dma->resu += 1; - if (dma->cmdi == AEON_D_RSIZE) { + if (dma->cmdi == AEON_D_CMD_RSIZE) { cmdi = 0, dma->cmdi = 1; - dma->cmdr[AEON_D_RSIZE].l = AEON_D_VALID | AEON_D_LAST | + dma->cmdr[AEON_D_CMD_RSIZE].l = AEON_D_VALID | AEON_D_LAST | AEON_D_MASKDONEIRQ | AEON_D_JUMP; } else cmdi = dma->cmdi++; - if (dma->resi == AEON_D_RSIZE) { + if (dma->resi == AEON_D_RES_RSIZE) { resi = 0, dma->resi = 1; - dma->resr[AEON_D_RSIZE].l = AEON_D_VALID | AEON_D_LAST | + dma->resr[AEON_D_RES_RSIZE].l = AEON_D_VALID | AEON_D_LAST | AEON_D_MASKDONEIRQ | AEON_D_JUMP; } else resi = dma->resi++; cmdlen = aeon_write_command(&cmd_buf_data, dma->command_bufs[cmdi]); dma->aeon_commands[cmdi] = cmd; - - /* - * .p for command/result already set - */ + /* .p for command/result already set */ dma->cmdr[cmdi].l = cmdlen | AEON_D_VALID | AEON_D_LAST | AEON_D_MASKDONEIRQ; + dma->cmdu += 1; - for (i = 0; i < nchunks; i++) { + for (i = 0; i < cmd->src_npa; i++) { int last = 0; - if (i == nchunks-1) + if (i == cmd->src_npa-1) last = AEON_D_LAST; - if (dma->srci == AEON_D_RSIZE) { + if (dma->srci == AEON_D_SRC_RSIZE) { srci = 0, dma->srci = 1; - dma->srcr[AEON_D_RSIZE].l = AEON_D_VALID | + dma->srcr[AEON_D_SRC_RSIZE].l = AEON_D_VALID | AEON_D_MASKDONEIRQ | AEON_D_JUMP; } else srci = dma->srci++; - dma->srcu++; - - dma->srcr[srci].p = vtophys(packp[i]); - dma->srcr[srci].l = packl[i] | AEON_D_VALID | + dma->srcr[srci].p = vtophys(cmd->src_packp[i]); + dma->srcr[srci].l = cmd->src_packl[i] | AEON_D_VALID | AEON_D_MASKDONEIRQ | last; + } + dma->srcu += cmd->src_npa; - if (dma->dsti == AEON_D_RSIZE) { + for (i = 0; i < cmd->dst_npa; i++) { + int last = 0; + + if (dma->dsti == AEON_D_DST_RSIZE) { dsti = 0, dma->dsti = 1; - dma->dstr[AEON_D_RSIZE].l = AEON_D_VALID | + dma->dstr[AEON_D_DST_RSIZE].l = AEON_D_VALID | AEON_D_MASKDONEIRQ | AEON_D_JUMP; } else dsti = dma->dsti++; - dma->dstu++; - - dma->dstr[dsti].p = vtophys(packp[i]); - dma->dstr[dsti].l = packl[i] | AEON_D_VALID | + dma->dstr[dsti].p = vtophys(cmd->dst_packp[i]); + dma->dstr[dsti].l = cmd->dst_packl[i] | AEON_D_VALID | AEON_D_MASKDONEIRQ | last; } + dma->dstu += cmd->dst_npa; /* * Unlike other descriptors, we don't mask done interrupt from * result descriptor. */ dma->resr[resi].l = AEON_MAX_RESULT | AEON_D_VALID | AEON_D_LAST; + dma->resu += 1; /* * We don't worry about missing an interrupt (which a waiting @@ -844,9 +891,7 @@ aeon_crypto(struct aeon_command *cmd) sc->sc_dv.dv_xname, error); } - printf("%s: command executed" - " -- Status Register 0x%08x" - " -- Interrupt Enable Reg 0x%08x\n", + printf("%s: command: stat %8x ier %8x\n", sc->sc_dv.dv_xname, READ_REG_1(sc, AEON_STATUS), READ_REG_1(sc, AEON_IRQEN)); @@ -854,62 +899,18 @@ aeon_crypto(struct aeon_command *cmd) return 0; /* success */ } -/* - * Part of interrupt handler--cleans out done jobs from rings - */ -void -aeon_intr_process_ring(struct aeon_softc *sc, struct aeon_dma *dma) -{ - if (dma->slots_in_use > AEON_D_RSIZE) - printf("%s: Internal Error -- ring overflow\n", - sc->sc_dv.dv_xname); - - while (dma->slots_in_use > 0) { - u_int32_t wake_pos = dma->wakeup_rpos; - struct aeon_command *cmd = dma->aeon_commands[wake_pos]; - - /* if still valid, stop processing */ - if (dma->resr[wake_pos].l & AEON_D_VALID) - break; - - if (AEON_USING_MAC(cmd->flags) && (cmd->flags & AEON_DECODE)) { - u_int8_t *result_buf = dma->result_bufs[wake_pos]; - - cmd->result_status = (result_buf[8] & 0x2) ? AEON_MAC_BAD : 0; - printf("%s: byte index 8 of result 0x%02x\n", - sc->sc_dv.dv_xname, (u_int32_t) result_buf[8]); - } - - /* position is done, notify producer with wakup or callback */ - if (cmd->dest_ready_callback == NULL) - wakeup((caddr_t) &dma->resr[wake_pos]); - else - cmd->dest_ready_callback(cmd); - - if (++dma->wakeup_rpos == AEON_D_RSIZE) - dma->wakeup_rpos = 0; - dma->slots_in_use--; - } -} - int aeon_intr(arg) void *arg; { struct aeon_softc *sc = arg; struct aeon_dma *dma = sc->sc_dma; - int r = 0; -#if 1 - printf("%s: Processing Interrupt" - " -- Status Reg 0x%08x" - " -- Interrupt Enable Reg 0x%08x" - " -- slots in use %u\n", + printf("%s: irq: stat %8x ien %8x u %d/%d/%d/%d\n", sc->sc_dv.dv_xname, READ_REG_1(sc, AEON_STATUS), READ_REG_1(sc, AEON_IRQEN), - dma->slots_in_use); -#endif - + dma->cmdu, dma->srcu, dma->dstu, dma->resu); + if (dma->slots_in_use == 0 && (READ_REG_1(sc, AEON_STATUS) & (1 << 2))) { /* * If no slots to process and we received a "waiting on @@ -917,22 +918,45 @@ aeon_intr(arg) * (by clearing it). */ WRITE_REG_1(sc, AEON_IRQEN, AEON_INTR_ON_RESULT_DONE); - r = 1; } else { - aeon_intr_process_ring(sc, dma); - r = 1; + if (dma->slots_in_use > AEON_D_RSIZE) + printf("%s: Internal Error -- ring overflow\n", + sc->sc_dv.dv_xname); + + while (dma->slots_in_use > 0) { + u_int32_t wake_pos = dma->wakeup_rpos; + struct aeon_command *cmd = dma->aeon_commands[wake_pos]; + + /* if still valid, stop processing */ + if (dma->resr[wake_pos].l & AEON_D_VALID) + break; + + if (AEON_USING_MAC(cmd->flags) && (cmd->flags & AEON_DECODE)) { + u_int8_t *result_buf = dma->result_bufs[wake_pos]; + + cmd->result_status = (result_buf[8] & 0x2) ? + AEON_MAC_BAD : 0; + printf("%s: byte index 8 of result 0x%02x\n", + sc->sc_dv.dv_xname, (u_int32_t) result_buf[8]); + } + + /* position is done, notify producer with wakup or callback */ + if (cmd->dest_ready_callback == NULL) + wakeup((caddr_t) &dma->resr[wake_pos]); + else + cmd->dest_ready_callback(cmd); + + if (++dma->wakeup_rpos == AEON_D_RSIZE) + dma->wakeup_rpos = 0; + dma->slots_in_use--; + } } -#if 1 - printf("%s: exiting interrupt handler -- slots in use %u\n", - sc->sc_dv.dv_xname, dma->slots_in_use); -#endif - /* * Clear "result done" and "waiting on command ring" flags in status * register. If we still have slots to process and we received a * waiting interrupt, this will interupt us again. */ WRITE_REG_1(sc, AEON_STATUS, (1 << 20) | (1 << 2)); - return (r); + return (1); } diff --git a/sys/dev/pci/aeonreg.h b/sys/dev/pci/aeonreg.h index 0890e3399fd..77094ac21f7 100644 --- a/sys/dev/pci/aeonreg.h +++ b/sys/dev/pci/aeonreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: aeonreg.h,v 1.2 1999/02/21 00:05:14 deraadt Exp $ */ +/* $OpenBSD: aeonreg.h,v 1.3 1999/02/24 06:09:45 deraadt Exp $ */ /* * Invertex AEON driver @@ -49,6 +49,11 @@ #define AEON_D_RSIZE 24 #define AEON_MAX_DEVICES 4 +#define AEON_D_CMD_RSIZE 24 +#define AEON_D_SRC_RSIZE 80 +#define AEON_D_DST_RSIZE 80 +#define AEON_D_RES_RSIZE 24 + /* * The values below should multiple of 4 -- and be large enough to handle * any command the driver implements. diff --git a/sys/dev/pci/aeonvar.h b/sys/dev/pci/aeonvar.h index c653bef36db..a933884346a 100644 --- a/sys/dev/pci/aeonvar.h +++ b/sys/dev/pci/aeonvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: aeonvar.h,v 1.2 1999/02/21 00:05:15 deraadt Exp $ */ +/* $OpenBSD: aeonvar.h,v 1.3 1999/02/24 06:09:45 deraadt Exp $ */ /* * Invertex AEON driver @@ -52,6 +52,8 @@ #define AEON_SHA1_LENGTH 20 #define AEON_MAC_TRUNC_LENGTH 12 +#define MAX_SCATTER 10 + /* * aeon_command_t * @@ -117,23 +119,9 @@ * Warning: Using session numbers and multiboard at the same time * is currently broken. * - * source_buf - * ---------- - * The source buffer is used for DMA -- it must be a 4-byte aligned - * address to physically contiguous memory where encode / decode - * input is read from. In a decode operation using authentication, - * the final bytes of the buffer should contain the appropriate hash - * data. - * - * dest_buf - * -------- - * The dest buffer is used for DMA -- it must be a 4-byte aligned - * address to physically contiguous memory where encoded / decoded - * output is written to. If desired, this buffer can be the same - * as the source buffer with no performance penalty. If - * authentication is used, the final bytes will always consist of - * the hashed value (even on decode operations). - * + * mbuf: either fill in the mbuf pointer and npa=0 or + * fill packp[] and packl[] and set npa to > 0 + * * mac_header_skip * --------------- * The number of bytes of the source_buf that are skipped over before @@ -196,19 +184,23 @@ typedef struct aeon_command { u_short session_num; - /* - * You should be able to convert any of these arrays into pointers - * (if desired) without modifying code in aeon.c. - */ u_char *iv, *ck, *mac; int iv_len, ck_len, mac_len; - struct mbuf *m; + struct mbuf *src_m; + long src_packp[MAX_SCATTER]; + int src_packl[MAX_SCATTER]; + int src_npa; + int src_l; + + struct mbuf *dst_m; + long dst_packp[MAX_SCATTER]; + int dst_packl[MAX_SCATTER]; + int dst_npa; + int dst_l; u_short mac_header_skip; u_short crypt_header_skip; - u_short source_length; - u_short dest_length; void (*dest_ready_callback)(struct aeon_command *); u_long private_data; @@ -278,7 +270,7 @@ typedef struct aeon_command { * behaviour was requested. * *************************************************************************/ -int aeon_crypto(aeon_command_t *command); +int aeon_crypto __P((aeon_command_t *command)); #endif /* _KERNEL */ diff --git a/sys/dev/pci/hifn7751.c b/sys/dev/pci/hifn7751.c index 6988d1c9be2..13bc79851cb 100644 --- a/sys/dev/pci/hifn7751.c +++ b/sys/dev/pci/hifn7751.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hifn7751.c,v 1.2 1999/02/21 00:05:14 deraadt Exp $ */ +/* $OpenBSD: hifn7751.c,v 1.3 1999/02/24 06:09:45 deraadt Exp $ */ /* * Invertex AEON driver @@ -75,12 +75,12 @@ void aeon_init_dma __P((struct aeon_softc *)); void aeon_init_pci_registers __P((struct aeon_softc *)); int aeon_checkram __P((struct aeon_softc *)); int aeon_intr __P((void *)); -u_int32_t aeon_write_command __P((const struct aeon_command_buf_data *, - u_int8_t *)); -int aeon_build_command __P((const struct aeon_command * cmd, - struct aeon_command_buf_data *)); -void aeon_intr_process_ring __P((struct aeon_softc *, struct aeon_dma *)); - +u_int aeon_write_command __P((const struct aeon_command_buf_data *, + u_int8_t *)); +int aeon_build_command __P((const struct aeon_command * cmd, + struct aeon_command_buf_data *)); +int aeon_mbuf __P((struct mbuf *, int *np, long *pp, int *lp, int maxp, + int *nicealign)); /* * Used for round robin crypto requests @@ -406,21 +406,22 @@ aeon_init_dma(sc) int i; /* initialize static pointer values */ - for (i = 0; i < AEON_D_RSIZE; i++) { + for (i = 0; i < AEON_D_CMD_RSIZE; i++) dma->cmdr[i].p = vtophys(dma->command_bufs[i]); + for (i = 0; i < AEON_D_RES_RSIZE; i++) dma->resr[i].p = vtophys(dma->result_bufs[i]); - } - dma->cmdr[AEON_D_RSIZE].p = vtophys(dma->cmdr); - dma->srcr[AEON_D_RSIZE].p = vtophys(dma->srcr); - dma->dstr[AEON_D_RSIZE].p = vtophys(dma->dstr); - dma->resr[AEON_D_RSIZE].p = vtophys(dma->resr); + + dma->cmdr[AEON_D_CMD_RSIZE].p = vtophys(dma->cmdr); + dma->srcr[AEON_D_SRC_RSIZE].p = vtophys(dma->srcr); + dma->dstr[AEON_D_DST_RSIZE].p = vtophys(dma->dstr); + dma->resr[AEON_D_RES_RSIZE].p = vtophys(dma->resr); } /* * Writes out the raw command buffer space. Returns the * command buffer size. */ -u_int32_t +u_int aeon_write_command(const struct aeon_command_buf_data *cmd_data, u_int8_t *command_buf) { @@ -538,14 +539,14 @@ aeon_build_command(const struct aeon_command *cmd, * checks!!!! */ - if (cmd->source_length <= mac_length) { + if (cmd->src_npa <= mac_length) { printf("aeon: command source buffer has no data\n"); return -1; } dest_diff = (flags & AEON_ENCODE) ? mac_length : -mac_length; - if (cmd->dest_length < cmd->source_length + dest_diff) { + if (cmd->dst_npa < cmd->dst_npa + dest_diff) { printf("aeon: command dest length %u too short -- needed %u\n", - cmd->dest_length, cmd->source_length + dest_diff); + cmd->dst_npa, cmd->dst_npa + dest_diff); return -1; } #endif @@ -570,8 +571,8 @@ aeon_build_command(const struct aeon_command *cmd, * Set total source and dest counts. These values are the same as the * values set in the length field of the source and dest descriptor rings. */ - base_cmd->total_source_count = cmd->source_length; - base_cmd->total_dest_count = cmd->dest_length; + base_cmd->total_source_count = cmd->src_l; + base_cmd->total_dest_count = cmd->dst_l; /* * XXX -- We need session number range checking... @@ -612,7 +613,7 @@ aeon_build_command(const struct aeon_command *cmd, * Set the mac header skip and source count. */ mac_cmd->header_skip = cmd->mac_header_skip; - mac_cmd->source_count = cmd->source_length - cmd->mac_header_skip; + mac_cmd->source_count = cmd->src_npa - cmd->mac_header_skip; if (flags & AEON_DECODE) mac_cmd->source_count -= mac_length; } @@ -639,7 +640,7 @@ aeon_build_command(const struct aeon_command *cmd, * Set the encrypt header skip and source count. */ crypt_cmd->header_skip = cmd->crypt_header_skip; - crypt_cmd->source_count = cmd->source_length - cmd->crypt_header_skip; + crypt_cmd->source_count = cmd->src_npa - cmd->crypt_header_skip; if (flags & AEON_DECODE) crypt_cmd->source_count -= mac_length; @@ -671,51 +672,21 @@ aeon_build_command(const struct aeon_command *cmd, return 0; /* success */ } -int -aeon_crypto(struct aeon_command *cmd) +int +aeon_mbuf(m, np, pp, lp, maxp, nicep) + struct mbuf *m; + int *np; + long *pp; + int *lp; + int maxp; + int *nicep; { - u_int32_t cmdlen; - static u_int32_t current_device = 0; - struct aeon_softc *sc; - struct aeon_dma *dma; - struct aeon_command_buf_data cmd_buf_data; - int cmdi, srci, dsti, resi; - int error, s; -#define MAX_SCATTER 10 - long packp[MAX_SCATTER]; - int packl[MAX_SCATTER]; - struct mbuf *m0, *m = cmd->m; - int nchunks, i; - - if (aeon_build_command(cmd, &cmd_buf_data) != 0) - return AEON_CRYPTO_BAD_INPUT; - - s = splimp(); + struct mbuf *m0; + int npa = *np; + int tlen = 0; - /* Pick the aeon board to send the data to. Right now we use a round - * robin approach. */ - sc = aeon_devices[current_device++]; - if (current_device == aeon_num_devices) - current_device = 0; - dma = sc->sc_dma; - -#if 1 - printf("%s: Entering command" - " -- Status Reg 0x%08x" - " -- Interrupt Enable Reg 0x%08x" - " -- slots in use %u" - " -- source length %u" - " -- dest length %u\n", - sc->sc_dv.dv_xname, - READ_REG_1(sc, AEON_STATUS), READ_REG_1(sc, AEON_IRQEN), - dma->slots_in_use, cmd->source_length, cmd->dest_length); -#endif - - /* - * Generate a [pa,len] array from an mbuf. - * This is very broken - */ - nchunks = 0; + /* generate a [pa,len] array from an mbuf */ + npa = 0; for (m0 = m; m; m = m->m_next) { void *va; long pg, npg; @@ -723,101 +694,177 @@ aeon_crypto(struct aeon_command *cmd) va = m->m_data; len = m->m_len; + tlen += len; - packl[nchunks] = len; - packp[nchunks] = vtophys(va); - pg = packp[nchunks] & ~PAGE_MASK; + lp[npa] = len; + pp[npa] = vtophys(va); + pg = pp[npa] & ~PAGE_MASK; off = (long)va & PAGE_MASK; while (len + off > PAGE_SIZE) { va = va + PAGE_SIZE - off; npg = vtophys(va); if (npg != pg) { - nchunks++; - break; + /* FUCKED UP condition */ + npa++; + continue; } - packl[nchunks] = PAGE_SIZE - off; + lp[npa] = PAGE_SIZE - off; off = 0; - ++nchunks; - packl[nchunks] = len - (PAGE_SIZE - off); - len -= packl[nchunks]; - packp[nchunks] = vtophys(va); + ++npa; + if (npa > maxp) + return (0); + lp[npa] = len - (PAGE_SIZE - off); + len -= lp[npa]; + pp[npa] = vtophys(va); } } + if (nicep) { + int nice = 1; + int i; + + /* see if each [pa,len] entry is long-word aligned */ + for (i = 0; i < npa; i++) + if ((lp[i] & 3) || (pp[i] & 3)) + nice = 0; + *nicep = nice; + } + + *np = npa; + return (tlen); +} + +int +aeon_crypto(struct aeon_command *cmd) +{ + u_int32_t cmdlen; + static u_int32_t current_device = 0; + struct aeon_softc *sc; + struct aeon_dma *dma; + struct aeon_command_buf_data cmd_buf_data; + int cmdi, srci, dsti, resi, nicealign = 0; + int error, s, i; + + /* Pick the aeon board to send the data to. Right now we use a round + * robin approach. */ + sc = aeon_devices[current_device++]; + if (current_device == aeon_num_devices) + current_device = 0; + dma = sc->sc_dma; + + if (cmd->src_npa == 0 && cmd->src_m) + cmd->src_l = aeon_mbuf(cmd->src_m, &cmd->src_npa, + cmd->src_packp, cmd->src_packl, MAX_SCATTER, &nicealign); + if (cmd->src_l == 0) + return (-1); + + if (nicealign == 0) { + cmd->dst_l = cmd->src_l; + MGETHDR(cmd->dst_m, M_DONTWAIT, MT_DATA); + if (cmd->dst_m == NULL) + return (-1); + if (cmd->src_l > MHLEN) { + MCLGET(cmd->dst_m, M_DONTWAIT); + if ((cmd->dst_m->m_flags & M_EXT) == 0) { + m_freem(cmd->dst_m); + return (-1); + } + } + } else + cmd->dst_m = cmd->src_m; + + cmd->dst_l = aeon_mbuf(cmd->dst_m, &cmd->dst_npa, + cmd->dst_packp, cmd->dst_packl, MAX_SCATTER, NULL); + if (cmd->dst_l == 0) + return (-1); + + if (aeon_build_command(cmd, &cmd_buf_data) != 0) + return AEON_CRYPTO_BAD_INPUT; + + printf("%s: Entering cmd: stat %8x ien %8x u %d/%d/%d/%d n %d/%d\n", + sc->sc_dv.dv_xname, + READ_REG_1(sc, AEON_STATUS), READ_REG_1(sc, AEON_IRQEN), + dma->cmdu, dma->srcu, dma->dstu, dma->resu, cmd->src_npa, + cmd->dst_npa); + + s = splimp(); + /* * need 1 cmd, and 1 res * need N src, and N dst */ - while (dma->cmdu+1 == AEON_D_RSIZE || dma->srcu+nchunks == AEON_D_RSIZE || - dma->dstu+nchunks == AEON_D_RSIZE || dma->resu+1 == AEON_D_RSIZE) { - if (cmd->flags & AEON_DMA_FULL_NOBLOCK) + while (dma->cmdu+1 > AEON_D_CMD_RSIZE || + dma->srcu+cmd->src_npa > AEON_D_SRC_RSIZE || + dma->dstu+cmd->dst_npa > AEON_D_DST_RSIZE || + dma->resu+1 > AEON_D_RES_RSIZE) { + if (cmd->flags & AEON_DMA_FULL_NOBLOCK) { splx(s); return (AEON_CRYPTO_RINGS_FULL); + } tsleep((caddr_t) dma, PZERO, "aeonring", 1); } - dma->cmdu += 1; - dma->resu += 1; - if (dma->cmdi == AEON_D_RSIZE) { + if (dma->cmdi == AEON_D_CMD_RSIZE) { cmdi = 0, dma->cmdi = 1; - dma->cmdr[AEON_D_RSIZE].l = AEON_D_VALID | AEON_D_LAST | + dma->cmdr[AEON_D_CMD_RSIZE].l = AEON_D_VALID | AEON_D_LAST | AEON_D_MASKDONEIRQ | AEON_D_JUMP; } else cmdi = dma->cmdi++; - if (dma->resi == AEON_D_RSIZE) { + if (dma->resi == AEON_D_RES_RSIZE) { resi = 0, dma->resi = 1; - dma->resr[AEON_D_RSIZE].l = AEON_D_VALID | AEON_D_LAST | + dma->resr[AEON_D_RES_RSIZE].l = AEON_D_VALID | AEON_D_LAST | AEON_D_MASKDONEIRQ | AEON_D_JUMP; } else resi = dma->resi++; cmdlen = aeon_write_command(&cmd_buf_data, dma->command_bufs[cmdi]); dma->aeon_commands[cmdi] = cmd; - - /* - * .p for command/result already set - */ + /* .p for command/result already set */ dma->cmdr[cmdi].l = cmdlen | AEON_D_VALID | AEON_D_LAST | AEON_D_MASKDONEIRQ; + dma->cmdu += 1; - for (i = 0; i < nchunks; i++) { + for (i = 0; i < cmd->src_npa; i++) { int last = 0; - if (i == nchunks-1) + if (i == cmd->src_npa-1) last = AEON_D_LAST; - if (dma->srci == AEON_D_RSIZE) { + if (dma->srci == AEON_D_SRC_RSIZE) { srci = 0, dma->srci = 1; - dma->srcr[AEON_D_RSIZE].l = AEON_D_VALID | + dma->srcr[AEON_D_SRC_RSIZE].l = AEON_D_VALID | AEON_D_MASKDONEIRQ | AEON_D_JUMP; } else srci = dma->srci++; - dma->srcu++; - - dma->srcr[srci].p = vtophys(packp[i]); - dma->srcr[srci].l = packl[i] | AEON_D_VALID | + dma->srcr[srci].p = vtophys(cmd->src_packp[i]); + dma->srcr[srci].l = cmd->src_packl[i] | AEON_D_VALID | AEON_D_MASKDONEIRQ | last; + } + dma->srcu += cmd->src_npa; - if (dma->dsti == AEON_D_RSIZE) { + for (i = 0; i < cmd->dst_npa; i++) { + int last = 0; + + if (dma->dsti == AEON_D_DST_RSIZE) { dsti = 0, dma->dsti = 1; - dma->dstr[AEON_D_RSIZE].l = AEON_D_VALID | + dma->dstr[AEON_D_DST_RSIZE].l = AEON_D_VALID | AEON_D_MASKDONEIRQ | AEON_D_JUMP; } else dsti = dma->dsti++; - dma->dstu++; - - dma->dstr[dsti].p = vtophys(packp[i]); - dma->dstr[dsti].l = packl[i] | AEON_D_VALID | + dma->dstr[dsti].p = vtophys(cmd->dst_packp[i]); + dma->dstr[dsti].l = cmd->dst_packl[i] | AEON_D_VALID | AEON_D_MASKDONEIRQ | last; } + dma->dstu += cmd->dst_npa; /* * Unlike other descriptors, we don't mask done interrupt from * result descriptor. */ dma->resr[resi].l = AEON_MAX_RESULT | AEON_D_VALID | AEON_D_LAST; + dma->resu += 1; /* * We don't worry about missing an interrupt (which a waiting @@ -844,9 +891,7 @@ aeon_crypto(struct aeon_command *cmd) sc->sc_dv.dv_xname, error); } - printf("%s: command executed" - " -- Status Register 0x%08x" - " -- Interrupt Enable Reg 0x%08x\n", + printf("%s: command: stat %8x ier %8x\n", sc->sc_dv.dv_xname, READ_REG_1(sc, AEON_STATUS), READ_REG_1(sc, AEON_IRQEN)); @@ -854,62 +899,18 @@ aeon_crypto(struct aeon_command *cmd) return 0; /* success */ } -/* - * Part of interrupt handler--cleans out done jobs from rings - */ -void -aeon_intr_process_ring(struct aeon_softc *sc, struct aeon_dma *dma) -{ - if (dma->slots_in_use > AEON_D_RSIZE) - printf("%s: Internal Error -- ring overflow\n", - sc->sc_dv.dv_xname); - - while (dma->slots_in_use > 0) { - u_int32_t wake_pos = dma->wakeup_rpos; - struct aeon_command *cmd = dma->aeon_commands[wake_pos]; - - /* if still valid, stop processing */ - if (dma->resr[wake_pos].l & AEON_D_VALID) - break; - - if (AEON_USING_MAC(cmd->flags) && (cmd->flags & AEON_DECODE)) { - u_int8_t *result_buf = dma->result_bufs[wake_pos]; - - cmd->result_status = (result_buf[8] & 0x2) ? AEON_MAC_BAD : 0; - printf("%s: byte index 8 of result 0x%02x\n", - sc->sc_dv.dv_xname, (u_int32_t) result_buf[8]); - } - - /* position is done, notify producer with wakup or callback */ - if (cmd->dest_ready_callback == NULL) - wakeup((caddr_t) &dma->resr[wake_pos]); - else - cmd->dest_ready_callback(cmd); - - if (++dma->wakeup_rpos == AEON_D_RSIZE) - dma->wakeup_rpos = 0; - dma->slots_in_use--; - } -} - int aeon_intr(arg) void *arg; { struct aeon_softc *sc = arg; struct aeon_dma *dma = sc->sc_dma; - int r = 0; -#if 1 - printf("%s: Processing Interrupt" - " -- Status Reg 0x%08x" - " -- Interrupt Enable Reg 0x%08x" - " -- slots in use %u\n", + printf("%s: irq: stat %8x ien %8x u %d/%d/%d/%d\n", sc->sc_dv.dv_xname, READ_REG_1(sc, AEON_STATUS), READ_REG_1(sc, AEON_IRQEN), - dma->slots_in_use); -#endif - + dma->cmdu, dma->srcu, dma->dstu, dma->resu); + if (dma->slots_in_use == 0 && (READ_REG_1(sc, AEON_STATUS) & (1 << 2))) { /* * If no slots to process and we received a "waiting on @@ -917,22 +918,45 @@ aeon_intr(arg) * (by clearing it). */ WRITE_REG_1(sc, AEON_IRQEN, AEON_INTR_ON_RESULT_DONE); - r = 1; } else { - aeon_intr_process_ring(sc, dma); - r = 1; + if (dma->slots_in_use > AEON_D_RSIZE) + printf("%s: Internal Error -- ring overflow\n", + sc->sc_dv.dv_xname); + + while (dma->slots_in_use > 0) { + u_int32_t wake_pos = dma->wakeup_rpos; + struct aeon_command *cmd = dma->aeon_commands[wake_pos]; + + /* if still valid, stop processing */ + if (dma->resr[wake_pos].l & AEON_D_VALID) + break; + + if (AEON_USING_MAC(cmd->flags) && (cmd->flags & AEON_DECODE)) { + u_int8_t *result_buf = dma->result_bufs[wake_pos]; + + cmd->result_status = (result_buf[8] & 0x2) ? + AEON_MAC_BAD : 0; + printf("%s: byte index 8 of result 0x%02x\n", + sc->sc_dv.dv_xname, (u_int32_t) result_buf[8]); + } + + /* position is done, notify producer with wakup or callback */ + if (cmd->dest_ready_callback == NULL) + wakeup((caddr_t) &dma->resr[wake_pos]); + else + cmd->dest_ready_callback(cmd); + + if (++dma->wakeup_rpos == AEON_D_RSIZE) + dma->wakeup_rpos = 0; + dma->slots_in_use--; + } } -#if 1 - printf("%s: exiting interrupt handler -- slots in use %u\n", - sc->sc_dv.dv_xname, dma->slots_in_use); -#endif - /* * Clear "result done" and "waiting on command ring" flags in status * register. If we still have slots to process and we received a * waiting interrupt, this will interupt us again. */ WRITE_REG_1(sc, AEON_STATUS, (1 << 20) | (1 << 2)); - return (r); + return (1); } diff --git a/sys/dev/pci/hifn7751reg.h b/sys/dev/pci/hifn7751reg.h index 4efdd174d45..809233f5603 100644 --- a/sys/dev/pci/hifn7751reg.h +++ b/sys/dev/pci/hifn7751reg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: hifn7751reg.h,v 1.2 1999/02/21 00:05:14 deraadt Exp $ */ +/* $OpenBSD: hifn7751reg.h,v 1.3 1999/02/24 06:09:45 deraadt Exp $ */ /* * Invertex AEON driver @@ -49,6 +49,11 @@ #define AEON_D_RSIZE 24 #define AEON_MAX_DEVICES 4 +#define AEON_D_CMD_RSIZE 24 +#define AEON_D_SRC_RSIZE 80 +#define AEON_D_DST_RSIZE 80 +#define AEON_D_RES_RSIZE 24 + /* * The values below should multiple of 4 -- and be large enough to handle * any command the driver implements. diff --git a/sys/dev/pci/hifn7751var.h b/sys/dev/pci/hifn7751var.h index 1cf840057d9..7483f4b23f8 100644 --- a/sys/dev/pci/hifn7751var.h +++ b/sys/dev/pci/hifn7751var.h @@ -1,4 +1,4 @@ -/* $OpenBSD: hifn7751var.h,v 1.2 1999/02/21 00:05:15 deraadt Exp $ */ +/* $OpenBSD: hifn7751var.h,v 1.3 1999/02/24 06:09:45 deraadt Exp $ */ /* * Invertex AEON driver @@ -52,6 +52,8 @@ #define AEON_SHA1_LENGTH 20 #define AEON_MAC_TRUNC_LENGTH 12 +#define MAX_SCATTER 10 + /* * aeon_command_t * @@ -117,23 +119,9 @@ * Warning: Using session numbers and multiboard at the same time * is currently broken. * - * source_buf - * ---------- - * The source buffer is used for DMA -- it must be a 4-byte aligned - * address to physically contiguous memory where encode / decode - * input is read from. In a decode operation using authentication, - * the final bytes of the buffer should contain the appropriate hash - * data. - * - * dest_buf - * -------- - * The dest buffer is used for DMA -- it must be a 4-byte aligned - * address to physically contiguous memory where encoded / decoded - * output is written to. If desired, this buffer can be the same - * as the source buffer with no performance penalty. If - * authentication is used, the final bytes will always consist of - * the hashed value (even on decode operations). - * + * mbuf: either fill in the mbuf pointer and npa=0 or + * fill packp[] and packl[] and set npa to > 0 + * * mac_header_skip * --------------- * The number of bytes of the source_buf that are skipped over before @@ -196,19 +184,23 @@ typedef struct aeon_command { u_short session_num; - /* - * You should be able to convert any of these arrays into pointers - * (if desired) without modifying code in aeon.c. - */ u_char *iv, *ck, *mac; int iv_len, ck_len, mac_len; - struct mbuf *m; + struct mbuf *src_m; + long src_packp[MAX_SCATTER]; + int src_packl[MAX_SCATTER]; + int src_npa; + int src_l; + + struct mbuf *dst_m; + long dst_packp[MAX_SCATTER]; + int dst_packl[MAX_SCATTER]; + int dst_npa; + int dst_l; u_short mac_header_skip; u_short crypt_header_skip; - u_short source_length; - u_short dest_length; void (*dest_ready_callback)(struct aeon_command *); u_long private_data; @@ -278,7 +270,7 @@ typedef struct aeon_command { * behaviour was requested. * *************************************************************************/ -int aeon_crypto(aeon_command_t *command); +int aeon_crypto __P((aeon_command_t *command)); #endif /* _KERNEL */ |