summaryrefslogtreecommitdiff
path: root/xhfc
diff options
context:
space:
mode:
authorNoe Rubinstein <nrubinstein@proformatique.com>2010-11-04 18:57:02 +0100
committerNoe Rubinstein <nrubinstein@proformatique.com>2010-11-04 19:08:01 +0100
commitdbb36f23299b01dc54d5145aa51a971ced62842b (patch)
treebeb0ac2f7f819aae3e1a03f5a860a549abd3f1fc /xhfc
parent1512ecac55bd47d0af37953baa27cfdc3c99aa3f (diff)
start rewriting software part of ST state machine
Diffstat (limited to 'xhfc')
-rw-r--r--xhfc/xhfc.h1
-rw-r--r--xhfc/xhfc_st_state.c148
-rw-r--r--xhfc/xhfc_timers_state.c375
3 files changed, 149 insertions, 375 deletions
diff --git a/xhfc/xhfc.h b/xhfc/xhfc.h
index 801c81b..793cf05 100644
--- a/xhfc/xhfc.h
+++ b/xhfc/xhfc.h
@@ -117,6 +117,7 @@ struct xhfc_span {
/* Got the following from DAHDI */
int oldstate;
+ int state, previous_state;
int newalarm;
unsigned long alarmtimer;
struct dahdi_chan* sigchan;
diff --git a/xhfc/xhfc_st_state.c b/xhfc/xhfc_st_state.c
new file mode 100644
index 0000000..f52425d
--- /dev/null
+++ b/xhfc/xhfc_st_state.c
@@ -0,0 +1,148 @@
+#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." */
+
+enum te_state { F0, F1, F2, F3, F4, F5, F6, F7, F8 };
+enum nt_state { G0, G1, G2, G3 };
+
+void activate_request(struct xhfc_span* s);
+void deactivate_request(struct xhfc_span* s);
+void handle_state_change(struct xhfc_span* s);
+
+static void expiry_T1(struct xhfc_span* s);
+static void expiry_T3(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 activate_request_nt(struct xhfc_span* s);
+static void activate_request_te(struct xhfc_span* s);
+
+static void print_current_state(struct xhfc_span* s);
+
+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(debug & DEBUG_ST_STATE) //XXX only place where this is used
+ print_state(s);
+
+ if(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?", s->port + 1);
+ 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 (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->prev_state != G3)
+ /* Start T1 */ ;
+ break;
+ case G3:
+ s->span.alarms = DAHDI_ALARM_NONE;
+ /* Stop T1 */
+ break;
+ }
+}
+
+static void handle_state_change_te(struct xhfc_span* s)
+{
+ switch(s->state) {
+ case F0:
+ case F1:
+ case F2:
+ case F3:
+ case F8:
+ s->span.alarms = DAHDI_ALARM_RED;
+ break;
+ case F4:
+ /* XXX If in F3 and receiving INFO0, the state machine
+ * should change to F4 and start T3. Is the jump to F4
+ * done by the XHFC in hard, (in which case the timer
+ * T3 will be started by the software when detecting a
+ * change of state towards F4) or should it be driven
+ * by the soft (in which case upon detection of the
+ * reception of INFO0 in F3 state, the state would be
+ * set to F4 and T3 started)?
+ *
+ * Andrew did the latter, and I can't seem to get if
+ * and how mISDN handles this.
+ *
+ * Here, the former hypothesis (state change driven by
+ * hard) is assumed.
+ */
+
+ /* Start T3 */
+
+ /* Fall through */
+ case F5:
+ case F6:
+ s->span.alarms = DAHDI_ALARM_YELLOW;
+ break;
+ case F7:
+ s->span.alarms = DAHDI_ALARM_NONE;
+ /* Stop T3 */
+ break;
+
+}
+
+static char *state_descriptions[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)
+{
+ printk(KERN_DEBUG DRIVER_NAME "port %d: %s state %c%d (%s)\n",
+ s->port + 1,
+ (s->nt ? "NT" : "TE"),
+ (s->nt ? 'G' : 'F'),
+ s->state,
+ state_description[s->nt][s->state]);
+}
+
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;
-}