[PATCH net-next v6 07/11] net: ti: prueth: Adds support for network filters for traffic control supported by PRU-ICSS

Parvathi Pudi posted 11 patches 9 months, 3 weeks ago
There is a newer version of this series
[PATCH net-next v6 07/11] net: ti: prueth: Adds support for network filters for traffic control supported by PRU-ICSS
Posted by Parvathi Pudi 9 months, 3 weeks ago
From: Roger Quadros <rogerq@ti.com>

Driver updates to enable/disable network filters and traffic control
features supported by the firmware running on PRU-ICSS.

Control of the following features are now supported:
1. Promiscuous mode
2. Network Storm prevention
3. Multicast filtering and
4. VLAN filtering

Firmware running on PRU-ICSS will go through all these filter checks
prior to sending the rx packets to the host.

Ethtool or dev ioctl can be used to enable/disable these features from
the user space.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Signed-off-by: Andrew F. Davis <afd@ti.com>
Signed-off-by: Basharath Hussain Khaja <basharath@couthit.com>
Signed-off-by: Parvathi Pudi <parvathi@couthit.com>
---
 drivers/net/ethernet/ti/Makefile              |   2 +-
 drivers/net/ethernet/ti/icssm/icssm_ethtool.c |  39 +++
 drivers/net/ethernet/ti/icssm/icssm_prueth.c  | 310 +++++++++++++++++-
 drivers/net/ethernet/ti/icssm/icssm_prueth.h  |  49 ++-
 .../net/ethernet/ti/icssm/icssm_prueth_dos.c  | 222 +++++++++++++
 drivers/net/ethernet/ti/icssm/icssm_switch.h  |   5 +
 .../ti/icssm/icssm_vlan_mcast_filter_mmap.h   | 120 +++++++
 7 files changed, 744 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/ethernet/ti/icssm/icssm_prueth_dos.c
 create mode 100644 drivers/net/ethernet/ti/icssm/icssm_vlan_mcast_filter_mmap.h

diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile
index f21dd11118ab..852640ce2b15 100644
--- a/drivers/net/ethernet/ti/Makefile
+++ b/drivers/net/ethernet/ti/Makefile
@@ -4,7 +4,7 @@
 #
 
 obj-$(CONFIG_TI_PRUETH) += icssm-prueth.o
-icssm-prueth-y := icssm/icssm_prueth.o icssm/icssm_ethtool.o
+icssm-prueth-y := icssm/icssm_prueth.o icssm/icssm_ethtool.o icssm/icssm_prueth_dos.o
 
 obj-$(CONFIG_TI_CPSW) += cpsw-common.o
 obj-$(CONFIG_TI_DAVINCI_EMAC) += cpsw-common.o
diff --git a/drivers/net/ethernet/ti/icssm/icssm_ethtool.c b/drivers/net/ethernet/ti/icssm/icssm_ethtool.c
index c1cd7f59c859..4b973e76724d 100644
--- a/drivers/net/ethernet/ti/icssm/icssm_ethtool.c
+++ b/drivers/net/ethernet/ti/icssm/icssm_ethtool.c
@@ -8,6 +8,7 @@
 #include <linux/if_bridge.h>
 #include <linux/if_vlan.h>
 #include "icssm_prueth.h"
+#include "icssm_vlan_mcast_filter_mmap.h"
 #include "../icssg/icss_iep.h"
 
 /* set PRU firmware statistics */
@@ -18,6 +19,11 @@ void icssm_emac_set_stats(struct prueth_emac *emac,
 
 	dram = emac->prueth->mem[emac->dram].va;
 	memcpy_toio(dram + STATISTICS_OFFSET, pstats, STAT_SIZE);
+
+	writel(pstats->vlan_dropped, dram +
+			ICSS_EMAC_FW_VLAN_FILTER_DROP_CNT_OFFSET);
+	writel(pstats->multicast_dropped, dram +
+			ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_OFFSET);
 }
 
 /* get statistics maintained by the PRU firmware into @pstats */
@@ -28,6 +34,11 @@ void icssm_emac_get_stats(struct prueth_emac *emac,
 
 	dram = emac->prueth->mem[emac->dram].va;
 	memcpy_fromio(pstats, dram + STATISTICS_OFFSET, STAT_SIZE);
+
+	pstats->vlan_dropped =
+		readl(dram + ICSS_EMAC_FW_VLAN_FILTER_DROP_CNT_OFFSET);
+	pstats->multicast_dropped =
+		readl(dram + ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_OFFSET);
 }
 
 /**
@@ -151,13 +162,40 @@ static void icssm_emac_get_ethtool_stats(struct net_device *ndev,
 	}
 }
 
+static int icssm_emac_get_regs_len(struct net_device *ndev)
+{
+	struct prueth_emac *emac = netdev_priv(ndev);
+	struct prueth *prueth = emac->prueth;
+
+	/* VLAN Table at the end of the memory map, after MultiCast
+	 * filter region. So VLAN table base +
+	 * size will give the entire size of reg dump in case of
+	 * Dual-EMAC firmware.
+	 */
+	if (PRUETH_IS_EMAC(prueth)) {
+		return ICSS_EMAC_FW_VLAN_FLTR_TBL_BASE_ADDR +
+		       ICSS_EMAC_FW_VLAN_FILTER_TABLE_SIZE_BYTES;
+	}
+
+	return 0;
+}
+
 static void icssm_emac_get_regs(struct net_device *ndev,
 				struct ethtool_regs *regs, void *p)
 {
 	struct prueth_emac *emac = netdev_priv(ndev);
 	struct prueth *prueth = emac->prueth;
+	void __iomem *ram;
+	u8 *reg = p;
 
 	regs->version = PRUETH_REG_DUMP_GET_VER(prueth);
+
+	/* Dump firmware's VLAN and MC tables */
+	if (PRUETH_IS_EMAC(prueth)) {
+		ram = prueth->mem[emac->dram].va;
+		memcpy_fromio(reg, ram, icssm_emac_get_regs_len(ndev));
+		return;
+	}
 }
 
 static const struct ethtool_rmon_hist_range icssm_emac_rmon_ranges[] = {
@@ -241,6 +279,7 @@ const struct ethtool_ops emac_ethtool_ops = {
 	.get_sset_count = icssm_emac_get_sset_count,
 	.get_strings = icssm_emac_get_strings,
 	.get_ethtool_stats = icssm_emac_get_ethtool_stats,
+	.get_regs_len = icssm_emac_get_regs_len,
 	.get_regs = icssm_emac_get_regs,
 	.get_rmon_stats = icssm_emac_get_rmon_stats,
 	.get_eth_mac_stats = icssm_emac_get_eth_mac_stats,
diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.c b/drivers/net/ethernet/ti/icssm/icssm_prueth.c
index a97aaa6bac4f..006f4b87e485 100644
--- a/drivers/net/ethernet/ti/icssm/icssm_prueth.c
+++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.c
@@ -29,6 +29,7 @@
 #include <net/pkt_cls.h>
 
 #include "icssm_prueth.h"
+#include "icssm_vlan_mcast_filter_mmap.h"
 #include "../icssg/icssg_mii_rt.h"
 #include "../icssg/icss_iep.h"
 
@@ -37,6 +38,26 @@
 #define TX_START_DELAY		0x40
 #define TX_CLK_DELAY_100M	0x6
 
+static struct prueth_fw_offsets fw_offsets_v2_1;
+
+static void icssm_prueth_set_fw_offsets(struct prueth *prueth)
+{
+	/* Set VLAN/Multicast filter control and table offsets */
+	if (PRUETH_IS_EMAC(prueth)) {
+		prueth->fw_offsets->vlan_ctrl_byte  =
+			ICSS_EMAC_FW_VLAN_FILTER_CTRL_BITMAP_OFFSET;
+		prueth->fw_offsets->vlan_filter_tbl =
+			ICSS_EMAC_FW_VLAN_FLTR_TBL_BASE_ADDR;
+
+		prueth->fw_offsets->mc_ctrl_byte  =
+			ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_OFFSET;
+		prueth->fw_offsets->mc_filter_mask =
+			ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OFFSET;
+		prueth->fw_offsets->mc_filter_tbl =
+			ICSS_EMAC_FW_MULTICAST_FILTER_TABLE;
+	}
+}
+
 static inline void icssm_prueth_write_reg(struct prueth *prueth,
 					  enum prueth_mem region,
 					  unsigned int reg, u32 val)
@@ -343,18 +364,25 @@ static void icssm_prueth_hostinit(struct prueth *prueth)
  */
 static void icssm_prueth_init_ethernet_mode(struct prueth *prueth)
 {
+	icssm_prueth_set_fw_offsets(prueth);
 	icssm_prueth_hostinit(prueth);
 }
 
 static void icssm_prueth_port_enable(struct prueth_emac *emac, bool enable)
 {
 	struct prueth *prueth = emac->prueth;
-	void __iomem *port_ctrl;
+	void __iomem *port_ctrl, *vlan_ctrl;
+	u32 vlan_ctrl_offset;
 	void __iomem *ram;
 
+	vlan_ctrl_offset = prueth->fw_offsets->vlan_ctrl_byte;
+
 	ram = prueth->mem[emac->dram].va;
 	port_ctrl = ram + PORT_CONTROL_ADDR;
 	writeb(!!enable, port_ctrl);
+
+	vlan_ctrl = ram + vlan_ctrl_offset;
+	writeb(!!enable, vlan_ctrl);
 }
 
 static int icssm_prueth_emac_config(struct prueth_emac *emac)
@@ -1422,6 +1450,174 @@ static void icssm_emac_ndo_get_stats64(struct net_device *ndev,
 	stats->rx_length_errors = ndev->stats.rx_length_errors;
 }
 
+/* enable/disable MC filter */
+static void icssm_emac_mc_filter_ctrl(struct prueth_emac *emac, bool enable)
+{
+	struct prueth *prueth = emac->prueth;
+	void __iomem *mc_filter_ctrl;
+	void __iomem *ram;
+	u32 mc_ctrl_byte;
+	u32 reg;
+
+	ram = prueth->mem[emac->dram].va;
+	mc_ctrl_byte = prueth->fw_offsets->mc_ctrl_byte;
+	mc_filter_ctrl = ram + mc_ctrl_byte;
+
+	if (enable)
+		reg = ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_ENABLED;
+	else
+		reg = ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_DISABLED;
+
+	writeb(reg, mc_filter_ctrl);
+}
+
+/* reset MC filter bins */
+static void icssm_emac_mc_filter_reset(struct prueth_emac *emac)
+{
+	struct prueth *prueth = emac->prueth;
+	void __iomem *mc_filter_tbl;
+	u32 mc_filter_tbl_base;
+	void __iomem *ram;
+
+	ram = prueth->mem[emac->dram].va;
+	mc_filter_tbl_base = prueth->fw_offsets->mc_filter_tbl;
+
+	mc_filter_tbl = ram + mc_filter_tbl_base;
+	memset_io(mc_filter_tbl, 0, ICSS_EMAC_FW_MULTICAST_TABLE_SIZE_BYTES);
+}
+
+/* set MC filter hashmask */
+static void icssm_emac_mc_filter_hashmask
+		(struct prueth_emac *emac,
+		 u8 mask[ICSS_EMAC_FW_MULTICAST_FILTER_MASK_SIZE_BYTES])
+{
+	struct prueth *prueth = emac->prueth;
+	void __iomem *mc_filter_mask;
+	u32 mc_filter_mask_base;
+	void __iomem *ram;
+
+	ram = prueth->mem[emac->dram].va;
+	mc_filter_mask_base = prueth->fw_offsets->mc_filter_mask;
+
+	mc_filter_mask = ram + mc_filter_mask_base;
+	memcpy_toio(mc_filter_mask, mask,
+		    ICSS_EMAC_FW_MULTICAST_FILTER_MASK_SIZE_BYTES);
+}
+
+static void icssm_emac_mc_filter_bin_update(struct prueth_emac *emac, u8 hash,
+					    u8 val)
+{
+	struct prueth *prueth = emac->prueth;
+	void __iomem *mc_filter_tbl;
+	u32 mc_filter_tbl_base;
+	void __iomem *ram;
+
+	ram = prueth->mem[emac->dram].va;
+	mc_filter_tbl_base = prueth->fw_offsets->mc_filter_tbl;
+
+	mc_filter_tbl = ram + mc_filter_tbl_base;
+	writeb(val, mc_filter_tbl + hash);
+}
+
+void icssm_emac_mc_filter_bin_allow(struct prueth_emac *emac, u8 hash)
+{
+	icssm_emac_mc_filter_bin_update
+		(emac, hash,
+		 ICSS_EMAC_FW_MULTICAST_FILTER_HOST_RCV_ALLOWED);
+}
+
+void icssm_emac_mc_filter_bin_disallow(struct prueth_emac *emac, u8 hash)
+{
+	icssm_emac_mc_filter_bin_update
+		(emac, hash,
+		 ICSS_EMAC_FW_MULTICAST_FILTER_HOST_RCV_NOT_ALLOWED);
+}
+
+u8 icssm_emac_get_mc_hash(u8 *mac, u8 *mask)
+{
+	u8 hash;
+	int j;
+
+	for (j = 0, hash = 0; j < ETH_ALEN; j++)
+		hash ^= (mac[j] & mask[j]);
+
+	return hash;
+}
+
+/**
+ * icssm_emac_ndo_set_rx_mode - EMAC set receive mode function
+ * @ndev: The EMAC network adapter
+ *
+ * Called when system wants to set the receive mode of the device.
+ *
+ */
+static void icssm_emac_ndo_set_rx_mode(struct net_device *ndev)
+{
+	struct prueth_emac *emac = netdev_priv(ndev);
+	bool promisc = ndev->flags & IFF_PROMISC;
+	struct netdev_hw_addr *ha;
+	struct prueth *prueth;
+	unsigned long flags;
+	void __iomem *sram;
+	u32 mask, reg;
+	u8 hash;
+
+	prueth = emac->prueth;
+	sram = prueth->mem[PRUETH_MEM_SHARED_RAM].va;
+	reg = readl(sram + EMAC_PROMISCUOUS_MODE_OFFSET);
+
+	/* for LRE, it is a shared table. So lock the access */
+	spin_lock_irqsave(&emac->addr_lock, flags);
+
+	/* Disable and reset multicast filter, allows allmulti */
+	icssm_emac_mc_filter_ctrl(emac, false);
+	icssm_emac_mc_filter_reset(emac);
+	icssm_emac_mc_filter_hashmask(emac, emac->mc_filter_mask);
+
+	if (PRUETH_IS_EMAC(prueth)) {
+		switch (emac->port_id) {
+		case PRUETH_PORT_MII0:
+			mask = EMAC_P1_PROMISCUOUS_BIT;
+			break;
+		case PRUETH_PORT_MII1:
+			mask = EMAC_P2_PROMISCUOUS_BIT;
+			break;
+		default:
+			netdev_err(ndev, "%s: invalid port\n", __func__);
+			goto unlock;
+		}
+
+		if (promisc) {
+			/* Enable promiscuous mode */
+			reg |= mask;
+		} else {
+			/* Disable promiscuous mode */
+			reg &= ~mask;
+		}
+
+		writel(reg, sram + EMAC_PROMISCUOUS_MODE_OFFSET);
+
+		if (promisc)
+			goto unlock;
+	}
+
+	if (ndev->flags & IFF_ALLMULTI && !PRUETH_IS_SWITCH(prueth))
+		goto unlock;
+
+	icssm_emac_mc_filter_ctrl(emac, true);	/* all multicast blocked */
+
+	if (netdev_mc_empty(ndev))
+		goto unlock;
+
+	netdev_for_each_mc_addr(ha, ndev) {
+		hash = icssm_emac_get_mc_hash(ha->addr, emac->mc_filter_mask);
+		icssm_emac_mc_filter_bin_allow(emac, hash);
+	}
+
+unlock:
+	spin_unlock_irqrestore(&emac->addr_lock, flags);
+}
+
 static int icssm_emac_hwtstamp_config_set(struct net_device *ndev,
 					  struct ifreq *ifr)
 {
@@ -1495,13 +1691,115 @@ static int icssm_emac_ndo_ioctl(struct net_device *ndev, struct ifreq *ifr,
 	return phy_do_ioctl(ndev, ifr, cmd);
 }
 
+int icssm_emac_add_del_vid(struct prueth_emac *emac,
+			   bool add, __be16 proto, u16 vid)
+{
+	struct prueth *prueth = emac->prueth;
+	u32 vlan_filter_tbl;
+	unsigned long flags;
+	void __iomem *ram;
+	u8 bit_index, val;
+	u16 byte_index;
+
+	vlan_filter_tbl = prueth->fw_offsets->vlan_filter_tbl;
+	ram = prueth->mem[emac->dram].va;
+
+	if (proto != htons(ETH_P_8021Q))
+		return -EINVAL;
+
+	if (vid >= ICSS_EMAC_FW_VLAN_FILTER_VID_MAX)
+		return -EINVAL;
+
+	/* By default, VLAN ID 0 (priority tagged packets) is routed to
+	 * host, so nothing to be done if vid = 0
+	 */
+	if (!vid)
+		return 0;
+
+	/* for LRE, it is a shared table. So lock the access */
+	spin_lock_irqsave(&emac->addr_lock, flags);
+
+	/* VLAN filter table is 512 bytes (4096 bit) bitmap.
+	 * Each bit controls enabling or disabling corresponding
+	 * VID. Therefore byte index that controls a given VID is
+	 * can calculated as vid / 8 and the bit within that byte
+	 * that controls VID is given by vid % 8. Allow untagged
+	 * frames to host by default.
+	 */
+	byte_index = vid / BITS_PER_BYTE;
+	bit_index = vid % BITS_PER_BYTE;
+	val = readb(ram + vlan_filter_tbl + byte_index);
+	if (add)
+		val |= BIT(bit_index);
+	else
+		val &= ~BIT(bit_index);
+	writeb(val, ram + vlan_filter_tbl + byte_index);
+
+	spin_unlock_irqrestore(&emac->addr_lock, flags);
+
+	netdev_dbg(emac->ndev, "%s VID bit at index %d and bit %d\n",
+		   add ? "Setting" : "Clearing", byte_index, bit_index);
+
+	return 0;
+}
+
+static int icssm_emac_ndo_vlan_rx_add_vid(struct net_device *dev,
+					  __be16 proto, u16 vid)
+{
+	struct prueth_emac *emac = netdev_priv(dev);
+
+	return icssm_emac_add_del_vid(emac, true, proto, vid);
+}
+
+static int icssm_emac_ndo_vlan_rx_kill_vid(struct net_device *dev,
+					   __be16 proto, u16 vid)
+{
+	struct prueth_emac *emac = netdev_priv(dev);
+
+	return icssm_emac_add_del_vid(emac, false, proto, vid);
+}
+
+static int icssm_emac_get_port_parent_id(struct net_device *dev,
+					 struct netdev_phys_item_id *ppid)
+{
+	struct prueth_emac *emac = netdev_priv(dev);
+	struct prueth *prueth = emac->prueth;
+
+	ppid->id_len = sizeof(prueth->base_mac);
+	memcpy(&ppid->id, &prueth->base_mac, ppid->id_len);
+
+	return 0;
+}
+
+static int icssm_emac_ndo_get_phys_port_name(struct net_device *ndev,
+					     char *name, size_t len)
+{
+	struct prueth_emac *emac = netdev_priv(ndev);
+	int err;
+
+	err = snprintf(name, len, "p%d", emac->port_id);
+
+	if (err >= len)
+		return -EINVAL;
+
+	return 0;
+}
+
 static const struct net_device_ops emac_netdev_ops = {
 	.ndo_open = icssm_emac_ndo_open,
 	.ndo_stop = icssm_emac_ndo_stop,
 	.ndo_start_xmit = icssm_emac_ndo_start_xmit,
+	.ndo_set_mac_address = eth_mac_addr,
+	.ndo_validate_addr = eth_validate_addr,
 	.ndo_tx_timeout = icssm_emac_ndo_tx_timeout,
 	.ndo_get_stats64 = icssm_emac_ndo_get_stats64,
+	.ndo_set_rx_mode = icssm_emac_ndo_set_rx_mode,
 	.ndo_eth_ioctl = icssm_emac_ndo_ioctl,
+	.ndo_vlan_rx_add_vid = icssm_emac_ndo_vlan_rx_add_vid,
+	.ndo_vlan_rx_kill_vid = icssm_emac_ndo_vlan_rx_kill_vid,
+	.ndo_setup_tc = icssm_emac_ndo_setup_tc,
+	.ndo_get_port_parent_id = icssm_emac_get_port_parent_id,
+	.ndo_get_phys_port_name = icssm_emac_ndo_get_phys_port_name,
 };
 
 /* get emac_port corresponding to eth_node name */
@@ -1567,6 +1865,7 @@ static int icssm_prueth_netdev_init(struct prueth *prueth,
 	emac->prueth = prueth;
 	emac->ndev = ndev;
 	emac->port_id = port;
+	memset(&emac->mc_filter_mask[0], 0xff, ETH_ALEN); /* default mask */
 
 	/* by default eth_type is EMAC */
 	switch (port) {
@@ -1608,7 +1907,9 @@ static int icssm_prueth_netdev_init(struct prueth *prueth,
 		dev_err(prueth->dev, "could not get ptp tx irq. Skipping PTP support\n");
 	}
 
+	spin_lock_init(&emac->lock);
 	spin_lock_init(&emac->ptp_skb_lock);
+	spin_lock_init(&emac->addr_lock);
 
 	/* get mac address from DT and set private and netdev addr */
 	ret = of_get_ethdev_address(eth_node, ndev);
@@ -1637,6 +1938,10 @@ static int icssm_prueth_netdev_init(struct prueth *prueth,
 	phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_Pause_BIT);
 	phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_Asym_Pause_BIT);
 
+	ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_TC;
+
+	ndev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
+
 	ndev->netdev_ops = &emac_netdev_ops;
 	ndev->ethtool_ops = &emac_ethtool_ops;
 
@@ -1689,6 +1994,7 @@ static int icssm_prueth_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, prueth);
 	prueth->dev = dev;
 	prueth->fw_data = device_get_match_data(dev);
+	prueth->fw_offsets = &fw_offsets_v2_1;
 
 	eth_ports_node = of_get_child_by_name(np, "ethernet-ports");
 	if (!eth_ports_node)
@@ -1875,6 +2181,8 @@ static int icssm_prueth_probe(struct platform_device *pdev)
 			prueth->emac[PRUETH_MAC1]->ndev;
 	}
 
+	eth_random_addr(prueth->base_mac);
+
 	dev_info(dev, "TI PRU ethernet driver initialized: %s EMAC mode\n",
 		 (!eth0_node || !eth1_node) ? "single" : "dual");
 
diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.h b/drivers/net/ethernet/ti/icssm/icssm_prueth.h
index 1709b3b6c2be..8a5f1647466a 100644
--- a/drivers/net/ethernet/ti/icssm/icssm_prueth.h
+++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.h
@@ -28,6 +28,9 @@
 #define EMAC_MAX_FRM_SUPPORT (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN + \
 			      ICSSM_LRE_TAG_SIZE)
 
+/* default timer for NSP and HSR/PRP */
+#define PRUETH_NSP_TIMER_MS	(100) /* Refresh NSP counters every 100ms */
+
 #define PRUETH_REG_DUMP_VER		1
 
 /* Encoding: 32-16: Reserved, 16-8: Reg dump version, 8-0: Ethertype  */
@@ -293,6 +296,29 @@ enum prueth_mem {
 	PRUETH_MEM_MAX,
 };
 
+/* Firmware offsets/size information */
+struct prueth_fw_offsets {
+	u32 index_array_offset;
+	u32 bin_array_offset;
+	u32 nt_array_offset;
+	u32 index_array_loc;
+	u32 bin_array_loc;
+	u32 nt_array_loc;
+	u32 index_array_max_entries;
+	u32 bin_array_max_entries;
+	u32 nt_array_max_entries;
+	u32 vlan_ctrl_byte;
+	u32 vlan_filter_tbl;
+	u32 mc_ctrl_byte;
+	u32 mc_filter_mask;
+	u32 mc_filter_tbl;
+	/* IEP wrap is used in the rx packet ordering logic and
+	 * is different for ICSSM v1.0 vs 2.1
+	 */
+	u32 iep_wrap;
+	u16 hash_mask;
+};
+
 enum pruss_device {
 	PRUSS_AM57XX = 0,
 	PRUSS_AM43XX,
@@ -314,6 +340,11 @@ struct prueth_private_data {
 	bool support_switch;
 };
 
+struct nsp_counter {
+	unsigned long cookie;
+	u16 credit;
+};
+
 /* data for each emac port */
 struct prueth_emac {
 	struct prueth *prueth;
@@ -338,8 +369,16 @@ struct prueth_emac {
 	const char *phy_id;
 	u32 msg_enable;
 	u8 mac_addr[6];
+	unsigned char mc_filter_mask[ETH_ALEN];	/* for multicast filtering */
 	phy_interface_t phy_if;
+
 	spinlock_t lock;	/* serialize access */
+	spinlock_t addr_lock;	/* serialize access to VLAN/MC filter table */
+
+	struct nsp_counter nsp_bc;
+	struct nsp_counter nsp_mc;
+	struct nsp_counter nsp_uc;
+	bool nsp_enabled;
 
 	struct sk_buff *ptp_skb[PRUETH_PTP_TS_EVENTS];
 	spinlock_t ptp_skb_lock;	/* serialize access */
@@ -367,19 +406,27 @@ struct prueth {
 	unsigned int eth_type;
 	size_t ocmc_ram_size;
 	u8 emac_configured;
+	u8 base_mac[ETH_ALEN];
 };
 
 extern const struct ethtool_ops emac_ethtool_ops;
 
+int icssm_emac_ndo_setup_tc(struct net_device *dev, enum tc_setup_type type,
+			    void *type_data);
 void icssm_parse_packet_info(struct prueth *prueth, u32 buffer_descriptor,
 			     struct prueth_packet_info *pkt_info);
 int icssm_emac_rx_packet(struct prueth_emac *emac, u16 *bd_rd_ptr,
 			 struct prueth_packet_info *pkt_info,
 			 const struct prueth_queue_info *rxqueue);
-
+int icssm_emac_add_del_vid(struct prueth_emac *emac,
+			   bool add, __be16 proto, u16 vid);
 irqreturn_t icssm_prueth_ptp_tx_irq_handle(int irq, void *dev);
 irqreturn_t icssm_prueth_ptp_tx_irq_work(int irq, void *dev);
 
+void icssm_emac_mc_filter_bin_allow(struct prueth_emac *emac, u8 hash);
+void icssm_emac_mc_filter_bin_disallow(struct prueth_emac *emac, u8 hash);
+u8 icssm_emac_get_mc_hash(u8 *mac, u8 *mask);
+
 void icssm_emac_set_stats(struct prueth_emac *emac,
 			  struct port_statistics *pstats);
 void icssm_emac_get_stats(struct prueth_emac *emac,
diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth_dos.c b/drivers/net/ethernet/ti/icssm/icssm_prueth_dos.c
new file mode 100644
index 000000000000..1a7499131b2b
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssm/icssm_prueth_dos.c
@@ -0,0 +1,222 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com
+ */
+
+#include <linux/kernel.h>
+#include <linux/remoteproc/pruss.h>
+#include <linux/regmap.h>
+#include <linux/remoteproc.h>
+#include <net/pkt_cls.h>
+
+#include "../icssg/icssg_mii_rt.h"
+#include "icssm_vlan_mcast_filter_mmap.h"
+#include "icssm_prueth.h"
+
+static void icssm_emac_nsp_enable(void __iomem *counter, u16 credit)
+{
+	writel((credit << PRUETH_NSP_CREDIT_SHIFT) | PRUETH_NSP_ENABLE,
+	       counter);
+}
+
+/**
+ * icssm_prueth_enable_nsp - enable nsp
+ *
+ * @emac: EMAC data structure
+ *
+ */
+static void icssm_prueth_enable_nsp(struct prueth_emac *emac)
+{
+	struct prueth *prueth = emac->prueth;
+	void __iomem *dram;
+
+	dram = prueth->mem[emac->dram].va;
+
+	if (emac->nsp_bc.cookie)
+		icssm_emac_nsp_enable(dram + STORM_PREVENTION_OFFSET_BC,
+				      emac->nsp_bc.credit);
+	if (emac->nsp_mc.cookie)
+		icssm_emac_nsp_enable(dram + STORM_PREVENTION_OFFSET_MC,
+				      emac->nsp_mc.credit);
+	if (emac->nsp_uc.cookie)
+		icssm_emac_nsp_enable(dram + STORM_PREVENTION_OFFSET_UC,
+				      emac->nsp_uc.credit);
+}
+
+static int icssm_emac_flower_parse_policer(struct prueth_emac *emac,
+					   struct netlink_ext_ack *extack,
+					   struct flow_cls_offload *cls,
+					   u64 rate_bytes_per_sec)
+{
+	struct flow_rule *rule = flow_cls_offload_flow_rule(cls);
+	struct flow_dissector *dissector = rule->match.dissector;
+	u8 null_mac[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+	u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+	u8 mc_mac[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00};
+	struct flow_match_eth_addrs match;
+	struct nsp_counter *nsp = NULL;
+	char *str;
+	u32 pps;
+
+	if (dissector->used_keys &
+	    ~(BIT(FLOW_DISSECTOR_KEY_BASIC) |
+	      BIT(FLOW_DISSECTOR_KEY_CONTROL) |
+	      BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
+		NL_SET_ERR_MSG_MOD(extack,
+				   "Unsupported keys used");
+		return -EOPNOTSUPP;
+	}
+
+	if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
+		NL_SET_ERR_MSG_MOD(extack, "Not matching on eth address");
+		return -EOPNOTSUPP;
+	}
+
+	flow_rule_match_eth_addrs(rule, &match);
+
+	if (!ether_addr_equal_masked(match.key->src, null_mac,
+				     match.mask->src)) {
+		NL_SET_ERR_MSG_MOD(extack,
+				   "Matching on source MAC not supported");
+		return -EOPNOTSUPP;
+	}
+
+	if (ether_addr_equal(match.key->dst, bc_mac)) {
+		if (!emac->nsp_bc.cookie ||
+		    emac->nsp_bc.cookie == cls->cookie)
+			nsp = &emac->nsp_bc;
+		else
+			NL_SET_ERR_MSG_MOD(extack, "BC Filter already set");
+		str = "Broad";
+	} else if (ether_addr_equal_masked(match.key->dst, mc_mac, mc_mac)) {
+		if (!emac->nsp_mc.cookie ||
+		    emac->nsp_mc.cookie == cls->cookie)
+			nsp = &emac->nsp_mc;
+		else
+			NL_SET_ERR_MSG_MOD(extack, "MC Filter already set");
+		str = "Multi";
+	} else {
+		if (!emac->nsp_uc.cookie ||
+		    emac->nsp_uc.cookie == cls->cookie)
+			nsp = &emac->nsp_uc;
+		else
+			NL_SET_ERR_MSG_MOD(extack, "UC Filter already set");
+		str = "Uni";
+	}
+
+	if (!nsp)
+		return -EOPNOTSUPP;
+
+	/* Calculate number of packets per second for given bps
+	 * assuming min ethernet packet size
+	 */
+	pps = div_u64(rate_bytes_per_sec, ETH_ZLEN);
+	/* Convert that to packets per 100ms */
+	pps /= MSEC_PER_SEC / PRUETH_NSP_TIMER_MS;
+
+	nsp->cookie = cls->cookie;
+	nsp->credit = pps;
+	emac->nsp_enabled = emac->nsp_bc.cookie | emac->nsp_mc.cookie |
+			    emac->nsp_uc.cookie;
+
+	icssm_prueth_enable_nsp(emac);
+
+	netdev_dbg(emac->ndev,
+		   "%scast filter set to %d packets per %dms\n", str,
+		   nsp->credit, PRUETH_NSP_TIMER_MS);
+
+	return 0;
+}
+
+static int icssm_emac_configure_clsflower(struct prueth_emac *emac,
+					  struct flow_cls_offload *cls)
+{
+	struct flow_rule *rule = flow_cls_offload_flow_rule(cls);
+	struct netlink_ext_ack *extack = cls->common.extack;
+	const struct flow_action_entry *act;
+
+	act = &rule->action.entries[0];
+	switch (act->id) {
+	case FLOW_ACTION_POLICE:
+		return icssm_emac_flower_parse_policer
+			(emac, extack, cls,
+			 act->police.rate_bytes_ps);
+	default:
+		NL_SET_ERR_MSG_MOD(extack,
+				   "Unsupported only ACTION_POLICE supported");
+		return -EOPNOTSUPP;
+	}
+}
+
+static int icssm_emac_delete_clsflower(struct prueth_emac *emac,
+				       struct flow_cls_offload *cls)
+{
+	struct prueth *prueth = emac->prueth;
+	void __iomem *dram;
+
+	dram = prueth->mem[emac->dram].va;
+
+	if (cls->cookie == emac->nsp_bc.cookie) {
+		emac->nsp_bc.cookie = 0;
+		emac->nsp_bc.credit = 0;
+		writel(0, dram + STORM_PREVENTION_OFFSET_BC);
+	} else if (cls->cookie == emac->nsp_mc.cookie) {
+		emac->nsp_mc.cookie = 0;
+		emac->nsp_mc.credit = 0;
+		writel(0, dram + STORM_PREVENTION_OFFSET_MC);
+	} else if (cls->cookie == emac->nsp_uc.cookie) {
+		emac->nsp_uc.cookie = 0;
+		emac->nsp_uc.credit = 0;
+		writel(0, dram + STORM_PREVENTION_OFFSET_UC);
+	}
+
+	emac->nsp_enabled = emac->nsp_bc.cookie | emac->nsp_mc.cookie |
+			    emac->nsp_uc.cookie;
+
+	return 0;
+}
+
+static int icssm_emac_setup_tc_cls_flower(struct prueth_emac *emac,
+					  struct flow_cls_offload *cls_flower)
+{
+	switch (cls_flower->command) {
+	case FLOW_CLS_REPLACE:
+		return icssm_emac_configure_clsflower(emac, cls_flower);
+	case FLOW_CLS_DESTROY:
+		return icssm_emac_delete_clsflower(emac, cls_flower);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static int icssm_emac_setup_tc_block_cb(enum tc_setup_type type,
+					void *type_data, void *cb_priv)
+{
+	struct prueth_emac *emac = cb_priv;
+
+	if (!tc_cls_can_offload_and_chain0(emac->ndev, type_data))
+		return -EOPNOTSUPP;
+
+	switch (type) {
+	case TC_SETUP_CLSFLOWER:
+		return icssm_emac_setup_tc_cls_flower(emac, type_data);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static LIST_HEAD(emac_block_cb_list);
+
+int icssm_emac_ndo_setup_tc(struct net_device *dev, enum tc_setup_type type,
+			    void *type_data)
+{
+	struct prueth_emac *emac = netdev_priv(dev);
+
+	if (type == TC_SETUP_BLOCK) {
+		return flow_block_cb_setup_simple(type_data,
+						  &emac_block_cb_list,
+						  icssm_emac_setup_tc_block_cb,
+						  emac, emac, true);
+	}
+
+	return -EOPNOTSUPP;
+}
diff --git a/drivers/net/ethernet/ti/icssm/icssm_switch.h b/drivers/net/ethernet/ti/icssm/icssm_switch.h
index b13e0706ccec..0053191380b7 100644
--- a/drivers/net/ethernet/ti/icssm/icssm_switch.h
+++ b/drivers/net/ethernet/ti/icssm/icssm_switch.h
@@ -146,6 +146,11 @@
 /* 4 bytes ? */
 #define STP_INVALID_STATE_OFFSET	(STATISTICS_OFFSET + STAT_SIZE + 33)
 
+/* Shared RAM Offsets for Switch */
+/* NSP (Network Storm Prevention) timer re-uses NT timer */
+#define PRUETH_NSP_CREDIT_SHIFT       8
+#define PRUETH_NSP_ENABLE            BIT(0)
+
 /* DRAM Offsets for EMAC
  * Present on Both DRAM0 and DRAM1
  */
diff --git a/drivers/net/ethernet/ti/icssm/icssm_vlan_mcast_filter_mmap.h b/drivers/net/ethernet/ti/icssm/icssm_vlan_mcast_filter_mmap.h
new file mode 100644
index 000000000000..32b5c228c5fb
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssm/icssm_vlan_mcast_filter_mmap.h
@@ -0,0 +1,120 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/* Copyright (C) 2015-2021 Texas Instruments Incorporated - https://www.ti.com
+ *
+ * This file contains VLAN/Multicast filtering feature memory map
+ *
+ */
+
+#ifndef ICSS_VLAN_MULTICAST_FILTER_MM_H
+#define ICSS_VLAN_MULTICAST_FILTER_MM_H
+
+/*  VLAN/Multicast filter defines & offsets,
+ *  present on both PRU0 and PRU1 DRAM
+ */
+
+/* Feature enable/disable values for multicast filtering */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_DISABLED		0x00
+#define ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_ENABLED		0x01
+
+/* Feature enable/disable values  for VLAN filtering */
+#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_DISABLED			0x00
+#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_ENABLED			0x01
+
+/* Add/remove multicast mac id for filtering bin */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_HOST_RCV_ALLOWED		0x01
+#define ICSS_EMAC_FW_MULTICAST_FILTER_HOST_RCV_NOT_ALLOWED	0x00
+
+/* Default HASH value for the multicast filtering Mask */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_INIT_VAL			0xFF
+
+/* Size requirements for Multicast filtering feature */
+#define ICSS_EMAC_FW_MULTICAST_TABLE_SIZE_BYTES			       256
+#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_SIZE_BYTES			 6
+#define ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_SIZE_BYTES			 1
+#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OVERRIDE_STATUS_SIZE_BYTES	 1
+#define ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_SIZE_BYTES		 4
+
+/* Size requirements for VLAN filtering feature : 4096 bits = 512 bytes */
+#define ICSS_EMAC_FW_VLAN_FILTER_TABLE_SIZE_BYTES		       512
+#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_SIZE_BYTES			 1
+#define ICSS_EMAC_FW_VLAN_FILTER_DROP_CNT_SIZE_BYTES			 4
+
+/* Mask override set status */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OVERRIDE_SET			 1
+/* Mask override not set status */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OVERRIDE_NOT_SET		 0
+/* 6 bytes HASH Mask for the MAC */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OFFSET	  0xF4
+/* 0 -> multicast filtering disabled | 1 -> multicast filtering enabled */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_OFFSET	\
+	(ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OFFSET +	\
+	 ICSS_EMAC_FW_MULTICAST_FILTER_MASK_SIZE_BYTES)
+/* Status indicating if the HASH override is done or not: 0: no, 1: yes */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_OVERRIDE_STATUS	\
+	(ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_OFFSET +	\
+	 ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_SIZE_BYTES)
+/* Multicast drop statistics */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_OFFSET	\
+	(ICSS_EMAC_FW_MULTICAST_FILTER_OVERRIDE_STATUS +\
+	 ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OVERRIDE_STATUS_SIZE_BYTES)
+/* Multicast table */
+#define ICSS_EMAC_FW_MULTICAST_FILTER_TABLE		\
+	(ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_OFFSET +\
+	 ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_SIZE_BYTES)
+
+/* Multicast filter defines & offsets for LRE
+ */
+#define ICSS_LRE_FW_MULTICAST_TABLE_SEARCH_OP_CONTROL_BIT	0xE0
+/* one byte field :
+ * 0 -> multicast filtering disabled
+ * 1 -> multicast filtering enabled
+ */
+#define ICSS_LRE_FW_MULTICAST_FILTER_MASK			 0xE4
+#define ICSS_LRE_FW_MULTICAST_FILTER_TABLE			 0x100
+
+/* VLAN table Offsets */
+#define ICSS_EMAC_FW_VLAN_FLTR_TBL_BASE_ADDR		 0x200
+#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_BITMAP_OFFSET	 0xEF
+#define ICSS_EMAC_FW_VLAN_FILTER_DROP_CNT_OFFSET	\
+	(ICSS_EMAC_FW_VLAN_FILTER_CTRL_BITMAP_OFFSET +	\
+	 ICSS_EMAC_FW_VLAN_FILTER_CTRL_SIZE_BYTES)
+
+/* VLAN filter Control Bit maps */
+/* one bit field, bit 0: | 0 : VLAN filter disabled (default),
+ * 1: VLAN filter enabled
+ */
+#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_ENABLE_BIT		       0
+/* one bit field, bit 1: | 0 : untagged host rcv allowed (default),
+ * 1: untagged host rcv not allowed
+ */
+#define ICSS_EMAC_FW_VLAN_FILTER_UNTAG_HOST_RCV_ALLOW_CTRL_BIT	       1
+/* one bit field, bit 1: | 0 : priotag host rcv allowed (default),
+ * 1: priotag host rcv not allowed
+ */
+#define ICSS_EMAC_FW_VLAN_FILTER_PRIOTAG_HOST_RCV_ALLOW_CTRL_BIT       2
+/* one bit field, bit 1: | 0 : skip sv vlan flow
+ * :1 : take sv vlan flow  (not applicable for dual emac )
+ */
+#define ICSS_EMAC_FW_VLAN_FILTER_SV_VLAN_FLOW_HOST_RCV_ALLOW_CTRL_BIT  3
+
+/* VLAN IDs */
+#define ICSS_EMAC_FW_VLAN_FILTER_PRIOTAG_VID			       0
+#define ICSS_EMAC_FW_VLAN_FILTER_VID_MIN			       0x0000
+#define ICSS_EMAC_FW_VLAN_FILTER_VID_MAX			       0x0FFF
+
+/* VLAN Filtering Commands */
+#define ICSS_EMAC_FW_VLAN_FILTER_ADD_VLAN_VID_CMD		       0x00
+#define ICSS_EMAC_FW_VLAN_FILTER_REMOVE_VLAN_VID_CMD		       0x01
+
+/* Switch defines for VLAN/MC filtering */
+/* SRAM
+ * VLAN filter defines & offsets
+ */
+#define ICSS_LRE_FW_VLAN_FLTR_CTRL_BYTE				 0x1FE
+/* one bit field | 0 : VLAN filter disabled
+ *		 | 1 : VLAN filter enabled
+ */
+#define ICSS_LRE_FW_VLAN_FLTR_TBL_BASE_ADDR			 0x200
+
+#endif /* ICSS_MULTICAST_FILTER_MM_H */
-- 
2.34.1
Re: [PATCH net-next v6 07/11] net: ti: prueth: Adds support for network filters for traffic control supported by PRU-ICSS
Posted by ALOK TIWARI 9 months, 1 week ago
> +	/* for LRE, it is a shared table. So lock the access */
> +	spin_lock_irqsave(&emac->addr_lock, flags);
> +
> +	/* VLAN filter table is 512 bytes (4096 bit) bitmap.
> +	 * Each bit controls enabling or disabling corresponding
> +	 * VID. Therefore byte index that controls a given VID is
> +	 * can calculated as vid / 8 and the bit within that byte
> +	 * that controls VID is given by vid % 8. Allow untagged
> +	 * frames to host by default.
> +	 */
> +	byte_index = vid / BITS_PER_BYTE;
> +	bit_index = vid % BITS_PER_BYTE;
> +	val = readb(ram + vlan_filter_tbl + byte_index);
> +	if (add)
> +		val |= BIT(bit_index);
> +	else
> +		val &= ~BIT(bit_index);
> +	writeb(val, ram + vlan_filter_tbl + byte_index);
> +
> +	spin_unlock_irqrestore(&emac->addr_lock, flags);
> +
> +	netdev_dbg(emac->ndev, "%s VID bit at index %d and bit %d\n",
> +		   add ? "Setting" : "Clearing", byte_index, bit_index);

VID bit at byte index

> +
> +	return 0;
> +}
> +
> +static int icssm_emac_ndo_vlan_rx_add_vid(struct net_device *dev,
> +					  __be16 proto, u16 vid)
> +{
> +	struct prueth_emac *emac = netdev_priv(dev);
> +
> +	return icssm_emac_add_del_vid(emac, true, proto, vid);
> +}
> +
> +static int icssm_emac_ndo_vlan_rx_kill_vid(struct net_device *dev,
> +					   __be16 proto, u16 vid)
> +{
> +	struct prueth_emac *emac = netdev_priv(dev);
> +
> +	return icssm_emac_add_del_vid(emac, false, proto, vid);
> +}
> +
> +static int icssm_emac_get_port_parent_id(struct net_device *dev,
> +					 struct netdev_phys_item_id *ppid)
> +{
> +	struct prueth_emac *emac = netdev_priv(dev);
> +	struct prueth *prueth = emac->prueth;
> +
> +	ppid->id_len = sizeof(prueth->base_mac);
> +	memcpy(&ppid->id, &prueth->base_mac, ppid->id_len);
> +
> +	return 0;
> +}
> +
> +static int icssm_emac_ndo_get_phys_port_name(struct net_device *ndev,
> +					     char *name, size_t len)
> +{
> +	struct prueth_emac *emac = netdev_priv(ndev);
> +	int err;
> +
> +	err = snprintf(name, len, "p%d", emac->port_id);
> +
> +	if (err >= len)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
>   static const struct net_device_ops emac_netdev_ops = {
>   	.ndo_open = icssm_emac_ndo_open,
>   	.ndo_stop = icssm_emac_ndo_stop,
>   	.ndo_start_xmit = icssm_emac_ndo_start_xmit,
> +	.ndo_set_mac_address = eth_mac_addr,
> +	.ndo_validate_addr = eth_validate_addr,
>   	.ndo_tx_timeout = icssm_emac_ndo_tx_timeout,
>   	.ndo_get_stats64 = icssm_emac_ndo_get_stats64,
> +	.ndo_set_rx_mode = icssm_emac_ndo_set_rx_mode,
>   	.ndo_eth_ioctl = icssm_emac_ndo_ioctl,
> +	.ndo_vlan_rx_add_vid = icssm_emac_ndo_vlan_rx_add_vid,
> +	.ndo_vlan_rx_kill_vid = icssm_emac_ndo_vlan_rx_kill_vid,
> +	.ndo_setup_tc = icssm_emac_ndo_setup_tc,
> +	.ndo_get_port_parent_id = icssm_emac_get_port_parent_id,
> +	.ndo_get_phys_port_name = icssm_emac_ndo_get_phys_port_name,
>   };
>   
>   /* get emac_port corresponding to eth_node name */
> @@ -1567,6 +1865,7 @@ static int icssm_prueth_netdev_init(struct prueth *prueth,
>   	emac->prueth = prueth;
>   	emac->ndev = ndev;
>   	emac->port_id = port;
> +	memset(&emac->mc_filter_mask[0], 0xff, ETH_ALEN); /* default mask */
>   
>   	/* by default eth_type is EMAC */
>   	switch (port) {
> @@ -1608,7 +1907,9 @@ static int icssm_prueth_netdev_init(struct prueth *prueth,
>   		dev_err(prueth->dev, "could not get ptp tx irq. Skipping PTP support\n");
>   	}
>   
> +	spin_lock_init(&emac->lock);
>   	spin_lock_init(&emac->ptp_skb_lock);
> +	spin_lock_init(&emac->addr_lock);
>   
>   	/* get mac address from DT and set private and netdev addr */
>   	ret = of_get_ethdev_address(eth_node, ndev);
> @@ -1637,6 +1938,10 @@ static int icssm_prueth_netdev_init(struct prueth *prueth,
>   	phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_Pause_BIT);
>   	phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_Asym_Pause_BIT);
>   
> +	ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_TC;
> +
> +	ndev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
> +
>   	ndev->netdev_ops = &emac_netdev_ops;
>   	ndev->ethtool_ops = &emac_ethtool_ops;
>   
> @@ -1689,6 +1994,7 @@ static int icssm_prueth_probe(struct platform_device *pdev)
>   	platform_set_drvdata(pdev, prueth);
>   	prueth->dev = dev;
>   	prueth->fw_data = device_get_match_data(dev);
> +	prueth->fw_offsets = &fw_offsets_v2_1;
>   
>   	eth_ports_node = of_get_child_by_name(np, "ethernet-ports");
>   	if (!eth_ports_node)
> @@ -1875,6 +2181,8 @@ static int icssm_prueth_probe(struct platform_device *pdev)
>   			prueth->emac[PRUETH_MAC1]->ndev;
>   	}
>   
> +	eth_random_addr(prueth->base_mac);
> +
>   	dev_info(dev, "TI PRU ethernet driver initialized: %s EMAC mode\n",
>   		 (!eth0_node || !eth1_node) ? "single" : "dual");
>   
> diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.h b/drivers/net/ethernet/ti/icssm/icssm_prueth.h
> index 1709b3b6c2be..8a5f1647466a 100644
> --- a/drivers/net/ethernet/ti/icssm/icssm_prueth.h
> +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.h
> @@ -28,6 +28,9 @@
>   #define EMAC_MAX_FRM_SUPPORT (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN + \
>   			      ICSSM_LRE_TAG_SIZE)
>   
> +/* default timer for NSP and HSR/PRP */
> +#define PRUETH_NSP_TIMER_MS	(100) /* Refresh NSP counters every 100ms */
> +
>   #define PRUETH_REG_DUMP_VER		1
>   
>   /* Encoding: 32-16: Reserved, 16-8: Reg dump version, 8-0: Ethertype  */

remove extra ' ' after Ethertype

> @@ -293,6 +296,29 @@ enum prueth_mem {
>   	PRUETH_MEM_MAX,
>   };
>   
> +/* Firmware offsets/size information */
> +struct prueth_fw_offsets {
> +	u32 index_array_offset;
> +	u32 bin_array_offset;
> +	u32 nt_array_offset;
> +	u32 index_array_loc;
> +	u32 bin_array_loc;
> +	u32 nt_array_loc;
> +	u32 index_array_max_entries;
> +	u32 bin_array_max_entries;
> +	u32 nt_array_max_entries;
> +	u32 vlan_ctrl_byte;
> +	u32 vlan_filter_tbl;
> +	u32 mc_ctrl_byte;
> +	u32 mc_filter_mask;
> +	u32 mc_filter_tbl;
> +	/* IEP wrap is used in the rx packet ordering logic and
> +	 * is different for ICSSM v1.0 vs 2.1
> +	 */
> +	u32 iep_wrap;
> +	u16 hash_mask;
> +};
> +
[clip]
> @@ -0,0 +1,120 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +/* Copyright (C) 2015-2021 Texas Instruments Incorporated - https://urldefense.com/v3/__https://www.ti.com__;!!ACWV5N9M2RV99hQ!Pnt8LQPwsRI73TtUPzBpwVw_Cn90DbuNXinXJ5m2isPHfFxjNTp4JBlr6UedPapFerELKSzV4SFNoiUfE1xa8g$
> + *
> + * This file contains VLAN/Multicast filtering feature memory map
> + *
> + */
> +
> +#ifndef ICSS_VLAN_MULTICAST_FILTER_MM_H
> +#define ICSS_VLAN_MULTICAST_FILTER_MM_H
> +
> +/*  VLAN/Multicast filter defines & offsets,
> + *  present on both PRU0 and PRU1 DRAM

remove extra ' '

> + */
> +
> +/* Feature enable/disable values for multicast filtering */
> +#define ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_DISABLED		0x00
> +#define ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_ENABLED		0x01
> +
> +/* Feature enable/disable values  for VLAN filtering */

remove extra ' ' after values

> +#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_DISABLED			0x00
> +#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_ENABLED			0x01
> +
> +/* Add/remove multicast mac id for filtering bin */
> +#define ICSS_EMAC_FW_MULTICAST_FILTER_HOST_RCV_ALLOWED		0x01
> +#define ICSS_EMAC_FW_MULTICAST_FILTER_HOST_RCV_NOT_ALLOWED	0x00
> +
> +/* Default HASH value for the multicast filtering Mask */
> +#define ICSS_EMAC_FW_MULTICAST_FILTER_INIT_VAL			0xFF
> +
> +/* Size requirements for Multicast filtering feature */
> +#define ICSS_EMAC_FW_MULTICAST_TABLE_SIZE_BYTES			       256
> +#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_SIZE_BYTES			 6
> +#define ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_SIZE_BYTES			 1
> +#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OVERRIDE_STATUS_SIZE_BYTES	 1
> +#define ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_SIZE_BYTES		 4
> +
> +/* Size requirements for VLAN filtering feature : 4096 bits = 512 bytes */
> +#define ICSS_EMAC_FW_VLAN_FILTER_TABLE_SIZE_BYTES		       512
> +#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_SIZE_BYTES			 1
> +#define ICSS_EMAC_FW_VLAN_FILTER_DROP_CNT_SIZE_BYTES			 4
> +
> +/* Mask override set status */
> +#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OVERRIDE_SET			 1
> +/* Mask override not set status */
> +#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OVERRIDE_NOT_SET		 0
> +/* 6 bytes HASH Mask for the MAC */
> +#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OFFSET	  0xF4
> +/* 0 -> multicast filtering disabled | 1 -> multicast filtering enabled */
> +#define ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_OFFSET	\
> +	(ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OFFSET +	\
> +	 ICSS_EMAC_FW_MULTICAST_FILTER_MASK_SIZE_BYTES)
> +/* Status indicating if the HASH override is done or not: 0: no, 1: yes */
> +#define ICSS_EMAC_FW_MULTICAST_FILTER_OVERRIDE_STATUS	\
> +	(ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_OFFSET +	\
> +	 ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_SIZE_BYTES)
> +/* Multicast drop statistics */
> +#define ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_OFFSET	\
> +	(ICSS_EMAC_FW_MULTICAST_FILTER_OVERRIDE_STATUS +\
> +	 ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OVERRIDE_STATUS_SIZE_BYTES)
> +/* Multicast table */
> +#define ICSS_EMAC_FW_MULTICAST_FILTER_TABLE		\
> +	(ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_OFFSET +\
> +	 ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_SIZE_BYTES)
> +
> +/* Multicast filter defines & offsets for LRE
> + */
> +#define ICSS_LRE_FW_MULTICAST_TABLE_SEARCH_OP_CONTROL_BIT	0xE0
> +/* one byte field :
> + * 0 -> multicast filtering disabled
> + * 1 -> multicast filtering enabled
> + */
> +#define ICSS_LRE_FW_MULTICAST_FILTER_MASK			 0xE4
> +#define ICSS_LRE_FW_MULTICAST_FILTER_TABLE			 0x100
> +
> +/* VLAN table Offsets */
> +#define ICSS_EMAC_FW_VLAN_FLTR_TBL_BASE_ADDR		 0x200
> +#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_BITMAP_OFFSET	 0xEF
> +#define ICSS_EMAC_FW_VLAN_FILTER_DROP_CNT_OFFSET	\
> +	(ICSS_EMAC_FW_VLAN_FILTER_CTRL_BITMAP_OFFSET +	\
> +	 ICSS_EMAC_FW_VLAN_FILTER_CTRL_SIZE_BYTES)
> +
> +/* VLAN filter Control Bit maps */
> +/* one bit field, bit 0: | 0 : VLAN filter disabled (default),
> + * 1: VLAN filter enabled
> + */
> +#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_ENABLE_BIT		       0
> +/* one bit field, bit 1: | 0 : untagged host rcv allowed (default),
> + * 1: untagged host rcv not allowed
> + */
> +#define ICSS_EMAC_FW_VLAN_FILTER_UNTAG_HOST_RCV_ALLOW_CTRL_BIT	       1
> +/* one bit field, bit 1: | 0 : priotag host rcv allowed (default),
> + * 1: priotag host rcv not allowed
> + */
> +#define ICSS_EMAC_FW_VLAN_FILTER_PRIOTAG_HOST_RCV_ALLOW_CTRL_BIT       2
> +/* one bit field, bit 1: | 0 : skip sv vlan flow
> + * :1 : take sv vlan flow  (not applicable for dual emac )
> + */
> +#define ICSS_EMAC_FW_VLAN_FILTER_SV_VLAN_FLOW_HOST_RCV_ALLOW_CTRL_BIT  3
> +
> +/* VLAN IDs */
> +#define ICSS_EMAC_FW_VLAN_FILTER_PRIOTAG_VID			       0
> +#define ICSS_EMAC_FW_VLAN_FILTER_VID_MIN			       0x0000
> +#define ICSS_EMAC_FW_VLAN_FILTER_VID_MAX			       0x0FFF
> +
> +/* VLAN Filtering Commands */
> +#define ICSS_EMAC_FW_VLAN_FILTER_ADD_VLAN_VID_CMD		       0x00
> +#define ICSS_EMAC_FW_VLAN_FILTER_REMOVE_VLAN_VID_CMD		       0x01
> +
> +/* Switch defines for VLAN/MC filtering */
> +/* SRAM
> + * VLAN filter defines & offsets
> + */
> +#define ICSS_LRE_FW_VLAN_FLTR_CTRL_BYTE				 0x1FE

lowercase hex please, all place.

> +/* one bit field | 0 : VLAN filter disabled
> + *		 | 1 : VLAN filter enabled
> + */
> +#define ICSS_LRE_FW_VLAN_FLTR_TBL_BASE_ADDR			 0x200
> +
> +#endif /* ICSS_MULTICAST_FILTER_MM_H */


Thanks,
Alok
Re: [PATCH net-next v6 07/11] net: ti: prueth: Adds support for network filters for traffic control supported by PRU-ICSS
Posted by Parvathi Pudi 9 months, 1 week ago
Hi,

>> +	/* for LRE, it is a shared table. So lock the access */
>> +	spin_lock_irqsave(&emac->addr_lock, flags);
>> +
>> +	/* VLAN filter table is 512 bytes (4096 bit) bitmap.
>> +	 * Each bit controls enabling or disabling corresponding
>> +	 * VID. Therefore byte index that controls a given VID is
>> +	 * can calculated as vid / 8 and the bit within that byte
>> +	 * that controls VID is given by vid % 8. Allow untagged
>> +	 * frames to host by default.
>> +	 */
>> +	byte_index = vid / BITS_PER_BYTE;
>> +	bit_index = vid % BITS_PER_BYTE;
>> +	val = readb(ram + vlan_filter_tbl + byte_index);
>> +	if (add)
>> +		val |= BIT(bit_index);
>> +	else
>> +		val &= ~BIT(bit_index);
>> +	writeb(val, ram + vlan_filter_tbl + byte_index);
>> +
>> +	spin_unlock_irqrestore(&emac->addr_lock, flags);
>> +
>> +	netdev_dbg(emac->ndev, "%s VID bit at index %d and bit %d\n",
>> +		   add ? "Setting" : "Clearing", byte_index, bit_index);
> 
> VID bit at byte index
> 
>> +
>> +	return 0;
>> +}
>> +
>> +static int icssm_emac_ndo_vlan_rx_add_vid(struct net_device *dev,
>> +					  __be16 proto, u16 vid)
>> +{
>> +	struct prueth_emac *emac = netdev_priv(dev);
>> +
>> +	return icssm_emac_add_del_vid(emac, true, proto, vid);
>> +}
>> +
>> +static int icssm_emac_ndo_vlan_rx_kill_vid(struct net_device *dev,
>> +					   __be16 proto, u16 vid)
>> +{
>> +	struct prueth_emac *emac = netdev_priv(dev);
>> +
>> +	return icssm_emac_add_del_vid(emac, false, proto, vid);
>> +}
>> +
>> +static int icssm_emac_get_port_parent_id(struct net_device *dev,
>> +					 struct netdev_phys_item_id *ppid)
>> +{
>> +	struct prueth_emac *emac = netdev_priv(dev);
>> +	struct prueth *prueth = emac->prueth;
>> +
>> +	ppid->id_len = sizeof(prueth->base_mac);
>> +	memcpy(&ppid->id, &prueth->base_mac, ppid->id_len);
>> +
>> +	return 0;
>> +}
>> +
>> +static int icssm_emac_ndo_get_phys_port_name(struct net_device *ndev,
>> +					     char *name, size_t len)
>> +{
>> +	struct prueth_emac *emac = netdev_priv(ndev);
>> +	int err;
>> +
>> +	err = snprintf(name, len, "p%d", emac->port_id);
>> +
>> +	if (err >= len)
>> +		return -EINVAL;
>> +
>> +	return 0;
>> +}
>> +
>>   static const struct net_device_ops emac_netdev_ops = {
>>   	.ndo_open = icssm_emac_ndo_open,
>>   	.ndo_stop = icssm_emac_ndo_stop,
>>   	.ndo_start_xmit = icssm_emac_ndo_start_xmit,
>> +	.ndo_set_mac_address = eth_mac_addr,
>> +	.ndo_validate_addr = eth_validate_addr,
>>   	.ndo_tx_timeout = icssm_emac_ndo_tx_timeout,
>>   	.ndo_get_stats64 = icssm_emac_ndo_get_stats64,
>> +	.ndo_set_rx_mode = icssm_emac_ndo_set_rx_mode,
>>   	.ndo_eth_ioctl = icssm_emac_ndo_ioctl,
>> +	.ndo_vlan_rx_add_vid = icssm_emac_ndo_vlan_rx_add_vid,
>> +	.ndo_vlan_rx_kill_vid = icssm_emac_ndo_vlan_rx_kill_vid,
>> +	.ndo_setup_tc = icssm_emac_ndo_setup_tc,
>> +	.ndo_get_port_parent_id = icssm_emac_get_port_parent_id,
>> +	.ndo_get_phys_port_name = icssm_emac_ndo_get_phys_port_name,
>>   };
>>   
>>   /* get emac_port corresponding to eth_node name */
>> @@ -1567,6 +1865,7 @@ static int icssm_prueth_netdev_init(struct prueth *prueth,
>>   	emac->prueth = prueth;
>>   	emac->ndev = ndev;
>>   	emac->port_id = port;
>> +	memset(&emac->mc_filter_mask[0], 0xff, ETH_ALEN); /* default mask */
>>   
>>   	/* by default eth_type is EMAC */
>>   	switch (port) {
>> @@ -1608,7 +1907,9 @@ static int icssm_prueth_netdev_init(struct prueth *prueth,
>>   		dev_err(prueth->dev, "could not get ptp tx irq. Skipping PTP support\n");
>>   	}
>>   
>> +	spin_lock_init(&emac->lock);
>>   	spin_lock_init(&emac->ptp_skb_lock);
>> +	spin_lock_init(&emac->addr_lock);
>>   
>>   	/* get mac address from DT and set private and netdev addr */
>>   	ret = of_get_ethdev_address(eth_node, ndev);
>> @@ -1637,6 +1938,10 @@ static int icssm_prueth_netdev_init(struct prueth
>> *prueth,
>>   	phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_Pause_BIT);
>>   	phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_Asym_Pause_BIT);
>>   
>> +	ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_TC;
>> +
>> +	ndev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
>> +
>>   	ndev->netdev_ops = &emac_netdev_ops;
>>   	ndev->ethtool_ops = &emac_ethtool_ops;
>>   
>> @@ -1689,6 +1994,7 @@ static int icssm_prueth_probe(struct platform_device
>> *pdev)
>>   	platform_set_drvdata(pdev, prueth);
>>   	prueth->dev = dev;
>>   	prueth->fw_data = device_get_match_data(dev);
>> +	prueth->fw_offsets = &fw_offsets_v2_1;
>>   
>>   	eth_ports_node = of_get_child_by_name(np, "ethernet-ports");
>>   	if (!eth_ports_node)
>> @@ -1875,6 +2181,8 @@ static int icssm_prueth_probe(struct platform_device
>> *pdev)
>>   			prueth->emac[PRUETH_MAC1]->ndev;
>>   	}
>>   
>> +	eth_random_addr(prueth->base_mac);
>> +
>>   	dev_info(dev, "TI PRU ethernet driver initialized: %s EMAC mode\n",
>>   		 (!eth0_node || !eth1_node) ? "single" : "dual");
>>   
>> diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.h
>> b/drivers/net/ethernet/ti/icssm/icssm_prueth.h
>> index 1709b3b6c2be..8a5f1647466a 100644
>> --- a/drivers/net/ethernet/ti/icssm/icssm_prueth.h
>> +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.h
>> @@ -28,6 +28,9 @@
>>   #define EMAC_MAX_FRM_SUPPORT (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN + \
>>   			      ICSSM_LRE_TAG_SIZE)
>>   
>> +/* default timer for NSP and HSR/PRP */
>> +#define PRUETH_NSP_TIMER_MS	(100) /* Refresh NSP counters every 100ms */
>> +
>>   #define PRUETH_REG_DUMP_VER		1
>>   
>>   /* Encoding: 32-16: Reserved, 16-8: Reg dump version, 8-0: Ethertype  */
> 
> remove extra ' ' after Ethertype
> 
>> @@ -293,6 +296,29 @@ enum prueth_mem {
>>   	PRUETH_MEM_MAX,
>>   };
>>   
>> +/* Firmware offsets/size information */
>> +struct prueth_fw_offsets {
>> +	u32 index_array_offset;
>> +	u32 bin_array_offset;
>> +	u32 nt_array_offset;
>> +	u32 index_array_loc;
>> +	u32 bin_array_loc;
>> +	u32 nt_array_loc;
>> +	u32 index_array_max_entries;
>> +	u32 bin_array_max_entries;
>> +	u32 nt_array_max_entries;
>> +	u32 vlan_ctrl_byte;
>> +	u32 vlan_filter_tbl;
>> +	u32 mc_ctrl_byte;
>> +	u32 mc_filter_mask;
>> +	u32 mc_filter_tbl;
>> +	/* IEP wrap is used in the rx packet ordering logic and
>> +	 * is different for ICSSM v1.0 vs 2.1
>> +	 */
>> +	u32 iep_wrap;
>> +	u16 hash_mask;
>> +};
>> +
> [clip]
>> @@ -0,0 +1,120 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +
>> +/* Copyright (C) 2015-2021 Texas Instruments Incorporated -
>> https://urldefense.com/v3/__https://www.ti.com__;!!ACWV5N9M2RV99hQ!Pnt8LQPwsRI73TtUPzBpwVw_Cn90DbuNXinXJ5m2isPHfFxjNTp4JBlr6UedPapFerELKSzV4SFNoiUfE1xa8g$
>> + *
>> + * This file contains VLAN/Multicast filtering feature memory map
>> + *
>> + */
>> +
>> +#ifndef ICSS_VLAN_MULTICAST_FILTER_MM_H
>> +#define ICSS_VLAN_MULTICAST_FILTER_MM_H
>> +
>> +/*  VLAN/Multicast filter defines & offsets,
>> + *  present on both PRU0 and PRU1 DRAM
> 
> remove extra ' '
> 
>> + */
>> +
>> +/* Feature enable/disable values for multicast filtering */
>> +#define ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_DISABLED		0x00
>> +#define ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_ENABLED		0x01
>> +
>> +/* Feature enable/disable values  for VLAN filtering */
> 
> remove extra ' ' after values
> 
>> +#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_DISABLED			0x00
>> +#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_ENABLED			0x01
>> +
>> +/* Add/remove multicast mac id for filtering bin */
>> +#define ICSS_EMAC_FW_MULTICAST_FILTER_HOST_RCV_ALLOWED		0x01
>> +#define ICSS_EMAC_FW_MULTICAST_FILTER_HOST_RCV_NOT_ALLOWED	0x00
>> +
>> +/* Default HASH value for the multicast filtering Mask */
>> +#define ICSS_EMAC_FW_MULTICAST_FILTER_INIT_VAL			0xFF
>> +
>> +/* Size requirements for Multicast filtering feature */
>> +#define ICSS_EMAC_FW_MULTICAST_TABLE_SIZE_BYTES			       256
>> +#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_SIZE_BYTES			 6
>> +#define ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_SIZE_BYTES			 1
>> +#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OVERRIDE_STATUS_SIZE_BYTES	 1
>> +#define ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_SIZE_BYTES		 4
>> +
>> +/* Size requirements for VLAN filtering feature : 4096 bits = 512 bytes */
>> +#define ICSS_EMAC_FW_VLAN_FILTER_TABLE_SIZE_BYTES		       512
>> +#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_SIZE_BYTES			 1
>> +#define ICSS_EMAC_FW_VLAN_FILTER_DROP_CNT_SIZE_BYTES			 4
>> +
>> +/* Mask override set status */
>> +#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OVERRIDE_SET			 1
>> +/* Mask override not set status */
>> +#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OVERRIDE_NOT_SET		 0
>> +/* 6 bytes HASH Mask for the MAC */
>> +#define ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OFFSET	  0xF4
>> +/* 0 -> multicast filtering disabled | 1 -> multicast filtering enabled */
>> +#define ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_OFFSET	\
>> +	(ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OFFSET +	\
>> +	 ICSS_EMAC_FW_MULTICAST_FILTER_MASK_SIZE_BYTES)
>> +/* Status indicating if the HASH override is done or not: 0: no, 1: yes */
>> +#define ICSS_EMAC_FW_MULTICAST_FILTER_OVERRIDE_STATUS	\
>> +	(ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_OFFSET +	\
>> +	 ICSS_EMAC_FW_MULTICAST_FILTER_CTRL_SIZE_BYTES)
>> +/* Multicast drop statistics */
>> +#define ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_OFFSET	\
>> +	(ICSS_EMAC_FW_MULTICAST_FILTER_OVERRIDE_STATUS +\
>> +	 ICSS_EMAC_FW_MULTICAST_FILTER_MASK_OVERRIDE_STATUS_SIZE_BYTES)
>> +/* Multicast table */
>> +#define ICSS_EMAC_FW_MULTICAST_FILTER_TABLE		\
>> +	(ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_OFFSET +\
>> +	 ICSS_EMAC_FW_MULTICAST_FILTER_DROP_CNT_SIZE_BYTES)
>> +
>> +/* Multicast filter defines & offsets for LRE
>> + */
>> +#define ICSS_LRE_FW_MULTICAST_TABLE_SEARCH_OP_CONTROL_BIT	0xE0
>> +/* one byte field :
>> + * 0 -> multicast filtering disabled
>> + * 1 -> multicast filtering enabled
>> + */
>> +#define ICSS_LRE_FW_MULTICAST_FILTER_MASK			 0xE4
>> +#define ICSS_LRE_FW_MULTICAST_FILTER_TABLE			 0x100
>> +
>> +/* VLAN table Offsets */
>> +#define ICSS_EMAC_FW_VLAN_FLTR_TBL_BASE_ADDR		 0x200
>> +#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_BITMAP_OFFSET	 0xEF
>> +#define ICSS_EMAC_FW_VLAN_FILTER_DROP_CNT_OFFSET	\
>> +	(ICSS_EMAC_FW_VLAN_FILTER_CTRL_BITMAP_OFFSET +	\
>> +	 ICSS_EMAC_FW_VLAN_FILTER_CTRL_SIZE_BYTES)
>> +
>> +/* VLAN filter Control Bit maps */
>> +/* one bit field, bit 0: | 0 : VLAN filter disabled (default),
>> + * 1: VLAN filter enabled
>> + */
>> +#define ICSS_EMAC_FW_VLAN_FILTER_CTRL_ENABLE_BIT		       0
>> +/* one bit field, bit 1: | 0 : untagged host rcv allowed (default),
>> + * 1: untagged host rcv not allowed
>> + */
>> +#define ICSS_EMAC_FW_VLAN_FILTER_UNTAG_HOST_RCV_ALLOW_CTRL_BIT	       1
>> +/* one bit field, bit 1: | 0 : priotag host rcv allowed (default),
>> + * 1: priotag host rcv not allowed
>> + */
>> +#define ICSS_EMAC_FW_VLAN_FILTER_PRIOTAG_HOST_RCV_ALLOW_CTRL_BIT       2
>> +/* one bit field, bit 1: | 0 : skip sv vlan flow
>> + * :1 : take sv vlan flow  (not applicable for dual emac )
>> + */
>> +#define ICSS_EMAC_FW_VLAN_FILTER_SV_VLAN_FLOW_HOST_RCV_ALLOW_CTRL_BIT  3
>> +
>> +/* VLAN IDs */
>> +#define ICSS_EMAC_FW_VLAN_FILTER_PRIOTAG_VID			       0
>> +#define ICSS_EMAC_FW_VLAN_FILTER_VID_MIN			       0x0000
>> +#define ICSS_EMAC_FW_VLAN_FILTER_VID_MAX			       0x0FFF
>> +
>> +/* VLAN Filtering Commands */
>> +#define ICSS_EMAC_FW_VLAN_FILTER_ADD_VLAN_VID_CMD		       0x00
>> +#define ICSS_EMAC_FW_VLAN_FILTER_REMOVE_VLAN_VID_CMD		       0x01
>> +
>> +/* Switch defines for VLAN/MC filtering */
>> +/* SRAM
>> + * VLAN filter defines & offsets
>> + */
>> +#define ICSS_LRE_FW_VLAN_FLTR_CTRL_BYTE				 0x1FE
> 
> lowercase hex please, all place.
> 

Thank you for the feedback.

We have addressed all the comments provided, except for the one regarding
hexadecimal format, where we need some clarity.

Is there any specific style guide or convention that mandates lowercase
hexadecimal formatting? We've observed that other drivers in the code base
consistently use uppercase hex values, and we've followed the same convention
throughout in our implementation.


Thanks and Regards,
Parvathi.