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)
}
if (stat & HDLC_INT_XDU) {
/* 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;
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);
* restart transmitting the whole frame. */
if (bcs->cs->debug & L1_DEB_WARN)
debugl1(bcs->cs, "ch%d XDU", bcs->channel);
xmit_restart_b(bcs);
bcs->hw.hdlc.ctrl.sr.xml = 0;
bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XRS;
write_ctrl(bcs, 1);
......@@ -441,15 +435,7 @@ HDLC_irq(struct BCState *bcs, u_int stat)
write_ctrl(bcs, 1);
hdlc_fill_fifo(bcs);
} else if (stat & HDLC_INT_XPR) {
if (bcs->tx_skb) {
if (bcs->tx_skb->len) {
hdlc_fill_fifo(bcs);
return;
}
xmit_complete_b(bcs);
bcs->count = 0;
}
xmit_ready_b(bcs);
xmit_xpr_b(bcs);
}
}
......
......@@ -558,23 +558,8 @@ Memhscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
sched_b_event(bcs, B_RCVBUFREADY);
}
}
if (val & 0x10) { /* XPR */
if (bcs->tx_skb) {
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);
}
if (val & 0x10) {
xmit_xpr(bcs);/* XPR */
}
}
......@@ -589,20 +574,16 @@ Memhscx_int_main(struct IsdnCardState *cs, u_char val)
bcs = cs->bcs + 1;
exval = MemReadHSCX(cs, 1, HSCX_EXIR);
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);
else {
/* Here we lost an TX interrupt, so
* restart transmitting the whole frame.
* restart transmitting the whole frame.
*/
if (bcs->tx_skb) {
skb_push(bcs->tx_skb, bcs->count);
bcs->tx_cnt += bcs->count;
bcs->count = 0;
}
xmit_restart_b(bcs);
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)
debugl1(cs, "HSCX B EXIR %x", exval);
......@@ -616,20 +597,16 @@ Memhscx_int_main(struct IsdnCardState *cs, u_char val)
bcs = cs->bcs;
exval = MemReadHSCX(cs, 0, HSCX_EXIR);
if (exval & 0x40) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "HSCX A EXIR %x", exval);
if (bcs->mode == L1_MODE_TRANS)
Memhscx_fill_fifo(bcs);
else {
/* Here we lost an TX interrupt, so
* restart transmitting the whole frame.
* restart transmitting the whole frame.
*/
if (bcs->tx_skb) {
skb_push(bcs->tx_skb, bcs->count);
bcs->tx_cnt += bcs->count;
bcs->count = 0;
}
xmit_restart_b(bcs);
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)
debugl1(cs, "HSCX A EXIR %x", exval);
......
......@@ -292,17 +292,10 @@ write_modem(struct BCState *bcs) {
return(ret);
}
inline void
static void
modem_fill(struct BCState *bcs)
{
if (bcs->tx_skb) {
if (bcs->tx_skb->len) {
write_modem(bcs);
return;
}
xmit_complete_b(bcs);
}
xmit_ready_b(bcs);
xmit_xpr_b(bcs);
}
static inline void receive_chars(struct IsdnCardState *cs,
......
......@@ -190,16 +190,8 @@ hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
sched_b_event(bcs, B_RCVBUFREADY);
}
}
if (val & 0x10) { /* XPR */
if (bcs->tx_skb) {
if (bcs->tx_skb->len) {
hscx_fill_fifo(bcs);
return;
}
xmit_complete_b(bcs);
bcs->count = 0;
}
xmit_ready_b(bcs);
if (val & 0x10) {
xmit_xpr_b(bcs);
}
}
......@@ -215,23 +207,13 @@ hscx_int_main(struct IsdnCardState *cs, u_char val)
bcs = cs->bcs + 1;
exval = READHSCX(cs, 1, HSCX_EXIR);
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);
else {
#ifdef ERROR_STATISTIC
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;
}
xmit_restart_b(bcs);
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)
debugl1(cs, "HSCX B EXIR %x", exval);
......@@ -245,23 +227,13 @@ hscx_int_main(struct IsdnCardState *cs, u_char val)
bcs = cs->bcs;
exval = READHSCX(cs, 0, HSCX_EXIR);
if (exval & 0x40) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "HSCX A EXIR %x", exval);
if (bcs->mode == L1_MODE_TRANS)
hscx_fill_fifo(bcs);
else {
/* Here we lost an TX interrupt, so
* 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;
}
xmit_restart_b(bcs);
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)
debugl1(cs, "HSCX A EXIR %x", exval);
......
......@@ -706,32 +706,18 @@ bch_int(struct IsdnCardState *cs, u_char hscx)
}
if (istab &0x10) { // XPR
if (bcs->tx_skb) {
if (bcs->tx_skb->len) {
ipacx_fill_fifo(bcs);
goto afterXPR;
}
xmit_complete_b(bcs);
bcs->count = 0;
}
xmit_ready_b(bcs);
xmit_xpr(bcs);
}
afterXPR:
if (istab &0x04) { // XDU
if (bcs->mode == L1_MODE_TRANS) {
ipacx_fill_fifo(bcs);
}
else {
if (bcs->tx_skb) { // restart transmitting the whole frame
skb_push(bcs->tx_skb, bcs->count);
bcs->tx_cnt += bcs->count;
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);
}
if (cs->debug &L1_DEB_WARN)
debugl1(cs, "bch_int() B-%d XDU error", hscx);
if (bcs->mode == L1_MODE_TRANS) {
ipacx_fill_fifo(bcs);
} else {
xmit_restart_b(bcs);
cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x01); // XRES
}
}
}
......
......@@ -121,3 +121,41 @@ xmit_pull_req_b(struct PStack *st, struct sk_buff *skb)
if (!busy)
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)
}
}
if (val & 0x10) { /* XPR */
if (bcs->tx_skb) {
if (bcs->tx_skb->len) {
jade_fill_fifo(bcs);
return;
}
xmit_complete_b(bcs);
bcs->count = 0;
}
xmit_ready_b(bcs);
xmit_xpr(bcs);
}
}
......@@ -205,22 +197,18 @@ jade_int_main(struct IsdnCardState *cs, u_char val, int jade)
val &= ~jadeISR_RFO;
}
if (val & jadeISR_XDU) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "JADE %c EXIR %x", 'A'+jade, val);
/* relevant in HDLC mode only */
/* don't reset XPR here */
if (bcs->mode == 1)
if (bcs->mode == L1_MODE_TRANSPARENT)
jade_fill_fifo(bcs);
else {
/* Here we lost an TX interrupt, so
* restart transmitting the whole frame.
* restart transmitting the whole frame.
*/
if (bcs->tx_skb) {
skb_push(bcs->tx_skb, bcs->count);
bcs->tx_cnt += bcs->count;
bcs->count = 0;
}
xmit_restart_b(bcs);
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)) {
......
......@@ -343,20 +343,16 @@ W6692B_interrupt(struct IsdnCardState *cs, u_char bchan)
xmit_xpr(bcs);
}
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);
else {
/* Here we lost an TX interrupt, so
* restart transmitting the whole frame.
* restart transmitting the whole frame.
*/
if (bcs->tx_skb) {
skb_push(bcs->tx_skb, bcs->count);
bcs->tx_cnt += bcs->count;
bcs->count = 0;
}
xmit_restart_b(bcs);
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