All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH v2 0/3] Introduce switch mode support for ICSSG driver
@ 2024-01-18  7:10 ` MD Danish Anwar
  0 siblings, 0 replies; 34+ messages in thread
From: MD Danish Anwar @ 2024-01-18  7:10 UTC (permalink / raw)
  To: Rob Herring, Dan Carpenter, Jan Kiszka, Andrew Lunn,
	Vladimir Oltean, Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, MD Danish Anwar, Paolo Abeni,
	Jakub Kicinski, Eric Dumazet, David S. Miller
  Cc: linux-arm-kernel, netdev, linux-kernel, srk, r-gunasekaran

This series adds support for switch-mode for ICSSG driver. This series
also introduces helper APIs to configure firmware maintained FDB
(Forwarding Database) and VLAN tables. These APIs are later used by ICSSG
driver in switch mode.

Now the driver will boot by default in dual EMAC mode. When first ICSSG
interface is added to bridge driver will still be in EMAC mode. As soon as
second ICSSG interface is added to same bridge, switch-mode will be
enabled and switch firmwares will be loaded to PRU cores. The driver will
remain in dual EMAC mode if ICSSG interfaces are added to two different
bridges or if two differnet interfaces (One ICSSG, one other) is added to
the same bridge. We'll only enable is_switch_mode flag when two ICSSG
interfaces are added to same bridge.

We start in dual MAC mode. Let's say lan0 and lan1 are ICSSG interfaces

ip link add name br0 type bridge
ip link set lan0 master br0

At this point, we get a CHANGEUPPER event. Only one port is a member of
the bridge, so we will still be in dual MAC mode.

ip link set lan1 master br0

We get a second CHANGEUPPER event, the secind interface lan1 is also ICSSG
interface so we will set the is_switch_mode flag and when interfaces are
brought up again, ICSSG switch firmwares will be loaded to PRU Cores.

There are some other cases to consider as well. 

ip link add name br0 type bridge
ip link add name br1 type bridge

ip link set lan0 master br0
ip link set ppp0 master br0

Here we are adding lan0 (ICSSG) and ppp0 (non ICSSG) to same bridge, as
they both are not ICSSG, we will still be running in dual EMAC mode.

ip link set lan1 master br1
ip link set vpn0 master br1

Here we are adding lan1 (ICSSG) and vpn0 (non ICSSG) to same bridge, as
they both are not ICSSG, we will still be running in dual EMAC mode.


This is v2 of the series [1]. It addresses commenst made on v1 [1].

Changes from v1 to v2:
*) Removed TAPRIO support patch from this series.
*) Stopped using devlink for enabling switch-mode as suggested by Andrew L
*) Added read_poll_timeout() in patch 1 / 3 as suggested by Andrew L.

[1] https://lore.kernel.org/all/20230830110847.1219515-4-danishanwar@ti.com/

Thanks and Regards,
Md Danish Anwar

MD Danish Anwar (3):
  net: ti: icssg-prueth: Add helper functions to configure FDB
  net: ti: icssg-switch: Add switchdev based driver for ethernet switch
    support
  net: ti: icssg-prueth: Add support for ICSSG switch firmware

 drivers/net/ethernet/ti/Kconfig               |   1 +
 drivers/net/ethernet/ti/Makefile              |   3 +-
 drivers/net/ethernet/ti/icssg/icssg_config.c  | 324 +++++++++++-
 drivers/net/ethernet/ti/icssg/icssg_config.h  |  26 +
 drivers/net/ethernet/ti/icssg/icssg_prueth.c  | 199 +++++++-
 drivers/net/ethernet/ti/icssg/icssg_prueth.h  |  36 ++
 .../net/ethernet/ti/icssg/icssg_switchdev.c   | 478 ++++++++++++++++++
 .../net/ethernet/ti/icssg/icssg_switchdev.h   |  13 +
 8 files changed, 1067 insertions(+), 13 deletions(-)
 create mode 100644 drivers/net/ethernet/ti/icssg/icssg_switchdev.c
 create mode 100644 drivers/net/ethernet/ti/icssg/icssg_switchdev.h

-- 
2.34.1


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

* [RFC PATCH v2 0/3] Introduce switch mode support for ICSSG driver
@ 2024-01-18  7:10 ` MD Danish Anwar
  0 siblings, 0 replies; 34+ messages in thread
From: MD Danish Anwar @ 2024-01-18  7:10 UTC (permalink / raw)
  To: Rob Herring, Dan Carpenter, Jan Kiszka, Andrew Lunn,
	Vladimir Oltean, Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, MD Danish Anwar, Paolo Abeni,
	Jakub Kicinski, Eric Dumazet, David S. Miller
  Cc: linux-arm-kernel, netdev, linux-kernel, srk, r-gunasekaran

This series adds support for switch-mode for ICSSG driver. This series
also introduces helper APIs to configure firmware maintained FDB
(Forwarding Database) and VLAN tables. These APIs are later used by ICSSG
driver in switch mode.

Now the driver will boot by default in dual EMAC mode. When first ICSSG
interface is added to bridge driver will still be in EMAC mode. As soon as
second ICSSG interface is added to same bridge, switch-mode will be
enabled and switch firmwares will be loaded to PRU cores. The driver will
remain in dual EMAC mode if ICSSG interfaces are added to two different
bridges or if two differnet interfaces (One ICSSG, one other) is added to
the same bridge. We'll only enable is_switch_mode flag when two ICSSG
interfaces are added to same bridge.

We start in dual MAC mode. Let's say lan0 and lan1 are ICSSG interfaces

ip link add name br0 type bridge
ip link set lan0 master br0

At this point, we get a CHANGEUPPER event. Only one port is a member of
the bridge, so we will still be in dual MAC mode.

ip link set lan1 master br0

We get a second CHANGEUPPER event, the secind interface lan1 is also ICSSG
interface so we will set the is_switch_mode flag and when interfaces are
brought up again, ICSSG switch firmwares will be loaded to PRU Cores.

There are some other cases to consider as well. 

ip link add name br0 type bridge
ip link add name br1 type bridge

ip link set lan0 master br0
ip link set ppp0 master br0

Here we are adding lan0 (ICSSG) and ppp0 (non ICSSG) to same bridge, as
they both are not ICSSG, we will still be running in dual EMAC mode.

ip link set lan1 master br1
ip link set vpn0 master br1

Here we are adding lan1 (ICSSG) and vpn0 (non ICSSG) to same bridge, as
they both are not ICSSG, we will still be running in dual EMAC mode.


This is v2 of the series [1]. It addresses commenst made on v1 [1].

Changes from v1 to v2:
*) Removed TAPRIO support patch from this series.
*) Stopped using devlink for enabling switch-mode as suggested by Andrew L
*) Added read_poll_timeout() in patch 1 / 3 as suggested by Andrew L.

[1] https://lore.kernel.org/all/20230830110847.1219515-4-danishanwar@ti.com/

Thanks and Regards,
Md Danish Anwar

MD Danish Anwar (3):
  net: ti: icssg-prueth: Add helper functions to configure FDB
  net: ti: icssg-switch: Add switchdev based driver for ethernet switch
    support
  net: ti: icssg-prueth: Add support for ICSSG switch firmware

 drivers/net/ethernet/ti/Kconfig               |   1 +
 drivers/net/ethernet/ti/Makefile              |   3 +-
 drivers/net/ethernet/ti/icssg/icssg_config.c  | 324 +++++++++++-
 drivers/net/ethernet/ti/icssg/icssg_config.h  |  26 +
 drivers/net/ethernet/ti/icssg/icssg_prueth.c  | 199 +++++++-
 drivers/net/ethernet/ti/icssg/icssg_prueth.h  |  36 ++
 .../net/ethernet/ti/icssg/icssg_switchdev.c   | 478 ++++++++++++++++++
 .../net/ethernet/ti/icssg/icssg_switchdev.h   |  13 +
 8 files changed, 1067 insertions(+), 13 deletions(-)
 create mode 100644 drivers/net/ethernet/ti/icssg/icssg_switchdev.c
 create mode 100644 drivers/net/ethernet/ti/icssg/icssg_switchdev.h

-- 
2.34.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [RFC PATCH v2 1/3] net: ti: icssg-prueth: Add helper functions to configure FDB
  2024-01-18  7:10 ` MD Danish Anwar
@ 2024-01-18  7:10   ` MD Danish Anwar
  -1 siblings, 0 replies; 34+ messages in thread
From: MD Danish Anwar @ 2024-01-18  7:10 UTC (permalink / raw)
  To: Rob Herring, Dan Carpenter, Jan Kiszka, Andrew Lunn,
	Vladimir Oltean, Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, MD Danish Anwar, Paolo Abeni,
	Jakub Kicinski, Eric Dumazet, David S. Miller
  Cc: linux-arm-kernel, netdev, linux-kernel, srk, r-gunasekaran

Introduce helper functions to configure firmware FDB tables, VLAN tables
and Port VLAN ID settings to aid adding Switch mode support.

Signed-off-by: MD Danish Anwar <danishanwar@ti.com>
---
 drivers/net/ethernet/ti/icssg/icssg_config.c | 188 +++++++++++++++++++
 drivers/net/ethernet/ti/icssg/icssg_config.h |  19 ++
 drivers/net/ethernet/ti/icssg/icssg_prueth.h |  12 ++
 3 files changed, 219 insertions(+)

diff --git a/drivers/net/ethernet/ti/icssg/icssg_config.c b/drivers/net/ethernet/ti/icssg/icssg_config.c
index 99de8a40ed60..afc10014ec03 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_config.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_config.c
@@ -469,3 +469,191 @@ void icssg_config_set_speed(struct prueth_emac *emac)
 
 	writeb(fw_speed, emac->dram.va + PORT_LINK_SPEED_OFFSET);
 }
+
+int icssg_send_fdb_msg(struct prueth_emac *emac, struct mgmt_cmd *cmd,
+		       struct mgmt_cmd_rsp *rsp)
+{
+	struct prueth *prueth = emac->prueth;
+	int slice = prueth_emac_slice(emac);
+	int addr, ret;
+
+	addr = icssg_queue_pop(prueth, slice == 0 ?
+			       ICSSG_CMD_POP_SLICE0 : ICSSG_CMD_POP_SLICE1);
+	if (addr < 0)
+		return addr;
+
+	/* First 4 bytes have FW owned buffer linking info which should
+	 * not be touched
+	 */
+	memcpy_toio(prueth->shram.va + addr + 4, cmd, sizeof(*cmd));
+	icssg_queue_push(prueth, slice == 0 ?
+			 ICSSG_CMD_PUSH_SLICE0 : ICSSG_CMD_PUSH_SLICE1, addr);
+	ret = read_poll_timeout(icssg_queue_pop, addr, addr >= 0,
+				2000, 20000000, false, prueth, slice == 0 ?
+				ICSSG_RSP_POP_SLICE0 : ICSSG_RSP_POP_SLICE1);
+	if (ret) {
+		netdev_err(emac->ndev, "Timedout sending HWQ message\n");
+		return ret;
+	}
+
+	memcpy_fromio(rsp, prueth->shram.va + addr, sizeof(*rsp));
+	/* Return buffer back for to pool */
+	icssg_queue_push(prueth, slice == 0 ?
+			 ICSSG_RSP_PUSH_SLICE0 : ICSSG_RSP_PUSH_SLICE1, addr);
+
+	return 0;
+}
+
+int icssg_fdb_add_del(struct prueth_emac *emac, const unsigned char *addr,
+		      u8 vid, u8 fid_c2, bool add)
+{
+	struct mgmt_cmd_rsp fdb_cmd_rsp = { 0 };
+	int slice = prueth_emac_slice(emac);
+	struct mgmt_cmd fdb_cmd = { 0 };
+	u8 mac_fid[ETH_ALEN + 2];
+	u16 fdb_slot;
+	u8 fid = vid;
+	int ret, i;
+
+	for (i = 0; i < ETH_ALEN; i++)
+		mac_fid[i] = addr[i];
+
+	/* 1-1 VID-FID mapping is already setup */
+	mac_fid[ETH_ALEN] = fid;
+	mac_fid[ETH_ALEN + 1] = 0;
+
+	fdb_slot = bitrev32(crc32_le(0, mac_fid, 8)) & PRUETH_SWITCH_FDB_MASK;
+
+	fdb_cmd.header = ICSSG_FW_MGMT_CMD_HEADER;
+	fdb_cmd.type   = ICSSG_FW_MGMT_FDB_CMD_TYPE;
+	fdb_cmd.seqnum = ++(emac->prueth->icssg_hwcmdseq);
+	if (add)
+		fdb_cmd.param  = ICSS_CMD_ADD_FDB;
+	else
+		fdb_cmd.param = ICSS_CMD_DEL_FDB;
+
+	fdb_cmd.param |= (slice << 4);
+
+	fid_c2 |= ICSSG_FDB_ENTRY_VALID;
+	memcpy(&fdb_cmd.cmd_args[0], addr, 4);
+	memcpy(&fdb_cmd.cmd_args[1], &addr[4], 2);
+	fdb_cmd.cmd_args[1] |= ((fid << 16) | (fid_c2 << 24));
+	fdb_cmd.cmd_args[2] = fdb_slot;
+
+	netdev_dbg(emac->ndev, "MAC %pM slot %X vlan %X FID %X\n",
+		   addr, fdb_slot, vid, fid);
+
+	ret = icssg_send_fdb_msg(emac, &fdb_cmd, &fdb_cmd_rsp);
+	if (ret)
+		return ret;
+
+	WARN_ON(fdb_cmd.seqnum != fdb_cmd_rsp.seqnum);
+	if (fdb_cmd_rsp.status == 1)
+		return 0;
+
+	return -EINVAL;
+}
+
+int icssg_fdb_lookup(struct prueth_emac *emac, const unsigned char *addr,
+		     u8 vid)
+{
+	struct mgmt_cmd_rsp fdb_cmd_rsp = { 0 };
+	int slice = prueth_emac_slice(emac);
+	struct mgmt_cmd fdb_cmd = { 0 };
+	struct prueth_fdb_slot *slot;
+	u8 mac_fid[ETH_ALEN + 2];
+	u16 fdb_slot;
+	u8 fid = vid;
+	int ret, i;
+
+	for (i = 0; i < ETH_ALEN; i++)
+		mac_fid[i] = addr[i];
+
+	/* 1-1 VID-FID mapping is already setup */
+	mac_fid[ETH_ALEN] = fid;
+	mac_fid[ETH_ALEN + 1] = 0;
+
+	fdb_slot = bitrev32(crc32_le(0, mac_fid, 8)) & PRUETH_SWITCH_FDB_MASK;
+
+	fdb_cmd.header = ICSSG_FW_MGMT_CMD_HEADER;
+	fdb_cmd.type   = ICSSG_FW_MGMT_FDB_CMD_TYPE;
+	fdb_cmd.seqnum = ++(emac->prueth->icssg_hwcmdseq);
+	fdb_cmd.param  = ICSS_CMD_GET_FDB_SLOT;
+
+	fdb_cmd.param |= (slice << 4);
+
+	memcpy(&fdb_cmd.cmd_args[0], addr, 4);
+	memcpy(&fdb_cmd.cmd_args[1], &addr[4], 2);
+	fdb_cmd.cmd_args[1] |= fid << 16;
+	fdb_cmd.cmd_args[2] = fdb_slot;
+
+	ret = icssg_send_fdb_msg(emac, &fdb_cmd, &fdb_cmd_rsp);
+	if (ret)
+		return ret;
+
+	WARN_ON(fdb_cmd.seqnum != fdb_cmd_rsp.seqnum);
+
+	slot = (struct prueth_fdb_slot __force *)(emac->dram.va + FDB_CMD_BUFFER);
+	for (i = 0; i < 4; i++) {
+		if (ether_addr_equal(addr, slot->mac) && vid == slot->fid)
+			return (slot->fid_c2 & ~ICSSG_FDB_ENTRY_VALID);
+		slot++;
+	}
+
+	return 0;
+}
+
+void icssg_vtbl_modify(struct prueth_emac *emac, u8 vid, u8 port_mask,
+		       u8 untag_mask, bool add)
+{
+	struct prueth *prueth = emac->prueth;
+	struct prueth_vlan_tbl *tbl;
+	u8 fid_c1;
+
+	tbl = prueth->vlan_tbl;
+	fid_c1 = tbl[vid].fid_c1;
+
+	/* FID_C1: bit0..2 port membership mask,
+	 * bit3..5 tagging mask for each port
+	 * bit6 Stream VID (not handled currently)
+	 * bit7 MC flood (not handled currently)
+	 */
+	if (add) {
+		fid_c1 |= (port_mask | port_mask << 3);
+		fid_c1 &= ~(untag_mask << 3);
+	} else {
+		fid_c1 &= ~(port_mask | port_mask << 3);
+	}
+
+	tbl[vid].fid_c1 = fid_c1;
+}
+
+u16 icssg_get_pvid(struct prueth_emac *emac)
+{
+	struct prueth *prueth = emac->prueth;
+	u32 pvid;
+
+	if (emac->port_id == PRUETH_PORT_MII0)
+		pvid = readl(prueth->shram.va + EMAC_ICSSG_SWITCH_PORT1_DEFAULT_VLAN_OFFSET);
+	else
+		pvid = readl(prueth->shram.va + EMAC_ICSSG_SWITCH_PORT2_DEFAULT_VLAN_OFFSET);
+
+	pvid = pvid >> 24;
+
+	return pvid;
+}
+
+void icssg_set_pvid(struct prueth *prueth, u8 vid, u8 port)
+{
+	u32 pvid;
+
+	/* only 256 VLANs are supported */
+	pvid = (u32 __force)cpu_to_be32((ETH_P_8021Q << 16) | (vid & 0xff));
+
+	if (port == PRUETH_PORT_MII0)
+		writel(pvid, prueth->shram.va + EMAC_ICSSG_SWITCH_PORT1_DEFAULT_VLAN_OFFSET);
+	else if (port == PRUETH_PORT_MII1)
+		writel(pvid, prueth->shram.va + EMAC_ICSSG_SWITCH_PORT2_DEFAULT_VLAN_OFFSET);
+	else
+		writel(pvid, prueth->shram.va + EMAC_ICSSG_SWITCH_PORT0_DEFAULT_VLAN_OFFSET);
+}
diff --git a/drivers/net/ethernet/ti/icssg/icssg_config.h b/drivers/net/ethernet/ti/icssg/icssg_config.h
index 43eb0922172a..0d5d5d253b7a 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_config.h
+++ b/drivers/net/ethernet/ti/icssg/icssg_config.h
@@ -35,6 +35,8 @@ struct icssg_flow_cfg {
 	(2 * (PRUETH_EMAC_BUF_POOL_SIZE * PRUETH_NUM_BUF_POOLS + \
 	 PRUETH_EMAC_RX_CTX_BUF_SIZE * 2))
 
+#define PRUETH_SWITCH_FDB_MASK ((SIZE_OF_FDB / NUMBER_OF_FDB_BUCKET_ENTRIES) - 1)
+
 struct icssg_rxq_ctx {
 	__le32 start[3];
 	__le32 end;
@@ -146,6 +148,23 @@ struct icssg_setclock_desc {
 #define ICSSG_TS_PUSH_SLICE0	40
 #define ICSSG_TS_PUSH_SLICE1	41
 
+struct mgmt_cmd {
+	u8 param;
+	u8 seqnum;
+	u8 type;
+	u8 header;
+	u32 cmd_args[3];
+} __packed;
+
+struct mgmt_cmd_rsp {
+	u32 reserved;
+	u8 status;
+	u8 seqnum;
+	u8 type;
+	u8 header;
+	u32 cmd_args[3];
+} __packed;
+
 /* FDB FID_C2 flag definitions */
 /* Indicates host port membership.*/
 #define ICSSG_FDB_ENTRY_P0_MEMBERSHIP         BIT(0)
diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h
index 8b6d6b497010..006f77217bd1 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.h
+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h
@@ -210,6 +210,7 @@ struct prueth_pdata {
  * @emacs_initialized: num of EMACs/ext ports that are up/running
  * @iep0: pointer to IEP0 device
  * @iep1: pointer to IEP1 device
+ * @vlan_tbl: VLAN-FID table pointer
  */
 struct prueth {
 	struct device *dev;
@@ -234,6 +235,7 @@ struct prueth {
 	int emacs_initialized;
 	struct icss_iep *iep0;
 	struct icss_iep *iep1;
+	struct prueth_vlan_tbl *vlan_tbl;
 };
 
 struct emac_tx_ts_response {
@@ -279,6 +281,16 @@ int icssg_queue_pop(struct prueth *prueth, u8 queue);
 void icssg_queue_push(struct prueth *prueth, int queue, u16 addr);
 u32 icssg_queue_level(struct prueth *prueth, int queue);
 
+int icssg_send_fdb_msg(struct prueth_emac *emac, struct mgmt_cmd *cmd,
+		       struct mgmt_cmd_rsp *rsp);
+int icssg_fdb_add_del(struct prueth_emac *emac,  const unsigned char *addr,
+		      u8 vid, u8 fid_c2, bool add);
+int icssg_fdb_lookup(struct prueth_emac *emac, const unsigned char *addr,
+		     u8 vid);
+void icssg_vtbl_modify(struct prueth_emac *emac, u8 vid, u8 port_mask,
+		       u8 untag_mask, bool add);
+u16 icssg_get_pvid(struct prueth_emac *emac);
+void icssg_set_pvid(struct prueth *prueth, u8 vid, u8 port);
 #define prueth_napi_to_tx_chn(pnapi) \
 	container_of(pnapi, struct prueth_tx_chn, napi_tx)
 
-- 
2.34.1


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

* [RFC PATCH v2 1/3] net: ti: icssg-prueth: Add helper functions to configure FDB
@ 2024-01-18  7:10   ` MD Danish Anwar
  0 siblings, 0 replies; 34+ messages in thread
From: MD Danish Anwar @ 2024-01-18  7:10 UTC (permalink / raw)
  To: Rob Herring, Dan Carpenter, Jan Kiszka, Andrew Lunn,
	Vladimir Oltean, Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, MD Danish Anwar, Paolo Abeni,
	Jakub Kicinski, Eric Dumazet, David S. Miller
  Cc: linux-arm-kernel, netdev, linux-kernel, srk, r-gunasekaran

Introduce helper functions to configure firmware FDB tables, VLAN tables
and Port VLAN ID settings to aid adding Switch mode support.

Signed-off-by: MD Danish Anwar <danishanwar@ti.com>
---
 drivers/net/ethernet/ti/icssg/icssg_config.c | 188 +++++++++++++++++++
 drivers/net/ethernet/ti/icssg/icssg_config.h |  19 ++
 drivers/net/ethernet/ti/icssg/icssg_prueth.h |  12 ++
 3 files changed, 219 insertions(+)

diff --git a/drivers/net/ethernet/ti/icssg/icssg_config.c b/drivers/net/ethernet/ti/icssg/icssg_config.c
index 99de8a40ed60..afc10014ec03 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_config.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_config.c
@@ -469,3 +469,191 @@ void icssg_config_set_speed(struct prueth_emac *emac)
 
 	writeb(fw_speed, emac->dram.va + PORT_LINK_SPEED_OFFSET);
 }
+
+int icssg_send_fdb_msg(struct prueth_emac *emac, struct mgmt_cmd *cmd,
+		       struct mgmt_cmd_rsp *rsp)
+{
+	struct prueth *prueth = emac->prueth;
+	int slice = prueth_emac_slice(emac);
+	int addr, ret;
+
+	addr = icssg_queue_pop(prueth, slice == 0 ?
+			       ICSSG_CMD_POP_SLICE0 : ICSSG_CMD_POP_SLICE1);
+	if (addr < 0)
+		return addr;
+
+	/* First 4 bytes have FW owned buffer linking info which should
+	 * not be touched
+	 */
+	memcpy_toio(prueth->shram.va + addr + 4, cmd, sizeof(*cmd));
+	icssg_queue_push(prueth, slice == 0 ?
+			 ICSSG_CMD_PUSH_SLICE0 : ICSSG_CMD_PUSH_SLICE1, addr);
+	ret = read_poll_timeout(icssg_queue_pop, addr, addr >= 0,
+				2000, 20000000, false, prueth, slice == 0 ?
+				ICSSG_RSP_POP_SLICE0 : ICSSG_RSP_POP_SLICE1);
+	if (ret) {
+		netdev_err(emac->ndev, "Timedout sending HWQ message\n");
+		return ret;
+	}
+
+	memcpy_fromio(rsp, prueth->shram.va + addr, sizeof(*rsp));
+	/* Return buffer back for to pool */
+	icssg_queue_push(prueth, slice == 0 ?
+			 ICSSG_RSP_PUSH_SLICE0 : ICSSG_RSP_PUSH_SLICE1, addr);
+
+	return 0;
+}
+
+int icssg_fdb_add_del(struct prueth_emac *emac, const unsigned char *addr,
+		      u8 vid, u8 fid_c2, bool add)
+{
+	struct mgmt_cmd_rsp fdb_cmd_rsp = { 0 };
+	int slice = prueth_emac_slice(emac);
+	struct mgmt_cmd fdb_cmd = { 0 };
+	u8 mac_fid[ETH_ALEN + 2];
+	u16 fdb_slot;
+	u8 fid = vid;
+	int ret, i;
+
+	for (i = 0; i < ETH_ALEN; i++)
+		mac_fid[i] = addr[i];
+
+	/* 1-1 VID-FID mapping is already setup */
+	mac_fid[ETH_ALEN] = fid;
+	mac_fid[ETH_ALEN + 1] = 0;
+
+	fdb_slot = bitrev32(crc32_le(0, mac_fid, 8)) & PRUETH_SWITCH_FDB_MASK;
+
+	fdb_cmd.header = ICSSG_FW_MGMT_CMD_HEADER;
+	fdb_cmd.type   = ICSSG_FW_MGMT_FDB_CMD_TYPE;
+	fdb_cmd.seqnum = ++(emac->prueth->icssg_hwcmdseq);
+	if (add)
+		fdb_cmd.param  = ICSS_CMD_ADD_FDB;
+	else
+		fdb_cmd.param = ICSS_CMD_DEL_FDB;
+
+	fdb_cmd.param |= (slice << 4);
+
+	fid_c2 |= ICSSG_FDB_ENTRY_VALID;
+	memcpy(&fdb_cmd.cmd_args[0], addr, 4);
+	memcpy(&fdb_cmd.cmd_args[1], &addr[4], 2);
+	fdb_cmd.cmd_args[1] |= ((fid << 16) | (fid_c2 << 24));
+	fdb_cmd.cmd_args[2] = fdb_slot;
+
+	netdev_dbg(emac->ndev, "MAC %pM slot %X vlan %X FID %X\n",
+		   addr, fdb_slot, vid, fid);
+
+	ret = icssg_send_fdb_msg(emac, &fdb_cmd, &fdb_cmd_rsp);
+	if (ret)
+		return ret;
+
+	WARN_ON(fdb_cmd.seqnum != fdb_cmd_rsp.seqnum);
+	if (fdb_cmd_rsp.status == 1)
+		return 0;
+
+	return -EINVAL;
+}
+
+int icssg_fdb_lookup(struct prueth_emac *emac, const unsigned char *addr,
+		     u8 vid)
+{
+	struct mgmt_cmd_rsp fdb_cmd_rsp = { 0 };
+	int slice = prueth_emac_slice(emac);
+	struct mgmt_cmd fdb_cmd = { 0 };
+	struct prueth_fdb_slot *slot;
+	u8 mac_fid[ETH_ALEN + 2];
+	u16 fdb_slot;
+	u8 fid = vid;
+	int ret, i;
+
+	for (i = 0; i < ETH_ALEN; i++)
+		mac_fid[i] = addr[i];
+
+	/* 1-1 VID-FID mapping is already setup */
+	mac_fid[ETH_ALEN] = fid;
+	mac_fid[ETH_ALEN + 1] = 0;
+
+	fdb_slot = bitrev32(crc32_le(0, mac_fid, 8)) & PRUETH_SWITCH_FDB_MASK;
+
+	fdb_cmd.header = ICSSG_FW_MGMT_CMD_HEADER;
+	fdb_cmd.type   = ICSSG_FW_MGMT_FDB_CMD_TYPE;
+	fdb_cmd.seqnum = ++(emac->prueth->icssg_hwcmdseq);
+	fdb_cmd.param  = ICSS_CMD_GET_FDB_SLOT;
+
+	fdb_cmd.param |= (slice << 4);
+
+	memcpy(&fdb_cmd.cmd_args[0], addr, 4);
+	memcpy(&fdb_cmd.cmd_args[1], &addr[4], 2);
+	fdb_cmd.cmd_args[1] |= fid << 16;
+	fdb_cmd.cmd_args[2] = fdb_slot;
+
+	ret = icssg_send_fdb_msg(emac, &fdb_cmd, &fdb_cmd_rsp);
+	if (ret)
+		return ret;
+
+	WARN_ON(fdb_cmd.seqnum != fdb_cmd_rsp.seqnum);
+
+	slot = (struct prueth_fdb_slot __force *)(emac->dram.va + FDB_CMD_BUFFER);
+	for (i = 0; i < 4; i++) {
+		if (ether_addr_equal(addr, slot->mac) && vid == slot->fid)
+			return (slot->fid_c2 & ~ICSSG_FDB_ENTRY_VALID);
+		slot++;
+	}
+
+	return 0;
+}
+
+void icssg_vtbl_modify(struct prueth_emac *emac, u8 vid, u8 port_mask,
+		       u8 untag_mask, bool add)
+{
+	struct prueth *prueth = emac->prueth;
+	struct prueth_vlan_tbl *tbl;
+	u8 fid_c1;
+
+	tbl = prueth->vlan_tbl;
+	fid_c1 = tbl[vid].fid_c1;
+
+	/* FID_C1: bit0..2 port membership mask,
+	 * bit3..5 tagging mask for each port
+	 * bit6 Stream VID (not handled currently)
+	 * bit7 MC flood (not handled currently)
+	 */
+	if (add) {
+		fid_c1 |= (port_mask | port_mask << 3);
+		fid_c1 &= ~(untag_mask << 3);
+	} else {
+		fid_c1 &= ~(port_mask | port_mask << 3);
+	}
+
+	tbl[vid].fid_c1 = fid_c1;
+}
+
+u16 icssg_get_pvid(struct prueth_emac *emac)
+{
+	struct prueth *prueth = emac->prueth;
+	u32 pvid;
+
+	if (emac->port_id == PRUETH_PORT_MII0)
+		pvid = readl(prueth->shram.va + EMAC_ICSSG_SWITCH_PORT1_DEFAULT_VLAN_OFFSET);
+	else
+		pvid = readl(prueth->shram.va + EMAC_ICSSG_SWITCH_PORT2_DEFAULT_VLAN_OFFSET);
+
+	pvid = pvid >> 24;
+
+	return pvid;
+}
+
+void icssg_set_pvid(struct prueth *prueth, u8 vid, u8 port)
+{
+	u32 pvid;
+
+	/* only 256 VLANs are supported */
+	pvid = (u32 __force)cpu_to_be32((ETH_P_8021Q << 16) | (vid & 0xff));
+
+	if (port == PRUETH_PORT_MII0)
+		writel(pvid, prueth->shram.va + EMAC_ICSSG_SWITCH_PORT1_DEFAULT_VLAN_OFFSET);
+	else if (port == PRUETH_PORT_MII1)
+		writel(pvid, prueth->shram.va + EMAC_ICSSG_SWITCH_PORT2_DEFAULT_VLAN_OFFSET);
+	else
+		writel(pvid, prueth->shram.va + EMAC_ICSSG_SWITCH_PORT0_DEFAULT_VLAN_OFFSET);
+}
diff --git a/drivers/net/ethernet/ti/icssg/icssg_config.h b/drivers/net/ethernet/ti/icssg/icssg_config.h
index 43eb0922172a..0d5d5d253b7a 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_config.h
+++ b/drivers/net/ethernet/ti/icssg/icssg_config.h
@@ -35,6 +35,8 @@ struct icssg_flow_cfg {
 	(2 * (PRUETH_EMAC_BUF_POOL_SIZE * PRUETH_NUM_BUF_POOLS + \
 	 PRUETH_EMAC_RX_CTX_BUF_SIZE * 2))
 
+#define PRUETH_SWITCH_FDB_MASK ((SIZE_OF_FDB / NUMBER_OF_FDB_BUCKET_ENTRIES) - 1)
+
 struct icssg_rxq_ctx {
 	__le32 start[3];
 	__le32 end;
@@ -146,6 +148,23 @@ struct icssg_setclock_desc {
 #define ICSSG_TS_PUSH_SLICE0	40
 #define ICSSG_TS_PUSH_SLICE1	41
 
+struct mgmt_cmd {
+	u8 param;
+	u8 seqnum;
+	u8 type;
+	u8 header;
+	u32 cmd_args[3];
+} __packed;
+
+struct mgmt_cmd_rsp {
+	u32 reserved;
+	u8 status;
+	u8 seqnum;
+	u8 type;
+	u8 header;
+	u32 cmd_args[3];
+} __packed;
+
 /* FDB FID_C2 flag definitions */
 /* Indicates host port membership.*/
 #define ICSSG_FDB_ENTRY_P0_MEMBERSHIP         BIT(0)
diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h
index 8b6d6b497010..006f77217bd1 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.h
+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h
@@ -210,6 +210,7 @@ struct prueth_pdata {
  * @emacs_initialized: num of EMACs/ext ports that are up/running
  * @iep0: pointer to IEP0 device
  * @iep1: pointer to IEP1 device
+ * @vlan_tbl: VLAN-FID table pointer
  */
 struct prueth {
 	struct device *dev;
@@ -234,6 +235,7 @@ struct prueth {
 	int emacs_initialized;
 	struct icss_iep *iep0;
 	struct icss_iep *iep1;
+	struct prueth_vlan_tbl *vlan_tbl;
 };
 
 struct emac_tx_ts_response {
@@ -279,6 +281,16 @@ int icssg_queue_pop(struct prueth *prueth, u8 queue);
 void icssg_queue_push(struct prueth *prueth, int queue, u16 addr);
 u32 icssg_queue_level(struct prueth *prueth, int queue);
 
+int icssg_send_fdb_msg(struct prueth_emac *emac, struct mgmt_cmd *cmd,
+		       struct mgmt_cmd_rsp *rsp);
+int icssg_fdb_add_del(struct prueth_emac *emac,  const unsigned char *addr,
+		      u8 vid, u8 fid_c2, bool add);
+int icssg_fdb_lookup(struct prueth_emac *emac, const unsigned char *addr,
+		     u8 vid);
+void icssg_vtbl_modify(struct prueth_emac *emac, u8 vid, u8 port_mask,
+		       u8 untag_mask, bool add);
+u16 icssg_get_pvid(struct prueth_emac *emac);
+void icssg_set_pvid(struct prueth *prueth, u8 vid, u8 port);
 #define prueth_napi_to_tx_chn(pnapi) \
 	container_of(pnapi, struct prueth_tx_chn, napi_tx)
 
-- 
2.34.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [RFC PATCH v2 2/3] net: ti: icssg-switch: Add switchdev based driver for ethernet switch support
  2024-01-18  7:10 ` MD Danish Anwar
@ 2024-01-18  7:10   ` MD Danish Anwar
  -1 siblings, 0 replies; 34+ messages in thread
From: MD Danish Anwar @ 2024-01-18  7:10 UTC (permalink / raw)
  To: Rob Herring, Dan Carpenter, Jan Kiszka, Andrew Lunn,
	Vladimir Oltean, Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, MD Danish Anwar, Paolo Abeni,
	Jakub Kicinski, Eric Dumazet, David S. Miller
  Cc: linux-arm-kernel, netdev, linux-kernel, srk, r-gunasekaran

ICSSG can operating in switch mode with 2 ext port and 1 host port with
VLAN/FDB/MDB and STP offloading. Add switchdev based driver to
support the same.

Driver itself will be integrated with icssg_prueth in future commits

Signed-off-by: MD Danish Anwar <danishanwar@ti.com>
---
 drivers/net/ethernet/ti/icssg/icssg_prueth.c  |   1 +
 drivers/net/ethernet/ti/icssg/icssg_prueth.h  |  24 +
 .../net/ethernet/ti/icssg/icssg_switchdev.c   | 478 ++++++++++++++++++
 .../net/ethernet/ti/icssg/icssg_switchdev.h   |  13 +
 4 files changed, 516 insertions(+)
 create mode 100644 drivers/net/ethernet/ti/icssg/icssg_switchdev.c
 create mode 100644 drivers/net/ethernet/ti/icssg/icssg_switchdev.h

diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
index 411898a4f38c..38d41ba6762a 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
@@ -30,6 +30,7 @@
 
 #include "icssg_prueth.h"
 #include "icssg_mii_rt.h"
+#include "icssg_switchdev.h"
 #include "../k3-cppi-desc-pool.h"
 
 #define PRUETH_MODULE_DESCRIPTION "PRUSS ICSSG Ethernet driver"
diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h
index 006f77217bd1..5b90e8f8ee48 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.h
+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h
@@ -174,6 +174,9 @@ struct prueth_emac {
 
 	struct pruss_mem_region dram;
 
+	bool offload_fwd_mark;
+	int port_vlan;
+
 	struct delayed_work stats_work;
 	u64 stats[ICSSG_NUM_STATS];
 };
@@ -182,10 +185,12 @@ struct prueth_emac {
  * struct prueth_pdata - PRUeth platform data
  * @fdqring_mode: Free desc queue mode
  * @quirk_10m_link_issue: 10M link detect errata
+ * @switch_mode: switch firmware support
  */
 struct prueth_pdata {
 	enum k3_ring_mode fdqring_mode;
 	u32	quirk_10m_link_issue:1;
+	u32	switch_mode:1;
 };
 
 /**
@@ -211,6 +216,15 @@ struct prueth_pdata {
  * @iep0: pointer to IEP0 device
  * @iep1: pointer to IEP1 device
  * @vlan_tbl: VLAN-FID table pointer
+ * @hw_bridge_dev: pointer to HW bridge net device
+ * @br_members: bitmask of bridge member ports
+ * @prueth_netdevice_nb: netdevice notifier block
+ * @prueth_switchdevice_nb: switchdev notifier block
+ * @prueth_switchdev_bl_nb: switchdev blocking notifier block
+ * @is_switch_mode: flag to indicate if device is in Switch mode
+ * @is_switchmode_supported: indicates platform support for switch mode
+ * @switch_id: ID for mapping switch ports to bridge
+ * @default_vlan: Default VLAN for host
  */
 struct prueth {
 	struct device *dev;
@@ -236,6 +250,16 @@ struct prueth {
 	struct icss_iep *iep0;
 	struct icss_iep *iep1;
 	struct prueth_vlan_tbl *vlan_tbl;
+
+	struct net_device *hw_bridge_dev;
+	u8 br_members;
+	struct notifier_block prueth_netdevice_nb;
+	struct notifier_block prueth_switchdev_nb;
+	struct notifier_block prueth_switchdev_bl_nb;
+	bool is_switch_mode;
+	bool is_switchmode_supported;
+	unsigned char switch_id[MAX_PHYS_ITEM_ID_LEN];
+	int default_vlan;
 };
 
 struct emac_tx_ts_response {
diff --git a/drivers/net/ethernet/ti/icssg/icssg_switchdev.c b/drivers/net/ethernet/ti/icssg/icssg_switchdev.c
new file mode 100644
index 000000000000..48d8ed4fa7a8
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssg/icssg_switchdev.c
@@ -0,0 +1,478 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* Texas Instruments K3 ICSSG Ethernet Switchdev Driver
+ *
+ * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/if_bridge.h>
+#include <linux/netdevice.h>
+#include <linux/workqueue.h>
+#include <net/switchdev.h>
+
+#include "icssg_prueth.h"
+#include "icssg_switchdev.h"
+#include "icss_mii_rt.h"
+
+struct prueth_switchdev_event_work {
+	struct work_struct work;
+	struct switchdev_notifier_fdb_info fdb_info;
+	struct prueth_emac *emac;
+	unsigned long event;
+};
+
+static int prueth_switchdev_stp_state_set(struct prueth_emac *emac,
+					  u8 state)
+{
+	enum icssg_port_state_cmd emac_state;
+	int ret = 0;
+
+	switch (state) {
+	case BR_STATE_FORWARDING:
+		emac_state = ICSSG_EMAC_PORT_FORWARD;
+		break;
+	case BR_STATE_DISABLED:
+		emac_state = ICSSG_EMAC_PORT_DISABLE;
+		break;
+	case BR_STATE_LEARNING:
+	case BR_STATE_LISTENING:
+	case BR_STATE_BLOCKING:
+		emac_state = ICSSG_EMAC_PORT_BLOCK;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	emac_set_port_state(emac, emac_state);
+	netdev_dbg(emac->ndev, "STP state: %u\n", emac_state);
+
+	return ret;
+}
+
+static int prueth_switchdev_attr_br_flags_set(struct prueth_emac *emac,
+					      struct net_device *orig_dev,
+					      struct switchdev_brport_flags brport_flags)
+{
+	enum icssg_port_state_cmd emac_state;
+
+	if (brport_flags.mask & BR_MCAST_FLOOD)
+		emac_state = ICSSG_EMAC_PORT_MC_FLOODING_ENABLE;
+	else
+		emac_state = ICSSG_EMAC_PORT_MC_FLOODING_DISABLE;
+
+	netdev_dbg(emac->ndev, "BR_MCAST_FLOOD: %d port %u\n",
+		   emac_state, emac->port_id);
+
+	emac_set_port_state(emac, emac_state);
+
+	return 0;
+}
+
+static int prueth_switchdev_attr_br_flags_pre_set(struct net_device *netdev,
+						  struct switchdev_brport_flags brport_flags)
+{
+	if (brport_flags.mask & ~(BR_LEARNING | BR_MCAST_FLOOD))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int prueth_switchdev_attr_set(struct net_device *ndev, const void *ctx,
+				     const struct switchdev_attr *attr,
+				     struct netlink_ext_ack *extack)
+{
+	struct prueth_emac *emac = netdev_priv(ndev);
+	int ret;
+
+	netdev_dbg(ndev, "attr: id %u port: %u\n", attr->id, emac->port_id);
+
+	switch (attr->id) {
+	case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS:
+		ret = prueth_switchdev_attr_br_flags_pre_set(ndev,
+							     attr->u.brport_flags);
+		break;
+	case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
+		ret = prueth_switchdev_stp_state_set(emac,
+						     attr->u.stp_state);
+		netdev_dbg(ndev, "stp state: %u\n", attr->u.stp_state);
+		break;
+	case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
+		ret = prueth_switchdev_attr_br_flags_set(emac, attr->orig_dev,
+							 attr->u.brport_flags);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+
+	return ret;
+}
+
+static void prueth_switchdev_fdb_offload_notify(struct net_device *ndev,
+						struct switchdev_notifier_fdb_info *rcv)
+{
+	struct switchdev_notifier_fdb_info info;
+
+	memset(&info, 0, sizeof(info));
+	info.addr = rcv->addr;
+	info.vid = rcv->vid;
+	info.offloaded = true;
+	call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED,
+				 ndev, &info.info, NULL);
+}
+
+static void prueth_switchdev_event_work(struct work_struct *work)
+{
+	struct prueth_switchdev_event_work *switchdev_work =
+		container_of(work, struct prueth_switchdev_event_work, work);
+	struct prueth_emac *emac = switchdev_work->emac;
+	struct switchdev_notifier_fdb_info *fdb;
+	int port_id = emac->port_id;
+	int ret;
+
+	rtnl_lock();
+	switch (switchdev_work->event) {
+	case SWITCHDEV_FDB_ADD_TO_DEVICE:
+		fdb = &switchdev_work->fdb_info;
+
+		netdev_dbg(emac->ndev, "prueth_fdb_add: MACID = %pM vid = %u flags = %u %u -- port %d\n",
+			   fdb->addr, fdb->vid, fdb->added_by_user,
+			   fdb->offloaded, port_id);
+
+		if (!fdb->added_by_user)
+			break;
+		if (memcmp(emac->mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0)
+			break;
+
+		ret = icssg_fdb_add_del(emac, fdb->addr, fdb->vid,
+					BIT(port_id), true);
+		if (!ret)
+			prueth_switchdev_fdb_offload_notify(emac->ndev, fdb);
+		break;
+	case SWITCHDEV_FDB_DEL_TO_DEVICE:
+		fdb = &switchdev_work->fdb_info;
+
+		netdev_dbg(emac->ndev, "prueth_fdb_del: MACID = %pM vid = %u flags = %u %u -- port %d\n",
+			   fdb->addr, fdb->vid, fdb->added_by_user,
+			   fdb->offloaded, port_id);
+
+		if (!fdb->added_by_user)
+			break;
+		if (memcmp(emac->mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0)
+			break;
+		icssg_fdb_add_del(emac, fdb->addr, fdb->vid,
+				  BIT(port_id), false);
+		break;
+	default:
+		break;
+	}
+	rtnl_unlock();
+
+	kfree(switchdev_work->fdb_info.addr);
+	kfree(switchdev_work);
+	dev_put(emac->ndev);
+}
+
+static int prueth_switchdev_event(struct notifier_block *unused,
+				  unsigned long event, void *ptr)
+{
+	struct net_device *ndev = switchdev_notifier_info_to_dev(ptr);
+	struct prueth_switchdev_event_work *switchdev_work;
+	struct switchdev_notifier_fdb_info *fdb_info = ptr;
+	struct prueth_emac *emac = netdev_priv(ndev);
+	int err;
+
+	if (!prueth_dev_check(ndev))
+		return NOTIFY_DONE;
+
+	if (event == SWITCHDEV_PORT_ATTR_SET) {
+		err = switchdev_handle_port_attr_set(ndev, ptr,
+						     prueth_dev_check,
+						     prueth_switchdev_attr_set);
+		return notifier_from_errno(err);
+	}
+
+	switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC);
+	if (WARN_ON(!switchdev_work))
+		return NOTIFY_BAD;
+
+	INIT_WORK(&switchdev_work->work, prueth_switchdev_event_work);
+	switchdev_work->emac = emac;
+	switchdev_work->event = event;
+
+	switch (event) {
+	case SWITCHDEV_FDB_ADD_TO_DEVICE:
+	case SWITCHDEV_FDB_DEL_TO_DEVICE:
+		memcpy(&switchdev_work->fdb_info, ptr,
+		       sizeof(switchdev_work->fdb_info));
+		switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC);
+		if (!switchdev_work->fdb_info.addr)
+			goto err_addr_alloc;
+		ether_addr_copy((u8 *)switchdev_work->fdb_info.addr,
+				fdb_info->addr);
+		dev_hold(ndev);
+		break;
+	default:
+		kfree(switchdev_work);
+		return NOTIFY_DONE;
+	}
+
+	queue_work(system_long_wq, &switchdev_work->work);
+
+	return NOTIFY_DONE;
+
+err_addr_alloc:
+	kfree(switchdev_work);
+	return NOTIFY_BAD;
+}
+
+static int prueth_switchdev_vlan_add(struct prueth_emac *emac, bool untag, bool pvid,
+				     u8 vid, struct net_device *orig_dev)
+{
+	bool cpu_port = netif_is_bridge_master(orig_dev);
+	int untag_mask = 0;
+	int port_mask;
+	int ret = 0;
+
+	if (cpu_port)
+		port_mask = BIT(PRUETH_PORT_HOST);
+	else
+		port_mask = BIT(emac->port_id);
+
+	if (untag)
+		untag_mask = port_mask;
+
+	icssg_vtbl_modify(emac, vid, port_mask, untag_mask, true);
+
+	netdev_dbg(emac->ndev, "VID add vid:%u port_mask:%X untag_mask %X PVID %d\n",
+		   vid, port_mask, untag_mask, pvid);
+
+	if (!pvid)
+		return ret;
+
+	icssg_set_pvid(emac->prueth, vid, emac->port_id);
+
+	return ret;
+}
+
+static int prueth_switchdev_vlan_del(struct prueth_emac *emac, u16 vid,
+				     struct net_device *orig_dev)
+{
+	bool cpu_port = netif_is_bridge_master(orig_dev);
+	int port_mask;
+	int ret = 0;
+
+	if (cpu_port)
+		port_mask = BIT(PRUETH_PORT_HOST);
+	else
+		port_mask = BIT(emac->port_id);
+
+	icssg_vtbl_modify(emac, vid, port_mask, 0, false);
+
+	if (cpu_port)
+		icssg_fdb_add_del(emac, emac->mac_addr, vid,
+				  BIT(PRUETH_PORT_HOST), false);
+
+	if (vid == icssg_get_pvid(emac))
+		icssg_set_pvid(emac->prueth, 0, emac->port_id);
+
+	netdev_dbg(emac->ndev, "VID del vid:%u port_mask:%X\n",
+		   vid, port_mask);
+
+	return ret;
+}
+
+static int prueth_switchdev_vlans_add(struct prueth_emac *emac,
+				      const struct switchdev_obj_port_vlan *vlan)
+{
+	bool untag = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
+	struct net_device *orig_dev = vlan->obj.orig_dev;
+	bool cpu_port = netif_is_bridge_master(orig_dev);
+	bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
+
+	netdev_dbg(emac->ndev, "VID add vid:%u flags:%X\n",
+		   vlan->vid, vlan->flags);
+
+	if (cpu_port && !(vlan->flags & BRIDGE_VLAN_INFO_BRENTRY))
+		return 0;
+
+	if (vlan->vid > 0xff)
+		return 0;
+
+	return prueth_switchdev_vlan_add(emac, untag, pvid, vlan->vid,
+					 orig_dev);
+}
+
+static int prueth_switchdev_vlans_del(struct prueth_emac *emac,
+				      const struct switchdev_obj_port_vlan *vlan)
+{
+	if (vlan->vid > 0xff)
+		return 0;
+
+	return prueth_switchdev_vlan_del(emac, vlan->vid,
+					 vlan->obj.orig_dev);
+}
+
+static int prueth_switchdev_mdb_add(struct prueth_emac *emac,
+				    struct switchdev_obj_port_mdb *mdb)
+{
+	struct net_device *orig_dev = mdb->obj.orig_dev;
+	u8 port_mask, fid_c2;
+	bool cpu_port;
+	int err;
+
+	cpu_port = netif_is_bridge_master(orig_dev);
+
+	if (cpu_port)
+		port_mask = BIT(PRUETH_PORT_HOST);
+	else
+		port_mask = BIT(emac->port_id);
+
+	fid_c2 = icssg_fdb_lookup(emac, mdb->addr, mdb->vid);
+
+	err = icssg_fdb_add_del(emac, mdb->addr, mdb->vid, fid_c2 | port_mask, true);
+	netdev_dbg(emac->ndev, "MDB add vid %u:%pM  ports: %X\n",
+		   mdb->vid, mdb->addr, port_mask);
+
+	return err;
+}
+
+static int prueth_switchdev_mdb_del(struct prueth_emac *emac,
+				    struct switchdev_obj_port_mdb *mdb)
+{
+	struct net_device *orig_dev = mdb->obj.orig_dev;
+	int del_mask, ret, fid_c2;
+	bool cpu_port;
+
+	cpu_port = netif_is_bridge_master(orig_dev);
+
+	if (cpu_port)
+		del_mask = BIT(PRUETH_PORT_HOST);
+	else
+		del_mask = BIT(emac->port_id);
+
+	fid_c2 = icssg_fdb_lookup(emac, mdb->addr, mdb->vid);
+
+	if (fid_c2 & ~del_mask)
+		ret = icssg_fdb_add_del(emac, mdb->addr, mdb->vid, fid_c2 & ~del_mask, true);
+	else
+		ret = icssg_fdb_add_del(emac, mdb->addr, mdb->vid, 0, false);
+
+	netdev_dbg(emac->ndev, "MDB del vid %u:%pM  ports: %X\n",
+		   mdb->vid, mdb->addr, del_mask);
+
+	return ret;
+}
+
+static int prueth_switchdev_obj_add(struct net_device *ndev, const void *ctx,
+				    const struct switchdev_obj *obj,
+				    struct netlink_ext_ack *extack)
+{
+	struct switchdev_obj_port_vlan *vlan = SWITCHDEV_OBJ_PORT_VLAN(obj);
+	struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj);
+	struct prueth_emac *emac = netdev_priv(ndev);
+	int err = 0;
+
+	netdev_dbg(ndev, "obj_add: id %u port: %u\n", obj->id, emac->port_id);
+
+	switch (obj->id) {
+	case SWITCHDEV_OBJ_ID_PORT_VLAN:
+		err = prueth_switchdev_vlans_add(emac, vlan);
+		break;
+	case SWITCHDEV_OBJ_ID_PORT_MDB:
+	case SWITCHDEV_OBJ_ID_HOST_MDB:
+		err = prueth_switchdev_mdb_add(emac, mdb);
+		break;
+	default:
+		err = -EOPNOTSUPP;
+		break;
+	}
+
+	return err;
+}
+
+static int prueth_switchdev_obj_del(struct net_device *ndev, const void *ctx,
+				    const struct switchdev_obj *obj)
+{
+	struct switchdev_obj_port_vlan *vlan = SWITCHDEV_OBJ_PORT_VLAN(obj);
+	struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj);
+	struct prueth_emac *emac = netdev_priv(ndev);
+	int err = 0;
+
+	netdev_dbg(ndev, "obj_del: id %u port: %u\n", obj->id, emac->port_id);
+
+	switch (obj->id) {
+	case SWITCHDEV_OBJ_ID_PORT_VLAN:
+		err = prueth_switchdev_vlans_del(emac, vlan);
+		break;
+	case SWITCHDEV_OBJ_ID_PORT_MDB:
+	case SWITCHDEV_OBJ_ID_HOST_MDB:
+		err = prueth_switchdev_mdb_del(emac, mdb);
+		break;
+	default:
+		err = -EOPNOTSUPP;
+		break;
+	}
+
+	return err;
+}
+
+static int prueth_switchdev_blocking_event(struct notifier_block *unused,
+					   unsigned long event, void *ptr)
+{
+	struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
+	int err;
+
+	switch (event) {
+	case SWITCHDEV_PORT_OBJ_ADD:
+		err = switchdev_handle_port_obj_add(dev, ptr,
+						    prueth_dev_check,
+						    prueth_switchdev_obj_add);
+		return notifier_from_errno(err);
+	case SWITCHDEV_PORT_OBJ_DEL:
+		err = switchdev_handle_port_obj_del(dev, ptr,
+						    prueth_dev_check,
+						    prueth_switchdev_obj_del);
+		return notifier_from_errno(err);
+	case SWITCHDEV_PORT_ATTR_SET:
+		err = switchdev_handle_port_attr_set(dev, ptr,
+						     prueth_dev_check,
+						     prueth_switchdev_attr_set);
+		return notifier_from_errno(err);
+	default:
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+int prueth_switchdev_register_notifiers(struct prueth *prueth)
+{
+	int ret = 0;
+
+	prueth->prueth_switchdev_nb.notifier_call = &prueth_switchdev_event;
+	ret = register_switchdev_notifier(&prueth->prueth_switchdev_nb);
+	if (ret) {
+		dev_err(prueth->dev, "register switchdev notifier fail ret:%d\n",
+			ret);
+		return ret;
+	}
+
+	prueth->prueth_switchdev_bl_nb.notifier_call = &prueth_switchdev_blocking_event;
+	ret = register_switchdev_blocking_notifier(&prueth->prueth_switchdev_bl_nb);
+	if (ret) {
+		dev_err(prueth->dev, "register switchdev blocking notifier ret:%d\n",
+			ret);
+		unregister_switchdev_notifier(&prueth->prueth_switchdev_nb);
+	}
+
+	return ret;
+}
+
+void prueth_switchdev_unregister_notifiers(struct prueth *prueth)
+{
+	unregister_switchdev_blocking_notifier(&prueth->prueth_switchdev_bl_nb);
+	unregister_switchdev_notifier(&prueth->prueth_switchdev_nb);
+}
diff --git a/drivers/net/ethernet/ti/icssg/icssg_switchdev.h b/drivers/net/ethernet/ti/icssg/icssg_switchdev.h
new file mode 100644
index 000000000000..0e64e7760a00
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssg/icssg_switchdev.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com/
+ */
+#ifndef __NET_TI_ICSSG_SWITCHDEV_H
+#define __NET_TI_ICSSG_SWITCHDEV_H
+
+#include "icssg_prueth.h"
+
+int prueth_switchdev_register_notifiers(struct prueth *prueth);
+void prueth_switchdev_unregister_notifiers(struct prueth *prueth);
+bool prueth_dev_check(const struct net_device *ndev);
+
+#endif /* __NET_TI_ICSSG_SWITCHDEV_H */
-- 
2.34.1


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

* [RFC PATCH v2 2/3] net: ti: icssg-switch: Add switchdev based driver for ethernet switch support
@ 2024-01-18  7:10   ` MD Danish Anwar
  0 siblings, 0 replies; 34+ messages in thread
From: MD Danish Anwar @ 2024-01-18  7:10 UTC (permalink / raw)
  To: Rob Herring, Dan Carpenter, Jan Kiszka, Andrew Lunn,
	Vladimir Oltean, Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, MD Danish Anwar, Paolo Abeni,
	Jakub Kicinski, Eric Dumazet, David S. Miller
  Cc: linux-arm-kernel, netdev, linux-kernel, srk, r-gunasekaran

ICSSG can operating in switch mode with 2 ext port and 1 host port with
VLAN/FDB/MDB and STP offloading. Add switchdev based driver to
support the same.

Driver itself will be integrated with icssg_prueth in future commits

Signed-off-by: MD Danish Anwar <danishanwar@ti.com>
---
 drivers/net/ethernet/ti/icssg/icssg_prueth.c  |   1 +
 drivers/net/ethernet/ti/icssg/icssg_prueth.h  |  24 +
 .../net/ethernet/ti/icssg/icssg_switchdev.c   | 478 ++++++++++++++++++
 .../net/ethernet/ti/icssg/icssg_switchdev.h   |  13 +
 4 files changed, 516 insertions(+)
 create mode 100644 drivers/net/ethernet/ti/icssg/icssg_switchdev.c
 create mode 100644 drivers/net/ethernet/ti/icssg/icssg_switchdev.h

diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
index 411898a4f38c..38d41ba6762a 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
@@ -30,6 +30,7 @@
 
 #include "icssg_prueth.h"
 #include "icssg_mii_rt.h"
+#include "icssg_switchdev.h"
 #include "../k3-cppi-desc-pool.h"
 
 #define PRUETH_MODULE_DESCRIPTION "PRUSS ICSSG Ethernet driver"
diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h
index 006f77217bd1..5b90e8f8ee48 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.h
+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h
@@ -174,6 +174,9 @@ struct prueth_emac {
 
 	struct pruss_mem_region dram;
 
+	bool offload_fwd_mark;
+	int port_vlan;
+
 	struct delayed_work stats_work;
 	u64 stats[ICSSG_NUM_STATS];
 };
@@ -182,10 +185,12 @@ struct prueth_emac {
  * struct prueth_pdata - PRUeth platform data
  * @fdqring_mode: Free desc queue mode
  * @quirk_10m_link_issue: 10M link detect errata
+ * @switch_mode: switch firmware support
  */
 struct prueth_pdata {
 	enum k3_ring_mode fdqring_mode;
 	u32	quirk_10m_link_issue:1;
+	u32	switch_mode:1;
 };
 
 /**
@@ -211,6 +216,15 @@ struct prueth_pdata {
  * @iep0: pointer to IEP0 device
  * @iep1: pointer to IEP1 device
  * @vlan_tbl: VLAN-FID table pointer
+ * @hw_bridge_dev: pointer to HW bridge net device
+ * @br_members: bitmask of bridge member ports
+ * @prueth_netdevice_nb: netdevice notifier block
+ * @prueth_switchdevice_nb: switchdev notifier block
+ * @prueth_switchdev_bl_nb: switchdev blocking notifier block
+ * @is_switch_mode: flag to indicate if device is in Switch mode
+ * @is_switchmode_supported: indicates platform support for switch mode
+ * @switch_id: ID for mapping switch ports to bridge
+ * @default_vlan: Default VLAN for host
  */
 struct prueth {
 	struct device *dev;
@@ -236,6 +250,16 @@ struct prueth {
 	struct icss_iep *iep0;
 	struct icss_iep *iep1;
 	struct prueth_vlan_tbl *vlan_tbl;
+
+	struct net_device *hw_bridge_dev;
+	u8 br_members;
+	struct notifier_block prueth_netdevice_nb;
+	struct notifier_block prueth_switchdev_nb;
+	struct notifier_block prueth_switchdev_bl_nb;
+	bool is_switch_mode;
+	bool is_switchmode_supported;
+	unsigned char switch_id[MAX_PHYS_ITEM_ID_LEN];
+	int default_vlan;
 };
 
 struct emac_tx_ts_response {
diff --git a/drivers/net/ethernet/ti/icssg/icssg_switchdev.c b/drivers/net/ethernet/ti/icssg/icssg_switchdev.c
new file mode 100644
index 000000000000..48d8ed4fa7a8
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssg/icssg_switchdev.c
@@ -0,0 +1,478 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* Texas Instruments K3 ICSSG Ethernet Switchdev Driver
+ *
+ * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/if_bridge.h>
+#include <linux/netdevice.h>
+#include <linux/workqueue.h>
+#include <net/switchdev.h>
+
+#include "icssg_prueth.h"
+#include "icssg_switchdev.h"
+#include "icss_mii_rt.h"
+
+struct prueth_switchdev_event_work {
+	struct work_struct work;
+	struct switchdev_notifier_fdb_info fdb_info;
+	struct prueth_emac *emac;
+	unsigned long event;
+};
+
+static int prueth_switchdev_stp_state_set(struct prueth_emac *emac,
+					  u8 state)
+{
+	enum icssg_port_state_cmd emac_state;
+	int ret = 0;
+
+	switch (state) {
+	case BR_STATE_FORWARDING:
+		emac_state = ICSSG_EMAC_PORT_FORWARD;
+		break;
+	case BR_STATE_DISABLED:
+		emac_state = ICSSG_EMAC_PORT_DISABLE;
+		break;
+	case BR_STATE_LEARNING:
+	case BR_STATE_LISTENING:
+	case BR_STATE_BLOCKING:
+		emac_state = ICSSG_EMAC_PORT_BLOCK;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	emac_set_port_state(emac, emac_state);
+	netdev_dbg(emac->ndev, "STP state: %u\n", emac_state);
+
+	return ret;
+}
+
+static int prueth_switchdev_attr_br_flags_set(struct prueth_emac *emac,
+					      struct net_device *orig_dev,
+					      struct switchdev_brport_flags brport_flags)
+{
+	enum icssg_port_state_cmd emac_state;
+
+	if (brport_flags.mask & BR_MCAST_FLOOD)
+		emac_state = ICSSG_EMAC_PORT_MC_FLOODING_ENABLE;
+	else
+		emac_state = ICSSG_EMAC_PORT_MC_FLOODING_DISABLE;
+
+	netdev_dbg(emac->ndev, "BR_MCAST_FLOOD: %d port %u\n",
+		   emac_state, emac->port_id);
+
+	emac_set_port_state(emac, emac_state);
+
+	return 0;
+}
+
+static int prueth_switchdev_attr_br_flags_pre_set(struct net_device *netdev,
+						  struct switchdev_brport_flags brport_flags)
+{
+	if (brport_flags.mask & ~(BR_LEARNING | BR_MCAST_FLOOD))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int prueth_switchdev_attr_set(struct net_device *ndev, const void *ctx,
+				     const struct switchdev_attr *attr,
+				     struct netlink_ext_ack *extack)
+{
+	struct prueth_emac *emac = netdev_priv(ndev);
+	int ret;
+
+	netdev_dbg(ndev, "attr: id %u port: %u\n", attr->id, emac->port_id);
+
+	switch (attr->id) {
+	case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS:
+		ret = prueth_switchdev_attr_br_flags_pre_set(ndev,
+							     attr->u.brport_flags);
+		break;
+	case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
+		ret = prueth_switchdev_stp_state_set(emac,
+						     attr->u.stp_state);
+		netdev_dbg(ndev, "stp state: %u\n", attr->u.stp_state);
+		break;
+	case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
+		ret = prueth_switchdev_attr_br_flags_set(emac, attr->orig_dev,
+							 attr->u.brport_flags);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+
+	return ret;
+}
+
+static void prueth_switchdev_fdb_offload_notify(struct net_device *ndev,
+						struct switchdev_notifier_fdb_info *rcv)
+{
+	struct switchdev_notifier_fdb_info info;
+
+	memset(&info, 0, sizeof(info));
+	info.addr = rcv->addr;
+	info.vid = rcv->vid;
+	info.offloaded = true;
+	call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED,
+				 ndev, &info.info, NULL);
+}
+
+static void prueth_switchdev_event_work(struct work_struct *work)
+{
+	struct prueth_switchdev_event_work *switchdev_work =
+		container_of(work, struct prueth_switchdev_event_work, work);
+	struct prueth_emac *emac = switchdev_work->emac;
+	struct switchdev_notifier_fdb_info *fdb;
+	int port_id = emac->port_id;
+	int ret;
+
+	rtnl_lock();
+	switch (switchdev_work->event) {
+	case SWITCHDEV_FDB_ADD_TO_DEVICE:
+		fdb = &switchdev_work->fdb_info;
+
+		netdev_dbg(emac->ndev, "prueth_fdb_add: MACID = %pM vid = %u flags = %u %u -- port %d\n",
+			   fdb->addr, fdb->vid, fdb->added_by_user,
+			   fdb->offloaded, port_id);
+
+		if (!fdb->added_by_user)
+			break;
+		if (memcmp(emac->mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0)
+			break;
+
+		ret = icssg_fdb_add_del(emac, fdb->addr, fdb->vid,
+					BIT(port_id), true);
+		if (!ret)
+			prueth_switchdev_fdb_offload_notify(emac->ndev, fdb);
+		break;
+	case SWITCHDEV_FDB_DEL_TO_DEVICE:
+		fdb = &switchdev_work->fdb_info;
+
+		netdev_dbg(emac->ndev, "prueth_fdb_del: MACID = %pM vid = %u flags = %u %u -- port %d\n",
+			   fdb->addr, fdb->vid, fdb->added_by_user,
+			   fdb->offloaded, port_id);
+
+		if (!fdb->added_by_user)
+			break;
+		if (memcmp(emac->mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0)
+			break;
+		icssg_fdb_add_del(emac, fdb->addr, fdb->vid,
+				  BIT(port_id), false);
+		break;
+	default:
+		break;
+	}
+	rtnl_unlock();
+
+	kfree(switchdev_work->fdb_info.addr);
+	kfree(switchdev_work);
+	dev_put(emac->ndev);
+}
+
+static int prueth_switchdev_event(struct notifier_block *unused,
+				  unsigned long event, void *ptr)
+{
+	struct net_device *ndev = switchdev_notifier_info_to_dev(ptr);
+	struct prueth_switchdev_event_work *switchdev_work;
+	struct switchdev_notifier_fdb_info *fdb_info = ptr;
+	struct prueth_emac *emac = netdev_priv(ndev);
+	int err;
+
+	if (!prueth_dev_check(ndev))
+		return NOTIFY_DONE;
+
+	if (event == SWITCHDEV_PORT_ATTR_SET) {
+		err = switchdev_handle_port_attr_set(ndev, ptr,
+						     prueth_dev_check,
+						     prueth_switchdev_attr_set);
+		return notifier_from_errno(err);
+	}
+
+	switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC);
+	if (WARN_ON(!switchdev_work))
+		return NOTIFY_BAD;
+
+	INIT_WORK(&switchdev_work->work, prueth_switchdev_event_work);
+	switchdev_work->emac = emac;
+	switchdev_work->event = event;
+
+	switch (event) {
+	case SWITCHDEV_FDB_ADD_TO_DEVICE:
+	case SWITCHDEV_FDB_DEL_TO_DEVICE:
+		memcpy(&switchdev_work->fdb_info, ptr,
+		       sizeof(switchdev_work->fdb_info));
+		switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC);
+		if (!switchdev_work->fdb_info.addr)
+			goto err_addr_alloc;
+		ether_addr_copy((u8 *)switchdev_work->fdb_info.addr,
+				fdb_info->addr);
+		dev_hold(ndev);
+		break;
+	default:
+		kfree(switchdev_work);
+		return NOTIFY_DONE;
+	}
+
+	queue_work(system_long_wq, &switchdev_work->work);
+
+	return NOTIFY_DONE;
+
+err_addr_alloc:
+	kfree(switchdev_work);
+	return NOTIFY_BAD;
+}
+
+static int prueth_switchdev_vlan_add(struct prueth_emac *emac, bool untag, bool pvid,
+				     u8 vid, struct net_device *orig_dev)
+{
+	bool cpu_port = netif_is_bridge_master(orig_dev);
+	int untag_mask = 0;
+	int port_mask;
+	int ret = 0;
+
+	if (cpu_port)
+		port_mask = BIT(PRUETH_PORT_HOST);
+	else
+		port_mask = BIT(emac->port_id);
+
+	if (untag)
+		untag_mask = port_mask;
+
+	icssg_vtbl_modify(emac, vid, port_mask, untag_mask, true);
+
+	netdev_dbg(emac->ndev, "VID add vid:%u port_mask:%X untag_mask %X PVID %d\n",
+		   vid, port_mask, untag_mask, pvid);
+
+	if (!pvid)
+		return ret;
+
+	icssg_set_pvid(emac->prueth, vid, emac->port_id);
+
+	return ret;
+}
+
+static int prueth_switchdev_vlan_del(struct prueth_emac *emac, u16 vid,
+				     struct net_device *orig_dev)
+{
+	bool cpu_port = netif_is_bridge_master(orig_dev);
+	int port_mask;
+	int ret = 0;
+
+	if (cpu_port)
+		port_mask = BIT(PRUETH_PORT_HOST);
+	else
+		port_mask = BIT(emac->port_id);
+
+	icssg_vtbl_modify(emac, vid, port_mask, 0, false);
+
+	if (cpu_port)
+		icssg_fdb_add_del(emac, emac->mac_addr, vid,
+				  BIT(PRUETH_PORT_HOST), false);
+
+	if (vid == icssg_get_pvid(emac))
+		icssg_set_pvid(emac->prueth, 0, emac->port_id);
+
+	netdev_dbg(emac->ndev, "VID del vid:%u port_mask:%X\n",
+		   vid, port_mask);
+
+	return ret;
+}
+
+static int prueth_switchdev_vlans_add(struct prueth_emac *emac,
+				      const struct switchdev_obj_port_vlan *vlan)
+{
+	bool untag = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
+	struct net_device *orig_dev = vlan->obj.orig_dev;
+	bool cpu_port = netif_is_bridge_master(orig_dev);
+	bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
+
+	netdev_dbg(emac->ndev, "VID add vid:%u flags:%X\n",
+		   vlan->vid, vlan->flags);
+
+	if (cpu_port && !(vlan->flags & BRIDGE_VLAN_INFO_BRENTRY))
+		return 0;
+
+	if (vlan->vid > 0xff)
+		return 0;
+
+	return prueth_switchdev_vlan_add(emac, untag, pvid, vlan->vid,
+					 orig_dev);
+}
+
+static int prueth_switchdev_vlans_del(struct prueth_emac *emac,
+				      const struct switchdev_obj_port_vlan *vlan)
+{
+	if (vlan->vid > 0xff)
+		return 0;
+
+	return prueth_switchdev_vlan_del(emac, vlan->vid,
+					 vlan->obj.orig_dev);
+}
+
+static int prueth_switchdev_mdb_add(struct prueth_emac *emac,
+				    struct switchdev_obj_port_mdb *mdb)
+{
+	struct net_device *orig_dev = mdb->obj.orig_dev;
+	u8 port_mask, fid_c2;
+	bool cpu_port;
+	int err;
+
+	cpu_port = netif_is_bridge_master(orig_dev);
+
+	if (cpu_port)
+		port_mask = BIT(PRUETH_PORT_HOST);
+	else
+		port_mask = BIT(emac->port_id);
+
+	fid_c2 = icssg_fdb_lookup(emac, mdb->addr, mdb->vid);
+
+	err = icssg_fdb_add_del(emac, mdb->addr, mdb->vid, fid_c2 | port_mask, true);
+	netdev_dbg(emac->ndev, "MDB add vid %u:%pM  ports: %X\n",
+		   mdb->vid, mdb->addr, port_mask);
+
+	return err;
+}
+
+static int prueth_switchdev_mdb_del(struct prueth_emac *emac,
+				    struct switchdev_obj_port_mdb *mdb)
+{
+	struct net_device *orig_dev = mdb->obj.orig_dev;
+	int del_mask, ret, fid_c2;
+	bool cpu_port;
+
+	cpu_port = netif_is_bridge_master(orig_dev);
+
+	if (cpu_port)
+		del_mask = BIT(PRUETH_PORT_HOST);
+	else
+		del_mask = BIT(emac->port_id);
+
+	fid_c2 = icssg_fdb_lookup(emac, mdb->addr, mdb->vid);
+
+	if (fid_c2 & ~del_mask)
+		ret = icssg_fdb_add_del(emac, mdb->addr, mdb->vid, fid_c2 & ~del_mask, true);
+	else
+		ret = icssg_fdb_add_del(emac, mdb->addr, mdb->vid, 0, false);
+
+	netdev_dbg(emac->ndev, "MDB del vid %u:%pM  ports: %X\n",
+		   mdb->vid, mdb->addr, del_mask);
+
+	return ret;
+}
+
+static int prueth_switchdev_obj_add(struct net_device *ndev, const void *ctx,
+				    const struct switchdev_obj *obj,
+				    struct netlink_ext_ack *extack)
+{
+	struct switchdev_obj_port_vlan *vlan = SWITCHDEV_OBJ_PORT_VLAN(obj);
+	struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj);
+	struct prueth_emac *emac = netdev_priv(ndev);
+	int err = 0;
+
+	netdev_dbg(ndev, "obj_add: id %u port: %u\n", obj->id, emac->port_id);
+
+	switch (obj->id) {
+	case SWITCHDEV_OBJ_ID_PORT_VLAN:
+		err = prueth_switchdev_vlans_add(emac, vlan);
+		break;
+	case SWITCHDEV_OBJ_ID_PORT_MDB:
+	case SWITCHDEV_OBJ_ID_HOST_MDB:
+		err = prueth_switchdev_mdb_add(emac, mdb);
+		break;
+	default:
+		err = -EOPNOTSUPP;
+		break;
+	}
+
+	return err;
+}
+
+static int prueth_switchdev_obj_del(struct net_device *ndev, const void *ctx,
+				    const struct switchdev_obj *obj)
+{
+	struct switchdev_obj_port_vlan *vlan = SWITCHDEV_OBJ_PORT_VLAN(obj);
+	struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj);
+	struct prueth_emac *emac = netdev_priv(ndev);
+	int err = 0;
+
+	netdev_dbg(ndev, "obj_del: id %u port: %u\n", obj->id, emac->port_id);
+
+	switch (obj->id) {
+	case SWITCHDEV_OBJ_ID_PORT_VLAN:
+		err = prueth_switchdev_vlans_del(emac, vlan);
+		break;
+	case SWITCHDEV_OBJ_ID_PORT_MDB:
+	case SWITCHDEV_OBJ_ID_HOST_MDB:
+		err = prueth_switchdev_mdb_del(emac, mdb);
+		break;
+	default:
+		err = -EOPNOTSUPP;
+		break;
+	}
+
+	return err;
+}
+
+static int prueth_switchdev_blocking_event(struct notifier_block *unused,
+					   unsigned long event, void *ptr)
+{
+	struct net_device *dev = switchdev_notifier_info_to_dev(ptr);
+	int err;
+
+	switch (event) {
+	case SWITCHDEV_PORT_OBJ_ADD:
+		err = switchdev_handle_port_obj_add(dev, ptr,
+						    prueth_dev_check,
+						    prueth_switchdev_obj_add);
+		return notifier_from_errno(err);
+	case SWITCHDEV_PORT_OBJ_DEL:
+		err = switchdev_handle_port_obj_del(dev, ptr,
+						    prueth_dev_check,
+						    prueth_switchdev_obj_del);
+		return notifier_from_errno(err);
+	case SWITCHDEV_PORT_ATTR_SET:
+		err = switchdev_handle_port_attr_set(dev, ptr,
+						     prueth_dev_check,
+						     prueth_switchdev_attr_set);
+		return notifier_from_errno(err);
+	default:
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+int prueth_switchdev_register_notifiers(struct prueth *prueth)
+{
+	int ret = 0;
+
+	prueth->prueth_switchdev_nb.notifier_call = &prueth_switchdev_event;
+	ret = register_switchdev_notifier(&prueth->prueth_switchdev_nb);
+	if (ret) {
+		dev_err(prueth->dev, "register switchdev notifier fail ret:%d\n",
+			ret);
+		return ret;
+	}
+
+	prueth->prueth_switchdev_bl_nb.notifier_call = &prueth_switchdev_blocking_event;
+	ret = register_switchdev_blocking_notifier(&prueth->prueth_switchdev_bl_nb);
+	if (ret) {
+		dev_err(prueth->dev, "register switchdev blocking notifier ret:%d\n",
+			ret);
+		unregister_switchdev_notifier(&prueth->prueth_switchdev_nb);
+	}
+
+	return ret;
+}
+
+void prueth_switchdev_unregister_notifiers(struct prueth *prueth)
+{
+	unregister_switchdev_blocking_notifier(&prueth->prueth_switchdev_bl_nb);
+	unregister_switchdev_notifier(&prueth->prueth_switchdev_nb);
+}
diff --git a/drivers/net/ethernet/ti/icssg/icssg_switchdev.h b/drivers/net/ethernet/ti/icssg/icssg_switchdev.h
new file mode 100644
index 000000000000..0e64e7760a00
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssg/icssg_switchdev.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com/
+ */
+#ifndef __NET_TI_ICSSG_SWITCHDEV_H
+#define __NET_TI_ICSSG_SWITCHDEV_H
+
+#include "icssg_prueth.h"
+
+int prueth_switchdev_register_notifiers(struct prueth *prueth);
+void prueth_switchdev_unregister_notifiers(struct prueth *prueth);
+bool prueth_dev_check(const struct net_device *ndev);
+
+#endif /* __NET_TI_ICSSG_SWITCHDEV_H */
-- 
2.34.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [RFC PATCH v2 3/3] net: ti: icssg-prueth: Add support for ICSSG switch firmware
  2024-01-18  7:10 ` MD Danish Anwar
@ 2024-01-18  7:10   ` MD Danish Anwar
  -1 siblings, 0 replies; 34+ messages in thread
From: MD Danish Anwar @ 2024-01-18  7:10 UTC (permalink / raw)
  To: Rob Herring, Dan Carpenter, Jan Kiszka, Andrew Lunn,
	Vladimir Oltean, Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, MD Danish Anwar, Paolo Abeni,
	Jakub Kicinski, Eric Dumazet, David S. Miller
  Cc: linux-arm-kernel, netdev, linux-kernel, srk, r-gunasekaran

Add support for ICSSG switch firmware using existing Dual EMAC driver
with switchdev.

Limitations:
VLAN offloading is limited to 0-256 IDs.
MDB/FDB static entries are limited to 511 entries and different FDBs can
hash to same bucket and thus may not completely offloaded

Switch mode requires loading of new firmware into ICSSG cores. This
means interfaces have to taken down and then reconfigured to switch
mode.

Example assuming ETH1 and ETH2 as ICSSG2 interfaces:

Switch to ICSSG Switch mode:
 ip link set dev eth1 down
 ip link set dev eth2 down
 ip link add name br0 type bridge
 ip link set dev eth1 master br0
 ip link set dev eth2 master br0
 ip link set dev br0 up
 ip link set dev eth1 up
 ip link set dev eth2 up
 bridge vlan add dev br0 vid 1 pvid untagged self

Going back to Dual EMAC mode:

 ip link set dev br0 down
 ip link set dev eth1 nomaster
 ip link set dev eth2 nomaster
 ip link set dev eth1 down
 ip link set dev eth2 down
 ip link del name br0 type bridge
 ip link set dev eth1 up
 ip link set dev eth2 up

By default, Dual EMAC firmware is loaded, and can be changed to switch
mode by above steps

Signed-off-by: MD Danish Anwar <danishanwar@ti.com>
---
 drivers/net/ethernet/ti/Kconfig               |   1 +
 drivers/net/ethernet/ti/Makefile              |   3 +-
 drivers/net/ethernet/ti/icssg/icssg_config.c  | 136 +++++++++++-
 drivers/net/ethernet/ti/icssg/icssg_config.h  |   7 +
 drivers/net/ethernet/ti/icssg/icssg_prueth.c  | 198 +++++++++++++++++-
 .../net/ethernet/ti/icssg/icssg_switchdev.c   |   2 +-
 6 files changed, 333 insertions(+), 14 deletions(-)

diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig
index be01450c20dc..c72f26828b04 100644
--- a/drivers/net/ethernet/ti/Kconfig
+++ b/drivers/net/ethernet/ti/Kconfig
@@ -188,6 +188,7 @@ config TI_ICSSG_PRUETH
 	select TI_ICSS_IEP
 	select TI_K3_CPPI_DESC_POOL
 	depends on PRU_REMOTEPROC
+	depends on NET_SWITCHDEV
 	depends on ARCH_K3 && OF && TI_K3_UDMA_GLUE_LAYER
 	help
 	  Support dual Gigabit Ethernet ports over the ICSSG PRU Subsystem.
diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile
index d8590304f3df..d295bded7a32 100644
--- a/drivers/net/ethernet/ti/Makefile
+++ b/drivers/net/ethernet/ti/Makefile
@@ -38,5 +38,6 @@ icssg-prueth-y := icssg/icssg_prueth.o \
 		  icssg/icssg_config.o \
 		  icssg/icssg_mii_cfg.o \
 		  icssg/icssg_stats.o \
-		  icssg/icssg_ethtool.o
+		  icssg/icssg_ethtool.o \
+		  icssg/icssg_switchdev.o
 obj-$(CONFIG_TI_ICSS_IEP) += icssg/icss_iep.o
diff --git a/drivers/net/ethernet/ti/icssg/icssg_config.c b/drivers/net/ethernet/ti/icssg/icssg_config.c
index afc10014ec03..eda08a87c902 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_config.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_config.c
@@ -105,28 +105,49 @@ static const struct map hwq_map[2][ICSSG_NUM_OTHER_QUEUES] = {
 	},
 };
 
+static void icssg_config_mii_init_switch(struct prueth_emac *emac)
+{
+	struct prueth *prueth = emac->prueth;
+	int mii = prueth_emac_slice(emac);
+	u32 txcfg_reg, pcnt_reg, txcfg;
+	struct regmap *mii_rt;
+
+	mii_rt = prueth->mii_rt;
+
+	txcfg_reg = (mii == ICSS_MII0) ? PRUSS_MII_RT_TXCFG0 :
+				       PRUSS_MII_RT_TXCFG1;
+	pcnt_reg = (mii == ICSS_MII0) ? PRUSS_MII_RT_RX_PCNT0 :
+				       PRUSS_MII_RT_RX_PCNT1;
+
+	txcfg = PRUSS_MII_RT_TXCFG_TX_ENABLE |
+		PRUSS_MII_RT_TXCFG_TX_AUTO_PREAMBLE |
+		PRUSS_MII_RT_TXCFG_TX_IPG_WIRE_CLK_EN;
+
+	if (emac->phy_if == PHY_INTERFACE_MODE_MII && mii == ICSS_MII1)
+		txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
+	else if (emac->phy_if != PHY_INTERFACE_MODE_MII && mii == ICSS_MII0)
+		txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
+
+	regmap_write(mii_rt, txcfg_reg, txcfg);
+	regmap_write(mii_rt, pcnt_reg, 0x1);
+}
+
 static void icssg_config_mii_init(struct prueth_emac *emac)
 {
-	u32 rxcfg, txcfg, rxcfg_reg, txcfg_reg, pcnt_reg;
 	struct prueth *prueth = emac->prueth;
 	int slice = prueth_emac_slice(emac);
+	u32 txcfg, txcfg_reg, pcnt_reg;
 	struct regmap *mii_rt;
 
 	mii_rt = prueth->mii_rt;
 
-	rxcfg_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_RXCFG0 :
-				       PRUSS_MII_RT_RXCFG1;
 	txcfg_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_TXCFG0 :
 				       PRUSS_MII_RT_TXCFG1;
 	pcnt_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_RX_PCNT0 :
 				       PRUSS_MII_RT_RX_PCNT1;
 
-	rxcfg = MII_RXCFG_DEFAULT;
 	txcfg = MII_TXCFG_DEFAULT;
 
-	if (slice == ICSS_MII1)
-		rxcfg |= PRUSS_MII_RT_RXCFG_RX_MUX_SEL;
-
 	/* In MII mode TX lines swapped inside ICSSG, so TX_MUX_SEL cfg need
 	 * to be swapped also comparing to RGMII mode.
 	 */
@@ -135,7 +156,6 @@ static void icssg_config_mii_init(struct prueth_emac *emac)
 	else if (emac->phy_if != PHY_INTERFACE_MODE_MII && slice == ICSS_MII1)
 		txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
 
-	regmap_write(mii_rt, rxcfg_reg, rxcfg);
 	regmap_write(mii_rt, txcfg_reg, txcfg);
 	regmap_write(mii_rt, pcnt_reg, 0x1);
 }
@@ -249,6 +269,66 @@ static int emac_r30_is_done(struct prueth_emac *emac)
 	return 1;
 }
 
+static int prueth_switch_buffer_setup(struct prueth_emac *emac)
+{
+	struct icssg_buffer_pool_cfg __iomem *bpool_cfg;
+	struct icssg_rxq_ctx __iomem *rxq_ctx;
+	struct prueth *prueth = emac->prueth;
+	int slice = prueth_emac_slice(emac);
+	u32 addr;
+	int i;
+
+	addr = lower_32_bits(prueth->msmcram.pa);
+	if (slice)
+		addr += PRUETH_NUM_BUF_POOLS * PRUETH_EMAC_BUF_POOL_SIZE;
+
+	if (addr % SZ_64K) {
+		dev_warn(prueth->dev, "buffer pool needs to be 64KB aligned\n");
+		return -EINVAL;
+	}
+
+	bpool_cfg = emac->dram.va + BUFFER_POOL_0_ADDR_OFFSET;
+	/* workaround for f/w bug. bpool 0 needs to be initilalized */
+	for (i = 0; i <  PRUETH_NUM_BUF_POOLS; i++) {
+		writel(addr, &bpool_cfg[i].addr);
+		writel(PRUETH_EMAC_BUF_POOL_SIZE, &bpool_cfg[i].len);
+		addr += PRUETH_EMAC_BUF_POOL_SIZE;
+	}
+
+	if (!slice)
+		addr += PRUETH_NUM_BUF_POOLS * PRUETH_EMAC_BUF_POOL_SIZE;
+	else
+		addr += PRUETH_SW_NUM_BUF_POOLS_HOST * PRUETH_SW_BUF_POOL_SIZE_HOST;
+
+	for (i = PRUETH_NUM_BUF_POOLS;
+	     i < 2 * PRUETH_SW_NUM_BUF_POOLS_HOST + PRUETH_NUM_BUF_POOLS;
+	     i++) {
+		/* The driver only uses first 4 queues per PRU so only initialize them */
+		if (i % PRUETH_SW_NUM_BUF_POOLS_HOST < PRUETH_SW_NUM_BUF_POOLS_PER_PRU) {
+			writel(addr, &bpool_cfg[i].addr);
+			writel(PRUETH_SW_BUF_POOL_SIZE_HOST, &bpool_cfg[i].len);
+			addr += PRUETH_SW_BUF_POOL_SIZE_HOST;
+		} else {
+			writel(0, &bpool_cfg[i].addr);
+			writel(0, &bpool_cfg[i].len);
+		}
+	}
+
+	if (!slice)
+		addr += PRUETH_SW_NUM_BUF_POOLS_HOST * PRUETH_SW_BUF_POOL_SIZE_HOST;
+	else
+		addr += PRUETH_EMAC_RX_CTX_BUF_SIZE;
+
+	rxq_ctx = emac->dram.va + HOST_RX_Q_PRE_CONTEXT_OFFSET;
+	for (i = 0; i < 3; i++)
+		writel(addr, &rxq_ctx->start[i]);
+
+	addr += PRUETH_EMAC_RX_CTX_BUF_SIZE;
+	writel(addr - SZ_2K, &rxq_ctx->end);
+
+	return 0;
+}
+
 static int prueth_emac_buffer_setup(struct prueth_emac *emac)
 {
 	struct icssg_buffer_pool_cfg __iomem *bpool_cfg;
@@ -325,13 +405,41 @@ static void icssg_init_emac_mode(struct prueth *prueth)
 	icssg_class_set_host_mac_addr(prueth->miig_rt, mac);
 }
 
+static void icssg_init_switch_mode(struct prueth *prueth)
+{
+	u32 addr = prueth->shram.pa + EMAC_ICSSG_SWITCH_DEFAULT_VLAN_TABLE_OFFSET;
+	int i;
+
+	if (prueth->emacs_initialized)
+		return;
+
+	/* Set VLAN TABLE address base */
+	regmap_update_bits(prueth->miig_rt, FDB_GEN_CFG1, SMEM_VLAN_OFFSET_MASK,
+			   addr <<  SMEM_VLAN_OFFSET);
+	/* Set enable VLAN aware mode, and FDBs for all PRUs */
+	regmap_write(prueth->miig_rt, FDB_GEN_CFG2, FDB_EN_ALL);
+	prueth->vlan_tbl = (struct prueth_vlan_tbl __force *)(prueth->shram.va +
+			    EMAC_ICSSG_SWITCH_DEFAULT_VLAN_TABLE_OFFSET);
+	for (i = 0; i < SZ_4K - 1; i++) {
+		prueth->vlan_tbl[i].fid = i;
+		prueth->vlan_tbl[i].fid_c1 = 0;
+	}
+
+	if (prueth->hw_bridge_dev)
+		icssg_class_set_host_mac_addr(prueth->miig_rt, prueth->hw_bridge_dev->dev_addr);
+	icssg_set_pvid(prueth, prueth->default_vlan, PRUETH_PORT_HOST);
+}
+
 int icssg_config(struct prueth *prueth, struct prueth_emac *emac, int slice)
 {
 	void __iomem *config = emac->dram.va + ICSSG_CONFIG_OFFSET;
 	struct icssg_flow_cfg __iomem *flow_cfg;
 	int ret;
 
-	icssg_init_emac_mode(prueth);
+	if (prueth->is_switch_mode)
+		icssg_init_switch_mode(prueth);
+	else
+		icssg_init_emac_mode(prueth);
 
 	memset_io(config, 0, TAS_GATE_MASK_LIST0);
 	icssg_miig_queues_init(prueth, slice);
@@ -345,7 +453,10 @@ int icssg_config(struct prueth *prueth, struct prueth_emac *emac, int slice)
 	regmap_update_bits(prueth->miig_rt, ICSSG_CFG_OFFSET,
 			   ICSSG_CFG_DEFAULT, ICSSG_CFG_DEFAULT);
 	icssg_miig_set_interface_mode(prueth->miig_rt, slice, emac->phy_if);
-	icssg_config_mii_init(emac);
+	if (prueth->is_switch_mode)
+		icssg_config_mii_init_switch(emac);
+	else
+		icssg_config_mii_init(emac);
 	icssg_config_ipg(emac);
 	icssg_update_rgmii_cfg(prueth->miig_rt, emac);
 
@@ -368,7 +479,10 @@ int icssg_config(struct prueth *prueth, struct prueth_emac *emac, int slice)
 	writeb(0, config + SPL_PKT_DEFAULT_PRIORITY);
 	writeb(0, config + QUEUE_NUM_UNTAGGED);
 
-	ret = prueth_emac_buffer_setup(emac);
+	if (prueth->is_switch_mode)
+		ret = prueth_switch_buffer_setup(emac);
+	else
+		ret = prueth_emac_buffer_setup(emac);
 	if (ret)
 		return ret;
 
diff --git a/drivers/net/ethernet/ti/icssg/icssg_config.h b/drivers/net/ethernet/ti/icssg/icssg_config.h
index 0d5d5d253b7a..cc923f1d4387 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_config.h
+++ b/drivers/net/ethernet/ti/icssg/icssg_config.h
@@ -35,6 +35,13 @@ struct icssg_flow_cfg {
 	(2 * (PRUETH_EMAC_BUF_POOL_SIZE * PRUETH_NUM_BUF_POOLS + \
 	 PRUETH_EMAC_RX_CTX_BUF_SIZE * 2))
 
+#define PRUETH_SW_BUF_POOL_SIZE_HOST	SZ_4K
+#define PRUETH_SW_NUM_BUF_POOLS_HOST	8
+#define PRUETH_SW_NUM_BUF_POOLS_PER_PRU 4
+#define MSMC_RAM_SIZE_SWITCH_MODE \
+	(MSMC_RAM_SIZE + \
+	(2 * PRUETH_SW_BUF_POOL_SIZE_HOST * PRUETH_SW_NUM_BUF_POOLS_HOST))
+
 #define PRUETH_SWITCH_FDB_MASK ((SIZE_OF_FDB / NUMBER_OF_FDB_BUCKET_ENTRIES) - 1)
 
 struct icssg_rxq_ctx {
diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
index 38d41ba6762a..9197599e5495 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
@@ -27,6 +27,7 @@
 #include <linux/remoteproc/pruss.h>
 #include <linux/regmap.h>
 #include <linux/remoteproc.h>
+#include <net/switchdev.h>
 
 #include "icssg_prueth.h"
 #include "icssg_mii_rt.h"
@@ -54,6 +55,10 @@
 
 #define prueth_napi_to_emac(napi) container_of(napi, struct prueth_emac, napi_rx)
 
+#define DEFAULT_VID		1
+#define DEFAULT_PORT_MASK	1
+#define DEFAULT_UNTAG_MASK	1
+
 /* CTRLMMR_ICSSG_RGMII_CTRL register bits */
 #define ICSSG_CTRL_RGMII_ID_MODE                BIT(24)
 
@@ -558,6 +563,8 @@ static int emac_rx_packet(struct prueth_emac *emac, u32 flow_id)
 	} else {
 		/* send the filled skb up the n/w stack */
 		skb_put(skb, pkt_len);
+		if (emac->prueth->is_switch_mode)
+			skb->offload_fwd_mark = emac->offload_fwd_mark;
 		skb->protocol = eth_type_trans(skb, ndev);
 		napi_gro_receive(&emac->napi_rx, skb);
 		ndev->stats.rx_bytes += pkt_len;
@@ -890,6 +897,19 @@ struct icssg_firmwares {
 	char *txpru;
 };
 
+static struct icssg_firmwares icssg_switch_firmwares[] = {
+	{
+		.pru = "ti-pruss/am65x-sr2-pru0-prusw-fw.elf",
+		.rtu = "ti-pruss/am65x-sr2-rtu0-prusw-fw.elf",
+		.txpru = "ti-pruss/am65x-sr2-txpru0-prusw-fw.elf",
+	},
+	{
+		.pru = "ti-pruss/am65x-sr2-pru1-prusw-fw.elf",
+		.rtu = "ti-pruss/am65x-sr2-rtu1-prusw-fw.elf",
+		.txpru = "ti-pruss/am65x-sr2-txpru1-prusw-fw.elf",
+	}
+};
+
 static struct icssg_firmwares icssg_emac_firmwares[] = {
 	{
 		.pru = "ti-pruss/am65x-sr2-pru0-prueth-fw.elf",
@@ -909,7 +929,10 @@ static int prueth_emac_start(struct prueth *prueth, struct prueth_emac *emac)
 	struct device *dev = prueth->dev;
 	int slice, ret;
 
-	firmwares = icssg_emac_firmwares;
+	if (prueth->is_switch_mode)
+		firmwares = icssg_switch_firmwares;
+	else
+		firmwares = icssg_emac_firmwares;
 
 	slice = prueth_emac_slice(emac);
 	if (slice < 0) {
@@ -1411,6 +1434,21 @@ static int emac_ndo_open(struct net_device *ndev)
 
 	queue_work(system_long_wq, &emac->stats_work.work);
 
+	if (prueth->is_switch_mode) {
+		icssg_fdb_add_del(emac, eth_stp_addr, prueth->default_vlan,
+				  ICSSG_FDB_ENTRY_P0_MEMBERSHIP |
+				  ICSSG_FDB_ENTRY_P1_MEMBERSHIP |
+				  ICSSG_FDB_ENTRY_P2_MEMBERSHIP |
+				  ICSSG_FDB_ENTRY_BLOCK,
+				  true);
+		icssg_vtbl_modify(emac, emac->port_vlan | DEFAULT_VID,
+				  BIT(emac->port_id) | DEFAULT_PORT_MASK,
+				  BIT(emac->port_id) | DEFAULT_UNTAG_MASK,
+				  true);
+		icssg_set_pvid(emac->prueth, emac->port_vlan, emac->port_id);
+		emac_set_port_state(emac, ICSSG_EMAC_PORT_VLAN_AWARE_ENABLE);
+	}
+
 	return 0;
 
 reset_tx_chan:
@@ -1949,6 +1987,148 @@ static void prueth_put_cores(struct prueth *prueth, int slice)
 		pru_rproc_put(prueth->pru[slice]);
 }
 
+static void prueth_offload_fwd_mark_update(struct prueth *prueth)
+{
+	int set_val = 0;
+	int i;
+
+	if (prueth->br_members == (PRUETH_PORT_MII0 | PRUETH_PORT_MII1))
+		set_val = 1;
+
+	dev_dbg(prueth->dev, "set offload_fwd_mark %d\n", set_val);
+
+	for (i = PRUETH_MAC0; i < PRUETH_NUM_MACS; i++) {
+		struct prueth_emac *emac = prueth->emac[i];
+
+		if (!emac || !emac->ndev)
+			continue;
+
+		emac->offload_fwd_mark = set_val;
+	}
+}
+
+bool prueth_dev_check(const struct net_device *ndev)
+{
+	if (ndev->netdev_ops == &emac_netdev_ops && netif_running(ndev)) {
+		struct prueth_emac *emac = netdev_priv(ndev);
+
+		return emac->prueth->is_switch_mode;
+	}
+
+	return false;
+}
+
+static int prueth_netdevice_port_link(struct net_device *ndev,
+				      struct net_device *br_ndev,
+				      struct netlink_ext_ack *extack)
+{
+	struct prueth_emac *emac = netdev_priv(ndev);
+	struct prueth *prueth = emac->prueth;
+	int err;
+
+	if (!prueth->br_members) {
+		prueth->hw_bridge_dev = br_ndev;
+	} else {
+		/* This is adding the port to a second bridge, this is
+		 * unsupported
+		 */
+		if (prueth->hw_bridge_dev != br_ndev)
+			return -EOPNOTSUPP;
+	}
+
+	err = switchdev_bridge_port_offload(br_ndev, ndev, emac,
+					    &prueth->prueth_switchdev_nb,
+					    &prueth->prueth_switchdev_bl_nb,
+					    false, extack);
+	if (err)
+		return err;
+
+	prueth->br_members |= BIT(emac->port_id);
+
+	if (prueth->br_members & BIT(PRUETH_PORT_MII0) &&
+	    prueth->br_members & BIT(PRUETH_PORT_MII1)) {
+		prueth->is_switch_mode = true;
+		prueth->default_vlan = 1;
+		emac->port_vlan = prueth->default_vlan;
+	}
+
+	prueth_offload_fwd_mark_update(prueth);
+
+	return NOTIFY_DONE;
+}
+
+static void prueth_netdevice_port_unlink(struct net_device *ndev)
+{
+	struct prueth_emac *emac = netdev_priv(ndev);
+	struct prueth *prueth = emac->prueth;
+
+	prueth->br_members &= ~BIT(emac->port_id);
+
+	prueth->is_switch_mode = false;
+	emac->port_vlan = 0;
+
+	prueth_offload_fwd_mark_update(prueth);
+
+	if (!prueth->br_members)
+		prueth->hw_bridge_dev = NULL;
+}
+
+/* netdev notifier */
+static int prueth_netdevice_event(struct notifier_block *unused,
+				  unsigned long event, void *ptr)
+{
+	struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(ptr);
+	struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
+	struct netdev_notifier_changeupper_info *info;
+	int ret = NOTIFY_DONE;
+
+	if (ndev->netdev_ops != &emac_netdev_ops)
+		return NOTIFY_DONE;
+
+	switch (event) {
+	case NETDEV_CHANGEUPPER:
+		info = ptr;
+
+		if (netif_is_bridge_master(info->upper_dev)) {
+			if (info->linking)
+				ret = prueth_netdevice_port_link(ndev, info->upper_dev, extack);
+			else
+				prueth_netdevice_port_unlink(ndev);
+		}
+		break;
+	default:
+		return NOTIFY_DONE;
+	}
+
+	return notifier_from_errno(ret);
+}
+
+static int prueth_register_notifiers(struct prueth *prueth)
+{
+	int ret = 0;
+
+	prueth->prueth_netdevice_nb.notifier_call = &prueth_netdevice_event;
+	ret = register_netdevice_notifier(&prueth->prueth_netdevice_nb);
+	if (ret) {
+		dev_err(prueth->dev, "can't register netdevice notifier\n");
+		return ret;
+	}
+
+	ret = prueth_switchdev_register_notifiers(prueth);
+	if (ret)
+		unregister_netdevice_notifier(&prueth->prueth_netdevice_nb);
+
+	return ret;
+}
+
+static void prueth_unregister_notifiers(struct prueth *prueth)
+{
+	prueth_switchdev_unregister_notifiers(prueth);
+	unregister_netdevice_notifier(&prueth->prueth_netdevice_nb);
+}
+
+static const struct of_device_id prueth_dt_match[];
+
 static int prueth_probe(struct platform_device *pdev)
 {
 	struct device_node *eth_node, *eth_ports_node;
@@ -2076,6 +2256,10 @@ static int prueth_probe(struct platform_device *pdev)
 	}
 
 	msmc_ram_size = MSMC_RAM_SIZE;
+	prueth->is_switchmode_supported = prueth->pdata.switch_mode;
+	if (prueth->is_switchmode_supported)
+		msmc_ram_size = MSMC_RAM_SIZE_SWITCH_MODE;
+
 
 	/* NOTE: FW bug needs buffer base to be 64KB aligned */
 	prueth->msmcram.va =
@@ -2171,6 +2355,14 @@ static int prueth_probe(struct platform_device *pdev)
 		phy_attached_info(prueth->emac[PRUETH_MAC1]->ndev->phydev);
 	}
 
+	if (prueth->is_switchmode_supported) {
+		ret = prueth_register_notifiers(prueth);
+		if (ret)
+			goto netdev_unregister;
+
+		sprintf(prueth->switch_id, "%s", dev_name(dev));
+	}
+
 	dev_info(dev, "TI PRU ethernet driver initialized: %s EMAC mode\n",
 		 (!eth0_node || !eth1_node) ? "single" : "dual");
 
@@ -2240,6 +2432,8 @@ static void prueth_remove(struct platform_device *pdev)
 	struct device_node *eth_node;
 	int i;
 
+	prueth_unregister_notifiers(prueth);
+
 	for (i = 0; i < PRUETH_NUM_MACS; i++) {
 		if (!prueth->registered_netdevs[i])
 			continue;
@@ -2337,10 +2531,12 @@ static const struct dev_pm_ops prueth_dev_pm_ops = {
 static const struct prueth_pdata am654_icssg_pdata = {
 	.fdqring_mode = K3_RINGACC_RING_MODE_MESSAGE,
 	.quirk_10m_link_issue = 1,
+	.switch_mode = 1,
 };
 
 static const struct prueth_pdata am64x_icssg_pdata = {
 	.fdqring_mode = K3_RINGACC_RING_MODE_RING,
+	.switch_mode = 1,
 };
 
 static const struct of_device_id prueth_dt_match[] = {
diff --git a/drivers/net/ethernet/ti/icssg/icssg_switchdev.c b/drivers/net/ethernet/ti/icssg/icssg_switchdev.c
index 48d8ed4fa7a8..90d0d98e0ef9 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_switchdev.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_switchdev.c
@@ -14,7 +14,7 @@
 
 #include "icssg_prueth.h"
 #include "icssg_switchdev.h"
-#include "icss_mii_rt.h"
+#include "icssg_mii_rt.h"
 
 struct prueth_switchdev_event_work {
 	struct work_struct work;
-- 
2.34.1


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

* [RFC PATCH v2 3/3] net: ti: icssg-prueth: Add support for ICSSG switch firmware
@ 2024-01-18  7:10   ` MD Danish Anwar
  0 siblings, 0 replies; 34+ messages in thread
From: MD Danish Anwar @ 2024-01-18  7:10 UTC (permalink / raw)
  To: Rob Herring, Dan Carpenter, Jan Kiszka, Andrew Lunn,
	Vladimir Oltean, Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, MD Danish Anwar, Paolo Abeni,
	Jakub Kicinski, Eric Dumazet, David S. Miller
  Cc: linux-arm-kernel, netdev, linux-kernel, srk, r-gunasekaran

Add support for ICSSG switch firmware using existing Dual EMAC driver
with switchdev.

Limitations:
VLAN offloading is limited to 0-256 IDs.
MDB/FDB static entries are limited to 511 entries and different FDBs can
hash to same bucket and thus may not completely offloaded

Switch mode requires loading of new firmware into ICSSG cores. This
means interfaces have to taken down and then reconfigured to switch
mode.

Example assuming ETH1 and ETH2 as ICSSG2 interfaces:

Switch to ICSSG Switch mode:
 ip link set dev eth1 down
 ip link set dev eth2 down
 ip link add name br0 type bridge
 ip link set dev eth1 master br0
 ip link set dev eth2 master br0
 ip link set dev br0 up
 ip link set dev eth1 up
 ip link set dev eth2 up
 bridge vlan add dev br0 vid 1 pvid untagged self

Going back to Dual EMAC mode:

 ip link set dev br0 down
 ip link set dev eth1 nomaster
 ip link set dev eth2 nomaster
 ip link set dev eth1 down
 ip link set dev eth2 down
 ip link del name br0 type bridge
 ip link set dev eth1 up
 ip link set dev eth2 up

By default, Dual EMAC firmware is loaded, and can be changed to switch
mode by above steps

Signed-off-by: MD Danish Anwar <danishanwar@ti.com>
---
 drivers/net/ethernet/ti/Kconfig               |   1 +
 drivers/net/ethernet/ti/Makefile              |   3 +-
 drivers/net/ethernet/ti/icssg/icssg_config.c  | 136 +++++++++++-
 drivers/net/ethernet/ti/icssg/icssg_config.h  |   7 +
 drivers/net/ethernet/ti/icssg/icssg_prueth.c  | 198 +++++++++++++++++-
 .../net/ethernet/ti/icssg/icssg_switchdev.c   |   2 +-
 6 files changed, 333 insertions(+), 14 deletions(-)

diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig
index be01450c20dc..c72f26828b04 100644
--- a/drivers/net/ethernet/ti/Kconfig
+++ b/drivers/net/ethernet/ti/Kconfig
@@ -188,6 +188,7 @@ config TI_ICSSG_PRUETH
 	select TI_ICSS_IEP
 	select TI_K3_CPPI_DESC_POOL
 	depends on PRU_REMOTEPROC
+	depends on NET_SWITCHDEV
 	depends on ARCH_K3 && OF && TI_K3_UDMA_GLUE_LAYER
 	help
 	  Support dual Gigabit Ethernet ports over the ICSSG PRU Subsystem.
diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile
index d8590304f3df..d295bded7a32 100644
--- a/drivers/net/ethernet/ti/Makefile
+++ b/drivers/net/ethernet/ti/Makefile
@@ -38,5 +38,6 @@ icssg-prueth-y := icssg/icssg_prueth.o \
 		  icssg/icssg_config.o \
 		  icssg/icssg_mii_cfg.o \
 		  icssg/icssg_stats.o \
-		  icssg/icssg_ethtool.o
+		  icssg/icssg_ethtool.o \
+		  icssg/icssg_switchdev.o
 obj-$(CONFIG_TI_ICSS_IEP) += icssg/icss_iep.o
diff --git a/drivers/net/ethernet/ti/icssg/icssg_config.c b/drivers/net/ethernet/ti/icssg/icssg_config.c
index afc10014ec03..eda08a87c902 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_config.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_config.c
@@ -105,28 +105,49 @@ static const struct map hwq_map[2][ICSSG_NUM_OTHER_QUEUES] = {
 	},
 };
 
+static void icssg_config_mii_init_switch(struct prueth_emac *emac)
+{
+	struct prueth *prueth = emac->prueth;
+	int mii = prueth_emac_slice(emac);
+	u32 txcfg_reg, pcnt_reg, txcfg;
+	struct regmap *mii_rt;
+
+	mii_rt = prueth->mii_rt;
+
+	txcfg_reg = (mii == ICSS_MII0) ? PRUSS_MII_RT_TXCFG0 :
+				       PRUSS_MII_RT_TXCFG1;
+	pcnt_reg = (mii == ICSS_MII0) ? PRUSS_MII_RT_RX_PCNT0 :
+				       PRUSS_MII_RT_RX_PCNT1;
+
+	txcfg = PRUSS_MII_RT_TXCFG_TX_ENABLE |
+		PRUSS_MII_RT_TXCFG_TX_AUTO_PREAMBLE |
+		PRUSS_MII_RT_TXCFG_TX_IPG_WIRE_CLK_EN;
+
+	if (emac->phy_if == PHY_INTERFACE_MODE_MII && mii == ICSS_MII1)
+		txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
+	else if (emac->phy_if != PHY_INTERFACE_MODE_MII && mii == ICSS_MII0)
+		txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
+
+	regmap_write(mii_rt, txcfg_reg, txcfg);
+	regmap_write(mii_rt, pcnt_reg, 0x1);
+}
+
 static void icssg_config_mii_init(struct prueth_emac *emac)
 {
-	u32 rxcfg, txcfg, rxcfg_reg, txcfg_reg, pcnt_reg;
 	struct prueth *prueth = emac->prueth;
 	int slice = prueth_emac_slice(emac);
+	u32 txcfg, txcfg_reg, pcnt_reg;
 	struct regmap *mii_rt;
 
 	mii_rt = prueth->mii_rt;
 
-	rxcfg_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_RXCFG0 :
-				       PRUSS_MII_RT_RXCFG1;
 	txcfg_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_TXCFG0 :
 				       PRUSS_MII_RT_TXCFG1;
 	pcnt_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_RX_PCNT0 :
 				       PRUSS_MII_RT_RX_PCNT1;
 
-	rxcfg = MII_RXCFG_DEFAULT;
 	txcfg = MII_TXCFG_DEFAULT;
 
-	if (slice == ICSS_MII1)
-		rxcfg |= PRUSS_MII_RT_RXCFG_RX_MUX_SEL;
-
 	/* In MII mode TX lines swapped inside ICSSG, so TX_MUX_SEL cfg need
 	 * to be swapped also comparing to RGMII mode.
 	 */
@@ -135,7 +156,6 @@ static void icssg_config_mii_init(struct prueth_emac *emac)
 	else if (emac->phy_if != PHY_INTERFACE_MODE_MII && slice == ICSS_MII1)
 		txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
 
-	regmap_write(mii_rt, rxcfg_reg, rxcfg);
 	regmap_write(mii_rt, txcfg_reg, txcfg);
 	regmap_write(mii_rt, pcnt_reg, 0x1);
 }
@@ -249,6 +269,66 @@ static int emac_r30_is_done(struct prueth_emac *emac)
 	return 1;
 }
 
+static int prueth_switch_buffer_setup(struct prueth_emac *emac)
+{
+	struct icssg_buffer_pool_cfg __iomem *bpool_cfg;
+	struct icssg_rxq_ctx __iomem *rxq_ctx;
+	struct prueth *prueth = emac->prueth;
+	int slice = prueth_emac_slice(emac);
+	u32 addr;
+	int i;
+
+	addr = lower_32_bits(prueth->msmcram.pa);
+	if (slice)
+		addr += PRUETH_NUM_BUF_POOLS * PRUETH_EMAC_BUF_POOL_SIZE;
+
+	if (addr % SZ_64K) {
+		dev_warn(prueth->dev, "buffer pool needs to be 64KB aligned\n");
+		return -EINVAL;
+	}
+
+	bpool_cfg = emac->dram.va + BUFFER_POOL_0_ADDR_OFFSET;
+	/* workaround for f/w bug. bpool 0 needs to be initilalized */
+	for (i = 0; i <  PRUETH_NUM_BUF_POOLS; i++) {
+		writel(addr, &bpool_cfg[i].addr);
+		writel(PRUETH_EMAC_BUF_POOL_SIZE, &bpool_cfg[i].len);
+		addr += PRUETH_EMAC_BUF_POOL_SIZE;
+	}
+
+	if (!slice)
+		addr += PRUETH_NUM_BUF_POOLS * PRUETH_EMAC_BUF_POOL_SIZE;
+	else
+		addr += PRUETH_SW_NUM_BUF_POOLS_HOST * PRUETH_SW_BUF_POOL_SIZE_HOST;
+
+	for (i = PRUETH_NUM_BUF_POOLS;
+	     i < 2 * PRUETH_SW_NUM_BUF_POOLS_HOST + PRUETH_NUM_BUF_POOLS;
+	     i++) {
+		/* The driver only uses first 4 queues per PRU so only initialize them */
+		if (i % PRUETH_SW_NUM_BUF_POOLS_HOST < PRUETH_SW_NUM_BUF_POOLS_PER_PRU) {
+			writel(addr, &bpool_cfg[i].addr);
+			writel(PRUETH_SW_BUF_POOL_SIZE_HOST, &bpool_cfg[i].len);
+			addr += PRUETH_SW_BUF_POOL_SIZE_HOST;
+		} else {
+			writel(0, &bpool_cfg[i].addr);
+			writel(0, &bpool_cfg[i].len);
+		}
+	}
+
+	if (!slice)
+		addr += PRUETH_SW_NUM_BUF_POOLS_HOST * PRUETH_SW_BUF_POOL_SIZE_HOST;
+	else
+		addr += PRUETH_EMAC_RX_CTX_BUF_SIZE;
+
+	rxq_ctx = emac->dram.va + HOST_RX_Q_PRE_CONTEXT_OFFSET;
+	for (i = 0; i < 3; i++)
+		writel(addr, &rxq_ctx->start[i]);
+
+	addr += PRUETH_EMAC_RX_CTX_BUF_SIZE;
+	writel(addr - SZ_2K, &rxq_ctx->end);
+
+	return 0;
+}
+
 static int prueth_emac_buffer_setup(struct prueth_emac *emac)
 {
 	struct icssg_buffer_pool_cfg __iomem *bpool_cfg;
@@ -325,13 +405,41 @@ static void icssg_init_emac_mode(struct prueth *prueth)
 	icssg_class_set_host_mac_addr(prueth->miig_rt, mac);
 }
 
+static void icssg_init_switch_mode(struct prueth *prueth)
+{
+	u32 addr = prueth->shram.pa + EMAC_ICSSG_SWITCH_DEFAULT_VLAN_TABLE_OFFSET;
+	int i;
+
+	if (prueth->emacs_initialized)
+		return;
+
+	/* Set VLAN TABLE address base */
+	regmap_update_bits(prueth->miig_rt, FDB_GEN_CFG1, SMEM_VLAN_OFFSET_MASK,
+			   addr <<  SMEM_VLAN_OFFSET);
+	/* Set enable VLAN aware mode, and FDBs for all PRUs */
+	regmap_write(prueth->miig_rt, FDB_GEN_CFG2, FDB_EN_ALL);
+	prueth->vlan_tbl = (struct prueth_vlan_tbl __force *)(prueth->shram.va +
+			    EMAC_ICSSG_SWITCH_DEFAULT_VLAN_TABLE_OFFSET);
+	for (i = 0; i < SZ_4K - 1; i++) {
+		prueth->vlan_tbl[i].fid = i;
+		prueth->vlan_tbl[i].fid_c1 = 0;
+	}
+
+	if (prueth->hw_bridge_dev)
+		icssg_class_set_host_mac_addr(prueth->miig_rt, prueth->hw_bridge_dev->dev_addr);
+	icssg_set_pvid(prueth, prueth->default_vlan, PRUETH_PORT_HOST);
+}
+
 int icssg_config(struct prueth *prueth, struct prueth_emac *emac, int slice)
 {
 	void __iomem *config = emac->dram.va + ICSSG_CONFIG_OFFSET;
 	struct icssg_flow_cfg __iomem *flow_cfg;
 	int ret;
 
-	icssg_init_emac_mode(prueth);
+	if (prueth->is_switch_mode)
+		icssg_init_switch_mode(prueth);
+	else
+		icssg_init_emac_mode(prueth);
 
 	memset_io(config, 0, TAS_GATE_MASK_LIST0);
 	icssg_miig_queues_init(prueth, slice);
@@ -345,7 +453,10 @@ int icssg_config(struct prueth *prueth, struct prueth_emac *emac, int slice)
 	regmap_update_bits(prueth->miig_rt, ICSSG_CFG_OFFSET,
 			   ICSSG_CFG_DEFAULT, ICSSG_CFG_DEFAULT);
 	icssg_miig_set_interface_mode(prueth->miig_rt, slice, emac->phy_if);
-	icssg_config_mii_init(emac);
+	if (prueth->is_switch_mode)
+		icssg_config_mii_init_switch(emac);
+	else
+		icssg_config_mii_init(emac);
 	icssg_config_ipg(emac);
 	icssg_update_rgmii_cfg(prueth->miig_rt, emac);
 
@@ -368,7 +479,10 @@ int icssg_config(struct prueth *prueth, struct prueth_emac *emac, int slice)
 	writeb(0, config + SPL_PKT_DEFAULT_PRIORITY);
 	writeb(0, config + QUEUE_NUM_UNTAGGED);
 
-	ret = prueth_emac_buffer_setup(emac);
+	if (prueth->is_switch_mode)
+		ret = prueth_switch_buffer_setup(emac);
+	else
+		ret = prueth_emac_buffer_setup(emac);
 	if (ret)
 		return ret;
 
diff --git a/drivers/net/ethernet/ti/icssg/icssg_config.h b/drivers/net/ethernet/ti/icssg/icssg_config.h
index 0d5d5d253b7a..cc923f1d4387 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_config.h
+++ b/drivers/net/ethernet/ti/icssg/icssg_config.h
@@ -35,6 +35,13 @@ struct icssg_flow_cfg {
 	(2 * (PRUETH_EMAC_BUF_POOL_SIZE * PRUETH_NUM_BUF_POOLS + \
 	 PRUETH_EMAC_RX_CTX_BUF_SIZE * 2))
 
+#define PRUETH_SW_BUF_POOL_SIZE_HOST	SZ_4K
+#define PRUETH_SW_NUM_BUF_POOLS_HOST	8
+#define PRUETH_SW_NUM_BUF_POOLS_PER_PRU 4
+#define MSMC_RAM_SIZE_SWITCH_MODE \
+	(MSMC_RAM_SIZE + \
+	(2 * PRUETH_SW_BUF_POOL_SIZE_HOST * PRUETH_SW_NUM_BUF_POOLS_HOST))
+
 #define PRUETH_SWITCH_FDB_MASK ((SIZE_OF_FDB / NUMBER_OF_FDB_BUCKET_ENTRIES) - 1)
 
 struct icssg_rxq_ctx {
diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
index 38d41ba6762a..9197599e5495 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
@@ -27,6 +27,7 @@
 #include <linux/remoteproc/pruss.h>
 #include <linux/regmap.h>
 #include <linux/remoteproc.h>
+#include <net/switchdev.h>
 
 #include "icssg_prueth.h"
 #include "icssg_mii_rt.h"
@@ -54,6 +55,10 @@
 
 #define prueth_napi_to_emac(napi) container_of(napi, struct prueth_emac, napi_rx)
 
+#define DEFAULT_VID		1
+#define DEFAULT_PORT_MASK	1
+#define DEFAULT_UNTAG_MASK	1
+
 /* CTRLMMR_ICSSG_RGMII_CTRL register bits */
 #define ICSSG_CTRL_RGMII_ID_MODE                BIT(24)
 
@@ -558,6 +563,8 @@ static int emac_rx_packet(struct prueth_emac *emac, u32 flow_id)
 	} else {
 		/* send the filled skb up the n/w stack */
 		skb_put(skb, pkt_len);
+		if (emac->prueth->is_switch_mode)
+			skb->offload_fwd_mark = emac->offload_fwd_mark;
 		skb->protocol = eth_type_trans(skb, ndev);
 		napi_gro_receive(&emac->napi_rx, skb);
 		ndev->stats.rx_bytes += pkt_len;
@@ -890,6 +897,19 @@ struct icssg_firmwares {
 	char *txpru;
 };
 
+static struct icssg_firmwares icssg_switch_firmwares[] = {
+	{
+		.pru = "ti-pruss/am65x-sr2-pru0-prusw-fw.elf",
+		.rtu = "ti-pruss/am65x-sr2-rtu0-prusw-fw.elf",
+		.txpru = "ti-pruss/am65x-sr2-txpru0-prusw-fw.elf",
+	},
+	{
+		.pru = "ti-pruss/am65x-sr2-pru1-prusw-fw.elf",
+		.rtu = "ti-pruss/am65x-sr2-rtu1-prusw-fw.elf",
+		.txpru = "ti-pruss/am65x-sr2-txpru1-prusw-fw.elf",
+	}
+};
+
 static struct icssg_firmwares icssg_emac_firmwares[] = {
 	{
 		.pru = "ti-pruss/am65x-sr2-pru0-prueth-fw.elf",
@@ -909,7 +929,10 @@ static int prueth_emac_start(struct prueth *prueth, struct prueth_emac *emac)
 	struct device *dev = prueth->dev;
 	int slice, ret;
 
-	firmwares = icssg_emac_firmwares;
+	if (prueth->is_switch_mode)
+		firmwares = icssg_switch_firmwares;
+	else
+		firmwares = icssg_emac_firmwares;
 
 	slice = prueth_emac_slice(emac);
 	if (slice < 0) {
@@ -1411,6 +1434,21 @@ static int emac_ndo_open(struct net_device *ndev)
 
 	queue_work(system_long_wq, &emac->stats_work.work);
 
+	if (prueth->is_switch_mode) {
+		icssg_fdb_add_del(emac, eth_stp_addr, prueth->default_vlan,
+				  ICSSG_FDB_ENTRY_P0_MEMBERSHIP |
+				  ICSSG_FDB_ENTRY_P1_MEMBERSHIP |
+				  ICSSG_FDB_ENTRY_P2_MEMBERSHIP |
+				  ICSSG_FDB_ENTRY_BLOCK,
+				  true);
+		icssg_vtbl_modify(emac, emac->port_vlan | DEFAULT_VID,
+				  BIT(emac->port_id) | DEFAULT_PORT_MASK,
+				  BIT(emac->port_id) | DEFAULT_UNTAG_MASK,
+				  true);
+		icssg_set_pvid(emac->prueth, emac->port_vlan, emac->port_id);
+		emac_set_port_state(emac, ICSSG_EMAC_PORT_VLAN_AWARE_ENABLE);
+	}
+
 	return 0;
 
 reset_tx_chan:
@@ -1949,6 +1987,148 @@ static void prueth_put_cores(struct prueth *prueth, int slice)
 		pru_rproc_put(prueth->pru[slice]);
 }
 
+static void prueth_offload_fwd_mark_update(struct prueth *prueth)
+{
+	int set_val = 0;
+	int i;
+
+	if (prueth->br_members == (PRUETH_PORT_MII0 | PRUETH_PORT_MII1))
+		set_val = 1;
+
+	dev_dbg(prueth->dev, "set offload_fwd_mark %d\n", set_val);
+
+	for (i = PRUETH_MAC0; i < PRUETH_NUM_MACS; i++) {
+		struct prueth_emac *emac = prueth->emac[i];
+
+		if (!emac || !emac->ndev)
+			continue;
+
+		emac->offload_fwd_mark = set_val;
+	}
+}
+
+bool prueth_dev_check(const struct net_device *ndev)
+{
+	if (ndev->netdev_ops == &emac_netdev_ops && netif_running(ndev)) {
+		struct prueth_emac *emac = netdev_priv(ndev);
+
+		return emac->prueth->is_switch_mode;
+	}
+
+	return false;
+}
+
+static int prueth_netdevice_port_link(struct net_device *ndev,
+				      struct net_device *br_ndev,
+				      struct netlink_ext_ack *extack)
+{
+	struct prueth_emac *emac = netdev_priv(ndev);
+	struct prueth *prueth = emac->prueth;
+	int err;
+
+	if (!prueth->br_members) {
+		prueth->hw_bridge_dev = br_ndev;
+	} else {
+		/* This is adding the port to a second bridge, this is
+		 * unsupported
+		 */
+		if (prueth->hw_bridge_dev != br_ndev)
+			return -EOPNOTSUPP;
+	}
+
+	err = switchdev_bridge_port_offload(br_ndev, ndev, emac,
+					    &prueth->prueth_switchdev_nb,
+					    &prueth->prueth_switchdev_bl_nb,
+					    false, extack);
+	if (err)
+		return err;
+
+	prueth->br_members |= BIT(emac->port_id);
+
+	if (prueth->br_members & BIT(PRUETH_PORT_MII0) &&
+	    prueth->br_members & BIT(PRUETH_PORT_MII1)) {
+		prueth->is_switch_mode = true;
+		prueth->default_vlan = 1;
+		emac->port_vlan = prueth->default_vlan;
+	}
+
+	prueth_offload_fwd_mark_update(prueth);
+
+	return NOTIFY_DONE;
+}
+
+static void prueth_netdevice_port_unlink(struct net_device *ndev)
+{
+	struct prueth_emac *emac = netdev_priv(ndev);
+	struct prueth *prueth = emac->prueth;
+
+	prueth->br_members &= ~BIT(emac->port_id);
+
+	prueth->is_switch_mode = false;
+	emac->port_vlan = 0;
+
+	prueth_offload_fwd_mark_update(prueth);
+
+	if (!prueth->br_members)
+		prueth->hw_bridge_dev = NULL;
+}
+
+/* netdev notifier */
+static int prueth_netdevice_event(struct notifier_block *unused,
+				  unsigned long event, void *ptr)
+{
+	struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(ptr);
+	struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
+	struct netdev_notifier_changeupper_info *info;
+	int ret = NOTIFY_DONE;
+
+	if (ndev->netdev_ops != &emac_netdev_ops)
+		return NOTIFY_DONE;
+
+	switch (event) {
+	case NETDEV_CHANGEUPPER:
+		info = ptr;
+
+		if (netif_is_bridge_master(info->upper_dev)) {
+			if (info->linking)
+				ret = prueth_netdevice_port_link(ndev, info->upper_dev, extack);
+			else
+				prueth_netdevice_port_unlink(ndev);
+		}
+		break;
+	default:
+		return NOTIFY_DONE;
+	}
+
+	return notifier_from_errno(ret);
+}
+
+static int prueth_register_notifiers(struct prueth *prueth)
+{
+	int ret = 0;
+
+	prueth->prueth_netdevice_nb.notifier_call = &prueth_netdevice_event;
+	ret = register_netdevice_notifier(&prueth->prueth_netdevice_nb);
+	if (ret) {
+		dev_err(prueth->dev, "can't register netdevice notifier\n");
+		return ret;
+	}
+
+	ret = prueth_switchdev_register_notifiers(prueth);
+	if (ret)
+		unregister_netdevice_notifier(&prueth->prueth_netdevice_nb);
+
+	return ret;
+}
+
+static void prueth_unregister_notifiers(struct prueth *prueth)
+{
+	prueth_switchdev_unregister_notifiers(prueth);
+	unregister_netdevice_notifier(&prueth->prueth_netdevice_nb);
+}
+
+static const struct of_device_id prueth_dt_match[];
+
 static int prueth_probe(struct platform_device *pdev)
 {
 	struct device_node *eth_node, *eth_ports_node;
@@ -2076,6 +2256,10 @@ static int prueth_probe(struct platform_device *pdev)
 	}
 
 	msmc_ram_size = MSMC_RAM_SIZE;
+	prueth->is_switchmode_supported = prueth->pdata.switch_mode;
+	if (prueth->is_switchmode_supported)
+		msmc_ram_size = MSMC_RAM_SIZE_SWITCH_MODE;
+
 
 	/* NOTE: FW bug needs buffer base to be 64KB aligned */
 	prueth->msmcram.va =
@@ -2171,6 +2355,14 @@ static int prueth_probe(struct platform_device *pdev)
 		phy_attached_info(prueth->emac[PRUETH_MAC1]->ndev->phydev);
 	}
 
+	if (prueth->is_switchmode_supported) {
+		ret = prueth_register_notifiers(prueth);
+		if (ret)
+			goto netdev_unregister;
+
+		sprintf(prueth->switch_id, "%s", dev_name(dev));
+	}
+
 	dev_info(dev, "TI PRU ethernet driver initialized: %s EMAC mode\n",
 		 (!eth0_node || !eth1_node) ? "single" : "dual");
 
@@ -2240,6 +2432,8 @@ static void prueth_remove(struct platform_device *pdev)
 	struct device_node *eth_node;
 	int i;
 
+	prueth_unregister_notifiers(prueth);
+
 	for (i = 0; i < PRUETH_NUM_MACS; i++) {
 		if (!prueth->registered_netdevs[i])
 			continue;
@@ -2337,10 +2531,12 @@ static const struct dev_pm_ops prueth_dev_pm_ops = {
 static const struct prueth_pdata am654_icssg_pdata = {
 	.fdqring_mode = K3_RINGACC_RING_MODE_MESSAGE,
 	.quirk_10m_link_issue = 1,
+	.switch_mode = 1,
 };
 
 static const struct prueth_pdata am64x_icssg_pdata = {
 	.fdqring_mode = K3_RINGACC_RING_MODE_RING,
+	.switch_mode = 1,
 };
 
 static const struct of_device_id prueth_dt_match[] = {
diff --git a/drivers/net/ethernet/ti/icssg/icssg_switchdev.c b/drivers/net/ethernet/ti/icssg/icssg_switchdev.c
index 48d8ed4fa7a8..90d0d98e0ef9 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_switchdev.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_switchdev.c
@@ -14,7 +14,7 @@
 
 #include "icssg_prueth.h"
 #include "icssg_switchdev.h"
-#include "icss_mii_rt.h"
+#include "icssg_mii_rt.h"
 
 struct prueth_switchdev_event_work {
 	struct work_struct work;
-- 
2.34.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [RFC PATCH v2 0/3] Introduce switch mode support for ICSSG driver
  2024-01-18  7:10 ` MD Danish Anwar
@ 2024-01-18 14:01   ` Andrew Lunn
  -1 siblings, 0 replies; 34+ messages in thread
From: Andrew Lunn @ 2024-01-18 14:01 UTC (permalink / raw)
  To: MD Danish Anwar
  Cc: Rob Herring, Dan Carpenter, Jan Kiszka, Vladimir Oltean,
	Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, Paolo Abeni, Jakub Kicinski,
	Eric Dumazet, David S. Miller, linux-arm-kernel, netdev,
	linux-kernel, srk, r-gunasekaran

On Thu, Jan 18, 2024 at 12:40:02PM +0530, MD Danish Anwar wrote:
> This series adds support for switch-mode for ICSSG driver. This series
> also introduces helper APIs to configure firmware maintained FDB
> (Forwarding Database) and VLAN tables. These APIs are later used by ICSSG
> driver in switch mode.
> 
> Now the driver will boot by default in dual EMAC mode. When first ICSSG
> interface is added to bridge driver will still be in EMAC mode. As soon as
> second ICSSG interface is added to same bridge, switch-mode will be
> enabled and switch firmwares will be loaded to PRU cores. The driver will
> remain in dual EMAC mode if ICSSG interfaces are added to two different
> bridges or if two differnet interfaces (One ICSSG, one other) is added to
> the same bridge. We'll only enable is_switch_mode flag when two ICSSG
> interfaces are added to same bridge.
> 
> We start in dual MAC mode. Let's say lan0 and lan1 are ICSSG interfaces
> 
> ip link add name br0 type bridge
> ip link set lan0 master br0
> 
> At this point, we get a CHANGEUPPER event. Only one port is a member of
> the bridge, so we will still be in dual MAC mode.
> 
> ip link set lan1 master br0
> 
> We get a second CHANGEUPPER event, the secind interface lan1 is also ICSSG
> interface so we will set the is_switch_mode flag and when interfaces are
> brought up again, ICSSG switch firmwares will be loaded to PRU Cores.
> 
> There are some other cases to consider as well. 
> 
> ip link add name br0 type bridge
> ip link add name br1 type bridge
> 
> ip link set lan0 master br0
> ip link set ppp0 master br0
> 
> Here we are adding lan0 (ICSSG) and ppp0 (non ICSSG) to same bridge, as
> they both are not ICSSG, we will still be running in dual EMAC mode.
> 
> ip link set lan1 master br1
> ip link set vpn0 master br1
> 
> Here we are adding lan1 (ICSSG) and vpn0 (non ICSSG) to same bridge, as
> they both are not ICSSG, we will still be running in dual EMAC mode.

This is going in the right direction, thanks for the changes.

What features does the dual EMAC firmware support which the switch
firmware does not?

If such features are in use, you should not reload firmware to the
switch firmware, since it will break whatever has been
configured. Keep with bridging in software.

Similarly, what features are supported by both firmwares? Does feature
configuration survive a firmware reload? Or is it necessary to pass
all the configuration to the firmware again?

    Andrew

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

* Re: [RFC PATCH v2 0/3] Introduce switch mode support for ICSSG driver
@ 2024-01-18 14:01   ` Andrew Lunn
  0 siblings, 0 replies; 34+ messages in thread
From: Andrew Lunn @ 2024-01-18 14:01 UTC (permalink / raw)
  To: MD Danish Anwar
  Cc: Rob Herring, Dan Carpenter, Jan Kiszka, Vladimir Oltean,
	Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, Paolo Abeni, Jakub Kicinski,
	Eric Dumazet, David S. Miller, linux-arm-kernel, netdev,
	linux-kernel, srk, r-gunasekaran

On Thu, Jan 18, 2024 at 12:40:02PM +0530, MD Danish Anwar wrote:
> This series adds support for switch-mode for ICSSG driver. This series
> also introduces helper APIs to configure firmware maintained FDB
> (Forwarding Database) and VLAN tables. These APIs are later used by ICSSG
> driver in switch mode.
> 
> Now the driver will boot by default in dual EMAC mode. When first ICSSG
> interface is added to bridge driver will still be in EMAC mode. As soon as
> second ICSSG interface is added to same bridge, switch-mode will be
> enabled and switch firmwares will be loaded to PRU cores. The driver will
> remain in dual EMAC mode if ICSSG interfaces are added to two different
> bridges or if two differnet interfaces (One ICSSG, one other) is added to
> the same bridge. We'll only enable is_switch_mode flag when two ICSSG
> interfaces are added to same bridge.
> 
> We start in dual MAC mode. Let's say lan0 and lan1 are ICSSG interfaces
> 
> ip link add name br0 type bridge
> ip link set lan0 master br0
> 
> At this point, we get a CHANGEUPPER event. Only one port is a member of
> the bridge, so we will still be in dual MAC mode.
> 
> ip link set lan1 master br0
> 
> We get a second CHANGEUPPER event, the secind interface lan1 is also ICSSG
> interface so we will set the is_switch_mode flag and when interfaces are
> brought up again, ICSSG switch firmwares will be loaded to PRU Cores.
> 
> There are some other cases to consider as well. 
> 
> ip link add name br0 type bridge
> ip link add name br1 type bridge
> 
> ip link set lan0 master br0
> ip link set ppp0 master br0
> 
> Here we are adding lan0 (ICSSG) and ppp0 (non ICSSG) to same bridge, as
> they both are not ICSSG, we will still be running in dual EMAC mode.
> 
> ip link set lan1 master br1
> ip link set vpn0 master br1
> 
> Here we are adding lan1 (ICSSG) and vpn0 (non ICSSG) to same bridge, as
> they both are not ICSSG, we will still be running in dual EMAC mode.

This is going in the right direction, thanks for the changes.

What features does the dual EMAC firmware support which the switch
firmware does not?

If such features are in use, you should not reload firmware to the
switch firmware, since it will break whatever has been
configured. Keep with bridging in software.

Similarly, what features are supported by both firmwares? Does feature
configuration survive a firmware reload? Or is it necessary to pass
all the configuration to the firmware again?

    Andrew

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [RFC PATCH v2 1/3] net: ti: icssg-prueth: Add helper functions to configure FDB
  2024-01-18  7:10   ` MD Danish Anwar
@ 2024-01-19 13:55     ` Andrew Lunn
  -1 siblings, 0 replies; 34+ messages in thread
From: Andrew Lunn @ 2024-01-19 13:55 UTC (permalink / raw)
  To: MD Danish Anwar
  Cc: Rob Herring, Dan Carpenter, Jan Kiszka, Vladimir Oltean,
	Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, Paolo Abeni, Jakub Kicinski,
	Eric Dumazet, David S. Miller, linux-arm-kernel, netdev,
	linux-kernel, srk, r-gunasekaran

> +int icssg_fdb_add_del(struct prueth_emac *emac, const unsigned char *addr,
> +		      u8 vid, u8 fid_c2, bool add)
> +{
> +
> +	for (i = 0; i < ETH_ALEN; i++)
> +		mac_fid[i] = addr[i];

ether_addr_copy()

> +
> +	/* 1-1 VID-FID mapping is already setup */
> +	mac_fid[ETH_ALEN] = fid;
> +	mac_fid[ETH_ALEN + 1] = 0;
> +
> +	fdb_slot = bitrev32(crc32_le(0, mac_fid, 8)) & PRUETH_SWITCH_FDB_MASK;
> +

> +	fid_c2 |= ICSSG_FDB_ENTRY_VALID;
> +	memcpy(&fdb_cmd.cmd_args[0], addr, 4);
> +	memcpy(&fdb_cmd.cmd_args[1], &addr[4], 2);
> +	fdb_cmd.cmd_args[1] |= ((fid << 16) | (fid_c2 << 24));
> +	fdb_cmd.cmd_args[2] = fdb_slot;

> +int icssg_fdb_lookup(struct prueth_emac *emac, const unsigned char *addr,
> +		     u8 vid)
> +{

> +	for (i = 0; i < ETH_ALEN; i++)
> +		mac_fid[i] = addr[i];
> +
> +	/* 1-1 VID-FID mapping is already setup */
> +	mac_fid[ETH_ALEN] = fid;
> +	mac_fid[ETH_ALEN + 1] = 0;

> +	memcpy(&fdb_cmd.cmd_args[0], addr, 4);
> +	memcpy(&fdb_cmd.cmd_args[1], &addr[4], 2);
> +	fdb_cmd.cmd_args[1] |= fid << 16;
> +	fdb_cmd.cmd_args[2] = fdb_slot;

Maybe add some helpers to reduce the amount of duplicated code?

      Andrew

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

* Re: [RFC PATCH v2 1/3] net: ti: icssg-prueth: Add helper functions to configure FDB
@ 2024-01-19 13:55     ` Andrew Lunn
  0 siblings, 0 replies; 34+ messages in thread
From: Andrew Lunn @ 2024-01-19 13:55 UTC (permalink / raw)
  To: MD Danish Anwar
  Cc: Rob Herring, Dan Carpenter, Jan Kiszka, Vladimir Oltean,
	Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, Paolo Abeni, Jakub Kicinski,
	Eric Dumazet, David S. Miller, linux-arm-kernel, netdev,
	linux-kernel, srk, r-gunasekaran

> +int icssg_fdb_add_del(struct prueth_emac *emac, const unsigned char *addr,
> +		      u8 vid, u8 fid_c2, bool add)
> +{
> +
> +	for (i = 0; i < ETH_ALEN; i++)
> +		mac_fid[i] = addr[i];

ether_addr_copy()

> +
> +	/* 1-1 VID-FID mapping is already setup */
> +	mac_fid[ETH_ALEN] = fid;
> +	mac_fid[ETH_ALEN + 1] = 0;
> +
> +	fdb_slot = bitrev32(crc32_le(0, mac_fid, 8)) & PRUETH_SWITCH_FDB_MASK;
> +

> +	fid_c2 |= ICSSG_FDB_ENTRY_VALID;
> +	memcpy(&fdb_cmd.cmd_args[0], addr, 4);
> +	memcpy(&fdb_cmd.cmd_args[1], &addr[4], 2);
> +	fdb_cmd.cmd_args[1] |= ((fid << 16) | (fid_c2 << 24));
> +	fdb_cmd.cmd_args[2] = fdb_slot;

> +int icssg_fdb_lookup(struct prueth_emac *emac, const unsigned char *addr,
> +		     u8 vid)
> +{

> +	for (i = 0; i < ETH_ALEN; i++)
> +		mac_fid[i] = addr[i];
> +
> +	/* 1-1 VID-FID mapping is already setup */
> +	mac_fid[ETH_ALEN] = fid;
> +	mac_fid[ETH_ALEN + 1] = 0;

> +	memcpy(&fdb_cmd.cmd_args[0], addr, 4);
> +	memcpy(&fdb_cmd.cmd_args[1], &addr[4], 2);
> +	fdb_cmd.cmd_args[1] |= fid << 16;
> +	fdb_cmd.cmd_args[2] = fdb_slot;

Maybe add some helpers to reduce the amount of duplicated code?

      Andrew

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [RFC PATCH v2 2/3] net: ti: icssg-switch: Add switchdev based driver for ethernet switch support
  2024-01-18  7:10   ` MD Danish Anwar
@ 2024-01-19 14:12     ` Andrew Lunn
  -1 siblings, 0 replies; 34+ messages in thread
From: Andrew Lunn @ 2024-01-19 14:12 UTC (permalink / raw)
  To: MD Danish Anwar
  Cc: Rob Herring, Dan Carpenter, Jan Kiszka, Vladimir Oltean,
	Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, Paolo Abeni, Jakub Kicinski,
	Eric Dumazet, David S. Miller, linux-arm-kernel, netdev,
	linux-kernel, srk, r-gunasekaran

> +static int prueth_switchdev_stp_state_set(struct prueth_emac *emac,
> +					  u8 state)
> +{
> +	enum icssg_port_state_cmd emac_state;
> +	int ret = 0;
> +
> +	switch (state) {
> +	case BR_STATE_FORWARDING:
> +		emac_state = ICSSG_EMAC_PORT_FORWARD;
> +		break;
> +	case BR_STATE_DISABLED:
> +		emac_state = ICSSG_EMAC_PORT_DISABLE;
> +		break;
> +	case BR_STATE_LEARNING:
> +	case BR_STATE_LISTENING:
> +	case BR_STATE_BLOCKING:
> +		emac_state = ICSSG_EMAC_PORT_BLOCK;
> +		break;

That is unusual. Does it still learn while in BLOCK? It might be you
need to flush the FDB for this port when it changes from BLOCKING to
LISTENING or LEARNING?

> +static void prueth_switchdev_event_work(struct work_struct *work)
> +{
> +	struct prueth_switchdev_event_work *switchdev_work =
> +		container_of(work, struct prueth_switchdev_event_work, work);
> +	struct prueth_emac *emac = switchdev_work->emac;
> +	struct switchdev_notifier_fdb_info *fdb;
> +	int port_id = emac->port_id;
> +	int ret;
> +
> +	rtnl_lock();
> +	switch (switchdev_work->event) {
> +	case SWITCHDEV_FDB_ADD_TO_DEVICE:
> +		fdb = &switchdev_work->fdb_info;
> +
> +		netdev_dbg(emac->ndev, "prueth_fdb_add: MACID = %pM vid = %u flags = %u %u -- port %d\n",
> +			   fdb->addr, fdb->vid, fdb->added_by_user,
> +			   fdb->offloaded, port_id);
> +
> +		if (!fdb->added_by_user)
> +			break;
> +		if (memcmp(emac->mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0)
> +			break;

ether_addr_equal(). Please review all the code and use these helpers
when possible.

So you don't add an FDB for the interfaces own MAC address? Does the
switch know the interfaces MAC address?

       Andrew

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

* Re: [RFC PATCH v2 2/3] net: ti: icssg-switch: Add switchdev based driver for ethernet switch support
@ 2024-01-19 14:12     ` Andrew Lunn
  0 siblings, 0 replies; 34+ messages in thread
From: Andrew Lunn @ 2024-01-19 14:12 UTC (permalink / raw)
  To: MD Danish Anwar
  Cc: Rob Herring, Dan Carpenter, Jan Kiszka, Vladimir Oltean,
	Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, Paolo Abeni, Jakub Kicinski,
	Eric Dumazet, David S. Miller, linux-arm-kernel, netdev,
	linux-kernel, srk, r-gunasekaran

> +static int prueth_switchdev_stp_state_set(struct prueth_emac *emac,
> +					  u8 state)
> +{
> +	enum icssg_port_state_cmd emac_state;
> +	int ret = 0;
> +
> +	switch (state) {
> +	case BR_STATE_FORWARDING:
> +		emac_state = ICSSG_EMAC_PORT_FORWARD;
> +		break;
> +	case BR_STATE_DISABLED:
> +		emac_state = ICSSG_EMAC_PORT_DISABLE;
> +		break;
> +	case BR_STATE_LEARNING:
> +	case BR_STATE_LISTENING:
> +	case BR_STATE_BLOCKING:
> +		emac_state = ICSSG_EMAC_PORT_BLOCK;
> +		break;

That is unusual. Does it still learn while in BLOCK? It might be you
need to flush the FDB for this port when it changes from BLOCKING to
LISTENING or LEARNING?

> +static void prueth_switchdev_event_work(struct work_struct *work)
> +{
> +	struct prueth_switchdev_event_work *switchdev_work =
> +		container_of(work, struct prueth_switchdev_event_work, work);
> +	struct prueth_emac *emac = switchdev_work->emac;
> +	struct switchdev_notifier_fdb_info *fdb;
> +	int port_id = emac->port_id;
> +	int ret;
> +
> +	rtnl_lock();
> +	switch (switchdev_work->event) {
> +	case SWITCHDEV_FDB_ADD_TO_DEVICE:
> +		fdb = &switchdev_work->fdb_info;
> +
> +		netdev_dbg(emac->ndev, "prueth_fdb_add: MACID = %pM vid = %u flags = %u %u -- port %d\n",
> +			   fdb->addr, fdb->vid, fdb->added_by_user,
> +			   fdb->offloaded, port_id);
> +
> +		if (!fdb->added_by_user)
> +			break;
> +		if (memcmp(emac->mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0)
> +			break;

ether_addr_equal(). Please review all the code and use these helpers
when possible.

So you don't add an FDB for the interfaces own MAC address? Does the
switch know the interfaces MAC address?

       Andrew

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [RFC PATCH v2 3/3] net: ti: icssg-prueth: Add support for ICSSG switch firmware
  2024-01-18  7:10   ` MD Danish Anwar
@ 2024-01-19 14:29     ` Andrew Lunn
  -1 siblings, 0 replies; 34+ messages in thread
From: Andrew Lunn @ 2024-01-19 14:29 UTC (permalink / raw)
  To: MD Danish Anwar
  Cc: Rob Herring, Dan Carpenter, Jan Kiszka, Vladimir Oltean,
	Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, Paolo Abeni, Jakub Kicinski,
	Eric Dumazet, David S. Miller, linux-arm-kernel, netdev,
	linux-kernel, srk, r-gunasekaran

On Thu, Jan 18, 2024 at 12:40:05PM +0530, MD Danish Anwar wrote:
> Add support for ICSSG switch firmware using existing Dual EMAC driver
> with switchdev.
> 
> Limitations:
> VLAN offloading is limited to 0-256 IDs.
> MDB/FDB static entries are limited to 511 entries and different FDBs can
> hash to same bucket and thus may not completely offloaded

What are the limits when using Dual EMAC driver? I'm just wondering if
we need to check that 257 VLANs have been offloaded, we cannot swap to
switch mode, keep with Dual EMAC?


> Switch mode requires loading of new firmware into ICSSG cores. This
> means interfaces have to taken down and then reconfigured to switch
> mode.

This is now out of date?

> 
> Example assuming ETH1 and ETH2 as ICSSG2 interfaces:
> 
> Switch to ICSSG Switch mode:
>  ip link set dev eth1 down
>  ip link set dev eth2 down
>  ip link add name br0 type bridge
>  ip link set dev eth1 master br0
>  ip link set dev eth2 master br0
>  ip link set dev br0 up
>  ip link set dev eth1 up
>  ip link set dev eth2 up
>  bridge vlan add dev br0 vid 1 pvid untagged self
> 
> Going back to Dual EMAC mode:
> 
>  ip link set dev br0 down
>  ip link set dev eth1 nomaster
>  ip link set dev eth2 nomaster
>  ip link set dev eth1 down
>  ip link set dev eth2 down
>  ip link del name br0 type bridge
>  ip link set dev eth1 up
>  ip link set dev eth2 up
> 
> By default, Dual EMAC firmware is loaded, and can be changed to switch
> mode by above steps
> 
> Signed-off-by: MD Danish Anwar <danishanwar@ti.com>
> ---
>  drivers/net/ethernet/ti/Kconfig               |   1 +
>  drivers/net/ethernet/ti/Makefile              |   3 +-
>  drivers/net/ethernet/ti/icssg/icssg_config.c  | 136 +++++++++++-
>  drivers/net/ethernet/ti/icssg/icssg_config.h  |   7 +
>  drivers/net/ethernet/ti/icssg/icssg_prueth.c  | 198 +++++++++++++++++-
>  .../net/ethernet/ti/icssg/icssg_switchdev.c   |   2 +-
>  6 files changed, 333 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig
> index be01450c20dc..c72f26828b04 100644
> --- a/drivers/net/ethernet/ti/Kconfig
> +++ b/drivers/net/ethernet/ti/Kconfig
> @@ -188,6 +188,7 @@ config TI_ICSSG_PRUETH
>  	select TI_ICSS_IEP
>  	select TI_K3_CPPI_DESC_POOL
>  	depends on PRU_REMOTEPROC
> +	depends on NET_SWITCHDEV
>  	depends on ARCH_K3 && OF && TI_K3_UDMA_GLUE_LAYER
>  	help
>  	  Support dual Gigabit Ethernet ports over the ICSSG PRU Subsystem.
> diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile
> index d8590304f3df..d295bded7a32 100644
> --- a/drivers/net/ethernet/ti/Makefile
> +++ b/drivers/net/ethernet/ti/Makefile
> @@ -38,5 +38,6 @@ icssg-prueth-y := icssg/icssg_prueth.o \
>  		  icssg/icssg_config.o \
>  		  icssg/icssg_mii_cfg.o \
>  		  icssg/icssg_stats.o \
> -		  icssg/icssg_ethtool.o
> +		  icssg/icssg_ethtool.o \
> +		  icssg/icssg_switchdev.o
>  obj-$(CONFIG_TI_ICSS_IEP) += icssg/icss_iep.o
> diff --git a/drivers/net/ethernet/ti/icssg/icssg_config.c b/drivers/net/ethernet/ti/icssg/icssg_config.c
> index afc10014ec03..eda08a87c902 100644
> --- a/drivers/net/ethernet/ti/icssg/icssg_config.c
> +++ b/drivers/net/ethernet/ti/icssg/icssg_config.c
> @@ -105,28 +105,49 @@ static const struct map hwq_map[2][ICSSG_NUM_OTHER_QUEUES] = {
>  	},
>  };
>  
> +static void icssg_config_mii_init_switch(struct prueth_emac *emac)

I'm surprised you need to configure the MII interface different in
switch mode. Please could you explain this a bit more.

> +{
> +	struct prueth *prueth = emac->prueth;
> +	int mii = prueth_emac_slice(emac);
> +	u32 txcfg_reg, pcnt_reg, txcfg;
> +	struct regmap *mii_rt;
> +
> +	mii_rt = prueth->mii_rt;
> +
> +	txcfg_reg = (mii == ICSS_MII0) ? PRUSS_MII_RT_TXCFG0 :
> +				       PRUSS_MII_RT_TXCFG1;
> +	pcnt_reg = (mii == ICSS_MII0) ? PRUSS_MII_RT_RX_PCNT0 :
> +				       PRUSS_MII_RT_RX_PCNT1;
> +
> +	txcfg = PRUSS_MII_RT_TXCFG_TX_ENABLE |
> +		PRUSS_MII_RT_TXCFG_TX_AUTO_PREAMBLE |
> +		PRUSS_MII_RT_TXCFG_TX_IPG_WIRE_CLK_EN;
> +
> +	if (emac->phy_if == PHY_INTERFACE_MODE_MII && mii == ICSS_MII1)
> +		txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
> +	else if (emac->phy_if != PHY_INTERFACE_MODE_MII && mii == ICSS_MII0)
> +		txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
> +
> +	regmap_write(mii_rt, txcfg_reg, txcfg);
> +	regmap_write(mii_rt, pcnt_reg, 0x1);
> +}
> +
>  static void icssg_config_mii_init(struct prueth_emac *emac)
>  {
> -	u32 rxcfg, txcfg, rxcfg_reg, txcfg_reg, pcnt_reg;
>  	struct prueth *prueth = emac->prueth;
>  	int slice = prueth_emac_slice(emac);
> +	u32 txcfg, txcfg_reg, pcnt_reg;
>  	struct regmap *mii_rt;
>  
>  	mii_rt = prueth->mii_rt;
>  
> -	rxcfg_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_RXCFG0 :
> -				       PRUSS_MII_RT_RXCFG1;
>  	txcfg_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_TXCFG0 :
>  				       PRUSS_MII_RT_TXCFG1;
>  	pcnt_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_RX_PCNT0 :
>  				       PRUSS_MII_RT_RX_PCNT1;
>  
> -	rxcfg = MII_RXCFG_DEFAULT;
>  	txcfg = MII_TXCFG_DEFAULT;
>  
> -	if (slice == ICSS_MII1)
> -		rxcfg |= PRUSS_MII_RT_RXCFG_RX_MUX_SEL;
> -
>  	/* In MII mode TX lines swapped inside ICSSG, so TX_MUX_SEL cfg need
>  	 * to be swapped also comparing to RGMII mode.
>  	 */
> @@ -135,7 +156,6 @@ static void icssg_config_mii_init(struct prueth_emac *emac)
>  	else if (emac->phy_if != PHY_INTERFACE_MODE_MII && slice == ICSS_MII1)
>  		txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
>  
> -	regmap_write(mii_rt, rxcfg_reg, rxcfg);
>  	regmap_write(mii_rt, txcfg_reg, txcfg);
>  	regmap_write(mii_rt, pcnt_reg, 0x1);
>  }
> @@ -249,6 +269,66 @@ static int emac_r30_is_done(struct prueth_emac *emac)
>  	return 1;
>  }
>  
> +static int prueth_switch_buffer_setup(struct prueth_emac *emac)
> +{
> +	struct icssg_buffer_pool_cfg __iomem *bpool_cfg;
> +	struct icssg_rxq_ctx __iomem *rxq_ctx;
> +	struct prueth *prueth = emac->prueth;
> +	int slice = prueth_emac_slice(emac);
> +	u32 addr;
> +	int i;
> +
> +	addr = lower_32_bits(prueth->msmcram.pa);
> +	if (slice)
> +		addr += PRUETH_NUM_BUF_POOLS * PRUETH_EMAC_BUF_POOL_SIZE;
> +
> +	if (addr % SZ_64K) {
> +		dev_warn(prueth->dev, "buffer pool needs to be 64KB aligned\n");
> +		return -EINVAL;
> +	}

What happens if its not? Do we cleanly stay in Dual EMAC mode without
any loss of configuration? Or do bad things happen? Maybe this should
be checked at probe time, so you can deny the swap to switch mode
quickly and easily?

	Andrew

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

* Re: [RFC PATCH v2 3/3] net: ti: icssg-prueth: Add support for ICSSG switch firmware
@ 2024-01-19 14:29     ` Andrew Lunn
  0 siblings, 0 replies; 34+ messages in thread
From: Andrew Lunn @ 2024-01-19 14:29 UTC (permalink / raw)
  To: MD Danish Anwar
  Cc: Rob Herring, Dan Carpenter, Jan Kiszka, Vladimir Oltean,
	Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, Paolo Abeni, Jakub Kicinski,
	Eric Dumazet, David S. Miller, linux-arm-kernel, netdev,
	linux-kernel, srk, r-gunasekaran

On Thu, Jan 18, 2024 at 12:40:05PM +0530, MD Danish Anwar wrote:
> Add support for ICSSG switch firmware using existing Dual EMAC driver
> with switchdev.
> 
> Limitations:
> VLAN offloading is limited to 0-256 IDs.
> MDB/FDB static entries are limited to 511 entries and different FDBs can
> hash to same bucket and thus may not completely offloaded

What are the limits when using Dual EMAC driver? I'm just wondering if
we need to check that 257 VLANs have been offloaded, we cannot swap to
switch mode, keep with Dual EMAC?


> Switch mode requires loading of new firmware into ICSSG cores. This
> means interfaces have to taken down and then reconfigured to switch
> mode.

This is now out of date?

> 
> Example assuming ETH1 and ETH2 as ICSSG2 interfaces:
> 
> Switch to ICSSG Switch mode:
>  ip link set dev eth1 down
>  ip link set dev eth2 down
>  ip link add name br0 type bridge
>  ip link set dev eth1 master br0
>  ip link set dev eth2 master br0
>  ip link set dev br0 up
>  ip link set dev eth1 up
>  ip link set dev eth2 up
>  bridge vlan add dev br0 vid 1 pvid untagged self
> 
> Going back to Dual EMAC mode:
> 
>  ip link set dev br0 down
>  ip link set dev eth1 nomaster
>  ip link set dev eth2 nomaster
>  ip link set dev eth1 down
>  ip link set dev eth2 down
>  ip link del name br0 type bridge
>  ip link set dev eth1 up
>  ip link set dev eth2 up
> 
> By default, Dual EMAC firmware is loaded, and can be changed to switch
> mode by above steps
> 
> Signed-off-by: MD Danish Anwar <danishanwar@ti.com>
> ---
>  drivers/net/ethernet/ti/Kconfig               |   1 +
>  drivers/net/ethernet/ti/Makefile              |   3 +-
>  drivers/net/ethernet/ti/icssg/icssg_config.c  | 136 +++++++++++-
>  drivers/net/ethernet/ti/icssg/icssg_config.h  |   7 +
>  drivers/net/ethernet/ti/icssg/icssg_prueth.c  | 198 +++++++++++++++++-
>  .../net/ethernet/ti/icssg/icssg_switchdev.c   |   2 +-
>  6 files changed, 333 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig
> index be01450c20dc..c72f26828b04 100644
> --- a/drivers/net/ethernet/ti/Kconfig
> +++ b/drivers/net/ethernet/ti/Kconfig
> @@ -188,6 +188,7 @@ config TI_ICSSG_PRUETH
>  	select TI_ICSS_IEP
>  	select TI_K3_CPPI_DESC_POOL
>  	depends on PRU_REMOTEPROC
> +	depends on NET_SWITCHDEV
>  	depends on ARCH_K3 && OF && TI_K3_UDMA_GLUE_LAYER
>  	help
>  	  Support dual Gigabit Ethernet ports over the ICSSG PRU Subsystem.
> diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile
> index d8590304f3df..d295bded7a32 100644
> --- a/drivers/net/ethernet/ti/Makefile
> +++ b/drivers/net/ethernet/ti/Makefile
> @@ -38,5 +38,6 @@ icssg-prueth-y := icssg/icssg_prueth.o \
>  		  icssg/icssg_config.o \
>  		  icssg/icssg_mii_cfg.o \
>  		  icssg/icssg_stats.o \
> -		  icssg/icssg_ethtool.o
> +		  icssg/icssg_ethtool.o \
> +		  icssg/icssg_switchdev.o
>  obj-$(CONFIG_TI_ICSS_IEP) += icssg/icss_iep.o
> diff --git a/drivers/net/ethernet/ti/icssg/icssg_config.c b/drivers/net/ethernet/ti/icssg/icssg_config.c
> index afc10014ec03..eda08a87c902 100644
> --- a/drivers/net/ethernet/ti/icssg/icssg_config.c
> +++ b/drivers/net/ethernet/ti/icssg/icssg_config.c
> @@ -105,28 +105,49 @@ static const struct map hwq_map[2][ICSSG_NUM_OTHER_QUEUES] = {
>  	},
>  };
>  
> +static void icssg_config_mii_init_switch(struct prueth_emac *emac)

I'm surprised you need to configure the MII interface different in
switch mode. Please could you explain this a bit more.

> +{
> +	struct prueth *prueth = emac->prueth;
> +	int mii = prueth_emac_slice(emac);
> +	u32 txcfg_reg, pcnt_reg, txcfg;
> +	struct regmap *mii_rt;
> +
> +	mii_rt = prueth->mii_rt;
> +
> +	txcfg_reg = (mii == ICSS_MII0) ? PRUSS_MII_RT_TXCFG0 :
> +				       PRUSS_MII_RT_TXCFG1;
> +	pcnt_reg = (mii == ICSS_MII0) ? PRUSS_MII_RT_RX_PCNT0 :
> +				       PRUSS_MII_RT_RX_PCNT1;
> +
> +	txcfg = PRUSS_MII_RT_TXCFG_TX_ENABLE |
> +		PRUSS_MII_RT_TXCFG_TX_AUTO_PREAMBLE |
> +		PRUSS_MII_RT_TXCFG_TX_IPG_WIRE_CLK_EN;
> +
> +	if (emac->phy_if == PHY_INTERFACE_MODE_MII && mii == ICSS_MII1)
> +		txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
> +	else if (emac->phy_if != PHY_INTERFACE_MODE_MII && mii == ICSS_MII0)
> +		txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
> +
> +	regmap_write(mii_rt, txcfg_reg, txcfg);
> +	regmap_write(mii_rt, pcnt_reg, 0x1);
> +}
> +
>  static void icssg_config_mii_init(struct prueth_emac *emac)
>  {
> -	u32 rxcfg, txcfg, rxcfg_reg, txcfg_reg, pcnt_reg;
>  	struct prueth *prueth = emac->prueth;
>  	int slice = prueth_emac_slice(emac);
> +	u32 txcfg, txcfg_reg, pcnt_reg;
>  	struct regmap *mii_rt;
>  
>  	mii_rt = prueth->mii_rt;
>  
> -	rxcfg_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_RXCFG0 :
> -				       PRUSS_MII_RT_RXCFG1;
>  	txcfg_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_TXCFG0 :
>  				       PRUSS_MII_RT_TXCFG1;
>  	pcnt_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_RX_PCNT0 :
>  				       PRUSS_MII_RT_RX_PCNT1;
>  
> -	rxcfg = MII_RXCFG_DEFAULT;
>  	txcfg = MII_TXCFG_DEFAULT;
>  
> -	if (slice == ICSS_MII1)
> -		rxcfg |= PRUSS_MII_RT_RXCFG_RX_MUX_SEL;
> -
>  	/* In MII mode TX lines swapped inside ICSSG, so TX_MUX_SEL cfg need
>  	 * to be swapped also comparing to RGMII mode.
>  	 */
> @@ -135,7 +156,6 @@ static void icssg_config_mii_init(struct prueth_emac *emac)
>  	else if (emac->phy_if != PHY_INTERFACE_MODE_MII && slice == ICSS_MII1)
>  		txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
>  
> -	regmap_write(mii_rt, rxcfg_reg, rxcfg);
>  	regmap_write(mii_rt, txcfg_reg, txcfg);
>  	regmap_write(mii_rt, pcnt_reg, 0x1);
>  }
> @@ -249,6 +269,66 @@ static int emac_r30_is_done(struct prueth_emac *emac)
>  	return 1;
>  }
>  
> +static int prueth_switch_buffer_setup(struct prueth_emac *emac)
> +{
> +	struct icssg_buffer_pool_cfg __iomem *bpool_cfg;
> +	struct icssg_rxq_ctx __iomem *rxq_ctx;
> +	struct prueth *prueth = emac->prueth;
> +	int slice = prueth_emac_slice(emac);
> +	u32 addr;
> +	int i;
> +
> +	addr = lower_32_bits(prueth->msmcram.pa);
> +	if (slice)
> +		addr += PRUETH_NUM_BUF_POOLS * PRUETH_EMAC_BUF_POOL_SIZE;
> +
> +	if (addr % SZ_64K) {
> +		dev_warn(prueth->dev, "buffer pool needs to be 64KB aligned\n");
> +		return -EINVAL;
> +	}

What happens if its not? Do we cleanly stay in Dual EMAC mode without
any loss of configuration? Or do bad things happen? Maybe this should
be checked at probe time, so you can deny the swap to switch mode
quickly and easily?

	Andrew

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [RFC PATCH v2 2/3] net: ti: icssg-switch: Add switchdev based driver for ethernet switch support
  2024-01-18  7:10   ` MD Danish Anwar
@ 2024-01-19 20:40     ` Simon Horman
  -1 siblings, 0 replies; 34+ messages in thread
From: Simon Horman @ 2024-01-19 20:40 UTC (permalink / raw)
  To: MD Danish Anwar
  Cc: Rob Herring, Dan Carpenter, Jan Kiszka, Andrew Lunn,
	Vladimir Oltean, Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, Paolo Abeni, Jakub Kicinski,
	Eric Dumazet, David S. Miller, linux-arm-kernel, netdev,
	linux-kernel, srk, r-gunasekaran

On Thu, Jan 18, 2024 at 12:40:04PM +0530, MD Danish Anwar wrote:

...

> @@ -211,6 +216,15 @@ struct prueth_pdata {
>   * @iep0: pointer to IEP0 device
>   * @iep1: pointer to IEP1 device
>   * @vlan_tbl: VLAN-FID table pointer
> + * @hw_bridge_dev: pointer to HW bridge net device
> + * @br_members: bitmask of bridge member ports
> + * @prueth_netdevice_nb: netdevice notifier block
> + * @prueth_switchdevice_nb: switchdev notifier block

nit: s/prueth_switchdevice_nb/prueth_switchdev_nb/

     Flagged by ./scripts/kernel-doc -none

> + * @prueth_switchdev_bl_nb: switchdev blocking notifier block
> + * @is_switch_mode: flag to indicate if device is in Switch mode
> + * @is_switchmode_supported: indicates platform support for switch mode
> + * @switch_id: ID for mapping switch ports to bridge
> + * @default_vlan: Default VLAN for host
>   */
>  struct prueth {
>  	struct device *dev;
> @@ -236,6 +250,16 @@ struct prueth {
>  	struct icss_iep *iep0;
>  	struct icss_iep *iep1;
>  	struct prueth_vlan_tbl *vlan_tbl;
> +
> +	struct net_device *hw_bridge_dev;
> +	u8 br_members;
> +	struct notifier_block prueth_netdevice_nb;
> +	struct notifier_block prueth_switchdev_nb;
> +	struct notifier_block prueth_switchdev_bl_nb;
> +	bool is_switch_mode;
> +	bool is_switchmode_supported;
> +	unsigned char switch_id[MAX_PHYS_ITEM_ID_LEN];
> +	int default_vlan;
>  };
>  
>  struct emac_tx_ts_response {

...

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

* Re: [RFC PATCH v2 2/3] net: ti: icssg-switch: Add switchdev based driver for ethernet switch support
@ 2024-01-19 20:40     ` Simon Horman
  0 siblings, 0 replies; 34+ messages in thread
From: Simon Horman @ 2024-01-19 20:40 UTC (permalink / raw)
  To: MD Danish Anwar
  Cc: Rob Herring, Dan Carpenter, Jan Kiszka, Andrew Lunn,
	Vladimir Oltean, Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, Paolo Abeni, Jakub Kicinski,
	Eric Dumazet, David S. Miller, linux-arm-kernel, netdev,
	linux-kernel, srk, r-gunasekaran

On Thu, Jan 18, 2024 at 12:40:04PM +0530, MD Danish Anwar wrote:

...

> @@ -211,6 +216,15 @@ struct prueth_pdata {
>   * @iep0: pointer to IEP0 device
>   * @iep1: pointer to IEP1 device
>   * @vlan_tbl: VLAN-FID table pointer
> + * @hw_bridge_dev: pointer to HW bridge net device
> + * @br_members: bitmask of bridge member ports
> + * @prueth_netdevice_nb: netdevice notifier block
> + * @prueth_switchdevice_nb: switchdev notifier block

nit: s/prueth_switchdevice_nb/prueth_switchdev_nb/

     Flagged by ./scripts/kernel-doc -none

> + * @prueth_switchdev_bl_nb: switchdev blocking notifier block
> + * @is_switch_mode: flag to indicate if device is in Switch mode
> + * @is_switchmode_supported: indicates platform support for switch mode
> + * @switch_id: ID for mapping switch ports to bridge
> + * @default_vlan: Default VLAN for host
>   */
>  struct prueth {
>  	struct device *dev;
> @@ -236,6 +250,16 @@ struct prueth {
>  	struct icss_iep *iep0;
>  	struct icss_iep *iep1;
>  	struct prueth_vlan_tbl *vlan_tbl;
> +
> +	struct net_device *hw_bridge_dev;
> +	u8 br_members;
> +	struct notifier_block prueth_netdevice_nb;
> +	struct notifier_block prueth_switchdev_nb;
> +	struct notifier_block prueth_switchdev_bl_nb;
> +	bool is_switch_mode;
> +	bool is_switchmode_supported;
> +	unsigned char switch_id[MAX_PHYS_ITEM_ID_LEN];
> +	int default_vlan;
>  };
>  
>  struct emac_tx_ts_response {

...

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [RFC PATCH v2 3/3] net: ti: icssg-prueth: Add support for ICSSG switch firmware
  2024-01-18  7:10   ` MD Danish Anwar
@ 2024-01-19 20:41     ` Simon Horman
  -1 siblings, 0 replies; 34+ messages in thread
From: Simon Horman @ 2024-01-19 20:41 UTC (permalink / raw)
  To: MD Danish Anwar
  Cc: Rob Herring, Dan Carpenter, Jan Kiszka, Andrew Lunn,
	Vladimir Oltean, Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, Paolo Abeni, Jakub Kicinski,
	Eric Dumazet, David S. Miller, linux-arm-kernel, netdev,
	linux-kernel, srk, r-gunasekaran

On Thu, Jan 18, 2024 at 12:40:05PM +0530, MD Danish Anwar wrote:

...

> diff --git a/drivers/net/ethernet/ti/icssg/icssg_switchdev.c b/drivers/net/ethernet/ti/icssg/icssg_switchdev.c
> index 48d8ed4fa7a8..90d0d98e0ef9 100644
> --- a/drivers/net/ethernet/ti/icssg/icssg_switchdev.c
> +++ b/drivers/net/ethernet/ti/icssg/icssg_switchdev.c
> @@ -14,7 +14,7 @@
>  
>  #include "icssg_prueth.h"
>  #include "icssg_switchdev.h"
> -#include "icss_mii_rt.h"
> +#include "icssg_mii_rt.h"
>  
>  struct prueth_switchdev_event_work {
>  	struct work_struct work;

Hi,

I think this hunk should be squashed into the previous patch.

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

* Re: [RFC PATCH v2 3/3] net: ti: icssg-prueth: Add support for ICSSG switch firmware
@ 2024-01-19 20:41     ` Simon Horman
  0 siblings, 0 replies; 34+ messages in thread
From: Simon Horman @ 2024-01-19 20:41 UTC (permalink / raw)
  To: MD Danish Anwar
  Cc: Rob Herring, Dan Carpenter, Jan Kiszka, Andrew Lunn,
	Vladimir Oltean, Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, Paolo Abeni, Jakub Kicinski,
	Eric Dumazet, David S. Miller, linux-arm-kernel, netdev,
	linux-kernel, srk, r-gunasekaran

On Thu, Jan 18, 2024 at 12:40:05PM +0530, MD Danish Anwar wrote:

...

> diff --git a/drivers/net/ethernet/ti/icssg/icssg_switchdev.c b/drivers/net/ethernet/ti/icssg/icssg_switchdev.c
> index 48d8ed4fa7a8..90d0d98e0ef9 100644
> --- a/drivers/net/ethernet/ti/icssg/icssg_switchdev.c
> +++ b/drivers/net/ethernet/ti/icssg/icssg_switchdev.c
> @@ -14,7 +14,7 @@
>  
>  #include "icssg_prueth.h"
>  #include "icssg_switchdev.h"
> -#include "icss_mii_rt.h"
> +#include "icssg_mii_rt.h"
>  
>  struct prueth_switchdev_event_work {
>  	struct work_struct work;

Hi,

I think this hunk should be squashed into the previous patch.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [RFC PATCH v2 3/3] net: ti: icssg-prueth: Add support for ICSSG switch firmware
  2024-01-19 20:41     ` Simon Horman
@ 2024-01-22  7:52       ` MD Danish Anwar
  -1 siblings, 0 replies; 34+ messages in thread
From: MD Danish Anwar @ 2024-01-22  7:52 UTC (permalink / raw)
  To: Simon Horman
  Cc: Rob Herring, Dan Carpenter, Jan Kiszka, Andrew Lunn,
	Vladimir Oltean, Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, Paolo Abeni, Jakub Kicinski,
	Eric Dumazet, David S. Miller, linux-arm-kernel, netdev,
	linux-kernel, srk, r-gunasekaran



On 20/01/24 2:11 am, Simon Horman wrote:
> On Thu, Jan 18, 2024 at 12:40:05PM +0530, MD Danish Anwar wrote:
> 
> ...
> 
>> diff --git a/drivers/net/ethernet/ti/icssg/icssg_switchdev.c b/drivers/net/ethernet/ti/icssg/icssg_switchdev.c
>> index 48d8ed4fa7a8..90d0d98e0ef9 100644
>> --- a/drivers/net/ethernet/ti/icssg/icssg_switchdev.c
>> +++ b/drivers/net/ethernet/ti/icssg/icssg_switchdev.c
>> @@ -14,7 +14,7 @@
>>  
>>  #include "icssg_prueth.h"
>>  #include "icssg_switchdev.h"
>> -#include "icss_mii_rt.h"
>> +#include "icssg_mii_rt.h"
>>  
>>  struct prueth_switchdev_event_work {
>>  	struct work_struct work;
> 
> Hi,
> 
> I think this hunk should be squashed into the previous patch.

Sure Simon, I'll move this to previous patch.

-- 
Thanks and Regards,
Danish

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

* Re: [RFC PATCH v2 3/3] net: ti: icssg-prueth: Add support for ICSSG switch firmware
@ 2024-01-22  7:52       ` MD Danish Anwar
  0 siblings, 0 replies; 34+ messages in thread
From: MD Danish Anwar @ 2024-01-22  7:52 UTC (permalink / raw)
  To: Simon Horman
  Cc: Rob Herring, Dan Carpenter, Jan Kiszka, Andrew Lunn,
	Vladimir Oltean, Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, Paolo Abeni, Jakub Kicinski,
	Eric Dumazet, David S. Miller, linux-arm-kernel, netdev,
	linux-kernel, srk, r-gunasekaran



On 20/01/24 2:11 am, Simon Horman wrote:
> On Thu, Jan 18, 2024 at 12:40:05PM +0530, MD Danish Anwar wrote:
> 
> ...
> 
>> diff --git a/drivers/net/ethernet/ti/icssg/icssg_switchdev.c b/drivers/net/ethernet/ti/icssg/icssg_switchdev.c
>> index 48d8ed4fa7a8..90d0d98e0ef9 100644
>> --- a/drivers/net/ethernet/ti/icssg/icssg_switchdev.c
>> +++ b/drivers/net/ethernet/ti/icssg/icssg_switchdev.c
>> @@ -14,7 +14,7 @@
>>  
>>  #include "icssg_prueth.h"
>>  #include "icssg_switchdev.h"
>> -#include "icss_mii_rt.h"
>> +#include "icssg_mii_rt.h"
>>  
>>  struct prueth_switchdev_event_work {
>>  	struct work_struct work;
> 
> Hi,
> 
> I think this hunk should be squashed into the previous patch.

Sure Simon, I'll move this to previous patch.

-- 
Thanks and Regards,
Danish

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [RFC PATCH v2 2/3] net: ti: icssg-switch: Add switchdev based driver for ethernet switch support
  2024-01-19 20:40     ` Simon Horman
@ 2024-01-22  7:54       ` MD Danish Anwar
  -1 siblings, 0 replies; 34+ messages in thread
From: MD Danish Anwar @ 2024-01-22  7:54 UTC (permalink / raw)
  To: Simon Horman
  Cc: Rob Herring, Dan Carpenter, Jan Kiszka, Andrew Lunn,
	Vladimir Oltean, Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, Paolo Abeni, Jakub Kicinski,
	Eric Dumazet, David S. Miller, linux-arm-kernel, netdev,
	linux-kernel, srk, r-gunasekaran



On 20/01/24 2:10 am, Simon Horman wrote:
> On Thu, Jan 18, 2024 at 12:40:04PM +0530, MD Danish Anwar wrote:
> 
> ...
> 
>> @@ -211,6 +216,15 @@ struct prueth_pdata {
>>   * @iep0: pointer to IEP0 device
>>   * @iep1: pointer to IEP1 device
>>   * @vlan_tbl: VLAN-FID table pointer
>> + * @hw_bridge_dev: pointer to HW bridge net device
>> + * @br_members: bitmask of bridge member ports
>> + * @prueth_netdevice_nb: netdevice notifier block
>> + * @prueth_switchdevice_nb: switchdev notifier block
> 
> nit: s/prueth_switchdevice_nb/prueth_switchdev_nb/
> 
>      Flagged by ./scripts/kernel-doc -none>

Sure Simon. I will fix this.

>> + * @prueth_switchdev_bl_nb: switchdev blocking notifier block
>> + * @is_switch_mode: flag to indicate if device is in Switch mode
>> + * @is_switchmode_supported: indicates platform support for switch mode
>> + * @switch_id: ID for mapping switch ports to bridge
>> + * @default_vlan: Default VLAN for host
>>   */
>>  struct prueth {
>>  	struct device *dev;
>> @@ -236,6 +250,16 @@ struct prueth {
>>  	struct icss_iep *iep0;
>>  	struct icss_iep *iep1;
>>  	struct prueth_vlan_tbl *vlan_tbl;
>> +
>> +	struct net_device *hw_bridge_dev;
>> +	u8 br_members;
>> +	struct notifier_block prueth_netdevice_nb;
>> +	struct notifier_block prueth_switchdev_nb;
>> +	struct notifier_block prueth_switchdev_bl_nb;
>> +	bool is_switch_mode;
>> +	bool is_switchmode_supported;
>> +	unsigned char switch_id[MAX_PHYS_ITEM_ID_LEN];
>> +	int default_vlan;
>>  };
>>  
>>  struct emac_tx_ts_response {
> 
> ...

-- 
Thanks and Regards,
Danish

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

* Re: [RFC PATCH v2 2/3] net: ti: icssg-switch: Add switchdev based driver for ethernet switch support
@ 2024-01-22  7:54       ` MD Danish Anwar
  0 siblings, 0 replies; 34+ messages in thread
From: MD Danish Anwar @ 2024-01-22  7:54 UTC (permalink / raw)
  To: Simon Horman
  Cc: Rob Herring, Dan Carpenter, Jan Kiszka, Andrew Lunn,
	Vladimir Oltean, Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, Paolo Abeni, Jakub Kicinski,
	Eric Dumazet, David S. Miller, linux-arm-kernel, netdev,
	linux-kernel, srk, r-gunasekaran



On 20/01/24 2:10 am, Simon Horman wrote:
> On Thu, Jan 18, 2024 at 12:40:04PM +0530, MD Danish Anwar wrote:
> 
> ...
> 
>> @@ -211,6 +216,15 @@ struct prueth_pdata {
>>   * @iep0: pointer to IEP0 device
>>   * @iep1: pointer to IEP1 device
>>   * @vlan_tbl: VLAN-FID table pointer
>> + * @hw_bridge_dev: pointer to HW bridge net device
>> + * @br_members: bitmask of bridge member ports
>> + * @prueth_netdevice_nb: netdevice notifier block
>> + * @prueth_switchdevice_nb: switchdev notifier block
> 
> nit: s/prueth_switchdevice_nb/prueth_switchdev_nb/
> 
>      Flagged by ./scripts/kernel-doc -none>

Sure Simon. I will fix this.

>> + * @prueth_switchdev_bl_nb: switchdev blocking notifier block
>> + * @is_switch_mode: flag to indicate if device is in Switch mode
>> + * @is_switchmode_supported: indicates platform support for switch mode
>> + * @switch_id: ID for mapping switch ports to bridge
>> + * @default_vlan: Default VLAN for host
>>   */
>>  struct prueth {
>>  	struct device *dev;
>> @@ -236,6 +250,16 @@ struct prueth {
>>  	struct icss_iep *iep0;
>>  	struct icss_iep *iep1;
>>  	struct prueth_vlan_tbl *vlan_tbl;
>> +
>> +	struct net_device *hw_bridge_dev;
>> +	u8 br_members;
>> +	struct notifier_block prueth_netdevice_nb;
>> +	struct notifier_block prueth_switchdev_nb;
>> +	struct notifier_block prueth_switchdev_bl_nb;
>> +	bool is_switch_mode;
>> +	bool is_switchmode_supported;
>> +	unsigned char switch_id[MAX_PHYS_ITEM_ID_LEN];
>> +	int default_vlan;
>>  };
>>  
>>  struct emac_tx_ts_response {
> 
> ...

-- 
Thanks and Regards,
Danish

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [RFC PATCH v2 3/3] net: ti: icssg-prueth: Add support for ICSSG switch firmware
  2024-01-19 14:29     ` Andrew Lunn
@ 2024-01-22 10:35       ` MD Danish Anwar
  -1 siblings, 0 replies; 34+ messages in thread
From: MD Danish Anwar @ 2024-01-22 10:35 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Rob Herring, Dan Carpenter, Jan Kiszka, Vladimir Oltean,
	Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, Paolo Abeni, Jakub Kicinski,
	Eric Dumazet, David S. Miller, linux-arm-kernel, netdev,
	linux-kernel, srk, r-gunasekaran

Hi Andrew,

On 19/01/24 7:59 pm, Andrew Lunn wrote:
> On Thu, Jan 18, 2024 at 12:40:05PM +0530, MD Danish Anwar wrote:
>> Add support for ICSSG switch firmware using existing Dual EMAC driver
>> with switchdev.
>>
>> Limitations:
>> VLAN offloading is limited to 0-256 IDs.
>> MDB/FDB static entries are limited to 511 entries and different FDBs can
>> hash to same bucket and thus may not completely offloaded
> 
> What are the limits when using Dual EMAC driver? I'm just wondering if
> we need to check that 257 VLANs have been offloaded, we cannot swap to
> switch mode, keep with Dual EMAC?
> 

Both Switch and dual EMAC has the same limit. Maximum 256 VIDs can ebe
offloaded in both dual EMAC and switch mode. When VID is greater than
256, we don't add the vid and return 0. You can see
prueth_switchdev_vlans_add() for details on how vlans are added.

>> Switch mode requires loading of new firmware into ICSSG cores. This
>> means interfaces have to taken down and then reconfigured to switch
>> mode.
> 
> This is now out of date?
> 
>>
>> Example assuming ETH1 and ETH2 as ICSSG2 interfaces:
>>
>> Switch to ICSSG Switch mode:
>>  ip link set dev eth1 down
>>  ip link set dev eth2 down
>>  ip link add name br0 type bridge
>>  ip link set dev eth1 master br0
>>  ip link set dev eth2 master br0
>>  ip link set dev br0 up
>>  ip link set dev eth1 up
>>  ip link set dev eth2 up
>>  bridge vlan add dev br0 vid 1 pvid untagged self
>>
>> Going back to Dual EMAC mode:
>>
>>  ip link set dev br0 down
>>  ip link set dev eth1 nomaster
>>  ip link set dev eth2 nomaster
>>  ip link set dev eth1 down
>>  ip link set dev eth2 down
>>  ip link del name br0 type bridge
>>  ip link set dev eth1 up
>>  ip link set dev eth2 up
>>
>> By default, Dual EMAC firmware is loaded, and can be changed to switch
>> mode by above steps
>>
>> Signed-off-by: MD Danish Anwar <danishanwar@ti.com>
>> ---
>>  drivers/net/ethernet/ti/Kconfig               |   1 +
>>  drivers/net/ethernet/ti/Makefile              |   3 +-
>>  drivers/net/ethernet/ti/icssg/icssg_config.c  | 136 +++++++++++-
>>  drivers/net/ethernet/ti/icssg/icssg_config.h  |   7 +
>>  drivers/net/ethernet/ti/icssg/icssg_prueth.c  | 198 +++++++++++++++++-
>>  .../net/ethernet/ti/icssg/icssg_switchdev.c   |   2 +-
>>  6 files changed, 333 insertions(+), 14 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig
>> index be01450c20dc..c72f26828b04 100644
>> --- a/drivers/net/ethernet/ti/Kconfig
>> +++ b/drivers/net/ethernet/ti/Kconfig
>> @@ -188,6 +188,7 @@ config TI_ICSSG_PRUETH
>>  	select TI_ICSS_IEP
>>  	select TI_K3_CPPI_DESC_POOL
>>  	depends on PRU_REMOTEPROC
>> +	depends on NET_SWITCHDEV
>>  	depends on ARCH_K3 && OF && TI_K3_UDMA_GLUE_LAYER
>>  	help
>>  	  Support dual Gigabit Ethernet ports over the ICSSG PRU Subsystem.
>> diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile
>> index d8590304f3df..d295bded7a32 100644
>> --- a/drivers/net/ethernet/ti/Makefile
>> +++ b/drivers/net/ethernet/ti/Makefile
>> @@ -38,5 +38,6 @@ icssg-prueth-y := icssg/icssg_prueth.o \
>>  		  icssg/icssg_config.o \
>>  		  icssg/icssg_mii_cfg.o \
>>  		  icssg/icssg_stats.o \
>> -		  icssg/icssg_ethtool.o
>> +		  icssg/icssg_ethtool.o \
>> +		  icssg/icssg_switchdev.o
>>  obj-$(CONFIG_TI_ICSS_IEP) += icssg/icss_iep.o
>> diff --git a/drivers/net/ethernet/ti/icssg/icssg_config.c b/drivers/net/ethernet/ti/icssg/icssg_config.c
>> index afc10014ec03..eda08a87c902 100644
>> --- a/drivers/net/ethernet/ti/icssg/icssg_config.c
>> +++ b/drivers/net/ethernet/ti/icssg/icssg_config.c
>> @@ -105,28 +105,49 @@ static const struct map hwq_map[2][ICSSG_NUM_OTHER_QUEUES] = {
>>  	},
>>  };
>>  
>> +static void icssg_config_mii_init_switch(struct prueth_emac *emac)
> 
> I'm surprised you need to configure the MII interface different in
> switch mode. Please could you explain this a bit more.>

Sure, I'll explain.

TX_MUX_SEL0 (BIT(8)) of TXCFG register indicated weather the port is
connected to txpru0 or txpru1

0h = TX data from PRU0 is selected
1h = TX data from PRU1 is selected

Refer to section 6.5.14.11.3 of TRM [1].

In dual EMAC mode, for port0 the connected PRU cores are pru0, rtu0 and
txpru0 similarly for port1 the connected PRU cores are pru1, rtu1 and
txpru1. Port0 and port1 can not communicate among each other as they
don't share any PRU cores. So BIT(8) for port0 is 0h (meaning TX data
from PRU0 is selected) and BIT(8) for port1 is 1h (meaning TX data from
PRU1 is selected)

In switch mode, for port0 the connected PRU cores are pru0, rtu0 and
*txpru1* similarly for port1 the connected PRU cores are pru1, rtu1 and
*txpru0*.

In switch mode, port0 is connected to txpru1 and port1 is connected to
txpru0. This enables the firmware to do the forwarding between the
ports. Now to enable this configuration BIT(8) needs to be set
differently in switch mode. BIT(8) for port0 is 1h (meaning TX data from
PRU1 is selected) and BIT(8) for port1 is 0h (meaning TX data from PRU0
is selected). This enables the forwarding between ports.

So MII interface needs to be configured differently for MAC and switch
mode. The only difference being the BIT(8)


>> +{
>> +	struct prueth *prueth = emac->prueth;
>> +	int mii = prueth_emac_slice(emac);
>> +	u32 txcfg_reg, pcnt_reg, txcfg;
>> +	struct regmap *mii_rt;
>> +
>> +	mii_rt = prueth->mii_rt;
>> +
>> +	txcfg_reg = (mii == ICSS_MII0) ? PRUSS_MII_RT_TXCFG0 :
>> +				       PRUSS_MII_RT_TXCFG1;
>> +	pcnt_reg = (mii == ICSS_MII0) ? PRUSS_MII_RT_RX_PCNT0 :
>> +				       PRUSS_MII_RT_RX_PCNT1;
>> +
>> +	txcfg = PRUSS_MII_RT_TXCFG_TX_ENABLE |
>> +		PRUSS_MII_RT_TXCFG_TX_AUTO_PREAMBLE |
>> +		PRUSS_MII_RT_TXCFG_TX_IPG_WIRE_CLK_EN;
>> +
>> +	if (emac->phy_if == PHY_INTERFACE_MODE_MII && mii == ICSS_MII1)
>> +		txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
>> +	else if (emac->phy_if != PHY_INTERFACE_MODE_MII && mii == ICSS_MII0)
>> +		txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
>> +
>> +	regmap_write(mii_rt, txcfg_reg, txcfg);
>> +	regmap_write(mii_rt, pcnt_reg, 0x1);
>> +}
>> +
>>  static void icssg_config_mii_init(struct prueth_emac *emac)
>>  {
>> -	u32 rxcfg, txcfg, rxcfg_reg, txcfg_reg, pcnt_reg;
>>  	struct prueth *prueth = emac->prueth;
>>  	int slice = prueth_emac_slice(emac);
>> +	u32 txcfg, txcfg_reg, pcnt_reg;
>>  	struct regmap *mii_rt;
>>  
>>  	mii_rt = prueth->mii_rt;
>>  
>> -	rxcfg_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_RXCFG0 :
>> -				       PRUSS_MII_RT_RXCFG1;
>>  	txcfg_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_TXCFG0 :
>>  				       PRUSS_MII_RT_TXCFG1;
>>  	pcnt_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_RX_PCNT0 :
>>  				       PRUSS_MII_RT_RX_PCNT1;
>>  
>> -	rxcfg = MII_RXCFG_DEFAULT;
>>  	txcfg = MII_TXCFG_DEFAULT;
>>  
>> -	if (slice == ICSS_MII1)
>> -		rxcfg |= PRUSS_MII_RT_RXCFG_RX_MUX_SEL;
>> -
>>  	/* In MII mode TX lines swapped inside ICSSG, so TX_MUX_SEL cfg need
>>  	 * to be swapped also comparing to RGMII mode.
>>  	 */
>> @@ -135,7 +156,6 @@ static void icssg_config_mii_init(struct prueth_emac *emac)
>>  	else if (emac->phy_if != PHY_INTERFACE_MODE_MII && slice == ICSS_MII1)
>>  		txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
>>  
>> -	regmap_write(mii_rt, rxcfg_reg, rxcfg);
>>  	regmap_write(mii_rt, txcfg_reg, txcfg);
>>  	regmap_write(mii_rt, pcnt_reg, 0x1);
>>  }
>> @@ -249,6 +269,66 @@ static int emac_r30_is_done(struct prueth_emac *emac)
>>  	return 1;
>>  }
>>  
>> +static int prueth_switch_buffer_setup(struct prueth_emac *emac)
>> +{
>> +	struct icssg_buffer_pool_cfg __iomem *bpool_cfg;
>> +	struct icssg_rxq_ctx __iomem *rxq_ctx;
>> +	struct prueth *prueth = emac->prueth;
>> +	int slice = prueth_emac_slice(emac);
>> +	u32 addr;
>> +	int i;
>> +
>> +	addr = lower_32_bits(prueth->msmcram.pa);
>> +	if (slice)
>> +		addr += PRUETH_NUM_BUF_POOLS * PRUETH_EMAC_BUF_POOL_SIZE;
>> +
>> +	if (addr % SZ_64K) {
>> +		dev_warn(prueth->dev, "buffer pool needs to be 64KB aligned\n");
>> +		return -EINVAL;
>> +	}
> 
> What happens if its not? Do we cleanly stay in Dual EMAC mode without
> any loss of configuration? Or do bad things happen? Maybe this should
> be checked at probe time, so you can deny the swap to switch mode
> quickly and easily?
> 

This is independent of MAC or switch. The MSMC address always needs to
be 64KB aligned. This is a bug in Firmware. If it's not 64KB aligned bad
things might happen, that's why we just stop and return -EINVAL. The
interface will simply not work. The same check is also done in
prueth_emac_buffer_setup().

During probe we make sure that the MSMC is aligned with 64KB. You can
have a look at prueth_probe() [2]. After probe during open() we check
again to see if MSMC is 64KB aligned and then only do the needed
configuration. I can move this check from individual switch / mac APIs
to the beginning of ndo_open() if you want that.

> 	Andrew


[1]
https://www.ti.com/lit/ug/spruid7e/spruid7e.pdf?ts=1705918869984&ref_url=https%253A%252F%252Fwww.ti.com%252Fproduct%252FAM6548

[2]
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/net/ethernet/ti/icssg/icssg_prueth.c?h=v6.8-rc1#n2079

-- 
Thanks and Regards,
Danish

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [RFC PATCH v2 3/3] net: ti: icssg-prueth: Add support for ICSSG switch firmware
@ 2024-01-22 10:35       ` MD Danish Anwar
  0 siblings, 0 replies; 34+ messages in thread
From: MD Danish Anwar @ 2024-01-22 10:35 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Rob Herring, Dan Carpenter, Jan Kiszka, Vladimir Oltean,
	Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, Paolo Abeni, Jakub Kicinski,
	Eric Dumazet, David S. Miller, linux-arm-kernel, netdev,
	linux-kernel, srk, r-gunasekaran

Hi Andrew,

On 19/01/24 7:59 pm, Andrew Lunn wrote:
> On Thu, Jan 18, 2024 at 12:40:05PM +0530, MD Danish Anwar wrote:
>> Add support for ICSSG switch firmware using existing Dual EMAC driver
>> with switchdev.
>>
>> Limitations:
>> VLAN offloading is limited to 0-256 IDs.
>> MDB/FDB static entries are limited to 511 entries and different FDBs can
>> hash to same bucket and thus may not completely offloaded
> 
> What are the limits when using Dual EMAC driver? I'm just wondering if
> we need to check that 257 VLANs have been offloaded, we cannot swap to
> switch mode, keep with Dual EMAC?
> 

Both Switch and dual EMAC has the same limit. Maximum 256 VIDs can ebe
offloaded in both dual EMAC and switch mode. When VID is greater than
256, we don't add the vid and return 0. You can see
prueth_switchdev_vlans_add() for details on how vlans are added.

>> Switch mode requires loading of new firmware into ICSSG cores. This
>> means interfaces have to taken down and then reconfigured to switch
>> mode.
> 
> This is now out of date?
> 
>>
>> Example assuming ETH1 and ETH2 as ICSSG2 interfaces:
>>
>> Switch to ICSSG Switch mode:
>>  ip link set dev eth1 down
>>  ip link set dev eth2 down
>>  ip link add name br0 type bridge
>>  ip link set dev eth1 master br0
>>  ip link set dev eth2 master br0
>>  ip link set dev br0 up
>>  ip link set dev eth1 up
>>  ip link set dev eth2 up
>>  bridge vlan add dev br0 vid 1 pvid untagged self
>>
>> Going back to Dual EMAC mode:
>>
>>  ip link set dev br0 down
>>  ip link set dev eth1 nomaster
>>  ip link set dev eth2 nomaster
>>  ip link set dev eth1 down
>>  ip link set dev eth2 down
>>  ip link del name br0 type bridge
>>  ip link set dev eth1 up
>>  ip link set dev eth2 up
>>
>> By default, Dual EMAC firmware is loaded, and can be changed to switch
>> mode by above steps
>>
>> Signed-off-by: MD Danish Anwar <danishanwar@ti.com>
>> ---
>>  drivers/net/ethernet/ti/Kconfig               |   1 +
>>  drivers/net/ethernet/ti/Makefile              |   3 +-
>>  drivers/net/ethernet/ti/icssg/icssg_config.c  | 136 +++++++++++-
>>  drivers/net/ethernet/ti/icssg/icssg_config.h  |   7 +
>>  drivers/net/ethernet/ti/icssg/icssg_prueth.c  | 198 +++++++++++++++++-
>>  .../net/ethernet/ti/icssg/icssg_switchdev.c   |   2 +-
>>  6 files changed, 333 insertions(+), 14 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig
>> index be01450c20dc..c72f26828b04 100644
>> --- a/drivers/net/ethernet/ti/Kconfig
>> +++ b/drivers/net/ethernet/ti/Kconfig
>> @@ -188,6 +188,7 @@ config TI_ICSSG_PRUETH
>>  	select TI_ICSS_IEP
>>  	select TI_K3_CPPI_DESC_POOL
>>  	depends on PRU_REMOTEPROC
>> +	depends on NET_SWITCHDEV
>>  	depends on ARCH_K3 && OF && TI_K3_UDMA_GLUE_LAYER
>>  	help
>>  	  Support dual Gigabit Ethernet ports over the ICSSG PRU Subsystem.
>> diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile
>> index d8590304f3df..d295bded7a32 100644
>> --- a/drivers/net/ethernet/ti/Makefile
>> +++ b/drivers/net/ethernet/ti/Makefile
>> @@ -38,5 +38,6 @@ icssg-prueth-y := icssg/icssg_prueth.o \
>>  		  icssg/icssg_config.o \
>>  		  icssg/icssg_mii_cfg.o \
>>  		  icssg/icssg_stats.o \
>> -		  icssg/icssg_ethtool.o
>> +		  icssg/icssg_ethtool.o \
>> +		  icssg/icssg_switchdev.o
>>  obj-$(CONFIG_TI_ICSS_IEP) += icssg/icss_iep.o
>> diff --git a/drivers/net/ethernet/ti/icssg/icssg_config.c b/drivers/net/ethernet/ti/icssg/icssg_config.c
>> index afc10014ec03..eda08a87c902 100644
>> --- a/drivers/net/ethernet/ti/icssg/icssg_config.c
>> +++ b/drivers/net/ethernet/ti/icssg/icssg_config.c
>> @@ -105,28 +105,49 @@ static const struct map hwq_map[2][ICSSG_NUM_OTHER_QUEUES] = {
>>  	},
>>  };
>>  
>> +static void icssg_config_mii_init_switch(struct prueth_emac *emac)
> 
> I'm surprised you need to configure the MII interface different in
> switch mode. Please could you explain this a bit more.>

Sure, I'll explain.

TX_MUX_SEL0 (BIT(8)) of TXCFG register indicated weather the port is
connected to txpru0 or txpru1

0h = TX data from PRU0 is selected
1h = TX data from PRU1 is selected

Refer to section 6.5.14.11.3 of TRM [1].

In dual EMAC mode, for port0 the connected PRU cores are pru0, rtu0 and
txpru0 similarly for port1 the connected PRU cores are pru1, rtu1 and
txpru1. Port0 and port1 can not communicate among each other as they
don't share any PRU cores. So BIT(8) for port0 is 0h (meaning TX data
from PRU0 is selected) and BIT(8) for port1 is 1h (meaning TX data from
PRU1 is selected)

In switch mode, for port0 the connected PRU cores are pru0, rtu0 and
*txpru1* similarly for port1 the connected PRU cores are pru1, rtu1 and
*txpru0*.

In switch mode, port0 is connected to txpru1 and port1 is connected to
txpru0. This enables the firmware to do the forwarding between the
ports. Now to enable this configuration BIT(8) needs to be set
differently in switch mode. BIT(8) for port0 is 1h (meaning TX data from
PRU1 is selected) and BIT(8) for port1 is 0h (meaning TX data from PRU0
is selected). This enables the forwarding between ports.

So MII interface needs to be configured differently for MAC and switch
mode. The only difference being the BIT(8)


>> +{
>> +	struct prueth *prueth = emac->prueth;
>> +	int mii = prueth_emac_slice(emac);
>> +	u32 txcfg_reg, pcnt_reg, txcfg;
>> +	struct regmap *mii_rt;
>> +
>> +	mii_rt = prueth->mii_rt;
>> +
>> +	txcfg_reg = (mii == ICSS_MII0) ? PRUSS_MII_RT_TXCFG0 :
>> +				       PRUSS_MII_RT_TXCFG1;
>> +	pcnt_reg = (mii == ICSS_MII0) ? PRUSS_MII_RT_RX_PCNT0 :
>> +				       PRUSS_MII_RT_RX_PCNT1;
>> +
>> +	txcfg = PRUSS_MII_RT_TXCFG_TX_ENABLE |
>> +		PRUSS_MII_RT_TXCFG_TX_AUTO_PREAMBLE |
>> +		PRUSS_MII_RT_TXCFG_TX_IPG_WIRE_CLK_EN;
>> +
>> +	if (emac->phy_if == PHY_INTERFACE_MODE_MII && mii == ICSS_MII1)
>> +		txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
>> +	else if (emac->phy_if != PHY_INTERFACE_MODE_MII && mii == ICSS_MII0)
>> +		txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
>> +
>> +	regmap_write(mii_rt, txcfg_reg, txcfg);
>> +	regmap_write(mii_rt, pcnt_reg, 0x1);
>> +}
>> +
>>  static void icssg_config_mii_init(struct prueth_emac *emac)
>>  {
>> -	u32 rxcfg, txcfg, rxcfg_reg, txcfg_reg, pcnt_reg;
>>  	struct prueth *prueth = emac->prueth;
>>  	int slice = prueth_emac_slice(emac);
>> +	u32 txcfg, txcfg_reg, pcnt_reg;
>>  	struct regmap *mii_rt;
>>  
>>  	mii_rt = prueth->mii_rt;
>>  
>> -	rxcfg_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_RXCFG0 :
>> -				       PRUSS_MII_RT_RXCFG1;
>>  	txcfg_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_TXCFG0 :
>>  				       PRUSS_MII_RT_TXCFG1;
>>  	pcnt_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_RX_PCNT0 :
>>  				       PRUSS_MII_RT_RX_PCNT1;
>>  
>> -	rxcfg = MII_RXCFG_DEFAULT;
>>  	txcfg = MII_TXCFG_DEFAULT;
>>  
>> -	if (slice == ICSS_MII1)
>> -		rxcfg |= PRUSS_MII_RT_RXCFG_RX_MUX_SEL;
>> -
>>  	/* In MII mode TX lines swapped inside ICSSG, so TX_MUX_SEL cfg need
>>  	 * to be swapped also comparing to RGMII mode.
>>  	 */
>> @@ -135,7 +156,6 @@ static void icssg_config_mii_init(struct prueth_emac *emac)
>>  	else if (emac->phy_if != PHY_INTERFACE_MODE_MII && slice == ICSS_MII1)
>>  		txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
>>  
>> -	regmap_write(mii_rt, rxcfg_reg, rxcfg);
>>  	regmap_write(mii_rt, txcfg_reg, txcfg);
>>  	regmap_write(mii_rt, pcnt_reg, 0x1);
>>  }
>> @@ -249,6 +269,66 @@ static int emac_r30_is_done(struct prueth_emac *emac)
>>  	return 1;
>>  }
>>  
>> +static int prueth_switch_buffer_setup(struct prueth_emac *emac)
>> +{
>> +	struct icssg_buffer_pool_cfg __iomem *bpool_cfg;
>> +	struct icssg_rxq_ctx __iomem *rxq_ctx;
>> +	struct prueth *prueth = emac->prueth;
>> +	int slice = prueth_emac_slice(emac);
>> +	u32 addr;
>> +	int i;
>> +
>> +	addr = lower_32_bits(prueth->msmcram.pa);
>> +	if (slice)
>> +		addr += PRUETH_NUM_BUF_POOLS * PRUETH_EMAC_BUF_POOL_SIZE;
>> +
>> +	if (addr % SZ_64K) {
>> +		dev_warn(prueth->dev, "buffer pool needs to be 64KB aligned\n");
>> +		return -EINVAL;
>> +	}
> 
> What happens if its not? Do we cleanly stay in Dual EMAC mode without
> any loss of configuration? Or do bad things happen? Maybe this should
> be checked at probe time, so you can deny the swap to switch mode
> quickly and easily?
> 

This is independent of MAC or switch. The MSMC address always needs to
be 64KB aligned. This is a bug in Firmware. If it's not 64KB aligned bad
things might happen, that's why we just stop and return -EINVAL. The
interface will simply not work. The same check is also done in
prueth_emac_buffer_setup().

During probe we make sure that the MSMC is aligned with 64KB. You can
have a look at prueth_probe() [2]. After probe during open() we check
again to see if MSMC is 64KB aligned and then only do the needed
configuration. I can move this check from individual switch / mac APIs
to the beginning of ndo_open() if you want that.

> 	Andrew


[1]
https://www.ti.com/lit/ug/spruid7e/spruid7e.pdf?ts=1705918869984&ref_url=https%253A%252F%252Fwww.ti.com%252Fproduct%252FAM6548

[2]
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/net/ethernet/ti/icssg/icssg_prueth.c?h=v6.8-rc1#n2079

-- 
Thanks and Regards,
Danish

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

* Re: [RFC PATCH v2 0/3] Introduce switch mode support for ICSSG driver
  2024-01-18 14:01   ` Andrew Lunn
@ 2024-01-22 10:45     ` MD Danish Anwar
  -1 siblings, 0 replies; 34+ messages in thread
From: MD Danish Anwar @ 2024-01-22 10:45 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Rob Herring, Dan Carpenter, Jan Kiszka, Vladimir Oltean,
	Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, Paolo Abeni, Jakub Kicinski,
	Eric Dumazet, David S. Miller, linux-arm-kernel, netdev,
	linux-kernel, srk, r-gunasekaran

On 18/01/24 7:31 pm, Andrew Lunn wrote:
> On Thu, Jan 18, 2024 at 12:40:02PM +0530, MD Danish Anwar wrote:
>> This series adds support for switch-mode for ICSSG driver. This series
>> also introduces helper APIs to configure firmware maintained FDB
>> (Forwarding Database) and VLAN tables. These APIs are later used by ICSSG
>> driver in switch mode.
>>
>> Now the driver will boot by default in dual EMAC mode. When first ICSSG
>> interface is added to bridge driver will still be in EMAC mode. As soon as
>> second ICSSG interface is added to same bridge, switch-mode will be
>> enabled and switch firmwares will be loaded to PRU cores. The driver will
>> remain in dual EMAC mode if ICSSG interfaces are added to two different
>> bridges or if two differnet interfaces (One ICSSG, one other) is added to
>> the same bridge. We'll only enable is_switch_mode flag when two ICSSG
>> interfaces are added to same bridge.
>>
>> We start in dual MAC mode. Let's say lan0 and lan1 are ICSSG interfaces
>>
>> ip link add name br0 type bridge
>> ip link set lan0 master br0
>>
>> At this point, we get a CHANGEUPPER event. Only one port is a member of
>> the bridge, so we will still be in dual MAC mode.
>>
>> ip link set lan1 master br0
>>
>> We get a second CHANGEUPPER event, the secind interface lan1 is also ICSSG
>> interface so we will set the is_switch_mode flag and when interfaces are
>> brought up again, ICSSG switch firmwares will be loaded to PRU Cores.
>>
>> There are some other cases to consider as well. 
>>
>> ip link add name br0 type bridge
>> ip link add name br1 type bridge
>>
>> ip link set lan0 master br0
>> ip link set ppp0 master br0
>>
>> Here we are adding lan0 (ICSSG) and ppp0 (non ICSSG) to same bridge, as
>> they both are not ICSSG, we will still be running in dual EMAC mode.
>>
>> ip link set lan1 master br1
>> ip link set vpn0 master br1
>>
>> Here we are adding lan1 (ICSSG) and vpn0 (non ICSSG) to same bridge, as
>> they both are not ICSSG, we will still be running in dual EMAC mode.
> 
> This is going in the right direction, thanks for the changes.
> 
> What features does the dual EMAC firmware support which the switch
> firmware does not?
> 

Feature wise, there is no major feature that EMAC firmware supports and
switch firmware doesn't.

The major difference between EMAC and switch firmware is that switch
firmware can do forwarding between ports which EMAC firmware can't. Data
is directly forwarded to DMA in dual EMAC mode. Whereas switch firmware
forwards the data to DMA as well as the other port depending upon the
configured rules. The forwarding path between one port to other is not
present in dual EMAC firmware. There are additional checks in switch
firmware to decide forwarding which also results in consuming extra cpu
cycle.

In dual EMAC mode, data is directly forwarded to DMA and a lot of checks
are removed resulting in less cpu cycle consumption.

> If such features are in use, you should not reload firmware to the
> switch firmware, since it will break whatever has been
> configured. Keep with bridging in software.
> 

There are no such features so I think it's safe to reload the switch
firmware when two ICSSG interfaces are added to the same bridge.

> Similarly, what features are supported by both firmwares? Does feature
> configuration survive a firmware reload? Or is it necessary to pass
> all the configuration to the firmware again?
> 

Some configurations doesn't need to be passed again. Any changes to MSMC
will still be valid after firmware reload. But FDB, r30 commands will be
lost and will be needed to reconfigured. So all FDB entries and r30
commands will need to be run again.

>     Andrew

-- 
Thanks and Regards,
Danish

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

* Re: [RFC PATCH v2 0/3] Introduce switch mode support for ICSSG driver
@ 2024-01-22 10:45     ` MD Danish Anwar
  0 siblings, 0 replies; 34+ messages in thread
From: MD Danish Anwar @ 2024-01-22 10:45 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Rob Herring, Dan Carpenter, Jan Kiszka, Vladimir Oltean,
	Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, Paolo Abeni, Jakub Kicinski,
	Eric Dumazet, David S. Miller, linux-arm-kernel, netdev,
	linux-kernel, srk, r-gunasekaran

On 18/01/24 7:31 pm, Andrew Lunn wrote:
> On Thu, Jan 18, 2024 at 12:40:02PM +0530, MD Danish Anwar wrote:
>> This series adds support for switch-mode for ICSSG driver. This series
>> also introduces helper APIs to configure firmware maintained FDB
>> (Forwarding Database) and VLAN tables. These APIs are later used by ICSSG
>> driver in switch mode.
>>
>> Now the driver will boot by default in dual EMAC mode. When first ICSSG
>> interface is added to bridge driver will still be in EMAC mode. As soon as
>> second ICSSG interface is added to same bridge, switch-mode will be
>> enabled and switch firmwares will be loaded to PRU cores. The driver will
>> remain in dual EMAC mode if ICSSG interfaces are added to two different
>> bridges or if two differnet interfaces (One ICSSG, one other) is added to
>> the same bridge. We'll only enable is_switch_mode flag when two ICSSG
>> interfaces are added to same bridge.
>>
>> We start in dual MAC mode. Let's say lan0 and lan1 are ICSSG interfaces
>>
>> ip link add name br0 type bridge
>> ip link set lan0 master br0
>>
>> At this point, we get a CHANGEUPPER event. Only one port is a member of
>> the bridge, so we will still be in dual MAC mode.
>>
>> ip link set lan1 master br0
>>
>> We get a second CHANGEUPPER event, the secind interface lan1 is also ICSSG
>> interface so we will set the is_switch_mode flag and when interfaces are
>> brought up again, ICSSG switch firmwares will be loaded to PRU Cores.
>>
>> There are some other cases to consider as well. 
>>
>> ip link add name br0 type bridge
>> ip link add name br1 type bridge
>>
>> ip link set lan0 master br0
>> ip link set ppp0 master br0
>>
>> Here we are adding lan0 (ICSSG) and ppp0 (non ICSSG) to same bridge, as
>> they both are not ICSSG, we will still be running in dual EMAC mode.
>>
>> ip link set lan1 master br1
>> ip link set vpn0 master br1
>>
>> Here we are adding lan1 (ICSSG) and vpn0 (non ICSSG) to same bridge, as
>> they both are not ICSSG, we will still be running in dual EMAC mode.
> 
> This is going in the right direction, thanks for the changes.
> 
> What features does the dual EMAC firmware support which the switch
> firmware does not?
> 

Feature wise, there is no major feature that EMAC firmware supports and
switch firmware doesn't.

The major difference between EMAC and switch firmware is that switch
firmware can do forwarding between ports which EMAC firmware can't. Data
is directly forwarded to DMA in dual EMAC mode. Whereas switch firmware
forwards the data to DMA as well as the other port depending upon the
configured rules. The forwarding path between one port to other is not
present in dual EMAC firmware. There are additional checks in switch
firmware to decide forwarding which also results in consuming extra cpu
cycle.

In dual EMAC mode, data is directly forwarded to DMA and a lot of checks
are removed resulting in less cpu cycle consumption.

> If such features are in use, you should not reload firmware to the
> switch firmware, since it will break whatever has been
> configured. Keep with bridging in software.
> 

There are no such features so I think it's safe to reload the switch
firmware when two ICSSG interfaces are added to the same bridge.

> Similarly, what features are supported by both firmwares? Does feature
> configuration survive a firmware reload? Or is it necessary to pass
> all the configuration to the firmware again?
> 

Some configurations doesn't need to be passed again. Any changes to MSMC
will still be valid after firmware reload. But FDB, r30 commands will be
lost and will be needed to reconfigured. So all FDB entries and r30
commands will need to be run again.

>     Andrew

-- 
Thanks and Regards,
Danish

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [RFC PATCH v2 1/3] net: ti: icssg-prueth: Add helper functions to configure FDB
  2024-01-19 13:55     ` Andrew Lunn
@ 2024-01-22 10:48       ` MD Danish Anwar
  -1 siblings, 0 replies; 34+ messages in thread
From: MD Danish Anwar @ 2024-01-22 10:48 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Rob Herring, Dan Carpenter, Jan Kiszka, Vladimir Oltean,
	Wolfram Sang, Arnd Bergmann, Vignesh Raghavendra, Roger Quadros,
	Paolo Abeni, Jakub Kicinski, Eric Dumazet, David S. Miller,
	linux-arm-kernel, netdev, linux-kernel, srk, r-gunasekaran



On 19/01/24 7:25 pm, Andrew Lunn wrote:
>> +int icssg_fdb_add_del(struct prueth_emac *emac, const unsigned char *addr,
>> +		      u8 vid, u8 fid_c2, bool add)
>> +{
>> +
>> +	for (i = 0; i < ETH_ALEN; i++)
>> +		mac_fid[i] = addr[i];
> 
> ether_addr_copy()

Sure.

> 
>> +
>> +	/* 1-1 VID-FID mapping is already setup */
>> +	mac_fid[ETH_ALEN] = fid;
>> +	mac_fid[ETH_ALEN + 1] = 0;
>> +
>> +	fdb_slot = bitrev32(crc32_le(0, mac_fid, 8)) & PRUETH_SWITCH_FDB_MASK;
>> +
> 
>> +	fid_c2 |= ICSSG_FDB_ENTRY_VALID;
>> +	memcpy(&fdb_cmd.cmd_args[0], addr, 4);
>> +	memcpy(&fdb_cmd.cmd_args[1], &addr[4], 2);
>> +	fdb_cmd.cmd_args[1] |= ((fid << 16) | (fid_c2 << 24));
>> +	fdb_cmd.cmd_args[2] = fdb_slot;
> 
>> +int icssg_fdb_lookup(struct prueth_emac *emac, const unsigned char *addr,
>> +		     u8 vid)
>> +{
> 
>> +	for (i = 0; i < ETH_ALEN; i++)
>> +		mac_fid[i] = addr[i];
>> +
>> +	/* 1-1 VID-FID mapping is already setup */
>> +	mac_fid[ETH_ALEN] = fid;
>> +	mac_fid[ETH_ALEN + 1] = 0;
> 
>> +	memcpy(&fdb_cmd.cmd_args[0], addr, 4);
>> +	memcpy(&fdb_cmd.cmd_args[1], &addr[4], 2);
>> +	fdb_cmd.cmd_args[1] |= fid << 16;
>> +	fdb_cmd.cmd_args[2] = fdb_slot;
> 
> Maybe add some helpers to reduce the amount of duplicated code?
> 

Some codes are duplicated in icssg_fdb_add_del() and icssg_fdb_lookup().
I'll try to add helpers in next version to minimize this.

>       Andrew

-- 
Thanks and Regards,
Danish

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

* Re: [RFC PATCH v2 1/3] net: ti: icssg-prueth: Add helper functions to configure FDB
@ 2024-01-22 10:48       ` MD Danish Anwar
  0 siblings, 0 replies; 34+ messages in thread
From: MD Danish Anwar @ 2024-01-22 10:48 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Rob Herring, Dan Carpenter, Jan Kiszka, Vladimir Oltean,
	Wolfram Sang, Arnd Bergmann, Vignesh Raghavendra, Roger Quadros,
	Paolo Abeni, Jakub Kicinski, Eric Dumazet, David S. Miller,
	linux-arm-kernel, netdev, linux-kernel, srk, r-gunasekaran



On 19/01/24 7:25 pm, Andrew Lunn wrote:
>> +int icssg_fdb_add_del(struct prueth_emac *emac, const unsigned char *addr,
>> +		      u8 vid, u8 fid_c2, bool add)
>> +{
>> +
>> +	for (i = 0; i < ETH_ALEN; i++)
>> +		mac_fid[i] = addr[i];
> 
> ether_addr_copy()

Sure.

> 
>> +
>> +	/* 1-1 VID-FID mapping is already setup */
>> +	mac_fid[ETH_ALEN] = fid;
>> +	mac_fid[ETH_ALEN + 1] = 0;
>> +
>> +	fdb_slot = bitrev32(crc32_le(0, mac_fid, 8)) & PRUETH_SWITCH_FDB_MASK;
>> +
> 
>> +	fid_c2 |= ICSSG_FDB_ENTRY_VALID;
>> +	memcpy(&fdb_cmd.cmd_args[0], addr, 4);
>> +	memcpy(&fdb_cmd.cmd_args[1], &addr[4], 2);
>> +	fdb_cmd.cmd_args[1] |= ((fid << 16) | (fid_c2 << 24));
>> +	fdb_cmd.cmd_args[2] = fdb_slot;
> 
>> +int icssg_fdb_lookup(struct prueth_emac *emac, const unsigned char *addr,
>> +		     u8 vid)
>> +{
> 
>> +	for (i = 0; i < ETH_ALEN; i++)
>> +		mac_fid[i] = addr[i];
>> +
>> +	/* 1-1 VID-FID mapping is already setup */
>> +	mac_fid[ETH_ALEN] = fid;
>> +	mac_fid[ETH_ALEN + 1] = 0;
> 
>> +	memcpy(&fdb_cmd.cmd_args[0], addr, 4);
>> +	memcpy(&fdb_cmd.cmd_args[1], &addr[4], 2);
>> +	fdb_cmd.cmd_args[1] |= fid << 16;
>> +	fdb_cmd.cmd_args[2] = fdb_slot;
> 
> Maybe add some helpers to reduce the amount of duplicated code?
> 

Some codes are duplicated in icssg_fdb_add_del() and icssg_fdb_lookup().
I'll try to add helpers in next version to minimize this.

>       Andrew

-- 
Thanks and Regards,
Danish

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [RFC PATCH v2 2/3] net: ti: icssg-switch: Add switchdev based driver for ethernet switch support
  2024-01-19 14:12     ` Andrew Lunn
@ 2024-01-22 11:08       ` MD Danish Anwar
  -1 siblings, 0 replies; 34+ messages in thread
From: MD Danish Anwar @ 2024-01-22 11:08 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Rob Herring, Dan Carpenter, Jan Kiszka, Vladimir Oltean,
	Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, Paolo Abeni, Jakub Kicinski,
	Eric Dumazet, David S. Miller, linux-arm-kernel, netdev,
	linux-kernel, srk, r-gunasekaran


On 19/01/24 7:42 pm, Andrew Lunn wrote:
>> +static int prueth_switchdev_stp_state_set(struct prueth_emac *emac,
>> +					  u8 state)
>> +{
>> +	enum icssg_port_state_cmd emac_state;
>> +	int ret = 0;
>> +
>> +	switch (state) {
>> +	case BR_STATE_FORWARDING:
>> +		emac_state = ICSSG_EMAC_PORT_FORWARD;
>> +		break;
>> +	case BR_STATE_DISABLED:
>> +		emac_state = ICSSG_EMAC_PORT_DISABLE;
>> +		break;
>> +	case BR_STATE_LEARNING:
>> +	case BR_STATE_LISTENING:
>> +	case BR_STATE_BLOCKING:
>> +		emac_state = ICSSG_EMAC_PORT_BLOCK;
>> +		break;
> 
> That is unusual. Does it still learn while in BLOCK? It might be you
> need to flush the FDB for this port when it changes from BLOCKING to
> LISTENING or LEARNING?

ICSSG firmware supports four different states,
1. ICSSG_EMAC_PORT_DISABLE - port is in completed disable state and no
traffic is being processed.
2. ICSSG_EMAC_PORT_BLOCK - All traffic is blocked except for special
packets (eg LLDP BPDU frames)
3. ICSSG_EMAC_PORT_FORWARD - Port is fully active and every packet is
being processed. The port will also learn the mac address.
4. ICSSG_EMAC_PORT_FORWARD_WO_LEARNING - Port is fully active and every
packet is being processed but the port will also learn the mac address.

We don't have any state where we only learn and not do the forwarding.
So for BR_STATE_LISTENING and BR_STATE_BLOCKING I think state
ICSSG_EMAC_PORT_BLOCK is OK. For learning I am not sure what should be
the state. If both learning and forwarding is OK then we can set the
state to BR_STATE_FORWARDING.

> 
>> +static void prueth_switchdev_event_work(struct work_struct *work)
>> +{
>> +	struct prueth_switchdev_event_work *switchdev_work =
>> +		container_of(work, struct prueth_switchdev_event_work, work);
>> +	struct prueth_emac *emac = switchdev_work->emac;
>> +	struct switchdev_notifier_fdb_info *fdb;
>> +	int port_id = emac->port_id;
>> +	int ret;
>> +
>> +	rtnl_lock();
>> +	switch (switchdev_work->event) {
>> +	case SWITCHDEV_FDB_ADD_TO_DEVICE:
>> +		fdb = &switchdev_work->fdb_info;
>> +
>> +		netdev_dbg(emac->ndev, "prueth_fdb_add: MACID = %pM vid = %u flags = %u %u -- port %d\n",
>> +			   fdb->addr, fdb->vid, fdb->added_by_user,
>> +			   fdb->offloaded, port_id);
>> +
>> +		if (!fdb->added_by_user)
>> +			break;
>> +		if (memcmp(emac->mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0)
>> +			break;
> 
> ether_addr_equal(). Please review all the code and use these helpers
> when possible.

Sure.

> 
> So you don't add an FDB for the interfaces own MAC address? Does the
> switch know the interfaces MAC address?
> 

Interface's own mac address isn't needed to be added to FDB. Switch
already knows the interfaces mac_addr as during emac_ndo_open() we do
write the interface's mac_addr to MII_G_RT register [1] and adding the
mac_addr to MII_G_RT register is enough to let the firmware know.

In case we want interface to have more than 1 mac_addr, the the extra
mac_addr needs to be added to FDB.

>        Andrew

[1]
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/net/ethernet/ti/icssg/icssg_prueth.c?h=v6.8-rc1#n1329

Thanks for the reviews and comments on all the patches. Please let me
know if more changes are needed in this series.

-- 
Thanks and Regards,
Danish

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [RFC PATCH v2 2/3] net: ti: icssg-switch: Add switchdev based driver for ethernet switch support
@ 2024-01-22 11:08       ` MD Danish Anwar
  0 siblings, 0 replies; 34+ messages in thread
From: MD Danish Anwar @ 2024-01-22 11:08 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Rob Herring, Dan Carpenter, Jan Kiszka, Vladimir Oltean,
	Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, Paolo Abeni, Jakub Kicinski,
	Eric Dumazet, David S. Miller, linux-arm-kernel, netdev,
	linux-kernel, srk, r-gunasekaran


On 19/01/24 7:42 pm, Andrew Lunn wrote:
>> +static int prueth_switchdev_stp_state_set(struct prueth_emac *emac,
>> +					  u8 state)
>> +{
>> +	enum icssg_port_state_cmd emac_state;
>> +	int ret = 0;
>> +
>> +	switch (state) {
>> +	case BR_STATE_FORWARDING:
>> +		emac_state = ICSSG_EMAC_PORT_FORWARD;
>> +		break;
>> +	case BR_STATE_DISABLED:
>> +		emac_state = ICSSG_EMAC_PORT_DISABLE;
>> +		break;
>> +	case BR_STATE_LEARNING:
>> +	case BR_STATE_LISTENING:
>> +	case BR_STATE_BLOCKING:
>> +		emac_state = ICSSG_EMAC_PORT_BLOCK;
>> +		break;
> 
> That is unusual. Does it still learn while in BLOCK? It might be you
> need to flush the FDB for this port when it changes from BLOCKING to
> LISTENING or LEARNING?

ICSSG firmware supports four different states,
1. ICSSG_EMAC_PORT_DISABLE - port is in completed disable state and no
traffic is being processed.
2. ICSSG_EMAC_PORT_BLOCK - All traffic is blocked except for special
packets (eg LLDP BPDU frames)
3. ICSSG_EMAC_PORT_FORWARD - Port is fully active and every packet is
being processed. The port will also learn the mac address.
4. ICSSG_EMAC_PORT_FORWARD_WO_LEARNING - Port is fully active and every
packet is being processed but the port will also learn the mac address.

We don't have any state where we only learn and not do the forwarding.
So for BR_STATE_LISTENING and BR_STATE_BLOCKING I think state
ICSSG_EMAC_PORT_BLOCK is OK. For learning I am not sure what should be
the state. If both learning and forwarding is OK then we can set the
state to BR_STATE_FORWARDING.

> 
>> +static void prueth_switchdev_event_work(struct work_struct *work)
>> +{
>> +	struct prueth_switchdev_event_work *switchdev_work =
>> +		container_of(work, struct prueth_switchdev_event_work, work);
>> +	struct prueth_emac *emac = switchdev_work->emac;
>> +	struct switchdev_notifier_fdb_info *fdb;
>> +	int port_id = emac->port_id;
>> +	int ret;
>> +
>> +	rtnl_lock();
>> +	switch (switchdev_work->event) {
>> +	case SWITCHDEV_FDB_ADD_TO_DEVICE:
>> +		fdb = &switchdev_work->fdb_info;
>> +
>> +		netdev_dbg(emac->ndev, "prueth_fdb_add: MACID = %pM vid = %u flags = %u %u -- port %d\n",
>> +			   fdb->addr, fdb->vid, fdb->added_by_user,
>> +			   fdb->offloaded, port_id);
>> +
>> +		if (!fdb->added_by_user)
>> +			break;
>> +		if (memcmp(emac->mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0)
>> +			break;
> 
> ether_addr_equal(). Please review all the code and use these helpers
> when possible.

Sure.

> 
> So you don't add an FDB for the interfaces own MAC address? Does the
> switch know the interfaces MAC address?
> 

Interface's own mac address isn't needed to be added to FDB. Switch
already knows the interfaces mac_addr as during emac_ndo_open() we do
write the interface's mac_addr to MII_G_RT register [1] and adding the
mac_addr to MII_G_RT register is enough to let the firmware know.

In case we want interface to have more than 1 mac_addr, the the extra
mac_addr needs to be added to FDB.

>        Andrew

[1]
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/net/ethernet/ti/icssg/icssg_prueth.c?h=v6.8-rc1#n1329

Thanks for the reviews and comments on all the patches. Please let me
know if more changes are needed in this series.

-- 
Thanks and Regards,
Danish

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

* Re: [RFC PATCH v2 2/3] net: ti: icssg-switch: Add switchdev based driver for ethernet switch support
  2024-01-22 11:08       ` MD Danish Anwar
@ 2024-03-19  9:49         ` MD Danish Anwar
  -1 siblings, 0 replies; 34+ messages in thread
From: MD Danish Anwar @ 2024-03-19  9:49 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Rob Herring, Dan Carpenter, Jan Kiszka, Vladimir Oltean,
	Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, Paolo Abeni, Jakub Kicinski,
	Eric Dumazet, David S. Miller, linux-arm-kernel, netdev,
	linux-kernel, srk, r-gunasekaran

Hi Andrew,

On 22/01/24 4:38 pm, MD Danish Anwar wrote:
> 
> On 19/01/24 7:42 pm, Andrew Lunn wrote:
>>> +static int prueth_switchdev_stp_state_set(struct prueth_emac *emac,
>>> +					  u8 state)
>>> +{
>>> +	enum icssg_port_state_cmd emac_state;
>>> +	int ret = 0;
>>> +
>>> +	switch (state) {
>>> +	case BR_STATE_FORWARDING:
>>> +		emac_state = ICSSG_EMAC_PORT_FORWARD;
>>> +		break;
>>> +	case BR_STATE_DISABLED:
>>> +		emac_state = ICSSG_EMAC_PORT_DISABLE;
>>> +		break;
>>> +	case BR_STATE_LEARNING:
>>> +	case BR_STATE_LISTENING:
>>> +	case BR_STATE_BLOCKING:
>>> +		emac_state = ICSSG_EMAC_PORT_BLOCK;
>>> +		break;
>>
>> That is unusual. Does it still learn while in BLOCK? It might be you
>> need to flush the FDB for this port when it changes from BLOCKING to
>> LISTENING or LEARNING?
> 
> ICSSG firmware supports four different states,
> 1. ICSSG_EMAC_PORT_DISABLE - port is in completed disable state and no
> traffic is being processed.
> 2. ICSSG_EMAC_PORT_BLOCK - All traffic is blocked except for special
> packets (eg LLDP BPDU frames)
> 3. ICSSG_EMAC_PORT_FORWARD - Port is fully active and every packet is
> being processed. The port will also learn the mac address.
> 4. ICSSG_EMAC_PORT_FORWARD_WO_LEARNING - Port is fully active and every
> packet is being processed but the port will also learn the mac address.
> 
> We don't have any state where we only learn and not do the forwarding.
> So for BR_STATE_LISTENING and BR_STATE_BLOCKING I think state
> ICSSG_EMAC_PORT_BLOCK is OK. For learning I am not sure what should be
> the state. If both learning and forwarding is OK then we can set the
> state to BR_STATE_FORWARDING.
> 

I have got confirmation from firmware team regarding "Does it still
learn while in BLOCK?"

ICSSG does not learn in BLOCK state. Learning will be done in Forwading
mode only. The ICSSG firmware doesn't support any state where "the port
will accept traffic only for the purpose of updating MAC address tables."

We only learn in forwarding mode where the packets is forwarded as well.

So, this will be the handling of different states by ICSSG firmware.

	switch (state) {
	case BR_STATE_FORWARDING:
		emac_state = ICSSG_EMAC_PORT_FORWARD;
		break;
	case BR_STATE_DISABLED:
		emac_state = ICSSG_EMAC_PORT_DISABLE;
		break;
	case BR_STATE_LISTENING:
	case BR_STATE_BLOCKING:
		emac_state = ICSSG_EMAC_PORT_BLOCK;
		break;
	default:
		return -EOPNOTSUPP;
	}

I will make this change and other changes requested in this series and
post a v3 soon. Please let me know if you have any question.

>>
>>> +static void prueth_switchdev_event_work(struct work_struct *work)
>>> +{
>>> +	struct prueth_switchdev_event_work *switchdev_work =
>>> +		container_of(work, struct prueth_switchdev_event_work, work);
>>> +	struct prueth_emac *emac = switchdev_work->emac;
>>> +	struct switchdev_notifier_fdb_info *fdb;
>>> +	int port_id = emac->port_id;
>>> +	int ret;
>>> +
>>> +	rtnl_lock();
>>> +	switch (switchdev_work->event) {
>>> +	case SWITCHDEV_FDB_ADD_TO_DEVICE:
>>> +		fdb = &switchdev_work->fdb_info;
>>> +
>>> +		netdev_dbg(emac->ndev, "prueth_fdb_add: MACID = %pM vid = %u flags = %u %u -- port %d\n",
>>> +			   fdb->addr, fdb->vid, fdb->added_by_user,
>>> +			   fdb->offloaded, port_id);
>>> +
>>> +		if (!fdb->added_by_user)
>>> +			break;
>>> +		if (memcmp(emac->mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0)
>>> +			break;
>>
>> ether_addr_equal(). Please review all the code and use these helpers
>> when possible.
> 
> Sure.
> 
>>
>> So you don't add an FDB for the interfaces own MAC address? Does the
>> switch know the interfaces MAC address?
>>
> 
> Interface's own mac address isn't needed to be added to FDB. Switch
> already knows the interfaces mac_addr as during emac_ndo_open() we do
> write the interface's mac_addr to MII_G_RT register [1] and adding the
> mac_addr to MII_G_RT register is enough to let the firmware know.
> 
> In case we want interface to have more than 1 mac_addr, the the extra
> mac_addr needs to be added to FDB.
> 
>>        Andrew
> 
> [1]
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/net/ethernet/ti/icssg/icssg_prueth.c?h=v6.8-rc1#n1329
> 
> Thanks for the reviews and comments on all the patches. Please let me
> know if more changes are needed in this series.
> 

-- 
Thanks and Regards,
Danish

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [RFC PATCH v2 2/3] net: ti: icssg-switch: Add switchdev based driver for ethernet switch support
@ 2024-03-19  9:49         ` MD Danish Anwar
  0 siblings, 0 replies; 34+ messages in thread
From: MD Danish Anwar @ 2024-03-19  9:49 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Rob Herring, Dan Carpenter, Jan Kiszka, Vladimir Oltean,
	Wolfram Sang, Arnd Bergmann, Grygorii Strashko,
	Vignesh Raghavendra, Roger Quadros, Paolo Abeni, Jakub Kicinski,
	Eric Dumazet, David S. Miller, linux-arm-kernel, netdev,
	linux-kernel, srk, r-gunasekaran

Hi Andrew,

On 22/01/24 4:38 pm, MD Danish Anwar wrote:
> 
> On 19/01/24 7:42 pm, Andrew Lunn wrote:
>>> +static int prueth_switchdev_stp_state_set(struct prueth_emac *emac,
>>> +					  u8 state)
>>> +{
>>> +	enum icssg_port_state_cmd emac_state;
>>> +	int ret = 0;
>>> +
>>> +	switch (state) {
>>> +	case BR_STATE_FORWARDING:
>>> +		emac_state = ICSSG_EMAC_PORT_FORWARD;
>>> +		break;
>>> +	case BR_STATE_DISABLED:
>>> +		emac_state = ICSSG_EMAC_PORT_DISABLE;
>>> +		break;
>>> +	case BR_STATE_LEARNING:
>>> +	case BR_STATE_LISTENING:
>>> +	case BR_STATE_BLOCKING:
>>> +		emac_state = ICSSG_EMAC_PORT_BLOCK;
>>> +		break;
>>
>> That is unusual. Does it still learn while in BLOCK? It might be you
>> need to flush the FDB for this port when it changes from BLOCKING to
>> LISTENING or LEARNING?
> 
> ICSSG firmware supports four different states,
> 1. ICSSG_EMAC_PORT_DISABLE - port is in completed disable state and no
> traffic is being processed.
> 2. ICSSG_EMAC_PORT_BLOCK - All traffic is blocked except for special
> packets (eg LLDP BPDU frames)
> 3. ICSSG_EMAC_PORT_FORWARD - Port is fully active and every packet is
> being processed. The port will also learn the mac address.
> 4. ICSSG_EMAC_PORT_FORWARD_WO_LEARNING - Port is fully active and every
> packet is being processed but the port will also learn the mac address.
> 
> We don't have any state where we only learn and not do the forwarding.
> So for BR_STATE_LISTENING and BR_STATE_BLOCKING I think state
> ICSSG_EMAC_PORT_BLOCK is OK. For learning I am not sure what should be
> the state. If both learning and forwarding is OK then we can set the
> state to BR_STATE_FORWARDING.
> 

I have got confirmation from firmware team regarding "Does it still
learn while in BLOCK?"

ICSSG does not learn in BLOCK state. Learning will be done in Forwading
mode only. The ICSSG firmware doesn't support any state where "the port
will accept traffic only for the purpose of updating MAC address tables."

We only learn in forwarding mode where the packets is forwarded as well.

So, this will be the handling of different states by ICSSG firmware.

	switch (state) {
	case BR_STATE_FORWARDING:
		emac_state = ICSSG_EMAC_PORT_FORWARD;
		break;
	case BR_STATE_DISABLED:
		emac_state = ICSSG_EMAC_PORT_DISABLE;
		break;
	case BR_STATE_LISTENING:
	case BR_STATE_BLOCKING:
		emac_state = ICSSG_EMAC_PORT_BLOCK;
		break;
	default:
		return -EOPNOTSUPP;
	}

I will make this change and other changes requested in this series and
post a v3 soon. Please let me know if you have any question.

>>
>>> +static void prueth_switchdev_event_work(struct work_struct *work)
>>> +{
>>> +	struct prueth_switchdev_event_work *switchdev_work =
>>> +		container_of(work, struct prueth_switchdev_event_work, work);
>>> +	struct prueth_emac *emac = switchdev_work->emac;
>>> +	struct switchdev_notifier_fdb_info *fdb;
>>> +	int port_id = emac->port_id;
>>> +	int ret;
>>> +
>>> +	rtnl_lock();
>>> +	switch (switchdev_work->event) {
>>> +	case SWITCHDEV_FDB_ADD_TO_DEVICE:
>>> +		fdb = &switchdev_work->fdb_info;
>>> +
>>> +		netdev_dbg(emac->ndev, "prueth_fdb_add: MACID = %pM vid = %u flags = %u %u -- port %d\n",
>>> +			   fdb->addr, fdb->vid, fdb->added_by_user,
>>> +			   fdb->offloaded, port_id);
>>> +
>>> +		if (!fdb->added_by_user)
>>> +			break;
>>> +		if (memcmp(emac->mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0)
>>> +			break;
>>
>> ether_addr_equal(). Please review all the code and use these helpers
>> when possible.
> 
> Sure.
> 
>>
>> So you don't add an FDB for the interfaces own MAC address? Does the
>> switch know the interfaces MAC address?
>>
> 
> Interface's own mac address isn't needed to be added to FDB. Switch
> already knows the interfaces mac_addr as during emac_ndo_open() we do
> write the interface's mac_addr to MII_G_RT register [1] and adding the
> mac_addr to MII_G_RT register is enough to let the firmware know.
> 
> In case we want interface to have more than 1 mac_addr, the the extra
> mac_addr needs to be added to FDB.
> 
>>        Andrew
> 
> [1]
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/net/ethernet/ti/icssg/icssg_prueth.c?h=v6.8-rc1#n1329
> 
> Thanks for the reviews and comments on all the patches. Please let me
> know if more changes are needed in this series.
> 

-- 
Thanks and Regards,
Danish

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

end of thread, other threads:[~2024-03-19  9:50 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-01-18  7:10 [RFC PATCH v2 0/3] Introduce switch mode support for ICSSG driver MD Danish Anwar
2024-01-18  7:10 ` MD Danish Anwar
2024-01-18  7:10 ` [RFC PATCH v2 1/3] net: ti: icssg-prueth: Add helper functions to configure FDB MD Danish Anwar
2024-01-18  7:10   ` MD Danish Anwar
2024-01-19 13:55   ` Andrew Lunn
2024-01-19 13:55     ` Andrew Lunn
2024-01-22 10:48     ` MD Danish Anwar
2024-01-22 10:48       ` MD Danish Anwar
2024-01-18  7:10 ` [RFC PATCH v2 2/3] net: ti: icssg-switch: Add switchdev based driver for ethernet switch support MD Danish Anwar
2024-01-18  7:10   ` MD Danish Anwar
2024-01-19 14:12   ` Andrew Lunn
2024-01-19 14:12     ` Andrew Lunn
2024-01-22 11:08     ` MD Danish Anwar
2024-01-22 11:08       ` MD Danish Anwar
2024-03-19  9:49       ` MD Danish Anwar
2024-03-19  9:49         ` MD Danish Anwar
2024-01-19 20:40   ` Simon Horman
2024-01-19 20:40     ` Simon Horman
2024-01-22  7:54     ` MD Danish Anwar
2024-01-22  7:54       ` MD Danish Anwar
2024-01-18  7:10 ` [RFC PATCH v2 3/3] net: ti: icssg-prueth: Add support for ICSSG switch firmware MD Danish Anwar
2024-01-18  7:10   ` MD Danish Anwar
2024-01-19 14:29   ` Andrew Lunn
2024-01-19 14:29     ` Andrew Lunn
2024-01-22 10:35     ` MD Danish Anwar
2024-01-22 10:35       ` MD Danish Anwar
2024-01-19 20:41   ` Simon Horman
2024-01-19 20:41     ` Simon Horman
2024-01-22  7:52     ` MD Danish Anwar
2024-01-22  7:52       ` MD Danish Anwar
2024-01-18 14:01 ` [RFC PATCH v2 0/3] Introduce switch mode support for ICSSG driver Andrew Lunn
2024-01-18 14:01   ` Andrew Lunn
2024-01-22 10:45   ` MD Danish Anwar
2024-01-22 10:45     ` MD Danish Anwar

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.