rk fb: from rk3368 fb only need to reserved 1 framebuffer
[firefly-linux-kernel-4.4.55.git] / drivers / net / rionet.c
index 5d3436d47edd45d52a45334e2a40a3ee86957429..f433b594388e170b28b1aa57a92485625d897cb6 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/ethtool.h>
 
 #define DRV_NAME        "rionet"
-#define DRV_VERSION     "0.2"
+#define DRV_VERSION     "0.3"
 #define DRV_AUTHOR      "Matt Porter <mporter@kernel.crashing.org>"
 #define DRV_DESC        "Ethernet over RapidIO"
 
@@ -47,8 +47,7 @@ MODULE_LICENSE("GPL");
 
 #define RIONET_TX_RING_SIZE    CONFIG_RIONET_TX_SIZE
 #define RIONET_RX_RING_SIZE    CONFIG_RIONET_RX_SIZE
-
-static LIST_HEAD(rionet_peers);
+#define RIONET_MAX_NETS                8
 
 struct rionet_private {
        struct rio_mport *mport;
@@ -69,27 +68,25 @@ struct rionet_peer {
        struct resource *res;
 };
 
-static int rionet_check = 0;
-static int rionet_capable = 1;
+struct rionet_net {
+       struct net_device *ndev;
+       struct list_head peers;
+       struct rio_dev **active;
+       int nact;       /* number of active peers */
+};
 
-/*
- * This is a fast lookup table for translating TX
- * Ethernet packets into a destination RIO device. It
- * could be made into a hash table to save memory depending
- * on system trade-offs.
- */
-static struct rio_dev **rionet_active;
+static struct rionet_net nets[RIONET_MAX_NETS];
 
-#define is_rionet_capable(pef, src_ops, dst_ops)               \
-                       ((pef & RIO_PEF_INB_MBOX) &&            \
-                        (pef & RIO_PEF_INB_DOORBELL) &&        \
+#define is_rionet_capable(src_ops, dst_ops)                    \
+                       ((src_ops & RIO_SRC_OPS_DATA_MSG) &&    \
+                        (dst_ops & RIO_DST_OPS_DATA_MSG) &&    \
                         (src_ops & RIO_SRC_OPS_DOORBELL) &&    \
                         (dst_ops & RIO_DST_OPS_DOORBELL))
 #define dev_rionet_capable(dev) \
-       is_rionet_capable(dev->pef, dev->src_ops, dev->dst_ops)
+       is_rionet_capable(dev->src_ops, dev->dst_ops)
 
-#define RIONET_MAC_MATCH(x)    (*(u32 *)x == 0x00010001)
-#define RIONET_GET_DESTID(x)   (*(u16 *)(x + 4))
+#define RIONET_MAC_MATCH(x)    (!memcmp((x), "\00\01\00\01", 4))
+#define RIONET_GET_DESTID(x)   ((*((u8 *)x + 4) << 8) | *((u8 *)x + 5))
 
 static int rionet_rx_clean(struct net_device *ndev)
 {
@@ -175,6 +172,7 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        struct ethhdr *eth = (struct ethhdr *)skb->data;
        u16 destid;
        unsigned long flags;
+       int add_num = 1;
 
        local_irq_save(flags);
        if (!spin_trylock(&rnet->tx_lock)) {
@@ -182,7 +180,10 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                return NETDEV_TX_LOCKED;
        }
 
-       if ((rnet->tx_cnt + 1) > RIONET_TX_RING_SIZE) {
+       if (is_multicast_ether_addr(eth->h_dest))
+               add_num = nets[rnet->mport->id].nact;
+
+       if ((rnet->tx_cnt + add_num) > RIONET_TX_RING_SIZE) {
                netif_stop_queue(ndev);
                spin_unlock_irqrestore(&rnet->tx_lock, flags);
                printk(KERN_ERR "%s: BUG! Tx Ring full when queue awake!\n",
@@ -190,16 +191,23 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                return NETDEV_TX_BUSY;
        }
 
-       if (eth->h_dest[0] & 0x01) {
+       if (is_multicast_ether_addr(eth->h_dest)) {
+               int count = 0;
+
                for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rnet->mport->sys_size);
                                i++)
-                       if (rionet_active[i])
+                       if (nets[rnet->mport->id].active[i]) {
                                rionet_queue_tx_msg(skb, ndev,
-                                                   rionet_active[i]);
+                                       nets[rnet->mport->id].active[i]);
+                               if (count)
+                                       atomic_inc(&skb->users);
+                               count++;
+                       }
        } else if (RIONET_MAC_MATCH(eth->h_dest)) {
                destid = RIONET_GET_DESTID(eth->h_dest);
-               if (rionet_active[destid])
-                       rionet_queue_tx_msg(skb, ndev, rionet_active[destid]);
+               if (nets[rnet->mport->id].active[destid])
+                       rionet_queue_tx_msg(skb, ndev,
+                                       nets[rnet->mport->id].active[destid]);
        }
 
        spin_unlock_irqrestore(&rnet->tx_lock, flags);
@@ -218,16 +226,21 @@ static void rionet_dbell_event(struct rio_mport *mport, void *dev_id, u16 sid, u
                printk(KERN_INFO "%s: doorbell sid %4.4x tid %4.4x info %4.4x",
                       DRV_NAME, sid, tid, info);
        if (info == RIONET_DOORBELL_JOIN) {
-               if (!rionet_active[sid]) {
-                       list_for_each_entry(peer, &rionet_peers, node) {
-                               if (peer->rdev->destid == sid)
-                                       rionet_active[sid] = peer->rdev;
+               if (!nets[rnet->mport->id].active[sid]) {
+                       list_for_each_entry(peer,
+                                          &nets[rnet->mport->id].peers, node) {
+                               if (peer->rdev->destid == sid) {
+                                       nets[rnet->mport->id].active[sid] =
+                                                               peer->rdev;
+                                       nets[rnet->mport->id].nact++;
+                               }
                        }
                        rio_mport_send_doorbell(mport, sid,
                                                RIONET_DOORBELL_JOIN);
                }
        } else if (info == RIONET_DOORBELL_LEAVE) {
-               rionet_active[sid] = NULL;
+               nets[rnet->mport->id].active[sid] = NULL;
+               nets[rnet->mport->id].nact--;
        } else {
                if (netif_msg_intr(rnet))
                        printk(KERN_WARNING "%s: unhandled doorbell\n",
@@ -282,7 +295,6 @@ static int rionet_open(struct net_device *ndev)
 {
        int i, rc = 0;
        struct rionet_peer *peer, *tmp;
-       u32 pwdcsr;
        struct rionet_private *rnet = netdev_priv(ndev);
 
        if (netif_msg_ifup(rnet))
@@ -322,7 +334,8 @@ static int rionet_open(struct net_device *ndev)
        netif_carrier_on(ndev);
        netif_start_queue(ndev);
 
-       list_for_each_entry_safe(peer, tmp, &rionet_peers, node) {
+       list_for_each_entry_safe(peer, tmp,
+                                &nets[rnet->mport->id].peers, node) {
                if (!(peer->res = rio_request_outb_dbell(peer->rdev,
                                                         RIONET_DOORBELL_JOIN,
                                                         RIONET_DOORBELL_LEAVE)))
@@ -332,13 +345,8 @@ static int rionet_open(struct net_device *ndev)
                        continue;
                }
 
-               /*
-                * If device has initialized inbound doorbells,
-                * send a join message
-                */
-               rio_read_config_32(peer->rdev, RIO_WRITE_PORT_CSR, &pwdcsr);
-               if (pwdcsr & RIO_DOORBELL_AVAIL)
-                       rio_send_doorbell(peer->rdev, RIONET_DOORBELL_JOIN);
+               /* Send a join message */
+               rio_send_doorbell(peer->rdev, RIONET_DOORBELL_JOIN);
        }
 
       out:
@@ -352,7 +360,7 @@ static int rionet_close(struct net_device *ndev)
        int i;
 
        if (netif_msg_ifup(rnet))
-               printk(KERN_INFO "%s: close\n", DRV_NAME);
+               printk(KERN_INFO "%s: close %s\n", DRV_NAME, ndev->name);
 
        netif_stop_queue(ndev);
        netif_carrier_off(ndev);
@@ -360,10 +368,11 @@ static int rionet_close(struct net_device *ndev)
        for (i = 0; i < RIONET_RX_RING_SIZE; i++)
                kfree_skb(rnet->rx_skb[i]);
 
-       list_for_each_entry_safe(peer, tmp, &rionet_peers, node) {
-               if (rionet_active[peer->rdev->destid]) {
+       list_for_each_entry_safe(peer, tmp,
+                                &nets[rnet->mport->id].peers, node) {
+               if (nets[rnet->mport->id].active[peer->rdev->destid]) {
                        rio_send_doorbell(peer->rdev, RIONET_DOORBELL_LEAVE);
-                       rionet_active[peer->rdev->destid] = NULL;
+                       nets[rnet->mport->id].active[peer->rdev->destid] = NULL;
                }
                rio_release_outb_dbell(peer->rdev, peer->res);
        }
@@ -379,17 +388,21 @@ static int rionet_close(struct net_device *ndev)
 static void rionet_remove(struct rio_dev *rdev)
 {
        struct net_device *ndev = rio_get_drvdata(rdev);
+       unsigned char netid = rdev->net->hport->id;
        struct rionet_peer *peer, *tmp;
 
-       free_pages((unsigned long)rionet_active, rdev->net->hport->sys_size ?
-                                       __fls(sizeof(void *)) + 4 : 0);
        unregister_netdev(ndev);
-       free_netdev(ndev);
 
-       list_for_each_entry_safe(peer, tmp, &rionet_peers, node) {
+       free_pages((unsigned long)nets[netid].active, get_order(sizeof(void *) *
+                       RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size)));
+       nets[netid].active = NULL;
+
+       list_for_each_entry_safe(peer, tmp, &nets[netid].peers, node) {
                list_del(&peer->node);
                kfree(peer);
        }
+
+       free_netdev(ndev);
 }
 
 static void rionet_get_drvinfo(struct net_device *ndev,
@@ -397,10 +410,10 @@ static void rionet_get_drvinfo(struct net_device *ndev,
 {
        struct rionet_private *rnet = netdev_priv(ndev);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->fw_version, "n/a");
-       strcpy(info->bus_info, rnet->mport->name);
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->fw_version, "n/a", sizeof(info->fw_version));
+       strlcpy(info->bus_info, rnet->mport->name, sizeof(info->bus_info));
 }
 
 static u32 rionet_get_msglevel(struct net_device *ndev)
@@ -438,15 +451,16 @@ static int rionet_setup_netdev(struct rio_mport *mport, struct net_device *ndev)
        int rc = 0;
        struct rionet_private *rnet;
        u16 device_id;
+       const size_t rionet_active_bytes = sizeof(void *) *
+                               RIO_MAX_ROUTE_ENTRIES(mport->sys_size);
 
-       rionet_active = (struct rio_dev **)__get_free_pages(GFP_KERNEL,
-                       mport->sys_size ? __fls(sizeof(void *)) + 4 : 0);
-       if (!rionet_active) {
+       nets[mport->id].active = (struct rio_dev **)__get_free_pages(GFP_KERNEL,
+                                               get_order(rionet_active_bytes));
+       if (!nets[mport->id].active) {
                rc = -ENOMEM;
                goto out;
        }
-       memset((void *)rionet_active, 0, sizeof(void *) *
-                               RIO_MAX_ROUTE_ENTRIES(mport->sys_size));
+       memset((void *)nets[mport->id].active, 0, rionet_active_bytes);
 
        /* Set up private area */
        rnet = netdev_priv(ndev);
@@ -475,63 +489,62 @@ static int rionet_setup_netdev(struct rio_mport *mport, struct net_device *ndev)
        if (rc != 0)
                goto out;
 
-       printk("%s: %s %s Version %s, MAC %pM\n",
+       printk(KERN_INFO "%s: %s %s Version %s, MAC %pM, %s\n",
               ndev->name,
               DRV_NAME,
               DRV_DESC,
               DRV_VERSION,
-              ndev->dev_addr);
+              ndev->dev_addr,
+              mport->name);
 
       out:
        return rc;
 }
 
-/*
- * XXX Make multi-net safe
- */
+static unsigned long net_table[RIONET_MAX_NETS/sizeof(unsigned long) + 1];
+
 static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id)
 {
        int rc = -ENODEV;
-       u32 lpef, lsrc_ops, ldst_ops;
+       u32 lsrc_ops, ldst_ops;
        struct rionet_peer *peer;
        struct net_device *ndev = NULL;
+       unsigned char netid = rdev->net->hport->id;
+       int oldnet;
 
-       /* If local device is not rionet capable, give up quickly */
-       if (!rionet_capable)
-               goto out;
+       if (netid >= RIONET_MAX_NETS)
+               return rc;
 
-       /* Allocate our net_device structure */
-       ndev = alloc_etherdev(sizeof(struct rionet_private));
-       if (ndev == NULL) {
-               printk(KERN_INFO "%s: could not allocate ethernet device.\n",
-                      DRV_NAME);
-               rc = -ENOMEM;
-               goto out;
-       }
+       oldnet = test_and_set_bit(netid, net_table);
 
        /*
         * First time through, make sure local device is rionet
-        * capable, setup netdev,  and set flags so this is skipped
-        * on later probes
+        * capable, setup netdev (will be skipped on later probes)
         */
-       if (!rionet_check) {
-               rio_local_read_config_32(rdev->net->hport, RIO_PEF_CAR, &lpef);
+       if (!oldnet) {
                rio_local_read_config_32(rdev->net->hport, RIO_SRC_OPS_CAR,
                                         &lsrc_ops);
                rio_local_read_config_32(rdev->net->hport, RIO_DST_OPS_CAR,
                                         &ldst_ops);
-               if (!is_rionet_capable(lpef, lsrc_ops, ldst_ops)) {
+               if (!is_rionet_capable(lsrc_ops, ldst_ops)) {
                        printk(KERN_ERR
-                              "%s: local device is not network capable\n",
-                              DRV_NAME);
-                       rionet_check = 1;
-                       rionet_capable = 0;
+                              "%s: local device %s is not network capable\n",
+                              DRV_NAME, rdev->net->hport->name);
                        goto out;
                }
 
+               /* Allocate our net_device structure */
+               ndev = alloc_etherdev(sizeof(struct rionet_private));
+               if (ndev == NULL) {
+                       rc = -ENOMEM;
+                       goto out;
+               }
+               nets[netid].ndev = ndev;
                rc = rionet_setup_netdev(rdev->net->hport, ndev);
-               rionet_check = 1;
-       }
+               INIT_LIST_HEAD(&nets[netid].peers);
+               nets[netid].nact = 0;
+       } else if (nets[netid].ndev == NULL)
+               goto out;
 
        /*
         * If the remote device has mailbox/doorbell capabilities,
@@ -543,10 +556,10 @@ static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id)
                        goto out;
                }
                peer->rdev = rdev;
-               list_add_tail(&peer->node, &rionet_peers);
+               list_add_tail(&peer->node, &nets[netid].peers);
        }
 
-       rio_set_drvdata(rdev, ndev);
+       rio_set_drvdata(rdev, nets[netid].ndev);
 
       out:
        return rc;