From 36b4f0072fd8f20a7b3f46f917b7d5af86fceb7b Mon Sep 17 00:00:00 2001 From: Shaun Ruffell Date: Thu, 25 Feb 2010 17:33:58 +0000 Subject: wctdm24xxp, wcte12xp: Buffer handling improvements. This patch moves the majority of the buffer processing for the voicebus based cards out of the interrupt handler and into a tasklet. When multiple cards are running on the same CPU, and there was a latency condition that would cause them to get behind, this now allows the tasklet to limit how many buffers are processed on each card before giving the other card a chance to start working on it's backlog. Additionally, when the card detects a hard under run, instead of trying to fix it up in the handling routine, it will now reschedule a work item that will completely reset the descriptor rings. git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@8095 a0bf4364-ded3-4de4-8d8a-66a801d63aff --- drivers/dahdi/wctdm24xxp/base.c | 89 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 80 insertions(+), 9 deletions(-) (limited to 'drivers/dahdi/wctdm24xxp') diff --git a/drivers/dahdi/wctdm24xxp/base.c b/drivers/dahdi/wctdm24xxp/base.c index 8990d70..9b16d80 100644 --- a/drivers/dahdi/wctdm24xxp/base.c +++ b/drivers/dahdi/wctdm24xxp/base.c @@ -473,6 +473,16 @@ static int config_vpmadt032(struct vpmadt032 *vpm, struct wctdm *wc) return 0; } +/** + * is_good_frame() - Whether the SFRAME received was one sent. + * + */ +static inline bool is_good_frame(const u8 *sframe) +{ + const u8 a = sframe[0*(EFRAME_SIZE+EFRAME_GAP) + (EFRAME_SIZE+1)]; + const u8 b = sframe[1*(EFRAME_SIZE+EFRAME_GAP) + (EFRAME_SIZE+1)]; + return a != b; +} static inline void cmd_dequeue_vpmadt032(struct wctdm *wc, u8 *writechunk, int whichframe) { @@ -1017,12 +1027,68 @@ static inline void cmd_retransmit(struct wctdm *wc) #endif } +/** + * extract_tdm_data() - Move TDM data from sframe to channels. + * + */ +static void extract_tdm_data(struct wctdm *wc, const u8 *sframe) +{ + int i; + register u8 *chanchunk; + + for (i = 0; i < wc->cards; i += 4) { + chanchunk = &wc->chans[0 + i]->readchunk[0]; + chanchunk[0] = sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*0]; + chanchunk[1] = sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*1]; + chanchunk[2] = sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*2]; + chanchunk[3] = sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*3]; + chanchunk[4] = sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*4]; + chanchunk[5] = sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*5]; + chanchunk[6] = sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*6]; + chanchunk[7] = sframe[0 + i + (EFRAME_SIZE + EFRAME_GAP)*7]; + + chanchunk = &wc->chans[1 + i]->readchunk[0]; + chanchunk[0] = sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*0]; + chanchunk[1] = sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*1]; + chanchunk[2] = sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*2]; + chanchunk[3] = sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*3]; + chanchunk[4] = sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*4]; + chanchunk[5] = sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*5]; + chanchunk[6] = sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*6]; + chanchunk[7] = sframe[1 + i + (EFRAME_SIZE + EFRAME_GAP)*7]; + + chanchunk = &wc->chans[2 + i]->readchunk[0]; + chanchunk[0] = sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*0]; + chanchunk[1] = sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*1]; + chanchunk[2] = sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*2]; + chanchunk[3] = sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*3]; + chanchunk[4] = sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*4]; + chanchunk[5] = sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*5]; + chanchunk[6] = sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*6]; + chanchunk[7] = sframe[2 + i + (EFRAME_SIZE + EFRAME_GAP)*7]; + + chanchunk = &wc->chans[3 + i]->readchunk[0]; + chanchunk[0] = sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*0]; + chanchunk[1] = sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*1]; + chanchunk[2] = sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*2]; + chanchunk[3] = sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*3]; + chanchunk[4] = sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*4]; + chanchunk[5] = sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*5]; + chanchunk[6] = sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*6]; + chanchunk[7] = sframe[3 + i + (EFRAME_SIZE + EFRAME_GAP)*7]; + } +} + static inline void wctdm_receiveprep(struct wctdm *wc, unsigned char *readchunk) { int x,y; unsigned char expected; - BUG_ON(NULL == readchunk); + if (unlikely(!is_good_frame(readchunk))) + return; + + if (likely(wc->initialized)) + extract_tdm_data(wc, readchunk); for (x=0;xdata); } -static void handle_transmit(struct voicebus *vb, void* vbb) +static void handle_transmit(struct voicebus *vb, struct list_head *buffers) { struct wctdm *wc = container_of(vb, struct wctdm, vb); - memset(vbb, 0, SFRAME_SIZE); - wctdm_transmitprep(wc, vbb); - wctdm_isr_misc(wc); - wc->intcount++; - voicebus_transmit(&wc->vb, vbb); + struct vbb *vbb; + + list_for_each_entry(vbb, buffers, entry) { + memset(vbb->data, 0, sizeof(vbb->data)); + wctdm_transmitprep(wc, vbb->data); + wctdm_isr_misc(wc); + wc->intcount++; + } } static int wctdm_voicedaa_insane(struct wctdm *wc, int card) -- cgit v1.2.3