summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShaun Ruffell <sruffell@digium.com>2012-04-18 00:12:06 +0000
committerShaun Ruffell <sruffell@digium.com>2012-04-18 00:12:06 +0000
commit2b6dcd736553860158b345c1d0d741abeb097115 (patch)
tree769f540951c60abe8eb9262b8ebad97e1a459637
parent2ec923262d529e9c35b5335a4ba9cb414abfa245 (diff)
wcb4xxp: Support for when network side deactivates layer1.
This is a port of the functionality in the wctdm24xxp driver to support power savings modes. Specifically, if the the network side of a BRI spans deactivates the span to save power, the B410P previously automatically activated it again. Now, if persistentlayer1=0 module parameter is set, the span will be allowed to stay deactivated until layer two has a message to send on the dchannel. This patch does not change any of the default behavior of the B410P driver and the defaults for the persistentlayer1 option is inconsistent with that of the B400M modules in the wctdm24xxp driver. Internal-Issue-ID: ABE-2845 From: Matthew Fredrickson <creslin@digium.com> [ Minor formatting, exposed the persistentlayer1 as module parameter, changed defaults for teignorered, alarmdebounce, and persistentlayer1 to match current defaults in wcb4xxp driver ] Signed-off-by: Shaun Ruffell <sruffell@digium.com> git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@10661 a0bf4364-ded3-4de4-8d8a-66a801d63aff
-rw-r--r--drivers/dahdi/wcb4xxp/base.c108
-rw-r--r--drivers/dahdi/wcb4xxp/wcb4xxp.h5
2 files changed, 77 insertions, 36 deletions
diff --git a/drivers/dahdi/wcb4xxp/base.c b/drivers/dahdi/wcb4xxp/base.c
index 4935fe6..15c065c 100644
--- a/drivers/dahdi/wcb4xxp/base.c
+++ b/drivers/dahdi/wcb4xxp/base.c
@@ -90,6 +90,7 @@ static int milliwatt = 0;
static int pedanticpci = 0;
static int teignorered = 0;
static int alarmdebounce = 500;
+static int persistentlayer1 = 1;
static int vpmsupport = 1;
static int timer_1_ms = 2000;
static int timer_3_ms = 30000;
@@ -139,7 +140,7 @@ static struct devtype hfc8s_BN = {"BeroNet BN8S0", .ports = 8, .card_type = BN8S
static struct devtype hfc4s_SW = {"Swyx 4xS0 SX2 QuadBri", .ports = 4, .card_type = BSWYX_SX2 };
static struct devtype hfc4s_EV = {"CCD HFC-4S Eval. Board", .ports = 4,
.card_type = QUADBRI_EVAL };
-
+
#define CARD_HAS_EC(card) ((card)->card_type == B410P)
static void echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec);
@@ -1294,6 +1295,9 @@ static void hfc_force_st_state(struct b4xxp *b4, int port, int state, int resume
hfc_handle_state(&b4->spans[port]);
}
+static void hfc_stop_st(struct b4xxp_span *s);
+static void hfc_start_st(struct b4xxp_span *s);
+
/* figures out what to do when an S/T port's timer expires. */
static void hfc_timer_expire(struct b4xxp_span *s, int t_no)
{
@@ -1307,10 +1311,15 @@ static void hfc_timer_expire(struct b4xxp_span *s, int 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.
+ * There are four 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.
+ * T4 is a special timer used for debug purposes for monitoring of L1 state
+ * during activation attempt.
*/
/* First, disable the expired timer; hfc_force_st_state() may activate it again. */
@@ -1324,7 +1333,14 @@ static void hfc_timer_expire(struct b4xxp_span *s, int t_no)
hfc_force_st_state(b4, s->port, 1, 1);
break;
case HFC_T3: /* switch to F3 (deactivated), resume auto mode */
- hfc_force_st_state(b4, s->port, 3, 1);
+ hfc_stop_st(s);
+ if (persistentlayer1)
+ hfc_start_st(s);
+ break;
+ case HFC_T4:
+ hfc_handle_state(s);
+ s->hfc_timers[HFC_T4] = b4->ticks + 1000;
+ s->hfc_timer_on[HFC_T4] = 1;
break;
default:
if (printk_ratelimit()) {
@@ -1347,9 +1363,9 @@ static void hfc_update_st_timers(struct b4xxp *b4)
for (i=0; i < b4->numspans; i++) {
s = &b4->spans[i];
- for (j=HFC_T1; j <= HFC_T3; j++) {
-
-/* we don't really do timer2, it is expired by the state change handler */
+ for (j = HFC_T1; j < ARRAY_SIZE(s->hfc_timers); j++) {
+ /* we don't really do timer2, it is expired by the
+ * state change handler */
if (j == HFC_T2)
continue;
@@ -1433,6 +1449,7 @@ static void hfc_handle_state(struct b4xxp_span *s)
break;
case 0x7: /* TE state F7: Activated */
s->hfc_timer_on[HFC_T3] = 0;
+ s->hfc_timer_on[HFC_T4] = 0;
s->newalarm = 0;
break;
}
@@ -1454,14 +1471,17 @@ static void hfc_handle_state(struct b4xxp_span *s)
/* If we're in F3 and receiving INFO0, start T3 and jump to F4 */
if (!nt && (sta == 3) && (state & V_INFO0)) {
- s->hfc_timers[HFC_T3] = b4->ticks + timer_3_ms;
- s->hfc_timer_on[HFC_T3] = 1;
- if (DBG_ST) {
- dev_info(&b4->pdev->dev,
- "port %d: receiving INFO0 in state 3, "
- "setting T3 and jumping to F4\n", s->port + 1);
+ if (persistentlayer1) {
+ s->hfc_timers[HFC_T3] = b4->ticks + timer_3_ms;
+ s->hfc_timer_on[HFC_T3] = 1;
+ if (DBG_ST) {
+ dev_info(&b4->pdev->dev,
+ "port %d: receiving INFO0 in state 3, "
+ "setting T3 and jumping to F4\n",
+ s->port + 1);
+ }
+ hfc_start_st(s);
}
- hfc_force_st_state(b4, s->port, 4, 1);
}
/* read in R_BERT_STA to determine where our current sync source is */
@@ -1476,6 +1496,24 @@ static void hfc_handle_state(struct b4xxp_span *s)
}
}
+static void hfc_stop_all_timers(struct b4xxp_span *s)
+{
+ s->hfc_timer_on[HFC_T4] = 0;
+ s->hfc_timer_on[HFC_T3] = 0;
+ s->hfc_timer_on[HFC_T2] = 0;
+ s->hfc_timer_on[HFC_T1] = 0;
+}
+
+static void hfc_stop_st(struct b4xxp_span *s)
+{
+ struct b4xxp *b4 = s->parent;
+
+ hfc_stop_all_timers(s);
+
+ b4xxp_setreg_ra(b4, R_ST_SEL, s->port, A_ST_WR_STA
+ V_ST_ACT_DEACTIVATE);
+}
+
/*
* resets an S/T interface to a given NT/TE mode
*/
@@ -1486,10 +1524,16 @@ static void hfc_reset_st(struct b4xxp_span *s)
b4 = s->parent;
+ hfc_stop_st(s);
+
/* force state G0/F0 (reset), then force state 1/2 (deactivated/sensing) */
b4xxp_setreg_ra(b4, R_ST_SEL, s->port, A_ST_WR_STA, V_ST_LD_STA);
flush_pci(); /* make sure write hit hardware */
+ s->span.alarms = DAHDI_ALARM_RED;
+ s->newalarm = DAHDI_ALARM_RED;
+ dahdi_alarm_notify(&s->span);
+
udelay(10);
/* set up the clock control register. Must be done before we activate the interface. */
@@ -1520,9 +1564,13 @@ static void hfc_start_st(struct b4xxp_span *s)
/* start T1 if in NT mode, T3 if in TE mode */
if (s->te_mode) {
- s->hfc_timers[HFC_T3] = b4->ticks + 500; /* 500ms wait first time, timer_t3_ms afterward. */
+ s->hfc_timers[HFC_T3] = b4->ticks + timer_3_ms;
s->hfc_timer_on[HFC_T3] = 1;
s->hfc_timer_on[HFC_T1] = 0;
+
+ s->hfc_timers[HFC_T4] = b4->ticks + 1000;
+ s->hfc_timer_on[HFC_T4] = 1;
+
if (DBG_ST) {
dev_info(&b4->pdev->dev,
"setting port %d t3 timer to %lu\n",
@@ -1540,17 +1588,6 @@ static void hfc_start_st(struct b4xxp_span *s)
}
}
-#if 0 /* TODO: This function is not called anywhere */
-static void hfc_stop_st(struct b4xxp_span *s)
-{
- b4xxp_setreg_ra(s->parent, R_ST_SEL, s->port, A_ST_WR_STA, V_ST_ACT_DEACTIVATE);
-
- s->hfc_timer_on[HFC_T1] = 0;
- s->hfc_timer_on[HFC_T2] = 0;
- s->hfc_timer_on[HFC_T3] = 0;
-}
-#endif
-
/*
* read in the HFC GPIO to determine each port's mode (TE or NT).
* Then, reset and start the port.
@@ -1583,8 +1620,6 @@ static void hfc_init_all_st(struct b4xxp *b4)
dev_info(&b4->pdev->dev,
"Port %d: %s mode\n", i + 1, (nt ? "NT" : "TE"));
- hfc_reset_st(s);
- hfc_start_st(s);
}
}
@@ -1841,10 +1876,10 @@ static int hdlc_tx_frame(struct b4xxp_span *bspan)
char debugbuf[256];
unsigned long irq_flags;
-/* if we're ignoring TE red alarms and we are in alarm, restart the S/T state machine */
- if (bspan->te_mode && teignorered && bspan->newalarm == DAHDI_ALARM_RED) {
- hfc_force_st_state(b4, bspan->port, 3, 1);
- }
+ /* if we're ignoring TE red alarms and we are in alarm, restart the
+ * S/T state machine */
+ if (bspan->te_mode && bspan->newalarm != 0)
+ hfc_start_st(bspan);
fifo = bspan->fifos[2];
res = dahdi_hdlc_getbuf(bspan->sigchan, buf, &size);
@@ -2332,6 +2367,10 @@ static int b4xxp_spanconfig(struct file *file, struct dahdi_span *span,
if (lc->sync)
b4->spans[lc->sync - 1].sync = (span->offset + 1);
+ hfc_reset_st(bspan);
+ if (persistentlayer1)
+ hfc_start_st(bspan);
+
b4xxp_reset_span(bspan);
/* call startup() manually here, because DAHDI won't call the startup function unless it receives an IOCTL to do so, and dahdi_cfg doesn't. */
@@ -3110,6 +3149,7 @@ module_param(vpmsupport, int, S_IRUGO);
module_param(timer_1_ms, int, S_IRUGO | S_IWUSR);
module_param(timer_3_ms, int, S_IRUGO | S_IWUSR);
module_param(companding, charp, S_IRUGO);
+module_param(persistentlayer1, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "bitmap: 1=general 2=dtmf 4=regops 8=fops 16=ec 32=st state 64=hdlc 128=alarm");
MODULE_PARM_DESC(spanfilter, "debug filter for spans. bitmap: 1=port 1, 2=port 2, 4=port 3, 8=port 4");
diff --git a/drivers/dahdi/wcb4xxp/wcb4xxp.h b/drivers/dahdi/wcb4xxp/wcb4xxp.h
index 80a28fe..c35c5dd 100644
--- a/drivers/dahdi/wcb4xxp/wcb4xxp.h
+++ b/drivers/dahdi/wcb4xxp/wcb4xxp.h
@@ -376,6 +376,7 @@
#define HFC_T1 0
#define HFC_T2 1
#define HFC_T3 2
+#define HFC_T4 3
#define MAX_SPANS_PER_CARD 8
@@ -396,8 +397,8 @@ struct b4xxp_span {
unsigned long alarmtimer;
int te_mode; /* 1=TE, 0=NT */
- unsigned long hfc_timers[WCB4XXP_CHANNELS_PER_SPAN]; /* T1, T2, T3 */
- int hfc_timer_on[WCB4XXP_CHANNELS_PER_SPAN]; /* 1=timer active */
+ unsigned long hfc_timers[4]; /* T1, T2, T3, Fake T4 */
+ int hfc_timer_on[4]; /* 1=timer active */
int fifos[WCB4XXP_CHANNELS_PER_SPAN]; /* B1, B2, D <--> host fifo numbers */
/* HDLC controller fields */