summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNoe Rubinstein <nrubinstein@proformatique.com>2010-12-09 18:32:46 +0100
committerNoe Rubinstein <nrubinstein@proformatique.com>2010-12-09 18:32:46 +0100
commit3ac1d0d7ca9901e2024daffeb4a05dea99136104 (patch)
tree02df60f31fe3827a8fb5417d3850b815aebf282a
parent820d1a2d16b4dd267fd4a3e881d17e78679636cb (diff)
parentf8dbef0ea7d8d2949956c24b2c392837a264480f (diff)
Merge branch 'st-state-rewrite'
-rw-r--r--xhfc/Makefile2
-rw-r--r--xhfc/TODO2
-rw-r--r--xhfc/xhfc.c315
-rw-r--r--xhfc/xhfc.h38
-rw-r--r--xhfc/xhfc_st_state.c353
-rw-r--r--xhfc/xhfc_timers_state.c375
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:
diff --git a/xhfc/TODO b/xhfc/TODO
index c20f80b..8706110 100644
--- a/xhfc/TODO
+++ b/xhfc/TODO
@@ -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;
-}