Commit 4271eabb authored by Andrey Shvetsov's avatar Andrey Shvetsov Committed by Greg Kroah-Hartman

staging: most: net: hold used net device

This adds the dev_hold and dev_put calls to the functions
aim_resume_tx_channel, aim_rx_data and on_netinfo to postpone the
unregistration of the used net device.
Signed-off-by: default avatarAndrey Shvetsov <andrey.shvetsov@k2l.de>
Signed-off-by: default avatarChristian Gromm <christian.gromm@microchip.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 2338652c
...@@ -73,7 +73,7 @@ struct net_dev_context { ...@@ -73,7 +73,7 @@ struct net_dev_context {
static struct list_head net_devices = LIST_HEAD_INIT(net_devices); static struct list_head net_devices = LIST_HEAD_INIT(net_devices);
static struct mutex probe_disc_mt; /* ch->linked = true, most_nd_open */ static struct mutex probe_disc_mt; /* ch->linked = true, most_nd_open */
static struct spinlock list_lock; static struct spinlock list_lock; /* list_head, ch->linked = false, dev_hold */
static struct most_aim aim; static struct most_aim aim;
static int skb_to_mamac(const struct sk_buff *skb, struct mbo *mbo) static int skb_to_mamac(const struct sk_buff *skb, struct mbo *mbo)
...@@ -271,21 +271,29 @@ static void most_nd_setup(struct net_device *dev) ...@@ -271,21 +271,29 @@ static void most_nd_setup(struct net_device *dev)
dev->netdev_ops = &most_nd_ops; dev->netdev_ops = &most_nd_ops;
} }
static struct net_dev_context *get_net_dev_context( static struct net_dev_context *get_net_dev(struct most_interface *iface)
struct most_interface *iface) {
struct net_dev_context *nd;
list_for_each_entry(nd, &net_devices, list)
if (nd->iface == iface)
return nd;
return NULL;
}
static struct net_dev_context *get_net_dev_hold(struct most_interface *iface)
{ {
struct net_dev_context *nd; struct net_dev_context *nd;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&list_lock, flags); spin_lock_irqsave(&list_lock, flags);
list_for_each_entry(nd, &net_devices, list) { nd = get_net_dev(iface);
if (nd->iface == iface) { if (nd && nd->rx.linked && nd->tx.linked)
dev_hold(nd->dev);
else
nd = NULL;
spin_unlock_irqrestore(&list_lock, flags); spin_unlock_irqrestore(&list_lock, flags);
return nd; return nd;
}
}
spin_unlock_irqrestore(&list_lock, flags);
return NULL;
} }
static int aim_probe_channel(struct most_interface *iface, int channel_idx, static int aim_probe_channel(struct most_interface *iface, int channel_idx,
...@@ -305,7 +313,7 @@ static int aim_probe_channel(struct most_interface *iface, int channel_idx, ...@@ -305,7 +313,7 @@ static int aim_probe_channel(struct most_interface *iface, int channel_idx,
return -EINVAL; return -EINVAL;
mutex_lock(&probe_disc_mt); mutex_lock(&probe_disc_mt);
nd = get_net_dev_context(iface); nd = get_net_dev(iface);
if (!nd) { if (!nd) {
dev = alloc_netdev(sizeof(struct net_dev_context), "meth%d", dev = alloc_netdev(sizeof(struct net_dev_context), "meth%d",
NET_NAME_UNKNOWN, most_nd_setup); NET_NAME_UNKNOWN, most_nd_setup);
...@@ -354,7 +362,7 @@ static int aim_disconnect_channel(struct most_interface *iface, ...@@ -354,7 +362,7 @@ static int aim_disconnect_channel(struct most_interface *iface,
int ret = 0; int ret = 0;
mutex_lock(&probe_disc_mt); mutex_lock(&probe_disc_mt);
nd = get_net_dev_context(iface); nd = get_net_dev(iface);
if (!nd) { if (!nd) {
ret = -EINVAL; ret = -EINVAL;
goto unlock; goto unlock;
...@@ -370,12 +378,15 @@ static int aim_disconnect_channel(struct most_interface *iface, ...@@ -370,12 +378,15 @@ static int aim_disconnect_channel(struct most_interface *iface,
} }
if (nd->rx.linked && nd->tx.linked) { if (nd->rx.linked && nd->tx.linked) {
spin_lock_irqsave(&list_lock, flags);
ch->linked = false;
spin_unlock_irqrestore(&list_lock, flags);
/* /*
* do not call most_stop_channel() here, because channels are * do not call most_stop_channel() here, because channels are
* going to be closed in ndo_stop() after unregister_netdev() * going to be closed in ndo_stop() after unregister_netdev()
*/ */
unregister_netdev(nd->dev); unregister_netdev(nd->dev);
ch->linked = false;
} else { } else {
spin_lock_irqsave(&list_lock, flags); spin_lock_irqsave(&list_lock, flags);
list_del(&nd->list); list_del(&nd->list);
...@@ -394,11 +405,17 @@ static int aim_resume_tx_channel(struct most_interface *iface, ...@@ -394,11 +405,17 @@ static int aim_resume_tx_channel(struct most_interface *iface,
{ {
struct net_dev_context *nd; struct net_dev_context *nd;
nd = get_net_dev_context(iface); nd = get_net_dev_hold(iface);
if (!nd || nd->tx.ch_id != channel_idx) if (!nd)
return 0; return 0;
if (nd->tx.ch_id != channel_idx)
goto put_nd;
netif_wake_queue(nd->dev); netif_wake_queue(nd->dev);
put_nd:
dev_put(nd->dev);
return 0; return 0;
} }
...@@ -411,21 +428,31 @@ static int aim_rx_data(struct mbo *mbo) ...@@ -411,21 +428,31 @@ static int aim_rx_data(struct mbo *mbo)
struct sk_buff *skb; struct sk_buff *skb;
struct net_device *dev; struct net_device *dev;
unsigned int skb_len; unsigned int skb_len;
int ret = 0;
nd = get_net_dev_context(mbo->ifp); nd = get_net_dev_hold(mbo->ifp);
if (!nd || nd->rx.ch_id != mbo->hdm_channel_id) if (!nd)
return -EIO; return -EIO;
if (nd->rx.ch_id != mbo->hdm_channel_id) {
ret = -EIO;
goto put_nd;
}
dev = nd->dev; dev = nd->dev;
if (nd->is_mamac) { if (nd->is_mamac) {
if (!PMS_IS_MAMAC(buf, len)) if (!PMS_IS_MAMAC(buf, len)) {
return -EIO; ret = -EIO;
goto put_nd;
}
skb = dev_alloc_skb(len - MDP_HDR_LEN + 2 * ETH_ALEN + 2); skb = dev_alloc_skb(len - MDP_HDR_LEN + 2 * ETH_ALEN + 2);
} else { } else {
if (!PMS_IS_MEP(buf, len)) if (!PMS_IS_MEP(buf, len)) {
return -EIO; ret = -EIO;
goto put_nd;
}
skb = dev_alloc_skb(len - MEP_HDR_LEN); skb = dev_alloc_skb(len - MEP_HDR_LEN);
} }
...@@ -468,7 +495,10 @@ static int aim_rx_data(struct mbo *mbo) ...@@ -468,7 +495,10 @@ static int aim_rx_data(struct mbo *mbo)
out: out:
most_put_mbo(mbo); most_put_mbo(mbo);
return 0;
put_nd:
dev_put(nd->dev);
return ret;
} }
static struct most_aim aim = { static struct most_aim aim = {
...@@ -504,7 +534,7 @@ static void on_netinfo(struct most_interface *iface, ...@@ -504,7 +534,7 @@ static void on_netinfo(struct most_interface *iface,
struct net_device *dev; struct net_device *dev;
const u8 *m = mac_addr; const u8 *m = mac_addr;
nd = get_net_dev_context(iface); nd = get_net_dev_hold(iface);
if (!nd) if (!nd)
return; return;
...@@ -526,6 +556,8 @@ static void on_netinfo(struct most_interface *iface, ...@@ -526,6 +556,8 @@ static void on_netinfo(struct most_interface *iface,
m[0], m[1], m[2], m[3], m[4], m[5]); m[0], m[1], m[2], m[3], m[4], m[5]);
} }
} }
dev_put(nd->dev);
} }
module_init(most_net_init); module_init(most_net_init);
......
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