summaryrefslogtreecommitdiff
path: root/drivers/dahdi/wctdm24xxp
diff options
context:
space:
mode:
authorShaun Ruffell <sruffell@digium.com>2010-02-25 17:33:58 +0000
committerShaun Ruffell <sruffell@digium.com>2010-02-25 17:33:58 +0000
commit36b4f0072fd8f20a7b3f46f917b7d5af86fceb7b (patch)
tree91b3cb5df3309772ad6fb9584f73a25d156c4996 /drivers/dahdi/wctdm24xxp
parent9a449e1df5edc16fda2c47afe68e8e5cf54026ee (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.c89
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)