FreeBSD/Linux Kernel Cross Reference
sys/dev/ic/iavc.c
1 /* $NetBSD: iavc.c,v 1.5 2006/10/16 13:00:36 pooka Exp $ */
2
3 /*
4 * Copyright (c) 2001-2003 Cubical Solutions Ltd. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * The AVM ISDN controllers' card specific support routines.
28 *
29 * $FreeBSD: src/sys/i4b/capi/iavc/iavc_card.c,v 1.1.2.1 2001/08/10 14:08:34 obrien Exp $
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: iavc.c,v 1.5 2006/10/16 13:00:36 pooka Exp $");
34
35 #include <sys/param.h>
36 #include <sys/kernel.h>
37 #include <sys/systm.h>
38 #include <sys/mbuf.h>
39 #include <sys/socket.h>
40 #include <sys/device.h>
41 #include <sys/callout.h>
42 #include <sys/reboot.h>
43 #include <net/if.h>
44
45 #include <machine/bus.h>
46
47 #include <netisdn/i4b_debug.h>
48 #include <netisdn/i4b_ioctl.h>
49 #include <netisdn/i4b_trace.h>
50 #include <netisdn/i4b_global.h>
51 #include <netisdn/i4b_l3l4.h>
52 #include <netisdn/i4b_mbuf.h>
53 #include <netisdn/i4b_capi.h>
54 #include <netisdn/i4b_capi_msgs.h>
55
56 #include <dev/ic/iavcvar.h>
57 #include <dev/ic/iavcreg.h>
58
59 /*
60 // AVM B1 (active BRI, PIO mode)
61 */
62
63 int
64 iavc_b1_detect(iavc_softc_t *sc)
65 {
66 if ((iavc_read_port(sc, B1_INSTAT) & 0xfc) ||
67 (iavc_read_port(sc, B1_OUTSTAT) & 0xfc))
68 return (1);
69
70 b1io_outp(sc, B1_INSTAT, 0x02);
71 b1io_outp(sc, B1_OUTSTAT, 0x02);
72 if ((iavc_read_port(sc, B1_INSTAT) & 0xfe) != 2 ||
73 (iavc_read_port(sc, B1_OUTSTAT) & 0xfe) != 2)
74 return (2);
75
76 b1io_outp(sc, B1_INSTAT, 0x00);
77 b1io_outp(sc, B1_OUTSTAT, 0x00);
78 if ((iavc_read_port(sc, B1_INSTAT) & 0xfe) ||
79 (iavc_read_port(sc, B1_OUTSTAT) & 0xfe))
80 return (3);
81
82 return (0); /* found */
83 }
84
85 void
86 iavc_b1_disable_irq(iavc_softc_t *sc)
87 {
88 b1io_outp(sc, B1_INSTAT, 0x00);
89 }
90
91 void
92 iavc_b1_reset(iavc_softc_t *sc)
93 {
94 b1io_outp(sc, B1_RESET, 0);
95 DELAY(55*2*1000);
96
97 b1io_outp(sc, B1_RESET, 1);
98 DELAY(55*2*1000);
99
100 b1io_outp(sc, B1_RESET, 0);
101 DELAY(55*2*1000);
102 }
103
104 /*
105 // Newer PCI-based B1's, and T1's, supports DMA
106 */
107
108 int
109 iavc_b1dma_detect(iavc_softc_t *sc)
110 {
111 AMCC_WRITE(sc, AMCC_MCSR, 0);
112 DELAY(10*1000);
113 AMCC_WRITE(sc, AMCC_MCSR, 0x0f000000);
114 DELAY(10*1000);
115 AMCC_WRITE(sc, AMCC_MCSR, 0);
116 DELAY(42*1000);
117
118 AMCC_WRITE(sc, AMCC_RXLEN, 0);
119 AMCC_WRITE(sc, AMCC_TXLEN, 0);
120 sc->sc_csr = 0;
121 AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
122
123 if (AMCC_READ(sc, AMCC_INTCSR) != 0)
124 return 1;
125
126 AMCC_WRITE(sc, AMCC_RXPTR, 0xffffffff);
127 AMCC_WRITE(sc, AMCC_TXPTR, 0xffffffff);
128 if ((AMCC_READ(sc, AMCC_RXPTR) != 0xfffffffc) ||
129 (AMCC_READ(sc, AMCC_TXPTR) != 0xfffffffc))
130 return 2;
131
132 AMCC_WRITE(sc, AMCC_RXPTR, 0);
133 AMCC_WRITE(sc, AMCC_TXPTR, 0);
134 if ((AMCC_READ(sc, AMCC_RXPTR) != 0) ||
135 (AMCC_READ(sc, AMCC_TXPTR) != 0))
136 return 3;
137
138 iavc_write_port(sc, 0x10, 0x00);
139 iavc_write_port(sc, 0x07, 0x00);
140
141 iavc_write_port(sc, 0x02, 0x02);
142 iavc_write_port(sc, 0x03, 0x02);
143
144 if (((iavc_read_port(sc, 0x02) & 0xfe) != 0x02) ||
145 (iavc_read_port(sc, 0x03) != 0x03))
146 return 4;
147
148 iavc_write_port(sc, 0x02, 0x00);
149 iavc_write_port(sc, 0x03, 0x00);
150
151 if (((iavc_read_port(sc, 0x02) & 0xfe) != 0x00) ||
152 (iavc_read_port(sc, 0x03) != 0x01))
153 return 5;
154
155 return (0); /* found */
156 }
157
158 void
159 iavc_b1dma_reset(iavc_softc_t *sc)
160 {
161 int s = splnet();
162
163 sc->sc_csr = 0;
164 AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
165 AMCC_WRITE(sc, AMCC_MCSR, 0);
166 AMCC_WRITE(sc, AMCC_RXLEN, 0);
167 AMCC_WRITE(sc, AMCC_TXLEN, 0);
168
169 iavc_write_port(sc, 0x10, 0x00); /* XXX magic numbers from */
170 iavc_write_port(sc, 0x07, 0x00); /* XXX the linux driver */
171
172 splx(s);
173
174 AMCC_WRITE(sc, AMCC_MCSR, 0);
175 DELAY(10 * 1000);
176 AMCC_WRITE(sc, AMCC_MCSR, 0x0f000000);
177 DELAY(10 * 1000);
178 AMCC_WRITE(sc, AMCC_MCSR, 0);
179 DELAY(42 * 1000);
180 }
181
182 /*
183 // AVM T1 (active PRI)
184 */
185
186 #define b1dma_tx_empty(sc) (b1io_read_reg((sc), T1_OUTSTAT) & 1)
187 #define b1dma_rx_full(sc) (b1io_read_reg((sc), T1_INSTAT) & 1)
188
189 static int b1dma_tolink(iavc_softc_t *sc, void *buf, int len)
190 {
191 volatile int spin;
192 char *s = (char*) buf;
193 while (len--) {
194 spin = 0;
195 while (!b1dma_tx_empty(sc) && spin < 100000)
196 spin++;
197 if (!b1dma_tx_empty(sc))
198 return -1;
199 t1io_outp(sc, 1, *s++);
200 }
201 return 0;
202 }
203
204 static int b1dma_fromlink(iavc_softc_t *sc, void *buf, int len)
205 {
206 volatile int spin;
207 char *s = (char*) buf;
208 while (len--) {
209 spin = 0;
210 while (!b1dma_rx_full(sc) && spin < 100000)
211 spin++;
212 if (!b1dma_rx_full(sc))
213 return -1;
214 *s++ = t1io_inp(sc, 0);
215 }
216 return 0;
217 }
218
219 static int WriteReg(iavc_softc_t *sc, u_int32_t reg, u_int8_t val)
220 {
221 u_int8_t cmd = 0;
222 if (b1dma_tolink(sc, &cmd, 1) == 0 &&
223 b1dma_tolink(sc, ®, 4) == 0) {
224 u_int32_t tmp = val;
225 return b1dma_tolink(sc, &tmp, 4);
226 }
227 return -1;
228 }
229
230 static u_int8_t ReadReg(iavc_softc_t *sc, u_int32_t reg)
231 {
232 u_int8_t cmd = 1;
233 if (b1dma_tolink(sc, &cmd, 1) == 0 &&
234 b1dma_tolink(sc, ®, 4) == 0) {
235 u_int32_t tmp;
236 if (b1dma_fromlink(sc, &tmp, 4) == 0)
237 return (u_int8_t) tmp;
238 }
239 return 0xff;
240 }
241
242 int
243 iavc_t1_detect(iavc_softc_t *sc)
244 {
245 int ret = iavc_b1dma_detect(sc);
246 if (ret) return ret;
247
248 if ((WriteReg(sc, 0x80001000, 0x11) != 0) ||
249 (WriteReg(sc, 0x80101000, 0x22) != 0) ||
250 (WriteReg(sc, 0x80201000, 0x33) != 0) ||
251 (WriteReg(sc, 0x80301000, 0x44) != 0))
252 return 6;
253
254 if ((ReadReg(sc, 0x80001000) != 0x11) ||
255 (ReadReg(sc, 0x80101000) != 0x22) ||
256 (ReadReg(sc, 0x80201000) != 0x33) ||
257 (ReadReg(sc, 0x80301000) != 0x44))
258 return 7;
259
260 if ((WriteReg(sc, 0x80001000, 0x55) != 0) ||
261 (WriteReg(sc, 0x80101000, 0x66) != 0) ||
262 (WriteReg(sc, 0x80201000, 0x77) != 0) ||
263 (WriteReg(sc, 0x80301000, 0x88) != 0))
264 return 8;
265
266 if ((ReadReg(sc, 0x80001000) != 0x55) ||
267 (ReadReg(sc, 0x80101000) != 0x66) ||
268 (ReadReg(sc, 0x80201000) != 0x77) ||
269 (ReadReg(sc, 0x80301000) != 0x88))
270 return 9;
271
272 return 0; /* found */
273 }
274
275 void
276 iavc_t1_disable_irq(iavc_softc_t *sc)
277 {
278 iavc_write_port(sc, T1_IRQMASTER, 0x00);
279 }
280
281 void
282 iavc_t1_reset(iavc_softc_t *sc)
283 {
284 iavc_b1_reset(sc);
285 iavc_write_port(sc, B1_INSTAT, 0x00);
286 iavc_write_port(sc, B1_OUTSTAT, 0x00);
287 iavc_write_port(sc, T1_IRQMASTER, 0x00);
288 iavc_write_port(sc, T1_RESETBOARD, 0x0f);
289 }
290
291 /* Forward declarations of local subroutines... */
292
293 static int iavc_send_init(iavc_softc_t *);
294
295 static void iavc_handle_rx(iavc_softc_t *);
296 static void iavc_start_tx(iavc_softc_t *);
297
298 static uint32_t iavc_tx_capimsg(iavc_softc_t *, struct mbuf *);
299 static uint32_t iavc_tx_ctrlmsg(iavc_softc_t *, struct mbuf *);
300
301 /*
302 // Callbacks from the upper (capi) layer:
303 // --------------------------------------
304 //
305 // iavc_load
306 // Resets the board and loads the firmware, then initiates
307 // board startup.
308 //
309 // iavc_register
310 // Registers a CAPI application id.
311 //
312 // iavc_release
313 // Releases a CAPI application id.
314 //
315 // iavc_send
316 // Sends a capi message.
317 */
318
319 int iavc_load(capi_softc_t *capi_sc, int len, u_int8_t *cp)
320 {
321 iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
322 u_int8_t val;
323
324 aprint_debug("%s: reset card ....\n", sc->sc_dev.dv_xname);
325
326 if (sc->sc_dma)
327 iavc_b1dma_reset(sc); /* PCI cards */
328 else if (sc->sc_t1)
329 iavc_t1_reset(sc); /* ISA attachment T1 */
330 else
331 iavc_b1_reset(sc); /* ISA attachment B1 */
332
333 DELAY(1000);
334
335 aprint_debug("%s: start loading %d bytes firmware\n",
336 sc->sc_dev.dv_xname, len);
337
338 while (len && b1io_save_put_byte(sc, *cp++) == 0)
339 len--;
340
341 if (len) {
342 aprint_error("%s: loading failed, can't write to card, len = %d\n",
343 sc->sc_dev.dv_xname, len);
344 return (EIO);
345 }
346
347 aprint_debug("%s: firmware loaded, wait for ACK\n", sc->sc_dev.dv_xname);
348
349 if(sc->sc_capi.card_type == CARD_TYPEC_AVM_B1_ISA)
350 iavc_put_byte(sc, SEND_POLL);
351 else
352 iavc_put_byte(sc, SEND_POLLACK);
353
354 for (len = 0; len < 1000 && !iavc_rx_full(sc); len++)
355 DELAY(100);
356
357 if (!iavc_rx_full(sc)) {
358 aprint_error("%s: loading failed, no ack\n", sc->sc_dev.dv_xname);
359 return (EIO);
360 }
361
362 val = iavc_get_byte(sc);
363
364 if ((sc->sc_dma && val != RECEIVE_POLLDWORD) ||
365 (!sc->sc_dma && val != RECEIVE_POLL)) {
366 aprint_error("%s: loading failed, bad ack = %02x\n",
367 sc->sc_dev.dv_xname, val);
368 return (EIO);
369 }
370
371 aprint_debug("%s: got ACK = 0x%02x\n", sc->sc_dev.dv_xname, val);
372
373 /* Start the DMA engine */
374 if (sc->sc_dma) {
375 int s;
376
377 s = splnet();
378
379 sc->sc_csr = AVM_FLAG;
380 AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
381 AMCC_WRITE(sc, AMCC_MCSR, (EN_A2P_TRANSFERS|EN_P2A_TRANSFERS|
382 A2P_HI_PRIORITY|P2A_HI_PRIORITY|
383 RESET_A2P_FLAGS|RESET_P2A_FLAGS));
384
385 iavc_write_port(sc, 0x07, 0x30); /* XXX magic numbers from */
386 iavc_write_port(sc, 0x10, 0xf0); /* XXX the linux driver */
387
388 bus_dmamap_sync(sc->dmat, sc->rx_map, 0, sc->rx_map->dm_mapsize,
389 BUS_DMASYNC_PREREAD);
390
391 sc->sc_recv1 = 0;
392 AMCC_WRITE(sc, AMCC_RXPTR, sc->rx_map->dm_segs[0].ds_addr);
393 AMCC_WRITE(sc, AMCC_RXLEN, 4);
394 sc->sc_csr |= EN_RX_TC_INT|EN_TX_TC_INT;
395 AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
396
397 splx(s);
398 }
399
400 #ifdef notyet
401 /* good happy place */
402 if(sc->sc_capi.card_type == CARD_TYPEC_AVM_B1_ISA)
403 b1isa_setup_irq(sc);
404 #endif
405
406 iavc_send_init(sc);
407
408 return 0;
409 }
410
411 int iavc_register(capi_softc_t *capi_sc, int applid, int nchan)
412 {
413 iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
414 struct mbuf *m = i4b_Dgetmbuf(23);
415 u_int8_t *p;
416
417 if (!m) {
418 aprint_error("iavc%d: can't get memory\n", sc->sc_unit);
419 return (ENOMEM);
420 }
421
422 /*
423 * byte 0x12 = SEND_REGISTER
424 * dword ApplId
425 * dword NumMessages
426 * dword NumB3Connections 0..nbch
427 * dword NumB3Blocks
428 * dword B3Size
429 */
430
431 p = amcc_put_byte(mtod(m, u_int8_t*), 0);
432 p = amcc_put_byte(p, 0);
433 p = amcc_put_byte(p, SEND_REGISTER);
434 p = amcc_put_word(p, applid);
435 #if 0
436 p = amcc_put_word(p, 1024 + (nchan + 1));
437 #else
438 p = amcc_put_word(p, 1024 * (nchan + 1));
439 #endif
440 p = amcc_put_word(p, nchan);
441 p = amcc_put_word(p, 8);
442 p = amcc_put_word(p, 2048);
443
444 IF_ENQUEUE(&sc->sc_txq, m);
445
446 iavc_start_tx(sc);
447
448 return 0;
449 }
450
451 int iavc_release(capi_softc_t *capi_sc, int applid)
452 {
453 iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
454 struct mbuf *m = i4b_Dgetmbuf(7);
455 u_int8_t *p;
456
457 if (!m) {
458 printf("%s: can't get memory\n", sc->sc_dev.dv_xname);
459 return (ENOMEM);
460 }
461
462 /*
463 * byte 0x14 = SEND_RELEASE
464 * dword ApplId
465 */
466
467 p = amcc_put_byte(mtod(m, u_int8_t*), 0);
468 p = amcc_put_byte(p, 0);
469 p = amcc_put_byte(p, SEND_RELEASE);
470 p = amcc_put_word(p, applid);
471
472 IF_ENQUEUE(&sc->sc_txq, m);
473
474 iavc_start_tx(sc);
475 return 0;
476 }
477
478 int iavc_send(capi_softc_t *capi_sc, struct mbuf *m)
479 {
480 iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
481
482 if (sc->sc_state != IAVC_UP) {
483 printf("%s: attempt to send before device up\n", sc->sc_dev.dv_xname);
484
485 if (m->m_next) i4b_Bfreembuf(m->m_next);
486 i4b_Dfreembuf(m);
487
488 return (ENXIO);
489 }
490
491 if (IF_QFULL(&sc->sc_txq)) {
492 IF_DROP(&sc->sc_txq);
493
494 printf("%s: tx overflow, message dropped\n", sc->sc_dev.dv_xname);
495
496 if (m->m_next) i4b_Bfreembuf(m->m_next);
497 i4b_Dfreembuf(m);
498
499 } else {
500 IF_ENQUEUE(&sc->sc_txq, m);
501
502 iavc_start_tx(sc);
503 }
504
505 return 0;
506 }
507
508 /*
509 // Functions called by ourself during the initialization sequence:
510 // ---------------------------------------------------------------
511 //
512 // iavc_send_init
513 // Sends the system initialization message to a newly loaded
514 // board, and sets state to INIT.
515 */
516
517 static int iavc_send_init(iavc_softc_t *sc)
518 {
519 struct mbuf *m = i4b_Dgetmbuf(15);
520 u_int8_t *p;
521 int s;
522
523 if (!m) {
524 printf("%s: can't get memory\n", sc->sc_dev.dv_xname);
525 return (ENOMEM);
526 }
527
528 /*
529 * byte 0x11 = SEND_INIT
530 * dword NumApplications
531 * dword NumNCCIs
532 * dword BoardNumber
533 */
534
535 p = amcc_put_byte(mtod(m, u_int8_t*), 0);
536 p = amcc_put_byte(p, 0);
537 p = amcc_put_byte(p, SEND_INIT);
538 p = amcc_put_word(p, 1); /* XXX MaxAppl XXX */
539 p = amcc_put_word(p, sc->sc_capi.sc_nbch);
540 p = amcc_put_word(p, sc->sc_unit);
541
542 s = splnet();
543 IF_ENQUEUE(&sc->sc_txq, m);
544
545 iavc_start_tx(sc);
546
547 sc->sc_state = IAVC_INIT;
548 splx(s);
549 return 0;
550 }
551
552 /*
553 // Functions called during normal operation:
554 // -----------------------------------------
555 //
556 // iavc_receive_init
557 // Reads the initialization reply and calls capi_ll_control().
558 //
559 // iavc_receive_new_ncci
560 // Reads a new NCCI notification and calls capi_ll_control().
561 //
562 // iavc_receive_free_ncci
563 // Reads a freed NCCI notification and calls capi_ll_control().
564 //
565 // iavc_receive_task_ready
566 // Reads a task ready message -- which should not occur XXX.
567 //
568 // iavc_receive_debugmsg
569 // Reads a debug message -- which should not occur XXX.
570 //
571 // iavc_receive_start
572 // Reads a START TRANSMIT message and unblocks device.
573 //
574 // iavc_receive_stop
575 // Reads a STOP TRANSMIT message and blocks device.
576 //
577 // iavc_receive
578 // Reads an incoming message and calls capi_ll_receive().
579 */
580
581 static int iavc_receive_init(iavc_softc_t *sc, u_int8_t *dmabuf)
582 {
583 u_int32_t Length;
584 u_int8_t *p;
585 u_int8_t *cardtype, *serial, *profile, *vers, *caps, *prot;
586
587 if (sc->sc_dma) {
588 p = amcc_get_word(dmabuf, &Length);
589 } else {
590 Length = iavc_get_slice(sc, sc->sc_recvbuf);
591 p = sc->sc_recvbuf;
592 }
593
594 #if 0
595 {
596 int len = 0;
597 printf("%s: rx_init: ", sc->sc_dev.dv_xname);
598 while (len < Length) {
599 printf(" %02x", p[len]);
600 if (len && (len % 16) == 0) printf("\n");
601 len++;
602 }
603 if (len % 16) printf("\n");
604 }
605 #endif
606
607 vers = (p + 1);
608 p += (*p + 1); /* driver version */
609 cardtype = (p + 1);
610 p += (*p + 1); /* card type */
611 p += (*p + 1); /* hardware ID */
612 serial = (p + 1);
613 p += (*p + 1); /* serial number */
614 caps = (p + 1);
615 p += (*p + 1); /* supported options */
616 prot = (p + 1);
617 p += (*p + 1); /* supported protocols */
618 profile = (p + 1);
619
620 if (cardtype && serial && profile) {
621 int nbch = ((profile[3]<<8) | profile[2]);
622
623 aprint_normal("%s: AVM %s, s/n %s, %d chans, f/w rev %s, prot %s\n",
624 sc->sc_dev.dv_xname, cardtype, serial, nbch, vers, prot);
625 aprint_verbose("%s: %s\n", sc->sc_dev.dv_xname, caps);
626
627 capi_ll_control(&sc->sc_capi, CAPI_CTRL_PROFILE, (int) profile);
628
629 } else {
630 printf("%s: no profile data in info response?\n", sc->sc_dev.dv_xname);
631 }
632
633 sc->sc_blocked = 1; /* controller will send START when ready */
634 return 0;
635 }
636
637 static int iavc_receive_start(iavc_softc_t *sc)
638 {
639 struct mbuf *m = i4b_Dgetmbuf(3);
640 u_int8_t *p;
641
642 if (sc->sc_blocked && sc->sc_state == IAVC_UP)
643 printf("%s: receive_start\n", sc->sc_dev.dv_xname);
644
645 if (!m) {
646 printf("%s: can't get memory\n", sc->sc_dev.dv_xname);
647 return (ENOMEM);
648 }
649
650 /*
651 * byte 0x73 = SEND_POLLACK
652 */
653
654 p = amcc_put_byte(mtod(m, u_int8_t*), 0);
655 p = amcc_put_byte(p, 0);
656 p = amcc_put_byte(p, SEND_POLLACK);
657
658 IF_PREPEND(&sc->sc_txq, m);
659
660 NDBGL4(L4_IAVCDBG, "%s: blocked = %d, state = %d",
661 sc->sc_dev.dv_xname, sc->sc_blocked, sc->sc_state);
662
663 sc->sc_blocked = 0;
664 iavc_start_tx(sc);
665
666 /* If this was our first START, register our readiness */
667 if (sc->sc_state != IAVC_UP) {
668 sc->sc_state = IAVC_UP;
669 capi_ll_control(&sc->sc_capi, CAPI_CTRL_READY, 1);
670 }
671
672 return 0;
673 }
674
675 static int iavc_receive_stop(iavc_softc_t *sc)
676 {
677 printf("%s: receive_stop\n", sc->sc_dev.dv_xname);
678 sc->sc_blocked = 1;
679 return 0;
680 }
681
682 static int iavc_receive_new_ncci(iavc_softc_t *sc, u_int8_t *dmabuf)
683 {
684 u_int32_t ApplId, NCCI, WindowSize;
685
686 if (sc->sc_dma) {
687 dmabuf = amcc_get_word(dmabuf, &ApplId);
688 dmabuf = amcc_get_word(dmabuf, &NCCI);
689 dmabuf = amcc_get_word(dmabuf, &WindowSize);
690 } else {
691 ApplId = iavc_get_word(sc);
692 NCCI = iavc_get_word(sc);
693 WindowSize = iavc_get_word(sc);
694 }
695
696 capi_ll_control(&sc->sc_capi, CAPI_CTRL_NEW_NCCI, NCCI);
697 return 0;
698 }
699
700 static int iavc_receive_free_ncci(iavc_softc_t *sc, u_int8_t *dmabuf)
701 {
702 u_int32_t ApplId, NCCI;
703
704 if (sc->sc_dma) {
705 dmabuf = amcc_get_word(dmabuf, &ApplId);
706 dmabuf = amcc_get_word(dmabuf, &NCCI);
707 } else {
708 ApplId = iavc_get_word(sc);
709 NCCI = iavc_get_word(sc);
710 }
711
712 capi_ll_control(&sc->sc_capi, CAPI_CTRL_FREE_NCCI, NCCI);
713 return 0;
714 }
715
716 static int iavc_receive_task_ready(iavc_softc_t *sc, u_int8_t *dmabuf)
717 {
718 u_int32_t TaskId, Length;
719 u_int8_t *p;
720 printf("%s: receive_task_ready\n", sc->sc_dev.dv_xname);
721
722 if (sc->sc_dma) {
723 p = amcc_get_word(dmabuf, &TaskId);
724 p = amcc_get_word(p, &Length);
725 } else {
726 TaskId = iavc_get_word(sc);
727 Length = iavc_get_slice(sc, sc->sc_recvbuf);
728 p = sc->sc_recvbuf;
729 }
730
731 /* XXX could show the message if trace enabled? XXX */
732 return 0;
733 }
734
735 static int iavc_receive_debugmsg(iavc_softc_t *sc, u_int8_t *dmabuf)
736 {
737 u_int32_t Length;
738 u_int8_t *p;
739 printf("%s: receive_debugmsg\n", sc->sc_dev.dv_xname);
740
741 if (sc->sc_dma) {
742 p = amcc_get_word(dmabuf, &Length);
743 } else {
744 Length = iavc_get_slice(sc, sc->sc_recvbuf);
745 p = sc->sc_recvbuf;
746 }
747
748 /* XXX could show the message if trace enabled? XXX */
749 return 0;
750 }
751
752 static int iavc_receive(iavc_softc_t *sc, u_int8_t *dmabuf, int b3data)
753 {
754 struct mbuf *m;
755 u_int32_t ApplId, Length;
756
757 /*
758 * byte 0x21 = RECEIVE_MESSAGE
759 * dword ApplId
760 * dword length
761 * ... CAPI msg
762 *
763 * --or--
764 *
765 * byte 0x22 = RECEIVE_DATA_B3_IND
766 * dword ApplId
767 * dword length
768 * ... CAPI msg
769 * dword datalen
770 * ... B3 data
771 */
772
773 if (sc->sc_dma) {
774 dmabuf = amcc_get_word(dmabuf, &ApplId);
775 dmabuf = amcc_get_word(dmabuf, &Length);
776 } else {
777 ApplId = iavc_get_word(sc);
778 Length = iavc_get_slice(sc, sc->sc_recvbuf);
779 dmabuf = sc->sc_recvbuf;
780 }
781
782 m = i4b_Dgetmbuf(Length);
783 if (!m) {
784 printf("%s: can't get memory for receive\n", sc->sc_dev.dv_xname);
785 return (ENOMEM);
786 }
787
788 memcpy(mtod(m, u_int8_t*), dmabuf, Length);
789
790 #if 0
791 {
792 u_int8_t *p = mtod(m, u_int8_t*);
793 int len = 0;
794 printf("%s: applid=%d, len=%d\n", sc->sc_dev.dv_xname,
795 ApplId, Length);
796 while (len < m->m_len) {
797 printf(" %02x", p[len]);
798 if (len && (len % 16) == 0) printf("\n");
799 len++;
800 }
801 if (len % 16) printf("\n");
802 }
803 #endif
804
805 if (b3data) {
806 if (sc->sc_dma) {
807 dmabuf = amcc_get_word(dmabuf + Length, &Length);
808 } else {
809 Length = iavc_get_slice(sc, sc->sc_recvbuf);
810 dmabuf = sc->sc_recvbuf;
811 }
812
813 m->m_next = i4b_Bgetmbuf(Length);
814 if (!m->m_next) {
815 printf("%s: can't get memory for receive\n", sc->sc_dev.dv_xname);
816 i4b_Dfreembuf(m);
817 return (ENOMEM);
818 }
819
820 memcpy(mtod(m->m_next, u_int8_t*), dmabuf, Length);
821 }
822
823 capi_ll_receive(&sc->sc_capi, m);
824 return 0;
825 }
826
827 /*
828 // iavc_handle_intr
829 // Checks device interrupt status and calls iavc_handle_{rx,tx}()
830 // as necessary.
831 //
832 // iavc_handle_rx
833 // Reads in the command byte and calls the subroutines above.
834 //
835 // iavc_start_tx
836 // Initiates DMA on the next queued message if possible.
837 */
838
839 int iavc_handle_intr(iavc_softc_t *sc)
840 {
841 u_int32_t status;
842 u_int32_t newcsr;
843
844 if (!sc->sc_dma) {
845 while (iavc_rx_full(sc))
846 iavc_handle_rx(sc);
847 return 0;
848 }
849
850 status = AMCC_READ(sc, AMCC_INTCSR);
851 if ((status & ANY_S5933_INT) == 0)
852 return 0;
853
854 newcsr = sc->sc_csr | (status & ALL_INT);
855 if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT;
856 if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT;
857 AMCC_WRITE(sc, AMCC_INTCSR, newcsr);
858 sc->sc_intr = 1;
859
860 if (status & RX_TC_INT) {
861 u_int32_t rxlen;
862
863 bus_dmamap_sync(sc->dmat, sc->rx_map, 0, sc->rx_map->dm_mapsize,
864 BUS_DMASYNC_POSTREAD);
865
866 if (sc->sc_recv1 == 0) {
867 sc->sc_recv1 = *(u_int32_t*)(sc->sc_recvbuf);
868 rxlen = (sc->sc_recv1 + 3) & ~3;
869
870 AMCC_WRITE(sc, AMCC_RXPTR, sc->rx_map->dm_segs[0].ds_addr);
871 AMCC_WRITE(sc, AMCC_RXLEN, rxlen ? rxlen : 4);
872 } else {
873 iavc_handle_rx(sc);
874 sc->sc_recv1 = 0;
875 AMCC_WRITE(sc, AMCC_RXPTR, sc->rx_map->dm_segs[0].ds_addr);
876 AMCC_WRITE(sc, AMCC_RXLEN, 4);
877 }
878 }
879
880 if (status & TX_TC_INT) {
881 bus_dmamap_sync(sc->dmat, sc->tx_map, 0, sc->tx_map->dm_mapsize,
882 BUS_DMASYNC_POSTWRITE);
883 sc->sc_csr &= ~EN_TX_TC_INT;
884 iavc_start_tx(sc);
885 }
886
887 AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
888 sc->sc_intr = 0;
889
890 return 0;
891 }
892
893 static void iavc_handle_rx(iavc_softc_t *sc)
894 {
895 u_int8_t *dmabuf = 0, cmd;
896
897 if (sc->sc_dma) {
898 dmabuf = amcc_get_byte(&sc->sc_recvbuf[0], &cmd);
899 } else {
900 cmd = iavc_get_byte(sc);
901 }
902
903 NDBGL4(L4_IAVCDBG, "iavc%d: command = 0x%02x", sc->sc_unit, cmd);
904
905 switch (cmd) {
906 case RECEIVE_DATA_B3_IND:
907 iavc_receive(sc, dmabuf, 1);
908 break;
909
910 case RECEIVE_MESSAGE:
911 iavc_receive(sc, dmabuf, 0);
912 break;
913
914 case RECEIVE_NEW_NCCI:
915 iavc_receive_new_ncci(sc, dmabuf);
916 break;
917
918 case RECEIVE_FREE_NCCI:
919 iavc_receive_free_ncci(sc, dmabuf);
920 break;
921
922 case RECEIVE_START:
923 iavc_receive_start(sc);
924 break;
925
926 case RECEIVE_STOP:
927 iavc_receive_stop(sc);
928 break;
929
930 case RECEIVE_INIT:
931 iavc_receive_init(sc, dmabuf);
932 break;
933
934 case RECEIVE_TASK_READY:
935 iavc_receive_task_ready(sc, dmabuf);
936 break;
937
938 case RECEIVE_DEBUGMSG:
939 iavc_receive_debugmsg(sc, dmabuf);
940 break;
941
942 default:
943 printf("%s: unknown msg %02x\n", sc->sc_dev.dv_xname, cmd);
944 }
945 }
946
947 static void iavc_start_tx(iavc_softc_t *sc)
948 {
949 struct mbuf *m;
950 u_int32_t txlen;
951
952 /* If device has put us on hold, punt. */
953
954 if (sc->sc_blocked) {
955 return;
956 }
957
958 /* If using DMA and transmitter busy, punt. */
959 if (sc->sc_dma && (sc->sc_csr & EN_TX_TC_INT)) {
960 return;
961 }
962
963 /* Else, see if we have messages to send. */
964 IF_DEQUEUE(&sc->sc_txq, m);
965 if (!m) {
966 return;
967 }
968
969 /* Have message, will send. */
970 if (CAPIMSG_LEN(m->m_data)) {
971 /* A proper CAPI message, possibly with B3 data */
972 txlen = iavc_tx_capimsg(sc, m);
973 } else {
974 /* A board control message to be sent as is */
975 txlen = iavc_tx_ctrlmsg(sc, m);
976 }
977
978 if (m->m_next) {
979 i4b_Bfreembuf(m->m_next);
980 m->m_next = NULL;
981 }
982 i4b_Dfreembuf(m);
983
984 /* Kick DMA into motion if applicable */
985 if (sc->sc_dma) {
986 txlen = (txlen + 3) & ~3;
987
988 bus_dmamap_sync(sc->dmat, sc->tx_map, 0, txlen,
989 BUS_DMASYNC_PREWRITE);
990
991 AMCC_WRITE(sc, AMCC_TXPTR, sc->tx_map->dm_segs[0].ds_addr);
992 AMCC_WRITE(sc, AMCC_TXLEN, txlen);
993 sc->sc_csr |= EN_TX_TC_INT;
994
995 if (!sc->sc_intr)
996 AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
997 }
998 }
999
1000 static uint32_t
1001 iavc_tx_capimsg(iavc_softc_t *sc, struct mbuf *m)
1002 {
1003 uint32_t txlen = 0;
1004 u_int8_t *dmabuf;
1005
1006 if (sc->sc_dma) {
1007 /* Copy message to DMA buffer. */
1008
1009 if (m->m_next)
1010 dmabuf = amcc_put_byte(&sc->sc_sendbuf[0], SEND_DATA_B3_REQ);
1011 else
1012 dmabuf = amcc_put_byte(&sc->sc_sendbuf[0], SEND_MESSAGE);
1013
1014 dmabuf = amcc_put_word(dmabuf, m->m_len);
1015 memcpy(dmabuf, m->m_data, m->m_len);
1016 dmabuf += m->m_len;
1017 txlen = 5 + m->m_len;
1018
1019 if (m->m_next) {
1020 dmabuf = amcc_put_word(dmabuf, m->m_next->m_len);
1021 memcpy(dmabuf, m->m_next->m_data, m->m_next->m_len);
1022 txlen += 4 + m->m_next->m_len;
1023 }
1024
1025 } else {
1026 /* Use PIO. */
1027
1028 if (m->m_next) {
1029 iavc_put_byte(sc, SEND_DATA_B3_REQ);
1030 NDBGL4(L4_IAVCDBG, "iavc%d: tx SDB3R msg, len = %d",
1031 sc->sc_unit, m->m_len);
1032 } else {
1033 iavc_put_byte(sc, SEND_MESSAGE);
1034 NDBGL4(L4_IAVCDBG, "iavc%d: tx SM msg, len = %d",
1035 sc->sc_unit, m->m_len);
1036 }
1037 #if 0
1038 {
1039 u_int8_t *p = mtod(m, u_int8_t*);
1040 int len;
1041 for (len = 0; len < m->m_len; len++) {
1042 printf(" %02x", *p++);
1043 if (len && (len % 16) == 0)
1044 printf("\n");
1045 }
1046 if (len % 16)
1047 printf("\n");
1048 }
1049 #endif
1050
1051 iavc_put_slice(sc, m->m_data, m->m_len);
1052
1053 if (m->m_next)
1054 iavc_put_slice(sc, m->m_next->m_data, m->m_next->m_len);
1055 }
1056
1057 return txlen;
1058 }
1059
1060 static uint32_t
1061 iavc_tx_ctrlmsg(iavc_softc_t *sc, struct mbuf *m)
1062 {
1063 uint32_t txlen = 0;
1064 uint8_t *dmabuf;
1065
1066 if (sc->sc_dma) {
1067 memcpy(&sc->sc_sendbuf[0], m->m_data + 2, m->m_len - 2);
1068 txlen = m->m_len - 2;
1069 } else {
1070
1071 #if 0
1072 {
1073 u_int8_t *p = mtod(m, u_int8_t*) + 2;
1074 int len;
1075
1076 printf("%s: tx BDC msg, len = %d, msg =", sc->sc_dev.dv_xname,
1077 m->m_len-2);
1078 for (len = 0; len < m->m_len-2; len++) {
1079 printf(" %02x", *p++);
1080 if (len && (len % 16) == 0) printf("\n");
1081 }
1082 if (len % 16)
1083 printf("\n");
1084 }
1085 #endif
1086
1087 /* no DMA */
1088 txlen = m->m_len - 2;
1089 dmabuf = mtod(m, char*) + 2;
1090 while(txlen--)
1091 b1io_put_byte(sc, *dmabuf++);
1092 }
1093
1094 return txlen;
1095 }
Cache object: fe21c6cde7812ae7063c8a632a0767f6
|