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.6 2006/12/22 23:44:56 swildner Exp $
36 * last edit-date: [Mon May 29 15:22:52 2000]
38 *---------------------------------------------------------------------------*/
40 #include "use_ifpi2.h"
43 #if (NIFPI2 > 0) && (NPCI > 0)
47 #include <sys/param.h>
48 #include <sys/systm.h>
50 #include <sys/socket.h>
55 #include <net/i4b/include/machine/i4b_debug.h>
56 #include <net/i4b/include/machine/i4b_ioctl.h>
57 #include <net/i4b/include/machine/i4b_trace.h>
59 #include "../i4b_l1.h"
60 #include "../isic/i4b_isic.h"
61 #include "../isic/i4b_hscx.h"
63 #include "i4b_ifpi2_ext.h"
64 #include "i4b_ifpi2_isacsx.h"
66 #include "../../include/i4b_global.h"
67 #include "../../include/i4b_mbuf.h"
69 static u_char ifpi2_isacsx_exir_hdlr(struct l1_softc *sc, u_char exir);
70 static void ifpi2_isacsx_ind_hdlr(struct l1_softc *sc, int ind);
72 /* the ISACSX has 2 mask registers of interest - cannot use ISAC_IMASK */
73 unsigned char isacsx_imaskd;
74 unsigned char isacsx_imask;
76 /*---------------------------------------------------------------------------*
77 * ISACSX interrupt service routine
78 *---------------------------------------------------------------------------*/
80 ifpi2_isacsx_irq(struct l1_softc *sc, int ista)
85 NDBGL1(L1_F_MSG, "unit %d: ista = 0x%02x", sc->sc_unit, ista);
87 /* was it an HDLC interrupt ? */
88 if (ista & ISACSX_ISTA_ICD)
90 istad = ISAC_READ(I_ISTAD);
91 NDBGL1(L1_F_MSG, "unit %d: istad = 0x%02x", sc->sc_unit, istad);
93 if(istad & (ISACSX_ISTAD_RFO|ISACSX_ISTAD_XMR|ISACSX_ISTAD_XDU))
95 /* not really EXIR, but very similar */
96 c |= ifpi2_isacsx_exir_hdlr(sc, istad);
100 if(istad & ISACSX_ISTAD_RME) /* receive message end */
105 /* get rx status register */
107 rsta = ISAC_READ(I_RSTAD);
109 /* Check for Frame and CRC valid */
110 if((rsta & ISACSX_RSTAD_MASK) != (ISACSX_RSTAD_VFR|ISACSX_RSTAD_CRC))
114 if(!(rsta & ISACSX_RSTAD_VFR)) /* VFR error */
117 NDBGL1(L1_I_ERR, "unit %d: Frame not valid error", sc->sc_unit);
120 if(!(rsta & ISACSX_RSTAD_CRC)) /* CRC error */
123 NDBGL1(L1_I_ERR, "unit %d: CRC error", sc->sc_unit);
126 if(rsta & ISACSX_RSTAD_RDO) /* ReceiveDataOverflow */
129 NDBGL1(L1_I_ERR, "unit %d: Data Overrun error", sc->sc_unit);
132 if(rsta & ISACSX_RSTAD_RAB) /* ReceiveABorted */
135 NDBGL1(L1_I_ERR, "unit %d: Receive Aborted error", sc->sc_unit);
139 NDBGL1(L1_I_ERR, "unit %d: RME unknown error, RSTAD = 0x%02x!", sc->sc_unit, rsta);
141 i4b_Dfreembuf(sc->sc_ibuf);
143 c |= ISACSX_CMDRD_RMC|ISACSX_CMDRD_RRES;
149 ISAC_WRITE(I_CMDRD, ISACSX_CMDRD_RMC|ISACSX_CMDRD_RRES);
154 rest = (ISAC_READ(I_RBCLD) & (ISACSX_FIFO_LEN-1));
157 rest = ISACSX_FIFO_LEN;
159 if(sc->sc_ibuf == NULL)
161 if((sc->sc_ibuf = i4b_Dgetmbuf(rest)) != NULL)
162 sc->sc_ib = sc->sc_ibuf->m_data;
164 panic("ifpi2_isacsx_irq: RME, i4b_Dgetmbuf returns NULL!\n");
168 if(sc->sc_ilen <= (MAX_DFRAME_LEN - rest))
170 ISAC_RDFIFO(sc->sc_ib, rest);
171 /* the last byte is status - strip it */
172 sc->sc_ilen += rest - 1;
174 sc->sc_ibuf->m_pkthdr.len =
175 sc->sc_ibuf->m_len = sc->sc_ilen;
177 if(sc->sc_trace & TRACE_D_RX)
180 hdr.unit = L0IFPI2UNIT(sc->sc_unit);
183 hdr.count = ++sc->sc_trace_dcount;
185 i4b_l1_trace_ind(&hdr, sc->sc_ibuf->m_len, sc->sc_ibuf->m_data);
188 c |= ISACSX_CMDRD_RMC;
191 (ctrl_desc[sc->sc_unit].protocol != PROTOCOL_D64S))
193 i4b_l1_ph_data_ind(L0IFPI2UNIT(sc->sc_unit), sc->sc_ibuf);
197 i4b_Dfreembuf(sc->sc_ibuf);
202 NDBGL1(L1_I_ERR, "RME, input buffer overflow!");
203 i4b_Dfreembuf(sc->sc_ibuf);
204 c |= ISACSX_CMDRD_RMC|ISACSX_CMDRD_RRES;
212 if(istad & ISACSX_ISTAD_RPF) /* receive fifo full */
214 if(sc->sc_ibuf == NULL)
216 if((sc->sc_ibuf = i4b_Dgetmbuf(MAX_DFRAME_LEN)) != NULL)
217 sc->sc_ib= sc->sc_ibuf->m_data;
219 panic("ifpi2_isacsx_irq: RPF, i4b_Dgetmbuf returns NULL!\n");
223 if(sc->sc_ilen <= (MAX_DFRAME_LEN - ISACSX_FIFO_LEN))
225 ISAC_RDFIFO(sc->sc_ib, ISACSX_FIFO_LEN);
226 sc->sc_ilen += ISACSX_FIFO_LEN;
227 sc->sc_ib += ISACSX_FIFO_LEN;
228 c |= ISACSX_CMDRD_RMC;
232 NDBGL1(L1_I_ERR, "RPF, input buffer overflow!");
233 i4b_Dfreembuf(sc->sc_ibuf);
237 c |= ISACSX_CMDRD_RMC|ISACSX_CMDRD_RRES;
241 if(istad & ISACSX_ISTAD_XPR) /* transmit fifo empty (XPR bit set) */
243 if((sc->sc_obuf2 != NULL) && (sc->sc_obuf == NULL))
245 sc->sc_freeflag = sc->sc_freeflag2;
246 sc->sc_obuf = sc->sc_obuf2;
247 sc->sc_op = sc->sc_obuf->m_data;
248 sc->sc_ol = sc->sc_obuf->m_len;
251 kprintf("ob2=%x, op=%x, ol=%d, f=%d #",
261 kprintf("ob=%x, op=%x, ol=%d, f=%d #",
271 ISAC_WRFIFO(sc->sc_op, min(sc->sc_ol, ISACSX_FIFO_LEN));
273 if(sc->sc_ol > ISACSX_FIFO_LEN) /* length > 32 ? */
275 sc->sc_op += ISACSX_FIFO_LEN; /* bufferptr+32 */
276 sc->sc_ol -= ISACSX_FIFO_LEN; /* length - 32 */
277 c |= ISACSX_CMDRD_XTF; /* set XTF bit */
283 i4b_Dfreembuf(sc->sc_obuf);
290 c |= ISACSX_CMDRD_XTF | ISACSX_CMDRD_XME;
295 sc->sc_state &= ~ISAC_TX_ACTIVE;
299 if(ista & ISACSX_ISTA_CIC) /* channel status change CISQ */
303 /* get command/indication rx register*/
305 ci = ISAC_READ(I_CIR0);
307 /* C/I code change IRQ (flag already cleared by CIR0 read) */
309 if(ci & ISACSX_CIR0_CIC0)
310 ifpi2_isacsx_ind_hdlr(sc, (ci >> 4) & 0xf);
315 ISAC_WRITE(I_CMDRD, c);
319 /*---------------------------------------------------------------------------*
320 * ISACSX L1 Extended IRQ handler
321 *---------------------------------------------------------------------------*/
323 ifpi2_isacsx_exir_hdlr(struct l1_softc *sc, u_char exir)
327 if(exir & ISACSX_ISTAD_XMR)
329 NDBGL1(L1_I_ERR, "EXIRQ Tx Message Repeat");
331 c |= ISACSX_CMDRD_XRES;
334 if(exir & ISACSX_ISTAD_XDU)
336 NDBGL1(L1_I_ERR, "EXIRQ Tx Data Underrun");
338 c |= ISACSX_CMDRD_XRES;
341 if(exir & ISACSX_ISTAD_RFO)
343 NDBGL1(L1_I_ERR, "EXIRQ Rx Frame Overflow");
345 c |= ISACSX_CMDRD_RMC;
348 #if 0 /* all blocked per default */
349 if(exir & ISACSX_EXIR_SOV)
351 NDBGL1(L1_I_ERR, "EXIRQ Sync Xfer Overflow");
354 if(exir & ISACSX_EXIR_MOS)
356 NDBGL1(L1_I_ERR, "EXIRQ Monitor Status");
359 if(exir & ISACSX_EXIR_SAW)
361 /* cannot happen, STCR:TSF is set to 0 */
363 NDBGL1(L1_I_ERR, "EXIRQ Subscriber Awake");
366 if(exir & ISACSX_EXIR_WOV)
368 /* cannot happen, STCR:TSF is set to 0 */
370 NDBGL1(L1_I_ERR, "EXIRQ Watchdog Timer Overflow");
377 /*---------------------------------------------------------------------------*
378 * ISACSX L1 Indication handler
379 *---------------------------------------------------------------------------*/
381 ifpi2_isacsx_ind_hdlr(struct l1_softc *sc, int ind)
387 case ISACSX_CIR0_IAI8:
388 NDBGL1(L1_I_CICO, "rx AI8 in state %s", ifpi2_printstate(sc));
389 if(sc->sc_bustyp == BUS_TYPE_IOM2)
390 ifpi2_isacsx_l1_cmd(sc, CMD_AR8);
392 i4b_l1_mph_status_ind(L0IFPI2UNIT(sc->sc_unit), STI_L1STAT, LAYER_ACTIVE, NULL);
395 case ISACSX_CIR0_IAI10:
396 NDBGL1(L1_I_CICO, "rx AI10 in state %s", ifpi2_printstate(sc));
397 if(sc->sc_bustyp == BUS_TYPE_IOM2)
398 ifpi2_isacsx_l1_cmd(sc, CMD_AR10);
400 i4b_l1_mph_status_ind(L0IFPI2UNIT(sc->sc_unit), STI_L1STAT, LAYER_ACTIVE, NULL);
403 case ISACSX_CIR0_IRSY:
404 NDBGL1(L1_I_CICO, "rx RSY in state %s", ifpi2_printstate(sc));
408 case ISACSX_CIR0_IPU:
409 NDBGL1(L1_I_CICO, "rx PU in state %s", ifpi2_printstate(sc));
413 case ISACSX_CIR0_IDR:
414 NDBGL1(L1_I_CICO, "rx DR in state %s", ifpi2_printstate(sc));
415 ifpi2_isacsx_l1_cmd(sc, CMD_DIU);
419 case ISACSX_CIR0_IDID:
420 NDBGL1(L1_I_CICO, "rx DID in state %s", ifpi2_printstate(sc));
422 i4b_l1_mph_status_ind(L0IFPI2UNIT(sc->sc_unit), STI_L1STAT, LAYER_IDLE, NULL);
425 case ISACSX_CIR0_IDIS:
426 NDBGL1(L1_I_CICO, "rx DIS in state %s", ifpi2_printstate(sc));
430 case ISACSX_CIR0_IEI:
431 NDBGL1(L1_I_CICO, "rx EI in state %s", ifpi2_printstate(sc));
432 ifpi2_isacsx_l1_cmd(sc, CMD_DIU);
436 case ISACSX_CIR0_IARD:
437 NDBGL1(L1_I_CICO, "rx ARD in state %s", ifpi2_printstate(sc));
441 case ISACSX_CIR0_ITI:
442 NDBGL1(L1_I_CICO, "rx TI in state %s", ifpi2_printstate(sc));
446 case ISACSX_CIR0_IATI:
447 NDBGL1(L1_I_CICO, "rx ATI in state %s", ifpi2_printstate(sc));
451 case ISACSX_CIR0_ISD:
452 NDBGL1(L1_I_CICO, "rx SD in state %s", ifpi2_printstate(sc));
457 NDBGL1(L1_I_ERR, "UNKNOWN Indication 0x%x in state %s", ind, ifpi2_printstate(sc));
461 ifpi2_next_state(sc, event);
464 /*---------------------------------------------------------------------------*
465 * execute a layer 1 command
466 *---------------------------------------------------------------------------*/
468 ifpi2_isacsx_l1_cmd(struct l1_softc *sc, int command)
472 #ifdef I4B_SMP_WORKAROUND
474 /* XXXXXXXXXXXXXXXXXXX */
477 * patch from Wolfgang Helbig:
479 * Here is a patch that makes i4b work on an SMP:
480 * The card (TELES 16.3) didn't interrupt on an SMP machine.
481 * This is a gross workaround, but anyway it works *and* provides
482 * some information as how to finally fix this problem.
485 HSCX_WRITE(0, H_MASK, 0xff);
486 HSCX_WRITE(1, H_MASK, 0xff);
487 ISAC_WRITE(I_MASKD, 0xff);
488 ISAC_WRITE(I_MASK, 0xff);
490 HSCX_WRITE(0, H_MASK, HSCX_A_IMASK);
491 HSCX_WRITE(1, H_MASK, HSCX_B_IMASK);
492 ISAC_WRITE(I_MASKD, isacsx_imaskd);
493 ISAC_WRITE(I_MASK, isacsx_imask);
495 /* XXXXXXXXXXXXXXXXXXX */
497 #endif /* I4B_SMP_WORKAROUND */
499 if(command < 0 || command > CMD_ILL)
501 NDBGL1(L1_I_ERR, "illegal cmd 0x%x in state %s", command, ifpi2_printstate(sc));
505 cmd = ISACSX_CIX0_LOW;
510 NDBGL1(L1_I_CICO, "tx TIM in state %s", ifpi2_printstate(sc));
511 cmd |= (ISACSX_CIX0_CTIM << 4);
515 NDBGL1(L1_I_CICO, "tx RS in state %s", ifpi2_printstate(sc));
516 cmd |= (ISACSX_CIX0_CRS << 4);
520 NDBGL1(L1_I_CICO, "tx AR8 in state %s", ifpi2_printstate(sc));
521 cmd |= (ISACSX_CIX0_CAR8 << 4);
525 NDBGL1(L1_I_CICO, "tx AR10 in state %s", ifpi2_printstate(sc));
526 cmd |= (ISACSX_CIX0_CAR10 << 4);
530 NDBGL1(L1_I_CICO, "tx DIU in state %s", ifpi2_printstate(sc));
531 cmd |= (ISACSX_CIX0_CDIU << 4);
534 ISAC_WRITE(I_CIX0, cmd);
537 /*---------------------------------------------------------------------------*
538 * L1 ISACSX initialization
539 *---------------------------------------------------------------------------*/
541 ifpi2_isacsx_init(struct l1_softc *sc)
543 isacsx_imaskd = 0xff; /* disable all irqs */
544 isacsx_imask = 0xff; /* disable all irqs */
546 ISAC_WRITE(I_MASKD, isacsx_imaskd);
547 ISAC_WRITE(I_MASK, isacsx_imask);
549 /* the ISACSX only runs in IOM-2 mode */
550 NDBGL1(L1_I_SETUP, "configuring for IOM-2 mode");
552 /* TR_CONF0: Transceiver Configuration Register 0:
553 * DIS_TR - transceiver enabled
554 * EN_ICV - normal operation
555 * EXLP - no external loop
556 * LDD - automatic clock generation
558 ISAC_WRITE(I_WTR_CONF0, 0);
560 /* TR_CONF2: Transceiver Configuration Register 1:
561 * DIS_TX - transmitter enabled
562 * PDS - phase deviation 2 S-bits
563 * RLP - remote line loop open
565 ISAC_WRITE(I_WTR_CONF2, 0);
567 /* MODED: Mode Register:
568 * MDSx - transparent mode 0
569 * TMD - timer mode = external
570 * RAC - Receiver enabled
571 * DIMx - digital i/f mode
573 ISAC_WRITE(I_WMODED, ISACSX_MODED_MDS2|ISACSX_MODED_MDS1|ISACSX_MODED_RAC|ISACSX_MODED_DIM0);
575 /* enabled interrupts:
576 * ===================
577 * RME - receive message end
578 * RPF - receive pool full
579 * RPO - receive pool overflow
580 * XPR - transmit pool ready
581 * XMR - transmit message repeat
582 * XDU - transmit data underrun
585 isacsx_imaskd = ISACSX_MASKD_LOW;
586 ISAC_WRITE(I_MASKD, isacsx_imaskd);
588 /* enabled interrupts:
589 * ===================
590 * ICD - HDLC interrupt from D-channel
591 * CIC - C/I channel change
594 isacsx_imask = ~(ISACSX_MASK_ICD | ISACSX_MASK_CIC);
596 ISAC_WRITE(I_MASK, isacsx_imask);
601 #endif /* NIFPI2 > 0 */