/*---------------------------------------------------------------------------* * isic_recovery - try to recover from irq lockup *---------------------------------------------------------------------------*/ void isic_recover(struct isic_softc *sc) { u_char byte; /* get hscx irq status from hscx b ista */ byte = HSCX_READ(HSCX_CH_B, H_ISTA); NDBGL1(L1_ERROR, "HSCX B: ISTA = 0x%x", byte); if(byte & HSCX_ISTA_ICA) NDBGL1(L1_ERROR, "HSCX A: ISTA = 0x%x", (u_char)HSCX_READ(HSCX_CH_A, H_ISTA)); if(byte & HSCX_ISTA_EXB) NDBGL1(L1_ERROR, "HSCX B: EXIR = 0x%x", (u_char)HSCX_READ(HSCX_CH_B, H_EXIR)); if(byte & HSCX_ISTA_EXA) NDBGL1(L1_ERROR, "HSCX A: EXIR = 0x%x", (u_char)HSCX_READ(HSCX_CH_A, H_EXIR)); /* get isac irq status */ byte = ISAC_READ(I_ISTA); NDBGL1(L1_ERROR, " ISAC: ISTA = 0x%x", byte); if(byte & ISAC_ISTA_EXI) NDBGL1(L1_ERROR, " ISAC: EXIR = 0x%x", (u_char)ISAC_READ(I_EXIR)); if(byte & ISAC_ISTA_CISQ) { byte = ISAC_READ(I_CIRR); NDBGL1(L1_ERROR, " ISAC: CISQ = 0x%x", byte); if(byte & ISAC_CIRR_SQC) NDBGL1(L1_ERROR, " ISAC: SQRR = 0x%x", (u_char)ISAC_READ(I_SQRR)); } NDBGL1(L1_ERROR, "HSCX B: IMASK = 0x%x", HSCX_B_IMASK); NDBGL1(L1_ERROR, "HSCX A: IMASK = 0x%x", HSCX_A_IMASK); HSCX_WRITE(0, H_MASK, 0xff); HSCX_WRITE(1, H_MASK, 0xff); DELAY(100); HSCX_WRITE(0, H_MASK, HSCX_A_IMASK); HSCX_WRITE(1, H_MASK, HSCX_B_IMASK); DELAY(100); NDBGL1(L1_ERROR, " ISAC: IMASK = 0x%x", ISAC_IMASK); ISAC_WRITE(I_MASK, 0xff); DELAY(100); ISAC_WRITE(I_MASK, ISAC_IMASK); }
/*---------------------------------------------------------------------------* * write command to HSCX command register *---------------------------------------------------------------------------*/ void isic_hscx_cmd(struct isic_softc *sc, int h_chan, unsigned char cmd) { int timeout = 20; while(((HSCX_READ(h_chan, H_STAR)) & HSCX_STAR_CEC) && timeout) { DELAY(10); timeout--; } if(timeout == 0) { NDBGL1(L1_H_ERR, "HSCX wait for CEC timeout!"); } HSCX_WRITE(h_chan, H_CMDR, cmd); }
/*---------------------------------------------------------------------------* * execute a layer 1 command *---------------------------------------------------------------------------*/ void isic_isacsx_l1_cmd(struct isic_softc *sc, int command) { u_char cmd; #ifdef I4B_SMP_WORKAROUND /* XXXXXXXXXXXXXXXXXXX */ /* * patch from Wolfgang Helbig: * * Here is a patch that makes i4b work on an SMP: * The card (TELES 16.3) didn't interrupt on an SMP machine. * This is a gross workaround, but anyway it works *and* provides * some information as how to finally fix this problem. */ HSCX_WRITE(0, H_MASK, 0xff); HSCX_WRITE(1, H_MASK, 0xff); ISAC_WRITE(I_MASKD, 0xff); ISAC_WRITE(I_MASK, 0xff); DELAY(100); HSCX_WRITE(0, H_MASK, HSCX_A_IMASK); HSCX_WRITE(1, H_MASK, HSCX_B_IMASK); ISAC_WRITE(I_MASKD, isacsx_imaskd); ISAC_WRITE(I_MASK, isacsx_imask); /* XXXXXXXXXXXXXXXXXXX */ #endif /* I4B_SMP_WORKAROUND */ if(command < 0 || command > CMD_ILL) { NDBGL1(L1_I_ERR, "illegal cmd 0x%x in state %s", command, isic_printstate(sc)); return; } cmd = ISACSX_CIX0_LOW; switch(command) { case CMD_TIM: NDBGL1(L1_I_CICO, "tx TIM in state %s", isic_printstate(sc)); cmd |= (ISACSX_CIX0_CTIM << 4); break; case CMD_RS: NDBGL1(L1_I_CICO, "tx RS in state %s", isic_printstate(sc)); cmd |= (ISACSX_CIX0_CRS << 4); break; case CMD_AR8: NDBGL1(L1_I_CICO, "tx AR8 in state %s", isic_printstate(sc)); cmd |= (ISACSX_CIX0_CAR8 << 4); break; case CMD_AR10: NDBGL1(L1_I_CICO, "tx AR10 in state %s", isic_printstate(sc)); cmd |= (ISACSX_CIX0_CAR10 << 4); break; case CMD_DIU: NDBGL1(L1_I_CICO, "tx DIU in state %s", isic_printstate(sc)); cmd |= (ISACSX_CIX0_CDIU << 4); break; } ISAC_WRITE(I_CIX0, cmd); }
/*---------------------------------------------------------------------------* * HSCX initialization * * for telephony: extended transparent mode 1 * for raw hdlc: transparent mode 0 *---------------------------------------------------------------------------*/ void isic_hscx_init(struct isic_softc *sc, int h_chan, int activate) { l1_bchan_state_t *chan = &sc->sc_chan[h_chan]; HSCX_WRITE(h_chan, H_MASK, 0xff); /* mask irq's */ if(sc->sc_ipac) { /* CCR1: Power Up, Clock Mode 5 */ HSCX_WRITE(h_chan, H_CCR1, HSCX_CCR1_PU | /* power up */ HSCX_CCR1_CM1); /* IPAC clock mode 5 */ } else { /* CCR1: Power Up, Clock Mode 5 */ HSCX_WRITE(h_chan, H_CCR1, HSCX_CCR1_PU | /* power up */ HSCX_CCR1_CM2 | /* HSCX clock mode 5 */ HSCX_CCR1_CM0); } /* XAD1: Transmit Address Byte 1 */ HSCX_WRITE(h_chan, H_XAD1, 0xff); /* XAD2: Transmit Address Byte 2 */ HSCX_WRITE(h_chan, H_XAD2, 0xff); /* RAH2: Receive Address Byte High Reg. 2 */ HSCX_WRITE(h_chan, H_RAH2, 0xff); /* XBCH: reset Transmit Byte Count High */ HSCX_WRITE(h_chan, H_XBCH, 0x00); /* RLCR: reset Receive Length Check Register */ HSCX_WRITE(h_chan, H_RLCR, 0x00); /* CCR2: set tx/rx clock shift bit 0 */ /* disable CTS irq, disable RIE irq*/ HSCX_WRITE(h_chan, H_CCR2, HSCX_CCR2_XCS0|HSCX_CCR2_RCS0); /* XCCR: tx bit count per time slot */ HSCX_WRITE(h_chan, H_XCCR, 0x07); /* RCCR: rx bit count per time slot */ HSCX_WRITE(h_chan, H_RCCR, 0x07); if(sc->sc_bustyp == BUS_TYPE_IOM2) { switch(h_chan) { case HSCX_CH_A: /* Prepare HSCX channel A */ /* TSAX: tx clock shift bits 1 & 2 */ /* tx time slot number */ HSCX_WRITE(h_chan, H_TSAX, 0x2f); /* TSAR: rx clock shift bits 1 & 2 */ /* rx time slot number */ HSCX_WRITE(h_chan, H_TSAR, 0x2f); break; case HSCX_CH_B: /* Prepare HSCX channel B */ /* TSAX: tx clock shift bits 1 & 2 */ /* tx time slot number */ HSCX_WRITE(h_chan, H_TSAX, 0x03); /* TSAR: rx clock shift bits 1 & 2 */ /* rx time slot number */ HSCX_WRITE(h_chan, H_TSAR, 0x03); break; } } else /* IOM 1 setup */ { /* TSAX: tx clock shift bits 1 & 2 */ /* tx time slot number */ HSCX_WRITE(h_chan, H_TSAX, 0x07); /* TSAR: rx clock shift bits 1 & 2 */ /* rx time slot number */ HSCX_WRITE(h_chan, H_TSAR, 0x07); } if(activate) { if(chan->bprot == BPROT_RHDLC) { /* HDLC Frames, transparent mode 0 */ HSCX_WRITE(h_chan, H_MODE, HSCX_MODE_MDS1|HSCX_MODE_RAC|HSCX_MODE_RTS); } else { /* Raw Telephony, extended transparent mode 1 */ HSCX_WRITE(h_chan, H_MODE, HSCX_MODE_MDS1|HSCX_MODE_MDS0|HSCX_MODE_ADM|HSCX_MODE_RTS); } isic_hscx_cmd(sc, h_chan, HSCX_CMDR_RHR|HSCX_CMDR_XRES); } else { /* TSAX: tx time slot */ HSCX_WRITE(h_chan, H_TSAX, 0xff); /* TSAR: rx time slot */ HSCX_WRITE(h_chan, H_TSAR, 0xff); /* Raw Telephony, extended transparent mode 1 */ HSCX_WRITE(h_chan, H_MODE, HSCX_MODE_MDS1|HSCX_MODE_MDS0|HSCX_MODE_ADM|HSCX_MODE_RTS); } /* don't touch ICA, EXA and EXB bits, this could be HSCX_CH_B */ /* always disable RSC and TIN */ chan->hscx_mask |= HSCX_MASK_RSC | HSCX_MASK_TIN; if(activate) { /* enable */ chan->hscx_mask &= ~(HSCX_MASK_RME | HSCX_MASK_RPF | HSCX_MASK_XPR); } else { /* disable */ chan->hscx_mask |= HSCX_MASK_RME | HSCX_MASK_RPF | HSCX_MASK_XPR; } /* handle ICA, EXA, and EXB via interrupt mask of channel b */ if (h_chan == HSCX_CH_A) { if (activate) HSCX_B_IMASK &= ~(HSCX_MASK_EXA | HSCX_MASK_ICA); else HSCX_B_IMASK |= HSCX_MASK_EXA | HSCX_MASK_ICA; HSCX_WRITE(HSCX_CH_A, H_MASK, HSCX_A_IMASK); HSCX_WRITE(HSCX_CH_B, H_MASK, HSCX_B_IMASK); } else { if (activate) HSCX_B_IMASK &= ~HSCX_MASK_EXB; else HSCX_B_IMASK |= HSCX_MASK_EXB; HSCX_WRITE(HSCX_CH_B, H_MASK, HSCX_B_IMASK); } /* clear spurious interrupts left over */ if(h_chan == HSCX_CH_A) { HSCX_READ(h_chan, H_EXIR); HSCX_READ(h_chan, H_ISTA); } else /* mask ICA, because it must not be cleared by reading ISTA */ { HSCX_WRITE(HSCX_CH_B, H_MASK, HSCX_B_IMASK | HSCX_MASK_ICA); HSCX_READ(h_chan, H_EXIR); HSCX_READ(h_chan, H_ISTA); HSCX_WRITE(HSCX_CH_B, H_MASK, HSCX_B_IMASK); } }
/*---------------------------------------------------------------------------* * isic - device driver interrupt routine *---------------------------------------------------------------------------*/ void isicintr(struct l1_softc *sc) { if(sc->sc_ipac == 0) /* HSCX/ISAC interupt routine */ { u_char was_hscx_irq = 0; u_char was_isac_irq = 0; register u_char hscx_irq_stat; register u_char isac_irq_stat; for(;;) { /* get hscx irq status from hscx b ista */ hscx_irq_stat = HSCX_READ(HSCX_CH_B, H_ISTA) & ~HSCX_B_IMASK; /* get isac irq status */ isac_irq_stat = ISAC_READ(I_ISTA); /* do as long as there are pending irqs in the chips */ if(!hscx_irq_stat && !isac_irq_stat) break; if(hscx_irq_stat & (HSCX_ISTA_RME | HSCX_ISTA_RPF | HSCX_ISTA_RSC | HSCX_ISTA_XPR | HSCX_ISTA_TIN | HSCX_ISTA_EXB)) { isic_hscx_irq(sc, hscx_irq_stat, HSCX_CH_B, hscx_irq_stat & HSCX_ISTA_EXB); was_hscx_irq = 1; } if(hscx_irq_stat & (HSCX_ISTA_ICA | HSCX_ISTA_EXA)) { isic_hscx_irq(sc, HSCX_READ(HSCX_CH_A, H_ISTA) & ~HSCX_A_IMASK, HSCX_CH_A, hscx_irq_stat & HSCX_ISTA_EXA); was_hscx_irq = 1; } if(isac_irq_stat) { isic_isac_irq(sc, isac_irq_stat); /* isac handler */ was_isac_irq = 1; } } HSCX_WRITE(0, H_MASK, 0xff); ISAC_WRITE(I_MASK, 0xff); HSCX_WRITE(1, H_MASK, 0xff); #ifdef ELSA_QS1ISA DELAY(80); if((sc->sc_cardtyp == CARD_TYPEP_ELSAQS1ISA) && (sc->clearirq)) { sc->clearirq(sc); } #else DELAY(100); #endif HSCX_WRITE(0, H_MASK, HSCX_A_IMASK); ISAC_WRITE(I_MASK, ISAC_IMASK); HSCX_WRITE(1, H_MASK, HSCX_B_IMASK); } else /* IPAC interrupt routine */ { register u_char ipac_irq_stat; register u_char was_ipac_irq = 0; for(;;) { /* get global irq status */ ipac_irq_stat = (IPAC_READ(IPAC_ISTA)) & 0x3f; /* check hscx a */ if(ipac_irq_stat & (IPAC_ISTA_ICA | IPAC_ISTA_EXA)) { /* HSCX A interrupt */ isic_hscx_irq(sc, HSCX_READ(HSCX_CH_A, H_ISTA), HSCX_CH_A, ipac_irq_stat & IPAC_ISTA_EXA); was_ipac_irq = 1; } if(ipac_irq_stat & (IPAC_ISTA_ICB | IPAC_ISTA_EXB)) { /* HSCX B interrupt */ isic_hscx_irq(sc, HSCX_READ(HSCX_CH_B, H_ISTA), HSCX_CH_B, ipac_irq_stat & IPAC_ISTA_EXB); was_ipac_irq = 1; } if(ipac_irq_stat & IPAC_ISTA_ICD) { /* ISAC interrupt */ isic_isac_irq(sc, ISAC_READ(I_ISTA)); was_ipac_irq = 1; } if(ipac_irq_stat & IPAC_ISTA_EXD) { /* force ISAC interrupt handling */ isic_isac_irq(sc, ISAC_ISTA_EXI); was_ipac_irq = 1; } /* do as long as there are pending irqs in the chip */ if(!ipac_irq_stat) break; } IPAC_WRITE(IPAC_MASK, 0xff); DELAY(50); IPAC_WRITE(IPAC_MASK, 0xc0); } }
/*---------------------------------------------------------------------------* * isic - device driver interrupt routine *---------------------------------------------------------------------------*/ int isicintr(void *arg) { struct isic_softc *sc = arg; /* could this be an interrupt for us? */ if (sc->sc_intr_valid == ISIC_INTR_DYING) return 0; /* do not touch removed hardware */ if(sc->sc_ipac == 0) /* HSCX/ISAC interupt routine */ { u_char was_hscx_irq = 0; u_char was_isac_irq = 0; register u_char hscx_irq_stat; register u_char isac_irq_stat; for(;;) { /* get hscx irq status from hscx b ista */ hscx_irq_stat = HSCX_READ(HSCX_CH_B, H_ISTA) & ~HSCX_B_IMASK; /* get isac irq status */ isac_irq_stat = ISAC_READ(I_ISTA); /* do as long as there are pending irqs in the chips */ if(!hscx_irq_stat && !isac_irq_stat) break; if(hscx_irq_stat & (HSCX_ISTA_RME | HSCX_ISTA_RPF | HSCX_ISTA_RSC | HSCX_ISTA_XPR | HSCX_ISTA_TIN | HSCX_ISTA_EXB)) { isic_hscx_irq(sc, hscx_irq_stat, HSCX_CH_B, hscx_irq_stat & HSCX_ISTA_EXB); was_hscx_irq = 1; } if(hscx_irq_stat & (HSCX_ISTA_ICA | HSCX_ISTA_EXA)) { isic_hscx_irq(sc, HSCX_READ(HSCX_CH_A, H_ISTA) & ~HSCX_A_IMASK, HSCX_CH_A, hscx_irq_stat & HSCX_ISTA_EXA); was_hscx_irq = 1; } if(isac_irq_stat) { /* isac handler */ isic_isac_irq(sc, isac_irq_stat); was_isac_irq = 1; } } HSCX_WRITE(0, H_MASK, 0xff); ISAC_WRITE(I_MASK, 0xff); HSCX_WRITE(1, H_MASK, 0xff); if (sc->clearirq) { DELAY(80); sc->clearirq(sc); } else DELAY(100); HSCX_WRITE(0, H_MASK, HSCX_A_IMASK); ISAC_WRITE(I_MASK, ISAC_IMASK); HSCX_WRITE(1, H_MASK, HSCX_B_IMASK); return(was_hscx_irq || was_isac_irq); } else /* IPAC interrupt routine */ { register u_char ipac_irq_stat; register u_char was_ipac_irq = 0; for(;;) { /* get global irq status */ ipac_irq_stat = (IPAC_READ(IPAC_ISTA)) & 0x3f; /* check hscx a */ if(ipac_irq_stat & (IPAC_ISTA_ICA | IPAC_ISTA_EXA)) { /* HSCX A interrupt */ isic_hscx_irq(sc, HSCX_READ(HSCX_CH_A, H_ISTA), HSCX_CH_A, ipac_irq_stat & IPAC_ISTA_EXA); was_ipac_irq = 1; } if(ipac_irq_stat & (IPAC_ISTA_ICB | IPAC_ISTA_EXB)) { /* HSCX B interrupt */ isic_hscx_irq(sc, HSCX_READ(HSCX_CH_B, H_ISTA), HSCX_CH_B, ipac_irq_stat & IPAC_ISTA_EXB); was_ipac_irq = 1; } if(ipac_irq_stat & IPAC_ISTA_ICD) { /* ISAC interrupt, Obey ISAC-IPAC differences */ u_int8_t isac_ista = ISAC_READ(I_ISTA); if (isac_ista & 0xfe) isic_isac_irq(sc, isac_ista & 0xfe); if (isac_ista & 0x01) /* unexpected */ printf("%s: unexpected ipac timer2 irq\n", sc->sc_dev.dv_xname); was_ipac_irq = 1; } if(ipac_irq_stat & IPAC_ISTA_EXD) { /* ISAC EXI interrupt */ isic_isac_irq(sc, ISAC_ISTA_EXI); was_ipac_irq = 1; } /* do as long as there are pending irqs in the chip */ if(!ipac_irq_stat) break; } #if 0 /* * This seems not to be necessary on IPACs - no idea why * it is here - but due to limit range of test cards, leave * it in for now, in case we have to resurrect it. */ IPAC_WRITE(IPAC_MASK, 0xff); DELAY(50); IPAC_WRITE(IPAC_MASK, 0xc0); #endif return(was_ipac_irq); } }