From 3b3d8f7b1186f672e16cd7e4ded2f405ec43cb1c Mon Sep 17 00:00:00 2001 From: tzafrir Date: Thu, 6 Mar 2008 22:54:16 +0000 Subject: 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 --- xpp/xbus-pcm.c | 430 ++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 276 insertions(+), 154 deletions(-) (limited to 'xpp/xbus-pcm.c') 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 -- cgit v1.2.3