diff options
author | Noe Rubinstein <nrubinstein@proformatique.com> | 2010-12-09 18:32:46 +0100 |
---|---|---|
committer | Noe Rubinstein <nrubinstein@proformatique.com> | 2010-12-09 18:32:46 +0100 |
commit | 3ac1d0d7ca9901e2024daffeb4a05dea99136104 (patch) | |
tree | 02df60f31fe3827a8fb5417d3850b815aebf282a | |
parent | 820d1a2d16b4dd267fd4a3e881d17e78679636cb (diff) | |
parent | f8dbef0ea7d8d2949956c24b2c392837a264480f (diff) |
Merge branch 'st-state-rewrite'
-rw-r--r-- | xhfc/Makefile | 2 | ||||
-rw-r--r-- | xhfc/TODO | 2 | ||||
-rw-r--r-- | xhfc/xhfc.c | 315 | ||||
-rw-r--r-- | xhfc/xhfc.h | 38 | ||||
-rw-r--r-- | xhfc/xhfc_st_state.c | 353 | ||||
-rw-r--r-- | xhfc/xhfc_timers_state.c | 375 |
6 files changed, 536 insertions, 549 deletions
diff --git a/xhfc/Makefile b/xhfc/Makefile index 62626f1..a7c8833 100644 --- a/xhfc/Makefile +++ b/xhfc/Makefile @@ -6,7 +6,7 @@ CFLAGS_MODULE += -I$(DAHDI_INCLUDE) -I$(abspath $(src)/../) -DUSE_GPIO obj-m := xhfcdm.o -xhfcdm-objs := xhfc.o xhfc_leb.o xhfc_timers_state.o +xhfcdm-objs := xhfc.o xhfc_leb.o xhfc_st_state.o modules: modules modules_install clean: @@ -2,7 +2,7 @@ tasklet? - Sync warning: prolly no problem currently, but linked to our architecture + context (hardirq vs. softirq) (running etc.) -- Rewrite the S/T state handling code. - Review again the FIFO rw code (WTF comments) - (Low priority) check support for other XHFCs +- The init structure is not very clear (xhfc_init_and_configure) diff --git a/xhfc/xhfc.c b/xhfc/xhfc.c index fcf9488..9eebf20 100644 --- a/xhfc/xhfc.c +++ b/xhfc/xhfc.c @@ -122,7 +122,9 @@ void xhfc_config_st(struct xhfc *x, int port, int nt) SET_V_B1_TX_EN(a_su_ctrl0, 1); SET_V_B2_TX_EN(a_su_ctrl0, 1); SET_V_ST_E_IGNO(a_su_ctrl1, nt ? 1 : 0); - SET_V_G2_G3_EN(a_su_ctrl1, 1); + SET_V_G2_G3_EN(a_su_ctrl1, 0); /* Disallowed in order to be able to + * guarantee that T1 is handled + * correctly (xref6) */ SET_V_B1_RX_EN(a_su_ctrl2, 1); SET_V_B2_RX_EN(a_su_ctrl2, 1); SET_V_SU_ACT(a_su_wr_sta, 3); /* activation */ @@ -189,7 +191,7 @@ int xhfc_config_pcm(struct xhfc *xhfc, int master_or_slave) return 0; } -#define debug_fz(b4, fifo, prefix, buf) \ +#define debug_fz(fifo, prefix, buf) \ do { \ sprintf(buf, "%s(fifo %d): flen=%d, " \ "zlen=%d", prefix, fifo, flen, \ @@ -299,26 +301,22 @@ void xhfc_config_data_flow(struct xhfc* x) */ static void hdlc_signal_complete(struct xhfc_span *xhfc_span, u8 stat) { - struct xhfc *xhfc = xhfc_span->xhfc; - -/* if STAT != 0, indicates bad frame */ if (stat != 0x00) { - if (DBG_HDLC && DBG_SPANFILTER) { - xhfc_info(xhfc, "(span %d) STAT=0x%02x indicates " - "frame problem: %s\n", xhfc_span->port + 1, + if (DBG_HDLC && DBG_SPAN(xhfc_span)) { + printk(KERN_INFO DRIVER_NAME "(port %d) STAT=0x%02x indicates " + "frame problem: %s\n", portno(xhfc_span), stat, (0xff == stat) ? "HDLC Abort" : "Bad FCS"); } dahdi_hdlc_abort(xhfc_span->sigchan, (0xff == stat) ? DAHDI_EVENT_ABORT : DAHDI_EVENT_BADFCS); -/* STAT == 0, means frame was OK */ } else { - if (DBG_HDLC && DBG_SPANFILTER) { - xhfc_info(xhfc, - "(span %d) Frame " /*"%d" */ "is good!\n", - xhfc_span->port + - 1 /*, xhfc_span->frames_in */ ); + if (DBG_HDLC && DBG_SPAN(xhfc_span)) { + printk(KERN_INFO DRIVER_NAME + "(port %d) Frame " /*"%d" */ "is good!\n", + portno(xhfc_span) + /*, xhfc_span->frames_in */ ); } dahdi_hdlc_finish(xhfc_span->sigchan); } @@ -342,29 +340,29 @@ static int hdlc_rx_frame(struct xhfc_span *xhfc_span) fifo = dchan_fifo(xhfc_span); - if (DBG_VERBOSE_HDLC && DBG_SPANFILTER) - xhfc_info(x, "%s(fifo %d): start\n", __func__, fifo); + if (DBG_VERBOSE_HDLC && DBG_SPAN(xhfc_span)) + printk(KERN_INFO DRIVER_NAME ": %s(fifo %d): start\n", + __func__, fifo); xhfc_selfifo(x, fifo, RECEIVE); flen = get_Flen(x); zlen = get_Zlen(x); - debug_fz(x, fifo, __func__, debugbuf); + debug_fz(fifo, __func__, debugbuf); if (!flen && !zlen) { - if (DBG_VERBOSE_HDLC && DBG_SPANFILTER) - xhfc_info(x, "%s, nothing to receive (%ld).\n", debugbuf, xhfc_span->non_rx_cnt); + if (DBG_VERBOSE_HDLC && DBG_SPAN(xhfc_span)) + printk(KERN_INFO DRIVER_NAME + ": %s, nothing to receive (%ld)\n", + debugbuf, xhfc_span->non_rx_cnt); xhfc_span->non_rx_cnt++; - if (DBG_HDLC && DBG_SPANFILTER && 0 == xhfc_span->non_rx_cnt % 2000) - xhfc_info(x, "%s(fifo %d): Received nothing for %ld seconds.\n", - __func__, fifo, xhfc_span->non_rx_cnt / 2000); return 0; } xhfc_span->non_rx_cnt = 0; - if (DBG_VERBOSE_HDLC && DBG_SPANFILTER) - xhfc_info(x, "%s\n", debugbuf); + if (DBG_VERBOSE_HDLC && DBG_SPAN(xhfc_span)) + printk(KERN_INFO DRIVER_NAME ": %s\n", debugbuf); /* if we have at least one complete frame, increment zleft to include * status byte */ @@ -373,12 +371,7 @@ static int hdlc_rx_frame(struct xhfc_span *xhfc_span) zleft++; do { - if (zleft > HDLC_BUF_LEN) - j = HDLC_BUF_LEN; - else - j = zleft; - - xhfc_selfifo(x, fifo, RECEIVE); + j = zleft > HDLC_BUF_LEN ? HDLC_BUF_LEN : zleft; for (i = 0; i < j; i++) buf[i] = read_xhfc(x, A_FIFO_DATA); @@ -394,20 +387,20 @@ static int hdlc_rx_frame(struct xhfc_span *xhfc_span) zleft -= j; - if (DBG_VERBOSE_HDLC && DBG_SPANFILTER) { - xhfc_info(x, "transmitted %d bytes to dahdi, " - "zleft=%d\n", k, zleft); - } + if (DBG_VERBOSE_HDLC && DBG_SPAN(xhfc_span)) + printk(KERN_INFO DRIVER_NAME + ": transmitted %d bytes to dahdi, " + "zleft=%d\n", k, zleft); - if (DBG_HDLC && DBG_SPANFILTER) { + if (DBG_HDLC && DBG_SPAN(xhfc_span)) { dbglen = 0; for (i = 0; i < j; i++) dbglen += sprintf(debugbuf+dbglen, "%02x ", buf[i]); debugbuf[dbglen] = '\0'; - xhfc_info(x, "hdlc_rx_frame(fifo %d): " - "zlen=%d, zleft=%d: %s\n", - fifo, zlen, zleft, debugbuf); + printk(KERN_INFO DRIVER_NAME ": %s(fifo %d): " + "zlen=%d, zleft=%d: %s\n", __func__, + fifo, zlen, zleft, debugbuf); } } while (zleft > 0); @@ -418,28 +411,19 @@ static int hdlc_rx_frame(struct xhfc_span *xhfc_span) /* If this channel is not configured with a signalling span we don't * need to notify the rest of dahdi about this frame. */ if (!xhfc_span->sigchan) { - if (DBG_HDLC && DBG_SPANFILTER) { - xhfc_info(x, "hdlc_rx_frame(fifo %d): " - "flen %d, early end.\n", fifo, flen); - } + if (DBG_HDLC && DBG_SPAN(xhfc_span)) + printk(KERN_INFO DRIVER_NAME + ": %s(fifo %d): flen %d, early end\n", + __func__, fifo, flen); return flen; } - if (flen) { -#if 0 /* disable < 3 check for now */ - if (zlen < 3) { - if (DBG_HDLC && DBG_SPANFILTER) - xhfc_info(x, "odd, zlen less then 3?\n"); - dahdi_hdlc_abort(xhfc_span->sigchan, DAHDI_EVENT_ABORT); - } else -#endif + if (flen) hdlc_signal_complete(xhfc_span, buf[i - 1]); - } - if (DBG_VERBOSE_HDLC && DBG_SPANFILTER) { - xhfc_info(x, "hdlc_rx_frame(fifo %d): flen=%d end.\n", - fifo, flen); - } + if (DBG_VERBOSE_HDLC && DBG_SPAN(xhfc_span)) + printk(KERN_INFO DRIVER_NAME ": %s(fifo %d): flen=%d end\n", + __func__, fifo, flen); return flen; } @@ -447,13 +431,14 @@ static int hdlc_rx_frame(struct xhfc_span *xhfc_span) static uint frames_out; /* * Takes one blob of data from DAHDI and shoots it out to the hardware. The -* blob may or may not be a complete HDLC frame. If it isn't, the D-channel -* FIFO interrupt handler will take care of pulling the rest. //XXX FOUTAISES!!! +* blob may or may not be a complete HDLC frame. If it isn't, the rest will be +* pulled during the next timer interrupt. * Returns nonzero if there is still data to send in the current HDLC frame. */ static int hdlc_tx_frame(struct xhfc_span *xhfc_span) { struct xhfc *x = xhfc_span->xhfc; + struct dahdi_span *dahdi_span = &xhfc_span->span; int res, i, fifo; int zlen; int flen = -1; @@ -463,9 +448,9 @@ static int hdlc_tx_frame(struct xhfc_span *xhfc_span) int dbglen; /* ignoring TE red alarms: if TE and we are in alarm, restart the - * S/T state machine ???*/ - if (!xhfc_span->nt && (xhfc_span->newalarm != 0)) { - hfc_start_st(xhfc_span); + * S/T state machine... */ + if (!xhfc_span->nt && (xhfc_span->span.alarms != 0)) { + activate_request(xhfc_span); } fifo = dchan_fifo(xhfc_span); @@ -474,12 +459,12 @@ static int hdlc_tx_frame(struct xhfc_span *xhfc_span) xhfc_selfifo(x, fifo, TRANSMIT); zlen = get_Zlen(x); - debug_fz(x, fifo, __func__, debugbuf); + debug_fz(fifo, __func__, debugbuf); /* TODO: check zlen, etc. */ if ((XHFC_ZMAX - zlen) < size) { static int arg; - xhfc_info(x, "xhfc: arg (%d), zlen (%d) < what we " + printk(KERN_INFO DRIVER_NAME ": arg (%d), zlen (%d) < what we " "grabbed from DAHDI (%d)!\n", ++arg, zlen, size); size = zlen; dahdi_hdlc_abort(xhfc_span->sigchan, DAHDI_EVENT_OVERRUN); @@ -499,24 +484,24 @@ static int hdlc_tx_frame(struct xhfc_span *xhfc_span) } } - if (DBG_HDLC && DBG_SPANFILTER) { - xhfc_info(xhfc_span->xhfc, "%s\n", debugbuf); + if (DBG_HDLC && DBG_SPAN(xhfc_span)) { + printk(KERN_INFO DRIVER_NAME ": %s\n", debugbuf); dbglen = 0; for (i = 0; i < size; i++) dbglen += sprintf(debugbuf+dbglen, "%02x ", buf[i]); debugbuf[dbglen] = '\0'; - xhfc_info(xhfc_span->xhfc, - "hdlc_tx_frame(span %d): DAHDI gave %d " + printk(KERN_INFO DRIVER_NAME + ": hdlc_tx_frame(span %d): DAHDI gave %d " "bytes for FIFO %d (res = %d): %s\n", - xhfc_span->port + 1, + dahdi_span->spanno, size, fifo, res, debugbuf); if (size && res != 0) - xhfc_info(xhfc_span->xhfc, - "Transmitted frame %d on span %d\n", - frames_out - 1, xhfc_span->port); + printk(KERN_INFO DRIVER_NAME + ": Transmitted frame %d on span %d\n", + frames_out - 1, dahdi_span->spanno); } return !res; @@ -525,22 +510,16 @@ static int hdlc_tx_frame(struct xhfc_span *xhfc_span) /* DAHDI calls this when it has data it wants to send to the HDLC controller */ void xhfc_hdlc_hard_xmit(struct dahdi_chan *chan) { - struct xhfc_span *xhfc_span; - struct dahdi_span *dspan; - struct xhfc *xhfc; - int span; + struct dahdi_span *dahdi_span = chan->span; + struct xhfc_span *xhfc_span = + container_of(dahdi_span, struct xhfc_span, span); - dspan = chan->span; - xhfc_span = container_of(dspan, struct xhfc_span, span); - xhfc = xhfc_span->xhfc; - span = xhfc_span->port; - - if ((DBG_FOPS || DBG_HDLC) && DBG_SPANFILTER) { - xhfc_info(xhfc, "hdlc_hard_xmit on chan %s (%i/%i), " \ - "span=%i (sigchan=%p, chan=%p)\n", chan->name, - chan->channo, chan->chanpos, span + 1, - xhfc_span->sigchan, chan); - } + if ((DBG_FOPS || DBG_HDLC) && DBG_SPAN(xhfc_span)) + printk(KERN_INFO DRIVER_NAME ": %s on chan %s (%i/%i), " + "span=%i (sigchan=%p, chan=%p)\n", + __func__, chan->name, chan->channo, + chan->chanpos, dahdi_span->spanno, + xhfc_span->sigchan, chan); /* Increment the hdlc_pending counter and trigger hdlc_tx_frame */ if (xhfc_span->sigchan == chan) @@ -552,9 +531,10 @@ void xhfc_hdlc_hard_xmit(struct dahdi_chan *chan) * scheduled in a tasklet instead * *****************************************************************************/ +#define fifo_test(reg, fifonum, dir) (reg[fifonum/4] & (1 << (((fifonum % 4) * 2) + dir))) + irqreturn_t xhfc_interrupt(int irq, void *dev_id, struct pt_regs* ptregs) { - /* (void) ptregs; */ struct xhfc_pi *pi = dev_id; struct xhfc *xhfc; @@ -562,6 +542,10 @@ irqreturn_t xhfc_interrupt(int irq, void *dev_id, struct pt_regs* ptregs) int i; u8 r_su_irq; u8 misc_irq; + u8 fifo_irq[SPANS_PER_CHIP]; + u8 fifo_fill[SPANS_PER_CHIP]; + + (void) ptregs; xhfc = &pi->xhfc; @@ -578,13 +562,24 @@ irqreturn_t xhfc_interrupt(int irq, void *dev_id, struct pt_regs* ptregs) if (misc_irq & M_TI_IRQMSK) xhfc->ticks++; + for(i = 0; i < SPANS_PER_CHIP; i++) { + fifo_irq[i] = read_xhfc(xhfc, R_FIFO_BL0_IRQ + i); + fifo_fill[i] = read_xhfc(xhfc, R_FILL_BL0 + i); + } + for (i = 0; i < SPANS_PER_CHIP; i++) { struct xhfc_span* s = &xhfc->spans[i]; if ((s->span.flags & DAHDI_FLAG_RUNNING) && s->sigchan) { - /* No need to loop here, no need to rx/tx - * more than one HDLC frame per millisecond. */ - hdlc_rx_frame(s); + + /* No need to loop, makes no sense to receive + * more than one HDLC frame per second. + */ + if ( fifo_test(fifo_irq, dchan_fifo(s), RECEIVE) || + fifo_test(fifo_fill, dchan_fifo(s), RECEIVE)) + + hdlc_rx_frame(s); + if (atomic_read(&s->hdlc_pending)) hdlc_tx_frame(s); #ifdef AUDIO @@ -619,11 +614,11 @@ irqreturn_t xhfc_interrupt(int irq, void *dev_id, struct pt_regs* ptregs) r_su_irq = read_xhfc(xhfc, R_SU_IRQ); - for (i = 0; i < ARRAY_SIZE(xhfc->spans); i++) - if (r_su_irq & (1 << i) || 2 == xhfc->ticks /* bootstrap XXX*/) - hfc_handle_state(&xhfc->spans[i]); // BOOM (recursion + GFP_KERNEL allocs there) - - hfc_update_st_timers(xhfc); + for (i = 0; i < SPANS_PER_CHIP; i++) { + handle_st_timers(&xhfc->spans[i]); + if (r_su_irq & (1 << i) || 2 == xhfc->ticks /* bootstrap XXX WTF*/) + handle_state_change(&xhfc->spans[i]); + } } return IRQ_HANDLED; @@ -650,6 +645,7 @@ static void disable_interrupts(struct xhfc * xhfc) /******************************************/ static void enable_interrupts(struct xhfc * xhfc) { + u8 r_irq_ctrl = 0; printk(KERN_INFO "%s %s\n", xhfc->name, __func__); set_mb(xhfc->running, 1); @@ -667,7 +663,9 @@ static void enable_interrupts(struct xhfc * xhfc) read_xhfc(xhfc, R_FIFO_BL3_IRQ); /* enable global interrupts */ - write_xhfc(xhfc, R_IRQ_CTRL, M_GLOB_IRQ_EN); + SET_V_GLOB_IRQ_EN(r_irq_ctrl, 1); + SET_V_FIFO_IRQ_EN(r_irq_ctrl, 1); + write_xhfc(xhfc, R_IRQ_CTRL, r_irq_ctrl); } @@ -718,8 +716,7 @@ void configure_port(int port, int nt, int lineterm) void xhfc_init_and_configure(struct xhfc* x) { - int i; - + u8 r_fifo_thres = 0; /* In DAHDI's driver's this part is "stage 1" */ xhfc_reset(x); @@ -729,12 +726,12 @@ void xhfc_init_and_configure(struct xhfc* x) /* "stage 2" */ xhfc_config_pcm(x, XHFC_PCM_MASTER); - for (i = 0; i < SPANS_PER_CHIP; i++) - xhfc_config_st(x, x->spans[i].port, x->spans[i].nt); - /* Now we need to setup the flow controller and stuff */ - xhfc_config_data_flow(x); + + SET_V_THRES_RX(r_fifo_thres, 2); + SET_V_THRES_TX(r_fifo_thres, 2); + write_xhfc(x, R_FIFO_THRES, r_fifo_thres); } static void xhfc_span_set_ntte(struct xhfc_span* s, int ntte) @@ -756,73 +753,77 @@ int xhfc_spanconfig(struct dahdi_span *span, struct dahdi_lineconfig *lc) term = (lc->lineconfig & DAHDI_CONFIG_TERM) ? 1 : 0; - xhfc_info(xhfc, "xhfc: Configuring port %d span %d in %s " \ - "mode with termination resistance %s\n", xhfc_span->port, - span->spanno, xhfc_span->nt ? "NT" : "TE", - term ? "ENABLED" : "DISABLED"); + printk(KERN_INFO DRIVER_NAME ": Configuring port %d span %d in %s mode" + " with termination resistance %s\n", + portno(xhfc_span), span->spanno, + xhfc_span->nt ? "NT" : "TE", + term ? "ENABLED" : "DISABLED"); /* TODO conf hardware interface w/ GPIO */ xhfc_config_st(xhfc, xhfc_span->port, xhfc_span->nt); - xhfc_info(xhfc, "WARNING: This driver can't configure the ports yet, " - "expect problems if port %d isn't configured in %s " - "mode.\n", xhfc_span->port, xhfc_span->nt ? "NT" : "TE"); + printk(KERN_INFO DRIVER_NAME ": WARNING: This driver can't configure " + "the ports yet, expect problems if port %d isn't " + "configured in %s mode\n", + portno(xhfc_span), xhfc_span->nt ? "NT" : "TE"); if (lc->sync < 0) { - xhfc_info(xhfc, "Span %d has invalid sync priority (%d), " \ - "removing from sync source list\n", span->spanno, - lc->sync); + printk(KERN_INFO DRIVER_NAME + ": Span %d has invalid sync priority (%d), " + "removing from sync source list\n", + span->spanno, lc->sync); lc->sync = 0; } if (xhfc_span->nt && lc->sync) { - xhfc_info(xhfc, "NT Spans cannot be timing sources. " \ - "Span %d requested to be timing source of " \ - "priority %d. Changing priority to 0\n", span->offset, - lc->sync); + printk(KERN_INFO DRIVER_NAME + ": NT Spans cannot be timing sources. " + "Span %d requested to be timing source of " + "priority %d. Changing priority to 0\n", + span->offset, lc->sync); lc->sync = 0; } + start_state_machine(xhfc_span); + return 0; } int xhfc_chanconfig(struct dahdi_chan *chan, int sigtype) { int alreadyrunning; - struct xhfc_span *bspan = container_of(chan->span, struct xhfc_span, span); - struct xhfc *b4 = bspan->xhfc; + struct xhfc_span *xhfc_span = container_of(chan->span, struct xhfc_span, span); int res; - alreadyrunning = bspan->span.flags & DAHDI_FLAG_RUNNING; + alreadyrunning = xhfc_span->span.flags & DAHDI_FLAG_RUNNING; - if (DBG_FOPS) { - xhfc_info(b4, "%s channel %d (%s) sigtype %08x\n", - alreadyrunning ? "Reconfigured" : "Configured", - chan->channo, chan->name, sigtype); - } + if (DBG_FOPS) + printk(KERN_INFO DRIVER_NAME + ": %s channel %d (%s) sigtype %08x\n", + alreadyrunning ? "Reconfigured" : "Configured", + chan->channo, chan->name, sigtype); switch (sigtype) { case DAHDI_SIG_HARDHDLC: /* xref1 */ - if (DBG_FOPS) { - xhfc_info(b4, "%sonfiguring hardware HDLC on %s\n", - ((sigtype == DAHDI_SIG_HARDHDLC) ? "C" : - "Unc"), chan->name); - } - bspan->sigchan = chan; - atomic_set(&bspan->hdlc_pending, 0); + if (DBG_FOPS) + printk(KERN_INFO DRIVER_NAME + ": Configuring hardware HDLC on %s\n", + chan->name); + xhfc_span->sigchan = chan; + atomic_set(&xhfc_span->hdlc_pending, 0); res = 0; break; case DAHDI_SIG_HDLCFCS: - xhfc_info(b4, "HDLCFCS not supported\n"); + printk(KERN_INFO DRIVER_NAME ": HDLCFCS not supported\n"); res = -ENOSYS; break; case DAHDI_SIG_HDLCNET: - xhfc_info(b4, "HDLCNET not supported\n"); + printk(KERN_INFO DRIVER_NAME ": HDLCNET not supported\n"); res = -ENOSYS; break; case DAHDI_SIG_HDLCRAW: - xhfc_info(b4, "HDLCRAW not supported\n"); + printk(KERN_INFO DRIVER_NAME ": HDLCRAW not supported\n"); res = -ENOSYS; break; default: @@ -838,18 +839,33 @@ static int xhfc_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long d return -ENOTTY; } -/************************************************************************ - * Responsible for initializing the xhfc_span and dahdi_span structures * - ************************************************************************/ +static int xhfc_span_startup(struct dahdi_span* s) +{ + struct xhfc_span *xhfc_span = container_of(s, struct xhfc_span, span); + activate_request(xhfc_span); + return 0; +} + +static int xhfc_span_shutdown(struct dahdi_span* s) +{ + struct xhfc_span *xhfc_span = container_of(s, struct xhfc_span, span); + deactivate_request(xhfc_span); + return 0; +} + static const struct dahdi_span_ops xhfc_span_ops = { .owner = THIS_MODULE, .spanconfig = xhfc_spanconfig, .chanconfig = xhfc_chanconfig, + .startup = xhfc_span_startup, + .shutdown = xhfc_span_shutdown, .ioctl = xhfc_ioctl, .hdlc_hard_xmit = xhfc_hdlc_hard_xmit, }; - +/************************************************************************ + * Responsible for initializing the xhfc_span and dahdi_span structures * + ************************************************************************/ void init_spans(struct xhfc* x) { int i, j; @@ -858,7 +874,7 @@ void init_spans(struct xhfc* x) struct dahdi_chan *chan; /* for each span on the card */ - for (i=0; i < SPANS_PER_CHIP; i++) { + for (i = 0; i < SPANS_PER_CHIP; i++) { xhfc_span = &x->spans[i]; dahdi_span = &xhfc_span->span; @@ -869,8 +885,6 @@ void init_spans(struct xhfc* x) xhfc_span->sigchan = NULL; /* conf'd in chanconfig (xref1) */ xhfc_span_set_ntte(xhfc_span, ntte & (1 << i)); /* reconf'd in spanconfig (xref2) */ - xhfc_span->newalarm = DAHDI_ALARM_RED; - /* All the timer stuff is done in the timer and state * functions, not here. */ @@ -886,7 +900,7 @@ void init_spans(struct xhfc* x) DAHDI_CONFIG_AMI | DAHDI_CONFIG_CCS ; sprintf(dahdi_span->name, "XHFC/%d", i+1); - sprintf(dahdi_span->desc, "XHFC Span %d", i+1); + sprintf(dahdi_span->desc, "XHFC port %d", i+1); dahdi_span->manufacturer = "Avencall"; dahdi_copy_string(dahdi_span->devicetype, "XHFC-4SU", sizeof(dahdi_span->devicetype)); @@ -894,6 +908,8 @@ void init_spans(struct xhfc* x) x->pi->pci_dev->bus->number, PCI_SLOT(x->pi->pci_dev->devfn) + 1); + dahdi_span->alarms = DAHDI_ALARM_RED; + init_waitqueue_head(&dahdi_span->maintq); /* kinda everyone does this */ @@ -934,7 +950,7 @@ static struct pci_driver xhfc_driver = { .id_table = tlp_leb_pci_tbl, .probe = xhfc_init_one, .remove = __devexit_p(xhfc_remove_one), - .shutdown = xhfc_shutdown, +// .shutdown = xhfc_shutdown, }; /* pci.txt: called from process context */ @@ -946,7 +962,7 @@ int __devinit xhfc_init_one(struct pci_dev *pdev, unsigned long base, size; int rc = -ENOMEM; - printk(KERN_DEBUG "entering xhfc_init_one.\n"); + printk(KERN_DEBUG "entering xhfc_init_one\n"); /**************** @@ -973,7 +989,7 @@ int __devinit xhfc_init_one(struct pci_dev *pdev, if (rc) goto err_enable_device; - printk(KERN_DEBUG "pci_enable_device succeeded.\n"); + printk(KERN_DEBUG "pci_enable_device succeeded\n"); rc = pci_request_regions(pdev, DRIVER_NAME); if (rc) @@ -1030,7 +1046,6 @@ int __devinit xhfc_init_one(struct pci_dev *pdev, pi->xhfc.pi = pi; /* only adress one xhfc per PI */ - pi->xhfc.chipidx = 0; pi->xhfc.name = pi->name; /* init interrupt engine */ @@ -1077,7 +1092,7 @@ int __devinit xhfc_init_one(struct pci_dev *pdev, for (span = 0; span < SPANS_PER_CHIP; span++) if ((rc = dahdi_register(&pi->xhfc.spans[span].span, /*prefmaster*/ 1)) < 0) { - printk(KERN_WARNING "%s %s: couldn't register spans.\n", pi->name, __func__); + printk(KERN_WARNING "%s %s: couldn't register spans\n", pi->name, __func__); goto err_in_dahdi_register; } @@ -1148,13 +1163,7 @@ void __devexit xhfc_remove_one(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); kfree(pi); - printk(KERN_DEBUG "%s: bye-bye.\n", __func__); -} - -void xhfc_shutdown(struct pci_dev *pdev) -{ - if (DBG) - printk(KERN_DEBUG "%s: Au revoir.\n", __func__); + printk(KERN_DEBUG "%s: bye-bye\n", __func__); } /***************/ diff --git a/xhfc/xhfc.h b/xhfc/xhfc.h index 801c81b..aadb566 100644 --- a/xhfc/xhfc.h +++ b/xhfc/xhfc.h @@ -37,8 +37,6 @@ #define XHFC_FMIN 0x00 #define XHFC_FMAX 0x07 -enum { XHFC_T1, XHFC_T2, XHFC_T3, XHFC_T4 }; - #if (DAHDI_CHUNKSIZE != 8) #error Sorry, the XHFC driver module does not support chunksize != 8 #endif @@ -71,10 +69,9 @@ enum { XHFC_T1, XHFC_T2, XHFC_T3, XHFC_T4 }; #define DBG_ALARM (debug & DEBUG_ALARM) #define DBG_TIMING (debug & DEBUG_TIMING) -#define DBG_SPANFILTER ((1 << xhfc_span->port) & dbg_spanfilter) +#define DBG_SPAN(xhfc_span) ((1 << xhfc_span->port) & dbg_spanfilter) #define CORRUPTED_FRAME (-1) -#define USE_FIFO_IRQ 0 #define HDLC_BUF_LEN 128 /* "arbitrary", or so say DAHDI's drivers */ @@ -85,6 +82,11 @@ enum { XHFC_T1, XHFC_T2, XHFC_T3, XHFC_T4 }; # define MIN(a, b) (((a) < (b))? (a) : (b)) #endif +#define V_SU_ACT_ACTIVATE 3 +#define V_SU_ACT_DEACTIVATE 2 + +#define NOT_RUNNING 0 /* timer not running */ + enum data_dir { TRANSMIT = 0, RECEIVE = 1 }; #define xhfc_info(x, format, arg...) \ @@ -114,31 +116,26 @@ struct xhfc_span { int port; /* (physical) S/T port number */ int nt; /* 1 if the port is nt, 0 if it's TE */ + /* Got the following from DAHDI */ - int oldstate; - int newalarm; - unsigned long alarmtimer; + u8 state, prev_state; + struct dahdi_chan* sigchan; int sigactive; - unsigned long hfc_timers[4]; /* T1, T2, T3, T4 */ - int hfc_timer_on[4]; /* 1=timer active */ + unsigned long activation_timer, f6_f7_transition; // timers; 0 when deactivated unsigned long non_rx_cnt; }; struct xhfc { char *name; - __u8 chipidx; /* index in pi->xhfcs[NUM_XHFCS] */ struct xhfc_pi *pi; /* backpointer to xhfc_pi */ struct xhfc_span spans[SPANS_PER_CHIP]; - /* from DAHDI */ - int running; - unsigned long ticks; - int setsyncspan; /* Span reported from HFC for sync on this card */ - int reportedsyncspan; /* Span reported from HFC for sync on this card */ + int running; + unsigned long ticks; }; struct xhfc_pi { @@ -156,7 +153,8 @@ struct xhfc_pi { #endif }; -#define dchan_fifo(span) (span->port * 4 + 2) +#define dchan_fifo(span) ((span)->port * 4 + 2) +#define portno(span) ((span)->port + 1) /* used for traces */ void xhfc_flush_fifo(struct xhfc* x, int fifo); int xhfc_hdlc_init(struct xhfc* x); @@ -169,9 +167,11 @@ int xhfc_reset(struct xhfc * xhfc); int xhfc_chipid(struct xhfc * xhfc); int xhfc_cfg_pcm(struct xhfc * xhfc, __u8 pcm); -void hfc_handle_state(struct xhfc_span *s); -void hfc_update_st_timers(struct xhfc *x); -void hfc_start_st(struct xhfc_span *s); +void start_state_machine(struct xhfc_span* s); +void activate_request(struct xhfc_span* s); +void deactivate_request(struct xhfc_span* s); +void handle_state_change(struct xhfc_span* s); +void handle_st_timers(struct xhfc_span* s); int __devinit xhfc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); void __devexit xhfc_remove_one(struct pci_dev *pdev); diff --git a/xhfc/xhfc_st_state.c b/xhfc/xhfc_st_state.c new file mode 100644 index 0000000..dfa9897 --- /dev/null +++ b/xhfc/xhfc_st_state.c @@ -0,0 +1,353 @@ +#include <linux/delay.h> +#include <linux/timer.h> + +#include "xhfc.h" +#include "xhfc_leb.h" + +/* Software-implemented timers for the S/T state machine, in milliseconds */ +#define T1_MS 100 /* NT activation timer. + 100..1000ms according to Cologne/ETSI TBR4 (??) + 100ms in Cologne's mISDN driver. */ +#define T3_MS 30000 /* TE activation timer. + according to I.430 "the value depends on the + subscriber loop transmission technique. The worst + case value is 30s." + XXX in DAHDI's mess, this was 500ms on the first + time, and then the worst-case value of 30s, which I + guess makes sense. Try to see if any document says + to do that and maybe do the same here? Can't seem to + understand how mISDN handles the matter. */ +#define F6_F7_MS 2 /* Wait before signalling the change to F7. + This is done because the XHFC might go to F7 + for a short time during a F6->F3 transition when + receiving INFO0. The wait time should be + "about 1ms", this set to 2 to guarantee that the + wait will be long enough. */ + +enum te_state { F0, F1, F2, F3, F4, F5, F6, F7, F8 }; +enum nt_state { G0, G1, G2, G3, G4 }; + +static void activation_timer_expiry(struct xhfc_span* s); +static void signal_f7_transition(struct xhfc_span* s); + +static void handle_state_change_nt(struct xhfc_span* s); +static void handle_state_change_te(struct xhfc_span* s); + +static void allow_G2_G3_transition(struct xhfc_span* s); + +static void print_state(struct xhfc_span* s); + +void start_state_machine(struct xhfc_span* s) +{ + u8 a_su_wr_sta = 0; + + SET_V_SU_LD_STA(a_su_wr_sta, 0); + + write_xhfc(s->xhfc, R_SU_SEL, s->port); + write_xhfc(s->xhfc, A_SU_WR_STA, 0); +} + +void activate_request(struct xhfc_span* s) +{ + u8 a_su_wr_sta = 0; + int sta = GET_V_SU_STA(s->state); + + int impossible_te = !s->nt && + (sta == F2 || sta == F4 || sta == F5 || sta == F5); + int impossible_nt = s->nt && + (sta == G2 || sta == G3); + int no_action_te = !s->nt && + (sta == F0 || sta == F6 || sta == F8); + + if (impossible_te || impossible_nt) { + printk(KERN_INFO DRIVER_NAME ": " + "activate impossible by definition of layer 1" + " in state %c%d on port %d\n", + (s->nt ? 'G' : 'F'), sta, portno(s)); + return; + } else if (no_action_te) { + if(DBG_ST && DBG_SPAN(s)) + printk(KERN_INFO DRIVER_NAME ": " + "no action for activate " + "in state %c%d on port %d\n", + (s->nt ? 'G' : 'F'), sta, portno(s)); + return; + } + + if (DBG_ST && DBG_SPAN(s)) + printk(KERN_DEBUG DRIVER_NAME + ": activate on port %d\n", + portno(s)); + + + SET_V_SU_ACT(a_su_wr_sta, V_SU_ACT_ACTIVATE); + + write_xhfc(s->xhfc, R_SU_SEL, s->port); + write_xhfc(s->xhfc, A_SU_WR_STA, a_su_wr_sta); + + if (!s->nt && sta == F3 && GET_V_SU_INFO0(s->state)) + s->activation_timer = s->xhfc->ticks + T3_MS; /* xref5 */ + else + s->activation_timer = NOT_RUNNING; + /* timer for NT activated by state change handler (xref3) */ +} + +void deactivate_request(struct xhfc_span* s) +{ + u8 a_su_wr_sta = 0; + int sta = GET_V_SU_STA(s->state); + + if (!s->nt || (s->nt && (sta == G1 || sta == G4))) { + printk(KERN_INFO DRIVER_NAME ": " + "deactivate impossible by definition of layer 1" + " in state %c%d on port %d\n", + (s->nt ? 'G' : 'F'), sta, portno(s)); + return; + } + + if(DBG_ST && DBG_SPAN(s)) + printk(KERN_DEBUG DRIVER_NAME + ": deactivate on port %d\n", + portno(s)); + + SET_V_SU_ACT(a_su_wr_sta, V_SU_ACT_DEACTIVATE); + + write_xhfc(s->xhfc, R_SU_SEL, s->port); + write_xhfc(s->xhfc, A_SU_WR_STA, a_su_wr_sta); + + if(s->nt && (sta == G2 || sta == G3)) + s->activation_timer = NOT_RUNNING; +} + +/* This function is meant to be ran each time an interface changes state; + * however, the state change is polled (during the timer interrupt; see + * enable_interrupts and xhfc_interrupt). Therefore, it is possible that + * two or more state changes happen on the same interface between two + * interruptions and that this functions gets only called once. + * Additionally, even when using the ST state change interrupt, an interruption + * can still be overlooked and lead to one of these conditions. + * + * However, there is no notable consequence because the actions are either: + * + * - Starting timers: + * - T3 is only started after an activation request, therefore we always now + * when T3 has to start (xref5) + * - T1 is only started when going to state G2, which can only yield G3 + * automatically. This can be disallowed in V_G2_G3_EN so that the timer + * can be started before allowing the transition with V_SU_SET_G2_G3. + * (xref6) + * - Stopping timers: + * - T1 is only stopped on G2->G3. + * From G3: + * - G3->G2: if the timer is already running, stop it (xref4) + * - on deactivate requests stop the timer + * - T3 is stopped on going to state F7. I don't think it's possible to + * guarantee this; however except F2->F7 which can not happen when T3 is + * running, every transition to F7 stops the timer, so there is no incoherent + * behaviour; + * - Changing alarms in DAHDI, which will be done anyway. No point notifying + * something that lasts less that 1ms. + */ +void handle_state_change(struct xhfc_span* s) +{ + struct xhfc* x = s->xhfc; + + s->prev_state = s->state; + + write_xhfc(x, R_SU_SEL, s->port); + s->state = read_xhfc(x, A_SU_RD_STA); + + if(DBG_ST && DBG_SPAN(s)) + print_state(s); + + if(unlikely(s->prev_state == s->state)) { + printk(KERN_WARNING DRIVER_NAME ": a state change has been " + "reported on port %d but it looks like the " + "state has not changed?\n", portno(s)); + return; + } + + if(s->nt) + handle_state_change_nt(s); + else + handle_state_change_te(s); +} + +static void handle_state_change_nt(struct xhfc_span* s) +{ + switch (GET_V_SU_STA(s->state)) { + case G0: + case G1: + case G4: + s->span.alarms = DAHDI_ALARM_RED; + break; + case G2: + s->span.alarms = DAHDI_ALARM_YELLOW; + if(s->activation_timer) + s->activation_timer = NOT_RUNNING; /* xref4 */ + else { + /* xref3, this should happen only if the + * previous state is not G3 */ + s->activation_timer = s->xhfc->ticks + T1_MS; + allow_G2_G3_transition(s); /* xref6 */ + } + + break; + case G3: + s->span.alarms = DAHDI_ALARM_NONE; + + s->activation_timer = NOT_RUNNING; + break; + } +} + +static void handle_state_change_te(struct xhfc_span* s) +{ + int sta = GET_V_SU_STA(s->state); + + if (sta != F7) + s->f6_f7_transition = NOT_RUNNING; + + switch(sta) { + case F0: + case F1: + case F2: + case F3: + case F4: + case F8: + s->span.alarms = DAHDI_ALARM_RED; + break; + case F5: + case F6: + s->span.alarms = DAHDI_ALARM_YELLOW; + break; + case F7: + s->activation_timer = NOT_RUNNING; + + if ( GET_V_SU_STA(s->prev_state) == F6 && + GET_V_SU_INFO0(s->state)) { + s->f6_f7_transition = s->xhfc->ticks + T1_MS; + break; + } + + signal_f7_transition(s); + + break; + } +} + +void handle_st_timers(struct xhfc_span* s) +{ + struct xhfc* x = s->xhfc; + + if(unlikely(s->activation_timer && s->activation_timer <= x->ticks)) + activation_timer_expiry(s); + if(unlikely(s->f6_f7_transition && s->f6_f7_transition <= x->ticks)) + signal_f7_transition(s); +} + +static void signal_f7_transition(struct xhfc_span* s) +{ + if(DBG_ST && DBG_SPAN(s)) + printk(KERN_DEBUG DRIVER_NAME ": signalling transition to F7 " + "on port %d\n", portno(s)); + + s->span.alarms = DAHDI_ALARM_NONE; + s->f6_f7_transition = NOT_RUNNING; +} + +static void activation_timer_expiry(struct xhfc_span* s) +{ + int sta = GET_V_SU_STA(s->state); + + int t1_expiry = s->nt && sta == G2; + int t3_expiry = !s->nt && (sta == F4 || sta == F5 || sta == F8); + + if(DBG_ST && DBG_SPAN(s)) + printk(KERN_INFO DRIVER_NAME + ": %s%s activation timeout" + " in state %c%d on port %d\n", + t1_expiry || t3_expiry ? "" : "no action for ", + s->nt ? "NT" : "TE", + s->nt ? 'G' : 'F', + sta, portno(s)); + + s->activation_timer = NOT_RUNNING; + + if (t1_expiry || t3_expiry) + deactivate_request(s); +} + +static void allow_G2_G3_transition(struct xhfc_span* s) +{ + u8 a_su_wr_sta = 0; + + SET_V_SU_SET_G2_G3(a_su_wr_sta, 1); + + write_xhfc(s->xhfc, R_SU_SEL, s->port); + write_xhfc(s->xhfc, A_SU_WR_STA, a_su_wr_sta); + + /* The bit is automatically cleared on G2->G3. G2->G4 is always + * triggered by using activate_request which clears this bit. Therefore + * this bit is always cleared correctly when exiting G2. */ +} + +static char *state_description[2][16] = { + { /* TE */ + /* F0 */ "reset", + /* F1 */ "inactive", + /* F2 */ "sensing", + /* F3 */ "deactivate", + /* F4 */ "awaiting signal", + /* F5 */ "identifying input", + /* F6 */ "synchronized", + /* F7 */ "activated", + /* F8 */ "lost framing", + "?", "?", "?", "?", "?", "?", "?" }, + { /* NT */ + /* G0 */ "reset", + /* G1 */ "deactivated", + /* G2 */ "pending activation", + /* G3 */ "active", + /* G4 */ "pending deactivation", + "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?" }}; + +static void print_state(struct xhfc_span* s) +{ + int sta = GET_V_SU_STA(s->state); + printk(KERN_DEBUG DRIVER_NAME ": port %d: %s state %c%d (%s)\n", + portno(s), + (s->nt ? "NT" : "TE"), + (s->nt ? 'G' : 'F'), + sta, + state_description[s->nt][sta]); +} + +#if 0 +/* This is not used right now, but it could be in the future */ +static void set_st_state(struct xhfc_span* s, int state) +{ + u8 a_su_wr_sta = 0; + + s->prev_state = s->state; + s->state = state; + + if(DBG_ST && DBG_SPAN(s)) { + printk(KERN_DEBUG DRIVER_NAME "port %d: " + "Forcing state change:\n", s->port +1); + print_state(s); + } + + SET_V_SU_SET_STA(a_su_wr_sta, state); + SET_V_SU_LD_STA(a_su_wr_sta, 1); + + write_xhfc(s->xhfc, R_SU_SEL, s->port); + write_xhfc(s->xhfc, A_SU_WR_STA, a_su_wr_sta); + + udelay(6); + + SET_V_SU_LD_STA(a_su_wr_sta, 0); + write_xhfc(s->xhfc, R_SU_SEL, s->port); /* just in case. (XXX?) */ + write_xhfc(s->xhfc, A_SU_WR_STA, a_su_wr_sta); +} +#endif diff --git a/xhfc/xhfc_timers_state.c b/xhfc/xhfc_timers_state.c deleted file mode 100644 index 7f59488..0000000 --- a/xhfc/xhfc_timers_state.c +++ /dev/null @@ -1,375 +0,0 @@ -#include <linux/delay.h> -#include <linux/timer.h> - -#include "xhfc.h" -#include "xhfc_leb.h" - -/***************************** - * Timers and state handling * - * (from DAHDI) * - *****************************/ - -#define bri_persistentlayer1 1 /* ??? No idea what this is and it's supposed - to do. - DAHDI says: Set to 0 for disabling - automatic layer 1 reactivation (when other - end deactivates it) */ -#define bri_teignorered 1 /* 1=ignore (do not inform DAHDI) if a red - alarm exists in TE mode */ -#define bri_alarmdebounce 0 /* msec to wait before set/clear alarm - condition */ - -#define TIMER_3_MS 30000 - -/* - * allocates memory and pretty-prints a given S/T state engine state to it. - * calling routine is responsible for freeing the pointer returned! Performs - * no hardware access whatsoever, but does use GFP_KERNEL so do not call from - * IRQ context. if full == 1, prints a "full" dump; otherwise just prints - * current state. - */ -static char *hfc_decode_st_state(struct xhfc *x, struct xhfc_span *span, - int state, int full) -{ - int nt, sta; - char s[128], *str; - const char *ststr[2][16] = { /* TE, NT */ - { "RESET", "?", "SENSING", "DEACT.", - "AWAIT.SIG", "IDENT.INPUT", "SYNCD", "ACTIVATED", - "LOSTFRAMING", "?", "?", "?", - "?", "?", "?", "?" }, - { "RESET", "DEACT.", "PEND.ACT", "ACTIVE", - "PEND.DEACT", "?", "?", "?", - "?", "?", "?", "?", - "?", "?", "?", "?" } - }; - - str = kmalloc(256, GFP_KERNEL); - if (!str) { - dev_warn(&x->pi->pci_dev->dev, - "could not allocate mem for ST state decode " \ - "string!\n"); - return NULL; - } - - nt = span->nt; - sta = GET_V_SU_STA(state); - - sprintf(str, "P%d: %s state %c%d (%s)", span->port + 1, - (nt ? "NT" : "TE"), (nt ? 'G' : 'F'), sta, - ststr[nt][sta]); - - if (full) { - sprintf(s, " SYNC: %s, RX INFO0: %s", - (GET_V_SU_FR_SYNC(state) ? "yes" : "no"), - (GET_V_SU_INFO0(state) ? "yes" : "no")); - strcat(str, s); - - if (nt) { - sprintf(s, ", T2 %s, auto G2->G3: %s", - (GET_V_SU_T2_EXP(state) ? "expired" : "OK"), - (GET_V_G2_G3(state) ? "yes" : "no")); - strcat(str, s); - } - } - - return str; -} - -static void hfc_stop_all_timers(struct xhfc_span *s); -#define V_SU_ACT_DEACTIVATE 2 -#define V_SU_ACT_ACTIVATE 3 -static void hfc_stop_st(struct xhfc_span *s) -{ - u8 a_su_wr_sta = 0x00; - struct xhfc *xhfc = s->xhfc; - - hfc_stop_all_timers(s); - - write_xhfc(xhfc, R_SU_SEL, s->port); - write_xhfc(xhfc, A_SU_WR_STA, - SET_V_SU_ACT(a_su_wr_sta, V_SU_ACT_DEACTIVATE)); -} - -void hfc_start_st(struct xhfc_span *s) -{ - u8 a_su_wr_sta = 0x00; - struct xhfc *xhfc = s->xhfc; - - write_xhfc(xhfc, R_SU_SEL, s->port); - write_xhfc(xhfc, A_SU_WR_STA, - SET_V_SU_ACT(a_su_wr_sta, V_SU_ACT_ACTIVATE)); - - /* start T1 if in NT mode, T3 if in TE mode */ - if (s->nt) { - static const int TIMER_1_MS = 1000; - s->hfc_timers[XHFC_T1] = xhfc->ticks + TIMER_1_MS; - s->hfc_timer_on[XHFC_T1] = 1; - s->hfc_timer_on[XHFC_T3] = 0; - if (DBG_ST) { - xhfc_info(xhfc, "setting port %d t1 timer to %lu\n", - s->port + 1, s->hfc_timers[XHFC_T1]); - } - } else { - /* 500ms wait first time, TIMER_3_MS afterward. */ - s->hfc_timers[XHFC_T3] = xhfc->ticks + TIMER_3_MS; - s->hfc_timer_on[XHFC_T3] = 1; - s->hfc_timer_on[XHFC_T1] = 0; - - s->hfc_timers[XHFC_T4] = xhfc->ticks + 1000; - s->hfc_timer_on[XHFC_T4] = 1; - - if (DBG_ST) { - xhfc_info(xhfc, "setting port %d t3 timer to %lu\n", - s->port + 1, s->hfc_timers[XHFC_T3]); - } - } -} - -/* - * sets an S/T port state machine to a given state. - * if 'auto' is nonzero, will put the state machine back in auto mode after setting the state. - */ -void hfc_handle_state(struct xhfc_span *s); - -static void hfc_force_st_state(struct xhfc *x, struct xhfc_span *s, - int state, int resume_auto) -{ - u8 r_su_sel = 0x00, a_su_wr_sta = 0x00; - write_xhfc(x, R_SU_SEL, SET_V_SU_SEL(r_su_sel, s->port)); - - SET_V_SU_LD_STA(a_su_wr_sta, 1); - SET_V_SU_SET_STA(a_su_wr_sta, state); - write_xhfc(x, A_SU_WR_STA, a_su_wr_sta); - - if (resume_auto) { - write_xhfc(x, R_SU_SEL, r_su_sel); - write_xhfc(x, A_SU_WR_STA, SET_V_SU_LD_STA(a_su_wr_sta, 0)); - } - - if (DBG_ST && ((1 << s->port) & dbg_spanfilter)) { - char *str; - - str = hfc_decode_st_state(x, s, state, 1); - xhfc_info(x, "forced port %d to state %d (auto: %d), " - "new decode: %s\n", s->port + 1, state, - resume_auto, str); - kfree(str); - } - - /* make sure that we activate any timers/etc needed by this state - * change */ - hfc_handle_state(s); -} - -/* figures out what to do when an S/T port's timer expires. */ -static void hfc_timer_expire(struct xhfc_span *s, int t_no) -{ - struct xhfc *x = s->xhfc; - - if (DBG_ST && ((1 << s->port) & dbg_spanfilter)) { - xhfc_info(x, "%lu: hfc_timer_expire, Port %d T%d " - "expired (value=%lu ena=%d)\n", x->ticks, - s->port + 1, t_no + 1, s->hfc_timers[t_no], - s->hfc_timer_on[t_no]); - } - /* - * there are three timers associated with every HFC S/T port. - * - * T1 is used by the NT state machine, and is the maximum time the NT - * side should wait for G3 (active) state. - * - * T2 is not actually used in the driver, it is handled by the HFC-4S - * internally. - * - * T3 is used by the TE state machine; it is the maximum time the TE - * side should wait for the INFO4 (activated) signal. - */ - - /* First, disable the expired timer; hfc_force_st_state() may activate - * it again. */ - s->hfc_timer_on[t_no] = 0; - - switch (t_no) { - case XHFC_T1: /* switch to G4 (pending deact.), resume auto mode */ - hfc_force_st_state(x, s, 4, 1); - break; - case XHFC_T2: /* switch to G1 (deactivated), resume auto mode */ - hfc_force_st_state(x, s, 1, 1); - break; - case XHFC_T3: /* switch to F3 (deactivated), resume auto mode */ - hfc_stop_st(s); - if (bri_persistentlayer1) - hfc_start_st(s); - break; - case XHFC_T4: /* switch to F3 (deactivated), resume auto mode */ - hfc_handle_state(s); - s->hfc_timers[XHFC_T4] = x->ticks + 1000; - s->hfc_timer_on[XHFC_T4] = 1; - break; - default: - if (printk_ratelimit()) { - dev_warn(&x->pi->pci_dev->dev, - "hfc_timer_expire found an unknown expired " - "timer (%d)??\n", t_no); - } - } -} - -/* - * Run through the active timers on a card and deal with any expiries. - * Also see if the alarm debounce time has expired and if it has, tell DAHDI. - */ -void hfc_update_st_timers(struct xhfc *x) -{ - int i, j; - struct xhfc_span *s; - - for (i = 0; i < 4; i++) { - s = &x->spans[i]; - - for (j = XHFC_T1; j <= XHFC_T4; j++) { - - /* we don't really do timer2, it is expired by the - * state change handler */ - if (j == XHFC_T2) - continue; - - if (s->hfc_timer_on[j] && - time_after_eq(x->ticks, s->hfc_timers[j])) - hfc_timer_expire(s, j); - } - - if (s->newalarm != s->span.alarms && - time_after_eq(x->ticks, s->alarmtimer)) { - s->span.alarms = s->newalarm; - if ((!s->newalarm && bri_teignorered) || (!bri_teignorered)) - dahdi_alarm_notify(&s->span); - - if (DBG_ALARM) { - dev_info(&x->pi->pci_dev->dev, "span %d: alarm " \ - "%d debounced\n", i + 1, - s->newalarm); - } - } - } -} - -/* this is the driver-level state machine for an S/T port */ -void hfc_handle_state(struct xhfc_span *s) -{ - struct xhfc *x; - unsigned char state, sta; - int nt, newsync, oldalarm; - unsigned long oldtimer; - - x = s->xhfc; - nt = s->nt; - - write_xhfc(x, R_SU_SEL, s->port); - state = read_xhfc(x, A_SU_RD_STA); - sta = GET_V_SU_STA(state); - - if (DBG_ST && ((1 << s->port) & dbg_spanfilter) /* && s->oldstate != state <--- WHAT IS THIS STUFF COMMENTED OUT??? */) { - char *str; - - str = hfc_decode_st_state(x, s, state, 1); - xhfc_info(x, "port %d A_SU_RD_STA old=0x%02x " - "now=0x%02x, decoded: %s\n", s->port + 1, - s->oldstate, state, str); - kfree(str); - } - - oldalarm = s->newalarm; - oldtimer = s->alarmtimer; - - if (nt) { - switch (sta) { - default: /* Invalid NT state */ - case 0x0: /* NT state G0: Reset */ - case 0x1: /* NT state G1: Deactivated */ - case 0x4: /* NT state G4: Pending Deactivation */ - s->newalarm = DAHDI_ALARM_RED; - break; - case 0x2: /* NT state G2: Pending Activation */ - s->newalarm = DAHDI_ALARM_YELLOW; - break; - case 0x3: /* NT state G3: Active */ - s->hfc_timer_on[XHFC_T1] = 0; - s->newalarm = 0; - break; - } - } else { - switch (sta) { - default: /* Invalid TE state */ - case 0x0: /* TE state F0: Reset */ - case 0x2: /* TE state F2: Sensing */ - case 0x3: /* TE state F3: Deactivated */ - case 0x4: /* TE state F4: Awaiting Signal */ - case 0x8: /* TE state F8: Lost Framing */ - s->newalarm = DAHDI_ALARM_RED; - break; - case 0x5: /* TE state F5: Identifying Input */ - case 0x6: /* TE state F6: Synchronized */ - s->newalarm = DAHDI_ALARM_YELLOW; - break; - case 0x7: /* TE state F7: Activated */ - s->hfc_timer_on[XHFC_T3] = 0; - s->hfc_timer_on[XHFC_T4] = 0; - s->newalarm = 0; - break; - } - } - - s->alarmtimer = x->ticks + bri_alarmdebounce; - s->oldstate = state; - - if (DBG_ALARM && ((1 << s->port) & dbg_spanfilter) /*&& oldalarm != s->newalarm */) { - xhfc_info(x, "span %d: old alarm %d expires %ld, " - "new alarm %d expires %ld\n", s->port + 1, oldalarm, - oldtimer, s->newalarm, s->alarmtimer); - } - - /* we only care about T2 expiry in G4. */ - if (nt && (sta == 4) && GET_V_SU_T2_EXP(state)) { - if (s->hfc_timer_on[XHFC_T2]) - hfc_timer_expire(s, XHFC_T2); /* handle T2 expiry */ - } - - /* If we're in F3 and receiving INFO0, start T3 and jump to F4 */ - if (!nt && (sta == 3) && GET_V_SU_INFO0(state)) { - if (bri_persistentlayer1) { - s->hfc_timers[XHFC_T3] = x->ticks + TIMER_3_MS; - s->hfc_timer_on[XHFC_T3] = 1; - if (DBG_ST) { - xhfc_info(x, "port %d: receiving " - "INFO0 in state 3, setting T3 and " - "jumping to F4\n", s->port + 1); - } - hfc_start_st(s); - } - } - - /* read in R_BERT_STA to determine where our current sync source is */ - newsync = GET_V_RD_SYNC_SRC(read_xhfc(x, R_BERT_STA)); - if (newsync != x->reportedsyncspan) { - if (DBG_TIMING) { - if (newsync == 5) { - xhfc_info(x, "new card sync source: SYNC_I\n"); - } else { - xhfc_info(x, "new sync source: port %d\n", - newsync); - } - } - - x->reportedsyncspan = newsync; - } -} - -static void hfc_stop_all_timers(struct xhfc_span *s) -{ - s->hfc_timer_on[XHFC_T4] = 0; - s->hfc_timer_on[XHFC_T3] = 0; - s->hfc_timer_on[XHFC_T2] = 0; - s->hfc_timer_on[XHFC_T1] = 0; -} |