netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 net-next 00/14] Add more feautues for ENETC v4 - round 2
@ 2025-03-11  5:38 Wei Fang
  2025-03-11  5:38 ` [PATCH v4 net-next 01/14] net: enetc: add initial netc-lib driver to support NTMP Wei Fang
                   ` (14 more replies)
  0 siblings, 15 replies; 58+ messages in thread
From: Wei Fang @ 2025-03-11  5:38 UTC (permalink / raw)
  To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
	davem, edumazet, kuba, pabeni
  Cc: christophe.leroy, netdev, linux-kernel, imx, linuxppc-dev,
	linux-arm-kernel

This patch set adds the following features.
1. Compared with ENETC v1, the formats of tables and command BD of ENETC
v4 have changed significantly, and the two are not compatible. Therefore,
in order to support the NETC Table Management Protocol (NTMP) v2.0, we
introduced the netc-lib driver and added support for MAC address filter
table and RSS table.
2. Add MAC filter and VLAN filter support for i.MX95 ENETC PF.
3. Add RSS support for i.MX95 ENETC PF.
4. Add loopback support for i.MX95 ENETC PF.

---
v1 Link: https://lore.kernel.org/imx/20250103060610.2233908-1-wei.fang@nxp.com/
v2 changes
1. Change NTMP_FILL_CRD() and NTMP_FILL_CRD_EID to functions
2. Fix the compile warning in enetc4_pf.c
v2 Link: https://lore.kernel.org/imx/20250113082245.2332775-1-wei.fang@nxp.com/
v3 changes
1. Rename ntmp_formats.h to ntmp_private.h, becuase in addition to
   defining some table formats, some macros and function declarations
   will be added to this header file in the future
2. Add struct ntmp_dma_buf, so refactor ntmp_alloc_data_mem() and
   ntmp_free_data_mem() accordingly
3. Add the setting for cache attributes of command BD Ring in
   enetc4_setup_cbdr()
4. Remove __free() and scoped_guard() from patch "net: enetc: add MAC
   filter for i.MX95 ENETC PF", as these cleanup APIs are discouraged
   within networking drivers.
5. Remove patch "net: enetc: make enetc_set_rxfh() and enetc_get_rxfh()
   reusable" in v2, and add enetc_set_rss_key() and enetc_get_rss_key()
   instead of adding .set_rss_key() and .get_rss_key() to enetc_pf_ops
6. Separate patch " net: enetc: check if the RSS hfunc is toeplitz" from
   patch "net: enetc: add RSS support for i.MX95 ENETC PF"
v3 Link:https://lore.kernel.org/imx/20250304072201.1332603-1-wei.fang@nxp.com/
v4 changes
1. Optimize the indentation in patch "net: enetc: add MAC filter for
   i.MX95 ENETC PF"
2. Remove pack(1) from ntmp.h and ntmp_private.h
3. Remove the string after "tristate" from CONFG_NXP_NETC_LIB
4. Separate two patches from the patch "net: enetc: add RSS support for
   i.MX95 ENETC PF", one is "net: enetc: add set/get_rss_table() to
   enetc_si_ops", the other one is "net: enetc: make enetc_set_rss_key()
   reusable"
5. Remove patch "net: enetc: check if the RSS hfunc is toeplitz" from
   this patch set.
---

Wei Fang (14):
  net: enetc: add initial netc-lib driver to support NTMP
  net: enetc: add command BD ring support for i.MX95 ENETC
  net: enetc: move generic MAC filterng interfaces to enetc-core
  net: enetc: add MAC filter for i.MX95 ENETC PF
  net: enetc: add debugfs interface to dump MAC filter
  net: enetc: add set/get_rss_table() to enetc_si_ops
  net: enetc: make enetc_set_rss_key() reusable
  net: enetc: add RSS support for i.MX95 ENETC PF
  net: enetc: enable RSS feature by default
  net: enetc: move generic VLAN filter interfaces to enetc-core
  net: enetc: move generic VLAN hash filter functions to
    enetc_pf_common.c
  net: enetc: add VLAN filtering support for i.MX95 ENETC PF
  net: enetc: add loopback support for i.MX95 ENETC PF
  MAINTAINERS: add new file ntmp.h to ENETC driver

 MAINTAINERS                                   |   1 +
 drivers/net/ethernet/freescale/enetc/Kconfig  |   8 +
 drivers/net/ethernet/freescale/enetc/Makefile |   4 +
 drivers/net/ethernet/freescale/enetc/enetc.c  | 103 +++-
 drivers/net/ethernet/freescale/enetc/enetc.h  |  59 +-
 .../ethernet/freescale/enetc/enetc4_debugfs.c |  93 +++
 .../ethernet/freescale/enetc/enetc4_debugfs.h |  20 +
 .../net/ethernet/freescale/enetc/enetc4_hw.h  |  12 +
 .../net/ethernet/freescale/enetc/enetc4_pf.c  | 533 +++++++++++++++++-
 .../net/ethernet/freescale/enetc/enetc_cbdr.c |  69 ++-
 .../ethernet/freescale/enetc/enetc_ethtool.c  |  69 ++-
 .../net/ethernet/freescale/enetc/enetc_hw.h   |   6 +
 .../net/ethernet/freescale/enetc/enetc_pf.c   | 124 +---
 .../net/ethernet/freescale/enetc/enetc_pf.h   |  30 +-
 .../freescale/enetc/enetc_pf_common.c         |  46 +-
 .../freescale/enetc/enetc_pf_common.h         |   2 +
 .../net/ethernet/freescale/enetc/enetc_vf.c   |  19 +-
 drivers/net/ethernet/freescale/enetc/ntmp.c   | 458 +++++++++++++++
 .../ethernet/freescale/enetc/ntmp_private.h   |  63 +++
 include/linux/fsl/ntmp.h                      | 174 ++++++
 20 files changed, 1702 insertions(+), 191 deletions(-)
 create mode 100644 drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c
 create mode 100644 drivers/net/ethernet/freescale/enetc/enetc4_debugfs.h
 create mode 100644 drivers/net/ethernet/freescale/enetc/ntmp.c
 create mode 100644 drivers/net/ethernet/freescale/enetc/ntmp_private.h
 create mode 100644 include/linux/fsl/ntmp.h

-- 
2.34.1


^ permalink raw reply	[flat|nested] 58+ messages in thread

* [PATCH v4 net-next 01/14] net: enetc: add initial netc-lib driver to support NTMP
  2025-03-11  5:38 [PATCH v4 net-next 00/14] Add more feautues for ENETC v4 - round 2 Wei Fang
@ 2025-03-11  5:38 ` Wei Fang
  2025-03-11 12:17   ` Michal Kubiak
  2025-03-13 16:35   ` Vladimir Oltean
  2025-03-11  5:38 ` [PATCH v4 net-next 02/14] net: enetc: add command BD ring support for i.MX95 ENETC Wei Fang
                   ` (13 subsequent siblings)
  14 siblings, 2 replies; 58+ messages in thread
From: Wei Fang @ 2025-03-11  5:38 UTC (permalink / raw)
  To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
	davem, edumazet, kuba, pabeni
  Cc: christophe.leroy, netdev, linux-kernel, imx, linuxppc-dev,
	linux-arm-kernel

Some NETC functionality is controlled using control messages sent to the
hardware using BD ring interface with 32B descriptor similar to transmit
BD ring used on ENETC. This BD ring interface is referred to as command
BD ring. It is used to configure functionality where the underlying
resources may be shared between different entities or being too large to
configure using direct registers. Therefore, a messaging protocol called
NETC Table Management Protocol (NTMP) is provided for exchanging
configuration and management information between the software and the
hardware using the command BD ring interface.

For i.MX95, NTMP has been upgraded to version 2.0, which is incompatible
with LS1028A, because the message formats have been changed. Therefore,
add the netc-lib driver to support NTMP 2.0 to operate various tables.
Note that, only MAC address filter table and RSS table are supported at
the moment. More tables will be supported in subsequent patches.

It is worth mentioning that the purpose of the netc-lib driver is to
provide some NTMP-based generic interfaces for ENETC and NETC Switch
drivers. Currently, it only supports the configurations of some tables.
Interfaces such as tc flower and debugfs will be added in the future.

Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
 drivers/net/ethernet/freescale/enetc/Kconfig  |   8 +
 drivers/net/ethernet/freescale/enetc/Makefile |   3 +
 drivers/net/ethernet/freescale/enetc/ntmp.c   | 458 ++++++++++++++++++
 .../ethernet/freescale/enetc/ntmp_private.h   |  63 +++
 include/linux/fsl/ntmp.h                      | 174 +++++++
 5 files changed, 706 insertions(+)
 create mode 100644 drivers/net/ethernet/freescale/enetc/ntmp.c
 create mode 100644 drivers/net/ethernet/freescale/enetc/ntmp_private.h
 create mode 100644 include/linux/fsl/ntmp.h

diff --git a/drivers/net/ethernet/freescale/enetc/Kconfig b/drivers/net/ethernet/freescale/enetc/Kconfig
index 6c2779047dcd..c8efbb6f2055 100644
--- a/drivers/net/ethernet/freescale/enetc/Kconfig
+++ b/drivers/net/ethernet/freescale/enetc/Kconfig
@@ -15,6 +15,13 @@ config NXP_ENETC_PF_COMMON
 
 	  If compiled as module (M), the module name is nxp-enetc-pf-common.
 
+config NXP_NETC_LIB
+	tristate
+	help
+	  This module provides common functionalities for both ENETC and NETC
+	  Switch, such as NETC Table Management Protocol (NTMP) 2.0, common tc
+	  flower and debugfs interfaces and so on.
+
 config FSL_ENETC
 	tristate "ENETC PF driver"
 	depends on PCI_MSI
@@ -40,6 +47,7 @@ config NXP_ENETC4
 	select FSL_ENETC_CORE
 	select FSL_ENETC_MDIO
 	select NXP_ENETC_PF_COMMON
+	select NXP_NETC_LIB
 	select PHYLINK
 	select DIMLIB
 	help
diff --git a/drivers/net/ethernet/freescale/enetc/Makefile b/drivers/net/ethernet/freescale/enetc/Makefile
index 6fd27ee4fcd1..707a68e26971 100644
--- a/drivers/net/ethernet/freescale/enetc/Makefile
+++ b/drivers/net/ethernet/freescale/enetc/Makefile
@@ -6,6 +6,9 @@ fsl-enetc-core-y := enetc.o enetc_cbdr.o enetc_ethtool.o
 obj-$(CONFIG_NXP_ENETC_PF_COMMON) += nxp-enetc-pf-common.o
 nxp-enetc-pf-common-y := enetc_pf_common.o
 
+obj-$(CONFIG_NXP_NETC_LIB) += nxp-netc-lib.o
+nxp-netc-lib-y := ntmp.o
+
 obj-$(CONFIG_FSL_ENETC) += fsl-enetc.o
 fsl-enetc-y := enetc_pf.o
 fsl-enetc-$(CONFIG_PCI_IOV) += enetc_msg.o
diff --git a/drivers/net/ethernet/freescale/enetc/ntmp.c b/drivers/net/ethernet/freescale/enetc/ntmp.c
new file mode 100644
index 000000000000..df10f2f310c1
--- /dev/null
+++ b/drivers/net/ethernet/freescale/enetc/ntmp.c
@@ -0,0 +1,458 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * NETC NTMP (NETC Table Management Protocol) 2.0 Library
+ * Copyright 2025 NXP
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/fsl/netc_global.h>
+#include <linux/iopoll.h>
+
+#include "ntmp_private.h"
+
+#define NETC_CBDR_TIMEOUT		1000 /* us */
+#define NETC_CBDR_MR_EN			BIT(31)
+
+#define NTMP_BASE_ADDR_ALIGN		128
+#define NTMP_DATA_ADDR_ALIGN		32
+
+/* Define NTMP Table ID */
+#define NTMP_MAFT_ID			1
+#define NTMP_RSST_ID			3
+
+/* Generic Update Actions for most tables */
+#define NTMP_GEN_UA_CFGEU		BIT(0)
+#define NTMP_GEN_UA_STSEU		BIT(1)
+
+#define NTMP_ENTRY_ID_SIZE		4
+#define RSST_ENTRY_NUM			64
+#define RSST_STSE_DATA_SIZE(n)		((n) * 8)
+#define RSST_CFGE_DATA_SIZE(n)		(n)
+
+int netc_setup_cbdr(struct device *dev, int cbd_num,
+		    struct netc_cbdr_regs *regs,
+		    struct netc_cbdr *cbdr)
+{
+	size_t size;
+
+	size = cbd_num * sizeof(union netc_cbd) + NTMP_BASE_ADDR_ALIGN;
+	cbdr->addr_base = dma_alloc_coherent(dev, size, &cbdr->dma_base,
+					     GFP_KERNEL);
+	if (!cbdr->addr_base)
+		return -ENOMEM;
+
+	cbdr->dma_size = size;
+	cbdr->bd_num = cbd_num;
+	cbdr->regs = *regs;
+
+	/* The base address of the Control BD Ring must be 128 bytes aligned */
+	cbdr->dma_base_align =  ALIGN(cbdr->dma_base,  NTMP_BASE_ADDR_ALIGN);
+	cbdr->addr_base_align = PTR_ALIGN(cbdr->addr_base,
+					  NTMP_BASE_ADDR_ALIGN);
+
+	cbdr->next_to_clean = 0;
+	cbdr->next_to_use = 0;
+	spin_lock_init(&cbdr->ring_lock);
+
+	/* Step 1: Configure the base address of the Control BD Ring */
+	netc_write(cbdr->regs.bar0, lower_32_bits(cbdr->dma_base_align));
+	netc_write(cbdr->regs.bar1, upper_32_bits(cbdr->dma_base_align));
+
+	/* Step 2: Configure the producer index register */
+	netc_write(cbdr->regs.pir, cbdr->next_to_clean);
+
+	/* Step 3: Configure the consumer index register */
+	netc_write(cbdr->regs.cir, cbdr->next_to_use);
+
+	/* Step4: Configure the number of BDs of the Control BD Ring */
+	netc_write(cbdr->regs.lenr, cbdr->bd_num);
+
+	/* Step 5: Enable the Control BD Ring */
+	netc_write(cbdr->regs.mr, NETC_CBDR_MR_EN);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(netc_setup_cbdr);
+
+void netc_teardown_cbdr(struct device *dev, struct netc_cbdr *cbdr)
+{
+	/* Disable the Control BD Ring */
+	netc_write(cbdr->regs.mr, 0);
+	dma_free_coherent(dev, cbdr->dma_size, cbdr->addr_base,
+			  cbdr->dma_base);
+	memset(cbdr, 0, sizeof(*cbdr));
+}
+EXPORT_SYMBOL_GPL(netc_teardown_cbdr);
+
+static int netc_get_free_cbd_num(struct netc_cbdr *cbdr)
+{
+	return (cbdr->next_to_clean - cbdr->next_to_use - 1 +
+		cbdr->bd_num) % cbdr->bd_num;
+}
+
+static union netc_cbd *netc_get_cbd(struct netc_cbdr *cbdr, int index)
+{
+	return &((union netc_cbd *)(cbdr->addr_base_align))[index];
+}
+
+static void netc_clean_cbdr(struct netc_cbdr *cbdr)
+{
+	union netc_cbd *cbd;
+	int i;
+
+	i = cbdr->next_to_clean;
+	while (netc_read(cbdr->regs.cir) != i) {
+		cbd = netc_get_cbd(cbdr, i);
+		memset(cbd, 0, sizeof(*cbd));
+		i = (i + 1) % cbdr->bd_num;
+	}
+
+	cbdr->next_to_clean = i;
+}
+
+static struct netc_cbdr *netc_select_cbdr(struct netc_cbdrs *cbdrs)
+{
+	int i;
+
+	for (i = 0; i < cbdrs->cbdr_num; i++) {
+		if (spin_is_locked(&cbdrs->ring[i].ring_lock))
+			continue;
+
+		return &cbdrs->ring[i];
+	}
+
+	return &cbdrs->ring[smp_processor_id() % cbdrs->cbdr_num];
+}
+
+static int netc_xmit_ntmp_cmd(struct netc_cbdrs *cbdrs, union netc_cbd *cbd)
+{
+	union netc_cbd *cur_cbd;
+	struct netc_cbdr *cbdr;
+	int i, err;
+	u16 status;
+	u32 val;
+
+	if (cbdrs->cbdr_num == 1)
+		cbdr = &cbdrs->ring[0];
+	else
+		cbdr = netc_select_cbdr(cbdrs);
+
+	spin_lock_bh(&cbdr->ring_lock);
+
+	if (unlikely(!netc_get_free_cbd_num(cbdr)))
+		netc_clean_cbdr(cbdr);
+
+	i = cbdr->next_to_use;
+	cur_cbd = netc_get_cbd(cbdr, i);
+	*cur_cbd = *cbd;
+
+	/* Update producer index of both software and hardware */
+	i = (i + 1) % cbdr->bd_num;
+	cbdr->next_to_use = i;
+	dma_wmb();
+	netc_write(cbdr->regs.pir, i);
+
+	err = read_poll_timeout_atomic(netc_read, val, val == i,
+				       10, NETC_CBDR_TIMEOUT, true,
+				       cbdr->regs.cir);
+	if (unlikely(err))
+		goto cbdr_unlock;
+
+	dma_rmb();
+	/* Get the writeback command BD, because the caller may need
+	 * to check some other fields of the response header.
+	 */
+	*cbd = *cur_cbd;
+
+	/* Check the writeback error status */
+	status = le16_to_cpu(cbd->resp_hdr.error_rr) & NTMP_RESP_ERROR;
+	if (unlikely(status)) {
+		err = -EIO;
+		dev_err(cbdrs->dma_dev, "Command BD error: 0x%04x\n", status);
+	}
+
+	netc_clean_cbdr(cbdr);
+	dma_wmb();
+
+cbdr_unlock:
+	spin_unlock_bh(&cbdr->ring_lock);
+
+	return err;
+}
+
+static int ntmp_alloc_data_mem(struct ntmp_dma_buf *data, void **buf_align)
+{
+	void *buf;
+
+	buf = dma_alloc_coherent(data->dev, data->size + NTMP_DATA_ADDR_ALIGN,
+				 &data->dma, GFP_ATOMIC);
+	if (!buf)
+		return -ENOMEM;
+
+	data->buf = buf;
+	*buf_align = PTR_ALIGN(buf, NTMP_DATA_ADDR_ALIGN);
+
+	return 0;
+}
+
+static void ntmp_free_data_mem(struct ntmp_dma_buf *data)
+{
+	dma_free_coherent(data->dev, data->size + NTMP_DATA_ADDR_ALIGN,
+			  data->buf, data->dma);
+}
+
+static void ntmp_fill_request_headr(union netc_cbd *cbd, dma_addr_t dma,
+				    int len, int table_id, int cmd,
+				    int access_method)
+{
+	dma_addr_t dma_align;
+
+	memset(cbd, 0, sizeof(*cbd));
+	dma_align = ALIGN(dma, NTMP_DATA_ADDR_ALIGN);
+	cbd->req_hdr.addr = cpu_to_le64(dma_align);
+	cbd->req_hdr.len = cpu_to_le32(len);
+	cbd->req_hdr.cmd = cmd;
+	cbd->req_hdr.access_method = FIELD_PREP(NTMP_ACCESS_METHOD,
+						access_method);
+	cbd->req_hdr.table_id = table_id;
+	cbd->req_hdr.ver_cci_rr = FIELD_PREP(NTMP_HDR_VERSION,
+					     NTMP_HDR_VER2);
+	/* For NTMP version 2.0 or later version */
+	cbd->req_hdr.npf = cpu_to_le32(NTMP_NPF);
+}
+
+static void ntmp_fill_crd(struct common_req_data *crd,
+			  u8 tblv, u8 qa, u16 ua)
+{
+	crd->update_act = cpu_to_le16(ua);
+	crd->tblv_qact = NTMP_TBLV_QACT(tblv, qa);
+}
+
+static void ntmp_fill_crd_eid(struct ntmp_req_by_eid *rbe, u8 tblv,
+			      u8 qa, u16 ua, u32 entry_id)
+{
+	ntmp_fill_crd(&rbe->crd, tblv, qa, ua);
+	rbe->entry_id = cpu_to_le32(entry_id);
+}
+
+static int ntmp_delete_entry_by_id(struct netc_cbdrs *cbdrs, int tbl_id,
+				   u8 tbl_ver, u32 entry_id, u32 req_len,
+				   u32 resp_len)
+{
+	struct ntmp_dma_buf data = {.dev = cbdrs->dma_dev};
+	struct ntmp_req_by_eid *req;
+	union netc_cbd cbd;
+	u32 len;
+	int err;
+
+	if (entry_id == NTMP_NULL_ENTRY_ID)
+		return 0;
+
+	/* If the req_len is 0, indicates the requested length is the
+	 * standard length.
+	 */
+	if (!req_len)
+		req_len = sizeof(*req);
+
+	data.size = req_len >= resp_len ? req_len : resp_len;
+	err = ntmp_alloc_data_mem(&data, (void **)&req);
+	if (err)
+		return err;
+
+	ntmp_fill_crd_eid(req, tbl_ver, 0, 0, entry_id);
+	len = NTMP_LEN(req_len, resp_len);
+	ntmp_fill_request_headr(&cbd, data.dma, len, tbl_id,
+				NTMP_CMD_DELETE, NTMP_AM_ENTRY_ID);
+
+	err = netc_xmit_ntmp_cmd(cbdrs, &cbd);
+	if (err)
+		dev_err(cbdrs->dma_dev, "Delete table (id: %d) entry failed: %d",
+			tbl_id, err);
+
+	ntmp_free_data_mem(&data);
+
+	return err;
+}
+
+static int ntmp_query_entry_by_id(struct netc_cbdrs *cbdrs, int tbl_id,
+				  u32 len, struct ntmp_req_by_eid *req,
+				  dma_addr_t dma, bool compare_eid)
+{
+	struct device *dev = cbdrs->dma_dev;
+	struct common_resp_query *resp;
+	int cmd = NTMP_CMD_QUERY;
+	union netc_cbd cbd;
+	u32 entry_id;
+	int err;
+
+	entry_id = le32_to_cpu(req->entry_id);
+	if (le16_to_cpu(req->crd.update_act))
+		cmd = NTMP_CMD_QU;
+
+	/* Request header */
+	ntmp_fill_request_headr(&cbd, dma, len, tbl_id,
+				cmd, NTMP_AM_ENTRY_ID);
+
+	err = netc_xmit_ntmp_cmd(cbdrs, &cbd);
+	if (err) {
+		dev_err(dev, "Query table (id: %d) entry failed: %d\n",
+			tbl_id, err);
+		return err;
+	}
+
+	/* For a few tables, the first field of its response data is not
+	 * entry_id, so directly return success.
+	 */
+	if (!compare_eid)
+		return 0;
+
+	resp = (struct common_resp_query *)req;
+	if (unlikely(le32_to_cpu(resp->entry_id) != entry_id)) {
+		dev_err(dev, "Table (id: %d) query EID:0x%0x, response EID:0x%x\n",
+			tbl_id, entry_id, le32_to_cpu(resp->entry_id));
+		return -EIO;
+	}
+
+	return 0;
+}
+
+int ntmp_maft_add_entry(struct netc_cbdrs *cbdrs, u32 entry_id,
+			struct maft_entry_data *maft)
+{
+	struct ntmp_dma_buf data = {.dev = cbdrs->dma_dev};
+	struct maft_req_add *req;
+	union netc_cbd cbd;
+	int err;
+
+	data.size = sizeof(*req);
+	err = ntmp_alloc_data_mem(&data, (void **)&req);
+	if (err)
+		return err;
+
+	/* Set mac address filter table request data buffer */
+	ntmp_fill_crd_eid(&req->rbe, cbdrs->tbl.maft_ver, 0, 0, entry_id);
+	req->keye = maft->keye;
+	req->cfge = maft->cfge;
+
+	ntmp_fill_request_headr(&cbd, data.dma, NTMP_LEN(data.size, 0),
+				NTMP_MAFT_ID, NTMP_CMD_ADD,
+				NTMP_AM_ENTRY_ID);
+	err = netc_xmit_ntmp_cmd(cbdrs, &cbd);
+	if (err)
+		dev_err(cbdrs->dma_dev, "Add MAFT entry failed (%d)", err);
+
+	ntmp_free_data_mem(&data);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(ntmp_maft_add_entry);
+
+int ntmp_maft_query_entry(struct netc_cbdrs *cbdrs, u32 entry_id,
+			  struct maft_entry_data *maft)
+{
+	struct ntmp_dma_buf data = {.dev = cbdrs->dma_dev};
+	struct maft_resp_query *resp;
+	struct ntmp_req_by_eid *req;
+	u32 req_len = sizeof(*req);
+	int err;
+
+	if (entry_id == NTMP_NULL_ENTRY_ID)
+		return -EINVAL;
+
+	data.size = sizeof(*resp);
+	err = ntmp_alloc_data_mem(&data, (void **)&req);
+	if (err)
+		return err;
+
+	ntmp_fill_crd_eid(req, cbdrs->tbl.maft_ver, 0, 0, entry_id);
+	err = ntmp_query_entry_by_id(cbdrs, NTMP_MAFT_ID,
+				     NTMP_LEN(req_len, data.size),
+				     req, data.dma, true);
+	if (err)
+		goto end;
+
+	resp = (struct maft_resp_query *)req;
+	maft->keye = resp->keye;
+	maft->cfge = resp->cfge;
+
+end:
+	ntmp_free_data_mem(&data);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(ntmp_maft_query_entry);
+
+int ntmp_maft_delete_entry(struct netc_cbdrs *cbdrs, u32 entry_id)
+{
+	return ntmp_delete_entry_by_id(cbdrs, NTMP_MAFT_ID,
+				       cbdrs->tbl.maft_ver,
+				       entry_id, 0, 0);
+}
+EXPORT_SYMBOL_GPL(ntmp_maft_delete_entry);
+
+int ntmp_rsst_query_or_update_entry(struct netc_cbdrs *cbdrs, u32 *table,
+				    int count, bool query)
+{
+	struct ntmp_dma_buf data = {.dev = cbdrs->dma_dev};
+	struct rsst_req_update *requ;
+	struct ntmp_req_by_eid *req;
+	union netc_cbd cbd;
+	int err, i;
+	u32 len;
+
+	if (count != RSST_ENTRY_NUM)
+		/* HW only takes in a full 64 entry table */
+		return -EINVAL;
+
+	if (query)
+		data.size = NTMP_ENTRY_ID_SIZE + RSST_STSE_DATA_SIZE(count) +
+			    RSST_CFGE_DATA_SIZE(count);
+	else
+		data.size = struct_size(requ, groups, count);
+
+	err = ntmp_alloc_data_mem(&data, (void **)&req);
+	if (err)
+		return err;
+
+	/* Set the request data buffer */
+	if (query) {
+		ntmp_fill_crd_eid(req, cbdrs->tbl.rsst_ver, 0, 0, 0);
+		len = NTMP_LEN(sizeof(*req), data.size);
+		ntmp_fill_request_headr(&cbd, data.dma, len, NTMP_RSST_ID,
+					NTMP_CMD_QUERY, NTMP_AM_ENTRY_ID);
+	} else {
+		requ = (struct rsst_req_update *)req;
+		ntmp_fill_crd_eid(&requ->rbe, cbdrs->tbl.rsst_ver, 0,
+				  NTMP_GEN_UA_CFGEU | NTMP_GEN_UA_STSEU, 0);
+		for (i = 0; i < count; i++)
+			requ->groups[i] = (u8)(table[i]);
+
+		len = NTMP_LEN(data.size, 0);
+		ntmp_fill_request_headr(&cbd, data.dma, len, NTMP_RSST_ID,
+					NTMP_CMD_UPDATE, NTMP_AM_ENTRY_ID);
+	}
+
+	err = netc_xmit_ntmp_cmd(cbdrs, &cbd);
+	if (err) {
+		dev_err(cbdrs->dma_dev, "%s RSS table entry failed (%d)",
+			query ? "Query" : "Update", err);
+		goto end;
+	}
+
+	if (query) {
+		u8 *group = (u8 *)req;
+
+		group += NTMP_ENTRY_ID_SIZE + RSST_STSE_DATA_SIZE(count);
+		for (i = 0; i < count; i++)
+			table[i] = group[i];
+	}
+
+end:
+	ntmp_free_data_mem(&data);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(ntmp_rsst_query_or_update_entry);
+
+MODULE_DESCRIPTION("NXP NETC Library");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/ethernet/freescale/enetc/ntmp_private.h b/drivers/net/ethernet/freescale/enetc/ntmp_private.h
new file mode 100644
index 000000000000..45e4d083ab0a
--- /dev/null
+++ b/drivers/net/ethernet/freescale/enetc/ntmp_private.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/*
+ * NTMP table request and response data buffer formats
+ * Copyright 2025 NXP
+ */
+
+#ifndef __NTMP_PRIVATE_H
+#define __NTMP_PRIVATE_H
+
+#include <linux/fsl/ntmp.h>
+
+struct ntmp_dma_buf {
+	struct device *dev;
+	size_t size;
+	void *buf;
+	dma_addr_t dma;
+};
+
+struct common_req_data {
+	__le16 update_act;
+	u8 dbg_opt;
+	u8 tblv_qact;
+#define NTMP_QUERY_ACT		GENMASK(3, 0)
+#define NTMP_TBL_VER		GENMASK(7, 0)
+#define NTMP_TBLV_QACT(v, a)	(FIELD_PREP(NTMP_TBL_VER, (v)) | \
+				 ((a) & NTMP_QUERY_ACT))
+};
+
+struct common_resp_query {
+	__le32 entry_id;
+};
+
+struct common_resp_nq {
+	__le32 status;
+};
+
+/* Generic structure for request data by entry ID  */
+struct ntmp_req_by_eid {
+	struct common_req_data crd;
+	__le32 entry_id;
+};
+
+/* MAC Address Filter Table Request Data Buffer Format of Add action */
+struct maft_req_add {
+	struct ntmp_req_by_eid rbe;
+	struct maft_keye_data keye;
+	struct maft_cfge_data cfge;
+};
+
+/* MAC Address Filter Table Response Data Buffer Format of Query action */
+struct maft_resp_query {
+	__le32 entry_id;
+	struct maft_keye_data keye;
+	struct maft_cfge_data cfge;
+};
+
+/* RSS Table Request Data Buffer Format of Update action */
+struct rsst_req_update {
+	struct ntmp_req_by_eid rbe;
+	u8 groups[];
+};
+
+#endif
diff --git a/include/linux/fsl/ntmp.h b/include/linux/fsl/ntmp.h
new file mode 100644
index 000000000000..fe15e394c4a4
--- /dev/null
+++ b/include/linux/fsl/ntmp.h
@@ -0,0 +1,174 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/* Copyright 2025 NXP */
+#ifndef __NETC_NTMP_H
+#define __NETC_NTMP_H
+
+#include <linux/bitops.h>
+#include <linux/if_ether.h>
+
+#define NTMP_NULL_ENTRY_ID		0xffffffffU
+#define NETC_CBDR_BD_NUM		256
+
+union netc_cbd {
+	struct {
+		__le64 addr;
+		__le32 len;
+#define NTMP_RESP_LEN		GENMASK(19, 0)
+#define NTMP_REQ_LEN		GENMASK(31, 20)
+#define NTMP_LEN(req, resp)	(FIELD_PREP(NTMP_REQ_LEN, (req)) | \
+				((resp) & NTMP_RESP_LEN))
+		u8 cmd;
+#define NTMP_CMD_DELETE		BIT(0)
+#define NTMP_CMD_UPDATE		BIT(1)
+#define NTMP_CMD_QUERY		BIT(2)
+#define NTMP_CMD_ADD		BIT(3)
+#define NTMP_CMD_QD		(NTMP_CMD_QUERY | NTMP_CMD_DELETE)
+#define NTMP_CMD_QU		(NTMP_CMD_QUERY | NTMP_CMD_UPDATE)
+#define NTMP_CMD_AU		(NTMP_CMD_ADD | NTMP_CMD_UPDATE)
+#define NTMP_CMD_AQ		(NTMP_CMD_ADD | NTMP_CMD_QUERY)
+#define NTMP_CMD_AQU		(NTMP_CMD_AQ | NTMP_CMD_UPDATE)
+		u8 access_method;
+#define NTMP_ACCESS_METHOD	GENMASK(7, 4)
+#define NTMP_AM_ENTRY_ID	0
+#define NTMP_AM_EXACT_KEY	1
+#define NTMP_AM_SEARCH		2
+#define NTMP_AM_TERNARY_KEY	3
+		u8 table_id;
+		u8 ver_cci_rr;
+#define NTMP_HDR_VERSION	GENMASK(5, 0)
+#define NTMP_HDR_VER2		2
+#define NTMP_CCI		BIT(6)
+#define NTMP_RR			BIT(7)
+		__le32 resv[3];
+		__le32 npf;
+#define NTMP_NPF		BIT(15)
+	} req_hdr;	/* NTMP Request Message Header Format */
+
+	struct {
+		__le32 resv0[3];
+		__le16 num_matched;
+		__le16 error_rr;
+#define NTMP_RESP_ERROR		GENMASK(11, 0)
+#define NTMP_RESP_RR		BIT(15)
+		__le32 resv1[4];
+	} resp_hdr; /* NTMP Response Message Header Format */
+};
+
+struct maft_keye_data {
+	u8 mac_addr[ETH_ALEN];
+	__le16 resv;
+};
+
+struct maft_cfge_data {
+	__le16 si_bitmap;
+	__le16 resv;
+};
+
+struct netc_cbdr_regs {
+	void __iomem *pir;
+	void __iomem *cir;
+	void __iomem *mr;
+
+	void __iomem *bar0;
+	void __iomem *bar1;
+	void __iomem *lenr;
+};
+
+struct netc_tbl_vers {
+	u8 maft_ver;
+	u8 rsst_ver;
+};
+
+struct netc_cbdr {
+	struct netc_cbdr_regs regs;
+
+	int bd_num;
+	int next_to_use;
+	int next_to_clean;
+
+	int dma_size;
+	void *addr_base;
+	void *addr_base_align;
+	dma_addr_t dma_base;
+	dma_addr_t dma_base_align;
+
+	spinlock_t ring_lock; /* Avoid race condition */
+};
+
+struct netc_cbdrs {
+	int cbdr_num;	/* number of control BD ring */
+	int cbdr_size;	/* number of BDs per control BD ring */
+	struct device *dma_dev;
+	struct netc_cbdr *ring;
+	struct netc_tbl_vers tbl;
+};
+
+enum netc_dev_type {
+	NETC_DEV_ENETC,
+	NETC_DEV_SWITCH
+};
+
+struct ntmp_priv {
+	enum netc_dev_type dev_type;
+	struct netc_cbdrs cbdrs;
+};
+
+struct maft_entry_data {
+	struct maft_keye_data keye;
+	struct maft_cfge_data cfge;
+};
+
+#if IS_ENABLED(CONFIG_NXP_NETC_LIB)
+int netc_setup_cbdr(struct device *dev, int cbd_num,
+		    struct netc_cbdr_regs *regs,
+		    struct netc_cbdr *cbdr);
+void netc_teardown_cbdr(struct device *dev, struct netc_cbdr *cbdr);
+
+/* NTMP APIs */
+int ntmp_maft_add_entry(struct netc_cbdrs *cbdrs, u32 entry_id,
+			struct maft_entry_data *maft);
+int ntmp_maft_query_entry(struct netc_cbdrs *cbdrs, u32 entry_id,
+			  struct maft_entry_data *maft);
+int ntmp_maft_delete_entry(struct netc_cbdrs *cbdrs, u32 entry_id);
+int ntmp_rsst_query_or_update_entry(struct netc_cbdrs *cbdrs,
+				    u32 *table, int count, bool query);
+#else
+static inline int netc_setup_cbdr(struct device *dev, int cbd_num,
+				  struct netc_cbdr_regs *regs,
+				  struct netc_cbdr *cbdr)
+{
+	return 0;
+}
+
+static inline void netc_teardown_cbdr(struct device *dev,
+				      struct netc_cbdr *cbdr)
+{
+}
+
+static inline int ntmp_maft_add_entry(struct netc_cbdrs *cbdrs, u32 entry_id,
+				      struct maft_entry_data *maft)
+{
+	return 0;
+}
+
+static inline int ntmp_maft_query_entry(struct netc_cbdrs *cbdrs, u32 entry_id,
+					struct maft_entry_data *maft)
+{
+	return 0;
+}
+
+static inline int ntmp_maft_delete_entry(struct netc_cbdrs *cbdrs, u32 entry_id)
+{
+	return 0;
+}
+
+static inline int ntmp_rsst_query_or_update_entry(struct netc_cbdrs *cbdrs,
+						  u32 *table, int count,
+						  bool query)
+{
+	return 0;
+}
+
+#endif
+
+#endif
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v4 net-next 02/14] net: enetc: add command BD ring support for i.MX95 ENETC
  2025-03-11  5:38 [PATCH v4 net-next 00/14] Add more feautues for ENETC v4 - round 2 Wei Fang
  2025-03-11  5:38 ` [PATCH v4 net-next 01/14] net: enetc: add initial netc-lib driver to support NTMP Wei Fang
@ 2025-03-11  5:38 ` Wei Fang
  2025-03-11 12:22   ` Michal Kubiak
  2025-03-13 16:49   ` Vladimir Oltean
  2025-03-11  5:38 ` [PATCH v4 net-next 03/14] net: enetc: move generic MAC filterng interfaces to enetc-core Wei Fang
                   ` (12 subsequent siblings)
  14 siblings, 2 replies; 58+ messages in thread
From: Wei Fang @ 2025-03-11  5:38 UTC (permalink / raw)
  To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
	davem, edumazet, kuba, pabeni
  Cc: christophe.leroy, netdev, linux-kernel, imx, linuxppc-dev,
	linux-arm-kernel

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=y, Size: 12052 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 | 55 +++++++++++++++++--
 .../net/ethernet/freescale/enetc/enetc_pf.c   | 13 +++--
 .../net/ethernet/freescale/enetc/enetc_vf.c   | 13 +++--
 5 files changed, 136 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 73ac8c6afb3a..63001379f0a0 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..4e5125331d7b 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,45 @@ 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;
+
+	/* 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 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 +94,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


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v4 net-next 03/14] net: enetc: move generic MAC filterng interfaces to enetc-core
  2025-03-11  5:38 [PATCH v4 net-next 00/14] Add more feautues for ENETC v4 - round 2 Wei Fang
  2025-03-11  5:38 ` [PATCH v4 net-next 01/14] net: enetc: add initial netc-lib driver to support NTMP Wei Fang
  2025-03-11  5:38 ` [PATCH v4 net-next 02/14] net: enetc: add command BD ring support for i.MX95 ENETC Wei Fang
@ 2025-03-11  5:38 ` Wei Fang
  2025-03-17  9:42   ` Vladimir Oltean
  2025-03-11  5:38 ` [PATCH v4 net-next 04/14] net: enetc: add MAC filter for i.MX95 ENETC PF Wei Fang
                   ` (11 subsequent siblings)
  14 siblings, 1 reply; 58+ messages in thread
From: Wei Fang @ 2025-03-11  5:38 UTC (permalink / raw)
  To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
	davem, edumazet, kuba, pabeni
  Cc: christophe.leroy, netdev, linux-kernel, imx, linuxppc-dev,
	linux-arm-kernel

Although only ENETC PF can access the MAC address filter table, the table
entries can specify MAC address filtering for one or more SIs based on
SI_BITMAP, which means that the table also supports MAC address filtering
for VFs.

Currently, only the ENETC v1 PF driver supports MAC address filtering. In
order to add the MAC address filtering support for the ENETC v4 PF driver
and VF driver in the future, the relevant generic interfaces are moved to
the enetc-core driver. At the same time, the struct enetc_mac_filter is
moved from enetc_pf to enetc_si, because enetc_si is a structure shared by
PF and VFs. This lays the basis for i.MX95 ENETC PF and VFs to support
MAC address filtering.

Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
 drivers/net/ethernet/freescale/enetc/enetc.c  | 36 ++++++++++++++
 drivers/net/ethernet/freescale/enetc/enetc.h  | 17 +++++++
 .../net/ethernet/freescale/enetc/enetc_pf.c   | 49 +++----------------
 .../net/ethernet/freescale/enetc/enetc_pf.h   | 14 ------
 4 files changed, 60 insertions(+), 56 deletions(-)

diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
index 2106861463e4..3832d2cd91ba 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
@@ -36,6 +36,42 @@ static void enetc_change_preemptible_tcs(struct enetc_ndev_priv *priv,
 	enetc_mm_commit_preemptible_tcs(priv);
 }
 
+static int enetc_mac_addr_hash_idx(const u8 *addr)
+{
+	u64 fold = __swab64(ether_addr_to_u64(addr)) >> 16;
+	u64 mask = 0;
+	int res = 0;
+	int i;
+
+	for (i = 0; i < 8; i++)
+		mask |= BIT_ULL(i * 6);
+
+	for (i = 0; i < 6; i++)
+		res |= (hweight64(fold & (mask << i)) & 0x1) << i;
+
+	return res;
+}
+
+void enetc_add_mac_addr_ht_filter(struct enetc_mac_filter *filter,
+				  const unsigned char *addr)
+{
+	int idx = enetc_mac_addr_hash_idx(addr);
+
+	/* add hash table entry */
+	__set_bit(idx, filter->mac_hash_table);
+	filter->mac_addr_cnt++;
+}
+EXPORT_SYMBOL_GPL(enetc_add_mac_addr_ht_filter);
+
+void enetc_reset_mac_addr_filter(struct enetc_mac_filter *filter)
+{
+	filter->mac_addr_cnt = 0;
+
+	bitmap_zero(filter->mac_hash_table,
+		    ENETC_MADDR_HASH_TBL_SZ);
+}
+EXPORT_SYMBOL_GPL(enetc_reset_mac_addr_filter);
+
 static int enetc_num_stack_tx_queues(struct enetc_ndev_priv *priv)
 {
 	int num_tx_rings = priv->num_tx_rings;
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index 4ff0957e69be..9380d3e8ca01 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -23,6 +23,18 @@
 
 #define ENETC_CBD_DATA_MEM_ALIGN 64
 
+#define ENETC_MADDR_HASH_TBL_SZ	64
+
+enum enetc_mac_addr_type {UC, MC, MADDR_TYPE};
+
+struct enetc_mac_filter {
+	union {
+		char mac_addr[ETH_ALEN];
+		DECLARE_BITMAP(mac_hash_table, ENETC_MADDR_HASH_TBL_SZ);
+	};
+	int mac_addr_cnt;
+};
+
 struct enetc_tx_swbd {
 	union {
 		struct sk_buff *skb;
@@ -302,6 +314,8 @@ struct enetc_si {
 	int hw_features;
 	const struct enetc_drvdata *drvdata;
 	const struct enetc_si_ops *ops;
+
+	struct enetc_mac_filter mac_filter[MADDR_TYPE];
 };
 
 #define ENETC_SI_ALIGN	32
@@ -484,6 +498,9 @@ int enetc_alloc_si_resources(struct enetc_ndev_priv *priv);
 void enetc_free_si_resources(struct enetc_ndev_priv *priv);
 int enetc_configure_si(struct enetc_ndev_priv *priv);
 int enetc_get_driver_data(struct enetc_si *si);
+void enetc_add_mac_addr_ht_filter(struct enetc_mac_filter *filter,
+				  const unsigned char *addr);
+void enetc_reset_mac_addr_filter(struct enetc_mac_filter *filter);
 
 int enetc_open(struct net_device *ndev);
 int enetc_close(struct net_device *ndev);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index a214749a4af6..cc3e52bd3096 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -72,30 +72,6 @@ static void enetc_set_isol_vlan(struct enetc_hw *hw, int si, u16 vlan, u8 qos)
 	enetc_port_wr(hw, ENETC_PSIVLANR(si), val);
 }
 
-static int enetc_mac_addr_hash_idx(const u8 *addr)
-{
-	u64 fold = __swab64(ether_addr_to_u64(addr)) >> 16;
-	u64 mask = 0;
-	int res = 0;
-	int i;
-
-	for (i = 0; i < 8; i++)
-		mask |= BIT_ULL(i * 6);
-
-	for (i = 0; i < 6; i++)
-		res |= (hweight64(fold & (mask << i)) & 0x1) << i;
-
-	return res;
-}
-
-static void enetc_reset_mac_addr_filter(struct enetc_mac_filter *filter)
-{
-	filter->mac_addr_cnt = 0;
-
-	bitmap_zero(filter->mac_hash_table,
-		    ENETC_MADDR_HASH_TBL_SZ);
-}
-
 static void enetc_add_mac_addr_em_filter(struct enetc_mac_filter *filter,
 					 const unsigned char *addr)
 {
@@ -104,16 +80,6 @@ static void enetc_add_mac_addr_em_filter(struct enetc_mac_filter *filter,
 	filter->mac_addr_cnt++;
 }
 
-static void enetc_add_mac_addr_ht_filter(struct enetc_mac_filter *filter,
-					 const unsigned char *addr)
-{
-	int idx = enetc_mac_addr_hash_idx(addr);
-
-	/* add hash table entry */
-	__set_bit(idx, filter->mac_hash_table);
-	filter->mac_addr_cnt++;
-}
-
 static void enetc_clear_mac_ht_flt(struct enetc_si *si, int si_idx, int type)
 {
 	bool err = si->errata & ENETC_ERR_UCMCSWP;
@@ -145,10 +111,9 @@ static void enetc_set_mac_ht_flt(struct enetc_si *si, int si_idx, int type,
 	}
 }
 
-static void enetc_sync_mac_filters(struct enetc_pf *pf)
+static void enetc_sync_mac_filters(struct enetc_si *si)
 {
-	struct enetc_mac_filter *f = pf->mac_filter;
-	struct enetc_si *si = pf->si;
+	struct enetc_mac_filter *f = si->mac_filter;
 	int i, pos;
 
 	pos = EMETC_MAC_ADDR_FILT_RES;
@@ -192,10 +157,10 @@ static void enetc_sync_mac_filters(struct enetc_pf *pf)
 static void enetc_pf_set_rx_mode(struct net_device *ndev)
 {
 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
-	struct enetc_pf *pf = enetc_si_priv(priv->si);
-	struct enetc_hw *hw = &priv->si->hw;
 	bool uprom = false, mprom = false;
 	struct enetc_mac_filter *filter;
+	struct enetc_si *si = priv->si;
+	struct enetc_hw *hw = &si->hw;
 	struct netdev_hw_addr *ha;
 	u32 psipmr = 0;
 	bool em;
@@ -214,7 +179,7 @@ static void enetc_pf_set_rx_mode(struct net_device *ndev)
 	/* first 2 filter entries belong to PF */
 	if (!uprom) {
 		/* Update unicast filters */
-		filter = &pf->mac_filter[UC];
+		filter = &si->mac_filter[UC];
 		enetc_reset_mac_addr_filter(filter);
 
 		em = (netdev_uc_count(ndev) == 1);
@@ -230,7 +195,7 @@ static void enetc_pf_set_rx_mode(struct net_device *ndev)
 
 	if (!mprom) {
 		/* Update multicast filters */
-		filter = &pf->mac_filter[MC];
+		filter = &si->mac_filter[MC];
 		enetc_reset_mac_addr_filter(filter);
 
 		netdev_for_each_mc_addr(ha, ndev) {
@@ -243,7 +208,7 @@ static void enetc_pf_set_rx_mode(struct net_device *ndev)
 
 	if (!uprom || !mprom)
 		/* update PF entries */
-		enetc_sync_mac_filters(pf);
+		enetc_sync_mac_filters(si);
 
 	psipmr |= enetc_port_rd(hw, ENETC_PSIPMR) &
 		  ~(ENETC_PSIPMR_SET_UP(0) | ENETC_PSIPMR_SET_MP(0));
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.h b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
index a26a12863855..2b9d0f625f01 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
@@ -6,18 +6,6 @@
 
 #define ENETC_PF_NUM_RINGS	8
 
-enum enetc_mac_addr_type {UC, MC, MADDR_TYPE};
-#define ENETC_MAX_NUM_MAC_FLT	((ENETC_MAX_NUM_VFS + 1) * MADDR_TYPE)
-
-#define ENETC_MADDR_HASH_TBL_SZ	64
-struct enetc_mac_filter {
-	union {
-		char mac_addr[ETH_ALEN];
-		DECLARE_BITMAP(mac_hash_table, ENETC_MADDR_HASH_TBL_SZ);
-	};
-	int mac_addr_cnt;
-};
-
 #define ENETC_VLAN_HT_SIZE	64
 
 enum enetc_vf_flags {
@@ -52,8 +40,6 @@ struct enetc_pf {
 	int total_vfs; /* max number of VFs, set for PF at probe */
 	struct enetc_vf_state *vf_state;
 
-	struct enetc_mac_filter mac_filter[ENETC_MAX_NUM_MAC_FLT];
-
 	struct enetc_msg_swbd rxmsg[ENETC_MAX_NUM_VFS];
 	struct work_struct msg_task;
 	char msg_int_name[ENETC_INT_NAME_MAX];
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v4 net-next 04/14] net: enetc: add MAC filter for i.MX95 ENETC PF
  2025-03-11  5:38 [PATCH v4 net-next 00/14] Add more feautues for ENETC v4 - round 2 Wei Fang
                   ` (2 preceding siblings ...)
  2025-03-11  5:38 ` [PATCH v4 net-next 03/14] net: enetc: move generic MAC filterng interfaces to enetc-core Wei Fang
@ 2025-03-11  5:38 ` Wei Fang
  2025-03-17 14:18   ` Vladimir Oltean
  2025-03-11  5:38 ` [PATCH v4 net-next 05/14] net: enetc: add debugfs interface to dump MAC filter Wei Fang
                   ` (10 subsequent siblings)
  14 siblings, 1 reply; 58+ messages in thread
From: Wei Fang @ 2025-03-11  5:38 UTC (permalink / raw)
  To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
	davem, edumazet, kuba, pabeni
  Cc: christophe.leroy, netdev, linux-kernel, imx, linuxppc-dev,
	linux-arm-kernel

The i.MX95 ENETC supports both MAC hash filter and MAC exact filter. MAC
hash filter is implenented through a 64-bits hash table to match against
the hashed addresses, PF and VFs each have two MAC hash tables, one is
for unicast and the other one is for multicast. But MAC exact filter is
shared between SIs (PF and VFs), each table entry contains a MAC address
that may be unicast or multicast and the entry also contains an SI bitmap
field that indicates for which SIs the entry is valid.

For i.MX95 ENETC, MAC exact filter only has 4 entries. According to the
observation of the system default network configuration, the MAC filter
will be configured with multiple multicast addresses, so MAC exact filter
does not have enough entries to implement multicast filtering. Therefore,
the current MAC exact filter is only used for unicast filtering. If the
number of unicast addresses exceeds 4, then MAC hash filter is used.

Note that both MAC hash filter and MAC exact filter can only be accessed
by PF, VFs can notify PF to set its corresponding MAC filter through the
mailbox mechanism of ENETC. But currently MAC filter is only added for
i.MX95 ENETC PF. The MAC filter support of ENETC VFs will be supported in
subsequent patches.

Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
 drivers/net/ethernet/freescale/enetc/enetc.h  |   2 +
 .../net/ethernet/freescale/enetc/enetc4_hw.h  |   8 +
 .../net/ethernet/freescale/enetc/enetc4_pf.c  | 422 +++++++++++++++++-
 .../net/ethernet/freescale/enetc/enetc_hw.h   |   6 +
 .../net/ethernet/freescale/enetc/enetc_pf.h   |  11 +
 5 files changed, 448 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index 9380d3e8ca01..4dba91408e3d 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -316,6 +316,8 @@ struct enetc_si {
 	const struct enetc_si_ops *ops;
 
 	struct enetc_mac_filter mac_filter[MADDR_TYPE];
+	struct workqueue_struct *workqueue;
+	struct work_struct rx_mode_task;
 };
 
 #define ENETC_SI_ALIGN	32
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
index 695cb07c74bc..826359004850 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
@@ -99,6 +99,14 @@
 #define ENETC4_PSICFGR2(a)		((a) * 0x80 + 0x2018)
 #define  PSICFGR2_NUM_MSIX		GENMASK(5, 0)
 
+/* Port station interface a unicast MAC hash filter register 0/1 */
+#define ENETC4_PSIUMHFR0(a)		((a) * 0x80 + 0x2050)
+#define ENETC4_PSIUMHFR1(a)		((a) * 0x80 + 0x2054)
+
+/* Port station interface a multicast MAC hash filter register 0/1 */
+#define ENETC4_PSIMMHFR0(a)		((a) * 0x80 + 0x2058)
+#define ENETC4_PSIMMHFR1(a)		((a) * 0x80 + 0x205c)
+
 #define ENETC4_PMCAPR			0x4004
 #define  PMCAPR_HD			BIT(8)
 #define  PMCAPR_FP			GENMASK(10, 9)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index 63001379f0a0..7d1c545f3f56 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -11,6 +11,15 @@
 
 #define ENETC_SI_MAX_RING_NUM	8
 
+#define ENETC_MAC_FILTER_TYPE_UC	BIT(0)
+#define ENETC_MAC_FILTER_TYPE_MC	BIT(1)
+#define ENETC_MAC_FILTER_TYPE_ALL	(ENETC_MAC_FILTER_TYPE_UC | \
+					 ENETC_MAC_FILTER_TYPE_MC)
+
+struct enetc_mac_addr {
+	u8 addr[ETH_ALEN];
+};
+
 static void enetc4_get_port_caps(struct enetc_pf *pf)
 {
 	struct enetc_hw *hw = &pf->si->hw;
@@ -26,6 +35,9 @@ static void enetc4_get_port_caps(struct enetc_pf *pf)
 
 	val = enetc_port_rd(hw, ENETC4_PMCAPR);
 	pf->caps.half_duplex = (val & PMCAPR_HD) ? 1 : 0;
+
+	val = enetc_port_rd(hw, ENETC4_PSIMAFCAPR);
+	pf->caps.mac_filter_num = val & PSIMAFCAPR_NUM_MAC_AFTE;
 }
 
 static void enetc4_pf_set_si_primary_mac(struct enetc_hw *hw, int si,
@@ -56,6 +68,341 @@ static void enetc4_pf_get_si_primary_mac(struct enetc_hw *hw, int si,
 	put_unaligned_le16(lower, addr + 4);
 }
 
+static void enetc4_pf_set_si_mac_promisc(struct enetc_hw *hw, int si,
+					 int type, bool en)
+{
+	u32 val = enetc_port_rd(hw, ENETC4_PSIPMMR);
+
+	if (type == UC) {
+		if (en)
+			val |= PSIPMMR_SI_MAC_UP(si);
+		else
+			val &= ~PSIPMMR_SI_MAC_UP(si);
+	} else { /* Multicast promiscuous mode. */
+		if (en)
+			val |= PSIPMMR_SI_MAC_MP(si);
+		else
+			val &= ~PSIPMMR_SI_MAC_MP(si);
+	}
+
+	enetc_port_wr(hw, ENETC4_PSIPMMR, val);
+}
+
+static void enetc4_pf_set_si_mac_hash_filter(struct enetc_hw *hw, int si,
+					     int type, u64 hash)
+{
+	if (type == UC) {
+		enetc_port_wr(hw, ENETC4_PSIUMHFR0(si), lower_32_bits(hash));
+		enetc_port_wr(hw, ENETC4_PSIUMHFR1(si), upper_32_bits(hash));
+	} else { /* MC */
+		enetc_port_wr(hw, ENETC4_PSIMMHFR0(si), lower_32_bits(hash));
+		enetc_port_wr(hw, ENETC4_PSIMMHFR1(si), upper_32_bits(hash));
+	}
+}
+
+static void enetc4_pf_destroy_mac_list(struct enetc_pf *pf)
+{
+	struct enetc_mac_list_entry *entry;
+	struct hlist_node *tmp;
+
+	mutex_lock(&pf->mac_list_lock);
+
+	hlist_for_each_entry_safe(entry, tmp, &pf->mac_list, node) {
+		hlist_del(&entry->node);
+		kfree(entry);
+	}
+
+	pf->num_mfe = 0;
+
+	mutex_unlock(&pf->mac_list_lock);
+}
+
+static bool enetc_mac_filter_type_check(int type, const u8 *addr)
+{
+	if (type == ENETC_MAC_FILTER_TYPE_UC)
+		return !is_multicast_ether_addr(addr);
+	else if (type == ENETC_MAC_FILTER_TYPE_MC)
+		return is_multicast_ether_addr(addr);
+	else
+		return true;
+}
+
+static struct enetc_mac_list_entry *
+enetc_mac_list_lookup_entry(struct enetc_pf *pf, const unsigned char *addr)
+{
+	struct enetc_mac_list_entry *entry;
+
+	hlist_for_each_entry(entry, &pf->mac_list, node)
+		if (ether_addr_equal(entry->mac, addr))
+			return entry;
+
+	return NULL;
+}
+
+static void enetc_mac_list_add_entry(struct enetc_pf *pf,
+				     struct enetc_mac_list_entry *entry)
+{
+	hlist_add_head(&entry->node, &pf->mac_list);
+}
+
+static void enetc_mac_list_del_entry(struct enetc_mac_list_entry *entry)
+{
+	hlist_del(&entry->node);
+	kfree(entry);
+}
+
+static void enetc_mac_list_del_matched_entries(struct enetc_pf *pf, u16 si_bit,
+					       struct enetc_mac_addr *mac,
+					       int mac_cnt)
+{
+	struct enetc_mac_list_entry *entry;
+	int i;
+
+	for (i = 0; i < mac_cnt; i++) {
+		entry = enetc_mac_list_lookup_entry(pf, mac[i].addr);
+		if (!entry)
+			continue;
+
+		entry->si_bitmap &= ~si_bit;
+		if (entry->si_bitmap)
+			continue;
+
+		enetc_mac_list_del_entry(entry);
+		pf->num_mfe--;
+	}
+}
+
+static bool enetc_mac_list_is_available(struct enetc_pf *pf,
+					struct enetc_mac_addr *mac,
+					int mac_cnt)
+{
+	int max_num_mfe = pf->caps.mac_filter_num;
+	struct enetc_mac_list_entry *entry;
+	int cur_num_mfe = pf->num_mfe;
+	int i, new_mac_cnt = 0;
+
+	if (mac_cnt > max_num_mfe)
+		return false;
+
+	/* Check MAC filter table whether has enough available entries */
+	hlist_for_each_entry(entry, &pf->mac_list, node) {
+		for (i = 0; i < mac_cnt; i++) {
+			if (ether_addr_equal(entry->mac, mac[i].addr))
+				break;
+		}
+
+		if (i == mac_cnt)
+			new_mac_cnt++;
+
+		if ((cur_num_mfe + new_mac_cnt) > max_num_mfe)
+			return false;
+	}
+
+	return true;
+}
+
+static int enetc4_pf_add_si_mac_exact_filter(struct enetc_pf *pf, int si_id,
+					     struct enetc_mac_addr *mac,
+					     int mac_cnt)
+{
+	struct enetc_mac_list_entry *entry;
+	struct maft_entry_data data = {0};
+	struct enetc_si *si = pf->si;
+	u16 si_bit = BIT(si_id);
+	int i, num_mfe, err = 0;
+
+	mutex_lock(&pf->mac_list_lock);
+
+	if (!enetc_mac_list_is_available(pf, mac, mac_cnt)) {
+		err = -ENOSPC;
+		goto mac_list_unlock;
+	}
+
+	num_mfe = pf->num_mfe;
+	/* Update mac_list */
+	for (i = 0; i < mac_cnt; i++) {
+		entry = enetc_mac_list_lookup_entry(pf, mac[i].addr);
+		if (entry) {
+			entry->si_bitmap |= si_bit;
+			continue;
+		}
+
+		entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+		if (unlikely(!entry)) {
+			/* Restore MAC list to the state before the update
+			 * if an error occurs.
+			 */
+			enetc_mac_list_del_matched_entries(pf, si_bit,
+							   mac, i + 1);
+			err = -ENOMEM;
+			goto mac_list_unlock;
+		}
+
+		ether_addr_copy(entry->mac, mac[i].addr);
+		entry->si_bitmap = si_bit;
+		enetc_mac_list_add_entry(pf, entry);
+		pf->num_mfe++;
+	}
+
+	/* Clear MAC filter table */
+	for (i = 0; i < num_mfe; i++)
+		ntmp_maft_delete_entry(&si->ntmp.cbdrs, i);
+
+	i = 0;
+	hlist_for_each_entry(entry, &pf->mac_list, node) {
+		data.cfge.si_bitmap = cpu_to_le16(entry->si_bitmap);
+		ether_addr_copy(data.keye.mac_addr, entry->mac);
+		ntmp_maft_add_entry(&si->ntmp.cbdrs, i++, &data);
+	}
+
+mac_list_unlock:
+	mutex_unlock(&pf->mac_list_lock);
+
+	return err;
+}
+
+static void enetc4_pf_flush_si_mac_exact_filter(struct enetc_pf *pf, int si_id,
+						int mac_type)
+{
+	struct enetc_mac_list_entry *entry;
+	struct maft_entry_data data = {0};
+	struct enetc_si *si = pf->si;
+	u16 si_bit = BIT(si_id);
+	struct hlist_node *tmp;
+	int i, num_mfe;
+
+	mutex_lock(&pf->mac_list_lock);
+
+	num_mfe = pf->num_mfe;
+	hlist_for_each_entry_safe(entry, tmp, &pf->mac_list, node) {
+		if (enetc_mac_filter_type_check(mac_type, entry->mac) &&
+		    entry->si_bitmap & si_bit) {
+			entry->si_bitmap ^= si_bit;
+			if (entry->si_bitmap)
+				continue;
+
+			enetc_mac_list_del_entry(entry);
+			pf->num_mfe--;
+		}
+	}
+
+	for (i = 0; i < num_mfe; i++)
+		ntmp_maft_delete_entry(&si->ntmp.cbdrs, i);
+
+	i = 0;
+	hlist_for_each_entry(entry, &pf->mac_list, node) {
+		data.cfge.si_bitmap = cpu_to_le16(entry->si_bitmap);
+		ether_addr_copy(data.keye.mac_addr, entry->mac);
+		ntmp_maft_add_entry(&si->ntmp.cbdrs, i++, &data);
+	}
+
+	mutex_unlock(&pf->mac_list_lock);
+}
+
+static int enetc4_pf_set_mac_exact_filter(struct enetc_pf *pf, int type)
+{
+	int max_num_mfe = pf->caps.mac_filter_num;
+	struct net_device *ndev = pf->si->ndev;
+	struct enetc_mac_addr *mac_tbl;
+	struct netdev_hw_addr *ha;
+	u8 si_mac[ETH_ALEN];
+	int mac_cnt = 0;
+	int err;
+
+	mac_tbl = kcalloc(max_num_mfe, sizeof(*mac_tbl), GFP_KERNEL);
+	if (!mac_tbl)
+		return -ENOMEM;
+
+	enetc_get_primary_mac_addr(&pf->si->hw, si_mac);
+
+	netif_addr_lock_bh(ndev);
+	if (type & ENETC_MAC_FILTER_TYPE_UC) {
+		netdev_for_each_uc_addr(ha, ndev) {
+			if (!is_valid_ether_addr(ha->addr) ||
+			    ether_addr_equal(ha->addr, si_mac))
+				continue;
+
+			if (mac_cnt >= max_num_mfe)
+				goto err_nospace_out;
+
+			ether_addr_copy(mac_tbl[mac_cnt++].addr, ha->addr);
+		}
+	}
+
+	if (type & ENETC_MAC_FILTER_TYPE_MC) {
+		netdev_for_each_mc_addr(ha, ndev) {
+			if (!is_multicast_ether_addr(ha->addr))
+				continue;
+
+			if (mac_cnt >= max_num_mfe)
+				goto err_nospace_out;
+
+			ether_addr_copy(mac_tbl[mac_cnt++].addr, ha->addr);
+		}
+	}
+	netif_addr_unlock_bh(ndev);
+
+	err = enetc4_pf_add_si_mac_exact_filter(pf, 0, mac_tbl, mac_cnt);
+	kfree(mac_tbl);
+
+	return err;
+
+err_nospace_out:
+	netif_addr_unlock_bh(ndev);
+	kfree(mac_tbl);
+
+	return -ENOSPC;
+}
+
+static void enetc4_pf_set_mac_hash_filter(struct enetc_pf *pf, int type)
+{
+	struct net_device *ndev = pf->si->ndev;
+	struct enetc_mac_filter *mac_filter;
+	struct enetc_hw *hw = &pf->si->hw;
+	struct enetc_si *si = pf->si;
+	struct netdev_hw_addr *ha;
+
+	netif_addr_lock_bh(ndev);
+	if (type & ENETC_MAC_FILTER_TYPE_UC) {
+		mac_filter = &si->mac_filter[UC];
+		enetc_reset_mac_addr_filter(mac_filter);
+		netdev_for_each_uc_addr(ha, ndev)
+			enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
+
+		enetc4_pf_set_si_mac_hash_filter(hw, 0, UC,
+						 *mac_filter->mac_hash_table);
+	}
+
+	if (type & ENETC_MAC_FILTER_TYPE_MC) {
+		mac_filter = &si->mac_filter[MC];
+		enetc_reset_mac_addr_filter(mac_filter);
+		netdev_for_each_mc_addr(ha, ndev)
+			enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
+
+		enetc4_pf_set_si_mac_hash_filter(hw, 0, MC,
+						 *mac_filter->mac_hash_table);
+	}
+	netif_addr_unlock_bh(ndev);
+}
+
+static void enetc4_pf_set_mac_filter(struct enetc_pf *pf, int type)
+{
+	/* Currently, the MAC address filter table only has 4 entries, and the
+	 * table is shared by PF and VFs. In the default network configuration,
+	 * the MAC filter will be configured with multiple multicast addresses,
+	 * so it is only suitable for unicast filtering. If the number of unicast
+	 * addresses exceeds the table capacity, the MAC hash filter will be used.
+	 */
+	if (type & ENETC_MAC_FILTER_TYPE_UC) {
+		if (enetc4_pf_set_mac_exact_filter(pf, ENETC_MAC_FILTER_TYPE_UC))
+			/* Fall back to the MAC hash filter */
+			enetc4_pf_set_mac_hash_filter(pf, ENETC_MAC_FILTER_TYPE_UC);
+	}
+
+	if (type & ENETC_MAC_FILTER_TYPE_MC)
+		enetc4_pf_set_mac_hash_filter(pf, ENETC_MAC_FILTER_TYPE_MC);
+}
+
 static const struct enetc_pf_ops enetc4_pf_ops = {
 	.set_si_primary_mac = enetc4_pf_set_si_primary_mac,
 	.get_si_primary_mac = enetc4_pf_get_si_primary_mac,
@@ -71,9 +418,18 @@ static int enetc4_pf_struct_init(struct enetc_si *si)
 
 	enetc4_get_port_caps(pf);
 
+	INIT_HLIST_HEAD(&pf->mac_list);
+	mutex_init(&pf->mac_list_lock);
+
 	return 0;
 }
 
+static void enetc4_pf_struct_free(struct enetc_pf *pf)
+{
+	enetc4_pf_destroy_mac_list(pf);
+	mutex_destroy(&pf->mac_list_lock);
+}
+
 static u32 enetc4_psicfgr0_val_construct(bool is_vf, u32 num_tx_bdr, u32 num_rx_bdr)
 {
 	u32 val;
@@ -305,12 +661,53 @@ static void enetc4_pf_free(struct enetc_pf *pf)
 	enetc4_free_ntmp_priv(pf->si);
 }
 
+static void enetc4_pf_do_set_rx_mode(struct work_struct *work)
+{
+	struct enetc_si *si = container_of(work, struct enetc_si, rx_mode_task);
+	struct enetc_pf *pf = enetc_si_priv(si);
+	struct net_device *ndev = si->ndev;
+	struct enetc_hw *hw = &si->hw;
+	bool uc_promisc = false;
+	bool mc_promisc = false;
+	int type = 0;
+
+	if (ndev->flags & IFF_PROMISC) {
+		uc_promisc = true;
+		mc_promisc = true;
+	} else if (ndev->flags & IFF_ALLMULTI) {
+		mc_promisc = true;
+		type = ENETC_MAC_FILTER_TYPE_UC;
+	} else {
+		type = ENETC_MAC_FILTER_TYPE_ALL;
+	}
+
+	enetc4_pf_set_si_mac_promisc(hw, 0, UC, uc_promisc);
+	enetc4_pf_set_si_mac_promisc(hw, 0, MC, mc_promisc);
+
+	/* Clear Old MAC filter */
+	enetc4_pf_flush_si_mac_exact_filter(pf, 0, ENETC_MAC_FILTER_TYPE_ALL);
+	enetc4_pf_set_si_mac_hash_filter(hw, 0, UC, 0);
+	enetc4_pf_set_si_mac_hash_filter(hw, 0, MC, 0);
+
+	/* Set new MAC filter */
+	enetc4_pf_set_mac_filter(pf, type);
+}
+
+static void enetc4_pf_set_rx_mode(struct net_device *ndev)
+{
+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
+	struct enetc_si *si = priv->si;
+
+	queue_work(si->workqueue, &si->rx_mode_task);
+}
+
 static const struct net_device_ops enetc4_ndev_ops = {
 	.ndo_open		= enetc_open,
 	.ndo_stop		= enetc_close,
 	.ndo_start_xmit		= enetc_xmit,
 	.ndo_get_stats		= enetc_get_stats,
 	.ndo_set_mac_address	= enetc_pf_set_mac_addr,
+	.ndo_set_rx_mode	= enetc4_pf_set_rx_mode,
 };
 
 static struct phylink_pcs *
@@ -721,6 +1118,19 @@ static const struct enetc_si_ops enetc4_psi_ops = {
 	.teardown_cbdr = enetc4_teardown_cbdr,
 };
 
+static int enetc4_pf_wq_task_init(struct enetc_si *si)
+{
+	char wq_name[24];
+
+	INIT_WORK(&si->rx_mode_task, enetc4_pf_do_set_rx_mode);
+	snprintf(wq_name, sizeof(wq_name), "enetc-%s", pci_name(si->pdev));
+	si->workqueue = create_singlethread_workqueue(wq_name);
+	if (!si->workqueue)
+		return -ENOMEM;
+
+	return 0;
+}
+
 static int enetc4_pf_probe(struct pci_dev *pdev,
 			   const struct pci_device_id *ent)
 {
@@ -756,9 +1166,13 @@ static int enetc4_pf_probe(struct pci_dev *pdev,
 		return err;
 
 	pf = enetc_si_priv(si);
+	err = enetc4_pf_wq_task_init(si);
+	if (err)
+		goto err_wq_task_init;
+
 	err = enetc4_pf_init(pf);
 	if (err)
-		return err;
+		goto err_pf_init;
 
 	enetc_get_si_caps(si);
 
@@ -770,6 +1184,10 @@ static int enetc4_pf_probe(struct pci_dev *pdev,
 
 err_netdev_create:
 	enetc4_pf_free(pf);
+err_pf_init:
+	destroy_workqueue(si->workqueue);
+err_wq_task_init:
+	enetc4_pf_struct_free(pf);
 
 	return err;
 }
@@ -781,6 +1199,8 @@ static void enetc4_pf_remove(struct pci_dev *pdev)
 
 	enetc4_pf_netdev_destroy(si);
 	enetc4_pf_free(pf);
+	destroy_workqueue(si->workqueue);
+	enetc4_pf_struct_free(pf);
 }
 
 static const struct pci_device_id enetc4_pf_id_table[] = {
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
index 4098f01479bc..2e676212d230 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
@@ -712,6 +712,12 @@ static inline void enetc_load_primary_mac_addr(struct enetc_hw *hw,
 	eth_hw_addr_set(ndev, addr);
 }
 
+static inline void enetc_get_primary_mac_addr(struct enetc_hw *hw, u8 *addr)
+{
+	*(u32 *)addr = __raw_readl(hw->reg + ENETC_SIPMAR0);
+	*(u16 *)(addr + 4) = __raw_readw(hw->reg + ENETC_SIPMAR1);
+}
+
 #define ENETC_SI_INT_IDX	0
 /* base index for Rx/Tx interrupts */
 #define ENETC_BDR_INT_BASE_IDX	1
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.h b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
index 2b9d0f625f01..3b0cb0d8bf48 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
@@ -22,6 +22,13 @@ struct enetc_port_caps {
 	int num_msix;
 	int num_rx_bdr;
 	int num_tx_bdr;
+	int mac_filter_num;
+};
+
+struct enetc_mac_list_entry {
+	u8 mac[ETH_ALEN];
+	u16 si_bitmap;
+	struct hlist_node node;
 };
 
 struct enetc_pf;
@@ -57,6 +64,10 @@ struct enetc_pf {
 
 	struct enetc_port_caps caps;
 	const struct enetc_pf_ops *ops;
+
+	struct hlist_head mac_list; /* MAC address filter table */
+	struct mutex mac_list_lock; /* mac_list lock */
+	int num_mfe;	/* number of mac address filter table entries */
 };
 
 #define phylink_to_enetc_pf(config) \
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v4 net-next 05/14] net: enetc: add debugfs interface to dump MAC filter
  2025-03-11  5:38 [PATCH v4 net-next 00/14] Add more feautues for ENETC v4 - round 2 Wei Fang
                   ` (3 preceding siblings ...)
  2025-03-11  5:38 ` [PATCH v4 net-next 04/14] net: enetc: add MAC filter for i.MX95 ENETC PF Wei Fang
@ 2025-03-11  5:38 ` Wei Fang
  2025-03-17 14:48   ` Vladimir Oltean
  2025-03-11  5:38 ` [PATCH v4 net-next 06/14] net: enetc: add set/get_rss_table() to enetc_si_ops Wei Fang
                   ` (9 subsequent siblings)
  14 siblings, 1 reply; 58+ messages in thread
From: Wei Fang @ 2025-03-11  5:38 UTC (permalink / raw)
  To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
	davem, edumazet, kuba, pabeni
  Cc: christophe.leroy, netdev, linux-kernel, imx, linuxppc-dev,
	linux-arm-kernel

ENETC's MAC filter consists of hash MAC filter and exact MAC filter. Hash
MAC filter is a 64-entry hash table consisting of two 32-bit registers.
Exact MAC filter is implemented by configuring MAC address filter table
through command BD ring. The table is stored in ENETC's internal memory
and needs to be read through command BD ring. In order to facilitate
debugging, added a debugfs interface to get the relevant information
about MAC filter.

Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
 drivers/net/ethernet/freescale/enetc/Makefile |  1 +
 drivers/net/ethernet/freescale/enetc/enetc.h  |  1 +
 .../ethernet/freescale/enetc/enetc4_debugfs.c | 93 +++++++++++++++++++
 .../ethernet/freescale/enetc/enetc4_debugfs.h | 20 ++++
 .../net/ethernet/freescale/enetc/enetc4_pf.c  |  4 +
 5 files changed, 119 insertions(+)
 create mode 100644 drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c
 create mode 100644 drivers/net/ethernet/freescale/enetc/enetc4_debugfs.h

diff --git a/drivers/net/ethernet/freescale/enetc/Makefile b/drivers/net/ethernet/freescale/enetc/Makefile
index 707a68e26971..f1c5ad45fd76 100644
--- a/drivers/net/ethernet/freescale/enetc/Makefile
+++ b/drivers/net/ethernet/freescale/enetc/Makefile
@@ -16,6 +16,7 @@ fsl-enetc-$(CONFIG_FSL_ENETC_QOS) += enetc_qos.o
 
 obj-$(CONFIG_NXP_ENETC4) += nxp-enetc4.o
 nxp-enetc4-y := enetc4_pf.o
+nxp-enetc4-$(CONFIG_DEBUG_FS) += enetc4_debugfs.o
 
 obj-$(CONFIG_FSL_ENETC_VF) += fsl-enetc-vf.o
 fsl-enetc-vf-y := enetc_vf.o
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index 4dba91408e3d..ca1bc85c0ac9 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -318,6 +318,7 @@ struct enetc_si {
 	struct enetc_mac_filter mac_filter[MADDR_TYPE];
 	struct workqueue_struct *workqueue;
 	struct work_struct rx_mode_task;
+	struct dentry *debugfs_root;
 };
 
 #define ENETC_SI_ALIGN	32
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c b/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c
new file mode 100644
index 000000000000..3a660c80344a
--- /dev/null
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright 2025 NXP */
+
+#include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#include "enetc_pf.h"
+#include "enetc4_debugfs.h"
+
+#define is_en(x)	(x) ? "Enabled" : "Disabled"
+
+static void enetc_show_si_mac_hash_filter(struct seq_file *s, int i)
+{
+	struct enetc_si *si = s->private;
+	struct enetc_hw *hw = &si->hw;
+	u32 hash_h, hash_l;
+
+	hash_l = enetc_port_rd(hw, ENETC4_PSIUMHFR0(i));
+	hash_h = enetc_port_rd(hw, ENETC4_PSIUMHFR1(i));
+	seq_printf(s, "SI %d unicast MAC hash filter: 0x%08x%08x\n",
+		   i, hash_h, hash_l);
+
+	hash_l = enetc_port_rd(hw, ENETC4_PSIMMHFR0(i));
+	hash_h = enetc_port_rd(hw, ENETC4_PSIMMHFR1(i));
+	seq_printf(s, "SI %d multicast MAC hash filter: 0x%08x%08x\n",
+		   i, hash_h, hash_l);
+}
+
+static int enetc_mac_filter_show(struct seq_file *s, void *data)
+{
+	struct maft_entry_data maft_data;
+	struct enetc_si *si = s->private;
+	struct enetc_hw *hw = &si->hw;
+	struct maft_keye_data *keye;
+	struct enetc_pf *pf;
+	int i, err, num_si;
+	u32 val;
+
+	pf = enetc_si_priv(si);
+	num_si = pf->caps.num_vsi + 1;
+
+	val = enetc_port_rd(hw, ENETC4_PSIPMMR);
+	for (i = 0; i < num_si; i++) {
+		seq_printf(s, "SI %d Unicast Promiscuous mode: %s\n",
+			   i, is_en(PSIPMMR_SI_MAC_UP(i) & val));
+		seq_printf(s, "SI %d Multicast Promiscuous mode: %s\n",
+			   i, is_en(PSIPMMR_SI_MAC_MP(i) & val));
+	}
+
+	/* MAC hash filter table */
+	for (i = 0; i < num_si; i++)
+		enetc_show_si_mac_hash_filter(s, i);
+
+	if (!pf->num_mfe)
+		return 0;
+
+	/* MAC address filter table */
+	seq_puts(s, "Show MAC address filter table\n");
+	for (i = 0; i < pf->num_mfe; i++) {
+		memset(&maft_data, 0, sizeof(maft_data));
+		err = ntmp_maft_query_entry(&si->ntmp.cbdrs, i, &maft_data);
+		if (err)
+			return err;
+
+		keye = &maft_data.keye;
+		seq_printf(s, "Entry %d, MAC: %pM, SI bitmap: 0x%04x\n", i,
+			   keye->mac_addr, le16_to_cpu(maft_data.cfge.si_bitmap));
+	}
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(enetc_mac_filter);
+
+void enetc_create_debugfs(struct enetc_si *si)
+{
+	struct net_device *ndev = si->ndev;
+	struct dentry *root;
+
+	root = debugfs_create_dir(netdev_name(ndev), NULL);
+	if (IS_ERR(root))
+		return;
+
+	si->debugfs_root = root;
+
+	debugfs_create_file("mac_filter", 0444, root, si, &enetc_mac_filter_fops);
+}
+
+void enetc_remove_debugfs(struct enetc_si *si)
+{
+	debugfs_remove_recursive(si->debugfs_root);
+	si->debugfs_root = NULL;
+}
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.h b/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.h
new file mode 100644
index 000000000000..96caca35f79d
--- /dev/null
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/* Copyright 2025 NXP */
+
+#ifndef __ENETC4_DEBUGFS_H
+#define __ENETC4_DEBUGFS_H
+
+#if IS_ENABLED(CONFIG_DEBUG_FS)
+void enetc_create_debugfs(struct enetc_si *si);
+void enetc_remove_debugfs(struct enetc_si *si);
+#else
+static inline void enetc_create_debugfs(struct enetc_si *si)
+{
+}
+
+static inline void enetc_remove_debugfs(struct enetc_si *si)
+{
+}
+#endif
+
+#endif
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index 7d1c545f3f56..a98ed059a83f 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -8,6 +8,7 @@
 #include <linux/unaligned.h>
 
 #include "enetc_pf_common.h"
+#include "enetc4_debugfs.h"
 
 #define ENETC_SI_MAX_RING_NUM	8
 
@@ -1180,6 +1181,8 @@ static int enetc4_pf_probe(struct pci_dev *pdev,
 	if (err)
 		goto err_netdev_create;
 
+	enetc_create_debugfs(si);
+
 	return 0;
 
 err_netdev_create:
@@ -1197,6 +1200,7 @@ 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);
 
+	enetc_remove_debugfs(si);
 	enetc4_pf_netdev_destroy(si);
 	enetc4_pf_free(pf);
 	destroy_workqueue(si->workqueue);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v4 net-next 06/14] net: enetc: add set/get_rss_table() to enetc_si_ops
  2025-03-11  5:38 [PATCH v4 net-next 00/14] Add more feautues for ENETC v4 - round 2 Wei Fang
                   ` (4 preceding siblings ...)
  2025-03-11  5:38 ` [PATCH v4 net-next 05/14] net: enetc: add debugfs interface to dump MAC filter Wei Fang
@ 2025-03-11  5:38 ` Wei Fang
  2025-03-17 16:42   ` Vladimir Oltean
  2025-03-11  5:38 ` [PATCH v4 net-next 07/14] net: enetc: make enetc_set_rss_key() reusable Wei Fang
                   ` (8 subsequent siblings)
  14 siblings, 1 reply; 58+ messages in thread
From: Wei Fang @ 2025-03-11  5:38 UTC (permalink / raw)
  To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
	davem, edumazet, kuba, pabeni
  Cc: christophe.leroy, netdev, linux-kernel, imx, linuxppc-dev,
	linux-arm-kernel

Since i.MX95 ENETC (v4) uses NTMP 2.0 to manage the RSS table, which is
different from LS1028A ENETC (v1). In order to reuse some functions
related to the RSS table, so add .get_rss_table() and .set_rss_table()
hooks to enetc_si_ops.

Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
 drivers/net/ethernet/freescale/enetc/enetc.c         |  2 +-
 drivers/net/ethernet/freescale/enetc/enetc.h         |  2 ++
 drivers/net/ethernet/freescale/enetc/enetc_ethtool.c | 12 ++++++------
 drivers/net/ethernet/freescale/enetc/enetc_pf.c      |  2 ++
 drivers/net/ethernet/freescale/enetc/enetc_vf.c      |  2 ++
 5 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
index 3832d2cd91ba..2a8fa455e96b 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
@@ -2405,7 +2405,7 @@ static int enetc_setup_default_rss_table(struct enetc_si *si, int num_groups)
 	for (i = 0; i < si->num_rss; i++)
 		rss_table[i] = i % num_groups;
 
-	enetc_set_rss_table(si, rss_table, si->num_rss);
+	si->ops->set_rss_table(si, rss_table, si->num_rss);
 
 	kfree(rss_table);
 
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index ca1bc85c0ac9..deda386b20a0 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -290,6 +290,8 @@ struct enetc_si;
 struct enetc_si_ops {
 	int (*setup_cbdr)(struct enetc_si *si);
 	void (*teardown_cbdr)(struct enetc_si *si);
+	int (*get_rss_table)(struct enetc_si *si, u32 *table, int count);
+	int (*set_rss_table)(struct enetc_si *si, const u32 *table, int count);
 };
 
 /* PCI IEP device data */
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
index ece3ae28ba82..d14182401d81 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
@@ -681,7 +681,8 @@ static int enetc_get_rxfh(struct net_device *ndev,
 			  struct ethtool_rxfh_param *rxfh)
 {
 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
-	struct enetc_hw *hw = &priv->si->hw;
+	struct enetc_si *si = priv->si;
+	struct enetc_hw *hw = &si->hw;
 	int err = 0, i;
 
 	/* return hash function */
@@ -695,8 +696,7 @@ static int enetc_get_rxfh(struct net_device *ndev,
 
 	/* return RSS table */
 	if (rxfh->indir)
-		err = enetc_get_rss_table(priv->si, rxfh->indir,
-					  priv->si->num_rss);
+		err = si->ops->get_rss_table(si, rxfh->indir, si->num_rss);
 
 	return err;
 }
@@ -715,7 +715,8 @@ static int enetc_set_rxfh(struct net_device *ndev,
 			  struct netlink_ext_ack *extack)
 {
 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
-	struct enetc_hw *hw = &priv->si->hw;
+	struct enetc_si *si = priv->si;
+	struct enetc_hw *hw = &si->hw;
 	int err = 0;
 
 	/* set hash key, if PF */
@@ -724,8 +725,7 @@ static int enetc_set_rxfh(struct net_device *ndev,
 
 	/* set RSS table */
 	if (rxfh->indir)
-		err = enetc_set_rss_table(priv->si, rxfh->indir,
-					  priv->si->num_rss);
+		err = si->ops->set_rss_table(si, rxfh->indir, si->num_rss);
 
 	return err;
 }
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index cc3e52bd3096..097a5b50e448 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -907,6 +907,8 @@ static int enetc_pf_register_with_ierb(struct pci_dev *pdev)
 static const struct enetc_si_ops enetc_psi_ops = {
 	.setup_cbdr = enetc_setup_cbdr,
 	.teardown_cbdr = enetc_teardown_cbdr,
+	.get_rss_table = enetc_get_rss_table,
+	.set_rss_table = enetc_set_rss_table,
 };
 
 static struct enetc_si *enetc_psi_create(struct pci_dev *pdev)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_vf.c b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
index d7d9a720069b..072e5b40a199 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_vf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
@@ -165,6 +165,8 @@ static void enetc_vf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
 static const struct enetc_si_ops enetc_vsi_ops = {
 	.setup_cbdr = enetc_setup_cbdr,
 	.teardown_cbdr = enetc_teardown_cbdr,
+	.get_rss_table = enetc_get_rss_table,
+	.set_rss_table = enetc_set_rss_table,
 };
 
 static int enetc_vf_probe(struct pci_dev *pdev,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v4 net-next 07/14] net: enetc: make enetc_set_rss_key() reusable
  2025-03-11  5:38 [PATCH v4 net-next 00/14] Add more feautues for ENETC v4 - round 2 Wei Fang
                   ` (5 preceding siblings ...)
  2025-03-11  5:38 ` [PATCH v4 net-next 06/14] net: enetc: add set/get_rss_table() to enetc_si_ops Wei Fang
@ 2025-03-11  5:38 ` Wei Fang
  2025-03-17 16:26   ` Vladimir Oltean
  2025-03-11  5:38 ` [PATCH v4 net-next 08/14] net: enetc: add RSS support for i.MX95 ENETC PF Wei Fang
                   ` (7 subsequent siblings)
  14 siblings, 1 reply; 58+ messages in thread
From: Wei Fang @ 2025-03-11  5:38 UTC (permalink / raw)
  To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
	davem, edumazet, kuba, pabeni
  Cc: christophe.leroy, netdev, linux-kernel, imx, linuxppc-dev,
	linux-arm-kernel

Since the offset of the RSS key registers of i.MX95 ENETC is different
from that of LS1028A, so add enetc_get_rss_key_base() to get the base
offset for the different chips, so that enetc_set_rss_key() can be
reused for this trivial.

Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
 drivers/net/ethernet/freescale/enetc/enetc.h  |  2 +-
 .../net/ethernet/freescale/enetc/enetc4_pf.c  | 11 +----------
 .../ethernet/freescale/enetc/enetc_ethtool.c  | 19 ++++++++++++++-----
 .../net/ethernet/freescale/enetc/enetc_pf.c   |  2 +-
 4 files changed, 17 insertions(+), 17 deletions(-)

diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index deda386b20a0..a3ce324c716c 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -539,7 +539,7 @@ int enetc_set_mac_flt_entry(struct enetc_si *si, int index,
 int enetc_clear_mac_flt_entry(struct enetc_si *si, int index);
 int enetc_set_fs_entry(struct enetc_si *si, struct enetc_cmd_rfse *rfse,
 		       int index);
-void enetc_set_rss_key(struct enetc_hw *hw, const u8 *bytes);
+void enetc_set_rss_key(struct enetc_si *si, const u8 *bytes);
 int enetc_get_rss_table(struct enetc_si *si, u32 *table, int count);
 int enetc_set_rss_table(struct enetc_si *si, const u32 *table, int count);
 int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index a98ed059a83f..f991e1aae85c 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -583,22 +583,13 @@ static void enetc4_set_trx_frame_size(struct enetc_pf *pf)
 	enetc4_pf_reset_tc_msdu(&si->hw);
 }
 
-static void enetc4_set_rss_key(struct enetc_hw *hw, const u8 *bytes)
-{
-	int i;
-
-	for (i = 0; i < ENETC_RSSHASH_KEY_SIZE / 4; i++)
-		enetc_port_wr(hw, ENETC4_PRSSKR(i), ((u32 *)bytes)[i]);
-}
-
 static void enetc4_set_default_rss_key(struct enetc_pf *pf)
 {
 	u8 hash_key[ENETC_RSSHASH_KEY_SIZE] = {0};
-	struct enetc_hw *hw = &pf->si->hw;
 
 	/* set up hash key */
 	get_random_bytes(hash_key, ENETC_RSSHASH_KEY_SIZE);
-	enetc4_set_rss_key(hw, hash_key);
+	enetc_set_rss_key(pf->si, hash_key);
 }
 
 static void enetc4_enable_trx(struct enetc_pf *pf)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
index d14182401d81..1a8fae3c406b 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
@@ -677,6 +677,14 @@ static u32 enetc_get_rxfh_indir_size(struct net_device *ndev)
 	return priv->si->num_rss;
 }
 
+static int enetc_get_rss_key_base(struct enetc_si *si)
+{
+	if (is_enetc_rev1(si))
+		return ENETC_PRSSK(0);
+
+	return ENETC4_PRSSKR(0);
+}
+
 static int enetc_get_rxfh(struct net_device *ndev,
 			  struct ethtool_rxfh_param *rxfh)
 {
@@ -701,12 +709,14 @@ static int enetc_get_rxfh(struct net_device *ndev,
 	return err;
 }
 
-void enetc_set_rss_key(struct enetc_hw *hw, const u8 *bytes)
+void enetc_set_rss_key(struct enetc_si *si, const u8 *bytes)
 {
+	int base = enetc_get_rss_key_base(si);
+	struct enetc_hw *hw = &si->hw;
 	int i;
 
 	for (i = 0; i < ENETC_RSSHASH_KEY_SIZE / 4; i++)
-		enetc_port_wr(hw, ENETC_PRSSK(i), ((u32 *)bytes)[i]);
+		enetc_port_wr(hw, base + i * 4, ((u32 *)bytes)[i]);
 }
 EXPORT_SYMBOL_GPL(enetc_set_rss_key);
 
@@ -716,12 +726,11 @@ static int enetc_set_rxfh(struct net_device *ndev,
 {
 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
 	struct enetc_si *si = priv->si;
-	struct enetc_hw *hw = &si->hw;
 	int err = 0;
 
 	/* set hash key, if PF */
-	if (rxfh->key && hw->port)
-		enetc_set_rss_key(hw, rxfh->key);
+	if (rxfh->key && enetc_si_is_pf(si))
+		enetc_set_rss_key(si, rxfh->key);
 
 	/* set RSS table */
 	if (rxfh->indir)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index 097a5b50e448..38ec7657b9aa 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -523,7 +523,7 @@ static void enetc_configure_port(struct enetc_pf *pf)
 
 	/* set up hash key */
 	get_random_bytes(hash_key, ENETC_RSSHASH_KEY_SIZE);
-	enetc_set_rss_key(hw, hash_key);
+	enetc_set_rss_key(pf->si, hash_key);
 
 	/* split up RFS entries */
 	enetc_port_assign_rfs_entries(pf->si);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v4 net-next 08/14] net: enetc: add RSS support for i.MX95 ENETC PF
  2025-03-11  5:38 [PATCH v4 net-next 00/14] Add more feautues for ENETC v4 - round 2 Wei Fang
                   ` (6 preceding siblings ...)
  2025-03-11  5:38 ` [PATCH v4 net-next 07/14] net: enetc: make enetc_set_rss_key() reusable Wei Fang
@ 2025-03-11  5:38 ` Wei Fang
  2025-03-17 15:55   ` Vladimir Oltean
  2025-03-11  5:38 ` [PATCH v4 net-next 09/14] net: enetc: enable RSS feature by default Wei Fang
                   ` (6 subsequent siblings)
  14 siblings, 1 reply; 58+ messages in thread
From: Wei Fang @ 2025-03-11  5:38 UTC (permalink / raw)
  To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
	davem, edumazet, kuba, pabeni
  Cc: christophe.leroy, netdev, linux-kernel, imx, linuxppc-dev,
	linux-arm-kernel

Compared with LS1028A, there are two main differences: first, i.MX95
ENETC uses NTMP 2.0 to manage the RSS table, and second, the offset
of the RSS Key registers is different. Some modifications have been
made in the previous patches based on these differences to ensure that
the relevant interfaces are compatible with i.MX95. So it's time to
add RSS support to i.MX95 ENETC PF.

Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
 drivers/net/ethernet/freescale/enetc/enetc.c  |  5 +--
 drivers/net/ethernet/freescale/enetc/enetc.h  |  2 +
 .../net/ethernet/freescale/enetc/enetc4_pf.c  | 11 +++++
 .../net/ethernet/freescale/enetc/enetc_cbdr.c | 14 +++++++
 .../ethernet/freescale/enetc/enetc_ethtool.c  | 42 ++++++++++++++++---
 .../freescale/enetc/enetc_pf_common.c         |  6 +--
 6 files changed, 67 insertions(+), 13 deletions(-)

diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
index 2a8fa455e96b..5b5e65ac8fab 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
@@ -2436,10 +2436,7 @@ int enetc_configure_si(struct enetc_ndev_priv *priv)
 	if (si->hw_features & ENETC_SI_F_LSO)
 		enetc_set_lso_flags_mask(hw);
 
-	/* TODO: RSS support for i.MX95 will be supported later, and the
-	 * is_enetc_rev1() condition will be removed
-	 */
-	if (si->num_rss && is_enetc_rev1(si)) {
+	if (si->num_rss) {
 		err = enetc_setup_default_rss_table(si, priv->num_rx_rings);
 		if (err)
 			return err;
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index a3ce324c716c..ecf79338cd79 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -543,6 +543,8 @@ void enetc_set_rss_key(struct enetc_si *si, const u8 *bytes);
 int enetc_get_rss_table(struct enetc_si *si, u32 *table, int count);
 int enetc_set_rss_table(struct enetc_si *si, const u32 *table, int count);
 int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd);
+int enetc4_get_rss_table(struct enetc_si *si, u32 *table, int count);
+int enetc4_set_rss_table(struct enetc_si *si, const u32 *table, int count);
 
 static inline void *enetc_cbd_alloc_data_mem(struct enetc_si *si,
 					     struct enetc_cbd *cbd,
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index f991e1aae85c..53dbd5d71859 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -693,6 +693,14 @@ static void enetc4_pf_set_rx_mode(struct net_device *ndev)
 	queue_work(si->workqueue, &si->rx_mode_task);
 }
 
+static int enetc4_pf_set_features(struct net_device *ndev,
+				  netdev_features_t features)
+{
+	enetc_set_features(ndev, features);
+
+	return 0;
+}
+
 static const struct net_device_ops enetc4_ndev_ops = {
 	.ndo_open		= enetc_open,
 	.ndo_stop		= enetc_close,
@@ -700,6 +708,7 @@ static const struct net_device_ops enetc4_ndev_ops = {
 	.ndo_get_stats		= enetc_get_stats,
 	.ndo_set_mac_address	= enetc_pf_set_mac_addr,
 	.ndo_set_rx_mode	= enetc4_pf_set_rx_mode,
+	.ndo_set_features	= enetc4_pf_set_features,
 };
 
 static struct phylink_pcs *
@@ -1108,6 +1117,8 @@ static void enetc4_pf_netdev_destroy(struct enetc_si *si)
 static const struct enetc_si_ops enetc4_psi_ops = {
 	.setup_cbdr = enetc4_setup_cbdr,
 	.teardown_cbdr = enetc4_teardown_cbdr,
+	.get_rss_table = enetc4_get_rss_table,
+	.set_rss_table = enetc4_set_rss_table,
 };
 
 static int enetc4_pf_wq_task_init(struct enetc_si *si)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
index 4e5125331d7b..1a74b93f1fd3 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
@@ -299,3 +299,17 @@ int enetc_set_rss_table(struct enetc_si *si, const u32 *table, int count)
 	return enetc_cmd_rss_table(si, (u32 *)table, count, false);
 }
 EXPORT_SYMBOL_GPL(enetc_set_rss_table);
+
+int enetc4_get_rss_table(struct enetc_si *si, u32 *table, int count)
+{
+	return ntmp_rsst_query_or_update_entry(&si->ntmp.cbdrs,
+					       table, count, true);
+}
+EXPORT_SYMBOL_GPL(enetc4_get_rss_table);
+
+int enetc4_set_rss_table(struct enetc_si *si, const u32 *table, int count)
+{
+	return ntmp_rsst_query_or_update_entry(&si->ntmp.cbdrs,
+					       (u32 *)table, count, false);
+}
+EXPORT_SYMBOL_GPL(enetc4_set_rss_table);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
index 1a8fae3c406b..bc65135925b8 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
@@ -625,6 +625,24 @@ static int enetc_get_rxnfc(struct net_device *ndev, struct ethtool_rxnfc *rxnfc,
 	return 0;
 }
 
+static int enetc4_get_rxnfc(struct net_device *ndev, struct ethtool_rxnfc *rxnfc,
+			    u32 *rule_locs)
+{
+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
+
+	switch (rxnfc->cmd) {
+	case ETHTOOL_GRXRINGS:
+		rxnfc->data = priv->num_rx_rings;
+		break;
+	case ETHTOOL_GRXFH:
+		return enetc_get_rsshash(rxnfc);
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
 static int enetc_set_rxnfc(struct net_device *ndev, struct ethtool_rxnfc *rxnfc)
 {
 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
@@ -685,22 +703,29 @@ static int enetc_get_rss_key_base(struct enetc_si *si)
 	return ENETC4_PRSSKR(0);
 }
 
+static void enetc_get_rss_key(struct enetc_si *si, const u8 *key)
+{
+	int base = enetc_get_rss_key_base(si);
+	struct enetc_hw *hw = &si->hw;
+	int i;
+
+	for (i = 0; i < ENETC_RSSHASH_KEY_SIZE / 4; i++)
+		((u32 *)key)[i] = enetc_port_rd(hw, base + i * 4);
+}
+
 static int enetc_get_rxfh(struct net_device *ndev,
 			  struct ethtool_rxfh_param *rxfh)
 {
 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
 	struct enetc_si *si = priv->si;
-	struct enetc_hw *hw = &si->hw;
-	int err = 0, i;
+	int err = 0;
 
 	/* return hash function */
 	rxfh->hfunc = ETH_RSS_HASH_TOP;
 
 	/* return hash key */
-	if (rxfh->key && hw->port)
-		for (i = 0; i < ENETC_RSSHASH_KEY_SIZE / 4; i++)
-			((u32 *)rxfh->key)[i] = enetc_port_rd(hw,
-							      ENETC_PRSSK(i));
+	if (rxfh->key && enetc_si_is_pf(si))
+		enetc_get_rss_key(si, rxfh->key);
 
 	/* return RSS table */
 	if (rxfh->indir)
@@ -1249,6 +1274,11 @@ const struct ethtool_ops enetc4_pf_ethtool_ops = {
 	.set_wol = enetc_set_wol,
 	.get_pauseparam = enetc_get_pauseparam,
 	.set_pauseparam = enetc_set_pauseparam,
+	.get_rxnfc = enetc4_get_rxnfc,
+	.get_rxfh_key_size = enetc_get_rxfh_key_size,
+	.get_rxfh_indir_size = enetc_get_rxfh_indir_size,
+	.get_rxfh = enetc_get_rxfh,
+	.set_rxfh = enetc_set_rxfh,
 };
 
 void enetc_set_ethtool_ops(struct net_device *ndev)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
index 3fd9b0727875..c346e0e3ad37 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
@@ -128,15 +128,15 @@ void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
 	if (si->hw_features & ENETC_SI_F_LSO)
 		priv->active_offloads |= ENETC_F_LSO;
 
+	if (si->num_rss)
+		ndev->hw_features |= NETIF_F_RXHASH;
+
 	/* TODO: currently, i.MX95 ENETC driver does not support advanced features */
 	if (!is_enetc_rev1(si)) {
 		ndev->hw_features &= ~(NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_LOOPBACK);
 		goto end;
 	}
 
-	if (si->num_rss)
-		ndev->hw_features |= NETIF_F_RXHASH;
-
 	ndev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT |
 			     NETDEV_XDP_ACT_NDO_XMIT | NETDEV_XDP_ACT_RX_SG |
 			     NETDEV_XDP_ACT_NDO_XMIT_SG;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v4 net-next 09/14] net: enetc: enable RSS feature by default
  2025-03-11  5:38 [PATCH v4 net-next 00/14] Add more feautues for ENETC v4 - round 2 Wei Fang
                   ` (7 preceding siblings ...)
  2025-03-11  5:38 ` [PATCH v4 net-next 08/14] net: enetc: add RSS support for i.MX95 ENETC PF Wei Fang
@ 2025-03-11  5:38 ` Wei Fang
  2025-03-17 16:33   ` Vladimir Oltean
  2025-03-11  5:38 ` [PATCH v4 net-next 10/14] net: enetc: move generic VLAN filter interfaces to enetc-core Wei Fang
                   ` (5 subsequent siblings)
  14 siblings, 1 reply; 58+ messages in thread
From: Wei Fang @ 2025-03-11  5:38 UTC (permalink / raw)
  To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
	davem, edumazet, kuba, pabeni
  Cc: christophe.leroy, netdev, linux-kernel, imx, linuxppc-dev,
	linux-arm-kernel

Receive side scaling (RSS) is a network driver technology that enables
the efficient distribution of network receive processing across multiple
CPUs in multiprocessor systems. Therefore, it is better to enable RSS by
default so that the CPU load can be balanced and network performance can
be improved when then network is enabled.

Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
 drivers/net/ethernet/freescale/enetc/enetc.c  | 35 ++++++++++---------
 .../freescale/enetc/enetc_pf_common.c         |  4 ++-
 .../net/ethernet/freescale/enetc/enetc_vf.c   |  4 ++-
 3 files changed, 25 insertions(+), 18 deletions(-)

diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
index 5b5e65ac8fab..8583ac9f7b9e 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
@@ -2420,6 +2420,22 @@ static void enetc_set_lso_flags_mask(struct enetc_hw *hw)
 	enetc_wr(hw, ENETC4_SILSOSFMR1, 0);
 }
 
+static int enetc_set_rss(struct net_device *ndev, int en)
+{
+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
+	struct enetc_hw *hw = &priv->si->hw;
+	u32 reg;
+
+	enetc_wr(hw, ENETC_SIRBGCR, priv->num_rx_rings);
+
+	reg = enetc_rd(hw, ENETC_SIMR);
+	reg &= ~ENETC_SIMR_RSSE;
+	reg |= (en) ? ENETC_SIMR_RSSE : 0;
+	enetc_wr(hw, ENETC_SIMR, reg);
+
+	return 0;
+}
+
 int enetc_configure_si(struct enetc_ndev_priv *priv)
 {
 	struct enetc_si *si = priv->si;
@@ -2440,6 +2456,9 @@ int enetc_configure_si(struct enetc_ndev_priv *priv)
 		err = enetc_setup_default_rss_table(si, priv->num_rx_rings);
 		if (err)
 			return err;
+
+		if (priv->ndev->features & NETIF_F_RXHASH)
+			enetc_set_rss(priv->ndev, true);
 	}
 
 	return 0;
@@ -3232,22 +3251,6 @@ struct net_device_stats *enetc_get_stats(struct net_device *ndev)
 }
 EXPORT_SYMBOL_GPL(enetc_get_stats);
 
-static int enetc_set_rss(struct net_device *ndev, int en)
-{
-	struct enetc_ndev_priv *priv = netdev_priv(ndev);
-	struct enetc_hw *hw = &priv->si->hw;
-	u32 reg;
-
-	enetc_wr(hw, ENETC_SIRBGCR, priv->num_rx_rings);
-
-	reg = enetc_rd(hw, ENETC_SIMR);
-	reg &= ~ENETC_SIMR_RSSE;
-	reg |= (en) ? ENETC_SIMR_RSSE : 0;
-	enetc_wr(hw, ENETC_SIMR, reg);
-
-	return 0;
-}
-
 static void enetc_enable_rxvlan(struct net_device *ndev, bool en)
 {
 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
index c346e0e3ad37..a737a7f8c79e 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
@@ -128,8 +128,10 @@ void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
 	if (si->hw_features & ENETC_SI_F_LSO)
 		priv->active_offloads |= ENETC_F_LSO;
 
-	if (si->num_rss)
+	if (si->num_rss) {
 		ndev->hw_features |= NETIF_F_RXHASH;
+		ndev->features |= NETIF_F_RXHASH;
+	}
 
 	/* TODO: currently, i.MX95 ENETC driver does not support advanced features */
 	if (!is_enetc_rev1(si)) {
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_vf.c b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
index 072e5b40a199..3372a9a779a6 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_vf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
@@ -155,8 +155,10 @@ static void enetc_vf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
 	ndev->vlan_features = NETIF_F_SG | NETIF_F_HW_CSUM |
 			      NETIF_F_TSO | NETIF_F_TSO6;
 
-	if (si->num_rss)
+	if (si->num_rss) {
 		ndev->hw_features |= NETIF_F_RXHASH;
+		ndev->features |= NETIF_F_RXHASH;
+	}
 
 	/* pick up primary MAC address from SI */
 	enetc_load_primary_mac_addr(&si->hw, ndev);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v4 net-next 10/14] net: enetc: move generic VLAN filter interfaces to enetc-core
  2025-03-11  5:38 [PATCH v4 net-next 00/14] Add more feautues for ENETC v4 - round 2 Wei Fang
                   ` (8 preceding siblings ...)
  2025-03-11  5:38 ` [PATCH v4 net-next 09/14] net: enetc: enable RSS feature by default Wei Fang
@ 2025-03-11  5:38 ` Wei Fang
  2025-03-17 17:05   ` Vladimir Oltean
  2025-03-11  5:38 ` [PATCH v4 net-next 11/14] net: enetc: move generic VLAN hash filter functions to enetc_pf_common.c Wei Fang
                   ` (4 subsequent siblings)
  14 siblings, 1 reply; 58+ messages in thread
From: Wei Fang @ 2025-03-11  5:38 UTC (permalink / raw)
  To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
	davem, edumazet, kuba, pabeni
  Cc: christophe.leroy, netdev, linux-kernel, imx, linuxppc-dev,
	linux-arm-kernel

For ENETC, each SI has a corresponding VLAN hash table. That is to say,
both PF and VFs can support VLAN filter. However, currently only ENETC v1
PF driver supports VLAN filter. In order to make i.MX95 ENETC (v4) PF and
VF drivers also support VLAN filter, some related macros are moved from
enetc_pf.h to enetc.h, and the related structure variables are moved from
enetc_pf to enetc_si.

Besides, enetc_vid_hash_idx() as a generic function is moved to enetc.c.
Extract enetc_refresh_vlan_ht_filter() from enetc_sync_vlan_ht_filter()
so that it can be shared by PF and VF drivers. This will make it easier
to add VLAN filter support for i.MX95 ENETC later.

Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
 drivers/net/ethernet/freescale/enetc/enetc.c  | 25 ++++++++++
 drivers/net/ethernet/freescale/enetc/enetc.h  |  6 +++
 .../net/ethernet/freescale/enetc/enetc_pf.c   | 46 +++++--------------
 .../net/ethernet/freescale/enetc/enetc_pf.h   |  4 --
 4 files changed, 42 insertions(+), 39 deletions(-)

diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
index 8583ac9f7b9e..248dbc874eec 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
@@ -72,6 +72,31 @@ void enetc_reset_mac_addr_filter(struct enetc_mac_filter *filter)
 }
 EXPORT_SYMBOL_GPL(enetc_reset_mac_addr_filter);
 
+int enetc_vid_hash_idx(unsigned int vid)
+{
+	int res = 0;
+	int i;
+
+	for (i = 0; i < 6; i++)
+		res |= (hweight8(vid & (BIT(i) | BIT(i + 6))) & 0x1) << i;
+
+	return res;
+}
+EXPORT_SYMBOL_GPL(enetc_vid_hash_idx);
+
+void enetc_refresh_vlan_ht_filter(struct enetc_si *si)
+{
+	int i;
+
+	bitmap_zero(si->vlan_ht_filter, ENETC_VLAN_HT_SIZE);
+	for_each_set_bit(i, si->active_vlans, VLAN_N_VID) {
+		int hidx = enetc_vid_hash_idx(i);
+
+		__set_bit(hidx, si->vlan_ht_filter);
+	}
+}
+EXPORT_SYMBOL_GPL(enetc_refresh_vlan_ht_filter);
+
 static int enetc_num_stack_tx_queues(struct enetc_ndev_priv *priv)
 {
 	int num_tx_rings = priv->num_tx_rings;
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index ecf79338cd79..c60741dfe358 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -24,6 +24,7 @@
 #define ENETC_CBD_DATA_MEM_ALIGN 64
 
 #define ENETC_MADDR_HASH_TBL_SZ	64
+#define ENETC_VLAN_HT_SIZE	64
 
 enum enetc_mac_addr_type {UC, MC, MADDR_TYPE};
 
@@ -321,6 +322,9 @@ struct enetc_si {
 	struct workqueue_struct *workqueue;
 	struct work_struct rx_mode_task;
 	struct dentry *debugfs_root;
+
+	DECLARE_BITMAP(vlan_ht_filter, ENETC_VLAN_HT_SIZE);
+	DECLARE_BITMAP(active_vlans, VLAN_N_VID);
 };
 
 #define ENETC_SI_ALIGN	32
@@ -506,6 +510,8 @@ int enetc_get_driver_data(struct enetc_si *si);
 void enetc_add_mac_addr_ht_filter(struct enetc_mac_filter *filter,
 				  const unsigned char *addr);
 void enetc_reset_mac_addr_filter(struct enetc_mac_filter *filter);
+int enetc_vid_hash_idx(unsigned int vid);
+void enetc_refresh_vlan_ht_filter(struct enetc_si *si);
 
 int enetc_open(struct net_device *ndev);
 int enetc_close(struct net_device *ndev);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index 38ec7657b9aa..f9b179ed6d8b 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -222,45 +222,18 @@ static void enetc_set_vlan_ht_filter(struct enetc_hw *hw, int si_idx,
 	enetc_port_wr(hw, ENETC_PSIVHFR1(si_idx), upper_32_bits(hash));
 }
 
-static int enetc_vid_hash_idx(unsigned int vid)
-{
-	int res = 0;
-	int i;
-
-	for (i = 0; i < 6; i++)
-		res |= (hweight8(vid & (BIT(i) | BIT(i + 6))) & 0x1) << i;
-
-	return res;
-}
-
-static void enetc_sync_vlan_ht_filter(struct enetc_pf *pf, bool rehash)
-{
-	int i;
-
-	if (rehash) {
-		bitmap_zero(pf->vlan_ht_filter, ENETC_VLAN_HT_SIZE);
-
-		for_each_set_bit(i, pf->active_vlans, VLAN_N_VID) {
-			int hidx = enetc_vid_hash_idx(i);
-
-			__set_bit(hidx, pf->vlan_ht_filter);
-		}
-	}
-
-	enetc_set_vlan_ht_filter(&pf->si->hw, 0, *pf->vlan_ht_filter);
-}
-
 static int enetc_vlan_rx_add_vid(struct net_device *ndev, __be16 prot, u16 vid)
 {
 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
-	struct enetc_pf *pf = enetc_si_priv(priv->si);
+	struct enetc_si *si = priv->si;
+	struct enetc_hw *hw = &si->hw;
 	int idx;
 
-	__set_bit(vid, pf->active_vlans);
+	__set_bit(vid, si->active_vlans);
 
 	idx = enetc_vid_hash_idx(vid);
-	if (!__test_and_set_bit(idx, pf->vlan_ht_filter))
-		enetc_sync_vlan_ht_filter(pf, false);
+	if (!__test_and_set_bit(idx, si->vlan_ht_filter))
+		enetc_set_vlan_ht_filter(hw, 0, *si->vlan_ht_filter);
 
 	return 0;
 }
@@ -268,10 +241,13 @@ static int enetc_vlan_rx_add_vid(struct net_device *ndev, __be16 prot, u16 vid)
 static int enetc_vlan_rx_del_vid(struct net_device *ndev, __be16 prot, u16 vid)
 {
 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
-	struct enetc_pf *pf = enetc_si_priv(priv->si);
+	struct enetc_si *si = priv->si;
+	struct enetc_hw *hw = &si->hw;
 
-	__clear_bit(vid, pf->active_vlans);
-	enetc_sync_vlan_ht_filter(pf, true);
+	if (__test_and_clear_bit(vid, si->active_vlans)) {
+		enetc_refresh_vlan_ht_filter(si);
+		enetc_set_vlan_ht_filter(hw, 0, *si->vlan_ht_filter);
+	}
 
 	return 0;
 }
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.h b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
index 3b0cb0d8bf48..90137fbb8f48 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
@@ -6,8 +6,6 @@
 
 #define ENETC_PF_NUM_RINGS	8
 
-#define ENETC_VLAN_HT_SIZE	64
-
 enum enetc_vf_flags {
 	ENETC_VF_FLAG_PF_SET_MAC	= BIT(0),
 };
@@ -52,8 +50,6 @@ struct enetc_pf {
 	char msg_int_name[ENETC_INT_NAME_MAX];
 
 	char vlan_promisc_simap; /* bitmap of SIs in VLAN promisc mode */
-	DECLARE_BITMAP(vlan_ht_filter, ENETC_VLAN_HT_SIZE);
-	DECLARE_BITMAP(active_vlans, VLAN_N_VID);
 
 	struct mii_bus *mdio; /* saved for cleanup */
 	struct mii_bus *imdio;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v4 net-next 11/14] net: enetc: move generic VLAN hash filter functions to enetc_pf_common.c
  2025-03-11  5:38 [PATCH v4 net-next 00/14] Add more feautues for ENETC v4 - round 2 Wei Fang
                   ` (9 preceding siblings ...)
  2025-03-11  5:38 ` [PATCH v4 net-next 10/14] net: enetc: move generic VLAN filter interfaces to enetc-core Wei Fang
@ 2025-03-11  5:38 ` Wei Fang
  2025-03-18 10:21   ` Vladimir Oltean
  2025-03-11  5:38 ` [PATCH v4 net-next 12/14] net: enetc: add VLAN filtering support for i.MX95 ENETC PF Wei Fang
                   ` (3 subsequent siblings)
  14 siblings, 1 reply; 58+ messages in thread
From: Wei Fang @ 2025-03-11  5:38 UTC (permalink / raw)
  To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
	davem, edumazet, kuba, pabeni
  Cc: christophe.leroy, netdev, linux-kernel, imx, linuxppc-dev,
	linux-arm-kernel

Since the VLAN hash filter of ENETC v1 and v4 is the basically same, the
only difference is the offset of the VLAN hash filter registers. So, the
.set_si_vlan_hash_filter() hook is added to struct enetc_pf_ops to set
the registers of the corresponding platform. In addition, the common VLAN
hash filter functions enetc_vlan_rx_add_vid() and enetc_vlan_rx_del_vid()
are moved to enetc_pf_common.c.

Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
 .../net/ethernet/freescale/enetc/enetc_pf.c   | 34 ++-----------------
 .../net/ethernet/freescale/enetc/enetc_pf.h   |  1 +
 .../freescale/enetc/enetc_pf_common.c         | 34 +++++++++++++++++++
 .../freescale/enetc/enetc_pf_common.h         |  2 ++
 4 files changed, 39 insertions(+), 32 deletions(-)

diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index f9b179ed6d8b..d3ca9e33893f 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -215,43 +215,12 @@ static void enetc_pf_set_rx_mode(struct net_device *ndev)
 	enetc_port_wr(hw, ENETC_PSIPMR, psipmr);
 }
 
-static void enetc_set_vlan_ht_filter(struct enetc_hw *hw, int si_idx,
-				     unsigned long hash)
+static void enetc_set_vlan_ht_filter(struct enetc_hw *hw, int si_idx, u64 hash)
 {
 	enetc_port_wr(hw, ENETC_PSIVHFR0(si_idx), lower_32_bits(hash));
 	enetc_port_wr(hw, ENETC_PSIVHFR1(si_idx), upper_32_bits(hash));
 }
 
-static int enetc_vlan_rx_add_vid(struct net_device *ndev, __be16 prot, u16 vid)
-{
-	struct enetc_ndev_priv *priv = netdev_priv(ndev);
-	struct enetc_si *si = priv->si;
-	struct enetc_hw *hw = &si->hw;
-	int idx;
-
-	__set_bit(vid, si->active_vlans);
-
-	idx = enetc_vid_hash_idx(vid);
-	if (!__test_and_set_bit(idx, si->vlan_ht_filter))
-		enetc_set_vlan_ht_filter(hw, 0, *si->vlan_ht_filter);
-
-	return 0;
-}
-
-static int enetc_vlan_rx_del_vid(struct net_device *ndev, __be16 prot, u16 vid)
-{
-	struct enetc_ndev_priv *priv = netdev_priv(ndev);
-	struct enetc_si *si = priv->si;
-	struct enetc_hw *hw = &si->hw;
-
-	if (__test_and_clear_bit(vid, si->active_vlans)) {
-		enetc_refresh_vlan_ht_filter(si);
-		enetc_set_vlan_ht_filter(hw, 0, *si->vlan_ht_filter);
-	}
-
-	return 0;
-}
-
 static void enetc_set_loopback(struct net_device *ndev, bool en)
 {
 	struct enetc_ndev_priv *priv = netdev_priv(ndev);
@@ -953,6 +922,7 @@ static const struct enetc_pf_ops enetc_pf_ops = {
 	.create_pcs = enetc_pf_create_pcs,
 	.destroy_pcs = enetc_pf_destroy_pcs,
 	.enable_psfp = enetc_psfp_enable,
+	.set_si_vlan_hash_filter = enetc_set_vlan_ht_filter,
 };
 
 static int enetc_pf_probe(struct pci_dev *pdev,
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.h b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
index 90137fbb8f48..704c4ee42f61 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
@@ -37,6 +37,7 @@ struct enetc_pf_ops {
 	struct phylink_pcs *(*create_pcs)(struct enetc_pf *pf, struct mii_bus *bus);
 	void (*destroy_pcs)(struct phylink_pcs *pcs);
 	int (*enable_psfp)(struct enetc_ndev_priv *priv);
+	void (*set_si_vlan_hash_filter)(struct enetc_hw *hw, int si, u64 hash);
 };
 
 struct enetc_pf {
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
index a737a7f8c79e..9f812c1af7a3 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
@@ -343,5 +343,39 @@ void enetc_phylink_destroy(struct enetc_ndev_priv *priv)
 }
 EXPORT_SYMBOL_GPL(enetc_phylink_destroy);
 
+int enetc_vlan_rx_add_vid(struct net_device *ndev, __be16 prot, u16 vid)
+{
+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
+	struct enetc_pf *pf = enetc_si_priv(priv->si);
+	struct enetc_si *si = priv->si;
+	struct enetc_hw *hw = &si->hw;
+	int idx;
+
+	__set_bit(vid, si->active_vlans);
+
+	idx = enetc_vid_hash_idx(vid);
+	if (!__test_and_set_bit(idx, si->vlan_ht_filter))
+		pf->ops->set_si_vlan_hash_filter(hw, 0, *si->vlan_ht_filter);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(enetc_vlan_rx_add_vid);
+
+int enetc_vlan_rx_del_vid(struct net_device *ndev, __be16 prot, u16 vid)
+{
+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
+	struct enetc_pf *pf = enetc_si_priv(priv->si);
+	struct enetc_si *si = priv->si;
+	struct enetc_hw *hw = &si->hw;
+
+	if (__test_and_clear_bit(vid, si->active_vlans)) {
+		enetc_refresh_vlan_ht_filter(si);
+		pf->ops->set_si_vlan_hash_filter(hw, 0, *si->vlan_ht_filter);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(enetc_vlan_rx_del_vid);
+
 MODULE_DESCRIPTION("NXP ENETC PF common functionality driver");
 MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
index 48f55ee743ad..253310859ca1 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
@@ -12,6 +12,8 @@ void enetc_mdiobus_destroy(struct enetc_pf *pf);
 int enetc_phylink_create(struct enetc_ndev_priv *priv, struct device_node *node,
 			 const struct phylink_mac_ops *ops);
 void enetc_phylink_destroy(struct enetc_ndev_priv *priv);
+int enetc_vlan_rx_add_vid(struct net_device *ndev, __be16 prot, u16 vid);
+int enetc_vlan_rx_del_vid(struct net_device *ndev, __be16 prot, u16 vid);
 
 static inline u16 enetc_get_ip_revision(struct enetc_hw *hw)
 {
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v4 net-next 12/14] net: enetc: add VLAN filtering support for i.MX95 ENETC PF
  2025-03-11  5:38 [PATCH v4 net-next 00/14] Add more feautues for ENETC v4 - round 2 Wei Fang
                   ` (10 preceding siblings ...)
  2025-03-11  5:38 ` [PATCH v4 net-next 11/14] net: enetc: move generic VLAN hash filter functions to enetc_pf_common.c Wei Fang
@ 2025-03-11  5:38 ` Wei Fang
  2025-03-11  5:38 ` [PATCH v4 net-next 13/14] net: enetc: add loopback " Wei Fang
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 58+ messages in thread
From: Wei Fang @ 2025-03-11  5:38 UTC (permalink / raw)
  To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
	davem, edumazet, kuba, pabeni
  Cc: christophe.leroy, netdev, linux-kernel, imx, linuxppc-dev,
	linux-arm-kernel

Add VLAN hash filter support for i.MX95 ENETC PF. If VLAN filtering is
disabled, then VLAN promiscuous mode will be enabled, which means that
PF qualifies for reception of all VLAN tags.

Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
 .../net/ethernet/freescale/enetc/enetc4_hw.h  |  4 ++++
 .../net/ethernet/freescale/enetc/enetc4_pf.c  | 20 +++++++++++++++++++
 .../freescale/enetc/enetc_pf_common.c         |  2 +-
 3 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
index 826359004850..aa25b445d301 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
@@ -107,6 +107,10 @@
 #define ENETC4_PSIMMHFR0(a)		((a) * 0x80 + 0x2058)
 #define ENETC4_PSIMMHFR1(a)		((a) * 0x80 + 0x205c)
 
+/* Port station interface a VLAN hash filter register 0/1 */
+#define ENETC4_PSIVHFR0(a)		((a) * 0x80 + 0x2060)
+#define ENETC4_PSIVHFR1(a)		((a) * 0x80 + 0x2064)
+
 #define ENETC4_PMCAPR			0x4004
 #define  PMCAPR_HD			BIT(8)
 #define  PMCAPR_FP			GENMASK(10, 9)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index 53dbd5d71859..4abbbbef00ff 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -101,6 +101,13 @@ static void enetc4_pf_set_si_mac_hash_filter(struct enetc_hw *hw, int si,
 	}
 }
 
+static void enetc4_pf_set_si_vlan_hash_filter(struct enetc_hw *hw,
+					      int si, u64 hash)
+{
+	enetc_port_wr(hw, ENETC4_PSIVHFR0(si), lower_32_bits(hash));
+	enetc_port_wr(hw, ENETC4_PSIVHFR1(si), upper_32_bits(hash));
+}
+
 static void enetc4_pf_destroy_mac_list(struct enetc_pf *pf)
 {
 	struct enetc_mac_list_entry *entry;
@@ -407,6 +414,7 @@ static void enetc4_pf_set_mac_filter(struct enetc_pf *pf, int type)
 static const struct enetc_pf_ops enetc4_pf_ops = {
 	.set_si_primary_mac = enetc4_pf_set_si_primary_mac,
 	.get_si_primary_mac = enetc4_pf_get_si_primary_mac,
+	.set_si_vlan_hash_filter = enetc4_pf_set_si_vlan_hash_filter,
 };
 
 static int enetc4_pf_struct_init(struct enetc_si *si)
@@ -696,6 +704,16 @@ static void enetc4_pf_set_rx_mode(struct net_device *ndev)
 static int enetc4_pf_set_features(struct net_device *ndev,
 				  netdev_features_t features)
 {
+	netdev_features_t changed = ndev->features ^ features;
+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
+	struct enetc_hw *hw = &priv->si->hw;
+
+	if (changed & NETIF_F_HW_VLAN_CTAG_FILTER) {
+		bool promisc_en = !(features & NETIF_F_HW_VLAN_CTAG_FILTER);
+
+		enetc4_pf_set_si_vlan_promisc(hw, 0, promisc_en);
+	}
+
 	enetc_set_features(ndev, features);
 
 	return 0;
@@ -709,6 +727,8 @@ static const struct net_device_ops enetc4_ndev_ops = {
 	.ndo_set_mac_address	= enetc_pf_set_mac_addr,
 	.ndo_set_rx_mode	= enetc4_pf_set_rx_mode,
 	.ndo_set_features	= enetc4_pf_set_features,
+	.ndo_vlan_rx_add_vid	= enetc_vlan_rx_add_vid,
+	.ndo_vlan_rx_kill_vid	= enetc_vlan_rx_del_vid,
 };
 
 static struct phylink_pcs *
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
index 9f812c1af7a3..3f7ccc482301 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
@@ -135,7 +135,7 @@ void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
 
 	/* TODO: currently, i.MX95 ENETC driver does not support advanced features */
 	if (!is_enetc_rev1(si)) {
-		ndev->hw_features &= ~(NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_LOOPBACK);
+		ndev->hw_features &= ~NETIF_F_LOOPBACK;
 		goto end;
 	}
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v4 net-next 13/14] net: enetc: add loopback support for i.MX95 ENETC PF
  2025-03-11  5:38 [PATCH v4 net-next 00/14] Add more feautues for ENETC v4 - round 2 Wei Fang
                   ` (11 preceding siblings ...)
  2025-03-11  5:38 ` [PATCH v4 net-next 12/14] net: enetc: add VLAN filtering support for i.MX95 ENETC PF Wei Fang
@ 2025-03-11  5:38 ` Wei Fang
  2025-03-11  5:38 ` [PATCH v4 net-next 14/14] MAINTAINERS: add new file ntmp.h to ENETC driver Wei Fang
  2025-03-13 13:50 ` [PATCH v4 net-next 00/14] Add more feautues for ENETC v4 - round 2 Vladimir Oltean
  14 siblings, 0 replies; 58+ messages in thread
From: Wei Fang @ 2025-03-11  5:38 UTC (permalink / raw)
  To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
	davem, edumazet, kuba, pabeni
  Cc: christophe.leroy, netdev, linux-kernel, imx, linuxppc-dev,
	linux-arm-kernel

Add internal loopback support for i.MX95 ENETC PF, the default loopback
mode is MAC level loopback, the MAC Tx data is looped back onto the Rx.
The MAC interface runs at a fixed 1:8 ratio of NETC clock in MAC-level
loopback mode, with no dependency on Tx clock.

Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
 .../net/ethernet/freescale/enetc/enetc4_pf.c   | 18 ++++++++++++++++++
 .../ethernet/freescale/enetc/enetc_pf_common.c |  4 +---
 2 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index 4abbbbef00ff..c169900ccb4a 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -108,6 +108,21 @@ static void enetc4_pf_set_si_vlan_hash_filter(struct enetc_hw *hw,
 	enetc_port_wr(hw, ENETC4_PSIVHFR1(si), upper_32_bits(hash));
 }
 
+static void enetc4_pf_set_loopback(struct net_device *ndev, bool en)
+{
+	struct enetc_ndev_priv *priv = netdev_priv(ndev);
+	struct enetc_si *si = priv->si;
+	u32 val;
+
+	val = enetc_port_mac_rd(si, ENETC4_PM_CMD_CFG(0));
+	val = u32_replace_bits(val, en ? 1 : 0, PM_CMD_CFG_LOOP_EN);
+	/* Default to select MAC level loopback mode if loopback is enabled. */
+	val = u32_replace_bits(val, en ? LPBCK_MODE_MAC_LEVEL : 0,
+			       PM_CMD_CFG_LPBK_MODE);
+
+	enetc_port_mac_wr(si, ENETC4_PM_CMD_CFG(0), val);
+}
+
 static void enetc4_pf_destroy_mac_list(struct enetc_pf *pf)
 {
 	struct enetc_mac_list_entry *entry;
@@ -714,6 +729,9 @@ static int enetc4_pf_set_features(struct net_device *ndev,
 		enetc4_pf_set_si_vlan_promisc(hw, 0, promisc_en);
 	}
 
+	if (changed & NETIF_F_LOOPBACK)
+		enetc4_pf_set_loopback(ndev, !!(features & NETIF_F_LOOPBACK));
+
 	enetc_set_features(ndev, features);
 
 	return 0;
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
index 3f7ccc482301..0a2b8769a175 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
@@ -134,10 +134,8 @@ void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
 	}
 
 	/* TODO: currently, i.MX95 ENETC driver does not support advanced features */
-	if (!is_enetc_rev1(si)) {
-		ndev->hw_features &= ~NETIF_F_LOOPBACK;
+	if (!is_enetc_rev1(si))
 		goto end;
-	}
 
 	ndev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT |
 			     NETDEV_XDP_ACT_NDO_XMIT | NETDEV_XDP_ACT_RX_SG |
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v4 net-next 14/14] MAINTAINERS: add new file ntmp.h to ENETC driver
  2025-03-11  5:38 [PATCH v4 net-next 00/14] Add more feautues for ENETC v4 - round 2 Wei Fang
                   ` (12 preceding siblings ...)
  2025-03-11  5:38 ` [PATCH v4 net-next 13/14] net: enetc: add loopback " Wei Fang
@ 2025-03-11  5:38 ` Wei Fang
  2025-03-17 17:06   ` Vladimir Oltean
  2025-03-13 13:50 ` [PATCH v4 net-next 00/14] Add more feautues for ENETC v4 - round 2 Vladimir Oltean
  14 siblings, 1 reply; 58+ messages in thread
From: Wei Fang @ 2025-03-11  5:38 UTC (permalink / raw)
  To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
	davem, edumazet, kuba, pabeni
  Cc: christophe.leroy, netdev, linux-kernel, imx, linuxppc-dev,
	linux-arm-kernel

Add new file ntmp.h. to ENETC driver.

Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
 MAINTAINERS | 1 +
 1 file changed, 1 insertion(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 7078199fcebf..e259b659eadb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9174,6 +9174,7 @@ F:	Documentation/devicetree/bindings/net/nxp,netc-blk-ctrl.yaml
 F:	drivers/net/ethernet/freescale/enetc/
 F:	include/linux/fsl/enetc_mdio.h
 F:	include/linux/fsl/netc_global.h
+F:	include/linux/fsl/ntmp.h
 
 FREESCALE eTSEC ETHERNET DRIVER (GIANFAR)
 M:	Claudiu Manoil <claudiu.manoil@nxp.com>
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* Re: [PATCH v4 net-next 01/14] net: enetc: add initial netc-lib driver to support NTMP
  2025-03-11  5:38 ` [PATCH v4 net-next 01/14] net: enetc: add initial netc-lib driver to support NTMP Wei Fang
@ 2025-03-11 12:17   ` Michal Kubiak
  2025-03-13 16:35   ` Vladimir Oltean
  1 sibling, 0 replies; 58+ messages in thread
From: Michal Kubiak @ 2025-03-11 12:17 UTC (permalink / raw)
  To: Wei Fang
  Cc: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
	davem, edumazet, kuba, pabeni, christophe.leroy, netdev,
	linux-kernel, imx, linuxppc-dev, linux-arm-kernel

On Tue, Mar 11, 2025 at 01:38:17PM +0800, Wei Fang wrote:
> Some NETC functionality is controlled using control messages sent to the
> hardware using BD ring interface with 32B descriptor similar to transmit
> BD ring used on ENETC. This BD ring interface is referred to as command
> BD ring. It is used to configure functionality where the underlying
> resources may be shared between different entities or being too large to
> configure using direct registers. Therefore, a messaging protocol called
> NETC Table Management Protocol (NTMP) is provided for exchanging
> configuration and management information between the software and the
> hardware using the command BD ring interface.
> 
> For i.MX95, NTMP has been upgraded to version 2.0, which is incompatible
> with LS1028A, because the message formats have been changed. Therefore,
> add the netc-lib driver to support NTMP 2.0 to operate various tables.
> Note that, only MAC address filter table and RSS table are supported at
> the moment. More tables will be supported in subsequent patches.
> 
> It is worth mentioning that the purpose of the netc-lib driver is to
> provide some NTMP-based generic interfaces for ENETC and NETC Switch
> drivers. Currently, it only supports the configurations of some tables.
> Interfaces such as tc flower and debugfs will be added in the future.
> 
> Signed-off-by: Wei Fang <wei.fang@nxp.com>

The patch looks OK to me.

Thanks,
Reviewed-by: Michal Kubiak <michal.kubiak@intel.com>

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v4 net-next 02/14] net: enetc: add command BD ring support for i.MX95 ENETC
  2025-03-11  5:38 ` [PATCH v4 net-next 02/14] net: enetc: add command BD ring support for i.MX95 ENETC Wei Fang
@ 2025-03-11 12:22   ` Michal Kubiak
  2025-03-13 16:49   ` Vladimir Oltean
  1 sibling, 0 replies; 58+ messages in thread
From: Michal Kubiak @ 2025-03-11 12:22 UTC (permalink / raw)
  To: Wei Fang
  Cc: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
	davem, edumazet, kuba, pabeni, christophe.leroy, netdev,
	linux-kernel, imx, linuxppc-dev, linux-arm-kernel

On Tue, Mar 11, 2025 at 01:38:18PM +0800, Wei Fang wrote:
> 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>

Thanks,
Reviewed-by: Michal Kubiak <michal.kubiak@intel.com>

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v4 net-next 00/14] Add more feautues for ENETC v4 - round 2
  2025-03-11  5:38 [PATCH v4 net-next 00/14] Add more feautues for ENETC v4 - round 2 Wei Fang
                   ` (13 preceding siblings ...)
  2025-03-11  5:38 ` [PATCH v4 net-next 14/14] MAINTAINERS: add new file ntmp.h to ENETC driver Wei Fang
@ 2025-03-13 13:50 ` Vladimir Oltean
  2025-03-14  1:28   ` Wei Fang
  14 siblings, 1 reply; 58+ messages in thread
From: Vladimir Oltean @ 2025-03-13 13:50 UTC (permalink / raw)
  To: Wei Fang
  Cc: claudiu.manoil, xiaoning.wang, andrew+netdev, davem, edumazet,
	kuba, pabeni, christophe.leroy, netdev, linux-kernel, imx,
	linuxppc-dev, linux-arm-kernel

On Tue, Mar 11, 2025 at 01:38:16PM +0800, Wei Fang wrote:
> This patch set adds the following features.
> 1. Compared with ENETC v1, the formats of tables and command BD of ENETC
> v4 have changed significantly, and the two are not compatible. Therefore,
> in order to support the NETC Table Management Protocol (NTMP) v2.0, we
> introduced the netc-lib driver and added support for MAC address filter
> table and RSS table.
> 2. Add MAC filter and VLAN filter support for i.MX95 ENETC PF.
> 3. Add RSS support for i.MX95 ENETC PF.
> 4. Add loopback support for i.MX95 ENETC PF.

Can you please fix the "feautues" typo in the cover letter title? It
will get used for the merge commit.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v4 net-next 01/14] net: enetc: add initial netc-lib driver to support NTMP
  2025-03-11  5:38 ` [PATCH v4 net-next 01/14] net: enetc: add initial netc-lib driver to support NTMP Wei Fang
  2025-03-11 12:17   ` Michal Kubiak
@ 2025-03-13 16:35   ` Vladimir Oltean
  2025-03-14  3:38     ` Wei Fang
  1 sibling, 1 reply; 58+ messages in thread
From: Vladimir Oltean @ 2025-03-13 16:35 UTC (permalink / raw)
  To: Wei Fang
  Cc: claudiu.manoil, xiaoning.wang, andrew+netdev, davem, edumazet,
	kuba, pabeni, christophe.leroy, netdev, linux-kernel, imx,
	linuxppc-dev, linux-arm-kernel

On Tue, Mar 11, 2025 at 01:38:17PM +0800, Wei Fang wrote:
> +int ntmp_rsst_query_or_update_entry(struct netc_cbdrs *cbdrs, u32 *table,
> +				    int count, bool query)
> +{
> +	struct ntmp_dma_buf data = {.dev = cbdrs->dma_dev};
> +	struct rsst_req_update *requ;
> +	struct ntmp_req_by_eid *req;
> +	union netc_cbd cbd;
> +	int err, i;
> +	u32 len;
> +
> +	if (count != RSST_ENTRY_NUM)
> +		/* HW only takes in a full 64 entry table */
> +		return -EINVAL;
> +
> +	if (query)
> +		data.size = NTMP_ENTRY_ID_SIZE + RSST_STSE_DATA_SIZE(count) +
> +			    RSST_CFGE_DATA_SIZE(count);
> +	else
> +		data.size = struct_size(requ, groups, count);
> +
> +	err = ntmp_alloc_data_mem(&data, (void **)&req);
> +	if (err)
> +		return err;
> +
> +	/* Set the request data buffer */
> +	if (query) {
> +		ntmp_fill_crd_eid(req, cbdrs->tbl.rsst_ver, 0, 0, 0);
> +		len = NTMP_LEN(sizeof(*req), data.size);
> +		ntmp_fill_request_headr(&cbd, data.dma, len, NTMP_RSST_ID,
> +					NTMP_CMD_QUERY, NTMP_AM_ENTRY_ID);

Please either use a commonly accepted abbreviation such as "hdr", or preferably,
just spell "header" as such. This reminded me of Kevin Malone's quote
"Why waste time say lot word when few word do trick?" :)

> +	} else {
> +		requ = (struct rsst_req_update *)req;
> +		ntmp_fill_crd_eid(&requ->rbe, cbdrs->tbl.rsst_ver, 0,
> +				  NTMP_GEN_UA_CFGEU | NTMP_GEN_UA_STSEU, 0);
> +		for (i = 0; i < count; i++)
> +			requ->groups[i] = (u8)(table[i]);
> +
> +		len = NTMP_LEN(data.size, 0);
> +		ntmp_fill_request_headr(&cbd, data.dma, len, NTMP_RSST_ID,
> +					NTMP_CMD_UPDATE, NTMP_AM_ENTRY_ID);
> +	}
> +
> +	err = netc_xmit_ntmp_cmd(cbdrs, &cbd);
> +	if (err) {
> +		dev_err(cbdrs->dma_dev, "%s RSS table entry failed (%d)",
> +			query ? "Query" : "Update", err);
> +		goto end;
> +	}
> +
> +	if (query) {
> +		u8 *group = (u8 *)req;
> +
> +		group += NTMP_ENTRY_ID_SIZE + RSST_STSE_DATA_SIZE(count);
> +		for (i = 0; i < count; i++)
> +			table[i] = group[i];
> +	}
> +
> +end:
> +	ntmp_free_data_mem(&data);
> +
> +	return err;
> +}
> +EXPORT_SYMBOL_GPL(ntmp_rsst_query_or_update_entry);

Instead of exporting "query_or_update" mixed semantics, can you please
export two separate functions, one for "query" and the other for "update"?
For query=false, you can make the "table" argument const.

Also, from the looks of their implementation, there isn't much that is
common anyway.

> +static int ntmp_alloc_data_mem(struct ntmp_dma_buf *data, void **buf_align)
> +{
> +	void *buf;
> +
> +	buf = dma_alloc_coherent(data->dev, data->size + NTMP_DATA_ADDR_ALIGN,
> +				 &data->dma, GFP_ATOMIC);

Is there any call site that can't use sleeping allocations (GFP_KERNEL)?

> +	if (!buf)
> +		return -ENOMEM;
> +
> +	data->buf = buf;
> +	*buf_align = PTR_ALIGN(buf, NTMP_DATA_ADDR_ALIGN);
> +
> +	return 0;
> +}
> +
> diff --git a/drivers/net/ethernet/freescale/enetc/ntmp_private.h b/drivers/net/ethernet/freescale/enetc/ntmp_private.h
> new file mode 100644
> index 000000000000..45e4d083ab0a
> --- /dev/null
> +++ b/drivers/net/ethernet/freescale/enetc/ntmp_private.h
> @@ -0,0 +1,63 @@
> +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
> +/*
> + * NTMP table request and response data buffer formats
> + * Copyright 2025 NXP
> + */
> +
> +#ifndef __NTMP_PRIVATE_H
> +#define __NTMP_PRIVATE_H
> +
> +#include <linux/fsl/ntmp.h>
> +
> +struct ntmp_dma_buf {
> +	struct device *dev;
> +	size_t size;
> +	void *buf;
> +	dma_addr_t dma;
> +};
> +
> +struct common_req_data {

Some maintainers prefer to avoid definitions which "sound" generic, but truly
are driver-specific, and instead recommend to prefix their names with
some kind of driver specific indication
(example: https://lore.kernel.org/netdev/20190413205311.GC2268@nanopsycho.orion/).

So, maybe something like "ntmp_common_req_data", "ntmp_common_resp_query", ...
would make that more clear?

> +	__le16 update_act;
> +	u8 dbg_opt;
> +	u8 tblv_qact;
> +#define NTMP_QUERY_ACT		GENMASK(3, 0)
> +#define NTMP_TBL_VER		GENMASK(7, 0)
> +#define NTMP_TBLV_QACT(v, a)	(FIELD_PREP(NTMP_TBL_VER, (v)) | \
> +				 ((a) & NTMP_QUERY_ACT))

Can you please move #define macros out of structure definitions?

> +};
> +
> +struct common_resp_query {
> +	__le32 entry_id;
> +};
> +
> +struct common_resp_nq {
> +	__le32 status;
> +};
> +
> +/* Generic structure for request data by entry ID  */
> +struct ntmp_req_by_eid {
> +	struct common_req_data crd;
> +	__le32 entry_id;
> +};
> +
> +/* MAC Address Filter Table Request Data Buffer Format of Add action */
> +struct maft_req_add {
> +	struct ntmp_req_by_eid rbe;
> +	struct maft_keye_data keye;
> +	struct maft_cfge_data cfge;
> +};
> +
> +/* MAC Address Filter Table Response Data Buffer Format of Query action */
> +struct maft_resp_query {
> +	__le32 entry_id;
> +	struct maft_keye_data keye;
> +	struct maft_cfge_data cfge;
> +};
> +
> +/* RSS Table Request Data Buffer Format of Update action */
> +struct rsst_req_update {
> +	struct ntmp_req_by_eid rbe;
> +	u8 groups[];
> +};
> +
> +#endif
> diff --git a/include/linux/fsl/ntmp.h b/include/linux/fsl/ntmp.h
> new file mode 100644
> index 000000000000..fe15e394c4a4
> --- /dev/null
> +++ b/include/linux/fsl/ntmp.h
> @@ -0,0 +1,174 @@
> +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
> +/* Copyright 2025 NXP */
> +#ifndef __NETC_NTMP_H
> +#define __NETC_NTMP_H
> +
> +#include <linux/bitops.h>
> +#include <linux/if_ether.h>
> +
> +#define NTMP_NULL_ENTRY_ID		0xffffffffU
> +#define NETC_CBDR_BD_NUM		256
> +
> +union netc_cbd {

Do you seriously need to export the netc_cbd definition outside of
drivers/net/ethernet/freescale/enetc/ntmp.c? I would say even if you do
(which this patch set doesn't appear to need), the NTMP library exports
an API which doesn't do a great job abstracting the information.

The question pertains to everything else that is exported to
include/linux/fsl/ntmp.h - what the API consumer sees. Is there a real
reason to export it? For many structures and macros, the answer seems no.

Even for cases like struct maft_keye_data which are only used by debugfs,
it still seems preferable to keep data encapsulation and offer a helper
function to retrieve a pointer to the MAC address from the MAFT entry.
Then, "struct maft_keye_data;" can simply be declared, without exposing
its full definition.

> +	struct {
> +		__le64 addr;
> +		__le32 len;
> +#define NTMP_RESP_LEN		GENMASK(19, 0)
> +#define NTMP_REQ_LEN		GENMASK(31, 20)
> +#define NTMP_LEN(req, resp)	(FIELD_PREP(NTMP_REQ_LEN, (req)) | \
> +				((resp) & NTMP_RESP_LEN))
> +		u8 cmd;
> +#define NTMP_CMD_DELETE		BIT(0)
> +#define NTMP_CMD_UPDATE		BIT(1)
> +#define NTMP_CMD_QUERY		BIT(2)
> +#define NTMP_CMD_ADD		BIT(3)
> +#define NTMP_CMD_QD		(NTMP_CMD_QUERY | NTMP_CMD_DELETE)
> +#define NTMP_CMD_QU		(NTMP_CMD_QUERY | NTMP_CMD_UPDATE)
> +#define NTMP_CMD_AU		(NTMP_CMD_ADD | NTMP_CMD_UPDATE)
> +#define NTMP_CMD_AQ		(NTMP_CMD_ADD | NTMP_CMD_QUERY)
> +#define NTMP_CMD_AQU		(NTMP_CMD_AQ | NTMP_CMD_UPDATE)
> +		u8 access_method;
> +#define NTMP_ACCESS_METHOD	GENMASK(7, 4)
> +#define NTMP_AM_ENTRY_ID	0
> +#define NTMP_AM_EXACT_KEY	1
> +#define NTMP_AM_SEARCH		2
> +#define NTMP_AM_TERNARY_KEY	3
> +		u8 table_id;
> +		u8 ver_cci_rr;
> +#define NTMP_HDR_VERSION	GENMASK(5, 0)
> +#define NTMP_HDR_VER2		2
> +#define NTMP_CCI		BIT(6)
> +#define NTMP_RR			BIT(7)
> +		__le32 resv[3];
> +		__le32 npf;
> +#define NTMP_NPF		BIT(15)
> +	} req_hdr;	/* NTMP Request Message Header Format */
> +
> +	struct {
> +		__le32 resv0[3];
> +		__le16 num_matched;
> +		__le16 error_rr;
> +#define NTMP_RESP_ERROR		GENMASK(11, 0)
> +#define NTMP_RESP_RR		BIT(15)
> +		__le32 resv1[4];
> +	} resp_hdr; /* NTMP Response Message Header Format */
> +};
> +
> +struct maft_keye_data {
> +	u8 mac_addr[ETH_ALEN];
> +	__le16 resv;
> +};
> +
> +struct maft_cfge_data {
> +	__le16 si_bitmap;
> +	__le16 resv;
> +};
> +
> +struct netc_cbdr_regs {
> +	void __iomem *pir;
> +	void __iomem *cir;
> +	void __iomem *mr;
> +
> +	void __iomem *bar0;
> +	void __iomem *bar1;
> +	void __iomem *lenr;
> +};
> +
> +struct netc_tbl_vers {
> +	u8 maft_ver;
> +	u8 rsst_ver;
> +};
> +
> +struct netc_cbdr {
> +	struct netc_cbdr_regs regs;
> +
> +	int bd_num;
> +	int next_to_use;
> +	int next_to_clean;
> +
> +	int dma_size;
> +	void *addr_base;
> +	void *addr_base_align;
> +	dma_addr_t dma_base;
> +	dma_addr_t dma_base_align;
> +
> +	spinlock_t ring_lock; /* Avoid race condition */

Can this description be more specific? This type of comment is as
useful as not having it. Make the reader understand what is serialized
with what, to prevent concurrent, non-atomic access to what resources.

> +};
> +
> +struct netc_cbdrs {
> +	int cbdr_num;	/* number of control BD ring */
> +	int cbdr_size;	/* number of BDs per control BD ring */
> +	struct device *dma_dev;
> +	struct netc_cbdr *ring;
> +	struct netc_tbl_vers tbl;
> +};
> +
> +enum netc_dev_type {
> +	NETC_DEV_ENETC,
> +	NETC_DEV_SWITCH
> +};

Can you delay the introduction of this distinction until when the
"dev_type" will actually be used for something, and it's clear to
reviewers what is the intention behind it? Currently the switch driver
does not exist, and this has no purpose.

> +
> +struct ntmp_priv {

Would it be better to name this "struct ntmp_client"? I don't really
understand the way in which it is "private".

I'm looking at this from an API perspective, and I don't really
understand which one is the "top-level" object for an NTMP consumer
driver. Is it ntmp_priv or netc_cbdrs? Logically, ntmp_priv encapsulates
netc_cbdrs, but I see that all functions take the smaller netc_cbdrs,
which I find unintuitive. Could you just perhaps squash them into a
single structure, if they in fact serve the same purpose?

> +	enum netc_dev_type dev_type;
> +	struct netc_cbdrs cbdrs;
> +};
> +
> +struct maft_entry_data {
> +	struct maft_keye_data keye;
> +	struct maft_cfge_data cfge;
> +};

> +static int ntmp_delete_entry_by_id(struct netc_cbdrs *cbdrs, int tbl_id,
> +				   u8 tbl_ver, u32 entry_id, u32 req_len,
> +				   u32 resp_len)
> +{
> +	struct ntmp_dma_buf data = {.dev = cbdrs->dma_dev};
> +	struct ntmp_req_by_eid *req;
> +	union netc_cbd cbd;
> +	u32 len;
> +	int err;
> +
> +	if (entry_id == NTMP_NULL_ENTRY_ID)
> +		return 0;

What's the idea with the null entry ID? Why special-case it?

> +
> +	/* If the req_len is 0, indicates the requested length is the
> +	 * standard length.
> +	 */
> +	if (!req_len)
> +		req_len = sizeof(*req);

Objection: as submitted in this patch set, the req_len argument is _only_
passed as zero (the only caller is ntmp_maft_delete_entry()). I don't
know about downstream, but let's only add complexity that we need, when
we need it.

> +
> +	data.size = req_len >= resp_len ? req_len : resp_len;
> +	err = ntmp_alloc_data_mem(&data, (void **)&req);
> +	if (err)
> +		return err;
> +
> +	ntmp_fill_crd_eid(req, tbl_ver, 0, 0, entry_id);
> +	len = NTMP_LEN(req_len, resp_len);
> +	ntmp_fill_request_headr(&cbd, data.dma, len, tbl_id,
> +				NTMP_CMD_DELETE, NTMP_AM_ENTRY_ID);
> +
> +	err = netc_xmit_ntmp_cmd(cbdrs, &cbd);
> +	if (err)
> +		dev_err(cbdrs->dma_dev, "Delete table (id: %d) entry failed: %d",
> +			tbl_id, err);
> +
> +	ntmp_free_data_mem(&data);
> +
> +	return err;
> +}
> +
> +static int ntmp_query_entry_by_id(struct netc_cbdrs *cbdrs, int tbl_id,
> +				  u32 len, struct ntmp_req_by_eid *req,
> +				  dma_addr_t dma, bool compare_eid)
> +{
> +	struct device *dev = cbdrs->dma_dev;
> +	struct common_resp_query *resp;
> +	int cmd = NTMP_CMD_QUERY;
> +	union netc_cbd cbd;
> +	u32 entry_id;
> +	int err;
> +
> +	entry_id = le32_to_cpu(req->entry_id);
> +	if (le16_to_cpu(req->crd.update_act))
> +		cmd = NTMP_CMD_QU;
> +
> +	/* Request header */
> +	ntmp_fill_request_headr(&cbd, dma, len, tbl_id,
> +				cmd, NTMP_AM_ENTRY_ID);
> +
> +	err = netc_xmit_ntmp_cmd(cbdrs, &cbd);
> +	if (err) {
> +		dev_err(dev, "Query table (id: %d) entry failed: %d\n",
> +			tbl_id, err);
> +		return err;
> +	}
> +
> +	/* For a few tables, the first field of its response data is not

s/its/their/

> +	 * entry_id, so directly return success.
> +	 */
> +	if (!compare_eid)
> +		return 0;
> +
> +	resp = (struct common_resp_query *)req;
> +	if (unlikely(le32_to_cpu(resp->entry_id) != entry_id)) {
> +		dev_err(dev, "Table (id: %d) query EID:0x%0x, response EID:0x%x\n",

Can you please put some spaces between ":" and "0".

> +			tbl_id, entry_id, le32_to_cpu(resp->entry_id));
> +		return -EIO;
> +	}
> +
> +	return 0;
> +}
> +
> +int ntmp_maft_add_entry(struct netc_cbdrs *cbdrs, u32 entry_id,
> +			struct maft_entry_data *maft)
> +{
> +	struct ntmp_dma_buf data = {.dev = cbdrs->dma_dev};
> +	struct maft_req_add *req;
> +	union netc_cbd cbd;
> +	int err;
> +
> +	data.size = sizeof(*req);
> +	err = ntmp_alloc_data_mem(&data, (void **)&req);
> +	if (err)
> +		return err;
> +
> +	/* Set mac address filter table request data buffer */
> +	ntmp_fill_crd_eid(&req->rbe, cbdrs->tbl.maft_ver, 0, 0, entry_id);
> +	req->keye = maft->keye;
> +	req->cfge = maft->cfge;
> +
> +	ntmp_fill_request_headr(&cbd, data.dma, NTMP_LEN(data.size, 0),
> +				NTMP_MAFT_ID, NTMP_CMD_ADD,
> +				NTMP_AM_ENTRY_ID);
> +	err = netc_xmit_ntmp_cmd(cbdrs, &cbd);
> +	if (err)
> +		dev_err(cbdrs->dma_dev, "Add MAFT entry failed (%d)", err);

Can you use symbolic error names? "Adding MAFT entry failed: %pe\n", ERR_PTR(err).
Also notice the missing \n in the error message..

Same comment for the error message in:
- ntmp_delete_entry_by_id()
- ntmp_rsst_query_or_update_entry() - which as per review feedback here
  should become 2 functions

> +
> +	ntmp_free_data_mem(&data);
> +
> +	return err;
> +}
> +EXPORT_SYMBOL_GPL(ntmp_maft_add_entry);
> +
> +int ntmp_maft_query_entry(struct netc_cbdrs *cbdrs, u32 entry_id,
> +			  struct maft_entry_data *maft)
> +{
> +	struct ntmp_dma_buf data = {.dev = cbdrs->dma_dev};
> +	struct maft_resp_query *resp;
> +	struct ntmp_req_by_eid *req;
> +	u32 req_len = sizeof(*req);
> +	int err;
> +
> +	if (entry_id == NTMP_NULL_ENTRY_ID)
> +		return -EINVAL;
> +
> +	data.size = sizeof(*resp);
> +	err = ntmp_alloc_data_mem(&data, (void **)&req);
> +	if (err)
> +		return err;
> +
> +	ntmp_fill_crd_eid(req, cbdrs->tbl.maft_ver, 0, 0, entry_id);
> +	err = ntmp_query_entry_by_id(cbdrs, NTMP_MAFT_ID,
> +				     NTMP_LEN(req_len, data.size),
> +				     req, data.dma, true);
> +	if (err)
> +		goto end;
> +
> +	resp = (struct maft_resp_query *)req;
> +	maft->keye = resp->keye;
> +	maft->cfge = resp->cfge;
> +
> +end:
> +	ntmp_free_data_mem(&data);
> +
> +	return err;
> +}
> +EXPORT_SYMBOL_GPL(ntmp_maft_query_entry);
> +
> +int ntmp_maft_delete_entry(struct netc_cbdrs *cbdrs, u32 entry_id)
> +{
> +	return ntmp_delete_entry_by_id(cbdrs, NTMP_MAFT_ID,
> +				       cbdrs->tbl.maft_ver,
> +				       entry_id, 0, 0);
> +}
> +EXPORT_SYMBOL_GPL(ntmp_maft_delete_entry);

> +static void netc_clean_cbdr(struct netc_cbdr *cbdr)
> +{
> +	union netc_cbd *cbd;
> +	int i;
> +
> +	i = cbdr->next_to_clean;
> +	while (netc_read(cbdr->regs.cir) != i) {
> +		cbd = netc_get_cbd(cbdr, i);
> +		memset(cbd, 0, sizeof(*cbd));
> +		i = (i + 1) % cbdr->bd_num;
> +	}
> +
> +	cbdr->next_to_clean = i;
> +}
> +
> +static struct netc_cbdr *netc_select_cbdr(struct netc_cbdrs *cbdrs)
> +{
> +	int i;
> +
> +	for (i = 0; i < cbdrs->cbdr_num; i++) {
> +		if (spin_is_locked(&cbdrs->ring[i].ring_lock))
> +			continue;
> +
> +		return &cbdrs->ring[i];
> +	}
> +
> +	return &cbdrs->ring[smp_processor_id() % cbdrs->cbdr_num];

I think you need to be in a "preemption disabled" / "migration disable"
calling context for smp_processor_id() to be reliable. Otherwise, the
task can migrate to another CPU as soon as this function returns.

Anyway, much can be said about this, but currently it is useless
complexity, because the only user, enetc4_setup_cbdr(), sets
"cbdrs->cbdr_num = 1", which side-steps the entire netc_select_cbdr()
logic.

Please strip all unnecessary logic and only add it when the need
presents itself, so we can all assess whether the solution is
appropriate for that particular need.

> +}
> +
> +static int netc_xmit_ntmp_cmd(struct netc_cbdrs *cbdrs, union netc_cbd *cbd)
> +{
> +	union netc_cbd *cur_cbd;
> +	struct netc_cbdr *cbdr;
> +	int i, err;
> +	u16 status;
> +	u32 val;
> +
> +	if (cbdrs->cbdr_num == 1)
> +		cbdr = &cbdrs->ring[0];
> +	else
> +		cbdr = netc_select_cbdr(cbdrs);
> +
> +	spin_lock_bh(&cbdr->ring_lock);
> +
> +	if (unlikely(!netc_get_free_cbd_num(cbdr)))
> +		netc_clean_cbdr(cbdr);
> +
> +	i = cbdr->next_to_use;
> +	cur_cbd = netc_get_cbd(cbdr, i);
> +	*cur_cbd = *cbd;
> +
> +	/* Update producer index of both software and hardware */
> +	i = (i + 1) % cbdr->bd_num;
> +	cbdr->next_to_use = i;
> +	dma_wmb();

Can you place this dma_wmb() right next to the "*cur_cbd = *cbd" line,
to make it obvious that updating the producer index has nothing to do
with it? Or is there another reason for this ordering?

> +	netc_write(cbdr->regs.pir, i);
> +
> +	err = read_poll_timeout_atomic(netc_read, val, val == i,
> +				       10, NETC_CBDR_TIMEOUT, true,
> +				       cbdr->regs.cir);
> +	if (unlikely(err))
> +		goto cbdr_unlock;
> +
> +	dma_rmb();
> +	/* Get the writeback command BD, because the caller may need
> +	 * to check some other fields of the response header.
> +	 */
> +	*cbd = *cur_cbd;
> +
> +	/* Check the writeback error status */
> +	status = le16_to_cpu(cbd->resp_hdr.error_rr) & NTMP_RESP_ERROR;
> +	if (unlikely(status)) {
> +		err = -EIO;
> +		dev_err(cbdrs->dma_dev, "Command BD error: 0x%04x\n", status);
> +	}
> +
> +	netc_clean_cbdr(cbdr);
> +	dma_wmb();
> +
> +cbdr_unlock:
> +	spin_unlock_bh(&cbdr->ring_lock);
> +
> +	return err;
> +}

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v4 net-next 02/14] net: enetc: add command BD ring support for i.MX95 ENETC
  2025-03-11  5:38 ` [PATCH v4 net-next 02/14] net: enetc: add command BD ring support for i.MX95 ENETC Wei Fang
  2025-03-11 12:22   ` Michal Kubiak
@ 2025-03-13 16:49   ` Vladimir Oltean
  2025-03-14  4:51     ` Wei Fang
  1 sibling, 1 reply; 58+ messages in thread
From: Vladimir Oltean @ 2025-03-13 16:49 UTC (permalink / raw)
  To: Wei Fang
  Cc: claudiu.manoil, xiaoning.wang, andrew+netdev, davem, edumazet,
	kuba, pabeni, christophe.leroy, netdev, linux-kernel, imx,
	linuxppc-dev, linux-arm-kernel

On Tue, Mar 11, 2025 at 01:38:18PM +0800, Wei Fang wrote:
> 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 | 55 +++++++++++++++++--
>  .../net/ethernet/freescale/enetc/enetc_pf.c   | 13 +++--
>  .../net/ethernet/freescale/enetc/enetc_vf.c   | 13 +++--
>  5 files changed, 136 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);
> +};

I don't understand the need for si->ops->setup_cbdr() and si->ops->teardown_cbdr()?
Doesn't every call site know which kind of SI it is dealing with, and thus it can
appropriately call the direct symbol?
- the v1 PSI and the VSI call enetc_setup_cbdr() and enetc_teardown_cbdr()
- the v4 PSI calls enetc4_setup_cbdr() and enetc4_teardown_cbdr()
What benefit is there to making an indirect function call?

At least that's what the current code does, I'm not sure if that is the intention.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v4 net-next 00/14] Add more feautues for ENETC v4 - round 2
  2025-03-13 13:50 ` [PATCH v4 net-next 00/14] Add more feautues for ENETC v4 - round 2 Vladimir Oltean
@ 2025-03-14  1:28   ` Wei Fang
  0 siblings, 0 replies; 58+ messages in thread
From: Wei Fang @ 2025-03-14  1:28 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Claudiu Manoil, Clark Wang, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, christophe.leroy@csgroup.eu,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org

> On Tue, Mar 11, 2025 at 01:38:16PM +0800, Wei Fang wrote:
> > This patch set adds the following features.
> > 1. Compared with ENETC v1, the formats of tables and command BD of ENETC
> > v4 have changed significantly, and the two are not compatible. Therefore,
> > in order to support the NETC Table Management Protocol (NTMP) v2.0, we
> > introduced the netc-lib driver and added support for MAC address filter
> > table and RSS table.
> > 2. Add MAC filter and VLAN filter support for i.MX95 ENETC PF.
> > 3. Add RSS support for i.MX95 ENETC PF.
> > 4. Add loopback support for i.MX95 ENETC PF.
> 
> Can you please fix the "feautues" typo in the cover letter title? It
> will get used for the merge commit.

Yes, sure, thanks for pointing this typo.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v4 net-next 01/14] net: enetc: add initial netc-lib driver to support NTMP
  2025-03-13 16:35   ` Vladimir Oltean
@ 2025-03-14  3:38     ` Wei Fang
  2025-03-14 12:37       ` Vladimir Oltean
  0 siblings, 1 reply; 58+ messages in thread
From: Wei Fang @ 2025-03-14  3:38 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Claudiu Manoil, Clark Wang, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, christophe.leroy@csgroup.eu,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org

> On Tue, Mar 11, 2025 at 01:38:17PM +0800, Wei Fang wrote:
> > +int ntmp_rsst_query_or_update_entry(struct netc_cbdrs *cbdrs, u32 *table,
> > +				    int count, bool query)
> > +{
> > +	struct ntmp_dma_buf data = {.dev = cbdrs->dma_dev};
> > +	struct rsst_req_update *requ;
> > +	struct ntmp_req_by_eid *req;
> > +	union netc_cbd cbd;
> > +	int err, i;
> > +	u32 len;
> > +
> > +	if (count != RSST_ENTRY_NUM)
> > +		/* HW only takes in a full 64 entry table */
> > +		return -EINVAL;
> > +
> > +	if (query)
> > +		data.size = NTMP_ENTRY_ID_SIZE + RSST_STSE_DATA_SIZE(count) +
> > +			    RSST_CFGE_DATA_SIZE(count);
> > +	else
> > +		data.size = struct_size(requ, groups, count);
> > +
> > +	err = ntmp_alloc_data_mem(&data, (void **)&req);
> > +	if (err)
> > +		return err;
> > +
> > +	/* Set the request data buffer */
> > +	if (query) {
> > +		ntmp_fill_crd_eid(req, cbdrs->tbl.rsst_ver, 0, 0, 0);
> > +		len = NTMP_LEN(sizeof(*req), data.size);
> > +		ntmp_fill_request_headr(&cbd, data.dma, len, NTMP_RSST_ID,
> > +					NTMP_CMD_QUERY, NTMP_AM_ENTRY_ID);
> 
> Please either use a commonly accepted abbreviation such as "hdr", or
> preferably,
> just spell "header" as such. This reminded me of Kevin Malone's quote
> "Why waste time say lot word when few word do trick?" :)
> 

Sure, I will fix it.

> > +	} else {
> > +		requ = (struct rsst_req_update *)req;
> > +		ntmp_fill_crd_eid(&requ->rbe, cbdrs->tbl.rsst_ver, 0,
> > +				  NTMP_GEN_UA_CFGEU | NTMP_GEN_UA_STSEU, 0);
> > +		for (i = 0; i < count; i++)
> > +			requ->groups[i] = (u8)(table[i]);
> > +
> > +		len = NTMP_LEN(data.size, 0);
> > +		ntmp_fill_request_headr(&cbd, data.dma, len, NTMP_RSST_ID,
> > +					NTMP_CMD_UPDATE, NTMP_AM_ENTRY_ID);
> > +	}
> > +
> > +	err = netc_xmit_ntmp_cmd(cbdrs, &cbd);
> > +	if (err) {
> > +		dev_err(cbdrs->dma_dev, "%s RSS table entry failed (%d)",
> > +			query ? "Query" : "Update", err);
> > +		goto end;
> > +	}
> > +
> > +	if (query) {
> > +		u8 *group = (u8 *)req;
> > +
> > +		group += NTMP_ENTRY_ID_SIZE + RSST_STSE_DATA_SIZE(count);
> > +		for (i = 0; i < count; i++)
> > +			table[i] = group[i];
> > +	}
> > +
> > +end:
> > +	ntmp_free_data_mem(&data);
> > +
> > +	return err;
> > +}
> > +EXPORT_SYMBOL_GPL(ntmp_rsst_query_or_update_entry);
> 
> Instead of exporting "query_or_update" mixed semantics, can you please
> export two separate functions, one for "query" and the other for "update"?
> For query=false, you can make the "table" argument const.
> 
> Also, from the looks of their implementation, there isn't much that is
> common anyway.
> 

Okay, accept, I will split it into two functions.

> > +static int ntmp_alloc_data_mem(struct ntmp_dma_buf *data, void
> **buf_align)
> > +{
> > +	void *buf;
> > +
> > +	buf = dma_alloc_coherent(data->dev, data->size +
> NTMP_DATA_ADDR_ALIGN,
> > +				 &data->dma, GFP_ATOMIC);
> 
> Is there any call site that can't use sleeping allocations (GFP_KERNEL)?
> 

The initial reason was that we called ntmp_maft_add_entry() directly when
implementing ndo_set_rx_mode(), so we changed it to GFP_ATOMIC. Later,
we implemented ndo_set_rx_mode() using workqueue, so for the current
patch, we can change it back to GFP_KERNEL.

> > +	if (!buf)
> > +		return -ENOMEM;
> > +
> > +	data->buf = buf;
> > +	*buf_align = PTR_ALIGN(buf, NTMP_DATA_ADDR_ALIGN);
> > +
> > +	return 0;
> > +}
> > +
> > diff --git a/drivers/net/ethernet/freescale/enetc/ntmp_private.h
> b/drivers/net/ethernet/freescale/enetc/ntmp_private.h
> > new file mode 100644
> > index 000000000000..45e4d083ab0a
> > --- /dev/null
> > +++ b/drivers/net/ethernet/freescale/enetc/ntmp_private.h
> > @@ -0,0 +1,63 @@
> > +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
> > +/*
> > + * NTMP table request and response data buffer formats
> > + * Copyright 2025 NXP
> > + */
> > +
> > +#ifndef __NTMP_PRIVATE_H
> > +#define __NTMP_PRIVATE_H
> > +
> > +#include <linux/fsl/ntmp.h>
> > +
> > +struct ntmp_dma_buf {
> > +	struct device *dev;
> > +	size_t size;
> > +	void *buf;
> > +	dma_addr_t dma;
> > +};
> > +
> > +struct common_req_data {
> 
> Some maintainers prefer to avoid definitions which "sound" generic, but truly
> are driver-specific, and instead recommend to prefix their names with
> some kind of driver specific indication
> (example:
> https://lore.kernel.org/netdev/20190413205311.GC2268@nanopsycho.orion/).
> 
> So, maybe something like "ntmp_common_req_data",
> "ntmp_common_resp_query", ...
> would make that more clear?
> 

I will rename these structs, thanks.

> > +	__le16 update_act;
> > +	u8 dbg_opt;
> > +	u8 tblv_qact;
> > +#define NTMP_QUERY_ACT		GENMASK(3, 0)
> > +#define NTMP_TBL_VER		GENMASK(7, 0)
> > +#define NTMP_TBLV_QACT(v, a)	(FIELD_PREP(NTMP_TBL_VER, (v)) | \
> > +				 ((a) & NTMP_QUERY_ACT))
> 
> Can you please move #define macros out of structure definitions?

No, I think these macros in the structure can better reflect the specific
meaning of these members. We can intuitively see what the bits of
these members represent, rather than finding the definition of these
bits in RM or elsewhere.

> 
> > +};
> > +
> > +struct common_resp_query {
> > +	__le32 entry_id;
> > +};
> > +
> > +struct common_resp_nq {
> > +	__le32 status;
> > +};
> > +
> > +/* Generic structure for request data by entry ID  */
> > +struct ntmp_req_by_eid {
> > +	struct common_req_data crd;
> > +	__le32 entry_id;
> > +};
> > +
> > +/* MAC Address Filter Table Request Data Buffer Format of Add action */
> > +struct maft_req_add {
> > +	struct ntmp_req_by_eid rbe;
> > +	struct maft_keye_data keye;
> > +	struct maft_cfge_data cfge;
> > +};
> > +
> > +/* MAC Address Filter Table Response Data Buffer Format of Query action */
> > +struct maft_resp_query {
> > +	__le32 entry_id;
> > +	struct maft_keye_data keye;
> > +	struct maft_cfge_data cfge;
> > +};
> > +
> > +/* RSS Table Request Data Buffer Format of Update action */
> > +struct rsst_req_update {
> > +	struct ntmp_req_by_eid rbe;
> > +	u8 groups[];
> > +};
> > +
> > +#endif
> > diff --git a/include/linux/fsl/ntmp.h b/include/linux/fsl/ntmp.h
> > new file mode 100644
> > index 000000000000..fe15e394c4a4
> > --- /dev/null
> > +++ b/include/linux/fsl/ntmp.h
> > @@ -0,0 +1,174 @@
> > +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
> > +/* Copyright 2025 NXP */
> > +#ifndef __NETC_NTMP_H
> > +#define __NETC_NTMP_H
> > +
> > +#include <linux/bitops.h>
> > +#include <linux/if_ether.h>
> > +
> > +#define NTMP_NULL_ENTRY_ID		0xffffffffU
> > +#define NETC_CBDR_BD_NUM		256
> > +
> > +union netc_cbd {
> 
> Do you seriously need to export the netc_cbd definition outside of
> drivers/net/ethernet/freescale/enetc/ntmp.c? I would say even if you do
> (which this patch set doesn't appear to need), the NTMP library exports
> an API which doesn't do a great job abstracting the information.

Sorry, I was not aware of the netc_cbd could be moved to ntmp_private.h
as well.

> 
> The question pertains to everything else that is exported to
> include/linux/fsl/ntmp.h - what the API consumer sees. Is there a real
> reason to export it? For many structures and macros, the answer seems no.
> 
> Even for cases like struct maft_keye_data which are only used by debugfs,
> it still seems preferable to keep data encapsulation and offer a helper
> function to retrieve a pointer to the MAC address from the MAFT entry.
> Then, "struct maft_keye_data;" can simply be declared, without exposing
> its full definition.

ntmp_private.h is only used for ntmp driver, I don't want it to be included
by any enetc files. ntmp.h is used for both enetc and switch drivers, so we
need to add full definitions of the table data.

> 
> > +	struct {
> > +		__le64 addr;
> > +		__le32 len;
> > +#define NTMP_RESP_LEN		GENMASK(19, 0)
> > +#define NTMP_REQ_LEN		GENMASK(31, 20)
> > +#define NTMP_LEN(req, resp)	(FIELD_PREP(NTMP_REQ_LEN, (req)) | \
> > +				((resp) & NTMP_RESP_LEN))
> > +		u8 cmd;
> > +#define NTMP_CMD_DELETE		BIT(0)
> > +#define NTMP_CMD_UPDATE		BIT(1)
> > +#define NTMP_CMD_QUERY		BIT(2)
> > +#define NTMP_CMD_ADD		BIT(3)
> > +#define NTMP_CMD_QD		(NTMP_CMD_QUERY |
> NTMP_CMD_DELETE)
> > +#define NTMP_CMD_QU		(NTMP_CMD_QUERY |
> NTMP_CMD_UPDATE)
> > +#define NTMP_CMD_AU		(NTMP_CMD_ADD | NTMP_CMD_UPDATE)
> > +#define NTMP_CMD_AQ		(NTMP_CMD_ADD | NTMP_CMD_QUERY)
> > +#define NTMP_CMD_AQU		(NTMP_CMD_AQ | NTMP_CMD_UPDATE)
> > +		u8 access_method;
> > +#define NTMP_ACCESS_METHOD	GENMASK(7, 4)
> > +#define NTMP_AM_ENTRY_ID	0
> > +#define NTMP_AM_EXACT_KEY	1
> > +#define NTMP_AM_SEARCH		2
> > +#define NTMP_AM_TERNARY_KEY	3
> > +		u8 table_id;
> > +		u8 ver_cci_rr;
> > +#define NTMP_HDR_VERSION	GENMASK(5, 0)
> > +#define NTMP_HDR_VER2		2
> > +#define NTMP_CCI		BIT(6)
> > +#define NTMP_RR			BIT(7)
> > +		__le32 resv[3];
> > +		__le32 npf;
> > +#define NTMP_NPF		BIT(15)
> > +	} req_hdr;	/* NTMP Request Message Header Format */
> > +
> > +	struct {
> > +		__le32 resv0[3];
> > +		__le16 num_matched;
> > +		__le16 error_rr;
> > +#define NTMP_RESP_ERROR		GENMASK(11, 0)
> > +#define NTMP_RESP_RR		BIT(15)
> > +		__le32 resv1[4];
> > +	} resp_hdr; /* NTMP Response Message Header Format */
> > +};
> > +
> > +struct maft_keye_data {
> > +	u8 mac_addr[ETH_ALEN];
> > +	__le16 resv;
> > +};
> > +
> > +struct maft_cfge_data {
> > +	__le16 si_bitmap;
> > +	__le16 resv;
> > +};
> > +
> > +struct netc_cbdr_regs {
> > +	void __iomem *pir;
> > +	void __iomem *cir;
> > +	void __iomem *mr;
> > +
> > +	void __iomem *bar0;
> > +	void __iomem *bar1;
> > +	void __iomem *lenr;
> > +};
> > +
> > +struct netc_tbl_vers {
> > +	u8 maft_ver;
> > +	u8 rsst_ver;
> > +};
> > +
> > +struct netc_cbdr {
> > +	struct netc_cbdr_regs regs;
> > +
> > +	int bd_num;
> > +	int next_to_use;
> > +	int next_to_clean;
> > +
> > +	int dma_size;
> > +	void *addr_base;
> > +	void *addr_base_align;
> > +	dma_addr_t dma_base;
> > +	dma_addr_t dma_base_align;
> > +
> > +	spinlock_t ring_lock; /* Avoid race condition */
> 
> Can this description be more specific? This type of comment is as
> useful as not having it. Make the reader understand what is serialized
> with what, to prevent concurrent, non-atomic access to what resources.
> 
> > +};
> > +
> > +struct netc_cbdrs {
> > +	int cbdr_num;	/* number of control BD ring */
> > +	int cbdr_size;	/* number of BDs per control BD ring */
> > +	struct device *dma_dev;
> > +	struct netc_cbdr *ring;
> > +	struct netc_tbl_vers tbl;
> > +};
> > +
> > +enum netc_dev_type {
> > +	NETC_DEV_ENETC,
> > +	NETC_DEV_SWITCH
> > +};
> 
> Can you delay the introduction of this distinction until when the
> "dev_type" will actually be used for something, and it's clear to
> reviewers what is the intention behind it? Currently the switch driver
> does not exist, and this has no purpose.
> 

Okay, I will remove it.

> > +
> > +struct ntmp_priv {
> 
> Would it be better to name this "struct ntmp_client"? I don't really
> understand the way in which it is "private".

It refers to some private data of NTMP of different devices (enetc or
switches). Since the current patch is only a small part of NTMP, many
members have not been added to the structure. The following is the
definition in our downstream.

struct ntmp_priv {
	enum netc_dev_type dev_type;
	struct netc_cbdrs cbdrs;
	u32 errata;

	struct ntmp_caps caps;
	/* bitmap of table entry ID */
	unsigned long *ist_eid_bitmap;
	unsigned long *rpt_eid_bitmap;
	unsigned long *sgit_eid_bitmap;
	unsigned long *isct_eid_bitmap;
	unsigned long *sgclt_word_bitmap;
	unsigned long *ett_eid_bitmap;
	unsigned long *ect_eid_bitmap;
	u32 ett_bitmap_size;
	u32 ect_bitmap_size;

	struct hlist_head flower_list;
	struct mutex flower_lock; /* flower_list lock */

	u64 (*adjust_base_time)(struct ntmp_priv *priv, u64 bt, u32 ct);
	u32 (*get_tgst_free_words)(struct ntmp_priv *priv);
};

> 
> I'm looking at this from an API perspective, and I don't really
> understand which one is the "top-level" object for an NTMP consumer
> driver. Is it ntmp_priv or netc_cbdrs? Logically, ntmp_priv encapsulates
> netc_cbdrs, but I see that all functions take the smaller netc_cbdrs,
> which I find unintuitive. Could you just perhaps squash them into a
> single structure, if they in fact serve the same purpose?
> 
> > +	enum netc_dev_type dev_type;
> > +	struct netc_cbdrs cbdrs;
> > +};
> > +
> > +struct maft_entry_data {
> > +	struct maft_keye_data keye;
> > +	struct maft_cfge_data cfge;
> > +};
> 
> > +static int ntmp_delete_entry_by_id(struct netc_cbdrs *cbdrs, int tbl_id,
> > +				   u8 tbl_ver, u32 entry_id, u32 req_len,
> > +				   u32 resp_len)
> > +{
> > +	struct ntmp_dma_buf data = {.dev = cbdrs->dma_dev};
> > +	struct ntmp_req_by_eid *req;
> > +	union netc_cbd cbd;
> > +	u32 len;
> > +	int err;
> > +
> > +	if (entry_id == NTMP_NULL_ENTRY_ID)
> > +		return 0;
> 
> What's the idea with the null entry ID? Why special-case it?
> 

Some functions are configured by multiple tables. If a table is
not needed in the current configuration, we may set its entry
id to NTMP_NULL_ENTRY_ID, indicating that the table is bypassed.
For the current patch, this condition can be removed.

> > +
> > +	/* If the req_len is 0, indicates the requested length is the
> > +	 * standard length.
> > +	 */
> > +	if (!req_len)
> > +		req_len = sizeof(*req);
> 
> Objection: as submitted in this patch set, the req_len argument is _only_
> passed as zero (the only caller is ntmp_maft_delete_entry()). I don't
> know about downstream, but let's only add complexity that we need, when
> we need it.
> 

Okay, I will remove it.

> > +
> > +	data.size = req_len >= resp_len ? req_len : resp_len;
> > +	err = ntmp_alloc_data_mem(&data, (void **)&req);
> > +	if (err)
> > +		return err;
> > +
> > +	ntmp_fill_crd_eid(req, tbl_ver, 0, 0, entry_id);
> > +	len = NTMP_LEN(req_len, resp_len);
> > +	ntmp_fill_request_headr(&cbd, data.dma, len, tbl_id,
> > +				NTMP_CMD_DELETE, NTMP_AM_ENTRY_ID);
> > +
> > +	err = netc_xmit_ntmp_cmd(cbdrs, &cbd);
> > +	if (err)
> > +		dev_err(cbdrs->dma_dev, "Delete table (id: %d) entry failed: %d",
> > +			tbl_id, err);
> > +
> > +	ntmp_free_data_mem(&data);
> > +
> > +	return err;
> > +}
> > +
> > +static int ntmp_query_entry_by_id(struct netc_cbdrs *cbdrs, int tbl_id,
> > +				  u32 len, struct ntmp_req_by_eid *req,
> > +				  dma_addr_t dma, bool compare_eid)
> > +{
> > +	struct device *dev = cbdrs->dma_dev;
> > +	struct common_resp_query *resp;
> > +	int cmd = NTMP_CMD_QUERY;
> > +	union netc_cbd cbd;
> > +	u32 entry_id;
> > +	int err;
> > +
> > +	entry_id = le32_to_cpu(req->entry_id);
> > +	if (le16_to_cpu(req->crd.update_act))
> > +		cmd = NTMP_CMD_QU;
> > +
> > +	/* Request header */
> > +	ntmp_fill_request_headr(&cbd, dma, len, tbl_id,
> > +				cmd, NTMP_AM_ENTRY_ID);
> > +
> > +	err = netc_xmit_ntmp_cmd(cbdrs, &cbd);
> > +	if (err) {
> > +		dev_err(dev, "Query table (id: %d) entry failed: %d\n",
> > +			tbl_id, err);
> > +		return err;
> > +	}
> > +
> > +	/* For a few tables, the first field of its response data is not
> 
> s/its/their/
> 
> > +	 * entry_id, so directly return success.
> > +	 */
> > +	if (!compare_eid)
> > +		return 0;
> > +
> > +	resp = (struct common_resp_query *)req;
> > +	if (unlikely(le32_to_cpu(resp->entry_id) != entry_id)) {
> > +		dev_err(dev, "Table (id: %d) query EID:0x%0x, response EID:0x%x\n",
> 
> Can you please put some spaces between ":" and "0".

Yes, sure.

> 
> > +			tbl_id, entry_id, le32_to_cpu(resp->entry_id));
> > +		return -EIO;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +int ntmp_maft_add_entry(struct netc_cbdrs *cbdrs, u32 entry_id,
> > +			struct maft_entry_data *maft)
> > +{
> > +	struct ntmp_dma_buf data = {.dev = cbdrs->dma_dev};
> > +	struct maft_req_add *req;
> > +	union netc_cbd cbd;
> > +	int err;
> > +
> > +	data.size = sizeof(*req);
> > +	err = ntmp_alloc_data_mem(&data, (void **)&req);
> > +	if (err)
> > +		return err;
> > +
> > +	/* Set mac address filter table request data buffer */
> > +	ntmp_fill_crd_eid(&req->rbe, cbdrs->tbl.maft_ver, 0, 0, entry_id);
> > +	req->keye = maft->keye;
> > +	req->cfge = maft->cfge;
> > +
> > +	ntmp_fill_request_headr(&cbd, data.dma, NTMP_LEN(data.size, 0),
> > +				NTMP_MAFT_ID, NTMP_CMD_ADD,
> > +				NTMP_AM_ENTRY_ID);
> > +	err = netc_xmit_ntmp_cmd(cbdrs, &cbd);
> > +	if (err)
> > +		dev_err(cbdrs->dma_dev, "Add MAFT entry failed (%d)", err);
> 
> Can you use symbolic error names? "Adding MAFT entry failed: %pe\n",
> ERR_PTR(err).
> Also notice the missing \n in the error message..

Okay, thanks.

> 
> Same comment for the error message in:
> - ntmp_delete_entry_by_id()
> - ntmp_rsst_query_or_update_entry() - which as per review feedback here
>   should become 2 functions
> 
> > +
> > +	ntmp_free_data_mem(&data);
> > +
> > +	return err;
> > +}
> > +EXPORT_SYMBOL_GPL(ntmp_maft_add_entry);
> > +
> > +int ntmp_maft_query_entry(struct netc_cbdrs *cbdrs, u32 entry_id,
> > +			  struct maft_entry_data *maft)
> > +{
> > +	struct ntmp_dma_buf data = {.dev = cbdrs->dma_dev};
> > +	struct maft_resp_query *resp;
> > +	struct ntmp_req_by_eid *req;
> > +	u32 req_len = sizeof(*req);
> > +	int err;
> > +
> > +	if (entry_id == NTMP_NULL_ENTRY_ID)
> > +		return -EINVAL;
> > +
> > +	data.size = sizeof(*resp);
> > +	err = ntmp_alloc_data_mem(&data, (void **)&req);
> > +	if (err)
> > +		return err;
> > +
> > +	ntmp_fill_crd_eid(req, cbdrs->tbl.maft_ver, 0, 0, entry_id);
> > +	err = ntmp_query_entry_by_id(cbdrs, NTMP_MAFT_ID,
> > +				     NTMP_LEN(req_len, data.size),
> > +				     req, data.dma, true);
> > +	if (err)
> > +		goto end;
> > +
> > +	resp = (struct maft_resp_query *)req;
> > +	maft->keye = resp->keye;
> > +	maft->cfge = resp->cfge;
> > +
> > +end:
> > +	ntmp_free_data_mem(&data);
> > +
> > +	return err;
> > +}
> > +EXPORT_SYMBOL_GPL(ntmp_maft_query_entry);
> > +
> > +int ntmp_maft_delete_entry(struct netc_cbdrs *cbdrs, u32 entry_id)
> > +{
> > +	return ntmp_delete_entry_by_id(cbdrs, NTMP_MAFT_ID,
> > +				       cbdrs->tbl.maft_ver,
> > +				       entry_id, 0, 0);
> > +}
> > +EXPORT_SYMBOL_GPL(ntmp_maft_delete_entry);
> 
> > +static void netc_clean_cbdr(struct netc_cbdr *cbdr)
> > +{
> > +	union netc_cbd *cbd;
> > +	int i;
> > +
> > +	i = cbdr->next_to_clean;
> > +	while (netc_read(cbdr->regs.cir) != i) {
> > +		cbd = netc_get_cbd(cbdr, i);
> > +		memset(cbd, 0, sizeof(*cbd));
> > +		i = (i + 1) % cbdr->bd_num;
> > +	}
> > +
> > +	cbdr->next_to_clean = i;
> > +}
> > +
> > +static struct netc_cbdr *netc_select_cbdr(struct netc_cbdrs *cbdrs)
> > +{
> > +	int i;
> > +
> > +	for (i = 0; i < cbdrs->cbdr_num; i++) {
> > +		if (spin_is_locked(&cbdrs->ring[i].ring_lock))
> > +			continue;
> > +
> > +		return &cbdrs->ring[i];
> > +	}
> > +
> > +	return &cbdrs->ring[smp_processor_id() % cbdrs->cbdr_num];
> 
> I think you need to be in a "preemption disabled" / "migration disable"
> calling context for smp_processor_id() to be reliable. Otherwise, the
> task can migrate to another CPU as soon as this function returns.
> 

It does not matter, we just want to select a command BD ring when all
command BD rings are busy. So smp_processor_id() is just a parameter,
we can also use a random number.

> Anyway, much can be said about this, but currently it is useless
> complexity, because the only user, enetc4_setup_cbdr(), sets
> "cbdrs->cbdr_num = 1", which side-steps the entire netc_select_cbdr()
> logic.
> 
> Please strip all unnecessary logic and only add it when the need
> presents itself, so we can all assess whether the solution is
> appropriate for that particular need.
> 

Okay, agree

> > +}
> > +
> > +static int netc_xmit_ntmp_cmd(struct netc_cbdrs *cbdrs, union netc_cbd
> *cbd)
> > +{
> > +	union netc_cbd *cur_cbd;
> > +	struct netc_cbdr *cbdr;
> > +	int i, err;
> > +	u16 status;
> > +	u32 val;
> > +
> > +	if (cbdrs->cbdr_num == 1)
> > +		cbdr = &cbdrs->ring[0];
> > +	else
> > +		cbdr = netc_select_cbdr(cbdrs);
> > +
> > +	spin_lock_bh(&cbdr->ring_lock);
> > +
> > +	if (unlikely(!netc_get_free_cbd_num(cbdr)))
> > +		netc_clean_cbdr(cbdr);
> > +
> > +	i = cbdr->next_to_use;
> > +	cur_cbd = netc_get_cbd(cbdr, i);
> > +	*cur_cbd = *cbd;
> > +
> > +	/* Update producer index of both software and hardware */
> > +	i = (i + 1) % cbdr->bd_num;
> > +	cbdr->next_to_use = i;
> > +	dma_wmb();
> 
> Can you place this dma_wmb() right next to the "*cur_cbd = *cbd" line,
> to make it obvious that updating the producer index has nothing to do
> with it? Or is there another reason for this ordering?
> 

No special reason for this ordering, I will move it after "*cur_cbd = *cbd".

> > +	netc_write(cbdr->regs.pir, i);
> > +
> > +	err = read_poll_timeout_atomic(netc_read, val, val == i,
> > +				       10, NETC_CBDR_TIMEOUT, true,
> > +				       cbdr->regs.cir);
> > +	if (unlikely(err))
> > +		goto cbdr_unlock;
> > +
> > +	dma_rmb();
> > +	/* Get the writeback command BD, because the caller may need
> > +	 * to check some other fields of the response header.
> > +	 */
> > +	*cbd = *cur_cbd;
> > +
> > +	/* Check the writeback error status */
> > +	status = le16_to_cpu(cbd->resp_hdr.error_rr) & NTMP_RESP_ERROR;
> > +	if (unlikely(status)) {
> > +		err = -EIO;
> > +		dev_err(cbdrs->dma_dev, "Command BD error: 0x%04x\n", status);
> > +	}
> > +
> > +	netc_clean_cbdr(cbdr);
> > +	dma_wmb();
> > +
> > +cbdr_unlock:
> > +	spin_unlock_bh(&cbdr->ring_lock);
> > +
> > +	return err;
> > +}

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v4 net-next 02/14] net: enetc: add command BD ring support for i.MX95 ENETC
  2025-03-13 16:49   ` Vladimir Oltean
@ 2025-03-14  4:51     ` Wei Fang
  2025-03-14 11:18       ` Vladimir Oltean
  0 siblings, 1 reply; 58+ messages in thread
From: Wei Fang @ 2025-03-14  4:51 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Claudiu Manoil, Clark Wang, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, christophe.leroy@csgroup.eu,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org

> On Tue, Mar 11, 2025 at 01:38:18PM +0800, Wei Fang wrote:
> > 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 | 55 +++++++++++++++++--
> >  .../net/ethernet/freescale/enetc/enetc_pf.c   | 13 +++--
> >  .../net/ethernet/freescale/enetc/enetc_vf.c   | 13 +++--
> >  5 files changed, 136 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);
> > +};
> 
> I don't understand the need for si->ops->setup_cbdr() and
> si->ops->teardown_cbdr()?
> Doesn't every call site know which kind of SI it is dealing with, and thus it can
> appropriately call the direct symbol?
> - the v1 PSI and the VSI call enetc_setup_cbdr() and enetc_teardown_cbdr()
> - the v4 PSI calls enetc4_setup_cbdr() and enetc4_teardown_cbdr()

Yes, for PSI we can use directly call these functions because they are different
drivers, but for VSI, v1 and v4 will use the same driver. I just want the PSI and
VSI to be consistent. If you don't like this, I can remove these interfaces from
the patch set, and add vf_setup_cbdr and vf_teardown_cbdr in the future when
I add the VF support for ENETC v4.

> What benefit is there to making an indirect function call?
> 
> At least that's what the current code does, I'm not sure if that is the intention.



^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v4 net-next 02/14] net: enetc: add command BD ring support for i.MX95 ENETC
  2025-03-14  4:51     ` Wei Fang
@ 2025-03-14 11:18       ` Vladimir Oltean
  2025-03-14 13:56         ` Wei Fang
  0 siblings, 1 reply; 58+ messages in thread
From: Vladimir Oltean @ 2025-03-14 11:18 UTC (permalink / raw)
  To: Wei Fang
  Cc: Claudiu Manoil, Clark Wang, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, christophe.leroy@csgroup.eu,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org

On Fri, Mar 14, 2025 at 06:51:06AM +0200, Wei Fang wrote:
> > I don't understand the need for si->ops->setup_cbdr() and
> > si->ops->teardown_cbdr()?
> > Doesn't every call site know which kind of SI it is dealing with, and thus it can
> > appropriately call the direct symbol?
> > - the v1 PSI and the VSI call enetc_setup_cbdr() and enetc_teardown_cbdr()
> > - the v4 PSI calls enetc4_setup_cbdr() and enetc4_teardown_cbdr()
> 
> Yes, for PSI we can use directly call these functions because they are different
> drivers, but for VSI, v1 and v4 will use the same driver. I just want the PSI and
> VSI to be consistent. If you don't like this, I can remove these interfaces from
> the patch set, and add vf_setup_cbdr and vf_teardown_cbdr in the future when
> I add the VF support for ENETC v4.

It's not that I don't like them, the point is rather simple: as far as
this patch set is concerned, converting direct function calls to
indirect ones is an unfinished idea. It needs to be evaluated in full
context, which is not present here - as you say, v4 VSIs need to be
further modified to call a different set of operations - but right now,
they call a single set of CBDR functions. Changes which require
subsequent patch sets in order to make any sense at all are discouraged.

Given the fact that the PSI code paths still don't benefit from an
indirect function call in any way, I would in principle recommend to
keep calling their CBDR methods directly. For VSIs I don't know which is
preferable (if-else vs function pointer), I need to see that code first.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v4 net-next 01/14] net: enetc: add initial netc-lib driver to support NTMP
  2025-03-14  3:38     ` Wei Fang
@ 2025-03-14 12:37       ` Vladimir Oltean
  2025-03-14 13:48         ` Wei Fang
  0 siblings, 1 reply; 58+ messages in thread
From: Vladimir Oltean @ 2025-03-14 12:37 UTC (permalink / raw)
  To: Wei Fang
  Cc: Claudiu Manoil, Clark Wang, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, christophe.leroy@csgroup.eu,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org

On Fri, Mar 14, 2025 at 05:38:18AM +0200, Wei Fang wrote:
> > > +	__le16 update_act;
> > > +	u8 dbg_opt;
> > > +	u8 tblv_qact;
> > > +#define NTMP_QUERY_ACT		GENMASK(3, 0)
> > > +#define NTMP_TBL_VER		GENMASK(7, 0)
> > > +#define NTMP_TBLV_QACT(v, a)	(FIELD_PREP(NTMP_TBL_VER, (v)) | \
> > > +				 ((a) & NTMP_QUERY_ACT))
> > 
> > Can you please move #define macros out of structure definitions?
> 
> No, I think these macros in the structure can better reflect the specific
> meaning of these members. We can intuitively see what the bits of
> these members represent, rather than finding the definition of these
> bits in RM or elsewhere.

I mean, I was just suggesting to group the macros with the macros, and
the struct fields with the struct fields. Mixing them together looks a
bit messy to me. Even worse in the definition of "union netc_cbd" which
IMO needs to be reconsidered a bit (a hint given below).

But you mention "intuitive" definitions without having to go to the RM.
If I look just at the definitions, I see that NTMP_QUERY_ACT and NTMP_TBL_VER
overlap, and that NTMP_TBLV_QACT() just ORs them together. How does that work?
Shouldn't NTMP_TBL_VER() have been GENMASK(7, 4)? If I do open the RM
and go to the "Generic NTMP Request Data Buffer Format" section, that
table does seem to agree with me.

The "normal" way to give more meaning to struct fields is to define them
as enum values. That doesn't work with "packed" field definitions as you
have here, which I agree is a challenge. But it is one of the reasons
why I tried to develop an API together with Jacob Keller which tries to
address this, by allowing you to define the structures in an "unpacked"
format, and have a separate data structure which informs the CPU how
that structure maps over the buffer layout.

Below is an example to illustrate this for the case of NTMP request buffers.
Note that the example is incomplete and doesn't even compile, because I
haven't even converted all ntmp_fill_crd_eid() callers - I don't want to
waste too much time doing that in case you disagree, but it's still
enough to show what I'm talking about. Disclaimer: I didn't even _try_
to compile it - it may contain bugs.

-- >8 --
diff --git a/drivers/net/ethernet/freescale/enetc/Kconfig b/drivers/net/ethernet/freescale/enetc/Kconfig
index c8efbb6f2055..35d5cf21f6f4 100644
--- a/drivers/net/ethernet/freescale/enetc/Kconfig
+++ b/drivers/net/ethernet/freescale/enetc/Kconfig
@@ -17,6 +17,7 @@ config NXP_ENETC_PF_COMMON
 
 config NXP_NETC_LIB
 	tristate
+	select PACKING
 	help
 	  This module provides common functionalities for both ENETC and NETC
 	  Switch, such as NETC Table Management Protocol (NTMP) 2.0, common tc
diff --git a/drivers/net/ethernet/freescale/enetc/ntmp.c b/drivers/net/ethernet/freescale/enetc/ntmp.c
index df10f2f310c1..f96cfca92a1c 100644
--- a/drivers/net/ethernet/freescale/enetc/ntmp.c
+++ b/drivers/net/ethernet/freescale/enetc/ntmp.c
@@ -180,7 +180,7 @@ static int netc_xmit_ntmp_cmd(struct netc_cbdrs *cbdrs, union netc_cbd *cbd)
 	return err;
 }
 
-static int ntmp_alloc_data_mem(struct ntmp_dma_buf *data, void **buf_align)
+static int ntmp_alloc_data_mem(struct ntmp_dma_buf *data, ntmp_common_req_msg_data_buf *buf_align)
 {
 	void *buf;
 
@@ -221,18 +221,24 @@ static void ntmp_fill_request_headr(union netc_cbd *cbd, dma_addr_t dma,
 	cbd->req_hdr.npf = cpu_to_le32(NTMP_NPF);
 }
 
-static void ntmp_fill_crd(struct common_req_data *crd,
-			  u8 tblv, u8 qa, u16 ua)
+static const struct packed_field_u8 ntmp_common_req_fields[] = {
+	PACKED_FIELD(31, 28, struct ntmp_common_req_data, table_version),
+	PACKED_FIELD(27, 24, struct ntmp_common_req_data, query_actions),
+	PACKED_FIELD(15, 0, struct ntmp_common_req_data, update_actions),
+};
+
+static void ntmp_fill_crd(ntmp_common_req_msg_data_buf *buf,
+			  const struct common_req_data *crd)
 {
-	crd->update_act = cpu_to_le16(ua);
-	crd->tblv_qact = NTMP_TBLV_QACT(tblv, qa);
+	pack_fields(buf, sizeof(*buf), crd, ntmp_common_req_fields,
+		    QUIRK_LITTLE_ENDIAN);
 }
 
-static void ntmp_fill_crd_eid(struct ntmp_req_by_eid *rbe, u8 tblv,
-			      u8 qa, u16 ua, u32 entry_id)
+static void ntmp_fill_crd_eid(struct ntmp_common_req_msg_data_buf *buf,
+			      const struct ntmp_req_by_eid *rbe)
 {
-	ntmp_fill_crd(&rbe->crd, tblv, qa, ua);
-	rbe->entry_id = cpu_to_le32(entry_id);
+	ntmp_fill_crd(buf, &rbe->crd);
+	pack(buf + 1, rbe->entry_id, 31, 0);
 }
 
 static int ntmp_delete_entry_by_id(struct netc_cbdrs *cbdrs, int tbl_id,
@@ -240,7 +246,13 @@ static int ntmp_delete_entry_by_id(struct netc_cbdrs *cbdrs, int tbl_id,
 				   u32 resp_len)
 {
 	struct ntmp_dma_buf data = {.dev = cbdrs->dma_dev};
-	struct ntmp_req_by_eid *req;
+	struct ntmp_req_by_eid req = {
+		.crd = {
+			.table_version = tbl_ver,
+		},
+		.entry_id = entry_id,
+	};
+	ntmp_common_req_msg_data_buf buf;
 	union netc_cbd cbd;
 	u32 len;
 	int err;
@@ -255,7 +267,7 @@ static int ntmp_delete_entry_by_id(struct netc_cbdrs *cbdrs, int tbl_id,
 		req_len = sizeof(*req);
 
 	data.size = req_len >= resp_len ? req_len : resp_len;
-	err = ntmp_alloc_data_mem(&data, (void **)&req);
+	err = ntmp_alloc_data_mem(&data, &buf);
 	if (err)
 		return err;
 
diff --git a/drivers/net/ethernet/freescale/enetc/ntmp_private.h b/drivers/net/ethernet/freescale/enetc/ntmp_private.h
index 45e4d083ab0a..e68b2a060176 100644
--- a/drivers/net/ethernet/freescale/enetc/ntmp_private.h
+++ b/drivers/net/ethernet/freescale/enetc/ntmp_private.h
@@ -16,14 +16,14 @@ struct ntmp_dma_buf {
 	dma_addr_t dma;
 };
 
-struct common_req_data {
-	__le16 update_act;
-	u8 dbg_opt;
-	u8 tblv_qact;
-#define NTMP_QUERY_ACT		GENMASK(3, 0)
-#define NTMP_TBL_VER		GENMASK(7, 0)
-#define NTMP_TBLV_QACT(v, a)	(FIELD_PREP(NTMP_TBL_VER, (v)) | \
-				 ((a) & NTMP_QUERY_ACT))
+#define NTMP_COMMON_REQ_MSG_DATA_BUFSZ	4
+
+typedef struct __packed { u8 buf[NTMP_COMMON_REQ_MSG_DATA_BUFSZ]; } ntmp_common_req_msg_data_buf;
+
+struct ntmp_common_req_data {
+	u16 update_actions;
+	u8 query_actions;
+	u8 table_version;
 };
 
 struct common_resp_query {
@@ -36,8 +36,8 @@ struct common_resp_nq {
 
 /* Generic structure for request data by entry ID  */
 struct ntmp_req_by_eid {
-	struct common_req_data crd;
-	__le32 entry_id;
+	struct ntmp_common_req_data crd;
+	u32 entry_id;
 };
 
 /* MAC Address Filter Table Request Data Buffer Format of Add action */
-- >8 --

Some remarks:
 - The fact that struct ntmp_common_req_data is an unpacked structure
   now means that the layout of fields is completely decoupled from the
   layout of the data buffer. You can make each field an enum type if
   you want, which I didn't do here.
 - You don't have to access its fields with le32_to_cpu() and friends,
   it's implicitly in CPU endianness.
 - The API is tolerant of the case where the CPU is in a different
   endianness from ENETC.
 - The API protects you against overlapping PACKED_FIELD() definitions,
   and gives a compile-time error if it detects an overlap.
 - The API allows you to define buffers of any size you want, and the
   bit field ranges vary according to the buffer size you chose. Notice
   how you are grouping two fields within the "u8 tblv_qact" field, and
   their offsets are 7-4 and 3-0, respectively, within that u8, but in
   the PACKED_FIELD() definition you can make them 31-28 and 27-24, just
   like in the RM.
 - struct ntmp_req_by_eid and struct ntmp_common_req_data don't have to
   be distinct structures. You can call pack_fields() and pack only a
   subset of the fields of an unpacked structure. Then pack the rest
   with explicit pack() calls, or not pack them at all.

I just want to present this alternative because I believe it offers some
distinct advantages which may be useful here. But note that just
"QUIRK_LITTLE_ENDIAN" may be wrong for NTMP. You need to see whether you
also need QUIRK_LSW32_IS_FIRST or not. For buffers up to 32 bits,
QUIRK_LSW32_IS_FIRST makes no difference, only for buffers larger than that.

> > The question pertains to everything else that is exported to
> > include/linux/fsl/ntmp.h - what the API consumer sees. Is there a real
> > reason to export it? For many structures and macros, the answer seems no.
> > 
> > Even for cases like struct maft_keye_data which are only used by debugfs,
> > it still seems preferable to keep data encapsulation and offer a helper
> > function to retrieve a pointer to the MAC address from the MAFT entry.
> > Then, "struct maft_keye_data;" can simply be declared, without exposing
> > its full definition.
> 
> ntmp_private.h is only used for ntmp driver, I don't want it to be included
> by any enetc files. ntmp.h is used for both enetc and switch drivers, so we
> need to add full definitions of the table data.

And I agree with you, I also don't want ntmp_private.h to be exposed to
the NTMP API consumers, and I wasn't suggesting that. I just want the
NTMP API to spare consumer drivers of the gory details, like for example
the buffer layout of a MAC filtering entry, reserved fields, things like
that. What I was saying is to keep the buffer layout private to
ntmp_private.h, and expose a more abstract data structure to API
consumers.

> > > +struct ntmp_priv {
> > 
> > Would it be better to name this "struct ntmp_client"? I don't really
> > understand the way in which it is "private".
> 
> It refers to some private data of NTMP of different devices (enetc or
> switches). Since the current patch is only a small part of NTMP, many
> members have not been added to the structure. The following is the
> definition in our downstream.
> 
> struct ntmp_priv {
> 	enum netc_dev_type dev_type;
> 	struct netc_cbdrs cbdrs;
> 	u32 errata;
> 
> 	struct ntmp_caps caps;
> 	/* bitmap of table entry ID */
> 	unsigned long *ist_eid_bitmap;
> 	unsigned long *rpt_eid_bitmap;
> 	unsigned long *sgit_eid_bitmap;
> 	unsigned long *isct_eid_bitmap;
> 	unsigned long *sgclt_word_bitmap;
> 	unsigned long *ett_eid_bitmap;
> 	unsigned long *ect_eid_bitmap;
> 	u32 ett_bitmap_size;
> 	u32 ect_bitmap_size;
> 
> 	struct hlist_head flower_list;
> 	struct mutex flower_lock; /* flower_list lock */
> 
> 	u64 (*adjust_base_time)(struct ntmp_priv *priv, u64 bt, u32 ct);
> 	u32 (*get_tgst_free_words)(struct ntmp_priv *priv);
> };

Thank you for posting the downstream layout of struct ntmp_priv which I
was already aware of. What I was saying is that the word "private" means
an aspect of the implementation which is hidden from other code layers.
There's nothing "private" here if the NTMP layer has access to the
definition of this structure. I was asking whether you agree that it's
more adequate to name this structure "ntmp_client", since it represents
the data associated with a consumer of the NTMP API - a NETC SI or (in
the future) the switch. Or some other name. But the word "private" seems
misused.

> > What's the idea with the null entry ID? Why special-case it?
> > 
> 
> Some functions are configured by multiple tables. If a table is
> not needed in the current configuration, we may set its entry
> id to NTMP_NULL_ENTRY_ID, indicating that the table is bypassed.
> For the current patch, this condition can be removed.

Ok, thank you.

> > > +	return &cbdrs->ring[smp_processor_id() % cbdrs->cbdr_num];
> > 
> > I think you need to be in a "preemption disabled" / "migration disable"
> > calling context for smp_processor_id() to be reliable. Otherwise, the
> > task can migrate to another CPU as soon as this function returns.
> > 
> 
> It does not matter, we just want to select a command BD ring when all
> command BD rings are busy. So smp_processor_id() is just a parameter,
> we can also use a random number.

Ok.

> > Can you place this dma_wmb() right next to the "*cur_cbd = *cbd" line,
> > to make it obvious that updating the producer index has nothing to do
> > with it? Or is there another reason for this ordering?
> > 
> 
> No special reason for this ordering, I will move it after "*cur_cbd = *cbd".

Thanks, I appreciate it.

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* RE: [PATCH v4 net-next 01/14] net: enetc: add initial netc-lib driver to support NTMP
  2025-03-14 12:37       ` Vladimir Oltean
@ 2025-03-14 13:48         ` Wei Fang
  2025-03-17  9:28           ` Vladimir Oltean
  0 siblings, 1 reply; 58+ messages in thread
From: Wei Fang @ 2025-03-14 13:48 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Claudiu Manoil, Clark Wang, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, christophe.leroy@csgroup.eu,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org



Best Regards,
Wei Fang

> -----Original Message-----
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> On Fri, Mar 14, 2025 at 05:38:18AM +0200, Wei Fang wrote:
> > > > +	__le16 update_act;
> > > > +	u8 dbg_opt;
> > > > +	u8 tblv_qact;
> > > > +#define NTMP_QUERY_ACT		GENMASK(3, 0)
> > > > +#define NTMP_TBL_VER		GENMASK(7, 0)
> > > > +#define NTMP_TBLV_QACT(v, a)	(FIELD_PREP(NTMP_TBL_VER, (v)) | \
> > > > +				 ((a) & NTMP_QUERY_ACT))
> > >
> > > Can you please move #define macros out of structure definitions?
> >
> > No, I think these macros in the structure can better reflect the specific
> > meaning of these members. We can intuitively see what the bits of
> > these members represent, rather than finding the definition of these
> > bits in RM or elsewhere.
> 
> I mean, I was just suggesting to group the macros with the macros, and
> the struct fields with the struct fields. Mixing them together looks a
> bit messy to me. Even worse in the definition of "union netc_cbd" which
> IMO needs to be reconsidered a bit (a hint given below).

I think this is a matter of personal preference. I was inspired by some
of Intel's structure definitions. I think this method allows me to quickly
understand what fields the member consists of and what bits each field
occupies.

> 
> But you mention "intuitive" definitions without having to go to the RM.
> If I look just at the definitions, I see that NTMP_QUERY_ACT and
> NTMP_TBL_VER
> overlap, and that NTMP_TBLV_QACT() just ORs them together. How does that
> work?
> Shouldn't NTMP_TBL_VER() have been GENMASK(7, 4)? If I do open the RM

I must admit that it is my fault, so yes, NTMP_TBL_VER should be GENMASK(7, 4).
I will fix it, thanks for pointing this.

> and go to the "Generic NTMP Request Data Buffer Format" section, that
> table does seem to agree with me.
> 
> The "normal" way to give more meaning to struct fields is to define them
> as enum values. That doesn't work with "packed" field definitions as you
> have here, which I agree is a challenge. But it is one of the reasons
> why I tried to develop an API together with Jacob Keller which tries to
> address this, by allowing you to define the structures in an "unpacked"
> format, and have a separate data structure which informs the CPU how
> that structure maps over the buffer layout.
> 
> Below is an example to illustrate this for the case of NTMP request buffers.
> Note that the example is incomplete and doesn't even compile, because I
> haven't even converted all ntmp_fill_crd_eid() callers - I don't want to
> waste too much time doing that in case you disagree, but it's still
> enough to show what I'm talking about. Disclaimer: I didn't even _try_
> to compile it - it may contain bugs.
> 
> -- >8 --
> diff --git a/drivers/net/ethernet/freescale/enetc/Kconfig
> b/drivers/net/ethernet/freescale/enetc/Kconfig
> index c8efbb6f2055..35d5cf21f6f4 100644
> --- a/drivers/net/ethernet/freescale/enetc/Kconfig
> +++ b/drivers/net/ethernet/freescale/enetc/Kconfig
> @@ -17,6 +17,7 @@ config NXP_ENETC_PF_COMMON
> 
>  config NXP_NETC_LIB
>  	tristate
> +	select PACKING
>  	help
>  	  This module provides common functionalities for both ENETC and NETC
>  	  Switch, such as NETC Table Management Protocol (NTMP) 2.0,
> common tc
> diff --git a/drivers/net/ethernet/freescale/enetc/ntmp.c
> b/drivers/net/ethernet/freescale/enetc/ntmp.c
> index df10f2f310c1..f96cfca92a1c 100644
> --- a/drivers/net/ethernet/freescale/enetc/ntmp.c
> +++ b/drivers/net/ethernet/freescale/enetc/ntmp.c
> @@ -180,7 +180,7 @@ static int netc_xmit_ntmp_cmd(struct netc_cbdrs
> *cbdrs, union netc_cbd *cbd)
>  	return err;
>  }
> 
> -static int ntmp_alloc_data_mem(struct ntmp_dma_buf *data, void
> **buf_align)
> +static int ntmp_alloc_data_mem(struct ntmp_dma_buf *data,
> ntmp_common_req_msg_data_buf *buf_align)
>  {
>  	void *buf;
> 
> @@ -221,18 +221,24 @@ static void ntmp_fill_request_headr(union netc_cbd
> *cbd, dma_addr_t dma,
>  	cbd->req_hdr.npf = cpu_to_le32(NTMP_NPF);
>  }
> 
> -static void ntmp_fill_crd(struct common_req_data *crd,
> -			  u8 tblv, u8 qa, u16 ua)
> +static const struct packed_field_u8 ntmp_common_req_fields[] = {
> +	PACKED_FIELD(31, 28, struct ntmp_common_req_data, table_version),
> +	PACKED_FIELD(27, 24, struct ntmp_common_req_data, query_actions),
> +	PACKED_FIELD(15, 0, struct ntmp_common_req_data, update_actions),
> +};
> +
> +static void ntmp_fill_crd(ntmp_common_req_msg_data_buf *buf,
> +			  const struct common_req_data *crd)
>  {
> -	crd->update_act = cpu_to_le16(ua);
> -	crd->tblv_qact = NTMP_TBLV_QACT(tblv, qa);
> +	pack_fields(buf, sizeof(*buf), crd, ntmp_common_req_fields,
> +		    QUIRK_LITTLE_ENDIAN);
>  }
> 
> -static void ntmp_fill_crd_eid(struct ntmp_req_by_eid *rbe, u8 tblv,
> -			      u8 qa, u16 ua, u32 entry_id)
> +static void ntmp_fill_crd_eid(struct ntmp_common_req_msg_data_buf *buf,
> +			      const struct ntmp_req_by_eid *rbe)
>  {
> -	ntmp_fill_crd(&rbe->crd, tblv, qa, ua);
> -	rbe->entry_id = cpu_to_le32(entry_id);
> +	ntmp_fill_crd(buf, &rbe->crd);
> +	pack(buf + 1, rbe->entry_id, 31, 0);
>  }
> 
>  static int ntmp_delete_entry_by_id(struct netc_cbdrs *cbdrs, int tbl_id,
> @@ -240,7 +246,13 @@ static int ntmp_delete_entry_by_id(struct
> netc_cbdrs *cbdrs, int tbl_id,
>  				   u32 resp_len)
>  {
>  	struct ntmp_dma_buf data = {.dev = cbdrs->dma_dev};
> -	struct ntmp_req_by_eid *req;
> +	struct ntmp_req_by_eid req = {
> +		.crd = {
> +			.table_version = tbl_ver,
> +		},
> +		.entry_id = entry_id,
> +	};
> +	ntmp_common_req_msg_data_buf buf;
>  	union netc_cbd cbd;
>  	u32 len;
>  	int err;
> @@ -255,7 +267,7 @@ static int ntmp_delete_entry_by_id(struct netc_cbdrs
> *cbdrs, int tbl_id,
>  		req_len = sizeof(*req);
> 
>  	data.size = req_len >= resp_len ? req_len : resp_len;
> -	err = ntmp_alloc_data_mem(&data, (void **)&req);
> +	err = ntmp_alloc_data_mem(&data, &buf);
>  	if (err)
>  		return err;
> 
> diff --git a/drivers/net/ethernet/freescale/enetc/ntmp_private.h
> b/drivers/net/ethernet/freescale/enetc/ntmp_private.h
> index 45e4d083ab0a..e68b2a060176 100644
> --- a/drivers/net/ethernet/freescale/enetc/ntmp_private.h
> +++ b/drivers/net/ethernet/freescale/enetc/ntmp_private.h
> @@ -16,14 +16,14 @@ struct ntmp_dma_buf {
>  	dma_addr_t dma;
>  };
> 
> -struct common_req_data {
> -	__le16 update_act;
> -	u8 dbg_opt;
> -	u8 tblv_qact;
> -#define NTMP_QUERY_ACT		GENMASK(3, 0)
> -#define NTMP_TBL_VER		GENMASK(7, 0)
> -#define NTMP_TBLV_QACT(v, a)	(FIELD_PREP(NTMP_TBL_VER, (v)) | \
> -				 ((a) & NTMP_QUERY_ACT))
> +#define NTMP_COMMON_REQ_MSG_DATA_BUFSZ	4
> +
> +typedef struct __packed { u8
> buf[NTMP_COMMON_REQ_MSG_DATA_BUFSZ]; }
> ntmp_common_req_msg_data_buf;
> +
> +struct ntmp_common_req_data {
> +	u16 update_actions;
> +	u8 query_actions;
> +	u8 table_version;
>  };
> 
>  struct common_resp_query {
> @@ -36,8 +36,8 @@ struct common_resp_nq {
> 
>  /* Generic structure for request data by entry ID  */
>  struct ntmp_req_by_eid {
> -	struct common_req_data crd;
> -	__le32 entry_id;
> +	struct ntmp_common_req_data crd;
> +	u32 entry_id;
>  };
> 
>  /* MAC Address Filter Table Request Data Buffer Format of Add action */
> -- >8 --
> 
> Some remarks:
>  - The fact that struct ntmp_common_req_data is an unpacked structure
>    now means that the layout of fields is completely decoupled from the
>    layout of the data buffer. You can make each field an enum type if
>    you want, which I didn't do here.
>  - You don't have to access its fields with le32_to_cpu() and friends,
>    it's implicitly in CPU endianness.
>  - The API is tolerant of the case where the CPU is in a different
>    endianness from ENETC.
>  - The API protects you against overlapping PACKED_FIELD() definitions,
>    and gives a compile-time error if it detects an overlap.
>  - The API allows you to define buffers of any size you want, and the
>    bit field ranges vary according to the buffer size you chose. Notice
>    how you are grouping two fields within the "u8 tblv_qact" field, and
>    their offsets are 7-4 and 3-0, respectively, within that u8, but in
>    the PACKED_FIELD() definition you can make them 31-28 and 27-24, just
>    like in the RM.
>  - struct ntmp_req_by_eid and struct ntmp_common_req_data don't have to
>    be distinct structures. You can call pack_fields() and pack only a
>    subset of the fields of an unpacked structure. Then pack the rest
>    with explicit pack() calls, or not pack them at all.
> 
> I just want to present this alternative because I believe it offers some
> distinct advantages which may be useful here. But note that just
> "QUIRK_LITTLE_ENDIAN" may be wrong for NTMP. You need to see whether
> you
> also need QUIRK_LSW32_IS_FIRST or not. For buffers up to 32 bits,
> QUIRK_LSW32_IS_FIRST makes no difference, only for buffers larger than that.
> 

Thanks, but we have added fully NTMP support in downstream, it's a great
challenge for me to convert it to the 'packing' method. I don't think I have
too much time to do this conversion. And I also need some time to figure
out how to use it and whether it is worth doing so.

> > > The question pertains to everything else that is exported to
> > > include/linux/fsl/ntmp.h - what the API consumer sees. Is there a real
> > > reason to export it? For many structures and macros, the answer seems no.
> > >
> > > Even for cases like struct maft_keye_data which are only used by debugfs,
> > > it still seems preferable to keep data encapsulation and offer a helper
> > > function to retrieve a pointer to the MAC address from the MAFT entry.
> > > Then, "struct maft_keye_data;" can simply be declared, without exposing
> > > its full definition.
> >
> > ntmp_private.h is only used for ntmp driver, I don't want it to be included
> > by any enetc files. ntmp.h is used for both enetc and switch drivers, so we
> > need to add full definitions of the table data.
> 
> And I agree with you, I also don't want ntmp_private.h to be exposed to
> the NTMP API consumers, and I wasn't suggesting that. I just want the
> NTMP API to spare consumer drivers of the gory details, like for example
> the buffer layout of a MAC filtering entry, reserved fields, things like
> that. What I was saying is to keep the buffer layout private to
> ntmp_private.h, and expose a more abstract data structure to API
> consumers.
> 

Sorry, I don't fully understand, for example, if we place the definition
of "struct maft_keye_data" in ntmp_private.h, how does the debugfs
get the information from "struct maft_keye_data"? Add a helper function
in the NTMP driver and export it to enetc driver? And how does
enetc4_pf_add_si_mac_exact_filter() to set the mac address to "struct
maft_keye_data", add another helper? If so, I think it is more complicated.

> > > > +struct ntmp_priv {
> > >
> > > Would it be better to name this "struct ntmp_client"? I don't really
> > > understand the way in which it is "private".
> >
> > It refers to some private data of NTMP of different devices (enetc or
> > switches). Since the current patch is only a small part of NTMP, many
> > members have not been added to the structure. The following is the
> > definition in our downstream.
> >
> > struct ntmp_priv {
> > 	enum netc_dev_type dev_type;
> > 	struct netc_cbdrs cbdrs;
> > 	u32 errata;
> >
> > 	struct ntmp_caps caps;
> > 	/* bitmap of table entry ID */
> > 	unsigned long *ist_eid_bitmap;
> > 	unsigned long *rpt_eid_bitmap;
> > 	unsigned long *sgit_eid_bitmap;
> > 	unsigned long *isct_eid_bitmap;
> > 	unsigned long *sgclt_word_bitmap;
> > 	unsigned long *ett_eid_bitmap;
> > 	unsigned long *ect_eid_bitmap;
> > 	u32 ett_bitmap_size;
> > 	u32 ect_bitmap_size;
> >
> > 	struct hlist_head flower_list;
> > 	struct mutex flower_lock; /* flower_list lock */
> >
> > 	u64 (*adjust_base_time)(struct ntmp_priv *priv, u64 bt, u32 ct);
> > 	u32 (*get_tgst_free_words)(struct ntmp_priv *priv);
> > };
> 
> Thank you for posting the downstream layout of struct ntmp_priv which I
> was already aware of. What I was saying is that the word "private" means
> an aspect of the implementation which is hidden from other code layers.
> There's nothing "private" here if the NTMP layer has access to the
> definition of this structure. I was asking whether you agree that it's
> more adequate to name this structure "ntmp_client", since it represents
> the data associated with a consumer of the NTMP API - a NETC SI or (in
> the future) the switch. Or some other name. But the word "private" seems
> misused.
> 

Okay, it seems to make you feel confused, let me rename it later, how about
"ntmp_user"?

> > > What's the idea with the null entry ID? Why special-case it?
> > >
> >
> > Some functions are configured by multiple tables. If a table is
> > not needed in the current configuration, we may set its entry
> > id to NTMP_NULL_ENTRY_ID, indicating that the table is bypassed.
> > For the current patch, this condition can be removed.
> 
> Ok, thank you.
> 
> > > > +	return &cbdrs->ring[smp_processor_id() % cbdrs->cbdr_num];
> > >
> > > I think you need to be in a "preemption disabled" / "migration disable"
> > > calling context for smp_processor_id() to be reliable. Otherwise, the
> > > task can migrate to another CPU as soon as this function returns.
> > >
> >
> > It does not matter, we just want to select a command BD ring when all
> > command BD rings are busy. So smp_processor_id() is just a parameter,
> > we can also use a random number.
> 
> Ok.
> 
> > > Can you place this dma_wmb() right next to the "*cur_cbd = *cbd" line,
> > > to make it obvious that updating the producer index has nothing to do
> > > with it? Or is there another reason for this ordering?
> > >
> >
> > No special reason for this ordering, I will move it after "*cur_cbd = *cbd".
> 
> Thanks, I appreciate it.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v4 net-next 02/14] net: enetc: add command BD ring support for i.MX95 ENETC
  2025-03-14 11:18       ` Vladimir Oltean
@ 2025-03-14 13:56         ` Wei Fang
  0 siblings, 0 replies; 58+ messages in thread
From: Wei Fang @ 2025-03-14 13:56 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Claudiu Manoil, Clark Wang, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, christophe.leroy@csgroup.eu,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org

> On Fri, Mar 14, 2025 at 06:51:06AM +0200, Wei Fang wrote:
> > > I don't understand the need for si->ops->setup_cbdr() and
> > > si->ops->teardown_cbdr()?
> > > Doesn't every call site know which kind of SI it is dealing with, and thus it
> can
> > > appropriately call the direct symbol?
> > > - the v1 PSI and the VSI call enetc_setup_cbdr() and enetc_teardown_cbdr()
> > > - the v4 PSI calls enetc4_setup_cbdr() and enetc4_teardown_cbdr()
> >
> > Yes, for PSI we can use directly call these functions because they are different
> > drivers, but for VSI, v1 and v4 will use the same driver. I just want the PSI and
> > VSI to be consistent. If you don't like this, I can remove these interfaces from
> > the patch set, and add vf_setup_cbdr and vf_teardown_cbdr in the future
> when
> > I add the VF support for ENETC v4.
> 
> It's not that I don't like them, the point is rather simple: as far as
> this patch set is concerned, converting direct function calls to
> indirect ones is an unfinished idea. It needs to be evaluated in full
> context, which is not present here - as you say, v4 VSIs need to be
> further modified to call a different set of operations - but right now,
> they call a single set of CBDR functions. Changes which require
> subsequent patch sets in order to make any sense at all are discouraged.
> 
> Given the fact that the PSI code paths still don't benefit from an
> indirect function call in any way, I would in principle recommend to
> keep calling their CBDR methods directly. For VSIs I don't know which is
> preferable (if-else vs function pointer), I need to see that code first.

Okay, let's keep directly calls in v1 and v4 PSI drivers. Regarding to the
VSI, some people don't like if-else because they think we may have v5,
v6, v7 in the future which may use different version of command BD ring,
so they prefer function pointer. But for trivial, like different register offsets
for different ENETC versions. I think if-else is enough.


^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v4 net-next 01/14] net: enetc: add initial netc-lib driver to support NTMP
  2025-03-14 13:48         ` Wei Fang
@ 2025-03-17  9:28           ` Vladimir Oltean
  2025-03-17  9:55             ` Wei Fang
  0 siblings, 1 reply; 58+ messages in thread
From: Vladimir Oltean @ 2025-03-17  9:28 UTC (permalink / raw)
  To: Wei Fang
  Cc: Claudiu Manoil, Clark Wang, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, christophe.leroy@csgroup.eu,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org

Hi Wei,

On Fri, Mar 14, 2025 at 03:48:21PM +0200, Wei Fang wrote:
> > I mean, I was just suggesting to group the macros with the macros, and
> > the struct fields with the struct fields. Mixing them together looks a
> > bit messy to me. Even worse in the definition of "union netc_cbd" which
> > IMO needs to be reconsidered a bit (a hint given below).
> 
> I think this is a matter of personal preference. I was inspired by some
> of Intel's structure definitions. I think this method allows me to quickly
> understand what fields the member consists of and what bits each field
> occupies.
(...)
> Thanks, but we have added fully NTMP support in downstream, it's a great
> challenge for me to convert it to the 'packing' method. I don't think I have
> too much time to do this conversion. And I also need some time to figure
> out how to use it and whether it is worth doing so.

Ok, I'm not forcing you to use pack_fields(), but given the fact that
bit field overlap is now something that has to be manually checked, and
a bug of this kind already exists in this set, you will have to wait for
me, or other reviewers, to go through the bit field definitions from the
entire set.

> > And I agree with you, I also don't want ntmp_private.h to be exposed to
> > the NTMP API consumers, and I wasn't suggesting that. I just want the
> > NTMP API to spare consumer drivers of the gory details, like for example
> > the buffer layout of a MAC filtering entry, reserved fields, things like
> > that. What I was saying is to keep the buffer layout private to
> > ntmp_private.h, and expose a more abstract data structure to API
> > consumers.
> 
> Sorry, I don't fully understand, for example, if we place the definition
> of "struct maft_keye_data" in ntmp_private.h, how does the debugfs
> get the information from "struct maft_keye_data"? Add a helper function
> in the NTMP driver and export it to enetc driver? And how does
> enetc4_pf_add_si_mac_exact_filter() to set the mac address to "struct
> maft_keye_data", add another helper? If so, I think it is more complicated.

Well, my complaint, which has to do with style and personal preference,
is that exposing packed data structures to NTMP API clients puts an
unnecessary burden on them. For example, NTMP users have to call cpu_to_le16()
to populate data.cfge.si_bitmap. A bug in the packed layout will
potentially have to be fixed in multiple places. The two options for a
more high-level NTMP API that I see are:
- You expose pointers to the packed data structures, but API functions
  provide getters and setters, and the exact buffer layout is only known
  to the NTMP layer.
- The API functions expose "unpacked" data structures, which are more
  abstract and don't contain reserved fields and are in CPU native
  endianness, and the NTMP layer packs them to buffers, either using
  pack_fields() or manually.

Claudiu, what do you think? I can withdraw the request to hide packed
MAFT (and other) struct definitions from include/linux/fsl/ntmp.h if you
think they're fine there.

> > Thank you for posting the downstream layout of struct ntmp_priv which I
> > was already aware of. What I was saying is that the word "private" means
> > an aspect of the implementation which is hidden from other code layers.
> > There's nothing "private" here if the NTMP layer has access to the
> > definition of this structure. I was asking whether you agree that it's
> > more adequate to name this structure "ntmp_client", since it represents
> > the data associated with a consumer of the NTMP API - a NETC SI or (in
> > the future) the switch. Or some other name. But the word "private" seems
> > misused.
> 
> Okay, it seems to make you feel confused, let me rename it later, how about
> "ntmp_user"?

"ntmp_user" works for me better than "ntmp_priv", thanks. Are you also
going to make the API functions from include/linux/fsl/ntmp.h take
"struct ntmp_user *" as first argument, rather than "struct netc_cbdrs *"?

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v4 net-next 03/14] net: enetc: move generic MAC filterng interfaces to enetc-core
  2025-03-11  5:38 ` [PATCH v4 net-next 03/14] net: enetc: move generic MAC filterng interfaces to enetc-core Wei Fang
@ 2025-03-17  9:42   ` Vladimir Oltean
  2025-03-17 10:00     ` Wei Fang
  0 siblings, 1 reply; 58+ messages in thread
From: Vladimir Oltean @ 2025-03-17  9:42 UTC (permalink / raw)
  To: Wei Fang
  Cc: claudiu.manoil, xiaoning.wang, andrew+netdev, davem, edumazet,
	kuba, pabeni, christophe.leroy, netdev, linux-kernel, imx,
	linuxppc-dev, linux-arm-kernel

title: s/filterng/filtering/

On Tue, Mar 11, 2025 at 01:38:19PM +0800, Wei Fang wrote:
> Although only ENETC PF can access the MAC address filter table, the table
> entries can specify MAC address filtering for one or more SIs based on
> SI_BITMAP, which means that the table also supports MAC address filtering
> for VFs.
> 
> Currently, only the ENETC v1 PF driver supports MAC address filtering. In
> order to add the MAC address filtering support for the ENETC v4 PF driver
> and VF driver in the future, the relevant generic interfaces are moved to
> the enetc-core driver. At the same time, the struct enetc_mac_filter is
> moved from enetc_pf to enetc_si, because enetc_si is a structure shared by
> PF and VFs. This lays the basis for i.MX95 ENETC PF and VFs to support
> MAC address filtering.
> 
> Signed-off-by: Wei Fang <wei.fang@nxp.com>
> ---

For this series I don't see any VF implementation of ndo_set_rx_mode().
I don't think you have to move struct enetc_mac_filter from struct enetc_pf
to struct enetc_si, so please don't do that until there is a justification
for it that is contained in the same patch set, and the two can be
evaluated together.

Moving enetc_add_mac_addr_ht_filter() and enetc_reset_mac_addr_filter()
to enetc.c seems fine.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v4 net-next 01/14] net: enetc: add initial netc-lib driver to support NTMP
  2025-03-17  9:28           ` Vladimir Oltean
@ 2025-03-17  9:55             ` Wei Fang
  2025-03-17 10:00               ` Vladimir Oltean
  0 siblings, 1 reply; 58+ messages in thread
From: Wei Fang @ 2025-03-17  9:55 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Claudiu Manoil, Clark Wang, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, christophe.leroy@csgroup.eu,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org

> On Fri, Mar 14, 2025 at 03:48:21PM +0200, Wei Fang wrote:
> > > I mean, I was just suggesting to group the macros with the macros, and
> > > the struct fields with the struct fields. Mixing them together looks a
> > > bit messy to me. Even worse in the definition of "union netc_cbd" which
> > > IMO needs to be reconsidered a bit (a hint given below).
> >
> > I think this is a matter of personal preference. I was inspired by some
> > of Intel's structure definitions. I think this method allows me to quickly
> > understand what fields the member consists of and what bits each field
> > occupies.
> (...)
> > Thanks, but we have added fully NTMP support in downstream, it's a great
> > challenge for me to convert it to the 'packing' method. I don't think I have
> > too much time to do this conversion. And I also need some time to figure
> > out how to use it and whether it is worth doing so.
> 
> Ok, I'm not forcing you to use pack_fields(), but given the fact that
> bit field overlap is now something that has to be manually checked, and
> a bug of this kind already exists in this set, you will have to wait for
> me, or other reviewers, to go through the bit field definitions from the
> entire set.
> 
> > > And I agree with you, I also don't want ntmp_private.h to be exposed to
> > > the NTMP API consumers, and I wasn't suggesting that. I just want the
> > > NTMP API to spare consumer drivers of the gory details, like for example
> > > the buffer layout of a MAC filtering entry, reserved fields, things like
> > > that. What I was saying is to keep the buffer layout private to
> > > ntmp_private.h, and expose a more abstract data structure to API
> > > consumers.
> >
> > Sorry, I don't fully understand, for example, if we place the definition
> > of "struct maft_keye_data" in ntmp_private.h, how does the debugfs
> > get the information from "struct maft_keye_data"? Add a helper function
> > in the NTMP driver and export it to enetc driver? And how does
> > enetc4_pf_add_si_mac_exact_filter() to set the mac address to "struct
> > maft_keye_data", add another helper? If so, I think it is more complicated.
> 
> Well, my complaint, which has to do with style and personal preference,
> is that exposing packed data structures to NTMP API clients puts an
> unnecessary burden on them. For example, NTMP users have to call
> cpu_to_le16()
> to populate data.cfge.si_bitmap. A bug in the packed layout will
> potentially have to be fixed in multiple places. The two options for a
> more high-level NTMP API that I see are:
> - You expose pointers to the packed data structures, but API functions
>   provide getters and setters, and the exact buffer layout is only known
>   to the NTMP layer.
> - The API functions expose "unpacked" data structures, which are more
>   abstract and don't contain reserved fields and are in CPU native
>   endianness, and the NTMP layer packs them to buffers, either using
>   pack_fields() or manually.
> 

Actually I did this is the original version, I mean in downstream kernel 6.6
tree. I add a "ntmp_mfe" in ntmp.h like below

struct ntmp_mfe {
	u8 mac[ETH_ALEN];
	u16 si_bitmap;
};

And the conversion was done by the NTMP driver. But then I found that this was
very troublesome. We get data from kernel "struct A,B,C", then the enetc driver
converts them to "struct D", and finally the ntmp driver converts it to "struct E".
So I thought why don't we convert "struct A,B,C" to "struct E" from the beginning?
After all, these data structures are only used by enetc and netc switch drivers, so
in kernel 6.12, I changed it to the current way.

> Claudiu, what do you think? I can withdraw the request to hide packed
> MAFT (and other) struct definitions from include/linux/fsl/ntmp.h if you
> think they're fine there.
> 
> > > Thank you for posting the downstream layout of struct ntmp_priv which I
> > > was already aware of. What I was saying is that the word "private" means
> > > an aspect of the implementation which is hidden from other code layers.
> > > There's nothing "private" here if the NTMP layer has access to the
> > > definition of this structure. I was asking whether you agree that it's
> > > more adequate to name this structure "ntmp_client", since it represents
> > > the data associated with a consumer of the NTMP API - a NETC SI or (in
> > > the future) the switch. Or some other name. But the word "private" seems
> > > misused.
> >
> > Okay, it seems to make you feel confused, let me rename it later, how about
> > "ntmp_user"?
> 
> "ntmp_user" works for me better than "ntmp_priv", thanks. Are you also
> going to make the API functions from include/linux/fsl/ntmp.h take
> "struct ntmp_user *" as first argument, rather than "struct netc_cbdrs *"?

I think we do not need to keep "struct netc_cbdrs", it can be integrated into
"struct ntmp_user".


^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v4 net-next 01/14] net: enetc: add initial netc-lib driver to support NTMP
  2025-03-17  9:55             ` Wei Fang
@ 2025-03-17 10:00               ` Vladimir Oltean
  2025-03-17 11:39                 ` Wei Fang
  0 siblings, 1 reply; 58+ messages in thread
From: Vladimir Oltean @ 2025-03-17 10:00 UTC (permalink / raw)
  To: Wei Fang
  Cc: Claudiu Manoil, Clark Wang, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, christophe.leroy@csgroup.eu,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org

On Mon, Mar 17, 2025 at 11:55:26AM +0200, Wei Fang wrote:
> Actually I did this is the original version, I mean in downstream kernel 6.6
> tree. I add a "ntmp_mfe" in ntmp.h like below
> 
> struct ntmp_mfe {
> 	u8 mac[ETH_ALEN];
> 	u16 si_bitmap;
> };
> 
> And the conversion was done by the NTMP driver. But then I found that this was
> very troublesome. We get data from kernel "struct A,B,C", then the enetc driver
> converts them to "struct D", and finally the ntmp driver converts it to "struct E".
> So I thought why don't we convert "struct A,B,C" to "struct E" from the beginning?
> After all, these data structures are only used by enetc and netc switch drivers, so
> in kernel 6.12, I changed it to the current way.

I understand. With pack_fields(), "struct E" (the packed representation
of "struct D") doesn't explicitly exist, just an abstract type
representing the u8 *buffer, and the struct packed_field_u8 array[]
which is hidden inside the NTMP layer.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v4 net-next 03/14] net: enetc: move generic MAC filterng interfaces to enetc-core
  2025-03-17  9:42   ` Vladimir Oltean
@ 2025-03-17 10:00     ` Wei Fang
  0 siblings, 0 replies; 58+ messages in thread
From: Wei Fang @ 2025-03-17 10:00 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Claudiu Manoil, Clark Wang, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, christophe.leroy@csgroup.eu,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org

> title: s/filterng/filtering/
> 
> On Tue, Mar 11, 2025 at 01:38:19PM +0800, Wei Fang wrote:
> > Although only ENETC PF can access the MAC address filter table, the table
> > entries can specify MAC address filtering for one or more SIs based on
> > SI_BITMAP, which means that the table also supports MAC address filtering
> > for VFs.
> >
> > Currently, only the ENETC v1 PF driver supports MAC address filtering. In
> > order to add the MAC address filtering support for the ENETC v4 PF driver
> > and VF driver in the future, the relevant generic interfaces are moved to
> > the enetc-core driver. At the same time, the struct enetc_mac_filter is
> > moved from enetc_pf to enetc_si, because enetc_si is a structure shared by
> > PF and VFs. This lays the basis for i.MX95 ENETC PF and VFs to support
> > MAC address filtering.
> >
> > Signed-off-by: Wei Fang <wei.fang@nxp.com>
> > ---
> 
> For this series I don't see any VF implementation of ndo_set_rx_mode().
> I don't think you have to move struct enetc_mac_filter from struct enetc_pf
> to struct enetc_si, so please don't do that until there is a justification
> for it that is contained in the same patch set, and the two can be
> evaluated together.

Okay, I will keep them in "struct enetc_pf". :)
> 
> Moving enetc_add_mac_addr_ht_filter() and enetc_reset_mac_addr_filter()
> to enetc.c seems fine.


^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v4 net-next 01/14] net: enetc: add initial netc-lib driver to support NTMP
  2025-03-17 10:00               ` Vladimir Oltean
@ 2025-03-17 11:39                 ` Wei Fang
  0 siblings, 0 replies; 58+ messages in thread
From: Wei Fang @ 2025-03-17 11:39 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Claudiu Manoil, Clark Wang, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, christophe.leroy@csgroup.eu,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org

> On Mon, Mar 17, 2025 at 11:55:26AM +0200, Wei Fang wrote:
> > Actually I did this is the original version, I mean in downstream kernel 6.6
> > tree. I add a "ntmp_mfe" in ntmp.h like below
> >
> > struct ntmp_mfe {
> > 	u8 mac[ETH_ALEN];
> > 	u16 si_bitmap;
> > };
> >
> > And the conversion was done by the NTMP driver. But then I found that this
> was
> > very troublesome. We get data from kernel "struct A,B,C", then the enetc
> driver
> > converts them to "struct D", and finally the ntmp driver converts it to "struct
> E".
> > So I thought why don't we convert "struct A,B,C" to "struct E" from the
> beginning?
> > After all, these data structures are only used by enetc and netc switch drivers,
> so
> > in kernel 6.12, I changed it to the current way.
> 
> I understand. With pack_fields(), "struct E" (the packed representation
> of "struct D") doesn't explicitly exist, just an abstract type
> representing the u8 *buffer, and the struct packed_field_u8 array[]
> which is hidden inside the NTMP layer.

Yes, "struct E" will not exist, but we need to pack every member in
"struct D" to convert them to the hardware structure, so there are
still two conversions ("struct A,B,C" -> "struct "D" --> hardware
structure).


^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v4 net-next 04/14] net: enetc: add MAC filter for i.MX95 ENETC PF
  2025-03-11  5:38 ` [PATCH v4 net-next 04/14] net: enetc: add MAC filter for i.MX95 ENETC PF Wei Fang
@ 2025-03-17 14:18   ` Vladimir Oltean
  2025-03-18  3:19     ` Wei Fang
  2025-03-18  8:08     ` Claudiu Manoil
  0 siblings, 2 replies; 58+ messages in thread
From: Vladimir Oltean @ 2025-03-17 14:18 UTC (permalink / raw)
  To: Wei Fang
  Cc: claudiu.manoil, xiaoning.wang, andrew+netdev, davem, edumazet,
	kuba, pabeni, christophe.leroy, netdev, linux-kernel, imx,
	linuxppc-dev, linux-arm-kernel

On Tue, Mar 11, 2025 at 01:38:20PM +0800, Wei Fang wrote:
> The i.MX95 ENETC supports both MAC hash filter and MAC exact filter. MAC
> hash filter is implenented through a 64-bits hash table to match against

s/implenented/implemented/
s/64-bits/64-bit/

> the hashed addresses, PF and VFs each have two MAC hash tables, one is
> for unicast and the other one is for multicast. But MAC exact filter is
> shared between SIs (PF and VFs), each table entry contains a MAC address
> that may be unicast or multicast and the entry also contains an SI bitmap
> field that indicates for which SIs the entry is valid.
> 
> For i.MX95 ENETC, MAC exact filter only has 4 entries. According to the
> observation of the system default network configuration, the MAC filter
> will be configured with multiple multicast addresses, so MAC exact filter
> does not have enough entries to implement multicast filtering. Therefore,
> the current MAC exact filter is only used for unicast filtering. If the
> number of unicast addresses exceeds 4, then MAC hash filter is used.
> 
> Note that both MAC hash filter and MAC exact filter can only be accessed
> by PF, VFs can notify PF to set its corresponding MAC filter through the
> mailbox mechanism of ENETC. But currently MAC filter is only added for
> i.MX95 ENETC PF. The MAC filter support of ENETC VFs will be supported in
> subsequent patches.
> 
> Signed-off-by: Wei Fang <wei.fang@nxp.com>
> ---
>  drivers/net/ethernet/freescale/enetc/enetc.h  |   2 +
>  .../net/ethernet/freescale/enetc/enetc4_hw.h  |   8 +
>  .../net/ethernet/freescale/enetc/enetc4_pf.c  | 422 +++++++++++++++++-
>  .../net/ethernet/freescale/enetc/enetc_hw.h   |   6 +
>  .../net/ethernet/freescale/enetc/enetc_pf.h   |  11 +
>  5 files changed, 448 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
> index 9380d3e8ca01..4dba91408e3d 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc.h
> +++ b/drivers/net/ethernet/freescale/enetc/enetc.h
> @@ -316,6 +316,8 @@ struct enetc_si {
>  	const struct enetc_si_ops *ops;
>  
>  	struct enetc_mac_filter mac_filter[MADDR_TYPE];
> +	struct workqueue_struct *workqueue;
> +	struct work_struct rx_mode_task;
>  };
>  
>  #define ENETC_SI_ALIGN	32
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
> index 695cb07c74bc..826359004850 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
> +++ b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
> @@ -99,6 +99,14 @@
>  #define ENETC4_PSICFGR2(a)		((a) * 0x80 + 0x2018)
>  #define  PSICFGR2_NUM_MSIX		GENMASK(5, 0)
>  
> +/* Port station interface a unicast MAC hash filter register 0/1 */
> +#define ENETC4_PSIUMHFR0(a)		((a) * 0x80 + 0x2050)
> +#define ENETC4_PSIUMHFR1(a)		((a) * 0x80 + 0x2054)
> +
> +/* Port station interface a multicast MAC hash filter register 0/1 */
> +#define ENETC4_PSIMMHFR0(a)		((a) * 0x80 + 0x2058)
> +#define ENETC4_PSIMMHFR1(a)		((a) * 0x80 + 0x205c)
> +
>  #define ENETC4_PMCAPR			0x4004
>  #define  PMCAPR_HD			BIT(8)
>  #define  PMCAPR_FP			GENMASK(10, 9)
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> index 63001379f0a0..7d1c545f3f56 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> @@ -11,6 +11,15 @@
>  
>  #define ENETC_SI_MAX_RING_NUM	8
>  
> +#define ENETC_MAC_FILTER_TYPE_UC	BIT(0)
> +#define ENETC_MAC_FILTER_TYPE_MC	BIT(1)
> +#define ENETC_MAC_FILTER_TYPE_ALL	(ENETC_MAC_FILTER_TYPE_UC | \
> +					 ENETC_MAC_FILTER_TYPE_MC)
> +
> +struct enetc_mac_addr {
> +	u8 addr[ETH_ALEN];
> +};
> +
>  static void enetc4_get_port_caps(struct enetc_pf *pf)
>  {
>  	struct enetc_hw *hw = &pf->si->hw;
> @@ -26,6 +35,9 @@ static void enetc4_get_port_caps(struct enetc_pf *pf)
>  
>  	val = enetc_port_rd(hw, ENETC4_PMCAPR);
>  	pf->caps.half_duplex = (val & PMCAPR_HD) ? 1 : 0;
> +
> +	val = enetc_port_rd(hw, ENETC4_PSIMAFCAPR);
> +	pf->caps.mac_filter_num = val & PSIMAFCAPR_NUM_MAC_AFTE;
>  }
>  
>  static void enetc4_pf_set_si_primary_mac(struct enetc_hw *hw, int si,
> @@ -56,6 +68,341 @@ static void enetc4_pf_get_si_primary_mac(struct enetc_hw *hw, int si,
>  	put_unaligned_le16(lower, addr + 4);
>  }
>  
> +static void enetc4_pf_set_si_mac_promisc(struct enetc_hw *hw, int si,
> +					 int type, bool en)
> +{
> +	u32 val = enetc_port_rd(hw, ENETC4_PSIPMMR);
> +
> +	if (type == UC) {
> +		if (en)
> +			val |= PSIPMMR_SI_MAC_UP(si);
> +		else
> +			val &= ~PSIPMMR_SI_MAC_UP(si);
> +	} else { /* Multicast promiscuous mode. */
> +		if (en)
> +			val |= PSIPMMR_SI_MAC_MP(si);
> +		else
> +			val &= ~PSIPMMR_SI_MAC_MP(si);
> +	}
> +
> +	enetc_port_wr(hw, ENETC4_PSIPMMR, val);
> +}
> +
> +static void enetc4_pf_set_si_mac_hash_filter(struct enetc_hw *hw, int si,
> +					     int type, u64 hash)
> +{
> +	if (type == UC) {
> +		enetc_port_wr(hw, ENETC4_PSIUMHFR0(si), lower_32_bits(hash));
> +		enetc_port_wr(hw, ENETC4_PSIUMHFR1(si), upper_32_bits(hash));
> +	} else { /* MC */
> +		enetc_port_wr(hw, ENETC4_PSIMMHFR0(si), lower_32_bits(hash));
> +		enetc_port_wr(hw, ENETC4_PSIMMHFR1(si), upper_32_bits(hash));
> +	}
> +}

Please split into separate functions for unicast and for multicast.
The implementations don't share any code, and the callers are not in
common code either.

> +
> +static void enetc4_pf_destroy_mac_list(struct enetc_pf *pf)
> +{
> +	struct enetc_mac_list_entry *entry;
> +	struct hlist_node *tmp;
> +
> +	mutex_lock(&pf->mac_list_lock);

The mutex_lock() usage here should raise serious questions. This is
running right before mutex_destroy(). So if there were any concurrent
attempt to acquire this lock, that concurrent code would have been broken
any time it would have lost arbitration, by the fact that it would
attempt to acquire a destroyed mutex.

But there's no such concurrent thread, because we run after destroy_workqueue()
which flushes those concurrent calls and prevents new ones. So the mutex
usage here is not necessary.

[ same thing with mutex_init() immediately followed by mutex_lock().
  It is an incorrect pattern most of the time. ]

> +
> +	hlist_for_each_entry_safe(entry, tmp, &pf->mac_list, node) {
> +		hlist_del(&entry->node);
> +		kfree(entry);
> +	}
> +
> +	pf->num_mfe = 0;
> +
> +	mutex_unlock(&pf->mac_list_lock);
> +}
> +
> +static bool enetc_mac_filter_type_check(int type, const u8 *addr)
> +{
> +	if (type == ENETC_MAC_FILTER_TYPE_UC)
> +		return !is_multicast_ether_addr(addr);
> +	else if (type == ENETC_MAC_FILTER_TYPE_MC)
> +		return is_multicast_ether_addr(addr);
> +	else
> +		return true;
> +}
> +
> +static struct enetc_mac_list_entry *
> +enetc_mac_list_lookup_entry(struct enetc_pf *pf, const unsigned char *addr)
> +{
> +	struct enetc_mac_list_entry *entry;
> +
> +	hlist_for_each_entry(entry, &pf->mac_list, node)
> +		if (ether_addr_equal(entry->mac, addr))
> +			return entry;
> +
> +	return NULL;
> +}
> +
> +static void enetc_mac_list_add_entry(struct enetc_pf *pf,
> +				     struct enetc_mac_list_entry *entry)
> +{
> +	hlist_add_head(&entry->node, &pf->mac_list);
> +}
> +
> +static void enetc_mac_list_del_entry(struct enetc_mac_list_entry *entry)
> +{
> +	hlist_del(&entry->node);
> +	kfree(entry);
> +}
> +
> +static void enetc_mac_list_del_matched_entries(struct enetc_pf *pf, u16 si_bit,
> +					       struct enetc_mac_addr *mac,
> +					       int mac_cnt)
> +{
> +	struct enetc_mac_list_entry *entry;
> +	int i;
> +
> +	for (i = 0; i < mac_cnt; i++) {
> +		entry = enetc_mac_list_lookup_entry(pf, mac[i].addr);
> +		if (!entry)
> +			continue;
> +
> +		entry->si_bitmap &= ~si_bit;
> +		if (entry->si_bitmap)
> +			continue;
> +
> +		enetc_mac_list_del_entry(entry);
> +		pf->num_mfe--;
> +	}
> +}
> +
> +static bool enetc_mac_list_is_available(struct enetc_pf *pf,
> +					struct enetc_mac_addr *mac,
> +					int mac_cnt)
> +{
> +	int max_num_mfe = pf->caps.mac_filter_num;
> +	struct enetc_mac_list_entry *entry;
> +	int cur_num_mfe = pf->num_mfe;
> +	int i, new_mac_cnt = 0;
> +
> +	if (mac_cnt > max_num_mfe)
> +		return false;
> +
> +	/* Check MAC filter table whether has enough available entries */
> +	hlist_for_each_entry(entry, &pf->mac_list, node) {
> +		for (i = 0; i < mac_cnt; i++) {
> +			if (ether_addr_equal(entry->mac, mac[i].addr))
> +				break;
> +		}
> +
> +		if (i == mac_cnt)
> +			new_mac_cnt++;
> +
> +		if ((cur_num_mfe + new_mac_cnt) > max_num_mfe)
> +			return false;
> +	}
> +
> +	return true;
> +}
> +
> +static int enetc4_pf_add_si_mac_exact_filter(struct enetc_pf *pf, int si_id,
> +					     struct enetc_mac_addr *mac,
> +					     int mac_cnt)
> +{
> +	struct enetc_mac_list_entry *entry;
> +	struct maft_entry_data data = {0};

As I've also learned, what you actually want is an empty struct initializer "= {}" here:
https://lore.kernel.org/netdev/20210810091238.GB1343@shell.armlinux.org.uk/

> +	struct enetc_si *si = pf->si;
> +	u16 si_bit = BIT(si_id);
> +	int i, num_mfe, err = 0;
> +
> +	mutex_lock(&pf->mac_list_lock);
> +
> +	if (!enetc_mac_list_is_available(pf, mac, mac_cnt)) {
> +		err = -ENOSPC;
> +		goto mac_list_unlock;
> +	}
> +
> +	num_mfe = pf->num_mfe;
> +	/* Update mac_list */
> +	for (i = 0; i < mac_cnt; i++) {
> +		entry = enetc_mac_list_lookup_entry(pf, mac[i].addr);
> +		if (entry) {
> +			entry->si_bitmap |= si_bit;
> +			continue;
> +		}
> +
> +		entry = kzalloc(sizeof(*entry), GFP_KERNEL);
> +		if (unlikely(!entry)) {
> +			/* Restore MAC list to the state before the update
> +			 * if an error occurs.
> +			 */
> +			enetc_mac_list_del_matched_entries(pf, si_bit,
> +							   mac, i + 1);
> +			err = -ENOMEM;
> +			goto mac_list_unlock;
> +		}
> +
> +		ether_addr_copy(entry->mac, mac[i].addr);
> +		entry->si_bitmap = si_bit;
> +		enetc_mac_list_add_entry(pf, entry);
> +		pf->num_mfe++;
> +	}
> +
> +	/* Clear MAC filter table */
> +	for (i = 0; i < num_mfe; i++)
> +		ntmp_maft_delete_entry(&si->ntmp.cbdrs, i);
> +
> +	i = 0;
> +	hlist_for_each_entry(entry, &pf->mac_list, node) {
> +		data.cfge.si_bitmap = cpu_to_le16(entry->si_bitmap);
> +		ether_addr_copy(data.keye.mac_addr, entry->mac);
> +		ntmp_maft_add_entry(&si->ntmp.cbdrs, i++, &data);

Don't discard error code.

> +	}
> +
> +mac_list_unlock:
> +	mutex_unlock(&pf->mac_list_lock);
> +
> +	return err;
> +}
> +
> +static void enetc4_pf_flush_si_mac_exact_filter(struct enetc_pf *pf, int si_id,
> +						int mac_type)
> +{
> +	struct enetc_mac_list_entry *entry;
> +	struct maft_entry_data data = {0};

s/{0}/{}/

> +	struct enetc_si *si = pf->si;
> +	u16 si_bit = BIT(si_id);
> +	struct hlist_node *tmp;
> +	int i, num_mfe;
> +
> +	mutex_lock(&pf->mac_list_lock);
> +
> +	num_mfe = pf->num_mfe;
> +	hlist_for_each_entry_safe(entry, tmp, &pf->mac_list, node) {
> +		if (enetc_mac_filter_type_check(mac_type, entry->mac) &&
> +		    entry->si_bitmap & si_bit) {
> +			entry->si_bitmap ^= si_bit;
> +			if (entry->si_bitmap)
> +				continue;
> +
> +			enetc_mac_list_del_entry(entry);
> +			pf->num_mfe--;
> +		}
> +	}
> +
> +	for (i = 0; i < num_mfe; i++)
> +		ntmp_maft_delete_entry(&si->ntmp.cbdrs, i);
> +
> +	i = 0;
> +	hlist_for_each_entry(entry, &pf->mac_list, node) {
> +		data.cfge.si_bitmap = cpu_to_le16(entry->si_bitmap);
> +		ether_addr_copy(data.keye.mac_addr, entry->mac);
> +		ntmp_maft_add_entry(&si->ntmp.cbdrs, i++, &data);

Don't discard error code.

Also, can't you edit MAFT entries in-place over NTMP? Deleting and
re-adding filters creates small time windows where you might have
RX packet loss, which is not ideal.

> +	}
> +
> +	mutex_unlock(&pf->mac_list_lock);
> +}
> +
> +static int enetc4_pf_set_mac_exact_filter(struct enetc_pf *pf, int type)
> +{
> +	int max_num_mfe = pf->caps.mac_filter_num;
> +	struct net_device *ndev = pf->si->ndev;
> +	struct enetc_mac_addr *mac_tbl;
> +	struct netdev_hw_addr *ha;
> +	u8 si_mac[ETH_ALEN];
> +	int mac_cnt = 0;
> +	int err;
> +
> +	mac_tbl = kcalloc(max_num_mfe, sizeof(*mac_tbl), GFP_KERNEL);

Can't you know ahead of time, based on netdev_uc_count(), whether you
will have space for exact match filters, and avoid unnecessary
allocations if not? enetc_mac_list_is_available() seems way too late.

> +	if (!mac_tbl)
> +		return -ENOMEM;
> +
> +	enetc_get_primary_mac_addr(&pf->si->hw, si_mac);
> +
> +	netif_addr_lock_bh(ndev);
> +	if (type & ENETC_MAC_FILTER_TYPE_UC) {
> +		netdev_for_each_uc_addr(ha, ndev) {
> +			if (!is_valid_ether_addr(ha->addr) ||
> +			    ether_addr_equal(ha->addr, si_mac))
> +				continue;
> +
> +			if (mac_cnt >= max_num_mfe)
> +				goto err_nospace_out;
> +
> +			ether_addr_copy(mac_tbl[mac_cnt++].addr, ha->addr);
> +		}
> +	}
> +
> +	if (type & ENETC_MAC_FILTER_TYPE_MC) {

Dead code, you never add multicast addresses as exact match filters.
Please remove.

> +		netdev_for_each_mc_addr(ha, ndev) {
> +			if (!is_multicast_ether_addr(ha->addr))
> +				continue;
> +
> +			if (mac_cnt >= max_num_mfe)
> +				goto err_nospace_out;
> +
> +			ether_addr_copy(mac_tbl[mac_cnt++].addr, ha->addr);
> +		}
> +	}
> +	netif_addr_unlock_bh(ndev);
> +
> +	err = enetc4_pf_add_si_mac_exact_filter(pf, 0, mac_tbl, mac_cnt);
> +	kfree(mac_tbl);
> +
> +	return err;
> +
> +err_nospace_out:
> +	netif_addr_unlock_bh(ndev);
> +	kfree(mac_tbl);
> +
> +	return -ENOSPC;
> +}
> +
> +static void enetc4_pf_set_mac_hash_filter(struct enetc_pf *pf, int type)
> +{
> +	struct net_device *ndev = pf->si->ndev;
> +	struct enetc_mac_filter *mac_filter;
> +	struct enetc_hw *hw = &pf->si->hw;
> +	struct enetc_si *si = pf->si;
> +	struct netdev_hw_addr *ha;
> +
> +	netif_addr_lock_bh(ndev);
> +	if (type & ENETC_MAC_FILTER_TYPE_UC) {
> +		mac_filter = &si->mac_filter[UC];
> +		enetc_reset_mac_addr_filter(mac_filter);
> +		netdev_for_each_uc_addr(ha, ndev)
> +			enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
> +
> +		enetc4_pf_set_si_mac_hash_filter(hw, 0, UC,
> +						 *mac_filter->mac_hash_table);
> +	}
> +
> +	if (type & ENETC_MAC_FILTER_TYPE_MC) {
> +		mac_filter = &si->mac_filter[MC];
> +		enetc_reset_mac_addr_filter(mac_filter);
> +		netdev_for_each_mc_addr(ha, ndev)
> +			enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
> +
> +		enetc4_pf_set_si_mac_hash_filter(hw, 0, MC,
> +						 *mac_filter->mac_hash_table);
> +	}
> +	netif_addr_unlock_bh(ndev);
> +}
> +
> +static void enetc4_pf_set_mac_filter(struct enetc_pf *pf, int type)
> +{
> +	/* Currently, the MAC address filter table only has 4 entries, and the
> +	 * table is shared by PF and VFs. In the default network configuration,
> +	 * the MAC filter will be configured with multiple multicast addresses,
> +	 * so it is only suitable for unicast filtering. If the number of unicast
> +	 * addresses exceeds the table capacity, the MAC hash filter will be used.
> +	 */
> +	if (type & ENETC_MAC_FILTER_TYPE_UC) {
> +		if (enetc4_pf_set_mac_exact_filter(pf, ENETC_MAC_FILTER_TYPE_UC))
> +			/* Fall back to the MAC hash filter */
> +			enetc4_pf_set_mac_hash_filter(pf, ENETC_MAC_FILTER_TYPE_UC);
> +	}
> +
> +	if (type & ENETC_MAC_FILTER_TYPE_MC)
> +		enetc4_pf_set_mac_hash_filter(pf, ENETC_MAC_FILTER_TYPE_MC);
> +}
> +
>  static const struct enetc_pf_ops enetc4_pf_ops = {
>  	.set_si_primary_mac = enetc4_pf_set_si_primary_mac,
>  	.get_si_primary_mac = enetc4_pf_get_si_primary_mac,
> @@ -71,9 +418,18 @@ static int enetc4_pf_struct_init(struct enetc_si *si)
>  
>  	enetc4_get_port_caps(pf);
>  
> +	INIT_HLIST_HEAD(&pf->mac_list);
> +	mutex_init(&pf->mac_list_lock);
> +
>  	return 0;
>  }
>  
> +static void enetc4_pf_struct_free(struct enetc_pf *pf)
> +{
> +	enetc4_pf_destroy_mac_list(pf);
> +	mutex_destroy(&pf->mac_list_lock);
> +}
> +
>  static u32 enetc4_psicfgr0_val_construct(bool is_vf, u32 num_tx_bdr, u32 num_rx_bdr)
>  {
>  	u32 val;
> @@ -305,12 +661,53 @@ static void enetc4_pf_free(struct enetc_pf *pf)
>  	enetc4_free_ntmp_priv(pf->si);
>  }
>  
> +static void enetc4_pf_do_set_rx_mode(struct work_struct *work)
> +{
> +	struct enetc_si *si = container_of(work, struct enetc_si, rx_mode_task);
> +	struct enetc_pf *pf = enetc_si_priv(si);
> +	struct net_device *ndev = si->ndev;
> +	struct enetc_hw *hw = &si->hw;
> +	bool uc_promisc = false;
> +	bool mc_promisc = false;
> +	int type = 0;
> +
> +	if (ndev->flags & IFF_PROMISC) {
> +		uc_promisc = true;
> +		mc_promisc = true;
> +	} else if (ndev->flags & IFF_ALLMULTI) {
> +		mc_promisc = true;
> +		type = ENETC_MAC_FILTER_TYPE_UC;
> +	} else {
> +		type = ENETC_MAC_FILTER_TYPE_ALL;
> +	}
> +
> +	enetc4_pf_set_si_mac_promisc(hw, 0, UC, uc_promisc);
> +	enetc4_pf_set_si_mac_promisc(hw, 0, MC, mc_promisc);

Why don't you call the function just once and provide both uc_promisc
and mc_promisc arguments? You would avoid a useless read of the
ENETC4_PSIPMMR register.

> +
> +	/* Clear Old MAC filter */
> +	enetc4_pf_flush_si_mac_exact_filter(pf, 0, ENETC_MAC_FILTER_TYPE_ALL);
> +	enetc4_pf_set_si_mac_hash_filter(hw, 0, UC, 0);
> +	enetc4_pf_set_si_mac_hash_filter(hw, 0, MC, 0);
> +
> +	/* Set new MAC filter */
> +	enetc4_pf_set_mac_filter(pf, type);
> +}
> +
> +static void enetc4_pf_set_rx_mode(struct net_device *ndev)
> +{
> +	struct enetc_ndev_priv *priv = netdev_priv(ndev);
> +	struct enetc_si *si = priv->si;
> +
> +	queue_work(si->workqueue, &si->rx_mode_task);
> +}
> +
>  static const struct net_device_ops enetc4_ndev_ops = {
>  	.ndo_open		= enetc_open,
>  	.ndo_stop		= enetc_close,
>  	.ndo_start_xmit		= enetc_xmit,
>  	.ndo_get_stats		= enetc_get_stats,
>  	.ndo_set_mac_address	= enetc_pf_set_mac_addr,
> +	.ndo_set_rx_mode	= enetc4_pf_set_rx_mode,
>  };
>  
>  static struct phylink_pcs *
> @@ -721,6 +1118,19 @@ static const struct enetc_si_ops enetc4_psi_ops = {
>  	.teardown_cbdr = enetc4_teardown_cbdr,
>  };
>  
> +static int enetc4_pf_wq_task_init(struct enetc_si *si)
> +{
> +	char wq_name[24];
> +
> +	INIT_WORK(&si->rx_mode_task, enetc4_pf_do_set_rx_mode);
> +	snprintf(wq_name, sizeof(wq_name), "enetc-%s", pci_name(si->pdev));
> +	si->workqueue = create_singlethread_workqueue(wq_name);
> +	if (!si->workqueue)
> +		return -ENOMEM;
> +
> +	return 0;
> +}

Naming scheme is inconsistent here: the function is called "pf" but
takes "si" as argument. Same for enetc4_pf_do_set_rx_mode() where the
rx_mode_task is part of the station interface structure.

> +
>  static int enetc4_pf_probe(struct pci_dev *pdev,
>  			   const struct pci_device_id *ent)
>  {
> @@ -756,9 +1166,13 @@ static int enetc4_pf_probe(struct pci_dev *pdev,
>  		return err;
>  
>  	pf = enetc_si_priv(si);
> +	err = enetc4_pf_wq_task_init(si);
> +	if (err)
> +		goto err_wq_task_init;
> +
>  	err = enetc4_pf_init(pf);
>  	if (err)
> -		return err;
> +		goto err_pf_init;
>  
>  	enetc_get_si_caps(si);
>  
> @@ -770,6 +1184,10 @@ static int enetc4_pf_probe(struct pci_dev *pdev,
>  
>  err_netdev_create:
>  	enetc4_pf_free(pf);
> +err_pf_init:
> +	destroy_workqueue(si->workqueue);
> +err_wq_task_init:
> +	enetc4_pf_struct_free(pf);
>  
>  	return err;
>  }
> @@ -781,6 +1199,8 @@ static void enetc4_pf_remove(struct pci_dev *pdev)
>  
>  	enetc4_pf_netdev_destroy(si);
>  	enetc4_pf_free(pf);
> +	destroy_workqueue(si->workqueue);
> +	enetc4_pf_struct_free(pf);
>  }
>  
>  static const struct pci_device_id enetc4_pf_id_table[] = {
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
> index 4098f01479bc..2e676212d230 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
> +++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
> @@ -712,6 +712,12 @@ static inline void enetc_load_primary_mac_addr(struct enetc_hw *hw,
>  	eth_hw_addr_set(ndev, addr);
>  }
>  
> +static inline void enetc_get_primary_mac_addr(struct enetc_hw *hw, u8 *addr)
> +{
> +	*(u32 *)addr = __raw_readl(hw->reg + ENETC_SIPMAR0);
> +	*(u16 *)(addr + 4) = __raw_readw(hw->reg + ENETC_SIPMAR1);
> +}
> +
>  #define ENETC_SI_INT_IDX	0
>  /* base index for Rx/Tx interrupts */
>  #define ENETC_BDR_INT_BASE_IDX	1
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.h b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
> index 2b9d0f625f01..3b0cb0d8bf48 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h
> +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
> @@ -22,6 +22,13 @@ struct enetc_port_caps {
>  	int num_msix;
>  	int num_rx_bdr;
>  	int num_tx_bdr;
> +	int mac_filter_num;
> +};
> +
> +struct enetc_mac_list_entry {
> +	u8 mac[ETH_ALEN];
> +	u16 si_bitmap;
> +	struct hlist_node node;
>  };
>  
>  struct enetc_pf;
> @@ -57,6 +64,10 @@ struct enetc_pf {
>  
>  	struct enetc_port_caps caps;
>  	const struct enetc_pf_ops *ops;
> +
> +	struct hlist_head mac_list; /* MAC address filter table */

One thing I don't understand is why, given this implementation and
final effect, you even bother to keep the mac_list persistently in
struct enetc_pf. You have:

enetc4_pf_do_set_rx_mode()
-> enetc4_pf_flush_si_mac_exact_filter(ENETC_MAC_FILTER_TYPE_ALL)
   -> hlist_for_each_entry_safe(&pf->mac_list)
      -> enetc_mac_list_del_entry()

which practically deletes all &pf->mac_list elements every time.
So why even store them persistently in the first place? Why not just
create an on-stack INIT_HLIST_HEAD() list?

> +	struct mutex mac_list_lock; /* mac_list lock */

Unsatisfactory explanation. If you try to explain why it is needed, you
will find it's not needed. That's the intention behind checkpatch
emitting warnings when locks don't have comments. Not to force you to
write blabla, but to force you to verbalize, and thus to think whether
the proposed locking scheme makes sense.

The si->rx_mode_task is an ordered workqueue, which, as per
include/linux/workqueue.h, "executes at most one work item at any given
time in the queued order". In other words, enetc4_pf_do_set_rx_mode()
doesn't race with itself.

Combined with the previous comment on enetc4_pf_destroy_mac_list(), I
suggest that there is no need for this lock.

> +	int num_mfe;	/* number of mac address filter table entries */
>  };
>  
>  #define phylink_to_enetc_pf(config) \
> -- 
> 2.34.1
>

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v4 net-next 05/14] net: enetc: add debugfs interface to dump MAC filter
  2025-03-11  5:38 ` [PATCH v4 net-next 05/14] net: enetc: add debugfs interface to dump MAC filter Wei Fang
@ 2025-03-17 14:48   ` Vladimir Oltean
  2025-03-18  3:28     ` Wei Fang
  0 siblings, 1 reply; 58+ messages in thread
From: Vladimir Oltean @ 2025-03-17 14:48 UTC (permalink / raw)
  To: Wei Fang
  Cc: claudiu.manoil, xiaoning.wang, andrew+netdev, davem, edumazet,
	kuba, pabeni, christophe.leroy, netdev, linux-kernel, imx,
	linuxppc-dev, linux-arm-kernel

On Tue, Mar 11, 2025 at 01:38:21PM +0800, Wei Fang wrote:
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c b/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c
> new file mode 100644
> index 000000000000..3a660c80344a
> --- /dev/null
> +++ b/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c
> @@ -0,0 +1,93 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/* Copyright 2025 NXP */
> +
> +#include <linux/device.h>
> +#include <linux/debugfs.h>
> +#include <linux/seq_file.h>
> +
> +#include "enetc_pf.h"
> +#include "enetc4_debugfs.h"
> +
> +#define is_en(x)	(x) ? "Enabled" : "Disabled"

str_enabled_disabled()

> +
> +static void enetc_show_si_mac_hash_filter(struct seq_file *s, int i)
> +{
> +	struct enetc_si *si = s->private;
> +	struct enetc_hw *hw = &si->hw;
> +	u32 hash_h, hash_l;
> +
> +	hash_l = enetc_port_rd(hw, ENETC4_PSIUMHFR0(i));
> +	hash_h = enetc_port_rd(hw, ENETC4_PSIUMHFR1(i));
> +	seq_printf(s, "SI %d unicast MAC hash filter: 0x%08x%08x\n",
> +		   i, hash_h, hash_l);

Maybe the ":" separator between the high and low 32 bits is clearer than "x".

> +
> +	hash_l = enetc_port_rd(hw, ENETC4_PSIMMHFR0(i));
> +	hash_h = enetc_port_rd(hw, ENETC4_PSIMMHFR1(i));
> +	seq_printf(s, "SI %d multicast MAC hash filter: 0x%08x%08x\n",
> +		   i, hash_h, hash_l);
> +}
> +
> +static int enetc_mac_filter_show(struct seq_file *s, void *data)
> +{
> +	struct maft_entry_data maft_data;
> +	struct enetc_si *si = s->private;
> +	struct enetc_hw *hw = &si->hw;
> +	struct maft_keye_data *keye;
> +	struct enetc_pf *pf;
> +	int i, err, num_si;
> +	u32 val;
> +
> +	pf = enetc_si_priv(si);
> +	num_si = pf->caps.num_vsi + 1;
> +
> +	val = enetc_port_rd(hw, ENETC4_PSIPMMR);
> +	for (i = 0; i < num_si; i++) {
> +		seq_printf(s, "SI %d Unicast Promiscuous mode: %s\n",
> +			   i, is_en(PSIPMMR_SI_MAC_UP(i) & val));
> +		seq_printf(s, "SI %d Multicast Promiscuous mode: %s\n",
> +			   i, is_en(PSIPMMR_SI_MAC_MP(i) & val));
> +	}
> +
> +	/* MAC hash filter table */
> +	for (i = 0; i < num_si; i++)
> +		enetc_show_si_mac_hash_filter(s, i);
> +
> +	if (!pf->num_mfe)
> +		return 0;
> +
> +	/* MAC address filter table */
> +	seq_puts(s, "Show MAC address filter table\n");

The word "show" seems superfluous.

> +	for (i = 0; i < pf->num_mfe; i++) {
> +		memset(&maft_data, 0, sizeof(maft_data));
> +		err = ntmp_maft_query_entry(&si->ntmp.cbdrs, i, &maft_data);
> +		if (err)
> +			return err;
> +
> +		keye = &maft_data.keye;
> +		seq_printf(s, "Entry %d, MAC: %pM, SI bitmap: 0x%04x\n", i,
> +			   keye->mac_addr, le16_to_cpu(maft_data.cfge.si_bitmap));
> +	}
> +
> +	return 0;
> +}
> +DEFINE_SHOW_ATTRIBUTE(enetc_mac_filter);

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v4 net-next 08/14] net: enetc: add RSS support for i.MX95 ENETC PF
  2025-03-11  5:38 ` [PATCH v4 net-next 08/14] net: enetc: add RSS support for i.MX95 ENETC PF Wei Fang
@ 2025-03-17 15:55   ` Vladimir Oltean
  2025-03-18  4:47     ` Wei Fang
  0 siblings, 1 reply; 58+ messages in thread
From: Vladimir Oltean @ 2025-03-17 15:55 UTC (permalink / raw)
  To: Wei Fang
  Cc: claudiu.manoil, xiaoning.wang, andrew+netdev, davem, edumazet,
	kuba, pabeni, christophe.leroy, netdev, linux-kernel, imx,
	linuxppc-dev, linux-arm-kernel

On Tue, Mar 11, 2025 at 01:38:24PM +0800, Wei Fang wrote:
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
> index a3ce324c716c..ecf79338cd79 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc.h
> +++ b/drivers/net/ethernet/freescale/enetc/enetc.h
> @@ -543,6 +543,8 @@ void enetc_set_rss_key(struct enetc_si *si, const u8 *bytes);
>  int enetc_get_rss_table(struct enetc_si *si, u32 *table, int count);
>  int enetc_set_rss_table(struct enetc_si *si, const u32 *table, int count);
>  int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd);
> +int enetc4_get_rss_table(struct enetc_si *si, u32 *table, int count);
> +int enetc4_set_rss_table(struct enetc_si *si, const u32 *table, int count);
>  
>  static inline void *enetc_cbd_alloc_data_mem(struct enetc_si *si,
>  					     struct enetc_cbd *cbd,
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> index f991e1aae85c..53dbd5d71859 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> @@ -693,6 +693,14 @@ static void enetc4_pf_set_rx_mode(struct net_device *ndev)
>  	queue_work(si->workqueue, &si->rx_mode_task);
>  }
>  
> +static int enetc4_pf_set_features(struct net_device *ndev,
> +				  netdev_features_t features)
> +{
> +	enetc_set_features(ndev, features);
> +
> +	return 0;
> +}
> +
>  static const struct net_device_ops enetc4_ndev_ops = {
>  	.ndo_open		= enetc_open,
>  	.ndo_stop		= enetc_close,
> @@ -700,6 +708,7 @@ static const struct net_device_ops enetc4_ndev_ops = {
>  	.ndo_get_stats		= enetc_get_stats,
>  	.ndo_set_mac_address	= enetc_pf_set_mac_addr,
>  	.ndo_set_rx_mode	= enetc4_pf_set_rx_mode,
> +	.ndo_set_features	= enetc4_pf_set_features,
>  };
>  
>  static struct phylink_pcs *
> @@ -1108,6 +1117,8 @@ static void enetc4_pf_netdev_destroy(struct enetc_si *si)
>  static const struct enetc_si_ops enetc4_psi_ops = {
>  	.setup_cbdr = enetc4_setup_cbdr,
>  	.teardown_cbdr = enetc4_teardown_cbdr,
> +	.get_rss_table = enetc4_get_rss_table,
> +	.set_rss_table = enetc4_set_rss_table,
>  };
>  
>  static int enetc4_pf_wq_task_init(struct enetc_si *si)
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
> index 4e5125331d7b..1a74b93f1fd3 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
> @@ -299,3 +299,17 @@ int enetc_set_rss_table(struct enetc_si *si, const u32 *table, int count)
>  	return enetc_cmd_rss_table(si, (u32 *)table, count, false);
>  }
>  EXPORT_SYMBOL_GPL(enetc_set_rss_table);
> +
> +int enetc4_get_rss_table(struct enetc_si *si, u32 *table, int count)
> +{
> +	return ntmp_rsst_query_or_update_entry(&si->ntmp.cbdrs,
> +					       table, count, true);
> +}
> +EXPORT_SYMBOL_GPL(enetc4_get_rss_table);
> +
> +int enetc4_set_rss_table(struct enetc_si *si, const u32 *table, int count)
> +{
> +	return ntmp_rsst_query_or_update_entry(&si->ntmp.cbdrs,
> +					       (u32 *)table, count, false);
> +}
> +EXPORT_SYMBOL_GPL(enetc4_set_rss_table);

I don't understand the logic for placing enetc4_get_rss_table() and
enetc4_set_rss_table() in enetc_cbdr.c (built as part of fsl-enetc-core-y)?
It's not core code, it's used only by NETC v4.

> diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
> index 1a8fae3c406b..bc65135925b8 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
> @@ -625,6 +625,24 @@ static int enetc_get_rxnfc(struct net_device *ndev, struct ethtool_rxnfc *rxnfc,
>  	return 0;
>  }
>  
> +static int enetc4_get_rxnfc(struct net_device *ndev, struct ethtool_rxnfc *rxnfc,
> +			    u32 *rule_locs)
> +{
> +	struct enetc_ndev_priv *priv = netdev_priv(ndev);
> +
> +	switch (rxnfc->cmd) {
> +	case ETHTOOL_GRXRINGS:
> +		rxnfc->data = priv->num_rx_rings;
> +		break;
> +	case ETHTOOL_GRXFH:
> +		return enetc_get_rsshash(rxnfc);

These rxnfc commands seem implemented identically to the corresponding
subset from enetc_get_rxnfc(). Rather than duplicating those, could you
rather return -EOPNOTSUPP for the unsupported ones on NETC v4, and reuse
enetc_get_rxnfc()?

> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +
> +	return 0;
> +}
> +
>  static int enetc_set_rxnfc(struct net_device *ndev, struct ethtool_rxnfc *rxnfc)
>  {
>  	struct enetc_ndev_priv *priv = netdev_priv(ndev);
> @@ -685,22 +703,29 @@ static int enetc_get_rss_key_base(struct enetc_si *si)
>  	return ENETC4_PRSSKR(0);
>  }
>  
> +static void enetc_get_rss_key(struct enetc_si *si, const u8 *key)
> +{
> +	int base = enetc_get_rss_key_base(si);
> +	struct enetc_hw *hw = &si->hw;
> +	int i;
> +
> +	for (i = 0; i < ENETC_RSSHASH_KEY_SIZE / 4; i++)
> +		((u32 *)key)[i] = enetc_port_rd(hw, base + i * 4);
> +}

I would have expected that this refactoring of code into
enetc_get_rss_key() would be done as part of the previous change:
"net: enetc: make enetc_set_rss_key() reusable".

> +
>  static int enetc_get_rxfh(struct net_device *ndev,
>  			  struct ethtool_rxfh_param *rxfh)
>  {
>  	struct enetc_ndev_priv *priv = netdev_priv(ndev);
>  	struct enetc_si *si = priv->si;
> -	struct enetc_hw *hw = &si->hw;
> -	int err = 0, i;
> +	int err = 0;
>  
>  	/* return hash function */
>  	rxfh->hfunc = ETH_RSS_HASH_TOP;
>  
>  	/* return hash key */
> -	if (rxfh->key && hw->port)
> -		for (i = 0; i < ENETC_RSSHASH_KEY_SIZE / 4; i++)
> -			((u32 *)rxfh->key)[i] = enetc_port_rd(hw,
> -							      ENETC_PRSSK(i));
> +	if (rxfh->key && enetc_si_is_pf(si))
> +		enetc_get_rss_key(si, rxfh->key);
>  
>  	/* return RSS table */
>  	if (rxfh->indir)
> @@ -1249,6 +1274,11 @@ const struct ethtool_ops enetc4_pf_ethtool_ops = {
>  	.set_wol = enetc_set_wol,
>  	.get_pauseparam = enetc_get_pauseparam,
>  	.set_pauseparam = enetc_set_pauseparam,
> +	.get_rxnfc = enetc4_get_rxnfc,
> +	.get_rxfh_key_size = enetc_get_rxfh_key_size,
> +	.get_rxfh_indir_size = enetc_get_rxfh_indir_size,
> +	.get_rxfh = enetc_get_rxfh,
> +	.set_rxfh = enetc_set_rxfh,
>  };
>  
>  void enetc_set_ethtool_ops(struct net_device *ndev)

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v4 net-next 07/14] net: enetc: make enetc_set_rss_key() reusable
  2025-03-11  5:38 ` [PATCH v4 net-next 07/14] net: enetc: make enetc_set_rss_key() reusable Wei Fang
@ 2025-03-17 16:26   ` Vladimir Oltean
  2025-03-18  4:54     ` Wei Fang
  0 siblings, 1 reply; 58+ messages in thread
From: Vladimir Oltean @ 2025-03-17 16:26 UTC (permalink / raw)
  To: Wei Fang
  Cc: claudiu.manoil, xiaoning.wang, andrew+netdev, davem, edumazet,
	kuba, pabeni, christophe.leroy, netdev, linux-kernel, imx,
	linuxppc-dev, linux-arm-kernel

On Tue, Mar 11, 2025 at 01:38:23PM +0800, Wei Fang wrote:
> Since the offset of the RSS key registers of i.MX95 ENETC is different
> from that of LS1028A, so add enetc_get_rss_key_base() to get the base
> offset for the different chips, so that enetc_set_rss_key() can be
> reused for this trivial.

for this trivial... ? task?

> 
> Signed-off-by: Wei Fang <wei.fang@nxp.com>
> ---
>  drivers/net/ethernet/freescale/enetc/enetc.h  |  2 +-
>  .../net/ethernet/freescale/enetc/enetc4_pf.c  | 11 +----------
>  .../ethernet/freescale/enetc/enetc_ethtool.c  | 19 ++++++++++++++-----
>  .../net/ethernet/freescale/enetc/enetc_pf.c   |  2 +-
>  4 files changed, 17 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> index a98ed059a83f..f991e1aae85c 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> @@ -583,22 +583,13 @@ static void enetc4_set_trx_frame_size(struct enetc_pf *pf)
>  	enetc4_pf_reset_tc_msdu(&si->hw);
>  }
>  
> -static void enetc4_set_rss_key(struct enetc_hw *hw, const u8 *bytes)
> -{
> -	int i;
> -
> -	for (i = 0; i < ENETC_RSSHASH_KEY_SIZE / 4; i++)
> -		enetc_port_wr(hw, ENETC4_PRSSKR(i), ((u32 *)bytes)[i]);
> -}
> -
>  static void enetc4_set_default_rss_key(struct enetc_pf *pf)
>  {
>  	u8 hash_key[ENETC_RSSHASH_KEY_SIZE] = {0};
> -	struct enetc_hw *hw = &pf->si->hw;
>  
>  	/* set up hash key */
>  	get_random_bytes(hash_key, ENETC_RSSHASH_KEY_SIZE);
> -	enetc4_set_rss_key(hw, hash_key);
> +	enetc_set_rss_key(pf->si, hash_key);
>  }

The entire enetc4_set_default_rss_key() seems reusable as
enetc_set_default_rss_key(). enetc_configure_port() has the same logic.

>  
>  static void enetc4_enable_trx(struct enetc_pf *pf)

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v4 net-next 09/14] net: enetc: enable RSS feature by default
  2025-03-11  5:38 ` [PATCH v4 net-next 09/14] net: enetc: enable RSS feature by default Wei Fang
@ 2025-03-17 16:33   ` Vladimir Oltean
  2025-03-18  5:00     ` Wei Fang
  0 siblings, 1 reply; 58+ messages in thread
From: Vladimir Oltean @ 2025-03-17 16:33 UTC (permalink / raw)
  To: Wei Fang
  Cc: claudiu.manoil, xiaoning.wang, andrew+netdev, davem, edumazet,
	kuba, pabeni, christophe.leroy, netdev, linux-kernel, imx,
	linuxppc-dev, linux-arm-kernel

On Tue, Mar 11, 2025 at 01:38:25PM +0800, Wei Fang wrote:
> Receive side scaling (RSS) is a network driver technology that enables
> the efficient distribution of network receive processing across multiple
> CPUs in multiprocessor systems. Therefore, it is better to enable RSS by
> default so that the CPU load can be balanced and network performance can
> be improved when then network is enabled.

s/then network/the network/

> 
> Signed-off-by: Wei Fang <wei.fang@nxp.com>
> ---
>  drivers/net/ethernet/freescale/enetc/enetc.c  | 35 ++++++++++---------
>  .../freescale/enetc/enetc_pf_common.c         |  4 ++-
>  .../net/ethernet/freescale/enetc/enetc_vf.c   |  4 ++-
>  3 files changed, 25 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
> index 5b5e65ac8fab..8583ac9f7b9e 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc.c
> @@ -2420,6 +2420,22 @@ static void enetc_set_lso_flags_mask(struct enetc_hw *hw)
>  	enetc_wr(hw, ENETC4_SILSOSFMR1, 0);
>  }
>  
> +static int enetc_set_rss(struct net_device *ndev, int en)

Can you please add a preliminary patch which converts this function's
prototype to:

static void enetc_set_rss(struct net_device *ndev, bool en)
?

After you do that please feel free to add my tag and keep it in future
patch submissions:

Acked-by: Vladimir Oltean <vladimir.oltean@nxp.com>

I don't see downsides to enabling RX hashing by default.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v4 net-next 06/14] net: enetc: add set/get_rss_table() to enetc_si_ops
  2025-03-11  5:38 ` [PATCH v4 net-next 06/14] net: enetc: add set/get_rss_table() to enetc_si_ops Wei Fang
@ 2025-03-17 16:42   ` Vladimir Oltean
  2025-03-18  5:06     ` Wei Fang
  0 siblings, 1 reply; 58+ messages in thread
From: Vladimir Oltean @ 2025-03-17 16:42 UTC (permalink / raw)
  To: Wei Fang
  Cc: claudiu.manoil, xiaoning.wang, andrew+netdev, davem, edumazet,
	kuba, pabeni, christophe.leroy, netdev, linux-kernel, imx,
	linuxppc-dev, linux-arm-kernel

On Tue, Mar 11, 2025 at 01:38:22PM +0800, Wei Fang wrote:
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc_vf.c b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
> index d7d9a720069b..072e5b40a199 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc_vf.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
> @@ -165,6 +165,8 @@ static void enetc_vf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
>  static const struct enetc_si_ops enetc_vsi_ops = {
>  	.setup_cbdr = enetc_setup_cbdr,
>  	.teardown_cbdr = enetc_teardown_cbdr,
> +	.get_rss_table = enetc_get_rss_table,
> +	.set_rss_table = enetc_set_rss_table,
>  };

Are the CBDR-based enetc_get_rss_table() and enetc_set_rss_table()
the correct implementations for NETC v4 VSIs? (I guess not). Does
the driver/hardware fail in a civilized way, or does it crash?

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v4 net-next 10/14] net: enetc: move generic VLAN filter interfaces to enetc-core
  2025-03-11  5:38 ` [PATCH v4 net-next 10/14] net: enetc: move generic VLAN filter interfaces to enetc-core Wei Fang
@ 2025-03-17 17:05   ` Vladimir Oltean
  2025-03-18  5:12     ` Wei Fang
  0 siblings, 1 reply; 58+ messages in thread
From: Vladimir Oltean @ 2025-03-17 17:05 UTC (permalink / raw)
  To: Wei Fang
  Cc: claudiu.manoil, xiaoning.wang, andrew+netdev, davem, edumazet,
	kuba, pabeni, christophe.leroy, netdev, linux-kernel, imx,
	linuxppc-dev, linux-arm-kernel

On Tue, Mar 11, 2025 at 01:38:26PM +0800, Wei Fang wrote:
> For ENETC, each SI has a corresponding VLAN hash table. That is to say,
> both PF and VFs can support VLAN filter. However, currently only ENETC v1
> PF driver supports VLAN filter. In order to make i.MX95 ENETC (v4) PF and
> VF drivers also support VLAN filter, some related macros are moved from
> enetc_pf.h to enetc.h, and the related structure variables are moved from
> enetc_pf to enetc_si.
> 
> Besides, enetc_vid_hash_idx() as a generic function is moved to enetc.c.
> Extract enetc_refresh_vlan_ht_filter() from enetc_sync_vlan_ht_filter()
> so that it can be shared by PF and VF drivers. This will make it easier
> to add VLAN filter support for i.MX95 ENETC later.
> 
> Signed-off-by: Wei Fang <wei.fang@nxp.com>
> ---

In this and the next patch, can you please separate the code movement
from the logical changes? It makes review much more difficult. With the
similar observation that, as in the case of MAC filtering, VSIs don't
yet support VLAN filtering, so the movement of the hash table structures
from per-PF to per-SI is currently premature. So I expect to see that
part removed from the next revision.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v4 net-next 14/14] MAINTAINERS: add new file ntmp.h to ENETC driver
  2025-03-11  5:38 ` [PATCH v4 net-next 14/14] MAINTAINERS: add new file ntmp.h to ENETC driver Wei Fang
@ 2025-03-17 17:06   ` Vladimir Oltean
  2025-03-18  5:13     ` Wei Fang
  0 siblings, 1 reply; 58+ messages in thread
From: Vladimir Oltean @ 2025-03-17 17:06 UTC (permalink / raw)
  To: Wei Fang
  Cc: claudiu.manoil, xiaoning.wang, andrew+netdev, davem, edumazet,
	kuba, pabeni, christophe.leroy, netdev, linux-kernel, imx,
	linuxppc-dev, linux-arm-kernel

On Tue, Mar 11, 2025 at 01:38:30PM +0800, Wei Fang wrote:
> Add new file ntmp.h. to ENETC driver.
> 
> Signed-off-by: Wei Fang <wei.fang@nxp.com>
> ---
>  MAINTAINERS | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 7078199fcebf..e259b659eadb 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -9174,6 +9174,7 @@ F:	Documentation/devicetree/bindings/net/nxp,netc-blk-ctrl.yaml
>  F:	drivers/net/ethernet/freescale/enetc/
>  F:	include/linux/fsl/enetc_mdio.h
>  F:	include/linux/fsl/netc_global.h
> +F:	include/linux/fsl/ntmp.h
>  
>  FREESCALE eTSEC ETHERNET DRIVER (GIANFAR)
>  M:	Claudiu Manoil <claudiu.manoil@nxp.com>
> -- 
> 2.34.1
>

This should be squashed with the patch that adds the initial NTMP support.
We don't split out patches to the MAINTAINERS file.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v4 net-next 04/14] net: enetc: add MAC filter for i.MX95 ENETC PF
  2025-03-17 14:18   ` Vladimir Oltean
@ 2025-03-18  3:19     ` Wei Fang
  2025-03-18  9:29       ` Vladimir Oltean
  2025-03-18  8:08     ` Claudiu Manoil
  1 sibling, 1 reply; 58+ messages in thread
From: Wei Fang @ 2025-03-18  3:19 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Claudiu Manoil, Clark Wang, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, christophe.leroy@csgroup.eu,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org

> > +
> > +static void enetc4_pf_set_si_mac_hash_filter(struct enetc_hw *hw, int si,
> > +					     int type, u64 hash)
> > +{
> > +	if (type == UC) {
> > +		enetc_port_wr(hw, ENETC4_PSIUMHFR0(si), lower_32_bits(hash));
> > +		enetc_port_wr(hw, ENETC4_PSIUMHFR1(si), upper_32_bits(hash));
> > +	} else { /* MC */
> > +		enetc_port_wr(hw, ENETC4_PSIMMHFR0(si), lower_32_bits(hash));
> > +		enetc_port_wr(hw, ENETC4_PSIMMHFR1(si), upper_32_bits(hash));
> > +	}
> > +}
> 
> Please split into separate functions for unicast and for multicast.
> The implementations don't share any code, and the callers are not in
> common code either.
> 

Just copied from enetc_set_mac_ht_flt (), I can split into two separate
functions.

> > +
> > +static void enetc4_pf_destroy_mac_list(struct enetc_pf *pf)
> > +{
> > +	struct enetc_mac_list_entry *entry;
> > +	struct hlist_node *tmp;
> > +
> > +	mutex_lock(&pf->mac_list_lock);
> 
> The mutex_lock() usage here should raise serious questions. This is
> running right before mutex_destroy(). So if there were any concurrent
> attempt to acquire this lock, that concurrent code would have been broken
> any time it would have lost arbitration, by the fact that it would
> attempt to acquire a destroyed mutex.
> 
> But there's no such concurrent thread, because we run after
> destroy_workqueue()
> which flushes those concurrent calls and prevents new ones. So the mutex
> usage here is not necessary.
> 

You are right, but I'm afraid of the Coverity will report an issue, because the
pf->mac_list and pf->num_mfe are protected by the mac_list_lock in other
functions. And enetc4_pf_destroy_mac_list() will be called in other function
in the subsequent patches. I don't think it is unnecessary.

> [ same thing with mutex_init() immediately followed by mutex_lock().
>   It is an incorrect pattern most of the time. ]
> 
> > +
> > +	hlist_for_each_entry_safe(entry, tmp, &pf->mac_list, node) {
> > +		hlist_del(&entry->node);
> > +		kfree(entry);
> > +	}
> > +
> > +	pf->num_mfe = 0;
> > +
> > +	mutex_unlock(&pf->mac_list_lock);
> > +}
> > +
> > +static bool enetc_mac_filter_type_check(int type, const u8 *addr)
> > +{
> > +	if (type == ENETC_MAC_FILTER_TYPE_UC)
> > +		return !is_multicast_ether_addr(addr);
> > +	else if (type == ENETC_MAC_FILTER_TYPE_MC)
> > +		return is_multicast_ether_addr(addr);
> > +	else
> > +		return true;
> > +}
> > +
> > +static struct enetc_mac_list_entry *
> > +enetc_mac_list_lookup_entry(struct enetc_pf *pf, const unsigned char
> *addr)
> > +{
> > +	struct enetc_mac_list_entry *entry;
> > +
> > +	hlist_for_each_entry(entry, &pf->mac_list, node)
> > +		if (ether_addr_equal(entry->mac, addr))
> > +			return entry;
> > +
> > +	return NULL;
> > +}
> > +
> > +static void enetc_mac_list_add_entry(struct enetc_pf *pf,
> > +				     struct enetc_mac_list_entry *entry)
> > +{
> > +	hlist_add_head(&entry->node, &pf->mac_list);
> > +}
> > +
> > +static void enetc_mac_list_del_entry(struct enetc_mac_list_entry *entry)
> > +{
> > +	hlist_del(&entry->node);
> > +	kfree(entry);
> > +}
> > +
> > +static void enetc_mac_list_del_matched_entries(struct enetc_pf *pf, u16
> si_bit,
> > +					       struct enetc_mac_addr *mac,
> > +					       int mac_cnt)
> > +{
> > +	struct enetc_mac_list_entry *entry;
> > +	int i;
> > +
> > +	for (i = 0; i < mac_cnt; i++) {
> > +		entry = enetc_mac_list_lookup_entry(pf, mac[i].addr);
> > +		if (!entry)
> > +			continue;
> > +
> > +		entry->si_bitmap &= ~si_bit;
> > +		if (entry->si_bitmap)
> > +			continue;
> > +
> > +		enetc_mac_list_del_entry(entry);
> > +		pf->num_mfe--;
> > +	}
> > +}
> > +
> > +static bool enetc_mac_list_is_available(struct enetc_pf *pf,
> > +					struct enetc_mac_addr *mac,
> > +					int mac_cnt)
> > +{
> > +	int max_num_mfe = pf->caps.mac_filter_num;
> > +	struct enetc_mac_list_entry *entry;
> > +	int cur_num_mfe = pf->num_mfe;
> > +	int i, new_mac_cnt = 0;
> > +
> > +	if (mac_cnt > max_num_mfe)
> > +		return false;
> > +
> > +	/* Check MAC filter table whether has enough available entries */
> > +	hlist_for_each_entry(entry, &pf->mac_list, node) {
> > +		for (i = 0; i < mac_cnt; i++) {
> > +			if (ether_addr_equal(entry->mac, mac[i].addr))
> > +				break;
> > +		}
> > +
> > +		if (i == mac_cnt)
> > +			new_mac_cnt++;
> > +
> > +		if ((cur_num_mfe + new_mac_cnt) > max_num_mfe)
> > +			return false;
> > +	}
> > +
> > +	return true;
> > +}
> > +
> > +static int enetc4_pf_add_si_mac_exact_filter(struct enetc_pf *pf, int si_id,
> > +					     struct enetc_mac_addr *mac,
> > +					     int mac_cnt)
> > +{
> > +	struct enetc_mac_list_entry *entry;
> > +	struct maft_entry_data data = {0};
> 
> As I've also learned, what you actually want is an empty struct initializer "= {}"
> here:
> https://lore.kernel.org/netdev/20210810091238.GB1343@shell.armlinux.org.u
> k/
> 

Thanks for the info, I will improve all of this in the patch set.

> > +	struct enetc_si *si = pf->si;
> > +	u16 si_bit = BIT(si_id);
> > +	int i, num_mfe, err = 0;
> > +
> > +	mutex_lock(&pf->mac_list_lock);
> > +
> > +	if (!enetc_mac_list_is_available(pf, mac, mac_cnt)) {
> > +		err = -ENOSPC;
> > +		goto mac_list_unlock;
> > +	}
> > +
> > +	num_mfe = pf->num_mfe;
> > +	/* Update mac_list */
> > +	for (i = 0; i < mac_cnt; i++) {
> > +		entry = enetc_mac_list_lookup_entry(pf, mac[i].addr);
> > +		if (entry) {
> > +			entry->si_bitmap |= si_bit;
> > +			continue;
> > +		}
> > +
> > +		entry = kzalloc(sizeof(*entry), GFP_KERNEL);
> > +		if (unlikely(!entry)) {
> > +			/* Restore MAC list to the state before the update
> > +			 * if an error occurs.
> > +			 */
> > +			enetc_mac_list_del_matched_entries(pf, si_bit,
> > +							   mac, i + 1);
> > +			err = -ENOMEM;
> > +			goto mac_list_unlock;
> > +		}
> > +
> > +		ether_addr_copy(entry->mac, mac[i].addr);
> > +		entry->si_bitmap = si_bit;
> > +		enetc_mac_list_add_entry(pf, entry);
> > +		pf->num_mfe++;
> > +	}
> > +
> > +	/* Clear MAC filter table */
> > +	for (i = 0; i < num_mfe; i++)
> > +		ntmp_maft_delete_entry(&si->ntmp.cbdrs, i);
> > +
> > +	i = 0;
> > +	hlist_for_each_entry(entry, &pf->mac_list, node) {
> > +		data.cfge.si_bitmap = cpu_to_le16(entry->si_bitmap);
> > +		ether_addr_copy(data.keye.mac_addr, entry->mac);
> > +		ntmp_maft_add_entry(&si->ntmp.cbdrs, i++, &data);
> 
> Don't discard error code.

Okay, I will add error check.
> 
> > +	}
> > +
> > +mac_list_unlock:
> > +	mutex_unlock(&pf->mac_list_lock);
> > +
> > +	return err;
> > +}
> > +
> > +static void enetc4_pf_flush_si_mac_exact_filter(struct enetc_pf *pf, int si_id,
> > +						int mac_type)
> > +{
> > +	struct enetc_mac_list_entry *entry;
> > +	struct maft_entry_data data = {0};
> 
> s/{0}/{}/
> 
> > +	struct enetc_si *si = pf->si;
> > +	u16 si_bit = BIT(si_id);
> > +	struct hlist_node *tmp;
> > +	int i, num_mfe;
> > +
> > +	mutex_lock(&pf->mac_list_lock);
> > +
> > +	num_mfe = pf->num_mfe;
> > +	hlist_for_each_entry_safe(entry, tmp, &pf->mac_list, node) {
> > +		if (enetc_mac_filter_type_check(mac_type, entry->mac) &&
> > +		    entry->si_bitmap & si_bit) {
> > +			entry->si_bitmap ^= si_bit;
> > +			if (entry->si_bitmap)
> > +				continue;
> > +
> > +			enetc_mac_list_del_entry(entry);
> > +			pf->num_mfe--;
> > +		}
> > +	}
> > +
> > +	for (i = 0; i < num_mfe; i++)
> > +		ntmp_maft_delete_entry(&si->ntmp.cbdrs, i);
> > +
> > +	i = 0;
> > +	hlist_for_each_entry(entry, &pf->mac_list, node) {
> > +		data.cfge.si_bitmap = cpu_to_le16(entry->si_bitmap);
> > +		ether_addr_copy(data.keye.mac_addr, entry->mac);
> > +		ntmp_maft_add_entry(&si->ntmp.cbdrs, i++, &data);
> 
> Don't discard error code.
> 
> Also, can't you edit MAFT entries in-place over NTMP? Deleting and
> re-adding filters creates small time windows where you might have
> RX packet loss, which is not ideal.

Actually MAFT does not support update action, if a MAC address has
been used by a SI, then another SI also wants to filter the same MAC
address, we only can delete the old entry and then add a new entry.
So there will be Rx packet loss as you said.

Second, the MAFT does not support key match, so we only access the
table through entry id. If we don't want to delete and re-add these
existing entries, then the driver needs to record the entry id of each
entry, this will make adding and removing entries more complicated.

So for your question about Rx packet loss, although it is a very corner
case, the solution I can think of is that we can use temporary MAC hash
filters before deleting MAFT entries and delete them after adding the
MAFT entries. Can you accept this proposal?

> 
> > +	}
> > +
> > +	mutex_unlock(&pf->mac_list_lock);
> > +}
> > +
> > +static int enetc4_pf_set_mac_exact_filter(struct enetc_pf *pf, int type)
> > +{
> > +	int max_num_mfe = pf->caps.mac_filter_num;
> > +	struct net_device *ndev = pf->si->ndev;
> > +	struct enetc_mac_addr *mac_tbl;
> > +	struct netdev_hw_addr *ha;
> > +	u8 si_mac[ETH_ALEN];
> > +	int mac_cnt = 0;
> > +	int err;
> > +
> > +	mac_tbl = kcalloc(max_num_mfe, sizeof(*mac_tbl), GFP_KERNEL);
> 
> Can't you know ahead of time, based on netdev_uc_count(), whether you
> will have space for exact match filters, and avoid unnecessary
> allocations if not? enetc_mac_list_is_available() seems way too late.
> 

I can add a check before alloc mac_tbl, but enetc_mac_list_is_available()
is still needed, because enetc4_pf_add_si_mac_exact_filter() is a common
function for all Sis, not only for PSI.

> > +	if (!mac_tbl)
> > +		return -ENOMEM;
> > +
> > +	enetc_get_primary_mac_addr(&pf->si->hw, si_mac);
> > +
> > +	netif_addr_lock_bh(ndev);
> > +	if (type & ENETC_MAC_FILTER_TYPE_UC) {
> > +		netdev_for_each_uc_addr(ha, ndev) {
> > +			if (!is_valid_ether_addr(ha->addr) ||
> > +			    ether_addr_equal(ha->addr, si_mac))
> > +				continue;
> > +
> > +			if (mac_cnt >= max_num_mfe)
> > +				goto err_nospace_out;
> > +
> > +			ether_addr_copy(mac_tbl[mac_cnt++].addr, ha->addr);
> > +		}
> > +	}
> > +
> > +	if (type & ENETC_MAC_FILTER_TYPE_MC) {
> 
> Dead code, you never add multicast addresses as exact match filters.
> Please remove.

Okay, I thought that we could support multicast exact filter for later
SoCs in the future with slight modification.

> 
> > +static void enetc4_pf_do_set_rx_mode(struct work_struct *work)
> > +{
> > +	struct enetc_si *si = container_of(work, struct enetc_si, rx_mode_task);
> > +	struct enetc_pf *pf = enetc_si_priv(si);
> > +	struct net_device *ndev = si->ndev;
> > +	struct enetc_hw *hw = &si->hw;
> > +	bool uc_promisc = false;
> > +	bool mc_promisc = false;
> > +	int type = 0;
> > +
> > +	if (ndev->flags & IFF_PROMISC) {
> > +		uc_promisc = true;
> > +		mc_promisc = true;
> > +	} else if (ndev->flags & IFF_ALLMULTI) {
> > +		mc_promisc = true;
> > +		type = ENETC_MAC_FILTER_TYPE_UC;
> > +	} else {
> > +		type = ENETC_MAC_FILTER_TYPE_ALL;
> > +	}
> > +
> > +	enetc4_pf_set_si_mac_promisc(hw, 0, UC, uc_promisc);
> > +	enetc4_pf_set_si_mac_promisc(hw, 0, MC, mc_promisc);
> 
> Why don't you call the function just once and provide both uc_promisc
> and mc_promisc arguments? You would avoid a useless read of the
> ENETC4_PSIPMMR register.
> 
Okay, I will refine the enetc4_pf_set_si_mac_promisc().

> > +static int enetc4_pf_wq_task_init(struct enetc_si *si)
> > +{
> > +	char wq_name[24];
> > +
> > +	INIT_WORK(&si->rx_mode_task, enetc4_pf_do_set_rx_mode);
> > +	snprintf(wq_name, sizeof(wq_name), "enetc-%s", pci_name(si->pdev));
> > +	si->workqueue = create_singlethread_workqueue(wq_name);
> > +	if (!si->workqueue)
> > +		return -ENOMEM;
> > +
> > +	return 0;
> > +}
> 
> Naming scheme is inconsistent here: the function is called "pf" but
> takes "si" as argument. Same for enetc4_pf_do_set_rx_mode() where the
> rx_mode_task is part of the station interface structure.
> 

So change 'pf' to 'psi'?

> > diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.h
> b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
> > index 2b9d0f625f01..3b0cb0d8bf48 100644
> > --- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h
> > +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
> > @@ -22,6 +22,13 @@ struct enetc_port_caps {
> >  	int num_msix;
> >  	int num_rx_bdr;
> >  	int num_tx_bdr;
> > +	int mac_filter_num;
> > +};
> > +
> > +struct enetc_mac_list_entry {
> > +	u8 mac[ETH_ALEN];
> > +	u16 si_bitmap;
> > +	struct hlist_node node;
> >  };
> >
> >  struct enetc_pf;
> > @@ -57,6 +64,10 @@ struct enetc_pf {
> >
> >  	struct enetc_port_caps caps;
> >  	const struct enetc_pf_ops *ops;
> > +
> > +	struct hlist_head mac_list; /* MAC address filter table */
> 
> One thing I don't understand is why, given this implementation and
> final effect, you even bother to keep the mac_list persistently in
> struct enetc_pf. You have:
> 
> enetc4_pf_do_set_rx_mode()
> -> enetc4_pf_flush_si_mac_exact_filter(ENETC_MAC_FILTER_TYPE_ALL)
>    -> hlist_for_each_entry_safe(&pf->mac_list)
>       -> enetc_mac_list_del_entry()
> 
> which practically deletes all &pf->mac_list elements every time.
> So why even store them persistently in the first place? Why not just
> create an on-stack INIT_HLIST_HEAD() list?

The enetc4_pf_add_si_mac_exact_filter() and
enetc4_pf_add_si_mac_exact_filter() are used for all Sis, but only
PF can access MAFT, and PSI and VSIs may share the same MAFT
entry, so we need to store them in struct enetc_pf. Although we
have not added VFs support yet, for such shared functions, we
should design its implementation from the beginning, rather than
modifying them when we add the VFs support.

> 
> > +	struct mutex mac_list_lock; /* mac_list lock */
> 
> Unsatisfactory explanation. If you try to explain why it is needed, you
> will find it's not needed. That's the intention behind checkpatch
> emitting warnings when locks don't have comments. Not to force you to
> write blabla, but to force you to verbalize, and thus to think whether
> the proposed locking scheme makes sense.
> 
> The si->rx_mode_task is an ordered workqueue, which, as per
> include/linux/workqueue.h, "executes at most one work item at any given
> time in the queued order". In other words, enetc4_pf_do_set_rx_mode()
> doesn't race with itself.
> 
> Combined with the previous comment on enetc4_pf_destroy_mac_list(), I
> suggest that there is no need for this lock.
> 

I thought we could lay some foundation for VF's MAC filter support, so that
it would be easier to support VF later. However, judging from the current patch,
what you said is not unreasonable, we should pay more attention to whether
the current implementation is consistent with the current functions to be
supported. I will remove some parts related to VF, thank you.

> > +	int num_mfe;	/* number of mac address filter table entries */
> >  };
> >
> >  #define phylink_to_enetc_pf(config) \
> > --
> > 2.34.1
> >

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v4 net-next 05/14] net: enetc: add debugfs interface to dump MAC filter
  2025-03-17 14:48   ` Vladimir Oltean
@ 2025-03-18  3:28     ` Wei Fang
  2025-03-18 14:54       ` Vladimir Oltean
  0 siblings, 1 reply; 58+ messages in thread
From: Wei Fang @ 2025-03-18  3:28 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Claudiu Manoil, Clark Wang, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, christophe.leroy@csgroup.eu,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org

> On Tue, Mar 11, 2025 at 01:38:21PM +0800, Wei Fang wrote:
> > diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c
> > b/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c
> > new file mode 100644
> > index 000000000000..3a660c80344a
> > --- /dev/null
> > +++ b/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c
> > @@ -0,0 +1,93 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/* Copyright 2025 NXP */
> > +
> > +#include <linux/device.h>
> > +#include <linux/debugfs.h>
> > +#include <linux/seq_file.h>
> > +
> > +#include "enetc_pf.h"
> > +#include "enetc4_debugfs.h"
> > +
> > +#define is_en(x)	(x) ? "Enabled" : "Disabled"
> 
> str_enabled_disabled()

Oh, good, I wondered if there was a general implementation in
the kernel, but I did not find one due to my limited knowledge.
Thanks!

> 
> > +
> > +static void enetc_show_si_mac_hash_filter(struct seq_file *s, int i)
> > +{
> > +	struct enetc_si *si = s->private;
> > +	struct enetc_hw *hw = &si->hw;
> > +	u32 hash_h, hash_l;
> > +
> > +	hash_l = enetc_port_rd(hw, ENETC4_PSIUMHFR0(i));
> > +	hash_h = enetc_port_rd(hw, ENETC4_PSIUMHFR1(i));
> > +	seq_printf(s, "SI %d unicast MAC hash filter: 0x%08x%08x\n",
> > +		   i, hash_h, hash_l);
> 
> Maybe the ":" separator between the high and low 32 bits is clearer than "x".

I want it to be presented as a full 64-bit entry. If it is in the format
of "%08x:%08x", it may be difficult to understand which is the high
32-bit and which is the low 32-bit.

> 
> > +
> > +	hash_l = enetc_port_rd(hw, ENETC4_PSIMMHFR0(i));
> > +	hash_h = enetc_port_rd(hw, ENETC4_PSIMMHFR1(i));
> > +	seq_printf(s, "SI %d multicast MAC hash filter: 0x%08x%08x\n",
> > +		   i, hash_h, hash_l);
> > +}
> > +
> > +static int enetc_mac_filter_show(struct seq_file *s, void *data) {
> > +	struct maft_entry_data maft_data;
> > +	struct enetc_si *si = s->private;
> > +	struct enetc_hw *hw = &si->hw;
> > +	struct maft_keye_data *keye;
> > +	struct enetc_pf *pf;
> > +	int i, err, num_si;
> > +	u32 val;
> > +
> > +	pf = enetc_si_priv(si);
> > +	num_si = pf->caps.num_vsi + 1;
> > +
> > +	val = enetc_port_rd(hw, ENETC4_PSIPMMR);
> > +	for (i = 0; i < num_si; i++) {
> > +		seq_printf(s, "SI %d Unicast Promiscuous mode: %s\n",
> > +			   i, is_en(PSIPMMR_SI_MAC_UP(i) & val));
> > +		seq_printf(s, "SI %d Multicast Promiscuous mode: %s\n",
> > +			   i, is_en(PSIPMMR_SI_MAC_MP(i) & val));
> > +	}
> > +
> > +	/* MAC hash filter table */
> > +	for (i = 0; i < num_si; i++)
> > +		enetc_show_si_mac_hash_filter(s, i);
> > +
> > +	if (!pf->num_mfe)
> > +		return 0;
> > +
> > +	/* MAC address filter table */
> > +	seq_puts(s, "Show MAC address filter table\n");
> 
> The word "show" seems superfluous.

Okay, will remove it.

> 
> > +	for (i = 0; i < pf->num_mfe; i++) {
> > +		memset(&maft_data, 0, sizeof(maft_data));
> > +		err = ntmp_maft_query_entry(&si->ntmp.cbdrs, i, &maft_data);
> > +		if (err)
> > +			return err;
> > +
> > +		keye = &maft_data.keye;
> > +		seq_printf(s, "Entry %d, MAC: %pM, SI bitmap: 0x%04x\n", i,
> > +			   keye->mac_addr, le16_to_cpu(maft_data.cfge.si_bitmap));
> > +	}
> > +
> > +	return 0;
> > +}
> > +DEFINE_SHOW_ATTRIBUTE(enetc_mac_filter);

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v4 net-next 08/14] net: enetc: add RSS support for i.MX95 ENETC PF
  2025-03-17 15:55   ` Vladimir Oltean
@ 2025-03-18  4:47     ` Wei Fang
  2025-03-18 11:43       ` Vladimir Oltean
  0 siblings, 1 reply; 58+ messages in thread
From: Wei Fang @ 2025-03-18  4:47 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Claudiu Manoil, Clark Wang, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, christophe.leroy@csgroup.eu,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org

> On Tue, Mar 11, 2025 at 01:38:24PM +0800, Wei Fang wrote:
> > diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h
> b/drivers/net/ethernet/freescale/enetc/enetc.h
> > index a3ce324c716c..ecf79338cd79 100644
> > --- a/drivers/net/ethernet/freescale/enetc/enetc.h
> > +++ b/drivers/net/ethernet/freescale/enetc/enetc.h
> > @@ -543,6 +543,8 @@ void enetc_set_rss_key(struct enetc_si *si, const u8
> *bytes);
> >  int enetc_get_rss_table(struct enetc_si *si, u32 *table, int count);
> >  int enetc_set_rss_table(struct enetc_si *si, const u32 *table, int count);
> >  int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd);
> > +int enetc4_get_rss_table(struct enetc_si *si, u32 *table, int count);
> > +int enetc4_set_rss_table(struct enetc_si *si, const u32 *table, int count);
> >
> >  static inline void *enetc_cbd_alloc_data_mem(struct enetc_si *si,
> >  					     struct enetc_cbd *cbd,
> > diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> > index f991e1aae85c..53dbd5d71859 100644
> > --- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> > +++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> > @@ -693,6 +693,14 @@ static void enetc4_pf_set_rx_mode(struct
> net_device *ndev)
> >  	queue_work(si->workqueue, &si->rx_mode_task);
> >  }
> >
> > +static int enetc4_pf_set_features(struct net_device *ndev,
> > +				  netdev_features_t features)
> > +{
> > +	enetc_set_features(ndev, features);
> > +
> > +	return 0;
> > +}
> > +
> >  static const struct net_device_ops enetc4_ndev_ops = {
> >  	.ndo_open		= enetc_open,
> >  	.ndo_stop		= enetc_close,
> > @@ -700,6 +708,7 @@ static const struct net_device_ops enetc4_ndev_ops
> = {
> >  	.ndo_get_stats		= enetc_get_stats,
> >  	.ndo_set_mac_address	= enetc_pf_set_mac_addr,
> >  	.ndo_set_rx_mode	= enetc4_pf_set_rx_mode,
> > +	.ndo_set_features	= enetc4_pf_set_features,
> >  };
> >
> >  static struct phylink_pcs *
> > @@ -1108,6 +1117,8 @@ static void enetc4_pf_netdev_destroy(struct
> enetc_si *si)
> >  static const struct enetc_si_ops enetc4_psi_ops = {
> >  	.setup_cbdr = enetc4_setup_cbdr,
> >  	.teardown_cbdr = enetc4_teardown_cbdr,
> > +	.get_rss_table = enetc4_get_rss_table,
> > +	.set_rss_table = enetc4_set_rss_table,
> >  };
> >
> >  static int enetc4_pf_wq_task_init(struct enetc_si *si)
> > diff --git a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
> b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
> > index 4e5125331d7b..1a74b93f1fd3 100644
> > --- a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
> > +++ b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c
> > @@ -299,3 +299,17 @@ int enetc_set_rss_table(struct enetc_si *si, const
> u32 *table, int count)
> >  	return enetc_cmd_rss_table(si, (u32 *)table, count, false);
> >  }
> >  EXPORT_SYMBOL_GPL(enetc_set_rss_table);
> > +
> > +int enetc4_get_rss_table(struct enetc_si *si, u32 *table, int count)
> > +{
> > +	return ntmp_rsst_query_or_update_entry(&si->ntmp.cbdrs,
> > +					       table, count, true);
> > +}
> > +EXPORT_SYMBOL_GPL(enetc4_get_rss_table);
> > +
> > +int enetc4_set_rss_table(struct enetc_si *si, const u32 *table, int count)
> > +{
> > +	return ntmp_rsst_query_or_update_entry(&si->ntmp.cbdrs,
> > +					       (u32 *)table, count, false);
> > +}
> > +EXPORT_SYMBOL_GPL(enetc4_set_rss_table);
> 
> I don't understand the logic for placing enetc4_get_rss_table() and
> enetc4_set_rss_table() in enetc_cbdr.c (built as part of fsl-enetc-core-y)?
> It's not core code, it's used only by NETC v4.

The ENETC v4 VF will reuse the driver of ENETC v1, and it also supports
RSS, so I think these functions are fine to be placed in enetc-core.

> 
> > diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
> b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
> > index 1a8fae3c406b..bc65135925b8 100644
> > --- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
> > +++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
> > @@ -625,6 +625,24 @@ static int enetc_get_rxnfc(struct net_device *ndev,
> struct ethtool_rxnfc *rxnfc,
> >  	return 0;
> >  }
> >
> > +static int enetc4_get_rxnfc(struct net_device *ndev, struct ethtool_rxnfc
> *rxnfc,
> > +			    u32 *rule_locs)
> > +{
> > +	struct enetc_ndev_priv *priv = netdev_priv(ndev);
> > +
> > +	switch (rxnfc->cmd) {
> > +	case ETHTOOL_GRXRINGS:
> > +		rxnfc->data = priv->num_rx_rings;
> > +		break;
> > +	case ETHTOOL_GRXFH:
> > +		return enetc_get_rsshash(rxnfc);
> 
> These rxnfc commands seem implemented identically to the corresponding
> subset from enetc_get_rxnfc(). Rather than duplicating those, could you
> rather return -EOPNOTSUPP for the unsupported ones on NETC v4, and reuse
> enetc_get_rxnfc()?
> 

I have explained it to Jakub in v2:
https://lore.kernel.org/imx/PAXPR04MB8510B52B7D27640C557680B4881A2@PAXPR04MB8510.eurprd04.prod.outlook.com/

So I don't want to reuse it for ENETC v4 PF.

> > +	default:
> > +		return -EOPNOTSUPP;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> >  static int enetc_set_rxnfc(struct net_device *ndev, struct ethtool_rxnfc
> *rxnfc)
> >  {
> >  	struct enetc_ndev_priv *priv = netdev_priv(ndev);
> > @@ -685,22 +703,29 @@ static int enetc_get_rss_key_base(struct enetc_si
> *si)
> >  	return ENETC4_PRSSKR(0);
> >  }
> >
> > +static void enetc_get_rss_key(struct enetc_si *si, const u8 *key)
> > +{
> > +	int base = enetc_get_rss_key_base(si);
> > +	struct enetc_hw *hw = &si->hw;
> > +	int i;
> > +
> > +	for (i = 0; i < ENETC_RSSHASH_KEY_SIZE / 4; i++)
> > +		((u32 *)key)[i] = enetc_port_rd(hw, base + i * 4);
> > +}
> 
> I would have expected that this refactoring of code into
> enetc_get_rss_key() would be done as part of the previous change:
> "net: enetc: make enetc_set_rss_key() reusable".
> 

I think this goes against the theme.


^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v4 net-next 07/14] net: enetc: make enetc_set_rss_key() reusable
  2025-03-17 16:26   ` Vladimir Oltean
@ 2025-03-18  4:54     ` Wei Fang
  0 siblings, 0 replies; 58+ messages in thread
From: Wei Fang @ 2025-03-18  4:54 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Claudiu Manoil, Clark Wang, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, christophe.leroy@csgroup.eu,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org

> On Tue, Mar 11, 2025 at 01:38:23PM +0800, Wei Fang wrote:
> > Since the offset of the RSS key registers of i.MX95 ENETC is different
> > from that of LS1028A, so add enetc_get_rss_key_base() to get the base
> > offset for the different chips, so that enetc_set_rss_key() can be
> > reused for this trivial.
> 
> for this trivial... ? task?

Sorry, it should be trivial thing.
> 
> >
> > Signed-off-by: Wei Fang <wei.fang@nxp.com>
> > ---
> >  drivers/net/ethernet/freescale/enetc/enetc.h  |  2 +-
> > .../net/ethernet/freescale/enetc/enetc4_pf.c  | 11 +----------
> > .../ethernet/freescale/enetc/enetc_ethtool.c  | 19 ++++++++++++++-----
> >  .../net/ethernet/freescale/enetc/enetc_pf.c   |  2 +-
> >  4 files changed, 17 insertions(+), 17 deletions(-)
> >
> > diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> > b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> > index a98ed059a83f..f991e1aae85c 100644
> > --- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> > +++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
> > @@ -583,22 +583,13 @@ static void enetc4_set_trx_frame_size(struct
> enetc_pf *pf)
> >  	enetc4_pf_reset_tc_msdu(&si->hw);
> >  }
> >
> > -static void enetc4_set_rss_key(struct enetc_hw *hw, const u8 *bytes)
> > -{
> > -	int i;
> > -
> > -	for (i = 0; i < ENETC_RSSHASH_KEY_SIZE / 4; i++)
> > -		enetc_port_wr(hw, ENETC4_PRSSKR(i), ((u32 *)bytes)[i]);
> > -}
> > -
> >  static void enetc4_set_default_rss_key(struct enetc_pf *pf)  {
> >  	u8 hash_key[ENETC_RSSHASH_KEY_SIZE] = {0};
> > -	struct enetc_hw *hw = &pf->si->hw;
> >
> >  	/* set up hash key */
> >  	get_random_bytes(hash_key, ENETC_RSSHASH_KEY_SIZE);
> > -	enetc4_set_rss_key(hw, hash_key);
> > +	enetc_set_rss_key(pf->si, hash_key);
> >  }
> 
> The entire enetc4_set_default_rss_key() seems reusable as
> enetc_set_default_rss_key(). enetc_configure_port() has the same logic.
> 

Yes, I can add enetc_set_default_rss_key() to enetc_pf_common.c

> >
> >  static void enetc4_enable_trx(struct enetc_pf *pf)

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v4 net-next 09/14] net: enetc: enable RSS feature by default
  2025-03-17 16:33   ` Vladimir Oltean
@ 2025-03-18  5:00     ` Wei Fang
  0 siblings, 0 replies; 58+ messages in thread
From: Wei Fang @ 2025-03-18  5:00 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Claudiu Manoil, Clark Wang, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, christophe.leroy@csgroup.eu,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org

> On Tue, Mar 11, 2025 at 01:38:25PM +0800, Wei Fang wrote:
> > Receive side scaling (RSS) is a network driver technology that enables
> > the efficient distribution of network receive processing across
> > multiple CPUs in multiprocessor systems. Therefore, it is better to
> > enable RSS by default so that the CPU load can be balanced and network
> > performance can be improved when then network is enabled.
> 
> s/then network/the network/
> 
> >
> > Signed-off-by: Wei Fang <wei.fang@nxp.com>
> > ---
> >  drivers/net/ethernet/freescale/enetc/enetc.c  | 35 ++++++++++---------
> >  .../freescale/enetc/enetc_pf_common.c         |  4 ++-
> >  .../net/ethernet/freescale/enetc/enetc_vf.c   |  4 ++-
> >  3 files changed, 25 insertions(+), 18 deletions(-)
> >
> > diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c
> > b/drivers/net/ethernet/freescale/enetc/enetc.c
> > index 5b5e65ac8fab..8583ac9f7b9e 100644
> > --- a/drivers/net/ethernet/freescale/enetc/enetc.c
> > +++ b/drivers/net/ethernet/freescale/enetc/enetc.c
> > @@ -2420,6 +2420,22 @@ static void enetc_set_lso_flags_mask(struct
> enetc_hw *hw)
> >  	enetc_wr(hw, ENETC4_SILSOSFMR1, 0);
> >  }
> >
> > +static int enetc_set_rss(struct net_device *ndev, int en)
> 
> Can you please add a preliminary patch which converts this function's prototype
> to:

Okay, I can add such a patch in this patch set.
> 
> static void enetc_set_rss(struct net_device *ndev, bool en) ?
> 
> After you do that please feel free to add my tag and keep it in future patch
> submissions:
> 
> Acked-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> 
> I don't see downsides to enabling RX hashing by default.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v4 net-next 06/14] net: enetc: add set/get_rss_table() to enetc_si_ops
  2025-03-17 16:42   ` Vladimir Oltean
@ 2025-03-18  5:06     ` Wei Fang
  0 siblings, 0 replies; 58+ messages in thread
From: Wei Fang @ 2025-03-18  5:06 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Claudiu Manoil, Clark Wang, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, christophe.leroy@csgroup.eu,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org

> On Tue, Mar 11, 2025 at 01:38:22PM +0800, Wei Fang wrote:
> > diff --git a/drivers/net/ethernet/freescale/enetc/enetc_vf.c
> b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
> > index d7d9a720069b..072e5b40a199 100644
> > --- a/drivers/net/ethernet/freescale/enetc/enetc_vf.c
> > +++ b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
> > @@ -165,6 +165,8 @@ static void enetc_vf_netdev_setup(struct enetc_si *si,
> struct net_device *ndev,
> >  static const struct enetc_si_ops enetc_vsi_ops = {
> >  	.setup_cbdr = enetc_setup_cbdr,
> >  	.teardown_cbdr = enetc_teardown_cbdr,
> > +	.get_rss_table = enetc_get_rss_table,
> > +	.set_rss_table = enetc_set_rss_table,
> >  };
> 
> Are the CBDR-based enetc_get_rss_table() and enetc_set_rss_table()
> the correct implementations for NETC v4 VSIs? (I guess not). Does
> the driver/hardware fail in a civilized way, or does it crash?

We have not added ENETC v4 VSI support yet, the current VSI driver
is only applicable to v1. I will add enetc4_vsi_ops when supporting
v4 VSI.


^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v4 net-next 10/14] net: enetc: move generic VLAN filter interfaces to enetc-core
  2025-03-17 17:05   ` Vladimir Oltean
@ 2025-03-18  5:12     ` Wei Fang
  0 siblings, 0 replies; 58+ messages in thread
From: Wei Fang @ 2025-03-18  5:12 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Claudiu Manoil, Clark Wang, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, christophe.leroy@csgroup.eu,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org

> On Tue, Mar 11, 2025 at 01:38:26PM +0800, Wei Fang wrote:
> > For ENETC, each SI has a corresponding VLAN hash table. That is to say,
> > both PF and VFs can support VLAN filter. However, currently only ENETC v1
> > PF driver supports VLAN filter. In order to make i.MX95 ENETC (v4) PF and
> > VF drivers also support VLAN filter, some related macros are moved from
> > enetc_pf.h to enetc.h, and the related structure variables are moved from
> > enetc_pf to enetc_si.
> >
> > Besides, enetc_vid_hash_idx() as a generic function is moved to enetc.c.
> > Extract enetc_refresh_vlan_ht_filter() from enetc_sync_vlan_ht_filter()
> > so that it can be shared by PF and VF drivers. This will make it easier
> > to add VLAN filter support for i.MX95 ENETC later.
> >
> > Signed-off-by: Wei Fang <wei.fang@nxp.com>
> > ---
> 
> In this and the next patch, can you please separate the code movement
> from the logical changes? It makes review much more difficult. With the
> similar observation that, as in the case of MAC filtering, VSIs don't
> yet support VLAN filtering, so the movement of the hash table structures
> from per-PF to per-SI is currently premature. So I expect to see that
> part removed from the next revision.

Okay, I will keep vlan_ht_filter in struct enetc_pf, and move common
interfaces to enetc_pf_common.c.


^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v4 net-next 14/14] MAINTAINERS: add new file ntmp.h to ENETC driver
  2025-03-17 17:06   ` Vladimir Oltean
@ 2025-03-18  5:13     ` Wei Fang
  0 siblings, 0 replies; 58+ messages in thread
From: Wei Fang @ 2025-03-18  5:13 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Claudiu Manoil, Clark Wang, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, christophe.leroy@csgroup.eu,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org

> On Tue, Mar 11, 2025 at 01:38:30PM +0800, Wei Fang wrote:
> > Add new file ntmp.h. to ENETC driver.
> >
> > Signed-off-by: Wei Fang <wei.fang@nxp.com>
> > ---
> >  MAINTAINERS | 1 +
> >  1 file changed, 1 insertion(+)
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS index
> > 7078199fcebf..e259b659eadb 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -9174,6 +9174,7 @@ F:
> 	Documentation/devicetree/bindings/net/nxp,netc-blk-ctrl.yaml
> >  F:	drivers/net/ethernet/freescale/enetc/
> >  F:	include/linux/fsl/enetc_mdio.h
> >  F:	include/linux/fsl/netc_global.h
> > +F:	include/linux/fsl/ntmp.h
> >
> >  FREESCALE eTSEC ETHERNET DRIVER (GIANFAR)
> >  M:	Claudiu Manoil <claudiu.manoil@nxp.com>
> > --
> > 2.34.1
> >
> 
> This should be squashed with the patch that adds the initial NTMP support.
> We don't split out patches to the MAINTAINERS file.

Okay, I will squashed it to the NTMP patch.


^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v4 net-next 04/14] net: enetc: add MAC filter for i.MX95 ENETC PF
  2025-03-17 14:18   ` Vladimir Oltean
  2025-03-18  3:19     ` Wei Fang
@ 2025-03-18  8:08     ` Claudiu Manoil
  2025-03-18  8:47       ` Vladimir Oltean
  1 sibling, 1 reply; 58+ messages in thread
From: Claudiu Manoil @ 2025-03-18  8:08 UTC (permalink / raw)
  To: Vladimir Oltean, Wei Fang
  Cc: Clark Wang, andrew+netdev@lunn.ch, davem@davemloft.net,
	edumazet@google.com, kuba@kernel.org, pabeni@redhat.com,
	christophe.leroy@csgroup.eu, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, imx@lists.linux.dev,
	linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org


> -----Original Message-----
> From: Vladimir Oltean <vladimir.oltean@nxp.com>
> Sent: Monday, March 17, 2025 4:18 PM
[...]
> Subject: Re: [PATCH v4 net-next 04/14] net: enetc: add MAC filter for i.MX95
> ENETC PF
> 
> On Tue, Mar 11, 2025 at 01:38:20PM +0800, Wei Fang wrote:
[...]
> > +static void enetc4_pf_destroy_mac_list(struct enetc_pf *pf)
> > +{
> > +	struct enetc_mac_list_entry *entry;
> > +	struct hlist_node *tmp;
> > +
> > +	mutex_lock(&pf->mac_list_lock);
> 
> The mutex_lock() usage here should raise serious questions. This is
> running right before mutex_destroy(). So if there were any concurrent
> attempt to acquire this lock, that concurrent code would have been broken
> any time it would have lost arbitration, by the fact that it would
> attempt to acquire a destroyed mutex.
> 
> But there's no such concurrent thread, because we run after destroy_workqueue()
> which flushes those concurrent calls and prevents new ones. So the mutex
> usage here is not necessary.
> 
> [ same thing with mutex_init() immediately followed by mutex_lock().
>   It is an incorrect pattern most of the time. ]
> 

This is not as bad as it seems. In the final version of the code, mutex 'mac_list_lock'
serializes the access btw the thread programming the filter for the PF instance,
and the threads programming the filter on behalf of underlying VFs (triggered by async
request from VF). But since VF support is not included in this patch set (as Wei
already mentioned) the lock can/should be added later, with the VF patches.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v4 net-next 04/14] net: enetc: add MAC filter for i.MX95 ENETC PF
  2025-03-18  8:08     ` Claudiu Manoil
@ 2025-03-18  8:47       ` Vladimir Oltean
  0 siblings, 0 replies; 58+ messages in thread
From: Vladimir Oltean @ 2025-03-18  8:47 UTC (permalink / raw)
  To: Claudiu Manoil
  Cc: Wei Fang, Clark Wang, andrew+netdev@lunn.ch, davem@davemloft.net,
	edumazet@google.com, kuba@kernel.org, pabeni@redhat.com,
	christophe.leroy@csgroup.eu, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, imx@lists.linux.dev,
	linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org

Hi Claudiu,

On Tue, Mar 18, 2025 at 10:08:24AM +0200, Claudiu Manoil wrote:
> 
> > -----Original Message-----
> > From: Vladimir Oltean <vladimir.oltean@nxp.com>
> > Sent: Monday, March 17, 2025 4:18 PM
> [...]
> > Subject: Re: [PATCH v4 net-next 04/14] net: enetc: add MAC filter for i.MX95
> > ENETC PF
> > 
> > On Tue, Mar 11, 2025 at 01:38:20PM +0800, Wei Fang wrote:
> [...]
> > > +static void enetc4_pf_destroy_mac_list(struct enetc_pf *pf)
> > > +{
> > > +	struct enetc_mac_list_entry *entry;
> > > +	struct hlist_node *tmp;
> > > +
> > > +	mutex_lock(&pf->mac_list_lock);
> > 
> > The mutex_lock() usage here should raise serious questions. This is
> > running right before mutex_destroy(). So if there were any concurrent
> > attempt to acquire this lock, that concurrent code would have been broken
> > any time it would have lost arbitration, by the fact that it would
> > attempt to acquire a destroyed mutex.
> > 
> > But there's no such concurrent thread, because we run after destroy_workqueue()
> > which flushes those concurrent calls and prevents new ones. So the mutex
> > usage here is not necessary.
> > 
> > [ same thing with mutex_init() immediately followed by mutex_lock().
> >   It is an incorrect pattern most of the time. ]
> > 
> 
> This is not as bad as it seems. In the final version of the code, mutex 'mac_list_lock'
> serializes the access btw the thread programming the filter for the PF instance,
> and the threads programming the filter on behalf of underlying VFs (triggered by async
> request from VF). But since VF support is not included in this patch set (as Wei
> already mentioned) the lock can/should be added later, with the VF patches.

We all agree that the lock is unnecessary as far as the logic presented
in this patch set is concerned, and thus should not be added.

When Wei will present new code that will make explicit serialization
necessary, we can comment more. But, I don't see how any extra logic
can change the basic fact I was pointing out in the portion that you've
quoted. Before you destroy the mutex, you need to do something that
ensures concurrent threads can no longer execute. Then, there's no point
in locking in enetc4_pf_destroy_mac_list(). I expect not to see such
locking there in future patch sets.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v4 net-next 04/14] net: enetc: add MAC filter for i.MX95 ENETC PF
  2025-03-18  3:19     ` Wei Fang
@ 2025-03-18  9:29       ` Vladimir Oltean
  2025-03-18  9:48         ` Wei Fang
  0 siblings, 1 reply; 58+ messages in thread
From: Vladimir Oltean @ 2025-03-18  9:29 UTC (permalink / raw)
  To: Wei Fang
  Cc: Claudiu Manoil, Clark Wang, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, christophe.leroy@csgroup.eu,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org

On Tue, Mar 18, 2025 at 05:19:51AM +0200, Wei Fang wrote:
> You are right, but I'm afraid of the Coverity will report an issue, because the
> pf->mac_list and pf->num_mfe are protected by the mac_list_lock in other
> functions. And enetc4_pf_destroy_mac_list() will be called in other function
> in the subsequent patches. I don't think it is unnecessary.

Sorry, but I can only take the presented code at face value. If the
Coverity tool signals an issue, you can still triage it and explain why
it is a false positive. Or, if it is a real issue, you can add locking
and provide a good justification for it. But the justification is
missing now.

> So for your question about Rx packet loss, although it is a very corner
> case, the solution I can think of is that we can use temporary MAC hash
> filters before deleting MAFT entries and delete them after adding the
> MAFT entries. Can you accept this proposal?

That sounds good. I'm thinking, for each MAC address filter, maybe you
need an information whether it is programmed to hardware as an exact
match filter or a hash filter, and make use of that functionality here:
temporarily make all filters be hash-based ones, and then see how many
you can convert to exact matches. With something like this, it should
also be easier to maximize the use of the exact match table. Currently,
AFAIU, if you have 5 MAC address filters, they will all be stored as hash
filters, even if 4 of them could have been exact matches. Maybe that can
also be improved with such extra information.

> > > +static int enetc4_pf_set_mac_exact_filter(struct enetc_pf *pf, int type)
> > > +{
> > > +	int max_num_mfe = pf->caps.mac_filter_num;
> > > +	struct net_device *ndev = pf->si->ndev;
> > > +	struct enetc_mac_addr *mac_tbl;
> > > +	struct netdev_hw_addr *ha;
> > > +	u8 si_mac[ETH_ALEN];
> > > +	int mac_cnt = 0;
> > > +	int err;
> > > +
> > > +	mac_tbl = kcalloc(max_num_mfe, sizeof(*mac_tbl), GFP_KERNEL);
> > 
> > Can't you know ahead of time, based on netdev_uc_count(), whether you
> > will have space for exact match filters, and avoid unnecessary
> > allocations if not? enetc_mac_list_is_available() seems way too late.
> 
> I can add a check before alloc mac_tbl, but enetc_mac_list_is_available()
> is still needed, because enetc4_pf_add_si_mac_exact_filter() is a common
> function for all Sis, not only for PSI.

From the way in which the discussion is progressing in the replies
above, it sounds to me like maybe this logic will change a bit more.

> > > +static int enetc4_pf_wq_task_init(struct enetc_si *si)
> > > +{
> > > +	char wq_name[24];
> > > +
> > > +	INIT_WORK(&si->rx_mode_task, enetc4_pf_do_set_rx_mode);
> > > +	snprintf(wq_name, sizeof(wq_name), "enetc-%s", pci_name(si->pdev));
> > > +	si->workqueue = create_singlethread_workqueue(wq_name);
> > > +	if (!si->workqueue)
> > > +		return -ENOMEM;
> > > +
> > > +	return 0;
> > > +}
> > 
> > Naming scheme is inconsistent here: the function is called "pf" but
> > takes "si" as argument. Same for enetc4_pf_do_set_rx_mode() where the
> > rx_mode_task is part of the station interface structure.
> 
> So change 'pf' to 'psi'?

Sounds better.

> > > +	struct hlist_head mac_list; /* MAC address filter table */
> > 
> > One thing I don't understand is why, given this implementation and
> > final effect, you even bother to keep the mac_list persistently in
> > struct enetc_pf. You have:
> > 
> > enetc4_pf_do_set_rx_mode()
> > -> enetc4_pf_flush_si_mac_exact_filter(ENETC_MAC_FILTER_TYPE_ALL)
> >    -> hlist_for_each_entry_safe(&pf->mac_list)
> >       -> enetc_mac_list_del_entry()
> > 
> > which practically deletes all &pf->mac_list elements every time.
> > So why even store them persistently in the first place? Why not just
> > create an on-stack INIT_HLIST_HEAD() list?
> 
> The enetc4_pf_add_si_mac_exact_filter() and
> enetc4_pf_add_si_mac_exact_filter() are used for all Sis, but only
> PF can access MAFT, and PSI and VSIs may share the same MAFT
> entry, so we need to store them in struct enetc_pf. Although we
> have not added VFs support yet, for such shared functions, we
> should design its implementation from the beginning, rather than
> modifying them when we add the VFs support.

Ok. We need to find a way in which the code also makes sense today
(who knows how much time will pass until VSIs are also supported in the
mainline kernel - we all hope "as soon as possible" but have to plan for
the worst). I don't disagree with the existence of &pf->mac_list,
but it seems slightly inconsistent with the fact that you rebuild it
(for now, completely, but I understand that it the future it will be
just partially) each time ndo_set_rx_mode() is called.

Are you aware of __dev_uc_sync() / __dev_mc_sync()? They are helpers
with explicit sync/unsync callbacks per address, so you don't have to
manually walk using netdev_for_each_uc_addr() / netdev_for_each_mc_addr()
each time, and instead act only on the delta. I haven't thought this
suggestion through, but with you mentioning future VSI mailbox support
for MAC filtering, maybe it is helpful if the PSI's MAC filters are also
structured in this way.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v4 net-next 04/14] net: enetc: add MAC filter for i.MX95 ENETC PF
  2025-03-18  9:29       ` Vladimir Oltean
@ 2025-03-18  9:48         ` Wei Fang
  0 siblings, 0 replies; 58+ messages in thread
From: Wei Fang @ 2025-03-18  9:48 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Claudiu Manoil, Clark Wang, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, christophe.leroy@csgroup.eu,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org

> On Tue, Mar 18, 2025 at 05:19:51AM +0200, Wei Fang wrote:
> > You are right, but I'm afraid of the Coverity will report an issue, because the
> > pf->mac_list and pf->num_mfe are protected by the mac_list_lock in other
> > functions. And enetc4_pf_destroy_mac_list() will be called in other function
> > in the subsequent patches. I don't think it is unnecessary.
> 
> Sorry, but I can only take the presented code at face value. If the
> Coverity tool signals an issue, you can still triage it and explain why
> it is a false positive. Or, if it is a real issue, you can add locking
> and provide a good justification for it. But the justification is
> missing now.
> 
> > So for your question about Rx packet loss, although it is a very corner
> > case, the solution I can think of is that we can use temporary MAC hash
> > filters before deleting MAFT entries and delete them after adding the
> > MAFT entries. Can you accept this proposal?
> 
> That sounds good. I'm thinking, for each MAC address filter, maybe you
> need an information whether it is programmed to hardware as an exact
> match filter or a hash filter, and make use of that functionality here:
> temporarily make all filters be hash-based ones, and then see how many
> you can convert to exact matches. With something like this, it should
> also be easier to maximize the use of the exact match table. Currently,
> AFAIU, if you have 5 MAC address filters, they will all be stored as hash
> filters, even if 4 of them could have been exact matches. Maybe that can
> also be improved with such extra information.
> 

Currently, I don't want to make the driver too complicated, I think if the number
of MACs exceeds the MAFT's capability, we just use hash filter. Otherwise, we
use MAFT.

> > > > +static int enetc4_pf_set_mac_exact_filter(struct enetc_pf *pf, int type)
> > > > +{
> > > > +	int max_num_mfe = pf->caps.mac_filter_num;
> > > > +	struct net_device *ndev = pf->si->ndev;
> > > > +	struct enetc_mac_addr *mac_tbl;
> > > > +	struct netdev_hw_addr *ha;
> > > > +	u8 si_mac[ETH_ALEN];
> > > > +	int mac_cnt = 0;
> > > > +	int err;
> > > > +
> > > > +	mac_tbl = kcalloc(max_num_mfe, sizeof(*mac_tbl), GFP_KERNEL);
> > >
> > > Can't you know ahead of time, based on netdev_uc_count(), whether you
> > > will have space for exact match filters, and avoid unnecessary
> > > allocations if not? enetc_mac_list_is_available() seems way too late.
> >
> > I can add a check before alloc mac_tbl, but enetc_mac_list_is_available()
> > is still needed, because enetc4_pf_add_si_mac_exact_filter() is a common
> > function for all Sis, not only for PSI.
> 
> From the way in which the discussion is progressing in the replies
> above, it sounds to me like maybe this logic will change a bit more.
> 
> > > > +static int enetc4_pf_wq_task_init(struct enetc_si *si)
> > > > +{
> > > > +	char wq_name[24];
> > > > +
> > > > +	INIT_WORK(&si->rx_mode_task, enetc4_pf_do_set_rx_mode);
> > > > +	snprintf(wq_name, sizeof(wq_name), "enetc-%s",
> pci_name(si->pdev));
> > > > +	si->workqueue = create_singlethread_workqueue(wq_name);
> > > > +	if (!si->workqueue)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	return 0;
> > > > +}
> > >
> > > Naming scheme is inconsistent here: the function is called "pf" but
> > > takes "si" as argument. Same for enetc4_pf_do_set_rx_mode() where the
> > > rx_mode_task is part of the station interface structure.
> >
> > So change 'pf' to 'psi'?
> 
> Sounds better.
> 
> > > > +	struct hlist_head mac_list; /* MAC address filter table */
> > >
> > > One thing I don't understand is why, given this implementation and
> > > final effect, you even bother to keep the mac_list persistently in
> > > struct enetc_pf. You have:
> > >
> > > enetc4_pf_do_set_rx_mode()
> > > -> enetc4_pf_flush_si_mac_exact_filter(ENETC_MAC_FILTER_TYPE_ALL)
> > >    -> hlist_for_each_entry_safe(&pf->mac_list)
> > >       -> enetc_mac_list_del_entry()
> > >
> > > which practically deletes all &pf->mac_list elements every time.
> > > So why even store them persistently in the first place? Why not just
> > > create an on-stack INIT_HLIST_HEAD() list?
> >
> > The enetc4_pf_add_si_mac_exact_filter() and
> > enetc4_pf_add_si_mac_exact_filter() are used for all Sis, but only
> > PF can access MAFT, and PSI and VSIs may share the same MAFT
> > entry, so we need to store them in struct enetc_pf. Although we
> > have not added VFs support yet, for such shared functions, we
> > should design its implementation from the beginning, rather than
> > modifying them when we add the VFs support.
> 
> Ok. We need to find a way in which the code also makes sense today
> (who knows how much time will pass until VSIs are also supported in the
> mainline kernel - we all hope "as soon as possible" but have to plan for
> the worst). I don't disagree with the existence of &pf->mac_list,
> but it seems slightly inconsistent with the fact that you rebuild it
> (for now, completely, but I understand that it the future it will be
> just partially) each time ndo_set_rx_mode() is called.
> 
> Are you aware of __dev_uc_sync() / __dev_mc_sync()? They are helpers

All I can say that I have been saw them in kernel, but I did not spend time
to study them.

> with explicit sync/unsync callbacks per address, so you don't have to
> manually walk using netdev_for_each_uc_addr() / netdev_for_each_mc_addr()
> each time, and instead act only on the delta. I haven't thought this
> suggestion through, but with you mentioning future VSI mailbox support
> for MAC filtering, maybe it is helpful if the PSI's MAC filters are also
> structured in this way.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v4 net-next 11/14] net: enetc: move generic VLAN hash filter functions to enetc_pf_common.c
  2025-03-11  5:38 ` [PATCH v4 net-next 11/14] net: enetc: move generic VLAN hash filter functions to enetc_pf_common.c Wei Fang
@ 2025-03-18 10:21   ` Vladimir Oltean
  2025-03-18 13:57     ` Wei Fang
  0 siblings, 1 reply; 58+ messages in thread
From: Vladimir Oltean @ 2025-03-18 10:21 UTC (permalink / raw)
  To: Wei Fang
  Cc: claudiu.manoil, xiaoning.wang, andrew+netdev, davem, edumazet,
	kuba, pabeni, christophe.leroy, netdev, linux-kernel, imx,
	linuxppc-dev, linux-arm-kernel

On Tue, Mar 11, 2025 at 01:38:27PM +0800, Wei Fang wrote:
> Since the VLAN hash filter of ENETC v1 and v4 is the basically same, the
> only difference is the offset of the VLAN hash filter registers. So, the
> .set_si_vlan_hash_filter() hook is added to struct enetc_pf_ops to set
> the registers of the corresponding platform.

For the RSS hash key register, you added a function which retrieves the
register base. For the VLAN hash filter, you add ops. Same problem,
different solutions?

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v4 net-next 08/14] net: enetc: add RSS support for i.MX95 ENETC PF
  2025-03-18  4:47     ` Wei Fang
@ 2025-03-18 11:43       ` Vladimir Oltean
  2025-03-18 14:00         ` Wei Fang
  0 siblings, 1 reply; 58+ messages in thread
From: Vladimir Oltean @ 2025-03-18 11:43 UTC (permalink / raw)
  To: Wei Fang
  Cc: Claudiu Manoil, Clark Wang, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, christophe.leroy@csgroup.eu,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org

On Tue, Mar 18, 2025 at 06:47:11AM +0200, Wei Fang wrote:
> > These rxnfc commands seem implemented identically to the corresponding
> > subset from enetc_get_rxnfc(). Rather than duplicating those, could you
> > rather return -EOPNOTSUPP for the unsupported ones on NETC v4, and reuse
> > enetc_get_rxnfc()?
> > 
> 
> I have explained it to Jakub in v2:
> https://lore.kernel.org/imx/PAXPR04MB8510B52B7D27640C557680B4881A2@PAXPR04MB8510.eurprd04.prod.outlook.com/
> 
> So I don't want to reuse it for ENETC v4 PF.

A detail of the review process, written in Documentation/process/6.Followthrough.rst,
is that "Andrew Morton has suggested that every review comment which does
not result in a code change should result in an additional code comment
instead; that can help future reviewers avoid the questions which came
up the first time around."

[ personal mention: it doesn't have to be a code comment but can also be
  a sentence in the commit message ]

I believe that it would be good if you could apply that suggestion for
future submissions (not only for this particular comment).

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v4 net-next 11/14] net: enetc: move generic VLAN hash filter functions to enetc_pf_common.c
  2025-03-18 10:21   ` Vladimir Oltean
@ 2025-03-18 13:57     ` Wei Fang
  0 siblings, 0 replies; 58+ messages in thread
From: Wei Fang @ 2025-03-18 13:57 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Claudiu Manoil, Clark Wang, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, christophe.leroy@csgroup.eu,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org

> On Tue, Mar 11, 2025 at 01:38:27PM +0800, Wei Fang wrote:
> > Since the VLAN hash filter of ENETC v1 and v4 is the basically same, the
> > only difference is the offset of the VLAN hash filter registers. So, the
> > .set_si_vlan_hash_filter() hook is added to struct enetc_pf_ops to set
> > the registers of the corresponding platform.
> 
> For the RSS hash key register, you added a function which retrieves the
> register base. For the VLAN hash filter, you add ops. Same problem,
> different solutions?

I thought it was a bit different, because we have a 'si' parameter, anyway,
I think it is fine to remove this ops and use the same way as RSS.


^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v4 net-next 08/14] net: enetc: add RSS support for i.MX95 ENETC PF
  2025-03-18 11:43       ` Vladimir Oltean
@ 2025-03-18 14:00         ` Wei Fang
  0 siblings, 0 replies; 58+ messages in thread
From: Wei Fang @ 2025-03-18 14:00 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Claudiu Manoil, Clark Wang, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, christophe.leroy@csgroup.eu,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org

> On Tue, Mar 18, 2025 at 06:47:11AM +0200, Wei Fang wrote:
> > > These rxnfc commands seem implemented identically to the corresponding
> > > subset from enetc_get_rxnfc(). Rather than duplicating those, could you
> > > rather return -EOPNOTSUPP for the unsupported ones on NETC v4, and
> reuse
> > > enetc_get_rxnfc()?
> > >
> >
> > I have explained it to Jakub in v2:
> >
> https://lore.kernel.org/imx/PAXPR04MB8510B52B7D27640C557680B4881A2
> @PAXPR04MB8510.eurprd04.prod.outlook.com/
> >
> > So I don't want to reuse it for ENETC v4 PF.
> 
> A detail of the review process, written in
> Documentation/process/6.Followthrough.rst,
> is that "Andrew Morton has suggested that every review comment which does
> not result in a code change should result in an additional code comment
> instead; that can help future reviewers avoid the questions which came
> up the first time around."
> 
> [ personal mention: it doesn't have to be a code comment but can also be
>   a sentence in the commit message ]
> 
> I believe that it would be good if you could apply that suggestion for
> future submissions (not only for this particular comment).

Okay, good to know this info, I will add a comments here.


^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v4 net-next 05/14] net: enetc: add debugfs interface to dump MAC filter
  2025-03-18  3:28     ` Wei Fang
@ 2025-03-18 14:54       ` Vladimir Oltean
  0 siblings, 0 replies; 58+ messages in thread
From: Vladimir Oltean @ 2025-03-18 14:54 UTC (permalink / raw)
  To: Wei Fang
  Cc: Claudiu Manoil, Clark Wang, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, christophe.leroy@csgroup.eu,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org

On Tue, Mar 18, 2025 at 05:28:56AM +0200, Wei Fang wrote:
> > On Tue, Mar 11, 2025 at 01:38:21PM +0800, Wei Fang wrote:
> > > +static void enetc_show_si_mac_hash_filter(struct seq_file *s, int i)
> > > +{
> > > +	struct enetc_si *si = s->private;
> > > +	struct enetc_hw *hw = &si->hw;
> > > +	u32 hash_h, hash_l;
> > > +
> > > +	hash_l = enetc_port_rd(hw, ENETC4_PSIUMHFR0(i));
> > > +	hash_h = enetc_port_rd(hw, ENETC4_PSIUMHFR1(i));
> > > +	seq_printf(s, "SI %d unicast MAC hash filter: 0x%08x%08x\n",
> > > +		   i, hash_h, hash_l);
> > 
> > Maybe the ":" separator between the high and low 32 bits is clearer than "x".
> 
> I want it to be presented as a full 64-bit entry. If it is in the format
> of "%08x:%08x", it may be difficult to understand which is the high
> 32-bit and which is the low 32-bit.

Ah :-/ sorry, I made a mistake. I believed you're printing a literal "x"
as a separator between the high and the low word, which made no sense
(hence my comment). But the "x" was in fact the printf format specifier
for "hexadecimal" (sorry!). What I was saying is that ":" is a clearer
separator than "x", which of course makes no sense now.

Anyway, I made a second mistake, which is that I didn't mean to suggest
":" as a separator, but ",". I had misremembered...

The reason I had made that suggestion is prior experience with phylink,
which prints link mode masks with "%*pb" (the implementation is in the
"pointer()" function in lib/vsprintf.c). This is an error message which
many users may have seen before:

[   61.800079] mv88e6085 d0032004.mdio-mii:12 sfp: validation with support 00,00000000,00000000,00000000 failed: -EINVAL

I think the semantics are also widely accepted for this format, and it's
a little bit easier on the eye. I have searched many times in the past
through enum ethtool_link_mode_bit_indices based on the bits set in this
bitmap, and others may have done that too. It's known that bit zero is
the right-most bit.

But overall, printing the 64-bit number with no separator at all is not
unacceptable, either.

^ permalink raw reply	[flat|nested] 58+ messages in thread

end of thread, other threads:[~2025-03-18 14:54 UTC | newest]

Thread overview: 58+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-03-11  5:38 [PATCH v4 net-next 00/14] Add more feautues for ENETC v4 - round 2 Wei Fang
2025-03-11  5:38 ` [PATCH v4 net-next 01/14] net: enetc: add initial netc-lib driver to support NTMP Wei Fang
2025-03-11 12:17   ` Michal Kubiak
2025-03-13 16:35   ` Vladimir Oltean
2025-03-14  3:38     ` Wei Fang
2025-03-14 12:37       ` Vladimir Oltean
2025-03-14 13:48         ` Wei Fang
2025-03-17  9:28           ` Vladimir Oltean
2025-03-17  9:55             ` Wei Fang
2025-03-17 10:00               ` Vladimir Oltean
2025-03-17 11:39                 ` Wei Fang
2025-03-11  5:38 ` [PATCH v4 net-next 02/14] net: enetc: add command BD ring support for i.MX95 ENETC Wei Fang
2025-03-11 12:22   ` Michal Kubiak
2025-03-13 16:49   ` Vladimir Oltean
2025-03-14  4:51     ` Wei Fang
2025-03-14 11:18       ` Vladimir Oltean
2025-03-14 13:56         ` Wei Fang
2025-03-11  5:38 ` [PATCH v4 net-next 03/14] net: enetc: move generic MAC filterng interfaces to enetc-core Wei Fang
2025-03-17  9:42   ` Vladimir Oltean
2025-03-17 10:00     ` Wei Fang
2025-03-11  5:38 ` [PATCH v4 net-next 04/14] net: enetc: add MAC filter for i.MX95 ENETC PF Wei Fang
2025-03-17 14:18   ` Vladimir Oltean
2025-03-18  3:19     ` Wei Fang
2025-03-18  9:29       ` Vladimir Oltean
2025-03-18  9:48         ` Wei Fang
2025-03-18  8:08     ` Claudiu Manoil
2025-03-18  8:47       ` Vladimir Oltean
2025-03-11  5:38 ` [PATCH v4 net-next 05/14] net: enetc: add debugfs interface to dump MAC filter Wei Fang
2025-03-17 14:48   ` Vladimir Oltean
2025-03-18  3:28     ` Wei Fang
2025-03-18 14:54       ` Vladimir Oltean
2025-03-11  5:38 ` [PATCH v4 net-next 06/14] net: enetc: add set/get_rss_table() to enetc_si_ops Wei Fang
2025-03-17 16:42   ` Vladimir Oltean
2025-03-18  5:06     ` Wei Fang
2025-03-11  5:38 ` [PATCH v4 net-next 07/14] net: enetc: make enetc_set_rss_key() reusable Wei Fang
2025-03-17 16:26   ` Vladimir Oltean
2025-03-18  4:54     ` Wei Fang
2025-03-11  5:38 ` [PATCH v4 net-next 08/14] net: enetc: add RSS support for i.MX95 ENETC PF Wei Fang
2025-03-17 15:55   ` Vladimir Oltean
2025-03-18  4:47     ` Wei Fang
2025-03-18 11:43       ` Vladimir Oltean
2025-03-18 14:00         ` Wei Fang
2025-03-11  5:38 ` [PATCH v4 net-next 09/14] net: enetc: enable RSS feature by default Wei Fang
2025-03-17 16:33   ` Vladimir Oltean
2025-03-18  5:00     ` Wei Fang
2025-03-11  5:38 ` [PATCH v4 net-next 10/14] net: enetc: move generic VLAN filter interfaces to enetc-core Wei Fang
2025-03-17 17:05   ` Vladimir Oltean
2025-03-18  5:12     ` Wei Fang
2025-03-11  5:38 ` [PATCH v4 net-next 11/14] net: enetc: move generic VLAN hash filter functions to enetc_pf_common.c Wei Fang
2025-03-18 10:21   ` Vladimir Oltean
2025-03-18 13:57     ` Wei Fang
2025-03-11  5:38 ` [PATCH v4 net-next 12/14] net: enetc: add VLAN filtering support for i.MX95 ENETC PF Wei Fang
2025-03-11  5:38 ` [PATCH v4 net-next 13/14] net: enetc: add loopback " Wei Fang
2025-03-11  5:38 ` [PATCH v4 net-next 14/14] MAINTAINERS: add new file ntmp.h to ENETC driver Wei Fang
2025-03-17 17:06   ` Vladimir Oltean
2025-03-18  5:13     ` Wei Fang
2025-03-13 13:50 ` [PATCH v4 net-next 00/14] Add more feautues for ENETC v4 - round 2 Vladimir Oltean
2025-03-14  1:28   ` Wei Fang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).