[<prev] [next>] [day] [month] [year] [list]
Message-Id: <20120423170551.A50999FB8D@pingi6.linux-pingi.de>
Date: Sat, 21 Apr 2012 18:16:58 +0200
From: Karsten Keil <isdn@...ux-pingi.de>
To: David Miller <davem@...emloft.net>
Cc: netdev@...r.kernel.org, isdn4linux@...tserv.isdn4linux.de
Subject: [PATCH 26/28] mISDN: Enhance hfcsusb driver
- Add support for MISDN_CTRL_RX_OFF and MISDN_CTRL_FILL_EMPTY
- Add MISDN_CTRL_RX_BUFFER handling
- Use a extra buffer pointer for the current transmitted frame, this allows
upper layers to send next data earlier and should avoid TX underuns
Signed-off-by: Karsten Keil <keil@...systems.de>
---
drivers/isdn/hardware/mISDN/hfcsusb.c | 205 ++++++++++++++++++++++-----------
drivers/isdn/hardware/mISDN/hfcsusb.h | 10 +-
2 files changed, 143 insertions(+), 72 deletions(-)
diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c
index cd0f2f6..02b9fe9 100644
--- a/drivers/isdn/hardware/mISDN/hfcsusb.c
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.c
@@ -27,7 +27,7 @@
* poll=<n>, default 128
* n : burst size of PH_DATA_IND at transparent rx data
*
- * Revision: 0.3.3 (socket), 2008-11-05
+ * Revision: 0.3.5 (socket), 2012-01-16
*/
#include <linux/module.h>
@@ -294,13 +294,12 @@ hfcusb_l2l1D(struct mISDNchannel *ch, struct sk_buff *skb)
switch (hh->prim) {
case PH_DATA_REQ:
- if (debug & DBG_HFC_CALL_TRACE)
- printk(KERN_DEBUG "%s: %s: PH_DATA_REQ\n",
- hw->name, __func__);
-
spin_lock_irqsave(&hw->lock, flags);
ret = dchannel_senddata(dch, skb);
spin_unlock_irqrestore(&hw->lock, flags);
+ if (debug & DBG_HFC_CALL_TRACE)
+ printk(KERN_DEBUG "%s: %s: PH_DATA_REQ ret %d\n",
+ hw->name, __func__, ret);
if (ret > 0) {
ret = 0;
queue_ch_frame(ch, PH_DATA_CNF, hh->id, NULL);
@@ -807,17 +806,49 @@ hfcsusb_ph_command(struct hfcsusb *hw, u_char command)
static int
channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
{
- int ret = 0;
+ struct hfcsusb *hw = bch->hw;
+ int idx, o1, o2, ret = 0;
+ idx = (bch->nr - 1) & 1;
switch (cq->op) {
case MISDN_CTRL_GETOP:
- cq->op = MISDN_CTRL_FILL_EMPTY;
+ cq->op = MISDN_CTRL_RX_OFF | MISDN_CTRL_FILL_EMPTY |
+ MISDN_CTRL_RX_BUFFER;
+ break;
+ case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */
+ o1 = hw->dropcnt[idx];
+ if (cq->p1) {
+ test_and_set_bit(FLG_RX_OFF, &bch->Flags);
+ hw->dropcnt[idx] = 0;
+ } else
+ test_and_clear_bit(FLG_RX_OFF, &bch->Flags);
+ cq->p2 = o1;
+ if (debug & DEBUG_HW_BCHANNEL)
+ printk(KERN_DEBUG "Bch%d RX %s dropped %d\n",
+ bch->nr, cq->p1 ? "off" : "on", o1);
break;
case MISDN_CTRL_FILL_EMPTY: /* fill fifo, if empty */
- test_and_set_bit(FLG_FILLEMPTY, &bch->Flags);
- if (debug & DEBUG_HW_OPEN)
- printk(KERN_DEBUG "%s: FILL_EMPTY request (nr=%d "
- "off=%d)\n", __func__, bch->nr, !!cq->p1);
+ if (cq->p1) {
+ test_and_set_bit(FLG_FILLEMPTY, &bch->Flags);
+ if (cq->p2 > -1)
+ hw->fillbyte[idx] = cq->p2 & 0xff;
+ } else
+ test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
+ if (debug & DEBUG_HW_BCHANNEL)
+ printk(KERN_DEBUG "FILL_EMPTY Bch%d %s val %02x\n",
+ bch->nr, cq->p1 ? "on" : "off",
+ hw->fillbyte[idx]);
+ break;
+ case MISDN_CTRL_RX_BUFFER:
+ /* We return the old values */
+ o1 = bch->minlen;
+ o2 = bch->maxlen;
+ if (cq->p1 != MISDN_CTRL_RX_SIZE_IGNORE)
+ bch->minlen = cq->p1;
+ if (cq->p2 != MISDN_CTRL_RX_SIZE_IGNORE)
+ bch->minlen = cq->p2;
+ cq->p1 = o1;
+ cq->p2 = o2;
break;
default:
printk(KERN_WARNING "%s: unknown Op %x\n", __func__, cq->op);
@@ -861,9 +892,21 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len,
hdlc = 1;
}
if (fifo->bch) {
+ if (test_bit(FLG_RX_OFF, &fifo->bch->Flags)) {
+ i = (fifo->bch->nr - 1) & 1;
+ hw->dropcnt[i]++;
+ spin_unlock(&hw->lock);
+ return;
+ }
rx_skb = fifo->bch->rx_skb;
maxlen = fifo->bch->maxlen;
hdlc = test_bit(FLG_HDLC, &fifo->bch->Flags);
+ if (!hdlc) {
+ if (len >= fifo->bch->minlen)
+ maxlen = len;
+ else
+ maxlen = 2 * fifo->bch->minlen;
+ }
}
if (fifo->ech) {
rx_skb = fifo->ech->rx_skb;
@@ -938,8 +981,7 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len,
if (fifo->bch)
recv_Bchannel(fifo->bch, MISDN_ID_ANY);
if (fifo->ech)
- recv_Echannel(fifo->ech,
- &hw->dch);
+ recv_Echannel(fifo->ech, &hw->dch);
} else {
if (debug & DBG_HFC_FIFO_VERBOSE) {
printk(KERN_DEBUG
@@ -957,7 +999,7 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len,
}
} else {
/* deliver transparent data to layer2 */
- if (rx_skb->len >= poll)
+ if (rx_skb->len >= fifo->bch->minlen)
recv_Bchannel(fifo->bch, MISDN_ID_ANY);
}
spin_unlock(&hw->lock);
@@ -1184,36 +1226,48 @@ tx_iso_complete(struct urb *urb)
struct iso_urb *context_iso_urb = (struct iso_urb *) urb->context;
struct usb_fifo *fifo = context_iso_urb->owner_fifo;
struct hfcsusb *hw = fifo->hw;
- struct sk_buff *tx_skb;
int k, tx_offset, num_isoc_packets, sink, remain, current_len,
- errcode, hdlc, i;
- int *tx_idx;
+ errcode, hdlc = 1, i;
int frame_complete, fifon, status;
- __u8 threshbit;
+ __u8 threshbit, fill = 0;
spin_lock(&hw->lock);
+ if (!fifo->ctx) {
+ if (fifo->dch) {
+ fifo->ctx = fifo->dch->tx_skb;
+ fifo->ctxi = 0;
+ if (fifo->ctx)
+ i = get_next_dframe(fifo->dch);
+ } else if (fifo->bch) {
+ fifo->ctx = fifo->bch->tx_skb;
+ fifo->ctxi = 0;
+ if (fifo->ctx)
+ get_next_bframe(fifo->bch);
+ hdlc = test_bit(FLG_HDLC, &fifo->bch->Flags);
+ if (!hdlc)
+ fill = hw->fillbyte[(fifo->bch->nr - 1) & 1];
+ } else {
+ printk(KERN_DEBUG "%s: %s: neither BCH nor DCH\n",
+ hw->name, __func__);
+ spin_unlock(&hw->lock);
+ return;
+ }
+ } else {
+ if (fifo->bch) {
+ hdlc = test_bit(FLG_HDLC, &fifo->bch->Flags);
+ if (!hdlc)
+ fill = hw->fillbyte[(fifo->bch->nr - 1) & 1];
+ }
+ }
if (fifo->stop_gracefull) {
fifo->stop_gracefull = 0;
fifo->active = 0;
+ if (fifo->ctx)
+ dev_kfree_skb(fifo->ctx);
+ fifo->ctx = NULL;
spin_unlock(&hw->lock);
return;
}
-
- if (fifo->dch) {
- tx_skb = fifo->dch->tx_skb;
- tx_idx = &fifo->dch->tx_idx;
- hdlc = 1;
- } else if (fifo->bch) {
- tx_skb = fifo->bch->tx_skb;
- tx_idx = &fifo->bch->tx_idx;
- hdlc = test_bit(FLG_HDLC, &fifo->bch->Flags);
- } else {
- printk(KERN_DEBUG "%s: %s: neither BCH nor DCH\n",
- hw->name, __func__);
- spin_unlock(&hw->lock);
- return;
- }
-
fifon = fifo->fifonum;
status = urb->status;
@@ -1248,7 +1302,7 @@ tx_iso_complete(struct urb *urb)
fifo->usb_packet_maxlen, fifo->intervall,
(usb_complete_t)tx_iso_complete, urb->context);
memset(context_iso_urb->buffer, 0,
- sizeof(context_iso_urb->buffer));
+ sizeof(context_iso_urb->buffer));
frame_complete = 0;
for (k = 0; k < num_isoc_packets; ++k) {
@@ -1263,10 +1317,14 @@ tx_iso_complete(struct urb *urb)
}
/* Generate next ISO Packets */
- if (tx_skb)
- remain = tx_skb->len - *tx_idx;
- else
+ if (fifo->ctx)
+ remain = fifo->ctx->len - fifo->ctxi;
+ else {
remain = 0;
+ if ((!hdlc) &&
+ test_bit(FLG_FILLEMPTY, &fifo->bch->Flags))
+ remain = 14;
+ }
if (remain > 0) {
fifo->bit_line -= sink;
@@ -1295,10 +1353,17 @@ tx_iso_complete(struct urb *urb)
}
/* copy tx data to iso-urb buffer */
- memcpy(context_iso_urb->buffer + tx_offset + 1,
- (tx_skb->data + *tx_idx), current_len);
- *tx_idx += current_len;
-
+ i = tx_offset + 1;
+ if (fifo->ctx) {
+ memcpy(context_iso_urb->buffer + i,
+ (fifo->ctx->data + fifo->ctxi),
+ current_len);
+ fifo->ctxi += current_len;
+ } else {
+ memset(context_iso_urb->buffer + i,
+ fill, current_len);
+ frame_complete = 1;
+ }
urb->iso_frame_desc[k].offset = tx_offset;
urb->iso_frame_desc[k].length = current_len + 1;
@@ -1313,14 +1378,14 @@ tx_iso_complete(struct urb *urb)
urb->iso_frame_desc[k].length);
for (i = urb->iso_frame_desc[k].offset;
- i < (urb->iso_frame_desc[k].offset
- + urb->iso_frame_desc[k].length);
- i++)
+ i < (urb->iso_frame_desc[k].offset +
+ urb->iso_frame_desc[k].length);
+ i++)
printk("%x ",
context_iso_urb->buffer[i]);
printk(" skb->len(%i) tx-idx(%d)\n",
- tx_skb->len, *tx_idx);
+ fifo->ctx->len, fifo->ctxi);
}
tx_offset += (current_len + 1);
@@ -1335,29 +1400,34 @@ tx_iso_complete(struct urb *urb)
if (frame_complete) {
frame_complete = 0;
-
if (debug & DBG_HFC_FIFO_VERBOSE) {
printk(KERN_DEBUG "%s: %s: "
"fifon(%i) new TX len(%i): ",
hw->name, __func__,
- fifon, tx_skb->len);
+ fifon, fifo->ctx->len);
i = 0;
- while (i < tx_skb->len)
+ while (i < fifo->ctx->len)
printk("%02x ",
- tx_skb->data[i++]);
+ fifo->ctx->data[i++]);
printk("\n");
}
-
- dev_kfree_skb(tx_skb);
- tx_skb = NULL;
- if (fifo->dch && get_next_dframe(fifo->dch))
- tx_skb = fifo->dch->tx_skb;
- else if (fifo->bch &&
- get_next_bframe(fifo->bch)) {
- if (test_bit(FLG_TRANSPARENT,
- &fifo->bch->Flags))
- confirm_Bsend(fifo->bch);
- tx_skb = fifo->bch->tx_skb;
+ dev_kfree_skb(fifo->ctx);
+ fifo->ctx = NULL;
+ fifo->ctxi = 0;
+ if (fifo->dch) {
+ if (fifo->dch->tx_skb) {
+ fifo->ctx = fifo->dch->tx_skb;
+ get_next_dframe(fifo->dch);
+ } else
+ test_and_clear_bit(FLG_TX_BUSY,
+ &fifo->dch->Flags);
+ } else if (fifo->bch) {
+ if (fifo->bch->tx_skb) {
+ fifo->ctx = fifo->bch->tx_skb;
+ get_next_bframe(fifo->bch);
+ } else
+ test_and_clear_bit(FLG_TX_BUSY,
+ &fifo->bch->Flags);
}
}
}
@@ -1417,11 +1487,10 @@ start_isoc_chain(struct usb_fifo *fifo, int num_packets_per_urb,
}
fifo->iso[i].owner_fifo = (struct usb_fifo *) fifo;
fifo->iso[i].indx = i;
-
/* Init the first iso */
if (ISO_BUFFER_SIZE >=
(fifo->usb_packet_maxlen *
- num_packets_per_urb)) {
+ num_packets_per_urb)) {
fill_isoc_urb(fifo->iso[i].urb,
fifo->hw->dev, fifo->pipe,
fifo->iso[i].buffer,
@@ -1430,7 +1499,7 @@ start_isoc_chain(struct usb_fifo *fifo, int num_packets_per_urb,
fifo->intervall, complete,
&fifo->iso[i]);
memset(fifo->iso[i].buffer, 0,
- sizeof(fifo->iso[i].buffer));
+ sizeof(fifo->iso[i].buffer));
for (k = 0; k < num_packets_per_urb; k++) {
fifo->iso[i].urb->
@@ -1471,7 +1540,7 @@ stop_iso_gracefull(struct usb_fifo *fifo)
spin_lock_irqsave(&hw->lock, flags);
if (debug)
printk(KERN_DEBUG "%s: %s for fifo %i.%i\n",
- hw->name, __func__, fifo->fifonum, i);
+ hw->name, __func__, fifo->fifonum, i);
fifo->stop_gracefull = 1;
spin_unlock_irqrestore(&hw->lock, flags);
}
@@ -1496,7 +1565,7 @@ stop_int_gracefull(struct usb_fifo *fifo)
spin_lock_irqsave(&hw->lock, flags);
if (debug)
printk(KERN_DEBUG "%s: %s for fifo %i\n",
- hw->name, __func__, fifo->fifonum);
+ hw->name, __func__, fifo->fifonum);
fifo->stop_gracefull = 1;
spin_unlock_irqrestore(&hw->lock, flags);
@@ -1505,7 +1574,7 @@ stop_int_gracefull(struct usb_fifo *fifo)
schedule_timeout_interruptible((HZ / 1000) * 3);
if (debug && fifo->stop_gracefull)
printk(KERN_DEBUG "%s: ERROR %s for fifo %i\n",
- hw->name, __func__, fifo->fifonum);
+ hw->name, __func__, fifo->fifonum);
}
/* start the interrupt transfer for the given fifo */
@@ -1870,7 +1939,7 @@ setup_instance(struct hfcsusb *hw, struct device *parent)
hw->bch[i].nr = i + 1;
set_channelmap(i + 1, hw->dch.dev.channelmap);
hw->bch[i].debug = debug;
- mISDN_initbchannel(&hw->bch[i], MAX_DATA_MEM, -1);
+ mISDN_initbchannel(&hw->bch[i], MAX_DATA_MEM, poll);
hw->bch[i].hw = hw;
hw->bch[i].ch.send = hfcusb_l2l1B;
hw->bch[i].ch.ctrl = hfc_bctrl;
diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.h b/drivers/isdn/hardware/mISDN/hfcsusb.h
index cb1231b..7d48b86 100644
--- a/drivers/isdn/hardware/mISDN/hfcsusb.h
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.h
@@ -263,6 +263,8 @@ struct usb_fifo {
struct dchannel *dch; /* link to hfcsusb_t->dch */
struct bchannel *bch; /* link to hfcsusb_t->bch */
struct dchannel *ech; /* link to hfcsusb_t->ech, TODO: E-CHANNEL */
+ struct sk_buff *ctx; /* current TX skb */
+ int ctxi; /* next byte to write from current TX skb */
int last_urblen; /* remember length of last packet */
__u8 stop_gracefull; /* stops URB retransmission */
};
@@ -282,7 +284,6 @@ struct hfcsusb {
int packet_size;
int iso_packet_size;
struct usb_fifo fifos[HFCUSB_NUM_FIFOS];
-
/* control pipe background handling */
struct ctrl_buf ctrl_buff[HFC_CTRL_BUFSIZE];
int ctrl_in_idx, ctrl_out_idx, ctrl_cnt;
@@ -293,15 +294,16 @@ struct hfcsusb {
int ctrl_in_pipe, ctrl_out_pipe;
spinlock_t ctrl_lock; /* lock for ctrl */
spinlock_t lock;
+ int nt_timer;
+ int open;
+ int dropcnt[2];
__u8 threshold_mask;
__u8 led_state;
-
__u8 protocol;
- int nt_timer;
- int open;
__u8 timers;
__u8 initdone;
+ __u8 fillbyte[2];
char name[MISDN_MAX_IDLEN];
};
--
1.7.3.4
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists