]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
octeontx2-pf: ethtool RSS config support
authorSunil Goutham <sgoutham@marvell.com>
Mon, 27 Jan 2020 13:05:29 +0000 (18:35 +0530)
committerDavid S. Miller <davem@davemloft.net>
Mon, 27 Jan 2020 13:33:39 +0000 (14:33 +0100)
Added support to show or configure RSS hash key, indirection table,
2,4 tuple via ethtool. Also added debug msg_level support
to dump messages when HW reports errors in packet received
or transmitted.

Signed-off-by: Prakash Brahmajyosyula <bprakash@marvell.com>
Signed-off-by: Sunil Goutham <sgoutham@marvell.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h
drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c

index 07d45596b62efcf1d03698e5b8cd3bb324c83ee8..8247d21d0432aaffbfa73200e9e959a53be6115c 100644 (file)
@@ -220,7 +220,7 @@ int otx2_hw_set_mtu(struct otx2_nic *pfvf, int mtu)
        return err;
 }
 
-static int otx2_set_flowkey_cfg(struct otx2_nic *pfvf)
+int otx2_set_flowkey_cfg(struct otx2_nic *pfvf)
 {
        struct otx2_rss_info *rss = &pfvf->hw.rss_info;
        struct nix_rss_flowkey_cfg *req;
@@ -241,7 +241,7 @@ static int otx2_set_flowkey_cfg(struct otx2_nic *pfvf)
        return err;
 }
 
-static int otx2_set_rss_table(struct otx2_nic *pfvf)
+int otx2_set_rss_table(struct otx2_nic *pfvf)
 {
        struct otx2_rss_info *rss = &pfvf->hw.rss_info;
        struct mbox *mbox = &pfvf->mbox;
@@ -280,7 +280,7 @@ static int otx2_set_rss_table(struct otx2_nic *pfvf)
        return err;
 }
 
-static void otx2_set_rss_key(struct otx2_nic *pfvf)
+void otx2_set_rss_key(struct otx2_nic *pfvf)
 {
        struct otx2_rss_info *rss = &pfvf->hw.rss_info;
        u64 *key = (u64 *)&rss->key[4];
index 95557e8425a3f9eaf028baa538562e8febd904b1..320f3b7bf57fd68f686c295ccbc38394ccc085fb 100644 (file)
@@ -222,6 +222,9 @@ struct otx2_nic {
        struct work_struct      reset_task;
        struct refill_work      *refill_wrk;
 
+       /* Ethtool stuff */
+       u32                     msg_enable;
+
        /* Block address of NIX either BLKADDR_NIX0 or BLKADDR_NIX1 */
        int                     nix_blkaddr;
 };
@@ -580,6 +583,9 @@ void otx2_cleanup_tx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq);
 
 /* RSS configuration APIs*/
 int otx2_rss_init(struct otx2_nic *pfvf);
+int otx2_set_flowkey_cfg(struct otx2_nic *pfvf);
+void otx2_set_rss_key(struct otx2_nic *pfvf);
+int otx2_set_rss_table(struct otx2_nic *pfvf);
 
 /* Mbox handlers */
 void mbox_handler_msix_offset(struct otx2_nic *pfvf,
index b1f61e069ed867adc6420782ae1f010f39a03133..60fcf82dd8cb6b0a5b91fa2b29cdacaf06a61185 100644 (file)
@@ -389,7 +389,253 @@ static int otx2_set_coalesce(struct net_device *netdev,
        return 0;
 }
 
+static int otx2_get_rss_hash_opts(struct otx2_nic *pfvf,
+                                 struct ethtool_rxnfc *nfc)
+{
+       struct otx2_rss_info *rss = &pfvf->hw.rss_info;
+
+       if (!(rss->flowkey_cfg &
+           (NIX_FLOW_KEY_TYPE_IPV4 | NIX_FLOW_KEY_TYPE_IPV6)))
+               return 0;
+
+       /* Mimimum is IPv4 and IPv6, SIP/DIP */
+       nfc->data = RXH_IP_SRC | RXH_IP_DST;
+
+       switch (nfc->flow_type) {
+       case TCP_V4_FLOW:
+       case TCP_V6_FLOW:
+               if (rss->flowkey_cfg & NIX_FLOW_KEY_TYPE_TCP)
+                       nfc->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+               break;
+       case UDP_V4_FLOW:
+       case UDP_V6_FLOW:
+               if (rss->flowkey_cfg & NIX_FLOW_KEY_TYPE_UDP)
+                       nfc->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+               break;
+       case SCTP_V4_FLOW:
+       case SCTP_V6_FLOW:
+               if (rss->flowkey_cfg & NIX_FLOW_KEY_TYPE_SCTP)
+                       nfc->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+               break;
+       case AH_ESP_V4_FLOW:
+       case AH_V4_FLOW:
+       case ESP_V4_FLOW:
+       case IPV4_FLOW:
+       case AH_ESP_V6_FLOW:
+       case AH_V6_FLOW:
+       case ESP_V6_FLOW:
+       case IPV6_FLOW:
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int otx2_set_rss_hash_opts(struct otx2_nic *pfvf,
+                                 struct ethtool_rxnfc *nfc)
+{
+       struct otx2_rss_info *rss = &pfvf->hw.rss_info;
+       u32 rxh_l4 = RXH_L4_B_0_1 | RXH_L4_B_2_3;
+       u32 rss_cfg = rss->flowkey_cfg;
+
+       if (!rss->enable) {
+               netdev_err(pfvf->netdev,
+                          "RSS is disabled, cannot change settings\n");
+               return -EIO;
+       }
+
+       /* Mimimum is IPv4 and IPv6, SIP/DIP */
+       if (!(nfc->data & RXH_IP_SRC) || !(nfc->data & RXH_IP_DST))
+               return -EINVAL;
+
+       switch (nfc->flow_type) {
+       case TCP_V4_FLOW:
+       case TCP_V6_FLOW:
+               /* Different config for v4 and v6 is not supported.
+                * Both of them have to be either 4-tuple or 2-tuple.
+                */
+               switch (nfc->data & rxh_l4) {
+               case 0:
+                       rss_cfg &= ~NIX_FLOW_KEY_TYPE_TCP;
+                       break;
+               case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+                       rss_cfg |= NIX_FLOW_KEY_TYPE_TCP;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case UDP_V4_FLOW:
+       case UDP_V6_FLOW:
+               switch (nfc->data & rxh_l4) {
+               case 0:
+                       rss_cfg &= ~NIX_FLOW_KEY_TYPE_UDP;
+                       break;
+               case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+                       rss_cfg |= NIX_FLOW_KEY_TYPE_UDP;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case SCTP_V4_FLOW:
+       case SCTP_V6_FLOW:
+               switch (nfc->data & rxh_l4) {
+               case 0:
+                       rss_cfg &= ~NIX_FLOW_KEY_TYPE_SCTP;
+                       break;
+               case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+                       rss_cfg |= NIX_FLOW_KEY_TYPE_SCTP;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case IPV4_FLOW:
+       case IPV6_FLOW:
+               rss_cfg = NIX_FLOW_KEY_TYPE_IPV4 | NIX_FLOW_KEY_TYPE_IPV6;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       rss->flowkey_cfg = rss_cfg;
+       otx2_set_flowkey_cfg(pfvf);
+       return 0;
+}
+
+static int otx2_get_rxnfc(struct net_device *dev,
+                         struct ethtool_rxnfc *nfc, u32 *rules)
+{
+       struct otx2_nic *pfvf = netdev_priv(dev);
+       int ret = -EOPNOTSUPP;
+
+       switch (nfc->cmd) {
+       case ETHTOOL_GRXRINGS:
+               nfc->data = pfvf->hw.rx_queues;
+               ret = 0;
+               break;
+       case ETHTOOL_GRXFH:
+               return otx2_get_rss_hash_opts(pfvf, nfc);
+       default:
+               break;
+       }
+       return ret;
+}
+
+static int otx2_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *nfc)
+{
+       struct otx2_nic *pfvf = netdev_priv(dev);
+       int ret = -EOPNOTSUPP;
+
+       switch (nfc->cmd) {
+       case ETHTOOL_SRXFH:
+               ret = otx2_set_rss_hash_opts(pfvf, nfc);
+               break;
+       default:
+               break;
+       }
+
+       return ret;
+}
+
+static u32 otx2_get_rxfh_key_size(struct net_device *netdev)
+{
+       struct otx2_nic *pfvf = netdev_priv(netdev);
+       struct otx2_rss_info *rss;
+
+       rss = &pfvf->hw.rss_info;
+
+       return sizeof(rss->key);
+}
+
+static u32 otx2_get_rxfh_indir_size(struct net_device *dev)
+{
+       struct otx2_nic *pfvf = netdev_priv(dev);
+
+       return pfvf->hw.rss_info.rss_size;
+}
+
+/* Get RSS configuration */
+static int otx2_get_rxfh(struct net_device *dev, u32 *indir,
+                        u8 *hkey, u8 *hfunc)
+{
+       struct otx2_nic *pfvf = netdev_priv(dev);
+       struct otx2_rss_info *rss;
+       int idx;
+
+       rss = &pfvf->hw.rss_info;
+
+       if (indir) {
+               for (idx = 0; idx < rss->rss_size; idx++)
+                       indir[idx] = rss->ind_tbl[idx];
+       }
+
+       if (hkey)
+               memcpy(hkey, rss->key, sizeof(rss->key));
+
+       if (hfunc)
+               *hfunc = ETH_RSS_HASH_TOP;
+
+       return 0;
+}
+
+/* Configure RSS table and hash key */
+static int otx2_set_rxfh(struct net_device *dev, const u32 *indir,
+                        const u8 *hkey, const u8 hfunc)
+{
+       struct otx2_nic *pfvf = netdev_priv(dev);
+       struct otx2_rss_info *rss;
+       int idx;
+
+       if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
+               return -EOPNOTSUPP;
+
+       rss = &pfvf->hw.rss_info;
+
+       if (!rss->enable) {
+               netdev_err(dev, "RSS is disabled, cannot change settings\n");
+               return -EIO;
+       }
+
+       if (indir) {
+               for (idx = 0; idx < rss->rss_size; idx++)
+                       rss->ind_tbl[idx] = indir[idx];
+       }
+
+       if (hkey) {
+               memcpy(rss->key, hkey, sizeof(rss->key));
+               otx2_set_rss_key(pfvf);
+       }
+
+       otx2_set_rss_table(pfvf);
+       return 0;
+}
+
+static u32 otx2_get_msglevel(struct net_device *netdev)
+{
+       struct otx2_nic *pfvf = netdev_priv(netdev);
+
+       return pfvf->msg_enable;
+}
+
+static void otx2_set_msglevel(struct net_device *netdev, u32 val)
+{
+       struct otx2_nic *pfvf = netdev_priv(netdev);
+
+       pfvf->msg_enable = val;
+}
+
+static u32 otx2_get_link(struct net_device *netdev)
+{
+       struct otx2_nic *pfvf = netdev_priv(netdev);
+
+       return pfvf->linfo.link_up;
+}
+
 static const struct ethtool_ops otx2_ethtool_ops = {
+       .get_link               = otx2_get_link,
        .get_drvinfo            = otx2_get_drvinfo,
        .get_strings            = otx2_get_strings,
        .get_ethtool_stats      = otx2_get_ethtool_stats,
@@ -400,6 +646,14 @@ static const struct ethtool_ops otx2_ethtool_ops = {
        .set_ringparam          = otx2_set_ringparam,
        .get_coalesce           = otx2_get_coalesce,
        .set_coalesce           = otx2_set_coalesce,
+       .get_rxnfc              = otx2_get_rxnfc,
+       .set_rxnfc              = otx2_set_rxnfc,
+       .get_rxfh_key_size      = otx2_get_rxfh_key_size,
+       .get_rxfh_indir_size    = otx2_get_rxfh_indir_size,
+       .get_rxfh               = otx2_get_rxfh,
+       .set_rxfh               = otx2_set_rxfh,
+       .get_msglevel           = otx2_get_msglevel,
+       .set_msglevel           = otx2_set_msglevel,
 };
 
 void otx2_set_ethtool_ops(struct net_device *netdev)
index 6a7ca3b4b9be44688c3493205e2be3d1173bc973..bef4c20fe314c1f86d964a29fe218836aeabaf84 100644 (file)
@@ -84,7 +84,7 @@ static void otx2_snd_pkt_handler(struct otx2_nic *pfvf,
        struct sk_buff *skb = NULL;
        struct sg_list *sg;
 
-       if (unlikely(snd_comp->status))
+       if (unlikely(snd_comp->status) && netif_msg_tx_err(pfvf))
                net_err_ratelimited("%s: TX%d: Error in send CQ status:%x\n",
                                    pfvf->netdev->name, cq->cint_idx,
                                    snd_comp->status);
@@ -144,6 +144,11 @@ static bool otx2_check_rcv_errors(struct otx2_nic *pfvf,
        struct otx2_drv_stats *stats = &pfvf->hw.drv_stats;
        struct nix_rx_parse_s *parse = &cqe->parse;
 
+       if (netif_msg_rx_err(pfvf))
+               netdev_err(pfvf->netdev,
+                          "RQ%d: Error pkt with errlev:0x%x errcode:0x%x\n",
+                          qidx, parse->errlev, parse->errcode);
+
        if (parse->errlev == NPC_ERRLVL_RE) {
                switch (parse->errcode) {
                case ERRCODE_FCS: