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
27 /*---------------------------------------------------------------------------
29 * i4b_ifpi2_isac.c - i4b Fritz PCI Version 2 ISACSX handler
30 * --------------------------------------------
33 *---------------------------------------------------------------------------*/
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
40 #include <sys/param.h>
41 #include <sys/systm.h>
43 #include <sys/socket.h>
48 #include <i4b/include/i4b_debug.h>
49 #include <i4b/include/i4b_ioctl.h>
50 #include <i4b/include/i4b_trace.h>
52 #include <i4b/layer1/i4b_l1.h>
54 #include <i4b/layer1/isic/i4b_isic.h>
55 #include <i4b/layer1/isic/i4b_hscx.h>
57 #include <i4b/layer1/ifpi2/i4b_ifpi2_ext.h>
58 #include <i4b/layer1/ifpi2/i4b_ifpi2_isacsx.h>
60 #include <i4b/include/i4b_global.h>
61 #include <i4b/include/i4b_mbuf.h>
63 static u_char ifpi2_isacsx_exir_hdlr(register struct l1_softc *sc, u_char exir);
64 static void ifpi2_isacsx_ind_hdlr(register struct l1_softc *sc, int ind);
66 /* the ISACSX has 2 mask registers of interest - cannot use ISAC_IMASK */
67 unsigned char isacsx_imaskd;
68 unsigned char isacsx_imask;
70 /*---------------------------------------------------------------------------*
71 * ISACSX interrupt service routine
72 *---------------------------------------------------------------------------*/
74 ifpi2_isacsx_irq(struct l1_softc *sc, int ista)
76 register u_char c = 0;
77 register u_char istad = 0;
79 NDBGL1(L1_F_MSG, "unit %d: ista = 0x%02x", sc->sc_unit, ista);
81 /* was it an HDLC interrupt ? */
82 if (ista & ISACSX_ISTA_ICD)
84 istad = ISAC_READ(I_ISTAD);
85 NDBGL1(L1_F_MSG, "unit %d: istad = 0x%02x", sc->sc_unit, istad);
87 if(istad & (ISACSX_ISTAD_RFO|ISACSX_ISTAD_XMR|ISACSX_ISTAD_XDU))
89 /* not really EXIR, but very similar */
90 c |= ifpi2_isacsx_exir_hdlr(sc, istad);
94 if(istad & ISACSX_ISTAD_RME) /* receive message end */
99 /* get rx status register */
101 rsta = ISAC_READ(I_RSTAD);
103 /* Check for Frame and CRC valid */
104 if((rsta & ISACSX_RSTAD_MASK) != (ISACSX_RSTAD_VFR|ISACSX_RSTAD_CRC))
108 if(!(rsta & ISACSX_RSTAD_VFR)) /* VFR error */
111 NDBGL1(L1_I_ERR, "unit %d: Frame not valid error", sc->sc_unit);
114 if(!(rsta & ISACSX_RSTAD_CRC)) /* CRC error */
117 NDBGL1(L1_I_ERR, "unit %d: CRC error", sc->sc_unit);
120 if(rsta & ISACSX_RSTAD_RDO) /* ReceiveDataOverflow */
123 NDBGL1(L1_I_ERR, "unit %d: Data Overrun error", sc->sc_unit);
126 if(rsta & ISACSX_RSTAD_RAB) /* ReceiveABorted */
129 NDBGL1(L1_I_ERR, "unit %d: Receive Aborted error", sc->sc_unit);
133 NDBGL1(L1_I_ERR, "unit %d: RME unknown error, RSTAD = 0x%02x!", sc->sc_unit, rsta);
135 i4b_Dfreembuf(sc->sc_ibuf);
137 c |= ISACSX_CMDRD_RMC|ISACSX_CMDRD_RRES;
143 ISAC_WRITE(I_CMDRD, ISACSX_CMDRD_RMC|ISACSX_CMDRD_RRES);
148 rest = (ISAC_READ(I_RBCLD) & (ISACSX_FIFO_LEN-1));
151 rest = ISACSX_FIFO_LEN;
153 if(sc->sc_ibuf == NULL)
155 if((sc->sc_ibuf = i4b_Dgetmbuf(rest)) != NULL)
156 sc->sc_ib = sc->sc_ibuf->m_data;
158 panic("ifpi2_isacsx_irq: RME, i4b_Dgetmbuf returns NULL!\n");
162 if(sc->sc_ilen <= (MAX_DFRAME_LEN - rest))
164 ISAC_RDFIFO(sc->sc_ib, rest);
165 /* the last byte contains status, strip it */
166 sc->sc_ilen += rest - 1;
168 sc->sc_ibuf->m_pkthdr.len =
169 sc->sc_ibuf->m_len = sc->sc_ilen;
171 if(sc->sc_trace & TRACE_D_RX)
174 hdr.unit = L0IFPI2UNIT(sc->sc_unit);
177 hdr.count = ++sc->sc_trace_dcount;
179 i4b_l1_trace_ind(&hdr, sc->sc_ibuf->m_len, sc->sc_ibuf->m_data);
182 c |= ISACSX_CMDRD_RMC;
185 (ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S))
187 i4b_l1_ph_data_ind(L0IFPI2UNIT(sc->sc_unit), sc->sc_ibuf);
191 i4b_Dfreembuf(sc->sc_ibuf);
196 NDBGL1(L1_I_ERR, "RME, input buffer overflow!");
197 i4b_Dfreembuf(sc->sc_ibuf);
198 c |= ISACSX_CMDRD_RMC|ISACSX_CMDRD_RRES;
206 if(istad & ISACSX_ISTAD_RPF) /* receive fifo full */
208 if(sc->sc_ibuf == NULL)
210 if((sc->sc_ibuf = i4b_Dgetmbuf(MAX_DFRAME_LEN)) != NULL)
211 sc->sc_ib= sc->sc_ibuf->m_data;
213 panic("ifpi2_isacsx_irq: RPF, i4b_Dgetmbuf returns NULL!\n");
217 if(sc->sc_ilen <= (MAX_DFRAME_LEN - ISACSX_FIFO_LEN))
219 ISAC_RDFIFO(sc->sc_ib, ISACSX_FIFO_LEN);
220 sc->sc_ilen += ISACSX_FIFO_LEN;
221 sc->sc_ib += ISACSX_FIFO_LEN;
222 c |= ISACSX_CMDRD_RMC;
226 NDBGL1(L1_I_ERR, "RPF, input buffer overflow!");
227 i4b_Dfreembuf(sc->sc_ibuf);
231 c |= ISACSX_CMDRD_RMC|ISACSX_CMDRD_RRES;
235 if(istad & ISACSX_ISTAD_XPR) /* transmit fifo empty (XPR bit set) */
237 if((sc->sc_obuf2 != NULL) && (sc->sc_obuf == NULL))
239 sc->sc_freeflag = sc->sc_freeflag2;
240 sc->sc_obuf = sc->sc_obuf2;
241 sc->sc_op = sc->sc_obuf->m_data;
242 sc->sc_ol = sc->sc_obuf->m_len;
245 printf("ob2=%x, op=%x, ol=%d, f=%d #",
255 printf("ob=%x, op=%x, ol=%d, f=%d #",
265 ISAC_WRFIFO(sc->sc_op, min(sc->sc_ol, ISACSX_FIFO_LEN));
267 if(sc->sc_ol > ISACSX_FIFO_LEN) /* length > 32 ? */
269 sc->sc_op += ISACSX_FIFO_LEN; /* bufferptr+32 */
270 sc->sc_ol -= ISACSX_FIFO_LEN; /* length - 32 */
271 c |= ISACSX_CMDRD_XTF; /* set XTF bit */
277 i4b_Dfreembuf(sc->sc_obuf);
284 c |= ISACSX_CMDRD_XTF | ISACSX_CMDRD_XME;
289 sc->sc_state &= ~ISAC_TX_ACTIVE;
293 if(ista & ISACSX_ISTA_CIC) /* channel status change CISQ */
297 /* get command/indication rx register*/
299 ci = ISAC_READ(I_CIR0);
301 /* C/I code change IRQ (flag already cleared by CIR0 read) */
303 if(ci & ISACSX_CIR0_CIC0)
304 ifpi2_isacsx_ind_hdlr(sc, (ci >> 4) & 0xf);
309 ISAC_WRITE(I_CMDRD, c);
313 /*---------------------------------------------------------------------------*
314 * ISACSX L1 Extended IRQ handler
315 *---------------------------------------------------------------------------*/
317 ifpi2_isacsx_exir_hdlr(register struct l1_softc *sc, u_char exir)
321 if(exir & ISACSX_ISTAD_XMR)
323 NDBGL1(L1_I_ERR, "EXIRQ Tx Message Repeat");
325 c |= ISACSX_CMDRD_XRES;
328 if(exir & ISACSX_ISTAD_XDU)
330 NDBGL1(L1_I_ERR, "EXIRQ Tx Data Underrun");
332 c |= ISACSX_CMDRD_XRES;
335 if(exir & ISACSX_ISTAD_RFO)
337 NDBGL1(L1_I_ERR, "EXIRQ Rx Frame Overflow");
339 c |= ISACSX_CMDRD_RMC;
342 #if 0 /* all blocked per default */
343 if(exir & ISACSX_EXIR_SOV)
345 NDBGL1(L1_I_ERR, "EXIRQ Sync Xfer Overflow");
348 if(exir & ISACSX_EXIR_MOS)
350 NDBGL1(L1_I_ERR, "EXIRQ Monitor Status");
353 if(exir & ISACSX_EXIR_SAW)
355 /* cannot happen, STCR:TSF is set to 0 */
357 NDBGL1(L1_I_ERR, "EXIRQ Subscriber Awake");
360 if(exir & ISACSX_EXIR_WOV)
362 /* cannot happen, STCR:TSF is set to 0 */
364 NDBGL1(L1_I_ERR, "EXIRQ Watchdog Timer Overflow");
371 /*---------------------------------------------------------------------------*
372 * ISACSX L1 Indication handler
373 *---------------------------------------------------------------------------*/
375 ifpi2_isacsx_ind_hdlr(register struct l1_softc *sc, int ind)
381 case ISACSX_CIR0_IAI8:
382 NDBGL1(L1_I_CICO, "rx AI8 in state %s", ifpi2_printstate(sc));
383 if(sc->sc_bustyp == BUS_TYPE_IOM2)
384 ifpi2_isacsx_l1_cmd(sc, CMD_AR8);
386 i4b_l1_mph_status_ind(L0IFPI2UNIT(sc->sc_unit), STI_L1STAT, LAYER_ACTIVE, NULL);
389 case ISACSX_CIR0_IAI10:
390 NDBGL1(L1_I_CICO, "rx AI10 in state %s", ifpi2_printstate(sc));
391 if(sc->sc_bustyp == BUS_TYPE_IOM2)
392 ifpi2_isacsx_l1_cmd(sc, CMD_AR10);
394 i4b_l1_mph_status_ind(L0IFPI2UNIT(sc->sc_unit), STI_L1STAT, LAYER_ACTIVE, NULL);
397 case ISACSX_CIR0_IRSY:
398 NDBGL1(L1_I_CICO, "rx RSY in state %s", ifpi2_printstate(sc));
402 case ISACSX_CIR0_IPU:
403 NDBGL1(L1_I_CICO, "rx PU in state %s", ifpi2_printstate(sc));
407 case ISACSX_CIR0_IDR:
408 NDBGL1(L1_I_CICO, "rx DR in state %s", ifpi2_printstate(sc));
409 ifpi2_isacsx_l1_cmd(sc, CMD_DIU);
413 case ISACSX_CIR0_IDID:
414 NDBGL1(L1_I_CICO, "rx DID in state %s", ifpi2_printstate(sc));
416 i4b_l1_mph_status_ind(L0IFPI2UNIT(sc->sc_unit), STI_L1STAT, LAYER_IDLE, NULL);
419 case ISACSX_CIR0_IDIS:
420 NDBGL1(L1_I_CICO, "rx DIS in state %s", ifpi2_printstate(sc));
424 case ISACSX_CIR0_IEI:
425 NDBGL1(L1_I_CICO, "rx EI in state %s", ifpi2_printstate(sc));
426 ifpi2_isacsx_l1_cmd(sc, CMD_DIU);
430 case ISACSX_CIR0_IARD:
431 NDBGL1(L1_I_CICO, "rx ARD in state %s", ifpi2_printstate(sc));
435 case ISACSX_CIR0_ITI:
436 NDBGL1(L1_I_CICO, "rx TI in state %s", ifpi2_printstate(sc));
440 case ISACSX_CIR0_IATI:
441 NDBGL1(L1_I_CICO, "rx ATI in state %s", ifpi2_printstate(sc));
445 case ISACSX_CIR0_ISD:
446 NDBGL1(L1_I_CICO, "rx SD in state %s", ifpi2_printstate(sc));
451 NDBGL1(L1_I_ERR, "UNKNOWN Indication 0x%x in state %s", ind, ifpi2_printstate(sc));
455 ifpi2_next_state(sc, event);
458 /*---------------------------------------------------------------------------*
459 * execute a layer 1 command
460 *---------------------------------------------------------------------------*/
462 ifpi2_isacsx_l1_cmd(struct l1_softc *sc, int command)
466 #ifdef I4B_SMP_WORKAROUND
468 /* XXXXXXXXXXXXXXXXXXX */
471 * patch from Wolfgang Helbig:
473 * Here is a patch that makes i4b work on an SMP:
474 * The card (TELES 16.3) didn't interrupt on an SMP machine.
475 * This is a gross workaround, but anyway it works *and* provides
476 * some information as how to finally fix this problem.
479 HSCX_WRITE(0, H_MASK, 0xff);
480 HSCX_WRITE(1, H_MASK, 0xff);
481 ISAC_WRITE(I_MASKD, 0xff);
482 ISAC_WRITE(I_MASK, 0xff);
484 HSCX_WRITE(0, H_MASK, HSCX_A_IMASK);
485 HSCX_WRITE(1, H_MASK, HSCX_B_IMASK);
486 ISAC_WRITE(I_MASKD, isacsx_imaskd);
487 ISAC_WRITE(I_MASK, isacsx_imask);
489 /* XXXXXXXXXXXXXXXXXXX */
491 #endif /* I4B_SMP_WORKAROUND */
493 if(command < 0 || command > CMD_ILL)
495 NDBGL1(L1_I_ERR, "illegal cmd 0x%x in state %s", command, ifpi2_printstate(sc));
499 cmd = ISACSX_CIX0_LOW;
504 NDBGL1(L1_I_CICO, "tx TIM in state %s", ifpi2_printstate(sc));
505 cmd |= (ISACSX_CIX0_CTIM << 4);
509 NDBGL1(L1_I_CICO, "tx RS in state %s", ifpi2_printstate(sc));
510 cmd |= (ISACSX_CIX0_CRS << 4);
514 NDBGL1(L1_I_CICO, "tx AR8 in state %s", ifpi2_printstate(sc));
515 cmd |= (ISACSX_CIX0_CAR8 << 4);
519 NDBGL1(L1_I_CICO, "tx AR10 in state %s", ifpi2_printstate(sc));
520 cmd |= (ISACSX_CIX0_CAR10 << 4);
524 NDBGL1(L1_I_CICO, "tx DIU in state %s", ifpi2_printstate(sc));
525 cmd |= (ISACSX_CIX0_CDIU << 4);
528 ISAC_WRITE(I_CIX0, cmd);
531 /*---------------------------------------------------------------------------*
532 * L1 ISACSX initialization
533 *---------------------------------------------------------------------------*/
535 ifpi2_isacsx_init(struct l1_softc *sc)
537 isacsx_imaskd = 0xff; /* disable all irqs */
538 isacsx_imask = 0xff; /* disable all irqs */
540 ISAC_WRITE(I_MASKD, isacsx_imaskd);
541 ISAC_WRITE(I_MASK, isacsx_imask);
543 /* the ISACSX only runs in IOM-2 mode */
544 NDBGL1(L1_I_SETUP, "configuring for IOM-2 mode");
546 /* TR_CONF0: Transceiver Configuration Register 0:
547 * DIS_TR - transceiver enabled
548 * EN_ICV - normal operation
549 * EXLP - no external loop
550 * LDD - automatic clock generation
552 ISAC_WRITE(I_WTR_CONF0, 0);
554 /* TR_CONF2: Transceiver Configuration Register 1:
555 * DIS_TX - transmitter enabled
556 * PDS - phase deviation 2 S-bits
557 * RLP - remote line loop open
559 ISAC_WRITE(I_WTR_CONF2, 0);
561 /* MODED: Mode Register:
562 * MDSx - transparent mode 0
563 * TMD - timer mode = external
564 * RAC - Receiver enabled
565 * DIMx - digital i/f mode
567 ISAC_WRITE(I_WMODED, ISACSX_MODED_MDS2|ISACSX_MODED_MDS1|ISACSX_MODED_RAC|ISACSX_MODED_DIM0);
569 /* enabled interrupts:
570 * ===================
571 * RME - receive message end
572 * RPF - receive pool full
573 * RPO - receive pool overflow
574 * XPR - transmit pool ready
575 * XMR - transmit message repeat
576 * XDU - transmit data underrun
579 isacsx_imaskd = ISACSX_MASKD_LOW;
580 ISAC_WRITE(I_MASKD, isacsx_imaskd);
582 /* enabled interrupts:
583 * ===================
584 * ICD - HDLC interrupt from D-channel
585 * CIC - C/I channel change
588 isacsx_imask = ~(ISACSX_MASK_ICD | ISACSX_MASK_CIC);
590 ISAC_WRITE(I_MASK, isacsx_imask);