From a6520f21947de1d6509a28cbe3b72bd194547672 Mon Sep 17 00:00:00 2001 From: Bhadram Varka Date: Tue, 17 Dec 2019 14:00:29 +0530 Subject: [PATCH] nvethernet: add support for RSS Changes takes care generation Hash key and population of hash table with necessary information. It also adds support ethtool to get/set hash key/table. Bug 200565647 Change-Id: I5d5364bc88f4dea9456919b886dd8ede7f638ae3 Signed-off-by: Bhadram Varka Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2263899 Reviewed-by: automaticguardword Reviewed-by: Narayan Reddy --- .../ethernet/nvidia/nvethernet/ether_linux.c | 38 +++++ .../net/ethernet/nvidia/nvethernet/ethtool.c | 140 ++++++++++++++++++ drivers/net/ethernet/nvidia/nvethernet/osd.c | 6 + 3 files changed, 184 insertions(+) diff --git a/drivers/net/ethernet/nvidia/nvethernet/ether_linux.c b/drivers/net/ethernet/nvidia/nvethernet/ether_linux.c index 7fa66219..374671c3 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/ether_linux.c +++ b/drivers/net/ethernet/nvidia/nvethernet/ether_linux.c @@ -4212,6 +4212,11 @@ static void ether_set_ndev_features(struct net_device *ndev, features |= NETIF_F_HW_VLAN_CTAG_RX; features |= NETIF_F_HW_VLAN_CTAG_FILTER; + /* Receive Hashing offload */ + if (pdata->hw_feat.rss_en) { + features |= NETIF_F_RXHASH; + } + /* Features available in HW */ ndev->hw_features = features; /* Features that can be changed by user */ @@ -4270,6 +4275,36 @@ static inline void tegra_pre_si_platform(struct osi_core_priv_data *osi_core, osi_dma->pre_si = 0; } +/** + * @brief ether_init_rss - Init OSI RSS structure + * + * Algorithm: Populates RSS hash key and table in OSI core structure. + * + * @param[in] pdata: Ethernet private data + * @param[in] features: Netdev features + */ +static void ether_init_rss(struct ether_priv_data *pdata, + netdev_features_t features) +{ + struct osi_core_priv_data *osi_core = pdata->osi_core; + unsigned int num_q = osi_core->num_mtl_queues; + unsigned int i = 0; + + if ((features & NETIF_F_RXHASH) == NETIF_F_RXHASH) { + osi_core->rss.enable = 1; + } else { + osi_core->rss.enable = 0; + return; + } + + /* generate random key */ + netdev_rss_key_fill(osi_core->rss.key, sizeof(osi_core->rss.key)); + + /* initialize hash table */ + for (i = 0; i < OSI_RSS_MAX_TABLE_SIZE; i++) + osi_core->rss.table[i] = ethtool_rxfh_indir_default(i, num_q); +} + /** * @brief Ethernet platform driver probe. * @@ -4388,6 +4423,9 @@ static int ether_probe(struct platform_device *pdev) /* Set netdev features based on hw features */ ether_set_ndev_features(ndev, pdata); + /* RSS init */ + ether_init_rss(pdata, ndev->features); + ret = ether_get_irqs(pdev, pdata, num_dma_chans); if (ret < 0) { dev_err(&pdev->dev, "failed to get IRQ's\n"); diff --git a/drivers/net/ethernet/nvidia/nvethernet/ethtool.c b/drivers/net/ethernet/nvidia/nvethernet/ethtool.c index e8497394..dcb1fef0 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/ethtool.c +++ b/drivers/net/ethernet/nvidia/nvethernet/ethtool.c @@ -1156,6 +1156,141 @@ static void ether_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) phy_ethtool_get_wol(pdata->phydev, wol); } +/** + * @brief Get RX flow classification rules + * + * Algorithm: Returns RX flow classification rules. + * + * param[in] ndev: Pointer to net device structure. + * param[in] rxnfc: Pointer to rxflow data + * param[in] rule_locs: TBD + * + * @note MAC and PHY need to be initialized. + * + * @retval 0 on success + * @retval negative on failure + */ +static int ether_get_rxnfc(struct net_device *ndev, + struct ethtool_rxnfc *rxnfc, + u32 *rule_locs) +{ + struct ether_priv_data *pdata = netdev_priv(ndev); + struct osi_core_priv_data *osi_core = pdata->osi_core; + + switch (rxnfc->cmd) { + case ETHTOOL_GRXRINGS: + rxnfc->data = osi_core->num_mtl_queues; + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +/** + * @brief Get the size of the RX flow hash key + * + * Algorithm: Returns size of RSS hash key + * + * param[in] ndev: Pointer to net device structure. + * + * @retval size of RSS Hash key + */ +static u32 ether_get_rxfh_key_size(struct net_device *ndev) +{ + struct ether_priv_data *pdata = netdev_priv(ndev); + struct osi_core_priv_data *osi_core = pdata->osi_core; + + return sizeof(osi_core->rss.key); +} + +/** + * @brief Get the size of the RX flow hash indirection table + * + * Algorithm: Returns size of the RX flow hash indirection table + * + * param[in] ndev: Pointer to net device structure. + * + * @retval size of RSS Hash table + */ +static u32 ether_get_rxfh_indir_size(struct net_device *ndev) +{ + struct ether_priv_data *pdata = netdev_priv(ndev); + struct osi_core_priv_data *osi_core = pdata->osi_core; + + return ARRAY_SIZE(osi_core->rss.table); +} + +/** + * @brief Get the contents of the RX flow hash indirection table, hash key + * and/or hash function + * + * param[in] ndev: Pointer to net device structure. + * param[out] indir: Pointer to indirection table + * param[out] key: Pointer to Hash key + * param[out] hfunc: Pointer to Hash function + * + * @retval 0 on success + */ +static int ether_get_rxfh(struct net_device *ndev, u32 *indir, u8 *key, + u8 *hfunc) +{ + struct ether_priv_data *pdata = netdev_priv(ndev); + struct osi_core_priv_data *osi_core = pdata->osi_core; + int i; + + if (indir) { + for (i = 0; i < ARRAY_SIZE(osi_core->rss.table); i++) + indir[i] = osi_core->rss.table[i]; + } + + if (key) + memcpy(key, osi_core->rss.key, sizeof(osi_core->rss.key)); + if (hfunc) + *hfunc = ETH_RSS_HASH_TOP; + + return 0; +} + +/** + * @brief Set the contents of the RX flow hash indirection table, hash key + * and/or hash function + * + * param[in] ndev: Pointer to net device structure. + * param[in] indir: Pointer to indirection table + * param[in] key: Pointer to Hash key + * param[hfunc] hfunc: Hash function + * + * @retval 0 on success + * @retval -1 on failure. + */ +static int ether_set_rxfh(struct net_device *ndev, const u32 *indir, + const u8 *key, const u8 hfunc) +{ + struct ether_priv_data *pdata = netdev_priv(ndev); + struct osi_core_priv_data *osi_core = pdata->osi_core; + int i; + + if (!netif_running(ndev)) { + netdev_err(pdata->ndev, "interface must be up\n"); + return -ENODEV; + } + + if ((hfunc != ETH_RSS_HASH_NO_CHANGE) && (hfunc != ETH_RSS_HASH_TOP)) + return -EOPNOTSUPP; + + if (indir) { + for (i = 0; i < ARRAY_SIZE(osi_core->rss.table); i++) + osi_core->rss.table[i] = indir[i]; + } + + if (key) + memcpy(osi_core->rss.key, key, sizeof(osi_core->rss.key)); + + return osi_config_rss(osi_core); +} + /** * @brief Set of ethtool operations */ @@ -1180,6 +1315,11 @@ static const struct ethtool_ops ether_ethtool_ops = { .get_eee = ether_get_eee, .set_eee = ether_set_eee, .self_test = ether_selftest_run, + .get_rxnfc = ether_get_rxnfc, + .get_rxfh_key_size = ether_get_rxfh_key_size, + .get_rxfh_indir_size = ether_get_rxfh_indir_size, + .get_rxfh = ether_get_rxfh, + .set_rxfh = ether_set_rxfh, }; void ether_set_ethtool_ops(struct net_device *ndev) diff --git a/drivers/net/ethernet/nvidia/nvethernet/osd.c b/drivers/net/ethernet/nvidia/nvethernet/osd.c index 88654fc9..2e8027ea 100644 --- a/drivers/net/ethernet/nvidia/nvethernet/osd.c +++ b/drivers/net/ethernet/nvidia/nvethernet/osd.c @@ -283,6 +283,11 @@ void osd_receive_packet(void *priv, void *rxring, unsigned int chan, skb->ip_summed = CHECKSUM_NONE; } + if ((rx_pkt_cx->flags & OSI_PKT_CX_RSS) == OSI_PKT_CX_RSS) { + skb_set_hash(skb, rx_pkt_cx->rx_hash, + rx_pkt_cx->rx_hash_type); + } + if ((rx_pkt_cx->flags & OSI_PKT_CX_VLAN) == OSI_PKT_CX_VLAN) { val = pdata->osi_dma->dstats.rx_vlan_pkt_n; pdata->osi_dma->dstats.rx_vlan_pkt_n = @@ -299,6 +304,7 @@ void osd_receive_packet(void *priv, void *rxring, unsigned int chan, shhwtstamp->hwtstamp = ns_to_ktime(rx_pkt_cx->ns); } + skb_record_rx_queue(skb, chan); skb->dev = ndev; skb->protocol = eth_type_trans(skb, ndev); ndev->stats.rx_bytes += skb->len;