diff --git a/drivers/event/octeontx/Makefile b/drivers/event/octeontx/Makefile
index 896e556..3076b85 100644
--- a/drivers/event/octeontx/Makefile
+++ b/drivers/event/octeontx/Makefile
@@ -47,6 +47,7 @@ LIBABIVER := 1
 # all source are stored in SRCS-y
 #
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_OCTEONTX_SSOVF) += ssovf_probe.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_OCTEONTX_SSOVF) += ssovf_mbox.c
 
 # install this header file
 SYMLINK-$(CONFIG_RTE_LIBRTE_PMD_OCTEONTX_SSOVF)-include := rte_pmd_octeontx_ssovf.h
diff --git a/drivers/event/octeontx/rte_pmd_octeontx_ssovf.h b/drivers/event/octeontx/rte_pmd_octeontx_ssovf.h
index e92a61f..3da7cfd 100644
--- a/drivers/event/octeontx/rte_pmd_octeontx_ssovf.h
+++ b/drivers/event/octeontx/rte_pmd_octeontx_ssovf.h
@@ -46,8 +46,16 @@ enum octeontx_ssovf_type {
 	OCTEONTX_SSO_HWS,  /* SSO hardware workslot vf */
 };
 
+struct octeontx_mbox_hdr {
+	uint16_t vfid;  /* VF index or pf resource index local to the domain */
+	uint8_t coproc; /* Coprocessor id */
+	uint8_t msg;    /* Message id */
+	uint8_t res_code; /* Functional layer response code */
+};
 
 int octeontx_ssovf_info(struct octeontx_ssovf_info *info);
 void *octeontx_ssovf_bar(enum octeontx_ssovf_type, uint8_t id, uint8_t bar);
+int octeontx_ssovf_mbox_send(struct octeontx_mbox_hdr *hdr,
+		void *txdata, uint16_t txlen, void *rxdata, uint16_t rxlen);
 
 #endif /* __RTE_PMD_OCTEONTX_SSOVF_H__ */
diff --git a/drivers/event/octeontx/rte_pmd_octeontx_ssovf_version.map b/drivers/event/octeontx/rte_pmd_octeontx_ssovf_version.map
index c71d4c7..3810a03 100644
--- a/drivers/event/octeontx/rte_pmd_octeontx_ssovf_version.map
+++ b/drivers/event/octeontx/rte_pmd_octeontx_ssovf_version.map
@@ -3,6 +3,7 @@ DPDK_17.05 {
 
 	octeontx_ssovf_info;
 	octeontx_ssovf_bar;
+	octeontx_ssovf_mbox_send;
 
 	local: *;
 };
diff --git a/drivers/event/octeontx/ssovf_mbox.c b/drivers/event/octeontx/ssovf_mbox.c
new file mode 100644
index 0000000..d07750f
--- /dev/null
+++ b/drivers/event/octeontx/ssovf_mbox.c
@@ -0,0 +1,232 @@
+/*
+ *   BSD LICENSE
+ *
+ *   Copyright (C) Cavium networks Ltd. 2017.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Cavium networks nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+#include <rte_atomic.h>
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_io.h>
+#include <rte_spinlock.h>
+
+#include "ssovf_evdev.h"
+
+/* Mbox operation timeout in milliseconds */
+#define MBOX_WAIT_TIME		3000
+#define MAX_RAM_MBOX_LEN	((SSOW_BAR4_LEN >> 1) - 8 /* Mbox header */)
+
+/* Mbox channel state */
+enum {
+	MBOX_CHAN_STATE_REQ = 1,
+	MBOX_CHAN_STATE_RES = 0,
+};
+
+/* Response messages */
+enum {
+	MBOX_RET_SUCCESS,
+	MBOX_RET_INVALID,
+	MBOX_RET_INTERNAL_ERR,
+};
+
+struct mbox {
+	int init_once;
+	uint8_t *ram_mbox_base; /* Base address of mbox message stored in ram */
+	uint8_t *reg; /* Store to this register triggers PF mbox interrupt */
+	uint16_t tag_own; /* Last tag which was written to own channel */
+	rte_spinlock_t lock;
+};
+
+static struct mbox octeontx_mbox;
+
+/*
+ * Structure used for mbox synchronization
+ * This structure sits at the begin of Mbox RAM and used as main
+ * synchronization point for channel communication
+ */
+struct mbox_ram_hdr {
+	union {
+		uint64_t u64;
+		struct {
+			uint8_t chan_state : 1;
+			uint8_t coproc : 7;
+			uint8_t msg;
+			uint8_t vfid;
+			uint8_t res_code;
+			uint16_t tag;
+			uint16_t len;
+		};
+	};
+};
+
+static inline void
+mbox_send_requeust(struct mbox *m, struct octeontx_mbox_hdr *hdr,
+			const void *txmsg, uint16_t txsize)
+{
+	struct mbox_ram_hdr old_hdr;
+	struct mbox_ram_hdr new_hdr = {0};
+	uint64_t *ram_mbox_hdr = (uint64_t *)m->ram_mbox_base;
+	uint8_t *ram_mbox_msg = m->ram_mbox_base + sizeof(struct mbox_ram_hdr);
+
+	/*
+	 * Initialize the channel with the tag left by last send.
+	 * On success full mbox send complete, PF increments the tag by one.
+	 * The sender can validate integrity of PF message with this scheme
+	 */
+	old_hdr.u64 = rte_read64(ram_mbox_hdr);
+	m->tag_own = (old_hdr.tag + 2) & (~0x1ul); /* next even number */
+
+	/* Copy msg body */
+	if (txmsg)
+		memcpy(ram_mbox_msg, txmsg, txsize);
+
+	/* Prepare new hdr */
+	new_hdr.chan_state = MBOX_CHAN_STATE_REQ;
+	new_hdr.coproc = hdr->coproc;
+	new_hdr.msg = hdr->msg;
+	new_hdr.vfid = hdr->vfid;
+	new_hdr.tag = m->tag_own;
+	new_hdr.len = txsize;
+
+	/* Write the msg header */
+	rte_write64(new_hdr.u64, ram_mbox_hdr);
+	rte_io_wmb();
+	/* Notify PF about the new msg - write to MBOX reg generates PF IRQ */
+	rte_write64(0, m->reg);
+}
+
+static inline int
+mbox_wait_response(struct mbox *m, struct octeontx_mbox_hdr *hdr,
+			void *rxmsg, uint16_t rxsize)
+{
+	int res = 0, wait;
+	uint16_t len;
+	struct mbox_ram_hdr rx_hdr;
+	uint64_t *ram_mbox_hdr = (uint64_t *)m->ram_mbox_base;
+	uint8_t *ram_mbox_msg = m->ram_mbox_base + sizeof(struct mbox_ram_hdr);
+
+	/* Wait for response */
+	wait = MBOX_WAIT_TIME;
+	while (wait > 0) {
+		rte_delay_us(100);
+		rx_hdr.u64 = rte_read64(ram_mbox_hdr);
+		if (rx_hdr.chan_state == MBOX_CHAN_STATE_RES)
+			break;
+		wait -= 10;
+	}
+
+	hdr->res_code = rx_hdr.res_code;
+	m->tag_own++;
+
+	/* Tag mismatch */
+	if (m->tag_own != rx_hdr.tag) {
+		res = -EBADR;
+		goto error;
+	}
+
+	/* PF nacked the msg */
+	if (rx_hdr.res_code != MBOX_RET_SUCCESS) {
+		res = -EBADMSG;
+		goto error;
+	}
+
+	/* Timeout */
+	if (wait <= 0) {
+		res = -ETIMEDOUT;
+		goto error;
+	}
+
+	len = RTE_MIN(rx_hdr.len, rxsize);
+	if (rxmsg)
+		memcpy(rxmsg, ram_mbox_msg, len);
+
+	return len;
+
+error:
+	ssovf_log_err("Failed to send mbox(%d/%d) coproc=%d msg=%d ret=(%d,%d)",
+			m->tag_own, rx_hdr.tag, hdr->msg, hdr->coproc, res,
+			hdr->res_code);
+	return res;
+}
+
+static inline int
+mbox_send(struct mbox *m, struct octeontx_mbox_hdr *hdr, const void *txmsg,
+		uint16_t txsize, void *rxmsg, uint16_t rxsize)
+{
+	int res = -EINVAL;
+
+	if (m->init_once == 0 || hdr == NULL ||
+		txsize > MAX_RAM_MBOX_LEN || rxsize > MAX_RAM_MBOX_LEN) {
+		ssovf_log_err("Invalid init_once=%d hdr=%p txsz=%d rxsz=%d",
+				m->init_once, hdr, txsize, rxsize);
+		return res;
+	}
+
+	rte_spinlock_lock(&m->lock);
+
+	mbox_send_requeust(m, hdr, txmsg, txsize);
+	res = mbox_wait_response(m, hdr, rxmsg, rxsize);
+
+	rte_spinlock_unlock(&m->lock);
+	return res;
+}
+
+static inline int
+mbox_setup(struct mbox *m)
+{
+	if (unlikely(m->init_once == 0)) {
+		rte_spinlock_init(&m->lock);
+		m->ram_mbox_base = octeontx_ssovf_bar(OCTEONTX_SSO_HWS, 0, 4);
+		m->reg = octeontx_ssovf_bar(OCTEONTX_SSO_GROUP, 0, 0);
+		m->reg += SSO_VHGRP_PF_MBOX(1);
+
+		if (m->ram_mbox_base == NULL || m->reg == NULL) {
+			ssovf_log_err("Invalid ram_mbox_base=%p or reg=%p",
+				m->ram_mbox_base, m->reg);
+			return -EINVAL;
+		}
+		m->init_once = 1;
+	}
+	return 0;
+}
+
+int
+octeontx_ssovf_mbox_send(struct octeontx_mbox_hdr *hdr, void *txdata,
+				 uint16_t txlen, void *rxdata, uint16_t rxlen)
+{
+	struct mbox *m = &octeontx_mbox;
+
+	RTE_BUILD_BUG_ON(sizeof(struct mbox_ram_hdr) != 8);
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY || mbox_setup(m))
+		return -EINVAL;
+
+	return mbox_send(m, hdr, txdata, txlen, rxdata, rxlen);
+}
