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