summaryrefslogtreecommitdiff
path: root/xpp/xpp_zap.c
diff options
context:
space:
mode:
authortzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-05-17 22:55:21 +0000
committertzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-05-17 22:55:21 +0000
commit3af1b5fa2ec86d21762ad1cea81d2b275d4a9d48 (patch)
tree12da5f31396b3b1d3f99ed1bad8725bd50120689 /xpp/xpp_zap.c
parentc16f6ead0e9050d59d73f39f3015ecb64aecc214 (diff)
XPP revision 3965:
* Tested with zaptel-1.2.17.1 * Add D-Channel TX, RX and BAD frames count in /proc/xpp/XBUS-*/XPD-*/bri_info * Adjust output of xpp_sync script. Pad for 8 port BRI. * Added a debugging module parport_debug (not compiled by default). * Added an optional patch to zaptel: - compiles only if ZAPTEL_SYNC_TICK is defined - Allow interested driver to register for "sync" notification. - Does not affect drivers that do not use this feature. * Added external synchronization feature: - Only if ZAPTEL_SYNC_TICK feature is compiled in - Than XPP may be synchronized by another card (e.g: an Astribank with FXS can be synchronized by a Digium PRI card). - May be enabled/disabled in runtime via the 'sync_tick_active' module parameter to the xpp.ko module. * Fixed a potential bug in D-Channel hexdump printing. * New visual indications in BRI leds: - Constant ON RED/GREEN: Shows the port type -- NT/TE. - Very fast "double blink": Layer1 work, no D-Channel yet. - Steady blinking (1/2 sec): D-Channel trafic detected. * xpp_fxloader moved to /usr/share/zaptel . * adj_clock removed: never really used. * Now we have Zaptel::Hardware and a sample zaptel_hardware script (not (installed by default). * We also have a sample perl zapconf (not installed by default) which aims at replacing genzaptelconf (sans the modules detection). git-svn-id: http://svn.digium.com/svn/zaptel/trunk@2537 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'xpp/xpp_zap.c')
-rw-r--r--xpp/xpp_zap.c189
1 files changed, 138 insertions, 51 deletions
diff --git a/xpp/xpp_zap.c b/xpp/xpp_zap.c
index 8642b7c..fb49e69 100644
--- a/xpp/xpp_zap.c
+++ b/xpp/xpp_zap.c
@@ -42,6 +42,7 @@
#include "xbus-core.h"
#include "xproto.h"
#include "xpp_zap.h"
+#include "parport_debug.h"
static const char rcsid[] = "$Id$";
@@ -64,24 +65,28 @@ static unsigned int xpp_timer_count = 0;
static unsigned int xpp_last_jiffies = 0;
#ifdef ZAPTEL_SYNC_TICK
+static unsigned int zaptel_tick_count = 0;
/*
* Statistics variables
*/
static struct timeval ticked_zaptel;
static struct timeval ticked_xpp;
static long usec_lag_curr; /* current: zaptel - xpp */
-static long usec_lag_prev; /* previous: zaptel - xpp */
-static long usec_delta; /* previous - current */
-static long usec_sigma; /* sum of deltas */
-static long status_cleared_at;
-static long since_status_clear;
+static long sigma_lag; /* sum of lags over SYNC_ADJ_INTERVAL */
+static long average_lag; /* average of lags over SYNC_ADJ_INTERVAL */
static bool zaptel_is_ticking;
+static bool have_sync_mastership;
+static unsigned int sync_tick_nomaster;
-#define ZAPTEL_BIG_LAG 500 /* usec */
+#define ZAPTEL_BIG_LAG 2000 /* usec */
+
+#define SYNC_ADJ_MIN (-30) /* minimal firmware drift unit */
+#define SYNC_ADJ_MAX 30 /* maximal firmware drift unit */
+#define SYNC_ADJ_INTERVAL 5000 /* minimum interval between fixes (usec) */
+#define SYNC_ADJ_FACTOR 30 /* sigma usec/drift_unit */
DEF_PARM_BOOL(sync_tick_active, 1, 0644, "Measure via zaptel sync_tick() method");
-static void sync_status_clear(void);
#endif
@@ -102,6 +107,41 @@ static int xpp_ec = 0;
#include "supress/ec_xpp.h"
#endif
+#ifdef DEBUG_SYNC_PARPORT
+/*
+ * Use parallel port to sample our PCM sync and diagnose quality and
+ * potential problems. A logic analizer or a scope should be connected
+ * to the data bits of the parallel port.
+ *
+ * Array parameter: Choose the two xbuses Id's to sample.
+ * This can be changed on runtime as well. Example:
+ * echo "3,5" > /sys/module/xpp/parameters/parport_xbuses
+ */
+static int parport_xbuses[2] = { 0, 1 };
+unsigned int parport_xbuses_num_values;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
+module_param_array(parport_xbuses, int, &parport_xbuses_num_values, 0577);
+#else
+module_param_array(parport_xbuses, int, parport_xbuses_num_values, 0577);
+#endif
+MODULE_PARM_DESC(parport_xbuses, "Id's of xbuses to sample (1-2)");
+
+/*
+ * Flip a single bit in the parallel port:
+ * - The bit number is either bitnum0 or bitnum1
+ * - Bit is selected by xbus number from parport_xbuses[]
+ */
+void xbus_flip_bit(xbus_t *xbus, unsigned int bitnum0, unsigned int bitnum1)
+{
+ int num = xbus->num;
+
+ if(num == parport_xbuses[0])
+ flip_parport_bit(bitnum0);
+ if(num == parport_xbuses[1])
+ flip_parport_bit(bitnum1);
+}
+EXPORT_SYMBOL(xbus_flip_bit);
+#endif
static void xpp_tick(unsigned long param);
static int zaptel_register_xpd(xpd_t *xpd);
@@ -175,8 +215,8 @@ static inline void send_pcm_frame(xbus_t *xbus, xframe_t *xframe)
static int rate_limit;
unsigned long flags;
struct timeval now;
- long sec_diff;
- long usec_diff;
+ unsigned long sec_diff;
+ unsigned long usec_diff;
spin_lock_irqsave(&xbus->lock, flags);
do_gettimeofday(&now);
@@ -336,7 +376,8 @@ void xpp_tick(unsigned long param)
int i;
#ifdef ZAPTEL_SYNC_TICK
- do_gettimeofday (&ticked_xpp);
+ flip_parport_bit(3);
+ do_gettimeofday(&ticked_xpp);
#endif
if(!sync_master) /* Called from timer */
mod_timer(&xpp_timer, jiffies + 1); /* Must be 1KHz rate */
@@ -390,46 +431,92 @@ void got_sync_from(xpd_t *xpd)
}
#ifdef ZAPTEL_SYNC_TICK
-static void sync_status_clear(void)
+static void send_drift(int drift)
{
- struct timeval now;
+ struct timeval now;
+ const char *msg;
+ xbus_t *xbus;
- do_gettimeofday (&now);
- usec_sigma = 0;
- status_cleared_at = now.tv_sec;
+ BUG_ON(!sync_master);
+ xbus = sync_master->xbus;
+ BUG_ON(drift < SYNC_ADJ_MIN || drift > SYNC_ADJ_MAX);
+ do_gettimeofday(&now);
+ if(drift == 0)
+ msg = "stop";
+ else if(drift > 0)
+ msg = "up";
+ else
+ msg = "down";
+ DBG("DRIFT adjust %s (%d) (last update %ld seconds ago)\n",
+ msg, drift, now.tv_sec - xbus->pll_updated_at);
+ CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, NULL, SYNC_MODE_PLL, drift);
+ xbus->pll_updated_at = now.tv_sec;
}
int zaptel_sync_tick(struct zt_span *span, int is_master)
{
xpd_t *xpd = span->pvt;
+ int offset;
- if(!sync_tick_active) {
- zaptel_is_ticking = 0;
- usec_sigma = 0;
- return 0; /* No auto sync from zaptel */
+ if(!sync_tick_active)
+ goto noop;
+ /*
+ * Detect if any of our spans is zaptel sync master
+ */
+ if(is_master) {
+ sync_tick_nomaster = 0; /* Yes */
+ have_sync_mastership = 1;
}
+ if(sync_tick_nomaster < MAX_BUSES * MAX_XPDS) {
+ sync_tick_nomaster++; /* Maybe */
+ goto noop;
+ }
+ /* Now we know for sure someone else is zaptel sync master */
+ have_sync_mastership = 0;
BUG_ON(!xpd);
/*
* Calculate only if:
- * - Called for the sync_master
* - HOST sync (for information only)
+ * - Called for the sync_master (the function is called
+ * for each span, so we don't want to do it multiple times).
*/
- if(sync_master && xpd != sync_master)
+ if(sync_master && sync_master != xpd)
return 0;
+ zaptel_tick_count++;
+ zaptel_is_ticking = 1;
+ flip_parport_bit(1);
do_gettimeofday(&ticked_zaptel);
usec_lag_curr =
(ticked_zaptel.tv_sec - ticked_xpp.tv_sec)*1000*1000 +
(ticked_zaptel.tv_usec - ticked_xpp.tv_usec);
- if(usec_lag_curr > ZAPTEL_BIG_LAG) {
- if(printk_ratelimit())
- NOTICE("Big lag of Xpp ticks relative to zaptel ticks: %ld\n", usec_lag_curr);
+ if(unlikely(usec_lag_curr > ZAPTEL_BIG_LAG)) {
+ static int rate_limit;
+
+ if((rate_limit++ % 1003) == 0)
+ DBG("Big lag of Xpp ticks relative to zaptel ticks: %ld\n", usec_lag_curr);
+ }
+ sigma_lag += usec_lag_curr;
+ if((zaptel_tick_count % SYNC_ADJ_INTERVAL) == 0) {
+ average_lag = sigma_lag / SYNC_ADJ_INTERVAL;
+ sigma_lag = 0;
+ if(sync_master == xpd) {
+ xbus_t *xbus = sync_master->xbus;
+
+ /* Calculate required fix */
+ offset = (average_lag - 500) / SYNC_ADJ_FACTOR;
+ if(offset < SYNC_ADJ_MIN)
+ offset = SYNC_ADJ_MIN;
+ if(offset > SYNC_ADJ_MAX)
+ offset = SYNC_ADJ_MAX;
+ if(xbus->sync_adjustment != offset) /* Only fix if needed */
+ send_drift(offset);
+ }
}
- usec_delta = usec_lag_curr - usec_lag_prev;
- usec_sigma += usec_delta;
- zaptel_is_ticking = 1;
- since_status_clear = ticked_zaptel.tv_sec - status_cleared_at;
- usec_lag_prev = usec_lag_curr;
return 0;
+noop:
+ zaptel_is_ticking = 0;
+ sigma_lag = 0;
+ return 0; /* No auto sync from zaptel */
}
#endif
@@ -938,40 +1025,48 @@ int proc_sync_read(char *page, char **start, off_t off, int count, int *eof, voi
{
int len = 0;
unsigned int xpp_timer_rate;
- unsigned int now;
+ unsigned int jiffies_now;
len += sprintf(page + len, "# To modify sync source write into this file:\n");
len += sprintf(page + len, "# HOST - For host based sync\n");
len += sprintf(page + len, "# SYNC=nn - XBUS-nn provide sync\n");
-#ifdef ZAPTEL_SYNC_TICK
- len += sprintf(page + len, "# CLS - Clear Statistics\n");
-#endif
len += sprintf(page + len, "# QUERY=nn - Query XBUS-nn for sync information (DEBUG)\n");
if(!sync_master)
len += sprintf(page + len, "HOST\n");
- else
+ else {
len += sprintf(page + len, "SYNC=%02d\n", sync_master->xbus->num);
+ len += sprintf(page + len, "PLL DRIFT=%d\n",
+ sync_master->xbus->sync_adjustment);
+ }
#ifdef ZAPTEL_SYNC_TICK
if(sync_tick_active) {
- len += sprintf(page + len, "\nZaptel Reference Sync:\n");
+ len += sprintf(page + len, "\nZaptel Reference Sync (%s):\n",
+ (have_sync_mastership)?"xpp":"external");
if(zaptel_is_ticking) {
+ if(sync_master) {
+ struct timeval now;
+ xbus_t *xbus = sync_master->xbus;
+
+ do_gettimeofday(&now);
+ len += sprintf(page + len, "\t%-19s: %5ld seconds ago\n",
+ "PLL updated",
+ (xbus->pll_updated_at == 0) ? 0 : now.tv_sec - xbus->pll_updated_at);
+ }
len += sprintf(page + len, "\t%-19s: %5ld (usec)\n",
"current lag", usec_lag_curr);
len += sprintf(page + len, "\t%-19s: %5ld (usec)\n",
- "delta lag", usec_delta);
- len += sprintf(page + len, "\t%-19s: %5ld (usec)\n",
- "sigma of deltas", usec_sigma);
- len += sprintf(page + len, "\t%-19s: %5ld seconds ago\n",
- "status cleared", since_status_clear);
+ "average lag", average_lag);
} else
len += sprintf(page + len, "\tNot activated\n");
}
+ len += sprintf(page + len, "zaptel_tick: #%d\n", zaptel_tick_count);
+ len += sprintf(page + len, "tick - zaptel_tick = %d\n", xpp_timer_count - zaptel_tick_count);
#endif
len += sprintf(page + len, "\ntick: #%d\n", xpp_timer_count);
xpp_timer_rate = 0;
- now = jiffies;
- if(now - xpp_last_jiffies > 0) {
- unsigned long delta = (now - xpp_last_jiffies);
+ jiffies_now = jiffies;
+ if(jiffies_now - xpp_last_jiffies > 0) {
+ unsigned long delta = (jiffies_now - xpp_last_jiffies);
xpp_timer_rate = (xpp_timer_count % SAMPLE_TICKS) * HZ / delta;
len += sprintf(page + len, "tick rate: %4d/second (SAMPLE_TICKS=%d)\n", xpp_timer_rate, SAMPLE_TICKS);
}
@@ -1003,10 +1098,6 @@ static int proc_sync_write(struct file *file, const char __user *buffer, unsigne
buf[count] = '\0';
if(strncmp("HOST", buf, 4) == 0) {
sync_master_is(NULL);
-#ifdef ZAPTEL_SYNC_TICK
- } else if(strncmp("CLS", buf, 3) == 0) {
- sync_status_clear();
-#endif
} else if(sscanf(buf, "SYNC=%d", &xbus_num) == 1) {
DBG("SYNC=%d\n", xbus_num);
if((xbus = xbus_of(xbus_num)) == NULL) {
@@ -1775,7 +1866,6 @@ int __init xpp_zap_init(void)
#else
INFO("FEATURE: %s without sync_tick() from ZAPTEL\n", THIS_MODULE->name);
#endif
-
#ifdef CONFIG_PROC_FS
xpp_proc_toplevel = proc_mkdir(PROC_DIR, NULL);
if(!xpp_proc_toplevel) {
@@ -1801,9 +1891,6 @@ int __init xpp_zap_init(void)
/* Only timer init. We add it only *after* zt_register */
init_timer(&xpp_timer);
sync_master_is(NULL); /* Internal ticking */
-#ifdef ZAPTEL_SYNC_TICK
- sync_status_clear();
-#endif
return 0;
err:
do_cleanup();