]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
octeontx2-pf: Create representor netdev
authorGeetha sowjanya <gakula@marvell.com>
Thu, 7 Nov 2024 16:08:29 +0000 (21:38 +0530)
committerDavid S. Miller <davem@davemloft.net>
Wed, 13 Nov 2024 11:57:11 +0000 (11:57 +0000)
Adds initial devlink support to set/get the switchdev mode.
Representor netdevs are created for each rvu devices when
the switch mode is set to 'switchdev'. These netdevs are
be used to control and configure VFs.

Signed-off-by: Geetha sowjanya <gakula@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_devlink.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
drivers/net/ethernet/marvell/octeontx2/nic/rep.c
drivers/net/ethernet/marvell/octeontx2/nic/rep.h

index 6e0183f0d5a12fb6784ab16d535d7e9ca98877a8..8b6e60dde684646d19aa4e1d641e15d260361afc 100644 (file)
@@ -246,6 +246,7 @@ int otx2_hw_set_mtu(struct otx2_nic *pfvf, int mtu)
        mutex_unlock(&pfvf->mbox.lock);
        return err;
 }
+EXPORT_SYMBOL(otx2_hw_set_mtu);
 
 int otx2_config_pause_frm(struct otx2_nic *pfvf)
 {
@@ -1782,6 +1783,7 @@ void otx2_free_cints(struct otx2_nic *pfvf, int n)
                free_irq(vector, &qset->napi[qidx]);
        }
 }
+EXPORT_SYMBOL(otx2_free_cints);
 
 void otx2_set_cints_affinity(struct otx2_nic *pfvf)
 {
index 53f14aa944bdba96c6de0fc37ed4b21525299781..33ec9a7f7c0339dabbc761619f4fdaaf0de5df12 100644 (file)
@@ -141,7 +141,56 @@ static const struct devlink_param otx2_dl_params[] = {
                             otx2_dl_ucast_flt_cnt_validate),
 };
 
+#ifdef CONFIG_RVU_ESWITCH
+static int otx2_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
+{
+       struct otx2_devlink *otx2_dl = devlink_priv(devlink);
+       struct otx2_nic *pfvf = otx2_dl->pfvf;
+
+       if (!otx2_rep_dev(pfvf->pdev))
+               return -EOPNOTSUPP;
+
+       *mode = pfvf->esw_mode;
+
+       return 0;
+}
+
+static int otx2_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
+                                        struct netlink_ext_ack *extack)
+{
+       struct otx2_devlink *otx2_dl = devlink_priv(devlink);
+       struct otx2_nic *pfvf = otx2_dl->pfvf;
+       int ret = 0;
+
+       if (!otx2_rep_dev(pfvf->pdev))
+               return -EOPNOTSUPP;
+
+       if (pfvf->esw_mode == mode)
+               return 0;
+
+       switch (mode) {
+       case DEVLINK_ESWITCH_MODE_LEGACY:
+               rvu_rep_destroy(pfvf);
+               break;
+       case DEVLINK_ESWITCH_MODE_SWITCHDEV:
+               ret = rvu_rep_create(pfvf, extack);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (!ret)
+               pfvf->esw_mode = mode;
+
+       return ret;
+}
+#endif
+
 static const struct devlink_ops otx2_devlink_ops = {
+#ifdef CONFIG_RVU_ESWITCH
+       .eswitch_mode_get = otx2_devlink_eswitch_mode_get,
+       .eswitch_mode_set = otx2_devlink_eswitch_mode_set,
+#endif
 };
 
 int otx2_register_dl(struct otx2_nic *pfvf)
index 8905cc6413acf1a1130e5493cc548e391767be32..c35327a10bc9fd2c2e73787e19183697fc8eb6f1 100644 (file)
@@ -1400,6 +1400,7 @@ irqreturn_t otx2_cq_intr_handler(int irq, void *cq_irq)
 
        return IRQ_HANDLED;
 }
+EXPORT_SYMBOL(otx2_cq_intr_handler);
 
 void otx2_disable_napi(struct otx2_nic *pf)
 {
@@ -1417,6 +1418,7 @@ void otx2_disable_napi(struct otx2_nic *pf)
                netif_napi_del(&cq_poll->napi);
        }
 }
+EXPORT_SYMBOL(otx2_disable_napi);
 
 static void otx2_free_cq_res(struct otx2_nic *pf)
 {
@@ -1607,6 +1609,7 @@ exit:
        mutex_unlock(&mbox->lock);
        return err;
 }
+EXPORT_SYMBOL(otx2_init_hw_resources);
 
 void otx2_free_hw_resources(struct otx2_nic *pf)
 {
@@ -1696,6 +1699,7 @@ void otx2_free_hw_resources(struct otx2_nic *pf)
        }
        mutex_unlock(&mbox->lock);
 }
+EXPORT_SYMBOL(otx2_free_hw_resources);
 
 static bool otx2_promisc_use_mce_list(struct otx2_nic *pfvf)
 {
@@ -1789,6 +1793,7 @@ void otx2_free_queue_mem(struct otx2_qset *qset)
        kfree(qset->napi);
        qset->napi = NULL;
 }
+EXPORT_SYMBOL(otx2_free_queue_mem);
 
 int otx2_alloc_queue_mem(struct otx2_nic *pf)
 {
@@ -1835,6 +1840,7 @@ err_free_mem:
        otx2_free_queue_mem(qset);
        return -ENOMEM;
 }
+EXPORT_SYMBOL(otx2_alloc_queue_mem);
 
 int otx2_open(struct net_device *netdev)
 {
@@ -2866,6 +2872,7 @@ int otx2_realloc_msix_vectors(struct otx2_nic *pf)
 
        return otx2_register_mbox_intr(pf, false);
 }
+EXPORT_SYMBOL(otx2_realloc_msix_vectors);
 
 static int otx2_sriov_vfcfg_init(struct otx2_nic *pf)
 {
index 7aaf32e9aa95e74472956e45c6ba10230dabdfe0..9b4e4c5b146833065cc90ac987e8d49d5a4bc60f 100644 (file)
@@ -594,6 +594,7 @@ int otx2_napi_handler(struct napi_struct *napi, int budget)
        }
        return workdone;
 }
+EXPORT_SYMBOL(otx2_napi_handler);
 
 void otx2_sqe_flush(void *dev, struct otx2_snd_queue *sq,
                    int size, int qidx)
index 284bceef448a4a25acea53963814f1440895a8c1..fda01a485b617772d265d534906e37dc6fb8b236 100644 (file)
@@ -28,6 +28,222 @@ MODULE_DESCRIPTION(DRV_STRING);
 MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, rvu_rep_id_table);
 
+static int rvu_rep_napi_init(struct otx2_nic *priv,
+                            struct netlink_ext_ack *extack)
+{
+       struct otx2_qset *qset = &priv->qset;
+       struct otx2_cq_poll *cq_poll = NULL;
+       struct otx2_hw *hw = &priv->hw;
+       int err = 0, qidx, vec;
+       char *irq_name;
+
+       qset->napi = kcalloc(hw->cint_cnt, sizeof(*cq_poll), GFP_KERNEL);
+       if (!qset->napi)
+               return -ENOMEM;
+
+       /* Register NAPI handler */
+       for (qidx = 0; qidx < hw->cint_cnt; qidx++) {
+               cq_poll = &qset->napi[qidx];
+               cq_poll->cint_idx = qidx;
+               cq_poll->cq_ids[CQ_RX] =
+                       (qidx <  hw->rx_queues) ? qidx : CINT_INVALID_CQ;
+               cq_poll->cq_ids[CQ_TX] = (qidx < hw->tx_queues) ?
+                                         qidx + hw->rx_queues :
+                                         CINT_INVALID_CQ;
+               cq_poll->cq_ids[CQ_XDP] = CINT_INVALID_CQ;
+               cq_poll->cq_ids[CQ_QOS] = CINT_INVALID_CQ;
+
+               cq_poll->dev = (void *)priv;
+               netif_napi_add(priv->reps[qidx]->netdev, &cq_poll->napi,
+                              otx2_napi_handler);
+               napi_enable(&cq_poll->napi);
+       }
+       /* Register CQ IRQ handlers */
+       vec = hw->nix_msixoff + NIX_LF_CINT_VEC_START;
+       for (qidx = 0; qidx < hw->cint_cnt; qidx++) {
+               irq_name = &hw->irq_name[vec * NAME_SIZE];
+
+               snprintf(irq_name, NAME_SIZE, "rep%d-rxtx-%d", qidx, qidx);
+
+               err = request_irq(pci_irq_vector(priv->pdev, vec),
+                                 otx2_cq_intr_handler, 0, irq_name,
+                                 &qset->napi[qidx]);
+               if (err) {
+                       NL_SET_ERR_MSG_FMT_MOD(extack,
+                                              "RVU REP IRQ registration failed for CQ%d",
+                                              qidx);
+                       goto err_free_cints;
+               }
+               vec++;
+
+               /* Enable CQ IRQ */
+               otx2_write64(priv, NIX_LF_CINTX_INT(qidx), BIT_ULL(0));
+               otx2_write64(priv, NIX_LF_CINTX_ENA_W1S(qidx), BIT_ULL(0));
+       }
+       priv->flags &= ~OTX2_FLAG_INTF_DOWN;
+       return 0;
+
+err_free_cints:
+       otx2_free_cints(priv, qidx);
+       otx2_disable_napi(priv);
+       return err;
+}
+
+static void rvu_rep_free_cq_rsrc(struct otx2_nic *priv)
+{
+       struct otx2_qset *qset = &priv->qset;
+       struct otx2_cq_poll *cq_poll = NULL;
+       int qidx, vec;
+
+       /* Cleanup CQ NAPI and IRQ */
+       vec = priv->hw.nix_msixoff + NIX_LF_CINT_VEC_START;
+       for (qidx = 0; qidx < priv->hw.cint_cnt; qidx++) {
+               /* Disable interrupt */
+               otx2_write64(priv, NIX_LF_CINTX_ENA_W1C(qidx), BIT_ULL(0));
+
+               synchronize_irq(pci_irq_vector(priv->pdev, vec));
+
+               cq_poll = &qset->napi[qidx];
+               napi_synchronize(&cq_poll->napi);
+               vec++;
+       }
+       otx2_free_cints(priv, priv->hw.cint_cnt);
+       otx2_disable_napi(priv);
+}
+
+static void rvu_rep_rsrc_free(struct otx2_nic *priv)
+{
+       struct otx2_qset *qset = &priv->qset;
+       struct delayed_work *work;
+       int wrk;
+
+       for (wrk = 0; wrk < priv->qset.cq_cnt; wrk++) {
+               work = &priv->refill_wrk[wrk].pool_refill_work;
+               cancel_delayed_work_sync(work);
+       }
+       devm_kfree(priv->dev, priv->refill_wrk);
+
+       otx2_free_hw_resources(priv);
+       otx2_free_queue_mem(qset);
+}
+
+static int rvu_rep_rsrc_init(struct otx2_nic *priv)
+{
+       struct otx2_qset *qset = &priv->qset;
+       int err;
+
+       err = otx2_alloc_queue_mem(priv);
+       if (err)
+               return err;
+
+       priv->hw.max_mtu = otx2_get_max_mtu(priv);
+       priv->tx_max_pktlen = priv->hw.max_mtu + OTX2_ETH_HLEN;
+       priv->rbsize = ALIGN(priv->hw.rbuf_len, OTX2_ALIGN) + OTX2_HEAD_ROOM;
+
+       err = otx2_init_hw_resources(priv);
+       if (err)
+               goto err_free_rsrc;
+
+       /* Set maximum frame size allowed in HW */
+       err = otx2_hw_set_mtu(priv, priv->hw.max_mtu);
+       if (err) {
+               dev_err(priv->dev, "Failed to set HW MTU\n");
+               goto err_free_rsrc;
+       }
+       return 0;
+
+err_free_rsrc:
+       otx2_free_hw_resources(priv);
+       otx2_free_queue_mem(qset);
+       return err;
+}
+
+void rvu_rep_destroy(struct otx2_nic *priv)
+{
+       struct rep_dev *rep;
+       int rep_id;
+
+       priv->flags |= OTX2_FLAG_INTF_DOWN;
+       rvu_rep_free_cq_rsrc(priv);
+       for (rep_id = 0; rep_id < priv->rep_cnt; rep_id++) {
+               rep = priv->reps[rep_id];
+               unregister_netdev(rep->netdev);
+               free_netdev(rep->netdev);
+       }
+       kfree(priv->reps);
+       rvu_rep_rsrc_free(priv);
+}
+
+int rvu_rep_create(struct otx2_nic *priv, struct netlink_ext_ack *extack)
+{
+       int rep_cnt = priv->rep_cnt;
+       struct net_device *ndev;
+       struct rep_dev *rep;
+       int rep_id, err;
+       u16 pcifunc;
+
+       err = rvu_rep_rsrc_init(priv);
+       if (err)
+               return -ENOMEM;
+
+       priv->reps = kcalloc(rep_cnt, sizeof(struct rep_dev *), GFP_KERNEL);
+       if (!priv->reps)
+               return -ENOMEM;
+
+       for (rep_id = 0; rep_id < rep_cnt; rep_id++) {
+               ndev = alloc_etherdev(sizeof(*rep));
+               if (!ndev) {
+                       NL_SET_ERR_MSG_FMT_MOD(extack,
+                                              "PFVF representor:%d creation failed",
+                                              rep_id);
+                       err = -ENOMEM;
+                       goto exit;
+               }
+
+               rep = netdev_priv(ndev);
+               priv->reps[rep_id] = rep;
+               rep->mdev = priv;
+               rep->netdev = ndev;
+               rep->rep_id = rep_id;
+
+               ndev->min_mtu = OTX2_MIN_MTU;
+               ndev->max_mtu = priv->hw.max_mtu;
+               pcifunc = priv->rep_pf_map[rep_id];
+               rep->pcifunc = pcifunc;
+
+               snprintf(ndev->name, sizeof(ndev->name), "Rpf%dvf%d",
+                        rvu_get_pf(pcifunc), (pcifunc & RVU_PFVF_FUNC_MASK));
+
+               ndev->hw_features = (NETIF_F_RXCSUM | NETIF_F_IP_CSUM |
+                              NETIF_F_IPV6_CSUM | NETIF_F_RXHASH |
+                              NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6);
+
+               ndev->features |= ndev->hw_features;
+               eth_hw_addr_random(ndev);
+               err = register_netdev(ndev);
+               if (err) {
+                       NL_SET_ERR_MSG_MOD(extack,
+                                          "PFVF reprentator registration failed");
+                       free_netdev(ndev);
+                       goto exit;
+               }
+       }
+       err = rvu_rep_napi_init(priv, extack);
+       if (err)
+               goto exit;
+
+       return 0;
+exit:
+       while (--rep_id >= 0) {
+               rep = priv->reps[rep_id];
+               unregister_netdev(rep->netdev);
+               free_netdev(rep->netdev);
+       }
+       kfree(priv->reps);
+       rvu_rep_rsrc_free(priv);
+       return err;
+}
+
 static int rvu_get_rep_cnt(struct otx2_nic *priv)
 {
        struct get_rep_cnt_rsp *rsp;
@@ -118,6 +334,10 @@ static int rvu_rep_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        if (err)
                goto err_detach_rsrc;
 
+       err = otx2_register_dl(priv);
+       if (err)
+               goto err_detach_rsrc;
+
        return 0;
 
 err_detach_rsrc:
@@ -139,6 +359,9 @@ static void rvu_rep_remove(struct pci_dev *pdev)
 {
        struct otx2_nic *priv = pci_get_drvdata(pdev);
 
+       otx2_unregister_dl(priv);
+       if (!(priv->flags & OTX2_FLAG_INTF_DOWN))
+               rvu_rep_destroy(priv);
        otx2_detach_resources(&priv->mbox);
        if (priv->hw.lmt_info)
                free_percpu(priv->hw.lmt_info);
index 565e75628df226c5867719eae320ba8c1172d899..c04874c4d4c604c8ed365e80a62cc1a24985a997 100644 (file)
@@ -28,4 +28,7 @@ static inline bool otx2_rep_dev(struct pci_dev *pdev)
 {
        return pdev->device == PCI_DEVID_RVU_REP;
 }
+
+int rvu_rep_create(struct otx2_nic *priv, struct netlink_ext_ack *extack);
+void rvu_rep_destroy(struct otx2_nic *priv);
 #endif /* REP_H */