recipes-kernel: update driver recipes
[AGL/meta-agl-demo.git] / recipes-kernel / aim-network / files / networking.c
diff --git a/recipes-kernel/aim-network/files/networking.c b/recipes-kernel/aim-network/files/networking.c
deleted file mode 100644 (file)
index 3cd90f7..0000000
+++ /dev/null
@@ -1,574 +0,0 @@
-/*
- * Networking AIM - Networking Application Interface Module for MostCore
- *
- * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * This file is licensed under GPLv2.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/wait.h>
-#include <linux/kobject.h>
-#include "mostcore.h"
-#include "networking.h"
-
-#define MEP_HDR_LEN 8
-#define MDP_HDR_LEN 16
-#define MAMAC_DATA_LEN (1024 - MDP_HDR_LEN)
-
-#define PMHL 5
-
-#define PMS_TELID_UNSEGM_MAMAC 0x0A
-#define PMS_FIFONO_MDP         0x01
-#define PMS_FIFONO_MEP         0x04
-#define PMS_MSGTYPE_DATA       0x04
-#define PMS_DEF_PRIO           0
-#define MEP_DEF_RETRY          15
-
-#define PMS_FIFONO_MASK                0x07
-#define PMS_FIFONO_SHIFT       3
-#define PMS_RETRY_SHIFT                4
-#define PMS_TELID_MASK         0x0F
-#define PMS_TELID_SHIFT                4
-
-#define HB(value)              ((u8)((u16)(value) >> 8))
-#define LB(value)              ((u8)(value))
-
-#define EXTRACT_BIT_SET(bitset_name, value) \
-       (((value) >> bitset_name##_SHIFT) & bitset_name##_MASK)
-
-#define PMS_IS_MEP(buf, len) \
-       ((len) > MEP_HDR_LEN && \
-        EXTRACT_BIT_SET(PMS_FIFONO, (buf)[3]) == PMS_FIFONO_MEP)
-
-#define PMS_IS_MAMAC(buf, len) \
-       ((len) > MDP_HDR_LEN && \
-        EXTRACT_BIT_SET(PMS_FIFONO, (buf)[3]) == PMS_FIFONO_MDP && \
-        EXTRACT_BIT_SET(PMS_TELID, (buf)[14]) == PMS_TELID_UNSEGM_MAMAC)
-
-struct net_dev_channel {
-       bool linked;
-       int ch_id;
-};
-
-struct net_dev_context {
-       struct most_interface *iface;
-       bool channels_opened;
-       bool is_mamac;
-       unsigned char link_stat;
-       struct net_device *dev;
-       struct net_dev_channel rx;
-       struct net_dev_channel tx;
-       struct list_head list;
-};
-
-static struct list_head net_devices = LIST_HEAD_INIT(net_devices);
-static struct spinlock list_lock;
-static struct most_aim aim;
-
-static int skb_to_mamac(const struct sk_buff *skb, struct mbo *mbo)
-{
-       u8 *buff = mbo->virt_address;
-       const u8 broadcast[] = { 0x03, 0xFF };
-       const u8 *dest_addr = skb->data + 4;
-       const u8 *eth_type = skb->data + 12;
-       unsigned int payload_len = skb->len - ETH_HLEN;
-       unsigned int mdp_len = payload_len + MDP_HDR_LEN;
-
-       if (mbo->buffer_length < mdp_len) {
-               pr_err("drop: too small buffer! (%d for %d)\n",
-                      mbo->buffer_length, mdp_len);
-               return -EINVAL;
-       }
-
-       if (skb->len < ETH_HLEN) {
-               pr_err("drop: too small packet! (%d)\n", skb->len);
-               return -EINVAL;
-       }
-
-       if (dest_addr[0] == 0xFF && dest_addr[1] == 0xFF)
-               dest_addr = broadcast;
-
-       *buff++ = HB(mdp_len - 2);
-       *buff++ = LB(mdp_len - 2);
-
-       *buff++ = PMHL;
-       *buff++ = (PMS_FIFONO_MDP << PMS_FIFONO_SHIFT) | PMS_MSGTYPE_DATA;
-       *buff++ = PMS_DEF_PRIO;
-       *buff++ = dest_addr[0];
-       *buff++ = dest_addr[1];
-       *buff++ = 0x00;
-
-       *buff++ = HB(payload_len + 6);
-       *buff++ = LB(payload_len + 6);
-
-       /* end of FPH here */
-
-       *buff++ = eth_type[0];
-       *buff++ = eth_type[1];
-       *buff++ = 0;
-       *buff++ = 0;
-
-       *buff++ = PMS_TELID_UNSEGM_MAMAC << 4 | HB(payload_len);
-       *buff++ = LB(payload_len);
-
-       memcpy(buff, skb->data + ETH_HLEN, payload_len);
-       mbo->buffer_length = mdp_len;
-       return 0;
-}
-
-static int skb_to_mep(const struct sk_buff *skb, struct mbo *mbo)
-{
-       u8 *buff = mbo->virt_address;
-       unsigned int mep_len = skb->len + MEP_HDR_LEN;
-
-       if (mbo->buffer_length < mep_len) {
-               pr_err("drop: too small buffer! (%d for %d)\n",
-                      mbo->buffer_length, mep_len);
-               return -EINVAL;
-       }
-
-       *buff++ = HB(mep_len - 2);
-       *buff++ = LB(mep_len - 2);
-
-       *buff++ = PMHL;
-       *buff++ = (PMS_FIFONO_MEP << PMS_FIFONO_SHIFT) | PMS_MSGTYPE_DATA;
-       *buff++ = (MEP_DEF_RETRY << PMS_RETRY_SHIFT) | PMS_DEF_PRIO;
-       *buff++ = 0;
-       *buff++ = 0;
-       *buff++ = 0;
-
-       memcpy(buff, skb->data, skb->len);
-       mbo->buffer_length = mep_len;
-       return 0;
-}
-
-static int most_nd_set_mac_address(struct net_device *dev, void *p)
-{
-       struct net_dev_context *nd = dev->ml_priv;
-       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);
-
-       /*
-        * Set default MTU for the given packet type.
-        * It is still possible to change MTU using ip tools afterwards.
-        */
-       dev->mtu = nd->is_mamac ? MAMAC_DATA_LEN : ETH_DATA_LEN;
-
-       return 0;
-}
-
-static int most_nd_open(struct net_device *dev)
-{
-       struct net_dev_context *nd = dev->ml_priv;
-
-       netdev_info(dev, "open net device\n");
-
-       BUG_ON(nd->dev != dev);
-
-       if (nd->channels_opened)
-               return -EFAULT;
-
-       BUG_ON(!nd->tx.linked || !nd->rx.linked);
-
-       if (most_start_channel(nd->iface, nd->rx.ch_id, &aim)) {
-               netdev_err(dev, "most_start_channel() failed\n");
-               return -EBUSY;
-       }
-
-       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;
-       }
-
-       nd->channels_opened = true;
-
-       if (nd->is_mamac) {
-               nd->link_stat = 1;
-               netif_wake_queue(dev);
-       } else {
-               nd->iface->request_netinfo(nd->iface, nd->tx.ch_id);
-       }
-
-       return 0;
-}
-
-static int most_nd_stop(struct net_device *dev)
-{
-       struct net_dev_context *nd = dev->ml_priv;
-
-       netdev_info(dev, "stop net device\n");
-
-       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;
-       }
-
-       return 0;
-}
-
-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 mbo *mbo;
-       int ret;
-
-       BUG_ON(nd->dev != dev);
-
-       mbo = most_get_mbo(nd->iface, nd->tx.ch_id, &aim);
-
-       if (!mbo) {
-               netif_stop_queue(dev);
-               dev->stats.tx_fifo_errors++;
-               return NETDEV_TX_BUSY;
-       }
-
-       if (nd->is_mamac)
-               ret = skb_to_mamac(skb, mbo);
-       else
-               ret = skb_to_mep(skb, mbo);
-
-       if (ret) {
-               most_put_mbo(mbo);
-               dev->stats.tx_dropped++;
-               kfree_skb(skb);
-               return NETDEV_TX_OK;
-       }
-
-       most_submit_mbo(mbo);
-       dev->stats.tx_packets++;
-       dev->stats.tx_bytes += skb->len;
-       kfree_skb(skb);
-       return NETDEV_TX_OK;
-}
-
-static const struct net_device_ops most_nd_ops = {
-       .ndo_open = most_nd_open,
-       .ndo_stop = most_nd_stop,
-       .ndo_start_xmit = most_nd_start_xmit,
-       .ndo_set_mac_address = most_nd_set_mac_address,
-};
-
-static void most_nd_setup(struct net_device *dev)
-{
-       netdev_info(dev, "setup net device\n");
-       ether_setup(dev);
-       dev->netdev_ops = &most_nd_ops;
-}
-
-static void most_net_rm_netdev_safe(struct net_dev_context *nd)
-{
-       if (!nd->dev)
-               return;
-
-       pr_info("remove net device %p\n", nd->dev);
-
-       unregister_netdev(nd->dev);
-       free_netdev(nd->dev);
-       nd->dev = NULL;
-}
-
-static struct net_dev_context *get_net_dev_context(
-       struct most_interface *iface)
-{
-       struct net_dev_context *nd, *tmp;
-
-       spin_lock(&list_lock);
-       list_for_each_entry_safe(nd, tmp, &net_devices, list) {
-               if (nd->iface == iface) {
-                       spin_unlock(&list_lock);
-                       return nd;
-               }
-       }
-       spin_unlock(&list_lock);
-       return NULL;
-}
-
-static int aim_probe_channel(struct most_interface *iface, int channel_idx,
-                            struct most_channel_config *ccfg,
-                            struct kobject *parent, char *name)
-{
-       struct net_dev_context *nd;
-       struct net_dev_channel *ch;
-
-       if (!iface)
-               return -EINVAL;
-
-       if (ccfg->data_type != MOST_CH_ASYNC)
-               return -EINVAL;
-
-       nd = get_net_dev_context(iface);
-
-       if (!nd) {
-               nd = kzalloc(sizeof(*nd), GFP_KERNEL);
-               if (!nd)
-                       return -ENOMEM;
-
-               nd->iface = iface;
-
-               spin_lock(&list_lock);
-               list_add(&nd->list, &net_devices);
-               spin_unlock(&list_lock);
-       }
-
-       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", most_nd_setup);
-
-               if (!dev) {
-                       pr_err("no memory for net_device\n");
-                       return -ENOMEM;
-               }
-
-               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;
-               }
-       }
-
-       ch->ch_id = channel_idx;
-       ch->linked = true;
-
-       return 0;
-}
-
-static int aim_disconnect_channel(struct most_interface *iface,
-                                 int channel_idx)
-{
-       struct net_dev_context *nd;
-       struct net_dev_channel *ch;
-
-       nd = get_net_dev_context(iface);
-       if (!nd)
-               return -EINVAL;
-
-       if (nd->rx.linked && channel_idx == nd->rx.ch_id)
-               ch = &nd->rx;
-       else if (nd->tx.linked && channel_idx == nd->tx.ch_id)
-               ch = &nd->tx;
-       else
-               return -EINVAL;
-
-       ch->linked = false;
-
-       /*
-        * 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(&list_lock);
-               list_del(&nd->list);
-               spin_unlock(&list_lock);
-               kfree(nd);
-       }
-
-       return 0;
-}
-
-static int aim_resume_tx_channel(struct most_interface *iface,
-                                int channel_idx)
-{
-       struct net_dev_context *nd;
-
-       nd = get_net_dev_context(iface);
-       if (!nd || !nd->channels_opened || nd->tx.ch_id != channel_idx)
-               return 0;
-
-       if (!nd->dev)
-               return 0;
-
-       netif_wake_queue(nd->dev);
-       return 0;
-}
-
-static int aim_rx_data(struct mbo *mbo)
-{
-       const u32 zero = 0;
-       struct net_dev_context *nd;
-       char *buf = mbo->virt_address;
-       u32 len = mbo->processed_length;
-       struct sk_buff *skb;
-       struct net_device *dev;
-       unsigned int skb_len;
-
-       nd = get_net_dev_context(mbo->ifp);
-       if (!nd || !nd->channels_opened || nd->rx.ch_id != mbo->hdm_channel_id)
-               return -EIO;
-
-       dev = nd->dev;
-       if (!dev) {
-               pr_err_once("drop packet: missing net_device\n");
-               return -EIO;
-       }
-
-       if (nd->is_mamac) {
-               if (!PMS_IS_MAMAC(buf, len))
-                       return -EIO;
-
-               skb = dev_alloc_skb(len - MDP_HDR_LEN + 2 * ETH_ALEN + 2);
-       } else {
-               if (!PMS_IS_MEP(buf, len))
-                       return -EIO;
-
-               skb = dev_alloc_skb(len - MEP_HDR_LEN);
-       }
-
-       if (!skb) {
-               dev->stats.rx_dropped++;
-               pr_err_once("drop packet: no memory for skb\n");
-               goto out;
-       }
-
-       skb->dev = dev;
-
-       if (nd->is_mamac) {
-               /* dest */
-               memcpy(skb_put(skb, ETH_ALEN), dev->dev_addr, ETH_ALEN);
-
-               /* src */
-               memcpy(skb_put(skb, 4), &zero, 4);
-               memcpy(skb_put(skb, 2), buf + 5, 2);
-
-               /* eth type */
-               memcpy(skb_put(skb, 2), buf + 10, 2);
-
-               buf += MDP_HDR_LEN;
-               len -= MDP_HDR_LEN;
-       } else {
-               buf += MEP_HDR_LEN;
-               len -= MEP_HDR_LEN;
-       }
-
-       memcpy(skb_put(skb, len), buf, len);
-       skb->protocol = eth_type_trans(skb, dev);
-       skb_len = skb->len;
-       if (netif_rx(skb) == NET_RX_SUCCESS) {
-               dev->stats.rx_packets++;
-               dev->stats.rx_bytes += skb_len;
-       } else {
-               dev->stats.rx_dropped++;
-       }
-
-out:
-       most_put_mbo(mbo);
-       return 0;
-}
-
-static struct most_aim aim = {
-       .name = "networking",
-       .probe_channel = aim_probe_channel,
-       .disconnect_channel = aim_disconnect_channel,
-       .tx_completion = aim_resume_tx_channel,
-       .rx_completion = aim_rx_data,
-};
-
-static int __init most_net_init(void)
-{
-       pr_info("most_net_init()\n");
-       spin_lock_init(&list_lock);
-       return most_register_aim(&aim);
-}
-
-static void __exit most_net_exit(void)
-{
-       struct net_dev_context *nd, *tmp;
-
-       spin_lock(&list_lock);
-       list_for_each_entry_safe(nd, tmp, &net_devices, list) {
-               list_del(&nd->list);
-               spin_unlock(&list_lock);
-               /*
-                * 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(&list_lock);
-       }
-       spin_unlock(&list_lock);
-
-       most_deregister_aim(&aim);
-       pr_info("most_net_exit()\n");
-}
-
-/**
- * most_deliver_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)
-{
-       struct net_dev_context *nd;
-       struct net_device *dev;
-
-       pr_info("Received netinfo from %s\n", iface->description);
-
-       nd = get_net_dev_context(iface);
-       if (!nd)
-               return;
-
-       dev = nd->dev;
-       if (!dev)
-               return;
-
-       if (mac_addr)
-               memcpy(dev->dev_addr, mac_addr, ETH_ALEN);
-
-       if (nd->link_stat != link_stat) {
-               nd->link_stat = link_stat;
-               if (nd->link_stat)
-                       netif_wake_queue(dev);
-               else
-                       netif_stop_queue(dev);
-       }
-}
-EXPORT_SYMBOL(most_deliver_netinfo);
-
-module_init(most_net_init);
-module_exit(most_net_exit);
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Andrey Shvetsov <andrey.shvetsov@k2l.de>");
-MODULE_DESCRIPTION("Networking Application Interface Module for MostCore");