diff options
author | Shaun Ruffell <sruffell@digium.com> | 2010-02-25 17:33:58 +0000 |
---|---|---|
committer | Shaun Ruffell <sruffell@digium.com> | 2010-02-25 17:33:58 +0000 |
commit | 36b4f0072fd8f20a7b3f46f917b7d5af86fceb7b (patch) | |
tree | 91b3cb5df3309772ad6fb9584f73a25d156c4996 /drivers/dahdi/wctdm24xxp | |
parent | 9a449e1df5edc16fda2c47afe68e8e5cf54026ee (diff) |
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
Diffstat (limited to 'drivers/dahdi/wctdm24xxp')
-rw-r--r-- | drivers/dahdi/wctdm24xxp/base.c | 89 |
1 files changed, 80 insertions, 9 deletions
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;x<DAHDI_CHUNKSIZE;x++) { if (x < DAHDI_CHUNKSIZE - 1) { @@ -1814,20 +1880,25 @@ static inline void wctdm_isr_misc(struct wctdm *wc) } } -static void handle_receive(struct voicebus *vb, void* vbb) +static void handle_receive(struct voicebus *vb, struct list_head *buffers) { struct wctdm *wc = container_of(vb, struct wctdm, vb); - wctdm_receiveprep(wc, vbb); + struct vbb *vbb; + list_for_each_entry(vbb, buffers, entry) + wctdm_receiveprep(wc, vbb->data); } -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) |