Line data Source code
1 : /* $OpenBSD: hifn7751.c,v 1.178 2018/04/28 15:44:59 jasper Exp $ */
2 :
3 : /*
4 : * Invertex AEON / Hifn 7751 driver
5 : * Copyright (c) 1999 Invertex Inc. All rights reserved.
6 : * Copyright (c) 1999 Theo de Raadt
7 : * Copyright (c) 2000-2001 Network Security Technologies, Inc.
8 : * http://www.netsec.net
9 : * Copyright (c) 2003 Hifn Inc.
10 :
11 : * This driver is based on a previous driver by Invertex, for which they
12 : * requested: Please send any comments, feedback, bug-fixes, or feature
13 : * requests to software@invertex.com.
14 : *
15 : * Redistribution and use in source and binary forms, with or without
16 : * modification, are permitted provided that the following conditions
17 : * are met:
18 : *
19 : * 1. Redistributions of source code must retain the above copyright
20 : * notice, this list of conditions and the following disclaimer.
21 : * 2. Redistributions in binary form must reproduce the above copyright
22 : * notice, this list of conditions and the following disclaimer in the
23 : * documentation and/or other materials provided with the distribution.
24 : * 3. The name of the author may not be used to endorse or promote products
25 : * derived from this software without specific prior written permission.
26 : *
27 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
28 : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
29 : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
30 : * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
31 : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
32 : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
36 : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 : *
38 : * Effort sponsored in part by the Defense Advanced Research Projects
39 : * Agency (DARPA) and Air Force Research Laboratory, Air Force
40 : * Materiel Command, USAF, under agreement number F30602-01-2-0537.
41 : *
42 : */
43 :
44 : /*
45 : * Driver for various Hifn encryption processors.
46 : */
47 :
48 : #include <sys/param.h>
49 : #include <sys/systm.h>
50 : #include <sys/timeout.h>
51 : #include <sys/errno.h>
52 : #include <sys/malloc.h>
53 : #include <sys/kernel.h>
54 : #include <sys/mbuf.h>
55 : #include <sys/device.h>
56 :
57 : #include <crypto/cryptodev.h>
58 : #include <dev/rndvar.h>
59 :
60 : #include <dev/pci/pcireg.h>
61 : #include <dev/pci/pcivar.h>
62 : #include <dev/pci/pcidevs.h>
63 :
64 : #include <dev/pci/hifn7751reg.h>
65 : #include <dev/pci/hifn7751var.h>
66 :
67 : #undef HIFN_DEBUG
68 :
69 : /*
70 : * Prototypes and count for the pci_device structure
71 : */
72 : int hifn_probe(struct device *, void *, void *);
73 : void hifn_attach(struct device *, struct device *, void *);
74 :
75 : struct cfattach hifn_ca = {
76 : sizeof(struct hifn_softc), hifn_probe, hifn_attach,
77 : };
78 :
79 : struct cfdriver hifn_cd = {
80 : 0, "hifn", DV_DULL
81 : };
82 :
83 : void hifn_reset_board(struct hifn_softc *, int);
84 : void hifn_reset_puc(struct hifn_softc *);
85 : void hifn_puc_wait(struct hifn_softc *);
86 : int hifn_enable_crypto(struct hifn_softc *, pcireg_t);
87 : void hifn_set_retry(struct hifn_softc *);
88 : void hifn_init_dma(struct hifn_softc *);
89 : void hifn_init_pci_registers(struct hifn_softc *);
90 : int hifn_sramsize(struct hifn_softc *);
91 : int hifn_dramsize(struct hifn_softc *);
92 : int hifn_ramtype(struct hifn_softc *);
93 : void hifn_sessions(struct hifn_softc *);
94 : int hifn_intr(void *);
95 : u_int hifn_write_command(struct hifn_command *, u_int8_t *);
96 : u_int32_t hifn_next_signature(u_int32_t a, u_int cnt);
97 : int hifn_newsession(u_int32_t *, struct cryptoini *);
98 : int hifn_freesession(u_int64_t);
99 : int hifn_process(struct cryptop *);
100 : void hifn_callback(struct hifn_softc *, struct hifn_command *, u_int8_t *);
101 : int hifn_crypto(struct hifn_softc *, struct hifn_command *,
102 : struct cryptop *);
103 : int hifn_readramaddr(struct hifn_softc *, int, u_int8_t *);
104 : int hifn_writeramaddr(struct hifn_softc *, int, u_int8_t *);
105 : int hifn_dmamap_aligned(bus_dmamap_t);
106 : int hifn_dmamap_load_src(struct hifn_softc *, struct hifn_command *);
107 : int hifn_dmamap_load_dst(struct hifn_softc *, struct hifn_command *);
108 : int hifn_init_pubrng(struct hifn_softc *);
109 : void hifn_rng(void *);
110 : void hifn_tick(void *);
111 : void hifn_abort(struct hifn_softc *);
112 : void hifn_alloc_slot(struct hifn_softc *, int *, int *, int *, int *);
113 : void hifn_write_4(struct hifn_softc *, int, bus_size_t, u_int32_t);
114 : u_int32_t hifn_read_4(struct hifn_softc *, int, bus_size_t);
115 : int hifn_compression(struct hifn_softc *, struct cryptop *,
116 : struct hifn_command *);
117 : struct mbuf *hifn_mkmbuf_chain(int, struct mbuf *);
118 : int hifn_compress_enter(struct hifn_softc *, struct hifn_command *);
119 : void hifn_callback_comp(struct hifn_softc *, struct hifn_command *,
120 : u_int8_t *);
121 :
122 : struct hifn_stats hifnstats;
123 :
124 : const struct pci_matchid hifn_devices[] = {
125 : { PCI_VENDOR_INVERTEX, PCI_PRODUCT_INVERTEX_AEON },
126 : { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7751 },
127 : { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7811 },
128 : { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7951 },
129 : { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7955 },
130 : { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7956 },
131 : { PCI_VENDOR_NETSEC, PCI_PRODUCT_NETSEC_7751 },
132 : };
133 :
134 : int
135 0 : hifn_probe(struct device *parent, void *match, void *aux)
136 : {
137 0 : return (pci_matchbyid((struct pci_attach_args *)aux, hifn_devices,
138 : nitems(hifn_devices)));
139 : }
140 :
141 : void
142 0 : hifn_attach(struct device *parent, struct device *self, void *aux)
143 : {
144 0 : struct hifn_softc *sc = (struct hifn_softc *)self;
145 0 : struct pci_attach_args *pa = aux;
146 0 : pci_chipset_tag_t pc = pa->pa_pc;
147 0 : pci_intr_handle_t ih;
148 : const char *intrstr = NULL;
149 : char rbase;
150 0 : bus_size_t iosize0, iosize1;
151 : u_int16_t ena;
152 : int rseg;
153 0 : caddr_t kva;
154 0 : int algs[CRYPTO_ALGORITHM_MAX + 1];
155 :
156 0 : sc->sc_pci_pc = pa->pa_pc;
157 0 : sc->sc_pci_tag = pa->pa_tag;
158 :
159 0 : if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_HIFN &&
160 0 : (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_HIFN_7951))
161 0 : sc->sc_flags = HIFN_HAS_RNG | HIFN_HAS_PUBLIC;
162 :
163 0 : if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_HIFN &&
164 0 : (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_HIFN_7955 ||
165 0 : PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_HIFN_7956))
166 0 : sc->sc_flags = HIFN_IS_7956 | HIFN_HAS_AES | HIFN_HAS_RNG |
167 : HIFN_HAS_PUBLIC;
168 :
169 0 : if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_HIFN &&
170 0 : PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_HIFN_7811)
171 0 : sc->sc_flags |= HIFN_IS_7811 | HIFN_HAS_RNG | HIFN_HAS_LEDS |
172 : HIFN_NO_BURSTWRITE;
173 :
174 0 : if (pci_mapreg_map(pa, HIFN_BAR0, PCI_MAPREG_TYPE_MEM, 0,
175 0 : &sc->sc_st0, &sc->sc_sh0, NULL, &iosize0, 0)) {
176 0 : printf(": can't find mem space %d\n", 0);
177 0 : return;
178 : }
179 :
180 0 : if (pci_mapreg_map(pa, HIFN_BAR1, PCI_MAPREG_TYPE_MEM, 0,
181 0 : &sc->sc_st1, &sc->sc_sh1, NULL, &iosize1, 0)) {
182 0 : printf(": can't find mem space %d\n", 1);
183 0 : goto fail_io0;
184 : }
185 :
186 0 : hifn_set_retry(sc);
187 :
188 0 : if (sc->sc_flags & HIFN_NO_BURSTWRITE) {
189 0 : sc->sc_waw_lastgroup = -1;
190 0 : sc->sc_waw_lastreg = 1;
191 0 : }
192 :
193 0 : sc->sc_dmat = pa->pa_dmat;
194 0 : if (bus_dmamap_create(sc->sc_dmat, sizeof(*sc->sc_dma), 1,
195 : sizeof(*sc->sc_dma), 0, BUS_DMA_NOWAIT, &sc->sc_dmamap)) {
196 0 : printf(": can't create dma map\n");
197 0 : goto fail_io1;
198 : }
199 0 : if (bus_dmamem_alloc(sc->sc_dmat, sizeof(*sc->sc_dma), PAGE_SIZE, 0,
200 : sc->sc_dmasegs, 1, &sc->sc_dmansegs,
201 : BUS_DMA_NOWAIT | BUS_DMA_ZERO)) {
202 0 : printf(": can't alloc dma buffer\n");
203 0 : bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamap);
204 0 : goto fail_io1;
205 : }
206 0 : if (bus_dmamem_map(sc->sc_dmat, sc->sc_dmasegs, sc->sc_dmansegs,
207 : sizeof(*sc->sc_dma), &kva, BUS_DMA_NOWAIT)) {
208 0 : printf(": can't map dma buffers (%lu bytes)\n",
209 : (u_long)sizeof(*sc->sc_dma));
210 0 : bus_dmamem_free(sc->sc_dmat, sc->sc_dmasegs, sc->sc_dmansegs);
211 0 : bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamap);
212 0 : goto fail_io1;
213 : }
214 0 : if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, kva,
215 : sizeof(*sc->sc_dma), NULL, BUS_DMA_NOWAIT)) {
216 0 : printf(": can't load dma map\n");
217 0 : bus_dmamem_unmap(sc->sc_dmat, kva, sizeof(*sc->sc_dma));
218 0 : bus_dmamem_free(sc->sc_dmat, sc->sc_dmasegs, sc->sc_dmansegs);
219 0 : bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamap);
220 0 : goto fail_io1;
221 : }
222 0 : sc->sc_dma = (struct hifn_dma *)kva;
223 :
224 0 : hifn_reset_board(sc, 0);
225 :
226 0 : if (hifn_enable_crypto(sc, pa->pa_id) != 0) {
227 0 : printf("%s: crypto enabling failed\n", sc->sc_dv.dv_xname);
228 0 : goto fail_mem;
229 : }
230 0 : hifn_reset_puc(sc);
231 :
232 0 : hifn_init_dma(sc);
233 0 : hifn_init_pci_registers(sc);
234 :
235 0 : if (sc->sc_flags & HIFN_IS_7956)
236 0 : sc->sc_drammodel = 1;
237 0 : else if (hifn_ramtype(sc))
238 : goto fail_mem;
239 :
240 0 : if (sc->sc_drammodel == 0)
241 0 : hifn_sramsize(sc);
242 : else
243 0 : hifn_dramsize(sc);
244 :
245 : /*
246 : * Workaround for NetSec 7751 rev A: half ram size because two
247 : * of the address lines were left floating
248 : */
249 0 : if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_NETSEC &&
250 0 : PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_NETSEC_7751 &&
251 0 : PCI_REVISION(pa->pa_class) == 0x61)
252 0 : sc->sc_ramsize >>= 1;
253 :
254 0 : if (pci_intr_map(pa, &ih)) {
255 0 : printf(": couldn't map interrupt\n");
256 0 : goto fail_mem;
257 : }
258 0 : intrstr = pci_intr_string(pc, ih);
259 0 : sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, hifn_intr, sc,
260 0 : self->dv_xname);
261 0 : if (sc->sc_ih == NULL) {
262 0 : printf(": couldn't establish interrupt");
263 0 : if (intrstr != NULL)
264 0 : printf(" at %s", intrstr);
265 0 : printf("\n");
266 0 : goto fail_mem;
267 : }
268 :
269 0 : hifn_sessions(sc);
270 :
271 0 : rseg = sc->sc_ramsize / 1024;
272 : rbase = 'K';
273 0 : if (sc->sc_ramsize >= (1024 * 1024)) {
274 : rbase = 'M';
275 0 : rseg /= 1024;
276 0 : }
277 0 : printf("%d%cB %cram, %s\n", rseg, rbase,
278 0 : sc->sc_drammodel ? 'd' : 's', intrstr);
279 :
280 0 : sc->sc_cid = crypto_get_driverid(0);
281 0 : if (sc->sc_cid < 0)
282 : goto fail_intr;
283 :
284 0 : WRITE_REG_0(sc, HIFN_0_PUCNFG,
285 : READ_REG_0(sc, HIFN_0_PUCNFG) | HIFN_PUCNFG_CHIPID);
286 0 : ena = READ_REG_0(sc, HIFN_0_PUSTAT) & HIFN_PUSTAT_CHIPENA;
287 :
288 0 : bzero(algs, sizeof(algs));
289 :
290 0 : algs[CRYPTO_LZS_COMP] = CRYPTO_ALG_FLAG_SUPPORTED;
291 0 : switch (ena) {
292 : case HIFN_PUSTAT_ENA_2:
293 0 : algs[CRYPTO_3DES_CBC] = CRYPTO_ALG_FLAG_SUPPORTED;
294 : /*FALLTHROUGH*/
295 : case HIFN_PUSTAT_ENA_1:
296 0 : algs[CRYPTO_MD5_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
297 0 : algs[CRYPTO_SHA1_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
298 0 : }
299 0 : if (sc->sc_flags & HIFN_HAS_AES)
300 0 : algs[CRYPTO_AES_CBC] = CRYPTO_ALG_FLAG_SUPPORTED;
301 :
302 0 : crypto_register(sc->sc_cid, algs, hifn_newsession,
303 : hifn_freesession, hifn_process);
304 :
305 0 : bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0,
306 : sc->sc_dmamap->dm_mapsize,
307 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
308 :
309 0 : if (sc->sc_flags & (HIFN_HAS_PUBLIC | HIFN_HAS_RNG))
310 0 : hifn_init_pubrng(sc);
311 :
312 0 : timeout_set(&sc->sc_tickto, hifn_tick, sc);
313 0 : timeout_add_sec(&sc->sc_tickto, 1);
314 :
315 0 : return;
316 :
317 : fail_intr:
318 0 : pci_intr_disestablish(pc, sc->sc_ih);
319 : fail_mem:
320 0 : bus_dmamap_unload(sc->sc_dmat, sc->sc_dmamap);
321 0 : bus_dmamem_unmap(sc->sc_dmat, kva, sizeof(*sc->sc_dma));
322 0 : bus_dmamem_free(sc->sc_dmat, sc->sc_dmasegs, sc->sc_dmansegs);
323 0 : bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamap);
324 :
325 : /* Turn off DMA polling */
326 0 : WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET |
327 : HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE);
328 :
329 : fail_io1:
330 0 : bus_space_unmap(sc->sc_st1, sc->sc_sh1, iosize1);
331 : fail_io0:
332 0 : bus_space_unmap(sc->sc_st0, sc->sc_sh0, iosize0);
333 0 : }
334 :
335 : int
336 0 : hifn_init_pubrng(struct hifn_softc *sc)
337 : {
338 : u_int32_t r;
339 : int i;
340 :
341 0 : if ((sc->sc_flags & HIFN_IS_7811) == 0) {
342 : /* Reset 7951 public key/rng engine */
343 0 : WRITE_REG_1(sc, HIFN_1_PUB_RESET,
344 : READ_REG_1(sc, HIFN_1_PUB_RESET) | HIFN_PUBRST_RESET);
345 :
346 0 : for (i = 0; i < 100; i++) {
347 0 : DELAY(1000);
348 0 : if ((READ_REG_1(sc, HIFN_1_PUB_RESET) &
349 0 : HIFN_PUBRST_RESET) == 0)
350 : break;
351 : }
352 :
353 0 : if (i == 100) {
354 0 : printf("%s: public key init failed\n",
355 0 : sc->sc_dv.dv_xname);
356 0 : return (1);
357 : }
358 : }
359 :
360 : /* Enable the rng, if available */
361 0 : if (sc->sc_flags & HIFN_HAS_RNG) {
362 0 : if (sc->sc_flags & HIFN_IS_7811) {
363 0 : r = READ_REG_1(sc, HIFN_1_7811_RNGENA);
364 0 : if (r & HIFN_7811_RNGENA_ENA) {
365 0 : r &= ~HIFN_7811_RNGENA_ENA;
366 0 : WRITE_REG_1(sc, HIFN_1_7811_RNGENA, r);
367 0 : }
368 0 : WRITE_REG_1(sc, HIFN_1_7811_RNGCFG,
369 : HIFN_7811_RNGCFG_DEFL);
370 0 : r |= HIFN_7811_RNGENA_ENA;
371 0 : WRITE_REG_1(sc, HIFN_1_7811_RNGENA, r);
372 0 : } else
373 0 : WRITE_REG_1(sc, HIFN_1_RNG_CONFIG,
374 : READ_REG_1(sc, HIFN_1_RNG_CONFIG) |
375 : HIFN_RNGCFG_ENA);
376 :
377 0 : sc->sc_rngfirst = 1;
378 0 : if (hz >= 100)
379 0 : sc->sc_rnghz = hz / 100;
380 : else
381 0 : sc->sc_rnghz = 1;
382 0 : timeout_set(&sc->sc_rngto, hifn_rng, sc);
383 0 : timeout_add(&sc->sc_rngto, sc->sc_rnghz);
384 0 : }
385 :
386 : /* Enable public key engine, if available */
387 0 : if (sc->sc_flags & HIFN_HAS_PUBLIC) {
388 0 : WRITE_REG_1(sc, HIFN_1_PUB_IEN, HIFN_PUBIEN_DONE);
389 0 : sc->sc_dmaier |= HIFN_DMAIER_PUBDONE;
390 0 : WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier);
391 0 : }
392 :
393 0 : return (0);
394 0 : }
395 :
396 : void
397 0 : hifn_rng(void *vsc)
398 : {
399 0 : struct hifn_softc *sc = vsc;
400 : u_int32_t num1, sts, num2;
401 : int i;
402 :
403 0 : if (sc->sc_flags & HIFN_IS_7811) {
404 0 : for (i = 0; i < 5; i++) {
405 0 : sts = READ_REG_1(sc, HIFN_1_7811_RNGSTS);
406 0 : if (sts & HIFN_7811_RNGSTS_UFL) {
407 0 : printf("%s: RNG underflow: disabling\n",
408 0 : sc->sc_dv.dv_xname);
409 0 : return;
410 : }
411 0 : if ((sts & HIFN_7811_RNGSTS_RDY) == 0)
412 : break;
413 :
414 : /*
415 : * There are at least two words in the RNG FIFO
416 : * at this point.
417 : */
418 0 : num1 = READ_REG_1(sc, HIFN_1_7811_RNGDAT);
419 0 : num2 = READ_REG_1(sc, HIFN_1_7811_RNGDAT);
420 0 : if (sc->sc_rngfirst)
421 0 : sc->sc_rngfirst = 0;
422 : else {
423 0 : enqueue_randomness(num1);
424 0 : enqueue_randomness(num2);
425 : }
426 : }
427 : } else {
428 0 : num1 = READ_REG_1(sc, HIFN_1_RNG_DATA);
429 :
430 0 : if (sc->sc_rngfirst)
431 0 : sc->sc_rngfirst = 0;
432 : else
433 0 : enqueue_randomness(num1);
434 : }
435 :
436 0 : timeout_add(&sc->sc_rngto, sc->sc_rnghz);
437 0 : }
438 :
439 : void
440 0 : hifn_puc_wait(struct hifn_softc *sc)
441 : {
442 : int i;
443 :
444 0 : for (i = 5000; i > 0; i--) {
445 0 : DELAY(1);
446 0 : if (!(READ_REG_0(sc, HIFN_0_PUCTRL) & HIFN_PUCTRL_RESET))
447 : break;
448 : }
449 0 : if (!i)
450 0 : printf("%s: proc unit did not reset\n", sc->sc_dv.dv_xname);
451 0 : }
452 :
453 : /*
454 : * Reset the processing unit.
455 : */
456 : void
457 0 : hifn_reset_puc(struct hifn_softc *sc)
458 : {
459 : /* Reset processing unit */
460 0 : WRITE_REG_0(sc, HIFN_0_PUCTRL, HIFN_PUCTRL_DMAENA);
461 0 : hifn_puc_wait(sc);
462 0 : }
463 :
464 : void
465 0 : hifn_set_retry(struct hifn_softc *sc)
466 : {
467 : u_int32_t r;
468 :
469 0 : r = pci_conf_read(sc->sc_pci_pc, sc->sc_pci_tag, HIFN_TRDY_TIMEOUT);
470 0 : r &= 0xffff0000;
471 0 : pci_conf_write(sc->sc_pci_pc, sc->sc_pci_tag, HIFN_TRDY_TIMEOUT, r);
472 0 : }
473 :
474 : /*
475 : * Resets the board. Values in the regesters are left as is
476 : * from the reset (i.e. initial values are assigned elsewhere).
477 : */
478 : void
479 0 : hifn_reset_board(struct hifn_softc *sc, int full)
480 : {
481 : u_int32_t reg;
482 :
483 : /*
484 : * Set polling in the DMA configuration register to zero. 0x7 avoids
485 : * resetting the board and zeros out the other fields.
486 : */
487 0 : WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET |
488 : HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE);
489 :
490 : /*
491 : * Now that polling has been disabled, we have to wait 1 ms
492 : * before resetting the board.
493 : */
494 0 : DELAY(1000);
495 :
496 : /* Reset the DMA unit */
497 0 : if (full) {
498 0 : WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MODE);
499 0 : DELAY(1000);
500 0 : } else {
501 0 : WRITE_REG_1(sc, HIFN_1_DMA_CNFG,
502 : HIFN_DMACNFG_MODE | HIFN_DMACNFG_MSTRESET);
503 0 : hifn_reset_puc(sc);
504 : }
505 :
506 0 : bzero(sc->sc_dma, sizeof(*sc->sc_dma));
507 :
508 : /* Bring dma unit out of reset */
509 0 : WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET |
510 : HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE);
511 :
512 0 : hifn_puc_wait(sc);
513 :
514 0 : hifn_set_retry(sc);
515 :
516 0 : if (sc->sc_flags & HIFN_IS_7811) {
517 0 : for (reg = 0; reg < 1000; reg++) {
518 0 : if (READ_REG_1(sc, HIFN_1_7811_MIPSRST) &
519 : HIFN_MIPSRST_CRAMINIT)
520 : break;
521 0 : DELAY(1000);
522 : }
523 0 : if (reg == 1000)
524 0 : printf(": cram init timeout\n");
525 : }
526 0 : }
527 :
528 : u_int32_t
529 0 : hifn_next_signature(u_int32_t a, u_int cnt)
530 : {
531 : int i;
532 : u_int32_t v;
533 :
534 0 : for (i = 0; i < cnt; i++) {
535 :
536 : /* get the parity */
537 0 : v = a & 0x80080125;
538 0 : v ^= v >> 16;
539 0 : v ^= v >> 8;
540 0 : v ^= v >> 4;
541 0 : v ^= v >> 2;
542 0 : v ^= v >> 1;
543 :
544 0 : a = (v & 1) ^ (a << 1);
545 : }
546 :
547 0 : return a;
548 : }
549 :
550 : struct pci2id {
551 : u_short pci_vendor;
552 : u_short pci_prod;
553 : char card_id[13];
554 : } pci2id[] = {
555 : {
556 : PCI_VENDOR_HIFN,
557 : PCI_PRODUCT_HIFN_7951,
558 : { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
559 : 0x00, 0x00, 0x00, 0x00, 0x00 }
560 : }, {
561 : PCI_VENDOR_HIFN,
562 : PCI_PRODUCT_HIFN_7955,
563 : { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
564 : 0x00, 0x00, 0x00, 0x00, 0x00 }
565 : }, {
566 : PCI_VENDOR_HIFN,
567 : PCI_PRODUCT_HIFN_7956,
568 : { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
569 : 0x00, 0x00, 0x00, 0x00, 0x00 }
570 : }, {
571 : PCI_VENDOR_NETSEC,
572 : PCI_PRODUCT_NETSEC_7751,
573 : { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
574 : 0x00, 0x00, 0x00, 0x00, 0x00 }
575 : }, {
576 : PCI_VENDOR_INVERTEX,
577 : PCI_PRODUCT_INVERTEX_AEON,
578 : { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
579 : 0x00, 0x00, 0x00, 0x00, 0x00 }
580 : }, {
581 : PCI_VENDOR_HIFN,
582 : PCI_PRODUCT_HIFN_7811,
583 : { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
584 : 0x00, 0x00, 0x00, 0x00, 0x00 }
585 : }, {
586 : /*
587 : * Other vendors share this PCI ID as well, such as
588 : * powercrypt, and obviously they also
589 : * use the same key.
590 : */
591 : PCI_VENDOR_HIFN,
592 : PCI_PRODUCT_HIFN_7751,
593 : { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
594 : 0x00, 0x00, 0x00, 0x00, 0x00 }
595 : },
596 : };
597 :
598 : /*
599 : * Checks to see if crypto is already enabled. If crypto isn't enable,
600 : * "hifn_enable_crypto" is called to enable it. The check is important,
601 : * as enabling crypto twice will lock the board.
602 : */
603 : int
604 0 : hifn_enable_crypto(struct hifn_softc *sc, pcireg_t pciid)
605 : {
606 : u_int32_t dmacfg, ramcfg, encl, addr, i;
607 : char *offtbl = NULL;
608 :
609 0 : for (i = 0; i < nitems(pci2id); i++) {
610 0 : if (pci2id[i].pci_vendor == PCI_VENDOR(pciid) &&
611 0 : pci2id[i].pci_prod == PCI_PRODUCT(pciid)) {
612 0 : offtbl = pci2id[i].card_id;
613 0 : break;
614 : }
615 : }
616 :
617 0 : if (offtbl == NULL) {
618 : #ifdef HIFN_DEBUG
619 : printf(": Unknown card!\n");
620 : #endif
621 0 : return (1);
622 : }
623 :
624 0 : ramcfg = READ_REG_0(sc, HIFN_0_PUCNFG);
625 0 : dmacfg = READ_REG_1(sc, HIFN_1_DMA_CNFG);
626 :
627 : /*
628 : * The RAM config register's encrypt level bit needs to be set before
629 : * every read performed on the encryption level register.
630 : */
631 0 : WRITE_REG_0(sc, HIFN_0_PUCNFG, ramcfg | HIFN_PUCNFG_CHIPID);
632 :
633 0 : encl = READ_REG_0(sc, HIFN_0_PUSTAT) & HIFN_PUSTAT_CHIPENA;
634 :
635 : /*
636 : * Make sure we don't re-unlock. Two unlocks kills chip until the
637 : * next reboot.
638 : */
639 0 : if (encl == HIFN_PUSTAT_ENA_1 || encl == HIFN_PUSTAT_ENA_2) {
640 : #ifdef HIFN_DEBUG
641 : printf(": Strong Crypto already enabled!\n");
642 : #endif
643 : goto report;
644 : }
645 :
646 0 : if (encl != 0 && encl != HIFN_PUSTAT_ENA_0) {
647 : #ifdef HIFN_DEBUG
648 : printf(": Unknown encryption level\n");
649 : #endif
650 0 : return 1;
651 : }
652 :
653 0 : WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_UNLOCK |
654 : HIFN_DMACNFG_MSTRESET | HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE);
655 0 : DELAY(1000);
656 0 : addr = READ_REG_1(sc, HIFN_1_UNLOCK_SECRET1);
657 0 : DELAY(1000);
658 0 : WRITE_REG_1(sc, HIFN_1_UNLOCK_SECRET2, 0);
659 0 : DELAY(1000);
660 :
661 0 : for (i = 0; i <= 12; i++) {
662 0 : addr = hifn_next_signature(addr, offtbl[i] + 0x101);
663 0 : WRITE_REG_1(sc, HIFN_1_UNLOCK_SECRET2, addr);
664 :
665 0 : DELAY(1000);
666 : }
667 :
668 0 : WRITE_REG_0(sc, HIFN_0_PUCNFG, ramcfg | HIFN_PUCNFG_CHIPID);
669 0 : encl = READ_REG_0(sc, HIFN_0_PUSTAT) & HIFN_PUSTAT_CHIPENA;
670 :
671 : #ifdef HIFN_DEBUG
672 : if (encl != HIFN_PUSTAT_ENA_1 && encl != HIFN_PUSTAT_ENA_2)
673 : printf(": engine is permanently locked until next system reset");
674 : else
675 : printf(": engine enabled successfully!");
676 : #endif
677 :
678 : report:
679 0 : WRITE_REG_0(sc, HIFN_0_PUCNFG, ramcfg);
680 0 : WRITE_REG_1(sc, HIFN_1_DMA_CNFG, dmacfg);
681 :
682 0 : switch (encl) {
683 : case HIFN_PUSTAT_ENA_0:
684 : offtbl = "LZS";
685 0 : break;
686 : case HIFN_PUSTAT_ENA_1:
687 : offtbl = "LZS DES";
688 0 : break;
689 : case HIFN_PUSTAT_ENA_2:
690 : offtbl = "LZS 3DES ARC4 MD5 SHA1";
691 0 : break;
692 : default:
693 : offtbl = "disabled";
694 0 : break;
695 : }
696 0 : printf(": %s", offtbl);
697 0 : if (sc->sc_flags & HIFN_HAS_RNG)
698 0 : printf(" RNG");
699 0 : if (sc->sc_flags & HIFN_HAS_AES)
700 0 : printf(" AES");
701 0 : if (sc->sc_flags & HIFN_HAS_PUBLIC)
702 0 : printf(" PK");
703 0 : printf(", ");
704 :
705 0 : return (0);
706 0 : }
707 :
708 : /*
709 : * Give initial values to the registers listed in the "Register Space"
710 : * section of the HIFN Software Development reference manual.
711 : */
712 : void
713 0 : hifn_init_pci_registers(struct hifn_softc *sc)
714 : {
715 : /* write fixed values needed by the Initialization registers */
716 0 : WRITE_REG_0(sc, HIFN_0_PUCTRL, HIFN_PUCTRL_DMAENA);
717 0 : WRITE_REG_0(sc, HIFN_0_FIFOCNFG, HIFN_FIFOCNFG_THRESHOLD);
718 0 : WRITE_REG_0(sc, HIFN_0_PUIER, HIFN_PUIER_DSTOVER);
719 :
720 : /* write all 4 ring address registers */
721 0 : WRITE_REG_1(sc, HIFN_1_DMA_CRAR, sc->sc_dmamap->dm_segs[0].ds_addr +
722 : offsetof(struct hifn_dma, cmdr[0]));
723 0 : WRITE_REG_1(sc, HIFN_1_DMA_SRAR, sc->sc_dmamap->dm_segs[0].ds_addr +
724 : offsetof(struct hifn_dma, srcr[0]));
725 0 : WRITE_REG_1(sc, HIFN_1_DMA_DRAR, sc->sc_dmamap->dm_segs[0].ds_addr +
726 : offsetof(struct hifn_dma, dstr[0]));
727 0 : WRITE_REG_1(sc, HIFN_1_DMA_RRAR, sc->sc_dmamap->dm_segs[0].ds_addr +
728 : offsetof(struct hifn_dma, resr[0]));
729 :
730 0 : DELAY(2000);
731 :
732 : /* write status register */
733 0 : WRITE_REG_1(sc, HIFN_1_DMA_CSR,
734 : HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS |
735 : HIFN_DMACSR_S_CTRL_DIS | HIFN_DMACSR_C_CTRL_DIS |
736 : HIFN_DMACSR_D_ABORT | HIFN_DMACSR_D_DONE | HIFN_DMACSR_D_LAST |
737 : HIFN_DMACSR_D_WAIT | HIFN_DMACSR_D_OVER |
738 : HIFN_DMACSR_R_ABORT | HIFN_DMACSR_R_DONE | HIFN_DMACSR_R_LAST |
739 : HIFN_DMACSR_R_WAIT | HIFN_DMACSR_R_OVER |
740 : HIFN_DMACSR_S_ABORT | HIFN_DMACSR_S_DONE | HIFN_DMACSR_S_LAST |
741 : HIFN_DMACSR_S_WAIT |
742 : HIFN_DMACSR_C_ABORT | HIFN_DMACSR_C_DONE | HIFN_DMACSR_C_LAST |
743 : HIFN_DMACSR_C_WAIT |
744 : HIFN_DMACSR_ENGINE |
745 : ((sc->sc_flags & HIFN_HAS_PUBLIC) ?
746 : HIFN_DMACSR_PUBDONE : 0) |
747 : ((sc->sc_flags & HIFN_IS_7811) ?
748 : HIFN_DMACSR_ILLW | HIFN_DMACSR_ILLR : 0));
749 :
750 0 : sc->sc_d_busy = sc->sc_r_busy = sc->sc_s_busy = sc->sc_c_busy = 0;
751 0 : sc->sc_dmaier |= HIFN_DMAIER_R_DONE | HIFN_DMAIER_C_ABORT |
752 : HIFN_DMAIER_D_OVER | HIFN_DMAIER_R_OVER |
753 : HIFN_DMAIER_S_ABORT | HIFN_DMAIER_D_ABORT | HIFN_DMAIER_R_ABORT |
754 0 : HIFN_DMAIER_ENGINE |
755 0 : ((sc->sc_flags & HIFN_IS_7811) ?
756 : HIFN_DMAIER_ILLW | HIFN_DMAIER_ILLR : 0);
757 0 : sc->sc_dmaier &= ~HIFN_DMAIER_C_WAIT;
758 0 : WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier);
759 0 : CLR_LED(sc, HIFN_MIPSRST_LED0 | HIFN_MIPSRST_LED1 | HIFN_MIPSRST_LED2);
760 :
761 0 : if (sc->sc_flags & HIFN_IS_7956) {
762 0 : WRITE_REG_0(sc, HIFN_0_PUCNFG, HIFN_PUCNFG_COMPSING |
763 : HIFN_PUCNFG_TCALLPHASES |
764 : HIFN_PUCNFG_TCDRVTOTEM | HIFN_PUCNFG_BUS32);
765 0 : WRITE_REG_1(sc, HIFN_1_PLL, HIFN_PLL_7956);
766 0 : } else {
767 0 : WRITE_REG_0(sc, HIFN_0_PUCNFG, HIFN_PUCNFG_COMPSING |
768 : HIFN_PUCNFG_DRFR_128 | HIFN_PUCNFG_TCALLPHASES |
769 : HIFN_PUCNFG_TCDRVTOTEM | HIFN_PUCNFG_BUS32 |
770 : (sc->sc_drammodel ? HIFN_PUCNFG_DRAM : HIFN_PUCNFG_SRAM));
771 : }
772 :
773 0 : WRITE_REG_0(sc, HIFN_0_PUISR, HIFN_PUISR_DSTOVER);
774 0 : WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET |
775 : HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE | HIFN_DMACNFG_LAST |
776 : ((HIFN_POLL_FREQUENCY << 16 ) & HIFN_DMACNFG_POLLFREQ) |
777 : ((HIFN_POLL_SCALAR << 8) & HIFN_DMACNFG_POLLINVAL));
778 0 : }
779 :
780 : /*
781 : * The maximum number of sessions supported by the card
782 : * is dependent on the amount of context ram, which
783 : * encryption algorithms are enabled, and how compression
784 : * is configured. This should be configured before this
785 : * routine is called.
786 : */
787 : void
788 0 : hifn_sessions(struct hifn_softc *sc)
789 : {
790 : u_int32_t pucnfg;
791 : int ctxsize;
792 :
793 0 : pucnfg = READ_REG_0(sc, HIFN_0_PUCNFG);
794 :
795 0 : if (pucnfg & HIFN_PUCNFG_COMPSING) {
796 0 : if (pucnfg & HIFN_PUCNFG_ENCCNFG)
797 0 : ctxsize = 128;
798 : else
799 : ctxsize = 512;
800 : /*
801 : * 7955/7956 has internal context memory of 32K
802 : */
803 0 : if (sc->sc_flags & HIFN_IS_7956)
804 0 : sc->sc_maxses = 32768 / ctxsize;
805 : else
806 0 : sc->sc_maxses = 1 +
807 0 : ((sc->sc_ramsize - 32768) / ctxsize);
808 : }
809 : else
810 0 : sc->sc_maxses = sc->sc_ramsize / 16384;
811 :
812 0 : if (sc->sc_maxses > 2048)
813 0 : sc->sc_maxses = 2048;
814 0 : }
815 :
816 : /*
817 : * Determine ram type (sram or dram). Board should be just out of a reset
818 : * state when this is called.
819 : */
820 : int
821 0 : hifn_ramtype(struct hifn_softc *sc)
822 : {
823 0 : u_int8_t data[8], dataexpect[8];
824 : int i;
825 :
826 0 : for (i = 0; i < sizeof(data); i++)
827 0 : data[i] = dataexpect[i] = 0x55;
828 0 : if (hifn_writeramaddr(sc, 0, data))
829 0 : return (-1);
830 0 : if (hifn_readramaddr(sc, 0, data))
831 0 : return (-1);
832 0 : if (bcmp(data, dataexpect, sizeof(data)) != 0) {
833 0 : sc->sc_drammodel = 1;
834 0 : return (0);
835 : }
836 :
837 0 : for (i = 0; i < sizeof(data); i++)
838 0 : data[i] = dataexpect[i] = 0xaa;
839 0 : if (hifn_writeramaddr(sc, 0, data))
840 0 : return (-1);
841 0 : if (hifn_readramaddr(sc, 0, data))
842 0 : return (-1);
843 0 : if (bcmp(data, dataexpect, sizeof(data)) != 0) {
844 0 : sc->sc_drammodel = 1;
845 0 : return (0);
846 : }
847 :
848 0 : return (0);
849 0 : }
850 :
851 : #define HIFN_SRAM_MAX (32 << 20)
852 : #define HIFN_SRAM_STEP_SIZE 16384
853 : #define HIFN_SRAM_GRANULARITY (HIFN_SRAM_MAX / HIFN_SRAM_STEP_SIZE)
854 :
855 : int
856 0 : hifn_sramsize(struct hifn_softc *sc)
857 : {
858 : u_int32_t a;
859 0 : u_int8_t data[8];
860 0 : u_int8_t dataexpect[sizeof(data)];
861 0 : int32_t i;
862 :
863 0 : for (i = 0; i < sizeof(data); i++)
864 0 : data[i] = dataexpect[i] = i ^ 0x5a;
865 :
866 0 : for (i = HIFN_SRAM_GRANULARITY - 1; i >= 0; i--) {
867 0 : a = i * HIFN_SRAM_STEP_SIZE;
868 0 : bcopy(&i, data, sizeof(i));
869 0 : hifn_writeramaddr(sc, a, data);
870 : }
871 :
872 0 : for (i = 0; i < HIFN_SRAM_GRANULARITY; i++) {
873 0 : a = i * HIFN_SRAM_STEP_SIZE;
874 0 : bcopy(&i, dataexpect, sizeof(i));
875 0 : if (hifn_readramaddr(sc, a, data) < 0)
876 0 : return (0);
877 0 : if (bcmp(data, dataexpect, sizeof(data)) != 0)
878 0 : return (0);
879 0 : sc->sc_ramsize = a + HIFN_SRAM_STEP_SIZE;
880 : }
881 :
882 0 : return (0);
883 0 : }
884 :
885 : /*
886 : * XXX For dram boards, one should really try all of the
887 : * HIFN_PUCNFG_DSZ_*'s. This just assumes that PUCNFG
888 : * is already set up correctly.
889 : */
890 : int
891 0 : hifn_dramsize(struct hifn_softc *sc)
892 : {
893 : u_int32_t cnfg;
894 :
895 0 : if (sc->sc_flags & HIFN_IS_7956) {
896 : /*
897 : * 7956/7956 have a fixed internal ram of only 32K.
898 : */
899 0 : sc->sc_ramsize = 32768;
900 0 : } else {
901 0 : cnfg = READ_REG_0(sc, HIFN_0_PUCNFG) &
902 : HIFN_PUCNFG_DRAMMASK;
903 0 : sc->sc_ramsize = 1 << ((cnfg >> 13) + 18);
904 : }
905 0 : return (0);
906 : }
907 :
908 : void
909 0 : hifn_alloc_slot(struct hifn_softc *sc, int *cmdp, int *srcp,
910 : int *dstp, int *resp)
911 : {
912 0 : struct hifn_dma *dma = sc->sc_dma;
913 :
914 0 : if (dma->cmdi == HIFN_D_CMD_RSIZE) {
915 0 : dma->cmdi = 0;
916 0 : dma->cmdr[HIFN_D_CMD_RSIZE].l = htole32(HIFN_D_VALID |
917 : HIFN_D_JUMP | HIFN_D_MASKDONEIRQ);
918 0 : HIFN_CMDR_SYNC(sc, HIFN_D_CMD_RSIZE,
919 : BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
920 0 : }
921 0 : *cmdp = dma->cmdi++;
922 0 : dma->cmdk = dma->cmdi;
923 :
924 0 : if (dma->srci == HIFN_D_SRC_RSIZE) {
925 0 : dma->srci = 0;
926 0 : dma->srcr[HIFN_D_SRC_RSIZE].l = htole32(HIFN_D_VALID |
927 : HIFN_D_JUMP | HIFN_D_MASKDONEIRQ);
928 0 : HIFN_SRCR_SYNC(sc, HIFN_D_SRC_RSIZE,
929 : BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
930 0 : }
931 0 : *srcp = dma->srci++;
932 0 : dma->srck = dma->srci;
933 :
934 0 : if (dma->dsti == HIFN_D_DST_RSIZE) {
935 0 : dma->dsti = 0;
936 0 : dma->dstr[HIFN_D_DST_RSIZE].l = htole32(HIFN_D_VALID |
937 : HIFN_D_JUMP | HIFN_D_MASKDONEIRQ);
938 0 : HIFN_DSTR_SYNC(sc, HIFN_D_DST_RSIZE,
939 : BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
940 0 : }
941 0 : *dstp = dma->dsti++;
942 0 : dma->dstk = dma->dsti;
943 :
944 0 : if (dma->resi == HIFN_D_RES_RSIZE) {
945 0 : dma->resi = 0;
946 0 : dma->resr[HIFN_D_RES_RSIZE].l = htole32(HIFN_D_VALID |
947 : HIFN_D_JUMP | HIFN_D_MASKDONEIRQ);
948 0 : HIFN_RESR_SYNC(sc, HIFN_D_RES_RSIZE,
949 : BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
950 0 : }
951 0 : *resp = dma->resi++;
952 0 : dma->resk = dma->resi;
953 0 : }
954 :
955 : int
956 0 : hifn_writeramaddr(struct hifn_softc *sc, int addr, u_int8_t *data)
957 : {
958 0 : struct hifn_dma *dma = sc->sc_dma;
959 0 : struct hifn_base_command wc;
960 : const u_int32_t masks = HIFN_D_VALID | HIFN_D_LAST | HIFN_D_MASKDONEIRQ;
961 0 : int r, cmdi, resi, srci, dsti;
962 :
963 0 : wc.masks = htole16(3 << 13);
964 0 : wc.session_num = htole16(addr >> 14);
965 0 : wc.total_source_count = htole16(8);
966 0 : wc.total_dest_count = htole16(addr & 0x3fff);
967 :
968 0 : hifn_alloc_slot(sc, &cmdi, &srci, &dsti, &resi);
969 :
970 0 : WRITE_REG_1(sc, HIFN_1_DMA_CSR,
971 : HIFN_DMACSR_C_CTRL_ENA | HIFN_DMACSR_S_CTRL_ENA |
972 : HIFN_DMACSR_D_CTRL_ENA | HIFN_DMACSR_R_CTRL_ENA);
973 :
974 : /* build write command */
975 0 : bzero(dma->command_bufs[cmdi], HIFN_MAX_COMMAND);
976 0 : *(struct hifn_base_command *)dma->command_bufs[cmdi] = wc;
977 0 : bcopy(data, &dma->test_src, sizeof(dma->test_src));
978 :
979 0 : dma->srcr[srci].p = htole32(sc->sc_dmamap->dm_segs[0].ds_addr
980 : + offsetof(struct hifn_dma, test_src));
981 0 : dma->dstr[dsti].p = htole32(sc->sc_dmamap->dm_segs[0].ds_addr
982 : + offsetof(struct hifn_dma, test_dst));
983 :
984 0 : dma->cmdr[cmdi].l = htole32(16 | masks);
985 0 : dma->srcr[srci].l = htole32(8 | masks);
986 0 : dma->dstr[dsti].l = htole32(4 | masks);
987 0 : dma->resr[resi].l = htole32(4 | masks);
988 :
989 0 : bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
990 : 0, sc->sc_dmamap->dm_mapsize,
991 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
992 :
993 0 : for (r = 10000; r >= 0; r--) {
994 0 : DELAY(10);
995 0 : bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
996 : 0, sc->sc_dmamap->dm_mapsize,
997 : BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
998 0 : if ((dma->resr[resi].l & htole32(HIFN_D_VALID)) == 0)
999 : break;
1000 0 : bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
1001 : 0, sc->sc_dmamap->dm_mapsize,
1002 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1003 : }
1004 0 : if (r == 0) {
1005 0 : printf("%s: writeramaddr -- "
1006 : "result[%d](addr %d) still valid\n",
1007 0 : sc->sc_dv.dv_xname, resi, addr);
1008 :
1009 0 : return (-1);
1010 : } else
1011 : r = 0;
1012 :
1013 0 : WRITE_REG_1(sc, HIFN_1_DMA_CSR,
1014 : HIFN_DMACSR_C_CTRL_DIS | HIFN_DMACSR_S_CTRL_DIS |
1015 : HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS);
1016 :
1017 0 : return (r);
1018 0 : }
1019 :
1020 : int
1021 0 : hifn_readramaddr(struct hifn_softc *sc, int addr, u_int8_t *data)
1022 : {
1023 0 : struct hifn_dma *dma = sc->sc_dma;
1024 0 : struct hifn_base_command rc;
1025 : const u_int32_t masks = HIFN_D_VALID | HIFN_D_LAST | HIFN_D_MASKDONEIRQ;
1026 0 : int r, cmdi, srci, dsti, resi;
1027 :
1028 0 : rc.masks = htole16(2 << 13);
1029 0 : rc.session_num = htole16(addr >> 14);
1030 0 : rc.total_source_count = htole16(addr & 0x3fff);
1031 0 : rc.total_dest_count = htole16(8);
1032 :
1033 0 : hifn_alloc_slot(sc, &cmdi, &srci, &dsti, &resi);
1034 :
1035 0 : WRITE_REG_1(sc, HIFN_1_DMA_CSR,
1036 : HIFN_DMACSR_C_CTRL_ENA | HIFN_DMACSR_S_CTRL_ENA |
1037 : HIFN_DMACSR_D_CTRL_ENA | HIFN_DMACSR_R_CTRL_ENA);
1038 :
1039 0 : bzero(dma->command_bufs[cmdi], HIFN_MAX_COMMAND);
1040 0 : *(struct hifn_base_command *)dma->command_bufs[cmdi] = rc;
1041 :
1042 0 : dma->srcr[srci].p = htole32(sc->sc_dmamap->dm_segs[0].ds_addr +
1043 : offsetof(struct hifn_dma, test_src));
1044 0 : dma->test_src = 0;
1045 0 : dma->dstr[dsti].p = htole32(sc->sc_dmamap->dm_segs[0].ds_addr +
1046 : offsetof(struct hifn_dma, test_dst));
1047 0 : dma->test_dst = 0;
1048 0 : dma->cmdr[cmdi].l = htole32(8 | masks);
1049 0 : dma->srcr[srci].l = htole32(8 | masks);
1050 0 : dma->dstr[dsti].l = htole32(8 | masks);
1051 0 : dma->resr[resi].l = htole32(HIFN_MAX_RESULT | masks);
1052 :
1053 0 : bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
1054 : 0, sc->sc_dmamap->dm_mapsize,
1055 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1056 :
1057 0 : for (r = 10000; r >= 0; r--) {
1058 0 : DELAY(10);
1059 0 : bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
1060 : 0, sc->sc_dmamap->dm_mapsize,
1061 : BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1062 0 : if ((dma->resr[resi].l & htole32(HIFN_D_VALID)) == 0)
1063 : break;
1064 0 : bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
1065 : 0, sc->sc_dmamap->dm_mapsize,
1066 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1067 : }
1068 0 : if (r == 0) {
1069 0 : printf("%s: readramaddr -- "
1070 : "result[%d](addr %d) still valid\n",
1071 0 : sc->sc_dv.dv_xname, resi, addr);
1072 : r = -1;
1073 0 : } else {
1074 : r = 0;
1075 0 : bcopy(&dma->test_dst, data, sizeof(dma->test_dst));
1076 : }
1077 :
1078 0 : WRITE_REG_1(sc, HIFN_1_DMA_CSR,
1079 : HIFN_DMACSR_C_CTRL_DIS | HIFN_DMACSR_S_CTRL_DIS |
1080 : HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS);
1081 :
1082 0 : return (r);
1083 0 : }
1084 :
1085 : /*
1086 : * Initialize the descriptor rings.
1087 : */
1088 : void
1089 0 : hifn_init_dma(struct hifn_softc *sc)
1090 : {
1091 0 : struct hifn_dma *dma = sc->sc_dma;
1092 : int i;
1093 :
1094 0 : hifn_set_retry(sc);
1095 :
1096 : /* initialize static pointer values */
1097 0 : for (i = 0; i < HIFN_D_CMD_RSIZE; i++)
1098 0 : dma->cmdr[i].p = htole32(sc->sc_dmamap->dm_segs[0].ds_addr +
1099 : offsetof(struct hifn_dma, command_bufs[i][0]));
1100 0 : for (i = 0; i < HIFN_D_RES_RSIZE; i++)
1101 0 : dma->resr[i].p = htole32(sc->sc_dmamap->dm_segs[0].ds_addr +
1102 : offsetof(struct hifn_dma, result_bufs[i][0]));
1103 :
1104 0 : dma->cmdr[HIFN_D_CMD_RSIZE].p =
1105 0 : htole32(sc->sc_dmamap->dm_segs[0].ds_addr +
1106 : offsetof(struct hifn_dma, cmdr[0]));
1107 0 : dma->srcr[HIFN_D_SRC_RSIZE].p =
1108 0 : htole32(sc->sc_dmamap->dm_segs[0].ds_addr +
1109 : offsetof(struct hifn_dma, srcr[0]));
1110 0 : dma->dstr[HIFN_D_DST_RSIZE].p =
1111 0 : htole32(sc->sc_dmamap->dm_segs[0].ds_addr +
1112 : offsetof(struct hifn_dma, dstr[0]));
1113 0 : dma->resr[HIFN_D_RES_RSIZE].p =
1114 0 : htole32(sc->sc_dmamap->dm_segs[0].ds_addr +
1115 : offsetof(struct hifn_dma, resr[0]));
1116 :
1117 0 : dma->cmdu = dma->srcu = dma->dstu = dma->resu = 0;
1118 0 : dma->cmdi = dma->srci = dma->dsti = dma->resi = 0;
1119 0 : dma->cmdk = dma->srck = dma->dstk = dma->resk = 0;
1120 0 : }
1121 :
1122 : /*
1123 : * Writes out the raw command buffer space. Returns the
1124 : * command buffer size.
1125 : */
1126 : u_int
1127 0 : hifn_write_command(struct hifn_command *cmd, u_int8_t *buf)
1128 : {
1129 : u_int8_t *buf_pos;
1130 : struct hifn_base_command *base_cmd;
1131 : struct hifn_mac_command *mac_cmd;
1132 : struct hifn_crypt_command *cry_cmd;
1133 : struct hifn_comp_command *comp_cmd;
1134 : int using_mac, using_crypt, using_comp, len, ivlen;
1135 : u_int32_t dlen, slen;
1136 :
1137 : buf_pos = buf;
1138 0 : using_mac = cmd->base_masks & HIFN_BASE_CMD_MAC;
1139 0 : using_crypt = cmd->base_masks & HIFN_BASE_CMD_CRYPT;
1140 0 : using_comp = cmd->base_masks & HIFN_BASE_CMD_COMP;
1141 :
1142 0 : base_cmd = (struct hifn_base_command *)buf_pos;
1143 0 : base_cmd->masks = htole16(cmd->base_masks);
1144 0 : slen = cmd->src_map->dm_mapsize;
1145 0 : if (cmd->sloplen)
1146 0 : dlen = cmd->dst_map->dm_mapsize - cmd->sloplen +
1147 : sizeof(u_int32_t);
1148 : else
1149 0 : dlen = cmd->dst_map->dm_mapsize;
1150 0 : base_cmd->total_source_count = htole16(slen & HIFN_BASE_CMD_LENMASK_LO);
1151 0 : base_cmd->total_dest_count = htole16(dlen & HIFN_BASE_CMD_LENMASK_LO);
1152 0 : dlen >>= 16;
1153 0 : slen >>= 16;
1154 0 : base_cmd->session_num = htole16(
1155 : ((slen << HIFN_BASE_CMD_SRCLEN_S) & HIFN_BASE_CMD_SRCLEN_M) |
1156 : ((dlen << HIFN_BASE_CMD_DSTLEN_S) & HIFN_BASE_CMD_DSTLEN_M));
1157 0 : buf_pos += sizeof(struct hifn_base_command);
1158 :
1159 0 : if (using_comp) {
1160 0 : comp_cmd = (struct hifn_comp_command *)buf_pos;
1161 0 : dlen = cmd->compcrd->crd_len;
1162 0 : comp_cmd->source_count = htole16(dlen & 0xffff);
1163 0 : dlen >>= 16;
1164 0 : comp_cmd->masks = htole16(cmd->comp_masks |
1165 : ((dlen << HIFN_COMP_CMD_SRCLEN_S) & HIFN_COMP_CMD_SRCLEN_M));
1166 0 : comp_cmd->header_skip = htole16(cmd->compcrd->crd_skip);
1167 0 : comp_cmd->reserved = 0;
1168 0 : buf_pos += sizeof(struct hifn_comp_command);
1169 0 : }
1170 :
1171 0 : if (using_mac) {
1172 0 : mac_cmd = (struct hifn_mac_command *)buf_pos;
1173 0 : dlen = cmd->maccrd->crd_len;
1174 0 : mac_cmd->source_count = htole16(dlen & 0xffff);
1175 0 : dlen >>= 16;
1176 0 : mac_cmd->masks = htole16(cmd->mac_masks |
1177 : ((dlen << HIFN_MAC_CMD_SRCLEN_S) & HIFN_MAC_CMD_SRCLEN_M));
1178 0 : mac_cmd->header_skip = htole16(cmd->maccrd->crd_skip);
1179 0 : mac_cmd->reserved = 0;
1180 0 : buf_pos += sizeof(struct hifn_mac_command);
1181 0 : }
1182 :
1183 0 : if (using_crypt) {
1184 0 : cry_cmd = (struct hifn_crypt_command *)buf_pos;
1185 0 : dlen = cmd->enccrd->crd_len;
1186 0 : cry_cmd->source_count = htole16(dlen & 0xffff);
1187 0 : dlen >>= 16;
1188 0 : cry_cmd->masks = htole16(cmd->cry_masks |
1189 : ((dlen << HIFN_CRYPT_CMD_SRCLEN_S) & HIFN_CRYPT_CMD_SRCLEN_M));
1190 0 : cry_cmd->header_skip = htole16(cmd->enccrd->crd_skip);
1191 0 : cry_cmd->reserved = 0;
1192 0 : buf_pos += sizeof(struct hifn_crypt_command);
1193 0 : }
1194 :
1195 0 : if (using_mac && cmd->mac_masks & HIFN_MAC_CMD_NEW_KEY) {
1196 0 : bcopy(cmd->mac, buf_pos, HIFN_MAC_KEY_LENGTH);
1197 0 : buf_pos += HIFN_MAC_KEY_LENGTH;
1198 0 : }
1199 :
1200 0 : if (using_crypt && cmd->cry_masks & HIFN_CRYPT_CMD_NEW_KEY) {
1201 0 : switch (cmd->cry_masks & HIFN_CRYPT_CMD_ALG_MASK) {
1202 : case HIFN_CRYPT_CMD_ALG_3DES:
1203 0 : bcopy(cmd->ck, buf_pos, HIFN_3DES_KEY_LENGTH);
1204 0 : buf_pos += HIFN_3DES_KEY_LENGTH;
1205 0 : break;
1206 : case HIFN_CRYPT_CMD_ALG_DES:
1207 0 : bcopy(cmd->ck, buf_pos, HIFN_DES_KEY_LENGTH);
1208 0 : buf_pos += HIFN_DES_KEY_LENGTH;
1209 0 : break;
1210 : case HIFN_CRYPT_CMD_ALG_RC4:
1211 : len = 256;
1212 0 : do {
1213 : int clen;
1214 :
1215 0 : clen = MIN(cmd->cklen, len);
1216 0 : bcopy(cmd->ck, buf_pos, clen);
1217 0 : len -= clen;
1218 0 : buf_pos += clen;
1219 0 : } while (len > 0);
1220 0 : bzero(buf_pos, 4);
1221 0 : buf_pos += 4;
1222 0 : break;
1223 : case HIFN_CRYPT_CMD_ALG_AES:
1224 : /*
1225 : * AES key are variable 128, 192 and
1226 : * 256 bits (16, 24 and 32 bytes).
1227 : */
1228 0 : bcopy(cmd->ck, buf_pos, cmd->cklen);
1229 0 : buf_pos += cmd->cklen;
1230 0 : break;
1231 : }
1232 : }
1233 :
1234 0 : if (using_crypt && cmd->cry_masks & HIFN_CRYPT_CMD_NEW_IV) {
1235 0 : if ((cmd->cry_masks & HIFN_CRYPT_CMD_ALG_MASK) ==
1236 : HIFN_CRYPT_CMD_ALG_AES)
1237 0 : ivlen = HIFN_AES_IV_LENGTH;
1238 : else
1239 : ivlen = HIFN_IV_LENGTH;
1240 0 : bcopy(cmd->iv, buf_pos, ivlen);
1241 0 : buf_pos += ivlen;
1242 0 : }
1243 :
1244 0 : if ((cmd->base_masks & (HIFN_BASE_CMD_MAC | HIFN_BASE_CMD_CRYPT |
1245 0 : HIFN_BASE_CMD_COMP)) == 0) {
1246 0 : bzero(buf_pos, 8);
1247 0 : buf_pos += 8;
1248 0 : }
1249 :
1250 0 : return (buf_pos - buf);
1251 : }
1252 :
1253 : int
1254 0 : hifn_dmamap_aligned(bus_dmamap_t map)
1255 : {
1256 : int i;
1257 :
1258 0 : for (i = 0; i < map->dm_nsegs; i++) {
1259 0 : if (map->dm_segs[i].ds_addr & 3)
1260 0 : return (0);
1261 0 : if ((i != (map->dm_nsegs - 1)) &&
1262 0 : (map->dm_segs[i].ds_len & 3))
1263 0 : return (0);
1264 : }
1265 0 : return (1);
1266 0 : }
1267 :
1268 : int
1269 0 : hifn_dmamap_load_dst(struct hifn_softc *sc, struct hifn_command *cmd)
1270 : {
1271 0 : struct hifn_dma *dma = sc->sc_dma;
1272 0 : bus_dmamap_t map = cmd->dst_map;
1273 : u_int32_t p, l;
1274 : int idx, used = 0, i;
1275 :
1276 0 : idx = dma->dsti;
1277 0 : for (i = 0; i < map->dm_nsegs - 1; i++) {
1278 0 : dma->dstr[idx].p = htole32(map->dm_segs[i].ds_addr);
1279 0 : dma->dstr[idx].l = htole32(HIFN_D_VALID |
1280 : HIFN_D_MASKDONEIRQ | map->dm_segs[i].ds_len);
1281 0 : HIFN_DSTR_SYNC(sc, idx,
1282 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1283 0 : used++;
1284 :
1285 0 : if (++idx == HIFN_D_DST_RSIZE) {
1286 0 : dma->dstr[idx].l = htole32(HIFN_D_VALID |
1287 : HIFN_D_JUMP | HIFN_D_MASKDONEIRQ);
1288 0 : HIFN_DSTR_SYNC(sc, idx,
1289 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1290 : idx = 0;
1291 0 : }
1292 : }
1293 :
1294 0 : if (cmd->sloplen == 0) {
1295 0 : p = map->dm_segs[i].ds_addr;
1296 0 : l = HIFN_D_VALID | HIFN_D_MASKDONEIRQ | HIFN_D_LAST |
1297 0 : map->dm_segs[i].ds_len;
1298 0 : } else {
1299 0 : p = sc->sc_dmamap->dm_segs[0].ds_addr +
1300 0 : offsetof(struct hifn_dma, slop[cmd->slopidx]);
1301 : l = HIFN_D_VALID | HIFN_D_MASKDONEIRQ | HIFN_D_LAST |
1302 : sizeof(u_int32_t);
1303 :
1304 0 : if ((map->dm_segs[i].ds_len - cmd->sloplen) != 0) {
1305 0 : dma->dstr[idx].p = htole32(map->dm_segs[i].ds_addr);
1306 0 : dma->dstr[idx].l = htole32(HIFN_D_VALID |
1307 : HIFN_D_MASKDONEIRQ |
1308 : (map->dm_segs[i].ds_len - cmd->sloplen));
1309 0 : HIFN_DSTR_SYNC(sc, idx,
1310 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1311 0 : used++;
1312 :
1313 0 : if (++idx == HIFN_D_DST_RSIZE) {
1314 0 : dma->dstr[idx].l = htole32(HIFN_D_VALID |
1315 : HIFN_D_JUMP | HIFN_D_MASKDONEIRQ);
1316 0 : HIFN_DSTR_SYNC(sc, idx,
1317 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1318 : idx = 0;
1319 0 : }
1320 : }
1321 : }
1322 0 : dma->dstr[idx].p = htole32(p);
1323 0 : dma->dstr[idx].l = htole32(l);
1324 0 : HIFN_DSTR_SYNC(sc, idx, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1325 0 : used++;
1326 :
1327 0 : if (++idx == HIFN_D_DST_RSIZE) {
1328 0 : dma->dstr[idx].l = htole32(HIFN_D_VALID | HIFN_D_JUMP |
1329 : HIFN_D_MASKDONEIRQ);
1330 0 : HIFN_DSTR_SYNC(sc, idx,
1331 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1332 : idx = 0;
1333 0 : }
1334 :
1335 0 : dma->dsti = idx;
1336 0 : dma->dstu += used;
1337 0 : return (idx);
1338 : }
1339 :
1340 : int
1341 0 : hifn_dmamap_load_src(struct hifn_softc *sc, struct hifn_command *cmd)
1342 : {
1343 0 : struct hifn_dma *dma = sc->sc_dma;
1344 0 : bus_dmamap_t map = cmd->src_map;
1345 : int idx, i;
1346 : u_int32_t last = 0;
1347 :
1348 0 : idx = dma->srci;
1349 0 : for (i = 0; i < map->dm_nsegs; i++) {
1350 0 : if (i == map->dm_nsegs - 1)
1351 0 : last = HIFN_D_LAST;
1352 :
1353 0 : dma->srcr[idx].p = htole32(map->dm_segs[i].ds_addr);
1354 0 : dma->srcr[idx].l = htole32(map->dm_segs[i].ds_len |
1355 : HIFN_D_VALID | HIFN_D_MASKDONEIRQ | last);
1356 0 : HIFN_SRCR_SYNC(sc, idx,
1357 : BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
1358 :
1359 0 : if (++idx == HIFN_D_SRC_RSIZE) {
1360 0 : dma->srcr[idx].l = htole32(HIFN_D_VALID |
1361 : HIFN_D_JUMP | HIFN_D_MASKDONEIRQ);
1362 0 : HIFN_SRCR_SYNC(sc, HIFN_D_SRC_RSIZE,
1363 : BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
1364 : idx = 0;
1365 0 : }
1366 : }
1367 0 : dma->srci = idx;
1368 0 : dma->srcu += map->dm_nsegs;
1369 0 : return (idx);
1370 : }
1371 :
1372 : int
1373 0 : hifn_crypto(struct hifn_softc *sc, struct hifn_command *cmd,
1374 : struct cryptop *crp)
1375 : {
1376 0 : struct hifn_dma *dma = sc->sc_dma;
1377 : u_int32_t cmdlen;
1378 : int cmdi, resi, s, err = 0;
1379 :
1380 0 : if (bus_dmamap_create(sc->sc_dmat, HIFN_MAX_DMALEN, MAX_SCATTER,
1381 : HIFN_MAX_SEGLEN, 0, BUS_DMA_NOWAIT, &cmd->src_map))
1382 0 : return (ENOMEM);
1383 :
1384 0 : if (crp->crp_flags & CRYPTO_F_IMBUF) {
1385 0 : if (bus_dmamap_load_mbuf(sc->sc_dmat, cmd->src_map,
1386 : cmd->srcu.src_m, BUS_DMA_NOWAIT)) {
1387 : err = ENOMEM;
1388 0 : goto err_srcmap1;
1389 : }
1390 0 : } else if (crp->crp_flags & CRYPTO_F_IOV) {
1391 0 : if (bus_dmamap_load_uio(sc->sc_dmat, cmd->src_map,
1392 : cmd->srcu.src_io, BUS_DMA_NOWAIT)) {
1393 : err = ENOMEM;
1394 0 : goto err_srcmap1;
1395 : }
1396 : } else {
1397 : err = EINVAL;
1398 0 : goto err_srcmap1;
1399 : }
1400 :
1401 0 : if (hifn_dmamap_aligned(cmd->src_map)) {
1402 0 : cmd->sloplen = cmd->src_map->dm_mapsize & 3;
1403 0 : if (crp->crp_flags & CRYPTO_F_IOV)
1404 0 : cmd->dstu.dst_io = cmd->srcu.src_io;
1405 0 : else if (crp->crp_flags & CRYPTO_F_IMBUF)
1406 0 : cmd->dstu.dst_m = cmd->srcu.src_m;
1407 0 : cmd->dst_map = cmd->src_map;
1408 0 : } else {
1409 0 : if (crp->crp_flags & CRYPTO_F_IOV) {
1410 : err = EINVAL;
1411 0 : goto err_srcmap;
1412 0 : } else if (crp->crp_flags & CRYPTO_F_IMBUF) {
1413 : int totlen, len;
1414 : struct mbuf *m, *m0, *mlast;
1415 :
1416 0 : totlen = cmd->src_map->dm_mapsize;
1417 0 : if (cmd->srcu.src_m->m_flags & M_PKTHDR) {
1418 : len = MHLEN;
1419 0 : MGETHDR(m0, M_DONTWAIT, MT_DATA);
1420 0 : } else {
1421 : len = MLEN;
1422 0 : MGET(m0, M_DONTWAIT, MT_DATA);
1423 : }
1424 0 : if (m0 == NULL) {
1425 : err = ENOMEM;
1426 0 : goto err_srcmap;
1427 : }
1428 0 : if (len == MHLEN) {
1429 0 : err = m_dup_pkthdr(m0, cmd->srcu.src_m,
1430 : M_DONTWAIT);
1431 0 : if (err) {
1432 0 : m_free(m0);
1433 0 : goto err_srcmap;
1434 : }
1435 : }
1436 0 : if (totlen >= MINCLSIZE) {
1437 0 : MCLGET(m0, M_DONTWAIT);
1438 0 : if (m0->m_flags & M_EXT)
1439 0 : len = MCLBYTES;
1440 : }
1441 0 : totlen -= len;
1442 0 : m0->m_pkthdr.len = m0->m_len = len;
1443 : mlast = m0;
1444 :
1445 0 : while (totlen > 0) {
1446 0 : MGET(m, M_DONTWAIT, MT_DATA);
1447 0 : if (m == NULL) {
1448 : err = ENOMEM;
1449 0 : m_freem(m0);
1450 0 : goto err_srcmap;
1451 : }
1452 : len = MLEN;
1453 0 : if (totlen >= MINCLSIZE) {
1454 0 : MCLGET(m, M_DONTWAIT);
1455 0 : if (m->m_flags & M_EXT)
1456 0 : len = MCLBYTES;
1457 : }
1458 :
1459 0 : m->m_len = len;
1460 0 : if (m0->m_flags & M_PKTHDR)
1461 0 : m0->m_pkthdr.len += len;
1462 0 : totlen -= len;
1463 :
1464 0 : mlast->m_next = m;
1465 : mlast = m;
1466 : }
1467 0 : cmd->dstu.dst_m = m0;
1468 0 : }
1469 : }
1470 :
1471 0 : if (cmd->dst_map == NULL) {
1472 0 : if (bus_dmamap_create(sc->sc_dmat,
1473 : HIFN_MAX_SEGLEN * MAX_SCATTER, MAX_SCATTER,
1474 : HIFN_MAX_SEGLEN, 0, BUS_DMA_NOWAIT, &cmd->dst_map)) {
1475 : err = ENOMEM;
1476 0 : goto err_srcmap;
1477 : }
1478 0 : if (crp->crp_flags & CRYPTO_F_IMBUF) {
1479 0 : if (bus_dmamap_load_mbuf(sc->sc_dmat, cmd->dst_map,
1480 : cmd->dstu.dst_m, BUS_DMA_NOWAIT)) {
1481 : err = ENOMEM;
1482 0 : goto err_dstmap1;
1483 : }
1484 0 : } else if (crp->crp_flags & CRYPTO_F_IOV) {
1485 0 : if (bus_dmamap_load_uio(sc->sc_dmat, cmd->dst_map,
1486 : cmd->dstu.dst_io, BUS_DMA_NOWAIT)) {
1487 : err = ENOMEM;
1488 0 : goto err_dstmap1;
1489 : }
1490 : }
1491 : }
1492 :
1493 : #ifdef HIFN_DEBUG
1494 : printf("%s: Entering cmd: stat %8x ien %8x u %d/%d/%d/%d n %d/%d\n",
1495 : sc->sc_dv.dv_xname,
1496 : READ_REG_1(sc, HIFN_1_DMA_CSR), READ_REG_1(sc, HIFN_1_DMA_IER),
1497 : dma->cmdu, dma->srcu, dma->dstu, dma->resu,
1498 : cmd->src_map->dm_nsegs, cmd->dst_map->dm_nsegs);
1499 : #endif
1500 :
1501 0 : if (cmd->src_map == cmd->dst_map)
1502 0 : bus_dmamap_sync(sc->sc_dmat, cmd->src_map,
1503 : 0, cmd->src_map->dm_mapsize,
1504 : BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
1505 : else {
1506 0 : bus_dmamap_sync(sc->sc_dmat, cmd->src_map,
1507 : 0, cmd->src_map->dm_mapsize, BUS_DMASYNC_PREWRITE);
1508 0 : bus_dmamap_sync(sc->sc_dmat, cmd->dst_map,
1509 : 0, cmd->dst_map->dm_mapsize, BUS_DMASYNC_PREREAD);
1510 : }
1511 :
1512 0 : s = splnet();
1513 :
1514 : /*
1515 : * need 1 cmd, and 1 res
1516 : * need N src, and N dst
1517 : */
1518 0 : if ((dma->cmdu + 1) > HIFN_D_CMD_RSIZE ||
1519 0 : (dma->resu + 1) > HIFN_D_RES_RSIZE) {
1520 0 : splx(s);
1521 : err = ENOMEM;
1522 0 : goto err_dstmap;
1523 : }
1524 0 : if ((dma->srcu + cmd->src_map->dm_nsegs) > HIFN_D_SRC_RSIZE ||
1525 0 : (dma->dstu + cmd->dst_map->dm_nsegs + 1) > HIFN_D_DST_RSIZE) {
1526 0 : splx(s);
1527 : err = ENOMEM;
1528 0 : goto err_dstmap;
1529 : }
1530 :
1531 0 : if (dma->cmdi == HIFN_D_CMD_RSIZE) {
1532 0 : dma->cmdi = 0;
1533 0 : dma->cmdr[HIFN_D_CMD_RSIZE].l = htole32(HIFN_D_VALID |
1534 : HIFN_D_JUMP | HIFN_D_MASKDONEIRQ);
1535 0 : HIFN_CMDR_SYNC(sc, HIFN_D_CMD_RSIZE,
1536 : BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
1537 0 : }
1538 0 : cmdi = dma->cmdi++;
1539 0 : cmdlen = hifn_write_command(cmd, dma->command_bufs[cmdi]);
1540 0 : HIFN_CMD_SYNC(sc, cmdi, BUS_DMASYNC_PREWRITE);
1541 :
1542 : /* .p for command/result already set */
1543 0 : dma->cmdr[cmdi].l = htole32(cmdlen | HIFN_D_VALID | HIFN_D_LAST |
1544 : HIFN_D_MASKDONEIRQ);
1545 0 : HIFN_CMDR_SYNC(sc, cmdi,
1546 : BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
1547 0 : dma->cmdu++;
1548 0 : if (sc->sc_c_busy == 0) {
1549 0 : WRITE_REG_1(sc, HIFN_1_DMA_CSR, HIFN_DMACSR_C_CTRL_ENA);
1550 0 : sc->sc_c_busy = 1;
1551 0 : SET_LED(sc, HIFN_MIPSRST_LED0);
1552 : }
1553 :
1554 : /*
1555 : * Always enable the command wait interrupt. We are obviously
1556 : * missing an interrupt or two somewhere. Enabling the command wait
1557 : * interrupt will guarantee we get called periodically until all
1558 : * of the queues are drained and thus work around this.
1559 : */
1560 0 : sc->sc_dmaier |= HIFN_DMAIER_C_WAIT;
1561 0 : WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier);
1562 :
1563 0 : hifnstats.hst_ipackets++;
1564 0 : hifnstats.hst_ibytes += cmd->src_map->dm_mapsize;
1565 :
1566 0 : hifn_dmamap_load_src(sc, cmd);
1567 0 : if (sc->sc_s_busy == 0) {
1568 0 : WRITE_REG_1(sc, HIFN_1_DMA_CSR, HIFN_DMACSR_S_CTRL_ENA);
1569 0 : sc->sc_s_busy = 1;
1570 0 : SET_LED(sc, HIFN_MIPSRST_LED1);
1571 : }
1572 :
1573 : /*
1574 : * Unlike other descriptors, we don't mask done interrupt from
1575 : * result descriptor.
1576 : */
1577 : #ifdef HIFN_DEBUG
1578 : printf("load res\n");
1579 : #endif
1580 0 : if (dma->resi == HIFN_D_RES_RSIZE) {
1581 0 : dma->resi = 0;
1582 0 : dma->resr[HIFN_D_RES_RSIZE].l = htole32(HIFN_D_VALID |
1583 : HIFN_D_JUMP | HIFN_D_MASKDONEIRQ);
1584 0 : HIFN_RESR_SYNC(sc, HIFN_D_RES_RSIZE,
1585 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1586 0 : }
1587 0 : resi = dma->resi++;
1588 0 : dma->hifn_commands[resi] = cmd;
1589 0 : HIFN_RES_SYNC(sc, resi, BUS_DMASYNC_PREREAD);
1590 0 : dma->resr[resi].l = htole32(HIFN_MAX_RESULT |
1591 : HIFN_D_VALID | HIFN_D_LAST);
1592 0 : HIFN_RESR_SYNC(sc, resi,
1593 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1594 0 : dma->resu++;
1595 0 : if (sc->sc_r_busy == 0) {
1596 0 : WRITE_REG_1(sc, HIFN_1_DMA_CSR, HIFN_DMACSR_R_CTRL_ENA);
1597 0 : sc->sc_r_busy = 1;
1598 0 : SET_LED(sc, HIFN_MIPSRST_LED2);
1599 : }
1600 :
1601 0 : if (cmd->sloplen)
1602 0 : cmd->slopidx = resi;
1603 :
1604 0 : hifn_dmamap_load_dst(sc, cmd);
1605 :
1606 0 : if (sc->sc_d_busy == 0) {
1607 0 : WRITE_REG_1(sc, HIFN_1_DMA_CSR, HIFN_DMACSR_D_CTRL_ENA);
1608 0 : sc->sc_d_busy = 1;
1609 0 : }
1610 :
1611 : #ifdef HIFN_DEBUG
1612 : printf("%s: command: stat %8x ier %8x\n",
1613 : sc->sc_dv.dv_xname,
1614 : READ_REG_1(sc, HIFN_1_DMA_CSR), READ_REG_1(sc, HIFN_1_DMA_IER));
1615 : #endif
1616 :
1617 0 : sc->sc_active = 5;
1618 0 : cmd->cmd_callback = hifn_callback;
1619 0 : splx(s);
1620 0 : return (err); /* success */
1621 :
1622 : err_dstmap:
1623 0 : if (cmd->src_map != cmd->dst_map)
1624 0 : bus_dmamap_unload(sc->sc_dmat, cmd->dst_map);
1625 : err_dstmap1:
1626 0 : if (cmd->src_map != cmd->dst_map)
1627 0 : bus_dmamap_destroy(sc->sc_dmat, cmd->dst_map);
1628 : err_srcmap:
1629 0 : if (crp->crp_flags & CRYPTO_F_IMBUF &&
1630 0 : cmd->srcu.src_m != cmd->dstu.dst_m)
1631 0 : m_freem(cmd->dstu.dst_m);
1632 0 : bus_dmamap_unload(sc->sc_dmat, cmd->src_map);
1633 : err_srcmap1:
1634 0 : bus_dmamap_destroy(sc->sc_dmat, cmd->src_map);
1635 0 : return (err);
1636 0 : }
1637 :
1638 : void
1639 0 : hifn_tick(void *vsc)
1640 : {
1641 0 : struct hifn_softc *sc = vsc;
1642 : int s;
1643 :
1644 0 : s = splnet();
1645 0 : if (sc->sc_active == 0) {
1646 0 : struct hifn_dma *dma = sc->sc_dma;
1647 : u_int32_t r = 0;
1648 :
1649 0 : if (dma->cmdu == 0 && sc->sc_c_busy) {
1650 0 : sc->sc_c_busy = 0;
1651 : r |= HIFN_DMACSR_C_CTRL_DIS;
1652 0 : CLR_LED(sc, HIFN_MIPSRST_LED0);
1653 : }
1654 0 : if (dma->srcu == 0 && sc->sc_s_busy) {
1655 0 : sc->sc_s_busy = 0;
1656 0 : r |= HIFN_DMACSR_S_CTRL_DIS;
1657 0 : CLR_LED(sc, HIFN_MIPSRST_LED1);
1658 : }
1659 0 : if (dma->dstu == 0 && sc->sc_d_busy) {
1660 0 : sc->sc_d_busy = 0;
1661 0 : r |= HIFN_DMACSR_D_CTRL_DIS;
1662 0 : }
1663 0 : if (dma->resu == 0 && sc->sc_r_busy) {
1664 0 : sc->sc_r_busy = 0;
1665 0 : r |= HIFN_DMACSR_R_CTRL_DIS;
1666 0 : CLR_LED(sc, HIFN_MIPSRST_LED2);
1667 : }
1668 0 : if (r)
1669 0 : WRITE_REG_1(sc, HIFN_1_DMA_CSR, r);
1670 0 : }
1671 : else
1672 0 : sc->sc_active--;
1673 0 : splx(s);
1674 0 : timeout_add_sec(&sc->sc_tickto, 1);
1675 0 : }
1676 :
1677 : int
1678 0 : hifn_intr(void *arg)
1679 : {
1680 0 : struct hifn_softc *sc = arg;
1681 0 : struct hifn_dma *dma = sc->sc_dma;
1682 : u_int32_t dmacsr, restart;
1683 : int i, u;
1684 :
1685 0 : dmacsr = READ_REG_1(sc, HIFN_1_DMA_CSR);
1686 :
1687 : #ifdef HIFN_DEBUG
1688 : printf("%s: irq: stat %08x ien %08x u %d/%d/%d/%d\n",
1689 : sc->sc_dv.dv_xname,
1690 : dmacsr, READ_REG_1(sc, HIFN_1_DMA_IER),
1691 : dma->cmdu, dma->srcu, dma->dstu, dma->resu);
1692 : #endif
1693 :
1694 : /* Nothing in the DMA unit interrupted */
1695 0 : if ((dmacsr & sc->sc_dmaier) == 0)
1696 0 : return (0);
1697 :
1698 0 : WRITE_REG_1(sc, HIFN_1_DMA_CSR, dmacsr & sc->sc_dmaier);
1699 :
1700 0 : if (dmacsr & HIFN_DMACSR_ENGINE)
1701 0 : WRITE_REG_0(sc, HIFN_0_PUISR, READ_REG_0(sc, HIFN_0_PUISR));
1702 :
1703 0 : if ((sc->sc_flags & HIFN_HAS_PUBLIC) &&
1704 0 : (dmacsr & HIFN_DMACSR_PUBDONE))
1705 0 : WRITE_REG_1(sc, HIFN_1_PUB_STATUS,
1706 : READ_REG_1(sc, HIFN_1_PUB_STATUS) | HIFN_PUBSTS_DONE);
1707 :
1708 0 : restart = dmacsr & (HIFN_DMACSR_R_OVER | HIFN_DMACSR_D_OVER);
1709 0 : if (restart)
1710 0 : printf("%s: overrun %x\n", sc->sc_dv.dv_xname, dmacsr);
1711 :
1712 0 : if (sc->sc_flags & HIFN_IS_7811) {
1713 0 : if (dmacsr & HIFN_DMACSR_ILLR)
1714 0 : printf("%s: illegal read\n", sc->sc_dv.dv_xname);
1715 0 : if (dmacsr & HIFN_DMACSR_ILLW)
1716 0 : printf("%s: illegal write\n", sc->sc_dv.dv_xname);
1717 : }
1718 :
1719 0 : restart = dmacsr & (HIFN_DMACSR_C_ABORT | HIFN_DMACSR_S_ABORT |
1720 : HIFN_DMACSR_D_ABORT | HIFN_DMACSR_R_ABORT);
1721 0 : if (restart) {
1722 0 : printf("%s: abort, resetting.\n", sc->sc_dv.dv_xname);
1723 0 : hifnstats.hst_abort++;
1724 0 : hifn_abort(sc);
1725 0 : return (1);
1726 : }
1727 :
1728 0 : if ((dmacsr & HIFN_DMACSR_C_WAIT) && (dma->resu == 0)) {
1729 : /*
1730 : * If no slots to process and we receive a "waiting on
1731 : * command" interrupt, we disable the "waiting on command"
1732 : * (by clearing it).
1733 : */
1734 0 : sc->sc_dmaier &= ~HIFN_DMAIER_C_WAIT;
1735 0 : WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier);
1736 0 : }
1737 :
1738 : /* clear the rings */
1739 0 : i = dma->resk;
1740 0 : while (dma->resu != 0) {
1741 0 : HIFN_RESR_SYNC(sc, i,
1742 : BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1743 0 : if (dma->resr[i].l & htole32(HIFN_D_VALID)) {
1744 0 : HIFN_RESR_SYNC(sc, i,
1745 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1746 0 : break;
1747 : }
1748 :
1749 0 : if (i != HIFN_D_RES_RSIZE) {
1750 : struct hifn_command *cmd;
1751 :
1752 0 : HIFN_RES_SYNC(sc, i, BUS_DMASYNC_POSTREAD);
1753 0 : cmd = dma->hifn_commands[i];
1754 :
1755 0 : (*cmd->cmd_callback)(sc, cmd, dma->result_bufs[i]);
1756 0 : hifnstats.hst_opackets++;
1757 0 : }
1758 :
1759 0 : if (++i == (HIFN_D_RES_RSIZE + 1))
1760 0 : i = 0;
1761 : else
1762 0 : dma->resu--;
1763 : }
1764 0 : dma->resk = i;
1765 :
1766 0 : i = dma->srck; u = dma->srcu;
1767 0 : while (u != 0) {
1768 0 : HIFN_SRCR_SYNC(sc, i,
1769 : BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1770 0 : if (dma->srcr[i].l & htole32(HIFN_D_VALID)) {
1771 0 : HIFN_SRCR_SYNC(sc, i,
1772 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1773 0 : break;
1774 : }
1775 0 : if (++i == (HIFN_D_SRC_RSIZE + 1))
1776 0 : i = 0;
1777 : else
1778 0 : u--;
1779 : }
1780 0 : dma->srck = i; dma->srcu = u;
1781 :
1782 0 : i = dma->cmdk; u = dma->cmdu;
1783 0 : while (u != 0) {
1784 0 : HIFN_CMDR_SYNC(sc, i,
1785 : BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1786 0 : if (dma->cmdr[i].l & htole32(HIFN_D_VALID)) {
1787 0 : HIFN_CMDR_SYNC(sc, i,
1788 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1789 0 : break;
1790 : }
1791 0 : if (i != HIFN_D_CMD_RSIZE) {
1792 0 : u--;
1793 0 : HIFN_CMD_SYNC(sc, i, BUS_DMASYNC_POSTWRITE);
1794 0 : }
1795 0 : if (++i == (HIFN_D_CMD_RSIZE + 1))
1796 : i = 0;
1797 : }
1798 0 : dma->cmdk = i; dma->cmdu = u;
1799 :
1800 0 : return (1);
1801 0 : }
1802 :
1803 : /*
1804 : * Allocate a new 'session' and return an encoded session id. 'sidp'
1805 : * contains our registration id, and should contain an encoded session
1806 : * id on successful allocation.
1807 : */
1808 : int
1809 0 : hifn_newsession(u_int32_t *sidp, struct cryptoini *cri)
1810 : {
1811 : struct cryptoini *c;
1812 : struct hifn_softc *sc = NULL;
1813 : int i, mac = 0, cry = 0, comp = 0, sesn;
1814 : struct hifn_session *ses = NULL;
1815 :
1816 0 : if (sidp == NULL || cri == NULL)
1817 0 : return (EINVAL);
1818 :
1819 0 : for (i = 0; i < hifn_cd.cd_ndevs; i++) {
1820 0 : sc = hifn_cd.cd_devs[i];
1821 0 : if (sc == NULL)
1822 : break;
1823 0 : if (sc->sc_cid == (*sidp))
1824 : break;
1825 : }
1826 0 : if (sc == NULL)
1827 0 : return (EINVAL);
1828 :
1829 0 : if (sc->sc_sessions == NULL) {
1830 0 : ses = sc->sc_sessions = (struct hifn_session *)malloc(
1831 : sizeof(*ses), M_DEVBUF, M_NOWAIT);
1832 0 : if (ses == NULL)
1833 0 : return (ENOMEM);
1834 : sesn = 0;
1835 0 : sc->sc_nsessions = 1;
1836 0 : } else {
1837 0 : for (sesn = 0; sesn < sc->sc_nsessions; sesn++) {
1838 0 : if (!sc->sc_sessions[sesn].hs_used) {
1839 : ses = &sc->sc_sessions[sesn];
1840 0 : break;
1841 : }
1842 : }
1843 :
1844 0 : if (ses == NULL) {
1845 0 : sesn = sc->sc_nsessions;
1846 0 : ses = mallocarray((sesn + 1), sizeof(*ses),
1847 : M_DEVBUF, M_NOWAIT);
1848 0 : if (ses == NULL)
1849 0 : return (ENOMEM);
1850 0 : bcopy(sc->sc_sessions, ses, sesn * sizeof(*ses));
1851 0 : explicit_bzero(sc->sc_sessions, sesn * sizeof(*ses));
1852 0 : free(sc->sc_sessions, M_DEVBUF, 0);
1853 0 : sc->sc_sessions = ses;
1854 0 : ses = &sc->sc_sessions[sesn];
1855 0 : sc->sc_nsessions++;
1856 0 : }
1857 : }
1858 0 : bzero(ses, sizeof(*ses));
1859 :
1860 0 : for (c = cri; c != NULL; c = c->cri_next) {
1861 0 : switch (c->cri_alg) {
1862 : case CRYPTO_MD5_HMAC:
1863 : case CRYPTO_SHA1_HMAC:
1864 0 : if (mac)
1865 0 : return (EINVAL);
1866 : mac = 1;
1867 0 : break;
1868 : case CRYPTO_3DES_CBC:
1869 : case CRYPTO_AES_CBC:
1870 0 : if (cry)
1871 0 : return (EINVAL);
1872 : cry = 1;
1873 0 : break;
1874 : case CRYPTO_LZS_COMP:
1875 0 : if (comp)
1876 0 : return (EINVAL);
1877 : comp = 1;
1878 0 : break;
1879 : default:
1880 0 : return (EINVAL);
1881 : }
1882 : }
1883 0 : if (mac == 0 && cry == 0 && comp == 0)
1884 0 : return (EINVAL);
1885 :
1886 : /*
1887 : * XXX only want to support compression without chaining to
1888 : * MAC/crypt engine right now
1889 : */
1890 0 : if ((comp && mac) || (comp && cry))
1891 0 : return (EINVAL);
1892 :
1893 0 : *sidp = HIFN_SID(sc->sc_dv.dv_unit, sesn);
1894 0 : ses->hs_used = 1;
1895 :
1896 0 : return (0);
1897 0 : }
1898 :
1899 : /*
1900 : * Deallocate a session.
1901 : * XXX this routine should run a zero'd mac/encrypt key into context ram.
1902 : * XXX to blow away any keys already stored there.
1903 : */
1904 : int
1905 0 : hifn_freesession(u_int64_t tid)
1906 : {
1907 : struct hifn_softc *sc;
1908 : int card, session;
1909 0 : u_int32_t sid = ((u_int32_t)tid) & 0xffffffff;
1910 :
1911 0 : card = HIFN_CARD(sid);
1912 0 : if (card >= hifn_cd.cd_ndevs || hifn_cd.cd_devs[card] == NULL)
1913 0 : return (EINVAL);
1914 :
1915 0 : sc = hifn_cd.cd_devs[card];
1916 0 : session = HIFN_SESSION(sid);
1917 0 : if (session >= sc->sc_nsessions)
1918 0 : return (EINVAL);
1919 :
1920 0 : bzero(&sc->sc_sessions[session], sizeof(sc->sc_sessions[session]));
1921 0 : return (0);
1922 0 : }
1923 :
1924 : int
1925 0 : hifn_process(struct cryptop *crp)
1926 : {
1927 : struct hifn_command *cmd = NULL;
1928 : int card, session, err = 0, ivlen;
1929 : struct hifn_softc *sc;
1930 : struct cryptodesc *crd1, *crd2 = NULL, *maccrd, *enccrd;
1931 :
1932 0 : if (crp == NULL || crp->crp_callback == NULL) {
1933 0 : hifnstats.hst_invalid++;
1934 0 : return (EINVAL);
1935 : }
1936 :
1937 0 : if (crp->crp_ilen == 0) {
1938 : err = EINVAL;
1939 0 : goto errout;
1940 : }
1941 :
1942 0 : card = HIFN_CARD(crp->crp_sid);
1943 0 : if (card >= hifn_cd.cd_ndevs || hifn_cd.cd_devs[card] == NULL) {
1944 : err = EINVAL;
1945 0 : goto errout;
1946 : }
1947 :
1948 0 : sc = hifn_cd.cd_devs[card];
1949 0 : session = HIFN_SESSION(crp->crp_sid);
1950 0 : if (session >= sc->sc_nsessions) {
1951 : err = EINVAL;
1952 0 : goto errout;
1953 : }
1954 :
1955 0 : cmd = malloc(sizeof(*cmd), M_DEVBUF, M_NOWAIT | M_ZERO);
1956 0 : if (cmd == NULL) {
1957 : err = ENOMEM;
1958 0 : goto errout;
1959 : }
1960 :
1961 0 : if (crp->crp_flags & CRYPTO_F_IMBUF) {
1962 0 : cmd->srcu.src_m = (struct mbuf *)crp->crp_buf;
1963 0 : cmd->dstu.dst_m = (struct mbuf *)crp->crp_buf;
1964 0 : } else if (crp->crp_flags & CRYPTO_F_IOV) {
1965 0 : cmd->srcu.src_io = (struct uio *)crp->crp_buf;
1966 0 : cmd->dstu.dst_io = (struct uio *)crp->crp_buf;
1967 : } else {
1968 : err = EINVAL;
1969 0 : goto errout; /* XXX we don't handle contiguous buffers! */
1970 : }
1971 :
1972 0 : if (crp->crp_ndesc < 1) {
1973 : err = EINVAL;
1974 0 : goto errout;
1975 : }
1976 0 : crd1 = &crp->crp_desc[0];
1977 0 : if (crp->crp_ndesc >= 2)
1978 0 : crd2 = &crp->crp_desc[1];
1979 :
1980 0 : if (crd2 == NULL) {
1981 0 : if (crd1->crd_alg == CRYPTO_MD5_HMAC ||
1982 0 : crd1->crd_alg == CRYPTO_SHA1_HMAC) {
1983 : maccrd = crd1;
1984 : enccrd = NULL;
1985 0 : } else if (crd1->crd_alg == CRYPTO_3DES_CBC ||
1986 0 : crd1->crd_alg == CRYPTO_AES_CBC) {
1987 0 : if ((crd1->crd_flags & CRD_F_ENCRYPT) == 0)
1988 0 : cmd->base_masks |= HIFN_BASE_CMD_DECODE;
1989 : maccrd = NULL;
1990 : enccrd = crd1;
1991 0 : } else if (crd1->crd_alg == CRYPTO_LZS_COMP) {
1992 0 : return (hifn_compression(sc, crp, cmd));
1993 : } else {
1994 : err = EINVAL;
1995 0 : goto errout;
1996 : }
1997 : } else {
1998 0 : if ((crd1->crd_alg == CRYPTO_MD5_HMAC ||
1999 0 : crd1->crd_alg == CRYPTO_SHA1_HMAC) &&
2000 0 : (crd2->crd_alg == CRYPTO_3DES_CBC ||
2001 0 : crd2->crd_alg == CRYPTO_AES_CBC) &&
2002 0 : ((crd2->crd_flags & CRD_F_ENCRYPT) == 0)) {
2003 0 : cmd->base_masks = HIFN_BASE_CMD_DECODE;
2004 : maccrd = crd1;
2005 : enccrd = crd2;
2006 0 : } else if ((crd1->crd_alg == CRYPTO_3DES_CBC ||
2007 0 : crd1->crd_alg == CRYPTO_AES_CBC) &&
2008 0 : (crd2->crd_alg == CRYPTO_MD5_HMAC ||
2009 0 : crd2->crd_alg == CRYPTO_SHA1_HMAC) &&
2010 0 : (crd1->crd_flags & CRD_F_ENCRYPT)) {
2011 : enccrd = crd1;
2012 : maccrd = crd2;
2013 : } else {
2014 : /*
2015 : * We cannot order the 7751 as requested
2016 : */
2017 : err = EINVAL;
2018 0 : goto errout;
2019 : }
2020 : }
2021 :
2022 0 : if (enccrd) {
2023 0 : cmd->enccrd = enccrd;
2024 0 : cmd->base_masks |= HIFN_BASE_CMD_CRYPT;
2025 0 : switch (enccrd->crd_alg) {
2026 : case CRYPTO_3DES_CBC:
2027 0 : cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_3DES |
2028 : HIFN_CRYPT_CMD_MODE_CBC |
2029 : HIFN_CRYPT_CMD_NEW_IV;
2030 0 : break;
2031 : case CRYPTO_AES_CBC:
2032 0 : cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_AES |
2033 : HIFN_CRYPT_CMD_MODE_CBC |
2034 : HIFN_CRYPT_CMD_NEW_IV;
2035 0 : break;
2036 : default:
2037 : err = EINVAL;
2038 0 : goto errout;
2039 : }
2040 0 : ivlen = ((enccrd->crd_alg == CRYPTO_AES_CBC) ?
2041 : HIFN_AES_IV_LENGTH : HIFN_IV_LENGTH);
2042 0 : if (enccrd->crd_flags & CRD_F_ENCRYPT) {
2043 0 : if (enccrd->crd_flags & CRD_F_IV_EXPLICIT)
2044 0 : bcopy(enccrd->crd_iv, cmd->iv, ivlen);
2045 : else
2046 0 : arc4random_buf(cmd->iv, ivlen);
2047 :
2048 0 : if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0) {
2049 0 : if (crp->crp_flags & CRYPTO_F_IMBUF)
2050 0 : err = m_copyback(cmd->srcu.src_m,
2051 0 : enccrd->crd_inject,
2052 0 : ivlen, cmd->iv, M_NOWAIT);
2053 0 : else if (crp->crp_flags & CRYPTO_F_IOV)
2054 0 : cuio_copyback(cmd->srcu.src_io,
2055 0 : enccrd->crd_inject,
2056 0 : ivlen, cmd->iv);
2057 0 : if (err)
2058 : goto errout;
2059 : }
2060 : } else {
2061 0 : if (enccrd->crd_flags & CRD_F_IV_EXPLICIT)
2062 0 : bcopy(enccrd->crd_iv, cmd->iv, ivlen);
2063 0 : else if (crp->crp_flags & CRYPTO_F_IMBUF)
2064 0 : m_copydata(cmd->srcu.src_m,
2065 0 : enccrd->crd_inject, ivlen, cmd->iv);
2066 0 : else if (crp->crp_flags & CRYPTO_F_IOV)
2067 0 : cuio_copydata(cmd->srcu.src_io,
2068 0 : enccrd->crd_inject, ivlen, cmd->iv);
2069 : }
2070 :
2071 0 : cmd->ck = enccrd->crd_key;
2072 0 : cmd->cklen = enccrd->crd_klen >> 3;
2073 0 : cmd->cry_masks |= HIFN_CRYPT_CMD_NEW_KEY;
2074 :
2075 : /*
2076 : * Need to specify the size for the AES key in the masks.
2077 : */
2078 0 : if ((cmd->cry_masks & HIFN_CRYPT_CMD_ALG_MASK) ==
2079 : HIFN_CRYPT_CMD_ALG_AES) {
2080 0 : switch (cmd->cklen) {
2081 : case 16:
2082 0 : cmd->cry_masks |= HIFN_CRYPT_CMD_KSZ_128;
2083 0 : break;
2084 : case 24:
2085 0 : cmd->cry_masks |= HIFN_CRYPT_CMD_KSZ_192;
2086 0 : break;
2087 : case 32:
2088 0 : cmd->cry_masks |= HIFN_CRYPT_CMD_KSZ_256;
2089 0 : break;
2090 : default:
2091 : err = EINVAL;
2092 0 : goto errout;
2093 : }
2094 : }
2095 : }
2096 :
2097 0 : if (maccrd) {
2098 0 : cmd->maccrd = maccrd;
2099 0 : cmd->base_masks |= HIFN_BASE_CMD_MAC;
2100 :
2101 0 : switch (maccrd->crd_alg) {
2102 : case CRYPTO_MD5_HMAC:
2103 0 : cmd->mac_masks |= HIFN_MAC_CMD_ALG_MD5 |
2104 : HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HMAC |
2105 : HIFN_MAC_CMD_POS_IPSEC | HIFN_MAC_CMD_TRUNC;
2106 0 : break;
2107 : case CRYPTO_SHA1_HMAC:
2108 0 : cmd->mac_masks |= HIFN_MAC_CMD_ALG_SHA1 |
2109 : HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HMAC |
2110 : HIFN_MAC_CMD_POS_IPSEC | HIFN_MAC_CMD_TRUNC;
2111 0 : break;
2112 : }
2113 :
2114 0 : if (maccrd->crd_alg == CRYPTO_SHA1_HMAC ||
2115 0 : maccrd->crd_alg == CRYPTO_MD5_HMAC) {
2116 0 : cmd->mac_masks |= HIFN_MAC_CMD_NEW_KEY;
2117 0 : bcopy(maccrd->crd_key, cmd->mac, maccrd->crd_klen >> 3);
2118 0 : bzero(cmd->mac + (maccrd->crd_klen >> 3),
2119 : HIFN_MAC_KEY_LENGTH - (maccrd->crd_klen >> 3));
2120 0 : }
2121 : }
2122 :
2123 0 : cmd->crp = crp;
2124 0 : cmd->session_num = session;
2125 0 : cmd->softc = sc;
2126 :
2127 0 : err = hifn_crypto(sc, cmd, crp);
2128 0 : if (!err)
2129 0 : return 0;
2130 :
2131 : errout:
2132 0 : if (cmd != NULL) {
2133 0 : explicit_bzero(cmd, sizeof(*cmd));
2134 0 : free(cmd, M_DEVBUF, sizeof *cmd);
2135 0 : }
2136 0 : if (err == EINVAL)
2137 0 : hifnstats.hst_invalid++;
2138 : else
2139 0 : hifnstats.hst_nomem++;
2140 0 : crp->crp_etype = err;
2141 0 : crypto_done(crp);
2142 0 : return (0);
2143 0 : }
2144 :
2145 : void
2146 0 : hifn_abort(struct hifn_softc *sc)
2147 : {
2148 0 : struct hifn_dma *dma = sc->sc_dma;
2149 : struct hifn_command *cmd;
2150 : struct cryptop *crp;
2151 : int i, u;
2152 :
2153 0 : i = dma->resk; u = dma->resu;
2154 0 : while (u != 0) {
2155 0 : cmd = dma->hifn_commands[i];
2156 0 : crp = cmd->crp;
2157 :
2158 0 : if ((dma->resr[i].l & htole32(HIFN_D_VALID)) == 0) {
2159 : /* Salvage what we can. */
2160 0 : hifnstats.hst_opackets++;
2161 0 : (*cmd->cmd_callback)(sc, cmd, dma->result_bufs[i]);
2162 0 : } else {
2163 0 : if (cmd->src_map == cmd->dst_map)
2164 0 : bus_dmamap_sync(sc->sc_dmat, cmd->src_map,
2165 : 0, cmd->src_map->dm_mapsize,
2166 : BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
2167 : else {
2168 0 : bus_dmamap_sync(sc->sc_dmat, cmd->src_map,
2169 : 0, cmd->src_map->dm_mapsize,
2170 : BUS_DMASYNC_POSTWRITE);
2171 0 : bus_dmamap_sync(sc->sc_dmat, cmd->dst_map,
2172 : 0, cmd->dst_map->dm_mapsize,
2173 : BUS_DMASYNC_POSTREAD);
2174 : }
2175 :
2176 0 : if (cmd->srcu.src_m != cmd->dstu.dst_m) {
2177 0 : m_freem(cmd->srcu.src_m);
2178 0 : crp->crp_buf = (caddr_t)cmd->dstu.dst_m;
2179 0 : }
2180 :
2181 : /* non-shared buffers cannot be restarted */
2182 0 : if (cmd->src_map != cmd->dst_map) {
2183 : /*
2184 : * XXX should be EAGAIN, delayed until
2185 : * after the reset.
2186 : */
2187 : crp->crp_etype = ENOMEM;
2188 0 : bus_dmamap_unload(sc->sc_dmat, cmd->dst_map);
2189 0 : bus_dmamap_destroy(sc->sc_dmat, cmd->dst_map);
2190 0 : } else
2191 : crp->crp_etype = ENOMEM;
2192 :
2193 0 : bus_dmamap_unload(sc->sc_dmat, cmd->src_map);
2194 0 : bus_dmamap_destroy(sc->sc_dmat, cmd->src_map);
2195 :
2196 0 : explicit_bzero(cmd, sizeof(*cmd));
2197 0 : free(cmd, M_DEVBUF, sizeof *cmd);
2198 0 : if (crp->crp_etype != EAGAIN)
2199 0 : crypto_done(crp);
2200 : }
2201 :
2202 0 : if (++i == HIFN_D_RES_RSIZE)
2203 : i = 0;
2204 0 : u--;
2205 : }
2206 0 : dma->resk = i; dma->resu = u;
2207 :
2208 0 : hifn_reset_board(sc, 1);
2209 0 : hifn_init_dma(sc);
2210 0 : hifn_init_pci_registers(sc);
2211 0 : }
2212 :
2213 : void
2214 0 : hifn_callback(struct hifn_softc *sc, struct hifn_command *cmd,
2215 : u_int8_t *resbuf)
2216 : {
2217 0 : struct hifn_dma *dma = sc->sc_dma;
2218 0 : struct cryptop *crp = cmd->crp;
2219 : struct cryptodesc *crd;
2220 : struct mbuf *m;
2221 : int totlen, i, u;
2222 :
2223 0 : if (cmd->src_map == cmd->dst_map)
2224 0 : bus_dmamap_sync(sc->sc_dmat, cmd->src_map,
2225 : 0, cmd->src_map->dm_mapsize,
2226 : BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
2227 : else {
2228 0 : bus_dmamap_sync(sc->sc_dmat, cmd->src_map,
2229 : 0, cmd->src_map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
2230 0 : bus_dmamap_sync(sc->sc_dmat, cmd->dst_map,
2231 : 0, cmd->dst_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
2232 : }
2233 :
2234 0 : if (crp->crp_flags & CRYPTO_F_IMBUF) {
2235 0 : if (cmd->srcu.src_m != cmd->dstu.dst_m) {
2236 0 : crp->crp_buf = (caddr_t)cmd->dstu.dst_m;
2237 0 : totlen = cmd->src_map->dm_mapsize;
2238 0 : for (m = cmd->dstu.dst_m; m != NULL; m = m->m_next) {
2239 0 : if (totlen < m->m_len) {
2240 0 : m->m_len = totlen;
2241 : totlen = 0;
2242 0 : } else
2243 0 : totlen -= m->m_len;
2244 : }
2245 0 : cmd->dstu.dst_m->m_pkthdr.len =
2246 0 : cmd->srcu.src_m->m_pkthdr.len;
2247 0 : m_freem(cmd->srcu.src_m);
2248 0 : }
2249 : }
2250 :
2251 0 : if (cmd->sloplen != 0) {
2252 0 : if (crp->crp_flags & CRYPTO_F_IMBUF)
2253 0 : crp->crp_etype =
2254 0 : m_copyback((struct mbuf *)crp->crp_buf,
2255 0 : cmd->src_map->dm_mapsize - cmd->sloplen,
2256 0 : cmd->sloplen, &dma->slop[cmd->slopidx],
2257 : M_NOWAIT);
2258 0 : else if (crp->crp_flags & CRYPTO_F_IOV)
2259 0 : cuio_copyback((struct uio *)crp->crp_buf,
2260 0 : cmd->src_map->dm_mapsize - cmd->sloplen,
2261 0 : cmd->sloplen, &dma->slop[cmd->slopidx]);
2262 0 : if (crp->crp_etype)
2263 : goto out;
2264 : }
2265 :
2266 0 : i = dma->dstk; u = dma->dstu;
2267 0 : while (u != 0) {
2268 0 : bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
2269 : offsetof(struct hifn_dma, dstr[i]), sizeof(struct hifn_desc),
2270 : BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
2271 0 : if (dma->dstr[i].l & htole32(HIFN_D_VALID)) {
2272 0 : bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
2273 : offsetof(struct hifn_dma, dstr[i]),
2274 : sizeof(struct hifn_desc),
2275 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2276 0 : break;
2277 : }
2278 0 : if (++i == (HIFN_D_DST_RSIZE + 1))
2279 0 : i = 0;
2280 : else
2281 0 : u--;
2282 : }
2283 0 : dma->dstk = i; dma->dstu = u;
2284 :
2285 0 : hifnstats.hst_obytes += cmd->dst_map->dm_mapsize;
2286 :
2287 0 : if (cmd->base_masks & HIFN_BASE_CMD_MAC) {
2288 : u_int8_t *macbuf;
2289 :
2290 0 : macbuf = resbuf + sizeof(struct hifn_base_result);
2291 0 : if (cmd->base_masks & HIFN_BASE_CMD_COMP)
2292 0 : macbuf += sizeof(struct hifn_comp_result);
2293 0 : macbuf += sizeof(struct hifn_mac_result);
2294 :
2295 0 : for (i = 0; i < crp->crp_ndesc; i++) {
2296 : int len;
2297 :
2298 0 : crd = &crp->crp_desc[i];
2299 :
2300 0 : if (crd->crd_alg == CRYPTO_MD5_HMAC ||
2301 0 : crd->crd_alg == CRYPTO_SHA1_HMAC)
2302 : len = 12;
2303 : else
2304 0 : continue;
2305 :
2306 0 : if (crp->crp_flags & CRYPTO_F_IMBUF)
2307 0 : crp->crp_etype =
2308 0 : m_copyback((struct mbuf *)crp->crp_buf,
2309 0 : crd->crd_inject, len, macbuf, M_NOWAIT);
2310 0 : else if ((crp->crp_flags & CRYPTO_F_IOV) && crp->crp_mac)
2311 0 : bcopy((caddr_t)macbuf, crp->crp_mac, len);
2312 0 : break;
2313 : }
2314 0 : }
2315 :
2316 : out:
2317 0 : if (cmd->src_map != cmd->dst_map) {
2318 0 : bus_dmamap_unload(sc->sc_dmat, cmd->dst_map);
2319 0 : bus_dmamap_destroy(sc->sc_dmat, cmd->dst_map);
2320 0 : }
2321 0 : bus_dmamap_unload(sc->sc_dmat, cmd->src_map);
2322 0 : bus_dmamap_destroy(sc->sc_dmat, cmd->src_map);
2323 0 : explicit_bzero(cmd, sizeof(*cmd));
2324 0 : free(cmd, M_DEVBUF, sizeof *cmd);
2325 0 : crypto_done(crp);
2326 0 : }
2327 :
2328 : int
2329 0 : hifn_compression(struct hifn_softc *sc, struct cryptop *crp,
2330 : struct hifn_command *cmd)
2331 : {
2332 0 : struct cryptodesc *crd = &crp->crp_desc[0];
2333 : int s, err = 0;
2334 :
2335 0 : cmd->compcrd = crd;
2336 0 : cmd->base_masks |= HIFN_BASE_CMD_COMP;
2337 :
2338 0 : if ((crp->crp_flags & CRYPTO_F_IMBUF) == 0) {
2339 : /*
2340 : * XXX can only handle mbufs right now since we can
2341 : * XXX dynamically resize them.
2342 : */
2343 : err = EINVAL;
2344 0 : return (ENOMEM);
2345 : }
2346 :
2347 0 : if ((crd->crd_flags & CRD_F_COMP) == 0)
2348 0 : cmd->base_masks |= HIFN_BASE_CMD_DECODE;
2349 0 : if (crd->crd_alg == CRYPTO_LZS_COMP)
2350 0 : cmd->comp_masks |= HIFN_COMP_CMD_ALG_LZS |
2351 : HIFN_COMP_CMD_CLEARHIST;
2352 :
2353 0 : if (bus_dmamap_create(sc->sc_dmat, HIFN_MAX_DMALEN, MAX_SCATTER,
2354 : HIFN_MAX_SEGLEN, 0, BUS_DMA_NOWAIT, &cmd->src_map)) {
2355 : err = ENOMEM;
2356 0 : goto fail;
2357 : }
2358 :
2359 0 : if (bus_dmamap_create(sc->sc_dmat, HIFN_MAX_DMALEN, MAX_SCATTER,
2360 : HIFN_MAX_SEGLEN, 0, BUS_DMA_NOWAIT, &cmd->dst_map)) {
2361 : err = ENOMEM;
2362 0 : goto fail;
2363 : }
2364 :
2365 0 : if (crp->crp_flags & CRYPTO_F_IMBUF) {
2366 : int len;
2367 :
2368 0 : if (bus_dmamap_load_mbuf(sc->sc_dmat, cmd->src_map,
2369 : cmd->srcu.src_m, BUS_DMA_NOWAIT)) {
2370 : err = ENOMEM;
2371 0 : goto fail;
2372 : }
2373 :
2374 0 : len = cmd->src_map->dm_mapsize / MCLBYTES;
2375 0 : if ((cmd->src_map->dm_mapsize % MCLBYTES) != 0)
2376 0 : len++;
2377 0 : len *= MCLBYTES;
2378 :
2379 0 : if ((crd->crd_flags & CRD_F_COMP) == 0)
2380 0 : len *= 4;
2381 :
2382 0 : if (len > HIFN_MAX_DMALEN)
2383 0 : len = HIFN_MAX_DMALEN;
2384 :
2385 0 : cmd->dstu.dst_m = hifn_mkmbuf_chain(len, cmd->srcu.src_m);
2386 0 : if (cmd->dstu.dst_m == NULL) {
2387 : err = ENOMEM;
2388 0 : goto fail;
2389 : }
2390 :
2391 0 : if (bus_dmamap_load_mbuf(sc->sc_dmat, cmd->dst_map,
2392 : cmd->dstu.dst_m, BUS_DMA_NOWAIT)) {
2393 : err = ENOMEM;
2394 0 : goto fail;
2395 : }
2396 0 : } else if (crp->crp_flags & CRYPTO_F_IOV) {
2397 0 : if (bus_dmamap_load_uio(sc->sc_dmat, cmd->src_map,
2398 : cmd->srcu.src_io, BUS_DMA_NOWAIT)) {
2399 : err = ENOMEM;
2400 0 : goto fail;
2401 : }
2402 0 : if (bus_dmamap_load_uio(sc->sc_dmat, cmd->dst_map,
2403 : cmd->dstu.dst_io, BUS_DMA_NOWAIT)) {
2404 : err = ENOMEM;
2405 0 : goto fail;
2406 : }
2407 : }
2408 :
2409 0 : if (cmd->src_map == cmd->dst_map)
2410 0 : bus_dmamap_sync(sc->sc_dmat, cmd->src_map,
2411 : 0, cmd->src_map->dm_mapsize,
2412 : BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
2413 : else {
2414 0 : bus_dmamap_sync(sc->sc_dmat, cmd->src_map,
2415 : 0, cmd->src_map->dm_mapsize, BUS_DMASYNC_PREWRITE);
2416 0 : bus_dmamap_sync(sc->sc_dmat, cmd->dst_map,
2417 : 0, cmd->dst_map->dm_mapsize, BUS_DMASYNC_PREREAD);
2418 : }
2419 :
2420 0 : cmd->crp = crp;
2421 : /*
2422 : * Always use session 0. The modes of compression we use are
2423 : * stateless and there is always at least one compression
2424 : * context, zero.
2425 : */
2426 0 : cmd->session_num = 0;
2427 0 : cmd->softc = sc;
2428 :
2429 0 : s = splnet();
2430 0 : err = hifn_compress_enter(sc, cmd);
2431 0 : splx(s);
2432 :
2433 0 : if (err != 0)
2434 : goto fail;
2435 0 : return (0);
2436 :
2437 : fail:
2438 0 : if (cmd->dst_map != NULL) {
2439 0 : if (cmd->dst_map->dm_nsegs > 0)
2440 0 : bus_dmamap_unload(sc->sc_dmat, cmd->dst_map);
2441 0 : bus_dmamap_destroy(sc->sc_dmat, cmd->dst_map);
2442 0 : }
2443 0 : if (cmd->src_map != NULL) {
2444 0 : if (cmd->src_map->dm_nsegs > 0)
2445 0 : bus_dmamap_unload(sc->sc_dmat, cmd->src_map);
2446 0 : bus_dmamap_destroy(sc->sc_dmat, cmd->src_map);
2447 0 : }
2448 0 : explicit_bzero(cmd, sizeof(*cmd));
2449 0 : free(cmd, M_DEVBUF, sizeof *cmd);
2450 0 : if (err == EINVAL)
2451 0 : hifnstats.hst_invalid++;
2452 : else
2453 0 : hifnstats.hst_nomem++;
2454 0 : crp->crp_etype = err;
2455 0 : crypto_done(crp);
2456 0 : return (0);
2457 0 : }
2458 :
2459 : /*
2460 : * must be called at splnet()
2461 : */
2462 : int
2463 0 : hifn_compress_enter(struct hifn_softc *sc, struct hifn_command *cmd)
2464 : {
2465 0 : struct hifn_dma *dma = sc->sc_dma;
2466 : int cmdi, resi;
2467 : u_int32_t cmdlen;
2468 :
2469 0 : if ((dma->cmdu + 1) > HIFN_D_CMD_RSIZE ||
2470 0 : (dma->resu + 1) > HIFN_D_CMD_RSIZE)
2471 0 : return (ENOMEM);
2472 :
2473 0 : if ((dma->srcu + cmd->src_map->dm_nsegs) > HIFN_D_SRC_RSIZE ||
2474 0 : (dma->dstu + cmd->dst_map->dm_nsegs) > HIFN_D_DST_RSIZE)
2475 0 : return (ENOMEM);
2476 :
2477 0 : if (dma->cmdi == HIFN_D_CMD_RSIZE) {
2478 0 : dma->cmdi = 0;
2479 0 : dma->cmdr[HIFN_D_CMD_RSIZE].l = htole32(HIFN_D_VALID |
2480 : HIFN_D_JUMP | HIFN_D_MASKDONEIRQ);
2481 0 : HIFN_CMDR_SYNC(sc, HIFN_D_CMD_RSIZE,
2482 : BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
2483 0 : }
2484 0 : cmdi = dma->cmdi++;
2485 0 : cmdlen = hifn_write_command(cmd, dma->command_bufs[cmdi]);
2486 0 : HIFN_CMD_SYNC(sc, cmdi, BUS_DMASYNC_PREWRITE);
2487 :
2488 : /* .p for command/result already set */
2489 0 : dma->cmdr[cmdi].l = htole32(cmdlen | HIFN_D_VALID | HIFN_D_LAST |
2490 : HIFN_D_MASKDONEIRQ);
2491 0 : HIFN_CMDR_SYNC(sc, cmdi,
2492 : BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
2493 0 : dma->cmdu++;
2494 0 : if (sc->sc_c_busy == 0) {
2495 0 : WRITE_REG_1(sc, HIFN_1_DMA_CSR, HIFN_DMACSR_C_CTRL_ENA);
2496 0 : sc->sc_c_busy = 1;
2497 0 : SET_LED(sc, HIFN_MIPSRST_LED0);
2498 : }
2499 :
2500 : /*
2501 : * Always enable the command wait interrupt. We are obviously
2502 : * missing an interrupt or two somewhere. Enabling the command wait
2503 : * interrupt will guarantee we get called periodically until all
2504 : * of the queues are drained and thus work around this.
2505 : */
2506 0 : sc->sc_dmaier |= HIFN_DMAIER_C_WAIT;
2507 0 : WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier);
2508 :
2509 0 : hifnstats.hst_ipackets++;
2510 0 : hifnstats.hst_ibytes += cmd->src_map->dm_mapsize;
2511 :
2512 0 : hifn_dmamap_load_src(sc, cmd);
2513 0 : if (sc->sc_s_busy == 0) {
2514 0 : WRITE_REG_1(sc, HIFN_1_DMA_CSR, HIFN_DMACSR_S_CTRL_ENA);
2515 0 : sc->sc_s_busy = 1;
2516 0 : SET_LED(sc, HIFN_MIPSRST_LED1);
2517 : }
2518 :
2519 : /*
2520 : * Unlike other descriptors, we don't mask done interrupt from
2521 : * result descriptor.
2522 : */
2523 0 : if (dma->resi == HIFN_D_RES_RSIZE) {
2524 0 : dma->resi = 0;
2525 0 : dma->resr[HIFN_D_RES_RSIZE].l = htole32(HIFN_D_VALID |
2526 : HIFN_D_JUMP | HIFN_D_MASKDONEIRQ);
2527 0 : HIFN_RESR_SYNC(sc, HIFN_D_RES_RSIZE,
2528 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2529 0 : }
2530 0 : resi = dma->resi++;
2531 0 : dma->hifn_commands[resi] = cmd;
2532 0 : HIFN_RES_SYNC(sc, resi, BUS_DMASYNC_PREREAD);
2533 0 : dma->resr[resi].l = htole32(HIFN_MAX_RESULT |
2534 : HIFN_D_VALID | HIFN_D_LAST);
2535 0 : HIFN_RESR_SYNC(sc, resi,
2536 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2537 0 : dma->resu++;
2538 0 : if (sc->sc_r_busy == 0) {
2539 0 : WRITE_REG_1(sc, HIFN_1_DMA_CSR, HIFN_DMACSR_R_CTRL_ENA);
2540 0 : sc->sc_r_busy = 1;
2541 0 : SET_LED(sc, HIFN_MIPSRST_LED2);
2542 : }
2543 :
2544 0 : if (cmd->sloplen)
2545 0 : cmd->slopidx = resi;
2546 :
2547 0 : hifn_dmamap_load_dst(sc, cmd);
2548 :
2549 0 : if (sc->sc_d_busy == 0) {
2550 0 : WRITE_REG_1(sc, HIFN_1_DMA_CSR, HIFN_DMACSR_D_CTRL_ENA);
2551 0 : sc->sc_d_busy = 1;
2552 0 : }
2553 0 : sc->sc_active = 5;
2554 0 : cmd->cmd_callback = hifn_callback_comp;
2555 0 : return (0);
2556 0 : }
2557 :
2558 : void
2559 0 : hifn_callback_comp(struct hifn_softc *sc, struct hifn_command *cmd,
2560 : u_int8_t *resbuf)
2561 : {
2562 0 : struct hifn_base_result baseres;
2563 0 : struct cryptop *crp = cmd->crp;
2564 0 : struct hifn_dma *dma = sc->sc_dma;
2565 : struct mbuf *m;
2566 : int err = 0, i, u;
2567 : u_int32_t olen;
2568 : bus_size_t dstsize;
2569 :
2570 0 : bus_dmamap_sync(sc->sc_dmat, cmd->src_map,
2571 : 0, cmd->src_map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
2572 0 : bus_dmamap_sync(sc->sc_dmat, cmd->dst_map,
2573 : 0, cmd->dst_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
2574 :
2575 0 : dstsize = cmd->dst_map->dm_mapsize;
2576 0 : bus_dmamap_unload(sc->sc_dmat, cmd->dst_map);
2577 :
2578 0 : bcopy(resbuf, &baseres, sizeof(struct hifn_base_result));
2579 :
2580 0 : i = dma->dstk; u = dma->dstu;
2581 0 : while (u != 0) {
2582 0 : bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
2583 : offsetof(struct hifn_dma, dstr[i]), sizeof(struct hifn_desc),
2584 : BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
2585 0 : if (dma->dstr[i].l & htole32(HIFN_D_VALID)) {
2586 0 : bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
2587 : offsetof(struct hifn_dma, dstr[i]),
2588 : sizeof(struct hifn_desc),
2589 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2590 0 : break;
2591 : }
2592 0 : if (++i == (HIFN_D_DST_RSIZE + 1))
2593 0 : i = 0;
2594 : else
2595 0 : u--;
2596 : }
2597 0 : dma->dstk = i; dma->dstu = u;
2598 :
2599 0 : if (baseres.flags & htole16(HIFN_BASE_RES_DSTOVERRUN)) {
2600 : bus_size_t xlen;
2601 :
2602 : xlen = dstsize;
2603 :
2604 0 : m_freem(cmd->dstu.dst_m);
2605 :
2606 0 : if (xlen == HIFN_MAX_DMALEN) {
2607 : /* We've done all we can. */
2608 : err = E2BIG;
2609 0 : goto out;
2610 : }
2611 :
2612 0 : xlen += MCLBYTES;
2613 :
2614 0 : if (xlen > HIFN_MAX_DMALEN)
2615 : xlen = HIFN_MAX_DMALEN;
2616 :
2617 0 : cmd->dstu.dst_m = hifn_mkmbuf_chain(xlen,
2618 0 : cmd->srcu.src_m);
2619 0 : if (cmd->dstu.dst_m == NULL) {
2620 : err = ENOMEM;
2621 0 : goto out;
2622 : }
2623 0 : if (bus_dmamap_load_mbuf(sc->sc_dmat, cmd->dst_map,
2624 : cmd->dstu.dst_m, BUS_DMA_NOWAIT)) {
2625 : err = ENOMEM;
2626 0 : goto out;
2627 : }
2628 :
2629 0 : bus_dmamap_sync(sc->sc_dmat, cmd->src_map,
2630 : 0, cmd->src_map->dm_mapsize, BUS_DMASYNC_PREWRITE);
2631 0 : bus_dmamap_sync(sc->sc_dmat, cmd->dst_map,
2632 : 0, cmd->dst_map->dm_mapsize, BUS_DMASYNC_PREREAD);
2633 :
2634 : /* already at splnet... */
2635 0 : err = hifn_compress_enter(sc, cmd);
2636 0 : if (err != 0)
2637 0 : goto out;
2638 0 : return;
2639 : }
2640 :
2641 0 : olen = dstsize - (letoh16(baseres.dst_cnt) |
2642 0 : (((letoh16(baseres.session) & HIFN_BASE_RES_DSTLEN_M) >>
2643 0 : HIFN_BASE_RES_DSTLEN_S) << 16));
2644 :
2645 0 : crp->crp_olen = olen - cmd->compcrd->crd_skip;
2646 :
2647 0 : bus_dmamap_unload(sc->sc_dmat, cmd->src_map);
2648 0 : bus_dmamap_destroy(sc->sc_dmat, cmd->src_map);
2649 0 : bus_dmamap_destroy(sc->sc_dmat, cmd->dst_map);
2650 :
2651 0 : m = cmd->dstu.dst_m;
2652 0 : if (m->m_flags & M_PKTHDR)
2653 0 : m->m_pkthdr.len = olen;
2654 0 : crp->crp_buf = (caddr_t)m;
2655 0 : for (; m != NULL; m = m->m_next) {
2656 0 : if (olen >= m->m_len)
2657 0 : olen -= m->m_len;
2658 : else {
2659 0 : m->m_len = olen;
2660 : olen = 0;
2661 : }
2662 : }
2663 :
2664 0 : m_freem(cmd->srcu.src_m);
2665 0 : explicit_bzero(cmd, sizeof(*cmd));
2666 0 : free(cmd, M_DEVBUF, sizeof *cmd);
2667 0 : crp->crp_etype = 0;
2668 0 : crypto_done(crp);
2669 0 : return;
2670 :
2671 : out:
2672 0 : if (cmd->dst_map != NULL) {
2673 0 : if (cmd->src_map->dm_nsegs != 0)
2674 0 : bus_dmamap_unload(sc->sc_dmat, cmd->src_map);
2675 0 : bus_dmamap_destroy(sc->sc_dmat, cmd->dst_map);
2676 0 : }
2677 0 : if (cmd->src_map != NULL) {
2678 0 : if (cmd->src_map->dm_nsegs != 0)
2679 0 : bus_dmamap_unload(sc->sc_dmat, cmd->src_map);
2680 0 : bus_dmamap_destroy(sc->sc_dmat, cmd->src_map);
2681 0 : }
2682 0 : m_freem(cmd->dstu.dst_m);
2683 0 : explicit_bzero(cmd, sizeof(*cmd));
2684 0 : free(cmd, M_DEVBUF, sizeof *cmd);
2685 0 : crp->crp_etype = err;
2686 0 : crypto_done(crp);
2687 0 : }
2688 :
2689 : struct mbuf *
2690 0 : hifn_mkmbuf_chain(int totlen, struct mbuf *mtemplate)
2691 : {
2692 : int len;
2693 : struct mbuf *m, *m0, *mlast;
2694 :
2695 0 : if (mtemplate->m_flags & M_PKTHDR) {
2696 : len = MHLEN;
2697 0 : MGETHDR(m0, M_DONTWAIT, MT_DATA);
2698 0 : } else {
2699 : len = MLEN;
2700 0 : MGET(m0, M_DONTWAIT, MT_DATA);
2701 : }
2702 0 : if (m0 == NULL)
2703 0 : return (NULL);
2704 0 : if (len == MHLEN) {
2705 0 : if (m_dup_pkthdr(m0, mtemplate, M_DONTWAIT)) {
2706 0 : m_free(m0);
2707 0 : return (NULL);
2708 : }
2709 : }
2710 0 : MCLGET(m0, M_DONTWAIT);
2711 0 : if (!(m0->m_flags & M_EXT)) {
2712 0 : m_freem(m0);
2713 0 : return (NULL);
2714 : }
2715 : len = MCLBYTES;
2716 :
2717 0 : totlen -= len;
2718 0 : m0->m_pkthdr.len = m0->m_len = len;
2719 : mlast = m0;
2720 :
2721 0 : while (totlen > 0) {
2722 0 : MGET(m, M_DONTWAIT, MT_DATA);
2723 0 : if (m == NULL) {
2724 0 : m_freem(m0);
2725 0 : return (NULL);
2726 : }
2727 0 : MCLGET(m, M_DONTWAIT);
2728 0 : if (!(m->m_flags & M_EXT)) {
2729 0 : m_free(m);
2730 0 : m_freem(m0);
2731 0 : return (NULL);
2732 : }
2733 : len = MCLBYTES;
2734 0 : m->m_len = len;
2735 0 : if (m0->m_flags & M_PKTHDR)
2736 0 : m0->m_pkthdr.len += len;
2737 0 : totlen -= len;
2738 :
2739 0 : mlast->m_next = m;
2740 : mlast = m;
2741 : }
2742 :
2743 0 : return (m0);
2744 0 : }
2745 :
2746 : void
2747 0 : hifn_write_4(struct hifn_softc *sc, int reggrp, bus_size_t reg,
2748 : u_int32_t val)
2749 : {
2750 : /*
2751 : * 7811 PB3 rev/2 parts lock-up on burst writes to Group 0
2752 : * and Group 1 registers; avoid conditions that could create
2753 : * burst writes by doing a read in between the writes.
2754 : */
2755 0 : if (sc->sc_flags & HIFN_NO_BURSTWRITE) {
2756 0 : if (sc->sc_waw_lastgroup == reggrp &&
2757 0 : sc->sc_waw_lastreg == reg - 4) {
2758 0 : bus_space_read_4(sc->sc_st1, sc->sc_sh1, HIFN_1_REVID);
2759 0 : }
2760 0 : sc->sc_waw_lastgroup = reggrp;
2761 0 : sc->sc_waw_lastreg = reg;
2762 0 : }
2763 0 : if (reggrp == 0)
2764 0 : bus_space_write_4(sc->sc_st0, sc->sc_sh0, reg, val);
2765 : else
2766 0 : bus_space_write_4(sc->sc_st1, sc->sc_sh1, reg, val);
2767 :
2768 0 : }
2769 :
2770 : u_int32_t
2771 0 : hifn_read_4(struct hifn_softc *sc, int reggrp, bus_size_t reg)
2772 : {
2773 0 : if (sc->sc_flags & HIFN_NO_BURSTWRITE) {
2774 0 : sc->sc_waw_lastgroup = -1;
2775 0 : sc->sc_waw_lastreg = 1;
2776 0 : }
2777 0 : if (reggrp == 0)
2778 0 : return (bus_space_read_4(sc->sc_st0, sc->sc_sh0, reg));
2779 0 : return (bus_space_read_4(sc->sc_st1, sc->sc_sh1, reg));
2780 0 : }
|