Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit beea50a5 authored by Raghu Vatsavayi's avatar Raghu Vatsavayi Committed by David S. Miller
Browse files

liquidio CN23XX: VF scatter gather lists

parent 50f7f94b
Loading
Loading
Loading
Loading
+134 −0
Original line number Diff line number Diff line
@@ -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);