diff options
Diffstat (limited to 'driver/aim-network')
-rw-r--r-- | driver/aim-network/Makefile | 18 | ||||
-rw-r--r-- | driver/aim-network/networking.c | 307 |
2 files changed, 140 insertions, 185 deletions
diff --git a/driver/aim-network/Makefile b/driver/aim-network/Makefile deleted file mode 100644 index 93d6570..0000000 --- a/driver/aim-network/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -# Makefile -# - -SRC := $(shell pwd) - -obj-m := aim_network.o -aim_network-y := networking.o -CFLAGS_networking.o := -I$(src)/../include/ - -all: - $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules - -modules_install: - $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install - -clean: - $(MAKE) -C $(KERNEL_SRC) M=$(SRC) clean - diff --git a/driver/aim-network/networking.c b/driver/aim-network/networking.c index ce1764c..936f013 100644 --- a/driver/aim-network/networking.c +++ b/driver/aim-network/networking.c @@ -22,7 +22,6 @@ #include <linux/wait.h> #include <linux/kobject.h> #include "mostcore.h" -#include "networking.h" #define MEP_HDR_LEN 8 #define MDP_HDR_LEN 16 @@ -65,17 +64,16 @@ struct net_dev_channel { struct net_dev_context { struct most_interface *iface; - bool channels_opened; bool is_mamac; struct net_device *dev; struct net_dev_channel rx; struct net_dev_channel tx; - struct completion mac_compl; struct list_head list; }; static struct list_head net_devices = LIST_HEAD_INIT(net_devices); -static struct spinlock list_lock; +static struct mutex probe_disc_mt; /* ch->linked = true, most_nd_open */ +static struct spinlock list_lock; /* list_head, ch->linked = false, dev_hold */ static struct most_aim aim; static int skb_to_mamac(const struct sk_buff *skb, struct mbo *mbo) @@ -157,14 +155,12 @@ static int skb_to_mep(const struct sk_buff *skb, struct mbo *mbo) static int most_nd_set_mac_address(struct net_device *dev, void *p) { - struct net_dev_context *nd = dev->ml_priv; + struct net_dev_context *nd = netdev_priv(dev); int err = eth_mac_addr(dev, p); if (err) return err; - BUG_ON(nd->dev != dev); - nd->is_mamac = (dev->dev_addr[0] == 0 && dev->dev_addr[1] == 0 && dev->dev_addr[2] == 0 && dev->dev_addr[3] == 0); @@ -178,71 +174,52 @@ static int most_nd_set_mac_address(struct net_device *dev, void *p) return 0; } +static void on_netinfo(struct most_interface *iface, + unsigned char link_stat, unsigned char *mac_addr); + static int most_nd_open(struct net_device *dev) { - struct net_dev_context *nd = dev->ml_priv; - long ret; - - netdev_info(dev, "open net device\n"); - - BUG_ON(nd->dev != dev); + struct net_dev_context *nd = netdev_priv(dev); + int ret = 0; - if (nd->channels_opened) - return -EFAULT; - - BUG_ON(!nd->tx.linked || !nd->rx.linked); + mutex_lock(&probe_disc_mt); if (most_start_channel(nd->iface, nd->rx.ch_id, &aim)) { netdev_err(dev, "most_start_channel() failed\n"); - return -EBUSY; + ret = -EBUSY; + goto unlock; } if (most_start_channel(nd->iface, nd->tx.ch_id, &aim)) { netdev_err(dev, "most_start_channel() failed\n"); most_stop_channel(nd->iface, nd->rx.ch_id, &aim); - return -EBUSY; + ret = -EBUSY; + goto unlock; } - if (!is_valid_ether_addr(dev->dev_addr)) { - nd->iface->request_netinfo(nd->iface, nd->tx.ch_id); - ret = wait_for_completion_interruptible_timeout( - &nd->mac_compl, msecs_to_jiffies(5000)); - if (!ret) { - netdev_err(dev, "mac timeout\n"); - ret = -EBUSY; - goto err; - } - - if (ret < 0) { - netdev_warn(dev, "mac waiting interrupted\n"); - goto err; - } - } - - nd->channels_opened = true; + netif_carrier_off(dev); + if (is_valid_ether_addr(dev->dev_addr)) + netif_dormant_off(dev); + else + netif_dormant_on(dev); netif_wake_queue(dev); - return 0; + if (nd->iface->request_netinfo) + nd->iface->request_netinfo(nd->iface, nd->tx.ch_id, on_netinfo); -err: - most_stop_channel(nd->iface, nd->tx.ch_id, &aim); - most_stop_channel(nd->iface, nd->rx.ch_id, &aim); +unlock: + mutex_unlock(&probe_disc_mt); return ret; } static int most_nd_stop(struct net_device *dev) { - struct net_dev_context *nd = dev->ml_priv; - - netdev_info(dev, "stop net device\n"); + struct net_dev_context *nd = netdev_priv(dev); - BUG_ON(nd->dev != dev); netif_stop_queue(dev); - - if (nd->channels_opened) { - most_stop_channel(nd->iface, nd->rx.ch_id, &aim); - most_stop_channel(nd->iface, nd->tx.ch_id, &aim); - nd->channels_opened = false; - } + if (nd->iface->request_netinfo) + nd->iface->request_netinfo(nd->iface, nd->tx.ch_id, NULL); + most_stop_channel(nd->iface, nd->rx.ch_id, &aim); + most_stop_channel(nd->iface, nd->tx.ch_id, &aim); return 0; } @@ -250,12 +227,10 @@ static int most_nd_stop(struct net_device *dev) static netdev_tx_t most_nd_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct net_dev_context *nd = dev->ml_priv; + struct net_dev_context *nd = netdev_priv(dev); struct mbo *mbo; int ret; - BUG_ON(nd->dev != dev); - mbo = most_get_mbo(nd->iface, nd->tx.ch_id, &aim); if (!mbo) { @@ -296,33 +271,29 @@ static void most_nd_setup(struct net_device *dev) dev->netdev_ops = &most_nd_ops; } -static void most_net_rm_netdev_safe(struct net_dev_context *nd) +static struct net_dev_context *get_net_dev(struct most_interface *iface) { - if (!nd->dev) - return; - - pr_info("remove net device %p\n", nd->dev); + struct net_dev_context *nd; - unregister_netdev(nd->dev); - free_netdev(nd->dev); - nd->dev = NULL; + list_for_each_entry(nd, &net_devices, list) + if (nd->iface == iface) + return nd; + return NULL; } -static struct net_dev_context *get_net_dev_context( - struct most_interface *iface) +static struct net_dev_context *get_net_dev_hold(struct most_interface *iface) { - struct net_dev_context *nd, *tmp; + struct net_dev_context *nd; unsigned long flags; spin_lock_irqsave(&list_lock, flags); - list_for_each_entry_safe(nd, tmp, &net_devices, list) { - if (nd->iface == iface) { - spin_unlock_irqrestore(&list_lock, flags); - return nd; - } - } + nd = get_net_dev(iface); + if (nd && nd->rx.linked && nd->tx.linked) + dev_hold(nd->dev); + else + nd = NULL; spin_unlock_irqrestore(&list_lock, flags); - return NULL; + return nd; } static int aim_probe_channel(struct most_interface *iface, int channel_idx, @@ -331,7 +302,9 @@ static int aim_probe_channel(struct most_interface *iface, int channel_idx, { struct net_dev_context *nd; struct net_dev_channel *ch; + struct net_device *dev; unsigned long flags; + int ret = 0; if (!iface) return -EINVAL; @@ -339,54 +312,45 @@ static int aim_probe_channel(struct most_interface *iface, int channel_idx, if (ccfg->data_type != MOST_CH_ASYNC) return -EINVAL; - nd = get_net_dev_context(iface); - + mutex_lock(&probe_disc_mt); + nd = get_net_dev(iface); if (!nd) { - nd = kzalloc(sizeof(*nd), GFP_KERNEL); - if (!nd) - return -ENOMEM; + dev = alloc_netdev(sizeof(struct net_dev_context), "meth%d", + NET_NAME_UNKNOWN, most_nd_setup); + if (!dev) { + ret = -ENOMEM; + goto unlock; + } - init_completion(&nd->mac_compl); + nd = netdev_priv(dev); nd->iface = iface; + nd->dev = dev; spin_lock_irqsave(&list_lock, flags); list_add(&nd->list, &net_devices); spin_unlock_irqrestore(&list_lock, flags); - } - ch = ccfg->direction == MOST_CH_TX ? &nd->tx : &nd->rx; - if (ch->linked) { - pr_err("only one channel per instance & direction allowed\n"); - return -EINVAL; - } - - if (nd->tx.linked || nd->rx.linked) { - struct net_device *dev = - alloc_netdev(0, "meth%d", NET_NAME_UNKNOWN, - most_nd_setup); - - if (!dev) { - pr_err("no memory for net_device\n"); - return -ENOMEM; + ch = ccfg->direction == MOST_CH_TX ? &nd->tx : &nd->rx; + } else { + ch = ccfg->direction == MOST_CH_TX ? &nd->tx : &nd->rx; + if (ch->linked) { + pr_err("direction is allocated\n"); + ret = -EINVAL; + goto unlock; } - nd->dev = dev; - ch->ch_id = channel_idx; - ch->linked = true; - - dev->ml_priv = nd; - if (register_netdev(dev)) { - pr_err("registering net device failed\n"); - ch->linked = false; - free_netdev(dev); - return -EINVAL; + if (register_netdev(nd->dev)) { + pr_err("register_netdev() failed\n"); + ret = -EINVAL; + goto unlock; } } - ch->ch_id = channel_idx; ch->linked = true; - return 0; +unlock: + mutex_unlock(&probe_disc_mt); + return ret; } static int aim_disconnect_channel(struct most_interface *iface, @@ -395,34 +359,45 @@ static int aim_disconnect_channel(struct most_interface *iface, struct net_dev_context *nd; struct net_dev_channel *ch; unsigned long flags; + int ret = 0; - nd = get_net_dev_context(iface); - if (!nd) - return -EINVAL; + mutex_lock(&probe_disc_mt); + nd = get_net_dev(iface); + if (!nd) { + ret = -EINVAL; + goto unlock; + } - if (nd->rx.linked && channel_idx == nd->rx.ch_id) + if (nd->rx.linked && channel_idx == nd->rx.ch_id) { ch = &nd->rx; - else if (nd->tx.linked && channel_idx == nd->tx.ch_id) + } else if (nd->tx.linked && channel_idx == nd->tx.ch_id) { ch = &nd->tx; - else - return -EINVAL; - - ch->linked = false; + } else { + ret = -EINVAL; + goto unlock; + } - /* - * do not call most_stop_channel() here, because channels are - * going to be closed in ndo_stop() after unregister_netdev() - */ - most_net_rm_netdev_safe(nd); + if (nd->rx.linked && nd->tx.linked) { + spin_lock_irqsave(&list_lock, flags); + ch->linked = false; + spin_unlock_irqrestore(&list_lock, flags); - if (!nd->rx.linked && !nd->tx.linked) { + /* + * do not call most_stop_channel() here, because channels are + * going to be closed in ndo_stop() after unregister_netdev() + */ + unregister_netdev(nd->dev); + } else { spin_lock_irqsave(&list_lock, flags); list_del(&nd->list); spin_unlock_irqrestore(&list_lock, flags); - kfree(nd); + + free_netdev(nd->dev); } - return 0; +unlock: + mutex_unlock(&probe_disc_mt); + return ret; } static int aim_resume_tx_channel(struct most_interface *iface, @@ -430,14 +405,17 @@ static int aim_resume_tx_channel(struct most_interface *iface, { struct net_dev_context *nd; - nd = get_net_dev_context(iface); - if (!nd || !nd->channels_opened || nd->tx.ch_id != channel_idx) + nd = get_net_dev_hold(iface); + if (!nd) return 0; - if (!nd->dev) - return 0; + if (nd->tx.ch_id != channel_idx) + goto put_nd; netif_wake_queue(nd->dev); + +put_nd: + dev_put(nd->dev); return 0; } @@ -450,25 +428,31 @@ static int aim_rx_data(struct mbo *mbo) struct sk_buff *skb; struct net_device *dev; unsigned int skb_len; + int ret = 0; - nd = get_net_dev_context(mbo->ifp); - if (!nd || !nd->channels_opened || nd->rx.ch_id != mbo->hdm_channel_id) + nd = get_net_dev_hold(mbo->ifp); + if (!nd) return -EIO; - dev = nd->dev; - if (!dev) { - pr_err_once("drop packet: missing net_device\n"); - return -EIO; + if (nd->rx.ch_id != mbo->hdm_channel_id) { + ret = -EIO; + goto put_nd; } + dev = nd->dev; + if (nd->is_mamac) { - if (!PMS_IS_MAMAC(buf, len)) - return -EIO; + if (!PMS_IS_MAMAC(buf, len)) { + ret = -EIO; + goto put_nd; + } skb = dev_alloc_skb(len - MDP_HDR_LEN + 2 * ETH_ALEN + 2); } else { - if (!PMS_IS_MEP(buf, len)) - return -EIO; + if (!PMS_IS_MEP(buf, len)) { + ret = -EIO; + goto put_nd; + } skb = dev_alloc_skb(len - MEP_HDR_LEN); } @@ -486,11 +470,11 @@ static int aim_rx_data(struct mbo *mbo) ether_addr_copy(skb_put(skb, ETH_ALEN), dev->dev_addr); /* src */ - memcpy(skb_put(skb, 4), &zero, 4); - memcpy(skb_put(skb, 2), buf + 5, 2); + skb_put_data(skb, &zero, 4); + skb_put_data(skb, buf + 5, 2); /* eth type */ - memcpy(skb_put(skb, 2), buf + 10, 2); + skb_put_data(skb, buf + 10, 2); buf += MDP_HDR_LEN; len -= MDP_HDR_LEN; @@ -499,7 +483,7 @@ static int aim_rx_data(struct mbo *mbo) len -= MEP_HDR_LEN; } - memcpy(skb_put(skb, len), buf, len); + skb_put_data(skb, buf, len); skb->protocol = eth_type_trans(skb, dev); skb_len = skb->len; if (netif_rx(skb) == NET_RX_SUCCESS) { @@ -511,7 +495,10 @@ static int aim_rx_data(struct mbo *mbo) out: most_put_mbo(mbo); - return 0; + +put_nd: + dev_put(nd->dev); + return ret; } static struct most_aim aim = { @@ -524,68 +511,54 @@ static struct most_aim aim = { static int __init most_net_init(void) { - pr_info("most_net_init()\n"); spin_lock_init(&list_lock); + mutex_init(&probe_disc_mt); return most_register_aim(&aim); } static void __exit most_net_exit(void) { - struct net_dev_context *nd, *tmp; - unsigned long flags; - - spin_lock_irqsave(&list_lock, flags); - list_for_each_entry_safe(nd, tmp, &net_devices, list) { - list_del(&nd->list); - spin_unlock_irqrestore(&list_lock, flags); - /* - * do not call most_stop_channel() here, because channels are - * going to be closed in ndo_stop() after unregister_netdev() - */ - most_net_rm_netdev_safe(nd); - kfree(nd); - spin_lock_irqsave(&list_lock, flags); - } - spin_unlock_irqrestore(&list_lock, flags); - most_deregister_aim(&aim); - pr_info("most_net_exit()\n"); } /** - * most_deliver_netinfo - callback for HDM to be informed about HW's MAC + * on_netinfo - callback for HDM to be informed about HW's MAC * @param iface - most interface instance * @param link_stat - link status * @param mac_addr - MAC address */ -void most_deliver_netinfo(struct most_interface *iface, - unsigned char link_stat, unsigned char *mac_addr) +static void on_netinfo(struct most_interface *iface, + unsigned char link_stat, unsigned char *mac_addr) { struct net_dev_context *nd; struct net_device *dev; const u8 *m = mac_addr; - nd = get_net_dev_context(iface); + nd = get_net_dev_hold(iface); if (!nd) return; dev = nd->dev; - if (!dev) - return; + + if (link_stat) + netif_carrier_on(dev); + else + netif_carrier_off(dev); if (m && is_valid_ether_addr(m)) { if (!is_valid_ether_addr(dev->dev_addr)) { netdev_info(dev, "set mac %02x-%02x-%02x-%02x-%02x-%02x\n", m[0], m[1], m[2], m[3], m[4], m[5]); ether_addr_copy(dev->dev_addr, m); - complete(&nd->mac_compl); + netif_dormant_off(dev); } else if (!ether_addr_equal(dev->dev_addr, m)) { netdev_warn(dev, "reject mac %02x-%02x-%02x-%02x-%02x-%02x\n", m[0], m[1], m[2], m[3], m[4], m[5]); } } + + dev_put(nd->dev); } -EXPORT_SYMBOL(most_deliver_netinfo); module_init(most_net_init); module_exit(most_net_exit); |