[qca-nss-drv] add support for vlan configuration

Enables sending of configuration messages to vlan dynamic interface
in NSS. This includes messages such as assign vsi/unassign vsi/add tag
/set mtu/set mac_addr.

Change-Id: Ie5b15b1512bc34f8a190d8aaa8c72459686c39fd
Signed-off-by: Stephen Wang <wstephen@codeaurora.org>
diff --git a/Makefile b/Makefile
index f35dbaf..14ce906 100644
--- a/Makefile
+++ b/Makefile
@@ -50,6 +50,7 @@
 			nss_trustsec_tx.o \
 			nss_tunipip6.o \
 			nss_virt_if.o \
+			nss_vlan.o \
 			nss_wifi.o \
 			nss_wifi_if.o \
 			nss_wifi_vdev.o
diff --git a/exports/nss_api_if.h b/exports/nss_api_if.h
index 433883a..7f0ed1a 100644
--- a/exports/nss_api_if.h
+++ b/exports/nss_api_if.h
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
  * above copyright notice and this permission notice appear in all copies.
@@ -68,6 +68,7 @@
 #include "nss_bridge.h"
 #include "nss_ppe.h"
 #include "nss_trustsec_tx.h"
+#include "nss_vlan.h"
 
 /*
  * Interface numbers are reserved in the
@@ -95,7 +96,7 @@
 #define NSS_MAX_PHYSICAL_INTERFACES 8
 #define NSS_MAX_VIRTUAL_INTERFACES 16
 #define NSS_MAX_TUNNEL_INTERFACES 4
-#define NSS_MAX_SPECIAL_INTERFACES 44
+#define NSS_MAX_SPECIAL_INTERFACES 45
 #define NSS_MAX_WIFI_RADIO_INTERFACES 3
 
 /**
@@ -154,6 +155,7 @@
 #define NSS_EDMA_INTERFACE (NSS_SPECIAL_IF_START + 41)	/* Special EDMA interface */
 #define NSS_GRE_TUNNEL_INTERFACE (NSS_SPECIAL_IF_START + 42)  /* Special NSS GRE TUNNEL interface */
 #define NSS_TRUSTSEC_TX_INTERFACE (NSS_SPECIAL_IF_START + 43)  /* Special TrustSec TX interface */
+#define NSS_VLAN_INTERFACE (NSS_SPECIAL_IF_START + 44)  /* Special VLAN interface */
 
 /**
  * This macro converts format for IPv6 address (from Linux to NSS)
diff --git a/exports/nss_dynamic_interface.h b/exports/nss_dynamic_interface.h
index 164b56a..9fce590 100644
--- a/exports/nss_dynamic_interface.h
+++ b/exports/nss_dynamic_interface.h
@@ -1,6 +1,6 @@
 /*
  **************************************************************************
- * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved.
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
  * above copyright notice and this permission notice appear in all copies.
@@ -45,6 +45,7 @@
 	NSS_DYNAMIC_INTERFACE_TYPE_MAP_T,		/* MAP-T Interface Type */
 	NSS_DYNAMIC_INTERFACE_TYPE_GRE_TUNNEL,		/* GRE Tunnel Interface Type */
 	NSS_DYNAMIC_INTERFACE_TYPE_BRIDGE,		/* Bridge Interface Type */
+	NSS_DYNAMIC_INTERFACE_TYPE_VLAN,		/* VLAN Interface Type */
 	NSS_DYNAMIC_INTERFACE_TYPE_MAX
 };
 
diff --git a/exports/nss_vlan.h b/exports/nss_vlan.h
new file mode 100644
index 0000000..63f8c02
--- /dev/null
+++ b/exports/nss_vlan.h
@@ -0,0 +1,207 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all copies.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ **************************************************************************
+ */
+
+/*
+ * nss_vlan.h
+ *	NSS TO HLOS interface definitions.
+ */
+
+#ifndef __NSS_VLAN_H
+#define __NSS_VLAN_H
+
+/**
+ * Vlan message types
+ */
+enum nss_vlan_msg_types {
+	NSS_VLAN_MSG_ADD_TAG = NSS_IF_MAX_MSG_TYPES + 1,
+					/**< Msg to add vlan tag on physical interface */
+	NSS_VLAN_MSG_TYPE_MAX,	/**< Max message types */
+};
+
+/**
+ * Vlan error types
+ */
+enum nss_vlan_error_types {
+	NSS_VLAN_ERROR_UNKNOWN_MSG = NSS_IF_ERROR_TYPE_MAX + 1,
+					/**< Message type is unknown */
+	NSS_VLAN_ERROR_TYPE_MAX,	/**< Max message types */
+};
+
+#define NSS_VLAN_TYPE_SINGLE 0
+#define NSS_VLAN_TYPE_DOUBLE 1
+
+/**
+ * VLAN message - add vlan tag
+ */
+struct nss_vlan_msg_add_tag {
+	uint32_t vlan_tag;	/* VLAN tag information */
+	uint32_t next_hop;	/* Parent interface */
+	uint32_t if_num;	/* Real Physical Interface */
+};
+
+/**
+ * Message structure to send/receive vlan messages
+ */
+struct nss_vlan_msg {
+	struct nss_cmn_msg cm;					/**< Message Header */
+	union {
+		union nss_if_msgs if_msg;			/**< nss_if base messages */
+		struct nss_vlan_msg_add_tag add_tag;		/**< Vlan add tag message */
+	} msg;
+};
+
+/**
+ * @brief Send vlan messages
+ *
+ * @param nss_ctx NSS context
+ * @param msg NSS vlan message
+ *
+ * @return nss_tx_status_t Tx status
+ */
+nss_tx_status_t nss_vlan_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_vlan_msg *msg);
+
+/**
+ * @brief Send vlan messages synchronously
+ *
+ * @param nss_ctx NSS context
+ * @param msg NSS vlan message
+ *
+ * @return nss_tx_status_t Tx status
+ */
+nss_tx_status_t nss_vlan_tx_msg_sync(struct nss_ctx_instance *nss_ctx, struct nss_vlan_msg *msg);
+
+/**
+ * @brief Initialize vlan msg
+ *
+ * @param nss_vlan_msg
+ * @param if_num Interface number
+ * @param type Message type
+ * @param len Message length
+ * @param cb message callback
+ * @param app_data
+ *
+ * @return None
+ */
+void nss_vlan_msg_init(struct nss_vlan_msg *ncm, uint16_t if_num, uint32_t type,  uint32_t len, void *cb, void *app_data);
+
+/**
+ * @brief Get the vlan context used in the nss_vlan_tx
+ *
+ * @return struct nss_ctx_instance *NSS context
+ */
+struct nss_ctx_instance *nss_vlan_get_context(void);
+
+/**
+ * @brief Callback when vlan data is received
+ *
+ * @param netdevice of vlan interface
+ * @param skb Pointer to data buffer
+ * @param napi pointer
+ *
+ * @return void
+ */
+typedef void (*nss_vlan_callback_t)(struct net_device *netdev, struct sk_buff *skb, struct napi_struct *napi);
+
+/**
+ * @brief Callback to receive vlan messages
+ *
+ * @param app_data Application context of the message
+ * @param msg Message data
+ *
+ * @return void
+ */
+typedef void (*nss_vlan_msg_callback_t)(void *app_data, struct nss_vlan_msg *msg);
+
+/**
+ * @brief Register to send/receive vlan messages to NSS
+ *
+ * @param if_num NSS interface number
+ * @param vlan_data_callback Callback for vlan data
+ * @param netdev netdevice associated with the vlan interface
+ * @param features denotes the skb types supported by this interface
+ *
+ * @return nss_ctx_instance* NSS context
+ */
+struct nss_ctx_instance *nss_register_vlan_if(uint32_t if_num, nss_vlan_callback_t vlan_data_callback,
+					      struct net_device *netdev, uint32_t features, void *app_ctx);
+
+/**
+ * @brief Unregister vlan interface with NSS
+ *
+ * @return void
+ */
+void nss_unregister_vlan_if(uint32_t if_num);
+
+/*
+ * @brief Send vlan set mtu message
+ *
+ * @param vlan_if_num NSS dynamic interface
+ * @param mtu MTU value to be set
+ *
+ * @return nss_tx_status_t Tx status
+ */
+nss_tx_status_t nss_vlan_tx_set_mtu_msg(uint32_t vlan_if_num, uint32_t mtu);
+
+/**
+ * @brief Send vlan set mac address message
+ *
+ * @param vlan_if_num NSS dynamic interface
+ * @param addr MAC addr to be set
+ *
+ * @return nss_tx_status_t Tx status
+ */
+nss_tx_status_t nss_vlan_tx_set_mac_addr_msg(uint32_t vlan_if_num, uint8_t *addr);
+
+/**
+ * @brief Send vlan attach VSI message
+ *
+ * @param vlan_if_num NSS dynamic interface
+ * @param vsi PPE VSI to attach
+ *
+ * @return nss_tx_status_t Tx status
+ */
+nss_tx_status_t nss_vlan_tx_vsi_attach_msg(uint32_t vlan_if_num, uint32_t vsi);
+
+/**
+ * @brief Send vlan detach VSI message
+ *
+ * @param vlan_if_num NSS dynamic interface
+ * @param vsi PPE VSI to detach
+ *
+ * @return nss_tx_status_t Tx status
+ */
+nss_tx_status_t nss_vlan_tx_vsi_detach_msg(uint32_t vlan_if_num, uint32_t vsi);
+
+/**
+ * @brief Send vlan add tag message
+ *
+ * @param vlan_if_num NSS dynamic interface
+ * @param vlan_tag vlan tag info
+ * @param next_hop parent interface
+ * @param physical_dev physical port which to add vlan tag
+ *
+ * @return nss_tx_status_t Tx status
+ */
+nss_tx_status_t nss_vlan_tx_add_tag_msg(uint32_t vlan_if_num, uint32_t vlan_tag, uint32_t next_hop, uint32_t physical_dev);
+
+/**
+ * @brief Initialize vlan
+ *
+ * @return None
+ */
+void nss_vlan_register_handler(void);
+
+#endif /* __NSS_VLAN_H */
diff --git a/nss_core.h b/nss_core.h
index e396f1f..64104f1 100644
--- a/nss_core.h
+++ b/nss_core.h
@@ -998,6 +998,7 @@
 	uint8_t edma_handler_id;
 	uint8_t bridge_handler_id;
 	uint8_t trustsec_tx_handler_id;
+	uint8_t vlan_handler_id;
 
 	/* subsystem registration data */
 	struct nss_subsystem_dataplane_register subsys_dp_register[NSS_MAX_NET_INTERFACES];
@@ -1052,6 +1053,8 @@
 					/* EDMA callback */
 	nss_bridge_msg_callback_t bridge_callback;
 					/* Bridge callback */
+	nss_vlan_msg_callback_t vlan_callback;
+					/* Vlan callback */
 	uint32_t dynamic_interface_table[NSS_DYNAMIC_INTERFACE_TYPE_MAX];
 
 	/*
@@ -1069,6 +1072,7 @@
 	void *oam_ctx;			/* oam context */
 	void *edma_ctx;			/* edma context */
 	void *bridge_ctx;		/* Bridge context */
+	void *vlan_ctx;			/* Vlan context */
 
 	/*
 	 * Statistics for various interfaces
@@ -1292,6 +1296,8 @@
 				/* Does this core handle WIFI OFFLOAD? */
 	enum nss_feature_enabled bridge_enabled;
 				/* Does this core handle bridge configuration */
+	enum nss_feature_enabled vlan_enabled;
+				/* Does this core handle vlan configuration */
 };
 #endif
 
diff --git a/nss_hal/nss_hal.c b/nss_hal/nss_hal.c
index 8adade5..2a7271b 100644
--- a/nss_hal/nss_hal.c
+++ b/nss_hal/nss_hal.c
@@ -123,6 +123,7 @@
 	npd->wlanredirect_enabled = of_property_read_bool(np, "qcom,wlanredirect-enabled");
 	npd->wifioffload_enabled = of_property_read_bool(np, "qcom,wlan-dataplane-offload-enabled");
 	npd->bridge_enabled = of_property_read_bool(np, "qcom,bridge-enabled");
+	npd->vlan_enabled = of_property_read_bool(np, "qcom,vlan-enabled");
 }
 
 /*
@@ -489,6 +490,12 @@
 		nss_bridge_init();
 	}
 
+	if (npd->vlan_enabled == NSS_FEATURE_ENABLED) {
+		nss_top->vlan_handler_id = nss_dev->id;
+		nss_top->dynamic_interface_table[NSS_DYNAMIC_INTERFACE_TYPE_VLAN] = nss_dev->id;
+		nss_vlan_register_handler();
+	}
+
 	if (nss_ctx->id == 0) {
 #if (NSS_FREQ_SCALE_SUPPORT == 1)
 		nss_freq_register_handler();
diff --git a/nss_vlan.c b/nss_vlan.c
new file mode 100644
index 0000000..7001f24
--- /dev/null
+++ b/nss_vlan.c
@@ -0,0 +1,437 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all copies.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ **************************************************************************
+ */
+
+#include "nss_tx_rx_common.h"
+
+#define NSS_VLAN_TX_TIMEOUT 1000 /* 1 Second */
+
+/*
+ * Private data structure
+ */
+static struct nss_vlan_pvt {
+	struct semaphore sem;
+	struct completion complete;
+	int response;
+	void *cb;
+	void *app_data;
+} vlan_pvt;
+
+/*
+ * nss_vlan_verify_if_num()
+ *	Verify if_num passed to us.
+ */
+static bool nss_vlan_verify_if_num(uint32_t if_num)
+{
+	if (!nss_is_dynamic_interface(if_num)) {
+		return false;
+	}
+
+	if (nss_dynamic_interface_get_type(if_num) != NSS_DYNAMIC_INTERFACE_TYPE_VLAN) {
+		return false;
+	}
+
+	return true;
+}
+
+/*
+ * nss_vlan_handler()
+ *	Handle NSS -> HLOS messages for vlan
+ */
+static void nss_vlan_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, void *app_data)
+{
+	struct nss_vlan_msg *nvm = (struct nss_vlan_msg *)ncm;
+	nss_vlan_msg_callback_t cb;
+
+	nss_assert(nss_vlan_verify_if_num(ncm->interface));
+
+	/*
+	 * Is this a valid request/response packet?
+	 */
+	if (ncm->type >= NSS_VLAN_MSG_TYPE_MAX) {
+		nss_warning("%p: received invalid message %d for vlan interface", nss_ctx, ncm->type);
+		return;
+	}
+
+	if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_vlan_msg)) {
+		nss_warning("%p: length of message is greater than required: %d", nss_ctx, nss_cmn_get_msg_len(ncm));
+		return;
+	}
+
+	/*
+	 * Update the callback and app_data for NOTIFY messages, vlan sends all notify messages
+	 * to the same callback/app_data.
+	 */
+	if (ncm->response == NSS_CMM_RESPONSE_NOTIFY) {
+		ncm->cb = (nss_ptr_t)nss_ctx->nss_top->vlan_callback;
+		ncm->app_data = (nss_ptr_t)app_data;
+	}
+
+	/*
+	 * Log failures
+	 */
+	nss_core_log_msg_failures(nss_ctx, ncm);
+
+	/*
+	 * Do we have a call back
+	 */
+	if (!ncm->cb) {
+		return;
+	}
+
+	/*
+	 * callback
+	 */
+	cb = (nss_vlan_msg_callback_t)ncm->cb;
+	cb((void *)ncm->app_data, nvm);
+}
+
+/*
+ * nss_vlan_callback()
+ *	Callback to handle the completion of NSS->HLOS messages.
+ */
+static void nss_vlan_callback(void *app_data, struct nss_vlan_msg *nvm)
+{
+	nss_vlan_msg_callback_t callback = (nss_vlan_msg_callback_t)vlan_pvt.cb;
+	void *data = vlan_pvt.app_data;
+
+	vlan_pvt.response = NSS_TX_SUCCESS;
+	vlan_pvt.cb = NULL;
+	vlan_pvt.app_data = NULL;
+
+	if (nvm->cm.response != NSS_CMN_RESPONSE_ACK) {
+		nss_warning("vlan error response %d\n", nvm->cm.response);
+		vlan_pvt.response = nvm->cm.response;
+	}
+
+	if (callback) {
+		callback(data, nvm);
+	}
+	complete(&vlan_pvt.complete);
+}
+
+/*
+ * nss_vlan_tx_msg()
+ *	Transmit a vlan message to NSSFW
+ */
+nss_tx_status_t nss_vlan_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_vlan_msg *msg)
+{
+	struct nss_vlan_msg *nm;
+	struct nss_cmn_msg *ncm = &msg->cm;
+	struct sk_buff *nbuf;
+	int32_t status;
+
+	NSS_VERIFY_CTX_MAGIC(nss_ctx);
+	if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
+		nss_warning("%p: vlan msg dropped as core not ready", nss_ctx);
+		return NSS_TX_FAILURE_NOT_READY;
+	}
+
+	/*
+	 * Sanity check the message
+	 */
+	if (!nss_vlan_verify_if_num(ncm->interface)) {
+		nss_warning("%p: tx request for interface that is not a vlan: %d", nss_ctx, ncm->interface);
+		return NSS_TX_FAILURE;
+	}
+
+	if (ncm->type >= NSS_VLAN_MSG_TYPE_MAX) {
+		nss_warning("%p: message type out of range: %d", nss_ctx, ncm->type);
+		return NSS_TX_FAILURE;
+	}
+
+	if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_vlan_msg)) {
+		nss_warning("%p: message length is invalid: %d", nss_ctx, nss_cmn_get_msg_len(ncm));
+		return NSS_TX_FAILURE;
+	}
+
+	nbuf = dev_alloc_skb(NSS_NBUF_PAYLOAD_SIZE);
+	if (unlikely(!nbuf)) {
+		NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NBUF_ALLOC_FAILS]);
+		nss_warning("%p: msg dropped as command allocation failed", nss_ctx);
+		return NSS_TX_FAILURE;
+	}
+
+	/*
+	 * Copy the message to our skb
+	 */
+	nm = (struct nss_vlan_msg *)skb_put(nbuf, sizeof(struct nss_vlan_msg));
+	memcpy(nm, msg, sizeof(struct nss_vlan_msg));
+
+	status = nss_core_send_buffer(nss_ctx, 0, nbuf, NSS_IF_CMD_QUEUE, H2N_BUFFER_CTRL, 0);
+	if (status != NSS_CORE_STATUS_SUCCESS) {
+		dev_kfree_skb_any(nbuf);
+		nss_warning("%p: Unable to enqueue 'vlan message'", nss_ctx);
+		return NSS_TX_FAILURE;
+	}
+
+	nss_hal_send_interrupt(nss_ctx, NSS_H2N_INTR_DATA_COMMAND_QUEUE);
+
+	NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_CMD_REQ]);
+	return NSS_TX_SUCCESS;
+}
+EXPORT_SYMBOL(nss_vlan_tx_msg);
+
+/*
+ * nss_vlan_tx_msg_sync()
+ *	Transmit a vlan message to NSS firmware synchronously.
+ */
+nss_tx_status_t nss_vlan_tx_msg_sync(struct nss_ctx_instance *nss_ctx, struct nss_vlan_msg *nvm)
+{
+	nss_tx_status_t status;
+	int ret = 0;
+
+	down(&vlan_pvt.sem);
+	vlan_pvt.cb = (void *)nvm->cm.cb;
+	vlan_pvt.app_data = (void *)nvm->cm.app_data;
+
+	nvm->cm.cb = (nss_ptr_t)nss_vlan_callback;
+	nvm->cm.app_data = (nss_ptr_t)NULL;
+
+	status = nss_vlan_tx_msg(nss_ctx, nvm);
+	if (status != NSS_TX_SUCCESS) {
+		nss_warning("%p: vlan_tx_msg failed\n", nss_ctx);
+		up(&vlan_pvt.sem);
+		return status;
+	}
+
+	ret = wait_for_completion_timeout(&vlan_pvt.complete, msecs_to_jiffies(NSS_VLAN_TX_TIMEOUT));
+	if (!ret) {
+		nss_warning("%p: vlan msg tx failed due to timeout\n", nss_ctx);
+		vlan_pvt.response = NSS_TX_FAILURE;
+	}
+
+	status = vlan_pvt.response;
+	up(&vlan_pvt.sem);
+	return status;
+}
+EXPORT_SYMBOL(nss_vlan_tx_msg_sync);
+
+/*
+ * nss_vlan_get_context()
+ */
+struct nss_ctx_instance *nss_vlan_get_context(void)
+{
+	return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.vlan_handler_id];
+}
+EXPORT_SYMBOL(nss_vlan_get_context);
+
+/*
+ * nss_vlan_msg_init()
+ *	Initialize nss_vlan_msg.
+ */
+void nss_vlan_msg_init(struct nss_vlan_msg *ncm, uint16_t if_num, uint32_t type, uint32_t len, void *cb, void *app_data)
+{
+	nss_cmn_msg_init(&ncm->cm, if_num, type, len, cb, app_data);
+}
+EXPORT_SYMBOL(nss_vlan_msg_init);
+
+/*
+ * nss_vlan_tx_change_mtu_msg
+ *	API to send change mtu message to NSS FW
+ */
+nss_tx_status_t nss_vlan_tx_set_mtu_msg(uint32_t vlan_if_num, uint32_t mtu)
+{
+	struct nss_ctx_instance *nss_ctx = nss_vlan_get_context();
+	struct nss_vlan_msg nvm;
+	struct nss_if_mtu_change *nimc;
+
+	if (!nss_ctx) {
+		nss_warning("Can't get nss context\n");
+		return NSS_TX_FAILURE;
+	}
+
+	if (nss_vlan_verify_if_num(vlan_if_num) == false) {
+		nss_warning("%p: received invalid interface %d", nss_ctx, vlan_if_num);
+		return NSS_TX_FAILURE;
+	}
+
+	nss_vlan_msg_init(&nvm, vlan_if_num, NSS_IF_MTU_CHANGE,
+			sizeof(struct nss_if_mtu_change), NULL, NULL);
+
+	nimc = &nvm.msg.if_msg.mtu_change;
+	nimc->min_buf_size = (uint16_t)mtu;
+
+	return nss_vlan_tx_msg_sync(nss_ctx, &nvm);
+}
+EXPORT_SYMBOL(nss_vlan_tx_set_mtu_msg);
+
+/*
+ * nss_vlan_tx_set_mac_addr_msg
+ *	API to send change mac addr message to NSS FW
+ */
+nss_tx_status_t nss_vlan_tx_set_mac_addr_msg(uint32_t vlan_if_num, uint8_t *addr)
+{
+	struct nss_ctx_instance *nss_ctx = nss_vlan_get_context();
+	struct nss_vlan_msg nvm;
+	struct nss_if_mac_address_set *nmas;
+
+	if (!nss_ctx) {
+		nss_warning("Can't get nss context\n");
+		return NSS_TX_FAILURE;
+	}
+
+	if (nss_vlan_verify_if_num(vlan_if_num) == false) {
+		nss_warning("%p: received invalid interface %d", nss_ctx, vlan_if_num);
+		return NSS_TX_FAILURE;
+	}
+
+	nss_vlan_msg_init(&nvm, vlan_if_num, NSS_IF_MAC_ADDR_SET,
+			sizeof(struct nss_if_mac_address_set), NULL, NULL);
+
+	nmas = &nvm.msg.if_msg.mac_address_set;
+	memcpy(nmas->mac_addr, addr, ETH_ALEN);
+	return nss_vlan_tx_msg_sync(nss_ctx, &nvm);
+}
+EXPORT_SYMBOL(nss_vlan_tx_set_mac_addr_msg);
+
+/*
+ * nss_vlan_tx_vsi_attach_msg
+ *	API to send VSI attach message to NSS FW
+ */
+nss_tx_status_t nss_vlan_tx_vsi_attach_msg(uint32_t vlan_if_num, uint32_t vsi)
+{
+	struct nss_ctx_instance *nss_ctx = nss_vlan_get_context();
+	struct nss_vlan_msg nvm;
+
+	if (!nss_ctx) {
+		nss_warning("Can't get nss context\n");
+		return NSS_TX_FAILURE;
+	}
+
+	if (nss_vlan_verify_if_num(vlan_if_num) == false) {
+		nss_warning("%p: received invalid interface %d\n", nss_ctx, vlan_if_num);
+		return NSS_TX_FAILURE;
+	}
+
+	nvm.msg.if_msg.vsi_assign.vsi = vsi;
+	nss_vlan_msg_init(&nvm, vlan_if_num, NSS_IF_VSI_ASSIGN,
+				sizeof(struct nss_if_vsi_assign), NULL, NULL);
+
+	return nss_vlan_tx_msg_sync(nss_ctx, &nvm);
+}
+EXPORT_SYMBOL(nss_vlan_tx_vsi_attach_msg);
+
+/*
+ * nss_vlan_tx_vsi_detach_msg
+ *	API to send VSI detach message to NSS FW
+ */
+nss_tx_status_t nss_vlan_tx_vsi_detach_msg(uint32_t vlan_if_num, uint32_t vsi)
+{
+	struct nss_ctx_instance *nss_ctx = nss_vlan_get_context();
+	struct nss_vlan_msg nvm;
+
+	if (!nss_ctx) {
+		nss_warning("Can't get nss context\n");
+		return NSS_TX_FAILURE;
+	}
+
+	if (nss_vlan_verify_if_num(vlan_if_num) == false) {
+		nss_warning("%p: received invalid interface %d\n", nss_ctx, vlan_if_num);
+		return NSS_TX_FAILURE;
+	}
+
+	nvm.msg.if_msg.vsi_unassign.vsi = vsi;
+	nss_vlan_msg_init(&nvm, vlan_if_num, NSS_IF_VSI_UNASSIGN,
+				sizeof(struct nss_if_vsi_unassign), NULL, NULL);
+
+	return nss_vlan_tx_msg_sync(nss_ctx, &nvm);
+}
+EXPORT_SYMBOL(nss_vlan_tx_vsi_detach_msg);
+
+/*
+ * nss_vlan_tx_add_tag_msg
+ *	API to send vlan add tag message to NSS FW
+ */
+nss_tx_status_t nss_vlan_tx_add_tag_msg(uint32_t vlan_if_num, uint32_t vlan_tag, uint32_t next_hop, uint32_t physical_dev)
+{
+	struct nss_ctx_instance *nss_ctx = nss_vlan_get_context();
+	struct nss_vlan_msg nvm;
+
+	if (!nss_ctx) {
+		nss_warning("Can't get nss context\n");
+		return NSS_TX_FAILURE;
+	}
+
+	if (nss_vlan_verify_if_num(vlan_if_num) == false) {
+		nss_warning("%p: received invalid interface %d\n", nss_ctx, vlan_if_num);
+		return NSS_TX_FAILURE;
+	}
+
+	nvm.msg.add_tag.next_hop = next_hop;
+	nvm.msg.add_tag.if_num = physical_dev;
+	nvm.msg.add_tag.vlan_tag = vlan_tag;
+	nss_vlan_msg_init(&nvm, vlan_if_num, NSS_VLAN_MSG_ADD_TAG,
+				sizeof(struct nss_vlan_msg_add_tag), NULL, NULL);
+
+	return nss_vlan_tx_msg_sync(nss_ctx, &nvm);
+}
+EXPORT_SYMBOL(nss_vlan_tx_add_tag_msg);
+
+/**
+ * @brief Register to send/receive vlan messages to NSS
+ *
+ * @param if_num NSS interface number
+ * @param vlan_data_callback Callback for vlan data
+ * @param netdev netdevice associated with the vlan interface
+ * @param features denotes the skb types supported by this interface
+ *
+ * @return nss_ctx_instance* NSS context
+ */
+struct nss_ctx_instance *nss_register_vlan_if(uint32_t if_num, nss_vlan_callback_t vlan_data_callback,
+					      struct net_device *netdev, uint32_t features, void *app_ctx)
+{
+	nss_assert(nss_vlan_verify_if_num(if_num));
+
+	nss_top_main.subsys_dp_register[if_num].ndev = netdev;
+	nss_top_main.subsys_dp_register[if_num].cb = vlan_data_callback;
+	nss_top_main.subsys_dp_register[if_num].app_data = app_ctx;
+	nss_top_main.subsys_dp_register[if_num].features = features;
+
+	nss_core_register_handler(if_num, nss_vlan_handler, app_ctx);
+
+	return nss_vlan_get_context();
+}
+EXPORT_SYMBOL(nss_register_vlan_if);
+
+/*
+ * nss_unregister_vlan_if()
+ */
+void nss_unregister_vlan_if(uint32_t if_num)
+{
+	nss_assert(nss_vlan_verify_if_num(if_num));
+
+	nss_top_main.subsys_dp_register[if_num].ndev = NULL;
+	nss_top_main.subsys_dp_register[if_num].cb = NULL;
+	nss_top_main.subsys_dp_register[if_num].app_data = NULL;
+	nss_top_main.subsys_dp_register[if_num].features = 0;
+
+	nss_core_unregister_handler(if_num);
+}
+EXPORT_SYMBOL(nss_unregister_vlan_if);
+
+/*
+ * nss_vlan_register_handler()
+ *   debugfs stats msg handler received on static vlan interface
+ */
+void nss_vlan_register_handler(void)
+{
+	nss_info("nss_vlan_register_handler\n");
+	nss_core_register_handler(NSS_VLAN_INTERFACE, nss_vlan_handler, NULL);
+
+	sema_init(&vlan_pvt.sem, 1);
+	init_completion(&vlan_pvt.complete);
+}
+EXPORT_SYMBOL(nss_vlan_register_handler);