|
@@ -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);
|