All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/12] staging: dpaa2-ethsw: add support for control interface traffic
@ 2019-11-05 12:34 Ioana Ciornei
  2019-11-05 12:34 ` [PATCH 01/12] staging: dpaa2-ethsw: get control interface attributes Ioana Ciornei
                   ` (12 more replies)
  0 siblings, 13 replies; 27+ messages in thread
From: Ioana Ciornei @ 2019-11-05 12:34 UTC (permalink / raw)
  To: gregkh, linux-kernel; +Cc: andrew, f.fainelli, Ioana Ciornei

This patch set adds support for Rx/Tx capabilities on switch port interfaces.
Also, control traffic is redirected through ACLs to the CPU in order to
enable proper STP protocol handling.

The control interface is comprised of 3 queues in total: Rx, Rx error and
Tx confirmation.  In this patch set we only enable Rx and Tx conf. All
switch ports share the same queues when frames are redirected to the CPU.
Information regarding the ingress switch port is passed through frame
metadata - the flow context field of the descriptor. NAPI instances are
also shared between switch net_devices and are enabled when at least on
one of the switch ports .dev_open() was called and disabled when at least
one switch port is still up.

The new feature is enabled only on MC versions greater than 10.19.0
(which is soon to be released).

Ioana Ciornei (12):
  staging: dpaa2-ethsw: get control interface attributes
  staging: dpaa2-ethsw: setup buffer pool for control traffic
  staging: dpaa2-ethsw: setup RX path rings
  staging: dpaa2-ethsw: setup dpio
  staging: dpaa2-ethsw: add ACL table at port probe
  staging: dpaa2-ethsw: add ACL entry to redirect STP to CPU
  staging: dpaa2-ethsw: seed the buffer pool
  staging: dpaa2-ethsw: handle Rx path on control interface
  staging: dpaa2-ethsw: add .ndo_start_xmit() callback
  staging: dpaa2-ethsw: enable the CTRL_IF based on the FW version
  staging: dpaa2-ethsw: enable the control interface
  staging: dpaa2-ethsw: remove control traffic from TODO file

 drivers/staging/fsl-dpaa2/ethsw/TODO       |   8 -
 drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h | 141 ++++-
 drivers/staging/fsl-dpaa2/ethsw/dpsw.c     | 365 +++++++++++
 drivers/staging/fsl-dpaa2/ethsw/dpsw.h     | 226 +++++++
 drivers/staging/fsl-dpaa2/ethsw/ethsw.c    | 964 ++++++++++++++++++++++++++++-
 drivers/staging/fsl-dpaa2/ethsw/ethsw.h    |  83 +++
 6 files changed, 1763 insertions(+), 24 deletions(-)

-- 
1.9.1


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

* [PATCH 01/12] staging: dpaa2-ethsw: get control interface attributes
  2019-11-05 12:34 [PATCH 00/12] staging: dpaa2-ethsw: add support for control interface traffic Ioana Ciornei
@ 2019-11-05 12:34 ` Ioana Ciornei
  2019-11-05 12:34 ` [PATCH 02/12] staging: dpaa2-ethsw: setup buffer pool for control traffic Ioana Ciornei
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 27+ messages in thread
From: Ioana Ciornei @ 2019-11-05 12:34 UTC (permalink / raw)
  To: gregkh, linux-kernel; +Cc: andrew, f.fainelli, Ioana Ciornei

Introduce a new structure to hold all necessary info related to an RX
queue for the control interface and populate the FQ IDs.
We only have one Rx queue and one Tx confirmation queue on the control
interface, both shared by all the switch ports.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
 drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h |  9 +++++++
 drivers/staging/fsl-dpaa2/ethsw/dpsw.c     | 31 +++++++++++++++++++++
 drivers/staging/fsl-dpaa2/ethsw/dpsw.h     | 21 +++++++++++++++
 drivers/staging/fsl-dpaa2/ethsw/ethsw.c    | 43 ++++++++++++++++++++++++++++++
 drivers/staging/fsl-dpaa2/ethsw/ethsw.h    | 15 +++++++++++
 5 files changed, 119 insertions(+)

diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
index 5e1339daa7c7..07a8178f4b37 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
@@ -69,6 +69,8 @@
 #define DPSW_CMDID_FDB_SET_LEARNING_MODE    DPSW_CMD_ID(0x088)
 #define DPSW_CMDID_FDB_DUMP                 DPSW_CMD_ID(0x08A)
 
+#define DPSW_CMDID_CTRL_IF_GET_ATTR         DPSW_CMD_ID(0x0A0)
+
 /* Macros for accessing command fields smaller than 1byte */
 #define DPSW_MASK(field)        \
 	GENMASK(DPSW_##field##_SHIFT + DPSW_##field##_SIZE - 1, \
@@ -364,6 +366,13 @@ struct dpsw_rsp_fdb_dump {
 	__le16 num_entries;
 };
 
+struct dpsw_rsp_ctrl_if_get_attr {
+	__le64 pad;
+	__le32 rx_fqid;
+	__le32 rx_err_fqid;
+	__le32 tx_err_conf_fqid;
+};
+
 struct dpsw_rsp_get_api_version {
 	__le16 version_major;
 	__le16 version_minor;
diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.c b/drivers/staging/fsl-dpaa2/ethsw/dpsw.c
index 56b0fa789a67..f093d622a0de 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/dpsw.c
+++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.c
@@ -1183,6 +1183,37 @@ int dpsw_fdb_set_learning_mode(struct fsl_mc_io *mc_io,
 }
 
 /**
+ * dpsw_ctrl_if_get_attributes() - Obtain control interface attributes
+ * @mc_io:	Pointer to MC portal's I/O object
+ * @cmd_flags:	Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token:	Token of DPSW object
+ * @attr:	Returned control interface attributes
+ *
+ * Return:	'0' on Success; Error code otherwise.
+ */
+int dpsw_ctrl_if_get_attributes(struct fsl_mc_io *mc_io, u32 cmd_flags,
+				u16 token, struct dpsw_ctrl_if_attr *attr)
+{
+	struct dpsw_rsp_ctrl_if_get_attr *rsp_params;
+	struct fsl_mc_command cmd = { 0 };
+	int err;
+
+	cmd.header = mc_encode_cmd_header(DPSW_CMDID_CTRL_IF_GET_ATTR,
+					  cmd_flags, token);
+
+	err = mc_send_command(mc_io, &cmd);
+	if (err)
+		return err;
+
+	rsp_params = (struct dpsw_rsp_ctrl_if_get_attr *)cmd.params;
+	attr->rx_fqid = le32_to_cpu(rsp_params->rx_fqid);
+	attr->rx_err_fqid = le32_to_cpu(rsp_params->rx_err_fqid);
+	attr->tx_err_conf_fqid = le32_to_cpu(rsp_params->tx_err_conf_fqid);
+
+	return 0;
+}
+
+/**
  * dpsw_get_api_version() - Get Data Path Switch API version
  * @mc_io:	Pointer to MC portal's I/O object
  * @cmd_flags:	Command flags; one or more of 'MC_CMD_FLAG_'
diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
index 25b45850925c..cae69e20490c 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
@@ -176,6 +176,27 @@ int dpsw_get_attributes(struct fsl_mc_io *mc_io,
 			struct dpsw_attr *attr);
 
 /**
+ * struct dpsw_ctrl_if_attr - Control interface attributes
+ * @rx_fqid:		Receive FQID
+ * @rx_err_fqid:	Receive error FQID
+ * @tx_err_conf_fqid:	Transmit error and confirmation FQID
+ */
+struct dpsw_ctrl_if_attr {
+	u32 rx_fqid;
+	u32 rx_err_fqid;
+	u32 tx_err_conf_fqid;
+};
+
+int dpsw_ctrl_if_get_attributes(struct fsl_mc_io *mc_io, u32 cmd_flags,
+				u16 token, struct dpsw_ctrl_if_attr *attr);
+
+enum dpsw_queue_type {
+	DPSW_QUEUE_RX,
+	DPSW_QUEUE_TX_ERR_CONF,
+	DPSW_QUEUE_RX_ERR,
+};
+
+/**
  * enum dpsw_action - Action selection for special/control frames
  * @DPSW_ACTION_DROP: Drop frame
  * @DPSW_ACTION_REDIRECT: Redirect frame to control port
diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
index 14a9eebf687e..633eff42b996 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
@@ -1357,6 +1357,43 @@ static int ethsw_register_notifier(struct device *dev)
 	return err;
 }
 
+static int ethsw_setup_fqs(struct ethsw_core *ethsw)
+{
+	struct dpsw_ctrl_if_attr ctrl_if_attr;
+	struct device *dev = ethsw->dev;
+	int i = 0;
+	int err;
+
+	err = dpsw_ctrl_if_get_attributes(ethsw->mc_io, 0, ethsw->dpsw_handle,
+					  &ctrl_if_attr);
+	if (err) {
+		dev_err(dev, "dpsw_ctrl_if_get_attributes() = %d\n", err);
+		return err;
+	}
+
+	ethsw->fq[i].fqid = ctrl_if_attr.rx_fqid;
+	ethsw->fq[i].ethsw = ethsw;
+	ethsw->fq[i++].type = DPSW_QUEUE_RX;
+
+	ethsw->fq[i].fqid = ctrl_if_attr.tx_err_conf_fqid;
+	ethsw->fq[i].ethsw = ethsw;
+	ethsw->fq[i++].type = DPSW_QUEUE_TX_ERR_CONF;
+
+	return 0;
+}
+
+static int ethsw_ctrl_if_setup(struct ethsw_core *ethsw)
+{
+	int err;
+
+	/* setup FQs for Rx and Tx Conf */
+	err = ethsw_setup_fqs(ethsw);
+	if (err)
+		return err;
+
+	return 0;
+}
+
 static int ethsw_init(struct fsl_mc_device *sw_dev)
 {
 	struct device *dev = &sw_dev->dev;
@@ -1442,6 +1479,12 @@ static int ethsw_init(struct fsl_mc_device *sw_dev)
 		goto err_close;
 	}
 
+	if (ethsw_has_ctrl_if(ethsw)) {
+		err = ethsw_ctrl_if_setup(ethsw);
+		if (err)
+			goto err_destroy_ordered_workqueue;
+	}
+
 	err = ethsw_register_notifier(dev);
 	if (err)
 		goto err_destroy_ordered_workqueue;
diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
index 3ea8a0ad8c10..3ce4ac4e84fc 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
@@ -37,10 +37,19 @@
 #define ETHSW_MAX_FRAME_LENGTH	(DPAA2_MFL - VLAN_ETH_HLEN - ETH_FCS_LEN)
 #define ETHSW_L2_MAX_FRM(mtu)	((mtu) + VLAN_ETH_HLEN + ETH_FCS_LEN)
 
+/* Number of receive queues (one RX and one TX_CONF) */
+#define ETHSW_RX_NUM_FQS		2
+
 extern const struct ethtool_ops ethsw_port_ethtool_ops;
 
 struct ethsw_core;
 
+struct ethsw_fq {
+	struct ethsw_core *ethsw;
+	enum dpsw_queue_type type;
+	u32 fqid;
+};
+
 /* Per port private data */
 struct ethsw_port_priv {
 	struct net_device	*netdev;
@@ -66,6 +75,12 @@ struct ethsw_core {
 
 	u8				vlans[VLAN_VID_MASK + 1];
 	bool				learning;
+
+	struct ethsw_fq			fq[ETHSW_RX_NUM_FQS];
 };
 
+static inline bool ethsw_has_ctrl_if(struct ethsw_core *ethsw)
+{
+	return !(ethsw->sw_attr.options & DPSW_OPT_CTRL_IF_DIS);
+}
 #endif	/* __ETHSW_H */
-- 
1.9.1


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

* [PATCH 02/12] staging: dpaa2-ethsw: setup buffer pool for control traffic
  2019-11-05 12:34 [PATCH 00/12] staging: dpaa2-ethsw: add support for control interface traffic Ioana Ciornei
  2019-11-05 12:34 ` [PATCH 01/12] staging: dpaa2-ethsw: get control interface attributes Ioana Ciornei
@ 2019-11-05 12:34 ` Ioana Ciornei
  2019-11-05 12:34 ` [PATCH 03/12] staging: dpaa2-ethsw: setup RX path rings Ioana Ciornei
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 27+ messages in thread
From: Ioana Ciornei @ 2019-11-05 12:34 UTC (permalink / raw)
  To: gregkh, linux-kernel; +Cc: andrew, f.fainelli, Ioana Ciornei

Allocate and setup a buffer pool, needed on the Rx path of the control
interface. Also, define the Rx buffer size seen by the WRIOP from the
PAGE_SIZE buffers seeded.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
 drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h | 12 ++++
 drivers/staging/fsl-dpaa2/ethsw/dpsw.c     | 31 ++++++++++
 drivers/staging/fsl-dpaa2/ethsw/dpsw.h     | 26 +++++++++
 drivers/staging/fsl-dpaa2/ethsw/ethsw.c    | 90 ++++++++++++++++++++++++++++++
 drivers/staging/fsl-dpaa2/ethsw/ethsw.h    | 10 ++++
 5 files changed, 169 insertions(+)

diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
index 07a8178f4b37..0f1f2c787e99 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
@@ -8,6 +8,8 @@
 #ifndef __FSL_DPSW_CMD_H
 #define __FSL_DPSW_CMD_H
 
+#include "dpsw.h"
+
 /* DPSW Version */
 #define DPSW_VER_MAJOR		8
 #define DPSW_VER_MINOR		1
@@ -70,6 +72,7 @@
 #define DPSW_CMDID_FDB_DUMP                 DPSW_CMD_ID(0x08A)
 
 #define DPSW_CMDID_CTRL_IF_GET_ATTR         DPSW_CMD_ID(0x0A0)
+#define DPSW_CMDID_CTRL_IF_SET_POOLS        DPSW_CMD_ID(0x0A1)
 
 /* Macros for accessing command fields smaller than 1byte */
 #define DPSW_MASK(field)        \
@@ -373,6 +376,15 @@ struct dpsw_rsp_ctrl_if_get_attr {
 	__le32 tx_err_conf_fqid;
 };
 
+#define DPSW_BACKUP_POOL(val, order)	(((val) & 0x1) << (order))
+struct dpsw_cmd_ctrl_if_set_pools {
+	u8 num_dpbp;
+	u8 backup_pool_mask;
+	__le16 pad;
+	__le32 dpbp_id[DPSW_MAX_DPBP];
+	__le16 buffer_size[DPSW_MAX_DPBP];
+};
+
 struct dpsw_rsp_get_api_version {
 	__le16 version_major;
 	__le16 version_minor;
diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.c b/drivers/staging/fsl-dpaa2/ethsw/dpsw.c
index f093d622a0de..bed7537efee5 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/dpsw.c
+++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.c
@@ -1214,6 +1214,37 @@ int dpsw_ctrl_if_get_attributes(struct fsl_mc_io *mc_io, u32 cmd_flags,
 }
 
 /**
+ * dpsw_ctrl_if_set_pools() - Set control interface buffer pools
+ * @mc_io:	Pointer to MC portal's I/O object
+ * @cmd_flags:	Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token:	Token of DPSW object
+ * @cfg:	Buffer pools configuration
+ *
+ * Return:	'0' on Success; Error code otherwise.
+ */
+int dpsw_ctrl_if_set_pools(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+			   const struct dpsw_ctrl_if_pools_cfg *cfg)
+{
+	struct dpsw_cmd_ctrl_if_set_pools *cmd_params;
+	struct fsl_mc_command cmd = { 0 };
+	int i;
+
+	cmd.header = mc_encode_cmd_header(DPSW_CMDID_CTRL_IF_SET_POOLS,
+					  cmd_flags, token);
+	cmd_params = (struct dpsw_cmd_ctrl_if_set_pools *)cmd.params;
+	cmd_params->num_dpbp = cfg->num_dpbp;
+	for (i = 0; i < DPSW_MAX_DPBP; i++) {
+		cmd_params->dpbp_id[i] = cpu_to_le32(cfg->pools[i].dpbp_id);
+		cmd_params->buffer_size[i] =
+			cpu_to_le16(cfg->pools[i].buffer_size);
+		cmd_params->backup_pool_mask |=
+			DPSW_BACKUP_POOL(cfg->pools[i].backup_pool, i);
+	}
+
+	return mc_send_command(mc_io, &cmd);
+}
+
+/**
  * dpsw_get_api_version() - Get Data Path Switch API version
  * @mc_io:	Pointer to MC portal's I/O object
  * @cmd_flags:	Command flags; one or more of 'MC_CMD_FLAG_'
diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
index cae69e20490c..9596d0ebe921 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
@@ -197,6 +197,32 @@ enum dpsw_queue_type {
 };
 
 /**
+ * Maximum number of DPBP
+ */
+#define DPSW_MAX_DPBP     8
+
+/**
+ * struct dpsw_ctrl_if_pools_cfg - Control interface buffer pools configuration
+ * @num_dpbp: Number of DPBPs
+ * @pools: Array of buffer pools parameters; The number of valid entries
+ *	must match 'num_dpbp' value
+ * @pools.dpbp_id: DPBP object ID
+ * @pools.buffer_size: Buffer size
+ * @pools.backup_pool: Backup pool
+ */
+struct dpsw_ctrl_if_pools_cfg {
+	u8 num_dpbp;
+	struct {
+		int dpbp_id;
+		u16 buffer_size;
+		int backup_pool;
+	} pools[DPSW_MAX_DPBP];
+};
+
+int dpsw_ctrl_if_set_pools(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+			   const struct dpsw_ctrl_if_pools_cfg *cfg);
+
+/**
  * enum dpsw_action - Action selection for special/control frames
  * @DPSW_ACTION_DROP: Drop frame
  * @DPSW_ACTION_REDIRECT: Redirect frame to control port
diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
index 633eff42b996..4ed335af2cc8 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
@@ -1382,6 +1382,83 @@ static int ethsw_setup_fqs(struct ethsw_core *ethsw)
 	return 0;
 }
 
+static int ethsw_setup_dpbp(struct ethsw_core *ethsw)
+{
+	struct dpsw_ctrl_if_pools_cfg dpsw_ctrl_if_pools_cfg = { 0 };
+	struct device *dev = ethsw->dev;
+	struct fsl_mc_device *dpbp_dev;
+	struct dpbp_attr dpbp_attrs;
+	int err;
+
+	err = fsl_mc_object_allocate(to_fsl_mc_device(dev), FSL_MC_POOL_DPBP,
+				     &dpbp_dev);
+	if (err) {
+		if (err == -ENXIO)
+			err = -EPROBE_DEFER;
+		else
+			dev_err(dev, "DPBP device allocation failed\n");
+		return err;
+	}
+	ethsw->dpbp_dev = dpbp_dev;
+
+	err = dpbp_open(ethsw->mc_io, 0, dpbp_dev->obj_desc.id,
+			&dpbp_dev->mc_handle);
+	if (err) {
+		dev_err(dev, "dpbp_open() failed\n");
+		goto err_open;
+	}
+
+	err = dpbp_reset(ethsw->mc_io, 0, dpbp_dev->mc_handle);
+	if (err) {
+		dev_err(dev, "dpbp_reset() failed\n");
+		goto err_reset;
+	}
+
+	err = dpbp_enable(ethsw->mc_io, 0, dpbp_dev->mc_handle);
+	if (err) {
+		dev_err(dev, "dpbp_enable() failed\n");
+		goto err_enable;
+	}
+
+	err = dpbp_get_attributes(ethsw->mc_io, 0, dpbp_dev->mc_handle,
+				  &dpbp_attrs);
+	if (err) {
+		dev_err(dev, "dpbp_get_attributes() failed\n");
+		goto err_get_attr;
+	}
+
+	dpsw_ctrl_if_pools_cfg.num_dpbp = 1;
+	dpsw_ctrl_if_pools_cfg.pools[0].dpbp_id = dpbp_attrs.id;
+	dpsw_ctrl_if_pools_cfg.pools[0].buffer_size = DPAA2_ETHSW_RX_BUF_SIZE;
+	dpsw_ctrl_if_pools_cfg.pools[0].backup_pool = 0;
+
+	err = dpsw_ctrl_if_set_pools(ethsw->mc_io, 0, ethsw->dpsw_handle,
+				     &dpsw_ctrl_if_pools_cfg);
+	if (err) {
+		dev_err(dev, "dpsw_ctrl_if_set_pools() failed\n");
+		goto err_get_attr;
+	}
+	ethsw->bpid = dpbp_attrs.id;
+
+	return 0;
+
+err_get_attr:
+	dpbp_disable(ethsw->mc_io, 0, dpbp_dev->mc_handle);
+err_enable:
+err_reset:
+	dpbp_close(ethsw->mc_io, 0, dpbp_dev->mc_handle);
+err_open:
+	fsl_mc_object_free(dpbp_dev);
+	return err;
+}
+
+static void ethsw_free_dpbp(struct ethsw_core *ethsw)
+{
+	dpbp_disable(ethsw->mc_io, 0, ethsw->dpbp_dev->mc_handle);
+	dpbp_close(ethsw->mc_io, 0, ethsw->dpbp_dev->mc_handle);
+	fsl_mc_object_free(ethsw->dpbp_dev);
+}
+
 static int ethsw_ctrl_if_setup(struct ethsw_core *ethsw)
 {
 	int err;
@@ -1391,6 +1468,11 @@ static int ethsw_ctrl_if_setup(struct ethsw_core *ethsw)
 	if (err)
 		return err;
 
+	/* setup the buffer poll needed on the Rx path */
+	err = ethsw_setup_dpbp(ethsw);
+	if (err)
+		return err;
+
 	return 0;
 }
 
@@ -1567,6 +1649,11 @@ static void ethsw_takedown(struct fsl_mc_device *sw_dev)
 		dev_warn(dev, "dpsw_close err %d\n", err);
 }
 
+static void ethsw_ctrl_if_teardown(struct ethsw_core *ethsw)
+{
+	ethsw_free_dpbp(ethsw);
+}
+
 static int ethsw_remove(struct fsl_mc_device *sw_dev)
 {
 	struct ethsw_port_priv *port_priv;
@@ -1577,6 +1664,9 @@ static int ethsw_remove(struct fsl_mc_device *sw_dev)
 	dev = &sw_dev->dev;
 	ethsw = dev_get_drvdata(dev);
 
+	if (ethsw_has_ctrl_if(ethsw))
+		ethsw_ctrl_if_teardown(ethsw);
+
 	ethsw_teardown_irqs(sw_dev);
 
 	destroy_workqueue(ethsw_owq);
diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
index 3ce4ac4e84fc..c3cfd08c21c7 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
@@ -17,6 +17,7 @@
 #include <uapi/linux/if_bridge.h>
 #include <net/switchdev.h>
 #include <linux/if_bridge.h>
+#include <linux/fsl/mc.h>
 
 #include "dpsw.h"
 
@@ -40,6 +41,13 @@
 /* Number of receive queues (one RX and one TX_CONF) */
 #define ETHSW_RX_NUM_FQS		2
 
+/* Hardware requires alignment for ingress/egress buffer addresses */
+#define DPAA2_ETHSW_RX_BUF_RAW_SIZE	PAGE_SIZE
+#define DPAA2_ETHSW_RX_BUF_TAILROOM \
+	SKB_DATA_ALIGN(sizeof(struct skb_shared_info))
+#define DPAA2_ETHSW_RX_BUF_SIZE \
+	(DPAA2_ETHSW_RX_BUF_RAW_SIZE - DPAA2_ETHSW_RX_BUF_TAILROOM)
+
 extern const struct ethtool_ops ethsw_port_ethtool_ops;
 
 struct ethsw_core;
@@ -77,6 +85,8 @@ struct ethsw_core {
 	bool				learning;
 
 	struct ethsw_fq			fq[ETHSW_RX_NUM_FQS];
+	struct fsl_mc_device		*dpbp_dev;
+	u16				bpid;
 };
 
 static inline bool ethsw_has_ctrl_if(struct ethsw_core *ethsw)
-- 
1.9.1


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

* [PATCH 03/12] staging: dpaa2-ethsw: setup RX path rings
  2019-11-05 12:34 [PATCH 00/12] staging: dpaa2-ethsw: add support for control interface traffic Ioana Ciornei
  2019-11-05 12:34 ` [PATCH 01/12] staging: dpaa2-ethsw: get control interface attributes Ioana Ciornei
  2019-11-05 12:34 ` [PATCH 02/12] staging: dpaa2-ethsw: setup buffer pool for control traffic Ioana Ciornei
@ 2019-11-05 12:34 ` Ioana Ciornei
  2019-11-05 12:34 ` [PATCH 04/12] staging: dpaa2-ethsw: setup dpio Ioana Ciornei
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 27+ messages in thread
From: Ioana Ciornei @ 2019-11-05 12:34 UTC (permalink / raw)
  To: gregkh, linux-kernel; +Cc: andrew, f.fainelli, Ioana Ciornei

On the Rx path, when a pull-dequeue operation is performed on a
software portal, available frame descriptors are put in a ring - a DMA
memory storage - for further usage. Create the needed rings for both
frame queues used on the control interface.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
 drivers/staging/fsl-dpaa2/ethsw/ethsw.c | 37 +++++++++++++++++++++++++++++++++
 drivers/staging/fsl-dpaa2/ethsw/ethsw.h |  6 ++++++
 2 files changed, 43 insertions(+)

diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
index 4ed335af2cc8..7b68eb22a951 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
@@ -1459,6 +1459,33 @@ static void ethsw_free_dpbp(struct ethsw_core *ethsw)
 	fsl_mc_object_free(ethsw->dpbp_dev);
 }
 
+static int ethsw_alloc_rings(struct ethsw_core *ethsw)
+{
+	int i;
+
+	for (i = 0; i < ETHSW_RX_NUM_FQS; i++) {
+		ethsw->fq[i].store =
+			dpaa2_io_store_create(DPAA2_ETHSW_STORE_SIZE,
+					      ethsw->dev);
+		if (!ethsw->fq[i].store) {
+			dev_err(ethsw->dev, "dpaa2_io_store_create failed\n");
+			while (--i >= 0)
+				dpaa2_io_store_destroy(ethsw->fq[i].store);
+			return -ENOMEM;
+		}
+	}
+
+	return 0;
+}
+
+static void ethsw_destroy_rings(struct ethsw_core *ethsw)
+{
+	int i;
+
+	for (i = 0; i < ETHSW_RX_NUM_FQS; i++)
+		dpaa2_io_store_destroy(ethsw->fq[i].store);
+}
+
 static int ethsw_ctrl_if_setup(struct ethsw_core *ethsw)
 {
 	int err;
@@ -1473,7 +1500,16 @@ static int ethsw_ctrl_if_setup(struct ethsw_core *ethsw)
 	if (err)
 		return err;
 
+	err = ethsw_alloc_rings(ethsw);
+	if (err)
+		goto err_free_dpbp;
+
 	return 0;
+
+err_free_dpbp:
+	ethsw_free_dpbp(ethsw);
+
+	return err;
 }
 
 static int ethsw_init(struct fsl_mc_device *sw_dev)
@@ -1651,6 +1687,7 @@ static void ethsw_takedown(struct fsl_mc_device *sw_dev)
 
 static void ethsw_ctrl_if_teardown(struct ethsw_core *ethsw)
 {
+	ethsw_destroy_rings(ethsw);
 	ethsw_free_dpbp(ethsw);
 }
 
diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
index c3cfd08c21c7..a1ca30c615d5 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
@@ -19,6 +19,8 @@
 #include <linux/if_bridge.h>
 #include <linux/fsl/mc.h>
 
+#include <soc/fsl/dpaa2-io.h>
+
 #include "dpsw.h"
 
 /* Number of IRQs supported */
@@ -48,6 +50,9 @@
 #define DPAA2_ETHSW_RX_BUF_SIZE \
 	(DPAA2_ETHSW_RX_BUF_RAW_SIZE - DPAA2_ETHSW_RX_BUF_TAILROOM)
 
+/* Dequeue store size */
+#define DPAA2_ETHSW_STORE_SIZE		16
+
 extern const struct ethtool_ops ethsw_port_ethtool_ops;
 
 struct ethsw_core;
@@ -55,6 +60,7 @@
 struct ethsw_fq {
 	struct ethsw_core *ethsw;
 	enum dpsw_queue_type type;
+	struct dpaa2_io_store *store;
 	u32 fqid;
 };
 
-- 
1.9.1


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

* [PATCH 04/12] staging: dpaa2-ethsw: setup dpio
  2019-11-05 12:34 [PATCH 00/12] staging: dpaa2-ethsw: add support for control interface traffic Ioana Ciornei
                   ` (2 preceding siblings ...)
  2019-11-05 12:34 ` [PATCH 03/12] staging: dpaa2-ethsw: setup RX path rings Ioana Ciornei
@ 2019-11-05 12:34 ` Ioana Ciornei
  2019-11-05 12:34 ` [PATCH 05/12] staging: dpaa2-ethsw: add ACL table at port probe Ioana Ciornei
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 27+ messages in thread
From: Ioana Ciornei @ 2019-11-05 12:34 UTC (permalink / raw)
  To: gregkh, linux-kernel; +Cc: andrew, f.fainelli, Ioana Ciornei

Setup interrupts on the control interface queues. We do not force an
exact affinity between the interrupts received from a specific queue and
a cpu.

Also, the DPSW object version is incremented since the
dpsw_ctrl_if_set_queue() API is introduced in the v8.4 object
(first seen in the MC 10.19.0 firmware).

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
 drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h | 17 +++++++-
 drivers/staging/fsl-dpaa2/ethsw/dpsw.c     | 33 +++++++++++++++
 drivers/staging/fsl-dpaa2/ethsw/dpsw.h     | 23 +++++++++++
 drivers/staging/fsl-dpaa2/ethsw/ethsw.c    | 65 ++++++++++++++++++++++++++++++
 drivers/staging/fsl-dpaa2/ethsw/ethsw.h    |  1 +
 5 files changed, 138 insertions(+), 1 deletion(-)

diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
index 0f1f2c787e99..ad25872a10b7 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
@@ -12,7 +12,7 @@
 
 /* DPSW Version */
 #define DPSW_VER_MAJOR		8
-#define DPSW_VER_MINOR		1
+#define DPSW_VER_MINOR		4
 
 #define DPSW_CMD_BASE_VERSION	1
 #define DPSW_CMD_ID_OFFSET	4
@@ -73,6 +73,7 @@
 
 #define DPSW_CMDID_CTRL_IF_GET_ATTR         DPSW_CMD_ID(0x0A0)
 #define DPSW_CMDID_CTRL_IF_SET_POOLS        DPSW_CMD_ID(0x0A1)
+#define DPSW_CMDID_CTRL_IF_SET_QUEUE        DPSW_CMD_ID(0x0A6)
 
 /* Macros for accessing command fields smaller than 1byte */
 #define DPSW_MASK(field)        \
@@ -385,6 +386,20 @@ struct dpsw_cmd_ctrl_if_set_pools {
 	__le16 buffer_size[DPSW_MAX_DPBP];
 };
 
+#define DPSW_DEST_TYPE_SHIFT	0
+#define DPSW_DEST_TYPE_SIZE	4
+
+struct dpsw_cmd_ctrl_if_set_queue {
+	__le32 dest_id;
+	u8 dest_priority;
+	u8 pad;
+	/* from LSB: dest_type:4 */
+	u8 dest_type;
+	u8 qtype;
+	__le64 user_ctx;
+	__le32 options;
+};
+
 struct dpsw_rsp_get_api_version {
 	__le16 version_major;
 	__le16 version_minor;
diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.c b/drivers/staging/fsl-dpaa2/ethsw/dpsw.c
index bed7537efee5..6f4d63b9f02e 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/dpsw.c
+++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.c
@@ -1245,6 +1245,39 @@ int dpsw_ctrl_if_set_pools(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
 }
 
 /**
+ * dpsw_ctrl_if_set_queue() - Set Rx queue configuration
+ * @mc_io:	Pointer to MC portal's I/O object
+ * @cmd_flags:	Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token:	Token of dpsw object
+ * @qtype:	dpsw_queue_type of the targeted queue
+ * @cfg:	Rx queue configuration
+ *
+ * Return:	'0' on Success; Error code otherwise.
+ */
+int dpsw_ctrl_if_set_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+			   enum dpsw_queue_type qtype,
+			   const struct dpsw_ctrl_if_queue_cfg *cfg)
+{
+	struct dpsw_cmd_ctrl_if_set_queue *cmd_params;
+	struct fsl_mc_command cmd = { 0 };
+
+	cmd.header = mc_encode_cmd_header(DPSW_CMDID_CTRL_IF_SET_QUEUE,
+					  cmd_flags,
+					  token);
+	cmd_params = (struct dpsw_cmd_ctrl_if_set_queue *)cmd.params;
+	cmd_params->dest_id = cpu_to_le32(cfg->dest_cfg.dest_id);
+	cmd_params->dest_priority = cfg->dest_cfg.priority;
+	cmd_params->qtype = qtype;
+	cmd_params->user_ctx = cpu_to_le64(cfg->user_ctx);
+	cmd_params->options = cpu_to_le32(cfg->options);
+	dpsw_set_field(cmd_params->dest_type,
+		       DEST_TYPE,
+		       cfg->dest_cfg.dest_type);
+
+	return mc_send_command(mc_io, &cmd);
+}
+
+/**
  * dpsw_get_api_version() - Get Data Path Switch API version
  * @mc_io:	Pointer to MC portal's I/O object
  * @cmd_flags:	Command flags; one or more of 'MC_CMD_FLAG_'
diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
index 9596d0ebe921..55b5bbac9fbd 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
@@ -222,6 +222,29 @@ struct dpsw_ctrl_if_pools_cfg {
 int dpsw_ctrl_if_set_pools(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
 			   const struct dpsw_ctrl_if_pools_cfg *cfg);
 
+#define DPSW_CTRL_IF_QUEUE_OPT_USER_CTX		0x00000001
+#define DPSW_CTRL_IF_QUEUE_OPT_DEST		0x00000002
+
+enum dpsw_ctrl_if_dest {
+	DPSW_CTRL_IF_DEST_NONE = 0,
+	DPSW_CTRL_IF_DEST_DPIO = 1,
+};
+
+struct dpsw_ctrl_if_dest_cfg {
+	enum dpsw_ctrl_if_dest dest_type;
+	int dest_id;
+	u8 priority;
+};
+
+struct dpsw_ctrl_if_queue_cfg {
+	u32 options;
+	u64 user_ctx;
+	struct dpsw_ctrl_if_dest_cfg dest_cfg;
+};
+
+int dpsw_ctrl_if_set_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+			   enum dpsw_queue_type qtype,
+			   const struct dpsw_ctrl_if_queue_cfg *cfg);
 /**
  * enum dpsw_action - Action selection for special/control frames
  * @DPSW_ACTION_DROP: Drop frame
diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
index 7b68eb22a951..125fd6ce669e 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
@@ -1486,6 +1486,64 @@ static void ethsw_destroy_rings(struct ethsw_core *ethsw)
 		dpaa2_io_store_destroy(ethsw->fq[i].store);
 }
 
+static int ethsw_setup_dpio(struct ethsw_core *ethsw)
+{
+	struct dpsw_ctrl_if_queue_cfg queue_cfg;
+	struct dpaa2_io_notification_ctx *nctx;
+	int err, i, j;
+
+	for (i = 0; i < ETHSW_RX_NUM_FQS; i++) {
+		nctx = &ethsw->fq[i].nctx;
+
+		/* Register a new software context for the FQID.
+		 * By using NULL as the first parameter, we specify that we do
+		 * not care on which cpu are interrupts received for this queue
+		 */
+		nctx->is_cdan = 0;
+		nctx->id = ethsw->fq[i].fqid;
+		nctx->desired_cpu = DPAA2_IO_ANY_CPU;
+		err = dpaa2_io_service_register(NULL, nctx, ethsw->dev);
+		if (err) {
+			err = -EPROBE_DEFER;
+			goto err_register;
+		}
+
+		queue_cfg.options = DPSW_CTRL_IF_QUEUE_OPT_DEST |
+				    DPSW_CTRL_IF_QUEUE_OPT_USER_CTX;
+		queue_cfg.dest_cfg.dest_type = DPSW_CTRL_IF_DEST_DPIO;
+		queue_cfg.dest_cfg.dest_id = nctx->dpio_id;
+		queue_cfg.dest_cfg.priority = 0;
+		queue_cfg.user_ctx = nctx->qman64;
+
+		err = dpsw_ctrl_if_set_queue(ethsw->mc_io, 0,
+					     ethsw->dpsw_handle,
+					     ethsw->fq[i].type,
+					     &queue_cfg);
+		if (err)
+			goto err_set_queue;
+	}
+
+	return 0;
+
+err_set_queue:
+	dpaa2_io_service_deregister(NULL, nctx, ethsw->dev);
+err_register:
+	for (j = 0; j < i; j++)
+		dpaa2_io_service_deregister(NULL, &ethsw->fq[j].nctx,
+					    ethsw->dev);
+
+	return err;
+}
+
+static void ethsw_free_dpio(struct ethsw_core *ethsw)
+{
+	int i;
+
+	for (i = 0; i < ETHSW_RX_NUM_FQS; i++)
+		dpaa2_io_service_deregister(NULL, &ethsw->fq[i].nctx,
+					    ethsw->dev);
+}
+
 static int ethsw_ctrl_if_setup(struct ethsw_core *ethsw)
 {
 	int err;
@@ -1504,8 +1562,14 @@ static int ethsw_ctrl_if_setup(struct ethsw_core *ethsw)
 	if (err)
 		goto err_free_dpbp;
 
+	err = ethsw_setup_dpio(ethsw);
+	if (err)
+		goto err_destroy_rings;
+
 	return 0;
 
+err_destroy_rings:
+	ethsw_destroy_rings(ethsw);
 err_free_dpbp:
 	ethsw_free_dpbp(ethsw);
 
@@ -1687,6 +1751,7 @@ static void ethsw_takedown(struct fsl_mc_device *sw_dev)
 
 static void ethsw_ctrl_if_teardown(struct ethsw_core *ethsw)
 {
+	ethsw_free_dpio(ethsw);
 	ethsw_destroy_rings(ethsw);
 	ethsw_free_dpbp(ethsw);
 }
diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
index a1ca30c615d5..e9a80cf185d7 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
@@ -60,6 +60,7 @@
 struct ethsw_fq {
 	struct ethsw_core *ethsw;
 	enum dpsw_queue_type type;
+	struct dpaa2_io_notification_ctx nctx;
 	struct dpaa2_io_store *store;
 	u32 fqid;
 };
-- 
1.9.1


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

* [PATCH 05/12] staging: dpaa2-ethsw: add ACL table at port probe
  2019-11-05 12:34 [PATCH 00/12] staging: dpaa2-ethsw: add support for control interface traffic Ioana Ciornei
                   ` (3 preceding siblings ...)
  2019-11-05 12:34 ` [PATCH 04/12] staging: dpaa2-ethsw: setup dpio Ioana Ciornei
@ 2019-11-05 12:34 ` Ioana Ciornei
  2019-11-05 12:34 ` [PATCH 06/12] staging: dpaa2-ethsw: add ACL entry to redirect STP to CPU Ioana Ciornei
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 27+ messages in thread
From: Ioana Ciornei @ 2019-11-05 12:34 UTC (permalink / raw)
  To: gregkh, linux-kernel; +Cc: andrew, f.fainelli, Ioana Ciornei

For each of the switch ports, an ACL table is created and initialized at
port probe. These tables will be used to add ACL entries to redirect
control traffic to the CPU.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
 drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h |  27 +++++++
 drivers/staging/fsl-dpaa2/ethsw/dpsw.c     | 111 +++++++++++++++++++++++++++++
 drivers/staging/fsl-dpaa2/ethsw/dpsw.h     |  30 ++++++++
 drivers/staging/fsl-dpaa2/ethsw/ethsw.c    |  44 +++++++++++-
 drivers/staging/fsl-dpaa2/ethsw/ethsw.h    |   3 +
 5 files changed, 214 insertions(+), 1 deletion(-)

diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
index ad25872a10b7..00244c6d39c9 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
@@ -71,6 +71,11 @@
 #define DPSW_CMDID_FDB_SET_LEARNING_MODE    DPSW_CMD_ID(0x088)
 #define DPSW_CMDID_FDB_DUMP                 DPSW_CMD_ID(0x08A)
 
+#define DPSW_CMDID_ACL_ADD                  DPSW_CMD_ID(0x090)
+#define DPSW_CMDID_ACL_REMOVE               DPSW_CMD_ID(0x091)
+#define DPSW_CMDID_ACL_ADD_IF               DPSW_CMD_ID(0x094)
+#define DPSW_CMDID_ACL_REMOVE_IF            DPSW_CMD_ID(0x095)
+
 #define DPSW_CMDID_CTRL_IF_GET_ATTR         DPSW_CMD_ID(0x0A0)
 #define DPSW_CMDID_CTRL_IF_SET_POOLS        DPSW_CMD_ID(0x0A1)
 #define DPSW_CMDID_CTRL_IF_SET_QUEUE        DPSW_CMD_ID(0x0A6)
@@ -400,6 +405,28 @@ struct dpsw_cmd_ctrl_if_set_queue {
 	__le32 options;
 };
 
+struct dpsw_cmd_acl_add {
+	__le16 pad;
+	__le16 max_entries;
+};
+
+struct dpsw_rsp_acl_add {
+	__le16 acl_id;
+};
+
+struct dpsw_cmd_acl_remove {
+	__le16 acl_id;
+};
+
+struct dpsw_cmd_acl_if {
+	/* cmd word 0 */
+	__le16 acl_id;
+	__le16 num_ifs;
+	__le32 pad;
+	/* cmd word 1 */
+	__le64 if_id[4];
+};
+
 struct dpsw_rsp_get_api_version {
 	__le16 version_major;
 	__le16 version_minor;
diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.c b/drivers/staging/fsl-dpaa2/ethsw/dpsw.c
index 6f4d63b9f02e..d9e27f0e9edb 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/dpsw.c
+++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.c
@@ -1278,6 +1278,117 @@ int dpsw_ctrl_if_set_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
 }
 
 /**
+ * dpsw_acl_add() - Adds ACL to L2 switch.
+ * @mc_io:	Pointer to MC portal's I/O object
+ * @cmd_flags:	Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token:	Token of DPSW object
+ * @acl_id:	Returned ACL ID, for the future reference
+ * @cfg:	ACL configuration
+ *
+ * Create Access Control List. Multiple ACLs can be created and
+ * co-exist in L2 switch
+ *
+ * Return:	'0' on Success; Error code otherwise.
+ */
+int dpsw_acl_add(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+		 u16 *acl_id, const struct dpsw_acl_cfg *cfg)
+{
+	struct dpsw_cmd_acl_add *cmd_params;
+	struct dpsw_rsp_acl_add *rsp_params;
+	struct fsl_mc_command cmd = { 0 };
+	int err;
+
+	cmd.header = mc_encode_cmd_header(DPSW_CMDID_ACL_ADD, cmd_flags, token);
+	cmd_params = (struct dpsw_cmd_acl_add *)cmd.params;
+	cmd_params->max_entries = cpu_to_le16(cfg->max_entries);
+
+	err = mc_send_command(mc_io, &cmd);
+	if (err)
+		return err;
+
+	rsp_params = (struct dpsw_rsp_acl_add *)cmd.params;
+	*acl_id = le16_to_cpu(rsp_params->acl_id);
+
+	return 0;
+}
+
+/**
+ * dpsw_acl_remove() - Removes ACL from L2 switch.
+ * @mc_io:	Pointer to MC portal's I/O object
+ * @cmd_flags:	Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token:	Token of DPSW object
+ * @acl_id:	ACL ID
+ *
+ * Return:	'0' on Success; Error code otherwise.
+ */
+int dpsw_acl_remove(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+		    u16 acl_id)
+{
+	struct dpsw_cmd_acl_remove *cmd_params;
+	struct fsl_mc_command cmd = { 0 };
+
+	cmd.header = mc_encode_cmd_header(DPSW_CMDID_ACL_REMOVE, cmd_flags,
+					  token);
+	cmd_params = (struct dpsw_cmd_acl_remove *)cmd.params;
+	cmd_params->acl_id = cpu_to_le16(acl_id);
+
+	return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_acl_add_if() - Associate interface/interfaces with ACL.
+ * @mc_io:	Pointer to MC portal's I/O object
+ * @cmd_flags:	Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token:	Token of DPSW object
+ * @acl_id:	ACL ID
+ * @cfg:	Interfaces list
+ *
+ * Return:	'0' on Success; Error code otherwise.
+ */
+int dpsw_acl_add_if(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+		    u16 acl_id, const struct dpsw_acl_if_cfg *cfg)
+{
+	struct dpsw_cmd_acl_if *cmd_params;
+	struct fsl_mc_command cmd = { 0 };
+
+	cmd.header = mc_encode_cmd_header(DPSW_CMDID_ACL_ADD_IF, cmd_flags,
+					  token);
+	cmd_params = (struct dpsw_cmd_acl_if *)cmd.params;
+	cmd_params->acl_id = cpu_to_le16(acl_id);
+	cmd_params->num_ifs = cpu_to_le16(cfg->num_ifs);
+	build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs);
+
+	return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_acl_remove_if() - De-associate interface/interfaces from ACL.
+ * @mc_io:	Pointer to MC portal's I/O object
+ * @cmd_flags:	Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token:	Token of DPSW object
+ * @acl_id:	ACL ID
+ * @cfg:	Interfaces list
+ *
+ * Return:	'0' on Success; Error code otherwise.
+ */
+int dpsw_acl_remove_if(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+		       u16 acl_id, const struct dpsw_acl_if_cfg *cfg)
+{
+	struct fsl_mc_command cmd = { 0 };
+	struct dpsw_cmd_acl_if *cmd_params;
+
+	cmd.header = mc_encode_cmd_header(DPSW_CMDID_ACL_REMOVE_IF,
+					  cmd_flags,
+					  token);
+	cmd_params = (struct dpsw_cmd_acl_if *)cmd.params;
+	cmd_params->acl_id = cpu_to_le16(acl_id);
+	cmd_params->num_ifs = cpu_to_le16(cfg->num_ifs);
+	build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs);
+
+	return mc_send_command(mc_io, &cmd);
+}
+
+/**
  * dpsw_get_api_version() - Get Data Path Switch API version
  * @mc_io:	Pointer to MC portal's I/O object
  * @cmd_flags:	Command flags; one or more of 'MC_CMD_FLAG_'
diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
index 55b5bbac9fbd..0726a5313c4e 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
@@ -645,6 +645,36 @@ struct dpsw_fdb_attr {
 	u16 max_fdb_mc_groups;
 };
 
+/**
+ * struct dpsw_acl_cfg - ACL Configuration
+ * @max_entries: Number of FDB entries
+ */
+struct dpsw_acl_cfg {
+	u16 max_entries;
+};
+
+int dpsw_acl_add(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+		 u16 *acl_id, const struct dpsw_acl_cfg *cfg);
+
+int dpsw_acl_remove(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+		    u16 acl_id);
+
+/**
+ * struct dpsw_acl_if_cfg - List of interfaces to associate with ACL table
+ * @num_ifs: Number of interfaces
+ * @if_id: List of interfaces
+ */
+struct dpsw_acl_if_cfg {
+	u16 num_ifs;
+	u16 if_id[DPSW_MAX_IF];
+};
+
+int dpsw_acl_add_if(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+		    u16 acl_id, const struct dpsw_acl_if_cfg *cfg);
+
+int dpsw_acl_remove_if(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+		       u16 acl_id, const struct dpsw_acl_if_cfg *cfg);
+
 int dpsw_get_api_version(struct fsl_mc_io *mc_io,
 			 u32 cmd_flags,
 			 u16 *major_ver,
diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
index 125fd6ce669e..f3e339c5e9a1 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
@@ -1683,9 +1683,11 @@ static int ethsw_init(struct fsl_mc_device *sw_dev)
 
 static int ethsw_port_init(struct ethsw_port_priv *port_priv, u16 port)
 {
-	struct net_device *netdev = port_priv->netdev;
 	struct ethsw_core *ethsw = port_priv->ethsw_data;
+	struct net_device *netdev = port_priv->netdev;
+	struct dpsw_acl_if_cfg acl_if_cfg;
 	struct dpsw_vlan_if_cfg vcfg;
+	struct dpsw_acl_cfg acl_cfg;
 	int err;
 
 	/* Switch starts with all ports configured to VLAN 1. Need to
@@ -1711,6 +1713,30 @@ static int ethsw_port_init(struct ethsw_port_priv *port_priv, u16 port)
 	if (err)
 		netdev_err(netdev, "dpsw_vlan_remove_if err %d\n", err);
 
+	/* create the ACL table for this particular interface */
+	acl_cfg.max_entries = DPAA2_ETHSW_PORT_MAX_ACL_ENTRIES,
+	err = dpsw_acl_add(ethsw->mc_io, 0, ethsw->dpsw_handle,
+			   &port_priv->acl_id, &acl_cfg);
+	if (err) {
+		netdev_err(netdev, "dpsw_acl_add err %d\n", err);
+		return err;
+	}
+
+	acl_if_cfg.num_ifs = 1;
+	acl_if_cfg.if_id[0] = port_priv->idx;
+	err = dpsw_acl_add_if(ethsw->mc_io, 0, ethsw->dpsw_handle,
+			      port_priv->acl_id, &acl_if_cfg);
+	if (err) {
+		netdev_err(netdev, "dpsw_acl_add_if err %d\n", err);
+		goto err_acl_add;
+	}
+
+	return 0;
+
+err_acl_add:
+	dpsw_acl_remove(ethsw->mc_io, 0, ethsw->dpsw_handle,
+			port_priv->acl_id);
+
 	return err;
 }
 
@@ -1756,6 +1782,21 @@ static void ethsw_ctrl_if_teardown(struct ethsw_core *ethsw)
 	ethsw_free_dpbp(ethsw);
 }
 
+static void ethsw_port_takedown(struct ethsw_port_priv *port_priv)
+{
+	struct dpsw_acl_if_cfg acl_if_cfg;
+
+	acl_if_cfg.num_ifs = 1,
+	acl_if_cfg.if_id[0] = port_priv->idx;
+	dpsw_acl_remove_if(port_priv->ethsw_data->mc_io, 0,
+			   port_priv->ethsw_data->dpsw_handle,
+			   port_priv->acl_id, &acl_if_cfg);
+
+	dpsw_acl_remove(port_priv->ethsw_data->mc_io, 0,
+			port_priv->ethsw_data->dpsw_handle,
+			port_priv->acl_id);
+}
+
 static int ethsw_remove(struct fsl_mc_device *sw_dev)
 {
 	struct ethsw_port_priv *port_priv;
@@ -1778,6 +1819,7 @@ static int ethsw_remove(struct fsl_mc_device *sw_dev)
 	for (i = 0; i < ethsw->sw_attr.num_ifs; i++) {
 		port_priv = ethsw->ports[i];
 		unregister_netdev(port_priv->netdev);
+		ethsw_port_takedown(port_priv);
 		free_netdev(port_priv->netdev);
 	}
 	kfree(ethsw->ports);
diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
index e9a80cf185d7..3e1da3de0ca6 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
@@ -53,6 +53,8 @@
 /* Dequeue store size */
 #define DPAA2_ETHSW_STORE_SIZE		16
 
+#define DPAA2_ETHSW_PORT_MAX_ACL_ENTRIES	16
+
 extern const struct ethtool_ops ethsw_port_ethtool_ops;
 
 struct ethsw_core;
@@ -77,6 +79,7 @@ struct ethsw_port_priv {
 	u8			vlans[VLAN_VID_MASK + 1];
 	u16			pvid;
 	struct net_device	*bridge_dev;
+	u16			acl_id;
 };
 
 /* Switch data */
-- 
1.9.1


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

* [PATCH 06/12] staging: dpaa2-ethsw: add ACL entry to redirect STP to CPU
  2019-11-05 12:34 [PATCH 00/12] staging: dpaa2-ethsw: add support for control interface traffic Ioana Ciornei
                   ` (4 preceding siblings ...)
  2019-11-05 12:34 ` [PATCH 05/12] staging: dpaa2-ethsw: add ACL table at port probe Ioana Ciornei
@ 2019-11-05 12:34 ` Ioana Ciornei
  2019-11-05 14:22   ` Andrew Lunn
  2019-11-05 12:34 ` [PATCH 07/12] staging: dpaa2-ethsw: seed the buffer pool Ioana Ciornei
                   ` (6 subsequent siblings)
  12 siblings, 1 reply; 27+ messages in thread
From: Ioana Ciornei @ 2019-11-05 12:34 UTC (permalink / raw)
  To: gregkh, linux-kernel; +Cc: andrew, f.fainelli, Ioana Ciornei

For the moment, only STP is redirected to the CPU. Add the necessary
ACL entry to match on the destination MAC address of the protocol.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
 drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h | 50 ++++++++++++++++
 drivers/staging/fsl-dpaa2/ethsw/dpsw.c     | 81 +++++++++++++++++++++++++
 drivers/staging/fsl-dpaa2/ethsw/dpsw.h     | 94 ++++++++++++++++++++++++++++++
 drivers/staging/fsl-dpaa2/ethsw/ethsw.c    | 83 +++++++++++++++++++++++++-
 drivers/staging/fsl-dpaa2/ethsw/ethsw.h    |  5 ++
 5 files changed, 311 insertions(+), 2 deletions(-)

diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
index 00244c6d39c9..7f8ad27f8db6 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
@@ -73,6 +73,7 @@
 
 #define DPSW_CMDID_ACL_ADD                  DPSW_CMD_ID(0x090)
 #define DPSW_CMDID_ACL_REMOVE               DPSW_CMD_ID(0x091)
+#define DPSW_CMDID_ACL_ADD_ENTRY            DPSW_CMD_ID(0x092)
 #define DPSW_CMDID_ACL_ADD_IF               DPSW_CMD_ID(0x094)
 #define DPSW_CMDID_ACL_REMOVE_IF            DPSW_CMD_ID(0x095)
 
@@ -418,6 +419,55 @@ struct dpsw_cmd_acl_remove {
 	__le16 acl_id;
 };
 
+struct dpsw_prep_acl_entry {
+	u8 match_l2_dest_mac[ETH_ALEN];
+	__le16 match_l2_tpid;
+
+	u8 match_l2_source_mac[ETH_ALEN];
+	__le16 match_l2_vlan_id;
+
+	__le32 match_l3_dest_ip;
+	__le32 match_l3_source_ip;
+
+	__le16 match_l4_dest_port;
+	__le16 match_l4_source_port;
+	__le16 match_l2_ether_type;
+	u8 match_l2_pcp_dei;
+	u8 match_l3_dscp;
+
+	u8 mask_l2_dest_mac[ETH_ALEN];
+	__le16 mask_l2_tpid;
+
+	u8 mask_l2_source_mac[ETH_ALEN];
+	__le16 mask_l2_vlan_id;
+
+	__le32 mask_l3_dest_ip;
+	__le32 mask_l3_source_ip;
+
+	__le16 mask_l4_dest_port;
+	__le16 mask_l4_source_port;
+	__le16 mask_l2_ether_type;
+	u8 mask_l2_pcp_dei;
+	u8 mask_l3_dscp;
+
+	u8 match_l3_protocol;
+	u8 mask_l3_protocol;
+};
+
+#define DPSW_RESULT_ACTION_SHIFT	0
+#define DPSW_RESULT_ACTION_SIZE		4
+
+struct dpsw_cmd_acl_entry {
+	__le16 acl_id;
+	__le16 result_if_id;
+	__le32 precedence;
+	/* from LSB only the first 4 bits */
+	u8 result_action;
+	u8 pad[7];
+	__le64 pad2[4];
+	__le64 key_iova;
+};
+
 struct dpsw_cmd_acl_if {
 	/* cmd word 0 */
 	__le16 acl_id;
diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.c b/drivers/staging/fsl-dpaa2/ethsw/dpsw.c
index d9e27f0e9edb..024da81226cd 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/dpsw.c
+++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.c
@@ -1336,6 +1336,87 @@ int dpsw_acl_remove(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
 }
 
 /**
+ * dpsw_acl_prepare_entry_cfg() - Prepare an ACL entry
+ * @key:		Key
+ * @entry_cfg_buf:	Zeroed 256 bytes of memory before mapping it to DMA
+ *
+ * This function has to be called before adding or removing an ACL entry
+ */
+void dpsw_acl_prepare_entry_cfg(const struct dpsw_acl_key *key,
+				u8 *entry_cfg_buf)
+{
+	struct dpsw_prep_acl_entry *entry;
+	int i;
+
+	entry = (struct dpsw_prep_acl_entry *)entry_cfg_buf;
+
+	for (i = 0; i < ETH_ALEN; i++) {
+		entry->match_l2_dest_mac[i] =
+			key->match.l2_dest_mac[ETH_ALEN - 1 - i];
+		entry->match_l2_source_mac[i] =
+			key->match.l2_source_mac[ETH_ALEN - 1 - i];
+		entry->mask_l2_dest_mac[i] =
+			key->mask.l2_dest_mac[ETH_ALEN - 1 - i];
+		entry->mask_l2_source_mac[i] =
+			key->mask.l2_source_mac[ETH_ALEN - 1 - i];
+	}
+
+	entry->match_l2_tpid = cpu_to_le16(key->match.l2_tpid);
+	entry->match_l2_vlan_id = cpu_to_le16(key->match.l2_vlan_id);
+	entry->match_l3_dest_ip = cpu_to_le32(key->match.l3_dest_ip);
+	entry->match_l3_source_ip = cpu_to_le32(key->match.l3_source_ip);
+	entry->match_l4_dest_port = cpu_to_le16(key->match.l4_dest_port);
+	entry->match_l4_source_port = cpu_to_le16(key->match.l4_source_port);
+	entry->match_l2_ether_type = cpu_to_le16(key->match.l2_ether_type);
+	entry->match_l2_pcp_dei = key->match.l2_pcp_dei;
+	entry->match_l3_dscp = key->match.l3_dscp;
+	entry->match_l3_protocol = key->match.l3_protocol;
+
+	entry->mask_l2_tpid = cpu_to_le16(key->mask.l2_tpid);
+	entry->mask_l2_vlan_id = cpu_to_le16(key->mask.l2_vlan_id);
+	entry->mask_l3_dest_ip = cpu_to_le32(key->mask.l3_dest_ip);
+	entry->mask_l3_source_ip = cpu_to_le32(key->mask.l3_source_ip);
+	entry->mask_l4_dest_port = cpu_to_le16(key->mask.l4_dest_port);
+	entry->mask_l4_source_port = cpu_to_le16(key->mask.l4_source_port);
+	entry->mask_l2_ether_type = cpu_to_le16(key->mask.l2_ether_type);
+	entry->mask_l2_pcp_dei = key->mask.l2_pcp_dei;
+	entry->mask_l3_dscp = key->mask.l3_dscp;
+	entry->mask_l3_protocol = key->mask.l3_protocol;
+}
+
+/**
+ * dpsw_acl_add_entry() - Add an entry to an ACL table
+ * @mc_io:	Pointer to MC portal's I/O object
+ * @cmd_flags:	Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token:	Token of DPSW object
+ * @acl_id:	ACL ID
+ * @cfg:	Entry configuration
+ *
+ * Warning: This function has to be called after dpsw_acl_set_entry_cfg()
+ *
+ * Return:	'0' on Success; Error code otherwise.
+ */
+int dpsw_acl_add_entry(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+		       u16 acl_id, const struct dpsw_acl_entry_cfg *cfg)
+{
+	struct dpsw_cmd_acl_entry *cmd_params;
+	struct fsl_mc_command cmd = { 0 };
+
+	cmd.header = mc_encode_cmd_header(DPSW_CMDID_ACL_ADD_ENTRY,
+					  cmd_flags,
+					  token);
+	cmd_params = (struct dpsw_cmd_acl_entry *)cmd.params;
+	cmd_params->acl_id = cpu_to_le16(acl_id);
+	cmd_params->result_if_id = cpu_to_le16(cfg->result.if_id);
+	cmd_params->precedence = cpu_to_le32(cfg->precedence);
+	dpsw_set_field(cmd_params->result_action, RESULT_ACTION,
+		       cfg->result.action);
+	cmd_params->key_iova = cpu_to_le64(cfg->key_iova);
+
+	return mc_send_command(mc_io, &cmd);
+}
+
+/**
  * dpsw_acl_add_if() - Associate interface/interfaces with ACL.
  * @mc_io:	Pointer to MC portal's I/O object
  * @cmd_flags:	Command flags; one or more of 'MC_CMD_FLAG_'
diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
index 0726a5313c4e..beacd5a56553 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
@@ -8,6 +8,8 @@
 #ifndef __FSL_DPSW_H
 #define __FSL_DPSW_H
 
+#include <linux/if_ether.h>
+
 /* Data Path L2-Switch API
  * Contains API for handling DPSW topology and functionality
  */
@@ -656,9 +658,101 @@ struct dpsw_acl_cfg {
 int dpsw_acl_add(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
 		 u16 *acl_id, const struct dpsw_acl_cfg *cfg);
 
+/**
+ * struct dpsw_acl_fields - ACL fields.
+ * @l2_dest_mac: Destination MAC address: Multicast, Broadcast, Unicast,
+ *	slow protocols (MVRP, STP)
+ * @l2_source_mac: Source MAC address
+ * @l2_tpid: Layer 2 (Ethernet) protocol type, used to identify the following
+ *	protocols: MPLS, PTP, PFC, ARP, Jumbo frames, LLDP, IEEE802.1ae,
+ *	Q-in-Q, IPv4, IPv6, PPPoE
+ * @l2_pcp_dei: indicate which protocol is encapsulated in the payload
+ * @l2_vlan_id: layer 2 VLAN ID
+ * @l2_ether_type: layer 2 Ethernet type
+ * @l3_dscp: Layer 3 differentiated services code point
+ * @l3_protocol: Tells the Network layer at the destination host, to which
+ *	Protocol this packet belongs to. The following protocol are
+ *	supported: ICMP, IGMP, IPv4 (encapsulation), TCP, IPv6
+ *	(encapsulation), GRE, PTP
+ * @l3_source_ip: Source IPv4 IP
+ * @l3_dest_ip: Destination IPv4 IP
+ * @l4_source_port: Source TCP/UDP Port
+ * @l4_dest_port: Destination TCP/UDP Port
+ */
+struct dpsw_acl_fields {
+	u8 l2_dest_mac[ETH_ALEN];
+	u8 l2_source_mac[ETH_ALEN];
+	u16 l2_tpid;
+	u8 l2_pcp_dei;
+	u16 l2_vlan_id;
+	u16 l2_ether_type;
+	u8 l3_dscp;
+	u8 l3_protocol;
+	u32 l3_source_ip;
+	u32 l3_dest_ip;
+	u16 l4_source_port;
+	u16 l4_dest_port;
+};
+
+/**
+ * struct dpsw_acl_key - ACL key
+ * @match: Match fields
+ * @mask: Mask: b'1 - valid, b'0 don't care
+ */
+struct dpsw_acl_key {
+	struct dpsw_acl_fields match;
+	struct dpsw_acl_fields mask;
+};
+
+/**
+ * enum dpsw_acl_action
+ * @DPSW_ACL_ACTION_DROP: Drop frame
+ * @DPSW_ACL_ACTION_REDIRECT: Redirect to certain port
+ * @DPSW_ACL_ACTION_ACCEPT: Accept frame
+ * @DPSW_ACL_ACTION_REDIRECT_TO_CTRL_IF: Redirect to control interface
+ */
+enum dpsw_acl_action {
+	DPSW_ACL_ACTION_DROP,
+	DPSW_ACL_ACTION_REDIRECT,
+	DPSW_ACL_ACTION_ACCEPT,
+	DPSW_ACL_ACTION_REDIRECT_TO_CTRL_IF
+};
+
+/**
+ * struct dpsw_acl_result - ACL action
+ * @action: Action should be taken when ACL entry hit
+ * @if_id:  Interface IDs to redirect frame.
+ *	Valid only if DPSW_ACL_ACTION_REDIRECT selected as action
+ */
+struct dpsw_acl_result {
+	enum dpsw_acl_action action;
+	u16 if_id;
+};
+
+/**
+ * struct dpsw_acl_entry_cfg - ACL entry
+ * @key_iova: I/O virtual address of DMA-able memory filled with key after call
+ *	to dpsw_acl_prepare_entry_cfg()
+ * @result: Required action when entry hit occurs
+ * @precedence: Precedence inside ACL. 0 is lowest. This priority can not change
+ *	during the lifetime of a policy. It is user responsibility to
+ *	space the priorities according to consequent rule additions.
+ */
+struct dpsw_acl_entry_cfg {
+	u64 key_iova;
+	struct dpsw_acl_result result;
+	int precedence;
+};
+
 int dpsw_acl_remove(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
 		    u16 acl_id);
 
+void dpsw_acl_prepare_entry_cfg(const struct dpsw_acl_key *key,
+				u8 *entry_cfg_buf);
+
+int dpsw_acl_add_entry(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+		       u16 acl_id, const struct dpsw_acl_entry_cfg *cfg);
+
 /**
  * struct dpsw_acl_if_cfg - List of interfaces to associate with ACL table
  * @num_ifs: Number of interfaces
diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
index f3e339c5e9a1..72c6f6c6e66f 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
@@ -1681,6 +1681,78 @@ static int ethsw_init(struct fsl_mc_device *sw_dev)
 	return err;
 }
 
+/* Add an ACL to redirect frames with specific destination MAC address to
+ * control interface
+ */
+static int ethsw_acl_mac_to_ctr_if(struct ethsw_port_priv *port_priv,
+				   const char *mac)
+{
+	struct device *dev = port_priv->netdev->dev.parent;
+	struct net_device *netdev = port_priv->netdev;
+	struct dpsw_acl_entry_cfg acl_entry_cfg;
+	struct dpsw_acl_fields *acl_h, *acl_m;
+	struct dpsw_acl_key acl_key;
+	u8 *cmd_buff;
+	int err = 0;
+
+	acl_h = &acl_key.match;
+	acl_m = &acl_key.mask;
+
+	if (port_priv->acl_cnt >= DPAA2_ETHSW_PORT_MAX_ACL_ENTRIES) {
+		netdev_err(netdev, "ACL table full\n");
+		return -ENOMEM;
+	}
+
+	/* Match destination MAC address */
+	memset(&acl_key, 0, sizeof(acl_key));
+	ether_addr_copy(acl_h->l2_dest_mac, mac);
+	eth_broadcast_addr(acl_m->l2_dest_mac);
+
+	cmd_buff = kzalloc(DPAA2_ETHSW_PORT_ACL_KEY_SIZE, GFP_KERNEL);
+	if (!cmd_buff)
+		return -ENOMEM;
+	dpsw_acl_prepare_entry_cfg(&acl_key, cmd_buff);
+
+	/* Add entry */
+	memset(&acl_entry_cfg, 0, sizeof(acl_entry_cfg));
+	acl_entry_cfg.precedence = port_priv->acl_cnt;
+	acl_entry_cfg.result.action = DPSW_ACL_ACTION_REDIRECT_TO_CTRL_IF;
+
+	acl_entry_cfg.key_iova = dma_map_single(dev, cmd_buff,
+						DPAA2_ETHSW_PORT_ACL_KEY_SIZE,
+						DMA_TO_DEVICE);
+	if (unlikely(dma_mapping_error(dev, acl_entry_cfg.key_iova))) {
+		netdev_err(netdev, "DMA mapping failed\n");
+		err = -EFAULT;
+		goto err_map_key;
+	}
+
+	err = dpsw_acl_add_entry(port_priv->ethsw_data->mc_io, 0,
+				 port_priv->ethsw_data->dpsw_handle,
+				 port_priv->acl_id, &acl_entry_cfg);
+	if (err) {
+		netdev_err(netdev, "dpsw_acl_add_entry() failed %d\n", err);
+		goto err_add_entry;
+	}
+
+	port_priv->acl_cnt++;
+
+err_add_entry:
+	dma_unmap_single(dev, acl_entry_cfg.key_iova,
+			 DPAA2_ETHSW_PORT_ACL_KEY_SIZE, DMA_TO_DEVICE);
+err_map_key:
+	kfree(cmd_buff);
+
+	return err;
+}
+
+static int ethsw_port_set_ctrl_if_acl(struct ethsw_port_priv *port_priv)
+{
+	const char stp_mac[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x00};
+
+	return ethsw_acl_mac_to_ctr_if(port_priv, stp_mac);
+}
+
 static int ethsw_port_init(struct ethsw_port_priv *port_priv, u16 port)
 {
 	struct ethsw_core *ethsw = port_priv->ethsw_data;
@@ -1728,12 +1800,19 @@ static int ethsw_port_init(struct ethsw_port_priv *port_priv, u16 port)
 			      port_priv->acl_id, &acl_if_cfg);
 	if (err) {
 		netdev_err(netdev, "dpsw_acl_add_if err %d\n", err);
-		goto err_acl_add;
+		goto err_remove_acl;
 	}
 
+	err = ethsw_port_set_ctrl_if_acl(port_priv);
+	if (err)
+		goto err_remove_acl_if;
+
 	return 0;
 
-err_acl_add:
+err_remove_acl_if:
+	dpsw_acl_remove_if(ethsw->mc_io, 0, ethsw->dpsw_handle,
+			   port_priv->acl_id, &acl_if_cfg);
+err_remove_acl:
 	dpsw_acl_remove(ethsw->mc_io, 0, ethsw->dpsw_handle,
 			port_priv->acl_id);
 
diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
index 3e1da3de0ca6..dfb8ce905250 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
@@ -21,6 +21,7 @@
 
 #include <soc/fsl/dpaa2-io.h>
 
+#include "dpsw-cmd.h"
 #include "dpsw.h"
 
 /* Number of IRQs supported */
@@ -53,7 +54,10 @@
 /* Dequeue store size */
 #define DPAA2_ETHSW_STORE_SIZE		16
 
+/* ACL related configuration points */
 #define DPAA2_ETHSW_PORT_MAX_ACL_ENTRIES	16
+#define DPAA2_ETHSW_PORT_ACL_KEY_SIZE \
+	sizeof(struct dpsw_prep_acl_entry)
 
 extern const struct ethtool_ops ethsw_port_ethtool_ops;
 
@@ -80,6 +84,7 @@ struct ethsw_port_priv {
 	u16			pvid;
 	struct net_device	*bridge_dev;
 	u16			acl_id;
+	u8			acl_cnt;
 };
 
 /* Switch data */
-- 
1.9.1


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

* [PATCH 07/12] staging: dpaa2-ethsw: seed the buffer pool
  2019-11-05 12:34 [PATCH 00/12] staging: dpaa2-ethsw: add support for control interface traffic Ioana Ciornei
                   ` (5 preceding siblings ...)
  2019-11-05 12:34 ` [PATCH 06/12] staging: dpaa2-ethsw: add ACL entry to redirect STP to CPU Ioana Ciornei
@ 2019-11-05 12:34 ` Ioana Ciornei
  2019-11-05 12:34 ` [PATCH 08/12] staging: dpaa2-ethsw: handle Rx path on control interface Ioana Ciornei
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 27+ messages in thread
From: Ioana Ciornei @ 2019-11-05 12:34 UTC (permalink / raw)
  To: gregkh, linux-kernel; +Cc: andrew, f.fainelli, Ioana Ciornei

Seed the buffer pool associated with the control interface at switch
probe and drain it at unbind. We allocate PAGE_SIZE buffers and release
them in the pool for the Rx path to use.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
 drivers/staging/fsl-dpaa2/ethsw/ethsw.c | 137 +++++++++++++++++++++++++++++++-
 drivers/staging/fsl-dpaa2/ethsw/ethsw.h |  14 ++++
 2 files changed, 150 insertions(+), 1 deletion(-)

diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
index 72c6f6c6e66f..53d651209feb 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
@@ -13,6 +13,7 @@
 #include <linux/msi.h>
 #include <linux/kthread.h>
 #include <linux/workqueue.h>
+#include <linux/iommu.h>
 
 #include <linux/fsl/mc.h>
 
@@ -26,6 +27,16 @@
 
 #define DEFAULT_VLAN_ID			1
 
+static void *dpaa2_iova_to_virt(struct iommu_domain *domain,
+				dma_addr_t iova_addr)
+{
+	phys_addr_t phys_addr;
+
+	phys_addr = domain ? iommu_iova_to_phys(domain, iova_addr) : iova_addr;
+
+	return phys_to_virt(phys_addr);
+}
+
 static int ethsw_add_vlan(struct ethsw_core *ethsw, u16 vid)
 {
 	int err;
@@ -1382,6 +1393,122 @@ static int ethsw_setup_fqs(struct ethsw_core *ethsw)
 	return 0;
 }
 
+/* Free buffers acquired from the buffer pool or which were meant to
+ * be released in the pool
+ */
+static void ethsw_free_bufs(struct ethsw_core *ethsw, u64 *buf_array, int count)
+{
+	struct device *dev = ethsw->dev;
+	void *vaddr;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		vaddr = dpaa2_iova_to_virt(ethsw->iommu_domain, buf_array[i]);
+		dma_unmap_page(dev, buf_array[i], DPAA2_ETHSW_RX_BUF_SIZE,
+			       DMA_BIDIRECTIONAL);
+		free_pages((unsigned long)vaddr, 0);
+	}
+}
+
+/* Perform a single release command to add buffers
+ * to the specified buffer pool
+ */
+static int ethsw_add_bufs(struct ethsw_core *ethsw, u16 bpid)
+{
+	struct device *dev = ethsw->dev;
+	u64 buf_array[BUFS_PER_CMD];
+	struct page *page;
+	int retries = 0;
+	dma_addr_t addr;
+	int err;
+	int i;
+
+	for (i = 0; i < BUFS_PER_CMD; i++) {
+		/* Allocate one page for each Rx buffer. WRIOP sees
+		 * the entire page except for a tailroom reserved for
+		 * skb shared info
+		 */
+		page = dev_alloc_pages(0);
+		if (!page) {
+			dev_err(dev, "buffer allocation failed\n");
+			goto err_alloc;
+		}
+
+		addr = dma_map_page(dev, page, 0, DPAA2_ETHSW_RX_BUF_SIZE,
+				    DMA_FROM_DEVICE);
+		if (dma_mapping_error(dev, addr)) {
+			dev_err(dev, "dma_map_single() failed\n");
+			goto err_map;
+		}
+		buf_array[i] = addr;
+	}
+
+release_bufs:
+	/* In case the portal is busy, retry until successful or
+	 * max retries hit.
+	 */
+	while ((err = dpaa2_io_service_release(NULL, bpid,
+					       buf_array, i)) == -EBUSY) {
+		if (retries++ >= DPAA2_ETHSW_SWP_BUSY_RETRIES)
+			break;
+
+		cpu_relax();
+	}
+
+	/* If release command failed, clean up and bail out.
+	 */
+	if (err) {
+		ethsw_free_bufs(ethsw, buf_array, i);
+		return 0;
+	}
+
+	return i;
+
+err_map:
+	__free_pages(page, 0);
+err_alloc:
+	/* If we managed to allocate at least some buffers,
+	 * release them to hardware
+	 */
+	if (i)
+		goto release_bufs;
+
+	return 0;
+}
+
+static int ethsw_seed_bp(struct ethsw_core *ethsw)
+{
+	int *count, i;
+
+	for (i = 0; i < DPAA2_ETHSW_NUM_BUFS; i += BUFS_PER_CMD) {
+		count = &ethsw->buf_count;
+		*count += ethsw_add_bufs(ethsw, ethsw->bpid);
+
+		if (unlikely(*count < BUFS_PER_CMD))
+			return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void ethsw_drain_bp(struct ethsw_core *ethsw)
+{
+	u64 buf_array[BUFS_PER_CMD];
+	int ret;
+
+	do {
+		ret = dpaa2_io_service_acquire(NULL, ethsw->bpid,
+					       buf_array, BUFS_PER_CMD);
+		if (ret < 0) {
+			dev_err(ethsw->dev,
+				"dpaa2_io_service_acquire() = %d\n", ret);
+			return;
+		}
+		ethsw_free_bufs(ethsw, buf_array, ret);
+
+	} while (ret);
+}
+
 static int ethsw_setup_dpbp(struct ethsw_core *ethsw)
 {
 	struct dpsw_ctrl_if_pools_cfg dpsw_ctrl_if_pools_cfg = { 0 };
@@ -1558,10 +1685,14 @@ static int ethsw_ctrl_if_setup(struct ethsw_core *ethsw)
 	if (err)
 		return err;
 
-	err = ethsw_alloc_rings(ethsw);
+	err = ethsw_seed_bp(ethsw);
 	if (err)
 		goto err_free_dpbp;
 
+	err = ethsw_alloc_rings(ethsw);
+	if (err)
+		goto err_drain_dpbp;
+
 	err = ethsw_setup_dpio(ethsw);
 	if (err)
 		goto err_destroy_rings;
@@ -1570,6 +1701,8 @@ static int ethsw_ctrl_if_setup(struct ethsw_core *ethsw)
 
 err_destroy_rings:
 	ethsw_destroy_rings(ethsw);
+err_drain_dpbp:
+	ethsw_drain_bp(ethsw);
 err_free_dpbp:
 	ethsw_free_dpbp(ethsw);
 
@@ -1858,6 +1991,7 @@ static void ethsw_ctrl_if_teardown(struct ethsw_core *ethsw)
 {
 	ethsw_free_dpio(ethsw);
 	ethsw_destroy_rings(ethsw);
+	ethsw_drain_bp(ethsw);
 	ethsw_free_dpbp(ethsw);
 }
 
@@ -1977,6 +2111,7 @@ static int ethsw_probe(struct fsl_mc_device *sw_dev)
 		return -ENOMEM;
 
 	ethsw->dev = dev;
+	ethsw->iommu_domain = iommu_get_domain_for_dev(dev);
 	dev_set_drvdata(dev, ethsw);
 
 	err = fsl_mc_portal_allocate(sw_dev, FSL_MC_IO_ATOMIC_CONTEXT_PORTAL,
diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
index dfb8ce905250..a118cb87b1c8 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
@@ -54,11 +54,23 @@
 /* Dequeue store size */
 #define DPAA2_ETHSW_STORE_SIZE		16
 
+/* Buffer management */
+#define BUFS_PER_CMD			7
+#define DPAA2_ETHSW_NUM_BUFS		(1024 * BUFS_PER_CMD)
+
 /* ACL related configuration points */
 #define DPAA2_ETHSW_PORT_MAX_ACL_ENTRIES	16
 #define DPAA2_ETHSW_PORT_ACL_KEY_SIZE \
 	sizeof(struct dpsw_prep_acl_entry)
 
+/* Number of times to retry DPIO portal operations while waiting
+ * for portal to finish executing current command and become
+ * available. We want to avoid being stuck in a while loop in case
+ * hardware becomes unresponsive, but not give up too easily if
+ * the portal really is busy for valid reasons
+ */
+#define DPAA2_ETHSW_SWP_BUSY_RETRIES	1000
+
 extern const struct ethtool_ops ethsw_port_ethtool_ops;
 
 struct ethsw_core;
@@ -95,12 +107,14 @@ struct ethsw_core {
 	struct dpsw_attr		sw_attr;
 	int				dev_id;
 	struct ethsw_port_priv		**ports;
+	struct iommu_domain		*iommu_domain;
 
 	u8				vlans[VLAN_VID_MASK + 1];
 	bool				learning;
 
 	struct ethsw_fq			fq[ETHSW_RX_NUM_FQS];
 	struct fsl_mc_device		*dpbp_dev;
+	int				buf_count;
 	u16				bpid;
 };
 
-- 
1.9.1


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

* [PATCH 08/12] staging: dpaa2-ethsw: handle Rx path on control interface
  2019-11-05 12:34 [PATCH 00/12] staging: dpaa2-ethsw: add support for control interface traffic Ioana Ciornei
                   ` (6 preceding siblings ...)
  2019-11-05 12:34 ` [PATCH 07/12] staging: dpaa2-ethsw: seed the buffer pool Ioana Ciornei
@ 2019-11-05 12:34 ` Ioana Ciornei
  2019-11-05 14:31   ` Andrew Lunn
  2019-11-05 12:34 ` [PATCH 09/12] staging: dpaa2-ethsw: add .ndo_start_xmit() callback Ioana Ciornei
                   ` (4 subsequent siblings)
  12 siblings, 1 reply; 27+ messages in thread
From: Ioana Ciornei @ 2019-11-05 12:34 UTC (permalink / raw)
  To: gregkh, linux-kernel; +Cc: andrew, f.fainelli, Ioana Ciornei

The dpaa2-ethsw supports only one Rx queue that is shared by all switch
ports. This means that information about which port was the ingress port
for a specific frame needs to be passed in metadata. In our case, the
Flow Context (FLC) field from the frame descriptor holds this
information. Besides the interface ID of the ingress port we also
receive the virtual QDID of the port. Below is a visual description of
the 64 bits of FLC.

63           47           31           15           0
+---------------------------------------------------+
|            |            |            |            |
|  RESERVED  |    IF_ID   |  RESERVED  |  IF QDID   |
|            |            |            |            |
+---------------------------------------------------+

Because all switch ports share the same Rx and Tx conf queues, NAPI
management takes into consideration when there is at least one switch
interface open to enable the NAPI instance.

The Rx path is common, for the most part, for both Rx and Tx conf with
the mention that each of them has its own consume function of a frame
descriptor. Dequeueing from a FQ, consuming dequeued store and also the
NAPI poll function is common between both queues.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
 drivers/staging/fsl-dpaa2/ethsw/ethsw.c | 311 +++++++++++++++++++++++++++++++-
 drivers/staging/fsl-dpaa2/ethsw/ethsw.h |   4 +
 2 files changed, 312 insertions(+), 3 deletions(-)

diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
index 53d651209feb..75e4b3b8c84c 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
@@ -478,9 +478,51 @@ static int port_carrier_state_sync(struct net_device *netdev)
 	return 0;
 }
 
+/* Manage all NAPI instances for the control interface.
+ *
+ * We only have one RX queue and one Tx Conf queue for all
+ * switch ports. Therefore, we only need to enable the NAPI instance once, the
+ * first time one of the switch ports runs .dev_open().
+ */
+
+static void ethsw_enable_ctrl_if_napi(struct ethsw_core *ethsw)
+{
+	int i;
+
+	/* a new interface is using the NAPI instance */
+	ethsw->napi_users++;
+
+	/* if there is already a user of the instance, return */
+	if (ethsw->napi_users > 1)
+		return;
+
+	if (!ethsw_has_ctrl_if(ethsw))
+		return;
+
+	for (i = 0; i < ETHSW_RX_NUM_FQS; i++)
+		napi_enable(&ethsw->fq[i].napi);
+}
+
+static void ethsw_disable_ctrl_if_napi(struct ethsw_core *ethsw)
+{
+	int i;
+
+	/* If we are not the last interface using the NAPI, return */
+	ethsw->napi_users--;
+	if (ethsw->napi_users)
+		return;
+
+	if (!ethsw_has_ctrl_if(ethsw))
+		return;
+
+	for (i = 0; i < ETHSW_RX_NUM_FQS; i++)
+		napi_disable(&ethsw->fq[i].napi);
+}
+
 static int port_open(struct net_device *netdev)
 {
 	struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+	struct ethsw_core *ethsw = port_priv->ethsw_data;
 	int err;
 
 	/* No need to allow Tx as control interface is disabled */
@@ -502,6 +544,8 @@ static int port_open(struct net_device *netdev)
 		goto err_carrier_sync;
 	}
 
+	ethsw_enable_ctrl_if_napi(ethsw);
+
 	return 0;
 
 err_carrier_sync:
@@ -514,6 +558,7 @@ static int port_open(struct net_device *netdev)
 static int port_stop(struct net_device *netdev)
 {
 	struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+	struct ethsw_core *ethsw = port_priv->ethsw_data;
 	int err;
 
 	err = dpsw_if_disable(port_priv->ethsw_data->mc_io, 0,
@@ -524,6 +569,8 @@ static int port_stop(struct net_device *netdev)
 		return err;
 	}
 
+	ethsw_disable_ctrl_if_napi(ethsw);
+
 	return 0;
 }
 
@@ -690,6 +737,28 @@ static int port_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
 	return err;
 }
 
+static void ethsw_free_fd(const struct ethsw_core *ethsw,
+			  const struct dpaa2_fd *fd)
+{
+	struct device *dev = ethsw->dev;
+	unsigned char *buffer_start;
+	struct sk_buff **skbh, *skb;
+	dma_addr_t fd_addr;
+
+	fd_addr = dpaa2_fd_get_addr(fd);
+	skbh = dpaa2_iova_to_virt(ethsw->iommu_domain, fd_addr);
+
+	skb = *skbh;
+	buffer_start = (unsigned char *)skbh;
+
+	dma_unmap_single(dev, fd_addr,
+			 skb_tail_pointer(skb) - buffer_start,
+			 DMA_TO_DEVICE);
+
+	/* Move on with skb release */
+	dev_kfree_skb(skb);
+}
+
 static const struct net_device_ops ethsw_port_ops = {
 	.ndo_open		= port_open,
 	.ndo_stop		= port_stop,
@@ -1368,6 +1437,104 @@ static int ethsw_register_notifier(struct device *dev)
 	return err;
 }
 
+/* Build a linear skb based on a single-buffer frame descriptor */
+static struct sk_buff *ethsw_build_linear_skb(struct ethsw_core *ethsw,
+					      const struct dpaa2_fd *fd)
+{
+	u16 fd_offset = dpaa2_fd_get_offset(fd);
+	u32 fd_length = dpaa2_fd_get_len(fd);
+	struct device *dev = ethsw->dev;
+	struct sk_buff *skb = NULL;
+	dma_addr_t addr;
+	void *fd_vaddr;
+
+	addr = dpaa2_fd_get_addr(fd);
+	dma_unmap_single(dev, addr, DPAA2_ETHSW_RX_BUF_SIZE,
+			 DMA_FROM_DEVICE);
+	fd_vaddr = dpaa2_iova_to_virt(ethsw->iommu_domain, addr);
+	prefetch(fd_vaddr + fd_offset);
+
+	skb = build_skb(fd_vaddr, DPAA2_ETHSW_RX_BUF_SIZE +
+			SKB_DATA_ALIGN(sizeof(struct skb_shared_info)));
+	if (unlikely(!skb)) {
+		dev_err(dev, "build_skb() failed\n");
+		return NULL;
+	}
+
+	skb_reserve(skb, fd_offset);
+	skb_put(skb, fd_length);
+
+	ethsw->buf_count--;
+
+	return skb;
+}
+
+static void ethsw_tx_conf(struct ethsw_fq *fq,
+			  const struct dpaa2_fd *fd)
+{
+	ethsw_free_fd(fq->ethsw, fd);
+}
+
+static void ethsw_rx(struct ethsw_fq *fq,
+		     const struct dpaa2_fd *fd)
+{
+	struct ethsw_core *ethsw = fq->ethsw;
+	struct ethsw_port_priv *port_priv;
+	struct net_device *netdev;
+	struct vlan_ethhdr *hdr;
+	struct sk_buff *skb;
+	u16 vlan_tci, vid;
+	int if_id = -1;
+	int err;
+
+	/* prefetch the frame descriptor */
+	prefetch(fd);
+
+	/* get switch ingress interface ID */
+	if_id = upper_32_bits(dpaa2_fd_get_flc(fd)) & 0x0000FFFF;
+
+	if (if_id < 0 || if_id >= ethsw->sw_attr.num_ifs) {
+		dev_err(ethsw->dev, "Frame received from unknown interface!\n");
+		goto err_free_fd;
+	}
+	port_priv = ethsw->ports[if_id];
+	netdev = port_priv->netdev;
+
+	/* build the SKB based on the FD received */
+	if (dpaa2_fd_get_format(fd) == dpaa2_fd_single) {
+		skb = ethsw_build_linear_skb(ethsw, fd);
+	} else {
+		netdev_err(netdev, "Received invalid frame format\n");
+		goto err_free_fd;
+	}
+
+	if (unlikely(!skb))
+		goto err_free_fd;
+
+	skb_reset_mac_header(skb);
+
+	/* Remove PVID from received frame */
+	hdr = vlan_eth_hdr(skb);
+	vid = ntohs(hdr->h_vlan_TCI) & VLAN_VID_MASK;
+	if (vid == port_priv->pvid) {
+		err = __skb_vlan_pop(skb, &vlan_tci);
+		if (err) {
+			dev_info(ethsw->dev, "skb_vlan_pop() failed %d", err);
+			goto err_free_fd;
+		}
+	}
+
+	skb->dev = netdev;
+	skb->protocol = eth_type_trans(skb, skb->dev);
+
+	netif_receive_skb(skb);
+
+	return;
+
+err_free_fd:
+	ethsw_free_fd(ethsw, fd);
+}
+
 static int ethsw_setup_fqs(struct ethsw_core *ethsw)
 {
 	struct dpsw_ctrl_if_attr ctrl_if_attr;
@@ -1384,11 +1551,13 @@ static int ethsw_setup_fqs(struct ethsw_core *ethsw)
 
 	ethsw->fq[i].fqid = ctrl_if_attr.rx_fqid;
 	ethsw->fq[i].ethsw = ethsw;
-	ethsw->fq[i++].type = DPSW_QUEUE_RX;
+	ethsw->fq[i].type = DPSW_QUEUE_RX;
+	ethsw->fq[i++].consume = ethsw_rx;
 
 	ethsw->fq[i].fqid = ctrl_if_attr.tx_err_conf_fqid;
 	ethsw->fq[i].ethsw = ethsw;
-	ethsw->fq[i++].type = DPSW_QUEUE_TX_ERR_CONF;
+	ethsw->fq[i].type = DPSW_QUEUE_TX_ERR_CONF;
+	ethsw->fq[i++].consume = ethsw_tx_conf;
 
 	return 0;
 }
@@ -1476,6 +1645,31 @@ static int ethsw_add_bufs(struct ethsw_core *ethsw, u16 bpid)
 	return 0;
 }
 
+static int ethsw_refill_bp(struct ethsw_core *ethsw)
+{
+	int *count = &ethsw->buf_count;
+	int new_count;
+	int err = 0;
+
+	if (unlikely(*count < DPAA2_ETHSW_REFILL_THRESH)) {
+		do {
+			new_count = ethsw_add_bufs(ethsw, ethsw->bpid);
+			if (unlikely(!new_count)) {
+				/* Out of memory; abort for now, we'll
+				 * try later on
+				 */
+				break;
+			}
+			*count += new_count;
+		} while (*count < DPAA2_ETHSW_NUM_BUFS);
+
+		if (unlikely(*count < DPAA2_ETHSW_NUM_BUFS))
+			err = -ENOMEM;
+	}
+
+	return err;
+}
+
 static int ethsw_seed_bp(struct ethsw_core *ethsw)
 {
 	int *count, i;
@@ -1613,6 +1807,106 @@ static void ethsw_destroy_rings(struct ethsw_core *ethsw)
 		dpaa2_io_store_destroy(ethsw->fq[i].store);
 }
 
+static int ethsw_pull_fq(struct ethsw_fq *fq)
+{
+	int err, retries = 0;
+
+	/* Try to pull from the FQ while the portal is busy and we didn't hit
+	 * the maximum number fo retries
+	 */
+	do {
+		err = dpaa2_io_service_pull_fq(NULL,
+					       fq->fqid,
+					       fq->store);
+		cpu_relax();
+	} while (err == -EBUSY && retries++ < DPAA2_ETHSW_SWP_BUSY_RETRIES);
+
+	if (unlikely(err))
+		dev_err(fq->ethsw->dev, "dpaa2_io_service_pull err %d", err);
+
+	return err;
+}
+
+/* Consume all frames pull-dequeued into the store */
+static int ethsw_store_consume(struct ethsw_fq *fq)
+{
+	struct ethsw_core *ethsw = fq->ethsw;
+	int cleaned = 0, is_last;
+	struct dpaa2_dq *dq;
+	int retries = 0;
+
+	do {
+		/* Get the next available FD from the store */
+		dq = dpaa2_io_store_next(fq->store, &is_last);
+		if (unlikely(!dq)) {
+			if (retries++ >= DPAA2_ETHSW_SWP_BUSY_RETRIES) {
+				dev_err_once(ethsw->dev,
+					     "No valid dequeue response\n");
+				return -ETIMEDOUT;
+			}
+			continue;
+		}
+
+		/* Process the FD */
+		fq->consume(fq, dpaa2_dq_fd(dq));
+		cleaned++;
+
+	} while (!is_last);
+
+	return cleaned;
+}
+
+/* NAPI poll routine */
+static int ethsw_poll(struct napi_struct *napi, int budget)
+{
+	int err, cleaned = 0, store_cleaned, work_done;
+	struct ethsw_fq *fq;
+	int retries = 0;
+
+	fq = container_of(napi, struct ethsw_fq, napi);
+
+	do {
+		err = ethsw_pull_fq(fq);
+		if (unlikely(err))
+			break;
+
+		/* Refill pool if appropriate */
+		ethsw_refill_bp(fq->ethsw);
+
+		store_cleaned = ethsw_store_consume(fq);
+		cleaned += store_cleaned;
+
+		if (cleaned >= budget) {
+			work_done = budget;
+			goto out;
+		}
+
+	} while (store_cleaned);
+
+	/* We didn't consume entire budget, so finish napi and
+	 * re-enable data availability notifications
+	 */
+	napi_complete_done(napi, cleaned);
+	do {
+		err = dpaa2_io_service_rearm(NULL, &fq->nctx);
+		cpu_relax();
+	} while (err == -EBUSY && retries++ < DPAA2_ETHSW_SWP_BUSY_RETRIES);
+
+	work_done = max(cleaned, 1);
+out:
+
+	return work_done;
+}
+
+static void ethsw_fqdan_cb(struct dpaa2_io_notification_ctx *nctx)
+{
+	struct ethsw_fq *fq;
+
+	fq = container_of(nctx, struct ethsw_fq, nctx);
+
+	napi_schedule_irqoff(&fq->napi);
+}
+
 static int ethsw_setup_dpio(struct ethsw_core *ethsw)
 {
 	struct dpsw_ctrl_if_queue_cfg queue_cfg;
@@ -1629,6 +1923,7 @@ static int ethsw_setup_dpio(struct ethsw_core *ethsw)
 		nctx->is_cdan = 0;
 		nctx->id = ethsw->fq[i].fqid;
 		nctx->desired_cpu = DPAA2_IO_ANY_CPU;
+		nctx->cb = ethsw_fqdan_cb;
 		err = dpaa2_io_service_register(NULL, nctx, ethsw->dev);
 		if (err) {
 			err = -EPROBE_DEFER;
@@ -1850,7 +2145,6 @@ static int ethsw_acl_mac_to_ctr_if(struct ethsw_port_priv *port_priv,
 	memset(&acl_entry_cfg, 0, sizeof(acl_entry_cfg));
 	acl_entry_cfg.precedence = port_priv->acl_cnt;
 	acl_entry_cfg.result.action = DPSW_ACL_ACTION_REDIRECT_TO_CTRL_IF;
-
 	acl_entry_cfg.key_iova = dma_map_single(dev, cmd_buff,
 						DPAA2_ETHSW_PORT_ACL_KEY_SIZE,
 						DMA_TO_DEVICE);
@@ -2147,6 +2441,17 @@ static int ethsw_probe(struct fsl_mc_device *sw_dev)
 			goto err_free_ports;
 	}
 
+	/* Add a NAPI instance for each of the Rx queues. The first port's
+	 * net_device will be associated with the instances since we do not have
+	 * different queues for each switch ports.
+	 */
+	if (ethsw_has_ctrl_if(ethsw)) {
+		for (i = 0; i < ETHSW_RX_NUM_FQS; i++)
+			netif_napi_add(ethsw->ports[0]->netdev,
+				       &ethsw->fq[i].napi, ethsw_poll,
+				       NAPI_POLL_WEIGHT);
+	}
+
 	err = dpsw_enable(ethsw->mc_io, 0, ethsw->dpsw_handle);
 	if (err) {
 		dev_err(ethsw->dev, "dpsw_enable err %d\n", err);
diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
index a118cb87b1c8..b585d06be105 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
@@ -57,6 +57,7 @@
 /* Buffer management */
 #define BUFS_PER_CMD			7
 #define DPAA2_ETHSW_NUM_BUFS		(1024 * BUFS_PER_CMD)
+#define DPAA2_ETHSW_REFILL_THRESH	(DPAA2_ETHSW_NUM_BUFS * 5 / 6)
 
 /* ACL related configuration points */
 #define DPAA2_ETHSW_PORT_MAX_ACL_ENTRIES	16
@@ -76,10 +77,12 @@
 struct ethsw_core;
 
 struct ethsw_fq {
+	void (*consume)(struct ethsw_fq *fq, const struct dpaa2_fd *fd);
 	struct ethsw_core *ethsw;
 	enum dpsw_queue_type type;
 	struct dpaa2_io_notification_ctx nctx;
 	struct dpaa2_io_store *store;
+	struct napi_struct napi;
 	u32 fqid;
 };
 
@@ -116,6 +119,7 @@ struct ethsw_core {
 	struct fsl_mc_device		*dpbp_dev;
 	int				buf_count;
 	u16				bpid;
+	int				napi_users;
 };
 
 static inline bool ethsw_has_ctrl_if(struct ethsw_core *ethsw)
-- 
1.9.1


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

* [PATCH 09/12] staging: dpaa2-ethsw: add .ndo_start_xmit() callback
  2019-11-05 12:34 [PATCH 00/12] staging: dpaa2-ethsw: add support for control interface traffic Ioana Ciornei
                   ` (7 preceding siblings ...)
  2019-11-05 12:34 ` [PATCH 08/12] staging: dpaa2-ethsw: handle Rx path on control interface Ioana Ciornei
@ 2019-11-05 12:34 ` Ioana Ciornei
  2019-11-05 12:34 ` [PATCH 10/12] staging: dpaa2-ethsw: enable the CTRL_IF based on the FW version Ioana Ciornei
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 27+ messages in thread
From: Ioana Ciornei @ 2019-11-05 12:34 UTC (permalink / raw)
  To: gregkh, linux-kernel; +Cc: andrew, f.fainelli, Ioana Ciornei

Implement the .ndo_start_xmit() callback for the switch port interfaces.
For each of the switch ports, gather the corresponding queue
destination ID (QDID) necessary for Tx enqueueing.

We'll reserve 64 bytes for software annotations, where we keep a skb
backpointer used on the Tx confirmation side for releasing the allocated
memory. At the moment, we only support linear skbs.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
 drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h |  24 +++++
 drivers/staging/fsl-dpaa2/ethsw/dpsw.c     |  41 ++++++++
 drivers/staging/fsl-dpaa2/ethsw/dpsw.h     |  27 ++++++
 drivers/staging/fsl-dpaa2/ethsw/ethsw.c    | 144 ++++++++++++++++++++++++++---
 drivers/staging/fsl-dpaa2/ethsw/ethsw.h    |  14 +++
 5 files changed, 236 insertions(+), 14 deletions(-)

diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
index 7f8ad27f8db6..4eab09fb2488 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
@@ -45,6 +45,8 @@
 #define DPSW_CMDID_IF_ENABLE                DPSW_CMD_ID(0x03D)
 #define DPSW_CMDID_IF_DISABLE               DPSW_CMD_ID(0x03E)
 
+#define DPSW_CMDID_IF_GET_ATTR              DPSW_CMD_ID(0x042)
+
 #define DPSW_CMDID_IF_SET_MAX_FRAME_LENGTH  DPSW_CMD_ID(0x044)
 
 #define DPSW_CMDID_IF_GET_LINK_STATE        DPSW_CMD_ID(0x046)
@@ -260,6 +262,28 @@ struct dpsw_cmd_if {
 	__le16 if_id;
 };
 
+#define DPSW_ADMIT_UNTAGGED_SHIFT	0
+#define DPSW_ADMIT_UNTAGGED_SIZE	4
+#define DPSW_ENABLED_SHIFT		5
+#define DPSW_ENABLED_SIZE		1
+#define DPSW_ACCEPT_ALL_VLAN_SHIFT	6
+#define DPSW_ACCEPT_ALL_VLAN_SIZE	1
+
+struct dpsw_rsp_if_get_attr {
+	/* cmd word 0 */
+	/* from LSB: admit_untagged:4 enabled:1 accept_all_vlan:1 */
+	u8 conf;
+	u8 pad1;
+	u8 num_tcs;
+	u8 pad2;
+	__le16 qdid;
+	/* cmd word 1 */
+	__le32 options;
+	__le32 pad3;
+	/* cmd word 2 */
+	__le32 rate;
+};
+
 struct dpsw_cmd_if_set_max_frame_length {
 	__le16 if_id;
 	__le16 frame_length;
diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.c b/drivers/staging/fsl-dpaa2/ethsw/dpsw.c
index 024da81226cd..aebf2a0f4e03 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/dpsw.c
+++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.c
@@ -705,6 +705,47 @@ int dpsw_if_disable(struct fsl_mc_io *mc_io,
 }
 
 /**
+ * dpsw_if_get_attributes() - Function obtains attributes of interface
+ * @mc_io:	Pointer to MC portal's I/O object
+ * @cmd_flags:	Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token:	Token of DPSW object
+ * @if_id:	Interface Identifier
+ * @attr:	Returned interface attributes
+ *
+ * Return:	Completion status. '0' on Success; Error code otherwise.
+ */
+int dpsw_if_get_attributes(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+			   u16 if_id, struct dpsw_if_attr *attr)
+{
+	struct dpsw_rsp_if_get_attr *rsp_params;
+	struct fsl_mc_command cmd = { 0 };
+	struct dpsw_cmd_if *cmd_params;
+	int err;
+
+	cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_GET_ATTR, cmd_flags,
+					  token);
+	cmd_params = (struct dpsw_cmd_if *)cmd.params;
+	cmd_params->if_id = cpu_to_le16(if_id);
+
+	err = mc_send_command(mc_io, &cmd);
+	if (err)
+		return err;
+
+	rsp_params = (struct dpsw_rsp_if_get_attr *)cmd.params;
+	attr->num_tcs = rsp_params->num_tcs;
+	attr->rate = le32_to_cpu(rsp_params->rate);
+	attr->options = le32_to_cpu(rsp_params->options);
+	attr->qdid = le16_to_cpu(rsp_params->qdid);
+	attr->enabled = dpsw_get_field(rsp_params->conf, ENABLED);
+	attr->accept_all_vlan = dpsw_get_field(rsp_params->conf,
+					       ACCEPT_ALL_VLAN);
+	attr->admit_untagged = dpsw_get_field(rsp_params->conf,
+					      ADMIT_UNTAGGED);
+
+	return 0;
+}
+
+/**
  * dpsw_if_set_max_frame_length() - Set Maximum Receive frame length.
  * @mc_io:		Pointer to MC portal's I/O object
  * @cmd_flags:		Command flags; one or more of 'MC_CMD_FLAG_'
diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
index beacd5a56553..f22f5ad4448a 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
@@ -441,6 +441,33 @@ int dpsw_if_disable(struct fsl_mc_io *mc_io,
 		    u32 cmd_flags,
 		    u16 token,
 		    u16 if_id);
+/**
+ * struct dpsw_if_attr - Structure representing DPSW interface attributes
+ * @num_tcs: Number of traffic classes
+ * @rate: Transmit rate in bits per second
+ * @options: Interface configuration options (bitmap)
+ * @enabled: Indicates if interface is enabled
+ * @accept_all_vlan: The device discards/accepts incoming frames
+ *		for VLANs that do not include this interface
+ * @admit_untagged: When set to 'DPSW_ADMIT_ONLY_VLAN_TAGGED', the device
+ *		discards untagged frames or priority-tagged frames received on
+ *		this interface;
+ *		When set to 'DPSW_ADMIT_ALL', untagged frames or priority-
+ *		tagged frames received on this interface are accepted
+ * @qdid: control frames transmit qdid
+ */
+struct dpsw_if_attr {
+	u8 num_tcs;
+	u32 rate;
+	u32 options;
+	int enabled;
+	int accept_all_vlan;
+	enum dpsw_accepted_frames admit_untagged;
+	u16 qdid;
+};
+
+int dpsw_if_get_attributes(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
+			   u16 if_id, struct dpsw_if_attr *attr);
 
 int dpsw_if_set_max_frame_length(struct fsl_mc_io *mc_io,
 				 u32 cmd_flags,
diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
index 75e4b3b8c84c..abe920f8a665 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
@@ -455,6 +455,7 @@ static int port_change_mtu(struct net_device *netdev, int mtu)
 static int port_carrier_state_sync(struct net_device *netdev)
 {
 	struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+	struct ethsw_core *ethsw = port_priv->ethsw_data;
 	struct dpsw_link_state state;
 	int err;
 
@@ -469,10 +470,15 @@ static int port_carrier_state_sync(struct net_device *netdev)
 	WARN_ONCE(state.up > 1, "Garbage read into link_state");
 
 	if (state.up != port_priv->link_state) {
-		if (state.up)
+		if (state.up) {
 			netif_carrier_on(netdev);
-		else
+			if (ethsw_has_ctrl_if(ethsw))
+				netif_tx_start_all_queues(netdev);
+		} else {
 			netif_carrier_off(netdev);
+			if (ethsw_has_ctrl_if(ethsw))
+				netif_tx_stop_all_queues(netdev);
+		}
 		port_priv->link_state = state.up;
 	}
 	return 0;
@@ -525,8 +531,10 @@ static int port_open(struct net_device *netdev)
 	struct ethsw_core *ethsw = port_priv->ethsw_data;
 	int err;
 
-	/* No need to allow Tx as control interface is disabled */
-	netif_tx_stop_all_queues(netdev);
+	if (!ethsw_has_ctrl_if(port_priv->ethsw_data)) {
+		/* No need to allow Tx as control interface is disabled */
+		netif_tx_stop_all_queues(netdev);
+	}
 
 	err = dpsw_if_enable(port_priv->ethsw_data->mc_io, 0,
 			     port_priv->ethsw_data->dpsw_handle,
@@ -574,15 +582,6 @@ static int port_stop(struct net_device *netdev)
 	return 0;
 }
 
-static netdev_tx_t port_dropframe(struct sk_buff *skb,
-				  struct net_device *netdev)
-{
-	/* we don't support I/O for now, drop the frame */
-	dev_kfree_skb_any(skb);
-
-	return NETDEV_TX_OK;
-}
-
 static int swdev_get_port_parent_id(struct net_device *dev,
 				    struct netdev_phys_item_id *ppid)
 {
@@ -759,6 +758,114 @@ static void ethsw_free_fd(const struct ethsw_core *ethsw,
 	dev_kfree_skb(skb);
 }
 
+static int ethsw_build_single_fd(struct ethsw_core *ethsw,
+				 struct sk_buff *skb,
+				 struct dpaa2_fd *fd)
+{
+	struct device *dev = ethsw->dev;
+	struct sk_buff **skbh;
+	dma_addr_t addr;
+	u8 *buff_start;
+	void *hwa;
+
+	buff_start = PTR_ALIGN(skb->data - DPAA2_ETHSW_TX_DATA_OFFSET -
+			       DPAA2_ETHSW_TX_BUF_ALIGN,
+			       DPAA2_ETHSW_TX_BUF_ALIGN);
+
+	/* Clear FAS to have consistent values for TX confirmation. It is
+	 * located in the first 8 bytes of the buffer's hardware annotation
+	 * area
+	 */
+	hwa = buff_start + DPAA2_ETHSW_SWA_SIZE;
+	memset(hwa, 0, 8);
+
+	/* Store a backpointer to the skb at the beginning of the buffer
+	 * (in the private data area) such that we can release it
+	 * on Tx confirm
+	 */
+	skbh = (struct sk_buff **)buff_start;
+	*skbh = skb;
+
+	addr = dma_map_single(dev, buff_start,
+			      skb_tail_pointer(skb) - buff_start,
+			      DMA_TO_DEVICE);
+	if (unlikely(dma_mapping_error(dev, addr)))
+		return -ENOMEM;
+
+	/* Setup the FD fields */
+	memset(fd, 0, sizeof(*fd));
+
+	dpaa2_fd_set_addr(fd, addr);
+	dpaa2_fd_set_offset(fd, (u16)(skb->data - buff_start));
+	dpaa2_fd_set_len(fd, skb->len);
+	dpaa2_fd_set_format(fd, dpaa2_fd_single);
+
+	return 0;
+}
+
+static netdev_tx_t ethsw_port_tx(struct sk_buff *skb,
+				 struct net_device *net_dev)
+{
+	struct ethsw_port_priv *port_priv = netdev_priv(net_dev);
+	struct ethsw_core *ethsw = port_priv->ethsw_data;
+	int retries = DPAA2_ETHSW_SWP_BUSY_RETRIES;
+	struct dpaa2_fd fd;
+	int err;
+
+	if (!ethsw_has_ctrl_if(ethsw))
+		goto err_free_skb;
+
+	if (unlikely(skb_headroom(skb) < DPAA2_ETHSW_NEEDED_HEADROOM)) {
+		struct sk_buff *ns;
+
+		ns = skb_realloc_headroom(skb, DPAA2_ETHSW_NEEDED_HEADROOM);
+		if (unlikely(!ns)) {
+			netdev_err(net_dev, "Error reallocating skb headroom\n");
+			goto err_free_skb;
+		}
+		dev_kfree_skb(skb);
+		skb = ns;
+	}
+
+	/* We'll be holding a back-reference to the skb until Tx confirmation */
+	skb = skb_unshare(skb, GFP_ATOMIC);
+	if (unlikely(!skb)) {
+		/* skb_unshare() has already freed the skb */
+		netdev_err(net_dev, "Error copying the socket buffer\n");
+		goto err_exit;
+	}
+
+	if (skb_is_nonlinear(skb)) {
+		netdev_err(net_dev, "No support for non-linear SKBs!\n");
+		goto err_free_skb;
+	}
+
+	err = ethsw_build_single_fd(ethsw, skb, &fd);
+	if (unlikely(err)) {
+		netdev_err(net_dev, "ethsw_build_*_fd() %d\n", err);
+		goto err_free_skb;
+	}
+
+	do {
+		err = dpaa2_io_service_enqueue_qd(NULL,
+						  port_priv->tx_qdid,
+						  8, 0, &fd);
+		retries--;
+	} while (err == -EBUSY && retries);
+
+	if (unlikely(err < 0)) {
+		ethsw_free_fd(ethsw, &fd);
+		goto err_exit;
+	}
+
+	return NETDEV_TX_OK;
+
+err_free_skb:
+	dev_kfree_skb(skb);
+err_exit:
+	return NETDEV_TX_OK;
+}
+
 static const struct net_device_ops ethsw_port_ops = {
 	.ndo_open		= port_open,
 	.ndo_stop		= port_stop,
@@ -772,7 +879,7 @@ static void ethsw_free_fd(const struct ethsw_core *ethsw,
 	.ndo_fdb_del		= port_fdb_del,
 	.ndo_fdb_dump		= port_fdb_dump,
 
-	.ndo_start_xmit		= port_dropframe,
+	.ndo_start_xmit		= ethsw_port_tx,
 	.ndo_get_port_parent_id	= swdev_get_port_parent_id,
 	.ndo_get_phys_port_name = port_get_phys_name,
 };
@@ -2185,6 +2292,7 @@ static int ethsw_port_init(struct ethsw_port_priv *port_priv, u16 port)
 	struct ethsw_core *ethsw = port_priv->ethsw_data;
 	struct net_device *netdev = port_priv->netdev;
 	struct dpsw_acl_if_cfg acl_if_cfg;
+	struct dpsw_if_attr dpsw_if_attr;
 	struct dpsw_vlan_if_cfg vcfg;
 	struct dpsw_acl_cfg acl_cfg;
 	int err;
@@ -2234,6 +2342,14 @@ static int ethsw_port_init(struct ethsw_port_priv *port_priv, u16 port)
 	if (err)
 		goto err_remove_acl_if;
 
+	err = dpsw_if_get_attributes(ethsw->mc_io, 0, ethsw->dpsw_handle,
+				     port_priv->idx, &dpsw_if_attr);
+	if (err) {
+		netdev_err(netdev, "dpsw_if_get_attributes err %d\n", err);
+		goto err_remove_acl_if;
+	}
+	port_priv->tx_qdid = dpsw_if_attr.qdid;
+
 	return 0;
 
 err_remove_acl_if:
diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
index b585d06be105..747a4e15d28a 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
@@ -72,6 +72,19 @@
  */
 #define DPAA2_ETHSW_SWP_BUSY_RETRIES	1000
 
+/* Hardware annotation buffer size */
+#define DPAA2_ETHSW_HWA_SIZE		64
+/* Software annotation buffer size */
+#define DPAA2_ETHSW_SWA_SIZE		64
+
+#define DPAA2_ETHSW_TX_BUF_ALIGN	64
+
+#define DPAA2_ETHSW_TX_DATA_OFFSET \
+	(DPAA2_ETHSW_HWA_SIZE + DPAA2_ETHSW_SWA_SIZE)
+
+#define DPAA2_ETHSW_NEEDED_HEADROOM \
+	(DPAA2_ETHSW_TX_DATA_OFFSET + DPAA2_ETHSW_TX_BUF_ALIGN)
+
 extern const struct ethtool_ops ethsw_port_ethtool_ops;
 
 struct ethsw_core;
@@ -100,6 +113,7 @@ struct ethsw_port_priv {
 	struct net_device	*bridge_dev;
 	u16			acl_id;
 	u8			acl_cnt;
+	u16			tx_qdid;
 };
 
 /* Switch data */
-- 
1.9.1


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

* [PATCH 10/12] staging: dpaa2-ethsw: enable the CTRL_IF based on the FW version
  2019-11-05 12:34 [PATCH 00/12] staging: dpaa2-ethsw: add support for control interface traffic Ioana Ciornei
                   ` (8 preceding siblings ...)
  2019-11-05 12:34 ` [PATCH 09/12] staging: dpaa2-ethsw: add .ndo_start_xmit() callback Ioana Ciornei
@ 2019-11-05 12:34 ` Ioana Ciornei
  2019-11-05 12:34 ` [PATCH 11/12] staging: dpaa2-ethsw: enable the control interface Ioana Ciornei
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 27+ messages in thread
From: Ioana Ciornei @ 2019-11-05 12:34 UTC (permalink / raw)
  To: gregkh, linux-kernel; +Cc: andrew, f.fainelli, Ioana Ciornei

Introduce a features bitmask in the dpaa2-ethsw driver that would be
populated based on the running version of MC firmware. The first and
only feature, at the moment, is the control traffic which is available
only when the DPSW object version is greater than 8.4.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
 drivers/staging/fsl-dpaa2/ethsw/ethsw.c | 13 +++++++++++++
 drivers/staging/fsl-dpaa2/ethsw/ethsw.h | 11 +++++++++++
 2 files changed, 24 insertions(+)

diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
index abe920f8a665..df9d81be242b 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
@@ -2111,6 +2111,14 @@ static int ethsw_ctrl_if_setup(struct ethsw_core *ethsw)
 	return err;
 }
 
+void dpaa2_ethsw_set_features(struct ethsw_core *ethsw,
+			      u16 major, u16 minor)
+{
+	if (major >= DPAA2_ETHSW_CTRL_IF_MIN_MAJOR &&
+	    minor >= DPAA2_ETHSW_CTRL_IF_MIN_MINOR)
+		ethsw->features |= DPAA2_ETHSW_CONTROL_TRAFFIC;
+}
+
 static int ethsw_init(struct fsl_mc_device *sw_dev)
 {
 	struct device *dev = &sw_dev->dev;
@@ -2154,6 +2162,11 @@ static int ethsw_init(struct fsl_mc_device *sw_dev)
 		goto err_close;
 	}
 
+	/* Compose the set of supported features by
+	 * the current firmware image
+	 */
+	dpaa2_ethsw_set_features(ethsw, version_major, version_minor);
+
 	err = dpsw_reset(ethsw->mc_io, 0, ethsw->dpsw_handle);
 	if (err) {
 		dev_err(dev, "dpsw_reset err %d\n", err);
diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
index 747a4e15d28a..d880a3321e14 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h
@@ -116,6 +116,13 @@ struct ethsw_port_priv {
 	u16			tx_qdid;
 };
 
+#define DPAA2_ETHSW_CTRL_IF_MIN_MAJOR 8
+#define DPAA2_ETHSW_CTRL_IF_MIN_MINOR 4
+
+enum dpaa2_ethsw_features {
+	DPAA2_ETHSW_CONTROL_TRAFFIC = BIT(0),
+};
+
 /* Switch data */
 struct ethsw_core {
 	struct device			*dev;
@@ -125,6 +132,7 @@ struct ethsw_core {
 	int				dev_id;
 	struct ethsw_port_priv		**ports;
 	struct iommu_domain		*iommu_domain;
+	int				features;
 
 	u8				vlans[VLAN_VID_MASK + 1];
 	bool				learning;
@@ -138,6 +146,9 @@ struct ethsw_core {
 
 static inline bool ethsw_has_ctrl_if(struct ethsw_core *ethsw)
 {
+	if (!ethsw->features & DPAA2_ETHSW_CONTROL_TRAFFIC)
+		return false;
+
 	return !(ethsw->sw_attr.options & DPSW_OPT_CTRL_IF_DIS);
 }
 #endif	/* __ETHSW_H */
-- 
1.9.1


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

* [PATCH 11/12] staging: dpaa2-ethsw: enable the control interface
  2019-11-05 12:34 [PATCH 00/12] staging: dpaa2-ethsw: add support for control interface traffic Ioana Ciornei
                   ` (9 preceding siblings ...)
  2019-11-05 12:34 ` [PATCH 10/12] staging: dpaa2-ethsw: enable the CTRL_IF based on the FW version Ioana Ciornei
@ 2019-11-05 12:34 ` Ioana Ciornei
  2019-11-05 12:34 ` [PATCH 12/12] staging: dpaa2-ethsw: remove control traffic from TODO file Ioana Ciornei
  2019-11-05 13:24 ` [PATCH 00/12] staging: dpaa2-ethsw: add support for control interface traffic Greg KH
  12 siblings, 0 replies; 27+ messages in thread
From: Ioana Ciornei @ 2019-11-05 12:34 UTC (permalink / raw)
  To: gregkh, linux-kernel; +Cc: andrew, f.fainelli, Ioana Ciornei

Enable the CTRL_IF of the switch object, now that all the pieces are in
place (buffer and queue management, interrupts, NAPI instances etc).

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
 drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h |  2 ++
 drivers/staging/fsl-dpaa2/ethsw/dpsw.c     | 37 ++++++++++++++++++++++++++++++
 drivers/staging/fsl-dpaa2/ethsw/dpsw.h     |  5 ++++
 drivers/staging/fsl-dpaa2/ethsw/ethsw.c    |  9 ++++++++
 4 files changed, 53 insertions(+)

diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
index 4eab09fb2488..736795dcd9f5 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h
@@ -81,6 +81,8 @@
 
 #define DPSW_CMDID_CTRL_IF_GET_ATTR         DPSW_CMD_ID(0x0A0)
 #define DPSW_CMDID_CTRL_IF_SET_POOLS        DPSW_CMD_ID(0x0A1)
+#define DPSW_CMDID_CTRL_IF_ENABLE           DPSW_CMD_ID(0x0A2)
+#define DPSW_CMDID_CTRL_IF_DISABLE          DPSW_CMD_ID(0x0A3)
 #define DPSW_CMDID_CTRL_IF_SET_QUEUE        DPSW_CMD_ID(0x0A6)
 
 /* Macros for accessing command fields smaller than 1byte */
diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.c b/drivers/staging/fsl-dpaa2/ethsw/dpsw.c
index aebf2a0f4e03..62919fe24d49 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/dpsw.c
+++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.c
@@ -1319,6 +1319,43 @@ int dpsw_ctrl_if_set_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
 }
 
 /**
+ * dpsw_ctrl_if_enable() - Enable control interface
+ * @mc_io:	Pointer to MC portal's I/O object
+ * @cmd_flags:	Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token:	Token of DPSW object
+ *
+ * Return:	'0' on Success; Error code otherwise.
+ */
+int dpsw_ctrl_if_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token)
+{
+	struct fsl_mc_command cmd = { 0 };
+
+	cmd.header = mc_encode_cmd_header(DPSW_CMDID_CTRL_IF_ENABLE, cmd_flags,
+					  token);
+
+	return mc_send_command(mc_io, &cmd);
+}
+
+/**
+ * dpsw_ctrl_if_disable() - Function disables control interface
+ * @mc_io:	Pointer to MC portal's I/O object
+ * @cmd_flags:	Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token:	Token of DPSW object
+ *
+ * Return:	'0' on Success; Error code otherwise.
+ */
+int dpsw_ctrl_if_disable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token)
+{
+	struct fsl_mc_command cmd = { 0 };
+
+	cmd.header = mc_encode_cmd_header(DPSW_CMDID_CTRL_IF_DISABLE,
+					  cmd_flags,
+					  token);
+
+	return mc_send_command(mc_io, &cmd);
+}
+
+/**
  * dpsw_acl_add() - Adds ACL to L2 switch.
  * @mc_io:	Pointer to MC portal's I/O object
  * @cmd_flags:	Command flags; one or more of 'MC_CMD_FLAG_'
diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
index f22f5ad4448a..a9ee8594df5b 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
+++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h
@@ -247,6 +247,11 @@ struct dpsw_ctrl_if_queue_cfg {
 int dpsw_ctrl_if_set_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
 			   enum dpsw_queue_type qtype,
 			   const struct dpsw_ctrl_if_queue_cfg *cfg);
+
+int dpsw_ctrl_if_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token);
+
+int dpsw_ctrl_if_disable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token);
+
 /**
  * enum dpsw_action - Action selection for special/control frames
  * @DPSW_ACTION_DROP: Drop frame
diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
index df9d81be242b..4b0a367bc308 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
@@ -2099,8 +2099,16 @@ static int ethsw_ctrl_if_setup(struct ethsw_core *ethsw)
 	if (err)
 		goto err_destroy_rings;
 
+	err = dpsw_ctrl_if_enable(ethsw->mc_io, 0, ethsw->dpsw_handle);
+	if (err) {
+		dev_err(ethsw->dev, "dpsw_ctrl_if_enable err %d\n", err);
+		goto err_deregister_dpio;
+	}
+
 	return 0;
 
+err_deregister_dpio:
+	ethsw_free_dpio(ethsw);
 err_destroy_rings:
 	ethsw_destroy_rings(ethsw);
 err_drain_dpbp:
@@ -2412,6 +2420,7 @@ static void ethsw_takedown(struct fsl_mc_device *sw_dev)
 
 static void ethsw_ctrl_if_teardown(struct ethsw_core *ethsw)
 {
+	dpsw_ctrl_if_disable(ethsw->mc_io, 0, ethsw->dpsw_handle);
 	ethsw_free_dpio(ethsw);
 	ethsw_destroy_rings(ethsw);
 	ethsw_drain_bp(ethsw);
-- 
1.9.1


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

* [PATCH 12/12] staging: dpaa2-ethsw: remove control traffic from TODO file
  2019-11-05 12:34 [PATCH 00/12] staging: dpaa2-ethsw: add support for control interface traffic Ioana Ciornei
                   ` (10 preceding siblings ...)
  2019-11-05 12:34 ` [PATCH 11/12] staging: dpaa2-ethsw: enable the control interface Ioana Ciornei
@ 2019-11-05 12:34 ` Ioana Ciornei
  2019-11-05 13:24 ` [PATCH 00/12] staging: dpaa2-ethsw: add support for control interface traffic Greg KH
  12 siblings, 0 replies; 27+ messages in thread
From: Ioana Ciornei @ 2019-11-05 12:34 UTC (permalink / raw)
  To: gregkh, linux-kernel; +Cc: andrew, f.fainelli, Ioana Ciornei

The dpaa2-ethsw driver just gained support for redirecting control
traffic to the CPU and and for Rx/Tx processing.
Remove the associated TODO items.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
 drivers/staging/fsl-dpaa2/ethsw/TODO | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/drivers/staging/fsl-dpaa2/ethsw/TODO b/drivers/staging/fsl-dpaa2/ethsw/TODO
index 4d46857b0b2b..21cac669de45 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/TODO
+++ b/drivers/staging/fsl-dpaa2/ethsw/TODO
@@ -1,13 +1,5 @@
-* Add I/O capabilities on switch port netdevices. This will allow control
-traffic to reach the CPU.
-* Add ACL to redirect control traffic to CPU.
 * Add support for multiple FDBs and switch port partitioning
 * MC firmware uprev; the DPAA2 objects used by the Ethernet Switch driver
 need to be kept in sync with binary interface changes in MC
 * refine README file
 * cleanup
-
-NOTE: At least first three of the above are required before getting the
-DPAA2 Ethernet Switch driver out of staging. Another requirement is that
-dpio driver is moved to drivers/soc (this is required for I/O).
-
-- 
1.9.1


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

* Re: [PATCH 00/12] staging: dpaa2-ethsw: add support for control interface traffic
  2019-11-05 12:34 [PATCH 00/12] staging: dpaa2-ethsw: add support for control interface traffic Ioana Ciornei
                   ` (11 preceding siblings ...)
  2019-11-05 12:34 ` [PATCH 12/12] staging: dpaa2-ethsw: remove control traffic from TODO file Ioana Ciornei
@ 2019-11-05 13:24 ` Greg KH
  2019-11-05 13:49   ` Ioana Ciornei
  2019-11-05 14:02   ` Andrew Lunn
  12 siblings, 2 replies; 27+ messages in thread
From: Greg KH @ 2019-11-05 13:24 UTC (permalink / raw)
  To: Ioana Ciornei; +Cc: linux-kernel, andrew, f.fainelli

On Tue, Nov 05, 2019 at 02:34:23PM +0200, Ioana Ciornei wrote:
> This patch set adds support for Rx/Tx capabilities on switch port interfaces.
> Also, control traffic is redirected through ACLs to the CPU in order to
> enable proper STP protocol handling.
> 
> The control interface is comprised of 3 queues in total: Rx, Rx error and
> Tx confirmation.  In this patch set we only enable Rx and Tx conf. All
> switch ports share the same queues when frames are redirected to the CPU.
> Information regarding the ingress switch port is passed through frame
> metadata - the flow context field of the descriptor. NAPI instances are
> also shared between switch net_devices and are enabled when at least on
> one of the switch ports .dev_open() was called and disabled when at least
> one switch port is still up.
> 
> The new feature is enabled only on MC versions greater than 10.19.0
> (which is soon to be released).

I thought I asked for no new features until this code gets out of
staging?  Only then can you add new stuff.  Please work to make that
happen first.

thanks,

greg k-h

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

* Re: [PATCH 00/12] staging: dpaa2-ethsw: add support for control interface traffic
  2019-11-05 13:24 ` [PATCH 00/12] staging: dpaa2-ethsw: add support for control interface traffic Greg KH
@ 2019-11-05 13:49   ` Ioana Ciornei
  2019-11-05 14:02   ` Andrew Lunn
  1 sibling, 0 replies; 27+ messages in thread
From: Ioana Ciornei @ 2019-11-05 13:49 UTC (permalink / raw)
  To: Greg KH; +Cc: linux-kernel, andrew, f.fainelli

On 05.11.2019 15:24, Greg KH wrote:
> On Tue, Nov 05, 2019 at 02:34:23PM +0200, Ioana Ciornei wrote:
>> This patch set adds support for Rx/Tx capabilities on switch port interfaces.
>> Also, control traffic is redirected through ACLs to the CPU in order to
>> enable proper STP protocol handling.
>>
>> The control interface is comprised of 3 queues in total: Rx, Rx error and
>> Tx confirmation.  In this patch set we only enable Rx and Tx conf. All
>> switch ports share the same queues when frames are redirected to the CPU.
>> Information regarding the ingress switch port is passed through frame
>> metadata - the flow context field of the descriptor. NAPI instances are
>> also shared between switch net_devices and are enabled when at least on
>> one of the switch ports .dev_open() was called and disabled when at least
>> one switch port is still up.
>>
>> The new feature is enabled only on MC versions greater than 10.19.0
>> (which is soon to be released).
> 
> I thought I asked for no new features until this code gets out of
> staging?  Only then can you add new stuff.  Please work to make that
> happen first.
> 
> thanks,
> 
> greg k-h
> 

Sorry but I do not remember your suggestion on first moving the driver 
out of staging.

Anyhow, I submitted against staging because in an earlier discussion[1] 
it was suggested to first add Rx/Tx capabilities before moving it:

"Ah. Does this also mean it cannot receive?

That makes some of this code pointless and untested.

I'm not sure we would be willing to move this out of staging until it
can transmit and receive."


I'm not sure how I should proceed here.

Thanks,
Ioana

[1] https://lkml.org/lkml/2019/8/9/892

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

* Re: [PATCH 00/12] staging: dpaa2-ethsw: add support for control interface traffic
  2019-11-05 13:24 ` [PATCH 00/12] staging: dpaa2-ethsw: add support for control interface traffic Greg KH
  2019-11-05 13:49   ` Ioana Ciornei
@ 2019-11-05 14:02   ` Andrew Lunn
  2019-11-05 14:22     ` Ioana Ciornei
  2019-11-05 15:32     ` Greg KH
  1 sibling, 2 replies; 27+ messages in thread
From: Andrew Lunn @ 2019-11-05 14:02 UTC (permalink / raw)
  To: Greg KH; +Cc: Ioana Ciornei, linux-kernel, f.fainelli

On Tue, Nov 05, 2019 at 02:24:35PM +0100, Greg KH wrote:
> On Tue, Nov 05, 2019 at 02:34:23PM +0200, Ioana Ciornei wrote:
> > This patch set adds support for Rx/Tx capabilities on switch port interfaces.
> > Also, control traffic is redirected through ACLs to the CPU in order to
> > enable proper STP protocol handling.
 
> I thought I asked for no new features until this code gets out of
> staging?  Only then can you add new stuff.  Please work to make that
> happen first.

Hi Greg

This is in response to my review of the code in staging. The current
code is missing a core feature for an Ethernet switch driver, being
able to send/receive frames from the host. At the moment it can only
control the hardware for how it switches Ethernet frames coming
into/going out of external ports.

One of the core ideas behind how linux handles Ethernet switches is
that they are just a bunch of network interfaces. And currently, these
network interfaces cannot send/receive. We would never move an
Ethernet driver out of staging which cannot send/receive, so i don't
see why we should move an Ethernet switch driver out of staging which
also cannot send/receive.

Maybe this patchset could be minimised. The STP handling is just nice
to have, and could wait until the driver has moved into the main tree.

   Andrew

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

* Re: [PATCH 06/12] staging: dpaa2-ethsw: add ACL entry to redirect STP to CPU
  2019-11-05 12:34 ` [PATCH 06/12] staging: dpaa2-ethsw: add ACL entry to redirect STP to CPU Ioana Ciornei
@ 2019-11-05 14:22   ` Andrew Lunn
  2019-11-05 14:31     ` Ioana Ciornei
  0 siblings, 1 reply; 27+ messages in thread
From: Andrew Lunn @ 2019-11-05 14:22 UTC (permalink / raw)
  To: Ioana Ciornei; +Cc: gregkh, linux-kernel, f.fainelli

> +static int ethsw_port_set_ctrl_if_acl(struct ethsw_port_priv *port_priv)
> +{
> +	const char stp_mac[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x00};

I think there is a standard define for that somewhere in include/linux
or maybe include/net.

But thinking about the big picture, i wonder why this is needed, at
least in a minimal implementation. Bit 0 is set in this MAC address,
so it is a L2 multicast frame. By default, all L2 multicast frames
should be delivered to the CPU. So it should work without this.

       Andrew

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

* Re: [PATCH 00/12] staging: dpaa2-ethsw: add support for control interface traffic
  2019-11-05 14:02   ` Andrew Lunn
@ 2019-11-05 14:22     ` Ioana Ciornei
  2019-11-05 14:44       ` Andrew Lunn
  2019-11-05 15:32     ` Greg KH
  1 sibling, 1 reply; 27+ messages in thread
From: Ioana Ciornei @ 2019-11-05 14:22 UTC (permalink / raw)
  To: Andrew Lunn, Greg KH; +Cc: linux-kernel, f.fainelli

On 05.11.2019 16:03, Andrew Lunn wrote:
> On Tue, Nov 05, 2019 at 02:24:35PM +0100, Greg KH wrote:
>> On Tue, Nov 05, 2019 at 02:34:23PM +0200, Ioana Ciornei wrote:
>>> This patch set adds support for Rx/Tx capabilities on switch port interfaces.
>>> Also, control traffic is redirected through ACLs to the CPU in order to
>>> enable proper STP protocol handling.
>   
>> I thought I asked for no new features until this code gets out of
>> staging?  Only then can you add new stuff.  Please work to make that
>> happen first.
> 
> Hi Greg
> 
> This is in response to my review of the code in staging. The current
> code is missing a core feature for an Ethernet switch driver, being
> able to send/receive frames from the host. At the moment it can only
> control the hardware for how it switches Ethernet frames coming
> into/going out of external ports.
> 
> One of the core ideas behind how linux handles Ethernet switches is
> that they are just a bunch of network interfaces. And currently, these
> network interfaces cannot send/receive. We would never move an
> Ethernet driver out of staging which cannot send/receive, so i don't
> see why we should move an Ethernet switch driver out of staging which
> also cannot send/receive.
> 
> Maybe this patchset could be minimised. The STP handling is just nice
> to have, and could wait until the driver has moved into the main tree.
> 
>     Andrew
> 


Hi Andrew,

Just to clarify...if the STP handling is removed, then we'll have a 
receive code path but no frame will reach it.
This is because, the only way we could direct traffic to the CPU is by 
adding an ACL rule.

Is that something that the netdev community would maybe accept?

Ioana



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

* Re: [PATCH 08/12] staging: dpaa2-ethsw: handle Rx path on control interface
  2019-11-05 12:34 ` [PATCH 08/12] staging: dpaa2-ethsw: handle Rx path on control interface Ioana Ciornei
@ 2019-11-05 14:31   ` Andrew Lunn
  0 siblings, 0 replies; 27+ messages in thread
From: Andrew Lunn @ 2019-11-05 14:31 UTC (permalink / raw)
  To: Ioana Ciornei; +Cc: gregkh, linux-kernel, f.fainelli

> +static void ethsw_rx(struct ethsw_fq *fq,
> +		     const struct dpaa2_fd *fd)
> +{
> +	struct ethsw_core *ethsw = fq->ethsw;
> +	struct ethsw_port_priv *port_priv;
> +	struct net_device *netdev;
> +	struct vlan_ethhdr *hdr;
> +	struct sk_buff *skb;
> +	u16 vlan_tci, vid;
> +	int if_id = -1;
> +	int err;
> +
> +	/* prefetch the frame descriptor */
> +	prefetch(fd);
> +
> +	/* get switch ingress interface ID */
> +	if_id = upper_32_bits(dpaa2_fd_get_flc(fd)) & 0x0000FFFF;

Does the prefetch do any good, since the very next thing you do is
access the frame descriptor? Ideally you want to issue the prefetch,
do something else for a while, and then make use of what the prefetch
got.


> +
> +	if (if_id < 0 || if_id >= ethsw->sw_attr.num_ifs) {

Is if_id signed? Seems odd.

   Andrew

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

* RE: [PATCH 06/12] staging: dpaa2-ethsw: add ACL entry to redirect STP to CPU
  2019-11-05 14:22   ` Andrew Lunn
@ 2019-11-05 14:31     ` Ioana Ciornei
  2019-11-05 15:59       ` Andrew Lunn
  0 siblings, 1 reply; 27+ messages in thread
From: Ioana Ciornei @ 2019-11-05 14:31 UTC (permalink / raw)
  To: Andrew Lunn; +Cc: gregkh, linux-kernel, f.fainelli

> Subject: Re: [PATCH 06/12] staging: dpaa2-ethsw: add ACL entry to redirect
> STP to CPU
> 
> > +static int ethsw_port_set_ctrl_if_acl(struct ethsw_port_priv
> > +*port_priv) {
> > +	const char stp_mac[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x00};
> 
> I think there is a standard define for that somewhere in include/linux or
> maybe include/net.
> 
> But thinking about the big picture, i wonder why this is needed, at least in a
> minimal implementation. Bit 0 is set in this MAC address, so it is a L2 multicast
> frame. By default, all L2 multicast frames should be delivered to the CPU. So
> it should work without this.
> 
>        Andrew

Now I see that I should have been more clear about what our switch can do.

The control queues do not form an actual interface in the sense that the CPU does not receive unknown unicast, broadcast and multicast frames by default.
For each frame that we want to direct to the CPU we must add an ACL entry.

Ioana


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

* Re: [PATCH 00/12] staging: dpaa2-ethsw: add support for control interface traffic
  2019-11-05 14:22     ` Ioana Ciornei
@ 2019-11-05 14:44       ` Andrew Lunn
  0 siblings, 0 replies; 27+ messages in thread
From: Andrew Lunn @ 2019-11-05 14:44 UTC (permalink / raw)
  To: Ioana Ciornei; +Cc: Greg KH, linux-kernel, f.fainelli

> Hi Andrew,
> 
> Just to clarify...if the STP handling is removed, then we'll have a 
> receive code path but no frame will reach it.
> This is because, the only way we could direct traffic to the CPU is by 
> adding an ACL rule.

Ah, that is not good.

As i said in one of my reviews, you need to receive all multicast and
broadcast traffic by default. Without that, ARP will not work.  Does
the switch perform learning on frames sent from the CPU? Does the
switch learn the CPUs MAC address and forward frames to it?  Can i add
an IP address to the interface and use ping?

   Andrew

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

* Re: [PATCH 00/12] staging: dpaa2-ethsw: add support for control interface traffic
  2019-11-05 14:02   ` Andrew Lunn
  2019-11-05 14:22     ` Ioana Ciornei
@ 2019-11-05 15:32     ` Greg KH
  1 sibling, 0 replies; 27+ messages in thread
From: Greg KH @ 2019-11-05 15:32 UTC (permalink / raw)
  To: Andrew Lunn; +Cc: Ioana Ciornei, linux-kernel, f.fainelli

On Tue, Nov 05, 2019 at 03:02:56PM +0100, Andrew Lunn wrote:
> On Tue, Nov 05, 2019 at 02:24:35PM +0100, Greg KH wrote:
> > On Tue, Nov 05, 2019 at 02:34:23PM +0200, Ioana Ciornei wrote:
> > > This patch set adds support for Rx/Tx capabilities on switch port interfaces.
> > > Also, control traffic is redirected through ACLs to the CPU in order to
> > > enable proper STP protocol handling.
>  
> > I thought I asked for no new features until this code gets out of
> > staging?  Only then can you add new stuff.  Please work to make that
> > happen first.
> 
> Hi Greg
> 
> This is in response to my review of the code in staging. The current
> code is missing a core feature for an Ethernet switch driver, being
> able to send/receive frames from the host. At the moment it can only
> control the hardware for how it switches Ethernet frames coming
> into/going out of external ports.
> 
> One of the core ideas behind how linux handles Ethernet switches is
> that they are just a bunch of network interfaces. And currently, these
> network interfaces cannot send/receive. We would never move an
> Ethernet driver out of staging which cannot send/receive, so i don't
> see why we should move an Ethernet switch driver out of staging which
> also cannot send/receive.
> 
> Maybe this patchset could be minimised. The STP handling is just nice
> to have, and could wait until the driver has moved into the main tree.

Ok, if the netdev developers say that this is needed before it can move
out of staging, then that's fine, I didn't get that from this
submission, sorry.

greg k-h

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

* Re: [PATCH 06/12] staging: dpaa2-ethsw: add ACL entry to redirect STP to CPU
  2019-11-05 14:31     ` Ioana Ciornei
@ 2019-11-05 15:59       ` Andrew Lunn
  2019-11-06 13:47         ` Ioana Ciornei
  0 siblings, 1 reply; 27+ messages in thread
From: Andrew Lunn @ 2019-11-05 15:59 UTC (permalink / raw)
  To: Ioana Ciornei; +Cc: gregkh, linux-kernel, f.fainelli

> The control queues do not form an actual interface in the sense that
> the CPU does not receive unknown unicast, broadcast and multicast
> frames by default.  For each frame that we want to direct to the CPU
> we must add an ACL entry.

So this appears to be one of the dumbest switches so far :-(

Can you add an ACL which is all L2 broadcast/multicast?  That would be
a good first step.

Does the ACL stop further processing of the frame? Ideally you want
the switch to also flood broadcast/multicast out other ports, if they
are in a bridge. If it cannot, you end up with the software bridge
doing the flooding.

So i also assume it does not perform learning on CPU frames? That
probably means you need to connect up the fdb add/remove calls to add
in ACLs. And you will need to implement ndo_set_rx_mode. Each unicast
and multicast address needs to be turned into an ACL. What i don't
know is if the network stack will automatically add the interfaces own
MAC address. You might have to handle that special case.

    Andrew

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

* RE: [PATCH 06/12] staging: dpaa2-ethsw: add ACL entry to redirect STP to CPU
  2019-11-05 15:59       ` Andrew Lunn
@ 2019-11-06 13:47         ` Ioana Ciornei
  2019-11-06 14:50           ` Andrew Lunn
  0 siblings, 1 reply; 27+ messages in thread
From: Ioana Ciornei @ 2019-11-06 13:47 UTC (permalink / raw)
  To: Andrew Lunn; +Cc: gregkh, linux-kernel, f.fainelli

> Subject: Re: [PATCH 06/12] staging: dpaa2-ethsw: add ACL entry to redirect
> STP to CPU
> 
> > The control queues do not form an actual interface in the sense that
> > the CPU does not receive unknown unicast, broadcast and multicast
> > frames by default.  For each frame that we want to direct to the CPU
> > we must add an ACL entry.
> 
> So this appears to be one of the dumbest switches so far :-(

To be fair, the actual hardware can do much more.
The problem here is that the firmware models the switch in a non-Linux style.

> 
> Can you add an ACL which is all L2 broadcast/multicast?  That would be a good
> first step.

I can add that but it would not be enough.
For example, unknown unicast would not be matched thus would not reach the CPU.

> 
> Does the ACL stop further processing of the frame? Ideally you want the
> switch to also flood broadcast/multicast out other ports, if they are in a
> bridge. If it cannot, you end up with the software bridge doing the flooding.

Yes, the ACL stops any further processing. 

> 
> So i also assume it does not perform learning on CPU frames? That probably
> means you need to connect up the fdb add/remove calls to add in ACLs. And
> you will need to implement ndo_set_rx_mode. Each unicast and multicast
> address needs to be turned into an ACL. What i don't know is if the network
> stack will automatically add the interfaces own MAC address. You might have
> to handle that special case.
> 
>     Andrew

Your assumption is true, learning, with the current implementation, is not possible for CPU frames.
In .ndo_start_xmit() we inject directly into the switch port's Tx queues, thus bypassing the entire learning process.

All in all, I do not see a way out just by using the ACL mechanism (because of unknown unicast frames).

I have to talk in detail with the firmware team, but from what I can understand if we make the following changes in firmware it would better fit the Linux framework:
 * make the CPU receive unknown unicast, broadcast and multicast frames by default (without any ACLs)
 * frames originated on the CPU should not bypass the learning process (it should have its own Tx queues that go through the same learning process)

Thanks,
Ioana



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

* Re: [PATCH 06/12] staging: dpaa2-ethsw: add ACL entry to redirect STP to CPU
  2019-11-06 13:47         ` Ioana Ciornei
@ 2019-11-06 14:50           ` Andrew Lunn
  2019-11-06 15:22             ` Ioana Ciornei
  0 siblings, 1 reply; 27+ messages in thread
From: Andrew Lunn @ 2019-11-06 14:50 UTC (permalink / raw)
  To: Ioana Ciornei; +Cc: gregkh, linux-kernel, f.fainelli

On Wed, Nov 06, 2019 at 01:47:47PM +0000, Ioana Ciornei wrote:
> > Subject: Re: [PATCH 06/12] staging: dpaa2-ethsw: add ACL entry to redirect
> > STP to CPU
> > 
> > > The control queues do not form an actual interface in the sense that
> > > the CPU does not receive unknown unicast, broadcast and multicast
> > > frames by default.  For each frame that we want to direct to the CPU
> > > we must add an ACL entry.
> > 
> > So this appears to be one of the dumbest switches so far :-(
> 
> To be fair, the actual hardware can do much more.
> The problem here is that the firmware models the switch in a non-Linux style.

Well, the whole hardware is not very linux like!

> > 
> > Can you add an ACL which is all L2 broadcast/multicast?  That would be a good
> > first step.
> 
> I can add that but it would not be enough.
> For example, unknown unicast would not be matched thus would not reach the CPU.

Not ideal, but you could rely on ARP and ND. Any conversation should
start with a broadcast/multicast ARP or ND. The bridge should add an
FDB based on what it just learned, and traffic should flow. And when
the interface is not part of a bridge, you don't care about unknown
unicast.

> > Does the ACL stop further processing of the frame? Ideally you want the
> > switch to also flood broadcast/multicast out other ports, if they are in a
> > bridge. If it cannot, you end up with the software bridge doing the flooding.
> 
> Yes, the ACL stops any further processing. 

O.K, the software bridge can handle that. It is not the best use for
hardware, but will work.

> Your assumption is true, learning, with the current implementation, is not possible for CPU frames.
> In .ndo_start_xmit() we inject directly into the switch port's Tx queues, thus bypassing the entire learning process.
> 
> All in all, I do not see a way out just by using the ACL mechanism (because of unknown unicast frames).
> 
> I have to talk in detail with the firmware team, but from what I can understand if we make the following changes in firmware it would better fit the Linux framework:
>  * make the CPU receive unknown unicast, broadcast and multicast frames by default (without any ACLs)

Yes, that is the first step. Some switches go further. Link local L2
frames are always passed to the CPU. All ARP and ND packets are
passed, IGMP, etc. Once you have the first step working, you start
thinking about the next step. That is blocking some of this traffic
hitting the CPU. IGMP snooping is one way. You need to continue
receiving the IGMP frames, but not the multicast traffic. But they use
the same MAC address. So the switch needs to look deeper into the
packet.

> * frames originated on the CPU should not bypass the learning
>   process (it should have its own Tx queues that go through the
>   same learning process)

Learning is needed. But maybe not its own Tx queue. It depends on the
QoS architecture. Ideally you want QoS to work on CPU frames, so they
get put into the correct egress queue for there QoS level.

With DSA this is simpler, since you have a physical interface
connected to the CPU, so you can use that interface number in all your
tables. But with a pure switchdev driver, each port effectively
becomes two ports, one to the front panel and one to the CPU port. And
your tables need to differentiate this.

     Andrew

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

* RE: [PATCH 06/12] staging: dpaa2-ethsw: add ACL entry to redirect STP to CPU
  2019-11-06 14:50           ` Andrew Lunn
@ 2019-11-06 15:22             ` Ioana Ciornei
  2019-11-06 16:01               ` Andrew Lunn
  0 siblings, 1 reply; 27+ messages in thread
From: Ioana Ciornei @ 2019-11-06 15:22 UTC (permalink / raw)
  To: Andrew Lunn; +Cc: gregkh, linux-kernel, f.fainelli

> Subject: Re: [PATCH 06/12] staging: dpaa2-ethsw: add ACL entry to redirect
> STP to CPU
> 
> On Wed, Nov 06, 2019 at 01:47:47PM +0000, Ioana Ciornei wrote:
> > > Subject: Re: [PATCH 06/12] staging: dpaa2-ethsw: add ACL entry to
> > > redirect STP to CPU
> > >
> > > > The control queues do not form an actual interface in the sense
> > > > that the CPU does not receive unknown unicast, broadcast and
> > > > multicast frames by default.  For each frame that we want to
> > > > direct to the CPU we must add an ACL entry.
> > >
> > > So this appears to be one of the dumbest switches so far :-(
> >
> > To be fair, the actual hardware can do much more.
> > The problem here is that the firmware models the switch in a non-Linux
> style.
> 
> Well, the whole hardware is not very linux like!

Well, that's a pretty good description of what I am dealing with here.

> 
> > >
> > > Can you add an ACL which is all L2 broadcast/multicast?  That would
> > > be a good first step.
> >
> > I can add that but it would not be enough.
> > For example, unknown unicast would not be matched thus would not
> reach the CPU.
> 
> Not ideal, but you could rely on ARP and ND. Any conversation should start
> with a broadcast/multicast ARP or ND. The bridge should add an FDB based
> on what it just learned, and traffic should flow. And when the interface is not
> part of a bridge, you don't care about unknown unicast.

If I do this, I would have an L2 switch that relies on IP traffic passing through it.
Also, if I use ACLs to model dynamic FDB entries than I will need to "software age
the ACLs... which is at least not ideal.

> 
> > > Does the ACL stop further processing of the frame? Ideally you want
> > > the switch to also flood broadcast/multicast out other ports, if
> > > they are in a bridge. If it cannot, you end up with the software bridge
> doing the flooding.
> >
> > Yes, the ACL stops any further processing.
> 
> O.K, the software bridge can handle that. It is not the best use for hardware,
> but will work.
> 
> > Your assumption is true, learning, with the current implementation, is not
> possible for CPU frames.
> > In .ndo_start_xmit() we inject directly into the switch port's Tx queues,
> thus bypassing the entire learning process.
> >
> > All in all, I do not see a way out just by using the ACL mechanism (because
> of unknown unicast frames).
> >
> > I have to talk in detail with the firmware team, but from what I can
> understand if we make the following changes in firmware it would better fit
> the Linux framework:
> >  * make the CPU receive unknown unicast, broadcast and multicast
> > frames by default (without any ACLs)
> 
> Yes, that is the first step. Some switches go further. Link local L2 frames are
> always passed to the CPU. All ARP and ND packets are passed, IGMP, etc.
> Once you have the first step working, you start thinking about the next step.
> That is blocking some of this traffic hitting the CPU. IGMP snooping is one
> way. You need to continue receiving the IGMP frames, but not the multicast
> traffic. But they use the same MAC address. So the switch needs to look
> deeper into the packet.
> 
> > * frames originated on the CPU should not bypass the learning
> >   process (it should have its own Tx queues that go through the
> >   same learning process)
> 
> Learning is needed. But maybe not its own Tx queue. It depends on the QoS
> architecture. Ideally you want QoS to work on CPU frames, so they get put
> into the correct egress queue for there QoS level.
> 
> With DSA this is simpler, since you have a physical interface connected to the
> CPU, so you can use that interface number in all your tables. But with a pure
> switchdev driver, each port effectively becomes two ports, one to the front
> panel and one to the CPU port. And your tables need to differentiate this.
> 
>      Andrew

Andrew, thanks for all the advice given but I feel like I have to see if the firmware
can be changed to better model the CPU traffic before adding a lot of hacks and
pushing something with the current implementation.

Ioana


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

* Re: [PATCH 06/12] staging: dpaa2-ethsw: add ACL entry to redirect STP to CPU
  2019-11-06 15:22             ` Ioana Ciornei
@ 2019-11-06 16:01               ` Andrew Lunn
  0 siblings, 0 replies; 27+ messages in thread
From: Andrew Lunn @ 2019-11-06 16:01 UTC (permalink / raw)
  To: Ioana Ciornei; +Cc: gregkh, linux-kernel, f.fainelli

> If I do this, I would have an L2 switch that relies on IP traffic
> passing through it.

Yes.

> Also, if I use ACLs to model dynamic FDB entries than I will need to "software age
> the ACLs... which is at least not ideal.

The bridge will do that for you.

> Andrew, thanks for all the advice given but I feel like I have to see if the firmware
> can be changed to better model the CPU traffic before adding a lot of hacks and
> pushing something with the current implementation.

Yes. I agree. If the firmware can change, great. If not, you might
have to do these hacks.

     Andrew

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

end of thread, other threads:[~2019-11-06 16:01 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-05 12:34 [PATCH 00/12] staging: dpaa2-ethsw: add support for control interface traffic Ioana Ciornei
2019-11-05 12:34 ` [PATCH 01/12] staging: dpaa2-ethsw: get control interface attributes Ioana Ciornei
2019-11-05 12:34 ` [PATCH 02/12] staging: dpaa2-ethsw: setup buffer pool for control traffic Ioana Ciornei
2019-11-05 12:34 ` [PATCH 03/12] staging: dpaa2-ethsw: setup RX path rings Ioana Ciornei
2019-11-05 12:34 ` [PATCH 04/12] staging: dpaa2-ethsw: setup dpio Ioana Ciornei
2019-11-05 12:34 ` [PATCH 05/12] staging: dpaa2-ethsw: add ACL table at port probe Ioana Ciornei
2019-11-05 12:34 ` [PATCH 06/12] staging: dpaa2-ethsw: add ACL entry to redirect STP to CPU Ioana Ciornei
2019-11-05 14:22   ` Andrew Lunn
2019-11-05 14:31     ` Ioana Ciornei
2019-11-05 15:59       ` Andrew Lunn
2019-11-06 13:47         ` Ioana Ciornei
2019-11-06 14:50           ` Andrew Lunn
2019-11-06 15:22             ` Ioana Ciornei
2019-11-06 16:01               ` Andrew Lunn
2019-11-05 12:34 ` [PATCH 07/12] staging: dpaa2-ethsw: seed the buffer pool Ioana Ciornei
2019-11-05 12:34 ` [PATCH 08/12] staging: dpaa2-ethsw: handle Rx path on control interface Ioana Ciornei
2019-11-05 14:31   ` Andrew Lunn
2019-11-05 12:34 ` [PATCH 09/12] staging: dpaa2-ethsw: add .ndo_start_xmit() callback Ioana Ciornei
2019-11-05 12:34 ` [PATCH 10/12] staging: dpaa2-ethsw: enable the CTRL_IF based on the FW version Ioana Ciornei
2019-11-05 12:34 ` [PATCH 11/12] staging: dpaa2-ethsw: enable the control interface Ioana Ciornei
2019-11-05 12:34 ` [PATCH 12/12] staging: dpaa2-ethsw: remove control traffic from TODO file Ioana Ciornei
2019-11-05 13:24 ` [PATCH 00/12] staging: dpaa2-ethsw: add support for control interface traffic Greg KH
2019-11-05 13:49   ` Ioana Ciornei
2019-11-05 14:02   ` Andrew Lunn
2019-11-05 14:22     ` Ioana Ciornei
2019-11-05 14:44       ` Andrew Lunn
2019-11-05 15:32     ` Greg KH

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.