diff options
author | Raghu Vatsavayi <rvatsavayi@caviumnetworks.com> | 2016-12-07 08:54:34 -0800 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-12-08 13:21:39 -0500 |
commit | beea50a5d56bfff2c3589d1ebff715e46dceffbd (patch) | |
tree | 725767a610eac31dd1f73bd7711226c31fbf247f /drivers/net/ethernet | |
parent | 50f7f94b96a9b9dad1996953b86ece3417cd0983 (diff) | |
download | blackbird-op-linux-beea50a5d56bfff2c3589d1ebff715e46dceffbd.tar.gz blackbird-op-linux-beea50a5d56bfff2c3589d1ebff715e46dceffbd.zip |
liquidio CN23XX: VF scatter gather lists
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>
Diffstat (limited to 'drivers/net/ethernet')
-rw-r--r-- | drivers/net/ethernet/cavium/liquidio/lio_vf_main.c | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c index 6f239448cd1a..f861a9bd6f3c 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c @@ -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; @@ -237,6 +255,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); |