--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2021 Marvell.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "roc_api.h"
+#include "roc_priv.h"
+
+#define RVU_AF_AFPF_MBOX0 (0x02000)
+#define RVU_AF_AFPF_MBOX1 (0x02008)
+
+#define RVU_PF_PFAF_MBOX0 (0xC00)
+#define RVU_PF_PFAF_MBOX1 (0xC08)
+
+#define RVU_PF_VFX_PFVF_MBOX0 (0x0000)
+#define RVU_PF_VFX_PFVF_MBOX1 (0x0008)
+
+#define RVU_VF_VFPF_MBOX0 (0x0000)
+#define RVU_VF_VFPF_MBOX1 (0x0008)
+
+/* RCLK, SCLK in MHz */
+uint16_t dev_rclk_freq;
+uint16_t dev_sclk_freq;
+
+static inline uint16_t
+msgs_offset(void)
+{
+ return PLT_ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN);
+}
+
+void
+mbox_fini(struct mbox *mbox)
+{
+ mbox->reg_base = 0;
+ mbox->hwbase = 0;
+ plt_free(mbox->dev);
+ mbox->dev = NULL;
+}
+
+void
+mbox_reset(struct mbox *mbox, int devid)
+{
+ struct mbox_dev *mdev = &mbox->dev[devid];
+ struct mbox_hdr *tx_hdr =
+ (struct mbox_hdr *)((uintptr_t)mdev->mbase + mbox->tx_start);
+ struct mbox_hdr *rx_hdr =
+ (struct mbox_hdr *)((uintptr_t)mdev->mbase + mbox->rx_start);
+
+ plt_spinlock_lock(&mdev->mbox_lock);
+ mdev->msg_size = 0;
+ mdev->rsp_size = 0;
+ tx_hdr->msg_size = 0;
+ tx_hdr->num_msgs = 0;
+ rx_hdr->msg_size = 0;
+ rx_hdr->num_msgs = 0;
+ plt_spinlock_unlock(&mdev->mbox_lock);
+}
+
+int
+mbox_init(struct mbox *mbox, uintptr_t hwbase, uintptr_t reg_base,
+ int direction, int ndevs, uint64_t intr_offset)
+{
+ struct mbox_dev *mdev;
+ char *var, *var_to;
+ int devid;
+
+ mbox->intr_offset = intr_offset;
+ mbox->reg_base = reg_base;
+ mbox->hwbase = hwbase;
+
+ switch (direction) {
+ case MBOX_DIR_AFPF:
+ case MBOX_DIR_PFVF:
+ mbox->tx_start = MBOX_DOWN_TX_START;
+ mbox->rx_start = MBOX_DOWN_RX_START;
+ mbox->tx_size = MBOX_DOWN_TX_SIZE;
+ mbox->rx_size = MBOX_DOWN_RX_SIZE;
+ break;
+ case MBOX_DIR_PFAF:
+ case MBOX_DIR_VFPF:
+ mbox->tx_start = MBOX_DOWN_RX_START;
+ mbox->rx_start = MBOX_DOWN_TX_START;
+ mbox->tx_size = MBOX_DOWN_RX_SIZE;
+ mbox->rx_size = MBOX_DOWN_TX_SIZE;
+ break;
+ case MBOX_DIR_AFPF_UP:
+ case MBOX_DIR_PFVF_UP:
+ mbox->tx_start = MBOX_UP_TX_START;
+ mbox->rx_start = MBOX_UP_RX_START;
+ mbox->tx_size = MBOX_UP_TX_SIZE;
+ mbox->rx_size = MBOX_UP_RX_SIZE;
+ break;
+ case MBOX_DIR_PFAF_UP:
+ case MBOX_DIR_VFPF_UP:
+ mbox->tx_start = MBOX_UP_RX_START;
+ mbox->rx_start = MBOX_UP_TX_START;
+ mbox->tx_size = MBOX_UP_RX_SIZE;
+ mbox->rx_size = MBOX_UP_TX_SIZE;
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ switch (direction) {
+ case MBOX_DIR_AFPF:
+ case MBOX_DIR_AFPF_UP:
+ mbox->trigger = RVU_AF_AFPF_MBOX0;
+ mbox->tr_shift = 4;
+ break;
+ case MBOX_DIR_PFAF:
+ case MBOX_DIR_PFAF_UP:
+ mbox->trigger = RVU_PF_PFAF_MBOX1;
+ mbox->tr_shift = 0;
+ break;
+ case MBOX_DIR_PFVF:
+ case MBOX_DIR_PFVF_UP:
+ mbox->trigger = RVU_PF_VFX_PFVF_MBOX0;
+ mbox->tr_shift = 12;
+ break;
+ case MBOX_DIR_VFPF:
+ case MBOX_DIR_VFPF_UP:
+ mbox->trigger = RVU_VF_VFPF_MBOX1;
+ mbox->tr_shift = 0;
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ mbox->dev = plt_zmalloc(ndevs * sizeof(struct mbox_dev), ROC_ALIGN);
+ if (!mbox->dev) {
+ mbox_fini(mbox);
+ return -ENOMEM;
+ }
+ mbox->ndevs = ndevs;
+ for (devid = 0; devid < ndevs; devid++) {
+ mdev = &mbox->dev[devid];
+ mdev->mbase = (void *)(mbox->hwbase + (devid * MBOX_SIZE));
+ plt_spinlock_init(&mdev->mbox_lock);
+ /* Init header to reset value */
+ mbox_reset(mbox, devid);
+ }
+
+ var = getenv("ROC_CN10K_MBOX_TIMEOUT");
+ var_to = getenv("ROC_MBOX_TIMEOUT");
+
+ if (var)
+ mbox->rsp_tmo = atoi(var);
+ else if (var_to)
+ mbox->rsp_tmo = atoi(var_to);
+ else
+ mbox->rsp_tmo = MBOX_RSP_TIMEOUT;
+
+ return 0;
+}
+
+/**
+ * @internal
+ * Allocate a message response
+ */
+struct mbox_msghdr *
+mbox_alloc_msg_rsp(struct mbox *mbox, int devid, int size, int size_rsp)
+{
+ struct mbox_dev *mdev = &mbox->dev[devid];
+ struct mbox_msghdr *msghdr = NULL;
+
+ plt_spinlock_lock(&mdev->mbox_lock);
+ size = PLT_ALIGN(size, MBOX_MSG_ALIGN);
+ size_rsp = PLT_ALIGN(size_rsp, MBOX_MSG_ALIGN);
+ /* Check if there is space in mailbox */
+ if ((mdev->msg_size + size) > mbox->tx_size - msgs_offset())
+ goto exit;
+ if ((mdev->rsp_size + size_rsp) > mbox->rx_size - msgs_offset())
+ goto exit;
+ if (mdev->msg_size == 0)
+ mdev->num_msgs = 0;
+ mdev->num_msgs++;
+
+ msghdr = (struct mbox_msghdr *)(((uintptr_t)mdev->mbase +
+ mbox->tx_start + msgs_offset() +
+ mdev->msg_size));
+
+ /* Clear the whole msg region */
+ mbox_memset(msghdr, 0, sizeof(*msghdr) + size);
+ /* Init message header with reset values */
+ msghdr->ver = MBOX_VERSION;
+ mdev->msg_size += size;
+ mdev->rsp_size += size_rsp;
+ msghdr->next_msgoff = mdev->msg_size + msgs_offset();
+exit:
+ plt_spinlock_unlock(&mdev->mbox_lock);
+
+ return msghdr;
+}
+
+/**
+ * @internal
+ * Send a mailbox message
+ */
+void
+mbox_msg_send(struct mbox *mbox, int devid)
+{
+ struct mbox_dev *mdev = &mbox->dev[devid];
+ struct mbox_hdr *tx_hdr =
+ (struct mbox_hdr *)((uintptr_t)mdev->mbase + mbox->tx_start);
+ struct mbox_hdr *rx_hdr =
+ (struct mbox_hdr *)((uintptr_t)mdev->mbase + mbox->rx_start);
+
+ /* Reset header for next messages */
+ tx_hdr->msg_size = mdev->msg_size;
+ mdev->msg_size = 0;
+ mdev->rsp_size = 0;
+ mdev->msgs_acked = 0;
+
+ /* num_msgs != 0 signals to the peer that the buffer has a number of
+ * messages. So this should be written after copying txmem
+ */
+ tx_hdr->num_msgs = mdev->num_msgs;
+ rx_hdr->num_msgs = 0;
+
+ /* Sync mbox data into memory */
+ plt_wmb();
+
+ /* The interrupt should be fired after num_msgs is written
+ * to the shared memory
+ */
+ plt_write64(1, (volatile void *)(mbox->reg_base +
+ (mbox->trigger |
+ (devid << mbox->tr_shift))));
+}
+
+/**
+ * @internal
+ * Wait and get mailbox response
+ */
+int
+mbox_get_rsp(struct mbox *mbox, int devid, void **msg)
+{
+ struct mbox_dev *mdev = &mbox->dev[devid];
+ struct mbox_msghdr *msghdr;
+ uint64_t offset;
+ int rc;
+
+ rc = mbox_wait_for_rsp(mbox, devid);
+ if (rc < 0)
+ return -EIO;
+
+ plt_rmb();
+
+ offset = mbox->rx_start +
+ PLT_ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN);
+ msghdr = (struct mbox_msghdr *)((uintptr_t)mdev->mbase + offset);
+ if (msg != NULL)
+ *msg = msghdr;
+
+ return msghdr->rc;
+}
+
+/**
+ * Polling for given wait time to get mailbox response
+ */
+static int
+mbox_poll(struct mbox *mbox, uint32_t wait)
+{
+ uint32_t timeout = 0, sleep = 1;
+ uint32_t wait_us = wait * 1000;
+ uint64_t rsp_reg = 0;
+ uintptr_t reg_addr;
+
+ reg_addr = mbox->reg_base + mbox->intr_offset;
+ do {
+ rsp_reg = plt_read64(reg_addr);
+
+ if (timeout >= wait_us)
+ return -ETIMEDOUT;
+
+ plt_delay_us(sleep);
+ timeout += sleep;
+ } while (!rsp_reg);
+
+ plt_rmb();
+
+ /* Clear interrupt */
+ plt_write64(rsp_reg, reg_addr);
+
+ /* Reset mbox */
+ mbox_reset(mbox, 0);
+
+ return 0;
+}
+
+/**
+ * @internal
+ * Wait and get mailbox response with timeout
+ */
+int
+mbox_get_rsp_tmo(struct mbox *mbox, int devid, void **msg, uint32_t tmo)
+{
+ struct mbox_dev *mdev = &mbox->dev[devid];
+ struct mbox_msghdr *msghdr;
+ uint64_t offset;
+ int rc;
+
+ rc = mbox_wait_for_rsp_tmo(mbox, devid, tmo);
+ if (rc != 1)
+ return -EIO;
+
+ plt_rmb();
+
+ offset = mbox->rx_start +
+ PLT_ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN);
+ msghdr = (struct mbox_msghdr *)((uintptr_t)mdev->mbase + offset);
+ if (msg != NULL)
+ *msg = msghdr;
+
+ return msghdr->rc;
+}
+
+static int
+mbox_wait(struct mbox *mbox, int devid, uint32_t rst_timo)
+{
+ volatile struct mbox_dev *mdev = &mbox->dev[devid];
+ uint32_t timeout = 0, sleep = 1;
+
+ rst_timo = rst_timo * 1000; /* Milli seconds to micro seconds */
+ while (mdev->num_msgs > mdev->msgs_acked) {
+ plt_delay_us(sleep);
+ timeout += sleep;
+ if (timeout >= rst_timo) {
+ struct mbox_hdr *tx_hdr =
+ (struct mbox_hdr *)((uintptr_t)mdev->mbase +
+ mbox->tx_start);
+ struct mbox_hdr *rx_hdr =
+ (struct mbox_hdr *)((uintptr_t)mdev->mbase +
+ mbox->rx_start);
+
+ plt_err("MBOX[devid: %d] message wait timeout %d, "
+ "num_msgs: %d, msgs_acked: %d "
+ "(tx/rx num_msgs: %d/%d), msg_size: %d, "
+ "rsp_size: %d",
+ devid, timeout, mdev->num_msgs,
+ mdev->msgs_acked, tx_hdr->num_msgs,
+ rx_hdr->num_msgs, mdev->msg_size,
+ mdev->rsp_size);
+
+ return -EIO;
+ }
+ plt_rmb();
+ }
+ return 0;
+}
+
+int
+mbox_wait_for_rsp_tmo(struct mbox *mbox, int devid, uint32_t tmo)
+{
+ struct mbox_dev *mdev = &mbox->dev[devid];
+ int rc = 0;
+
+ /* Sync with mbox region */
+ plt_rmb();
+
+ if (mbox->trigger == RVU_PF_VFX_PFVF_MBOX1 ||
+ mbox->trigger == RVU_PF_VFX_PFVF_MBOX0) {
+ /* In case of VF, Wait a bit more to account round trip delay */
+ tmo = tmo * 2;
+ }
+
+ /* Wait message */
+ if (plt_thread_is_intr())
+ rc = mbox_poll(mbox, tmo);
+ else
+ rc = mbox_wait(mbox, devid, tmo);
+
+ if (!rc)
+ rc = mdev->num_msgs;
+
+ return rc;
+}
+
+/**
+ * @internal
+ * Wait for the mailbox response
+ */
+int
+mbox_wait_for_rsp(struct mbox *mbox, int devid)
+{
+ return mbox_wait_for_rsp_tmo(mbox, devid, mbox->rsp_tmo);
+}
+
+int
+mbox_get_availmem(struct mbox *mbox, int devid)
+{
+ struct mbox_dev *mdev = &mbox->dev[devid];
+ int avail;
+
+ plt_spinlock_lock(&mdev->mbox_lock);
+ avail = mbox->tx_size - mdev->msg_size - msgs_offset();
+ plt_spinlock_unlock(&mdev->mbox_lock);
+
+ return avail;
+}
+
+int
+send_ready_msg(struct mbox *mbox, uint16_t *pcifunc)
+{
+ struct ready_msg_rsp *rsp;
+ int rc;
+
+ mbox_alloc_msg_ready(mbox);
+
+ rc = mbox_process_msg(mbox, (void *)&rsp);
+ if (rc)
+ return rc;
+
+ if (rsp->hdr.ver != MBOX_VERSION) {
+ plt_err("Incompatible MBox versions(AF: 0x%04x Client: 0x%04x)",
+ rsp->hdr.ver, MBOX_VERSION);
+ return -EPIPE;
+ }
+
+ if (pcifunc)
+ *pcifunc = rsp->hdr.pcifunc;
+
+ /* Save rclk & sclk freq */
+ if (!dev_rclk_freq || !dev_sclk_freq) {
+ dev_rclk_freq = rsp->rclk_freq;
+ dev_sclk_freq = rsp->sclk_freq;
+ }
+ return 0;
+}
+
+int
+reply_invalid_msg(struct mbox *mbox, int devid, uint16_t pcifunc, uint16_t id)
+{
+ struct msg_rsp *rsp;
+
+ rsp = (struct msg_rsp *)mbox_alloc_msg(mbox, devid, sizeof(*rsp));
+ if (!rsp)
+ return -ENOMEM;
+ rsp->hdr.id = id;
+ rsp->hdr.sig = MBOX_RSP_SIG;
+ rsp->hdr.rc = MBOX_MSG_INVALID;
+ rsp->hdr.pcifunc = pcifunc;
+
+ return 0;
+}
+
+/**
+ * @internal
+ * Convert mail box ID to name
+ */
+const char *
+mbox_id2name(uint16_t id)
+{
+ switch (id) {
+ default:
+ return "INVALID ID";
+#define M(_name, _id, _1, _2, _3) \
+ case _id: \
+ return #_name;
+ MBOX_MESSAGES
+ MBOX_UP_CGX_MESSAGES
+#undef M
+ }
+}
+
+int
+mbox_id2size(uint16_t id)
+{
+ switch (id) {
+ default:
+ return 0;
+#define M(_1, _id, _2, _req_type, _3) \
+ case _id: \
+ return sizeof(struct _req_type);
+ MBOX_MESSAGES
+ MBOX_UP_CGX_MESSAGES
+#undef M
+ }
+}
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2021 Marvell.
+ */
+
+#ifndef __ROC_MBOX_PRIV_H__
+#define __ROC_MBOX_PRIV_H__
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#define SZ_64K (64ULL * 1024ULL)
+#define SZ_1K (1ULL * 1024ULL)
+#define MBOX_SIZE SZ_64K
+
+/* AF/PF: PF initiated, PF/VF VF initiated */
+#define MBOX_DOWN_RX_START 0
+#define MBOX_DOWN_RX_SIZE (46 * SZ_1K)
+#define MBOX_DOWN_TX_START (MBOX_DOWN_RX_START + MBOX_DOWN_RX_SIZE)
+#define MBOX_DOWN_TX_SIZE (16 * SZ_1K)
+/* AF/PF: AF initiated, PF/VF PF initiated */
+#define MBOX_UP_RX_START (MBOX_DOWN_TX_START + MBOX_DOWN_TX_SIZE)
+#define MBOX_UP_RX_SIZE SZ_1K
+#define MBOX_UP_TX_START (MBOX_UP_RX_START + MBOX_UP_RX_SIZE)
+#define MBOX_UP_TX_SIZE SZ_1K
+
+#if MBOX_UP_TX_SIZE + MBOX_UP_TX_START != MBOX_SIZE
+#error "Incorrect mailbox area sizes"
+#endif
+
+#define INTR_MASK(pfvfs) ((pfvfs < 64) ? (BIT_ULL(pfvfs) - 1) : (~0ull))
+
+#define MBOX_RSP_TIMEOUT 3000 /* Time to wait for mbox response in ms */
+
+#define MBOX_MSG_ALIGN 16 /* Align mbox msg start to 16bytes */
+
+/* Mailbox directions */
+#define MBOX_DIR_AFPF 0 /* AF replies to PF */
+#define MBOX_DIR_PFAF 1 /* PF sends messages to AF */
+#define MBOX_DIR_PFVF 2 /* PF replies to VF */
+#define MBOX_DIR_VFPF 3 /* VF sends messages to PF */
+#define MBOX_DIR_AFPF_UP 4 /* AF sends messages to PF */
+#define MBOX_DIR_PFAF_UP 5 /* PF replies to AF */
+#define MBOX_DIR_PFVF_UP 6 /* PF sends messages to VF */
+#define MBOX_DIR_VFPF_UP 7 /* VF replies to PF */
+
+struct mbox_dev {
+ void *mbase; /* This dev's mbox region */
+ plt_spinlock_t mbox_lock;
+ uint16_t msg_size; /* Total msg size to be sent */
+ uint16_t rsp_size; /* Total rsp size to be sure the reply is ok */
+ uint16_t num_msgs; /* No of msgs sent or waiting for response */
+ uint16_t msgs_acked; /* No of msgs for which response is received */
+};
+
+struct mbox {
+ uintptr_t hwbase; /* Mbox region advertised by HW */
+ uintptr_t reg_base; /* CSR base for this dev */
+ uint64_t trigger; /* Trigger mbox notification */
+ uint16_t tr_shift; /* Mbox trigger shift */
+ uint64_t rx_start; /* Offset of Rx region in mbox memory */
+ uint64_t tx_start; /* Offset of Tx region in mbox memory */
+ uint16_t rx_size; /* Size of Rx region */
+ uint16_t tx_size; /* Size of Tx region */
+ uint16_t ndevs; /* The number of peers */
+ struct mbox_dev *dev;
+ uint64_t intr_offset; /* Offset to interrupt register */
+ uint32_t rsp_tmo;
+};
+
+const char *mbox_id2name(uint16_t id);
+int mbox_id2size(uint16_t id);
+void mbox_reset(struct mbox *mbox, int devid);
+int mbox_init(struct mbox *mbox, uintptr_t hwbase, uintptr_t reg_base,
+ int direction, int ndevsi, uint64_t intr_offset);
+void mbox_fini(struct mbox *mbox);
+void mbox_msg_send(struct mbox *mbox, int devid);
+int mbox_wait_for_rsp(struct mbox *mbox, int devid);
+int mbox_wait_for_rsp_tmo(struct mbox *mbox, int devid, uint32_t tmo);
+int mbox_get_rsp(struct mbox *mbox, int devid, void **msg);
+int mbox_get_rsp_tmo(struct mbox *mbox, int devid, void **msg, uint32_t tmo);
+int mbox_get_availmem(struct mbox *mbox, int devid);
+struct mbox_msghdr *mbox_alloc_msg_rsp(struct mbox *mbox, int devid, int size,
+ int size_rsp);
+
+static inline struct mbox_msghdr *
+mbox_alloc_msg(struct mbox *mbox, int devid, int size)
+{
+ return mbox_alloc_msg_rsp(mbox, devid, size, 0);
+}
+
+static inline void
+mbox_req_init(uint16_t mbox_id, void *msghdr)
+{
+ struct mbox_msghdr *hdr = msghdr;
+
+ hdr->sig = MBOX_REQ_SIG;
+ hdr->ver = MBOX_VERSION;
+ hdr->id = mbox_id;
+ hdr->pcifunc = 0;
+}
+
+static inline void
+mbox_rsp_init(uint16_t mbox_id, void *msghdr)
+{
+ struct mbox_msghdr *hdr = msghdr;
+
+ hdr->sig = MBOX_RSP_SIG;
+ hdr->rc = -ETIMEDOUT;
+ hdr->id = mbox_id;
+}
+
+static inline bool
+mbox_nonempty(struct mbox *mbox, int devid)
+{
+ struct mbox_dev *mdev = &mbox->dev[devid];
+ bool ret;
+
+ plt_spinlock_lock(&mdev->mbox_lock);
+ ret = mdev->num_msgs != 0;
+ plt_spinlock_unlock(&mdev->mbox_lock);
+
+ return ret;
+}
+
+static inline int
+mbox_process(struct mbox *mbox)
+{
+ mbox_msg_send(mbox, 0);
+ return mbox_get_rsp(mbox, 0, NULL);
+}
+
+static inline int
+mbox_process_msg(struct mbox *mbox, void **msg)
+{
+ mbox_msg_send(mbox, 0);
+ return mbox_get_rsp(mbox, 0, msg);
+}
+
+static inline int
+mbox_process_tmo(struct mbox *mbox, uint32_t tmo)
+{
+ mbox_msg_send(mbox, 0);
+ return mbox_get_rsp_tmo(mbox, 0, NULL, tmo);
+}
+
+static inline int
+mbox_process_msg_tmo(struct mbox *mbox, void **msg, uint32_t tmo)
+{
+ mbox_msg_send(mbox, 0);
+ return mbox_get_rsp_tmo(mbox, 0, msg, tmo);
+}
+
+int send_ready_msg(struct mbox *mbox, uint16_t *pf_func /* out */);
+int reply_invalid_msg(struct mbox *mbox, int devid, uint16_t pf_func,
+ uint16_t id);
+
+#define M(_name, _id, _fn_name, _req_type, _rsp_type) \
+ static inline struct _req_type *mbox_alloc_msg_##_fn_name( \
+ struct mbox *mbox) \
+ { \
+ struct _req_type *req; \
+ req = (struct _req_type *)mbox_alloc_msg_rsp( \
+ mbox, 0, sizeof(struct _req_type), \
+ sizeof(struct _rsp_type)); \
+ if (!req) \
+ return NULL; \
+ req->hdr.sig = MBOX_REQ_SIG; \
+ req->hdr.id = _id; \
+ plt_mbox_dbg("id=0x%x (%s)", req->hdr.id, \
+ mbox_id2name(req->hdr.id)); \
+ return req; \
+ }
+
+MBOX_MESSAGES
+#undef M
+
+/* This is required for copy operations from device memory which do not work on
+ * addresses which are unaligned to 16B. This is because of specific
+ * optimizations to libc memcpy.
+ */
+static inline volatile void *
+mbox_memcpy(volatile void *d, const volatile void *s, size_t l)
+{
+ const volatile uint8_t *sb;
+ volatile uint8_t *db;
+ size_t i;
+
+ if (!d || !s)
+ return NULL;
+ db = (volatile uint8_t *)d;
+ sb = (const volatile uint8_t *)s;
+ for (i = 0; i < l; i++)
+ db[i] = sb[i];
+ return d;
+}
+
+/* This is required for memory operations from device memory which do not
+ * work on addresses which are unaligned to 16B. This is because of specific
+ * optimizations to libc memset.
+ */
+static inline void
+mbox_memset(volatile void *d, uint8_t val, size_t l)
+{
+ volatile uint8_t *db;
+ size_t i = 0;
+
+ if (!d || !l)
+ return;
+ db = (volatile uint8_t *)d;
+ for (i = 0; i < l; i++)
+ db[i] = val;
+}
+
+#endif /* __ROC_MBOX_PRIV_H__ */