2 * Copyright (c) 1997, 2000 Hellmuth Michaelis. All rights reserved.
3 * Copyright (c) 2001 Gary Jennejohn. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 *---------------------------------------------------------------------------
28 * i4b_ifpi2_isac.c - i4b Fritz PCI Version 2 ISACSX handler
29 * --------------------------------------------
33 * $FreeBSD: src/sys/i4b/layer1/ifpi2/i4b_ifpi2_isacsx.c,v 1.1.2.1 2002/04/25 20:26:50 gj Exp $
34 * $DragonFly: src/sys/net/i4b/layer1/ifpi2/i4b_ifpi2_isacsx.c,v 1.2 2003/06/17 04:28:39 dillon Exp $
36 * last edit-date: [Mon May 29 15:22:52 2000]
38 *---------------------------------------------------------------------------*/
43 #if (NIFPI2 > 0) && (NPCI > 0)
47 #include <sys/param.h>
48 #include <sys/systm.h>
50 #include <sys/socket.h>
55 #include <machine/i4b_debug.h>
56 #include <machine/i4b_ioctl.h>
57 #include <machine/i4b_trace.h>
59 #include <i4b/layer1/i4b_l1.h>
61 #include <i4b/layer1/isic/i4b_isic.h>
62 #include <i4b/layer1/isic/i4b_hscx.h>
64 #include <i4b/layer1/ifpi2/i4b_ifpi2_ext.h>
65 #include <i4b/layer1/ifpi2/i4b_ifpi2_isacsx.h>
67 #include <i4b/include/i4b_global.h>
68 #include <i4b/include/i4b_mbuf.h>
70 static u_char ifpi2_isacsx_exir_hdlr(register struct l1_softc *sc, u_char exir);
71 static void ifpi2_isacsx_ind_hdlr(register struct l1_softc *sc, int ind);
73 /* the ISACSX has 2 mask registers of interest - cannot use ISAC_IMASK */
74 unsigned char isacsx_imaskd;
75 unsigned char isacsx_imask;
77 /*---------------------------------------------------------------------------*
78 * ISACSX interrupt service routine
79 *---------------------------------------------------------------------------*/
81 ifpi2_isacsx_irq(struct l1_softc *sc, int ista)
83 register u_char c = 0;
84 register u_char istad = 0;
86 NDBGL1(L1_F_MSG, "unit %d: ista = 0x%02x", sc->sc_unit, ista);
88 /* was it an HDLC interrupt ? */
89 if (ista & ISACSX_ISTA_ICD)
91 istad = ISAC_READ(I_ISTAD);
92 NDBGL1(L1_F_MSG, "unit %d: istad = 0x%02x", sc->sc_unit, istad);
94 if(istad & (ISACSX_ISTAD_RFO|ISACSX_ISTAD_XMR|ISACSX_ISTAD_XDU))
96 /* not really EXIR, but very similar */
97 c |= ifpi2_isacsx_exir_hdlr(sc, istad);
101 if(istad & ISACSX_ISTAD_RME) /* receive message end */
106 /* get rx status register */
108 rsta = ISAC_READ(I_RSTAD);
110 /* Check for Frame and CRC valid */
111 if((rsta & ISACSX_RSTAD_MASK) != (ISACSX_RSTAD_VFR|ISACSX_RSTAD_CRC))
115 if(!(rsta & ISACSX_RSTAD_VFR)) /* VFR error */
118 NDBGL1(L1_I_ERR, "unit %d: Frame not valid error", sc->sc_unit);
121 if(!(rsta & ISACSX_RSTAD_CRC)) /* CRC error */
124 NDBGL1(L1_I_ERR, "unit %d: CRC error", sc->sc_unit);
127 if(rsta & ISACSX_RSTAD_RDO) /* ReceiveDataOverflow */
130 NDBGL1(L1_I_ERR, "unit %d: Data Overrun error", sc->sc_unit);
133 if(rsta & ISACSX_RSTAD_RAB) /* ReceiveABorted */
136 NDBGL1(L1_I_ERR, "unit %d: Receive Aborted error", sc->sc_unit);
140 NDBGL1(L1_I_ERR, "unit %d: RME unknown error, RSTAD = 0x%02x!", sc->sc_unit, rsta);
142 i4b_Dfreembuf(sc->sc_ibuf);
144 c |= ISACSX_CMDRD_RMC|ISACSX_CMDRD_RRES;
150 ISAC_WRITE(I_CMDRD, ISACSX_CMDRD_RMC|ISACSX_CMDRD_RRES);
155 rest = (ISAC_READ(I_RBCLD) & (ISACSX_FIFO_LEN-1));
158 rest = ISACSX_FIFO_LEN;
160 if(sc->sc_ibuf == NULL)
162 if((sc->sc_ibuf = i4b_Dgetmbuf(rest)) != NULL)
163 sc->sc_ib = sc->sc_ibuf->m_data;
165 panic("ifpi2_isacsx_irq: RME, i4b_Dgetmbuf returns NULL!\n");
169 if(sc->sc_ilen <= (MAX_DFRAME_LEN - rest))
171 ISAC_RDFIFO(sc->sc_ib, rest);
172 /* the last byte is status - strip it */
173 sc->sc_ilen += rest - 1;
175 sc->sc_ibuf->m_pkthdr.len =
176 sc->sc_ibuf->m_len = sc->sc_ilen;
178 if(sc->sc_trace & TRACE_D_RX)
181 hdr.unit = L0IFPI2UNIT(sc->sc_unit);
184 hdr.count = ++sc->sc_trace_dcount;
186 i4b_l1_trace_ind(&hdr, sc->sc_ibuf->m_len, sc->sc_ibuf->m_data);
189 c |= ISACSX_CMDRD_RMC;
192 (ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S))
194 i4b_l1_ph_data_ind(L0IFPI2UNIT(sc->sc_unit), sc->sc_ibuf);
198 i4b_Dfreembuf(sc->sc_ibuf);
203 NDBGL1(L1_I_ERR, "RME, input buffer overflow!");
204 i4b_Dfreembuf(sc->sc_ibuf);
205 c |= ISACSX_CMDRD_RMC|ISACSX_CMDRD_RRES;
213 if(istad & ISACSX_ISTAD_RPF) /* receive fifo full */
215 if(sc->sc_ibuf == NULL)
217 if((sc->sc_ibuf = i4b_Dgetmbuf(MAX_DFRAME_LEN)) != NULL)
218 sc->sc_ib= sc->sc_ibuf->m_data;
220 panic("ifpi2_isacsx_irq: RPF, i4b_Dgetmbuf returns NULL!\n");
224 if(sc->sc_ilen <= (MAX_DFRAME_LEN - ISACSX_FIFO_LEN))
226 ISAC_RDFIFO(sc->sc_ib, ISACSX_FIFO_LEN);
227 sc->sc_ilen += ISACSX_FIFO_LEN;
228 sc->sc_ib += ISACSX_FIFO_LEN;
229 c |= ISACSX_CMDRD_RMC;
233 NDBGL1(L1_I_ERR, "RPF, input buffer overflow!");
234 i4b_Dfreembuf(sc->sc_ibuf);
238 c |= ISACSX_CMDRD_RMC|ISACSX_CMDRD_RRES;
242 if(istad & ISACSX_ISTAD_XPR) /* transmit fifo empty (XPR bit set) */
244 if((sc->sc_obuf2 != NULL) && (sc->sc_obuf == NULL))
246 sc->sc_freeflag = sc->sc_freeflag2;
247 sc->sc_obuf = sc->sc_obuf2;
248 sc->sc_op = sc->sc_obuf->m_data;
249 sc->sc_ol = sc->sc_obuf->m_len;
252 printf("ob2=%x, op=%x, ol=%d, f=%d #",
262 printf("ob=%x, op=%x, ol=%d, f=%d #",
272 ISAC_WRFIFO(sc->sc_op, min(sc->sc_ol, ISACSX_FIFO_LEN));
274 if(sc->sc_ol > ISACSX_FIFO_LEN) /* length > 32 ? */
276 sc->sc_op += ISACSX_FIFO_LEN; /* bufferptr+32 */
277 sc->sc_ol -= ISACSX_FIFO_LEN; /* length - 32 */
278 c |= ISACSX_CMDRD_XTF; /* set XTF bit */
284 i4b_Dfreembuf(sc->sc_obuf);
291 c |= ISACSX_CMDRD_XTF | ISACSX_CMDRD_XME;
296 sc->sc_state &= ~ISAC_TX_ACTIVE;
300 if(ista & ISACSX_ISTA_CIC) /* channel status change CISQ */
304 /* get command/indication rx register*/
306 ci = ISAC_READ(I_CIR0);
308 /* C/I code change IRQ (flag already cleared by CIR0 read) */
310 if(ci & ISACSX_CIR0_CIC0)
311 ifpi2_isacsx_ind_hdlr(sc, (ci >> 4) & 0xf);
316 ISAC_WRITE(I_CMDRD, c);
320 /*---------------------------------------------------------------------------*
321 * ISACSX L1 Extended IRQ handler
322 *---------------------------------------------------------------------------*/
324 ifpi2_isacsx_exir_hdlr(register struct l1_softc *sc, u_char exir)
328 if(exir & ISACSX_ISTAD_XMR)
330 NDBGL1(L1_I_ERR, "EXIRQ Tx Message Repeat");
332 c |= ISACSX_CMDRD_XRES;
335 if(exir & ISACSX_ISTAD_XDU)
337 NDBGL1(L1_I_ERR, "EXIRQ Tx Data Underrun");
339 c |= ISACSX_CMDRD_XRES;
342 if(exir & ISACSX_ISTAD_RFO)
344 NDBGL1(L1_I_ERR, "EXIRQ Rx Frame Overflow");
346 c |= ISACSX_CMDRD_RMC;
349 #if 0 /* all blocked per default */
350 if(exir & ISACSX_EXIR_SOV)
352 NDBGL1(L1_I_ERR, "EXIRQ Sync Xfer Overflow");
355 if(exir & ISACSX_EXIR_MOS)
357 NDBGL1(L1_I_ERR, "EXIRQ Monitor Status");
360 if(exir & ISACSX_EXIR_SAW)
362 /* cannot happen, STCR:TSF is set to 0 */
364 NDBGL1(L1_I_ERR, "EXIRQ Subscriber Awake");
367 if(exir & ISACSX_EXIR_WOV)
369 /* cannot happen, STCR:TSF is set to 0 */
371 NDBGL1(L1_I_ERR, "EXIRQ Watchdog Timer Overflow");
378 /*---------------------------------------------------------------------------*
379 * ISACSX L1 Indication handler
380 *---------------------------------------------------------------------------*/
382 ifpi2_isacsx_ind_hdlr(register struct l1_softc *sc, int ind)
388 case ISACSX_CIR0_IAI8:
389 NDBGL1(L1_I_CICO, "rx AI8 in state %s", ifpi2_printstate(sc));
390 if(sc->sc_bustyp == BUS_TYPE_IOM2)
391 ifpi2_isacsx_l1_cmd(sc, CMD_AR8);
393 i4b_l1_mph_status_ind(L0IFPI2UNIT(sc->sc_unit), STI_L1STAT, LAYER_ACTIVE, NULL);
396 case ISACSX_CIR0_IAI10:
397 NDBGL1(L1_I_CICO, "rx AI10 in state %s", ifpi2_printstate(sc));
398 if(sc->sc_bustyp == BUS_TYPE_IOM2)
399 ifpi2_isacsx_l1_cmd(sc, CMD_AR10);
401 i4b_l1_mph_status_ind(L0IFPI2UNIT(sc->sc_unit), STI_L1STAT, LAYER_ACTIVE, NULL);
404 case ISACSX_CIR0_IRSY:
405 NDBGL1(L1_I_CICO, "rx RSY in state %s", ifpi2_printstate(sc));
409 case ISACSX_CIR0_IPU:
410 NDBGL1(L1_I_CICO, "rx PU in state %s", ifpi2_printstate(sc));
414 case ISACSX_CIR0_IDR:
415 NDBGL1(L1_I_CICO, "rx DR in state %s", ifpi2_printstate(sc));
416 ifpi2_isacsx_l1_cmd(sc, CMD_DIU);
420 case ISACSX_CIR0_IDID:
421 NDBGL1(L1_I_CICO, "rx DID in state %s", ifpi2_printstate(sc));
423 i4b_l1_mph_status_ind(L0IFPI2UNIT(sc->sc_unit), STI_L1STAT, LAYER_IDLE, NULL);
426 case ISACSX_CIR0_IDIS:
427 NDBGL1(L1_I_CICO, "rx DIS in state %s", ifpi2_printstate(sc));
431 case ISACSX_CIR0_IEI:
432 NDBGL1(L1_I_CICO, "rx EI in state %s", ifpi2_printstate(sc));
433 ifpi2_isacsx_l1_cmd(sc, CMD_DIU);
437 case ISACSX_CIR0_IARD:
438 NDBGL1(L1_I_CICO, "rx ARD in state %s", ifpi2_printstate(sc));
442 case ISACSX_CIR0_ITI:
443 NDBGL1(L1_I_CICO, "rx TI in state %s", ifpi2_printstate(sc));
447 case ISACSX_CIR0_IATI:
448 NDBGL1(L1_I_CICO, "rx ATI in state %s", ifpi2_printstate(sc));
452 case ISACSX_CIR0_ISD:
453 NDBGL1(L1_I_CICO, "rx SD in state %s", ifpi2_printstate(sc));
458 NDBGL1(L1_I_ERR, "UNKNOWN Indication 0x%x in state %s", ind, ifpi2_printstate(sc));
462 ifpi2_next_state(sc, event);
465 /*---------------------------------------------------------------------------*
466 * execute a layer 1 command
467 *---------------------------------------------------------------------------*/
469 ifpi2_isacsx_l1_cmd(struct l1_softc *sc, int command)
473 #ifdef I4B_SMP_WORKAROUND
475 /* XXXXXXXXXXXXXXXXXXX */
478 * patch from Wolfgang Helbig:
480 * Here is a patch that makes i4b work on an SMP:
481 * The card (TELES 16.3) didn't interrupt on an SMP machine.
482 * This is a gross workaround, but anyway it works *and* provides
483 * some information as how to finally fix this problem.
486 HSCX_WRITE(0, H_MASK, 0xff);
487 HSCX_WRITE(1, H_MASK, 0xff);
488 ISAC_WRITE(I_MASKD, 0xff);
489 ISAC_WRITE(I_MASK, 0xff);
491 HSCX_WRITE(0, H_MASK, HSCX_A_IMASK);
492 HSCX_WRITE(1, H_MASK, HSCX_B_IMASK);
493 ISAC_WRITE(I_MASKD, isacsx_imaskd);
494 ISAC_WRITE(I_MASK, isacsx_imask);
496 /* XXXXXXXXXXXXXXXXXXX */
498 #endif /* I4B_SMP_WORKAROUND */
500 if(command < 0 || command > CMD_ILL)
502 NDBGL1(L1_I_ERR, "illegal cmd 0x%x in state %s", command, ifpi2_printstate(sc));
506 cmd = ISACSX_CIX0_LOW;
511 NDBGL1(L1_I_CICO, "tx TIM in state %s", ifpi2_printstate(sc));
512 cmd |= (ISACSX_CIX0_CTIM << 4);
516 NDBGL1(L1_I_CICO, "tx RS in state %s", ifpi2_printstate(sc));
517 cmd |= (ISACSX_CIX0_CRS << 4);
521 NDBGL1(L1_I_CICO, "tx AR8 in state %s", ifpi2_printstate(sc));
522 cmd |= (ISACSX_CIX0_CAR8 << 4);
526 NDBGL1(L1_I_CICO, "tx AR10 in state %s", ifpi2_printstate(sc));
527 cmd |= (ISACSX_CIX0_CAR10 << 4);
531 NDBGL1(L1_I_CICO, "tx DIU in state %s", ifpi2_printstate(sc));
532 cmd |= (ISACSX_CIX0_CDIU << 4);
535 ISAC_WRITE(I_CIX0, cmd);
538 /*---------------------------------------------------------------------------*
539 * L1 ISACSX initialization
540 *---------------------------------------------------------------------------*/
542 ifpi2_isacsx_init(struct l1_softc *sc)
544 isacsx_imaskd = 0xff; /* disable all irqs */
545 isacsx_imask = 0xff; /* disable all irqs */
547 ISAC_WRITE(I_MASKD, isacsx_imaskd);
548 ISAC_WRITE(I_MASK, isacsx_imask);
550 /* the ISACSX only runs in IOM-2 mode */
551 NDBGL1(L1_I_SETUP, "configuring for IOM-2 mode");
553 /* TR_CONF0: Transceiver Configuration Register 0:
554 * DIS_TR - transceiver enabled
555 * EN_ICV - normal operation
556 * EXLP - no external loop
557 * LDD - automatic clock generation
559 ISAC_WRITE(I_WTR_CONF0, 0);
561 /* TR_CONF2: Transceiver Configuration Register 1:
562 * DIS_TX - transmitter enabled
563 * PDS - phase deviation 2 S-bits
564 * RLP - remote line loop open
566 ISAC_WRITE(I_WTR_CONF2, 0);
568 /* MODED: Mode Register:
569 * MDSx - transparent mode 0
570 * TMD - timer mode = external
571 * RAC - Receiver enabled
572 * DIMx - digital i/f mode
574 ISAC_WRITE(I_WMODED, ISACSX_MODED_MDS2|ISACSX_MODED_MDS1|ISACSX_MODED_RAC|ISACSX_MODED_DIM0);
576 /* enabled interrupts:
577 * ===================
578 * RME - receive message end
579 * RPF - receive pool full
580 * RPO - receive pool overflow
581 * XPR - transmit pool ready
582 * XMR - transmit message repeat
583 * XDU - transmit data underrun
586 isacsx_imaskd = ISACSX_MASKD_LOW;
587 ISAC_WRITE(I_MASKD, isacsx_imaskd);
589 /* enabled interrupts:
590 * ===================
591 * ICD - HDLC interrupt from D-channel
592 * CIC - C/I channel change
595 isacsx_imask = ~(ISACSX_MASK_ICD | ISACSX_MASK_CIC);
597 ISAC_WRITE(I_MASK, isacsx_imask);
602 #endif /* NIFPI2 > 0 */