diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c index 7af74fb450a0..a602e6b96ff7 100644 --- a/drivers/atm/nicstar.c +++ b/drivers/atm/nicstar.c @@ -130,8 +130,9 @@ static int ns_open(struct atm_vcc *vcc); static void ns_close(struct atm_vcc *vcc); static void fill_tst(ns_dev * card, int n, vc_map * vc); static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb); +static int ns_send_bh(struct atm_vcc *vcc, struct sk_buff *skb); static int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd, - struct sk_buff *skb); + struct sk_buff *skb, bool may_sleep); static void process_tsq(ns_dev * card); static void drain_scq(ns_dev * card, scq_info * scq, int pos); static void process_rsq(ns_dev * card); @@ -160,6 +161,7 @@ static const struct atmdev_ops atm_ops = { .close = ns_close, .ioctl = ns_ioctl, .send = ns_send, + .send_bh = ns_send_bh, .phy_put = ns_phy_put, .phy_get = ns_phy_get, .proc_read = ns_proc_read, @@ -1620,7 +1622,7 @@ static void fill_tst(ns_dev * card, int n, vc_map * vc) card->tst_addr = new_tst; } -static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb) +static int _ns_send(struct atm_vcc *vcc, struct sk_buff *skb, bool may_sleep) { ns_dev *card; vc_map *vc; @@ -1704,7 +1706,7 @@ static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb) scq = card->scq0; } - if (push_scqe(card, vc, scq, &scqe, skb) != 0) { + if (push_scqe(card, vc, scq, &scqe, skb, may_sleep) != 0) { atomic_inc(&vcc->stats->tx_err); dev_kfree_skb_any(skb); return -EIO; @@ -1714,8 +1716,18 @@ static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb) return 0; } +static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb) +{ + return _ns_send(vcc, skb, true); +} + +static int ns_send_bh(struct atm_vcc *vcc, struct sk_buff *skb) +{ + return _ns_send(vcc, skb, false); +} + static int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd, - struct sk_buff *skb) + struct sk_buff *skb, bool may_sleep) { unsigned long flags; ns_scqe tsr; @@ -1726,7 +1738,7 @@ static int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd, spin_lock_irqsave(&scq->lock, flags); while (scq->tail == scq->next) { - if (in_interrupt()) { + if (!may_sleep) { spin_unlock_irqrestore(&scq->lock, flags); printk("nicstar%d: Error pushing TBD.\n", card->index); return 1; @@ -1771,7 +1783,7 @@ static int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd, int has_run = 0; while (scq->tail == scq->next) { - if (in_interrupt()) { + if (!may_sleep) { data = scq_virt_to_bus(scq, scq->next); ns_write_sram(card, scq->scd, &data, 1); spin_unlock_irqrestore(&scq->lock, flags); diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h index 5d5ff2203fa2..d7493016cd46 100644 --- a/include/linux/atmdev.h +++ b/include/linux/atmdev.h @@ -186,6 +186,7 @@ struct atmdev_ops { /* only send is required */ void __user *arg); #endif int (*send)(struct atm_vcc *vcc,struct sk_buff *skb); + int (*send_bh)(struct atm_vcc *vcc, struct sk_buff *skb); int (*send_oam)(struct atm_vcc *vcc,void *cell,int flags); void (*phy_put)(struct atm_dev *dev,unsigned char value, unsigned long addr); diff --git a/net/atm/raw.c b/net/atm/raw.c index b3ba44aab0ee..2b5f78a7ec3e 100644 --- a/net/atm/raw.c +++ b/net/atm/raw.c @@ -54,6 +54,8 @@ static int atm_send_aal0(struct atm_vcc *vcc, struct sk_buff *skb) kfree_skb(skb); return -EADDRNOTAVAIL; } + if (vcc->dev->ops->send_bh) + return vcc->dev->ops->send_bh(vcc, skb); return vcc->dev->ops->send(vcc, skb); } @@ -71,7 +73,10 @@ int atm_init_aal34(struct atm_vcc *vcc) vcc->push = atm_push_raw; vcc->pop = atm_pop_raw; vcc->push_oam = NULL; - vcc->send = vcc->dev->ops->send; + if (vcc->dev->ops->send_bh) + vcc->send = vcc->dev->ops->send_bh; + else + vcc->send = vcc->dev->ops->send; return 0; } @@ -80,7 +85,10 @@ int atm_init_aal5(struct atm_vcc *vcc) vcc->push = atm_push_raw; vcc->pop = atm_pop_raw; vcc->push_oam = NULL; - vcc->send = vcc->dev->ops->send; + if (vcc->dev->ops->send_bh) + vcc->send = vcc->dev->ops->send_bh; + else + vcc->send = vcc->dev->ops->send; return 0; } EXPORT_SYMBOL(atm_init_aal5);