[PATCH v2 net-next 02/13] net: enetc: add command BD ring support for i.MX95 ENETC

Wei Fang
2025-01-13T08:39:54Z

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=y, Size: 11933 bytes --]

The command BD ring is used to configure functionality where the
underlying resources may be shared between different entities or being
too large to configure using direct registers (such as lookup tables).

Because the command BD and table formats of i.MX95 and LS1028A are very
different, the software processing logic is also different. In order to
ensure driver compatibility, struct enetc_si_ops is introduced. This
structure defines some hooks shared by VSI and PSI. Different hardware
driver will register different hooks, For example, setup_cbdr() is used
to initialize the command BD ring, and teardown_cbdr() is used to free
the command BD ring.

Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
drivers/net/ethernet/freescale/enetc/enetc.h | 27 ++++++++--
.../net/ethernet/freescale/enetc/enetc4_pf.c | 47 ++++++++++++++++-
.../net/ethernet/freescale/enetc/enetc_cbdr.c | 51 ++++++++++++++++---
.../net/ethernet/freescale/enetc/enetc_pf.c | 13 +++--
.../net/ethernet/freescale/enetc/enetc_vf.c | 13 +++--
5 files changed, 132 insertions(+), 19 deletions(-)

diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index 4ad4eb5c5a74..4ff0957e69be 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -8,6 +8,7 @@
#include <linux/dma-mapping.h>
#include <linux/skbuff.h>
#include <linux/ethtool.h>
+#include <linux/fsl/ntmp.h>
#include <linux/if_vlan.h>
#include <linux/phylink.h>
#include <linux/dim.h>
@@ -266,6 +267,19 @@ struct enetc_platform_info {
const struct enetc_drvdata *data;
};

+struct enetc_si;
+
+/*
+ * This structure defines the some common hooks for ENETC PSI and VSI.
+ * In addition, since VSI only uses the struct enetc_si as its private
+ * driver data, so this structure also define some hooks specifically
+ * for VSI. For VSI-specific hooks, the format is ‘vf_*()’.
+ */
+struct enetc_si_ops {
+ int (*setup_cbdr)(struct enetc_si *si);
+ void (*teardown_cbdr)(struct enetc_si *si);
+};
+
/* PCI IEP device data */
struct enetc_si {
struct pci_dev *pdev;
@@ -274,7 +288,10 @@ struct enetc_si {

struct net_device *ndev; /* back ref. */

- struct enetc_cbdr cbd_ring;
+ union {
+ struct enetc_cbdr cbd_ring; /* Only ENETC 1.0 */
+ struct ntmp_priv ntmp; /* ENETC 4.1 and later */
+ };

int num_rx_rings; /* how many rings are available in the SI */
int num_tx_rings;
@@ -284,6 +301,7 @@ struct enetc_si {
u16 revision;
int hw_features;
const struct enetc_drvdata *drvdata;
+ const struct enetc_si_ops *ops;
};

#define ENETC_SI_ALIGN 32
@@ -490,9 +508,10 @@ void enetc_mm_link_state_update(struct enetc_ndev_priv *priv, bool link);
void enetc_mm_commit_preemptible_tcs(struct enetc_ndev_priv *priv);

/* control buffer descriptor ring (CBDR) */
-int enetc_setup_cbdr(struct device *dev, struct enetc_hw *hw, int bd_count,
- struct enetc_cbdr *cbdr);
-void enetc_teardown_cbdr(struct enetc_cbdr *cbdr);
+int enetc_setup_cbdr(struct enetc_si *si);
+void enetc_teardown_cbdr(struct enetc_si *si);
+int enetc4_setup_cbdr(struct enetc_si *si);
+void enetc4_teardown_cbdr(struct enetc_si *si);
int enetc_set_mac_flt_entry(struct enetc_si *si, int index,
char *mac_addr, int si_map);
int enetc_clear_mac_flt_entry(struct enetc_si *si, int index);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index fc41078c4f5d..b957e92e3a00 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -260,6 +260,23 @@ static void enetc4_configure_port(struct enetc_pf *pf)
enetc4_enable_trx(pf);
}

+static int enetc4_init_ntmp_priv(struct enetc_si *si)
+{
+ struct ntmp_priv *ntmp = &si->ntmp;
+
+ ntmp->dev_type = NETC_DEV_ENETC;
+
+ /* For ENETC 4.1, all table versions are 0 */
+ memset(&ntmp->cbdrs.tbl, 0, sizeof(ntmp->cbdrs.tbl));
+
+ return si->ops->setup_cbdr(si);
+}
+
+static void enetc4_free_ntmp_priv(struct enetc_si *si)
+{
+ si->ops->teardown_cbdr(si);
+}
+
static int enetc4_pf_init(struct enetc_pf *pf)
{
struct device *dev = &pf->si->pdev->dev;
@@ -272,11 +289,22 @@ static int enetc4_pf_init(struct enetc_pf *pf)
return err;
}

+ err = enetc4_init_ntmp_priv(pf->si);
+ if (err) {
+ dev_err(dev, "Failed to init CBDR\n");
+ return err;
+ }
+
enetc4_configure_port(pf);

return 0;
}

+static void enetc4_pf_free(struct enetc_pf *pf)
+{
+ enetc4_free_ntmp_priv(pf->si);
+}
+
static const struct net_device_ops enetc4_ndev_ops = {
.ndo_open = enetc_open,
.ndo_stop = enetc_close,
@@ -688,6 +716,11 @@ static void enetc4_pf_netdev_destroy(struct enetc_si *si)
free_netdev(ndev);
}

+static const struct enetc_si_ops enetc4_psi_ops = {
+ .setup_cbdr = enetc4_setup_cbdr,
+ .teardown_cbdr = enetc4_teardown_cbdr,
+};
+
static int enetc4_pf_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -712,6 +745,7 @@ static int enetc4_pf_probe(struct pci_dev *pdev,
"Couldn't map PF only space\n");

si->revision = enetc_get_ip_revision(&si->hw);
+ si->ops = &enetc4_psi_ops;
err = enetc_get_driver_data(si);
if (err)
return dev_err_probe(dev, err,
@@ -728,14 +762,25 @@ static int enetc4_pf_probe(struct pci_dev *pdev,

enetc_get_si_caps(si);

- return enetc4_pf_netdev_create(si);
+ err = enetc4_pf_netdev_create(si);
+ if (err)
+ goto err_netdev_create;
+
+ return 0;
+
+err_netdev_create:
+ enetc4_pf_free(pf);
+
+ return err;
}

static void enetc4_pf_remove(struct pci_dev *pdev)
{
struct enetc_si *si = pci_get_drvdata(pdev);
+ struct enetc_pf *pf = enetc_si_priv(si);

enetc4_pf_netdev_destroy(si);
+ enetc4_pf_free(pf);
}

static const struct pci_device_id enetc4_pf_id_table[] = {
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
index 20bfdf7fb4b4..31bb82ee512d 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
@@ -3,10 +3,12 @@

#include "enetc.h"

-int enetc_setup_cbdr(struct device *dev, struct enetc_hw *hw, int bd_count,
- struct enetc_cbdr *cbdr)
+int enetc_setup_cbdr(struct enetc_si *si)
{
- int size = bd_count * sizeof(struct enetc_cbd);
+ int size = ENETC_CBDR_DEFAULT_SIZE * sizeof(struct enetc_cbd);
+ struct enetc_cbdr *cbdr = &si->cbd_ring;
+ struct device *dev = &si->pdev->dev;
+ struct enetc_hw *hw = &si->hw;

cbdr->bd_base = dma_alloc_coherent(dev, size, &cbdr->bd_dma_base,
GFP_KERNEL);
@@ -23,7 +25,7 @@ int enetc_setup_cbdr(struct device *dev, struct enetc_hw *hw, int bd_count,
cbdr->next_to_clean = 0;
cbdr->next_to_use = 0;
cbdr->dma_dev = dev;
- cbdr->bd_count = bd_count;
+ cbdr->bd_count = ENETC_CBDR_DEFAULT_SIZE;

cbdr->pir = hw->reg + ENETC_SICBDRPIR;
cbdr->cir = hw->reg + ENETC_SICBDRCIR;
@@ -46,13 +48,41 @@ int enetc_setup_cbdr(struct device *dev, struct enetc_hw *hw, int bd_count,
}
EXPORT_SYMBOL_GPL(enetc_setup_cbdr);

-void enetc_teardown_cbdr(struct enetc_cbdr *cbdr)
+int enetc4_setup_cbdr(struct enetc_si *si)
{
- int size = cbdr->bd_count * sizeof(struct enetc_cbd);
+ struct netc_cbdrs *cbdrs = &si->ntmp.cbdrs;
+ struct device *dev = &si->pdev->dev;
+ struct enetc_hw *hw = &si->hw;
+ struct netc_cbdr_regs regs;
+
+ cbdrs->cbdr_num = 1;
+ cbdrs->cbdr_size = NETC_CBDR_BD_NUM;
+ cbdrs->dma_dev = dev;
+ cbdrs->ring = devm_kcalloc(dev, cbdrs->cbdr_num,
+ sizeof(struct netc_cbdr), GFP_KERNEL);
+ if (!cbdrs->ring)
+ return -ENOMEM;
+
+ regs.pir = hw->reg + ENETC_SICBDRPIR;
+ regs.cir = hw->reg + ENETC_SICBDRCIR;
+ regs.mr = hw->reg + ENETC_SICBDRMR;
+ regs.bar0 = hw->reg + ENETC_SICBDRBAR0;
+ regs.bar1 = hw->reg + ENETC_SICBDRBAR1;
+ regs.lenr = hw->reg + ENETC_SICBDRLENR;
+
+ return netc_setup_cbdr(dev, cbdrs->cbdr_size, &regs, cbdrs->ring);
+}
+EXPORT_SYMBOL_GPL(enetc4_setup_cbdr);
+
+void enetc_teardown_cbdr(struct enetc_si *si)
+{
+ struct enetc_cbdr *cbdr = &si->cbd_ring;
+ int size;

/* disable ring */
enetc_wr_reg(cbdr->mr, 0);

+ size = cbdr->bd_count * sizeof(struct enetc_cbd);
dma_free_coherent(cbdr->dma_dev, size, cbdr->bd_base,
cbdr->bd_dma_base);
cbdr->bd_base = NULL;
@@ -60,6 +90,15 @@ void enetc_teardown_cbdr(struct enetc_cbdr *cbdr)
}
EXPORT_SYMBOL_GPL(enetc_teardown_cbdr);

+void enetc4_teardown_cbdr(struct enetc_si *si)
+{
+ struct netc_cbdrs *cbdrs = &si->ntmp.cbdrs;
+
+ netc_teardown_cbdr(cbdrs->dma_dev, cbdrs->ring);
+ cbdrs->dma_dev = NULL;
+}
+EXPORT_SYMBOL_GPL(enetc4_teardown_cbdr);
+
static void enetc_clean_cbdr(struct enetc_cbdr *ring)
{
struct enetc_cbd *dest_cbd;
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index 203862ec1114..a214749a4af6 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -939,6 +939,11 @@ static int enetc_pf_register_with_ierb(struct pci_dev *pdev)
return enetc_ierb_register_pf(ierb_pdev, pdev);
}

+static const struct enetc_si_ops enetc_psi_ops = {
+ .setup_cbdr = enetc_setup_cbdr,
+ .teardown_cbdr = enetc_teardown_cbdr,
+};
+
static struct enetc_si *enetc_psi_create(struct pci_dev *pdev)
{
struct enetc_si *si;
@@ -957,6 +962,7 @@ static struct enetc_si *enetc_psi_create(struct pci_dev *pdev)
goto out_pci_remove;
}

+ si->ops = &enetc_psi_ops;
si->revision = enetc_get_ip_revision(&si->hw);
err = enetc_get_driver_data(si);
if (err) {
@@ -964,8 +970,7 @@ static struct enetc_si *enetc_psi_create(struct pci_dev *pdev)
goto out_pci_remove;
}

- err = enetc_setup_cbdr(&pdev->dev, &si->hw, ENETC_CBDR_DEFAULT_SIZE,
- &si->cbd_ring);
+ err = si->ops->setup_cbdr(si);
if (err)
goto out_pci_remove;

@@ -984,7 +989,7 @@ static struct enetc_si *enetc_psi_create(struct pci_dev *pdev)
return si;

out_teardown_cbdr:
- enetc_teardown_cbdr(&si->cbd_ring);
+ si->ops->teardown_cbdr(si);
out_pci_remove:
enetc_pci_remove(pdev);
out:
@@ -995,7 +1000,7 @@ static void enetc_psi_destroy(struct pci_dev *pdev)
{
struct enetc_si *si = pci_get_drvdata(pdev);

- enetc_teardown_cbdr(&si->cbd_ring);
+ si->ops->teardown_cbdr(si);
enetc_pci_remove(pdev);
}

diff --git a/drivers/net/ethernet/freescale/enetc/enetc_vf.c b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
index 3768752b6008..d7d9a720069b 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_vf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
@@ -162,6 +162,11 @@ static void enetc_vf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
enetc_load_primary_mac_addr(&si->hw, ndev);
}

+static const struct enetc_si_ops enetc_vsi_ops = {
+ .setup_cbdr = enetc_setup_cbdr,
+ .teardown_cbdr = enetc_teardown_cbdr,
+};
+
static int enetc_vf_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -176,6 +181,7 @@ static int enetc_vf_probe(struct pci_dev *pdev,

si = pci_get_drvdata(pdev);
si->revision = ENETC_REV_1_0;
+ si->ops = &enetc_vsi_ops;
err = enetc_get_driver_data(si);
if (err) {
dev_err_probe(&pdev->dev, err,
@@ -198,8 +204,7 @@ static int enetc_vf_probe(struct pci_dev *pdev,

enetc_init_si_rings_params(priv);

- err = enetc_setup_cbdr(priv->dev, &si->hw, ENETC_CBDR_DEFAULT_SIZE,
- &si->cbd_ring);
+ err = si->ops->setup_cbdr(si);
if (err)
goto err_setup_cbdr;

@@ -235,7 +240,7 @@ static int enetc_vf_probe(struct pci_dev *pdev,
err_alloc_msix:
enetc_free_si_resources(priv);
err_alloc_si_res:
- enetc_teardown_cbdr(&si->cbd_ring);
+ si->ops->teardown_cbdr(si);
err_setup_cbdr:
si->ndev = NULL;
free_netdev(ndev);
@@ -256,7 +261,7 @@ static void enetc_vf_remove(struct pci_dev *pdev)
enetc_free_msix(priv);

enetc_free_si_resources(priv);
- enetc_teardown_cbdr(&si->cbd_ring);
+ si->ops->teardown_cbdr(si);

free_netdev(si->ndev);

--
2.34.1