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

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
...@@ -166,6 +166,8 @@ struct octnic_gather { ...@@ -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,64 +793,116 @@ static inline struct list_head *list_delete_head(struct list_head *root) ...@@ -791,64 +793,116 @@ 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;
do { if (!lio->glist)
g = (struct octnic_gather *) return;
list_delete_head(&lio->glist);
if (g) { for (i = 0; i < lio->linfo.num_txpciq; i++) {
if (g->sg) do {
kfree((void *)((unsigned long)g->sg - g = (struct octnic_gather *)
g->adjust)); list_delete_head(&lio->glist[i]);
kfree(g); if (g) {
} if (g->sg) {
} while (g); 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 -
g->adjust));
}
kfree(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;
for (i = 0; i < lio->tx_qsize; i++) { lio->glist = kcalloc(num_iqs, sizeof(*lio->glist),
g = kzalloc(sizeof(*g), GFP_KERNEL); GFP_KERNEL);
if (!g) if (!lio->glist) {
break; kfree((void *)lio->glist_lock);
return 1;
}
g->sg_size = for (i = 0; i < num_iqs; i++) {
((ROUNDUP4(OCTNIC_MAX_SG) >> 2) * OCT_SG_ENTRY_SIZE); int numa_node = cpu_to_node(i % num_online_cpus());
g->sg = kmalloc(g->sg_size + 8, GFP_KERNEL); spin_lock_init(&lio->glist_lock[i]);
if (!g->sg) {
kfree(g); INIT_LIST_HEAD(&lio->glist[i]);
break;
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);
if (!g)
break;
g->sg_size = ((ROUNDUP4(OCTNIC_MAX_SG) >> 2) *
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);
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);
}
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;
}
list_add_tail(&g->list, &lio->glist[i]);
} }
/* The gather component should be aligned on 64-bit boundary */ if (j != lio->tx_qsize) {
if (((unsigned long)g->sg) & 7) { delete_glists(lio);
g->adjust = 8 - (((unsigned long)g->sg) & 7); return 1;
g->sg = (struct octeon_sg_entry *)
((unsigned long)g->sg + g->adjust);
} }
list_add_tail(&g->list, &lio->glist);
} }
if (i == lio->tx_qsize) return 0;
return 0;
delete_glist(lio);
return 1;
} }
/** /**
...@@ -1209,7 +1263,7 @@ static void liquidio_destroy_nic_device(struct octeon_device *oct, int ifidx) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
spin_lock(&lio->lock); iq = skb_iq(lio, skb);
list_add_tail(&g->list, &lio->glist);
spin_unlock(&lio->lock); spin_lock(&lio->glist_lock[iq]);
list_add_tail(&g->list, &lio->glist[iq]);
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) ...@@ -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) ...@@ -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,21 +2932,31 @@ static int liquidio_xmit(struct sk_buff *skb, struct net_device *netdev) ...@@ -2865,21 +2932,31 @@ static int liquidio_xmit(struct sk_buff *skb, struct net_device *netdev)
frag->size, frag->size,
DMA_TO_DEVICE); DMA_TO_DEVICE);
if (dma_mapping_error(&oct->pci_dev->dev,
g->sg[i >> 2].ptr[i & 3])) {
dma_unmap_single(&oct->pci_dev->dev,
g->sg[0].ptr[0],
skb->len - skb->data_len,
DMA_TO_DEVICE);
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",
__func__);
return NETDEV_TX_BUSY;
}
add_sg_size(&g->sg[(i >> 2)], frag->size, (i & 3)); add_sg_size(&g->sg[(i >> 2)], frag->size, (i & 3));
i++; i++;
} }
ndata.cmd.dptr = dma_map_single(&oct->pci_dev->dev, dma_sync_single_for_device(&oct->pci_dev->dev, g->sg_dma_ptr,
g->sg, g->sg_size, g->sg_size, DMA_TO_DEVICE);
DMA_TO_DEVICE); dptr = g->sg_dma_ptr;
if (dma_mapping_error(&oct->pci_dev->dev, ndata.cmd.dptr)) {
dev_err(&oct->pci_dev->dev, "%s DMA mapping error 3\n",
__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;
}
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) ...@@ -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) ...@@ -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;
......
...@@ -48,11 +48,11 @@ struct lio { ...@@ -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.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment