]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: enetc: add command BD ring support for i.MX95 ENETC
authorWei Fang <wei.fang@nxp.com>
Tue, 6 May 2025 08:07:23 +0000 (16:07 +0800)
committerJakub Kicinski <kuba@kernel.org>
Fri, 9 May 2025 02:43:51 +0000 (19:43 -0700)
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. So add
enetc4_setup_cbdr() and enetc4_teardown_cbdr() for ENETC v4 drivers.

Signed-off-by: Wei Fang <wei.fang@nxp.com>
Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Link: https://patch.msgid.link/20250506080735.3444381-3-wei.fang@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/freescale/enetc/enetc.h
drivers/net/ethernet/freescale/enetc/enetc4_pf.c
drivers/net/ethernet/freescale/enetc/enetc_cbdr.c

index 4ad4eb5c5a747d937ac5cad5b77b960af9335920..384e0bded87f8a55706f820c310700935c066b3f 100644 (file)
@@ -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>
@@ -274,7 +275,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_user ntmp_user; /* ENETC 4.1 and later */
+       };
 
        int num_rx_rings; /* how many rings are available in the SI */
        int num_tx_rings;
@@ -284,6 +288,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
@@ -493,6 +498,8 @@ void enetc_mm_commit_preemptible_tcs(struct enetc_ndev_priv *priv);
 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 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);
index 73ac8c6afb3ad8d0b0eae38ccedf4a473a043d4b..175eebadde769c75bc48103d2d980ad9d62599e6 100644 (file)
@@ -260,6 +260,21 @@ static void enetc4_configure_port(struct enetc_pf *pf)
        enetc4_enable_trx(pf);
 }
 
+static int enetc4_init_ntmp_user(struct enetc_si *si)
+{
+       struct ntmp_user *user = &si->ntmp_user;
+
+       /* For ENETC 4.1, all table versions are 0 */
+       memset(&user->tbl, 0, sizeof(user->tbl));
+
+       return enetc4_setup_cbdr(si);
+}
+
+static void enetc4_free_ntmp_user(struct enetc_si *si)
+{
+       enetc4_teardown_cbdr(si);
+}
+
 static int enetc4_pf_init(struct enetc_pf *pf)
 {
        struct device *dev = &pf->si->pdev->dev;
@@ -272,11 +287,22 @@ static int enetc4_pf_init(struct enetc_pf *pf)
                return err;
        }
 
+       err = enetc4_init_ntmp_user(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_user(pf->si);
+}
+
 static const struct net_device_ops enetc4_ndev_ops = {
        .ndo_open               = enetc_open,
        .ndo_stop               = enetc_close,
@@ -728,14 +754,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[] = {
index 20bfdf7fb4b4bba7bdef02b2e4a17fb7b34768c1..71e4da5300282bcafff46aa71683853db4f1b90f 100644 (file)
@@ -60,6 +60,44 @@ void enetc_teardown_cbdr(struct enetc_cbdr *cbdr)
 }
 EXPORT_SYMBOL_GPL(enetc_teardown_cbdr);
 
+int enetc4_setup_cbdr(struct enetc_si *si)
+{
+       struct ntmp_user *user = &si->ntmp_user;
+       struct device *dev = &si->pdev->dev;
+       struct enetc_hw *hw = &si->hw;
+       struct netc_cbdr_regs regs;
+
+       user->cbdr_num = 1;
+       user->dev = dev;
+       user->ring = devm_kcalloc(dev, user->cbdr_num,
+                                 sizeof(struct netc_cbdr), GFP_KERNEL);
+       if (!user->ring)
+               return -ENOMEM;
+
+       /* set CBDR cache attributes */
+       enetc_wr(hw, ENETC_SICAR2,
+                ENETC_SICAR_RD_COHERENT | ENETC_SICAR_WR_COHERENT);
+
+       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 ntmp_init_cbdr(user->ring, dev, &regs);
+}
+EXPORT_SYMBOL_GPL(enetc4_setup_cbdr);
+
+void enetc4_teardown_cbdr(struct enetc_si *si)
+{
+       struct ntmp_user *user = &si->ntmp_user;
+
+       ntmp_free_cbdr(user->ring);
+       user->dev = NULL;
+}
+EXPORT_SYMBOL_GPL(enetc4_teardown_cbdr);
+
 static void enetc_clean_cbdr(struct enetc_cbdr *ring)
 {
        struct enetc_cbd *dest_cbd;