[net-next PATCH 3/9] octeontx2-pf: Create representor netdev

Geetha sowjanya posted 9 patches 1 year, 10 months ago
There is a newer version of this series
[net-next PATCH 3/9] octeontx2-pf: Create representor netdev
Posted by Geetha sowjanya 1 year, 10 months ago
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>
---
 .../marvell/octeontx2/nic/otx2_devlink.c      |  48 ++++++
 .../net/ethernet/marvell/octeontx2/nic/rep.c  | 159 ++++++++++++++++++
 .../net/ethernet/marvell/octeontx2/nic/rep.h  |   2 +
 3 files changed, 209 insertions(+)

diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c
index 4e1130496573..f4f5f5d93c7e 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c
@@ -76,7 +76,53 @@ static const struct devlink_param otx2_dl_params[] = {
 			     otx2_dl_mcam_count_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 (!is_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;
+
+	if (!is_rep_dev(pfvf->pdev))
+		return -EOPNOTSUPP;
+
+	if (pfvf->esw_mode == mode)
+		return 0;
+
+	pfvf->esw_mode = mode;
+	switch (mode) {
+	case DEVLINK_ESWITCH_MODE_LEGACY:
+		rvu_rep_destroy(pfvf);
+		break;
+	case DEVLINK_ESWITCH_MODE_SWITCHDEV:
+		rvu_rep_create(pfvf);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+#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)
@@ -112,6 +158,7 @@ int otx2_register_dl(struct otx2_nic *pfvf)
 	devlink_free(dl);
 	return err;
 }
+EXPORT_SYMBOL(otx2_register_dl);
 
 void otx2_unregister_dl(struct otx2_nic *pfvf)
 {
@@ -123,3 +170,4 @@ void otx2_unregister_dl(struct otx2_nic *pfvf)
 				  ARRAY_SIZE(otx2_dl_params));
 	devlink_free(dl);
 }
+EXPORT_SYMBOL(otx2_unregister_dl);
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/rep.c b/drivers/net/ethernet/marvell/octeontx2/nic/rep.c
index b892a7fe3ddc..fd55ef40c934 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/rep.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/rep.c
@@ -28,6 +28,159 @@ 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 otx2_cq_poll *cq_poll = NULL;
+	struct otx2_qset *qset = &priv->qset;
+	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) {
+			dev_err(priv->dev,
+				"RVU REP IRQ registration failed for CQ%d\n", 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_cq_poll *cq_poll = NULL;
+	struct otx2_qset *qset = &priv->qset;
+	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_free_netdev(struct otx2_nic *priv)
+{
+	struct rep_dev *rep;
+	int rep_id;
+
+	for (rep_id = 0; rep_id < priv->rep_cnt; rep_id++) {
+		rep = priv->reps[rep_id];
+		if (rep && rep->netdev->netdev_ops) {
+			unregister_netdev(rep->netdev);
+			free_netdev(rep->netdev);
+		}
+	}
+	devm_kfree(priv->dev, priv->reps);
+}
+
+void rvu_rep_destroy(struct otx2_nic *priv)
+{
+	rvu_rep_free_cq_rsrc(priv);
+	rvu_rep_free_netdev(priv);
+}
+
+int rvu_rep_create(struct otx2_nic *priv)
+{
+	int rep_cnt = priv->rep_cnt;
+	struct net_device *ndev;
+	struct rep_dev *rep;
+	int rep_id, err;
+	u16 pcifunc;
+
+	priv->reps = devm_kcalloc(priv->dev, 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) {
+			dev_err(priv->dev, "PFVF representor:%d creation failed\n", 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), "r%dp%dv%d", rep_id,
+			 rvu_get_pf(pcifunc), (pcifunc & RVU_PFVF_FUNC_MASK));
+
+		eth_hw_addr_random(ndev);
+		if (register_netdev(ndev)) {
+			dev_err(priv->dev, "PFVF reprentator registration failed\n");
+			free_netdev(ndev);
+			ndev->netdev_ops = NULL;
+			goto exit;
+		}
+	}
+	err = rvu_rep_napi_init(priv);
+	if (err)
+		goto exit;
+
+	return 0;
+exit:
+	rvu_rep_free_netdev(priv);
+	return err;
+}
+
 static int rvu_rep_rsrc_free(struct otx2_nic *priv)
 {
 	struct otx2_qset *qset = &priv->qset;
@@ -162,6 +315,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:
@@ -183,6 +340,8 @@ static void rvu_rep_remove(struct pci_dev *pdev)
 {
 	struct otx2_nic *priv = pci_get_drvdata(pdev);
 
+	otx2_unregister_dl(priv);
+	rvu_rep_destroy(priv);
 	rvu_rep_rsrc_free(priv);
 	otx2_detach_resources(&priv->mbox);
 	if (priv->hw.lmt_info)
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/rep.h b/drivers/net/ethernet/marvell/octeontx2/nic/rep.h
index 30cce17eb48b..be6c939e5cba 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/rep.h
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/rep.h
@@ -29,4 +29,6 @@ static inline bool is_rep_dev(struct pci_dev *pdev)
 	return pdev->device == PCI_DEVID_RVU_REP;
 }
 
+int rvu_rep_create(struct otx2_nic *priv);
+void rvu_rep_destroy(struct otx2_nic *priv);
 #endif /* REP_H */
-- 
2.25.1
Re: [net-next PATCH 3/9] octeontx2-pf: Create representor netdev
Posted by Dan Carpenter 1 year, 10 months ago
Hi Geetha,

kernel test robot noticed the following build warnings:

url:    https://github.com/intel-lab-lkp/linux/commits/Geetha-sowjanya/octeontx2-pf-Refactoring-RVU-driver/20240416-131052
base:   net-next/main
patch link:    https://lore.kernel.org/r/20240416050616.6056-4-gakula%40marvell.com
patch subject: [net-next PATCH 3/9] octeontx2-pf: Create representor netdev
config: alpha-randconfig-r081-20240417 (https://download.01.org/0day-ci/archive/20240417/202404172208.4REfSKKS-lkp@intel.com/config)
compiler: alpha-linux-gcc (GCC) 13.2.0

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
| Closes: https://lore.kernel.org/r/202404172208.4REfSKKS-lkp@intel.com/

New smatch warnings:
drivers/net/ethernet/marvell/octeontx2/nic/rep.c:170 rvu_rep_create() error: dereferencing freed memory 'ndev'

vim +/ndev +170 drivers/net/ethernet/marvell/octeontx2/nic/rep.c

f9a5b510759eeb Geetha sowjanya 2024-04-16  131  
f9a5b510759eeb Geetha sowjanya 2024-04-16  132  int rvu_rep_create(struct otx2_nic *priv)
f9a5b510759eeb Geetha sowjanya 2024-04-16  133  {
f9a5b510759eeb Geetha sowjanya 2024-04-16  134  	int rep_cnt = priv->rep_cnt;
f9a5b510759eeb Geetha sowjanya 2024-04-16  135  	struct net_device *ndev;
f9a5b510759eeb Geetha sowjanya 2024-04-16  136  	struct rep_dev *rep;
f9a5b510759eeb Geetha sowjanya 2024-04-16  137  	int rep_id, err;
f9a5b510759eeb Geetha sowjanya 2024-04-16  138  	u16 pcifunc;
f9a5b510759eeb Geetha sowjanya 2024-04-16  139  
f9a5b510759eeb Geetha sowjanya 2024-04-16  140  	priv->reps = devm_kcalloc(priv->dev, rep_cnt, sizeof(struct rep_dev), GFP_KERNEL);
f9a5b510759eeb Geetha sowjanya 2024-04-16  141  	if (!priv->reps)
f9a5b510759eeb Geetha sowjanya 2024-04-16  142  		return -ENOMEM;
f9a5b510759eeb Geetha sowjanya 2024-04-16  143  
f9a5b510759eeb Geetha sowjanya 2024-04-16  144  	for (rep_id = 0; rep_id < rep_cnt; rep_id++) {
f9a5b510759eeb Geetha sowjanya 2024-04-16  145  		ndev = alloc_etherdev(sizeof(*rep));
f9a5b510759eeb Geetha sowjanya 2024-04-16  146  		if (!ndev) {
f9a5b510759eeb Geetha sowjanya 2024-04-16  147  			dev_err(priv->dev, "PFVF representor:%d creation failed\n", rep_id);
f9a5b510759eeb Geetha sowjanya 2024-04-16  148  			err = -ENOMEM;
f9a5b510759eeb Geetha sowjanya 2024-04-16  149  			goto exit;
f9a5b510759eeb Geetha sowjanya 2024-04-16  150  		}
f9a5b510759eeb Geetha sowjanya 2024-04-16  151  
f9a5b510759eeb Geetha sowjanya 2024-04-16  152  		rep = netdev_priv(ndev);
f9a5b510759eeb Geetha sowjanya 2024-04-16  153  		priv->reps[rep_id] = rep;
f9a5b510759eeb Geetha sowjanya 2024-04-16  154  		rep->mdev = priv;
f9a5b510759eeb Geetha sowjanya 2024-04-16  155  		rep->netdev = ndev;
f9a5b510759eeb Geetha sowjanya 2024-04-16  156  		rep->rep_id = rep_id;
f9a5b510759eeb Geetha sowjanya 2024-04-16  157  
f9a5b510759eeb Geetha sowjanya 2024-04-16  158  		ndev->min_mtu = OTX2_MIN_MTU;
f9a5b510759eeb Geetha sowjanya 2024-04-16  159  		ndev->max_mtu = priv->hw.max_mtu;
f9a5b510759eeb Geetha sowjanya 2024-04-16  160  		pcifunc = priv->rep_pf_map[rep_id];
f9a5b510759eeb Geetha sowjanya 2024-04-16  161  		rep->pcifunc = pcifunc;
f9a5b510759eeb Geetha sowjanya 2024-04-16  162  
f9a5b510759eeb Geetha sowjanya 2024-04-16  163  		snprintf(ndev->name, sizeof(ndev->name), "r%dp%dv%d", rep_id,
f9a5b510759eeb Geetha sowjanya 2024-04-16  164  			 rvu_get_pf(pcifunc), (pcifunc & RVU_PFVF_FUNC_MASK));
f9a5b510759eeb Geetha sowjanya 2024-04-16  165  
f9a5b510759eeb Geetha sowjanya 2024-04-16  166  		eth_hw_addr_random(ndev);
f9a5b510759eeb Geetha sowjanya 2024-04-16  167  		if (register_netdev(ndev)) {

err = register_netdev(ndev);
if (err) {

f9a5b510759eeb Geetha sowjanya 2024-04-16  168  			dev_err(priv->dev, "PFVF reprentator registration failed\n");
f9a5b510759eeb Geetha sowjanya 2024-04-16  169  			free_netdev(ndev);
                                                                                    ^^^^
freed

f9a5b510759eeb Geetha sowjanya 2024-04-16 @170  			ndev->netdev_ops = NULL;
                                                                        ^^^^^^^^^^^^^^^^^^^^^^^
Use after free

f9a5b510759eeb Geetha sowjanya 2024-04-16  171  			goto exit;
f9a5b510759eeb Geetha sowjanya 2024-04-16  172  		}
f9a5b510759eeb Geetha sowjanya 2024-04-16  173  	}
f9a5b510759eeb Geetha sowjanya 2024-04-16  174  	err = rvu_rep_napi_init(priv);
f9a5b510759eeb Geetha sowjanya 2024-04-16  175  	if (err)
f9a5b510759eeb Geetha sowjanya 2024-04-16  176  		goto exit;
f9a5b510759eeb Geetha sowjanya 2024-04-16  177  
f9a5b510759eeb Geetha sowjanya 2024-04-16  178  	return 0;
f9a5b510759eeb Geetha sowjanya 2024-04-16  179  exit:
f9a5b510759eeb Geetha sowjanya 2024-04-16  180  	rvu_rep_free_netdev(priv);

rvu_rep_free_netdev() also calls free_netdev() so it's a double free.  I
would normally write this as:

exit:
	while (--rep_id >= 0) {
		unregister_netdev(priv->reps[rep_id]);
		free_netdev(priv->reps[rep_id]);
	}

	return err;

When you write it that way then rvu_rep_free_netdev() can be made easier
as well:

static void rvu_rep_free_netdev(struct otx2_nic *priv)
{
	int rep_id;

	for (rep_id = 0; rep_id < priv->rep_cnt; rep_id++) {
		unregister_netdev(priv->reps[rep_id]);
		free_netdev(priv->reps[rep_id]);
	}
}

There should be no need to call devm_kfree(priv->dev, priv->reps);.

f9a5b510759eeb Geetha sowjanya 2024-04-16 @181  	return err;
f9a5b510759eeb Geetha sowjanya 2024-04-16  182  }

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Re: [net-next PATCH 3/9] octeontx2-pf: Create representor netdev
Posted by Dan Carpenter 1 year, 10 months ago
On Wed, Apr 17, 2024 at 06:24:13PM +0300, Dan Carpenter wrote:
> f9a5b510759eeb Geetha sowjanya 2024-04-16  132  int rvu_rep_create(struct otx2_nic *priv)
> f9a5b510759eeb Geetha sowjanya 2024-04-16  133  {
> f9a5b510759eeb Geetha sowjanya 2024-04-16  134  	int rep_cnt = priv->rep_cnt;
> f9a5b510759eeb Geetha sowjanya 2024-04-16  135  	struct net_device *ndev;
> f9a5b510759eeb Geetha sowjanya 2024-04-16  136  	struct rep_dev *rep;
> f9a5b510759eeb Geetha sowjanya 2024-04-16  137  	int rep_id, err;
> f9a5b510759eeb Geetha sowjanya 2024-04-16  138  	u16 pcifunc;
> f9a5b510759eeb Geetha sowjanya 2024-04-16  139  
> f9a5b510759eeb Geetha sowjanya 2024-04-16  140  	priv->reps = devm_kcalloc(priv->dev, rep_cnt, sizeof(struct rep_dev), GFP_KERNEL);
> f9a5b510759eeb Geetha sowjanya 2024-04-16  141  	if (!priv->reps)
> f9a5b510759eeb Geetha sowjanya 2024-04-16  142  		return -ENOMEM;
> f9a5b510759eeb Geetha sowjanya 2024-04-16  143  
> f9a5b510759eeb Geetha sowjanya 2024-04-16  144  	for (rep_id = 0; rep_id < rep_cnt; rep_id++) {
> f9a5b510759eeb Geetha sowjanya 2024-04-16  145  		ndev = alloc_etherdev(sizeof(*rep));
> f9a5b510759eeb Geetha sowjanya 2024-04-16  146  		if (!ndev) {
> f9a5b510759eeb Geetha sowjanya 2024-04-16  147  			dev_err(priv->dev, "PFVF representor:%d creation failed\n", rep_id);
> f9a5b510759eeb Geetha sowjanya 2024-04-16  148  			err = -ENOMEM;
> f9a5b510759eeb Geetha sowjanya 2024-04-16  149  			goto exit;
> f9a5b510759eeb Geetha sowjanya 2024-04-16  150  		}
> f9a5b510759eeb Geetha sowjanya 2024-04-16  151  
> f9a5b510759eeb Geetha sowjanya 2024-04-16  152  		rep = netdev_priv(ndev);
> f9a5b510759eeb Geetha sowjanya 2024-04-16  153  		priv->reps[rep_id] = rep;
> f9a5b510759eeb Geetha sowjanya 2024-04-16  154  		rep->mdev = priv;
> f9a5b510759eeb Geetha sowjanya 2024-04-16  155  		rep->netdev = ndev;
> f9a5b510759eeb Geetha sowjanya 2024-04-16  156  		rep->rep_id = rep_id;
> f9a5b510759eeb Geetha sowjanya 2024-04-16  157  
> f9a5b510759eeb Geetha sowjanya 2024-04-16  158  		ndev->min_mtu = OTX2_MIN_MTU;
> f9a5b510759eeb Geetha sowjanya 2024-04-16  159  		ndev->max_mtu = priv->hw.max_mtu;
> f9a5b510759eeb Geetha sowjanya 2024-04-16  160  		pcifunc = priv->rep_pf_map[rep_id];
> f9a5b510759eeb Geetha sowjanya 2024-04-16  161  		rep->pcifunc = pcifunc;
> f9a5b510759eeb Geetha sowjanya 2024-04-16  162  
> f9a5b510759eeb Geetha sowjanya 2024-04-16  163  		snprintf(ndev->name, sizeof(ndev->name), "r%dp%dv%d", rep_id,
> f9a5b510759eeb Geetha sowjanya 2024-04-16  164  			 rvu_get_pf(pcifunc), (pcifunc & RVU_PFVF_FUNC_MASK));
> f9a5b510759eeb Geetha sowjanya 2024-04-16  165  
> f9a5b510759eeb Geetha sowjanya 2024-04-16  166  		eth_hw_addr_random(ndev);
> f9a5b510759eeb Geetha sowjanya 2024-04-16  167  		if (register_netdev(ndev)) {
> 
> err = register_netdev(ndev);
> if (err) {
> 
> f9a5b510759eeb Geetha sowjanya 2024-04-16  168  			dev_err(priv->dev, "PFVF reprentator registration failed\n");
> f9a5b510759eeb Geetha sowjanya 2024-04-16  169  			free_netdev(ndev);
>                                                                                     ^^^^
> freed
> 
> f9a5b510759eeb Geetha sowjanya 2024-04-16 @170  			ndev->netdev_ops = NULL;
>                                                                         ^^^^^^^^^^^^^^^^^^^^^^^
> Use after free
> 
> f9a5b510759eeb Geetha sowjanya 2024-04-16  171  			goto exit;
> f9a5b510759eeb Geetha sowjanya 2024-04-16  172  		}
> f9a5b510759eeb Geetha sowjanya 2024-04-16  173  	}
> f9a5b510759eeb Geetha sowjanya 2024-04-16  174  	err = rvu_rep_napi_init(priv);
> f9a5b510759eeb Geetha sowjanya 2024-04-16  175  	if (err)
> f9a5b510759eeb Geetha sowjanya 2024-04-16  176  		goto exit;
> f9a5b510759eeb Geetha sowjanya 2024-04-16  177  
> f9a5b510759eeb Geetha sowjanya 2024-04-16  178  	return 0;
> f9a5b510759eeb Geetha sowjanya 2024-04-16  179  exit:
> f9a5b510759eeb Geetha sowjanya 2024-04-16  180  	rvu_rep_free_netdev(priv);
> 
> rvu_rep_free_netdev() also calls free_netdev() so it's a double free.

Actually the rep->netdev->netdev_ops check in rvu_rep_free_netdev() was
supposed to prevent the double free.  But since rep->netdev is already
freed, then it's another use after free.  You could use a different flag
instead of rep->netdev->netdev_ops to mean "don't free this".  But
really, it's just better to write it how I have suggested.

My patch adds some duplicate code but when you remove the conditions in
rvu_rep_free_netdev() and the "ndev->netdev_ops = NULL" assignment, then
overall it's fewer lines of code this way.

https://staticthinking.wordpress.com/2022/04/28/free-the-last-thing-style/

regards,
dan carpenter
Re: [net-next PATCH 3/9] octeontx2-pf: Create representor netdev
Posted by Kalesh Anakkur Purayil 1 year, 10 months ago
On Tue, Apr 16, 2024 at 10:37 AM Geetha sowjanya <gakula@marvell.com> wrote:
>
> 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>
> ---
>  .../marvell/octeontx2/nic/otx2_devlink.c      |  48 ++++++
>  .../net/ethernet/marvell/octeontx2/nic/rep.c  | 159 ++++++++++++++++++
>  .../net/ethernet/marvell/octeontx2/nic/rep.h  |   2 +
>  3 files changed, 209 insertions(+)
>
> diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c
> index 4e1130496573..f4f5f5d93c7e 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c
> +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c
> @@ -76,7 +76,53 @@ static const struct devlink_param otx2_dl_params[] = {
>                              otx2_dl_mcam_count_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 (!is_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;
> +
> +       if (!is_rep_dev(pfvf->pdev))
> +               return -EOPNOTSUPP;
> +
> +       if (pfvf->esw_mode == mode)
> +               return 0;
> +
> +       pfvf->esw_mode = mode;
[Kalesh] Move this assignment after the switch block. Else, you will
end up updating pfvf->esw_mode to an unsupported mode even though
drover returns error.
> +       switch (mode) {
> +       case DEVLINK_ESWITCH_MODE_LEGACY:
> +               rvu_rep_destroy(pfvf);
> +               break;
> +       case DEVLINK_ESWITCH_MODE_SWITCHDEV:
> +               rvu_rep_create(pfvf);
> +               break;
> +       default:
> +               return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +#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)
> @@ -112,6 +158,7 @@ int otx2_register_dl(struct otx2_nic *pfvf)
>         devlink_free(dl);
>         return err;
>  }
> +EXPORT_SYMBOL(otx2_register_dl);
>
>  void otx2_unregister_dl(struct otx2_nic *pfvf)
>  {
> @@ -123,3 +170,4 @@ void otx2_unregister_dl(struct otx2_nic *pfvf)
>                                   ARRAY_SIZE(otx2_dl_params));
>         devlink_free(dl);
>  }
> +EXPORT_SYMBOL(otx2_unregister_dl);
> diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/rep.c b/drivers/net/ethernet/marvell/octeontx2/nic/rep.c
> index b892a7fe3ddc..fd55ef40c934 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/nic/rep.c
> +++ b/drivers/net/ethernet/marvell/octeontx2/nic/rep.c
> @@ -28,6 +28,159 @@ 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 otx2_cq_poll *cq_poll = NULL;
> +       struct otx2_qset *qset = &priv->qset;
> +       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) {
> +                       dev_err(priv->dev,
> +                               "RVU REP IRQ registration failed for CQ%d\n", 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_cq_poll *cq_poll = NULL;
> +       struct otx2_qset *qset = &priv->qset;
> +       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_free_netdev(struct otx2_nic *priv)
> +{
> +       struct rep_dev *rep;
> +       int rep_id;
> +
> +       for (rep_id = 0; rep_id < priv->rep_cnt; rep_id++) {
> +               rep = priv->reps[rep_id];
> +               if (rep && rep->netdev->netdev_ops) {
> +                       unregister_netdev(rep->netdev);
> +                       free_netdev(rep->netdev);
> +               }
> +       }
> +       devm_kfree(priv->dev, priv->reps);
> +}
> +
> +void rvu_rep_destroy(struct otx2_nic *priv)
> +{
> +       rvu_rep_free_cq_rsrc(priv);
> +       rvu_rep_free_netdev(priv);
> +}
> +
> +int rvu_rep_create(struct otx2_nic *priv)
> +{
> +       int rep_cnt = priv->rep_cnt;
> +       struct net_device *ndev;
> +       struct rep_dev *rep;
> +       int rep_id, err;
> +       u16 pcifunc;
> +
> +       priv->reps = devm_kcalloc(priv->dev, 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) {
> +                       dev_err(priv->dev, "PFVF representor:%d creation failed\n", 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), "r%dp%dv%d", rep_id,
> +                        rvu_get_pf(pcifunc), (pcifunc & RVU_PFVF_FUNC_MASK));
> +
> +               eth_hw_addr_random(ndev);
> +               if (register_netdev(ndev)) {
> +                       dev_err(priv->dev, "PFVF reprentator registration failed\n");
> +                       free_netdev(ndev);
> +                       ndev->netdev_ops = NULL;
[Kalesh] update "rc" with the return status of register_netdev()
> +                       goto exit;
> +               }
> +       }
> +       err = rvu_rep_napi_init(priv);
> +       if (err)
> +               goto exit;
> +
> +       return 0;
> +exit:
> +       rvu_rep_free_netdev(priv);
> +       return err;
> +}
> +
>  static int rvu_rep_rsrc_free(struct otx2_nic *priv)
>  {
>         struct otx2_qset *qset = &priv->qset;
> @@ -162,6 +315,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:
> @@ -183,6 +340,8 @@ static void rvu_rep_remove(struct pci_dev *pdev)
>  {
>         struct otx2_nic *priv = pci_get_drvdata(pdev);
>
> +       otx2_unregister_dl(priv);
> +       rvu_rep_destroy(priv);
>         rvu_rep_rsrc_free(priv);
>         otx2_detach_resources(&priv->mbox);
>         if (priv->hw.lmt_info)
> diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/rep.h b/drivers/net/ethernet/marvell/octeontx2/nic/rep.h
> index 30cce17eb48b..be6c939e5cba 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/nic/rep.h
> +++ b/drivers/net/ethernet/marvell/octeontx2/nic/rep.h
> @@ -29,4 +29,6 @@ static inline bool is_rep_dev(struct pci_dev *pdev)
>         return pdev->device == PCI_DEVID_RVU_REP;
>  }
>
> +int rvu_rep_create(struct otx2_nic *priv);
> +void rvu_rep_destroy(struct otx2_nic *priv);
>  #endif /* REP_H */
> --
> 2.25.1
>
>


-- 
Regards,
Kalesh A P
Re: [net-next PATCH 3/9] octeontx2-pf: Create representor netdev
Posted by kernel test robot 1 year, 10 months ago
Hi Geetha,

kernel test robot noticed the following build warnings:

[auto build test WARNING on net-next/main]

url:    https://github.com/intel-lab-lkp/linux/commits/Geetha-sowjanya/octeontx2-pf-Refactoring-RVU-driver/20240416-131052
base:   net-next/main
patch link:    https://lore.kernel.org/r/20240416050616.6056-4-gakula%40marvell.com
patch subject: [net-next PATCH 3/9] octeontx2-pf: Create representor netdev
config: x86_64-allyesconfig (https://download.01.org/0day-ci/archive/20240417/202404170922.RBiIclFT-lkp@intel.com/config)
compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240417/202404170922.RBiIclFT-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202404170922.RBiIclFT-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/net/ethernet/marvell/octeontx2/nic/rep.c:167:7: warning: variable 'err' is used uninitialized whenever 'if' condition is true [-Wsometimes-uninitialized]
     167 |                 if (register_netdev(ndev)) {
         |                     ^~~~~~~~~~~~~~~~~~~~~
   drivers/net/ethernet/marvell/octeontx2/nic/rep.c:181:9: note: uninitialized use occurs here
     181 |         return err;
         |                ^~~
   drivers/net/ethernet/marvell/octeontx2/nic/rep.c:167:3: note: remove the 'if' if its condition is always false
     167 |                 if (register_netdev(ndev)) {
         |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
     168 |                         dev_err(priv->dev, "PFVF reprentator registration failed\n");
         |                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     169 |                         free_netdev(ndev);
         |                         ~~~~~~~~~~~~~~~~~~
     170 |                         ndev->netdev_ops = NULL;
         |                         ~~~~~~~~~~~~~~~~~~~~~~~~
     171 |                         goto exit;
         |                         ~~~~~~~~~~
     172 |                 }
         |                 ~
   drivers/net/ethernet/marvell/octeontx2/nic/rep.c:137:17: note: initialize the variable 'err' to silence this warning
     137 |         int rep_id, err;
         |                        ^
         |                         = 0
   1 warning generated.


vim +167 drivers/net/ethernet/marvell/octeontx2/nic/rep.c

   131	
   132	int rvu_rep_create(struct otx2_nic *priv)
   133	{
   134		int rep_cnt = priv->rep_cnt;
   135		struct net_device *ndev;
   136		struct rep_dev *rep;
   137		int rep_id, err;
   138		u16 pcifunc;
   139	
   140		priv->reps = devm_kcalloc(priv->dev, rep_cnt, sizeof(struct rep_dev), GFP_KERNEL);
   141		if (!priv->reps)
   142			return -ENOMEM;
   143	
   144		for (rep_id = 0; rep_id < rep_cnt; rep_id++) {
   145			ndev = alloc_etherdev(sizeof(*rep));
   146			if (!ndev) {
   147				dev_err(priv->dev, "PFVF representor:%d creation failed\n", rep_id);
   148				err = -ENOMEM;
   149				goto exit;
   150			}
   151	
   152			rep = netdev_priv(ndev);
   153			priv->reps[rep_id] = rep;
   154			rep->mdev = priv;
   155			rep->netdev = ndev;
   156			rep->rep_id = rep_id;
   157	
   158			ndev->min_mtu = OTX2_MIN_MTU;
   159			ndev->max_mtu = priv->hw.max_mtu;
   160			pcifunc = priv->rep_pf_map[rep_id];
   161			rep->pcifunc = pcifunc;
   162	
   163			snprintf(ndev->name, sizeof(ndev->name), "r%dp%dv%d", rep_id,
   164				 rvu_get_pf(pcifunc), (pcifunc & RVU_PFVF_FUNC_MASK));
   165	
   166			eth_hw_addr_random(ndev);
 > 167			if (register_netdev(ndev)) {
   168				dev_err(priv->dev, "PFVF reprentator registration failed\n");
   169				free_netdev(ndev);
   170				ndev->netdev_ops = NULL;
   171				goto exit;
   172			}
   173		}
   174		err = rvu_rep_napi_init(priv);
   175		if (err)
   176			goto exit;
   177	
   178		return 0;
   179	exit:
   180		rvu_rep_free_netdev(priv);
   181		return err;
   182	}
   183	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Re: [net-next PATCH 3/9] octeontx2-pf: Create representor netdev
Posted by kernel test robot 1 year, 10 months ago
Hi Geetha,

kernel test robot noticed the following build warnings:

[auto build test WARNING on net-next/main]

url:    https://github.com/intel-lab-lkp/linux/commits/Geetha-sowjanya/octeontx2-pf-Refactoring-RVU-driver/20240416-131052
base:   net-next/main
patch link:    https://lore.kernel.org/r/20240416050616.6056-4-gakula%40marvell.com
patch subject: [net-next PATCH 3/9] octeontx2-pf: Create representor netdev
config: loongarch-allmodconfig (https://download.01.org/0day-ci/archive/20240417/202404170853.i93jboPB-lkp@intel.com/config)
compiler: loongarch64-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240417/202404170853.i93jboPB-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202404170853.i93jboPB-lkp@intel.com/

All warnings (new ones prefixed by >>):

   drivers/net/ethernet/marvell/octeontx2/nic/rep.c: In function 'rvu_rep_create':
>> drivers/net/ethernet/marvell/octeontx2/nic/rep.c:163:66: warning: '%d' directive output may be truncated writing between 1 and 4 bytes into a region of size between 1 and 11 [-Wformat-truncation=]
     163 |                 snprintf(ndev->name, sizeof(ndev->name), "r%dp%dv%d", rep_id,
         |                                                                  ^~
   drivers/net/ethernet/marvell/octeontx2/nic/rep.c:163:58: note: directive argument in the range [0, 1023]
     163 |                 snprintf(ndev->name, sizeof(ndev->name), "r%dp%dv%d", rep_id,
         |                                                          ^~~~~~~~~~~
   drivers/net/ethernet/marvell/octeontx2/nic/rep.c:163:17: note: 'snprintf' output between 7 and 20 bytes into a destination of size 16
     163 |                 snprintf(ndev->name, sizeof(ndev->name), "r%dp%dv%d", rep_id,
         |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     164 |                          rvu_get_pf(pcifunc), (pcifunc & RVU_PFVF_FUNC_MASK));
         |                          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


vim +163 drivers/net/ethernet/marvell/octeontx2/nic/rep.c

   131	
   132	int rvu_rep_create(struct otx2_nic *priv)
   133	{
   134		int rep_cnt = priv->rep_cnt;
   135		struct net_device *ndev;
   136		struct rep_dev *rep;
   137		int rep_id, err;
   138		u16 pcifunc;
   139	
   140		priv->reps = devm_kcalloc(priv->dev, rep_cnt, sizeof(struct rep_dev), GFP_KERNEL);
   141		if (!priv->reps)
   142			return -ENOMEM;
   143	
   144		for (rep_id = 0; rep_id < rep_cnt; rep_id++) {
   145			ndev = alloc_etherdev(sizeof(*rep));
   146			if (!ndev) {
   147				dev_err(priv->dev, "PFVF representor:%d creation failed\n", rep_id);
   148				err = -ENOMEM;
   149				goto exit;
   150			}
   151	
   152			rep = netdev_priv(ndev);
   153			priv->reps[rep_id] = rep;
   154			rep->mdev = priv;
   155			rep->netdev = ndev;
   156			rep->rep_id = rep_id;
   157	
   158			ndev->min_mtu = OTX2_MIN_MTU;
   159			ndev->max_mtu = priv->hw.max_mtu;
   160			pcifunc = priv->rep_pf_map[rep_id];
   161			rep->pcifunc = pcifunc;
   162	
 > 163			snprintf(ndev->name, sizeof(ndev->name), "r%dp%dv%d", rep_id,
   164				 rvu_get_pf(pcifunc), (pcifunc & RVU_PFVF_FUNC_MASK));
   165	
   166			eth_hw_addr_random(ndev);
   167			if (register_netdev(ndev)) {
   168				dev_err(priv->dev, "PFVF reprentator registration failed\n");
   169				free_netdev(ndev);
   170				ndev->netdev_ops = NULL;
   171				goto exit;
   172			}
   173		}
   174		err = rvu_rep_napi_init(priv);
   175		if (err)
   176			goto exit;
   177	
   178		return 0;
   179	exit:
   180		rvu_rep_free_netdev(priv);
   181		return err;
   182	}
   183	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki