Commit 93ab17e8 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] i4l: hisax deadlock fix

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.
parent bb257be4
/* $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 * low level stuff for AVM Fritz!PCI and ISA PnP isdn cards
* *
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
extern const char *CardType[]; 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_PCI 1
#define AVM_FRITZ_PNP 2 #define AVM_FRITZ_PNP 2
...@@ -427,9 +427,14 @@ HDLC_irq(struct BCState *bcs, u_int stat) { ...@@ -427,9 +427,14 @@ HDLC_irq(struct BCState *bcs, u_int stat) {
hdlc_fill_fifo(bcs); hdlc_fill_fifo(bcs);
return; return;
} else { } else {
if (bcs->st->lli.l1writewakeup && if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
(PACKET_NOACK != bcs->tx_skb->pkt_type)) (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hdlc.count); 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); dev_kfree_skb_irq(bcs->tx_skb);
bcs->hw.hdlc.count = 0; bcs->hw.hdlc.count = 0;
bcs->tx_skb = NULL; bcs->tx_skb = NULL;
......
/* $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 * Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de> * Copyright by Karsten Keil <keil@isdn4linux.de>
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
#include "hisax.h" #include "hisax.h"
#include <linux/isdn/capicmd.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 struct IsdnCard cards[];
extern int nrcards; extern int nrcards;
...@@ -1065,7 +1065,6 @@ init_d_st(struct Channel *chanp) ...@@ -1065,7 +1065,6 @@ init_d_st(struct Channel *chanp)
setstack_isdnl2(st, tmp); setstack_isdnl2(st, tmp);
setstack_l3dc(st, chanp); setstack_l3dc(st, chanp);
st->lli.userdata = chanp; st->lli.userdata = chanp;
st->lli.l2writewakeup = NULL;
st->l3.l3l4 = dchan_l3l4; st->l3.l3l4 = dchan_l3l4;
return 0; return 0;
...@@ -1247,8 +1246,8 @@ lltrans_handler(struct PStack *st, int pr, void *arg) ...@@ -1247,8 +1246,8 @@ lltrans_handler(struct PStack *st, int pr, void *arg)
} }
} }
static void void
ll_writewakeup(struct PStack *st, int len) lli_writewakeup(struct PStack *st, int len)
{ {
struct Channel *chanp = st->lli.userdata; struct Channel *chanp = st->lli.userdata;
isdn_ctrl ic; isdn_ctrl ic;
...@@ -1312,8 +1311,8 @@ init_b_st(struct Channel *chanp, int incoming) ...@@ -1312,8 +1311,8 @@ init_b_st(struct Channel *chanp, int incoming)
setstack_l3bc(st, chanp); setstack_l3bc(st, chanp);
st->l2.l2l3 = lldata_handler; st->l2.l2l3 = lldata_handler;
st->lli.userdata = chanp; st->lli.userdata = chanp;
st->lli.l1writewakeup = NULL; test_and_clear_bit(FLG_LLI_L1WAKEUP, &st->lli.flag);
st->lli.l2writewakeup = ll_writewakeup; test_and_set_bit(FLG_LLI_L2WAKEUP, &st->lli.flag);
st->l2.l2m.debug = chanp->debug & 16; st->l2.l2m.debug = chanp->debug & 16;
st->l2.debug = chanp->debug & 64; st->l2.debug = chanp->debug & 64;
break; break;
...@@ -1324,7 +1323,8 @@ init_b_st(struct Channel *chanp, int incoming) ...@@ -1324,7 +1323,8 @@ init_b_st(struct Channel *chanp, int incoming)
case (ISDN_PROTO_L2_FAX): case (ISDN_PROTO_L2_FAX):
st->l1.l1l2 = lltrans_handler; st->l1.l1l2 = lltrans_handler;
st->lli.userdata = chanp; 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_transl2(st);
setstack_l3bc(st, chanp); setstack_l3bc(st, chanp);
break; break;
......
/* $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 * Author Karsten Keil
* Copyright by Karsten Keil <keil@isdn4linux.de> * Copyright by Karsten Keil <keil@isdn4linux.de>
...@@ -1734,8 +1734,13 @@ static void hisax_b_l1l2(struct hisax_if *ifc, int pr, void *arg) ...@@ -1734,8 +1734,13 @@ static void hisax_b_l1l2(struct hisax_if *ifc, int pr, void *arg)
break; break;
case PH_DATA | CONFIRM: case PH_DATA | CONFIRM:
bcs->tx_cnt -= (int) arg; bcs->tx_cnt -= (int) arg;
if (bcs->st->lli.l1writewakeup) if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag)) {
bcs->st->lli.l1writewakeup(bcs->st, (int) arg); 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); skb = skb_dequeue(&bcs->squeue);
if (skb) { if (skb) {
B_L2L1(b_if, PH_DATA | REQUEST, skb); B_L2L1(b_if, PH_DATA | REQUEST, skb);
......
/* $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 * low level stuff for Eicon.Diehl Diva Family ISDN cards
* *
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
extern const char *CardType[]; 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 byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr) #define bytein(addr) inb(addr)
...@@ -542,9 +542,14 @@ Memhscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx) ...@@ -542,9 +542,14 @@ Memhscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
Memhscx_fill_fifo(bcs); Memhscx_fill_fifo(bcs);
return; return;
} else { } else {
if (bcs->st->lli.l1writewakeup && if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
(PACKET_NOACK != bcs->tx_skb->pkt_type)) (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count); 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); dev_kfree_skb_irq(bcs->tx_skb);
bcs->hw.hscx.count = 0; bcs->hw.hscx.count = 0;
bcs->tx_skb = NULL; bcs->tx_skb = NULL;
......
/* $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 * stuff for the serial modem on ELSA cards
* *
...@@ -283,10 +283,14 @@ modem_fill(struct BCState *bcs) { ...@@ -283,10 +283,14 @@ modem_fill(struct BCState *bcs) {
write_modem(bcs); write_modem(bcs);
return; return;
} else { } else {
if (bcs->st->lli.l1writewakeup && if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
(PACKET_NOACK != bcs->tx_skb->pkt_type)) (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
bcs->st->lli.l1writewakeup(bcs->st, u_long flags;
bcs->hw.hscx.count); 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); dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL; bcs->tx_skb = NULL;
} }
......
/* $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 * specific routines for CCD's HFC 2BDS0
* *
...@@ -314,9 +314,14 @@ hfc_fill_fifo(struct BCState *bcs) ...@@ -314,9 +314,14 @@ hfc_fill_fifo(struct BCState *bcs)
printk(KERN_WARNING "HFC S FIFO channel %d BUSY Error\n", bcs->channel); printk(KERN_WARNING "HFC S FIFO channel %d BUSY Error\n", bcs->channel);
} else { } else {
bcs->tx_cnt -= bcs->tx_skb->len; bcs->tx_cnt -= bcs->tx_skb->len;
if (bcs->st->lli.l1writewakeup && if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
(PACKET_NOACK != bcs->tx_skb->pkt_type)) (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); 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); dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL; bcs->tx_skb = NULL;
} }
......
/* $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 * specific routines for CCD's HFC 2BS0
* *
...@@ -308,8 +308,14 @@ hfc_fill_fifo(struct BCState *bcs) ...@@ -308,8 +308,14 @@ hfc_fill_fifo(struct BCState *bcs)
WaitNoBusy(cs); WaitNoBusy(cs);
cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F1_INC | HFC_SEND | HFC_CHANNEL(bcs->channel)); 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)) if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
bcs->st->lli.l1writewakeup(bcs->st, count); (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); test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
} }
return; return;
......
/* $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 CCDs hfc-pci based cards * low level driver for CCDs hfc-pci based cards
* *
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
extern const char *CardType[]; 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 */ /* table entry in the PCI devices list */
typedef struct { typedef struct {
...@@ -649,9 +649,14 @@ hfcpci_fill_fifo(struct BCState *bcs) ...@@ -649,9 +649,14 @@ hfcpci_fill_fifo(struct BCState *bcs)
debugl1(cs, "hfcpci_fill_fifo_trans %d frame length %d discarded", debugl1(cs, "hfcpci_fill_fifo_trans %d frame length %d discarded",
bcs->channel, bcs->tx_skb->len); bcs->channel, bcs->tx_skb->len);
if (bcs->st->lli.l1writewakeup && if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
(PACKET_NOACK != bcs->tx_skb->pkt_type)) (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); 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); dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = skb_dequeue(&bcs->squeue); /* fetch next data */ bcs->tx_skb = skb_dequeue(&bcs->squeue); /* fetch next data */
...@@ -707,9 +712,14 @@ hfcpci_fill_fifo(struct BCState *bcs) ...@@ -707,9 +712,14 @@ hfcpci_fill_fifo(struct BCState *bcs)
memcpy(dst, src, count); memcpy(dst, src, count);
} }
bcs->tx_cnt -= bcs->tx_skb->len; bcs->tx_cnt -= bcs->tx_skb->len;
if (bcs->st->lli.l1writewakeup && if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
(PACKET_NOACK != bcs->tx_skb->pkt_type)) (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); 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->za[new_f1].z1 = new_z1; /* for next buffer */
bz->f1 = new_f1; /* next frame */ bz->f1 = new_f1; /* next frame */
...@@ -1689,11 +1699,11 @@ setup_hfcpci(struct IsdnCard *card) ...@@ -1689,11 +1699,11 @@ setup_hfcpci(struct IsdnCard *card)
/* Allocate memory for FIFOS */ /* Allocate memory for FIFOS */
/* Because the HFC-PCI needs a 32K physical alignment, we */ /* Because the HFC-PCI needs a 32K physical alignment, we */
/* need to allocate the double mem and align the address */ /* need to allocate the double mem and align the address */
if (!((void *) cs->hw.hfcpci.share_start = kmalloc(65536, GFP_KERNEL))) { if (!(cs->hw.hfcpci.share_start = kmalloc(65536, GFP_KERNEL))) {
printk(KERN_WARNING "HFC-PCI: Error allocating memory for FIFO!\n"); printk(KERN_WARNING "HFC-PCI: Error allocating memory for FIFO!\n");
return 0; return 0;
} }
(ulong) cs->hw.hfcpci.fifos = cs->hw.hfcpci.fifos = (void *)
(((ulong) cs->hw.hfcpci.share_start) & ~0x7FFF) + 0x8000; (((ulong) cs->hw.hfcpci.share_start) & ~0x7FFF) + 0x8000;
pci_write_config_dword(cs->hw.hfcpci.dev, 0x80, (u_int) virt_to_bus(cs->hw.hfcpci.fifos)); pci_write_config_dword(cs->hw.hfcpci.dev, 0x80, (u_int) virt_to_bus(cs->hw.hfcpci.fifos));
cs->hw.hfcpci.pci_io = ioremap((ulong) cs->hw.hfcpci.pci_io, 256); cs->hw.hfcpci.pci_io = ioremap((ulong) cs->hw.hfcpci.pci_io, 256);
......
/* $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 * level driver for Cologne Chip Designs hfc-s+/sp based cards
* *
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
extern const char *CardType[]; 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 */ /* IRQ-table for CCDs demo board */
...@@ -540,9 +540,14 @@ hfcsx_fill_fifo(struct BCState *bcs) ...@@ -540,9 +540,14 @@ hfcsx_fill_fifo(struct BCState *bcs)
HFCSX_BTRANS_THRESHOLD : 0)) { HFCSX_BTRANS_THRESHOLD : 0)) {
bcs->tx_cnt -= bcs->tx_skb->len; bcs->tx_cnt -= bcs->tx_skb->len;
if (bcs->st->lli.l1writewakeup && if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
(PACKET_NOACK != bcs->tx_skb->pkt_type)) (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); 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); dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL; bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
......
/* $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 * Basic declarations, defines and prototypes
* *
...@@ -280,10 +280,11 @@ struct LLInterface { ...@@ -280,10 +280,11 @@ struct LLInterface {
void (*l4l3) (struct PStack *, int, void *); void (*l4l3) (struct PStack *, int, void *);
int (*l4l3_proto) (struct PStack *, isdn_ctrl *); int (*l4l3_proto) (struct PStack *, isdn_ctrl *);
void *userdata; void *userdata;
void (*l1writewakeup) (struct PStack *, int); u_long flag;
void (*l2writewakeup) (struct PStack *, int);
}; };
#define FLG_LLI_L1WAKEUP 1
#define FLG_LLI_L2WAKEUP 2
struct Management { struct Management {
int ri; int ri;
...@@ -494,6 +495,8 @@ struct BCState { ...@@ -494,6 +495,8 @@ struct BCState {
struct sk_buff *tx_skb; /* B-Channel transmit Buffer */ struct sk_buff *tx_skb; /* B-Channel transmit Buffer */
struct sk_buff_head rqueue; /* B-Channel receive Queue */ struct sk_buff_head rqueue; /* B-Channel receive Queue */
struct sk_buff_head squeue; /* B-Channel send Queue */ struct sk_buff_head squeue; /* B-Channel send Queue */
int ackcnt;
spinlock_t aclock;
struct PStack *st; struct PStack *st;
u_char *blog; u_char *blog;
u_char *conmsg; u_char *conmsg;
...@@ -1281,6 +1284,7 @@ void setstack_isdnl2(struct PStack *st, char *debug_id); ...@@ -1281,6 +1284,7 @@ void setstack_isdnl2(struct PStack *st, char *debug_id);
void releasestack_isdnl2(struct PStack *st); void releasestack_isdnl2(struct PStack *st);
void setstack_transl2(struct PStack *st); void setstack_transl2(struct PStack *st);
void releasestack_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_l3dc(struct PStack *st, struct Channel *chanp);
void setstack_l3bc(struct PStack *st, struct Channel *chanp); void setstack_l3bc(struct PStack *st, struct Channel *chanp);
......
/* $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 * low level b-channel stuff for Siemens HSCX
* *
...@@ -197,9 +197,14 @@ hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx) ...@@ -197,9 +197,14 @@ hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
hscx_fill_fifo(bcs); hscx_fill_fifo(bcs);
return; return;
} else { } else {
if (bcs->st->lli.l1writewakeup && if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
(PACKET_NOACK != bcs->tx_skb->pkt_type)) (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count); 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); dev_kfree_skb_irq(bcs->tx_skb);
bcs->hw.hscx.count = 0; bcs->hw.hscx.count = 0;
bcs->tx_skb = NULL; bcs->tx_skb = NULL;
......
...@@ -733,35 +733,38 @@ bch_int(struct IsdnCardState *cs, u_char hscx) ...@@ -733,35 +733,38 @@ bch_int(struct IsdnCardState *cs, u_char hscx)
if (istab &0x20) { // RFO if (istab &0x20) { // RFO
if (cs->debug &L1_DEB_WARN) if (cs->debug &L1_DEB_WARN)
debugl1(cs, "bch_int() B-%d: RFO error", hscx); debugl1(cs, "bch_int() B-%d: RFO error", hscx);
cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x40); // RRES cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x40); // RRES
} }
if (istab &0x10) { // XPR if (istab &0x10) { // XPR
if (bcs->tx_skb) { if (bcs->tx_skb) {
if (bcs->tx_skb->len) { if (bcs->tx_skb->len) {
bch_fill_fifo(bcs); bch_fill_fifo(bcs);
goto afterXPR; goto afterXPR;
} } else {
else { if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
if (bcs->st->lli.l1writewakeup && (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
(PACKET_NOACK != bcs->tx_skb->pkt_type)) { u_long flags;
bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count); spin_lock_irqsave(&bcs->aclock, flags);
} bcs->ackcnt += bcs->hw.hscx.count;
dev_kfree_skb_irq(bcs->tx_skb); spin_unlock_irqrestore(&bcs->aclock, flags);
bcs->hw.hscx.count = 0; schedule_event(bcs, B_ACKPENDING);
bcs->tx_skb = NULL; }
} }
} dev_kfree_skb_irq(bcs->tx_skb);
if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { bcs->hw.hscx.count = 0;
bcs->hw.hscx.count = 0; bcs->tx_skb = NULL;
set_bit(BC_FLG_BUSY, &bcs->Flag); }
bch_fill_fifo(bcs); if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
} else { bcs->hw.hscx.count = 0;
clear_bit(BC_FLG_BUSY, &bcs->Flag); set_bit(BC_FLG_BUSY, &bcs->Flag);
schedule_event(bcs, B_XMTBUFREADY); bch_fill_fifo(bcs);
} } else {
} clear_bit(BC_FLG_BUSY, &bcs->Flag);
schedule_event(bcs, B_XMTBUFREADY);
}
}
afterXPR: afterXPR:
if (istab &0x04) { // XDU if (istab &0x04) { // XDU
......
/* $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 * isar.c ISAR (Siemens PSB 7110) specific routines
* *
...@@ -759,9 +759,14 @@ send_frames(struct BCState *bcs) ...@@ -759,9 +759,14 @@ send_frames(struct BCState *bcs)
isar_fill_fifo(bcs); isar_fill_fifo(bcs);
return; return;
} else { } else {
if (bcs->st->lli.l1writewakeup && if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
(PACKET_NOACK != bcs->tx_skb->pkt_type)) (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.isar.txcnt); 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->mode == L1_MODE_FAX) {
if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) { if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) {
if (test_bit(BC_FLG_LASTDATA, &bcs->Flag)) { if (test_bit(BC_FLG_LASTDATA, &bcs->Flag)) {
......
/* $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 * common low level stuff for Siemens Chipsetbased isdn cards
* *
...@@ -18,7 +18,7 @@ ...@@ -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 <linux/init.h>
#include "hisax.h" #include "hisax.h"
...@@ -299,6 +299,20 @@ BChannel_proc_rcv(struct BCState *bcs) ...@@ -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 void
BChannel_bh(struct BCState *bcs) BChannel_bh(struct BCState *bcs)
{ {
...@@ -308,6 +322,8 @@ BChannel_bh(struct BCState *bcs) ...@@ -308,6 +322,8 @@ BChannel_bh(struct BCState *bcs)
BChannel_proc_rcv(bcs); BChannel_proc_rcv(bcs);
if (test_and_clear_bit(B_XMTBUFREADY, &bcs->event)) if (test_and_clear_bit(B_XMTBUFREADY, &bcs->event))
BChannel_proc_xmt(bcs); BChannel_proc_xmt(bcs);
if (test_and_clear_bit(B_ACKPENDING, &bcs->event))
BChannel_proc_ack(bcs);
} }
void void
...@@ -346,6 +362,7 @@ init_bcstate(struct IsdnCardState *cs, int bc) ...@@ -346,6 +362,7 @@ init_bcstate(struct IsdnCardState *cs, int bc)
bcs->cs = cs; bcs->cs = cs;
bcs->channel = bc; bcs->channel = bc;
INIT_WORK(&bcs->tqueue, (void *)(void *) BChannel_bh, bcs); INIT_WORK(&bcs->tqueue, (void *)(void *) BChannel_bh, bcs);
spin_lock_init(&bcs->aclock);
bcs->BC_SetStack = NULL; bcs->BC_SetStack = NULL;
bcs->BC_Close = NULL; bcs->BC_Close = NULL;
bcs->Flag = 0; bcs->Flag = 0;
......
/* $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 * Layer 1 defines
* *
...@@ -17,8 +17,9 @@ ...@@ -17,8 +17,9 @@
#define D_TX_MON1 7 #define D_TX_MON1 7
#define E_RCVBUFREADY 8 #define E_RCVBUFREADY 8
#define B_RCVBUFREADY 0 #define B_RCVBUFREADY 0
#define B_XMTBUFREADY 1 #define B_XMTBUFREADY 1
#define B_ACKPENDING 2
extern void debugl1(struct IsdnCardState *cs, char *fmt, ...); extern void debugl1(struct IsdnCardState *cs, char *fmt, ...);
extern void DChannel_proc_xmt(struct IsdnCardState *cs); extern void DChannel_proc_xmt(struct IsdnCardState *cs);
......
/* $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 * Author Karsten Keil
* based on the teles driver from Jan den Ouden * based on the teles driver from Jan den Ouden
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
#include "hisax.h" #include "hisax.h"
#include "isdnl2.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, ...); static void l2m_debug(struct FsmInst *fi, char *fmt, ...);
...@@ -420,8 +420,8 @@ setva(struct PStack *st, unsigned int nr) ...@@ -420,8 +420,8 @@ setva(struct PStack *st, unsigned int nr)
l2->windowar[l2->sow] = NULL; l2->windowar[l2->sow] = NULL;
l2->sow = (l2->sow + 1) % l2->window; l2->sow = (l2->sow + 1) % l2->window;
spin_unlock_irqrestore(&l2->lock, flags); spin_unlock_irqrestore(&l2->lock, flags);
if (st->lli.l2writewakeup && (len >=0)) if (test_bit(FLG_LLI_L2WAKEUP, &st->lli.flag) && (len >=0))
st->lli.l2writewakeup(st, len); lli_writewakeup(st, len);
spin_lock_irqsave(&l2->lock, flags); spin_lock_irqsave(&l2->lock, flags);
} }
spin_unlock_irqrestore(&l2->lock, flags); spin_unlock_irqrestore(&l2->lock, flags);
......
/* $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) * Low level JADE IRQ stuff (derived from original hscx_irq.c)
* *
...@@ -175,9 +175,14 @@ jade_interrupt(struct IsdnCardState *cs, u_char val, u_char jade) ...@@ -175,9 +175,14 @@ jade_interrupt(struct IsdnCardState *cs, u_char val, u_char jade)
jade_fill_fifo(bcs); jade_fill_fifo(bcs);
return; return;
} else { } else {
if (bcs->st->lli.l1writewakeup && if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
(PACKET_NOACK != bcs->tx_skb->pkt_type)) (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count); 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); dev_kfree_skb_irq(bcs->tx_skb);
bcs->hw.hscx.count = 0; bcs->hw.hscx.count = 0;
bcs->tx_skb = NULL; bcs->tx_skb = NULL;
......
/* $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 * low level stuff for Traverse Technologie NETJet ISDN cards
* *
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#include <asm/io.h> #include <asm/io.h>
#include "netjet.h" #include "netjet.h"
const char *NETjet_revision = "$Revision: 1.29.2.3 $"; const char *NETjet_revision = "$Revision: 1.29.2.4 $";
/* Interface functions */ /* Interface functions */
...@@ -748,9 +748,14 @@ static void write_raw(struct BCState *bcs, u_int *buf, int cnt) { ...@@ -748,9 +748,14 @@ static void write_raw(struct BCState *bcs, u_int *buf, int cnt) {
if (!bcs->tx_skb) { if (!bcs->tx_skb) {
debugl1(bcs->cs,"tiger write_raw: NULL skb s_cnt %d", s_cnt); debugl1(bcs->cs,"tiger write_raw: NULL skb s_cnt %d", s_cnt);
} else { } else {
if (bcs->st->lli.l1writewakeup && if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
(PACKET_NOACK != bcs->tx_skb->pkt_type)) (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); 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); dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL; bcs->tx_skb = NULL;
} }
......
/* $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 * Winbond W6692 specific routines
* *
...@@ -41,7 +41,7 @@ static const PCI_ENTRY id_list[] = ...@@ -41,7 +41,7 @@ static const PCI_ENTRY id_list[] =
extern const char *CardType[]; 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 #define DBUSY_TIMER_VALUE 80
...@@ -376,9 +376,14 @@ W6692B_interrupt(struct IsdnCardState *cs, u_char bchan) ...@@ -376,9 +376,14 @@ W6692B_interrupt(struct IsdnCardState *cs, u_char bchan)
W6692B_fill_fifo(bcs); W6692B_fill_fifo(bcs);
return; return;
} else { } else {
if (bcs->st->lli.l1writewakeup && if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) &&
(PACKET_NOACK != bcs->tx_skb->pkt_type)) (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.w6692.count); 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); dev_kfree_skb_irq(bcs->tx_skb);
bcs->hw.w6692.count = 0; bcs->hw.w6692.count = 0;
bcs->tx_skb = NULL; bcs->tx_skb = NULL;
......
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