liquidio CN23XX: VF scatter gather lists
authorRaghu Vatsavayi <rvatsavayi@caviumnetworks.com>
Wed, 7 Dec 2016 16:54:34 +0000 (08:54 -0800)
committerDavid S. Miller <davem@davemloft.net>
Thu, 8 Dec 2016 18:21:39 +0000 (13:21 -0500)
Adds support for VF scatter gather lists.

Signed-off-by: Raghu Vatsavayi <raghu.vatsavayi@caviumnetworks.com>
Signed-off-by: Derek Chickles <derek.chickles@caviumnetworks.com>
Signed-off-by: Satanand Burla <satananda.burla@caviumnetworks.com>
Signed-off-by: Felix Manlunas <felix.manlunas@caviumnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/cavium/liquidio/lio_vf_main.c

index 6f239448cd1a7839e94f8a2a995e6142f2939b51..f861a9bd6f3c3b5e7b057669d57ef3962ebbba7e 100644 (file)
@@ -55,10 +55,28 @@ struct liquidio_if_cfg_resp {
        u64 status;
 };
 
+#define OCTNIC_MAX_SG  (MAX_SKB_FRAGS)
+
 #define OCTNIC_GSO_MAX_HEADER_SIZE 128
 #define OCTNIC_GSO_MAX_SIZE \
                (CN23XX_DEFAULT_INPUT_JABBER - OCTNIC_GSO_MAX_HEADER_SIZE)
 
+struct octnic_gather {
+       /* List manipulation. Next and prev pointers. */
+       struct list_head list;
+
+       /* Size of the gather component at sg in bytes. */
+       int sg_size;
+
+       /* Number of bytes that sg was adjusted to make it 8B-aligned. */
+       int adjust;
+
+       /* Gather component that can accommodate max sized fragment list
+        * received from the IP layer.
+        */
+       struct octeon_sg_entry *sg;
+};
+
 struct octeon_device_priv {
        /* Tasklet structures for this device. */
        struct tasklet_struct droq_tasklet;
@@ -236,6 +254,114 @@ static void start_txq(struct net_device *netdev)
        }
 }
 
+/**
+ * Remove the node at the head of the list. The list would be empty at
+ * the end of this call if there are no more nodes in the list.
+ */
+static struct list_head *list_delete_head(struct list_head *root)
+{
+       struct list_head *node;
+
+       if ((root->prev == root) && (root->next == root))
+               node = NULL;
+       else
+               node = root->next;
+
+       if (node)
+               list_del(node);
+
+       return node;
+}
+
+/**
+ * \brief Delete gather lists
+ * @param lio per-network private data
+ */
+static void delete_glists(struct lio *lio)
+{
+       struct octnic_gather *g;
+       int i;
+
+       if (!lio->glist)
+               return;
+
+       for (i = 0; i < lio->linfo.num_txpciq; i++) {
+               do {
+                       g = (struct octnic_gather *)
+                           list_delete_head(&lio->glist[i]);
+                       if (g) {
+                               if (g->sg)
+                                       kfree((void *)((unsigned long)g->sg -
+                                                       g->adjust));
+                               kfree(g);
+                       }
+               } while (g);
+       }
+
+       kfree(lio->glist);
+       kfree(lio->glist_lock);
+}
+
+/**
+ * \brief Setup gather lists
+ * @param lio per-network private data
+ */
+static int setup_glists(struct lio *lio, int num_iqs)
+{
+       struct octnic_gather *g;
+       int i, j;
+
+       lio->glist_lock =
+           kzalloc(sizeof(*lio->glist_lock) * num_iqs, GFP_KERNEL);
+       if (!lio->glist_lock)
+               return 1;
+
+       lio->glist =
+           kzalloc(sizeof(*lio->glist) * num_iqs, GFP_KERNEL);
+       if (!lio->glist) {
+               kfree(lio->glist_lock);
+               return 1;
+       }
+
+       for (i = 0; i < num_iqs; i++) {
+               spin_lock_init(&lio->glist_lock[i]);
+
+               INIT_LIST_HEAD(&lio->glist[i]);
+
+               for (j = 0; j < lio->tx_qsize; j++) {
+                       g = kzalloc(sizeof(*g), GFP_KERNEL);
+                       if (!g)
+                               break;
+
+                       g->sg_size = ((ROUNDUP4(OCTNIC_MAX_SG) >> 2) *
+                                     OCT_SG_ENTRY_SIZE);
+
+                       g->sg = kmalloc(g->sg_size + 8, GFP_KERNEL);
+                       if (!g->sg) {
+                               kfree(g);
+                               break;
+                       }
+
+                       /* The gather component should be aligned on 64-bit
+                        * boundary
+                        */
+                       if (((unsigned long)g->sg) & 7) {
+                               g->adjust = 8 - (((unsigned long)g->sg) & 7);
+                               g->sg = (struct octeon_sg_entry *)
+                                       ((unsigned long)g->sg + g->adjust);
+                       }
+                       list_add_tail(&g->list, &lio->glist[i]);
+               }
+
+               if (j != lio->tx_qsize) {
+                       delete_glists(lio);
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
 /**
  * \brief Print link information
  * @param netdev network device
@@ -681,6 +807,8 @@ static void liquidio_destroy_nic_device(struct octeon_device *oct, int ifidx)
 
        cleanup_link_status_change_wq(netdev);
 
+       delete_glists(lio);
+
        free_netdev(netdev);
 
        oct->props[ifidx].gmxport = -1;
@@ -1379,6 +1507,12 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
                /* Copy MAC Address to OS network device structure */
                ether_addr_copy(netdev->dev_addr, mac);
 
+               if (setup_glists(lio, num_iqueues)) {
+                       dev_err(&octeon_dev->pci_dev->dev,
+                               "Gather list allocation failed\n");
+                       goto setup_nic_dev_fail;
+               }
+
                if (netdev->features & NETIF_F_LRO)
                        liquidio_set_feature(netdev, OCTNET_CMD_LRO_ENABLE,
                                             OCTNIC_LROIPV4 | OCTNIC_LROIPV6);