From c626c127279b265ab293348763e043864d58d42c Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Fri, 4 May 2012 04:15:33 +0000 Subject: mISDN: Make layer1 timer 3 value configurable For certification test it is very useful to change the layer1 timer3 value on runtime. Signed-off-by: Karsten Keil Signed-off-by: David S. Miller --- drivers/isdn/hardware/mISDN/netjet.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/isdn/hardware/mISDN/netjet.c') diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c index c726e09d098..27998d7188a 100644 --- a/drivers/isdn/hardware/mISDN/netjet.c +++ b/drivers/isdn/hardware/mISDN/netjet.c @@ -837,7 +837,7 @@ channel_ctrl(struct tiger_hw *card, struct mISDN_ctrl_req *cq) switch (cq->op) { case MISDN_CTRL_GETOP: - cq->op = MISDN_CTRL_LOOP; + cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_L1_TIMER3; break; case MISDN_CTRL_LOOP: /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */ @@ -847,6 +847,9 @@ channel_ctrl(struct tiger_hw *card, struct mISDN_ctrl_req *cq) } ret = card->isac.ctrl(&card->isac, HW_TESTLOOP, cq->channel); break; + case MISDN_CTRL_L1_TIMER3: + ret = card->isac.ctrl(&card->isac, HW_TIMER3_VALUE, cq->p1); + break; default: pr_info("%s: %s unknown Op %x\n", card->name, __func__, cq->op); ret = -EINVAL; -- cgit v1.2.3-70-g09d2 From 1368112c07bae879fa3d1c21f236ca8eea3e5e84 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Tue, 15 May 2012 23:51:01 +0000 Subject: mISDN: Cleanup channel also if it already was deactivated If a channel was closed after it was deactivated it could happen that something was not proper resetted. The test if a channel is still activ was wrong, so remove it and always do the cleanup. Signed-off-by: Karsten Keil Signed-off-by: David S. Miller --- drivers/isdn/hardware/mISDN/avmfritz.c | 12 ++++-------- drivers/isdn/hardware/mISDN/hfcmulti.c | 3 +-- drivers/isdn/hardware/mISDN/hfcpci.c | 3 +-- drivers/isdn/hardware/mISDN/hfcsusb.c | 3 +-- drivers/isdn/hardware/mISDN/mISDNipac.c | 13 ++++--------- drivers/isdn/hardware/mISDN/mISDNisar.c | 13 ++++--------- drivers/isdn/hardware/mISDN/netjet.c | 12 ++++-------- drivers/isdn/hardware/mISDN/w6692.c | 13 ++++--------- 8 files changed, 23 insertions(+), 49 deletions(-) (limited to 'drivers/isdn/hardware/mISDN/netjet.c') diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c index 6bf2c58795a..2271f2b7d50 100644 --- a/drivers/isdn/hardware/mISDN/avmfritz.c +++ b/drivers/isdn/hardware/mISDN/avmfritz.c @@ -839,14 +839,10 @@ avm_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) switch (cmd) { case CLOSE_CHANNEL: test_and_clear_bit(FLG_OPEN, &bch->Flags); - if (test_bit(FLG_ACTIVE, &bch->Flags)) { - spin_lock_irqsave(&fc->lock, flags); - mISDN_freebchannel(bch); - test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); - test_and_clear_bit(FLG_ACTIVE, &bch->Flags); - modehdlc(bch, ISDN_P_NONE); - spin_unlock_irqrestore(&fc->lock, flags); - } + spin_lock_irqsave(&fc->lock, flags); + mISDN_freebchannel(bch); + modehdlc(bch, ISDN_P_NONE); + spin_unlock_irqrestore(&fc->lock, flags); ch->protocol = ISDN_P_NONE; ch->peer = NULL; module_put(THIS_MODULE); diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index 9f4e2efa7ff..1dae761d973 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -3725,8 +3725,7 @@ hfcm_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) switch (cmd) { case CLOSE_CHANNEL: test_and_clear_bit(FLG_OPEN, &bch->Flags); - if (test_bit(FLG_ACTIVE, &bch->Flags)) - deactivate_bchannel(bch); /* locked there */ + deactivate_bchannel(bch); /* locked there */ ch->protocol = ISDN_P_NONE; ch->peer = NULL; module_put(THIS_MODULE); diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 5fe993e2dee..f7a5ea7988e 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -1581,8 +1581,7 @@ hfc_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) break; case CLOSE_CHANNEL: test_and_clear_bit(FLG_OPEN, &bch->Flags); - if (test_bit(FLG_ACTIVE, &bch->Flags)) - deactivate_bchannel(bch); + deactivate_bchannel(bch); ch->protocol = ISDN_P_NONE; ch->peer = NULL; module_put(THIS_MODULE); diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c index 8cde2a0538a..add28acd54d 100644 --- a/drivers/isdn/hardware/mISDN/hfcsusb.c +++ b/drivers/isdn/hardware/mISDN/hfcsusb.c @@ -1836,8 +1836,7 @@ hfc_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) case CLOSE_CHANNEL: test_and_clear_bit(FLG_OPEN, &bch->Flags); - if (test_bit(FLG_ACTIVE, &bch->Flags)) - deactivate_bchannel(bch); + deactivate_bchannel(bch); ch->protocol = ISDN_P_NONE; ch->peer = NULL; module_put(THIS_MODULE); diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c index 92d4a78bc0a..6c044d55536 100644 --- a/drivers/isdn/hardware/mISDN/mISDNipac.c +++ b/drivers/isdn/hardware/mISDN/mISDNipac.c @@ -1420,15 +1420,10 @@ hscx_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) switch (cmd) { case CLOSE_CHANNEL: test_and_clear_bit(FLG_OPEN, &bch->Flags); - if (test_bit(FLG_ACTIVE, &bch->Flags)) { - spin_lock_irqsave(hx->ip->hwlock, flags); - mISDN_freebchannel(bch); - hscx_mode(hx, ISDN_P_NONE); - spin_unlock_irqrestore(hx->ip->hwlock, flags); - } else { - skb_queue_purge(&bch->rqueue); - bch->rcount = 0; - } + spin_lock_irqsave(hx->ip->hwlock, flags); + mISDN_freebchannel(bch); + hscx_mode(hx, ISDN_P_NONE); + spin_unlock_irqrestore(hx->ip->hwlock, flags); ch->protocol = ISDN_P_NONE; ch->peer = NULL; module_put(hx->ip->owner); diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c index 9a6da6edcfa..af9a966a1fd 100644 --- a/drivers/isdn/hardware/mISDN/mISDNisar.c +++ b/drivers/isdn/hardware/mISDN/mISDNisar.c @@ -1603,15 +1603,10 @@ isar_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) switch (cmd) { case CLOSE_CHANNEL: test_and_clear_bit(FLG_OPEN, &bch->Flags); - if (test_bit(FLG_ACTIVE, &bch->Flags)) { - spin_lock_irqsave(ich->is->hwlock, flags); - mISDN_freebchannel(bch); - modeisar(ich, ISDN_P_NONE); - spin_unlock_irqrestore(ich->is->hwlock, flags); - } else { - skb_queue_purge(&bch->rqueue); - bch->rcount = 0; - } + spin_lock_irqsave(ich->is->hwlock, flags); + mISDN_freebchannel(bch); + modeisar(ich, ISDN_P_NONE); + spin_unlock_irqrestore(ich->is->hwlock, flags); ch->protocol = ISDN_P_NONE; ch->peer = NULL; module_put(ich->is->owner); diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c index 27998d7188a..55a77ed7b17 100644 --- a/drivers/isdn/hardware/mISDN/netjet.c +++ b/drivers/isdn/hardware/mISDN/netjet.c @@ -808,14 +808,10 @@ nj_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) switch (cmd) { case CLOSE_CHANNEL: test_and_clear_bit(FLG_OPEN, &bch->Flags); - if (test_bit(FLG_ACTIVE, &bch->Flags)) { - spin_lock_irqsave(&card->lock, flags); - mISDN_freebchannel(bch); - test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); - test_and_clear_bit(FLG_ACTIVE, &bch->Flags); - mode_tiger(bc, ISDN_P_NONE); - spin_unlock_irqrestore(&card->lock, flags); - } + spin_lock_irqsave(&card->lock, flags); + mISDN_freebchannel(bch); + mode_tiger(bc, ISDN_P_NONE); + spin_unlock_irqrestore(&card->lock, flags); ch->protocol = ISDN_P_NONE; ch->peer = NULL; module_put(THIS_MODULE); diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c index 1d044670ff6..0b5e9297e95 100644 --- a/drivers/isdn/hardware/mISDN/w6692.c +++ b/drivers/isdn/hardware/mISDN/w6692.c @@ -1061,15 +1061,10 @@ w6692_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg) switch (cmd) { case CLOSE_CHANNEL: test_and_clear_bit(FLG_OPEN, &bch->Flags); - if (test_bit(FLG_ACTIVE, &bch->Flags)) { - spin_lock_irqsave(&card->lock, flags); - mISDN_freebchannel(bch); - w6692_mode(bc, ISDN_P_NONE); - spin_unlock_irqrestore(&card->lock, flags); - } else { - skb_queue_purge(&bch->rqueue); - bch->rcount = 0; - } + spin_lock_irqsave(&card->lock, flags); + mISDN_freebchannel(bch); + w6692_mode(bc, ISDN_P_NONE); + spin_unlock_irqrestore(&card->lock, flags); ch->protocol = ISDN_P_NONE; ch->peer = NULL; module_put(THIS_MODULE); -- cgit v1.2.3-70-g09d2 From 8bfddfbe2100862fd39b97001d0559ccd4c77f19 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Tue, 15 May 2012 23:51:02 +0000 Subject: 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 Signed-off-by: David S. Miller --- drivers/isdn/hardware/mISDN/avmfritz.c | 21 ++++++--------------- drivers/isdn/hardware/mISDN/hfcmulti.c | 21 +++++---------------- drivers/isdn/hardware/mISDN/hfcpci.c | 14 +++----------- drivers/isdn/hardware/mISDN/hfcsusb.c | 15 ++------------- drivers/isdn/hardware/mISDN/mISDNipac.c | 21 ++++++--------------- drivers/isdn/hardware/mISDN/mISDNisar.c | 18 +++++------------- drivers/isdn/hardware/mISDN/netjet.c | 21 ++++++--------------- drivers/isdn/hardware/mISDN/w6692.c | 21 ++++++--------------- drivers/isdn/mISDN/hwchannel.c | 8 ++++---- include/linux/mISDNhw.h | 1 - 10 files changed, 43 insertions(+), 118 deletions(-) (limited to 'drivers/isdn/hardware/mISDN/netjet.c') diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c index 2271f2b7d50..788b9a7c4df 100644 --- a/drivers/isdn/hardware/mISDN/avmfritz.c +++ b/drivers/isdn/hardware/mISDN/avmfritz.c @@ -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); diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index 1dae761d973..ab3d2983e3a 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -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) diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index f7a5ea7988e..123e8e5e57b 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -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); diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c index add28acd54d..a4c5b24b226 100644 --- a/drivers/isdn/hardware/mISDN/hfcsusb.c +++ b/drivers/isdn/hardware/mISDN/hfcsusb.c @@ -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); diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c index 6c044d55536..e4b6d8d51aa 100644 --- a/drivers/isdn/hardware/mISDN/mISDNipac.c +++ b/drivers/isdn/hardware/mISDN/mISDNipac.c @@ -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); diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c index af9a966a1fd..9deea88c994 100644 --- a/drivers/isdn/hardware/mISDN/mISDNisar.c +++ b/drivers/isdn/hardware/mISDN/mISDNisar.c @@ -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); diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c index 55a77ed7b17..da13b07cd85 100644 --- a/drivers/isdn/hardware/mISDN/netjet.c +++ b/drivers/isdn/hardware/mISDN/netjet.c @@ -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); diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c index 0b5e9297e95..f1c0bf1ac68 100644 --- a/drivers/isdn/hardware/mISDN/w6692.c +++ b/drivers/isdn/hardware/mISDN/w6692.c @@ -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); diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c index c74c363554c..5c5ab478f66 100644 --- a/drivers/isdn/mISDN/hwchannel.c +++ b/drivers/isdn/mISDN/hwchannel.c @@ -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; } } diff --git a/include/linux/mISDNhw.h b/include/linux/mISDNhw.h index de165b54237..491afd6d570 100644 --- a/include/linux/mISDNhw.h +++ b/include/linux/mISDNhw.h @@ -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 *); -- cgit v1.2.3-70-g09d2 From 7206e659f689558b41aa058c3040b081cb281d03 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Tue, 15 May 2012 23:51:05 +0000 Subject: mISDN: Reduce RX buffer allocation for transparent data We did allways allocate maxsize buffers, but for transparent data we know the actual size. Use a common function to calculate size and detect overflows. Signed-off-by: Karsten Keil Signed-off-by: David S. Miller --- drivers/isdn/hardware/mISDN/avmfritz.c | 18 +++----- drivers/isdn/hardware/mISDN/hfcmulti.c | 61 +++++++++++-------------- drivers/isdn/hardware/mISDN/hfcpci.c | 11 ++--- drivers/isdn/hardware/mISDN/hfcsusb.c | 52 ++++++++++------------ drivers/isdn/hardware/mISDN/mISDNipac.c | 20 +++------ drivers/isdn/hardware/mISDN/mISDNisar.c | 37 +++++---------- drivers/isdn/hardware/mISDN/netjet.c | 79 ++++++++++++++------------------- drivers/isdn/hardware/mISDN/w6692.c | 20 +++------ drivers/isdn/mISDN/hwchannel.c | 75 ++++++++++++++++++++++++++----- include/linux/mISDNhw.h | 1 + 10 files changed, 186 insertions(+), 188 deletions(-) (limited to 'drivers/isdn/hardware/mISDN/netjet.c') diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c index cc782646886..808136735f3 100644 --- a/drivers/isdn/hardware/mISDN/avmfritz.c +++ b/drivers/isdn/hardware/mISDN/avmfritz.c @@ -404,21 +404,14 @@ hdlc_empty_fifo(struct bchannel *bch, int count) u32 *ptr; u8 *p; u32 val, addr; - int cnt = 0; + int cnt; struct fritzcard *fc = bch->hw; pr_debug("%s: %s %d\n", fc->name, __func__, count); - if (!bch->rx_skb) { - bch->rx_skb = mI_alloc_skb(bch->maxlen, GFP_ATOMIC); - if (!bch->rx_skb) { - pr_info("%s: B receive out of memory\n", - fc->name); - return; - } - } - if ((bch->rx_skb->len + count) > bch->maxlen) { - pr_debug("%s: overrun %d\n", fc->name, - bch->rx_skb->len + count); + cnt = bchannel_get_rxbuf(bch, count); + if (cnt < 0) { + pr_warning("%s.B%d: No bufferspace for %d bytes\n", + fc->name, bch->nr, count); return; } p = skb_put(bch->rx_skb, count); @@ -430,6 +423,7 @@ hdlc_empty_fifo(struct bchannel *bch, int count) addr = fc->addr + CHIP_WINDOW; outl(bch->nr == 2 ? AVM_HDLC_2 : AVM_HDLC_1, fc->addr); } + cnt = 0; while (cnt < count) { val = le32_to_cpu(inl(addr)); put_unaligned(val, ptr); diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index ab3d2983e3a..60dd6efa187 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -2196,24 +2196,20 @@ hfcmulti_rx(struct hfc_multi *hc, int ch) int f1 = 0, f2 = 0; /* = 0, to make GCC happy */ int again = 0; struct bchannel *bch; - struct dchannel *dch; + struct dchannel *dch = NULL; struct sk_buff *skb, **sp = NULL; int maxlen; bch = hc->chan[ch].bch; - dch = hc->chan[ch].dch; - if ((!dch) && (!bch)) - return; - if (dch) { + if (bch) { + if (!test_bit(FLG_ACTIVE, &bch->Flags)) + return; + } else if (hc->chan[ch].dch) { + dch = hc->chan[ch].dch; if (!test_bit(FLG_ACTIVE, &dch->Flags)) return; - sp = &dch->rx_skb; - maxlen = dch->maxlen; } else { - if (!test_bit(FLG_ACTIVE, &bch->Flags)) - return; - sp = &bch->rx_skb; - maxlen = bch->maxlen; + return; } next_frame: /* on first AND before getting next valid frame, R_FIFO must be written @@ -2260,13 +2256,26 @@ next_frame: if (Zsize <= 0) return; - if (*sp == NULL) { - *sp = mI_alloc_skb(maxlen + 3, GFP_ATOMIC); - if (*sp == NULL) { - printk(KERN_DEBUG "%s: No mem for rx_skb\n", - __func__); + if (bch) { + maxlen = bchannel_get_rxbuf(bch, Zsize); + if (maxlen < 0) { + pr_warning("card%d.B%d: No bufferspace for %d bytes\n", + hc->id + 1, bch->nr, Zsize); return; } + sp = &bch->rx_skb; + maxlen = bch->maxlen; + } else { /* Dchannel */ + sp = &dch->rx_skb; + maxlen = dch->maxlen + 3; + if (*sp == NULL) { + *sp = mI_alloc_skb(maxlen, GFP_ATOMIC); + if (*sp == NULL) { + pr_warning("card%d: No mem for dch rx_skb\n", + hc->id + 1); + return; + } + } } /* show activity */ if (dch) @@ -2281,7 +2290,7 @@ next_frame: Zsize, z1, z2, (f1 == f2) ? "fragment" : "COMPLETE", f1, f2, Zsize + (*sp)->len, again); /* HDLC */ - if ((Zsize + (*sp)->len) > (maxlen + 3)) { + if ((Zsize + (*sp)->len) > maxlen) { if (debug & DEBUG_HFCMULTI_FIFO) printk(KERN_DEBUG "%s(card %d): hdlc-frame too large.\n", @@ -2351,24 +2360,7 @@ next_frame: /* there is an incomplete frame */ } else { /* transparent */ - if (Zsize > skb_tailroom(*sp)) - Zsize = skb_tailroom(*sp); hc->read_fifo(hc, skb_put(*sp, Zsize), Zsize); - if (((*sp)->len) < MISDN_COPY_SIZE) { - skb = *sp; - *sp = mI_alloc_skb(skb->len, GFP_ATOMIC); - if (*sp) { - memcpy(skb_put(*sp, skb->len), - skb->data, skb->len); - skb_trim(skb, 0); - } else { - printk(KERN_DEBUG "%s: No mem\n", __func__); - *sp = skb; - skb = NULL; - } - } else { - skb = NULL; - } if (debug & DEBUG_HFCMULTI_FIFO) printk(KERN_DEBUG "%s(card %d): fifo(%d) reading %d bytes " @@ -2376,7 +2368,6 @@ next_frame: __func__, hc->id + 1, ch, Zsize, z1, z2); /* only bch is transparent */ recv_Bchannel(bch, hc->chan[ch].Zfill); - *sp = skb; } } diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 123e8e5e57b..0622e05ae06 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -577,8 +577,11 @@ hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *rxbz, fcnt_tx = B_FIFO_SIZE - fcnt_tx; /* remaining bytes to send (bytes in tx-fifo) */ - bch->rx_skb = mI_alloc_skb(fcnt_rx, GFP_ATOMIC); - if (bch->rx_skb) { + maxlen = bchannel_get_rxbuf(bch, fcnt_rx); + if (maxlen < 0) { + pr_warning("B%d: No bufferspace for %d bytes\n", + bch->nr, fcnt_rx); + } else { ptr = skb_put(bch->rx_skb, fcnt_rx); if (le16_to_cpu(*z2r) + fcnt_rx <= B_FIFO_SIZE + B_SUB_VAL) maxlen = fcnt_rx; /* complete transfer */ @@ -597,9 +600,7 @@ hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *rxbz, memcpy(ptr, ptr1, fcnt_rx); /* rest */ } recv_Bchannel(bch, fcnt_tx); /* bch, id */ - } else - printk(KERN_WARNING "HFCPCI: receive out of memory\n"); - + } *z2r = cpu_to_le16(new_z2); /* new position */ } diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c index 919ecccb993..6bb689b8d66 100644 --- a/drivers/isdn/hardware/mISDN/hfcsusb.c +++ b/drivers/isdn/hardware/mISDN/hfcsusb.c @@ -860,7 +860,16 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len, hdlc = 1; } if (fifo->bch) { + maxlen = bchannel_get_rxbuf(fifo->bch, len); rx_skb = fifo->bch->rx_skb; + if (maxlen < 0) { + if (rx_skb) + skb_trim(rx_skb, 0); + pr_warning("%s.B%d: No bufferspace for %d bytes\n", + hw->name, fifo->bch->nr, len); + spin_unlock(&hw->lock); + return; + } maxlen = fifo->bch->maxlen; hdlc = test_bit(FLG_HDLC, &fifo->bch->Flags); } @@ -870,25 +879,22 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len, hdlc = 1; } - if (!rx_skb) { - rx_skb = mI_alloc_skb(maxlen, GFP_ATOMIC); - if (rx_skb) { - if (fifo->dch) - fifo->dch->rx_skb = rx_skb; - if (fifo->bch) - fifo->bch->rx_skb = rx_skb; - if (fifo->ech) - fifo->ech->rx_skb = rx_skb; - skb_trim(rx_skb, 0); - } else { - printk(KERN_DEBUG "%s: %s: No mem for rx_skb\n", - hw->name, __func__); - spin_unlock(&hw->lock); - return; - } - } - if (fifo->dch || fifo->ech) { + if (!rx_skb) { + rx_skb = mI_alloc_skb(maxlen, GFP_ATOMIC); + if (rx_skb) { + if (fifo->dch) + fifo->dch->rx_skb = rx_skb; + if (fifo->ech) + fifo->ech->rx_skb = rx_skb; + skb_trim(rx_skb, 0); + } else { + printk(KERN_DEBUG "%s: %s: No mem for rx_skb\n", + hw->name, __func__); + spin_unlock(&hw->lock); + return; + } + } /* D/E-Channel SKB range check */ if ((rx_skb->len + len) >= MAX_DFRAME_LEN_L1) { printk(KERN_DEBUG "%s: %s: sbk mem exceeded " @@ -898,16 +904,6 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len, spin_unlock(&hw->lock); return; } - } else if (fifo->bch) { - /* B-Channel SKB range check */ - if ((rx_skb->len + len) >= (MAX_BCH_SIZE + 3)) { - printk(KERN_DEBUG "%s: %s: sbk mem exceeded " - "for fifo(%d) HFCUSB_B_RX\n", - hw->name, __func__, fifon); - skb_trim(rx_skb, 0); - spin_unlock(&hw->lock); - return; - } } memcpy(skb_put(rx_skb, len), data, len); diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c index e4b6d8d51aa..7d109ed3536 100644 --- a/drivers/isdn/hardware/mISDN/mISDNipac.c +++ b/drivers/isdn/hardware/mISDN/mISDNipac.c @@ -933,22 +933,16 @@ static void hscx_empty_fifo(struct hscx_hw *hscx, u8 count) { u8 *p; + int maxlen; pr_debug("%s: B%1d %d\n", hscx->ip->name, hscx->bch.nr, count); - if (!hscx->bch.rx_skb) { - hscx->bch.rx_skb = mI_alloc_skb(hscx->bch.maxlen, GFP_ATOMIC); - if (!hscx->bch.rx_skb) { - pr_info("%s: B receive out of memory\n", - hscx->ip->name); - hscx_cmdr(hscx, 0x80); /* RMC */ - return; - } - } - if ((hscx->bch.rx_skb->len + count) > hscx->bch.maxlen) { - pr_debug("%s: overrun %d\n", hscx->ip->name, - hscx->bch.rx_skb->len + count); - skb_trim(hscx->bch.rx_skb, 0); + maxlen = bchannel_get_rxbuf(&hscx->bch, count); + if (maxlen < 0) { hscx_cmdr(hscx, 0x80); /* RMC */ + if (hscx->bch.rx_skb) + skb_trim(hscx->bch.rx_skb, 0); + pr_warning("%s.B%d: No bufferspace for %d bytes\n", + hscx->ip->name, hscx->bch.nr, count); return; } p = skb_put(hscx->bch.rx_skb, count); diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c index 9deea88c994..4169bb2db19 100644 --- a/drivers/isdn/hardware/mISDN/mISDNisar.c +++ b/drivers/isdn/hardware/mISDN/mISDNisar.c @@ -421,7 +421,8 @@ deliver_status(struct isar_ch *ch, int status) static inline void isar_rcv_frame(struct isar_ch *ch) { - u8 *ptr; + u8 *ptr; + int maxlen; if (!ch->is->clsb) { pr_debug("%s; ISAR zero len frame\n", ch->is->name); @@ -437,36 +438,22 @@ isar_rcv_frame(struct isar_ch *ch) case ISDN_P_B_RAW: case ISDN_P_B_L2DTMF: case ISDN_P_B_MODEM_ASYNC: - if (!ch->bch.rx_skb) { - ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen, - GFP_ATOMIC); - if (unlikely(!ch->bch.rx_skb)) { - pr_info("%s: B receive out of memory\n", - ch->is->name); - ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); - break; - } + maxlen = bchannel_get_rxbuf(&ch->bch, ch->is->clsb); + if (maxlen < 0) { + pr_warning("%s.B%d: No bufferspace for %d bytes\n", + ch->is->name, ch->bch.nr, ch->is->clsb); + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + break; } rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb)); recv_Bchannel(&ch->bch, 0); break; case ISDN_P_B_HDLC: - if (!ch->bch.rx_skb) { - ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen, - GFP_ATOMIC); - if (unlikely(!ch->bch.rx_skb)) { - pr_info("%s: B receive out of memory\n", - ch->is->name); - ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); - break; - } - } - if ((ch->bch.rx_skb->len + ch->is->clsb) > - (ch->bch.maxlen + 2)) { - pr_debug("%s: incoming packet too large\n", - ch->is->name); + maxlen = bchannel_get_rxbuf(&ch->bch, ch->is->clsb); + if (maxlen < 0) { + pr_warning("%s.B%d: No bufferspace for %d bytes\n", + ch->is->name, ch->bch.nr, ch->is->clsb); ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); - skb_trim(ch->bch.rx_skb, 0); break; } if (ch->is->cmsb & HDLC_ERROR) { diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c index da13b07cd85..3f28057e725 100644 --- a/drivers/isdn/hardware/mISDN/netjet.c +++ b/drivers/isdn/hardware/mISDN/netjet.c @@ -386,24 +386,16 @@ read_dma(struct tiger_ch *bc, u32 idx, int cnt) bc->bch.nr, idx); } bc->lastrx = idx; - if (!bc->bch.rx_skb) { - bc->bch.rx_skb = mI_alloc_skb(bc->bch.maxlen, GFP_ATOMIC); - if (!bc->bch.rx_skb) { - pr_info("%s: B%1d receive out of memory\n", - card->name, bc->bch.nr); - return; - } + stat = bchannel_get_rxbuf(&bc->bch, cnt); + /* only transparent use the count here, HDLC overun is detected later */ + if (stat == ENOMEM) { + pr_warning("%s.B%d: No memory for %d bytes\n", + card->name, bc->bch.nr, cnt); + return; } - - if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags)) { - if ((bc->bch.rx_skb->len + cnt) > bc->bch.maxlen) { - pr_debug("%s: B%1d overrun %d\n", card->name, - bc->bch.nr, bc->bch.rx_skb->len + cnt); - skb_trim(bc->bch.rx_skb, 0); - return; - } + if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags)) p = skb_put(bc->bch.rx_skb, cnt); - } else + else p = bc->hrbuf; for (i = 0; i < cnt; i++) { @@ -414,48 +406,45 @@ read_dma(struct tiger_ch *bc, u32 idx, int cnt) idx = 0; p[i] = val & 0xff; } + + if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags)) { + recv_Bchannel(&bc->bch, 0); + return; + } + pn = bc->hrbuf; -next_frame: - if (test_bit(FLG_HDLC, &bc->bch.Flags)) { + while (cnt > 0) { stat = isdnhdlc_decode(&bc->hrecv, pn, cnt, &i, bc->bch.rx_skb->data, bc->bch.maxlen); - if (stat > 0) /* valid frame received */ + if (stat > 0) { /* valid frame received */ p = skb_put(bc->bch.rx_skb, stat); - else if (stat == -HDLC_CRC_ERROR) + if (debug & DEBUG_HW_BFIFO) { + snprintf(card->log, LOG_SIZE, + "B%1d-recv %s %d ", bc->bch.nr, + card->name, stat); + print_hex_dump_bytes(card->log, + DUMP_PREFIX_OFFSET, p, + stat); + } + recv_Bchannel(&bc->bch, 0); + stat = bchannel_get_rxbuf(&bc->bch, bc->bch.maxlen); + if (stat < 0) { + pr_warning("%s.B%d: No memory for %d bytes\n", + card->name, bc->bch.nr, cnt); + return; + } + } else if (stat == -HDLC_CRC_ERROR) { pr_info("%s: B%1d receive frame CRC error\n", card->name, bc->bch.nr); - else if (stat == -HDLC_FRAMING_ERROR) + } else if (stat == -HDLC_FRAMING_ERROR) { pr_info("%s: B%1d receive framing error\n", card->name, bc->bch.nr); - else if (stat == -HDLC_LENGTH_ERROR) + } else if (stat == -HDLC_LENGTH_ERROR) { pr_info("%s: B%1d receive frame too long (> %d)\n", card->name, bc->bch.nr, bc->bch.maxlen); - } else - stat = cnt; - - if (stat > 0) { - if (debug & DEBUG_HW_BFIFO) { - snprintf(card->log, LOG_SIZE, "B%1d-recv %s %d ", - bc->bch.nr, card->name, stat); - print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, - p, stat); } - recv_Bchannel(&bc->bch, 0); - } - if (test_bit(FLG_HDLC, &bc->bch.Flags)) { pn += i; cnt -= i; - if (!bc->bch.rx_skb) { - bc->bch.rx_skb = mI_alloc_skb(bc->bch.maxlen, - GFP_ATOMIC); - if (!bc->bch.rx_skb) { - pr_info("%s: B%1d receive out of memory\n", - card->name, bc->bch.nr); - return; - } - } - if (cnt > 0) - goto next_frame; } } diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c index f1c0bf1ac68..8324b20c7f1 100644 --- a/drivers/isdn/hardware/mISDN/w6692.c +++ b/drivers/isdn/hardware/mISDN/w6692.c @@ -465,6 +465,7 @@ W6692_empty_Bfifo(struct w6692_ch *wch, int count) { struct w6692_hw *card = wch->bch.hw; u8 *ptr; + int maxlen; pr_debug("%s: empty_Bfifo %d\n", card->name, count); if (unlikely(wch->bch.state == ISDN_P_NONE)) { @@ -474,20 +475,13 @@ W6692_empty_Bfifo(struct w6692_ch *wch, int count) skb_trim(wch->bch.rx_skb, 0); return; } - if (!wch->bch.rx_skb) { - wch->bch.rx_skb = mI_alloc_skb(wch->bch.maxlen, GFP_ATOMIC); - if (unlikely(!wch->bch.rx_skb)) { - pr_info("%s: B receive out of memory\n", card->name); - WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | - W_B_CMDR_RACT); - return; - } - } - if (wch->bch.rx_skb->len + count > wch->bch.maxlen) { - pr_debug("%s: empty_Bfifo incoming packet too large\n", - card->name); + maxlen = bchannel_get_rxbuf(&wch->bch, count); + if (maxlen < 0) { WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); - skb_trim(wch->bch.rx_skb, 0); + if (wch->bch.rx_skb) + skb_trim(wch->bch.rx_skb, 0); + pr_warning("%s.B%d: No bufferspace for %d bytes\n", + card->name, wch->bch.nr, count); return; } ptr = skb_put(wch->bch.rx_skb, count); diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c index 5c5ab478f66..3c2145d8c3f 100644 --- a/drivers/isdn/mISDN/hwchannel.c +++ b/drivers/isdn/mISDN/hwchannel.c @@ -201,20 +201,30 @@ recv_Bchannel(struct bchannel *bch, unsigned int id) { struct mISDNhead *hh; - hh = mISDN_HEAD_P(bch->rx_skb); - hh->prim = PH_DATA_IND; - hh->id = id; - if (bch->rcount >= 64) { - printk(KERN_WARNING "B-channel %p receive queue overflow, " - "flushing!\n", bch); - skb_queue_purge(&bch->rqueue); - bch->rcount = 0; + /* if allocation did fail upper functions still may call us */ + if (unlikely(!bch->rx_skb)) return; + if (unlikely(!bch->rx_skb->len)) { + /* we have no data to send - this may happen after recovery + * from overflow or too small allocation. + * We need to free the buffer here */ + dev_kfree_skb(bch->rx_skb); + bch->rx_skb = NULL; + } else { + hh = mISDN_HEAD_P(bch->rx_skb); + hh->prim = PH_DATA_IND; + hh->id = id; + if (bch->rcount >= 64) { + printk(KERN_WARNING + "B%d receive queue overflow - flushing!\n", + bch->nr); + skb_queue_purge(&bch->rqueue); + } + bch->rcount++; + skb_queue_tail(&bch->rqueue, bch->rx_skb); + bch->rx_skb = NULL; + schedule_event(bch, FLG_RECVQUEUE); } - bch->rcount++; - skb_queue_tail(&bch->rqueue, bch->rx_skb); - bch->rx_skb = NULL; - schedule_event(bch, FLG_RECVQUEUE); } EXPORT_SYMBOL(recv_Bchannel); @@ -399,3 +409,44 @@ bchannel_senddata(struct bchannel *ch, struct sk_buff *skb) } } EXPORT_SYMBOL(bchannel_senddata); + +/* The function allocates a new receive skb on demand with a size for the + * requirements of the current protocol. It returns the tailroom of the + * receive skb or an error. + */ +int +bchannel_get_rxbuf(struct bchannel *bch, int reqlen) +{ + int len; + + if (bch->rx_skb) { + len = skb_tailroom(bch->rx_skb); + if (len < reqlen) { + pr_warning("B%d no space for %d (only %d) bytes\n", + bch->nr, reqlen, len); + if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { + /* send what we have now and try a new buffer */ + recv_Bchannel(bch, 0); + } else { + /* on HDLC we have to drop too big frames */ + return -EMSGSIZE; + } + } else { + return len; + } + } + if (unlikely(reqlen > bch->maxlen)) + return -EMSGSIZE; + if (test_bit(FLG_TRANSPARENT, &bch->Flags)) + len = reqlen; + else /* with HDLC we do not know the length yet */ + len = bch->maxlen; + bch->rx_skb = mI_alloc_skb(len, GFP_ATOMIC); + if (!bch->rx_skb) { + pr_warning("B%d receive no memory for %d bytes\n", + bch->nr, len); + len = -ENOMEM; + } + return len; +} +EXPORT_SYMBOL(bchannel_get_rxbuf); diff --git a/include/linux/mISDNhw.h b/include/linux/mISDNhw.h index 491afd6d570..a86d86beff7 100644 --- a/include/linux/mISDNhw.h +++ b/include/linux/mISDNhw.h @@ -177,6 +177,7 @@ extern void queue_ch_frame(struct mISDNchannel *, u_int, int, struct sk_buff *); extern int dchannel_senddata(struct dchannel *, struct sk_buff *); extern int bchannel_senddata(struct bchannel *, struct sk_buff *); +extern int bchannel_get_rxbuf(struct bchannel *, int); extern void recv_Dchannel(struct dchannel *); extern void recv_Echannel(struct dchannel *, struct dchannel *); extern void recv_Bchannel(struct bchannel *, unsigned int id); -- cgit v1.2.3-70-g09d2 From 034005a0119b9c2aabe0ac3953eb9a65ca937a69 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Tue, 15 May 2012 23:51:06 +0000 Subject: mISDN: Allow to set a minimum length for transparent data If the FIFO of the card is small, many short messages are queued up to the upper layers and the userspace. This change allows the applications to set a minimum datalen they want from the drivers. Create a common control function to avoid code duplication in each driver. Signed-off-by: Karsten Keil Signed-off-by: David S. Miller --- drivers/isdn/hardware/mISDN/avmfritz.c | 35 +++++++----------- drivers/isdn/hardware/mISDN/hfcmulti.c | 17 ++++----- drivers/isdn/hardware/mISDN/hfcpci.c | 12 +++--- drivers/isdn/hardware/mISDN/hfcsusb.c | 14 +++---- drivers/isdn/hardware/mISDN/mISDNipac.c | 27 +++----------- drivers/isdn/hardware/mISDN/mISDNisar.c | 25 +++---------- drivers/isdn/hardware/mISDN/netjet.c | 23 +++--------- drivers/isdn/hardware/mISDN/w6692.c | 25 +++---------- drivers/isdn/mISDN/hwchannel.c | 65 ++++++++++++++++++++++++++++++--- drivers/isdn/mISDN/l1oip_core.c | 2 +- include/linux/mISDNhw.h | 13 +++++-- include/linux/mISDNif.h | 9 ++++- 12 files changed, 135 insertions(+), 132 deletions(-) (limited to 'drivers/isdn/hardware/mISDN/netjet.c') diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c index 808136735f3..7cd3a963ed2 100644 --- a/drivers/isdn/hardware/mISDN/avmfritz.c +++ b/drivers/isdn/hardware/mISDN/avmfritz.c @@ -536,12 +536,12 @@ HDLC_irq(struct bchannel *bch, u32 stat) hdlc_empty_fifo(bch, len); if (!bch->rx_skb) goto handle_tx; - if (test_bit(FLG_TRANSPARENT, &bch->Flags) || - (stat & HDLC_STAT_RME)) { - if (((stat & HDLC_STAT_CRCVFRRAB) == - HDLC_STAT_CRCVFR) || - test_bit(FLG_TRANSPARENT, &bch->Flags)) { - recv_Bchannel(bch, 0); + if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { + recv_Bchannel(bch, 0, false); + } else if (stat & HDLC_STAT_RME) { + if ((stat & HDLC_STAT_CRCVFRRAB) == + HDLC_STAT_CRCVFR) { + recv_Bchannel(bch, 0, false); } else { pr_warning("%s: got invalid frame\n", fc->name); @@ -809,21 +809,7 @@ init_card(struct fritzcard *fc) static int channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) { - int ret = 0; - struct fritzcard *fc = bch->hw; - - switch (cq->op) { - case MISDN_CTRL_GETOP: - cq->op = 0; - break; - /* Nothing implemented yet */ - case MISDN_CTRL_FILL_EMPTY: - default: - pr_info("%s: %s unknown Op %x\n", fc->name, __func__, cq->op); - ret = -EINVAL; - break; - } - return ret; + return mISDN_ctrl_bchannel(bch, cq); } static int @@ -1019,6 +1005,7 @@ static int __devinit setup_instance(struct fritzcard *card) { int i, err; + unsigned short minsize; u_long flags; snprintf(card->name, MISDN_MAX_IDLEN - 1, "AVM.%d", AVM_cnt + 1); @@ -1038,7 +1025,11 @@ setup_instance(struct fritzcard *card) for (i = 0; i < 2; i++) { card->bch[i].nr = i + 1; set_channelmap(i + 1, card->isac.dch.dev.channelmap); - mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM); + if (AVM_FRITZ_PCIV2 == card->type) + minsize = HDLC_FIFO_SIZE_V2; + else + minsize = HDLC_FIFO_SIZE_V1; + mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM, minsize); card->bch[i].hw = card; card->bch[i].ch.send = avm_l2l1B; card->bch[i].ch.ctrl = avm_bctrl; diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index 60dd6efa187..3d4b36d2a31 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -2352,7 +2352,7 @@ next_frame: if (dch) recv_Dchannel(dch); else - recv_Bchannel(bch, MISDN_ID_ANY); + recv_Bchannel(bch, MISDN_ID_ANY, false); *sp = skb; again++; goto next_frame; @@ -2367,7 +2367,7 @@ next_frame: "(z1=%04x, z2=%04x) TRANS\n", __func__, hc->id + 1, ch, Zsize, z1, z2); /* only bch is transparent */ - recv_Bchannel(bch, hc->chan[ch].Zfill); + recv_Bchannel(bch, hc->chan[ch].Zfill, false); } } @@ -3574,8 +3574,9 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) switch (cq->op) { case MISDN_CTRL_GETOP: - cq->op = MISDN_CTRL_HFC_OP | MISDN_CTRL_HW_FEATURES_OP - | MISDN_CTRL_RX_OFF | MISDN_CTRL_FILL_EMPTY; + ret = mISDN_ctrl_bchannel(bch, cq); + cq->op |= MISDN_CTRL_HFC_OP | MISDN_CTRL_HW_FEATURES_OP | + MISDN_CTRL_RX_OFF | MISDN_CTRL_FILL_EMPTY; break; case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */ hc->chan[bch->slot].rx_off = !!cq->p1; @@ -3683,9 +3684,7 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) ret = -EINVAL; break; default: - printk(KERN_WARNING "%s: unknown Op %x\n", - __func__, cq->op); - ret = -EINVAL; + ret = mISDN_ctrl_bchannel(bch, cq); break; } return ret; @@ -4855,7 +4854,7 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m, int pt) bch->nr = ch; bch->slot = ch; bch->debug = debug; - mISDN_initbchannel(bch, MAX_DATA_MEM); + mISDN_initbchannel(bch, MAX_DATA_MEM, poll >> 1); bch->hw = hc; bch->ch.send = handle_bmsg; bch->ch.ctrl = hfcm_bctrl; @@ -4928,7 +4927,7 @@ init_multi_port(struct hfc_multi *hc, int pt) bch->nr = ch + 1; bch->slot = i + ch; bch->debug = debug; - mISDN_initbchannel(bch, MAX_DATA_MEM); + mISDN_initbchannel(bch, MAX_DATA_MEM, poll >> 1); bch->hw = hc; bch->ch.send = handle_bmsg; bch->ch.ctrl = hfcm_bctrl; diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 0622e05ae06..27743754ab8 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -453,7 +453,7 @@ hfcpci_empty_bfifo(struct bchannel *bch, struct bzfifo *bz, } bz->za[new_f2].z2 = cpu_to_le16(new_z2); bz->f2 = new_f2; /* next buffer */ - recv_Bchannel(bch, MISDN_ID_ANY); + recv_Bchannel(bch, MISDN_ID_ANY, false); } } @@ -599,7 +599,7 @@ hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *rxbz, ptr1 = bdata; /* start of buffer */ memcpy(ptr, ptr1, fcnt_rx); /* rest */ } - recv_Bchannel(bch, fcnt_tx); /* bch, id */ + recv_Bchannel(bch, fcnt_tx, false); /* bch, id, !force */ } *z2r = cpu_to_le16(new_z2); /* new position */ } @@ -1535,7 +1535,8 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) switch (cq->op) { case MISDN_CTRL_GETOP: - cq->op = MISDN_CTRL_FILL_EMPTY; + ret = mISDN_ctrl_bchannel(bch, cq); + cq->op |= MISDN_CTRL_FILL_EMPTY; break; case MISDN_CTRL_FILL_EMPTY: /* fill fifo, if empty */ test_and_set_bit(FLG_FILLEMPTY, &bch->Flags); @@ -1544,8 +1545,7 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) "off=%d)\n", __func__, bch->nr, !!cq->p1); break; default: - printk(KERN_WARNING "%s: unknown Op %x\n", __func__, cq->op); - ret = -EINVAL; + ret = mISDN_ctrl_bchannel(bch, cq); break; } return ret; @@ -2116,7 +2116,7 @@ setup_card(struct hfc_pci *card) card->bch[i].nr = i + 1; set_channelmap(i + 1, card->dch.dev.channelmap); card->bch[i].debug = debug; - mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM); + mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM, poll >> 1); card->bch[i].hw = card; card->bch[i].ch.send = hfcpci_l2l1B; card->bch[i].ch.ctrl = hfc_bctrl; diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c index 6bb689b8d66..9c17473da83 100644 --- a/drivers/isdn/hardware/mISDN/hfcsusb.c +++ b/drivers/isdn/hardware/mISDN/hfcsusb.c @@ -810,7 +810,8 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) switch (cq->op) { case MISDN_CTRL_GETOP: - cq->op = MISDN_CTRL_FILL_EMPTY; + ret = mISDN_ctrl_bchannel(bch, cq); + cq->op |= MISDN_CTRL_FILL_EMPTY; break; case MISDN_CTRL_FILL_EMPTY: /* fill fifo, if empty */ test_and_set_bit(FLG_FILLEMPTY, &bch->Flags); @@ -819,8 +820,7 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) "off=%d)\n", __func__, bch->nr, !!cq->p1); break; default: - printk(KERN_WARNING "%s: unknown Op %x\n", __func__, cq->op); - ret = -EINVAL; + ret = mISDN_ctrl_bchannel(bch, cq); break; } return ret; @@ -931,7 +931,8 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len, if (fifo->dch) recv_Dchannel(fifo->dch); if (fifo->bch) - recv_Bchannel(fifo->bch, MISDN_ID_ANY); + recv_Bchannel(fifo->bch, MISDN_ID_ANY, + 0); if (fifo->ech) recv_Echannel(fifo->ech, &hw->dch); @@ -952,8 +953,7 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len, } } else { /* deliver transparent data to layer2 */ - if (rx_skb->len >= poll) - recv_Bchannel(fifo->bch, MISDN_ID_ANY); + recv_Bchannel(fifo->bch, MISDN_ID_ANY, false); } spin_unlock(&hw->lock); } @@ -1861,7 +1861,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); + mISDN_initbchannel(&hw->bch[i], MAX_DATA_MEM, poll >> 1); 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/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c index 7d109ed3536..3e71a5ef4bb 100644 --- a/drivers/isdn/hardware/mISDN/mISDNipac.c +++ b/drivers/isdn/hardware/mISDN/mISDNipac.c @@ -1063,7 +1063,7 @@ ipac_rme(struct hscx_hw *hx) skb_trim(hx->bch.rx_skb, 0); } else { skb_trim(hx->bch.rx_skb, hx->bch.rx_skb->len - 1); - recv_Bchannel(&hx->bch, 0); + recv_Bchannel(&hx->bch, 0, false); } } @@ -1114,11 +1114,8 @@ ipac_irq(struct hscx_hw *hx, u8 ista) if (istab & IPACX_B_RPF) { hscx_empty_fifo(hx, hx->fifo_size); - if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) { - /* receive transparent audio data */ - if (hx->bch.rx_skb) - recv_Bchannel(&hx->bch, 0); - } + if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) + recv_Bchannel(&hx->bch, 0, false); } if (istab & IPACX_B_RFO) { @@ -1377,20 +1374,7 @@ hscx_l2l1(struct mISDNchannel *ch, struct sk_buff *skb) static int channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) { - int ret = 0; - - switch (cq->op) { - case MISDN_CTRL_GETOP: - cq->op = 0; - break; - /* Nothing implemented yet */ - case MISDN_CTRL_FILL_EMPTY: - default: - pr_info("%s: unknown Op %x\n", __func__, cq->op); - ret = -EINVAL; - break; - } - return ret; + return mISDN_ctrl_bchannel(bch, cq); } static int @@ -1608,7 +1592,8 @@ mISDNipac_init(struct ipac_hw *ipac, void *hw) set_channelmap(i + 1, ipac->isac.dch.dev.channelmap); list_add(&ipac->hscx[i].bch.ch.list, &ipac->isac.dch.dev.bchannels); - mISDN_initbchannel(&ipac->hscx[i].bch, MAX_DATA_MEM); + mISDN_initbchannel(&ipac->hscx[i].bch, MAX_DATA_MEM, + ipac->hscx[i].fifo_size); ipac->hscx[i].bch.ch.nr = i + 1; ipac->hscx[i].bch.ch.send = &hscx_l2l1; ipac->hscx[i].bch.ch.ctrl = hscx_bctrl; diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c index 4169bb2db19..e74ad385e73 100644 --- a/drivers/isdn/hardware/mISDN/mISDNisar.c +++ b/drivers/isdn/hardware/mISDN/mISDNisar.c @@ -446,7 +446,7 @@ isar_rcv_frame(struct isar_ch *ch) break; } rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb)); - recv_Bchannel(&ch->bch, 0); + recv_Bchannel(&ch->bch, 0, false); break; case ISDN_P_B_HDLC: maxlen = bchannel_get_rxbuf(&ch->bch, ch->is->clsb); @@ -481,7 +481,7 @@ isar_rcv_frame(struct isar_ch *ch) break; } skb_trim(ch->bch.rx_skb, ch->bch.rx_skb->len - 2); - recv_Bchannel(&ch->bch, 0); + recv_Bchannel(&ch->bch, 0, false); } break; case ISDN_P_B_T30_FAX: @@ -517,7 +517,7 @@ isar_rcv_frame(struct isar_ch *ch) ch->state = STFAX_ESCAPE; /* set_skb_flag(skb, DF_NOMOREDATA); */ } - recv_Bchannel(&ch->bch, 0); + recv_Bchannel(&ch->bch, 0, false); if (ch->is->cmsb & SART_NMD) deliver_status(ch, HW_MOD_NOCARR); break; @@ -557,7 +557,7 @@ isar_rcv_frame(struct isar_ch *ch) break; } skb_trim(ch->bch.rx_skb, ch->bch.rx_skb->len - 2); - recv_Bchannel(&ch->bch, 0); + recv_Bchannel(&ch->bch, 0, false); } if (ch->is->cmsb & SART_NMD) { /* ABORT */ pr_debug("%s: isar_rcv_frame: no more data\n", @@ -1554,20 +1554,7 @@ isar_l2l1(struct mISDNchannel *ch, struct sk_buff *skb) static int channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) { - int ret = 0; - - switch (cq->op) { - case MISDN_CTRL_GETOP: - cq->op = 0; - break; - /* Nothing implemented yet */ - case MISDN_CTRL_FILL_EMPTY: - default: - pr_info("%s: unknown Op %x\n", __func__, cq->op); - ret = -EINVAL; - break; - } - return ret; + return mISDN_ctrl_bchannel(bch, cq); } static int @@ -1665,7 +1652,7 @@ mISDNisar_init(struct isar_hw *isar, void *hw) isar->hw = hw; for (i = 0; i < 2; i++) { isar->ch[i].bch.nr = i + 1; - mISDN_initbchannel(&isar->ch[i].bch, MAX_DATA_MEM); + mISDN_initbchannel(&isar->ch[i].bch, MAX_DATA_MEM, 32); isar->ch[i].bch.ch.nr = i + 1; isar->ch[i].bch.ch.send = &isar_l2l1; isar->ch[i].bch.ch.ctrl = isar_bctrl; diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c index 3f28057e725..47d30749d8a 100644 --- a/drivers/isdn/hardware/mISDN/netjet.c +++ b/drivers/isdn/hardware/mISDN/netjet.c @@ -408,7 +408,7 @@ read_dma(struct tiger_ch *bc, u32 idx, int cnt) } if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags)) { - recv_Bchannel(&bc->bch, 0); + recv_Bchannel(&bc->bch, 0, false); return; } @@ -426,7 +426,7 @@ read_dma(struct tiger_ch *bc, u32 idx, int cnt) DUMP_PREFIX_OFFSET, p, stat); } - recv_Bchannel(&bc->bch, 0); + recv_Bchannel(&bc->bch, 0, false); stat = bchannel_get_rxbuf(&bc->bch, bc->bch.maxlen); if (stat < 0) { pr_warning("%s.B%d: No memory for %d bytes\n", @@ -758,21 +758,7 @@ nj_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) static int channel_bctrl(struct tiger_ch *bc, struct mISDN_ctrl_req *cq) { - int ret = 0; - struct tiger_hw *card = bc->bch.hw; - - switch (cq->op) { - case MISDN_CTRL_GETOP: - cq->op = 0; - break; - /* Nothing implemented yet */ - case MISDN_CTRL_FILL_EMPTY: - default: - pr_info("%s: %s unknown Op %x\n", card->name, __func__, cq->op); - ret = -EINVAL; - break; - } - return ret; + return mISDN_ctrl_bchannel(&bc->bch, cq); } static int @@ -1006,7 +992,8 @@ setup_instance(struct tiger_hw *card) for (i = 0; i < 2; i++) { card->bc[i].bch.nr = i + 1; set_channelmap(i + 1, card->isac.dch.dev.channelmap); - mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM); + mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM, + NJ_DMA_RXSIZE >> 1); card->bc[i].bch.hw = card; card->bc[i].bch.ch.send = nj_l2l1B; card->bc[i].bch.ch.ctrl = nj_bctrl; diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c index 8324b20c7f1..03fb4a34fd5 100644 --- a/drivers/isdn/hardware/mISDN/w6692.c +++ b/drivers/isdn/hardware/mISDN/w6692.c @@ -688,7 +688,7 @@ W6692B_interrupt(struct w6692_hw *card, int ch) if (count == 0) count = W_B_FIFO_THRESH; W6692_empty_Bfifo(wch, count); - recv_Bchannel(&wch->bch, 0); + recv_Bchannel(&wch->bch, 0, false); } } if (stat & W_B_EXI_RMR) { @@ -704,9 +704,8 @@ W6692B_interrupt(struct w6692_hw *card, int ch) W_B_CMDR_RRST | W_B_CMDR_RACT); } else { W6692_empty_Bfifo(wch, W_B_FIFO_THRESH); - if (test_bit(FLG_TRANSPARENT, &wch->bch.Flags) && - wch->bch.rx_skb && (wch->bch.rx_skb->len > 0)) - recv_Bchannel(&wch->bch, 0); + if (test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) + recv_Bchannel(&wch->bch, 0, false); } } if (stat & W_B_EXI_RDOV) { @@ -979,20 +978,7 @@ w6692_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) static int channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) { - int ret = 0; - - switch (cq->op) { - case MISDN_CTRL_GETOP: - cq->op = 0; - break; - /* Nothing implemented yet */ - case MISDN_CTRL_FILL_EMPTY: - default: - pr_info("%s: unknown Op %x\n", __func__, cq->op); - ret = -EINVAL; - break; - } - return ret; + return mISDN_ctrl_bchannel(bch, cq); } static int @@ -1303,7 +1289,8 @@ setup_instance(struct w6692_hw *card) card->dch.hw = card; card->dch.dev.nrbchan = 2; for (i = 0; i < 2; i++) { - mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM); + mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM, + W_B_FIFO_THRESH); card->bc[i].bch.hw = card; card->bc[i].bch.nr = i + 1; card->bc[i].bch.ch.nr = i + 1; diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c index 3c2145d8c3f..d42ad0e98de 100644 --- a/drivers/isdn/mISDN/hwchannel.c +++ b/drivers/isdn/mISDN/hwchannel.c @@ -81,10 +81,16 @@ mISDN_initdchannel(struct dchannel *ch, int maxlen, void *phf) EXPORT_SYMBOL(mISDN_initdchannel); int -mISDN_initbchannel(struct bchannel *ch, int maxlen) +mISDN_initbchannel(struct bchannel *ch, unsigned short maxlen, + unsigned short minlen) { ch->Flags = 0; + ch->minlen = minlen; + ch->next_minlen = minlen; + ch->init_minlen = minlen; ch->maxlen = maxlen; + ch->next_maxlen = maxlen; + ch->init_maxlen = maxlen; ch->hw = NULL; ch->rx_skb = NULL; ch->tx_skb = NULL; @@ -134,6 +140,10 @@ mISDN_clear_bchannel(struct bchannel *ch) test_and_clear_bit(FLG_TX_BUSY, &ch->Flags); test_and_clear_bit(FLG_TX_NEXT, &ch->Flags); test_and_clear_bit(FLG_ACTIVE, &ch->Flags); + ch->minlen = ch->init_minlen; + ch->next_minlen = ch->init_minlen; + ch->maxlen = ch->init_maxlen; + ch->next_maxlen = ch->init_maxlen; } EXPORT_SYMBOL(mISDN_clear_bchannel); @@ -148,6 +158,33 @@ mISDN_freebchannel(struct bchannel *ch) } EXPORT_SYMBOL(mISDN_freebchannel); +int +mISDN_ctrl_bchannel(struct bchannel *bch, struct mISDN_ctrl_req *cq) +{ + int ret = 0; + + switch (cq->op) { + case MISDN_CTRL_GETOP: + cq->op = MISDN_CTRL_RX_BUFFER; + break; + case MISDN_CTRL_RX_BUFFER: + if (cq->p2 > MISDN_CTRL_RX_SIZE_IGNORE) + bch->next_maxlen = cq->p2; + if (cq->p1 > MISDN_CTRL_RX_SIZE_IGNORE) + bch->next_minlen = cq->p1; + /* we return the old values */ + cq->p1 = bch->minlen; + cq->p2 = bch->maxlen; + break; + default: + pr_info("mISDN unhandled control %x operation\n", cq->op); + ret = -EINVAL; + break; + } + return ret; +} +EXPORT_SYMBOL(mISDN_ctrl_bchannel); + static inline u_int get_sapi_tei(u_char *p) { @@ -197,7 +234,7 @@ recv_Echannel(struct dchannel *ech, struct dchannel *dch) EXPORT_SYMBOL(recv_Echannel); void -recv_Bchannel(struct bchannel *bch, unsigned int id) +recv_Bchannel(struct bchannel *bch, unsigned int id, bool force) { struct mISDNhead *hh; @@ -211,6 +248,9 @@ recv_Bchannel(struct bchannel *bch, unsigned int id) dev_kfree_skb(bch->rx_skb); bch->rx_skb = NULL; } else { + if (test_bit(FLG_TRANSPARENT, &bch->Flags) && + (bch->rx_skb->len < bch->minlen) && !force) + return; hh = mISDN_HEAD_P(bch->rx_skb); hh->prim = PH_DATA_IND; hh->id = id; @@ -426,7 +466,7 @@ bchannel_get_rxbuf(struct bchannel *bch, int reqlen) bch->nr, reqlen, len); if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { /* send what we have now and try a new buffer */ - recv_Bchannel(bch, 0); + recv_Bchannel(bch, 0, true); } else { /* on HDLC we have to drop too big frames */ return -EMSGSIZE; @@ -435,12 +475,25 @@ bchannel_get_rxbuf(struct bchannel *bch, int reqlen) return len; } } + /* update current min/max length first */ + if (unlikely(bch->maxlen != bch->next_maxlen)) + bch->maxlen = bch->next_maxlen; + if (unlikely(bch->minlen != bch->next_minlen)) + bch->minlen = bch->next_minlen; if (unlikely(reqlen > bch->maxlen)) return -EMSGSIZE; - if (test_bit(FLG_TRANSPARENT, &bch->Flags)) - len = reqlen; - else /* with HDLC we do not know the length yet */ + if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { + if (reqlen >= bch->minlen) { + len = reqlen; + } else { + len = 2 * bch->minlen; + if (len > bch->maxlen) + len = bch->maxlen; + } + } else { + /* with HDLC we do not know the length yet */ len = bch->maxlen; + } bch->rx_skb = mI_alloc_skb(len, GFP_ATOMIC); if (!bch->rx_skb) { pr_warning("B%d receive no memory for %d bytes\n", diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c index 0f88acf1185..db50f788855 100644 --- a/drivers/isdn/mISDN/l1oip_core.c +++ b/drivers/isdn/mISDN/l1oip_core.c @@ -1420,7 +1420,7 @@ init_card(struct l1oip *hc, int pri, int bundle) bch->nr = i + ch; bch->slot = i + ch; bch->debug = debug; - mISDN_initbchannel(bch, MAX_DATA_MEM); + mISDN_initbchannel(bch, MAX_DATA_MEM, 0); bch->hw = hc; bch->ch.send = handle_bmsg; bch->ch.ctrl = l1oip_bctrl; diff --git a/include/linux/mISDNhw.h b/include/linux/mISDNhw.h index a86d86beff7..226886cf31e 100644 --- a/include/linux/mISDNhw.h +++ b/include/linux/mISDNhw.h @@ -154,7 +154,12 @@ struct bchannel { struct timer_list timer; /* receive data */ struct sk_buff *rx_skb; - int maxlen; + unsigned short maxlen; + unsigned short init_maxlen; /* initial value */ + unsigned short next_maxlen; /* pending value */ + unsigned short minlen; /* for transparent data */ + unsigned short init_minlen; /* initial value */ + unsigned short next_minlen; /* pending value */ /* send data */ struct sk_buff *next_skb; struct sk_buff *tx_skb; @@ -169,10 +174,12 @@ struct bchannel { }; extern int mISDN_initdchannel(struct dchannel *, int, void *); -extern int mISDN_initbchannel(struct bchannel *, int); +extern int mISDN_initbchannel(struct bchannel *, unsigned short, + unsigned short); extern int mISDN_freedchannel(struct dchannel *); extern void mISDN_clear_bchannel(struct bchannel *); extern int mISDN_freebchannel(struct bchannel *); +extern int mISDN_ctrl_bchannel(struct bchannel *, struct mISDN_ctrl_req *); extern void queue_ch_frame(struct mISDNchannel *, u_int, int, struct sk_buff *); extern int dchannel_senddata(struct dchannel *, struct sk_buff *); @@ -180,7 +187,7 @@ extern int bchannel_senddata(struct bchannel *, struct sk_buff *); extern int bchannel_get_rxbuf(struct bchannel *, int); extern void recv_Dchannel(struct dchannel *); extern void recv_Echannel(struct dchannel *, struct dchannel *); -extern void recv_Bchannel(struct bchannel *, unsigned int id); +extern void recv_Bchannel(struct bchannel *, unsigned int, bool); extern void recv_Dchannel_skb(struct dchannel *, struct sk_buff *); extern void recv_Bchannel_skb(struct bchannel *, struct sk_buff *); extern int get_next_bframe(struct bchannel *); diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h index ce6e613dff4..246a3529ecf 100644 --- a/include/linux/mISDNif.h +++ b/include/linux/mISDNif.h @@ -37,7 +37,7 @@ */ #define MISDN_MAJOR_VERSION 1 #define MISDN_MINOR_VERSION 1 -#define MISDN_RELEASE 28 +#define MISDN_RELEASE 29 /* primitives for information exchange * generell format @@ -365,6 +365,7 @@ clear_channelmap(u_int nr, u_char *map) #define MISDN_CTRL_LOOP 0x0001 #define MISDN_CTRL_CONNECT 0x0002 #define MISDN_CTRL_DISCONNECT 0x0004 +#define MISDN_CTRL_RX_BUFFER 0x0008 #define MISDN_CTRL_PCMCONNECT 0x0010 #define MISDN_CTRL_PCMDISCONNECT 0x0020 #define MISDN_CTRL_SETPEER 0x0040 @@ -387,6 +388,12 @@ clear_channelmap(u_int nr, u_char *map) #define MISDN_CTRL_HFC_WD_INIT 0x4009 #define MISDN_CTRL_HFC_WD_RESET 0x400A +/* special RX buffer value for MISDN_CTRL_RX_BUFFER request.p1 is the minimum + * buffer size request.p2 the maximum. Using MISDN_CTRL_RX_SIZE_IGNORE will + * not change the value, but still read back the actual stetting. + */ +#define MISDN_CTRL_RX_SIZE_IGNORE -1 + /* socket options */ #define MISDN_TIME_STAMP 0x0001 -- cgit v1.2.3-70-g09d2 From 6d1ee48fd0d8d2586aaeda24dacffc426c2be44a Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Tue, 15 May 2012 23:51:07 +0000 Subject: mISDN: Implement MISDN_CTRL_FILL_EMPTY for more drivers MISDN_CTRL_FILL_EMPTY is a meachanism to send a fixed value (normally silence) as long no data from upper layers is available. It can be used when recording voice messages or with unidirectional protocols. Signed-off-by: Karsten Keil Signed-off-by: David S. Miller --- drivers/isdn/hardware/mISDN/avmfritz.c | 64 ++++++++++++++++++--------- drivers/isdn/hardware/mISDN/hfcmulti.c | 12 +++-- drivers/isdn/hardware/mISDN/hfcpci.c | 59 ++++++++----------------- drivers/isdn/hardware/mISDN/hfcsusb.c | 44 ++++++++----------- drivers/isdn/hardware/mISDN/mISDNipac.c | 44 ++++++++++++------- drivers/isdn/hardware/mISDN/mISDNisar.c | 33 +++++++++----- drivers/isdn/hardware/mISDN/netjet.c | 78 +++++++++++++++++++++++---------- drivers/isdn/hardware/mISDN/w6692.c | 53 ++++++++++++++-------- drivers/isdn/mISDN/dsp_core.c | 1 + drivers/isdn/mISDN/hwchannel.c | 12 ++++- include/linux/mISDNhw.h | 4 +- 11 files changed, 243 insertions(+), 161 deletions(-) (limited to 'drivers/isdn/hardware/mISDN/netjet.c') diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c index 7cd3a963ed2..c6fa505a1d1 100644 --- a/drivers/isdn/hardware/mISDN/avmfritz.c +++ b/drivers/isdn/hardware/mISDN/avmfritz.c @@ -30,7 +30,7 @@ #include "ipac.h" -#define AVMFRITZ_REV "2.2" +#define AVMFRITZ_REV "2.3" static int AVM_cnt; static int debug; @@ -442,19 +442,26 @@ hdlc_fill_fifo(struct bchannel *bch) { struct fritzcard *fc = bch->hw; struct hdlc_hw *hdlc; - int count, fs, cnt = 0; + int count, fs, cnt = 0, idx, fillempty = 0; u8 *p; u32 *ptr, val, addr; - hdlc = &fc->hdlc[(bch->nr - 1) & 1]; - if (!bch->tx_skb) - return; - count = bch->tx_skb->len - bch->tx_idx; - if (count <= 0) - return; + idx = (bch->nr - 1) & 1; + hdlc = &fc->hdlc[idx]; fs = (fc->type == AVM_FRITZ_PCIV2) ? HDLC_FIFO_SIZE_V2 : HDLC_FIFO_SIZE_V1; - p = bch->tx_skb->data + bch->tx_idx; + if (!bch->tx_skb) { + if (!test_bit(FLG_TX_EMPTY, &bch->Flags)) + return; + count = fs; + p = bch->fill; + fillempty = 1; + } else { + count = bch->tx_skb->len - bch->tx_idx; + if (count <= 0) + return; + p = bch->tx_skb->data + bch->tx_idx; + } hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XME; if (count > fs) { count = fs; @@ -462,10 +469,14 @@ hdlc_fill_fifo(struct bchannel *bch) if (test_bit(FLG_HDLC, &bch->Flags)) hdlc->ctrl.sr.cmd |= HDLC_CMD_XME; } - pr_debug("%s: %s %d/%d/%d", fc->name, __func__, count, - bch->tx_idx, bch->tx_skb->len); ptr = (u32 *)p; - bch->tx_idx += count; + if (fillempty) { + pr_debug("%s.B%d: %d/%d/%d", fc->name, bch->nr, count, + bch->tx_idx, bch->tx_skb->len); + bch->tx_idx += count; + } else { + pr_debug("%s.B%d: fillempty %d\n", fc->name, bch->nr, count); + } hdlc->ctrl.sr.xml = ((count == fs) ? 0 : count); if (fc->type == AVM_FRITZ_PCIV2) { __write_ctrl_pciv2(fc, hdlc, bch->nr); @@ -475,13 +486,21 @@ hdlc_fill_fifo(struct bchannel *bch) __write_ctrl_pci(fc, hdlc, bch->nr); addr = fc->addr + CHIP_WINDOW; } - while (cnt < count) { - val = get_unaligned(ptr); - outl(cpu_to_le32(val), addr); - ptr++; - cnt += 4; + if (fillempty) { + while (cnt < count) { + /* all bytes the same - no worry about endian */ + outl(*ptr, addr); + cnt += 4; + } + } else { + while (cnt < count) { + val = get_unaligned(ptr); + outl(cpu_to_le32(val), addr); + ptr++; + cnt += 4; + } } - if (debug & DEBUG_HW_BFIFO) { + if ((debug & DEBUG_HW_BFIFO) && !fillempty) { snprintf(fc->log, LOG_SIZE, "B%1d-send %s %d ", bch->nr, fc->name, count); print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count); @@ -496,8 +515,12 @@ HDLC_irq_xpr(struct bchannel *bch) } else { if (bch->tx_skb) dev_kfree_skb(bch->tx_skb); - if (get_next_bframe(bch)) + if (get_next_bframe(bch)) { hdlc_fill_fifo(bch); + test_and_clear_bit(FLG_TX_EMPTY, &bch->Flags); + } else if (test_bit(FLG_TX_EMPTY, &bch->Flags)) { + hdlc_fill_fifo(bch); + } } } @@ -561,6 +584,8 @@ handle_tx: if (bch->tx_skb && bch->tx_skb->len) { if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) bch->tx_idx = 0; + } else if (test_bit(FLG_FILLEMPTY, &bch->Flags)) { + test_and_set_bit(FLG_TX_EMPTY, &bch->Flags); } hdlc->ctrl.sr.xml = 0; hdlc->ctrl.sr.cmd |= HDLC_CMD_XRS; @@ -882,7 +907,6 @@ open_bchannel(struct fritzcard *fc, struct channel_req *rq) bch = &fc->bch[rq->adr.channel - 1]; if (test_and_set_bit(FLG_OPEN, &bch->Flags)) return -EBUSY; /* b-channel can be only open once */ - test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); bch->ch.protocol = rq->protocol; rq->ch = &bch->ch; return 0; diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index 3d4b36d2a31..db9b0451982 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -3576,7 +3576,7 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) case MISDN_CTRL_GETOP: ret = mISDN_ctrl_bchannel(bch, cq); cq->op |= MISDN_CTRL_HFC_OP | MISDN_CTRL_HW_FEATURES_OP | - MISDN_CTRL_RX_OFF | MISDN_CTRL_FILL_EMPTY; + MISDN_CTRL_RX_OFF; break; case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */ hc->chan[bch->slot].rx_off = !!cq->p1; @@ -3591,11 +3591,10 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) printk(KERN_DEBUG "%s: RX_OFF request (nr=%d off=%d)\n", __func__, bch->nr, hc->chan[bch->slot].rx_off); break; - case MISDN_CTRL_FILL_EMPTY: /* fill fifo, if empty */ - test_and_set_bit(FLG_FILLEMPTY, &bch->Flags); - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: FILL_EMPTY request (nr=%d " - "off=%d)\n", __func__, bch->nr, !!cq->p1); + case MISDN_CTRL_FILL_EMPTY: + ret = mISDN_ctrl_bchannel(bch, cq); + hc->silence = bch->fill[0]; + memset(hc->silence_data, hc->silence, sizeof(hc->silence_data)); break; case MISDN_CTRL_HW_FEATURES: /* fill features structure */ if (debug & DEBUG_HFCMULTI_MSG) @@ -4118,7 +4117,6 @@ open_bchannel(struct hfc_multi *hc, struct dchannel *dch, } if (test_and_set_bit(FLG_OPEN, &bch->Flags)) return -EBUSY; /* b-channel can be only open once */ - test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); bch->ch.protocol = rq->protocol; hc->chan[ch].rx_off = 0; rq->ch = &bch->ch; diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 27743754ab8..1bd8bc7eb5c 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -565,11 +565,6 @@ hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *rxbz, if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) new_z2 -= B_FIFO_SIZE; /* buffer wrap */ - if (fcnt_rx > MAX_DATA_SIZE) { /* flush, if oversized */ - *z2r = cpu_to_le16(new_z2); /* new position */ - return; - } - fcnt_tx = le16_to_cpu(*z2t) - le16_to_cpu(*z1t); if (fcnt_tx <= 0) fcnt_tx += B_FIFO_SIZE; @@ -761,9 +756,14 @@ hfcpci_fill_fifo(struct bchannel *bch) if ((bch->debug & DEBUG_HW_BCHANNEL) && !(bch->debug & DEBUG_HW_BFIFO)) printk(KERN_DEBUG "%s\n", __func__); - if ((!bch->tx_skb) || bch->tx_skb->len <= 0) - return; - count = bch->tx_skb->len - bch->tx_idx; + if ((!bch->tx_skb) || bch->tx_skb->len == 0) { + if (!test_bit(FLG_FILLEMPTY, &bch->Flags) && + !test_bit(FLG_TRANSPARENT, &bch->Flags)) + return; + count = HFCPCI_FILLEMPTY; + } else { + count = bch->tx_skb->len - bch->tx_idx; + } if ((bch->nr & 2) && (!hc->hw.bswapped)) { bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2; bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.txdat_b2; @@ -782,16 +782,10 @@ hfcpci_fill_fifo(struct bchannel *bch) fcnt = le16_to_cpu(*z2t) - le16_to_cpu(*z1t); if (fcnt <= 0) fcnt += B_FIFO_SIZE; - /* fcnt contains available bytes in fifo */ - fcnt = B_FIFO_SIZE - fcnt; - /* remaining bytes to send (bytes in fifo) */ - - /* "fill fifo if empty" feature */ - if (test_bit(FLG_FILLEMPTY, &bch->Flags) && !fcnt) { - /* printk(KERN_DEBUG "%s: buffer empty, so we have " - "underrun\n", __func__); */ - /* fill buffer, to prevent future underrun */ - count = HFCPCI_FILLEMPTY; + if (test_bit(FLG_FILLEMPTY, &bch->Flags)) { + /* fcnt contains available bytes in fifo */ + if (count > fcnt) + count = fcnt; new_z1 = le16_to_cpu(*z1t) + count; /* new buffer Position */ if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL)) @@ -803,17 +797,20 @@ hfcpci_fill_fifo(struct bchannel *bch) printk(KERN_DEBUG "hfcpci_FFt fillempty " "fcnt(%d) maxl(%d) nz1(%x) dst(%p)\n", fcnt, maxlen, new_z1, dst); - fcnt += count; if (maxlen > count) maxlen = count; /* limit size */ - memset(dst, 0x2a, maxlen); /* first copy */ + memset(dst, bch->fill[0], maxlen); /* first copy */ count -= maxlen; /* remaining bytes */ if (count) { dst = bdata; /* start of buffer */ - memset(dst, 0x2a, count); + memset(dst, bch->fill[0], count); } *z1t = cpu_to_le16(new_z1); /* now send data */ + return; } + /* fcnt contains available bytes in fifo */ + fcnt = B_FIFO_SIZE - fcnt; + /* remaining bytes to send (bytes in fifo) */ next_t_frame: count = bch->tx_skb->len - bch->tx_idx; @@ -1531,24 +1528,7 @@ deactivate_bchannel(struct bchannel *bch) static int channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) { - int ret = 0; - - switch (cq->op) { - case MISDN_CTRL_GETOP: - ret = mISDN_ctrl_bchannel(bch, cq); - cq->op |= MISDN_CTRL_FILL_EMPTY; - 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); - break; - default: - ret = mISDN_ctrl_bchannel(bch, cq); - break; - } - return ret; + return mISDN_ctrl_bchannel(bch, cq); } static int hfc_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) @@ -1964,7 +1944,6 @@ open_bchannel(struct hfc_pci *hc, struct channel_req *rq) bch = &hc->bch[rq->adr.channel - 1]; if (test_and_set_bit(FLG_OPEN, &bch->Flags)) return -EBUSY; /* b-channel can be only open once */ - test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); bch->ch.protocol = rq->protocol; rq->ch = &bch->ch; /* TODO: E-channel */ if (!try_module_get(THIS_MODULE)) diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c index 9c17473da83..b539b10d6f3 100644 --- a/drivers/isdn/hardware/mISDN/hfcsusb.c +++ b/drivers/isdn/hardware/mISDN/hfcsusb.c @@ -491,7 +491,6 @@ open_bchannel(struct hfcsusb *hw, struct channel_req *rq) bch = &hw->bch[rq->adr.channel - 1]; if (test_and_set_bit(FLG_OPEN, &bch->Flags)) return -EBUSY; /* b-channel can be only open once */ - test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); bch->ch.protocol = rq->protocol; rq->ch = &bch->ch; @@ -806,24 +805,7 @@ hfcsusb_ph_command(struct hfcsusb *hw, u_char command) static int channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) { - int ret = 0; - - switch (cq->op) { - case MISDN_CTRL_GETOP: - ret = mISDN_ctrl_bchannel(bch, cq); - cq->op |= MISDN_CTRL_FILL_EMPTY; - 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); - break; - default: - ret = mISDN_ctrl_bchannel(bch, cq); - break; - } - return ret; + return mISDN_ctrl_bchannel(bch, cq); } /* collect data from incoming interrupt or isochron USB data */ @@ -1183,8 +1165,8 @@ tx_iso_complete(struct urb *urb) int k, tx_offset, num_isoc_packets, sink, remain, current_len, errcode, hdlc, i; int *tx_idx; - int frame_complete, fifon, status; - __u8 threshbit; + int frame_complete, fifon, status, fillempty = 0; + __u8 threshbit, *p; spin_lock(&hw->lock); if (fifo->stop_gracefull) { @@ -1202,6 +1184,9 @@ tx_iso_complete(struct urb *urb) tx_skb = fifo->bch->tx_skb; tx_idx = &fifo->bch->tx_idx; hdlc = test_bit(FLG_HDLC, &fifo->bch->Flags); + if (!tx_skb && !hdlc && + test_bit(FLG_FILLEMPTY, &fifo->bch->Flags)) + fillempty = 1; } else { printk(KERN_DEBUG "%s: %s: neither BCH nor DCH\n", hw->name, __func__); @@ -1260,6 +1245,8 @@ tx_iso_complete(struct urb *urb) /* Generate next ISO Packets */ if (tx_skb) remain = tx_skb->len - *tx_idx; + else if (fillempty) + remain = 15; /* > not complete */ else remain = 0; @@ -1290,15 +1277,20 @@ 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; - + p = context_iso_urb->buffer + tx_offset + 1; + if (fillempty) { + memset(p, fifo->bch->fill[0], + current_len); + } else { + memcpy(p, (tx_skb->data + *tx_idx), + current_len); + *tx_idx += current_len; + } urb->iso_frame_desc[k].offset = tx_offset; urb->iso_frame_desc[k].length = current_len + 1; /* USB data log for every D ISO out */ - if ((fifon == HFCUSB_D_RX) && + if ((fifon == HFCUSB_D_RX) && !fillempty && (debug & DBG_HFC_USB_VERBOSE)) { printk(KERN_DEBUG "%s: %s (%d/%d) offs(%d) len(%d) ", diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c index 3e71a5ef4bb..374a17751ff 100644 --- a/drivers/isdn/hardware/mISDN/mISDNipac.c +++ b/drivers/isdn/hardware/mISDN/mISDNipac.c @@ -969,22 +969,28 @@ hscx_fill_fifo(struct hscx_hw *hscx) int count, more; u8 *p; - if (!hscx->bch.tx_skb) - return; - count = hscx->bch.tx_skb->len - hscx->bch.tx_idx; - if (count <= 0) - return; - p = hscx->bch.tx_skb->data + hscx->bch.tx_idx; - - more = test_bit(FLG_TRANSPARENT, &hscx->bch.Flags) ? 1 : 0; - if (count > hscx->fifo_size) { + if (!hscx->bch.tx_skb) { + if (!test_bit(FLG_TX_EMPTY, &hscx->bch.Flags)) + return; count = hscx->fifo_size; more = 1; - } - pr_debug("%s: B%1d %d/%d/%d\n", hscx->ip->name, hscx->bch.nr, count, - hscx->bch.tx_idx, hscx->bch.tx_skb->len); - hscx->bch.tx_idx += count; + p = hscx->log; + memset(p, hscx->bch.fill[0], count); + } else { + count = hscx->bch.tx_skb->len - hscx->bch.tx_idx; + if (count <= 0) + return; + p = hscx->bch.tx_skb->data + hscx->bch.tx_idx; + more = test_bit(FLG_TRANSPARENT, &hscx->bch.Flags) ? 1 : 0; + if (count > hscx->fifo_size) { + count = hscx->fifo_size; + more = 1; + } + pr_debug("%s: B%1d %d/%d/%d\n", hscx->ip->name, hscx->bch.nr, + count, hscx->bch.tx_idx, hscx->bch.tx_skb->len); + hscx->bch.tx_idx += count; + } if (hscx->ip->type & IPAC_TYPE_IPACX) hscx->ip->write_fifo(hscx->ip->hw, hscx->off + IPACX_XFIFOB, p, count); @@ -995,7 +1001,7 @@ hscx_fill_fifo(struct hscx_hw *hscx) } hscx_cmdr(hscx, more ? 0x08 : 0x0a); - if (hscx->bch.debug & DEBUG_HW_BFIFO) { + if (hscx->bch.tx_skb && (hscx->bch.debug & DEBUG_HW_BFIFO)) { snprintf(hscx->log, 64, "B%1d-send %s %d ", hscx->bch.nr, hscx->ip->name, count); print_hex_dump_bytes(hscx->log, DUMP_PREFIX_OFFSET, p, count); @@ -1010,8 +1016,12 @@ hscx_xpr(struct hscx_hw *hx) } else { if (hx->bch.tx_skb) dev_kfree_skb(hx->bch.tx_skb); - if (get_next_bframe(&hx->bch)) + if (get_next_bframe(&hx->bch)) { hscx_fill_fifo(hx); + test_and_clear_bit(FLG_TX_EMPTY, &hx->bch.Flags); + } else if (test_bit(FLG_TX_EMPTY, &hx->bch.Flags)) { + hscx_fill_fifo(hx); + } } } @@ -1128,7 +1138,9 @@ ipac_irq(struct hscx_hw *hx, u8 ista) if (istab & IPACX_B_XDU) { if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) { - hscx_fill_fifo(hx); + if (test_bit(FLG_FILLEMPTY, &hx->bch.Flags)) + test_and_set_bit(FLG_TX_EMPTY, &hx->bch.Flags); + hscx_xpr(hx); return; } pr_debug("%s: B%1d XDU error at len %d\n", hx->ip->name, diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c index e74ad385e73..901be3257a7 100644 --- a/drivers/isdn/hardware/mISDN/mISDNisar.c +++ b/drivers/isdn/hardware/mISDN/mISDNisar.c @@ -585,16 +585,25 @@ isar_fill_fifo(struct isar_ch *ch) u8 msb; u8 *ptr; - pr_debug("%s: ch%d tx_skb %p tx_idx %d\n", - ch->is->name, ch->bch.nr, ch->bch.tx_skb, ch->bch.tx_idx); - if (!ch->bch.tx_skb) + pr_debug("%s: ch%d tx_skb %d tx_idx %d\n", ch->is->name, ch->bch.nr, + ch->bch.tx_skb ? ch->bch.tx_skb->len : -1, ch->bch.tx_idx); + if (!(ch->is->bstat & + (ch->dpath == 1 ? BSTAT_RDM1 : BSTAT_RDM2))) + return; + if (!ch->bch.tx_skb) { + if (!test_bit(FLG_TX_EMPTY, &ch->bch.Flags) || + (ch->bch.state != ISDN_P_B_RAW)) + return; + count = ch->mml; + /* use the card buffer */ + memset(ch->is->buf, ch->bch.fill[0], count); + send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA, + 0, count, ch->is->buf); return; + } count = ch->bch.tx_skb->len - ch->bch.tx_idx; if (count <= 0) return; - if (!(ch->is->bstat & - (ch->dpath == 1 ? BSTAT_RDM1 : BSTAT_RDM2))) - return; if (count > ch->mml) { msb = 0; count = ch->mml; @@ -673,9 +682,9 @@ sel_bch_isar(struct isar_hw *isar, u8 dpath) static void send_next(struct isar_ch *ch) { - pr_debug("%s: %s ch%d tx_skb %p tx_idx %d\n", - ch->is->name, __func__, ch->bch.nr, - ch->bch.tx_skb, ch->bch.tx_idx); + pr_debug("%s: %s ch%d tx_skb %d tx_idx %d\n", ch->is->name, __func__, + ch->bch.nr, ch->bch.tx_skb ? ch->bch.tx_skb->len : -1, + ch->bch.tx_idx); if (ch->bch.state == ISDN_P_B_T30_FAX) { if (ch->cmd == PCTRL_CMD_FTH) { if (test_bit(FLG_LASTDATA, &ch->bch.Flags)) { @@ -693,6 +702,9 @@ send_next(struct isar_ch *ch) dev_kfree_skb(ch->bch.tx_skb); if (get_next_bframe(&ch->bch)) { isar_fill_fifo(ch); + test_and_clear_bit(FLG_TX_EMPTY, &ch->bch.Flags); + } else if (test_bit(FLG_TX_EMPTY, &ch->bch.Flags)) { + isar_fill_fifo(ch); } else { if (test_and_clear_bit(FLG_DLEETX, &ch->bch.Flags)) { if (test_and_clear_bit(FLG_LASTDATA, @@ -707,6 +719,8 @@ send_next(struct isar_ch *ch) } else { deliver_status(ch, HW_MOD_CONNECT); } + } else if (test_bit(FLG_FILLEMPTY, &ch->bch.Flags)) { + test_and_set_bit(FLG_TX_EMPTY, &ch->bch.Flags); } } } @@ -1638,7 +1652,6 @@ isar_open(struct isar_hw *isar, struct channel_req *rq) bch = &isar->ch[rq->adr.channel - 1].bch; if (test_and_set_bit(FLG_OPEN, &bch->Flags)) return -EBUSY; /* b-channel can be only open once */ - test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); bch->ch.protocol = rq->protocol; rq->ch = &bch->ch; return 0; diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c index 47d30749d8a..aa95cc7d32f 100644 --- a/drivers/isdn/hardware/mISDN/netjet.c +++ b/drivers/isdn/hardware/mISDN/netjet.c @@ -533,22 +533,31 @@ static void fill_dma(struct tiger_ch *bc) { struct tiger_hw *card = bc->bch.hw; - int count, i; - u32 m, v; + int count, i, fillempty = 0; + u32 m, v, n = 0; u8 *p; if (bc->free == 0) return; - count = bc->bch.tx_skb->len - bc->bch.tx_idx; - if (count <= 0) - return; - pr_debug("%s: %s B%1d %d/%d/%d/%d state %x idx %d/%d\n", card->name, - __func__, bc->bch.nr, count, bc->free, bc->bch.tx_idx, - bc->bch.tx_skb->len, bc->txstate, bc->idx, card->send.idx); + if (!bc->bch.tx_skb) { + if (!test_bit(FLG_TX_EMPTY, &bc->bch.Flags)) + return; + fillempty = 1; + count = card->send.size >> 1; + p = bc->bch.fill; + } else { + count = bc->bch.tx_skb->len - bc->bch.tx_idx; + if (count <= 0) + return; + pr_debug("%s: %s B%1d %d/%d/%d/%d state %x idx %d/%d\n", + card->name, __func__, bc->bch.nr, count, bc->free, + bc->bch.tx_idx, bc->bch.tx_skb->len, bc->txstate, + bc->idx, card->send.idx); + p = bc->bch.tx_skb->data + bc->bch.tx_idx; + } if (bc->txstate & (TX_IDLE | TX_INIT | TX_UNDERRUN)) resync(bc, card); - p = bc->bch.tx_skb->data + bc->bch.tx_idx; - if (test_bit(FLG_HDLC, &bc->bch.Flags)) { + if (test_bit(FLG_HDLC, &bc->bch.Flags) && !fillempty) { count = isdnhdlc_encode(&bc->hsend, p, count, &i, bc->hsbuf, bc->free); pr_debug("%s: B%1d hdlc encoded %d in %d\n", card->name, @@ -559,17 +568,33 @@ fill_dma(struct tiger_ch *bc) } else { if (count > bc->free) count = bc->free; - bc->bch.tx_idx += count; + if (!fillempty) + bc->bch.tx_idx += count; bc->free -= count; } m = (bc->bch.nr & 1) ? 0xffffff00 : 0xffff00ff; - for (i = 0; i < count; i++) { - if (bc->idx >= card->send.size) - bc->idx = 0; - v = card->send.start[bc->idx]; - v &= m; - v |= (bc->bch.nr & 1) ? (u32)(p[i]) : ((u32)(p[i])) << 8; - card->send.start[bc->idx++] = v; + if (fillempty) { + n = p[0]; + if (!(bc->bch.nr & 1)) + n <<= 8; + for (i = 0; i < count; i++) { + if (bc->idx >= card->send.size) + bc->idx = 0; + v = card->send.start[bc->idx]; + v &= m; + v |= n; + card->send.start[bc->idx++] = v; + } + } else { + for (i = 0; i < count; i++) { + if (bc->idx >= card->send.size) + bc->idx = 0; + v = card->send.start[bc->idx]; + v &= m; + n = p[i]; + v |= (bc->bch.nr & 1) ? n : n << 8; + card->send.start[bc->idx++] = v; + } } if (debug & DEBUG_HW_BFIFO) { snprintf(card->log, LOG_SIZE, "B%1d-send %s %d ", @@ -584,17 +609,26 @@ fill_dma(struct tiger_ch *bc) static int bc_next_frame(struct tiger_ch *bc) { + int ret = 1; + if (bc->bch.tx_skb && bc->bch.tx_idx < bc->bch.tx_skb->len) { fill_dma(bc); } else { if (bc->bch.tx_skb) dev_kfree_skb(bc->bch.tx_skb); - if (get_next_bframe(&bc->bch)) + if (get_next_bframe(&bc->bch)) { fill_dma(bc); - else - return 0; + test_and_clear_bit(FLG_TX_EMPTY, &bc->bch.Flags); + } else if (test_bit(FLG_TX_EMPTY, &bc->bch.Flags)) { + fill_dma(bc); + } else if (test_bit(FLG_FILLEMPTY, &bc->bch.Flags)) { + test_and_set_bit(FLG_TX_EMPTY, &bc->bch.Flags); + ret = 0; + } else { + ret = 0; + } } - return 1; + return ret; } static void diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c index 03fb4a34fd5..183181f0192 100644 --- a/drivers/isdn/hardware/mISDN/w6692.c +++ b/drivers/isdn/hardware/mISDN/w6692.c @@ -498,16 +498,22 @@ static void W6692_fill_Bfifo(struct w6692_ch *wch) { struct w6692_hw *card = wch->bch.hw; - int count; + int count, fillempty = 0; u8 *ptr, cmd = W_B_CMDR_RACT | W_B_CMDR_XMS; pr_debug("%s: fill Bfifo\n", card->name); - if (!wch->bch.tx_skb) - return; - count = wch->bch.tx_skb->len - wch->bch.tx_idx; - if (count <= 0) - return; - ptr = wch->bch.tx_skb->data + wch->bch.tx_idx; + if (!wch->bch.tx_skb) { + if (!test_bit(FLG_TX_EMPTY, &wch->bch.Flags)) + return; + ptr = wch->bch.fill; + count = W_B_FIFO_THRESH; + fillempty = 1; + } else { + count = wch->bch.tx_skb->len - wch->bch.tx_idx; + if (count <= 0) + return; + ptr = wch->bch.tx_skb->data + wch->bch.tx_idx; + } if (count > W_B_FIFO_THRESH) count = W_B_FIFO_THRESH; else if (test_bit(FLG_HDLC, &wch->bch.Flags)) @@ -516,9 +522,16 @@ W6692_fill_Bfifo(struct w6692_ch *wch) pr_debug("%s: fill Bfifo%d/%d\n", card->name, count, wch->bch.tx_idx); wch->bch.tx_idx += count; - outsb(wch->addr + W_B_XFIFO, ptr, count); + if (fillempty) { + while (count > 0) { + outsb(wch->addr + W_B_XFIFO, ptr, MISDN_BCH_FILL_SIZE); + count -= MISDN_BCH_FILL_SIZE; + } + } else { + outsb(wch->addr + W_B_XFIFO, ptr, count); + } WriteW6692B(wch, W_B_CMDR, cmd); - if (debug & DEBUG_HW_DFIFO) { + if ((debug & DEBUG_HW_BFIFO) && !fillempty) { snprintf(card->log, 63, "B%1d-send %s %d ", wch->bch.nr, card->name, count); print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count); @@ -637,8 +650,12 @@ send_next(struct w6692_ch *wch) } else { if (wch->bch.tx_skb) dev_kfree_skb(wch->bch.tx_skb); - if (get_next_bframe(&wch->bch)) + if (get_next_bframe(&wch->bch)) { + W6692_fill_Bfifo(wch); + test_and_clear_bit(FLG_TX_EMPTY, &wch->bch.Flags); + } else if (test_bit(FLG_TX_EMPTY, &wch->bch.Flags)) { W6692_fill_Bfifo(wch); + } } } @@ -727,8 +744,8 @@ W6692B_interrupt(struct w6692_hw *card, int ch) wch->bch.nr, star); } if (star & W_B_STAR_XDOW) { - pr_debug("%s: B%d XDOW proto=%x\n", card->name, - wch->bch.nr, wch->bch.state); + pr_warning("%s: B%d XDOW proto=%x\n", card->name, + wch->bch.nr, wch->bch.state); #ifdef ERROR_STATISTIC wch->bch.err_xdu++; #endif @@ -741,20 +758,21 @@ W6692B_interrupt(struct w6692_hw *card, int ch) } } send_next(wch); - if (stat & W_B_EXI_XDUN) + if (star & W_B_STAR_XDOW) return; /* handle XDOW only once */ } if (stat & W_B_EXI_XDUN) { - pr_debug("%s: B%d XDUN proto=%x\n", card->name, - wch->bch.nr, wch->bch.state); + pr_warning("%s: B%d XDUN proto=%x\n", card->name, + wch->bch.nr, wch->bch.state); #ifdef ERROR_STATISTIC wch->bch.err_xdu++; #endif - WriteW6692B(wch, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT); - /* resend */ + /* resend - no XRST needed */ if (wch->bch.tx_skb) { if (!test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) wch->bch.tx_idx = 0; + } else if (test_bit(FLG_FILLEMPTY, &wch->bch.Flags)) { + test_and_set_bit(FLG_TX_EMPTY, &wch->bch.Flags); } send_next(wch); } @@ -993,7 +1011,6 @@ open_bchannel(struct w6692_hw *card, struct channel_req *rq) bch = &card->bc[rq->adr.channel - 1].bch; if (test_and_set_bit(FLG_OPEN, &bch->Flags)) return -EBUSY; /* b-channel can be only open once */ - test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); bch->ch.protocol = rq->protocol; rq->ch = &bch->ch; return 0; diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c index 2ac2d7a25a9..28c99c623bc 100644 --- a/drivers/isdn/mISDN/dsp_core.c +++ b/drivers/isdn/mISDN/dsp_core.c @@ -268,6 +268,7 @@ dsp_fill_empty(struct dsp *dsp) } cq.op = MISDN_CTRL_FILL_EMPTY; cq.p1 = 1; + cq.p2 = dsp_silence; if (dsp->ch.peer->ctrl(dsp->ch.peer, CONTROL_CHANNEL, &cq)) { printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n", __func__); diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c index d42ad0e98de..e541b65f68b 100644 --- a/drivers/isdn/mISDN/hwchannel.c +++ b/drivers/isdn/mISDN/hwchannel.c @@ -140,6 +140,8 @@ mISDN_clear_bchannel(struct bchannel *ch) test_and_clear_bit(FLG_TX_BUSY, &ch->Flags); test_and_clear_bit(FLG_TX_NEXT, &ch->Flags); test_and_clear_bit(FLG_ACTIVE, &ch->Flags); + test_and_clear_bit(FLG_FILLEMPTY, &ch->Flags); + test_and_clear_bit(FLG_TX_EMPTY, &ch->Flags); ch->minlen = ch->init_minlen; ch->next_minlen = ch->init_minlen; ch->maxlen = ch->init_maxlen; @@ -165,7 +167,15 @@ mISDN_ctrl_bchannel(struct bchannel *bch, struct mISDN_ctrl_req *cq) switch (cq->op) { case MISDN_CTRL_GETOP: - cq->op = MISDN_CTRL_RX_BUFFER; + cq->op = MISDN_CTRL_RX_BUFFER | MISDN_CTRL_FILL_EMPTY; + break; + case MISDN_CTRL_FILL_EMPTY: + if (cq->p1) { + memset(bch->fill, cq->p2 & 0xff, MISDN_BCH_FILL_SIZE); + test_and_set_bit(FLG_FILLEMPTY, &bch->Flags); + } else { + test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); + } break; case MISDN_CTRL_RX_BUFFER: if (cq->p2 > MISDN_CTRL_RX_SIZE_IGNORE) diff --git a/include/linux/mISDNhw.h b/include/linux/mISDNhw.h index 226886cf31e..62118421656 100644 --- a/include/linux/mISDNhw.h +++ b/include/linux/mISDNhw.h @@ -72,7 +72,7 @@ #define FLG_LL_OK 24 #define FLG_LL_CONN 25 #define FLG_DTMFSEND 26 - +#define FLG_TX_EMPTY 27 /* workq events */ #define FLG_RECVQUEUE 30 #define FLG_PHCHANGE 31 @@ -142,6 +142,7 @@ extern int create_l1(struct dchannel *, dchannel_l1callback *); struct layer1; extern int l1_event(struct layer1 *, u_int); +#define MISDN_BCH_FILL_SIZE 4 struct bchannel { struct mISDNchannel ch; @@ -153,6 +154,7 @@ struct bchannel { int slot; /* multiport card channel slot */ struct timer_list timer; /* receive data */ + u8 fill[MISDN_BCH_FILL_SIZE]; struct sk_buff *rx_skb; unsigned short maxlen; unsigned short init_maxlen; /* initial value */ -- cgit v1.2.3-70-g09d2 From c27b46e7f1cbf3be95a4cf5840c76a7b7d54b26f Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Tue, 15 May 2012 23:51:08 +0000 Subject: mISDN: Implement MISDN_CTRL_RX_OFF for more drivers MISDN_CTRL_RX_OFF is a meachanism to discard RX data in the driver if the data is not needed by the application. It can be used when playing mesages, but not recording or with unidirectional protocols. Signed-off-by: Karsten Keil Signed-off-by: David S. Miller --- drivers/isdn/hardware/mISDN/avmfritz.c | 25 ++++++++++++++++--------- drivers/isdn/hardware/mISDN/hfcmulti.c | 9 ++++++--- drivers/isdn/hardware/mISDN/hfcpci.c | 5 +++++ drivers/isdn/hardware/mISDN/hfcsusb.c | 5 +++++ drivers/isdn/hardware/mISDN/mISDNipac.c | 5 +++++ drivers/isdn/hardware/mISDN/mISDNisar.c | 5 +++++ drivers/isdn/hardware/mISDN/netjet.c | 4 ++++ drivers/isdn/hardware/mISDN/w6692.c | 5 +++++ drivers/isdn/mISDN/hwchannel.c | 14 +++++++++++++- include/linux/mISDNhw.h | 3 +++ 10 files changed, 67 insertions(+), 13 deletions(-) (limited to 'drivers/isdn/hardware/mISDN/netjet.c') diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c index c6fa505a1d1..c08fc605e56 100644 --- a/drivers/isdn/hardware/mISDN/avmfritz.c +++ b/drivers/isdn/hardware/mISDN/avmfritz.c @@ -408,13 +408,18 @@ hdlc_empty_fifo(struct bchannel *bch, int count) struct fritzcard *fc = bch->hw; pr_debug("%s: %s %d\n", fc->name, __func__, count); - cnt = bchannel_get_rxbuf(bch, count); - if (cnt < 0) { - pr_warning("%s.B%d: No bufferspace for %d bytes\n", - fc->name, bch->nr, count); - return; + if (test_bit(FLG_RX_OFF, &bch->Flags)) { + p = NULL; + bch->dropcnt += count; + } else { + cnt = bchannel_get_rxbuf(bch, count); + if (cnt < 0) { + pr_warning("%s.B%d: No bufferspace for %d bytes\n", + fc->name, bch->nr, count); + return; + } + p = skb_put(bch->rx_skb, count); } - p = skb_put(bch->rx_skb, count); ptr = (u32 *)p; if (fc->type == AVM_FRITZ_PCIV2) addr = fc->addr + (bch->nr == 2 ? @@ -426,11 +431,13 @@ hdlc_empty_fifo(struct bchannel *bch, int count) cnt = 0; while (cnt < count) { val = le32_to_cpu(inl(addr)); - put_unaligned(val, ptr); - ptr++; + if (p) { + put_unaligned(val, ptr); + ptr++; + } cnt += 4; } - if (debug & DEBUG_HW_BFIFO) { + if (p && (debug & DEBUG_HW_BFIFO)) { snprintf(fc->log, LOG_SIZE, "B%1d-recv %s %d ", bch->nr, fc->name, count); print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count); diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index db9b0451982..5e402cf2e79 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -2224,8 +2224,11 @@ next_frame: HFC_wait_nodebug(hc); /* ignore if rx is off BUT change fifo (above) to start pending TX */ - if (hc->chan[ch].rx_off) + if (hc->chan[ch].rx_off) { + if (bch) + bch->dropcnt += poll; /* not exact but fair enough */ return; + } if (dch || test_bit(FLG_HDLC, &bch->Flags)) { f1 = HFC_inb_nodebug(hc, A_F1); @@ -3575,10 +3578,10 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) switch (cq->op) { case MISDN_CTRL_GETOP: ret = mISDN_ctrl_bchannel(bch, cq); - cq->op |= MISDN_CTRL_HFC_OP | MISDN_CTRL_HW_FEATURES_OP | - MISDN_CTRL_RX_OFF; + cq->op |= MISDN_CTRL_HFC_OP | MISDN_CTRL_HW_FEATURES_OP; break; case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */ + ret = mISDN_ctrl_bchannel(bch, cq); hc->chan[bch->slot].rx_off = !!cq->p1; if (!hc->chan[bch->slot].rx_off) { /* reset fifo on rx on */ diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 1bd8bc7eb5c..81363ffa535 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -572,6 +572,11 @@ hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *rxbz, fcnt_tx = B_FIFO_SIZE - fcnt_tx; /* remaining bytes to send (bytes in tx-fifo) */ + if (test_bit(FLG_RX_OFF, &bch->Flags)) { + bch->dropcnt += fcnt_rx; + *z2r = cpu_to_le16(new_z2); + return; + } maxlen = bchannel_get_rxbuf(bch, fcnt_rx); if (maxlen < 0) { pr_warning("B%d: No bufferspace for %d bytes\n", diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c index b539b10d6f3..83206e453d4 100644 --- a/drivers/isdn/hardware/mISDN/hfcsusb.c +++ b/drivers/isdn/hardware/mISDN/hfcsusb.c @@ -842,6 +842,11 @@ 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)) { + fifo->bch->dropcnt += len; + spin_unlock(&hw->lock); + return; + } maxlen = bchannel_get_rxbuf(fifo->bch, len); rx_skb = fifo->bch->rx_skb; if (maxlen < 0) { diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c index 374a17751ff..752e0825591 100644 --- a/drivers/isdn/hardware/mISDN/mISDNipac.c +++ b/drivers/isdn/hardware/mISDN/mISDNipac.c @@ -936,6 +936,11 @@ hscx_empty_fifo(struct hscx_hw *hscx, u8 count) int maxlen; pr_debug("%s: B%1d %d\n", hscx->ip->name, hscx->bch.nr, count); + if (test_bit(FLG_RX_OFF, &hscx->bch.Flags)) { + hscx->bch.dropcnt += count; + hscx_cmdr(hscx, 0x80); /* RMC */ + return; + } maxlen = bchannel_get_rxbuf(&hscx->bch, count); if (maxlen < 0) { hscx_cmdr(hscx, 0x80); /* RMC */ diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c index 901be3257a7..be5973ded6d 100644 --- a/drivers/isdn/hardware/mISDN/mISDNisar.c +++ b/drivers/isdn/hardware/mISDN/mISDNisar.c @@ -429,6 +429,11 @@ isar_rcv_frame(struct isar_ch *ch) ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); return; } + if (test_bit(FLG_RX_OFF, &ch->bch.Flags)) { + ch->bch.dropcnt += ch->is->clsb; + ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); + return; + } switch (ch->bch.state) { case ISDN_P_NONE: pr_debug("%s: ISAR protocol 0 spurious IIS_RDATA %x/%x/%x\n", diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c index aa95cc7d32f..c3e3e768627 100644 --- a/drivers/isdn/hardware/mISDN/netjet.c +++ b/drivers/isdn/hardware/mISDN/netjet.c @@ -386,6 +386,10 @@ read_dma(struct tiger_ch *bc, u32 idx, int cnt) bc->bch.nr, idx); } bc->lastrx = idx; + if (test_bit(FLG_RX_OFF, &bc->bch.Flags)) { + bc->bch.dropcnt += cnt; + return; + } stat = bchannel_get_rxbuf(&bc->bch, cnt); /* only transparent use the count here, HDLC overun is detected later */ if (stat == ENOMEM) { diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c index 183181f0192..26a86b84609 100644 --- a/drivers/isdn/hardware/mISDN/w6692.c +++ b/drivers/isdn/hardware/mISDN/w6692.c @@ -475,6 +475,11 @@ W6692_empty_Bfifo(struct w6692_ch *wch, int count) skb_trim(wch->bch.rx_skb, 0); return; } + if (test_bit(FLG_RX_OFF, &wch->bch.Flags)) { + wch->bch.dropcnt += count; + WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); + return; + } maxlen = bchannel_get_rxbuf(&wch->bch, count); if (maxlen < 0) { WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c index e541b65f68b..ef34fd40867 100644 --- a/drivers/isdn/mISDN/hwchannel.c +++ b/drivers/isdn/mISDN/hwchannel.c @@ -142,6 +142,8 @@ mISDN_clear_bchannel(struct bchannel *ch) test_and_clear_bit(FLG_ACTIVE, &ch->Flags); test_and_clear_bit(FLG_FILLEMPTY, &ch->Flags); test_and_clear_bit(FLG_TX_EMPTY, &ch->Flags); + test_and_clear_bit(FLG_RX_OFF, &ch->Flags); + ch->dropcnt = 0; ch->minlen = ch->init_minlen; ch->next_minlen = ch->init_minlen; ch->maxlen = ch->init_maxlen; @@ -167,7 +169,8 @@ mISDN_ctrl_bchannel(struct bchannel *bch, struct mISDN_ctrl_req *cq) switch (cq->op) { case MISDN_CTRL_GETOP: - cq->op = MISDN_CTRL_RX_BUFFER | MISDN_CTRL_FILL_EMPTY; + cq->op = MISDN_CTRL_RX_BUFFER | MISDN_CTRL_FILL_EMPTY | + MISDN_CTRL_RX_OFF; break; case MISDN_CTRL_FILL_EMPTY: if (cq->p1) { @@ -177,6 +180,15 @@ mISDN_ctrl_bchannel(struct bchannel *bch, struct mISDN_ctrl_req *cq) test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); } break; + case MISDN_CTRL_RX_OFF: + /* read back dropped byte count */ + cq->p2 = bch->dropcnt; + if (cq->p1) + test_and_set_bit(FLG_RX_OFF, &bch->Flags); + else + test_and_clear_bit(FLG_RX_OFF, &bch->Flags); + bch->dropcnt = 0; + break; case MISDN_CTRL_RX_BUFFER: if (cq->p2 > MISDN_CTRL_RX_SIZE_IGNORE) bch->next_maxlen = cq->p2; diff --git a/include/linux/mISDNhw.h b/include/linux/mISDNhw.h index 62118421656..d0752eca9b4 100644 --- a/include/linux/mISDNhw.h +++ b/include/linux/mISDNhw.h @@ -73,6 +73,8 @@ #define FLG_LL_CONN 25 #define FLG_DTMFSEND 26 #define FLG_TX_EMPTY 27 +/* stop sending received data upstream */ +#define FLG_RX_OFF 28 /* workq events */ #define FLG_RECVQUEUE 30 #define FLG_PHCHANGE 31 @@ -173,6 +175,7 @@ struct bchannel { int err_crc; int err_tx; int err_rx; + int dropcnt; }; extern int mISDN_initdchannel(struct dchannel *, int, void *); -- cgit v1.2.3-70-g09d2