From: Karsten Keil <kkeil@suse.de> This patch fix a deadlock in HiSax (reported from David Woodhouse <dwmw2@infradead.org>). upper layer was called back while holding the card lock fix is to move the wakeup call into BH handler to avoid direct callbacks. --- 25-akpm/drivers/isdn/hisax/avm_pci.c | 15 ++++++--- 25-akpm/drivers/isdn/hisax/callc.c | 16 +++++----- 25-akpm/drivers/isdn/hisax/config.c | 11 +++++-- 25-akpm/drivers/isdn/hisax/diva.c | 15 ++++++--- 25-akpm/drivers/isdn/hisax/elsa_ser.c | 14 +++++---- 25-akpm/drivers/isdn/hisax/hfc_2bds0.c | 13 +++++--- 25-akpm/drivers/isdn/hisax/hfc_2bs0.c | 12 +++++-- 25-akpm/drivers/isdn/hisax/hfc_pci.c | 26 +++++++++++----- 25-akpm/drivers/isdn/hisax/hfc_sx.c | 15 ++++++--- 25-akpm/drivers/isdn/hisax/hisax.h | 10 ++++-- 25-akpm/drivers/isdn/hisax/hscx_irq.c | 13 +++++--- 25-akpm/drivers/isdn/hisax/ipacx.c | 51 +++++++++++++++++---------------- 25-akpm/drivers/isdn/hisax/isar.c | 13 +++++--- 25-akpm/drivers/isdn/hisax/isdnl1.c | 21 ++++++++++++- 25-akpm/drivers/isdn/hisax/isdnl1.h | 7 ++-- 25-akpm/drivers/isdn/hisax/isdnl2.c | 8 ++--- 25-akpm/drivers/isdn/hisax/jade_irq.c | 13 +++++--- 25-akpm/drivers/isdn/hisax/netjet.c | 15 ++++++--- 25-akpm/drivers/isdn/hisax/w6692.c | 15 ++++++--- 19 files changed, 199 insertions(+), 104 deletions(-) diff -puN drivers/isdn/hisax/avm_pci.c~i4l-hisax-deadlock-fix drivers/isdn/hisax/avm_pci.c --- 25/drivers/isdn/hisax/avm_pci.c~i4l-hisax-deadlock-fix Wed Feb 11 13:59:06 2004 +++ 25-akpm/drivers/isdn/hisax/avm_pci.c Wed Feb 11 13:59:06 2004 @@ -1,4 +1,4 @@ -/* $Id: avm_pci.c,v 1.29.2.3 2004/01/13 14:31:24 keil Exp $ +/* $Id: avm_pci.c,v 1.29.2.4 2004/02/11 13:21:32 keil Exp $ * * low level stuff for AVM Fritz!PCI and ISA PnP isdn cards * @@ -22,7 +22,7 @@ #include <linux/interrupt.h> extern const char *CardType[]; -static const char *avm_pci_rev = "$Revision: 1.29.2.3 $"; +static const char *avm_pci_rev = "$Revision: 1.29.2.4 $"; #define AVM_FRITZ_PCI 1 #define AVM_FRITZ_PNP 2 @@ -427,9 +427,14 @@ HDLC_irq(struct BCState *bcs, u_int stat hdlc_fill_fifo(bcs); return; } else { - if (bcs->st->lli.l1writewakeup && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) - bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hdlc.count); + if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) { + u_long flags; + spin_lock_irqsave(&bcs->aclock, flags); + bcs->ackcnt += bcs->hw.hdlc.count; + spin_unlock_irqrestore(&bcs->aclock, flags); + schedule_event(bcs, B_ACKPENDING); + } dev_kfree_skb_irq(bcs->tx_skb); bcs->hw.hdlc.count = 0; bcs->tx_skb = NULL; diff -puN drivers/isdn/hisax/callc.c~i4l-hisax-deadlock-fix drivers/isdn/hisax/callc.c --- 25/drivers/isdn/hisax/callc.c~i4l-hisax-deadlock-fix Wed Feb 11 13:59:06 2004 +++ 25-akpm/drivers/isdn/hisax/callc.c Wed Feb 11 13:59:06 2004 @@ -1,4 +1,4 @@ -/* $Id: callc.c,v 2.59.2.3 2004/01/13 14:31:24 keil Exp $ +/* $Id: callc.c,v 2.59.2.4 2004/02/11 13:21:32 keil Exp $ * * Author Karsten Keil * Copyright by Karsten Keil <keil@isdn4linux.de> @@ -21,7 +21,7 @@ #include "hisax.h" #include <linux/isdn/capicmd.h> -const char *lli_revision = "$Revision: 2.59.2.3 $"; +const char *lli_revision = "$Revision: 2.59.2.4 $"; extern struct IsdnCard cards[]; extern int nrcards; @@ -1065,7 +1065,6 @@ init_d_st(struct Channel *chanp) setstack_isdnl2(st, tmp); setstack_l3dc(st, chanp); st->lli.userdata = chanp; - st->lli.l2writewakeup = NULL; st->l3.l3l4 = dchan_l3l4; return 0; @@ -1247,8 +1246,8 @@ lltrans_handler(struct PStack *st, int p } } -static void -ll_writewakeup(struct PStack *st, int len) +void +lli_writewakeup(struct PStack *st, int len) { struct Channel *chanp = st->lli.userdata; isdn_ctrl ic; @@ -1312,8 +1311,8 @@ init_b_st(struct Channel *chanp, int inc setstack_l3bc(st, chanp); st->l2.l2l3 = lldata_handler; st->lli.userdata = chanp; - st->lli.l1writewakeup = NULL; - st->lli.l2writewakeup = ll_writewakeup; + test_and_clear_bit(FLG_LLI_L1WAKEUP, &st->lli.flag); + test_and_set_bit(FLG_LLI_L2WAKEUP, &st->lli.flag); st->l2.l2m.debug = chanp->debug & 16; st->l2.debug = chanp->debug & 64; break; @@ -1324,7 +1323,8 @@ init_b_st(struct Channel *chanp, int inc case (ISDN_PROTO_L2_FAX): st->l1.l1l2 = lltrans_handler; st->lli.userdata = chanp; - st->lli.l1writewakeup = ll_writewakeup; + test_and_set_bit(FLG_LLI_L1WAKEUP, &st->lli.flag); + test_and_clear_bit(FLG_LLI_L2WAKEUP, &st->lli.flag); setstack_transl2(st); setstack_l3bc(st, chanp); break; diff -puN drivers/isdn/hisax/config.c~i4l-hisax-deadlock-fix drivers/isdn/hisax/config.c --- 25/drivers/isdn/hisax/config.c~i4l-hisax-deadlock-fix Wed Feb 11 13:59:06 2004 +++ 25-akpm/drivers/isdn/hisax/config.c Wed Feb 11 13:59:06 2004 @@ -1,4 +1,4 @@ -/* $Id: config.c,v 2.84.2.4 2004/01/24 20:47:20 keil Exp $ +/* $Id: config.c,v 2.84.2.5 2004/02/11 13:21:33 keil Exp $ * * Author Karsten Keil * Copyright by Karsten Keil <keil@isdn4linux.de> @@ -1734,8 +1734,13 @@ static void hisax_b_l1l2(struct hisax_if break; case PH_DATA | CONFIRM: bcs->tx_cnt -= (int) arg; - if (bcs->st->lli.l1writewakeup) - bcs->st->lli.l1writewakeup(bcs->st, (int) arg); + if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag)) { + u_long flags; + spin_lock_irqsave(&bcs->aclock, flags); + bcs->ackcnt += (int) arg; + spin_unlock_irqrestore(&bcs->aclock, flags); + schedule_event(bcs, B_ACKPENDING); + } skb = skb_dequeue(&bcs->squeue); if (skb) { B_L2L1(b_if, PH_DATA | REQUEST, skb); diff -puN drivers/isdn/hisax/diva.c~i4l-hisax-deadlock-fix drivers/isdn/hisax/diva.c --- 25/drivers/isdn/hisax/diva.c~i4l-hisax-deadlock-fix Wed Feb 11 13:59:06 2004 +++ 25-akpm/drivers/isdn/hisax/diva.c Wed Feb 11 13:59:06 2004 @@ -1,4 +1,4 @@ -/* $Id: diva.c,v 1.33.2.5 2004/01/14 00:49:43 keil Exp $ +/* $Id: diva.c,v 1.33.2.6 2004/02/11 13:21:33 keil Exp $ * * low level stuff for Eicon.Diehl Diva Family ISDN cards * @@ -28,7 +28,7 @@ extern const char *CardType[]; -const char *Diva_revision = "$Revision: 1.33.2.5 $"; +const char *Diva_revision = "$Revision: 1.33.2.6 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -542,9 +542,14 @@ Memhscx_interrupt(struct IsdnCardState * Memhscx_fill_fifo(bcs); return; } else { - if (bcs->st->lli.l1writewakeup && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) - bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count); + if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) { + u_long flags; + spin_lock_irqsave(&bcs->aclock, flags); + bcs->ackcnt += bcs->hw.hscx.count; + spin_unlock_irqrestore(&bcs->aclock, flags); + schedule_event(bcs, B_ACKPENDING); + } dev_kfree_skb_irq(bcs->tx_skb); bcs->hw.hscx.count = 0; bcs->tx_skb = NULL; diff -puN drivers/isdn/hisax/elsa_ser.c~i4l-hisax-deadlock-fix drivers/isdn/hisax/elsa_ser.c --- 25/drivers/isdn/hisax/elsa_ser.c~i4l-hisax-deadlock-fix Wed Feb 11 13:59:06 2004 +++ 25-akpm/drivers/isdn/hisax/elsa_ser.c Wed Feb 11 13:59:06 2004 @@ -1,4 +1,4 @@ -/* $Id: elsa_ser.c,v 2.14.2.2 2004/01/12 22:52:26 keil Exp $ +/* $Id: elsa_ser.c,v 2.14.2.3 2004/02/11 13:21:33 keil Exp $ * * stuff for the serial modem on ELSA cards * @@ -283,10 +283,14 @@ modem_fill(struct BCState *bcs) { write_modem(bcs); return; } else { - if (bcs->st->lli.l1writewakeup && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) - bcs->st->lli.l1writewakeup(bcs->st, - bcs->hw.hscx.count); + if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) { + u_long flags; + spin_lock_irqsave(&bcs->aclock, flags); + bcs->ackcnt += bcs->hw.hscx.count; + spin_unlock_irqrestore(&bcs->aclock, flags); + schedule_event(bcs, B_ACKPENDING); + } dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; } diff -puN drivers/isdn/hisax/hfc_2bds0.c~i4l-hisax-deadlock-fix drivers/isdn/hisax/hfc_2bds0.c --- 25/drivers/isdn/hisax/hfc_2bds0.c~i4l-hisax-deadlock-fix Wed Feb 11 13:59:06 2004 +++ 25-akpm/drivers/isdn/hisax/hfc_2bds0.c Wed Feb 11 13:59:06 2004 @@ -1,4 +1,4 @@ -/* $Id: hfc_2bds0.c,v 1.18.2.5 2004/01/19 15:31:50 keil Exp $ +/* $Id: hfc_2bds0.c,v 1.18.2.6 2004/02/11 13:21:33 keil Exp $ * * specific routines for CCD's HFC 2BDS0 * @@ -314,9 +314,14 @@ hfc_fill_fifo(struct BCState *bcs) printk(KERN_WARNING "HFC S FIFO channel %d BUSY Error\n", bcs->channel); } else { bcs->tx_cnt -= bcs->tx_skb->len; - if (bcs->st->lli.l1writewakeup && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) - bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); + if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) { + u_long flags; + spin_lock_irqsave(&bcs->aclock, flags); + bcs->ackcnt += bcs->tx_skb->len; + spin_unlock_irqrestore(&bcs->aclock, flags); + schedule_event(bcs, B_ACKPENDING); + } dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; } diff -puN drivers/isdn/hisax/hfc_2bs0.c~i4l-hisax-deadlock-fix drivers/isdn/hisax/hfc_2bs0.c --- 25/drivers/isdn/hisax/hfc_2bs0.c~i4l-hisax-deadlock-fix Wed Feb 11 13:59:06 2004 +++ 25-akpm/drivers/isdn/hisax/hfc_2bs0.c Wed Feb 11 13:59:06 2004 @@ -1,4 +1,4 @@ -/* $Id: hfc_2bs0.c,v 1.20.2.5 2004/01/19 15:31:50 keil Exp $ +/* $Id: hfc_2bs0.c,v 1.20.2.6 2004/02/11 13:21:33 keil Exp $ * * specific routines for CCD's HFC 2BS0 * @@ -308,8 +308,14 @@ hfc_fill_fifo(struct BCState *bcs) WaitNoBusy(cs); cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F1_INC | HFC_SEND | HFC_CHANNEL(bcs->channel)); } - if (bcs->st->lli.l1writewakeup && (count >= 0)) - bcs->st->lli.l1writewakeup(bcs->st, count); + if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) && + (count >= 0)) { + u_long flags; + spin_lock_irqsave(&bcs->aclock, flags); + bcs->ackcnt += count; + spin_unlock_irqrestore(&bcs->aclock, flags); + schedule_event(bcs, B_ACKPENDING); + } test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } return; diff -puN drivers/isdn/hisax/hfc_pci.c~i4l-hisax-deadlock-fix drivers/isdn/hisax/hfc_pci.c --- 25/drivers/isdn/hisax/hfc_pci.c~i4l-hisax-deadlock-fix Wed Feb 11 13:59:06 2004 +++ 25-akpm/drivers/isdn/hisax/hfc_pci.c Wed Feb 11 13:59:06 2004 @@ -1,4 +1,4 @@ -/* $Id: hfc_pci.c,v 1.48.2.3 2004/01/13 14:31:25 keil Exp $ +/* $Id: hfc_pci.c,v 1.48.2.4 2004/02/11 13:21:33 keil Exp $ * * low level driver for CCD�s hfc-pci based cards * @@ -25,7 +25,7 @@ extern const char *CardType[]; -static const char *hfcpci_revision = "$Revision: 1.48.2.3 $"; +static const char *hfcpci_revision = "$Revision: 1.48.2.4 $"; /* table entry in the PCI devices list */ typedef struct { @@ -649,9 +649,14 @@ hfcpci_fill_fifo(struct BCState *bcs) debugl1(cs, "hfcpci_fill_fifo_trans %d frame length %d discarded", bcs->channel, bcs->tx_skb->len); - if (bcs->st->lli.l1writewakeup && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) - bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); + if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) { + u_long flags; + spin_lock_irqsave(&bcs->aclock, flags); + bcs->ackcnt += bcs->tx_skb->len; + spin_unlock_irqrestore(&bcs->aclock, flags); + schedule_event(bcs, B_ACKPENDING); + } dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = skb_dequeue(&bcs->squeue); /* fetch next data */ @@ -707,9 +712,14 @@ hfcpci_fill_fifo(struct BCState *bcs) memcpy(dst, src, count); } bcs->tx_cnt -= bcs->tx_skb->len; - if (bcs->st->lli.l1writewakeup && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) - bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); + if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) { + u_long flags; + spin_lock_irqsave(&bcs->aclock, flags); + bcs->ackcnt += bcs->tx_skb->len; + spin_unlock_irqrestore(&bcs->aclock, flags); + schedule_event(bcs, B_ACKPENDING); + } bz->za[new_f1].z1 = new_z1; /* for next buffer */ bz->f1 = new_f1; /* next frame */ diff -puN drivers/isdn/hisax/hfc_sx.c~i4l-hisax-deadlock-fix drivers/isdn/hisax/hfc_sx.c --- 25/drivers/isdn/hisax/hfc_sx.c~i4l-hisax-deadlock-fix Wed Feb 11 13:59:06 2004 +++ 25-akpm/drivers/isdn/hisax/hfc_sx.c Wed Feb 11 13:59:06 2004 @@ -1,4 +1,4 @@ -/* $Id: hfc_sx.c,v 1.12.2.4 2004/01/14 16:04:48 keil Exp $ +/* $Id: hfc_sx.c,v 1.12.2.5 2004/02/11 13:21:33 keil Exp $ * * level driver for Cologne Chip Designs hfc-s+/sp based cards * @@ -20,7 +20,7 @@ extern const char *CardType[]; -static const char *hfcsx_revision = "$Revision: 1.12.2.4 $"; +static const char *hfcsx_revision = "$Revision: 1.12.2.5 $"; /***************************************/ /* IRQ-table for CCDs demo board */ @@ -540,9 +540,14 @@ hfcsx_fill_fifo(struct BCState *bcs) HFCSX_BTRANS_THRESHOLD : 0)) { bcs->tx_cnt -= bcs->tx_skb->len; - if (bcs->st->lli.l1writewakeup && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) - bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); + if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) { + u_long flags; + spin_lock_irqsave(&bcs->aclock, flags); + bcs->ackcnt += bcs->tx_skb->len; + spin_unlock_irqrestore(&bcs->aclock, flags); + schedule_event(bcs, B_ACKPENDING); + } dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); diff -puN drivers/isdn/hisax/hisax.h~i4l-hisax-deadlock-fix drivers/isdn/hisax/hisax.h --- 25/drivers/isdn/hisax/hisax.h~i4l-hisax-deadlock-fix Wed Feb 11 13:59:06 2004 +++ 25-akpm/drivers/isdn/hisax/hisax.h Wed Feb 11 13:59:06 2004 @@ -1,4 +1,4 @@ -/* $Id: hisax.h,v 2.64.2.3 2004/01/24 20:47:23 keil Exp $ +/* $Id: hisax.h,v 2.64.2.4 2004/02/11 13:21:33 keil Exp $ * * Basic declarations, defines and prototypes * @@ -280,10 +280,11 @@ struct LLInterface { void (*l4l3) (struct PStack *, int, void *); int (*l4l3_proto) (struct PStack *, isdn_ctrl *); void *userdata; - void (*l1writewakeup) (struct PStack *, int); - void (*l2writewakeup) (struct PStack *, int); + u_long flag; }; +#define FLG_LLI_L1WAKEUP 1 +#define FLG_LLI_L2WAKEUP 2 struct Management { int ri; @@ -494,6 +495,8 @@ struct BCState { struct sk_buff *tx_skb; /* B-Channel transmit Buffer */ struct sk_buff_head rqueue; /* B-Channel receive Queue */ struct sk_buff_head squeue; /* B-Channel send Queue */ + int ackcnt; + spinlock_t aclock; struct PStack *st; u_char *blog; u_char *conmsg; @@ -1281,6 +1284,7 @@ void setstack_isdnl2(struct PStack *st, void releasestack_isdnl2(struct PStack *st); void setstack_transl2(struct PStack *st); void releasestack_transl2(struct PStack *st); +void lli_writewakeup(struct PStack *st, int len); void setstack_l3dc(struct PStack *st, struct Channel *chanp); void setstack_l3bc(struct PStack *st, struct Channel *chanp); diff -puN drivers/isdn/hisax/hscx_irq.c~i4l-hisax-deadlock-fix drivers/isdn/hisax/hscx_irq.c --- 25/drivers/isdn/hisax/hscx_irq.c~i4l-hisax-deadlock-fix Wed Feb 11 13:59:06 2004 +++ 25-akpm/drivers/isdn/hisax/hscx_irq.c Wed Feb 11 13:59:06 2004 @@ -1,4 +1,4 @@ -/* $Id: hscx_irq.c,v 1.18.2.2 2004/01/12 22:52:26 keil Exp $ +/* $Id: hscx_irq.c,v 1.18.2.3 2004/02/11 13:21:34 keil Exp $ * * low level b-channel stuff for Siemens HSCX * @@ -197,9 +197,14 @@ hscx_interrupt(struct IsdnCardState *cs, hscx_fill_fifo(bcs); return; } else { - if (bcs->st->lli.l1writewakeup && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) - bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count); + if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) { + u_long flags; + spin_lock_irqsave(&bcs->aclock, flags); + bcs->ackcnt += bcs->hw.hscx.count; + spin_unlock_irqrestore(&bcs->aclock, flags); + schedule_event(bcs, B_ACKPENDING); + } dev_kfree_skb_irq(bcs->tx_skb); bcs->hw.hscx.count = 0; bcs->tx_skb = NULL; diff -puN drivers/isdn/hisax/ipacx.c~i4l-hisax-deadlock-fix drivers/isdn/hisax/ipacx.c --- 25/drivers/isdn/hisax/ipacx.c~i4l-hisax-deadlock-fix Wed Feb 11 13:59:06 2004 +++ 25-akpm/drivers/isdn/hisax/ipacx.c Wed Feb 11 13:59:06 2004 @@ -733,35 +733,38 @@ bch_int(struct IsdnCardState *cs, u_char if (istab &0x20) { // RFO if (cs->debug &L1_DEB_WARN) - debugl1(cs, "bch_int() B-%d: RFO error", hscx); - cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x40); // RRES + debugl1(cs, "bch_int() B-%d: RFO error", hscx); + cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x40); // RRES } if (istab &0x10) { // XPR if (bcs->tx_skb) { if (bcs->tx_skb->len) { - bch_fill_fifo(bcs); - goto afterXPR; - } - else { - if (bcs->st->lli.l1writewakeup && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) { - bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count); - } - dev_kfree_skb_irq(bcs->tx_skb); - bcs->hw.hscx.count = 0; - bcs->tx_skb = NULL; - } - } - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - bcs->hw.hscx.count = 0; - set_bit(BC_FLG_BUSY, &bcs->Flag); - bch_fill_fifo(bcs); - } else { - clear_bit(BC_FLG_BUSY, &bcs->Flag); - schedule_event(bcs, B_XMTBUFREADY); - } - } + bch_fill_fifo(bcs); + goto afterXPR; + } else { + if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) { + u_long flags; + spin_lock_irqsave(&bcs->aclock, flags); + bcs->ackcnt += bcs->hw.hscx.count; + spin_unlock_irqrestore(&bcs->aclock, flags); + schedule_event(bcs, B_ACKPENDING); + } + } + dev_kfree_skb_irq(bcs->tx_skb); + bcs->hw.hscx.count = 0; + bcs->tx_skb = NULL; + } + if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { + bcs->hw.hscx.count = 0; + set_bit(BC_FLG_BUSY, &bcs->Flag); + bch_fill_fifo(bcs); + } else { + clear_bit(BC_FLG_BUSY, &bcs->Flag); + schedule_event(bcs, B_XMTBUFREADY); + } + } afterXPR: if (istab &0x04) { // XDU diff -puN drivers/isdn/hisax/isar.c~i4l-hisax-deadlock-fix drivers/isdn/hisax/isar.c --- 25/drivers/isdn/hisax/isar.c~i4l-hisax-deadlock-fix Wed Feb 11 13:59:06 2004 +++ 25-akpm/drivers/isdn/hisax/isar.c Wed Feb 11 13:59:06 2004 @@ -1,4 +1,4 @@ -/* $Id: isar.c,v 1.22.2.5 2004/01/14 00:49:44 keil Exp $ +/* $Id: isar.c,v 1.22.2.6 2004/02/11 13:21:34 keil Exp $ * * isar.c ISAR (Siemens PSB 7110) specific routines * @@ -759,9 +759,14 @@ send_frames(struct BCState *bcs) isar_fill_fifo(bcs); return; } else { - if (bcs->st->lli.l1writewakeup && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) - bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.isar.txcnt); + if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) { + u_long flags; + spin_lock_irqsave(&bcs->aclock, flags); + bcs->ackcnt += bcs->hw.isar.txcnt; + spin_unlock_irqrestore(&bcs->aclock, flags); + schedule_event(bcs, B_ACKPENDING); + } if (bcs->mode == L1_MODE_FAX) { if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) { if (test_bit(BC_FLG_LASTDATA, &bcs->Flag)) { diff -puN drivers/isdn/hisax/isdnl1.c~i4l-hisax-deadlock-fix drivers/isdn/hisax/isdnl1.c --- 25/drivers/isdn/hisax/isdnl1.c~i4l-hisax-deadlock-fix Wed Feb 11 13:59:06 2004 +++ 25-akpm/drivers/isdn/hisax/isdnl1.c Wed Feb 11 13:59:06 2004 @@ -1,4 +1,4 @@ -/* $Id: isdnl1.c,v 2.46.2.4 2004/01/13 21:46:03 keil Exp $ +/* $Id: isdnl1.c,v 2.46.2.5 2004/02/11 13:21:34 keil Exp $ * * common low level stuff for Siemens Chipsetbased isdn cards * @@ -18,7 +18,7 @@ * */ -const char *l1_revision = "$Revision: 2.46.2.4 $"; +const char *l1_revision = "$Revision: 2.46.2.5 $"; #include <linux/init.h> #include "hisax.h" @@ -299,6 +299,20 @@ BChannel_proc_rcv(struct BCState *bcs) } } +static void +BChannel_proc_ack(struct BCState *bcs) +{ + u_long flags; + int ack; + + spin_lock_irqsave(&bcs->aclock, flags); + ack = bcs->ackcnt; + bcs->ackcnt = 0; + spin_unlock_irqrestore(&bcs->aclock, flags); + if (ack) + lli_writewakeup(bcs->st, ack); +} + void BChannel_bh(struct BCState *bcs) { @@ -308,6 +322,8 @@ BChannel_bh(struct BCState *bcs) BChannel_proc_rcv(bcs); if (test_and_clear_bit(B_XMTBUFREADY, &bcs->event)) BChannel_proc_xmt(bcs); + if (test_and_clear_bit(B_ACKPENDING, &bcs->event)) + BChannel_proc_ack(bcs); } void @@ -346,6 +362,7 @@ init_bcstate(struct IsdnCardState *cs, i bcs->cs = cs; bcs->channel = bc; INIT_WORK(&bcs->tqueue, (void *)(void *) BChannel_bh, bcs); + spin_lock_init(&bcs->aclock); bcs->BC_SetStack = NULL; bcs->BC_Close = NULL; bcs->Flag = 0; diff -puN drivers/isdn/hisax/isdnl1.h~i4l-hisax-deadlock-fix drivers/isdn/hisax/isdnl1.h --- 25/drivers/isdn/hisax/isdnl1.h~i4l-hisax-deadlock-fix Wed Feb 11 13:59:06 2004 +++ 25-akpm/drivers/isdn/hisax/isdnl1.h Wed Feb 11 13:59:06 2004 @@ -1,4 +1,4 @@ -/* $Id: isdnl1.h,v 2.12.2.2 2004/01/12 22:52:27 keil Exp $ +/* $Id: isdnl1.h,v 2.12.2.3 2004/02/11 13:21:34 keil Exp $ * * Layer 1 defines * @@ -17,8 +17,9 @@ #define D_TX_MON1 7 #define E_RCVBUFREADY 8 -#define B_RCVBUFREADY 0 -#define B_XMTBUFREADY 1 +#define B_RCVBUFREADY 0 +#define B_XMTBUFREADY 1 +#define B_ACKPENDING 2 extern void debugl1(struct IsdnCardState *cs, char *fmt, ...); extern void DChannel_proc_xmt(struct IsdnCardState *cs); diff -puN drivers/isdn/hisax/isdnl2.c~i4l-hisax-deadlock-fix drivers/isdn/hisax/isdnl2.c --- 25/drivers/isdn/hisax/isdnl2.c~i4l-hisax-deadlock-fix Wed Feb 11 13:59:06 2004 +++ 25-akpm/drivers/isdn/hisax/isdnl2.c Wed Feb 11 13:59:06 2004 @@ -1,4 +1,4 @@ -/* $Id: isdnl2.c,v 2.30.2.3 2004/01/13 14:31:25 keil Exp $ +/* $Id: isdnl2.c,v 2.30.2.4 2004/02/11 13:21:34 keil Exp $ * * Author Karsten Keil * based on the teles driver from Jan den Ouden @@ -19,7 +19,7 @@ #include "hisax.h" #include "isdnl2.h" -const char *l2_revision = "$Revision: 2.30.2.3 $"; +const char *l2_revision = "$Revision: 2.30.2.4 $"; static void l2m_debug(struct FsmInst *fi, char *fmt, ...); @@ -420,8 +420,8 @@ setva(struct PStack *st, unsigned int nr l2->windowar[l2->sow] = NULL; l2->sow = (l2->sow + 1) % l2->window; spin_unlock_irqrestore(&l2->lock, flags); - if (st->lli.l2writewakeup && (len >=0)) - st->lli.l2writewakeup(st, len); + if (test_bit(FLG_LLI_L2WAKEUP, &st->lli.flag) && (len >=0)) + lli_writewakeup(st, len); spin_lock_irqsave(&l2->lock, flags); } spin_unlock_irqrestore(&l2->lock, flags); diff -puN drivers/isdn/hisax/jade_irq.c~i4l-hisax-deadlock-fix drivers/isdn/hisax/jade_irq.c --- 25/drivers/isdn/hisax/jade_irq.c~i4l-hisax-deadlock-fix Wed Feb 11 13:59:06 2004 +++ 25-akpm/drivers/isdn/hisax/jade_irq.c Wed Feb 11 13:59:06 2004 @@ -1,4 +1,4 @@ -/* $Id: jade_irq.c,v 1.7.2.3 2004/01/14 16:04:48 keil Exp $ +/* $Id: jade_irq.c,v 1.7.2.4 2004/02/11 13:21:34 keil Exp $ * * Low level JADE IRQ stuff (derived from original hscx_irq.c) * @@ -175,9 +175,14 @@ jade_interrupt(struct IsdnCardState *cs, jade_fill_fifo(bcs); return; } else { - if (bcs->st->lli.l1writewakeup && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) - bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count); + if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) { + u_long flags; + spin_lock_irqsave(&bcs->aclock, flags); + bcs->ackcnt += bcs->hw.hscx.count; + spin_unlock_irqrestore(&bcs->aclock, flags); + schedule_event(bcs, B_ACKPENDING); + } dev_kfree_skb_irq(bcs->tx_skb); bcs->hw.hscx.count = 0; bcs->tx_skb = NULL; diff -puN drivers/isdn/hisax/netjet.c~i4l-hisax-deadlock-fix drivers/isdn/hisax/netjet.c --- 25/drivers/isdn/hisax/netjet.c~i4l-hisax-deadlock-fix Wed Feb 11 13:59:06 2004 +++ 25-akpm/drivers/isdn/hisax/netjet.c Wed Feb 11 13:59:06 2004 @@ -1,4 +1,4 @@ -/* $Id: netjet.c,v 1.29.2.3 2004/01/13 14:31:26 keil Exp $ +/* $Id: netjet.c,v 1.29.2.4 2004/02/11 13:21:34 keil Exp $ * * low level stuff for Traverse Technologie NETJet ISDN cards * @@ -25,7 +25,7 @@ #include <asm/io.h> #include "netjet.h" -const char *NETjet_revision = "$Revision: 1.29.2.3 $"; +const char *NETjet_revision = "$Revision: 1.29.2.4 $"; /* Interface functions */ @@ -748,9 +748,14 @@ static void write_raw(struct BCState *bc if (!bcs->tx_skb) { debugl1(bcs->cs,"tiger write_raw: NULL skb s_cnt %d", s_cnt); } else { - if (bcs->st->lli.l1writewakeup && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) - bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); + if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) { + u_long flags; + spin_lock_irqsave(&bcs->aclock, flags); + bcs->ackcnt += bcs->tx_skb->len; + spin_unlock_irqrestore(&bcs->aclock, flags); + schedule_event(bcs, B_ACKPENDING); + } dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; } diff -puN drivers/isdn/hisax/w6692.c~i4l-hisax-deadlock-fix drivers/isdn/hisax/w6692.c --- 25/drivers/isdn/hisax/w6692.c~i4l-hisax-deadlock-fix Wed Feb 11 13:59:06 2004 +++ 25-akpm/drivers/isdn/hisax/w6692.c Wed Feb 11 13:59:06 2004 @@ -1,4 +1,4 @@ -/* $Id: w6692.c,v 1.18.2.3 2004/01/13 14:31:26 keil Exp $ +/* $Id: w6692.c,v 1.18.2.4 2004/02/11 13:21:34 keil Exp $ * * Winbond W6692 specific routines * @@ -41,7 +41,7 @@ static const PCI_ENTRY id_list[] = extern const char *CardType[]; -const char *w6692_revision = "$Revision: 1.18.2.3 $"; +const char *w6692_revision = "$Revision: 1.18.2.4 $"; #define DBUSY_TIMER_VALUE 80 @@ -376,9 +376,14 @@ W6692B_interrupt(struct IsdnCardState *c W6692B_fill_fifo(bcs); return; } else { - if (bcs->st->lli.l1writewakeup && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) - bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.w6692.count); + if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) && + (PACKET_NOACK != bcs->tx_skb->pkt_type)) { + u_long flags; + spin_lock_irqsave(&bcs->aclock, flags); + bcs->ackcnt += bcs->hw.w6692.count; + spin_unlock_irqrestore(&bcs->aclock, flags); + schedule_event(bcs, B_ACKPENDING); + } dev_kfree_skb_irq(bcs->tx_skb); bcs->hw.w6692.count = 0; bcs->tx_skb = NULL; _