Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Sebastian Andrzej Siewior and committed by
Jakub Kicinski
f2bcc2fa 030946fd

+29 -8
+18 -6
drivers/atm/nicstar.c
··· 130 130 static void ns_close(struct atm_vcc *vcc); 131 131 static void fill_tst(ns_dev * card, int n, vc_map * vc); 132 132 static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb); 133 + static int ns_send_bh(struct atm_vcc *vcc, struct sk_buff *skb); 133 134 static int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd, 134 - struct sk_buff *skb); 135 + struct sk_buff *skb, bool may_sleep); 135 136 static void process_tsq(ns_dev * card); 136 137 static void drain_scq(ns_dev * card, scq_info * scq, int pos); 137 138 static void process_rsq(ns_dev * card); ··· 161 160 .close = ns_close, 162 161 .ioctl = ns_ioctl, 163 162 .send = ns_send, 163 + .send_bh = ns_send_bh, 164 164 .phy_put = ns_phy_put, 165 165 .phy_get = ns_phy_get, 166 166 .proc_read = ns_proc_read, ··· 1622 1620 card->tst_addr = new_tst; 1623 1621 } 1624 1622 1625 - static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb) 1623 + static int _ns_send(struct atm_vcc *vcc, struct sk_buff *skb, bool may_sleep) 1626 1624 { 1627 1625 ns_dev *card; 1628 1626 vc_map *vc; ··· 1706 1704 scq = card->scq0; 1707 1705 } 1708 1706 1709 - if (push_scqe(card, vc, scq, &scqe, skb) != 0) { 1707 + if (push_scqe(card, vc, scq, &scqe, skb, may_sleep) != 0) { 1710 1708 atomic_inc(&vcc->stats->tx_err); 1711 1709 dev_kfree_skb_any(skb); 1712 1710 return -EIO; ··· 1716 1714 return 0; 1717 1715 } 1718 1716 1717 + static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb) 1718 + { 1719 + return _ns_send(vcc, skb, true); 1720 + } 1721 + 1722 + static int ns_send_bh(struct atm_vcc *vcc, struct sk_buff *skb) 1723 + { 1724 + return _ns_send(vcc, skb, false); 1725 + } 1726 + 1719 1727 static int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd, 1720 - struct sk_buff *skb) 1728 + struct sk_buff *skb, bool may_sleep) 1721 1729 { 1722 1730 unsigned long flags; 1723 1731 ns_scqe tsr; ··· 1738 1726 1739 1727 spin_lock_irqsave(&scq->lock, flags); 1740 1728 while (scq->tail == scq->next) { 1741 - if (in_interrupt()) { 1729 + if (!may_sleep) { 1742 1730 spin_unlock_irqrestore(&scq->lock, flags); 1743 1731 printk("nicstar%d: Error pushing TBD.\n", card->index); 1744 1732 return 1; ··· 1783 1771 int has_run = 0; 1784 1772 1785 1773 while (scq->tail == scq->next) { 1786 - if (in_interrupt()) { 1774 + if (!may_sleep) { 1787 1775 data = scq_virt_to_bus(scq, scq->next); 1788 1776 ns_write_sram(card, scq->scd, &data, 1); 1789 1777 spin_unlock_irqrestore(&scq->lock, flags);
+1
include/linux/atmdev.h
··· 186 186 void __user *arg); 187 187 #endif 188 188 int (*send)(struct atm_vcc *vcc,struct sk_buff *skb); 189 + int (*send_bh)(struct atm_vcc *vcc, struct sk_buff *skb); 189 190 int (*send_oam)(struct atm_vcc *vcc,void *cell,int flags); 190 191 void (*phy_put)(struct atm_dev *dev,unsigned char value, 191 192 unsigned long addr);
+10 -2
net/atm/raw.c
··· 54 54 kfree_skb(skb); 55 55 return -EADDRNOTAVAIL; 56 56 } 57 + if (vcc->dev->ops->send_bh) 58 + return vcc->dev->ops->send_bh(vcc, skb); 57 59 return vcc->dev->ops->send(vcc, skb); 58 60 } 59 61 ··· 73 71 vcc->push = atm_push_raw; 74 72 vcc->pop = atm_pop_raw; 75 73 vcc->push_oam = NULL; 76 - vcc->send = vcc->dev->ops->send; 74 + if (vcc->dev->ops->send_bh) 75 + vcc->send = vcc->dev->ops->send_bh; 76 + else 77 + vcc->send = vcc->dev->ops->send; 77 78 return 0; 78 79 } 79 80 ··· 85 80 vcc->push = atm_push_raw; 86 81 vcc->pop = atm_pop_raw; 87 82 vcc->push_oam = NULL; 88 - vcc->send = vcc->dev->ops->send; 83 + if (vcc->dev->ops->send_bh) 84 + vcc->send = vcc->dev->ops->send_bh; 85 + else 86 + vcc->send = vcc->dev->ops->send; 89 87 return 0; 90 88 } 91 89 EXPORT_SYMBOL(atm_init_aal5);