Commit f2bcc2fa authored by Sebastian Andrzej Siewior's avatar Sebastian Andrzej Siewior Committed by Jakub Kicinski

atm: nicstar: Replace in_interrupt() usage

push_scqe() uses in_interrupt() to figure out if it is allowed to sleep.

The usage of in_interrupt() in drivers is phased out and Linus clearly
requested that code which changes behaviour depending on context should
either be separated or the context be conveyed in an argument passed by the
caller, which usually knows the context.

Aside of that in_interrupt() is not correct as it does not catch preempt
disabled regions which neither can sleep.

ns_send() (the only caller of push_scqe()) has the following callers:

- vcc_sendmsg() used as proto_ops::sendmsg is expected to be invoked in
  preemtible context.
  -> vcc->dev->ops->send() (ns_send())

- atm_vcc::send via atmdev_ops::send either directly (pointer copied by
  atm_init_aal34() or atm_init_aal5()) or via atm_send_aal0().
  This is invoked by drivers (like br2684, clip, pppoatm, ...) which are
  called from net_device_ops::ndo_start_xmit with BH disabled.

Add atmdev_ops::send_bh which is used by callers from BH context
(atm_send_aal*()) and if this callback missing then ::send is used
instead.
Implement this callback in nicstar and use it to replace in_interrupt().

Cc: Chas Williams <3chas3@gmail.com>
Signed-off-by: default avatarSebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 030946fd
...@@ -130,8 +130,9 @@ static int ns_open(struct atm_vcc *vcc); ...@@ -130,8 +130,9 @@ static int ns_open(struct atm_vcc *vcc);
static void ns_close(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 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(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, 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 process_tsq(ns_dev * card);
static void drain_scq(ns_dev * card, scq_info * scq, int pos); static void drain_scq(ns_dev * card, scq_info * scq, int pos);
static void process_rsq(ns_dev * card); static void process_rsq(ns_dev * card);
...@@ -160,6 +161,7 @@ static const struct atmdev_ops atm_ops = { ...@@ -160,6 +161,7 @@ static const struct atmdev_ops atm_ops = {
.close = ns_close, .close = ns_close,
.ioctl = ns_ioctl, .ioctl = ns_ioctl,
.send = ns_send, .send = ns_send,
.send_bh = ns_send_bh,
.phy_put = ns_phy_put, .phy_put = ns_phy_put,
.phy_get = ns_phy_get, .phy_get = ns_phy_get,
.proc_read = ns_proc_read, .proc_read = ns_proc_read,
...@@ -1620,7 +1622,7 @@ static void fill_tst(ns_dev * card, int n, vc_map * vc) ...@@ -1620,7 +1622,7 @@ static void fill_tst(ns_dev * card, int n, vc_map * vc)
card->tst_addr = new_tst; 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; ns_dev *card;
vc_map *vc; vc_map *vc;
...@@ -1704,7 +1706,7 @@ static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb) ...@@ -1704,7 +1706,7 @@ static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb)
scq = card->scq0; 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); atomic_inc(&vcc->stats->tx_err);
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
return -EIO; return -EIO;
...@@ -1714,8 +1716,18 @@ static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb) ...@@ -1714,8 +1716,18 @@ static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb)
return 0; 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, 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; unsigned long flags;
ns_scqe tsr; ns_scqe tsr;
...@@ -1726,7 +1738,7 @@ static int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd, ...@@ -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); spin_lock_irqsave(&scq->lock, flags);
while (scq->tail == scq->next) { while (scq->tail == scq->next) {
if (in_interrupt()) { if (!may_sleep) {
spin_unlock_irqrestore(&scq->lock, flags); spin_unlock_irqrestore(&scq->lock, flags);
printk("nicstar%d: Error pushing TBD.\n", card->index); printk("nicstar%d: Error pushing TBD.\n", card->index);
return 1; return 1;
...@@ -1771,7 +1783,7 @@ static int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd, ...@@ -1771,7 +1783,7 @@ static int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd,
int has_run = 0; int has_run = 0;
while (scq->tail == scq->next) { while (scq->tail == scq->next) {
if (in_interrupt()) { if (!may_sleep) {
data = scq_virt_to_bus(scq, scq->next); data = scq_virt_to_bus(scq, scq->next);
ns_write_sram(card, scq->scd, &data, 1); ns_write_sram(card, scq->scd, &data, 1);
spin_unlock_irqrestore(&scq->lock, flags); spin_unlock_irqrestore(&scq->lock, flags);
......
...@@ -186,6 +186,7 @@ struct atmdev_ops { /* only send is required */ ...@@ -186,6 +186,7 @@ struct atmdev_ops { /* only send is required */
void __user *arg); void __user *arg);
#endif #endif
int (*send)(struct atm_vcc *vcc,struct sk_buff *skb); 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); int (*send_oam)(struct atm_vcc *vcc,void *cell,int flags);
void (*phy_put)(struct atm_dev *dev,unsigned char value, void (*phy_put)(struct atm_dev *dev,unsigned char value,
unsigned long addr); unsigned long addr);
......
...@@ -54,6 +54,8 @@ static int atm_send_aal0(struct atm_vcc *vcc, struct sk_buff *skb) ...@@ -54,6 +54,8 @@ static int atm_send_aal0(struct atm_vcc *vcc, struct sk_buff *skb)
kfree_skb(skb); kfree_skb(skb);
return -EADDRNOTAVAIL; return -EADDRNOTAVAIL;
} }
if (vcc->dev->ops->send_bh)
return vcc->dev->ops->send_bh(vcc, skb);
return vcc->dev->ops->send(vcc, skb); return vcc->dev->ops->send(vcc, skb);
} }
...@@ -71,7 +73,10 @@ int atm_init_aal34(struct atm_vcc *vcc) ...@@ -71,7 +73,10 @@ int atm_init_aal34(struct atm_vcc *vcc)
vcc->push = atm_push_raw; vcc->push = atm_push_raw;
vcc->pop = atm_pop_raw; vcc->pop = atm_pop_raw;
vcc->push_oam = NULL; 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; return 0;
} }
...@@ -80,7 +85,10 @@ int atm_init_aal5(struct atm_vcc *vcc) ...@@ -80,7 +85,10 @@ int atm_init_aal5(struct atm_vcc *vcc)
vcc->push = atm_push_raw; vcc->push = atm_push_raw;
vcc->pop = atm_pop_raw; vcc->pop = atm_pop_raw;
vcc->push_oam = NULL; 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; return 0;
} }
EXPORT_SYMBOL(atm_init_aal5); EXPORT_SYMBOL(atm_init_aal5);
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