linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Satha Koteswara Rao <satha.rao@caviumnetworks.com>
To: <linux-kernel@vger.kernel.org>
Cc: <sgoutham@cavium.com>, <rric@kernel.org>, <davem@davemloft.net>,
	<david.daney@cavium.com>, <rvatsavayi@caviumnetworks.com>,
	<derek.chickles@caviumnetworks.com>,
	<satha.rao@caviumnetworks.com>, <philip.romanov@cavium.com>,
	<netdev@vger.kernel.org>, <linux-arm-kernel@lists.infradead.org>
Subject: [RFC PATCH 7/7] Get notifications from PF driver and configure filter block based on request data
Date: Wed, 21 Dec 2016 14:16:51 +0530	[thread overview]
Message-ID: <1482310011-1862-8-git-send-email-satha.rao@caviumnetworks.com> (raw)
In-Reply-To: <1482310011-1862-1-git-send-email-satha.rao@caviumnetworks.com>

---
 drivers/net/ethernet/cavium/thunder/pf_filter.c | 1678 +++++++++++++++++++++++
 1 file changed, 1678 insertions(+)
 create mode 100644 drivers/net/ethernet/cavium/thunder/pf_filter.c

diff --git a/drivers/net/ethernet/cavium/thunder/pf_filter.c b/drivers/net/ethernet/cavium/thunder/pf_filter.c
new file mode 100644
index 0000000..5a04da6
--- /dev/null
+++ b/drivers/net/ethernet/cavium/thunder/pf_filter.c
@@ -0,0 +1,1678 @@
+/*
+ * Copyright (C) 2015 Cavium, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/version.h>
+#include <linux/proc_fs.h>
+#include <linux/device.h>
+#include <linux/mman.h>
+#include <linux/uaccess.h>
+#include <linux/delay.h>
+#include <linux/cdev.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include "pf_globals.h"
+#include "pf_locals.h"
+#include "nic.h"
+
+u32 intr_to_ingressgrp[MAX_NUMNODES][TNS_MAC_FILTER_MAX_SYS_PORTS];
+struct vf_register_s vf_reg_data[MAX_NUMNODES][TNS_MAX_VF];
+struct ing_grp_gblvif ingressgrp_gblvif[MAX_NUMNODES][TNS_MAX_INGRESS_GROUP];
+
+u32 macfilter_freeindex[MAX_NUMNODES];
+u32 vlanfilter_freeindex[MAX_NUMNODES];
+
+int tns_filter_valid_entry(int node, int req_type, int vf, int vlan)
+{
+	if (req_type == NIC_MBOX_MSG_UC_MC) {
+		if (vf_reg_data[node][vf].vf_in_mcast_promis ||
+		    (macfilter_freeindex[node] >= TNS_MAC_FILTER_MAX_INDEX))
+			return TNS_ERR_MAX_LIMIT;
+		if (vf_reg_data[node][vf].filter_count >= TNS_MAX_MAC_PER_VF) {
+			tns_enable_mcast_promis(node, vf);
+			vf_reg_data[node][vf].vf_in_mcast_promis = 1;
+			return TNS_ERR_MAX_LIMIT;
+		}
+	} else if (req_type == NIC_MBOX_MSG_VLAN ||
+		   req_type == NIC_MBOX_MSG_ADMIN_VLAN) {
+		if (vf_reg_data[node][vf].vlan_count >= TNS_MAX_VLAN_PER_VF)
+			return TNS_ERR_MAX_LIMIT;
+
+		if (vlanfilter_freeindex[node] >= TNS_VLAN_FILTER_MAX_INDEX) {
+			int ret;
+			struct vlan_filter_entry tbl_entry;
+			int vlan_tbl_idx = -1;
+
+			tbl_entry.key.is_valid = 1;
+			tbl_entry.key.key_type.key_value  = 0x0ull;
+			tbl_entry.mask.key_type.key_value = ~0x0ull;
+			tbl_entry.key.key_type.s.ingress_grp =
+				intr_to_ingressgrp[node][vf];
+			tbl_entry.mask.key_type.s.ingress_grp = 0x0;
+			tbl_entry.key.key_type.s.vlan = vlan;
+			tbl_entry.mask.key_type.s.vlan = 0x0;
+
+			ret = filter_tbl_lookup(node, VLAN_FILTER_TABLE,
+						&tbl_entry, &vlan_tbl_idx);
+			if (ret || vlan_tbl_idx == -1)
+				return TNS_ERR_MAX_LIMIT;
+		}
+	} else {
+		filter_dbg(FERR, "Invalid Request %d VF %d\n", req_type, vf);
+	}
+
+	return TNS_NO_ERR;
+}
+
+int dump_port_cfg_etry(struct itt_entry_s *port_cfg_entry)
+{
+	filter_dbg(FINFO, "PortConfig Entry\n");
+	filter_dbg(FINFO, "pkt_dir:			0x%x\n",
+		   port_cfg_entry->pkt_dir);
+	filter_dbg(FINFO, "is_admin_vlan_enabled:	0x%x\n",
+		   port_cfg_entry->is_admin_vlan_enabled);
+	filter_dbg(FINFO, "default_evif:		0x%x\n",
+		   port_cfg_entry->default_evif);
+	filter_dbg(FINFO, "admin_vlan:			0x%x\n",
+		   port_cfg_entry->admin_vlan);
+
+	return TNS_NO_ERR;
+}
+
+int dump_evif_entry(struct evif_entry *evif_dat)
+{
+	filter_dbg(FINFO, "EVIF Entry\n");
+	filter_dbg(FINFO, "prt_bmap_136_73: 0x%llx\n",
+		   evif_dat->prt_bmap_136_73);
+	filter_dbg(FINFO, "prt_bmap_72_9:   0x%llx\n",
+		   evif_dat->prt_bmap_72_9);
+	filter_dbg(FINFO, "prt_bmap_8:      0x%x\n", evif_dat->prt_bmap_8);
+	filter_dbg(FINFO, "mre_ptr:         0x%x\n", evif_dat->mre_ptr);
+	filter_dbg(FINFO, "insert_ptr2:     0x%x\n", evif_dat->insert_ptr2);
+	filter_dbg(FINFO, "insert_ptr1:     0x%x\n", evif_dat->insert_ptr1);
+	filter_dbg(FINFO, "insert_ptr0:     0x%x\n", evif_dat->insert_ptr0);
+	filter_dbg(FINFO, "data31_0:        0x%x\n", evif_dat->data31_0);
+	filter_dbg(FINFO, "rewrite_ptr1:    0x%x\n", evif_dat->rewrite_ptr1);
+	filter_dbg(FINFO, "rewrite_ptr0:    0x%x\n", evif_dat->rewrite_ptr0);
+	filter_dbg(FINFO, "prt_bmap7_0:     0x%x\n", evif_dat->prt_bmap7_0);
+	filter_dbg(FINFO, "q_mirror_en:     0x%x\n", evif_dat->q_mirror_en);
+	filter_dbg(FINFO, "mirror_en:       0x%x\n", evif_dat->mirror_en);
+	filter_dbg(FINFO, "mtu_prf:         0x%x\n", evif_dat->mtu_prf);
+	filter_dbg(FINFO, "truncate:        0x%x\n", evif_dat->truncate);
+	filter_dbg(FINFO, "rsp_type:        0x%x\n", evif_dat->rsp_type);
+
+	return TNS_NO_ERR;
+}
+
+static inline int validate_port(int port_num)
+{
+	if (port_num < 0 && port_num >= TNS_MAC_FILTER_MAX_SYS_PORTS) {
+		filter_dbg(FERR, "%s Invalid Port: %d (Valid range 0-136)\n",
+			   __func__, port_num);
+		return TNS_ERR_WRONG_PORT_NUMBER;
+	}
+	return TNS_NO_ERR;
+}
+
+int enable_port(int port_num, struct evif_entry *tbl_entry)
+{
+	s64 port_base;
+
+	if (validate_port(port_num))
+		return TNS_ERR_WRONG_PORT_NUMBER;
+
+	if (port_num < 8) {
+		tbl_entry->prt_bmap7_0 = tbl_entry->prt_bmap7_0 |
+					 (0x1 << port_num);
+	} else if (port_num == 8) {
+		tbl_entry->prt_bmap_8 = 1;
+	} else if (port_num <= 72) {
+		port_base = port_num - 9;
+		tbl_entry->prt_bmap_72_9 = tbl_entry->prt_bmap_72_9 |
+						(0x1ull << port_base);
+	} else if (port_num <= TNS_MAC_FILTER_MAX_SYS_PORTS) {
+		port_base = port_num - 73;
+		tbl_entry->prt_bmap_136_73 = tbl_entry->prt_bmap_136_73 |
+						(0x1ull << port_base);
+	}
+
+	return TNS_NO_ERR;
+}
+
+int disable_port(int port_num, struct evif_entry *tbl_entry)
+{
+	s64 port_base;
+
+	if (validate_port(port_num))
+		return TNS_ERR_WRONG_PORT_NUMBER;
+
+	if (port_num < 8) {
+		tbl_entry->prt_bmap7_0 = tbl_entry->prt_bmap7_0 &
+					 ~(0x1 << port_num);
+	} else if (port_num == 8) {
+		tbl_entry->prt_bmap_8 = 0;
+	} else if (port_num <= 72) {
+		port_base = port_num - 9;
+		tbl_entry->prt_bmap_72_9 = tbl_entry->prt_bmap_72_9 &
+						~(0x1ull << port_base);
+	} else if (port_num <= TNS_MAC_FILTER_MAX_SYS_PORTS) {
+		port_base = port_num - 73;
+		tbl_entry->prt_bmap_136_73 = tbl_entry->prt_bmap_136_73 &
+						~(0x1ull << port_base);
+	}
+
+	return TNS_NO_ERR;
+}
+
+int disable_all_ports(struct evif_entry *tbl_entry)
+{
+	tbl_entry->prt_bmap_136_73 = 0x0ull;
+	tbl_entry->prt_bmap_72_9 = 0x0ull;
+	tbl_entry->prt_bmap_8 = 0x0;
+	tbl_entry->prt_bmap7_0 = 0x0;
+
+	return TNS_NO_ERR;
+}
+
+int is_vlan_port_enabled(int vf, vlan_port_bitmap_t vlan_vif)
+{
+	int port_base = (vf / 8), port_offset = (vf % 8);
+
+	if (validate_port(vf))
+		return TNS_ERR_WRONG_PORT_NUMBER;
+
+	if (vlan_vif[port_base] & (1 << port_offset))
+		return 1;
+
+	return 0;
+}
+
+int enable_vlan_port(int port_num, vlan_port_bitmap_t vlan_vif)
+{
+	int port_base = (port_num / 8), port_offset = (port_num % 8);
+
+	if (validate_port(port_num))
+		return TNS_ERR_WRONG_PORT_NUMBER;
+
+	vlan_vif[port_base] = vlan_vif[port_base] | (1 << port_offset);
+
+	return TNS_NO_ERR;
+}
+
+int disable_vlan_port(int port_num, vlan_port_bitmap_t vlan_vif)
+{
+	int port_base = (port_num / 8), port_offset = (port_num % 8);
+
+	if (validate_port(port_num))
+		return TNS_ERR_WRONG_PORT_NUMBER;
+
+	vlan_vif[port_base] = vlan_vif[port_base] & ~(1 << port_offset);
+
+	return TNS_NO_ERR;
+}
+
+int disable_vlan_vif_ports(vlan_port_bitmap_t vlan_vif)
+{
+	memset((void *)(&vlan_vif[0]), 0x0, sizeof(vlan_port_bitmap_t));
+
+	return TNS_NO_ERR;
+}
+
+int dump_vlan_vif_portss(vlan_port_bitmap_t vlan_vif)
+{
+	int i;
+
+	filter_dbg(FINFO, "Port Bitmap (0...135) 0x ");
+	for (i = 0; i < (TNS_MAC_FILTER_MAX_SYS_PORTS / 8); i++)
+		filter_dbg(FINFO, "%x ", vlan_vif[i]);
+	filter_dbg(FINFO, "\n");
+
+	return TNS_NO_ERR;
+}
+
+static inline int getingress_grp(int node, int vf)
+{
+	int i;
+
+	for (i = 0; i < TNS_MAX_INGRESS_GROUP; i++) {
+		if (ingressgrp_gblvif[node][i].is_valid &&
+		    (ingressgrp_gblvif[node][i].ingress_grp ==
+		     intr_to_ingressgrp[node][vf]))
+			return i;
+	}
+	return -1;
+}
+
+inline int vf_bcast_vif(int node, int vf, int *bcast_vif)
+{
+	int ing_grp = getingress_grp(node, vf);
+
+	if (ing_grp == -1)
+		return TNS_ERR_ENTRY_NOT_FOUND;
+
+	*bcast_vif = ingressgrp_gblvif[node][ing_grp].bcast_vif;
+
+	return TNS_NO_ERR;
+}
+
+inline int vf_mcast_vif(int node, int vf, int *mcast_vif)
+{
+	int ing_grp = getingress_grp(node, vf);
+
+	if (ing_grp == -1)
+		return TNS_ERR_ENTRY_NOT_FOUND;
+
+	*mcast_vif = ingressgrp_gblvif[node][ing_grp].mcast_vif;
+
+	return TNS_NO_ERR;
+}
+
+inline int vf_pfvf_id(int node, int vf, int *pfvf)
+{
+	int ing_grp = getingress_grp(node, vf);
+
+	if (ing_grp == -1)
+		return TNS_ERR_ENTRY_NOT_FOUND;
+
+	*pfvf = ingressgrp_gblvif[node][ing_grp].pf_vf;
+
+	return TNS_NO_ERR;
+}
+
+bool is_vf_registered_entry(int node, int vf, int index)
+{
+	int i;
+
+	for (i = 0; i < vf_reg_data[node][vf].filter_count; i++) {
+		if (vf_reg_data[node][vf].filter_index[i] == index)
+			return true;
+	}
+
+	return false;
+}
+
+bool is_vlan_registered(int node, int vf, int vlan)
+{
+	int i;
+
+	for (i = 0; i < vf_reg_data[node][vf].vlan_count; i++) {
+		if (vf_reg_data[node][vf].vlan[i] == vlan)
+			return true;
+	}
+
+	return false;
+}
+
+int is_empty_vif(int node, int vf, struct evif_entry *evif_dat)
+{
+	int i;
+
+	for (i = 0; i < TNS_MAX_VF; i++)
+		if (intr_to_ingressgrp[node][vf] ==
+		    intr_to_ingressgrp[node][i] &&
+		    (vf_reg_data[node][i].vf_in_promis ||
+		     vf_reg_data[node][i].vf_in_mcast_promis))
+			disable_port(i, evif_dat);
+	disable_port(intr_to_ingressgrp[node][vf], evif_dat);
+
+	if (evif_dat->prt_bmap7_0 || evif_dat->prt_bmap_8 ||
+	    evif_dat->prt_bmap_72_9 || evif_dat->prt_bmap_136_73)
+		return 0;
+
+	return 1;
+}
+
+int is_empty_vlan(int node, int vf, int vlan, vlan_port_bitmap_t vlan_vif)
+{
+	int i, pf_vf;
+	int ret;
+
+	ret = vf_pfvf_id(node, vf, &pf_vf);
+	if (ret)
+		return ret;
+
+	if (vf_reg_data[node][pf_vf].vf_in_promis &&
+	    !is_vlan_registered(node, pf_vf, vlan))
+		disable_vlan_port(pf_vf, vlan_vif);
+
+	disable_vlan_port(intr_to_ingressgrp[node][vf], vlan_vif);
+	for (i = 0; i < sizeof(vlan_port_bitmap_t); i++)
+		if (vlan_vif[i])
+			break;
+
+	if (i == sizeof(vlan_port_bitmap_t))
+		return 1;
+
+	return 0;
+}
+
+int filter_tbl_lookup(int node, int table_id, void *entry, int *index)
+{
+	switch (table_id) {
+	case MAC_FILTER_TABLE:
+	{
+		struct mac_filter_entry tbl_entry;
+		struct mac_filter_entry *inp = (struct mac_filter_entry *)entry;
+		int i;
+		int ret;
+
+		for (i = 0; i < TNS_MAC_FILTER_MAX_INDEX; i++) {
+			ret = tbl_read(node, MAC_FILTER_TABLE, i,
+				       &tbl_entry.key, &tbl_entry.mask,
+				       &tbl_entry.data);
+
+			if (ret && (ret != TNS_ERR_MAC_FILTER_INVALID_ENTRY))
+				return ret;
+			else if (ret == TNS_ERR_MAC_FILTER_INVALID_ENTRY)
+				continue;
+
+			if ((tbl_entry.key.key_type.key_value ==
+			     inp->key.key_type.key_value) &&
+			    (tbl_entry.mask.key_type.key_value ==
+			     inp->mask.key_type.key_value)) {
+				//Found an Entry
+				*index = i;
+				inp->data.data = tbl_entry.data.data;
+				return TNS_NO_ERR;
+			}
+			//Unable to find entry
+			*index = -1;
+		}
+		break;
+	}
+	case VLAN_FILTER_TABLE:
+	{
+		struct vlan_filter_entry tbl_entry;
+		struct vlan_filter_entry *inp_entry;
+		int i;
+		int ret;
+
+		inp_entry = (struct vlan_filter_entry *)entry;
+		for (i = 1; i < TNS_VLAN_FILTER_MAX_INDEX; i++) {
+			ret = tbl_read(node, VLAN_FILTER_TABLE, i,
+				       &tbl_entry.key, &tbl_entry.mask,
+					&tbl_entry.data);
+			if (ret && (ret != TNS_ERR_MAC_FILTER_INVALID_ENTRY))
+				return ret;
+			else if (ret == TNS_ERR_MAC_FILTER_INVALID_ENTRY)
+				continue;
+
+			if ((tbl_entry.key.key_type.key_value ==
+			     inp_entry->key.key_type.key_value) &&
+			    (tbl_entry.mask.key_type.key_value ==
+			     inp_entry->mask.key_type.key_value)) {
+				//Found an Entry
+				*index = i;
+				inp_entry->data.data = tbl_entry.data.data;
+				return TNS_NO_ERR;
+			}
+		}
+		//Unable to find entry
+		*index = -1;
+		break;
+	}
+	default:
+		filter_dbg(FERR, "Wrong Table ID: %d\n", table_id);
+		return TNS_ERR_INVALID_TBL_ID;
+	}
+
+	return TNS_NO_ERR;
+}
+
+int tns_enable_mcast_promis(int node, int vf)
+{
+	int mcast_vif;
+	int j;
+	int ret;
+	struct evif_entry evif_dat;
+	int ing_grp = getingress_grp(node, vf);
+	int pports;
+
+	if (ing_grp == -1)
+		return TNS_ERROR_INVALID_ARG;
+
+	ret = vf_mcast_vif(node, vf, &mcast_vif);
+	if (ret) {
+		filter_dbg(FERR, "Error: Unable to get multicast VIF\n");
+		return ret;
+	}
+
+	ret = tbl_read(node, MAC_EVIF_TABLE, mcast_vif, NULL, NULL, &evif_dat);
+	if (ret)
+		return ret;
+
+	enable_port(vf, &evif_dat);
+	dump_evif_entry(&evif_dat);
+	ret = tbl_write(node, MAC_EVIF_TABLE, mcast_vif, NULL, NULL,
+			(void *)&evif_dat);
+	if (ret)
+		return ret;
+
+	pports = ingressgrp_gblvif[node][ing_grp].valid_mcast_promis_ports;
+	//Enable VF in multicast MAC promiscuous group
+	for (j = 0; j < pports; j++) {
+		if (MCAST_PROMIS(node, ing_grp, j) == vf) {
+			filter_dbg(FDEBUG, "VF found in MCAST promis group\n");
+			return TNS_NO_ERR;
+		}
+	}
+	MCAST_PROMIS(node, ing_grp, pports) = vf;
+	ingressgrp_gblvif[node][ing_grp].valid_mcast_promis_ports += 1;
+	filter_dbg(FINFO, "VF %d permanently entered into MCAST promisc mode\n",
+		   vf);
+
+	return TNS_NO_ERR;
+}
+
+int remove_vf_from_regi_mcast_vif(int node, int vf)
+{
+	int ret;
+	int mcast_vif;
+	struct evif_entry evif_dat;
+
+	ret = vf_mcast_vif(node, vf, &mcast_vif);
+	if (ret) {
+		filter_dbg(FERR, "Error: Unable to get multicast VIF\n");
+		return ret;
+	}
+
+	ret = tbl_read(node, MAC_EVIF_TABLE, mcast_vif, NULL, NULL, &evif_dat);
+	if (ret)
+		return ret;
+	disable_port(vf, &evif_dat);
+	dump_evif_entry(&evif_dat);
+	ret = tbl_write(node, MAC_EVIF_TABLE, mcast_vif, NULL, NULL,
+			(void *)&evif_dat);
+	if (ret)
+		return ret;
+
+	return TNS_NO_ERR;
+}
+
+int remove_vf_from_mcast_promis_grp(int node, int vf)
+{
+	int j, k;
+	int ing_grp = getingress_grp(node, vf);
+	int pports;
+
+	if (ing_grp == -1)
+		return TNS_ERROR_INVALID_ARG;
+
+	pports = ingressgrp_gblvif[node][ing_grp].valid_mcast_promis_ports;
+	for (j = 0; j < pports; j++) {
+		if (MCAST_PROMIS(node, ing_grp, j) != vf)
+			continue;
+
+		filter_dbg(FDEBUG, "VF found in MCAST promis group %d\n",
+			   intr_to_ingressgrp[node][vf]);
+		for (k = j; k < (pports - 1); k++)
+			MCAST_PROMIS(node, ing_grp, k) =
+			 MCAST_PROMIS(node, ing_grp, (k + 1));
+		VALID_MCAST_PROMIS(node, ing_grp) -= 1;
+		remove_vf_from_regi_mcast_vif(node, vf);
+		return TNS_NO_ERR;
+	}
+	filter_dbg(FDEBUG, "VF %d not found in multicast promiscuous group\n",
+		   vf);
+
+	return TNS_ERR_ENTRY_NOT_FOUND;
+}
+
+int registered_vf_filter_index(int node, int vf, int mac_idx, int action)
+{
+	int f_count = vf_reg_data[node][vf].filter_count, j;
+
+	if (!action) {
+		for (j = 0; j < f_count; j++) {
+			if (vf_reg_data[node][vf].filter_index[j] == mac_idx) {
+				int i, k = j + 1;
+
+				for (i = j; i < f_count - 1; i++, k++)
+					vf_reg_data[node][vf].filter_index[i] =
+					 vf_reg_data[node][vf].filter_index[k];
+				break;
+			}
+		}
+		if (j == vf_reg_data[node][vf].filter_count)
+			filter_dbg(FDEBUG, "VF not in registered filtr list\n");
+		else
+			vf_reg_data[node][vf].filter_count -= 1;
+	} else {
+		vf_reg_data[node][vf].filter_index[f_count] = mac_idx;
+		vf_reg_data[node][vf].filter_count += 1;
+		filter_dbg(FINFO, "%s Added at Filter count %d Index %d\n",
+			   __func__, vf_reg_data[node][vf].filter_count,
+			   mac_idx);
+	}
+
+	/* We are restricting each VF to register atmost 11 filter entries
+	 * (including unicast & multicast)
+	 */
+	if (vf_reg_data[node][vf].filter_count <= TNS_MAX_MAC_PER_VF) {
+		vf_reg_data[node][vf].vf_in_mcast_promis = 0;
+		if (!vf_reg_data[node][vf].vf_in_promis)
+			remove_vf_from_mcast_promis_grp(node, vf);
+		filter_dbg(FINFO, "VF %d removed from MCAST promis mode\n", vf);
+	}
+
+	return TNS_NO_ERR;
+}
+
+int add_mac_filter_mcast_entry(int node, int table_id, int vf, int mac_idx,
+			       void *mac_DA)
+{
+	int ret;
+	struct mac_filter_entry tbl_entry;
+	struct mac_filter_keymask_s key, mask;
+	union mac_filter_data_s data;
+	int vif = -1, k, j;
+	struct evif_entry evif_dat;
+	int ing_grp = getingress_grp(node, vf);
+
+	if (ing_grp == -1)
+		return TNS_ERROR_INVALID_ARG;
+
+	if (vf_reg_data[node][vf].filter_count >= TNS_MAX_MAC_PER_VF) {
+		if (!vf_reg_data[node][vf].vf_in_mcast_promis) {
+			tns_enable_mcast_promis(node, vf);
+			vf_reg_data[node][vf].vf_in_mcast_promis = 1;
+		}
+		return TNS_ERR_MAX_LIMIT;
+	}
+
+	tbl_entry.key.is_valid = 1;
+	tbl_entry.key.key_type.s.ingress_grp = intr_to_ingressgrp[node][vf];
+	tbl_entry.mask.key_type.s.ingress_grp = 0x0;
+	for (j = 5, k = 0; j >= 0; j--, k++) {
+		tbl_entry.key.key_type.s.mac_DA[k] = ((u8 *)mac_DA)[j];
+		tbl_entry.mask.key_type.s.mac_DA[k] = 0x0;
+	}
+	ret = filter_tbl_lookup(node, MAC_FILTER_TABLE, &tbl_entry, &mac_idx);
+	if (ret)
+		return ret;
+	if (mac_idx != -1 &&
+	    !(mac_idx >= (TNS_MAC_FILTER_MAX_INDEX - TNS_MAX_INGRESS_GROUP) &&
+	      mac_idx < TNS_MAC_FILTER_MAX_INDEX)) {
+		int evif = tbl_entry.data.s.evif;
+
+		filter_dbg(FINFO, "Multicast MAC found at %d evif: %d\n",
+			   mac_idx, evif);
+		ret = tbl_read(node, MAC_EVIF_TABLE, evif, NULL, NULL,
+			       &evif_dat);
+		if (ret)
+			return ret;
+		if (is_vf_registered_entry(node, vf, mac_idx)) {
+			//No Need to register again
+			return TNS_NO_ERR;
+		}
+		enable_port(vf, &evif_dat);
+		ret = tbl_write(node, MAC_EVIF_TABLE, evif, NULL, NULL,
+				(void *)&evif_dat);
+		if (ret)
+			return ret;
+		registered_vf_filter_index(node, vf, mac_idx, 1);
+		dump_evif_entry(&evif_dat);
+		return TNS_NO_ERR;
+	}
+
+	//New multicast MAC registration
+	if (alloc_table_index(node, MAC_FILTER_TABLE, &mac_idx)) {
+		filter_dbg(FERR, "%s Filter Table Full\n", __func__);
+		return TNS_ERR_MAX_LIMIT;
+	}
+	key.is_valid = 1;
+	mask.is_valid = 1;
+	key.key_type.s.ingress_grp = intr_to_ingressgrp[node][vf];
+	mask.key_type.s.ingress_grp = 0;
+	for (j = 5, k = 0; j >= 0; j--, k++) {
+		key.key_type.s.mac_DA[k] = ((u8 *)mac_DA)[j];
+		mask.key_type.s.mac_DA[k] = 0x0;
+	}
+	if (alloc_table_index(node, MAC_EVIF_TABLE, &vif)) {
+		filter_dbg(FERR, "%s EVIF Table Full\n", __func__);
+		return TNS_ERR_MAX_LIMIT;
+	}
+	evif_dat.insert_ptr0 = 0xFFFF;
+	evif_dat.insert_ptr1 = 0xFFFF;
+	evif_dat.insert_ptr2 = 0xFFFF;
+	evif_dat.mre_ptr = 0x7FFF;
+	evif_dat.rewrite_ptr0 = 0xFF;
+	evif_dat.rewrite_ptr1 = 0xFF;
+	evif_dat.data31_0 = 0x0;
+	evif_dat.q_mirror_en = 0x0;
+	evif_dat.mirror_en = 0x0;
+	evif_dat.mtu_prf = 0x0;
+	evif_dat.truncate = 0x0;
+	evif_dat.rsp_type = 0x3;
+	disable_all_ports(&evif_dat);
+	for (j = 0; j < VALID_MCAST_PROMIS(node, ing_grp); j++)
+		enable_port(MCAST_PROMIS(node, ing_grp, j), &evif_dat);
+	enable_port(vf, &evif_dat);
+	ret = tbl_write(node, MAC_EVIF_TABLE, vif, NULL, NULL, &evif_dat);
+	if (ret)
+		return ret;
+	data.data = 0x0ull;
+	data.s.evif = vif;
+	ret = tbl_write(node, MAC_FILTER_TABLE, mac_idx, &key, &mask, &data);
+	if (ret)
+		return ret;
+	macfilter_freeindex[node] += 1;
+	registered_vf_filter_index(node, vf, mac_idx, 1);
+
+	return TNS_NO_ERR;
+}
+
+int del_mac_filter_entry(int node, int table_id, int vf, int mac_idx,
+			 void *mac_DA, int addr_type)
+{
+	int ret;
+	struct mac_filter_entry tbl_entry;
+	int old_mac_idx = -1, vif;
+	int j, k;
+
+	tbl_entry.key.is_valid = 1;
+	tbl_entry.key.key_type.s.ingress_grp = intr_to_ingressgrp[node][vf];
+	tbl_entry.mask.key_type.s.ingress_grp = 0x0;
+
+	for (j = 5, k = 0; j >= 0; j--, k++) {
+		tbl_entry.key.key_type.s.mac_DA[k] = ((u8 *)mac_DA)[j];
+		tbl_entry.mask.key_type.s.mac_DA[k] = 0x0;
+	}
+
+	ret = filter_tbl_lookup(node, MAC_FILTER_TABLE, (void *)&tbl_entry,
+				&old_mac_idx);
+	if (ret)
+		return ret;
+
+	if (old_mac_idx == -1) {
+		filter_dbg(FDEBUG, "Invalid Delete, entry not found\n");
+		return TNS_ERR_ENTRY_NOT_FOUND;
+	}
+	if (mac_idx != -1 && mac_idx != old_mac_idx) {
+		filter_dbg(FDEBUG, "Found and requested are mismatched\n");
+		return TNS_ERR_ENTRY_NOT_FOUND;
+	}
+	if (old_mac_idx == vf) {
+		filter_dbg(FDEBUG, "Primary Unicast MAC delete not allowed\n");
+		return TNS_ERR_MAC_FILTER_INVALID_ENTRY;
+	}
+
+	//Remove MAC Filter entry from VF register MAC filter list
+	registered_vf_filter_index(node, vf, old_mac_idx, 0);
+
+	//Remove VIF entry (output portmask) related to this filter entry
+	vif = tbl_entry.data.s.evif;
+	if (addr_type) {
+		struct evif_entry evif_dat;
+
+		ret = tbl_read(node, MAC_EVIF_TABLE, vif, NULL, NULL,
+			       &evif_dat);
+		if (ret)
+			return ret;
+
+		disable_port(vf, &evif_dat);
+		ret = tbl_write(node, MAC_EVIF_TABLE, vif, NULL, NULL,
+				&evif_dat);
+		if (ret)
+			return ret;
+
+		dump_evif_entry(&evif_dat);
+		//In case of multicast MAC check for empty portmask
+		if (!is_empty_vif(node, vf, &evif_dat))
+			return TNS_NO_ERR;
+	}
+	invalidate_table_entry(node, MAC_FILTER_TABLE, old_mac_idx);
+	free_table_index(node, MAC_FILTER_TABLE, old_mac_idx);
+	free_table_index(node, MAC_EVIF_TABLE, vif);
+	macfilter_freeindex[node] -= 1;
+
+	return TNS_NO_ERR;
+}
+
+int add_mac_filter_entry(int node, int table_id, int vf, int mac_idx,
+			 void *mac_DA)
+{
+	int ret;
+	struct mac_filter_entry tbl_entry;
+	int old_mac_idx = -1;
+	int j, k;
+	struct mac_filter_keymask_s key, mask;
+	union mac_filter_data_s data;
+
+	/* We are restricting each VF to register atmost 11 filter entries
+	 * (including unicast & multicast)
+	 */
+	if (mac_idx != vf &&
+	    vf_reg_data[node][vf].filter_count >= TNS_MAX_MAC_PER_VF) {
+		if (!vf_reg_data[node][vf].vf_in_mcast_promis) {
+			tns_enable_mcast_promis(node, vf);
+			vf_reg_data[node][vf].vf_in_mcast_promis = 1;
+		}
+		return TNS_ERR_MAX_LIMIT;
+	}
+
+	//Adding Multicast MAC will be handled differently
+	if ((((u8 *)mac_DA)[0]) & 0x1) {
+		filter_dbg(FDEBUG, "%s It is multicast MAC entry\n", __func__);
+		return add_mac_filter_mcast_entry(node, table_id, vf, mac_idx,
+						  mac_DA);
+	}
+
+	tbl_entry.key.is_valid = 1;
+	tbl_entry.key.key_type.s.ingress_grp = intr_to_ingressgrp[node][vf];
+	tbl_entry.mask.key_type.s.ingress_grp = 0x0;
+	for (j = 5, k = 0; j >= 0; j--, k++) {
+		tbl_entry.key.key_type.s.mac_DA[k] = ((u8 *)mac_DA)[j];
+		tbl_entry.mask.key_type.s.mac_DA[k] = 0x0;
+	}
+	ret = filter_tbl_lookup(node, MAC_FILTER_TABLE, (void *)&tbl_entry,
+				&old_mac_idx);
+	if (ret)
+		return ret;
+	if (old_mac_idx != -1) {
+		filter_dbg(FINFO, "Duplicate entry found at %d\n", old_mac_idx);
+		if (tbl_entry.data.s.evif != vf) {
+			filter_dbg(FDEBUG, "Registered VF %d Requested VF %d\n",
+				   (int)tbl_entry.data.s.evif, (int)vf);
+			return TNS_ERR_DUPLICATE_MAC;
+		}
+		return TNS_NO_ERR;
+	}
+	if (alloc_table_index(node, MAC_FILTER_TABLE, &mac_idx)) {
+		filter_dbg(FERR, "(%s) Filter Table Full\n", __func__);
+		return TNS_ERR_MAX_LIMIT;
+	}
+	if (mac_idx == -1) {
+		filter_dbg(FERR, "!!!ERROR!!! reached maximum limit\n");
+		return TNS_ERR_MAX_LIMIT;
+	}
+	key.is_valid = 1;
+	mask.is_valid = 1;
+	key.key_type.s.ingress_grp = intr_to_ingressgrp[node][vf];
+	mask.key_type.s.ingress_grp = 0;
+	for (j = 5, k = 0; j >= 0; j--, k++) {
+		key.key_type.s.mac_DA[k] = ((u8 *)mac_DA)[j];
+		mask.key_type.s.mac_DA[k] = 0x0;
+	}
+	filter_dbg(FINFO, "VF id: %d with ingress_grp: %d ", vf,
+		   key.key_type.s.ingress_grp);
+	filter_dbg(FINFO, "MAC: %x: %x: %x %x: %x %x Added at Index: %d\n",
+		   ((u8 *)mac_DA)[0], ((u8 *)mac_DA)[1],
+		   ((u8 *)mac_DA)[2], ((u8 *)mac_DA)[3],
+		   ((u8 *)mac_DA)[4], ((u8 *)mac_DA)[5], mac_idx);
+
+	data.data = 0x0ull;
+	data.s.evif = vf;
+	ret = tbl_write(node, MAC_FILTER_TABLE, mac_idx, &key, &mask, &data);
+	if (ret)
+		return ret;
+
+	if (mac_idx != vf) {
+		registered_vf_filter_index(node, vf, mac_idx, 1);
+		macfilter_freeindex[node] += 1;
+	}
+
+	return TNS_NO_ERR;
+}
+
+int vf_interface_up(int node, int tbl_id, int vf, void *mac_DA)
+{
+	int ret;
+
+	//Enable unicast MAC entry for this VF
+	ret = add_mac_filter_entry(node, tbl_id, vf, vf, mac_DA);
+	if (ret)
+		return ret;
+
+	return TNS_NO_ERR;
+}
+
+int del_vlan_entry(int node, int vf, int vlan, int vlanx)
+{
+	int ret;
+	struct vlan_filter_entry tbl_entry;
+	int vlan_tbl_idx = -1, i;
+	vlan_port_bitmap_t vlan_vif;
+	int vlan_cnt = vf_reg_data[node][vf].vlan_count;
+
+	tbl_entry.key.is_valid = 1;
+	tbl_entry.key.key_type.key_value  = 0x0ull;
+	tbl_entry.mask.key_type.key_value = 0xFFFFFFFFFFFFFFFFull;
+	tbl_entry.key.key_type.s.ingress_grp = intr_to_ingressgrp[node][vf];
+	tbl_entry.mask.key_type.s.ingress_grp = 0x0;
+	tbl_entry.key.key_type.s.vlan = vlan;
+	tbl_entry.mask.key_type.s.vlan = 0x0;
+
+	filter_dbg(FINFO, "%s VF %d with ingress_grp %d VLANID %d\n",
+		   __func__, vf, tbl_entry.key.key_type.s.ingress_grp,
+		   tbl_entry.key.key_type.s.vlan);
+
+	ret = filter_tbl_lookup(node, VLAN_FILTER_TABLE, &tbl_entry,
+				&vlan_tbl_idx);
+	if (ret)
+		return ret;
+
+	if (vlan_tbl_idx == -1) {
+		filter_dbg(FINFO, "VF %d VLAN %d filter not registered\n",
+			   vf, vlan);
+		return TNS_NO_ERR;
+	}
+
+	if (vlan_tbl_idx < 1 && vlan_tbl_idx >= TNS_VLAN_FILTER_MAX_INDEX) {
+		filter_dbg(FERR, "Invalid VLAN Idx: %d\n", vlan_tbl_idx);
+		return TNS_ERR_VLAN_FILTER_INVLAID_ENTRY;
+	}
+
+	vlanx = tbl_entry.data.s.filter_idx;
+	ret = tbl_read(node, VLAN_EVIF_TABLE, vlanx, NULL, NULL,
+		       (void *)(&vlan_vif[0]));
+	if (ret)
+		return ret;
+
+	disable_vlan_port(vf, vlan_vif);
+	ret = tbl_write(node, VLAN_EVIF_TABLE, vlanx, NULL, NULL,
+			(void *)(&vlan_vif[0]));
+	if (ret)
+		return ret;
+
+	for (i = 0; i < vlan_cnt; i++) {
+		if (vf_reg_data[node][vf].vlan[i] == vlan) {
+			int j;
+
+			for (j = i; j < vlan_cnt - 1; j++)
+				vf_reg_data[node][vf].vlan[j] =
+				 vf_reg_data[node][vf].vlan[j + 1];
+			vf_reg_data[node][vf].vlan_count -= 1;
+			break;
+		}
+	}
+	if (is_empty_vlan(node, vf, vlan, vlan_vif)) {
+		free_table_index(node, VLAN_FILTER_TABLE, vlanx);
+		vlanfilter_freeindex[node] -= 1;
+		invalidate_table_entry(node, VLAN_FILTER_TABLE, vlanx);
+	}
+
+	return TNS_NO_ERR;
+}
+
+int add_vlan_entry(int node, int vf, int vlan, int vlanx)
+{
+	int ret;
+	int pf_vf;
+	struct vlan_filter_entry tbl_entry;
+	int vlan_tbl_idx = -1;
+	vlan_port_bitmap_t vlan_vif;
+
+	if (vf_reg_data[node][vf].vlan_count >= TNS_MAX_VLAN_PER_VF) {
+		filter_dbg(FDEBUG, "Reached maximum limit per VF count: %d\n",
+			   vf_reg_data[node][vf].vlan_count);
+		return TNS_ERR_MAX_LIMIT;
+	}
+
+	tbl_entry.key.is_valid = 1;
+	tbl_entry.key.key_type.key_value  = 0x0ull;
+	tbl_entry.mask.key_type.key_value = 0xFFFFFFFFFFFFFFFFull;
+	tbl_entry.key.key_type.s.ingress_grp = intr_to_ingressgrp[node][vf];
+	tbl_entry.mask.key_type.s.ingress_grp = 0x0;
+	tbl_entry.key.key_type.s.vlan = vlan;
+	tbl_entry.mask.key_type.s.vlan = 0x0;
+
+	ret = filter_tbl_lookup(node, VLAN_FILTER_TABLE, &tbl_entry,
+				&vlan_tbl_idx);
+	if (ret)
+		return ret;
+
+	if (vlan_tbl_idx != -1) {
+		filter_dbg(FINFO, "Duplicate entry found at %d\n",
+			   vlan_tbl_idx);
+		if (vlan_tbl_idx < 1 &&
+		    vlan_tbl_idx >= TNS_VLAN_FILTER_MAX_INDEX) {
+			filter_dbg(FDEBUG, "Invalid VLAN Idx %d\n",
+				   vlan_tbl_idx);
+			return TNS_ERR_VLAN_FILTER_INVLAID_ENTRY;
+		}
+
+		vlanx = tbl_entry.data.s.filter_idx;
+		ret = tbl_read(node, VLAN_EVIF_TABLE, vlanx, NULL, NULL,
+			       (void *)(&vlan_vif[0]));
+		if (ret)
+			return ret;
+
+		enable_vlan_port(vf, vlan_vif);
+		ret = tbl_write(node, VLAN_EVIF_TABLE, vlanx, NULL, NULL,
+				(void *)(&vlan_vif[0]));
+		if (ret)
+			return ret;
+
+		vf_reg_data[node][vf].vlan[vf_reg_data[node][vf].vlan_count] =
+		 vlan;
+		vf_reg_data[node][vf].vlan_count += 1;
+
+		return TNS_NO_ERR;
+	}
+
+	if (alloc_table_index(node, VLAN_FILTER_TABLE, &vlanx)) {
+		filter_dbg(FDEBUG, "%s VLAN Filter Table Full\n", __func__);
+		return TNS_ERR_MAX_LIMIT;
+	}
+	disable_vlan_vif_ports(vlan_vif);
+	enable_vlan_port(vf, vlan_vif);
+	enable_vlan_port(intr_to_ingressgrp[node][vf], vlan_vif);
+	ret = vf_pfvf_id(node, vf, &pf_vf);
+
+	if (ret)
+		return ret;
+
+	if (vf_reg_data[node][pf_vf].vf_in_promis)
+		enable_vlan_port(pf_vf, vlan_vif);
+
+	dump_vlan_vif_portss(vlan_vif);
+	ret = tbl_write(node, VLAN_EVIF_TABLE, vlanx, NULL, NULL,
+			(void *)(&vlan_vif[0]));
+	if (ret)
+		return ret;
+
+	tbl_entry.key.is_valid = 1;
+	tbl_entry.key.key_type.s.ingress_grp = intr_to_ingressgrp[node][vf];
+	tbl_entry.key.key_type.s.vlan = vlan;
+	tbl_entry.key.key_type.s.reserved = 0x0;
+	tbl_entry.key.key_type.s.reserved1 = 0x0;
+	tbl_entry.mask.is_valid = 1;
+	tbl_entry.mask.key_type.s.ingress_grp = 0x0;
+	tbl_entry.mask.key_type.s.vlan = 0x0;
+	tbl_entry.mask.key_type.s.reserved = 0xF;
+	tbl_entry.mask.key_type.s.reserved1 = 0xFFFFFFFF;
+	tbl_entry.data.data = 0x0ull;
+	tbl_entry.data.s.filter_idx = vlanx;
+	ret = tbl_write(node, VLAN_FILTER_TABLE, vlanx, &tbl_entry.key,
+			&tbl_entry.mask, &tbl_entry.data);
+	if (ret)
+		return ret;
+
+	filter_dbg(FINFO, "VF %d with ingress_grp %d VLAN %d Added at %d\n",
+		   vf, tbl_entry.key.key_type.s.ingress_grp,
+		   tbl_entry.key.key_type.s.vlan, vlanx);
+
+	vlanfilter_freeindex[node] += 1;
+	vf_reg_data[node][vf].vlan[vf_reg_data[node][vf].vlan_count] = vlan;
+	vf_reg_data[node][vf].vlan_count += 1;
+
+	return TNS_NO_ERR;
+}
+
+int enable_promiscuous_mode(int node, int vf)
+{
+	int ret = tns_enable_mcast_promis(node, vf);
+	int pf_vf;
+
+	if (ret)
+		return ret;
+
+	vf_reg_data[node][vf].vf_in_promis = 1;
+	ret = vf_pfvf_id(node, vf, &pf_vf);
+	if (ret)
+		return ret;
+
+	if (vf == pf_vf) {
+		//PFVF interface, enable full promiscuous mode
+		int i;
+		int vif = intr_to_ingressgrp[node][vf];
+		struct evif_entry evif_dat;
+		struct itt_entry_s port_cfg_entry;
+
+		for (i = 0; i < macfilter_freeindex[node]; i++) {
+			struct mac_filter_entry tbl_entry;
+
+			ret = tbl_read(node, MAC_FILTER_TABLE, i,
+				       &tbl_entry.key, &tbl_entry.mask,
+				       &tbl_entry.data);
+			if (ret && (ret != TNS_ERR_MAC_FILTER_INVALID_ENTRY))
+				return ret;
+			else if (ret == TNS_ERR_MAC_FILTER_INVALID_ENTRY)
+				continue;
+
+			if (tbl_entry.key.key_type.s.ingress_grp ==
+			    intr_to_ingressgrp[node][vf]) {
+				int vif = tbl_entry.data.s.evif;
+				struct evif_entry evif_dat;
+
+				ret = tbl_read(node, MAC_EVIF_TABLE, vif, NULL,
+					       NULL, &evif_dat);
+				if (ret)
+					return ret;
+
+				enable_port(vf, &evif_dat);
+				dump_evif_entry(&evif_dat);
+				ret = tbl_write(node, MAC_EVIF_TABLE, vif, NULL,
+						NULL, (void *)&evif_dat);
+				if (ret)
+					return ret;
+			}
+		}
+		/*If pfVf interface enters in promiscuous mode we will forward
+		 * packets destined to corresponding LMAC
+		 */
+
+		ret = tbl_read(node, MAC_EVIF_TABLE, vif, NULL, NULL,
+			       &evif_dat);
+		if (ret)
+			return ret;
+		enable_port(vf, &evif_dat);
+		dump_evif_entry(&evif_dat);
+		ret = tbl_write(node, MAC_EVIF_TABLE, vif, NULL, NULL,
+				(void *)&evif_dat);
+		if (ret)
+			return ret;
+
+		/* Update default_evif of LMAC from NULLVif to pfVf interface,
+		 * so that pfVf will shows all dropped packets as well
+		 */
+		ret = tbl_read(node, PORT_CONFIG_TABLE,
+			       intr_to_ingressgrp[node][vf], NULL, NULL,
+			       &port_cfg_entry);
+		if (ret)
+			return ret;
+
+		port_cfg_entry.default_evif = vf;
+		ret = tbl_write(node, PORT_CONFIG_TABLE,
+				intr_to_ingressgrp[node][vf], NULL, NULL,
+				(void *)&port_cfg_entry);
+		if (ret)
+			return ret;
+
+		filter_dbg(FINFO, "%s Port %d pkt_dir %d defaultVif %d",
+			   __func__, vf, port_cfg_entry.pkt_dir,
+			   port_cfg_entry.default_evif);
+		filter_dbg(FINFO, " adminVlan %d %s\n",
+			   port_cfg_entry.admin_vlan,
+			   port_cfg_entry.is_admin_vlan_enabled ? "Enable" :
+				"Disable");
+
+		for (i = 1; i < vlanfilter_freeindex[node]; i++) {
+			struct vlan_filter_entry tbl_entry;
+
+			ret = tbl_read(node, VLAN_FILTER_TABLE, i,
+				       &tbl_entry.key, &tbl_entry.mask,
+				       &tbl_entry.data);
+			if (ret && (ret != TNS_ERR_MAC_FILTER_INVALID_ENTRY))
+				return ret;
+			else if (ret == TNS_ERR_MAC_FILTER_INVALID_ENTRY)
+				continue;
+
+			if (tbl_entry.key.key_type.s.ingress_grp ==
+			    intr_to_ingressgrp[node][vf]) {
+				int vlanx = tbl_entry.data.s.filter_idx;
+				vlan_port_bitmap_t vlan_vif;
+
+				ret = tbl_read(node, VLAN_EVIF_TABLE, vlanx,
+					       NULL, NULL,
+					       (void *)(&vlan_vif[0]));
+				if (ret)
+					return ret;
+				enable_vlan_port(vf, vlan_vif);
+				ret = tbl_write(node, VLAN_EVIF_TABLE, vlanx,
+						NULL, NULL,
+						(void *)(&vlan_vif[0]));
+				if (ret)
+					return ret;
+			}
+		}
+	} else {
+		//VF interface enable multicast promiscuous mode
+		int i;
+		int ret;
+
+		for (i = TNS_MAX_VF; i < macfilter_freeindex[node]; i++) {
+			struct mac_filter_entry tbl_entry;
+
+			ret = tbl_read(node, MAC_FILTER_TABLE, i,
+				       &tbl_entry.key, &tbl_entry.mask,
+				       &tbl_entry.data);
+			if (ret && (ret != TNS_ERR_MAC_FILTER_INVALID_ENTRY))
+				return ret;
+			else if (ret == TNS_ERR_MAC_FILTER_INVALID_ENTRY)
+				continue;
+
+			/* We found filter entry, lets verify either this is
+			 * unicast or multicast
+			 */
+			if (((((u8 *)tbl_entry.key.key_type.s.mac_DA)[5]) &
+			       0x1) && (tbl_entry.key.key_type.s.ingress_grp ==
+					intr_to_ingressgrp[node][vf])) {
+				int vif = tbl_entry.data.s.evif;
+				struct evif_entry evif_dat;
+
+				ret = tbl_read(node, MAC_EVIF_TABLE, vif, NULL,
+					       NULL, &evif_dat);
+				if (ret)
+					return ret;
+				enable_port(vf, &evif_dat);
+				dump_evif_entry(&evif_dat);
+				ret = tbl_write(node, MAC_EVIF_TABLE, vif, NULL,
+						NULL, (void *)&evif_dat);
+				if (ret)
+					return ret;
+			}
+		}
+	}
+
+	return TNS_NO_ERR;
+}
+
+int disable_promiscuous_mode(int node, int vf)
+{
+	int i, pf_vf;
+	int ret;
+
+	vf_reg_data[node][vf].vf_in_promis = 0;
+	ret = vf_pfvf_id(node, vf, &pf_vf);
+	if (ret)
+		return ret;
+
+	for (i = TNS_MAX_VF; i < macfilter_freeindex[node]; i++) {
+		struct mac_filter_entry tbl_entry;
+
+		ret = tbl_read(node, MAC_FILTER_TABLE, i, &tbl_entry.key,
+			       &tbl_entry.mask, &tbl_entry.data);
+		if (ret && (ret != TNS_ERR_MAC_FILTER_INVALID_ENTRY))
+			return ret;
+		else if (ret == TNS_ERR_MAC_FILTER_INVALID_ENTRY)
+			continue;
+
+		//We found an entry belongs to this group
+		if (tbl_entry.key.key_type.s.ingress_grp ==
+		    intr_to_ingressgrp[node][vf]) {
+			int vif = tbl_entry.data.s.evif;
+			struct evif_entry evif_dat;
+
+			if (is_vf_registered_entry(node, vf, i))
+				continue;
+
+			//Is this multicast entry
+			if (((((u8 *)tbl_entry.key.key_type.s.mac_DA)[5]) &
+			       0x1) && vf_reg_data[node][vf].vf_in_mcast_promis)
+				continue;
+
+			//Disable port bitmap in EVIF entry
+			ret = tbl_read(node, MAC_EVIF_TABLE, vif, NULL,
+				       NULL, &evif_dat);
+			if (ret)
+				return ret;
+			disable_port(vf, &evif_dat);
+			dump_evif_entry(&evif_dat);
+			ret = tbl_write(node, MAC_EVIF_TABLE, vif, NULL, NULL,
+					(void *)&evif_dat);
+			if (ret)
+				return ret;
+		}
+	}
+	/* If pfVf interface exit from promiscuous mode, then  we will change
+	 * portbitmap corresponding to LMAC
+	 */
+	if (vf == pf_vf) {
+		int vif = intr_to_ingressgrp[node][vf];
+		struct evif_entry evif_dat;
+		struct itt_entry_s port_cfg_entry;
+
+		ret = tbl_read(node, MAC_EVIF_TABLE, vif, NULL, NULL,
+			       &evif_dat);
+		if (ret)
+			return ret;
+
+		disable_port(vf, &evif_dat);
+		dump_evif_entry(&evif_dat);
+		ret = tbl_write(node, MAC_EVIF_TABLE, vif, NULL, NULL,
+				(void *)&evif_dat);
+		if (ret)
+			return ret;
+
+		for (i = 1; i < vlanfilter_freeindex[node]; i++) {
+			struct vlan_filter_entry tbl_entry;
+
+			ret = tbl_read(node, VLAN_FILTER_TABLE, i,
+				       &tbl_entry.key, &tbl_entry.mask,
+				       &tbl_entry.data);
+			if (ret && (ret != TNS_ERR_MAC_FILTER_INVALID_ENTRY))
+				return ret;
+			else if (ret == TNS_ERR_MAC_FILTER_INVALID_ENTRY)
+				continue;
+
+			if (tbl_entry.key.key_type.s.ingress_grp ==
+			    intr_to_ingressgrp[node][vf]) {
+				int vlanx = tbl_entry.data.s.filter_idx;
+				vlan_port_bitmap_t vlan_vif;
+				int vlan = tbl_entry.key.key_type.s.vlan;
+
+				if (!is_vlan_registered(node, vf, vlan)) {
+					ret = tbl_read(node, VLAN_EVIF_TABLE,
+						       vlanx, NULL, NULL,
+						       (void *)(&vlan_vif[0]));
+					if (ret)
+						return ret;
+					disable_vlan_port(vf, vlan_vif);
+					ret = tbl_write(node, VLAN_EVIF_TABLE,
+							vlanx, NULL, NULL,
+							(void *)(&vlan_vif[0]));
+					if (ret)
+						return ret;
+				}
+			}
+		}
+		//Update default_evif of LMAC to NULLVif
+		ret = tbl_read(node, PORT_CONFIG_TABLE,
+			       intr_to_ingressgrp[node][vf], NULL, NULL,
+			       &port_cfg_entry);
+		if (ret)
+			return ret;
+
+		port_cfg_entry.default_evif = TNS_NULL_VIF;
+		ret = tbl_write(node, PORT_CONFIG_TABLE,
+				intr_to_ingressgrp[node][vf], NULL, NULL,
+				(void *)&port_cfg_entry);
+		if (ret)
+			return ret;
+		filter_dbg(FINFO, "%s Port %d pkt_dir %d defaultVif %d ",
+			   __func__, vf, port_cfg_entry.pkt_dir,
+			   port_cfg_entry.default_evif);
+		filter_dbg(FINFO, "adminVlan %d %s\n",
+			   port_cfg_entry.admin_vlan,
+			   port_cfg_entry.is_admin_vlan_enabled ? "Enable" :
+			   "Disable");
+	}
+	if (!vf_reg_data[node][vf].vf_in_mcast_promis)
+		remove_vf_from_mcast_promis_grp(node, vf);
+
+	return TNS_NO_ERR;
+}
+
+/* CRB-1S configuration
+ * Valid LMAC's - 3 (128, 132, & 133)
+ * PFVF - 3 (0, 64, & 96)
+ * bcast_vif - 3 (136, 140, & 141)
+ * mcast_vif - 3 (144, 148, & 149)
+ * null_vif - 1 (152)
+ */
+int mac_filter_config(void)
+{
+	int node, j;
+
+	for (node = 0; node < nr_node_ids; node++) {
+		int lmac;
+
+		//Reset inerface to Ingress Group
+		for (j = 0; j < TNS_MAC_FILTER_MAX_SYS_PORTS; j++)
+			intr_to_ingressgrp[node][j] = j;
+
+		if (!pf_vf_map_data[node].valid)
+			continue;
+
+		for (j = 0; j < TNS_MAX_INGRESS_GROUP; j++)
+			ingressgrp_gblvif[node][j].is_valid = 0;
+
+		for (lmac = 0; lmac < pf_vf_map_data[node].lmac_cnt; lmac++) {
+			int slm = pf_vf_map_data[node].pf_vf[lmac].sys_lmac;
+			int valid_pf = pf_vf_map_data[node].pf_vf[lmac].pf_id;
+			int num_vfs = pf_vf_map_data[node].pf_vf[lmac].num_vfs;
+			struct evif_entry evif_dat;
+			int bvif, mvif;
+			int ret;
+
+			bvif = TNS_BASE_BCAST_VIF + slm;
+			mvif = TNS_BASE_MCAST_VIF + slm;
+
+			//Map inerface to Ingress Group
+			for (j = valid_pf; j < (valid_pf + num_vfs); j++) {
+				struct itt_entry_s port_cfg_entry;
+				int ret;
+
+				intr_to_ingressgrp[node][j] = TNS_MAX_VF + slm;
+
+				ret = tbl_read(node, PORT_CONFIG_TABLE, j, NULL,
+					       NULL, (void *)&port_cfg_entry);
+				if (ret)
+					return ret;
+				port_cfg_entry.default_evif =
+					intr_to_ingressgrp[node][j];
+				ret = tbl_write(node, PORT_CONFIG_TABLE, j,
+						NULL, NULL,
+						(void *)&port_cfg_entry);
+				if (ret)
+					return ret;
+			}
+
+			//LMAC Configuration
+			ingressgrp_gblvif[node][slm].is_valid = 1;
+			ingressgrp_gblvif[node][slm].ingress_grp = TNS_MAX_VF +
+								     slm;
+			ingressgrp_gblvif[node][slm].pf_vf = valid_pf;
+			ingressgrp_gblvif[node][slm].bcast_vif = bvif;
+			ingressgrp_gblvif[node][slm].mcast_vif = mvif;
+			ingressgrp_gblvif[node][slm].null_vif = TNS_NULL_VIF;
+			MCAST_PROMIS(node, slm, 0) = TNS_MAX_VF + slm;
+			VALID_MCAST_PROMIS(node, slm) = 1;
+
+			filter_dbg(FINFO, "lmac %d syslm %d num_vfs %d ",
+				   lmac, slm,
+				   pf_vf_map_data[node].pf_vf[lmac].num_vfs);
+			filter_dbg(FINFO, "ingress_grp %d pfVf %d bCast %d ",
+				   ingressgrp_gblvif[node][slm].ingress_grp,
+				   ingressgrp_gblvif[node][slm].pf_vf,
+				   ingressgrp_gblvif[node][slm].bcast_vif);
+			filter_dbg(FINFO, "mCast: %d\n",
+				   ingressgrp_gblvif[node][slm].mcast_vif);
+
+			ret = tbl_read(node, MAC_EVIF_TABLE, bvif, NULL, NULL,
+				       &evif_dat);
+			if (ret)
+				return ret;
+
+			evif_dat.rewrite_ptr0 = 0xFF;
+			evif_dat.rewrite_ptr1 = 0xFF;
+			enable_port(ingressgrp_gblvif[node][slm].ingress_grp,
+				    &evif_dat);
+
+			ret = tbl_write(node, MAC_EVIF_TABLE, bvif, NULL, NULL,
+					(void *)&evif_dat);
+			if (ret)
+				return ret;
+
+			ret = tbl_read(node, MAC_EVIF_TABLE, mvif, NULL, NULL,
+				       &evif_dat);
+			if (ret)
+				return ret;
+
+			evif_dat.rewrite_ptr0 = 0xFF;
+			evif_dat.rewrite_ptr1 = 0xFF;
+			enable_port(ingressgrp_gblvif[node][slm].ingress_grp,
+				    &evif_dat);
+
+			ret = tbl_write(node, MAC_EVIF_TABLE, mvif, NULL, NULL,
+					(void *)&evif_dat);
+			if (ret)
+				return ret;
+
+			ret = tbl_read(node, MAC_EVIF_TABLE, TNS_NULL_VIF, NULL,
+				       NULL, &evif_dat);
+			if (ret)
+				return ret;
+
+			evif_dat.rewrite_ptr0 = 0xFF;
+			evif_dat.rewrite_ptr1 = 0xFF;
+
+			ret = tbl_write(node, MAC_EVIF_TABLE, TNS_NULL_VIF,
+					NULL, NULL, (void *)&evif_dat);
+			if (ret)
+				return ret;
+		}
+		j = 0;
+		alloc_table_index(node, VLAN_FILTER_TABLE, &j);
+
+		for (j = 0; j < TNS_MAX_VF; j++) {
+			vf_reg_data[node][j].vf_in_mcast_promis = 0;
+			vf_reg_data[node][j].filter_count = 1;
+			vf_reg_data[node][j].filter_index[0] = j;
+			vf_reg_data[node][j].vlan_count = 0;
+			alloc_table_index(node, MAC_FILTER_TABLE, &j);
+		}
+		for (j = 0; j <= TNS_NULL_VIF; j++)
+			alloc_table_index(node, MAC_EVIF_TABLE, &j);
+		macfilter_freeindex[node] = TNS_MAX_VF;
+		vlanfilter_freeindex[node] = 1;
+	}
+
+	return TNS_NO_ERR;
+}
+
+int add_admin_vlan(int node, int vf, int vlan)
+{
+	int index = -1;
+	int ret;
+	struct itt_entry_s port_cfg_entry;
+
+	ret = add_vlan_entry(node, vf, vlan, index);
+	if (ret) {
+		filter_dbg(FERR, "Add admin VLAN for VF: %d Failed %d\n",
+			   vf, ret);
+		return ret;
+	}
+
+	ret = tbl_read(node, PORT_CONFIG_TABLE, vf, NULL, NULL,
+		       (void *)&port_cfg_entry);
+	if (ret)
+		return ret;
+	port_cfg_entry.is_admin_vlan_enabled = 1;
+	port_cfg_entry.admin_vlan = vlan;
+	ret = tbl_write(node, PORT_CONFIG_TABLE, vf, NULL, NULL,
+			(void *)&port_cfg_entry);
+	if (ret)
+		return ret;
+	filter_dbg(FINFO, "%s Port %d dir %d defaultVif %d adminVlan %d %s\n",
+		   __func__, vf, port_cfg_entry.pkt_dir,
+		   port_cfg_entry.default_evif, port_cfg_entry.admin_vlan,
+		   port_cfg_entry.is_admin_vlan_enabled ? "Enable" : "Disable");
+
+	return TNS_NO_ERR;
+}
+
+int del_admin_vlan(int node, int vf, int vlan)
+{
+	int index = -1;
+	int ret;
+	struct itt_entry_s port_cfg_entry;
+
+	ret = del_vlan_entry(node, vf, vlan, index);
+	if (ret) {
+		filter_dbg(FERR, "Delete admin VLAN: %d for VF %d failed %d\n",
+			   vlan, vf, ret);
+		return ret;
+	}
+
+	ret = tbl_read(node, PORT_CONFIG_TABLE, vf, NULL, NULL,
+		       (void *)&port_cfg_entry);
+	if (ret)
+		return ret;
+	port_cfg_entry.is_admin_vlan_enabled = 0;
+	port_cfg_entry.admin_vlan = 0x0;
+	ret = tbl_write(node, PORT_CONFIG_TABLE, vf, NULL, NULL,
+			(void *)&port_cfg_entry);
+	if (ret)
+		return ret;
+	filter_dbg(FINFO, "%s Port %d dir %d defaultVif %d adminVlan %d %s\n",
+		   __func__, vf, port_cfg_entry.pkt_dir,
+		   port_cfg_entry.default_evif, port_cfg_entry.admin_vlan,
+		   port_cfg_entry.is_admin_vlan_enabled ? "Enable" : "Disable");
+
+	return TNS_NO_ERR;
+}
+
+void link_status_notification(int node, int vf, void *arg)
+{
+	int status =  *((int *)arg);
+	int bcast_vif;
+	int ret;
+	struct evif_entry evif_dat;
+
+	filter_dbg(FINFO, "VF %d Link %s\n", vf, status ? "up " : "down");
+	if (status) {
+		ret = vf_bcast_vif(node, vf, &bcast_vif);
+		if (ret)
+			return;
+
+		ret = tbl_read(node, MAC_EVIF_TABLE, bcast_vif, NULL, NULL,
+			       &evif_dat);
+		if (ret)
+			return;
+
+		enable_port(vf, &evif_dat);
+		dump_evif_entry(&evif_dat);
+		ret = tbl_write(node, MAC_EVIF_TABLE, bcast_vif, NULL, NULL,
+				(void *)&evif_dat);
+		if (ret)
+			return;
+	} else {
+		ret = vf_bcast_vif(node, vf, &bcast_vif);
+		if (ret)
+			return;
+
+		ret = tbl_read(node, MAC_EVIF_TABLE, bcast_vif, NULL, NULL,
+			       &evif_dat);
+		if (ret)
+			return;
+
+		disable_port(vf, &evif_dat);
+		dump_evif_entry(&evif_dat);
+		ret = tbl_write(node, MAC_EVIF_TABLE, bcast_vif, NULL, NULL,
+				(void *)&evif_dat);
+		if (ret)
+			return;
+	}
+}
+
+void mac_update_notification(int node, int vf_id, void *arg)
+{
+	u8 *mac = (u8 *)arg;
+
+	filter_dbg(FINFO, "VF:%d MAC %02x:%02x:%02x:%02x:%02x:%02x Updated\n",
+		   vf_id, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+	vf_interface_up(node, MAC_FILTER_TABLE, vf_id, arg);
+}
+
+void promisc_update_notification(int node, int vf_id, void *arg)
+{
+	int on = *(int *)arg;
+
+	filter_dbg(FERR, "VF %d %s promiscuous mode\n", vf_id,
+		   on ? "enter" : "left");
+	if (on)
+		enable_promiscuous_mode(node, vf_id);
+	else
+		disable_promiscuous_mode(node, vf_id);
+}
+
+void uc_mc_update_notification(int node, int vf_id, void *arg)
+{
+	struct uc_mc_msg *uc_mc_cfg = (struct uc_mc_msg *)arg;
+	u8 *mac;
+
+	mac = (u8 *)uc_mc_cfg->mac_addr;
+	if (uc_mc_cfg->is_flush) {
+		filter_dbg(FINFO, "\nNOTIFICATION VF:%d %s %s\n", vf_id,
+			   uc_mc_cfg->addr_type ? "mc" : "uc", "flush");
+	} else {
+		filter_dbg(FINFO, "\nNOTIFICATION VF:%d %s %s ", vf_id,
+			   uc_mc_cfg->addr_type ? "mc" : "uc",
+			   uc_mc_cfg->is_add ? "add" : "del");
+		filter_dbg(FINFO, "MAC ADDRESS %02x:%02x:%02x:%02x:%02x:%02x\n",
+			   mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+		if (uc_mc_cfg->is_add) {
+			if (uc_mc_cfg->addr_type)
+				add_mac_filter_mcast_entry(node,
+							   MAC_FILTER_TABLE,
+							   vf_id, -1, mac);
+			else
+				add_mac_filter_entry(node, MAC_FILTER_TABLE,
+						     vf_id, -1, mac);
+		} else {
+			del_mac_filter_entry(node, MAC_FILTER_TABLE, vf_id, -1,
+					     mac, uc_mc_cfg->addr_type);
+		}
+	}
+}
+
+void admin_vlan_update_notification(int node, int vf_id, void *arg)
+{
+	struct vlan_msg *vlan_cfg = (struct vlan_msg *)arg;
+
+	filter_dbg(FINFO, "\nNOTIFICATION ADMIN VF %d VLAN id %d %s\n", vf_id,
+		   vlan_cfg->vlan_id, (vlan_cfg->vlan_add) ? "add" : "del");
+	if (vlan_cfg->vlan_add)
+		add_admin_vlan(node, vf_id, vlan_cfg->vlan_id);
+	else
+		del_admin_vlan(node, vf_id, vlan_cfg->vlan_id);
+}
+
+void vlan_update_notification(int node, int vf_id, void *arg)
+{
+	struct vlan_msg *vlan_cfg = (struct vlan_msg *)arg;
+
+	filter_dbg(FINFO, "\nNOTIFICATION VF %d VLAN id %d %s\n", vf_id,
+		   vlan_cfg->vlan_id, (vlan_cfg->vlan_add) ? "add" : "del");
+	if (vlan_cfg->vlan_add && vlan_cfg->vlan_id) {
+		int index = -1;
+		int ret = add_vlan_entry(node, vf_id, vlan_cfg->vlan_id,
+					      index);
+
+		if (ret)
+			filter_dbg(FERR, "Adding VLAN failed: %d\n", ret);
+		else
+			filter_dbg(FINFO, "VF: %d with VLAN: %d added\n",
+				   vf_id, vlan_cfg->vlan_id);
+	} else if (!vlan_cfg->vlan_add && vlan_cfg->vlan_id) {
+		int index = -1;
+		int ret = del_vlan_entry(node, vf_id, vlan_cfg->vlan_id,
+						index);
+
+		if (ret)
+			filter_dbg(FERR, "Deleting VLAN failed: %d\n", ret);
+		else
+			filter_dbg(FINFO, "VF: %d with VLAN: %d deleted\n",
+				   vf_id, vlan_cfg->vlan_id);
+	}
+}
+
+void pf_notify_msg_handler(int node, void *arg)
+{
+	union nic_mbx *mbx = (union nic_mbx *)arg;
+	int status;
+
+	switch (mbx->msg.msg) {
+	case NIC_MBOX_MSG_ADMIN_VLAN:
+		admin_vlan_update_notification(node, mbx->vlan_cfg.vf_id,
+					       &mbx->vlan_cfg);
+		break;
+	case NIC_MBOX_MSG_VLAN:
+		vlan_update_notification(node, mbx->vlan_cfg.vf_id,
+					 &mbx->vlan_cfg);
+		break;
+	case NIC_MBOX_MSG_UC_MC:
+		uc_mc_update_notification(node, mbx->vlan_cfg.vf_id,
+					  &mbx->uc_mc_cfg);
+		break;
+	case NIC_MBOX_MSG_SET_MAC:
+		mac_update_notification(node, mbx->mac.vf_id,
+					(void *)mbx->mac.mac_addr);
+		break;
+	case NIC_MBOX_MSG_CFG_DONE:
+	case NIC_MBOX_MSG_OP_UP:
+		status = true;
+		link_status_notification(node, mbx->mac.vf_id, (void *)&status);
+		break;
+	case NIC_MBOX_MSG_SHUTDOWN:
+	case NIC_MBOX_MSG_OP_DOWN:
+		status = false;
+		link_status_notification(node, mbx->mac.vf_id, (void *)&status);
+		break;
+	case NIC_MBOX_MSG_PROMISC:
+		status = mbx->promisc_cfg.on;
+		promisc_update_notification(node, mbx->promisc_cfg.vf_id,
+					    (void *)&status);
+		break;
+	}
+}
+
+int pf_filter_init(void)
+{
+	mac_filter_config();
+
+	return 0;
+}
-- 
1.8.3.1

  parent reply	other threads:[~2016-12-21  8:48 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-12-21  8:46 [RFC PATCH 0/7] ThunderX Embedded switch support Satha Koteswara Rao
2016-12-21  8:46 ` [RFC PATCH 1/7] PF driver modified to enable HW filter support, changes works in backward compatibility mode Enable required things in Makefile Enable LZ4 dependecy inside config file Satha Koteswara Rao
2016-12-21 13:05   ` Sunil Kovvuri
2016-12-26 14:20     ` Koteshwar Rao, Satha
2016-12-27  4:19       ` Sunil Kovvuri
2016-12-21  8:46 ` [RFC PATCH 2/7] VF driver changes to enable hooks to get kernel notifications Satha Koteswara Rao
2016-12-21  8:46 ` [RFC PATCH 3/7] Enable pause frame support Satha Koteswara Rao
     [not found]   ` <DM5PR07MB2889471E0668C95BD2A266709E930@DM5PR07MB2889.namprd07.prod.outlook.com>
2016-12-26 14:21     ` Koteshwar Rao, Satha
2016-12-21  8:46 ` [RFC PATCH 4/7] HW Filter Initialization code and register access APIs Satha Koteswara Rao
2016-12-21 12:36   ` Sunil Kovvuri
2016-12-26 14:13     ` Koteshwar Rao, Satha
2016-12-21  8:46 ` [RFC PATCH 5/7] Multiple VF's grouped together under single physical port called PF group PF Group maintainance API's Satha Koteswara Rao
2016-12-21 12:43   ` Sunil Kovvuri
2016-12-26 14:16     ` Koteshwar Rao, Satha
2016-12-21  8:46 ` [RFC PATCH 6/7] HW Filter Table access API's Satha Koteswara Rao
2016-12-21  8:46 ` Satha Koteswara Rao [this message]
2016-12-21 12:03 ` [RFC PATCH 0/7] ThunderX Embedded switch support Sunil Kovvuri
2016-12-26 14:04   ` Koteshwar Rao, Satha
2016-12-26 14:55     ` Andrew Lunn

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1482310011-1862-8-git-send-email-satha.rao@caviumnetworks.com \
    --to=satha.rao@caviumnetworks.com \
    --cc=davem@davemloft.net \
    --cc=david.daney@cavium.com \
    --cc=derek.chickles@caviumnetworks.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=philip.romanov@cavium.com \
    --cc=rric@kernel.org \
    --cc=rvatsavayi@caviumnetworks.com \
    --cc=sgoutham@cavium.com \
    --subject='Re: [RFC PATCH 7/7] Get notifications from PF driver and configure filter block based on request data' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

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