mISDN: Early confirm for transparent data

It is better to send a confirm for transparent data early as possible
to avoid TX underuns.

Signed-off-by: Karsten Keil <kkeil@linux-pingi.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Karsten Keil 2012-05-15 23:51:02 +00:00 committed by David S. Miller
parent 1368112c07
commit 8bfddfbe21
10 changed files with 43 additions and 118 deletions

View File

@ -488,15 +488,11 @@ hdlc_fill_fifo(struct bchannel *bch)
static void
HDLC_irq_xpr(struct bchannel *bch)
{
if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len)
if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len) {
hdlc_fill_fifo(bch);
else {
if (bch->tx_skb) {
/* send confirm, on trans, free on hdlc. */
if (test_bit(FLG_TRANSPARENT, &bch->Flags))
confirm_Bsend(bch);
} else {
if (bch->tx_skb)
dev_kfree_skb(bch->tx_skb);
}
if (get_next_bframe(bch))
hdlc_fill_fifo(bch);
}
@ -659,22 +655,17 @@ avm_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
struct fritzcard *fc = bch->hw;
int ret = -EINVAL;
struct mISDNhead *hh = mISDN_HEAD_P(skb);
u32 id;
u_long flags;
unsigned long flags;
switch (hh->prim) {
case PH_DATA_REQ:
spin_lock_irqsave(&fc->lock, flags);
ret = bchannel_senddata(bch, skb);
if (ret > 0) { /* direct TX */
id = hh->id; /* skb can be freed */
hdlc_fill_fifo(bch);
ret = 0;
spin_unlock_irqrestore(&fc->lock, flags);
if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
} else
spin_unlock_irqrestore(&fc->lock, flags);
}
spin_unlock_irqrestore(&fc->lock, flags);
return ret;
case PH_ACTIVATE_REQ:
spin_lock_irqsave(&fc->lock, flags);

View File

@ -2166,13 +2166,9 @@ next_frame:
HFC_wait_nodebug(hc);
}
/* send confirm, since get_net_bframe will not do it with trans */
if (bch && test_bit(FLG_TRANSPARENT, &bch->Flags))
confirm_Bsend(bch);
/* check for next frame */
dev_kfree_skb(*sp);
if (bch && get_next_bframe(bch)) { /* hdlc is confirmed here */
/* check for next frame */
if (bch && get_next_bframe(bch)) {
len = (*sp)->len;
goto next_frame;
}
@ -3482,8 +3478,7 @@ handle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb)
struct hfc_multi *hc = bch->hw;
int ret = -EINVAL;
struct mISDNhead *hh = mISDN_HEAD_P(skb);
unsigned int id;
u_long flags;
unsigned long flags;
switch (hh->prim) {
case PH_DATA_REQ:
@ -3492,19 +3487,13 @@ handle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb)
spin_lock_irqsave(&hc->lock, flags);
ret = bchannel_senddata(bch, skb);
if (ret > 0) { /* direct TX */
id = hh->id; /* skb can be freed */
hfcmulti_tx(hc, bch->slot);
ret = 0;
/* start fifo */
HFC_outb_nodebug(hc, R_FIFO, 0);
HFC_wait_nodebug(hc);
if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) {
spin_unlock_irqrestore(&hc->lock, flags);
queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
} else
spin_unlock_irqrestore(&hc->lock, flags);
} else
spin_unlock_irqrestore(&hc->lock, flags);
}
spin_unlock_irqrestore(&hc->lock, flags);
return ret;
case PH_ACTIVATE_REQ:
if (debug & DEBUG_HFCMULTI_MSG)

View File

@ -849,9 +849,6 @@ hfcpci_fill_fifo(struct bchannel *bch)
*z1t = cpu_to_le16(new_z1); /* now send data */
if (bch->tx_idx < bch->tx_skb->len)
return;
/* send confirm, on trans, free on hdlc. */
if (test_bit(FLG_TRANSPARENT, &bch->Flags))
confirm_Bsend(bch);
dev_kfree_skb(bch->tx_skb);
if (get_next_bframe(bch))
goto next_t_frame;
@ -1691,22 +1688,17 @@ hfcpci_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
struct hfc_pci *hc = bch->hw;
int ret = -EINVAL;
struct mISDNhead *hh = mISDN_HEAD_P(skb);
unsigned int id;
u_long flags;
unsigned long flags;
switch (hh->prim) {
case PH_DATA_REQ:
spin_lock_irqsave(&hc->lock, flags);
ret = bchannel_senddata(bch, skb);
if (ret > 0) { /* direct TX */
id = hh->id; /* skb can be freed */
hfcpci_fill_fifo(bch);
ret = 0;
spin_unlock_irqrestore(&hc->lock, flags);
if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
} else
spin_unlock_irqrestore(&hc->lock, flags);
}
spin_unlock_irqrestore(&hc->lock, flags);
return ret;
case PH_ACTIVATE_REQ:
spin_lock_irqsave(&hc->lock, flags);

View File

@ -226,15 +226,8 @@ hfcusb_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
if (debug & DBG_HFC_CALL_TRACE)
printk(KERN_DEBUG "%s: %s PH_DATA_REQ ret(%i)\n",
hw->name, __func__, ret);
if (ret > 0) {
/*
* other l1 drivers don't send early confirms on
* transp data, but hfcsusb does because tx_next
* skb is needed in tx_iso_complete()
*/
queue_ch_frame(ch, PH_DATA_CNF, hh->id, NULL);
if (ret > 0)
ret = 0;
}
return ret;
case PH_ACTIVATE_REQ:
if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) {
@ -1365,12 +1358,8 @@ tx_iso_complete(struct urb *urb)
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);
get_next_bframe(fifo->bch))
tx_skb = fifo->bch->tx_skb;
}
}
}
errcode = usb_submit_urb(urb, GFP_ATOMIC);

View File

@ -1011,15 +1011,11 @@ hscx_fill_fifo(struct hscx_hw *hscx)
static void
hscx_xpr(struct hscx_hw *hx)
{
if (hx->bch.tx_skb && hx->bch.tx_idx < hx->bch.tx_skb->len)
if (hx->bch.tx_skb && hx->bch.tx_idx < hx->bch.tx_skb->len) {
hscx_fill_fifo(hx);
else {
if (hx->bch.tx_skb) {
/* send confirm, on trans, free on hdlc. */
if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags))
confirm_Bsend(&hx->bch);
} else {
if (hx->bch.tx_skb)
dev_kfree_skb(hx->bch.tx_skb);
}
if (get_next_bframe(&hx->bch))
hscx_fill_fifo(hx);
}
@ -1342,22 +1338,17 @@ hscx_l2l1(struct mISDNchannel *ch, struct sk_buff *skb)
struct hscx_hw *hx = container_of(bch, struct hscx_hw, bch);
int ret = -EINVAL;
struct mISDNhead *hh = mISDN_HEAD_P(skb);
u32 id;
u_long flags;
unsigned long flags;
switch (hh->prim) {
case PH_DATA_REQ:
spin_lock_irqsave(hx->ip->hwlock, flags);
ret = bchannel_senddata(bch, skb);
if (ret > 0) { /* direct TX */
id = hh->id; /* skb can be freed */
ret = 0;
hscx_fill_fifo(hx);
spin_unlock_irqrestore(hx->ip->hwlock, flags);
if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
} else
spin_unlock_irqrestore(hx->ip->hwlock, flags);
}
spin_unlock_irqrestore(hx->ip->hwlock, flags);
return ret;
case PH_ACTIVATE_REQ:
spin_lock_irqsave(hx->ip->hwlock, flags);

View File

@ -702,15 +702,11 @@ send_next(struct isar_ch *ch)
}
}
}
if (ch->bch.tx_skb) {
/* send confirm, on trans, free on hdlc. */
if (test_bit(FLG_TRANSPARENT, &ch->bch.Flags))
confirm_Bsend(&ch->bch);
if (ch->bch.tx_skb)
dev_kfree_skb(ch->bch.tx_skb);
}
if (get_next_bframe(&ch->bch))
if (get_next_bframe(&ch->bch)) {
isar_fill_fifo(ch);
else {
} else {
if (test_and_clear_bit(FLG_DLEETX, &ch->bch.Flags)) {
if (test_and_clear_bit(FLG_LASTDATA,
&ch->bch.Flags)) {
@ -1487,14 +1483,10 @@ isar_l2l1(struct mISDNchannel *ch, struct sk_buff *skb)
spin_lock_irqsave(ich->is->hwlock, flags);
ret = bchannel_senddata(bch, skb);
if (ret > 0) { /* direct TX */
id = hh->id; /* skb can be freed */
ret = 0;
isar_fill_fifo(ich);
spin_unlock_irqrestore(ich->is->hwlock, flags);
if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
} else
spin_unlock_irqrestore(ich->is->hwlock, flags);
}
spin_unlock_irqrestore(ich->is->hwlock, flags);
return ret;
case PH_ACTIVATE_REQ:
spin_lock_irqsave(ich->is->hwlock, flags);

View File

@ -595,15 +595,11 @@ fill_dma(struct tiger_ch *bc)
static int
bc_next_frame(struct tiger_ch *bc)
{
if (bc->bch.tx_skb && bc->bch.tx_idx < bc->bch.tx_skb->len)
if (bc->bch.tx_skb && bc->bch.tx_idx < bc->bch.tx_skb->len) {
fill_dma(bc);
else {
if (bc->bch.tx_skb) {
/* send confirm, on trans, free on hdlc. */
if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags))
confirm_Bsend(&bc->bch);
} else {
if (bc->bch.tx_skb)
dev_kfree_skb(bc->bch.tx_skb);
}
if (get_next_bframe(&bc->bch))
fill_dma(bc);
else
@ -732,22 +728,17 @@ nj_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
struct tiger_ch *bc = container_of(bch, struct tiger_ch, bch);
struct tiger_hw *card = bch->hw;
struct mISDNhead *hh = mISDN_HEAD_P(skb);
u32 id;
u_long flags;
unsigned long flags;
switch (hh->prim) {
case PH_DATA_REQ:
spin_lock_irqsave(&card->lock, flags);
ret = bchannel_senddata(bch, skb);
if (ret > 0) { /* direct TX */
id = hh->id; /* skb can be freed */
fill_dma(bc);
ret = 0;
spin_unlock_irqrestore(&card->lock, flags);
if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
} else
spin_unlock_irqrestore(&card->lock, flags);
}
spin_unlock_irqrestore(&card->lock, flags);
return ret;
case PH_ACTIVATE_REQ:
spin_lock_irqsave(&card->lock, flags);

View File

@ -638,15 +638,11 @@ w6692_mode(struct w6692_ch *wch, u32 pr)
static void
send_next(struct w6692_ch *wch)
{
if (wch->bch.tx_skb && wch->bch.tx_idx < wch->bch.tx_skb->len)
if (wch->bch.tx_skb && wch->bch.tx_idx < wch->bch.tx_skb->len) {
W6692_fill_Bfifo(wch);
else {
if (wch->bch.tx_skb) {
/* send confirm, on trans, free on hdlc. */
if (test_bit(FLG_TRANSPARENT, &wch->bch.Flags))
confirm_Bsend(&wch->bch);
} else {
if (wch->bch.tx_skb)
dev_kfree_skb(wch->bch.tx_skb);
}
if (get_next_bframe(&wch->bch))
W6692_fill_Bfifo(wch);
}
@ -944,22 +940,17 @@ w6692_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
struct w6692_hw *card = bch->hw;
int ret = -EINVAL;
struct mISDNhead *hh = mISDN_HEAD_P(skb);
u32 id;
u_long flags;
unsigned long flags;
switch (hh->prim) {
case PH_DATA_REQ:
spin_lock_irqsave(&card->lock, flags);
ret = bchannel_senddata(bch, skb);
if (ret > 0) { /* direct TX */
id = hh->id; /* skb can be freed */
ret = 0;
W6692_fill_Bfifo(bc);
spin_unlock_irqrestore(&card->lock, flags);
if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
} else
spin_unlock_irqrestore(&card->lock, flags);
}
spin_unlock_irqrestore(&card->lock, flags);
return ret;
case PH_ACTIVATE_REQ:
spin_lock_irqsave(&card->lock, flags);

View File

@ -272,7 +272,7 @@ get_next_dframe(struct dchannel *dch)
}
EXPORT_SYMBOL(get_next_dframe);
void
static void
confirm_Bsend(struct bchannel *bch)
{
struct sk_buff *skb;
@ -294,7 +294,6 @@ confirm_Bsend(struct bchannel *bch)
skb_queue_tail(&bch->rqueue, skb);
schedule_event(bch, FLG_RECVQUEUE);
}
EXPORT_SYMBOL(confirm_Bsend);
int
get_next_bframe(struct bchannel *bch)
@ -305,8 +304,8 @@ get_next_bframe(struct bchannel *bch)
if (bch->tx_skb) {
bch->next_skb = NULL;
test_and_clear_bit(FLG_TX_NEXT, &bch->Flags);
if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
confirm_Bsend(bch); /* not for transparent */
/* confirm imediately to allow next data */
confirm_Bsend(bch);
return 1;
} else {
test_and_clear_bit(FLG_TX_NEXT, &bch->Flags);
@ -395,6 +394,7 @@ bchannel_senddata(struct bchannel *ch, struct sk_buff *skb)
/* write to fifo */
ch->tx_skb = skb;
ch->tx_idx = 0;
confirm_Bsend(ch);
return 1;
}
}

View File

@ -182,7 +182,6 @@ extern void recv_Echannel(struct dchannel *, struct dchannel *);
extern void recv_Bchannel(struct bchannel *, unsigned int id);
extern void recv_Dchannel_skb(struct dchannel *, struct sk_buff *);
extern void recv_Bchannel_skb(struct bchannel *, struct sk_buff *);
extern void confirm_Bsend(struct bchannel *bch);
extern int get_next_bframe(struct bchannel *);
extern int get_next_dframe(struct dchannel *);