summaryrefslogtreecommitdiff
path: root/drivers/dahdi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dahdi')
-rw-r--r--drivers/dahdi/wcb4xxp/base.c49
-rw-r--r--drivers/dahdi/wcb4xxp/wcb4xxp.h2
2 files changed, 37 insertions, 14 deletions
diff --git a/drivers/dahdi/wcb4xxp/base.c b/drivers/dahdi/wcb4xxp/base.c
index 38e45ec..977127c 100644
--- a/drivers/dahdi/wcb4xxp/base.c
+++ b/drivers/dahdi/wcb4xxp/base.c
@@ -1522,32 +1522,44 @@ static void hdlc_stop(struct b4xxp *b4, int fifo)
/*
* Inner loop for D-channel receive function.
* Retrieves a full HDLC frame from the hardware.
- * If the hardware indicates that the frame is complete, checks the FCS and updates
- * DAHDI as needed.
- * Returns 1 if an HDLC frame was correctly received, 0 otherwise.
+ * If the hardware indicates that the frame is complete,
+ * we check the HDLC engine's STAT byte and update DAHDI as needed.
+ *
+ * Returns the number of HDLC frames left in the FIFO.
*/
static int hdlc_rx_frame(struct b4xxp_span *bspan)
{
- int fifo, i, j, zlen, zleft, z1, z2, ret;
- unsigned char buf[32]; /* arbitrary */
+ int fifo, i, j, zleft;
+ int z1, z2, zlen, f1, f2, flen;
+ unsigned char buf[WCB4XXP_HDLC_BUF_LEN];
unsigned long irq_flags;
struct b4xxp *b4 = bspan->parent;
- ret = 0;
fifo = bspan->fifos[2];
++bspan->frames_in;
spin_lock_irqsave(&b4->fifolock, irq_flags);
hfc_setreg_waitbusy(b4, R_FIFO, (fifo << V_FIFO_NUM_SHIFT) | V_FIFO_DIR);
+ get_F(f1, f2, flen);
get_Z(z1, z2, zlen);
spin_unlock_irqrestore(&b4->fifolock, irq_flags);
+/* first check to make sure we really do have HDLC frames available to retrieve */
+ if (flen == 0) {
+ if (DBG_HDLC) {
+ dev_info(b4->dev, "hdlc_rx_frame(span %d): no frames available?\n",
+ bspan->port + 1);
+ }
+
+ return flen;
+ }
+
zlen++; /* include STAT byte that the HFC injects after FCS */
zleft = zlen;
do {
- if (zleft > 32)
- j = 32;
+ if (zleft > WCB4XXP_HDLC_BUF_LEN)
+ j = WCB4XXP_HDLC_BUF_LEN;
else
j = zleft;
@@ -1558,7 +1570,7 @@ static int hdlc_rx_frame(struct b4xxp_span *bspan)
spin_unlock_irqrestore(&b4->fifolock, irq_flags);
/* don't send STAT byte to DAHDI */
- dahdi_hdlc_putbuf(bspan->sigchan, buf, (j == 32) ? j : j - 1);
+ dahdi_hdlc_putbuf(bspan->sigchan, buf, (j == WCB4XXP_HDLC_BUF_LEN) ? j : j - 1);
zleft -= j;
if (DBG_HDLC) {
@@ -1568,8 +1580,10 @@ static int hdlc_rx_frame(struct b4xxp_span *bspan)
}
} while (zleft > 0);
+/* Frame received, increment F2 and get an updated count of frames left */
spin_lock_irqsave(&b4->fifolock, irq_flags);
hfc_setreg_waitbusy(b4, A_INC_RES_FIFO, V_INC_F);
+ get_F(f1, f2, flen);
spin_unlock_irqrestore(&b4->fifolock, irq_flags);
if (zlen < 3) {
@@ -1597,11 +1611,10 @@ static int hdlc_rx_frame(struct b4xxp_span *bspan)
if (DBG_HDLC)
dev_info(b4->dev, "(span %d) Frame %d is good!\n", bspan->port + 1, bspan->frames_in);
dahdi_hdlc_finish(bspan->sigchan);
- ret = 1;
}
}
- return ret;
+ return flen;
}
@@ -1615,9 +1628,9 @@ static int hdlc_tx_frame(struct b4xxp_span *bspan)
{
struct b4xxp *b4 = bspan->parent;
int res, i, fifo;
- unsigned int size = 32;
int z1, z2, zlen;
- unsigned char buf[32];
+ unsigned char buf[WCB4XXP_HDLC_BUF_LEN];
+ unsigned int size = sizeof(buf) / sizeof(buf[0]);
unsigned long irq_flags;
/* if we're ignoring TE red alarms and we are in alarm, restart the S/T state machine */
@@ -2269,7 +2282,15 @@ static void b4xxp_bottom_half(unsigned long data)
if (b & V_IRQ_FIFOx_RX) {
if (fifo >=8 && fifo <= 11) {
- hdlc_rx_frame(&b4->spans[fifo - 8]);
+/*
+ * I have to loop here until hdlc_rx_frame says there are no more frames waiting.
+ * for whatever reason, the HFC will not generate another interrupt if there are
+ * still HDLC frames waiting to be received.
+ * i.e. I get an int when F1 changes, not when F1 != F2.
+ */
+ do {
+ k = hdlc_rx_frame(&b4->spans[fifo - 8]);
+ } while (k);
} else {
if (printk_ratelimit())
dev_warn(b4->dev, "Got FIFO RX int from non-d-chan FIFO %d??\n", fifo);
diff --git a/drivers/dahdi/wcb4xxp/wcb4xxp.h b/drivers/dahdi/wcb4xxp/wcb4xxp.h
index 07f7cf1..a656fed 100644
--- a/drivers/dahdi/wcb4xxp/wcb4xxp.h
+++ b/drivers/dahdi/wcb4xxp/wcb4xxp.h
@@ -381,6 +381,7 @@
#define MAX_SPANS_PER_CARD 4
#define WCB4XXP_CHANNELS_PER_SPAN 3 /* 2 B-channels and 1 D-Channel for each BRI span */
+#define WCB4XXP_HDLC_BUF_LEN 32 /* arbitrary, just the max # of byts we will send to DAHDI per call */
struct b4xxp_span {
struct b4xxp *parent;
@@ -508,3 +509,4 @@ struct b4xxp {
#endif /* __KERNEL__ */
#endif /* _B4XX_H_ */
+