octeontx2-pf: Receive side scaling support
authorSunil Goutham <sgoutham@marvell.com>
Mon, 27 Jan 2020 13:05:25 +0000 (18:35 +0530)
committerDavid S. Miller <davem@davemloft.net>
Mon, 27 Jan 2020 13:33:39 +0000 (14:33 +0100)
Adds receive side scaling (RSS) support to distribute
pkts/flows across multiple queues. Sets up key, indirection
table etc. Also added extraction of HW calculated rxhash and
adding to same to SKB ie NETIF_F_RXHASH offload support.

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_pf.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c

index 2b50306..9675158 100644 (file)
@@ -106,6 +106,126 @@ int otx2_hw_set_mtu(struct otx2_nic *pfvf, int mtu)
        return err;
 }
 
+static int otx2_set_flowkey_cfg(struct otx2_nic *pfvf)
+{
+       struct otx2_rss_info *rss = &pfvf->hw.rss_info;
+       struct nix_rss_flowkey_cfg *req;
+       int err;
+
+       otx2_mbox_lock(&pfvf->mbox);
+       req = otx2_mbox_alloc_msg_nix_rss_flowkey_cfg(&pfvf->mbox);
+       if (!req) {
+               otx2_mbox_unlock(&pfvf->mbox);
+               return -ENOMEM;
+       }
+       req->mcam_index = -1; /* Default or reserved index */
+       req->flowkey_cfg = rss->flowkey_cfg;
+       req->group = DEFAULT_RSS_CONTEXT_GROUP;
+
+       err = otx2_sync_mbox_msg(&pfvf->mbox);
+       otx2_mbox_unlock(&pfvf->mbox);
+       return err;
+}
+
+static int otx2_set_rss_table(struct otx2_nic *pfvf)
+{
+       struct otx2_rss_info *rss = &pfvf->hw.rss_info;
+       struct mbox *mbox = &pfvf->mbox;
+       struct nix_aq_enq_req *aq;
+       int idx, err;
+
+       otx2_mbox_lock(mbox);
+       /* Get memory to put this msg */
+       for (idx = 0; idx < rss->rss_size; idx++) {
+               aq = otx2_mbox_alloc_msg_nix_aq_enq(mbox);
+               if (!aq) {
+                       /* The shared memory buffer can be full.
+                        * Flush it and retry
+                        */
+                       err = otx2_sync_mbox_msg(mbox);
+                       if (err) {
+                               otx2_mbox_unlock(mbox);
+                               return err;
+                       }
+                       aq = otx2_mbox_alloc_msg_nix_aq_enq(mbox);
+                       if (!aq) {
+                               otx2_mbox_unlock(mbox);
+                               return -ENOMEM;
+                       }
+               }
+
+               aq->rss.rq = rss->ind_tbl[idx];
+
+               /* Fill AQ info */
+               aq->qidx = idx;
+               aq->ctype = NIX_AQ_CTYPE_RSS;
+               aq->op = NIX_AQ_INSTOP_INIT;
+       }
+       err = otx2_sync_mbox_msg(mbox);
+       otx2_mbox_unlock(mbox);
+       return err;
+}
+
+static void otx2_set_rss_key(struct otx2_nic *pfvf)
+{
+       struct otx2_rss_info *rss = &pfvf->hw.rss_info;
+       u64 *key = (u64 *)&rss->key[4];
+       int idx;
+
+       /* 352bit or 44byte key needs to be configured as below
+        * NIX_LF_RX_SECRETX0 = key<351:288>
+        * NIX_LF_RX_SECRETX1 = key<287:224>
+        * NIX_LF_RX_SECRETX2 = key<223:160>
+        * NIX_LF_RX_SECRETX3 = key<159:96>
+        * NIX_LF_RX_SECRETX4 = key<95:32>
+        * NIX_LF_RX_SECRETX5<63:32> = key<31:0>
+        */
+       otx2_write64(pfvf, NIX_LF_RX_SECRETX(5),
+                    (u64)(*((u32 *)&rss->key)) << 32);
+       idx = sizeof(rss->key) / sizeof(u64);
+       while (idx > 0) {
+               idx--;
+               otx2_write64(pfvf, NIX_LF_RX_SECRETX(idx), *key++);
+       }
+}
+
+int otx2_rss_init(struct otx2_nic *pfvf)
+{
+       struct otx2_rss_info *rss = &pfvf->hw.rss_info;
+       int idx, ret = 0;
+
+       rss->rss_size = sizeof(rss->ind_tbl);
+
+       /* Init RSS key if it is not setup already */
+       if (!rss->enable)
+               netdev_rss_key_fill(rss->key, sizeof(rss->key));
+       otx2_set_rss_key(pfvf);
+
+       if (!netif_is_rxfh_configured(pfvf->netdev)) {
+               /* Default indirection table */
+               for (idx = 0; idx < rss->rss_size; idx++)
+                       rss->ind_tbl[idx] =
+                               ethtool_rxfh_indir_default(idx,
+                                                          pfvf->hw.rx_queues);
+       }
+       ret = otx2_set_rss_table(pfvf);
+       if (ret)
+               return ret;
+
+       /* Flowkey or hash config to be used for generating flow tag */
+       rss->flowkey_cfg = rss->enable ? rss->flowkey_cfg :
+                          NIX_FLOW_KEY_TYPE_IPV4 | NIX_FLOW_KEY_TYPE_IPV6 |
+                          NIX_FLOW_KEY_TYPE_TCP | NIX_FLOW_KEY_TYPE_UDP |
+                          NIX_FLOW_KEY_TYPE_SCTP;
+
+       ret = otx2_set_flowkey_cfg(pfvf);
+       if (ret)
+               return ret;
+
+       rss->enable = true;
+       return 0;
+}
+
 void otx2_config_irq_coalescing(struct otx2_nic *pfvf, int qidx)
 {
        /* Configure CQE interrupt coalescing parameters
@@ -608,6 +728,8 @@ int otx2_config_nix(struct otx2_nic *pfvf)
        nixlf->rq_cnt = pfvf->hw.rx_queues;
        nixlf->sq_cnt = pfvf->hw.tx_queues;
        nixlf->cq_cnt = pfvf->qset.cq_cnt;
+       nixlf->rss_sz = MAX_RSS_INDIR_TBL_SIZE;
+       nixlf->rss_grps = 1; /* Single RSS indir table supported, for now */
        nixlf->xqe_sz = NIX_XQESZ_W16;
        /* We don't know absolute NPA LF idx attached.
         * AF will replace 'RVU_DEFAULT_PF_FUNC' with
index 2a81211..f9149ef 100644 (file)
@@ -41,6 +41,16 @@ enum arua_mapped_qtypes {
 #define NIX_LF_ERR_VEC                         0x81
 #define NIX_LF_POISON_VEC                      0x82
 
+/* RSS configuration */
+struct otx2_rss_info {
+       u8 enable;
+       u32 flowkey_cfg;
+       u16 rss_size;
+       u8  ind_tbl[MAX_RSS_INDIR_TBL_SIZE];
+#define RSS_HASH_KEY_SIZE      44   /* 352 bit key */
+       u8  key[RSS_HASH_KEY_SIZE];
+};
+
 /* NIX (or NPC) RX errors */
 enum otx2_errlvl {
        NPC_ERRLVL_RE,
@@ -95,6 +105,7 @@ struct mbox {
 
 struct otx2_hw {
        struct pci_dev          *pdev;
+       struct otx2_rss_info    rss_info;
        u16                     rx_queues;
        u16                     tx_queues;
        u16                     max_queues;
@@ -510,6 +521,9 @@ void otx2_ctx_disable(struct mbox *mbox, int type, bool npa);
 void otx2_cleanup_rx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq);
 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);
+
 /* Mbox handlers */
 void mbox_handler_msix_offset(struct otx2_nic *pfvf,
                              struct msix_offset_rsp *rsp);
index 171bab0..5f78215 100644 (file)
@@ -838,6 +838,11 @@ int otx2_open(struct net_device *netdev)
        if (err)
                goto err_disable_napi;
 
+       /* Initialize RSS */
+       err = otx2_rss_init(pf);
+       if (err)
+               goto err_disable_napi;
+
        /* Register Queue IRQ handlers */
        vec = pf->hw.nix_msixoff + NIX_LF_QINT_VEC_START;
        irq_name = &pf->hw.irq_name[vec * NAME_SIZE];
@@ -1237,7 +1242,8 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        pf->iommu_domain = iommu_get_domain_for_dev(dev);
 
        netdev->hw_features = (NETIF_F_RXCSUM | NETIF_F_IP_CSUM |
-                              NETIF_F_IPV6_CSUM | NETIF_F_SG);
+                              NETIF_F_IPV6_CSUM | NETIF_F_RXHASH |
+                              NETIF_F_SG);
        netdev->features |= netdev->hw_features;
 
        netdev->hw_features |= NETIF_F_LOOPBACK | NETIF_F_RXALL;
index 94dac84..513b126 100644 (file)
@@ -115,6 +115,28 @@ static void otx2_skb_add_frag(struct otx2_nic *pfvf, struct sk_buff *skb,
                            pfvf->rbsize, DMA_FROM_DEVICE);
 }
 
+static void otx2_set_rxhash(struct otx2_nic *pfvf,
+                           struct nix_cqe_rx_s *cqe, struct sk_buff *skb)
+{
+       enum pkt_hash_types hash_type = PKT_HASH_TYPE_NONE;
+       struct otx2_rss_info *rss;
+       u32 hash = 0;
+
+       if (!(pfvf->netdev->features & NETIF_F_RXHASH))
+               return;
+
+       rss = &pfvf->hw.rss_info;
+       if (rss->flowkey_cfg) {
+               if (rss->flowkey_cfg &
+                   ~(NIX_FLOW_KEY_TYPE_IPV4 | NIX_FLOW_KEY_TYPE_IPV6))
+                       hash_type = PKT_HASH_TYPE_L4;
+               else
+                       hash_type = PKT_HASH_TYPE_L3;
+               hash = cqe->hdr.flow_tag;
+       }
+       skb_set_hash(skb, hash, hash_type);
+}
+
 static bool otx2_check_rcv_errors(struct otx2_nic *pfvf,
                                  struct nix_cqe_rx_s *cqe, int qidx)
 {
@@ -194,6 +216,8 @@ static void otx2_rcv_pkt_handler(struct otx2_nic *pfvf,
        otx2_skb_add_frag(pfvf, skb, cqe->sg.seg_addr, cqe->sg.seg_size);
        cq->pool_ptrs++;
 
+       otx2_set_rxhash(pfvf, cqe, skb);
+
        skb_record_rx_queue(skb, cq->cq_idx);
        if (pfvf->netdev->features & NETIF_F_RXCSUM)
                skb->ip_summed = CHECKSUM_UNNECESSARY;