You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2022/05/23 19:25:42 UTC

[incubator-nuttx] branch master updated: risc-v/mpfs: amend OpenSBI to utilize IHC

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 3ea7d4bab4 risc-v/mpfs: amend OpenSBI to utilize IHC
3ea7d4bab4 is described below

commit 3ea7d4bab4aff4bd670c2b071934ef52395f676b
Author: Eero Nurkkala <ee...@offcode.fi>
AuthorDate: Fri May 20 07:12:54 2022 +0300

    risc-v/mpfs: amend OpenSBI to utilize IHC
    
    Linux kernel uses M-mode trap for handling Inter-Hart Communication (IHC).
    This patch provides all the required functionalities for this purpose.
    Previously, HSS bootloader was required. Now, NuttX is run as the
    bootloader providing OpenSBI vendor extensions instead. This setup has
    been tested on the following configuration:
    
     - Hart 0 has NuttX in bootloader mode with OpenSBI
     - Hart 1 unused
     - Hart 2 has NuttX configured at 0xa2000000
     - Hart 3 has U-boot / Linux kernel (at 0x80200000)
     - Hart 4 has U-boot / Linux kernel (at 0x80200000)
    
    Upon startup, NuttX on hart 0 will initialize SD-card driver, loads
    the hart 2 NuttX from the SD-card and loads the U-boot to 0x80200000.
    Also the nuttx.sbi -binary is loaded from SD-card into address 0x80000000,
    which is also marked as reserved area in the Linux kernel device tree (for
    the chuck 0x80000000 - 0x80200000).
    
    Hart 2 NuttX waits until Linux kernel (IHC master) is started. After the
    initial handshake, RPMsg / virtIO bus along with the IHC may be used for
    proper AMP mode.
    
    Signed-off-by: Eero Nurkkala <ee...@offcode.fi>
---
 arch/risc-v/src/mpfs/hardware/mpfs_ihc.h |  68 ++----
 arch/risc-v/src/mpfs/mpfs_ihc.c          | 374 +++++++++++++++++++++++--------
 arch/risc-v/src/mpfs/mpfs_ihc.h          |  24 +-
 arch/risc-v/src/mpfs/mpfs_opensbi.c      | 106 ++++++++-
 boards/risc-v/mpfs/common/src/mpfs_ihc.c |   8 +-
 5 files changed, 427 insertions(+), 153 deletions(-)

diff --git a/arch/risc-v/src/mpfs/hardware/mpfs_ihc.h b/arch/risc-v/src/mpfs/hardware/mpfs_ihc.h
index dbc9b6736e..930a8001b4 100755
--- a/arch/risc-v/src/mpfs/hardware/mpfs_ihc.h
+++ b/arch/risc-v/src/mpfs/hardware/mpfs_ihc.h
@@ -272,59 +272,23 @@
 #define MPIE_MASK              (1 << 2)
 #define ACK_INT_MASK           (1 << 3)
 
-#define IHC_MAX_MESSAGE_SIZE    4
+#define IHC_MAX_MESSAGE_SIZE    2
 
-typedef union ihca_ip_int_en_t_
-{
-  uint32_t int_en;
-  struct
-  {
-    uint32_t mp_h0_en  : 1;
-    uint32_t ack_h0_en : 1;
-    uint32_t mp_h1_en  : 1;
-    uint32_t ack_h1_en : 1;
-    uint32_t mp_h2_en  : 1;
-    uint32_t ack_h2_en : 1;
-    uint32_t mp_h3_en  : 1;
-    uint32_t ack_h3_en : 1;
-    uint32_t mp_h4_en  : 1;
-    uint32_t ack_h4_en : 1;
-    uint32_t reserved  : 22;
-  } bitfield;
-} ihca_ip_int_en_t;
-
-typedef union ihca_ip_msg_avail_stat_t_
-{
-  uint32_t msg_avail;
-  struct
-  {
-    uint32_t mp_h0    : 1;
-    uint32_t ack_h0   : 1;
-    uint32_t mp_h1    : 1;
-    uint32_t ack_h1   : 1;
-    uint32_t mp_h2    : 1;
-    uint32_t ack_h2   : 1;
-    uint32_t mp_h3    : 1;
-    uint32_t ack_h3   : 1;
-    uint32_t mp_h4    : 1;
-    uint32_t ack_h4   : 1;
-    uint32_t reserved : 22;
-  } bitfield;
-} ihca_ip_msg_avail_stat_t;
-
-typedef union
+#define SBI_EXT_IHC_CTX_INIT    0
+#define SBI_EXT_IHC_SEND        1
+#define SBI_EXT_IHC_RECEIVE     2
+
+enum ihc_channel_e
 {
-  uint32_t ctl_reg;
-  struct
-    {
-      uint32_t rpm        :1; /* Remote message present */
-      uint32_t mp         :1; /* Message present */
-      uint32_t mpie       :1; /* Message present interrupt enable */
-      uint32_t ack        :1;
-      uint32_t clr_ack    :1;
-      uint32_t ackie      :1; /* Ack interrupt enable */
-      uint32_t reserved   :26;
-    } bitfield;
-} miv_ihcc_ctl_reg_t;
+  IHC_CHANNEL_TO_HART0    = 0x00, /* Your hart to hart 0 */
+  IHC_CHANNEL_TO_HART1    = 0x01, /* Your hart to hart 1 */
+  IHC_CHANNEL_TO_HART2    = 0x02, /* Your hart to hart 2 */
+  IHC_CHANNEL_TO_HART3    = 0x03, /* Your hart to hart 3 */
+  IHC_CHANNEL_TO_HART4    = 0x04, /* Your hart to hart 4 */
+  IHC_CHANNEL_TO_CONTEXTA = 0x05, /* Your hart to context A */
+  IHC_CHANNEL_TO_CONTEXTB = 0x06, /* Your hart to context B */
+};
+
+typedef enum ihc_channel_e ihc_channel_t;
 
 #endif /* __ARCH_RISCV_SRC_MPFS_HARDWARE_MPFS_IHC_H */
diff --git a/arch/risc-v/src/mpfs/mpfs_ihc.c b/arch/risc-v/src/mpfs/mpfs_ihc.c
index d399364a33..09101d33d6 100755
--- a/arch/risc-v/src/mpfs/mpfs_ihc.c
+++ b/arch/risc-v/src/mpfs/mpfs_ihc.c
@@ -46,7 +46,6 @@
 #include <nuttx/list.h>
 
 #include <arch/board/board.h>
-
 #include "hardware/mpfs_sysreg.h"
 #include "hardware/mpfs_ihc.h"
 #include "riscv_internal.h"
@@ -115,22 +114,30 @@ struct mpfs_rptun_dev_s
   char                       shmemname[RPMSG_NAME_SIZE + 1];
 };
 
-typedef enum
-{
-  IHC_CHANNEL_TO_HART0    = 0x00, /* Your hart to hart 0 */
-  IHC_CHANNEL_TO_HART1    = 0x01, /* Your hart to hart 1 */
-  IHC_CHANNEL_TO_HART2    = 0x02, /* Your hart to hart 2 */
-  IHC_CHANNEL_TO_HART3    = 0x03, /* Your hart to hart 3 */
-  IHC_CHANNEL_TO_HART4    = 0x04, /* Your hart to hart 4 */
-  IHC_CHANNEL_TO_CONTEXTA = 0x05, /* Your hart to context A */
-  IHC_CHANNEL_TO_CONTEXTB = 0x06, /* Your hart to context B */
-} ihc_channel_t;
-
-struct mpfs_queue_table
+struct mpfs_queue_table_s
 {
   void *data;
 };
 
+enum mpfs_irq_type_e
+{
+  MP_IRQ  = 0x0,
+  ACK_IRQ = 0x1,
+};
+
+struct mpfs_ihc_msg_s
+{
+  uint32_t msg[IHC_MAX_MESSAGE_SIZE];
+};
+
+/* Used to store information for the remote via ecall (eg. Linux) */
+
+struct ihc_sbi_rx_msg_s
+{
+  uint8_t irq_type;
+  struct mpfs_ihc_msg_s ihc_msg;
+};
+
 /****************************************************************************
  * Private Function Prototypes
  ****************************************************************************/
@@ -158,13 +165,14 @@ static int mpfs_rptun_register_callback(struct rptun_dev_s *dev,
  * combination with u-boot / Linux kernel will not boot if this NuttX image
  * is small.  In the linker script we KEEP the filler_area section so that no
  * compiler will optimize it away.  This will be removed once the root cause
- * has been found out.
+ * has been found out.  This is not needed if NuttX is the bootloader, not
+ * HSS.
  */
 
 uint8_t unused_filler[0x80000] __attribute__((section(".filler_area")));
 
 static struct rpmsg_endpoint        g_mpgs_echo_ping_ept;
-static struct mpfs_queue_table      g_mpfs_virtqueue_table[VRINGS];
+static struct mpfs_queue_table_s    g_mpfs_virtqueue_table[VRINGS];
 static struct mpfs_rptun_shmem_s    g_shmem;
 static struct rpmsg_device         *g_mpfs_rpmsg_device;
 static struct rpmsg_virtio_device  *g_mpfs_virtio_device;
@@ -222,6 +230,9 @@ static const struct rptun_ops_s g_mpfs_rptun_ops =
  *   acking to a message or not.
  *
  * Input Parameters:
+ *   mhartid - My hart id.  If remote owns multiple harts, this is the
+ *             mhartid base on the context, not necessarily the actual
+ *             mhartid.
  *   is_ack  - Boolean that is set true if an ack has been found
  *
  * Returned Value:
@@ -229,9 +240,9 @@ static const struct rptun_ops_s g_mpfs_rptun_ops =
  *
  ****************************************************************************/
 
-static uint32_t mpfs_ihc_parse_incoming_hartid(bool *is_ack)
+static uint32_t mpfs_ihc_parse_incoming_hartid(uint32_t mhartid,
+                                               bool *is_ack)
 {
-  uint32_t mhartid        = riscv_mhartid();
   uint32_t hart_id        = 0;
   uint32_t return_hart_id = UNDEFINED_HART_ID;
   uint32_t msg_avail      = getreg32(MPFS_IHC_MSG_AVAIL(mhartid));
@@ -331,6 +342,68 @@ static uint32_t mpfs_ihc_context_to_remote_hart_id(ihc_channel_t channel)
   return hart;
 }
 
+/****************************************************************************
+ * Name: mpfs_ihc_context_to_local_hart_id
+ *
+ * Description:
+ *   Maps the context to a local hart id.
+ *
+ * Input Parameters:
+ *   channel   - Enum that describes the channel used.
+ *
+ * Returned Value:
+ *   Local hart id
+ *
+ ****************************************************************************/
+
+static uint32_t mpfs_ihc_context_to_local_hart_id(ihc_channel_t channel)
+{
+  uint32_t hart             = UNDEFINED_HART_ID;
+  uint32_t hart_idx         = 0;
+  uint32_t harts_in_context = LIBERO_SETTING_CONTEXT_B_HART_EN;
+  uint64_t mhartid          = riscv_mhartid();
+
+  /* If we are sending to a Context, assume we are a Context.
+   * i.e. HSS bootloader will not send directly to a context.
+   */
+
+  if (channel <= IHC_CHANNEL_TO_HART4)
+    {
+      hart = (uint32_t)mhartid;
+    }
+  else
+    {
+      if (channel == IHC_CHANNEL_TO_CONTEXTA)
+        {
+          /* We are context B */
+
+          harts_in_context = LIBERO_SETTING_CONTEXT_B_HART_EN;
+        }
+      else
+        {
+          /* We are context A */
+
+          harts_in_context = LIBERO_SETTING_CONTEXT_A_HART_EN;
+        }
+
+      hart_idx = 0;
+      while (hart_idx < MPFS_NUM_HARTS)
+        {
+          if (harts_in_context & (1 << hart_idx))
+            {
+              hart = hart_idx;
+              break;
+            }
+
+          hart_idx++;
+        }
+    }
+
+  DEBUGASSERT(hart < MPFS_NUM_HARTS);
+
+  return hart;
+}
+
 /****************************************************************************
  * Name: mpfs_ihc_rx_handler
  *
@@ -367,6 +440,53 @@ static void mpfs_ihc_rx_handler(uint32_t *message, bool is_ack)
     }
 }
 
+/****************************************************************************
+ * Name: mpfs_ihc_message_present_handler
+ *
+ * Description:
+ *   This function fills up a structure that gets into the remote end, such
+ *   as Linux kernel.  The structure may contain data from the
+ *   MPFS_IHC_MSG_IN -register, or in case of an ack, just the irq_type.
+ *
+ * Input Parameters:
+ *   message  - Pointer for storing data, must not be NULL
+ *   mhartid  - The primary hart id of a set of hartids.  Not necessarily
+ *              the absolute mhartid if multiple harts are incorporated
+ *              within the remote (eg. Linux kernel used on 2 harts).
+ *   rhartid  - Remote hart id
+ *   is_ack   - Boolean indicating an ack message
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void mpfs_ihc_message_present_handler(uint32_t *message,
+                                             uint32_t mhartid,
+                                             uint32_t rhartid,
+                                             bool is_ack)
+{
+  struct ihc_sbi_rx_msg_s *msg;
+  uintptr_t message_ihc     = (uintptr_t)MPFS_IHC_MSG_IN(mhartid, rhartid);
+  uint32_t message_size_ihc = getreg32(MPFS_IHC_MSG_SIZE(mhartid, rhartid));
+
+  msg = (struct ihc_sbi_rx_msg_s *)message;
+
+  if (is_ack)
+    {
+      msg->irq_type = ACK_IRQ;
+
+      /* msg->ihc_msg content doesn't matter here */
+    }
+  else
+    {
+      msg->irq_type = MP_IRQ;
+      msg->ihc_msg = *(struct mpfs_ihc_msg_s *)message_ihc;
+    }
+
+    DEBUGASSERT(sizeof(msg->ihc_msg) >= message_size_ihc);
+}
+
 /****************************************************************************
  * Name: mpfs_ihc_rx_message
  *
@@ -376,30 +496,55 @@ static void mpfs_ihc_rx_handler(uint32_t *message, bool is_ack)
  *
  * Input Parameters:
  *   channel  - Enum that describes the channel used.
+ *   mhartid  - Context hart id, not necessarily the absolute mhartid but
+ *              rather, the primary hartid of the set of harts.
  *   is_ack   - Boolean indicating an ack message
+ *   msg      - For storing data, could be NULL
  *
  * Returned Value:
  *   None
  *
  ****************************************************************************/
 
-static void mpfs_ihc_rx_message(ihc_channel_t channel, bool is_ack)
+static void mpfs_ihc_rx_message(ihc_channel_t channel, uint32_t mhartid,
+                                bool is_ack, uint32_t *msg)
 {
-  uint64_t mhartid  = riscv_mhartid();
   uint32_t rhartid  = mpfs_ihc_context_to_remote_hart_id(channel);
   uint32_t ctrl_reg = getreg32(MPFS_IHC_CTRL(mhartid, rhartid));
 
   if (is_ack)
     {
-      mpfs_ihc_rx_handler((uint32_t *)MPFS_IHC_MSG_IN(mhartid, rhartid),
-                          is_ack);
+      if (mhartid == CONTEXTB_HARTID)
+        {
+          uintptr_t msg_in = MPFS_IHC_MSG_IN(mhartid, rhartid);
+          DEBUGASSERT(msg == NULL);
+          mpfs_ihc_rx_handler((uint32_t *)msg_in, is_ack);
+        }
+      else
+        {
+          /* This path is meant for the OpenSBI vendor extension only */
+
+          DEBUGASSERT(msg != NULL);
+          mpfs_ihc_message_present_handler(msg, mhartid, rhartid, is_ack);
+        }
     }
   else if (MP_MESSAGE_PRESENT == (ctrl_reg & MP_MASK))
     {
       /* Check if we have a message */
 
-      mpfs_ihc_rx_handler((uint32_t *)MPFS_IHC_MSG_IN(mhartid, rhartid),
-                          is_ack);
+      if (mhartid == CONTEXTB_HARTID)
+        {
+          uintptr_t msg_in = MPFS_IHC_MSG_IN(mhartid, rhartid);
+          DEBUGASSERT(msg == NULL);
+          mpfs_ihc_rx_handler((uint32_t *)msg_in, is_ack);
+        }
+      else
+        {
+          /* This path is meant for the OpenSBI vendor extension only */
+
+          DEBUGASSERT(msg != NULL);
+          mpfs_ihc_message_present_handler(msg, mhartid, rhartid, is_ack);
+        }
 
       /* Set MP to 0. Note this generates an interrupt on the other hart
        * if it has RMPIE bit set in the control register
@@ -441,7 +586,7 @@ static void mpfs_ihc_message_present_isr(void)
 
   /* Check all our channels */
 
-  uint32_t origin_hart = mpfs_ihc_parse_incoming_hartid(&is_ack);
+  uint32_t origin_hart = mpfs_ihc_parse_incoming_hartid(mhartid, &is_ack);
 
   if (origin_hart != UNDEFINED_HART_ID)
     {
@@ -451,7 +596,7 @@ static void mpfs_ihc_message_present_isr(void)
 
       /* Process incoming packet */
 
-      mpfs_ihc_rx_message(origin_hart, is_ack);
+      mpfs_ihc_rx_message(origin_hart, mhartid, is_ack, NULL);
 
       if (is_ack)
         {
@@ -493,6 +638,47 @@ static int mpfs_ihc_interrupt(int irq, void *context, void *arg)
   return OK;
 }
 
+/****************************************************************************
+ * Name: mpfs_ihc_sbi_message_present_indirect_isr
+ *
+ * Description:
+ *   This is used by OpenSBI.  This is handled as an OpenSBI extension.
+ *   The S-mode kernel uses this in its extended OpenSBI vendor call.
+ *
+ * Input Parameters:
+ *   channel   - Enum that describes the channel used.
+ *   msg       - The msg pointer from sbi_trap_regs->a1 register for data
+ *               exchange.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_MPFS_OPENSBI
+void mpfs_ihc_sbi_message_present_indirect_isr(ihc_channel_t channel,
+                                               uint32_t *msg)
+{
+  bool is_ack;
+  uint32_t mhartid     = mpfs_ihc_context_to_local_hart_id(channel);
+  uint32_t origin_hart = mpfs_ihc_parse_incoming_hartid(mhartid, &is_ack);
+
+  if (origin_hart != UNDEFINED_HART_ID)
+    {
+      /* Process incoming packet */
+
+      mpfs_ihc_rx_message(origin_hart, mhartid, is_ack, msg);
+
+      if (is_ack)
+        {
+          /* Clear the ack */
+
+          modifyreg32(MPFS_IHC_CTRL(mhartid, origin_hart), ACK_CLR, 0);
+        }
+    }
+}
+#endif
+
 /****************************************************************************
  * Name: mpfs_ihc_local_context_init
  *
@@ -522,8 +708,15 @@ static void mpfs_ihc_local_context_init(uint32_t hart_to_configure)
       rhartid++;
     }
 
+#ifdef CONFIG_MPFS_OPENSBI
+  /* With OpenSBI we act the opposite direction */
+
+  g_connected_harts     = (HSS_HART_MASK | (1 << CONTEXTB_HARTID));
+  g_connected_hart_ints = IHCIA_CONTEXTA_INTS;
+#else
   g_connected_harts     = ihcia_remote_harts[hart_to_configure];
   g_connected_hart_ints = ihcia_remote_hart_ints[hart_to_configure];
+#endif
 }
 
 /****************************************************************************
@@ -553,68 +746,6 @@ static void mpfs_ihc_local_remote_config(uint32_t hart_to_configure,
                             ACKIE_EN);
 }
 
-/****************************************************************************
- * Name: mpfs_ihc_context_to_local_hart_id
- *
- * Description:
- *   Maps the context to a local hart id.
- *
- * Input Parameters:
- *   channel   - Enum that describes the channel used.
- *
- * Returned Value:
- *   Local hart id
- *
- ****************************************************************************/
-
-static uint32_t mpfs_ihc_context_to_local_hart_id(ihc_channel_t channel)
-{
-  uint32_t hart             = UNDEFINED_HART_ID;
-  uint32_t hart_idx         = 0;
-  uint32_t harts_in_context = LIBERO_SETTING_CONTEXT_B_HART_EN;
-  uint64_t mhartid          = riscv_mhartid();
-
-  /* If we are sending to a Context, assume we are a Context.
-   * i.e. HSS bootloader will not send directly to a context.
-   */
-
-  if (channel <= IHC_CHANNEL_TO_HART4)
-    {
-      hart = (uint32_t)mhartid;
-    }
-  else
-    {
-      if (channel == IHC_CHANNEL_TO_CONTEXTA)
-        {
-          /* We are context B */
-
-          harts_in_context = LIBERO_SETTING_CONTEXT_B_HART_EN;
-        }
-      else
-        {
-          /* We are context A */
-
-          harts_in_context = LIBERO_SETTING_CONTEXT_A_HART_EN;
-        }
-
-      hart_idx = 0;
-      while (hart_idx < MPFS_NUM_HARTS)
-        {
-          if (harts_in_context & (1 << hart_idx))
-            {
-              hart = hart_idx;
-              break;
-            }
-
-          hart_idx++;
-        }
-    }
-
-  DEBUGASSERT(hart < MPFS_NUM_HARTS);
-
-  return hart;
-}
-
 /****************************************************************************
  * Name: mpfs_ihc_tx_message
  *
@@ -676,7 +807,12 @@ static int mpfs_ihc_tx_message(ihc_channel_t channel, uint32_t *message)
 
       /* Wait for the ACK to arrive to maintain the logic */
 
-      nxsem_wait_uninterruptible(&g_mpfs_ack_sig);
+      if (mhartid == CONTEXTB_HARTID)
+        {
+          /* Only applicable for the CONTEXTB_HART */
+
+          nxsem_wait_uninterruptible(&g_mpfs_ack_sig);
+        }
     }
 
   return OK;
@@ -1117,7 +1253,7 @@ static void mpfs_rpmsg_device_created(struct rpmsg_device *rdev, void *priv_)
 
 static int mpfs_rptun_thread(int argc, char *argv[])
 {
-  struct mpfs_queue_table *info;
+  struct mpfs_queue_table_s *info;
 
   while (1)
     {
@@ -1134,6 +1270,66 @@ static int mpfs_rptun_thread(int argc, char *argv[])
  * Public Functions
  ****************************************************************************/
 
+/****************************************************************************
+ * Name: mpfs_ihc_sbi_ecall_handler
+ *
+ * Description:
+ *   This is sbi_platform_operations / vendor_ext_provider ecall handler.
+ *   Related Linux ecalls end up here.
+ *
+ * Input Parameters:
+ *   funcid          - SBI_EXT_IHC_CTX_INIT, SBI_EXT_IHC_SEND or
+ *                     SBI_EXT_IHC_RECEIVE.  Others are invalid.
+ *   remote_channel  - The remote we're communicating with
+ *   message_ptr     - Local storage for data exchange
+ *
+ * Returned Value:
+ *   OK on success, a negated error code otherwise
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_MPFS_OPENSBI
+int mpfs_ihc_sbi_ecall_handler(unsigned long funcid, uint32_t remote_channel,
+                               uint32_t *message_ptr)
+{
+  uint32_t mhartid;
+  uint32_t rhartid;
+  int result = OK;
+
+  /* Check the channel is bound to a valid context */
+
+  if ((remote_channel < IHC_CHANNEL_TO_CONTEXTA) ||
+      (remote_channel > IHC_CHANNEL_TO_CONTEXTB))
+    {
+      return -EINVAL;
+    }
+
+  switch (funcid)
+    {
+      case SBI_EXT_IHC_CTX_INIT:
+        mhartid = mpfs_ihc_context_to_local_hart_id(remote_channel);
+        rhartid = mpfs_ihc_context_to_remote_hart_id(remote_channel);
+        mpfs_ihc_local_context_init(mhartid);
+        mpfs_ihc_local_remote_config(mhartid, rhartid);
+        break;
+
+      case SBI_EXT_IHC_SEND:
+        result = mpfs_ihc_tx_message(remote_channel, message_ptr);
+        break;
+
+      case SBI_EXT_IHC_RECEIVE:
+        mpfs_ihc_sbi_message_present_indirect_isr(remote_channel,
+                                                  message_ptr);
+        break;
+
+      default:
+        result = -ENOTSUP;
+  }
+
+  return result;
+}
+#endif
+
 /****************************************************************************
  * Name: mpfs_ihc_init
  *
diff --git a/arch/risc-v/src/mpfs/mpfs_ihc.h b/arch/risc-v/src/mpfs/mpfs_ihc.h
index 2cefad9001..c0eebdbe15 100755
--- a/arch/risc-v/src/mpfs/mpfs_ihc.h
+++ b/arch/risc-v/src/mpfs/mpfs_ihc.h
@@ -27,9 +27,6 @@
 
 #include <nuttx/config.h>
 #include <sys/types.h>
-#include <stdbool.h>
-
-#include "chip.h"
 
 /****************************************************************************
  * Public Function Prototypes
@@ -65,6 +62,27 @@ extern "C"
 
 int mpfs_ihc_init(void);
 
+/****************************************************************************
+ * Name: mpfs_ihc_sbi_ecall_handler
+ *
+ * Description:
+ *   This is sbi_platform_operations / vendor_ext_provider ecall handler.
+ *   Related Linux ecalls end up here.
+ *
+ * Input Parameters:
+ *   funcid          - SBI_EXT_IHC_CTX_INIT, SBI_EXT_IHC_SEND or
+ *                     SBI_EXT_IHC_RECEIVE.  Others are invalid.
+ *   remote_channel  - The remote we're communicating with
+ *   message_ptr     - Local storage for data exchange
+ *
+ * Returned Value:
+ *   OK on success, a negated error code otherwise
+ *
+ ****************************************************************************/
+
+int mpfs_ihc_sbi_ecall_handler(unsigned long funcid, uint32_t remote_channel,
+                               uint32_t *message_ptr);
+
 #undef EXTERN
 #if defined(__cplusplus)
 }
diff --git a/arch/risc-v/src/mpfs/mpfs_opensbi.c b/arch/risc-v/src/mpfs/mpfs_opensbi.c
index 5627f857e8..e3cbcc6d30 100644
--- a/arch/risc-v/src/mpfs/mpfs_opensbi.c
+++ b/arch/risc-v/src/mpfs/mpfs_opensbi.c
@@ -26,6 +26,9 @@
 #include <hardware/mpfs_memorymap.h>
 #include <hardware/mpfs_clint.h>
 #include <hardware/mpfs_sysreg.h>
+#ifdef CONFIG_MPFS_IHC
+#include <hardware/mpfs_ihc.h>
+#endif
 
 #include <sbi/riscv_io.h>
 #include <sbi/riscv_encoding.h>
@@ -33,10 +36,15 @@
 #include <sbi/sbi_platform.h>
 #include <sbi/sbi_init.h>
 #include <sbi/sbi_scratch.h>
+#include <sbi/sbi_trap.h>
 #include <sbi_utils/irqchip/plic.h>
 #include <sbi_utils/ipi/aclint_mswi.h>
 #include <sbi_utils/timer/aclint_mtimer.h>
 
+#ifdef CONFIG_MPFS_IHC
+#include <mpfs_ihc.h>
+#endif
+
 /****************************************************************************
  * Pre-processor Definitions
  ****************************************************************************/
@@ -64,6 +72,10 @@
 #define MPFS_SYSREG_SUBBLK_CLOCK_CR   (MPFS_SYSREG_BASE + \
                                        MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET)
 
+#define MICROCHIP_TECHNOLOGY_MVENDOR_ID  0x029
+#define SBI_EXT_MICROCHIP_TECHNOLOGY     (SBI_EXT_VENDOR_START | \
+                                          MICROCHIP_TECHNOLOGY_MVENDOR_ID)
+
 /****************************************************************************
  * Private Types
  ****************************************************************************/
@@ -94,6 +106,13 @@ static int  mpfs_opensbi_console_init(void);
 static int  mpfs_irqchip_init(bool cold_boot);
 static int  mpfs_ipi_init(bool cold_boot);
 static int  mpfs_timer_init(bool cold_boot);
+#ifdef CONFIG_MPFS_IHC
+static int  mpfs_opensbi_vendor_ext_check(long extid);
+static int  mpfs_opensbi_ecall_handler(long extid, long funcid,
+                                       const struct sbi_trap_regs *regs,
+                                       unsigned long *out_val,
+                                       struct sbi_trap_info *out_trap);
+#endif
 
 /****************************************************************************
  * Extern Function Declarations
@@ -138,14 +157,18 @@ static struct aclint_mtimer_data mpfs_mtimer =
 
 static const struct sbi_platform_operations platform_ops =
 {
-  .console_init   = mpfs_opensbi_console_init,
-  .early_init     = mpfs_early_init,
-  .irqchip_init   = mpfs_irqchip_init,
-  .irqchip_exit   = NULL,
-  .ipi_init       = mpfs_ipi_init,
-  .ipi_exit       = NULL,
-  .timer_init     = mpfs_timer_init,
-  .timer_exit     = NULL,
+  .console_init        = mpfs_opensbi_console_init,
+  .early_init          = mpfs_early_init,
+  .irqchip_init        = mpfs_irqchip_init,
+  .irqchip_exit        = NULL,
+  .ipi_init            = mpfs_ipi_init,
+  .ipi_exit            = NULL,
+  .timer_init          = mpfs_timer_init,
+  .timer_exit          = NULL,
+#ifdef CONFIG_MPFS_IHC
+  .vendor_ext_check    = mpfs_opensbi_vendor_ext_check,
+  .vendor_ext_provider = mpfs_opensbi_ecall_handler,
+#endif
 };
 
 static struct aclint_mswi_data mpfs_mswi =
@@ -499,6 +522,73 @@ static void mpfs_opensbi_pmp_setup(void)
   csr_write(pmpcfg2, 0);
 }
 
+/****************************************************************************
+ * Name: mpfs_opensbi_vendor_ext_check
+ *
+ * Description:
+ *   Used by the OpenSBI in vendor probe to check the vendor ID.
+ *
+ * Input Parameters:
+ *   extid       - Vendor ID to be checked
+ *
+ * Returned Value:
+ *   1 on match, zero in case of no match
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_MPFS_IHC
+static int mpfs_opensbi_vendor_ext_check(long extid)
+{
+  return (SBI_EXT_MICROCHIP_TECHNOLOGY == extid);
+}
+
+/****************************************************************************
+ * Name: mpfs_opensbi_ecall_handler
+ *
+ * Description:
+ *   Used by the S-mode kernel such as Linux to perform M-mode ecall actions
+ *   related to Inter-Hart Communication (IHC).
+ *
+ * Input Parameters:
+ *   extid          - Vendor ID
+ *   funcid         - One of the valid functions
+ *   sbi_trap_regs  - SBI trap registers
+ *   out_val        - Error code location
+ *   out_trap       - Trap registers such as epc, unused
+ *
+ * Returned Value:
+ *   0 always
+ *
+ ****************************************************************************/
+
+static int mpfs_opensbi_ecall_handler(long extid, long funcid,
+                                      const struct sbi_trap_regs *regs,
+                                      unsigned long *out_val,
+                                      struct sbi_trap_info *out_trap)
+{
+  uint32_t remote_channel = (uint32_t)regs->a0;
+  uint32_t *message_ptr   = (uint32_t *)regs->a1;
+  int result = 0;
+
+  switch (funcid)
+    {
+      case SBI_EXT_IHC_CTX_INIT:
+      case SBI_EXT_IHC_SEND:
+      case SBI_EXT_IHC_RECEIVE:
+        result = mpfs_ihc_sbi_ecall_handler(funcid, remote_channel,
+                                            message_ptr);
+        break;
+
+      default:
+        result = SBI_ENOTSUPP;
+    }
+
+  *out_val = result;
+
+  return 0;
+}
+#endif
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
diff --git a/boards/risc-v/mpfs/common/src/mpfs_ihc.c b/boards/risc-v/mpfs/common/src/mpfs_ihc.c
index feda98f3f7..f2ae898a3b 100644
--- a/boards/risc-v/mpfs/common/src/mpfs_ihc.c
+++ b/boards/risc-v/mpfs/common/src/mpfs_ihc.c
@@ -48,7 +48,11 @@
 
 int mpfs_board_ihc_init(void)
 {
-  int ret;
+  int ret = 0;
+
+  /* With OpenSBI, initilization comes via mpfs_opensbi.c, not here */
+
+#ifndef CONFIG_MPFS_OPENSBI
 
   ret = mpfs_ihc_init();
 
@@ -58,5 +62,7 @@ int mpfs_board_ihc_init(void)
              ret);
     }
 
+#endif
+
   return ret;
 }