diff options
author | Noe Rubinstein <nrubinstein@proformatique.com> | 2010-11-04 18:57:02 +0100 |
---|---|---|
committer | Noe Rubinstein <nrubinstein@proformatique.com> | 2010-11-04 19:08:01 +0100 |
commit | dbb36f23299b01dc54d5145aa51a971ced62842b (patch) | |
tree | beb0ac2f7f819aae3e1a03f5a860a549abd3f1fc /xhfc | |
parent | 1512ecac55bd47d0af37953baa27cfdc3c99aa3f (diff) |
start rewriting software part of ST state machine
Diffstat (limited to 'xhfc')
-rw-r--r-- | xhfc/xhfc.h | 1 | ||||
-rw-r--r-- | xhfc/xhfc_st_state.c | 148 | ||||
-rw-r--r-- | xhfc/xhfc_timers_state.c | 375 |
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; -} |