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

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

liquidio:Scatter gather list per IQ



This patch is to allocate and manage scatter gather lists per
input queue(iq's) and remove queue's interdependence.

Signed-off-by: default avatarDerek Chickles <derek.chickles@caviumnetworks.com>
Signed-off-by: default avatarSatanand Burla <satananda.burla@caviumnetworks.com>
Signed-off-by: default avatarFelix Manlunas <felix.manlunas@caviumnetworks.com>
Signed-off-by: default avatarRaghu Vatsavayi <raghu.vatsavayi@caviumnetworks.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 26236fa9
Loading
Loading
Loading
Loading
+145 −69
Original line number Original line Diff line number Diff line
@@ -166,6 +166,8 @@ struct octnic_gather {
	 *  received from the IP layer.
	 *  received from the IP layer.
	 */
	 */
	struct octeon_sg_entry *sg;
	struct octeon_sg_entry *sg;

	u64 sg_dma_ptr;
};
};


/** This structure is used by NIC driver to store information required
/** This structure is used by NIC driver to store information required
@@ -791,65 +793,117 @@ static inline struct list_head *list_delete_head(struct list_head *root)
}
}


/**
/**
 * \brief Delete gather list
 * \brief Delete gather lists
 * @param lio per-network private data
 * @param lio per-network private data
 */
 */
static void delete_glist(struct lio *lio)
static void delete_glists(struct lio *lio)
{
{
	struct octnic_gather *g;
	struct octnic_gather *g;
	int i;

	if (!lio->glist)
		return;


	for (i = 0; i < lio->linfo.num_txpciq; i++) {
		do {
		do {
			g = (struct octnic_gather *)
			g = (struct octnic_gather *)
		    list_delete_head(&lio->glist);
				list_delete_head(&lio->glist[i]);
			if (g) {
			if (g) {
			if (g->sg)
				if (g->sg) {
					dma_unmap_single(&lio->oct_dev->
							 pci_dev->dev,
							 g->sg_dma_ptr,
							 g->sg_size,
							 DMA_TO_DEVICE);
					kfree((void *)((unsigned long)g->sg -
					kfree((void *)((unsigned long)g->sg -
						       g->adjust));
						       g->adjust));
				}
				kfree(g);
				kfree(g);
			}
			}
		} while (g);
		} while (g);
	}
	}


	kfree((void *)lio->glist);
}

/**
/**
 * \brief Setup gather list
 * \brief Setup gather lists
 * @param lio per-network private data
 * @param lio per-network private data
 */
 */
static int setup_glist(struct lio *lio)
static int setup_glists(struct octeon_device *oct, struct lio *lio, int num_iqs)
{
{
	int i;
	int i, j;
	struct octnic_gather *g;
	struct octnic_gather *g;


	INIT_LIST_HEAD(&lio->glist);
	lio->glist_lock = kcalloc(num_iqs, sizeof(*lio->glist_lock),
				  GFP_KERNEL);
	if (!lio->glist_lock)
		return 1;

	lio->glist = kcalloc(num_iqs, sizeof(*lio->glist),
			     GFP_KERNEL);
	if (!lio->glist) {
		kfree((void *)lio->glist_lock);
		return 1;
	}

	for (i = 0; i < num_iqs; i++) {
		int numa_node = cpu_to_node(i % num_online_cpus());


	for (i = 0; i < lio->tx_qsize; i++) {
		spin_lock_init(&lio->glist_lock[i]);

		INIT_LIST_HEAD(&lio->glist[i]);

		for (j = 0; j < lio->tx_qsize; j++) {
			g = kzalloc_node(sizeof(*g), GFP_KERNEL,
					 numa_node);
			if (!g)
				g = kzalloc(sizeof(*g), GFP_KERNEL);
				g = kzalloc(sizeof(*g), GFP_KERNEL);
			if (!g)
			if (!g)
				break;
				break;


		g->sg_size =
			g->sg_size = ((ROUNDUP4(OCTNIC_MAX_SG) >> 2) *
			((ROUNDUP4(OCTNIC_MAX_SG) >> 2) * OCT_SG_ENTRY_SIZE);
				      OCT_SG_ENTRY_SIZE);


			g->sg = kmalloc_node(g->sg_size + 8,
					     GFP_KERNEL, numa_node);
			if (!g->sg)
				g->sg = kmalloc(g->sg_size + 8, GFP_KERNEL);
				g->sg = kmalloc(g->sg_size + 8, GFP_KERNEL);
			if (!g->sg) {
			if (!g->sg) {
				kfree(g);
				kfree(g);
				break;
				break;
			}
			}


		/* The gather component should be aligned on 64-bit boundary */
			/* The gather component should be aligned on 64-bit
			 * boundary
			 */
			if (((unsigned long)g->sg) & 7) {
			if (((unsigned long)g->sg) & 7) {
				g->adjust = 8 - (((unsigned long)g->sg) & 7);
				g->adjust = 8 - (((unsigned long)g->sg) & 7);
				g->sg = (struct octeon_sg_entry *)
				g->sg = (struct octeon_sg_entry *)
					((unsigned long)g->sg + g->adjust);
					((unsigned long)g->sg + g->adjust);
			}
			}
		list_add_tail(&g->list, &lio->glist);
			g->sg_dma_ptr = dma_map_single(&oct->pci_dev->dev,
						       g->sg, g->sg_size,
						       DMA_TO_DEVICE);
			if (dma_mapping_error(&oct->pci_dev->dev,
					      g->sg_dma_ptr)) {
				kfree((void *)((unsigned long)g->sg -
					       g->adjust));
				kfree(g);
				break;
			}
			}


	if (i == lio->tx_qsize)
			list_add_tail(&g->list, &lio->glist[i]);
		return 0;
		}


	delete_glist(lio);
		if (j != lio->tx_qsize) {
			delete_glists(lio);
			return 1;
			return 1;
		}
		}
	}

	return 0;
}


/**
/**
 * \brief Print link information
 * \brief Print link information
@@ -1209,7 +1263,7 @@ static void liquidio_destroy_nic_device(struct octeon_device *oct, int ifidx)
	if (atomic_read(&lio->ifstate) & LIO_IFSTATE_REGISTERED)
	if (atomic_read(&lio->ifstate) & LIO_IFSTATE_REGISTERED)
		unregister_netdev(netdev);
		unregister_netdev(netdev);


	delete_glist(lio);
	delete_glists(lio);


	free_netdev(netdev);
	free_netdev(netdev);


@@ -1331,6 +1385,16 @@ static int octeon_pci_os_setup(struct octeon_device *oct)
	return 0;
	return 0;
}
}


static inline int skb_iq(struct lio *lio, struct sk_buff *skb)
{
	int q = 0;

	if (netif_is_multiqueue(lio->netdev))
		q = skb->queue_mapping % lio->linfo.num_txpciq;

	return q;
}

/**
/**
 * \brief Check Tx queue state for a given network buffer
 * \brief Check Tx queue state for a given network buffer
 * @param lio per-network private data
 * @param lio per-network private data
@@ -1388,7 +1452,7 @@ static void free_netsgbuf(void *buf)
	struct sk_buff *skb;
	struct sk_buff *skb;
	struct lio *lio;
	struct lio *lio;
	struct octnic_gather *g;
	struct octnic_gather *g;
	int i, frags;
	int i, frags, iq;


	finfo = (struct octnet_buf_free_info *)buf;
	finfo = (struct octnet_buf_free_info *)buf;
	skb = finfo->skb;
	skb = finfo->skb;
@@ -1410,13 +1474,13 @@ static void free_netsgbuf(void *buf)
		i++;
		i++;
	}
	}


	dma_unmap_single(&lio->oct_dev->pci_dev->dev,
	dma_sync_single_for_cpu(&lio->oct_dev->pci_dev->dev,
			 finfo->dptr, g->sg_size,
				g->sg_dma_ptr, g->sg_size, DMA_TO_DEVICE);
			 DMA_TO_DEVICE);


	spin_lock(&lio->lock);
	iq = skb_iq(lio, skb);
	list_add_tail(&g->list, &lio->glist);
	spin_lock(&lio->glist_lock[iq]);
	spin_unlock(&lio->lock);
	list_add_tail(&g->list, &lio->glist[iq]);
	spin_unlock(&lio->glist_lock[iq]);


	check_txq_state(lio, skb);     /* mq support: sub-queue state check */
	check_txq_state(lio, skb);     /* mq support: sub-queue state check */


@@ -1434,7 +1498,7 @@ static void free_netsgbuf_with_resp(void *buf)
	struct sk_buff *skb;
	struct sk_buff *skb;
	struct lio *lio;
	struct lio *lio;
	struct octnic_gather *g;
	struct octnic_gather *g;
	int i, frags;
	int i, frags, iq;


	sc = (struct octeon_soft_command *)buf;
	sc = (struct octeon_soft_command *)buf;
	skb = (struct sk_buff *)sc->callback_arg;
	skb = (struct sk_buff *)sc->callback_arg;
@@ -1458,13 +1522,14 @@ static void free_netsgbuf_with_resp(void *buf)
		i++;
		i++;
	}
	}


	dma_unmap_single(&lio->oct_dev->pci_dev->dev,
	dma_sync_single_for_cpu(&lio->oct_dev->pci_dev->dev,
			 finfo->dptr, g->sg_size,
				g->sg_dma_ptr, g->sg_size, DMA_TO_DEVICE);
			 DMA_TO_DEVICE);

	iq = skb_iq(lio, skb);


	spin_lock(&lio->lock);
	spin_lock(&lio->glist_lock[iq]);
	list_add_tail(&g->list, &lio->glist);
	list_add_tail(&g->list, &lio->glist[iq]);
	spin_unlock(&lio->lock);
	spin_unlock(&lio->glist_lock[iq]);


	/* Don't free the skb yet */
	/* Don't free the skb yet */


@@ -2683,7 +2748,8 @@ static int liquidio_xmit(struct sk_buff *skb, struct net_device *netdev)
	struct oct_iq_stats *stats;
	struct oct_iq_stats *stats;
	int status = 0;
	int status = 0;
	int q_idx = 0, iq_no = 0;
	int q_idx = 0, iq_no = 0;
	int xmit_more;
	int xmit_more, j;
	u64 dptr = 0;
	u32 tag = 0;
	u32 tag = 0;


	lio = GET_LIO(netdev);
	lio = GET_LIO(netdev);
@@ -2826,9 +2892,10 @@ static int liquidio_xmit(struct sk_buff *skb, struct net_device *netdev)
		struct skb_frag_struct *frag;
		struct skb_frag_struct *frag;
		struct octnic_gather *g;
		struct octnic_gather *g;


		spin_lock(&lio->lock);
		spin_lock(&lio->glist_lock[q_idx]);
		g = (struct octnic_gather *)list_delete_head(&lio->glist);
		g = (struct octnic_gather *)
		spin_unlock(&lio->lock);
			list_delete_head(&lio->glist[q_idx]);
		spin_unlock(&lio->glist_lock[q_idx]);


		if (!g) {
		if (!g) {
			netif_info(lio, tx_err, lio->netdev,
			netif_info(lio, tx_err, lio->netdev,
@@ -2865,22 +2932,32 @@ static int liquidio_xmit(struct sk_buff *skb, struct net_device *netdev)
					     frag->size,
					     frag->size,
					     DMA_TO_DEVICE);
					     DMA_TO_DEVICE);


			add_sg_size(&g->sg[(i >> 2)], frag->size, (i & 3));
			if (dma_mapping_error(&oct->pci_dev->dev,
			i++;
					      g->sg[i >> 2].ptr[i & 3])) {
		}
				dma_unmap_single(&oct->pci_dev->dev,

						 g->sg[0].ptr[0],
		ndata.cmd.dptr = dma_map_single(&oct->pci_dev->dev,
						 skb->len - skb->data_len,
						g->sg, g->sg_size,
						 DMA_TO_DEVICE);
						 DMA_TO_DEVICE);
		if (dma_mapping_error(&oct->pci_dev->dev, ndata.cmd.dptr)) {
				for (j = 1; j < i; j++) {
					frag = &skb_shinfo(skb)->frags[j - 1];
					dma_unmap_page(&oct->pci_dev->dev,
						       g->sg[j >> 2].ptr[j & 3],
						       frag->size,
						       DMA_TO_DEVICE);
				}
				dev_err(&oct->pci_dev->dev, "%s DMA mapping error 3\n",
				dev_err(&oct->pci_dev->dev, "%s DMA mapping error 3\n",
					__func__);
					__func__);
			dma_unmap_single(&oct->pci_dev->dev, g->sg[0].ptr[0],
					 skb->len - skb->data_len,
					 DMA_TO_DEVICE);
				return NETDEV_TX_BUSY;
				return NETDEV_TX_BUSY;
			}
			}


			add_sg_size(&g->sg[(i >> 2)], frag->size, (i & 3));
			i++;
		}

		dma_sync_single_for_device(&oct->pci_dev->dev, g->sg_dma_ptr,
					   g->sg_size, DMA_TO_DEVICE);
		dptr = g->sg_dma_ptr;

		finfo->dptr = ndata.cmd.dptr;
		finfo->dptr = ndata.cmd.dptr;
		finfo->g = g;
		finfo->g = g;


@@ -3301,7 +3378,6 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
		lio->oct_dev = octeon_dev;
		lio->oct_dev = octeon_dev;
		lio->octprops = props;
		lio->octprops = props;
		lio->netdev = netdev;
		lio->netdev = netdev;
		spin_lock_init(&lio->lock);


		dev_dbg(&octeon_dev->pci_dev->dev,
		dev_dbg(&octeon_dev->pci_dev->dev,
			"if%d gmx: %d hw_addr: 0x%llx\n", i,
			"if%d gmx: %d hw_addr: 0x%llx\n", i,
@@ -3331,7 +3407,7 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
		lio->tx_qsize = octeon_get_tx_qsize(octeon_dev, lio->txq);
		lio->tx_qsize = octeon_get_tx_qsize(octeon_dev, lio->txq);
		lio->rx_qsize = octeon_get_rx_qsize(octeon_dev, lio->rxq);
		lio->rx_qsize = octeon_get_rx_qsize(octeon_dev, lio->rxq);


		if (setup_glist(lio)) {
		if (setup_glists(octeon_dev, lio, num_iqueues)) {
			dev_err(&octeon_dev->pci_dev->dev,
			dev_err(&octeon_dev->pci_dev->dev,
				"Gather list allocation failed\n");
				"Gather list allocation failed\n");
			goto setup_nic_dev_fail;
			goto setup_nic_dev_fail;
+4 −4
Original line number Original line Diff line number Diff line
@@ -48,11 +48,11 @@ struct lio {
	 */
	 */
	int rxq;
	int rxq;


	/** Guards the glist */
	/** Guards each glist */
	spinlock_t lock;
	spinlock_t *glist_lock;


	/** Linked list of gather components */
	/** Array of gather component linked lists */
	struct list_head glist;
	struct list_head *glist;


	/** Pointer to the NIC properties for the Octeon device this network
	/** Pointer to the NIC properties for the Octeon device this network
	 *  interface is associated with.
	 *  interface is associated with.