1 /* $OpenBSD: noct.c,v 1.16 2004/05/04 16:59:31 grange Exp $ */
2
3 /*
4 * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Effort sponsored in part by the Defense Advanced Research Projects
29 * Agency (DARPA) and Air Force Research Laboratory, Air Force
30 * Materiel Command, USAF, under agreement number F30602-01-2-0537.
31 *
32 */
33
34 /*
35 * Driver for the Netoctave NSP2000 security processor.
36 */
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/proc.h>
41 #include <sys/errno.h>
42 #include <sys/malloc.h>
43 #include <sys/kernel.h>
44 #include <sys/mbuf.h>
45 #include <sys/device.h>
46 #include <sys/extent.h>
47 #include <sys/kthread.h>
48
49 #include <crypto/cryptodev.h>
50 #include <dev/rndvar.h>
51
52 #include <dev/pci/pcireg.h>
53 #include <dev/pci/pcivar.h>
54 #include <dev/pci/pcidevs.h>
55
56 #include <dev/pci/noctreg.h>
57 #include <dev/pci/noctvar.h>
58
59 int noct_probe(struct device *, void *, void *);
60 void noct_attach(struct device *, struct device *, void *);
61 int noct_intr(void *);
62
63 int noct_ram_size(struct noct_softc *);
64 void noct_ram_write(struct noct_softc *, u_int32_t, u_int64_t);
65 u_int64_t noct_ram_read(struct noct_softc *, u_int32_t);
66
67 void noct_rng_enable(struct noct_softc *);
68 void noct_rng_disable(struct noct_softc *);
69 void noct_rng_init(struct noct_softc *);
70 void noct_rng_intr(struct noct_softc *);
71 void noct_rng_tick(void *);
72
73 void noct_pkh_enable(struct noct_softc *);
74 void noct_pkh_disable(struct noct_softc *);
75 void noct_pkh_init(struct noct_softc *);
76 void noct_pkh_intr(struct noct_softc *);
77 void noct_pkh_freedesc(struct noct_softc *, int);
78 u_int32_t noct_pkh_nfree(struct noct_softc *);
79 int noct_kload(struct noct_softc *, struct crparam *, u_int32_t);
80 void noct_kload_cb(struct noct_softc *, u_int32_t, int);
81 void noct_modmul_cb(struct noct_softc *, u_int32_t, int);
82
83 void noct_ea_enable(struct noct_softc *);
84 void noct_ea_disable(struct noct_softc *);
85 void noct_ea_init(struct noct_softc *);
86 void noct_ea_intr(struct noct_softc *);
87 void noct_ea_create_thread(void *);
88 void noct_ea_thread(void *);
89 u_int32_t noct_ea_nfree(struct noct_softc *);
90 void noct_ea_start(struct noct_softc *, struct noct_workq *);
91 void noct_ea_start_hash(struct noct_softc *, struct noct_workq *,
92 struct cryptop *, struct cryptodesc *);
93 void noct_ea_start_des(struct noct_softc *, struct noct_workq *,
94 struct cryptop *, struct cryptodesc *);
95 int noct_newsession(u_int32_t *, struct cryptoini *);
96 int noct_freesession(u_int64_t);
97 int noct_process(struct cryptop *);
98
99 u_int32_t noct_read_4(struct noct_softc *, bus_size_t);
100 void noct_write_4(struct noct_softc *, bus_size_t, u_int32_t);
101 u_int64_t noct_read_8(struct noct_softc *, u_int32_t);
102 void noct_write_8(struct noct_softc *, u_int32_t, u_int64_t);
103
104 struct noct_softc *noct_kfind(struct cryptkop *);
105 int noct_ksigbits(struct crparam *);
106 int noct_kprocess(struct cryptkop *);
107 int noct_kprocess_modexp(struct noct_softc *, struct cryptkop *);
108
109 struct cfattach noct_ca = {
110 sizeof(struct noct_softc), noct_probe, noct_attach,
111 };
112
113 struct cfdriver noct_cd = {
114 0, "noct", DV_DULL
115 };
116
117 #define SWAP32(x) (x) = htole32(ntohl((x)))
118
119 int
noct_probe(parent,match,aux)120 noct_probe(parent, match, aux)
121 struct device *parent;
122 void *match;
123 void *aux;
124 {
125 struct pci_attach_args *pa = (struct pci_attach_args *) aux;
126
127 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_NETOCTAVE &&
128 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_NETOCTAVE_NSP2K)
129 return (1);
130 return (0);
131 }
132
133 void
noct_attach(parent,self,aux)134 noct_attach(parent, self, aux)
135 struct device *parent, *self;
136 void *aux;
137 {
138 struct noct_softc *sc = (struct noct_softc *)self;
139 struct pci_attach_args *pa = aux;
140 pci_chipset_tag_t pc = pa->pa_pc;
141 pci_intr_handle_t ih;
142 const char *intrstr = NULL;
143 bus_size_t iosize = 0;
144 u_int32_t cmd;
145
146 cmd = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
147 cmd |= PCI_COMMAND_MEM_ENABLE;
148 pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, cmd);
149 cmd = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
150
151 if (!(cmd & PCI_COMMAND_MEM_ENABLE)) {
152 printf(": failed to enable memory mapping\n");
153 goto fail;
154 }
155
156 if (pci_mapreg_map(pa, NOCT_BAR0, PCI_MAPREG_MEM_TYPE_64BIT, 0,
157 &sc->sc_st, &sc->sc_sh, NULL, &iosize, 0)) {
158 printf(": can't map mem space\n");
159 goto fail;
160 }
161
162 /* Before we do anything else, put the chip in little endian mode */
163 NOCT_WRITE_4(sc, NOCT_BRDG_ENDIAN, 0);
164 sc->sc_rar_last = 0xffffffff;
165 sc->sc_waw_last = 0xffffffff;
166 sc->sc_dmat = pa->pa_dmat;
167
168 sc->sc_cid = crypto_get_driverid(0);
169 if (sc->sc_cid < 0) {
170 printf(": couldn't register cid\n");
171 goto fail;
172 }
173
174 if (pci_intr_map(pa, &ih)) {
175 printf(": couldn't map interrupt\n");
176 goto fail;
177 }
178 intrstr = pci_intr_string(pc, ih);
179 sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, noct_intr, sc,
180 self->dv_xname);
181 if (sc->sc_ih == NULL) {
182 printf(": couldn't establish interrupt");
183 if (intrstr != NULL)
184 printf(" at %s", intrstr);
185 printf("\n");
186 goto fail;
187 }
188
189 if (noct_ram_size(sc))
190 goto fail;
191
192 printf(":");
193
194 noct_rng_init(sc);
195 noct_pkh_init(sc);
196 noct_ea_init(sc);
197
198 printf(", %uMB, %s\n", sc->sc_ramsize, intrstr);
199
200 return;
201
202 fail:
203 if (iosize != 0)
204 bus_space_unmap(sc->sc_st, sc->sc_sh, iosize);
205 }
206
207 int
noct_intr(vsc)208 noct_intr(vsc)
209 void *vsc;
210 {
211 struct noct_softc *sc = vsc;
212 u_int32_t reg;
213 int r = 0;
214
215 reg = NOCT_READ_4(sc, NOCT_BRDG_STAT);
216
217 if (reg & BRDGSTS_RNG_INT) {
218 r = 1;
219 noct_rng_intr(sc);
220 }
221
222 if (reg & BRDGSTS_PKP_INT) {
223 r = 1;
224 noct_pkh_intr(sc);
225 }
226
227 if (reg & BRDGSTS_CCH_INT) {
228 r = 1;
229 noct_ea_intr(sc);
230 }
231
232 return (r);
233 }
234
235 int
noct_ram_size(sc)236 noct_ram_size(sc)
237 struct noct_softc *sc;
238 {
239 u_int64_t t;
240
241 noct_ram_write(sc, 0x000000, 64);
242 noct_ram_write(sc, 0x400000, 32);
243 t = noct_ram_read(sc, 0x000000);
244 noct_ram_write(sc, 0x000000, 128);
245 noct_ram_write(sc, 0x800000, t);
246 t = noct_ram_read(sc, 0x000000);
247
248 if (t != 32 && t != 64 && t != 128) {
249 printf(": invalid ram size %llx\n", (unsigned long long)t);
250 return (1);
251 }
252
253 sc->sc_ramsize = t;
254 return (0);
255 }
256
257 void
noct_ram_write(sc,adr,dat)258 noct_ram_write(sc, adr, dat)
259 struct noct_softc *sc;
260 u_int32_t adr;
261 u_int64_t dat;
262 {
263 u_int32_t reg;
264
265 /* wait for pending writes to finish */
266 for (;;) {
267 reg = NOCT_READ_4(sc, NOCT_EA_CTX_ADDR);
268 if ((reg & EACTXADDR_WRITEPEND) == 0)
269 break;
270 }
271
272 NOCT_WRITE_4(sc, NOCT_EA_CTX_ADDR, adr);
273 NOCT_WRITE_4(sc, NOCT_EA_CTX_DAT_1, (dat >> 32) & 0xffffffff);
274 NOCT_WRITE_4(sc, NOCT_EA_CTX_DAT_0, (dat >> 0) & 0xffffffff);
275
276 for (;;) {
277 reg = NOCT_READ_4(sc, NOCT_EA_CTX_ADDR);
278 if ((reg & EACTXADDR_WRITEPEND) == 0)
279 break;
280 }
281 }
282
283 u_int64_t
noct_ram_read(sc,adr)284 noct_ram_read(sc, adr)
285 struct noct_softc *sc;
286 u_int32_t adr;
287 {
288 u_int64_t dat;
289 u_int32_t reg;
290
291 /* wait for pending reads to finish */
292 for (;;) {
293 reg = NOCT_READ_4(sc, NOCT_EA_CTX_ADDR);
294 if ((reg & EACTXADDR_READPEND) == 0)
295 break;
296 }
297
298 NOCT_WRITE_4(sc, NOCT_EA_CTX_ADDR, adr | EACTXADDR_READPEND);
299
300 for (;;) {
301 reg = NOCT_READ_4(sc, NOCT_EA_CTX_ADDR);
302 if ((reg & EACTXADDR_READPEND) == 0)
303 break;
304 }
305
306 dat = NOCT_READ_4(sc, NOCT_EA_CTX_DAT_1);
307 dat <<= 32;
308 dat |= NOCT_READ_4(sc, NOCT_EA_CTX_DAT_0);
309 return (dat);
310 }
311
312 void
noct_pkh_disable(sc)313 noct_pkh_disable(sc)
314 struct noct_softc *sc;
315 {
316 u_int32_t r;
317
318 /* Turn off PK irq */
319 NOCT_WRITE_4(sc, NOCT_BRDG_CTL,
320 NOCT_READ_4(sc, NOCT_BRDG_CTL) & ~(BRDGCTL_PKIRQ_ENA));
321
322 /* Turn off PK interrupts */
323 r = NOCT_READ_4(sc, NOCT_PKH_IER);
324 r &= ~(PKHIER_CMDSI | PKHIER_SKSWR | PKHIER_SKSOFF | PKHIER_PKHLEN |
325 PKHIER_PKHOPCODE | PKHIER_BADQBASE | PKHIER_LOADERR |
326 PKHIER_STOREERR | PKHIER_CMDERR | PKHIER_ILL | PKHIER_PKERESV |
327 PKHIER_PKEWDT | PKHIER_PKENOTPRIME |
328 PKHIER_PKE_B | PKHIER_PKE_A | PKHIER_PKE_M | PKHIER_PKE_R |
329 PKHIER_PKEOPCODE);
330 NOCT_WRITE_4(sc, NOCT_PKH_IER, r);
331
332 /* Disable PK unit */
333 r = NOCT_READ_4(sc, NOCT_PKH_CSR);
334 r &= ~PKHCSR_PKH_ENA;
335 NOCT_WRITE_4(sc, NOCT_PKH_CSR, r);
336 for (;;) {
337 r = NOCT_READ_4(sc, NOCT_PKH_CSR);
338 if ((r & PKHCSR_PKH_BUSY) == 0)
339 break;
340 }
341
342 /* Clear status bits */
343 r |= PKHCSR_CMDSI | PKHCSR_SKSWR | PKHCSR_SKSOFF | PKHCSR_PKHLEN |
344 PKHCSR_PKHOPCODE | PKHCSR_BADQBASE | PKHCSR_LOADERR |
345 PKHCSR_STOREERR | PKHCSR_CMDERR | PKHCSR_ILL | PKHCSR_PKERESV |
346 PKHCSR_PKEWDT | PKHCSR_PKENOTPRIME |
347 PKHCSR_PKE_B | PKHCSR_PKE_A | PKHCSR_PKE_M | PKHCSR_PKE_R |
348 PKHCSR_PKEOPCODE;
349 NOCT_WRITE_4(sc, NOCT_PKH_CSR, r);
350 }
351
352 void
noct_pkh_enable(sc)353 noct_pkh_enable(sc)
354 struct noct_softc *sc;
355 {
356 u_int64_t adr;
357
358 sc->sc_pkhwp = 0;
359 sc->sc_pkhrp = 0;
360
361 adr = sc->sc_pkhmap->dm_segs[0].ds_addr;
362 NOCT_WRITE_4(sc, NOCT_PKH_Q_BASE_HI, (adr >> 32) & 0xffffffff);
363 NOCT_WRITE_4(sc, NOCT_PKH_Q_LEN, NOCT_PKH_QLEN);
364 NOCT_WRITE_4(sc, NOCT_PKH_Q_BASE_LO, (adr >> 0) & 0xffffffff);
365
366 NOCT_WRITE_4(sc, NOCT_PKH_IER,
367 PKHIER_CMDSI | PKHIER_SKSWR | PKHIER_SKSOFF | PKHIER_PKHLEN |
368 PKHIER_PKHOPCODE | PKHIER_BADQBASE | PKHIER_LOADERR |
369 PKHIER_STOREERR | PKHIER_CMDERR | PKHIER_ILL | PKHIER_PKERESV |
370 PKHIER_PKEWDT | PKHIER_PKENOTPRIME |
371 PKHIER_PKE_B | PKHIER_PKE_A | PKHIER_PKE_M | PKHIER_PKE_R |
372 PKHIER_PKEOPCODE);
373
374 NOCT_WRITE_4(sc, NOCT_PKH_CSR,
375 NOCT_READ_4(sc, NOCT_PKH_CSR) | PKHCSR_PKH_ENA);
376
377 NOCT_WRITE_4(sc, NOCT_BRDG_CTL,
378 NOCT_READ_4(sc, NOCT_BRDG_CTL) | BRDGCTL_PKIRQ_ENA);
379 }
380
381 void
noct_pkh_init(sc)382 noct_pkh_init(sc)
383 struct noct_softc *sc;
384 {
385 bus_dma_segment_t seg, bnseg;
386 int rseg, bnrseg;
387
388 sc->sc_pkh_bn = extent_create("noctbn", 0, 255, M_DEVBUF,
389 NULL, NULL, EX_NOWAIT | EX_NOCOALESCE);
390 if (sc->sc_pkh_bn == NULL) {
391 printf("%s: failed pkh bn extent\n", sc->sc_dv.dv_xname);
392 goto fail;
393 }
394
395 if (bus_dmamem_alloc(sc->sc_dmat, NOCT_PKH_BUFSIZE,
396 PAGE_SIZE, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) {
397 printf("%s: failed pkh buf alloc\n", sc->sc_dv.dv_xname);
398 goto fail;
399 }
400 if (bus_dmamem_map(sc->sc_dmat, &seg, rseg, NOCT_PKH_BUFSIZE,
401 (caddr_t *)&sc->sc_pkhcmd, BUS_DMA_NOWAIT)) {
402 printf("%s: failed pkh buf map\n", sc->sc_dv.dv_xname);
403 goto fail_1;
404 }
405 if (bus_dmamap_create(sc->sc_dmat, NOCT_PKH_BUFSIZE, rseg,
406 NOCT_PKH_BUFSIZE, 0, BUS_DMA_NOWAIT, &sc->sc_pkhmap)) {
407 printf("%s: failed pkh map create\n", sc->sc_dv.dv_xname);
408 goto fail_2;
409 }
410 if (bus_dmamap_load_raw(sc->sc_dmat, sc->sc_pkhmap,
411 &seg, rseg, NOCT_PKH_BUFSIZE, BUS_DMA_NOWAIT)) {
412 printf("%s: failed pkh buf load\n", sc->sc_dv.dv_xname);
413 goto fail_3;
414 }
415
416 /*
417 * Allocate shadow big number cache.
418 */
419 if (bus_dmamem_alloc(sc->sc_dmat, NOCT_BN_CACHE_SIZE, PAGE_SIZE, 0,
420 &bnseg, 1, &bnrseg, BUS_DMA_NOWAIT)) {
421 printf("%s: failed bnc buf alloc\n", sc->sc_dv.dv_xname);
422 goto fail_4;
423 }
424 if (bus_dmamem_map(sc->sc_dmat, &bnseg, bnrseg, NOCT_BN_CACHE_SIZE,
425 (caddr_t *)&sc->sc_bncache, BUS_DMA_NOWAIT)) {
426 printf("%s: failed bnc buf map\n", sc->sc_dv.dv_xname);
427 goto fail_5;
428 }
429 if (bus_dmamap_create(sc->sc_dmat, NOCT_BN_CACHE_SIZE, bnrseg,
430 NOCT_BN_CACHE_SIZE, 0, BUS_DMA_NOWAIT, &sc->sc_bnmap)) {
431 printf("%s: failed bnc map create\n", sc->sc_dv.dv_xname);
432 goto fail_6;
433 }
434 if (bus_dmamap_load_raw(sc->sc_dmat, sc->sc_bnmap,
435 &bnseg, bnrseg, NOCT_BN_CACHE_SIZE, BUS_DMA_NOWAIT)) {
436 printf("%s: failed bnc buf load\n", sc->sc_dv.dv_xname);
437 goto fail_7;
438 }
439
440 noct_pkh_disable(sc);
441 noct_pkh_enable(sc);
442
443 #if 0
444 /*
445 * XXX MODEXP is implemented as MODMUL for debugging, don't
446 * XXX actually register.
447 */
448 crypto_kregister(sc->sc_cid, CRK_MOD_EXP, 0, noct_kprocess);
449 printf(" PK");
450 #endif
451
452 return;
453
454 fail_7:
455 bus_dmamap_destroy(sc->sc_dmat, sc->sc_bnmap);
456 fail_6:
457 bus_dmamem_unmap(sc->sc_dmat,
458 (caddr_t)sc->sc_pkhcmd, NOCT_PKH_BUFSIZE);
459 fail_5:
460 bus_dmamem_free(sc->sc_dmat, &bnseg, bnrseg);
461 fail_4:
462 bus_dmamap_unload(sc->sc_dmat, sc->sc_pkhmap);
463 fail_3:
464 bus_dmamap_destroy(sc->sc_dmat, sc->sc_pkhmap);
465 fail_2:
466 bus_dmamem_unmap(sc->sc_dmat,
467 (caddr_t)sc->sc_pkhcmd, NOCT_PKH_BUFSIZE);
468 fail_1:
469 bus_dmamem_free(sc->sc_dmat, &seg, rseg);
470 fail:
471 if (sc->sc_pkh_bn != NULL) {
472 extent_destroy(sc->sc_pkh_bn);
473 sc->sc_pkh_bn = NULL;
474 }
475 sc->sc_pkhcmd = NULL;
476 sc->sc_pkhmap = NULL;
477 }
478
479 void
noct_pkh_intr(sc)480 noct_pkh_intr(sc)
481 struct noct_softc *sc;
482 {
483 u_int32_t csr;
484 u_int32_t rp;
485
486 csr = NOCT_READ_4(sc, NOCT_PKH_CSR);
487 NOCT_WRITE_4(sc, NOCT_PKH_CSR, csr |
488 PKHCSR_CMDSI | PKHCSR_SKSWR | PKHCSR_SKSOFF | PKHCSR_PKHLEN |
489 PKHCSR_PKHOPCODE | PKHCSR_BADQBASE | PKHCSR_LOADERR |
490 PKHCSR_STOREERR | PKHCSR_CMDERR | PKHCSR_ILL | PKHCSR_PKERESV |
491 PKHCSR_PKEWDT | PKHCSR_PKENOTPRIME |
492 PKHCSR_PKE_B | PKHCSR_PKE_A | PKHCSR_PKE_M | PKHCSR_PKE_R |
493 PKHCSR_PKEOPCODE);
494
495 rp = (NOCT_READ_4(sc, NOCT_PKH_Q_PTR) & PKHQPTR_READ_M) >>
496 PKHQPTR_READ_S;
497
498 while (sc->sc_pkhrp != rp) {
499 if (sc->sc_pkh_bnsw[sc->sc_pkhrp].bn_callback != NULL)
500 (*sc->sc_pkh_bnsw[sc->sc_pkhrp].bn_callback)(sc,
501 sc->sc_pkhrp, 0);
502 if (++sc->sc_pkhrp == NOCT_PKH_ENTRIES)
503 sc->sc_pkhrp = 0;
504 }
505 sc->sc_pkhrp = rp;
506
507 if (csr & PKHCSR_CMDSI) {
508 /* command completed */
509 }
510
511 if (csr & PKHCSR_SKSWR)
512 printf("%s:%x: sks write error\n", sc->sc_dv.dv_xname, rp);
513 if (csr & PKHCSR_SKSOFF)
514 printf("%s:%x: sks offset error\n", sc->sc_dv.dv_xname, rp);
515 if (csr & PKHCSR_PKHLEN)
516 printf("%s:%x: pkh invalid length\n", sc->sc_dv.dv_xname, rp);
517 if (csr & PKHCSR_PKHOPCODE)
518 printf("%s:%x: pkh bad opcode\n", sc->sc_dv.dv_xname, rp);
519 if (csr & PKHCSR_BADQBASE)
520 printf("%s:%x: pkh base qbase\n", sc->sc_dv.dv_xname, rp);
521 if (csr & PKHCSR_LOADERR)
522 printf("%s:%x: pkh load error\n", sc->sc_dv.dv_xname, rp);
523 if (csr & PKHCSR_STOREERR)
524 printf("%s:%x: pkh store error\n", sc->sc_dv.dv_xname, rp);
525 if (csr & PKHCSR_CMDERR)
526 printf("%s:%x: pkh command error\n", sc->sc_dv.dv_xname, rp);
527 if (csr & PKHCSR_ILL)
528 printf("%s:%x: pkh illegal access\n", sc->sc_dv.dv_xname, rp);
529 if (csr & PKHCSR_PKERESV)
530 printf("%s:%x: pke reserved error\n", sc->sc_dv.dv_xname, rp);
531 if (csr & PKHCSR_PKEWDT)
532 printf("%s:%x: pke watchdog\n", sc->sc_dv.dv_xname, rp);
533 if (csr & PKHCSR_PKENOTPRIME)
534 printf("%s:%x: pke not prime\n", sc->sc_dv.dv_xname, rp);
535 if (csr & PKHCSR_PKE_B)
536 printf("%s:%x: pke bad 'b'\n", sc->sc_dv.dv_xname, rp);
537 if (csr & PKHCSR_PKE_A)
538 printf("%s:%x: pke bad 'a'\n", sc->sc_dv.dv_xname, rp);
539 if (csr & PKHCSR_PKE_M)
540 printf("%s:%x: pke bad 'm'\n", sc->sc_dv.dv_xname, rp);
541 if (csr & PKHCSR_PKE_R)
542 printf("%s:%x: pke bad 'r'\n", sc->sc_dv.dv_xname, rp);
543 if (csr & PKHCSR_PKEOPCODE)
544 printf("%s:%x: pke bad opcode\n", sc->sc_dv.dv_xname, rp);
545 }
546
547 void
noct_rng_disable(sc)548 noct_rng_disable(sc)
549 struct noct_softc *sc;
550 {
551 u_int64_t csr;
552 u_int32_t r;
553
554 /* Turn off RN irq */
555 NOCT_WRITE_4(sc, NOCT_BRDG_CTL,
556 NOCT_READ_4(sc, NOCT_BRDG_CTL) & ~(BRDGCTL_RNIRQ_ENA));
557
558 /* Turn off RNH interrupts */
559 r = NOCT_READ_4(sc, NOCT_RNG_CSR);
560 r &= ~(RNGCSR_INT_KEY | RNGCSR_INT_DUP |
561 RNGCSR_INT_BUS | RNGCSR_INT_ACCESS);
562 NOCT_WRITE_4(sc, NOCT_RNG_CSR, r);
563
564 /* Turn off RN queue */
565 r = NOCT_READ_4(sc, NOCT_RNG_CSR);
566 r &= ~(RNGCSR_XFER_ENABLE | RNGCSR_INT_KEY | RNGCSR_INT_BUS |
567 RNGCSR_INT_DUP | RNGCSR_INT_ACCESS);
568 NOCT_WRITE_4(sc, NOCT_RNG_CSR, r);
569
570 for (;;) {
571 r = NOCT_READ_4(sc, NOCT_RNG_CSR);
572 if ((r & RNGCSR_XFER_BUSY) == 0)
573 break;
574 }
575
576 /* Turn off RN generator */
577 csr = NOCT_READ_8(sc, NOCT_RNG_CTL);
578 csr &= ~RNGCTL_RNG_ENA;
579 NOCT_WRITE_8(sc, NOCT_RNG_CTL, csr);
580 }
581
582 void
noct_rng_enable(sc)583 noct_rng_enable(sc)
584 struct noct_softc *sc;
585 {
586 u_int64_t adr;
587 u_int32_t r;
588
589 adr = sc->sc_rngmap->dm_segs[0].ds_addr;
590 NOCT_WRITE_4(sc, NOCT_RNG_Q_BASE_HI, (adr >> 32) & 0xffffffff);
591 NOCT_WRITE_4(sc, NOCT_RNG_Q_LEN, NOCT_RNG_QLEN);
592 NOCT_WRITE_4(sc, NOCT_RNG_Q_BASE_LO, (adr >> 0 ) & 0xffffffff);
593
594 NOCT_WRITE_8(sc, NOCT_RNG_CTL,
595 RNGCTL_RNG_ENA |
596 RNGCTL_TOD_ENA |
597 RNGCTL_BUFSRC_SEED |
598 RNGCTL_SEEDSRC_INT |
599 RNGCTL_EXTCLK_ENA |
600 RNGCTL_DIAG |
601 (100 & RNGCTL_ITERCNT));
602
603 /* Turn on interrupts and enable xfer */
604 r = RNGCSR_XFER_ENABLE | RNGCSR_INT_ACCESS |
605 RNGCSR_INT_KEY | RNGCSR_INT_BUS | RNGCSR_INT_DUP;
606 NOCT_WRITE_4(sc, NOCT_RNG_CSR, r);
607
608 /* Turn on bridge/rng interrupts */
609 r = NOCT_READ_4(sc, NOCT_BRDG_CTL);
610 r |= BRDGCTL_RNIRQ_ENA;
611 NOCT_WRITE_4(sc, NOCT_BRDG_CTL, r);
612 }
613
614 void
noct_rng_init(sc)615 noct_rng_init(sc)
616 struct noct_softc *sc;
617 {
618 bus_dma_segment_t seg;
619 int rseg;
620
621 if (bus_dmamem_alloc(sc->sc_dmat, NOCT_RNG_BUFSIZE,
622 PAGE_SIZE, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) {
623 printf("%s: failed rng buf alloc\n", sc->sc_dv.dv_xname);
624 goto fail;
625 }
626 if (bus_dmamem_map(sc->sc_dmat, &seg, rseg, NOCT_RNG_BUFSIZE,
627 (caddr_t *)&sc->sc_rngbuf, BUS_DMA_NOWAIT)) {
628 printf("%s: failed rng buf map\n", sc->sc_dv.dv_xname);
629 goto fail_1;
630 }
631 if (bus_dmamap_create(sc->sc_dmat, NOCT_RNG_BUFSIZE, rseg,
632 NOCT_RNG_BUFSIZE, 0, BUS_DMA_NOWAIT, &sc->sc_rngmap)) {
633 printf("%s: failed rng map create\n", sc->sc_dv.dv_xname);
634 goto fail_2;
635 }
636 if (bus_dmamap_load_raw(sc->sc_dmat, sc->sc_rngmap,
637 &seg, rseg, NOCT_RNG_BUFSIZE, BUS_DMA_NOWAIT)) {
638 printf("%s: failed rng buf load\n", sc->sc_dv.dv_xname);
639 goto fail_3;
640 }
641
642 noct_rng_disable(sc);
643 noct_rng_enable(sc);
644
645 printf(" RNG");
646
647 if (hz > 100)
648 sc->sc_rngtick = hz/100;
649 else
650 sc->sc_rngtick = 1;
651 timeout_set(&sc->sc_rngto, noct_rng_tick, sc);
652 timeout_add(&sc->sc_rngto, sc->sc_rngtick);
653
654 return;
655
656 fail_3:
657 bus_dmamap_destroy(sc->sc_dmat, sc->sc_rngmap);
658 fail_2:
659 bus_dmamem_unmap(sc->sc_dmat,
660 (caddr_t)sc->sc_rngbuf, NOCT_RNG_BUFSIZE);
661 fail_1:
662 bus_dmamem_free(sc->sc_dmat, &seg, rseg);
663 fail:
664 sc->sc_rngbuf = NULL;
665 sc->sc_rngmap = NULL;
666 }
667
668 void
noct_rng_intr(sc)669 noct_rng_intr(sc)
670 struct noct_softc *sc;
671 {
672 u_int32_t csr;
673 int enable = 1;
674
675 csr = NOCT_READ_4(sc, NOCT_RNG_CSR);
676 NOCT_WRITE_4(sc, NOCT_RNG_CSR, csr);
677
678 if (csr & RNGCSR_ERR_KEY) {
679 u_int32_t ctl;
680
681 enable = 0;
682 ctl = NOCT_READ_4(sc, NOCT_RNG_CTL);
683 printf("%s: rng bad key(s)", sc->sc_dv.dv_xname);
684 if (ctl & RNGCTL_KEY1PAR_ERR)
685 printf(", key1 parity");
686 if (ctl & RNGCTL_KEY2PAR_ERR)
687 printf(", key2 parity");
688 printf("\n");
689 }
690 if (csr & RNGCSR_ERR_BUS) {
691 enable = 0;
692 printf("%s: rng bus error\n", sc->sc_dv.dv_xname);
693 }
694 if (csr & RNGCSR_ERR_DUP) {
695 enable = 0;
696 printf("%s: rng duplicate block\n", sc->sc_dv.dv_xname);
697 }
698 if (csr & RNGCSR_ERR_ACCESS) {
699 enable = 0;
700 printf("%s: rng invalid access\n", sc->sc_dv.dv_xname);
701 }
702
703 if (!enable)
704 noct_rng_disable(sc);
705 }
706
707 void
noct_rng_tick(vsc)708 noct_rng_tick(vsc)
709 void *vsc;
710 {
711 struct noct_softc *sc = vsc;
712 u_int64_t val;
713 u_int32_t reg, rd, wr;
714 int cons = 0;
715
716 reg = NOCT_READ_4(sc, NOCT_RNG_Q_PTR);
717 rd = (reg & RNGQPTR_READ_M) >> RNGQPTR_READ_S;
718 wr = (reg & RNGQPTR_WRITE_M) >> RNGQPTR_WRITE_S;
719
720 while (rd != wr && cons < 32) {
721 val = sc->sc_rngbuf[rd];
722 add_true_randomness((val >> 32) & 0xffffffff);
723 add_true_randomness((val >> 0) & 0xffffffff);
724 if (++rd == NOCT_RNG_ENTRIES)
725 rd = 0;
726 cons++;
727 }
728
729 if (cons != 0)
730 NOCT_WRITE_4(sc, NOCT_RNG_Q_PTR, rd);
731 timeout_add(&sc->sc_rngto, sc->sc_rngtick);
732 }
733
734 u_int32_t
noct_ea_nfree(sc)735 noct_ea_nfree(sc)
736 struct noct_softc *sc;
737 {
738 if (sc->sc_eawp == sc->sc_earp)
739 return (NOCT_EA_ENTRIES);
740 if (sc->sc_eawp < sc->sc_earp)
741 return (sc->sc_earp - sc->sc_eawp - 1);
742 return (sc->sc_earp + NOCT_EA_ENTRIES - sc->sc_eawp - 1);
743 }
744
745 void
noct_ea_disable(sc)746 noct_ea_disable(sc)
747 struct noct_softc *sc;
748 {
749 u_int32_t r;
750
751 /* Turn off EA irq */
752 NOCT_WRITE_4(sc, NOCT_BRDG_CTL,
753 NOCT_READ_4(sc, NOCT_BRDG_CTL) & ~(BRDGCTL_EAIRQ_ENA));
754
755 /* Turn off EA interrupts */
756 r = NOCT_READ_4(sc, NOCT_EA_IER);
757 r &= ~(EAIER_QALIGN | EAIER_CMDCMPL | EAIER_OPERR | EAIER_CMDREAD |
758 EAIER_CMDWRITE | EAIER_DATAREAD | EAIER_DATAWRITE |
759 EAIER_INTRNLLEN | EAIER_EXTRNLLEN | EAIER_DESBLOCK |
760 EAIER_DESKEY | EAIER_ILL);
761 NOCT_WRITE_4(sc, NOCT_EA_IER, r);
762
763 /* Disable EA unit */
764 r = NOCT_READ_4(sc, NOCT_EA_CSR);
765 r &= ~EACSR_ENABLE;
766 NOCT_WRITE_4(sc, NOCT_EA_CSR, r);
767 for (;;) {
768 r = NOCT_READ_4(sc, NOCT_EA_CSR);
769 if ((r & EACSR_BUSY) == 0)
770 break;
771 }
772
773 /* Clear status bits */
774 r = NOCT_READ_4(sc, NOCT_EA_CSR);
775 r |= EACSR_QALIGN | EACSR_CMDCMPL | EACSR_OPERR | EACSR_CMDREAD |
776 EACSR_CMDWRITE | EACSR_DATAREAD | EACSR_DATAWRITE |
777 EACSR_INTRNLLEN | EACSR_EXTRNLLEN | EACSR_DESBLOCK |
778 EACSR_DESKEY | EACSR_ILL;
779 NOCT_WRITE_4(sc, NOCT_EA_CSR, r);
780 }
781
782 void
noct_ea_enable(sc)783 noct_ea_enable(sc)
784 struct noct_softc *sc;
785 {
786 u_int64_t adr;
787
788 sc->sc_eawp = 0;
789 sc->sc_earp = 0;
790
791 adr = sc->sc_eamap->dm_segs[0].ds_addr;
792 NOCT_WRITE_4(sc, NOCT_EA_Q_BASE_HI, (adr >> 32) & 0xffffffff);
793 NOCT_WRITE_4(sc, NOCT_EA_Q_LEN, NOCT_EA_QLEN);
794 NOCT_WRITE_4(sc, NOCT_EA_Q_BASE_LO, (adr >> 0) & 0xffffffff);
795
796 NOCT_WRITE_4(sc, NOCT_EA_IER,
797 EAIER_QALIGN | EAIER_CMDCMPL | EAIER_OPERR | EAIER_CMDREAD |
798 EAIER_CMDWRITE | EAIER_DATAREAD | EAIER_DATAWRITE |
799 EAIER_INTRNLLEN | EAIER_EXTRNLLEN | EAIER_DESBLOCK |
800 EAIER_DESKEY | EAIER_ILL);
801
802 NOCT_WRITE_4(sc, NOCT_EA_CSR,
803 NOCT_READ_4(sc, NOCT_EA_CSR) | EACSR_ENABLE);
804
805 NOCT_WRITE_4(sc, NOCT_BRDG_CTL,
806 NOCT_READ_4(sc, NOCT_BRDG_CTL) | BRDGCTL_EAIRQ_ENA);
807 }
808
809 void
noct_ea_init(sc)810 noct_ea_init(sc)
811 struct noct_softc *sc;
812 {
813 bus_dma_segment_t seg;
814 int rseg, algs[CRYPTO_ALGORITHM_MAX + 1];
815
816 if (bus_dmamem_alloc(sc->sc_dmat, NOCT_EA_BUFSIZE,
817 PAGE_SIZE, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) {
818 printf("%s: failed ea buf alloc\n", sc->sc_dv.dv_xname);
819 goto fail;
820 }
821 if (bus_dmamem_map(sc->sc_dmat, &seg, rseg, NOCT_EA_BUFSIZE,
822 (caddr_t *)&sc->sc_eacmd, BUS_DMA_NOWAIT)) {
823 printf("%s: failed ea buf map\n", sc->sc_dv.dv_xname);
824 goto fail_1;
825 }
826 if (bus_dmamap_create(sc->sc_dmat, NOCT_EA_BUFSIZE, rseg,
827 NOCT_EA_BUFSIZE, 0, BUS_DMA_NOWAIT, &sc->sc_eamap)) {
828 printf("%s: failed ea map create\n", sc->sc_dv.dv_xname);
829 goto fail_2;
830 }
831 if (bus_dmamap_load_raw(sc->sc_dmat, sc->sc_eamap,
832 &seg, rseg, NOCT_EA_BUFSIZE, BUS_DMA_NOWAIT)) {
833 printf("%s: failed ea buf load\n", sc->sc_dv.dv_xname);
834 goto fail_3;
835 }
836
837 noct_ea_disable(sc);
838 noct_ea_enable(sc);
839
840 SIMPLEQ_INIT(&sc->sc_inq);
841 SIMPLEQ_INIT(&sc->sc_chipq);
842 SIMPLEQ_INIT(&sc->sc_outq);
843
844 bzero(algs, sizeof(algs));
845
846 algs[CRYPTO_MD5] = CRYPTO_ALG_FLAG_SUPPORTED;
847 algs[CRYPTO_SHA1] = CRYPTO_ALG_FLAG_SUPPORTED;
848 algs[CRYPTO_DES_CBC] = CRYPTO_ALG_FLAG_SUPPORTED;
849 algs[CRYPTO_3DES_CBC] = CRYPTO_ALG_FLAG_SUPPORTED;
850
851 crypto_register(sc->sc_cid, algs,
852 noct_newsession, noct_freesession, noct_process);
853 printf(" MD5 SHA1 3DES");
854
855 kthread_create_deferred(noct_ea_create_thread, sc);
856
857 return;
858
859 fail_3:
860 bus_dmamap_destroy(sc->sc_dmat, sc->sc_eamap);
861 fail_2:
862 bus_dmamem_unmap(sc->sc_dmat,
863 (caddr_t)sc->sc_eacmd, NOCT_EA_BUFSIZE);
864 fail_1:
865 bus_dmamem_free(sc->sc_dmat, &seg, rseg);
866 fail:
867 sc->sc_eacmd = NULL;
868 sc->sc_eamap = NULL;
869 }
870
871 void
noct_ea_create_thread(vsc)872 noct_ea_create_thread(vsc)
873 void *vsc;
874 {
875 struct noct_softc *sc = vsc;
876
877 if (kthread_create(noct_ea_thread, sc, NULL,
878 "%s", sc->sc_dv.dv_xname))
879 panic("%s: unable to create ea thread", sc->sc_dv.dv_xname);
880 }
881
882 void
noct_ea_thread(vsc)883 noct_ea_thread(vsc)
884 void *vsc;
885 {
886 struct noct_softc *sc = vsc;
887 struct noct_workq *q;
888 struct cryptop *crp;
889 struct cryptodesc *crd;
890 int s, rseg;
891 u_int32_t len;
892
893 for (;;) {
894 tsleep(&sc->sc_eawp, PWAIT, "noctea", 0);
895
896 /* Handle output queue */
897 s = splnet();
898 while (!SIMPLEQ_EMPTY(&sc->sc_outq)) {
899 q = SIMPLEQ_FIRST(&sc->sc_outq);
900 SIMPLEQ_REMOVE_HEAD(&sc->sc_outq, q_next);
901 splx(s);
902
903 crp = q->q_crp;
904 crd = crp->crp_desc;
905 switch (crd->crd_alg) {
906 case CRYPTO_MD5:
907 len = 16;
908 break;
909 case CRYPTO_SHA1:
910 len = 20;
911 break;
912 default:
913 len = 0;
914 break;
915 }
916
917 bus_dmamap_sync(sc->sc_dmat, q->q_dmamap,
918 0, q->q_dmamap->dm_mapsize,
919 BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
920
921 if (len != 0) {
922 if (crp->crp_flags & CRYPTO_F_IMBUF)
923 m_copyback((struct mbuf *)crp->crp_buf,
924 crd->crd_inject, len,
925 q->q_macbuf);
926 else if (crp->crp_flags & CRYPTO_F_IOV)
927 bcopy(q->q_macbuf, crp->crp_mac, len);
928 }
929
930 if (crd->crd_alg == CRYPTO_DES_CBC ||
931 crd->crd_alg == CRYPTO_3DES_CBC) {
932 if (crp->crp_flags & CRYPTO_F_IMBUF)
933 m_copyback((struct mbuf *)crp->crp_buf,
934 crd->crd_skip, crd->crd_len,
935 q->q_buf);
936 else if (crp->crp_flags & CRYPTO_F_IOV)
937 cuio_copyback((struct uio *)crp->crp_buf,
938 crd->crd_skip, crd->crd_len,
939 q->q_buf);
940 }
941
942 bus_dmamap_unload(sc->sc_dmat, q->q_dmamap);
943 bus_dmamap_destroy(sc->sc_dmat, q->q_dmamap);
944 bus_dmamem_unmap(sc->sc_dmat, q->q_buf, crd->crd_len);
945 bus_dmamem_free(sc->sc_dmat, &q->q_dmaseg, rseg);
946 crp->crp_etype = 0;
947 free(q, M_DEVBUF);
948 s = splnet();
949 crypto_done(crp);
950 }
951 splx(s);
952
953 /* Handle input queue */
954 s = splnet();
955 while (!SIMPLEQ_EMPTY(&sc->sc_inq)) {
956 q = SIMPLEQ_FIRST(&sc->sc_inq);
957 SIMPLEQ_REMOVE_HEAD(&sc->sc_inq, q_next);
958 splx(s);
959
960 noct_ea_start(sc, q);
961 s = splnet();
962 }
963 splx(s);
964 }
965 }
966
967 void
noct_ea_start(sc,q)968 noct_ea_start(sc, q)
969 struct noct_softc *sc;
970 struct noct_workq *q;
971 {
972 struct cryptop *crp;
973 struct cryptodesc *crd;
974 int s, err;
975
976 crp = q->q_crp;
977 crd = crp->crp_desc;
978
979 /* XXX Can't handle multiple ops yet */
980 if (crd->crd_next != NULL) {
981 err = EOPNOTSUPP;
982 goto errout;
983 }
984
985 switch (crd->crd_alg) {
986 case CRYPTO_MD5:
987 case CRYPTO_SHA1:
988 noct_ea_start_hash(sc, q, crp, crd);
989 break;
990 case CRYPTO_DES_CBC:
991 case CRYPTO_3DES_CBC:
992 noct_ea_start_des(sc, q, crp, crd);
993 break;
994 default:
995 err = EOPNOTSUPP;
996 goto errout;
997 }
998
999 return;
1000
1001 errout:
1002 crp->crp_etype = err;
1003 free(q, M_DEVBUF);
1004 s = splnet();
1005 crypto_done(crp);
1006 splx(s);
1007 }
1008
1009 void
noct_ea_start_hash(sc,q,crp,crd)1010 noct_ea_start_hash(sc, q, crp, crd)
1011 struct noct_softc *sc;
1012 struct noct_workq *q;
1013 struct cryptop *crp;
1014 struct cryptodesc *crd;
1015 {
1016 u_int64_t adr;
1017 int s, err, i, rseg;
1018 u_int32_t wp;
1019
1020 if (crd->crd_len > 0x4800) {
1021 err = ERANGE;
1022 goto errout;
1023 }
1024
1025 if ((err = bus_dmamem_alloc(sc->sc_dmat, crd->crd_len, PAGE_SIZE, 0,
1026 &q->q_dmaseg, 1, &rseg, BUS_DMA_WAITOK | BUS_DMA_STREAMING)) != 0)
1027 goto errout;
1028
1029 if ((err = bus_dmamem_map(sc->sc_dmat, &q->q_dmaseg, rseg,
1030 crd->crd_len, (caddr_t *)&q->q_buf, BUS_DMA_WAITOK)) != 0)
1031 goto errout_dmafree;
1032
1033 if ((err = bus_dmamap_create(sc->sc_dmat, crd->crd_len, 1,
1034 crd->crd_len, 0, BUS_DMA_WAITOK, &q->q_dmamap)) != 0)
1035 goto errout_dmaunmap;
1036
1037 if ((err = bus_dmamap_load_raw(sc->sc_dmat, q->q_dmamap, &q->q_dmaseg,
1038 rseg, crd->crd_len, BUS_DMA_WAITOK)) != 0)
1039 goto errout_dmadestroy;
1040
1041 if (crp->crp_flags & CRYPTO_F_IMBUF)
1042 m_copydata((struct mbuf *)crp->crp_buf,
1043 crd->crd_skip, crd->crd_len, q->q_buf);
1044 else if (crp->crp_flags & CRYPTO_F_IOV)
1045 cuio_copydata((struct uio *)crp->crp_buf,
1046 crd->crd_skip, crd->crd_len, q->q_buf);
1047 else {
1048 err = EINVAL;
1049 goto errout_dmaunload;
1050 }
1051
1052 bus_dmamap_sync(sc->sc_dmat, q->q_dmamap, 0, q->q_dmamap->dm_mapsize,
1053 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1054
1055 s = splnet();
1056 if (noct_ea_nfree(sc) < 1) {
1057 err = ENOMEM;
1058 goto errout_dmaunload;
1059 }
1060 wp = sc->sc_eawp;
1061 if (++sc->sc_eawp == NOCT_EA_ENTRIES)
1062 sc->sc_eawp = 0;
1063 for (i = 0; i < EA_CMD_WORDS; i++)
1064 sc->sc_eacmd[wp].buf[i] = 0;
1065 sc->sc_eacmd[wp].buf[0] = EA_0_SI;
1066 switch (crd->crd_alg) {
1067 case CRYPTO_MD5:
1068 sc->sc_eacmd[wp].buf[1] = htole32(EA_OP_MD5);
1069 break;
1070 case CRYPTO_SHA1:
1071 sc->sc_eacmd[wp].buf[1] = htole32(EA_OP_SHA1);
1072 break;
1073 }
1074
1075 /* Source, new buffer just allocated */
1076 sc->sc_eacmd[wp].buf[1] |= htole32(crd->crd_len);
1077 adr = q->q_dmamap->dm_segs[0].ds_addr;
1078 sc->sc_eacmd[wp].buf[2] = htole32(adr >> 32);
1079 sc->sc_eacmd[wp].buf[3] = htole32(adr & 0xffffffff);
1080
1081 /* Dest, hide it in the descriptor */
1082 adr = sc->sc_eamap->dm_segs[0].ds_addr +
1083 (wp * sizeof(struct noct_ea_cmd)) +
1084 offsetof(struct noct_ea_cmd, buf[6]);
1085 sc->sc_eacmd[wp].buf[4] = htole32(adr >> 32);
1086 sc->sc_eacmd[wp].buf[5] = htole32(adr & 0xffffffff);
1087
1088 bus_dmamap_sync(sc->sc_dmat, sc->sc_eamap,
1089 (wp * sizeof(struct noct_ea_cmd)), sizeof(struct noct_ea_cmd),
1090 BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
1091
1092 if (++wp == NOCT_EA_ENTRIES)
1093 wp = 0;
1094 NOCT_WRITE_4(sc, NOCT_EA_Q_PTR, wp);
1095 sc->sc_eawp = wp;
1096
1097 SIMPLEQ_INSERT_TAIL(&sc->sc_chipq, q, q_next);
1098 splx(s);
1099
1100 return;
1101
1102 errout_dmaunload:
1103 bus_dmamap_unload(sc->sc_dmat, q->q_dmamap);
1104 errout_dmadestroy:
1105 bus_dmamap_destroy(sc->sc_dmat, q->q_dmamap);
1106 errout_dmaunmap:
1107 bus_dmamem_unmap(sc->sc_dmat, q->q_buf, crd->crd_len);
1108 errout_dmafree:
1109 bus_dmamem_free(sc->sc_dmat, &q->q_dmaseg, rseg);
1110 errout:
1111 crp->crp_etype = err;
1112 free(q, M_DEVBUF);
1113 s = splnet();
1114 crypto_done(crp);
1115 splx(s);
1116 }
1117
1118 void
noct_ea_start_des(sc,q,crp,crd)1119 noct_ea_start_des(sc, q, crp, crd)
1120 struct noct_softc *sc;
1121 struct noct_workq *q;
1122 struct cryptop *crp;
1123 struct cryptodesc *crd;
1124 {
1125 u_int64_t adr;
1126 volatile u_int8_t *pb;
1127 int s, err, i, rseg;
1128 u_int32_t wp;
1129 u_int8_t iv[8], key[24];
1130
1131 if (crd->crd_len > 0x4800) {
1132 err = ERANGE;
1133 goto errout;
1134 }
1135
1136 if ((crd->crd_len & 3) != 0) {
1137 err = ERANGE;
1138 goto errout;
1139 }
1140
1141 if (crd->crd_alg == CRYPTO_DES_CBC) {
1142 for (i = 0; i < 8; i++)
1143 key[i] = key[i + 8] = key[i + 16] = crd->crd_key[i];
1144 } else {
1145 for (i = 0; i < 24; i++)
1146 key[i] = crd->crd_key[i];
1147 }
1148
1149 if (crd->crd_flags & CRD_F_ENCRYPT) {
1150 if (crd->crd_flags & CRD_F_IV_EXPLICIT)
1151 bcopy(crd->crd_iv, iv, 8);
1152 else
1153 get_random_bytes(iv, sizeof(iv));
1154
1155 if (!(crd->crd_flags & CRD_F_IV_PRESENT)) {
1156 if (crp->crp_flags & CRYPTO_F_IMBUF)
1157 m_copyback((struct mbuf *)crp->crp_buf,
1158 crd->crd_inject, 8, iv);
1159 else if (crp->crp_flags & CRYPTO_F_IOV)
1160 cuio_copyback((struct uio *)crp->crp_buf,
1161 crd->crd_inject, 8, iv);
1162 }
1163 } else {
1164 if (crd->crd_flags & CRD_F_IV_EXPLICIT)
1165 bcopy(crd->crd_iv, iv, 8);
1166 else if (crp->crp_flags & CRYPTO_F_IMBUF)
1167 m_copydata((struct mbuf *)crp->crp_buf,
1168 crd->crd_inject, 8, iv);
1169 else if (crp->crp_flags & CRYPTO_F_IOV)
1170 cuio_copydata((struct uio *)crp->crp_buf,
1171 crd->crd_inject, 8, iv);
1172 }
1173
1174 if ((err = bus_dmamem_alloc(sc->sc_dmat, crd->crd_len, PAGE_SIZE, 0,
1175 &q->q_dmaseg, 1, &rseg, BUS_DMA_WAITOK | BUS_DMA_STREAMING)) != 0)
1176 goto errout;
1177
1178 if ((err = bus_dmamem_map(sc->sc_dmat, &q->q_dmaseg, rseg,
1179 crd->crd_len, (caddr_t *)&q->q_buf, BUS_DMA_WAITOK)) != 0)
1180 goto errout_dmafree;
1181
1182 if ((err = bus_dmamap_create(sc->sc_dmat, crd->crd_len, 1,
1183 crd->crd_len, 0, BUS_DMA_WAITOK, &q->q_dmamap)) != 0)
1184 goto errout_dmaunmap;
1185
1186 if ((err = bus_dmamap_load_raw(sc->sc_dmat, q->q_dmamap, &q->q_dmaseg,
1187 rseg, crd->crd_len, BUS_DMA_WAITOK)) != 0)
1188 goto errout_dmadestroy;
1189
1190 if (crp->crp_flags & CRYPTO_F_IMBUF)
1191 m_copydata((struct mbuf *)crp->crp_buf,
1192 crd->crd_skip, crd->crd_len, q->q_buf);
1193 else if (crp->crp_flags & CRYPTO_F_IOV)
1194 cuio_copydata((struct uio *)crp->crp_buf,
1195 crd->crd_skip, crd->crd_len, q->q_buf);
1196 else {
1197 err = EINVAL;
1198 goto errout_dmaunload;
1199 }
1200
1201 bus_dmamap_sync(sc->sc_dmat, q->q_dmamap, 0, q->q_dmamap->dm_mapsize,
1202 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1203
1204 s = splnet();
1205 if (noct_ea_nfree(sc) < 1) {
1206 err = ENOMEM;
1207 goto errout_dmaunload;
1208 }
1209 wp = sc->sc_eawp;
1210 if (++sc->sc_eawp == NOCT_EA_ENTRIES)
1211 sc->sc_eawp = 0;
1212
1213 for (i = 0; i < EA_CMD_WORDS; i++)
1214 sc->sc_eacmd[wp].buf[i] = 0;
1215
1216 sc->sc_eacmd[wp].buf[0] = EA_0_SI;
1217
1218 if (crd->crd_flags & CRD_F_ENCRYPT)
1219 sc->sc_eacmd[wp].buf[1] = htole32(EA_OP_3DESCBCE);
1220 else
1221 sc->sc_eacmd[wp].buf[1] = htole32(EA_OP_3DESCBCD);
1222
1223 /* Source, new buffer just allocated */
1224 sc->sc_eacmd[wp].buf[1] |= htole32(crd->crd_len);
1225 adr = q->q_dmamap->dm_segs[0].ds_addr;
1226 sc->sc_eacmd[wp].buf[2] = htole32(adr >> 32);
1227 sc->sc_eacmd[wp].buf[3] = htole32(adr & 0xffffffff);
1228
1229 /* Dest, same as source. */
1230 sc->sc_eacmd[wp].buf[4] = htole32(adr >> 32);
1231 sc->sc_eacmd[wp].buf[5] = htole32(adr & 0xffffffff);
1232
1233 /* IV and key */
1234 pb = (volatile u_int8_t *)&sc->sc_eacmd[wp].buf[20];
1235 for (i = 0; i < 8; i++)
1236 pb[i] = iv[i];
1237 SWAP32(sc->sc_eacmd[wp].buf[20]);
1238 SWAP32(sc->sc_eacmd[wp].buf[21]);
1239 pb = (volatile u_int8_t *)&sc->sc_eacmd[wp].buf[24];
1240 for (i = 0; i < 24; i++)
1241 pb[i] = key[i];
1242 SWAP32(sc->sc_eacmd[wp].buf[24]);
1243 SWAP32(sc->sc_eacmd[wp].buf[25]);
1244 SWAP32(sc->sc_eacmd[wp].buf[26]);
1245 SWAP32(sc->sc_eacmd[wp].buf[27]);
1246 SWAP32(sc->sc_eacmd[wp].buf[28]);
1247 SWAP32(sc->sc_eacmd[wp].buf[29]);
1248
1249 bus_dmamap_sync(sc->sc_dmat, sc->sc_eamap,
1250 (wp * sizeof(struct noct_ea_cmd)), sizeof(struct noct_ea_cmd),
1251 BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
1252
1253 if (++wp == NOCT_EA_ENTRIES)
1254 wp = 0;
1255 NOCT_WRITE_4(sc, NOCT_EA_Q_PTR, wp);
1256 sc->sc_eawp = wp;
1257
1258 SIMPLEQ_INSERT_TAIL(&sc->sc_chipq, q, q_next);
1259 splx(s);
1260
1261 return;
1262
1263 errout_dmaunload:
1264 bus_dmamap_unload(sc->sc_dmat, q->q_dmamap);
1265 errout_dmadestroy:
1266 bus_dmamap_destroy(sc->sc_dmat, q->q_dmamap);
1267 errout_dmaunmap:
1268 bus_dmamem_unmap(sc->sc_dmat, q->q_buf, crd->crd_len);
1269 errout_dmafree:
1270 bus_dmamem_free(sc->sc_dmat, &q->q_dmaseg, rseg);
1271 errout:
1272 crp->crp_etype = err;
1273 free(q, M_DEVBUF);
1274 s = splnet();
1275 crypto_done(crp);
1276 splx(s);
1277 }
1278
1279 void
noct_ea_intr(sc)1280 noct_ea_intr(sc)
1281 struct noct_softc *sc;
1282 {
1283 struct noct_workq *q;
1284 u_int32_t csr, rp;
1285
1286 csr = NOCT_READ_4(sc, NOCT_EA_CSR);
1287 NOCT_WRITE_4(sc, NOCT_EA_CSR, csr |
1288 EACSR_QALIGN | EACSR_CMDCMPL | EACSR_OPERR | EACSR_CMDREAD |
1289 EACSR_CMDWRITE | EACSR_DATAREAD | EACSR_DATAWRITE |
1290 EACSR_INTRNLLEN | EACSR_EXTRNLLEN | EACSR_DESBLOCK |
1291 EACSR_DESKEY | EACSR_ILL);
1292
1293 rp = (NOCT_READ_4(sc, NOCT_EA_Q_PTR) & EAQPTR_READ_M) >>
1294 EAQPTR_READ_S;
1295 while (sc->sc_earp != rp) {
1296 if (SIMPLEQ_EMPTY(&sc->sc_chipq))
1297 panic("%s: empty chipq", sc->sc_dv.dv_xname);
1298 q = SIMPLEQ_FIRST(&sc->sc_chipq);
1299 SIMPLEQ_REMOVE_HEAD(&sc->sc_chipq, q_next);
1300 SIMPLEQ_INSERT_TAIL(&sc->sc_outq, q, q_next);
1301
1302 bus_dmamap_sync(sc->sc_dmat, sc->sc_eamap,
1303 (sc->sc_earp * sizeof(struct noct_ea_cmd)),
1304 sizeof(struct noct_ea_cmd),
1305 BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
1306 bcopy((u_int8_t *)&sc->sc_eacmd[sc->sc_earp].buf[6],
1307 q->q_macbuf, 20);
1308
1309 NOCT_WAKEUP(sc);
1310 if (++sc->sc_earp == NOCT_EA_ENTRIES)
1311 sc->sc_earp = 0;
1312 }
1313 sc->sc_earp = rp;
1314
1315 if (csr & EACSR_QALIGN)
1316 printf("%s: ea bad queue alignment\n", sc->sc_dv.dv_xname);
1317 if (csr & EACSR_OPERR)
1318 printf("%s: ea bad opcode\n", sc->sc_dv.dv_xname);
1319 if (csr & EACSR_CMDREAD)
1320 printf("%s: ea command read error\n", sc->sc_dv.dv_xname);
1321 if (csr & EACSR_CMDWRITE)
1322 printf("%s: ea command write error\n", sc->sc_dv.dv_xname);
1323 if (csr & EACSR_DATAREAD)
1324 printf("%s: ea data read error\n", sc->sc_dv.dv_xname);
1325 if (csr & EACSR_DATAWRITE)
1326 printf("%s: ea data write error\n", sc->sc_dv.dv_xname);
1327 if (csr & EACSR_INTRNLLEN)
1328 printf("%s: ea bad internal len\n", sc->sc_dv.dv_xname);
1329 if (csr & EACSR_EXTRNLLEN)
1330 printf("%s: ea bad external len\n", sc->sc_dv.dv_xname);
1331 if (csr & EACSR_DESBLOCK)
1332 printf("%s: ea bad des block\n", sc->sc_dv.dv_xname);
1333 if (csr & EACSR_DESKEY)
1334 printf("%s: ea bad des key\n", sc->sc_dv.dv_xname);
1335 if (csr & EACSR_ILL)
1336 printf("%s: ea illegal access\n", sc->sc_dv.dv_xname);
1337 }
1338
1339 void
noct_write_8(sc,reg,val)1340 noct_write_8(sc, reg, val)
1341 struct noct_softc *sc;
1342 u_int32_t reg;
1343 u_int64_t val;
1344 {
1345 NOCT_WRITE_4(sc, reg, (val >> 32) & 0xffffffff);
1346 NOCT_WRITE_4(sc, reg + 4, (val >> 0) & 0xffffffff);
1347 }
1348
1349 u_int64_t
noct_read_8(sc,reg)1350 noct_read_8(sc, reg)
1351 struct noct_softc *sc;
1352 u_int32_t reg;
1353 {
1354 u_int64_t ret;
1355
1356 ret = NOCT_READ_4(sc, reg);
1357 ret <<= 32;
1358 ret |= NOCT_READ_4(sc, reg + 4);
1359 return (ret);
1360 }
1361
1362 /*
1363 * NSP2000 is has a nifty bug, writes or reads to consecutive addresses
1364 * can be coalesced by a PCI bridge and executed as a burst read or write
1365 * which NSP2000's AMBA bridge doesn't grok. Avoid the hazard.
1366 */
1367 u_int32_t
noct_read_4(sc,off)1368 noct_read_4(sc, off)
1369 struct noct_softc *sc;
1370 bus_size_t off;
1371 {
1372 if (sc->sc_rar_last == off - 4 ||
1373 sc->sc_rar_last == off + 4) {
1374 bus_space_write_4(sc->sc_st, sc->sc_sh, NOCT_BRDG_TEST, 0);
1375 sc->sc_rar_last = off;
1376 sc->sc_waw_last = 0xffffffff;
1377 }
1378 return (bus_space_read_4(sc->sc_st, sc->sc_sh, off));
1379 }
1380
1381 void
noct_write_4(sc,off,val)1382 noct_write_4(sc, off, val)
1383 struct noct_softc *sc;
1384 bus_size_t off;
1385 u_int32_t val;
1386 {
1387 if (sc->sc_waw_last == off - 4 ||
1388 sc->sc_waw_last == off + 4) {
1389 bus_space_read_4(sc->sc_st, sc->sc_sh, NOCT_BRDG_TEST);
1390 sc->sc_waw_last = off;
1391 sc->sc_rar_last = 0xffffffff;
1392 }
1393 bus_space_write_4(sc->sc_st, sc->sc_sh, off, val);
1394 }
1395
1396 struct noct_softc *
noct_kfind(krp)1397 noct_kfind(krp)
1398 struct cryptkop *krp;
1399 {
1400 struct noct_softc *sc;
1401 int i;
1402
1403 for (i = 0; i < noct_cd.cd_ndevs; i++) {
1404 sc = noct_cd.cd_devs[i];
1405 if (sc == NULL)
1406 continue;
1407 if (sc->sc_cid == krp->krp_hid)
1408 return (sc);
1409 }
1410 return (NULL);
1411 }
1412
1413 int
noct_kprocess(krp)1414 noct_kprocess(krp)
1415 struct cryptkop *krp;
1416 {
1417 struct noct_softc *sc;
1418
1419 if (krp == NULL || krp->krp_callback == NULL)
1420 return (EINVAL);
1421 if ((sc = noct_kfind(krp)) == NULL) {
1422 krp->krp_status = EINVAL;
1423 crypto_kdone(krp);
1424 return (0);
1425 }
1426
1427 switch (krp->krp_op) {
1428 case CRK_MOD_EXP:
1429 noct_kprocess_modexp(sc, krp);
1430 break;
1431 default:
1432 printf("%s: kprocess: invalid op 0x%x\n",
1433 sc->sc_dv.dv_xname, krp->krp_op);
1434 krp->krp_status = EOPNOTSUPP;
1435 crypto_kdone(krp);
1436 break;
1437 }
1438 return (0);
1439 }
1440
1441 u_int32_t
noct_pkh_nfree(sc)1442 noct_pkh_nfree(sc)
1443 struct noct_softc *sc;
1444 {
1445 if (sc->sc_pkhwp == sc->sc_pkhrp)
1446 return (NOCT_PKH_ENTRIES);
1447 if (sc->sc_pkhwp < sc->sc_pkhrp)
1448 return (sc->sc_pkhrp - sc->sc_pkhwp - 1);
1449 return (sc->sc_pkhrp + NOCT_PKH_ENTRIES - sc->sc_pkhwp - 1);
1450 }
1451
1452 int
noct_kprocess_modexp(sc,krp)1453 noct_kprocess_modexp(sc, krp)
1454 struct noct_softc *sc;
1455 struct cryptkop *krp;
1456 {
1457 int s, err;
1458 u_int32_t wp, aidx, bidx, midx;
1459 u_int64_t adr;
1460 union noct_pkh_cmd *cmd;
1461 int i, bits, mbits, digits, rmodidx, mmulidx;
1462
1463 s = splnet();
1464 if (noct_pkh_nfree(sc) < 7) {
1465 /* Need 7 entries: 3 loads, 1 store, 3 ops */
1466 splx(s);
1467 return (ENOMEM);
1468 }
1469
1470 /* Load M */
1471 midx = wp = sc->sc_pkhwp;
1472 mbits = bits = noct_ksigbits(&krp->krp_param[2]);
1473 if (bits > 4096) {
1474 err = ERANGE;
1475 goto errout;
1476 }
1477 sc->sc_pkh_bnsw[midx].bn_siz = (bits + 127) / 128;
1478 if (extent_alloc(sc->sc_pkh_bn, sc->sc_pkh_bnsw[midx].bn_siz,
1479 EX_NOALIGN, 0, EX_NOBOUNDARY, EX_NOWAIT,
1480 &sc->sc_pkh_bnsw[midx].bn_off)) {
1481 err = ENOMEM;
1482 goto errout;
1483 }
1484 cmd = &sc->sc_pkhcmd[midx];
1485 cmd->cache.op = htole32(PKH_OP_CODE_LOAD);
1486 cmd->cache.r = htole32(sc->sc_pkh_bnsw[midx].bn_off);
1487 adr = sc->sc_bnmap->dm_segs[0].ds_addr +
1488 (sc->sc_pkh_bnsw[midx].bn_off * 16);
1489 cmd->cache.addrhi = htole32((adr >> 32) & 0xffffffff);
1490 cmd->cache.addrlo = htole32((adr >> 0 ) & 0xffffffff);
1491 cmd->cache.len = htole32(sc->sc_pkh_bnsw[midx].bn_siz);
1492 cmd->cache.unused[0] = cmd->cache.unused[1] = cmd->cache.unused[2] = 0;
1493 bus_dmamap_sync(sc->sc_dmat, sc->sc_pkhmap,
1494 midx * sizeof(union noct_pkh_cmd), sizeof(union noct_pkh_cmd),
1495 BUS_DMASYNC_PREWRITE);
1496 for (i = 0; i < (digits * 16); i++)
1497 sc->sc_bncache[(sc->sc_pkh_bnsw[midx].bn_off * 16) + i] = 0;
1498 for (i = 0; i < ((bits + 7) / 8); i++)
1499 sc->sc_bncache[(sc->sc_pkh_bnsw[midx].bn_off * 16) +
1500 (digits * 16) - 1 - i] = krp->krp_param[2].crp_p[i];
1501 bus_dmamap_sync(sc->sc_dmat, sc->sc_bnmap,
1502 sc->sc_pkh_bnsw[midx].bn_off * 16, digits * 16,
1503 BUS_DMASYNC_PREWRITE);
1504 if (++wp == NOCT_PKH_ENTRIES)
1505 wp = 0;
1506
1507 /* Store RMOD(m) -> location tmp1 */
1508 rmodidx = wp;
1509 sc->sc_pkh_bnsw[rmodidx].bn_siz = sc->sc_pkh_bnsw[midx].bn_siz;
1510 if (extent_alloc(sc->sc_pkh_bn, sc->sc_pkh_bnsw[rmodidx].bn_siz,
1511 EX_NOALIGN, 0, EX_NOBOUNDARY, EX_NOWAIT,
1512 &sc->sc_pkh_bnsw[rmodidx].bn_off)) {
1513 err = ENOMEM;
1514 goto errout_m;
1515 }
1516 cmd = &sc->sc_pkhcmd[rmodidx];
1517 cmd->arith.op = htole32(PKH_OP_CODE_RMOD);
1518 cmd->arith.r = htole32(sc->sc_pkh_bnsw[rmodidx].bn_off);
1519 cmd->arith.m = htole32(sc->sc_pkh_bnsw[midx].bn_off |
1520 (sc->sc_pkh_bnsw[midx].bn_siz << 16));
1521 cmd->arith.a = cmd->arith.b = cmd->arith.c = cmd->arith.unused[0] =
1522 cmd->arith.unused[1] = 0;
1523 bus_dmamap_sync(sc->sc_dmat, sc->sc_pkhmap,
1524 rmodidx * sizeof(union noct_pkh_cmd), sizeof(union noct_pkh_cmd),
1525 BUS_DMASYNC_PREWRITE);
1526 if (++wp == NOCT_PKH_ENTRIES)
1527 wp = 0;
1528
1529 /* Load A XXX deal with A < M padding ... */
1530 aidx = wp = sc->sc_pkhwp;
1531 bits = noct_ksigbits(&krp->krp_param[0]);
1532 if (bits > 4096 || bits > mbits) {
1533 err = ERANGE;
1534 goto errout_rmod;
1535 }
1536 sc->sc_pkh_bnsw[aidx].bn_siz = (bits + 127) / 128;
1537 if (extent_alloc(sc->sc_pkh_bn, sc->sc_pkh_bnsw[aidx].bn_siz,
1538 EX_NOALIGN, 0, EX_NOBOUNDARY, EX_NOWAIT,
1539 &sc->sc_pkh_bnsw[aidx].bn_off)) {
1540 err = ENOMEM;
1541 goto errout_rmod;
1542 }
1543 cmd = &sc->sc_pkhcmd[aidx];
1544 cmd->cache.op = htole32(PKH_OP_CODE_LOAD);
1545 cmd->cache.r = htole32(sc->sc_pkh_bnsw[aidx].bn_off);
1546 adr = sc->sc_bnmap->dm_segs[0].ds_addr +
1547 (sc->sc_pkh_bnsw[aidx].bn_off * 16);
1548 cmd->cache.addrhi = htole32((adr >> 32) & 0xffffffff);
1549 cmd->cache.addrlo = htole32((adr >> 0 ) & 0xffffffff);
1550 cmd->cache.len = htole32(sc->sc_pkh_bnsw[aidx].bn_siz);
1551 cmd->cache.unused[0] = cmd->cache.unused[1] = cmd->cache.unused[2] = 0;
1552 bus_dmamap_sync(sc->sc_dmat, sc->sc_pkhmap,
1553 aidx * sizeof(union noct_pkh_cmd), sizeof(union noct_pkh_cmd),
1554 BUS_DMASYNC_PREWRITE);
1555 for (i = 0; i < (digits * 16); i++)
1556 sc->sc_bncache[(sc->sc_pkh_bnsw[aidx].bn_off * 16) + i] = 0;
1557 for (i = 0; i < ((bits + 7) / 8); i++)
1558 sc->sc_bncache[(sc->sc_pkh_bnsw[aidx].bn_off * 16) +
1559 (digits * 16) - 1 - i] = krp->krp_param[2].crp_p[i];
1560 bus_dmamap_sync(sc->sc_dmat, sc->sc_bnmap,
1561 sc->sc_pkh_bnsw[aidx].bn_off * 16, digits * 16,
1562 BUS_DMASYNC_PREWRITE);
1563 if (++wp == NOCT_PKH_ENTRIES)
1564 wp = 0;
1565
1566 /* Compute (A * tmp1) mod m -> A */
1567 mmulidx = wp;
1568 sc->sc_pkh_bnsw[mmulidx].bn_siz = 0;
1569 sc->sc_pkh_bnsw[mmulidx].bn_off = 0;
1570 cmd = &sc->sc_pkhcmd[mmulidx];
1571 cmd->arith.op = htole32(PKH_OP_CODE_MUL);
1572 cmd->arith.r = htole32(sc->sc_pkh_bnsw[aidx].bn_off);
1573 cmd->arith.m = htole32(sc->sc_pkh_bnsw[midx].bn_off |
1574 (sc->sc_pkh_bnsw[midx].bn_siz << 16));
1575 cmd->arith.a = htole32(sc->sc_pkh_bnsw[aidx].bn_off |
1576 (sc->sc_pkh_bnsw[aidx].bn_siz << 16));
1577 cmd->arith.b = htole32(sc->sc_pkh_bnsw[rmodidx].bn_off |
1578 (sc->sc_pkh_bnsw[rmodidx].bn_siz << 16));
1579 cmd->arith.c = cmd->arith.unused[0] = cmd->arith.unused[1] = 0;
1580 bus_dmamap_sync(sc->sc_dmat, sc->sc_pkhmap,
1581 rmodidx * sizeof(union noct_pkh_cmd), sizeof(union noct_pkh_cmd),
1582 BUS_DMASYNC_PREWRITE);
1583 if (++wp == NOCT_PKH_ENTRIES)
1584 wp = 0;
1585
1586 /* Load B */
1587 bidx = wp = sc->sc_pkhwp;
1588 bits = noct_ksigbits(&krp->krp_param[1]);
1589 if (bits > 4096) {
1590 err = ERANGE;
1591 goto errout_a;
1592 }
1593 sc->sc_pkh_bnsw[bidx].bn_siz = (bits + 127) / 128;
1594 if (extent_alloc(sc->sc_pkh_bn, sc->sc_pkh_bnsw[bidx].bn_siz,
1595 EX_NOALIGN, 0, EX_NOBOUNDARY, EX_NOWAIT,
1596 &sc->sc_pkh_bnsw[bidx].bn_off)) {
1597 err = ENOMEM;
1598 goto errout_a;
1599 }
1600 cmd = &sc->sc_pkhcmd[bidx];
1601 cmd->cache.op = htole32(PKH_OP_CODE_LOAD);
1602 cmd->cache.r = htole32(sc->sc_pkh_bnsw[bidx].bn_off);
1603 adr = sc->sc_bnmap->dm_segs[0].ds_addr +
1604 (sc->sc_pkh_bnsw[bidx].bn_off * 16);
1605 cmd->cache.addrhi = htole32((adr >> 32) & 0xffffffff);
1606 cmd->cache.addrlo = htole32((adr >> 0 ) & 0xffffffff);
1607 cmd->cache.len = htole32(sc->sc_pkh_bnsw[bidx].bn_siz);
1608 cmd->cache.unused[0] = cmd->cache.unused[1] = cmd->cache.unused[2] = 0;
1609 bus_dmamap_sync(sc->sc_dmat, sc->sc_pkhmap,
1610 bidx * sizeof(union noct_pkh_cmd), sizeof(union noct_pkh_cmd),
1611 BUS_DMASYNC_PREWRITE);
1612 for (i = 0; i < (digits * 16); i++)
1613 sc->sc_bncache[(sc->sc_pkh_bnsw[bidx].bn_off * 16) + i] = 0;
1614 for (i = 0; i < ((bits + 7) / 8); i++)
1615 sc->sc_bncache[(sc->sc_pkh_bnsw[bidx].bn_off * 16) +
1616 (digits * 16) - 1 - i] = krp->krp_param[2].crp_p[i];
1617 bus_dmamap_sync(sc->sc_dmat, sc->sc_bnmap,
1618 sc->sc_pkh_bnsw[bidx].bn_off * 16, digits * 16,
1619 BUS_DMASYNC_PREWRITE);
1620 if (++wp == NOCT_PKH_ENTRIES)
1621 wp = 0;
1622
1623 NOCT_WRITE_4(sc, NOCT_PKH_Q_PTR, wp);
1624 sc->sc_pkhwp = wp;
1625
1626 splx(s);
1627
1628 return (0);
1629
1630 errout_a:
1631 extent_free(sc->sc_pkh_bn, sc->sc_pkh_bnsw[aidx].bn_off,
1632 sc->sc_pkh_bnsw[aidx].bn_siz, EX_NOWAIT);
1633 errout_rmod:
1634 extent_free(sc->sc_pkh_bn, sc->sc_pkh_bnsw[rmodidx].bn_off,
1635 sc->sc_pkh_bnsw[rmodidx].bn_siz, EX_NOWAIT);
1636 errout_m:
1637 extent_free(sc->sc_pkh_bn, sc->sc_pkh_bnsw[midx].bn_off,
1638 sc->sc_pkh_bnsw[midx].bn_siz, EX_NOWAIT);
1639 errout:
1640 splx(s);
1641 krp->krp_status = err;
1642 crypto_kdone(krp);
1643 return (1);
1644 }
1645
1646 void
noct_pkh_freedesc(sc,idx)1647 noct_pkh_freedesc(sc, idx)
1648 struct noct_softc *sc;
1649 int idx;
1650 {
1651 if (sc->sc_pkh_bnsw[idx].bn_callback != NULL)
1652 (*sc->sc_pkh_bnsw[idx].bn_callback)(sc, idx, 0);
1653 }
1654
1655 /*
1656 * Return the number of significant bits of a big number.
1657 */
1658 int
noct_ksigbits(cr)1659 noct_ksigbits(cr)
1660 struct crparam *cr;
1661 {
1662 u_int plen = (cr->crp_nbits + 7) / 8;
1663 int i, sig = plen * 8;
1664 u_int8_t c, *p = cr->crp_p;
1665
1666 for (i = plen - 1; i >= 0; i--) {
1667 c = p[i];
1668 if (c != 0) {
1669 while ((c & 0x80) == 0) {
1670 sig--;
1671 c <<= 1;
1672 }
1673 break;
1674 }
1675 sig -= 8;
1676 }
1677 return (sig);
1678 }
1679
1680 int
noct_kload(sc,cr,wp)1681 noct_kload(sc, cr, wp)
1682 struct noct_softc *sc;
1683 struct crparam *cr;
1684 u_int32_t wp;
1685 {
1686 u_int64_t adr;
1687 union noct_pkh_cmd *cmd;
1688 u_long off;
1689 int bits, digits, i;
1690 u_int32_t wpnext;
1691
1692 wpnext = wp + 1;
1693 if (wpnext == NOCT_PKH_ENTRIES)
1694 wpnext = 0;
1695 if (wpnext == sc->sc_pkhrp)
1696 return (ENOMEM);
1697
1698 bits = noct_ksigbits(cr);
1699 if (bits > 4096)
1700 return (E2BIG);
1701
1702 digits = (bits + 127) / 128;
1703
1704 if (extent_alloc(sc->sc_pkh_bn, digits, EX_NOALIGN, 0, EX_NOBOUNDARY,
1705 EX_NOWAIT, &off))
1706 return (ENOMEM);
1707
1708 cmd = &sc->sc_pkhcmd[wp];
1709 cmd->cache.op = htole32(PKH_OP_CODE_LOAD);
1710 cmd->cache.r = htole32(off);
1711 adr = sc->sc_bnmap->dm_segs[0].ds_addr + (off * 16);
1712 cmd->cache.addrhi = htole32((adr >> 32) & 0xffffffff);
1713 cmd->cache.addrlo = htole32((adr >> 0 ) & 0xffffffff);
1714 cmd->cache.len = htole32(digits * 16);
1715 cmd->cache.unused[0] = cmd->cache.unused[1] = cmd->cache.unused[2] = 0;
1716 bus_dmamap_sync(sc->sc_dmat, sc->sc_pkhmap,
1717 wp * sizeof(union noct_pkh_cmd), sizeof(union noct_pkh_cmd),
1718 BUS_DMASYNC_PREWRITE);
1719
1720 for (i = 0; i < (digits * 16); i++)
1721 sc->sc_bncache[(off * 16) + i] = 0;
1722 for (i = 0; i < ((bits + 7) / 8); i++)
1723 sc->sc_bncache[(off * 16) + (digits * 16) - 1 - i] =
1724 cr->crp_p[i];
1725 bus_dmamap_sync(sc->sc_dmat, sc->sc_bnmap, off * 16, digits * 16,
1726 BUS_DMASYNC_PREWRITE);
1727
1728 sc->sc_pkh_bnsw[wp].bn_off = off;
1729 sc->sc_pkh_bnsw[wp].bn_siz = digits;
1730 sc->sc_pkh_bnsw[wp].bn_callback = noct_kload_cb;
1731 return (0);
1732 }
1733
1734 void
noct_kload_cb(sc,wp,err)1735 noct_kload_cb(sc, wp, err)
1736 struct noct_softc *sc;
1737 u_int32_t wp;
1738 int err;
1739 {
1740 struct noct_bnc_sw *sw = &sc->sc_pkh_bnsw[wp];
1741
1742 extent_free(sc->sc_pkh_bn, sw->bn_off, sw->bn_siz, EX_NOWAIT);
1743 bzero(&sc->sc_bncache[sw->bn_off * 16], sw->bn_siz * 16);
1744 }
1745
1746 void
noct_modmul_cb(sc,wp,err)1747 noct_modmul_cb(sc, wp, err)
1748 struct noct_softc *sc;
1749 u_int32_t wp;
1750 int err;
1751 {
1752 struct noct_bnc_sw *sw = &sc->sc_pkh_bnsw[wp];
1753 struct cryptkop *krp = sw->bn_krp;
1754 int i, j;
1755
1756 if (err)
1757 goto out;
1758
1759 i = (sw->bn_off * 16) + (sw->bn_siz * 16) - 1;
1760 for (j = 0; j < (krp->krp_param[3].crp_nbits + 7) / 8; j++) {
1761 krp->krp_param[3].crp_p[j] = sc->sc_bncache[i];
1762 i--;
1763 }
1764
1765 out:
1766 extent_free(sc->sc_pkh_bn, sw->bn_off, sw->bn_siz, EX_NOWAIT);
1767 bzero(&sc->sc_bncache[sw->bn_off * 16], sw->bn_siz * 16);
1768 krp->krp_status = err;
1769 crypto_kdone(krp);
1770 }
1771
1772 static const u_int8_t noct_odd_parity[] = {
1773 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x07, 0x07,
1774 0x08, 0x08, 0x0b, 0x0b, 0x0d, 0x0d, 0x0e, 0x0e,
1775 0x10, 0x10, 0x13, 0x13, 0x15, 0x15, 0x16, 0x16,
1776 0x19, 0x19, 0x1a, 0x1a, 0x1c, 0x1c, 0x1f, 0x1f,
1777 0x20, 0x20, 0x23, 0x23, 0x25, 0x25, 0x26, 0x26,
1778 0x29, 0x29, 0x2a, 0x2a, 0x2c, 0x2c, 0x2f, 0x2f,
1779 0x31, 0x31, 0x32, 0x32, 0x34, 0x34, 0x37, 0x37,
1780 0x38, 0x38, 0x3b, 0x3b, 0x3d, 0x3d, 0x3e, 0x3e,
1781 0x40, 0x40, 0x43, 0x43, 0x45, 0x45, 0x46, 0x46,
1782 0x49, 0x49, 0x4a, 0x4a, 0x4c, 0x4c, 0x4f, 0x4f,
1783 0x51, 0x51, 0x52, 0x52, 0x54, 0x54, 0x57, 0x57,
1784 0x58, 0x58, 0x5b, 0x5b, 0x5d, 0x5d, 0x5e, 0x5e,
1785 0x61, 0x61, 0x62, 0x62, 0x64, 0x64, 0x67, 0x67,
1786 0x68, 0x68, 0x6b, 0x6b, 0x6d, 0x6d, 0x6e, 0x6e,
1787 0x70, 0x70, 0x73, 0x73, 0x75, 0x75, 0x76, 0x76,
1788 0x79, 0x79, 0x7a, 0x7a, 0x7c, 0x7c, 0x7f, 0x7f,
1789 0x80, 0x80, 0x83, 0x83, 0x85, 0x85, 0x86, 0x86,
1790 0x89, 0x89, 0x8a, 0x8a, 0x8c, 0x8c, 0x8f, 0x8f,
1791 0x91, 0x91, 0x92, 0x92, 0x94, 0x94, 0x97, 0x97,
1792 0x98, 0x98, 0x9b, 0x9b, 0x9d, 0x9d, 0x9e, 0x9e,
1793 0xa1, 0xa1, 0xa2, 0xa2, 0xa4, 0xa4, 0xa7, 0xa7,
1794 0xa8, 0xa8, 0xab, 0xab, 0xad, 0xad, 0xae, 0xae,
1795 0xb0, 0xb0, 0xb3, 0xb3, 0xb5, 0xb5, 0xb6, 0xb6,
1796 0xb9, 0xb9, 0xba, 0xba, 0xbc, 0xbc, 0xbf, 0xbf,
1797 0xc1, 0xc1, 0xc2, 0xc2, 0xc4, 0xc4, 0xc7, 0xc7,
1798 0xc8, 0xc8, 0xcb, 0xcb, 0xcd, 0xcd, 0xce, 0xce,
1799 0xd0, 0xd0, 0xd3, 0xd3, 0xd5, 0xd5, 0xd6, 0xd6,
1800 0xd9, 0xd9, 0xda, 0xda, 0xdc, 0xdc, 0xdf, 0xdf,
1801 0xe0, 0xe0, 0xe3, 0xe3, 0xe5, 0xe5, 0xe6, 0xe6,
1802 0xe9, 0xe9, 0xea, 0xea, 0xec, 0xec, 0xef, 0xef,
1803 0xf1, 0xf1, 0xf2, 0xf2, 0xf4, 0xf4, 0xf7, 0xf7,
1804 0xf8, 0xf8, 0xfb, 0xfb, 0xfd, 0xfd, 0xfe, 0xfe,
1805 };
1806
1807 int
noct_newsession(sidp,cri)1808 noct_newsession(sidp, cri)
1809 u_int32_t *sidp;
1810 struct cryptoini *cri;
1811 {
1812 struct noct_softc *sc;
1813 int i;
1814
1815 for (i = 0; i < noct_cd.cd_ndevs; i++) {
1816 sc = noct_cd.cd_devs[i];
1817 if (sc == NULL || sc->sc_cid == (*sidp))
1818 break;
1819 }
1820 if (sc == NULL)
1821 return (EINVAL);
1822
1823 /* XXX Can only handle single operations */
1824 if (cri->cri_next != NULL)
1825 return (EINVAL);
1826
1827 if (cri->cri_alg == CRYPTO_DES_CBC || cri->cri_alg == CRYPTO_3DES_CBC) {
1828 u_int8_t key[24];
1829
1830 if (cri->cri_alg == CRYPTO_DES_CBC) {
1831 if (cri->cri_klen != 64)
1832 return (EINVAL);
1833 for (i = 0; i < 8; i++)
1834 key[i] = key[i + 8] = key[i + 16] =
1835 cri->cri_key[i];
1836 } else {
1837 if (cri->cri_klen != 192)
1838 return (EINVAL);
1839 for (i = 0; i < 24; i++)
1840 key[i] = cri->cri_key[i];
1841 }
1842
1843 /* Verify key parity */
1844 for (i = 0; i < 24; i++)
1845 if (key[i] != noct_odd_parity[key[i]])
1846 return (ENOEXEC);
1847 }
1848
1849 *sidp = NOCT_SID(sc->sc_dv.dv_unit, 0);
1850 return (0);
1851 }
1852
1853 int
noct_freesession(tid)1854 noct_freesession(tid)
1855 u_int64_t tid;
1856 {
1857 int card;
1858 u_int32_t sid = ((u_int32_t)tid) & 0xffffffff;
1859
1860 card = NOCT_CARD(sid);
1861 if (card >= noct_cd.cd_ndevs || noct_cd.cd_devs[card] == NULL)
1862 return (EINVAL);
1863 return (0);
1864 }
1865
1866 int
noct_process(crp)1867 noct_process(crp)
1868 struct cryptop *crp;
1869 {
1870 struct noct_softc *sc;
1871 struct noct_workq *q = NULL;
1872 int card, err, s;
1873
1874 if (crp == NULL || crp->crp_callback == NULL)
1875 return (EINVAL);
1876
1877 card = NOCT_CARD(crp->crp_sid);
1878 if (card >= noct_cd.cd_ndevs || noct_cd.cd_devs[card] == NULL)
1879 return (EINVAL);
1880 sc = noct_cd.cd_devs[card];
1881
1882 q = (struct noct_workq *)malloc(sizeof(struct noct_workq),
1883 M_DEVBUF, M_NOWAIT);
1884 if (q == NULL) {
1885 err = ENOMEM;
1886 goto errout;
1887 }
1888 q->q_crp = crp;
1889
1890 s = splnet();
1891 SIMPLEQ_INSERT_TAIL(&sc->sc_inq, q, q_next);
1892 splx(s);
1893 NOCT_WAKEUP(sc);
1894 return (0);
1895
1896 errout:
1897 if (q != NULL)
1898 free(q, M_DEVBUF);
1899 crp->crp_etype = err;
1900 crypto_done(crp);
1901 return (0);
1902 }
1903