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;

_