summaryrefslogtreecommitdiff
path: root/xpp/xbus-pcm.c
diff options
context:
space:
mode:
authortzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2008-03-06 22:54:16 +0000
committertzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2008-03-06 22:54:16 +0000
commit3b3d8f7b1186f672e16cd7e4ded2f405ec43cb1c (patch)
tree5e592d92e3030b4eb28cab7585f769dbbeab2d74 /xpp/xbus-pcm.c
parent07b404b68141bc981adbc1f5a00cbe90116fb9c1 (diff)
xpp.r5512:
* Build: - Zaptel >= 1.4.9 is migrating to storing kernel stuff in zaptel/kernel/* - We conditionally use old/new directory scheme: In xpp/Kbuild and xpp/utils/Makefile use ZAP_KERNEL variable, so it's not confused with ZAPTEL_DIR (which appears in zaptel/Makefile as well). - Fix compile warnings on 64 bit systems. - Compile fixes for kernel-2.6.24 * UDEV: - /etc/udev/rules.d/xpp.rules now uses XPP_INIT_DIR to find astribank_hook. - astribank_hook: Modify to do nothing. Add some documentation. * Autoconfiguration -- zapconf: - Don't fail zapconf et.al. if no config file was found. - Skip the 'IRQ Missing:' line in /proc/zaptel/nnn for wcte1xp(?). - Add some newer Digium cards to our hardware inventory. - Partially handle cases where the /proc/zaptel strings does not contain info about E1/T1/J1 or NT/TE. * Better SYNC: - Finer tuning of PLL (New firmware). - Change calculation algorithm of sync offset. It now copes better with the variance in USB frame reception timing. - Statistics: . The view of results was moved from /proc/xpp/XBUS-*/summary to a new /sys/bus/astribanks/devices/xbus-*/timing and enhanced. . A new xpp_timing script shows all astribanks. . A new write only /sys/bus/astribanks/devices/xbus-*/cls is used to clear statistics. Eventually, clearing of XBUS related statistics should be done here. One that was migrated is the clearing of 'PCM [TR]X:' numbers currently appearing in /proc/xpp/XBUS-*/summary (they should be moved too later). - Shorten the strings representation sync_mode ("SYNC_MODE_AB" -> "AB") adapted their use in printk and /proc so the text is clear. - Added a command line parameter xpp.disable_pll_sync to stop all adjustments command to AB (calculations still continue as usual). * PRI: - 4 port support - set clocking master span via ztcfg, like other zaptel devices. * FXO: - Fix false hangups in some countries (voltage fluctuations). - Some countries send caller-id before first ring. Added code to handle caller-id PCM pass through according to a new command line parameter (xpd_fxo.caller_id_style). - No longer sends an event on zt_open. See #12160 . * Misc: - Adapt to zaptel-1.4.8 and above ztscan: added fields returend by new ZT_SPANSTAT_V2 ioctl() - Document sysfs and waitfor_xpds. - Miscelaneous optimizations and bugfixes. - Remove deprecated pcm_tasklet parameter. The rx_tasklet parameter has replaced it a long time ago. - Add RX_CMD counter to /proc/xpp/XBUS-*/summary - Unclutter some of the usb disconnect messages. - xpp_usb: minor preformance improvements in receive. Expose the number of pending receive URB's in /proc/xpp/XBUS-*/xpp_usb git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.2@3952 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'xpp/xbus-pcm.c')
-rw-r--r--xpp/xbus-pcm.c430
1 files changed, 276 insertions, 154 deletions
diff --git a/xpp/xbus-pcm.c b/xpp/xbus-pcm.c
index 0b1e5d1..09d50f6 100644
--- a/xpp/xbus-pcm.c
+++ b/xpp/xbus-pcm.c
@@ -49,23 +49,32 @@ DEF_PARM(int, disable_pcm, 0, 0644, "Disable all PCM transmissions");
DEF_PARM(int, pcmtx, -1, 0644, "Forced PCM value to transmit (negative to disable)");
DEF_PARM(int, pcmtx_chan, 0, 0644, "channel to force PCM value");
#endif
-DEF_PARM_BOOL(pcm_tasklet, 0, 0644, "Handle PCM in a tasklet (lower interrupt load)");
-#define PCM_TASKLET_DEPRECATION "\n" \
- "====================================================================\n" \
- "CONFIGURATION ERROR: 'pcm_tasklet' module parameter is deprecated!!!\n" \
- "====================================================================\n"
+DEF_PARM_BOOL(disable_pll_sync, 0, 0644, "Disable automatic adjustment of AB clocks");
static xbus_t *syncer; /* current syncer */
-static struct xpp_timing ref_sync;
-static atomic_t xpp_tick_counter;
-static const struct xpp_timing *global_ticker; /* increment xpp_tick_counter */
-static bool zaptel_syncer = 0;
+static atomic_t xpp_tick_counter = ATOMIC_INIT(0);
+static struct xpp_ticker zaptel_ticker;
+/*
+ * The ref_ticker points to the current referece tick source.
+ * I.e: one of our AB or zaptel_ticker
+ */
+static struct xpp_ticker *ref_ticker = NULL;
+static spinlock_t ref_ticker_lock = SPIN_LOCK_UNLOCKED;
+static bool force_zaptel_sync = 0; /* from "/proc/xpp/sync" */
+static xbus_t *global_ticker;
+static struct xpp_ticker global_ticks_series;
#define PROC_SYNC "sync"
#define BIG_TICK_INTERVAL 1000
-#define SYNC_ADJ_MIN (-30) /* minimal firmware drift unit */
-#define SYNC_ADJ_MAX 30 /* maximal firmware drift unit */
-#define SYNC_ADJ_FACTOR(x) ((x) / 30) /* average usec/drift_unit */
+#define SYNC_ADJ_MAX 63 /* maximal firmware drift unit (63) */
+/*
+ * The USB bulk endpoints have a large jitter in the timing of frames
+ * from the AB to the ehci-hcd. This is because we cannot predict
+ * in which USB micro-frame our data passes. Each micro-frame is
+ * A 125 usec.
+ */
+#define SYNC_ADJ_QUICK 1000
+#define SYNC_ADJ_SLOW 10000
#ifdef ZAPTEL_SYNC_TICK
static unsigned int zaptel_tick_count = 0;
@@ -73,14 +82,191 @@ static unsigned int zaptel_tick_count = 0;
/*------------------------- SYNC Handling --------------------------*/
+static void send_drift(xbus_t *xbus, int drift);
+
+static void xpp_ticker_init(struct xpp_ticker *ticker)
+{
+ memset(ticker, 0, sizeof(*ticker));
+ do_gettimeofday(&ticker->last_sample.tv);
+ ticker->first_sample = ticker->last_sample;
+ ticker->cycle = SYNC_ADJ_QUICK;
+ spin_lock_init(&ticker->lock);
+}
+
+static int xpp_ticker_step(struct xpp_ticker *ticker, const struct timeval *t)
+{
+ unsigned long flags;
+ long usec;
+ bool cycled = 0;
+
+ spin_lock_irqsave(&ticker->lock, flags);
+ ticker->last_sample.tv = *t;
+ if((ticker->count % ticker->cycle) == ticker->cycle - 1) { /* rate adjust */
+ usec = (long)usec_diff(
+ &ticker->last_sample.tv,
+ &ticker->first_sample.tv);
+ ticker->first_sample = ticker->last_sample;
+ ticker->tick_period = usec / ticker->cycle;
+ cycled = 1;
+ }
+ ticker->count++;
+ spin_unlock_irqrestore(&ticker->lock, flags);
+ return cycled;
+}
+
+static inline void driftinfo_recalc(struct xpp_drift *driftinfo)
+{
+ driftinfo->delta_max = INT_MIN;
+ driftinfo->delta_min = INT_MAX;
+}
+
+/*
+ * No locking. It is called only from:
+ * - update_sync_master() in a globall spinlock protected code.
+ * - initalization.
+ */
+static inline void xbus_drift_clear(xbus_t *xbus)
+{
+ struct xpp_drift *driftinfo = &xbus->drift;
+
+ driftinfo_recalc(driftinfo);
+ driftinfo->calc_drift = 0;
+ xbus->ticker.cycle = SYNC_ADJ_QUICK;
+}
+
+void xpp_drift_init(xbus_t *xbus)
+{
+ memset(&xbus->drift, 0, sizeof(xbus->drift));
+ spin_lock_init(&xbus->drift.lock);
+ xpp_ticker_init(&xbus->ticker);
+ xbus->drift.wanted_offset = 500;
+ xbus_drift_clear(xbus);
+}
+
+#ifdef SAMPLE_TICKS
+static void sample_tick(xbus_t *xbus, int sample)
+{
+ if(!xbus->sample_running)
+ return;
+ if(xbus->sample_pos < SAMPLE_SIZE)
+ xbus->sample_ticks[xbus->sample_pos++] = sample;
+ else {
+ xbus->sample_running = 0;
+ xbus->sample_pos = 0;
+ }
+}
+#else
+#define sample_tick(x,y)
+#endif
+
+static void xpp_drift_step(xbus_t *xbus, const struct timeval *tv)
+{
+ struct xpp_drift *driftinfo = &xbus->drift;
+ struct xpp_ticker *ticker = &xbus->ticker;
+ unsigned long flags;
+ bool cycled;
+
+ spin_lock_irqsave(&driftinfo->lock, flags);
+ cycled = xpp_ticker_step(&xbus->ticker, tv);
+ if(ref_ticker && syncer && xbus->sync_mode == SYNC_MODE_PLL) {
+ int new_delta_tick = ticker->count - ref_ticker->count;
+ int lost_ticks = new_delta_tick - driftinfo->delta_tick;
+
+ driftinfo->delta_tick = new_delta_tick;
+ if(lost_ticks) {
+ driftinfo->lost_ticks++;
+ driftinfo->lost_tick_count += abs(lost_ticks);
+ XBUS_DBG(SYNC, xbus, "Lost %d tick%s\n",
+ lost_ticks,
+ (abs(lost_ticks) > 1) ? "s": "");
+ ticker->cycle = SYNC_ADJ_QUICK;
+ if(abs(lost_ticks) > 100)
+ ticker->count = ref_ticker->count;
+ } else {
+ long usec_delta;
+ bool nofix = 0;
+
+ usec_delta = (long)usec_diff(
+ &ticker->last_sample.tv,
+ &ref_ticker->last_sample.tv);
+ usec_delta -= driftinfo->wanted_offset;
+ sample_tick(xbus, usec_delta);
+ if(abs(usec_delta) > 300) {
+ /*
+ * We are close to the edge, send a brutal
+ * fix, and skip calculation until next time.
+ */
+ if(usec_delta > 0 && xbus->sync_adjustment > -SYNC_ADJ_MAX) {
+ XBUS_DBG(SYNC, xbus, "Pullback usec_delta=%ld\n", usec_delta);
+ send_drift(xbus, -SYNC_ADJ_MAX); /* emergency push */
+ }
+ if(usec_delta < 0 && xbus->sync_adjustment < SYNC_ADJ_MAX) {
+ XBUS_DBG(SYNC, xbus, "Pushback usec_delta=%ld\n", usec_delta);
+ send_drift(xbus, SYNC_ADJ_MAX); /* emergency push */
+ }
+ ticker->cycle = SYNC_ADJ_QUICK;
+ nofix = 1;
+ } else {
+ /* good data, use it */
+ if(usec_delta > driftinfo->delta_max)
+ driftinfo->delta_max = usec_delta;
+ if(usec_delta < driftinfo->delta_min)
+ driftinfo->delta_min = usec_delta;
+ }
+ if(!nofix && cycled) {
+ int offset = 0;
+
+ driftinfo->median = (driftinfo->delta_max + driftinfo->delta_min) / 2;
+ driftinfo->jitter = driftinfo->delta_max - driftinfo->delta_min;
+ if(abs(driftinfo->median) >= 150) { /* more than 1 usb uframe */
+ int factor = abs(driftinfo->median) / 125;
+
+ factor = 1 + (factor * 8000) / ticker->cycle;
+ if(driftinfo->median > 0)
+ offset = driftinfo->calc_drift - factor;
+ else
+ offset = driftinfo->calc_drift + factor;
+ /* for large median, push some more */
+ if(abs(driftinfo->median) >= 300) { /* more than 2 usb uframes */
+ ticker->cycle = SYNC_ADJ_QUICK;
+ XBUS_NOTICE(xbus,
+ "Back to quick: median=%d\n",
+ driftinfo->median);
+ }
+ } else {
+ ticker->cycle += 500;
+ if(ticker->cycle >= SYNC_ADJ_SLOW)
+ ticker->cycle = SYNC_ADJ_SLOW;
+ }
+ driftinfo->calc_drift = offset;
+ XBUS_DBG(SYNC, xbus,
+ "ADJ: min=%d max=%d jitter=%d median=%d offset=%d\n",
+ driftinfo->delta_min,
+ driftinfo->delta_max,
+ driftinfo->jitter,
+ driftinfo->median,
+ offset);
+ if(offset < -SYNC_ADJ_MAX)
+ offset = -SYNC_ADJ_MAX;
+ if(offset > SYNC_ADJ_MAX)
+ offset = SYNC_ADJ_MAX;
+ xbus->sync_adjustment_offset = offset;
+ if(xbus != syncer && xbus->sync_adjustment != offset)
+ send_drift(xbus, offset);
+ driftinfo_recalc(driftinfo);
+ }
+ }
+ }
+ spin_unlock_irqrestore(&driftinfo->lock, flags);
+}
const char *sync_mode_name(enum sync_mode mode)
{
static const char *sync_mode_names[] = {
- [SYNC_MODE_AB] "SYNC_MODE_AB",
- [SYNC_MODE_NONE] "SYNC_MODE_NONE",
- [SYNC_MODE_PLL] "SYNC_MODE_PLL",
- [SYNC_MODE_QUERY] "SYNC_MODE_QUERY",
+ [SYNC_MODE_AB] "AB",
+ [SYNC_MODE_NONE] "NONE",
+ [SYNC_MODE_PLL] "PLL",
+ [SYNC_MODE_QUERY] "QUERY",
};
if(mode >= ARRAY_SIZE(sync_mode_names))
return NULL;
@@ -101,76 +287,6 @@ static void xpp_set_syncer(xbus_t *xbus, bool on)
(syncer) ? syncer->busname : "NO-SYNC");
}
-void xpp_timing_init(struct xpp_timing *timing, const char *name)
-{
- memset(timing, 0, sizeof(*timing));
- do_gettimeofday(&timing->timing_val);
- spin_lock_init(&timing->lock);
- timing->name = name;
-}
-
-#define XPP_TIMING_SAMPLES 50
-#define XPP_TIMING_TICKS 100
-#define XPP_TIMING_MAX_STDDEV 500
-
-static void xpp_timing_tick(struct xpp_timing *timing, const struct timeval *val)
-{
- long usec;
- int diff_sec;
- int diff_usec;
- unsigned long flags;
-
- spin_lock_irqsave(&timing->lock, flags);
- if((timing->timing_count % XPP_TIMING_TICKS) != 0)
- goto out;
- diff_sec = val->tv_sec - timing->timing_val.tv_sec;
- diff_usec = val->tv_usec - timing->timing_val.tv_usec;
- timing->timing_val = *val;
- /* ignore first batch of samples */
- if(timing->timing_count < (XPP_TIMING_TICKS * XPP_TIMING_SAMPLES))
- goto out;
- if(abs(diff_sec) > 2) {
- static int rate_limit;
-
- if((rate_limit++ % 1003) == 0)
- NOTICE("TIMING(%s): bad timing: diff_sec=%d\n",
- timing->name, diff_sec);
- goto out;
- }
- usec = diff_sec * 1000000 + diff_usec;
- if(usec)
- timing->tick_rate = XPP_TIMING_TICKS * 1000000 / usec;
- usec -= 1000 * XPP_TIMING_TICKS; /* normalize */
-
- timing->accumulated_usec += usec;
- timing->accumulated_usec_sqr += usec * usec;
- if((timing->timing_count % (XPP_TIMING_TICKS * XPP_TIMING_SAMPLES)) == 0) {
- int avg;
- int stddev;
-
- avg = timing->accumulated_usec / XPP_TIMING_SAMPLES;
- stddev = (timing->accumulated_usec_sqr / XPP_TIMING_SAMPLES);
- stddev = int_sqrt(stddev);
- timing->accumulated_usec = 0;
- timing->accumulated_usec_sqr = 0;
- if(stddev > XPP_TIMING_MAX_STDDEV) {
- static int rate_limit;
-
- if((rate_limit++ % 1003) == 0)
- NOTICE("TIMING(%s): bad timing: stddev=%d avg=%d\n",
- timing->name, stddev, avg);
- goto out;
- }
- timing->tick_avg = avg;
- timing->tick_stddev = stddev;
- }
-out:
- timing->timing_count++;
- if(timing == global_ticker)
- atomic_inc(&xpp_tick_counter);
- spin_unlock_irqrestore(&timing->lock, flags);
-}
-
void xbus_command_timer(unsigned long param)
{
xbus_t *xbus = (xbus_t *)param;
@@ -209,12 +325,12 @@ void got_new_syncer(xbus_t *xbus, enum sync_mode mode, int drift)
{
unsigned long flags;
- XBUS_DBG(SYNC, xbus, "%s (%d), drift=%d (pcm_rx_counter=%d)\n",
+ XBUS_DBG(SYNC, xbus, "Mode %s (%d), drift=%d (pcm_rx_counter=%d)\n",
sync_mode_name(mode), mode, drift, atomic_read(&xbus->pcm_rx_counter));
spin_lock_irqsave(&xbus->lock, flags);
xbus->sync_adjustment = (signed char)drift;
if(xbus->sync_mode == mode) {
- XBUS_DBG(SYNC, xbus, "Already in %s. Ignored\n", sync_mode_name(mode));
+ XBUS_DBG(SYNC, xbus, "Already in mode '%s'. Ignored\n", sync_mode_name(mode));
goto out;
}
switch(mode) {
@@ -222,11 +338,13 @@ void got_new_syncer(xbus_t *xbus, enum sync_mode mode, int drift)
xbus->sync_mode = mode;
xbus_set_command_timer(xbus, 0);
xpp_set_syncer(xbus, 1);
+ global_ticker = xbus;
break;
case SYNC_MODE_PLL:
xbus->sync_mode = mode;
xbus_set_command_timer(xbus, 0);
xpp_set_syncer(xbus, 0);
+ global_ticker = xbus;
break;
case SYNC_MODE_NONE: /* lost sync source */
xbus->sync_mode = mode;
@@ -281,27 +399,41 @@ static void send_drift(xbus_t *xbus, int drift)
struct timeval now;
const char *msg;
- BUG_ON(drift < SYNC_ADJ_MIN || drift > SYNC_ADJ_MAX);
+ BUG_ON(abs(drift) > SYNC_ADJ_MAX);
do_gettimeofday(&now);
if(drift > xbus->sync_adjustment)
msg = "up";
else
msg = "down";
- XBUS_DBG(SYNC, xbus, "DRIFT adjust %s (%d) (last update %ld seconds ago)\n",
+ XBUS_DBG(SYNC, xbus, "%sDRIFT adjust %s (%d) (last update %ld seconds ago)\n",
+ (disable_pll_sync) ? "Fake " : "",
msg, drift, now.tv_sec - xbus->pll_updated_at);
- CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, NULL, SYNC_MODE_PLL, drift);
+ if(!disable_pll_sync)
+ CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, NULL, SYNC_MODE_PLL, drift);
xbus->pll_updated_at = now.tv_sec;
}
+static void global_tick(void)
+{
+ struct timeval now;
+
+ do_gettimeofday(&now);
+ atomic_inc(&xpp_tick_counter);
+ if((atomic_read(&xpp_tick_counter) % BIG_TICK_INTERVAL) == 0)
+ reset_sync_counters();
+ xpp_ticker_step(&global_ticks_series, &now);
+}
+
#ifdef ZAPTEL_SYNC_TICK
int zaptel_sync_tick(struct zt_span *span, int is_master)
{
xpd_t *xpd = span->pvt;
- struct timeval now;
static int redundant_ticks; /* for extra spans */
+ struct timeval now;
- if(!zaptel_syncer)
+ if(!force_zaptel_sync)
goto noop;
+ do_gettimeofday(&now);
BUG_ON(!xpd);
/*
* Detect if any of our spans is zaptel sync master
@@ -338,33 +470,15 @@ int zaptel_sync_tick(struct zt_span *span, int is_master)
#endif
goto noop;
}
- do_gettimeofday(&now);
- xpp_timing_tick(&ref_sync, &now);
+ xpp_ticker_step(&zaptel_ticker, &now);
zaptel_tick_count++;
- flip_parport_bit(1);
+ //flip_parport_bit(1);
return 0;
noop:
return 0; /* No auto sync from zaptel */
}
#endif
-
-static void sync_rate_adjust(xbus_t *xbus)
-{
- int offset;
-
- xbus->sync_offset_usec = xbus->timing.tick_avg - ref_sync.tick_avg;
- /* Calculate required PLL fix */
- offset = SYNC_ADJ_FACTOR(xbus->sync_offset_usec);
- if(offset < SYNC_ADJ_MIN)
- offset = SYNC_ADJ_MIN;
- if(offset > SYNC_ADJ_MAX)
- offset = SYNC_ADJ_MAX;
- xbus->sync_adjustment_offset = offset;
- if(xbus != syncer && xbus->sync_adjustment != offset)
- send_drift(xbus, offset);
-}
-
/*
* called from elect_syncer()
* if new_syncer is NULL, than we move all to SYNC_MODE_PLL
@@ -372,20 +486,34 @@ static void sync_rate_adjust(xbus_t *xbus)
*/
static void update_sync_master(xbus_t *new_syncer)
{
- const char *msg = (zaptel_syncer) ? "ZAPTEL" : "NO-SYNC";
+ const char *msg = (force_zaptel_sync) ? "ZAPTEL" : "NO-SYNC";
int i;
+ unsigned long flags;
DBG(SYNC, "%s => %s\n",
(syncer) ? syncer->busname : msg,
(new_syncer) ? new_syncer->busname : msg);
+ /*
+ * This global locking protects:
+ * - The ref_ticker so it won't be used while we change it.
+ * - The xbus_drift_clear() from corrupting driftinfo data.
+ */
+ spin_lock_irqsave(&ref_ticker_lock, flags);
+ if(syncer)
+ xbus_drift_clear(syncer); /* Clean old data */
if(new_syncer) {
XBUS_DBG(SYNC, new_syncer, "pcm_rx_counter=%d\n",
atomic_read(&new_syncer->pcm_rx_counter));
- zaptel_syncer = 0;
- global_ticker = &new_syncer->timing;
+ force_zaptel_sync = 0;
+ ref_ticker = &new_syncer->ticker;
+ xbus_drift_clear(new_syncer); /* Clean new data */
xbus_request_sync(new_syncer, SYNC_MODE_AB);
- } else
- global_ticker = &ref_sync;
+ } else if(force_zaptel_sync) {
+ ref_ticker = &zaptel_ticker;
+ } else {
+ ref_ticker = NULL;
+ }
+ spin_unlock_irqrestore(&ref_ticker_lock, flags);
DBG(SYNC, "stop unwanted syncers\n");
/* Shut all down except the wanted sync master */
for(i = 0; i < MAX_BUSES; i++) {
@@ -420,7 +548,7 @@ void elect_syncer(const char *msg)
for(j = 0; j < MAX_XPDS; j++) {
xpd_t *xpd = xpd_of(xbus, j);
- if(!xpd)
+ if(!xpd || !xpd->card_present)
continue;
if(xpd->timing_priority > timing_priority) {
timing_priority = xpd->timing_priority;
@@ -539,10 +667,10 @@ static inline void xpp_ec_chunk(struct zt_chan *chan, unsigned char *rxchunk, co
static void do_ec(xpd_t *xpd)
{
+#ifdef WITH_ECHO_SUPPRESSION
struct zt_chan *chans = xpd->span.chans;
int i;
-#ifdef WITH_ECHO_SUPPRESSION
/* FIXME: need to Echo cancel double buffered data */
for (i = 0;i < xpd->span.channels; i++) {
if(unlikely(IS_SET(xpd->digital_signalling, i))) /* Don't echo cancel BRI D-chans */
@@ -670,7 +798,7 @@ static inline void pcm_frame_out(xbus_t *xbus, xframe_t *xframe)
spin_unlock_irqrestore(&xbus->lock, flags);
/* OK, really send it */
if(print_dbg & DBG_PCM )
- dump_xframe("TX_XFRAME_PCM", xbus, xframe);
+ dump_xframe("TX_XFRAME_PCM", xbus, xframe, print_dbg);
send_pcm_frame(xbus, xframe);
XBUS_COUNTER(xbus, TX_XFRAME_PCM)++;
return;
@@ -759,7 +887,7 @@ static int copy_pcm_tospan(xbus_t *xbus, xframe_t *xframe)
int ret = -EPROTO; /* Assume error */
if(print_dbg & DBG_PCM)
- dump_xframe("RX_XFRAME_PCM", xbus, xframe);
+ dump_xframe("RX_XFRAME_PCM", xbus, xframe, print_dbg);
/* handle content */
p = xframe->packets;
@@ -778,7 +906,7 @@ static int copy_pcm_tospan(xbus_t *xbus, xframe_t *xframe)
XBUS_NOTICE(xbus,
"%s: Non-PCM packet within a PCM xframe. (%d)\n",
__FUNCTION__, rate_limit);
- dump_xframe("In PCM xframe", xbus, xframe);
+ dump_xframe("In PCM xframe", xbus, xframe, print_dbg);
}
goto out;
}
@@ -790,7 +918,7 @@ static int copy_pcm_tospan(xbus_t *xbus, xframe_t *xframe)
XBUS_NOTICE(xbus,
"%s: Invalid packet length %d. (%d)\n",
__FUNCTION__, len, rate_limit);
- dump_xframe("BAD LENGTH", xbus, xframe);
+ dump_xframe("BAD LENGTH", xbus, xframe, print_dbg);
}
goto out;
}
@@ -800,7 +928,7 @@ static int copy_pcm_tospan(xbus_t *xbus, xframe_t *xframe)
if((rate_limit++ % 1003) == 0) {
notify_bad_xpd(__FUNCTION__, xbus, XPACKET_ADDR(pack), "RECEIVE PCM");
- dump_xframe("Unknown XPD addr", xbus, xframe);
+ dump_xframe("Unknown XPD addr", xbus, xframe, print_dbg);
}
goto out;
}
@@ -898,8 +1026,7 @@ static void xbus_tick(xbus_t *xbus)
/*
* Receive PCM
*/
- i = atomic_read(&xbus->pcm_rx_counter) & 1;
- while((xframe = xframe_dequeue(&xbus->pcm_tospan[i])) != NULL) {
+ while((xframe = xframe_dequeue(&xbus->pcm_tospan)) != NULL) {
copy_pcm_tospan(xbus, xframe);
if(XPACKET_ADDR_SYNC((xpacket_t *)xframe->packets)) {
struct timeval now;
@@ -942,21 +1069,17 @@ static void xbus_tick(xbus_t *xbus)
}
}
-void do_tick(xbus_t *xbus, struct timeval tv_received)
+static void do_tick(xbus_t *xbus, const struct timeval *tv_received)
{
- int counter = atomic_read(&xpp_tick_counter);
+ int counter = atomic_read(&xpp_tick_counter);
+ unsigned long flags;
xbus_command_queue_tick(xbus);
- xpp_timing_tick(&xbus->timing, &tv_received);
- if(syncer == xbus) {
- xpp_timing_tick(&ref_sync, &tv_received);
- if((counter % BIG_TICK_INTERVAL) == 0)
- reset_sync_counters();
- }
- if((atomic_read(&xbus->pcm_rx_counter) % BIG_TICK_INTERVAL) == 0) {
- if(xbus->sync_mode == SYNC_MODE_PLL)
- sync_rate_adjust(xbus);
- }
+ if(global_ticker == xbus)
+ global_tick(); /* called from here or zaptel_sync_tick() */
+ spin_lock_irqsave(&ref_ticker_lock, flags);
+ xpp_drift_step(xbus, tv_received);
+ spin_unlock_irqrestore(&ref_ticker_lock, flags);
if(likely(xbus->self_ticking))
xbus_tick(xbus);
xbus->global_counter = counter;
@@ -964,9 +1087,7 @@ void do_tick(xbus_t *xbus, struct timeval tv_received)
void xframe_receive_pcm(xbus_t *xbus, xframe_t *xframe)
{
- int which = atomic_read(&xbus->pcm_rx_counter) & 1;
-
- if(!xframe_enqueue(&xbus->pcm_tospan[which], xframe)) {
+ if(!xframe_enqueue(&xbus->pcm_tospan, xframe)) {
static int rate_limit;
if((rate_limit++ % 1003) == 0)
@@ -981,7 +1102,7 @@ void xframe_receive_pcm(xbus_t *xbus, xframe_t *xframe)
* FIXME: what about PRI split?
*/
if(XPACKET_ADDR_SYNC((xpacket_t *)xframe->packets)) {
- do_tick(xbus, xframe->tv_received);
+ do_tick(xbus, &xframe->tv_received);
atomic_inc(&xbus->pcm_rx_counter);
} else
xbus->xbus_frag_count++;
@@ -1001,14 +1122,14 @@ int proc_sync_read(char *page, char **start, off_t off, int count, int *eof, voi
len += sprintf(page + len, "# SYNC=nn - XBUS-nn provide sync\n");
len += sprintf(page + len, "# QUERY=nn - Query XBUS-nn for sync information (DEBUG)\n");
if(!syncer) {
- if(zaptel_syncer)
+ if(force_zaptel_sync)
len += sprintf(page + len, "ZAPTEL\n");
else
len += sprintf(page + len, "NO-SYNC\n");
} else
len += sprintf(page + len, "SYNC=%02d\n", syncer->num);
#ifdef ZAPTEL_SYNC_TICK
- if(zaptel_syncer) {
+ if(force_zaptel_sync) {
len += sprintf(page + len,
"Zaptel Reference Sync (%d registered spans):\n",
total_registered_spans());
@@ -1020,14 +1141,12 @@ int proc_sync_read(char *page, char **start, off_t off, int count, int *eof, voi
"Zaptel Reference Sync Not activated\n");
}
#endif
- usec = usec_diff(&now, &ref_sync.timing_val);
+ usec = usec_diff(&now, &global_ticks_series.last_sample.tv);
len += sprintf(page + len, "\ntick: #%d\n", counter);
len += sprintf(page + len,
- "tick rate: %4d/second (measured %ld.%ld msec ago)\n",
- ref_sync.tick_rate,
+ "tick duration: %d usec (measured %ld.%ld msec ago)\n",
+ global_ticks_series.tick_period,
usec / 1000, usec % 1000);
- if(pcm_tasklet)
- len += sprintf(page + len, PCM_TASKLET_DEPRECATION);
if (len <= off+count)
*eof = 1;
*start = page + off;
@@ -1055,7 +1174,7 @@ static int proc_sync_write(struct file *file, const char __user *buffer, unsigne
buf[count] = '\0';
if(strncmp("ZAPTEL", buf, 6) == 0) {
DBG(SYNC, "ZAPTEL\n");
- zaptel_syncer=1;
+ force_zaptel_sync=1;
update_sync_master(NULL);
} else if(sscanf(buf, "SYNC=%d", &xbus_num) == 1) {
DBG(SYNC, "SYNC=%d\n", xbus_num);
@@ -1127,6 +1246,8 @@ int xbus_pcm_init(struct proc_dir_entry *toplevel)
#else
INFO("FEATURE: without sync_tick() from ZAPTEL\n");
#endif
+ xpp_ticker_init(&global_ticks_series);
+ xpp_ticker_init(&zaptel_ticker);
#ifdef CONFIG_PROC_FS
top = toplevel;
ent = create_proc_entry(PROC_SYNC, 0644, top);
@@ -1138,9 +1259,6 @@ int xbus_pcm_init(struct proc_dir_entry *toplevel)
ent->write_proc = proc_sync_write;
ent->data = NULL;
#endif
- if(pcm_tasklet)
- ERR(PCM_TASKLET_DEPRECATION);
- xpp_timing_init(&ref_sync, "REF-SYNC");
err:
return ret;
}
@@ -1165,4 +1283,8 @@ EXPORT_SYMBOL(__pcm_recompute);
EXPORT_SYMBOL(pcm_recompute);
EXPORT_SYMBOL(generic_card_pcm_tospan);
EXPORT_SYMBOL(generic_card_pcm_fromspan);
+#ifdef DEBUG_PCMTX
+EXPORT_SYMBOL(pcmtx);
+EXPORT_SYMBOL(pcmtx_chan);
+#endif