Commit 54e36513 authored by Kai Germaschewski's avatar Kai Germaschewski

ISDN/HiSax: Share code for retransmitting frame on B-channel

If we lose a fragment of a frame, we need to restart from the beginning,
share that code.
parent 081f88f0
...@@ -424,16 +424,10 @@ HDLC_irq(struct BCState *bcs, u_int stat) ...@@ -424,16 +424,10 @@ HDLC_irq(struct BCState *bcs, u_int stat)
} }
if (stat & HDLC_INT_XDU) { if (stat & HDLC_INT_XDU) {
/* Here we lost an TX interrupt, so /* Here we lost an TX interrupt, so
* restart transmitting the whole frame. * restart transmitting the whole frame. */
*/ if (bcs->cs->debug & L1_DEB_WARN)
if (bcs->tx_skb) { debugl1(bcs->cs, "ch%d XDU", bcs->channel);
skb_push(bcs->tx_skb, bcs->count); xmit_restart_b(bcs);
bcs->tx_cnt += bcs->count;
bcs->count = 0;
if (bcs->cs->debug & L1_DEB_WARN)
debugl1(bcs->cs, "ch%d XDU", bcs->channel);
} else if (bcs->cs->debug & L1_DEB_WARN)
debugl1(bcs->cs, "ch%d XDU without skb", bcs->channel);
bcs->hw.hdlc.ctrl.sr.xml = 0; bcs->hw.hdlc.ctrl.sr.xml = 0;
bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XRS; bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XRS;
write_ctrl(bcs, 1); write_ctrl(bcs, 1);
...@@ -441,15 +435,7 @@ HDLC_irq(struct BCState *bcs, u_int stat) ...@@ -441,15 +435,7 @@ HDLC_irq(struct BCState *bcs, u_int stat)
write_ctrl(bcs, 1); write_ctrl(bcs, 1);
hdlc_fill_fifo(bcs); hdlc_fill_fifo(bcs);
} else if (stat & HDLC_INT_XPR) { } else if (stat & HDLC_INT_XPR) {
if (bcs->tx_skb) { xmit_xpr_b(bcs);
if (bcs->tx_skb->len) {
hdlc_fill_fifo(bcs);
return;
}
xmit_complete_b(bcs);
bcs->count = 0;
}
xmit_ready_b(bcs);
} }
} }
......
...@@ -558,23 +558,8 @@ Memhscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx) ...@@ -558,23 +558,8 @@ Memhscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
sched_b_event(bcs, B_RCVBUFREADY); sched_b_event(bcs, B_RCVBUFREADY);
} }
} }
if (val & 0x10) { /* XPR */ if (val & 0x10) {
if (bcs->tx_skb) { xmit_xpr(bcs);/* XPR */
if (bcs->tx_skb->len) {
Memhscx_fill_fifo(bcs);
return;
}
xmit_complete_b(bcs);
bcs->count = 0;
}
if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
bcs->count = 0;
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
Memhscx_fill_fifo(bcs);
} else {
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
sched_b_event(bcs, B_XMTBUFREADY);
}
} }
} }
...@@ -589,20 +574,16 @@ Memhscx_int_main(struct IsdnCardState *cs, u_char val) ...@@ -589,20 +574,16 @@ Memhscx_int_main(struct IsdnCardState *cs, u_char val)
bcs = cs->bcs + 1; bcs = cs->bcs + 1;
exval = MemReadHSCX(cs, 1, HSCX_EXIR); exval = MemReadHSCX(cs, 1, HSCX_EXIR);
if (exval & 0x40) { if (exval & 0x40) {
if (bcs->mode == 1) if (cs->debug & L1_DEB_WARN)
debugl1(cs, "HSCX B EXIR %x", exval);
if (bcs->mode == L1_MODE_TRANS)
Memhscx_fill_fifo(bcs); Memhscx_fill_fifo(bcs);
else { else {
/* Here we lost an TX interrupt, so /* Here we lost an TX interrupt, so
* restart transmitting the whole frame. * restart transmitting the whole frame.
*/ */
if (bcs->tx_skb) { xmit_restart_b(bcs);
skb_push(bcs->tx_skb, bcs->count);
bcs->tx_cnt += bcs->count;
bcs->count = 0;
}
MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01); MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "HSCX B EXIR %x Lost TX", exval);
} }
} else if (cs->debug & L1_DEB_HSCX) } else if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "HSCX B EXIR %x", exval); debugl1(cs, "HSCX B EXIR %x", exval);
...@@ -616,20 +597,16 @@ Memhscx_int_main(struct IsdnCardState *cs, u_char val) ...@@ -616,20 +597,16 @@ Memhscx_int_main(struct IsdnCardState *cs, u_char val)
bcs = cs->bcs; bcs = cs->bcs;
exval = MemReadHSCX(cs, 0, HSCX_EXIR); exval = MemReadHSCX(cs, 0, HSCX_EXIR);
if (exval & 0x40) { if (exval & 0x40) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "HSCX A EXIR %x", exval);
if (bcs->mode == L1_MODE_TRANS) if (bcs->mode == L1_MODE_TRANS)
Memhscx_fill_fifo(bcs); Memhscx_fill_fifo(bcs);
else { else {
/* Here we lost an TX interrupt, so /* Here we lost an TX interrupt, so
* restart transmitting the whole frame. * restart transmitting the whole frame.
*/ */
if (bcs->tx_skb) { xmit_restart_b(bcs);
skb_push(bcs->tx_skb, bcs->count);
bcs->tx_cnt += bcs->count;
bcs->count = 0;
}
MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01); MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "HSCX A EXIR %x Lost TX", exval);
} }
} else if (cs->debug & L1_DEB_HSCX) } else if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "HSCX A EXIR %x", exval); debugl1(cs, "HSCX A EXIR %x", exval);
......
...@@ -292,17 +292,10 @@ write_modem(struct BCState *bcs) { ...@@ -292,17 +292,10 @@ write_modem(struct BCState *bcs) {
return(ret); return(ret);
} }
inline void static void
modem_fill(struct BCState *bcs) modem_fill(struct BCState *bcs)
{ {
if (bcs->tx_skb) { xmit_xpr_b(bcs);
if (bcs->tx_skb->len) {
write_modem(bcs);
return;
}
xmit_complete_b(bcs);
}
xmit_ready_b(bcs);
} }
static inline void receive_chars(struct IsdnCardState *cs, static inline void receive_chars(struct IsdnCardState *cs,
......
...@@ -190,16 +190,8 @@ hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx) ...@@ -190,16 +190,8 @@ hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
sched_b_event(bcs, B_RCVBUFREADY); sched_b_event(bcs, B_RCVBUFREADY);
} }
} }
if (val & 0x10) { /* XPR */ if (val & 0x10) {
if (bcs->tx_skb) { xmit_xpr_b(bcs);
if (bcs->tx_skb->len) {
hscx_fill_fifo(bcs);
return;
}
xmit_complete_b(bcs);
bcs->count = 0;
}
xmit_ready_b(bcs);
} }
} }
...@@ -215,23 +207,13 @@ hscx_int_main(struct IsdnCardState *cs, u_char val) ...@@ -215,23 +207,13 @@ hscx_int_main(struct IsdnCardState *cs, u_char val)
bcs = cs->bcs + 1; bcs = cs->bcs + 1;
exval = READHSCX(cs, 1, HSCX_EXIR); exval = READHSCX(cs, 1, HSCX_EXIR);
if (exval & 0x40) { if (exval & 0x40) {
if (bcs->mode == 1) if (cs->debug & L1_DEB_WARN)
debugl1(cs, "HSCX B EXIR %x", exval);
if (bcs->mode == L1_MODE_TRANS)
hscx_fill_fifo(bcs); hscx_fill_fifo(bcs);
else { else {
#ifdef ERROR_STATISTIC xmit_restart_b(bcs);
bcs->err_tx++;
#endif
/* Here we lost an TX interrupt, so
* restart transmitting the whole frame.
*/
if (bcs->tx_skb) {
skb_push(bcs->tx_skb, bcs->count);
bcs->tx_cnt += bcs->count;
bcs->count = 0;
}
WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01); WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "HSCX B EXIR %x Lost TX", exval);
} }
} else if (cs->debug & L1_DEB_HSCX) } else if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "HSCX B EXIR %x", exval); debugl1(cs, "HSCX B EXIR %x", exval);
...@@ -245,23 +227,13 @@ hscx_int_main(struct IsdnCardState *cs, u_char val) ...@@ -245,23 +227,13 @@ hscx_int_main(struct IsdnCardState *cs, u_char val)
bcs = cs->bcs; bcs = cs->bcs;
exval = READHSCX(cs, 0, HSCX_EXIR); exval = READHSCX(cs, 0, HSCX_EXIR);
if (exval & 0x40) { if (exval & 0x40) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "HSCX A EXIR %x", exval);
if (bcs->mode == L1_MODE_TRANS) if (bcs->mode == L1_MODE_TRANS)
hscx_fill_fifo(bcs); hscx_fill_fifo(bcs);
else { else {
/* Here we lost an TX interrupt, so xmit_restart_b(bcs);
* restart transmitting the whole frame.
*/
#ifdef ERROR_STATISTIC
bcs->err_tx++;
#endif
if (bcs->tx_skb) {
skb_push(bcs->tx_skb, bcs->count);
bcs->tx_cnt += bcs->count;
bcs->count = 0;
}
WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01); WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01);
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "HSCX A EXIR %x Lost TX", exval);
} }
} else if (cs->debug & L1_DEB_HSCX) } else if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "HSCX A EXIR %x", exval); debugl1(cs, "HSCX A EXIR %x", exval);
......
...@@ -706,32 +706,18 @@ bch_int(struct IsdnCardState *cs, u_char hscx) ...@@ -706,32 +706,18 @@ bch_int(struct IsdnCardState *cs, u_char hscx)
} }
if (istab &0x10) { // XPR if (istab &0x10) { // XPR
if (bcs->tx_skb) { xmit_xpr(bcs);
if (bcs->tx_skb->len) {
ipacx_fill_fifo(bcs);
goto afterXPR;
}
xmit_complete_b(bcs);
bcs->count = 0;
}
xmit_ready_b(bcs);
} }
afterXPR:
if (istab &0x04) { // XDU if (istab &0x04) { // XDU
if (bcs->mode == L1_MODE_TRANS) { if (cs->debug &L1_DEB_WARN)
ipacx_fill_fifo(bcs); debugl1(cs, "bch_int() B-%d XDU error", hscx);
} if (bcs->mode == L1_MODE_TRANS) {
else { ipacx_fill_fifo(bcs);
if (bcs->tx_skb) { // restart transmitting the whole frame } else {
skb_push(bcs->tx_skb, bcs->count); xmit_restart_b(bcs);
bcs->tx_cnt += bcs->count; cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x01); // XRES
bcs->count = 0; }
}
cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x01); // XRES
if (cs->debug &L1_DEB_WARN)
debugl1(cs, "bch_int() B-%d XDU error", hscx);
}
} }
} }
......
...@@ -121,3 +121,41 @@ xmit_pull_req_b(struct PStack *st, struct sk_buff *skb) ...@@ -121,3 +121,41 @@ xmit_pull_req_b(struct PStack *st, struct sk_buff *skb)
if (!busy) if (!busy)
L1L2(st, PH_PULL | CONFIRM, NULL); L1L2(st, PH_PULL | CONFIRM, NULL);
} }
/* called with the card lock held */
static inline void
xmit_restart_b(struct BCState *bcs)
{
#ifdef ERROR_STATISTIC
bcs->err_tx++;
#endif
if (!bcs->tx_skb) {
WARN_ON(1);
return;
}
skb_push(bcs->tx_skb, bcs->count);
bcs->tx_cnt += bcs->count;
bcs->count = 0;
}
/* Useful for HSCX work-alike's */
/* ---------------------------------------------------------------------- */
/* XPR - transmit pool ready */
/* called with the card lock held */
static inline void
xmit_xpr_b(struct BCState *bcs)
{
/* current frame? */
if (bcs->tx_skb) {
/* last frame not done yet? */
if (bcs->tx_skb->len) {
bcs->cs->BC_Send_Data(bcs);
return;
}
xmit_complete_b(bcs);
bcs->count = 0;
}
xmit_ready_b(bcs);
}
...@@ -181,15 +181,7 @@ jade_interrupt(struct IsdnCardState *cs, u_char val, u_char jade) ...@@ -181,15 +181,7 @@ jade_interrupt(struct IsdnCardState *cs, u_char val, u_char jade)
} }
} }
if (val & 0x10) { /* XPR */ if (val & 0x10) { /* XPR */
if (bcs->tx_skb) { xmit_xpr(bcs);
if (bcs->tx_skb->len) {
jade_fill_fifo(bcs);
return;
}
xmit_complete_b(bcs);
bcs->count = 0;
}
xmit_ready_b(bcs);
} }
} }
...@@ -205,22 +197,18 @@ jade_int_main(struct IsdnCardState *cs, u_char val, int jade) ...@@ -205,22 +197,18 @@ jade_int_main(struct IsdnCardState *cs, u_char val, int jade)
val &= ~jadeISR_RFO; val &= ~jadeISR_RFO;
} }
if (val & jadeISR_XDU) { if (val & jadeISR_XDU) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "JADE %c EXIR %x", 'A'+jade, val);
/* relevant in HDLC mode only */ /* relevant in HDLC mode only */
/* don't reset XPR here */ /* don't reset XPR here */
if (bcs->mode == 1) if (bcs->mode == L1_MODE_TRANSPARENT)
jade_fill_fifo(bcs); jade_fill_fifo(bcs);
else { else {
/* Here we lost an TX interrupt, so /* Here we lost an TX interrupt, so
* restart transmitting the whole frame. * restart transmitting the whole frame.
*/ */
if (bcs->tx_skb) { xmit_restart_b(bcs);
skb_push(bcs->tx_skb, bcs->count);
bcs->tx_cnt += bcs->count;
bcs->count = 0;
}
WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, jadeXCMD_XRES); WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, jadeXCMD_XRES);
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "JADE %c EXIR %x Lost TX", 'A'+jade, val);
} }
} }
if (val & (jadeISR_RME|jadeISR_RPF|jadeISR_XPR)) { if (val & (jadeISR_RME|jadeISR_RPF|jadeISR_XPR)) {
......
...@@ -343,20 +343,16 @@ W6692B_interrupt(struct IsdnCardState *cs, u_char bchan) ...@@ -343,20 +343,16 @@ W6692B_interrupt(struct IsdnCardState *cs, u_char bchan)
xmit_xpr(bcs); xmit_xpr(bcs);
} }
if (val & W_B_EXI_XDUN) { /* XDUN */ if (val & W_B_EXI_XDUN) { /* XDUN */
if (bcs->mode == 1) if (cs->debug & L1_DEB_WARN)
debugl1(cs, "W6692 B EXIR %x", val);
if (bcs->mode == L1_MODE_TRANSPARENT)
W6692B_fill_fifo(bcs); W6692B_fill_fifo(bcs);
else { else {
/* Here we lost an TX interrupt, so /* Here we lost an TX interrupt, so
* restart transmitting the whole frame. * restart transmitting the whole frame.
*/ */
if (bcs->tx_skb) { xmit_restart_b(bcs);
skb_push(bcs->tx_skb, bcs->count);
bcs->tx_cnt += bcs->count;
bcs->count = 0;
}
cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT); cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT);
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "W6692 B EXIR %x Lost TX", val);
} }
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment