ionic: Add RSS support
authorShannon Nelson <snelson@pensando.io>
Tue, 3 Sep 2019 22:28:20 +0000 (15:28 -0700)
committerDavid S. Miller <davem@davemloft.net>
Thu, 5 Sep 2019 07:24:44 +0000 (09:24 +0200)
Add code to manipulate through ethtool the RSS configuration
used by the NIC.

Signed-off-by: Shannon Nelson <snelson@pensando.io>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
drivers/net/ethernet/pensando/ionic/ionic_lif.c
drivers/net/ethernet/pensando/ionic/ionic_lif.h

index ab17066..321b054 100644 (file)
@@ -482,6 +482,74 @@ static int ionic_set_priv_flags(struct net_device *netdev, u32 priv_flags)
        return 0;
 }
 
+static int ionic_get_rxnfc(struct net_device *netdev,
+                          struct ethtool_rxnfc *info, u32 *rules)
+{
+       struct ionic_lif *lif = netdev_priv(netdev);
+       int err = 0;
+
+       switch (info->cmd) {
+       case ETHTOOL_GRXRINGS:
+               info->data = lif->nxqs;
+               break;
+       default:
+               netdev_err(netdev, "Command parameter %d is not supported\n",
+                          info->cmd);
+               err = -EOPNOTSUPP;
+       }
+
+       return err;
+}
+
+static u32 ionic_get_rxfh_indir_size(struct net_device *netdev)
+{
+       struct ionic_lif *lif = netdev_priv(netdev);
+
+       return le16_to_cpu(lif->ionic->ident.lif.eth.rss_ind_tbl_sz);
+}
+
+static u32 ionic_get_rxfh_key_size(struct net_device *netdev)
+{
+       return IONIC_RSS_HASH_KEY_SIZE;
+}
+
+static int ionic_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
+                         u8 *hfunc)
+{
+       struct ionic_lif *lif = netdev_priv(netdev);
+       unsigned int i, tbl_sz;
+
+       if (indir) {
+               tbl_sz = le16_to_cpu(lif->ionic->ident.lif.eth.rss_ind_tbl_sz);
+               for (i = 0; i < tbl_sz; i++)
+                       indir[i] = lif->rss_ind_tbl[i];
+       }
+
+       if (key)
+               memcpy(key, lif->rss_hash_key, IONIC_RSS_HASH_KEY_SIZE);
+
+       if (hfunc)
+               *hfunc = ETH_RSS_HASH_TOP;
+
+       return 0;
+}
+
+static int ionic_set_rxfh(struct net_device *netdev, const u32 *indir,
+                         const u8 *key, const u8 hfunc)
+{
+       struct ionic_lif *lif = netdev_priv(netdev);
+       int err;
+
+       if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
+               return -EOPNOTSUPP;
+
+       err = ionic_lif_rss_config(lif, lif->rss_types, key, indir);
+       if (err)
+               return err;
+
+       return 0;
+}
+
 static int ionic_get_module_info(struct net_device *netdev,
                                 struct ethtool_modinfo *modinfo)
 
@@ -584,6 +652,11 @@ static const struct ethtool_ops ionic_ethtool_ops = {
        .get_sset_count         = ionic_get_sset_count,
        .get_priv_flags         = ionic_get_priv_flags,
        .set_priv_flags         = ionic_set_priv_flags,
+       .get_rxnfc              = ionic_get_rxnfc,
+       .get_rxfh_indir_size    = ionic_get_rxfh_indir_size,
+       .get_rxfh_key_size      = ionic_get_rxfh_key_size,
+       .get_rxfh               = ionic_get_rxfh,
+       .set_rxfh               = ionic_set_rxfh,
        .get_module_info        = ionic_get_module_info,
        .get_module_eeprom      = ionic_get_module_eeprom,
        .get_pauseparam         = ionic_get_pauseparam,
index 025ad6a..966a810 100644 (file)
@@ -1315,6 +1315,65 @@ static int ionic_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto,
        return ionic_adminq_post_wait(lif, &ctx);
 }
 
+int ionic_lif_rss_config(struct ionic_lif *lif, const u16 types,
+                        const u8 *key, const u32 *indir)
+{
+       struct ionic_admin_ctx ctx = {
+               .work = COMPLETION_INITIALIZER_ONSTACK(ctx.work),
+               .cmd.lif_setattr = {
+                       .opcode = IONIC_CMD_LIF_SETATTR,
+                       .attr = IONIC_LIF_ATTR_RSS,
+                       .rss.types = cpu_to_le16(types),
+                       .rss.addr = cpu_to_le64(lif->rss_ind_tbl_pa),
+               },
+       };
+       unsigned int i, tbl_sz;
+
+       lif->rss_types = types;
+
+       if (key)
+               memcpy(lif->rss_hash_key, key, IONIC_RSS_HASH_KEY_SIZE);
+
+       if (indir) {
+               tbl_sz = le16_to_cpu(lif->ionic->ident.lif.eth.rss_ind_tbl_sz);
+               for (i = 0; i < tbl_sz; i++)
+                       lif->rss_ind_tbl[i] = indir[i];
+       }
+
+       memcpy(ctx.cmd.lif_setattr.rss.key, lif->rss_hash_key,
+              IONIC_RSS_HASH_KEY_SIZE);
+
+       return ionic_adminq_post_wait(lif, &ctx);
+}
+
+static int ionic_lif_rss_init(struct ionic_lif *lif)
+{
+       u8 rss_key[IONIC_RSS_HASH_KEY_SIZE];
+       unsigned int tbl_sz;
+       unsigned int i;
+
+       netdev_rss_key_fill(rss_key, IONIC_RSS_HASH_KEY_SIZE);
+
+       lif->rss_types = IONIC_RSS_TYPE_IPV4     |
+                        IONIC_RSS_TYPE_IPV4_TCP |
+                        IONIC_RSS_TYPE_IPV4_UDP |
+                        IONIC_RSS_TYPE_IPV6     |
+                        IONIC_RSS_TYPE_IPV6_TCP |
+                        IONIC_RSS_TYPE_IPV6_UDP;
+
+       /* Fill indirection table with 'default' values */
+       tbl_sz = le16_to_cpu(lif->ionic->ident.lif.eth.rss_ind_tbl_sz);
+       for (i = 0; i < tbl_sz; i++)
+               lif->rss_ind_tbl[i] = ethtool_rxfh_indir_default(i, lif->nxqs);
+
+       return ionic_lif_rss_config(lif, lif->rss_types, rss_key, NULL);
+}
+
+static int ionic_lif_rss_deinit(struct ionic_lif *lif)
+{
+       return ionic_lif_rss_config(lif, 0x0, NULL, NULL);
+}
+
 static void ionic_txrx_disable(struct ionic_lif *lif)
 {
        unsigned int i;
@@ -1413,6 +1472,9 @@ static int ionic_txrx_init(struct ionic_lif *lif)
                }
        }
 
+       if (lif->netdev->features & NETIF_F_RXHASH)
+               ionic_lif_rss_init(lif);
+
        ionic_set_rx_mode(lif->netdev);
 
        return 0;
@@ -1558,6 +1620,7 @@ static struct ionic_lif *ionic_lif_alloc(struct ionic *ionic, unsigned int index
        struct device *dev = ionic->dev;
        struct net_device *netdev;
        struct ionic_lif *lif;
+       int tbl_sz;
        int err;
 
        netdev = alloc_etherdev_mqs(sizeof(*lif),
@@ -1610,10 +1673,24 @@ static struct ionic_lif *ionic_lif_alloc(struct ionic *ionic, unsigned int index
        if (err)
                goto err_out_free_lif_info;
 
+       /* allocate rss indirection table */
+       tbl_sz = le16_to_cpu(lif->ionic->ident.lif.eth.rss_ind_tbl_sz);
+       lif->rss_ind_tbl_sz = sizeof(*lif->rss_ind_tbl) * tbl_sz;
+       lif->rss_ind_tbl = dma_alloc_coherent(dev, lif->rss_ind_tbl_sz,
+                                             &lif->rss_ind_tbl_pa,
+                                             GFP_KERNEL);
+
+       if (!lif->rss_ind_tbl) {
+               dev_err(dev, "Failed to allocate rss indirection table, aborting\n");
+               goto err_out_free_qcqs;
+       }
+
        list_add_tail(&lif->list, &ionic->lifs);
 
        return lif;
 
+err_out_free_qcqs:
+       ionic_qcqs_free(lif);
 err_out_free_lif_info:
        dma_free_coherent(dev, lif->info_sz, lif->info, lif->info_pa);
        lif->info = NULL;
@@ -1652,6 +1729,12 @@ static void ionic_lif_free(struct ionic_lif *lif)
 {
        struct device *dev = lif->ionic->dev;
 
+       /* free rss indirection table */
+       dma_free_coherent(dev, lif->rss_ind_tbl_sz, lif->rss_ind_tbl,
+                         lif->rss_ind_tbl_pa);
+       lif->rss_ind_tbl = NULL;
+       lif->rss_ind_tbl_pa = 0;
+
        /* free queues */
        ionic_qcqs_free(lif);
        ionic_lif_reset(lif);
@@ -1693,6 +1776,7 @@ static void ionic_lif_deinit(struct ionic_lif *lif)
        clear_bit(IONIC_LIF_INITED, lif->state);
 
        ionic_rx_filters_deinit(lif);
+       ionic_lif_rss_deinit(lif);
 
        napi_disable(&lif->adminqcq->napi);
        ionic_lif_qcq_deinit(lif, lif->notifyqcq);
index 4e0b65d..2e931a7 100644 (file)
@@ -164,6 +164,12 @@ struct ionic_lif {
        dma_addr_t info_pa;
        u32 info_sz;
 
+       u16 rss_types;
+       u8 rss_hash_key[IONIC_RSS_HASH_KEY_SIZE];
+       u8 *rss_ind_tbl;
+       dma_addr_t rss_ind_tbl_pa;
+       u32 rss_ind_tbl_sz;
+
        struct ionic_rx_filters rx_filters;
        struct ionic_deferred deferred;
        unsigned long *dbid_inuse;
@@ -198,6 +204,8 @@ void ionic_lifs_unregister(struct ionic *ionic);
 int ionic_lif_identify(struct ionic *ionic, u8 lif_type,
                       union ionic_lif_identity *lif_ident);
 int ionic_lifs_size(struct ionic *ionic);
+int ionic_lif_rss_config(struct ionic_lif *lif, u16 types,
+                        const u8 *key, const u32 *indir);
 
 int ionic_open(struct net_device *netdev);
 int ionic_stop(struct net_device *netdev);