platform: msm_shared: Add GLink support

GLink is a protocol for IPC communication and is needed
for LK to talk to RPM processor

Change-Id: I2f4a44ac0d9950d5a5046c6b4aa341821a8dc663
diff --git a/platform/msm_shared/glink/glink_api.c b/platform/msm_shared/glink/glink_api.c
new file mode 100644
index 0000000..24f777d
--- /dev/null
+++ b/platform/msm_shared/glink/glink_api.c
@@ -0,0 +1,1532 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+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 The Linux Foundation 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+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 FILES
+===========================================================================*/
+#include <glink.h>
+#include <glink_rpm.h>
+#include <glink_os_utils.h>
+#include <glink_internal.h>
+#include <glink_vector.h>
+#include <glink_channel_migration.h>
+#include <smem_list.h>
+#include <smem_type.h>
+
+#define GLINK_NOT_INITIALIZED 0
+#define GLINK_INITIALIZED     1
+
+/*===========================================================================
+                              GLOBAL DATA DECLARATIONS
+===========================================================================*/
+int glink_core_status = GLINK_NOT_INITIALIZED;
+
+os_cs_type *glink_transport_q_cs;
+os_cs_type *glink_mem_log_cs;
+
+glink_mem_log_entry_type glink_mem_log_arr[GLINK_MEM_LOG_SIZE];
+uint32 glink_mem_log_idx = 0;
+
+/* Keep a list of registered transport for each edge allowed for this host */
+smem_list_type glink_registered_transports[GLINK_NUM_HOSTS];
+
+smem_list_type glink_link_notif_list;
+
+/* List of supported hosts */
+const char* glink_hosts_supported[]   = { "apss",
+                                          "mpss",
+                                          "lpass",
+                                          "dsps",
+                                          "wcnss",
+                                          "tz",
+                                          "rpm",
+                                        };
+
+/* Forward function declarations */
+void glinki_free_intents(glink_channel_ctx_type *open_ch_ctx);
+
+/*===========================================================================
+                    LOCAL FUNCTION DEFINITIONS
+===========================================================================*/
+
+glink_err_type glinki_add_ch_to_xport
+(
+  glink_transport_if_type  *if_ptr,
+  glink_transport_if_type  *req_if_ptr,
+  glink_channel_ctx_type   *ch_ctx,
+  glink_channel_ctx_type   **allocated_ch_ctx,
+  unsigned int              local_open,
+  boolean                      migration_state,
+  glink_xport_priority      migrated_ch_prio
+)
+{
+  glink_err_type             status = 0;
+  glink_channel_ctx_type     *open_ch_ctx;
+  glink_core_xport_ctx_type  *xport_ctx = if_ptr->glink_core_priv;
+
+  /* See if channel already exists in open_list */
+  glink_os_cs_acquire(&xport_ctx->channel_q_cs);
+  open_ch_ctx = smem_list_first(&if_ptr->glink_core_priv->open_list);
+  while(open_ch_ctx != NULL)
+  {
+    if (strcmp(open_ch_ctx->name, ch_ctx->name) == 0)
+    {
+      /* We've found a channel name is already in the list of open channel */
+      /* increase reference open count for channel */
+      *allocated_ch_ctx = open_ch_ctx;
+      open_ch_ctx->ref_count++;
+
+      /* Case A: Channel was opened before on the same host */
+      if((open_ch_ctx->state == GLINK_CH_STATE_REMOTE_OPEN) && local_open) {
+
+        open_ch_ctx->req_if_ptr = req_if_ptr;
+
+        /* Copy local open ctx params */
+        open_ch_ctx->notify_rx = ch_ctx->notify_rx;
+        open_ch_ctx->notify_rxv = ch_ctx->notify_rxv;
+        open_ch_ctx->notify_tx_done = ch_ctx->notify_tx_done;
+        open_ch_ctx->notify_state = ch_ctx->notify_state;
+        open_ch_ctx->notify_rx_intent_req = ch_ctx->notify_rx_intent_req;
+        open_ch_ctx->notify_rx_intent = ch_ctx->notify_rx_intent;
+        open_ch_ctx->notify_rx_sigs = ch_ctx->notify_rx_sigs;
+        open_ch_ctx->priv = ch_ctx->priv;
+        open_ch_ctx->ch_open_options = ch_ctx->ch_open_options;
+
+        /* release lock before context switch otherwise it is causing
+         * deadlock */
+        glink_os_cs_release(&xport_ctx->channel_q_cs);
+
+        /* Send open cmd to transport */
+        status = if_ptr->tx_cmd_ch_open(if_ptr,
+                      open_ch_ctx->lcid, open_ch_ctx->name,
+                      open_ch_ctx->req_if_ptr->glink_priority);
+      }
+      else if ((open_ch_ctx->state == GLINK_CH_STATE_LOCAL_OPEN) &&
+               (!local_open))
+      {
+        /* Case B: Channel was opened on this end and we got a remote open */
+        open_ch_ctx->rcid = ch_ctx->rcid;
+
+        status = xport_ctx->channel_init(open_ch_ctx);
+
+        /* release lock before context switch otherwise it is causing deadlock */
+        glink_os_cs_release(&xport_ctx->channel_q_cs);
+
+        if (status == GLINK_STATUS_SUCCESS)
+        {
+          /* Send ACK to transport */
+          if_ptr->tx_cmd_ch_remote_open_ack(if_ptr, open_ch_ctx->rcid, migrated_ch_prio);
+        }
+      } else if ((open_ch_ctx->state == GLINK_CH_STATE_REMOTE_OPEN_LOCAL_CLOSE)
+                  && (local_open)) {
+        /* Allocate new channel context */
+        break; /* code would break out of loop and create new ch ctx */
+      } else {
+        /* Can't handle this state */
+        ASSERT(0);
+      }
+
+      break;
+    } /* end if match found */
+    open_ch_ctx = smem_list_next(open_ch_ctx);
+  }/* end while */
+
+  if (open_ch_ctx != NULL)
+  {
+    glink_os_free(ch_ctx);
+
+    /* connect channel here if state is local open and remote open request
+     * comes up and channel migration is done; channel will be connected in
+     * remote_open_ack if channel state is remote open and local open
+     * request comes up */
+    if(open_ch_ctx->state == GLINK_CH_STATE_LOCAL_OPEN &&
+       migration_state == FALSE && status == GLINK_STATUS_SUCCESS)
+    {
+      /* Set the channel state to OPEN */
+      open_ch_ctx->state = GLINK_CH_STATE_OPEN;
+      /* Inform the client */
+      open_ch_ctx->notify_state(open_ch_ctx, open_ch_ctx->priv,
+                                GLINK_CONNECTED);
+    }
+  }
+  else
+  {
+    /* Channel not in the list - it was not previously opened */
+    ch_ctx->if_ptr = if_ptr;
+    *allocated_ch_ctx = ch_ctx;
+
+    /* Set channel state */
+    if (local_open) {
+      /* This is a local open */
+      ch_ctx->state      = GLINK_CH_STATE_LOCAL_OPEN;
+      ch_ctx->req_if_ptr = req_if_ptr;
+    }
+    else {
+      ch_ctx->state = GLINK_CH_STATE_REMOTE_OPEN;
+    }
+
+    glink_os_cs_init(&ch_ctx->tx_cs);
+
+    /* Append the channel to the transport interface's open_list */
+    ch_ctx->ref_count++;
+    ch_ctx->lcid = xport_ctx->free_lcid;
+    xport_ctx->free_lcid++;
+    smem_list_append(&if_ptr->glink_core_priv->open_list, ch_ctx);
+
+    /* release lock before context switch otherwise it is causing deadlock */
+    glink_os_cs_release(&xport_ctx->channel_q_cs);
+
+    /* Send the OPEN command to transport */
+    if (local_open)
+    {
+      status = if_ptr->tx_cmd_ch_open(if_ptr, ch_ctx->lcid,
+                                      ch_ctx->name,
+                                      ch_ctx->req_if_ptr->glink_priority);
+    }
+    else
+    {
+      /* initialize channel resources */
+      status = xport_ctx->channel_init(ch_ctx);
+
+      /* ACK the transport for remote open */
+      if (status == GLINK_STATUS_SUCCESS)
+      {
+        if_ptr->tx_cmd_ch_remote_open_ack(if_ptr, ch_ctx->rcid,
+                                          migrated_ch_prio);
+      }
+    }
+
+    if (status != GLINK_STATUS_SUCCESS)
+    {
+      /* Remove the channel from the transport interface's open_list */
+      xport_ctx->free_lcid--;
+
+      glink_os_cs_acquire(&xport_ctx->channel_q_cs);
+      smem_list_delete(&if_ptr->glink_core_priv->open_list, ch_ctx);
+      glink_os_cs_release(&xport_ctx->channel_q_cs);
+
+      /* free the ch_ctx structure and return */
+      xport_ctx->channel_cleanup(ch_ctx);
+      glink_os_free(ch_ctx);
+    }
+  }
+
+  return status;
+}
+
+/** Default implementation of optional callbacks */
+
+static void glink_default_notify_rx_sigs
+(
+  glink_handle_type  handle,
+  const void         *priv,
+  uint32             prev,
+  uint32             curr
+)
+{
+  return;
+}
+
+static void glinki_call_link_notifier
+(
+  glink_link_notif_data_type *link_notif_data,
+  glink_core_xport_ctx_type  *xport_ctx,
+  glink_link_state_type      state
+)
+{
+  glink_link_info_type link_info;
+
+  ASSERT(xport_ctx);
+  ASSERT(link_notif_data);
+
+  link_info.xport = xport_ctx->xport;
+  link_info.remote_ss = xport_ctx->remote_ss;
+  link_info.link_state = state;
+  link_notif_data->link_notifier(&link_info, link_notif_data->priv);
+}
+
+static uint32 glinki_find_remote_host
+(
+  const char *remote_ss
+)
+{
+  uint32 remote_host;
+  ASSERT(remote_ss);
+
+  for(remote_host = 0;
+      remote_host < sizeof(glink_hosts_supported)/sizeof(char *);
+      remote_host++) {
+    if( 0 == strcmp(glink_hosts_supported[remote_host], remote_ss) ) {
+      /* Match found, break out of loop */
+      break;
+    }
+  }
+  return remote_host;
+}
+
+static void glinki_check_xport_and_notify
+(
+  glink_link_notif_data_type *link_notif_data,
+  glink_core_xport_ctx_type  *xport_ctx,
+  glink_link_state_type      state
+)
+{
+  glink_link_info_type link_info;
+
+  ASSERT(xport_ctx);
+  ASSERT(link_notif_data);
+
+  link_info.xport = xport_ctx->xport;
+  link_info.remote_ss = xport_ctx->remote_ss;
+  link_info.link_state = state;
+
+  if(link_notif_data->xport == NULL ||
+     0 == strcmp(xport_ctx->xport, link_notif_data->xport)) {
+    /* xport not specified, or it is specified and matches the current xport */
+    /* Invoke registered callback */
+    link_notif_data->link_notifier(&link_info, link_notif_data->priv);
+  }
+}
+
+
+static void glinki_scan_xports_and_notify
+(
+  glink_link_notif_data_type *link_notif_data
+)
+{
+  unsigned int remote_host;
+  glink_transport_if_type *if_ptr;
+  glink_core_xport_ctx_type  *xport_ctx;
+
+  ASSERT(link_notif_data);
+
+  /* Find matching subsystem */
+  if(link_notif_data->remote_ss) {
+    remote_host = glinki_find_remote_host(link_notif_data->remote_ss);
+
+    /* Find the xport and give link UP notification */
+    if_ptr = smem_list_first(&glink_registered_transports[remote_host]);
+    if(if_ptr == NULL) {
+      /* No registered xports at this time, return without doing anything */
+      return;
+    }
+
+    if(link_notif_data->xport) {
+      do {
+        xport_ctx = if_ptr->glink_core_priv;
+        if( 0 == strcmp(xport_ctx->xport, link_notif_data->xport) ) {
+          /* Match found, break out of loop */
+          break;
+        }
+      }while ((if_ptr = smem_list_next(if_ptr)) != NULL);
+
+      if((if_ptr != NULL) && (xport_ctx->status == GLINK_XPORT_LINK_UP)) {
+        /* Invoke registered callback */
+        glinki_call_link_notifier(link_notif_data, xport_ctx,
+                                  GLINK_LINK_STATE_UP);
+      }
+    } else {
+      /* No xport has been specified, invoke notifier for all registered
+       * xports */
+      do {
+        xport_ctx = if_ptr->glink_core_priv;
+        if(xport_ctx->status == GLINK_XPORT_LINK_UP) {
+          /* Invoke registered callback */
+          glinki_call_link_notifier(link_notif_data, xport_ctx,
+                                    GLINK_LINK_STATE_UP);
+        }
+      }while ((if_ptr = smem_list_next(if_ptr)) != NULL);
+    }
+  } else {
+    /* No remote ss is specified, invoke notifier for all remote_ss */
+    for(remote_host = 0;
+        remote_host < sizeof(glink_hosts_supported)/sizeof(char *);
+        remote_host++) {
+      /* Find the xport and give link UP notification */
+      if_ptr = smem_list_first(&glink_registered_transports[remote_host]);
+      if(if_ptr == NULL) {
+        /* No registered xports at this time, continue with next remote_ss */
+        continue;
+      }
+
+      if(link_notif_data->xport) {
+        do {
+          xport_ctx = if_ptr->glink_core_priv;
+          if( 0 == strcmp(xport_ctx->xport, link_notif_data->xport) ) {
+            /* Match found, break out of loop */
+            break;
+          }
+        }while ((if_ptr = smem_list_next(if_ptr)) != NULL);
+
+        if((if_ptr != NULL) && (xport_ctx->status == GLINK_XPORT_LINK_UP)) {
+          /* Invoke registered callback */
+          glinki_call_link_notifier(link_notif_data, xport_ctx,
+                                    GLINK_LINK_STATE_UP);
+        }
+      } else {
+        /* No xport has been specified, invoke notifier for all registered
+         * xports */
+        do {
+          xport_ctx = if_ptr->glink_core_priv;
+          if(xport_ctx->status == GLINK_XPORT_LINK_UP) {
+            /* Invoke registered callback */
+            glinki_call_link_notifier(link_notif_data, xport_ctx,
+                                      GLINK_LINK_STATE_UP);
+          }
+        }while ((if_ptr = smem_list_next(if_ptr)) != NULL);
+      }
+    } /* end for remote_host */
+  }/* end if else (link_notif_data->remote_ss) */
+} /* glinki_scan_xports_and_notify */
+
+void glinki_scan_notif_list_and_notify
+(
+  glink_transport_if_type *if_ptr,
+  glink_link_state_type state
+)
+{
+  glink_link_notif_data_type *link_notif_data;
+  glink_core_xport_ctx_type  *xport_ctx = if_ptr->glink_core_priv;
+
+  link_notif_data = smem_list_first(&glink_link_notif_list);
+
+  if(link_notif_data == NULL) {
+    /* list empty */
+    return;
+  }
+
+  do {
+      if(link_notif_data->remote_ss &&
+         0 == strcmp(xport_ctx->remote_ss, link_notif_data->remote_ss)) {
+        /* remote_ss specified and matches */
+        glinki_check_xport_and_notify(link_notif_data, xport_ctx, state);
+      } else if(link_notif_data->remote_ss == NULL) {
+        /* remote_ss not specified, invoke link notif for any remote_ss */
+        if(link_notif_data->xport) {
+          glinki_check_xport_and_notify(link_notif_data, xport_ctx, state);
+        } /* if else link_notif_data->xport */
+      } /* if else link_notif_data->remote_ss */
+  } while ( (link_notif_data = smem_list_next(link_notif_data)) != NULL);
+
+} /* glinki_scan_notif_list_and_notify */
+
+void glinki_scan_channels_and_notify_discon
+(
+  glink_transport_if_type *if_ptr
+)
+{
+  glink_channel_ctx_type *open_ch_ctx;
+  glink_core_xport_ctx_type  *xport_ctx;
+
+  ASSERT(if_ptr != NULL);
+
+  xport_ctx = if_ptr->glink_core_priv;
+
+  /* Find channel in the open_list */
+  glink_os_cs_acquire(&xport_ctx->channel_q_cs);
+  open_ch_ctx = smem_list_first(&if_ptr->glink_core_priv->open_list);
+  while(open_ch_ctx != NULL)
+  {
+    /* Found channel, transition it to appropriate state based
+     * on current state */
+    if(open_ch_ctx->state == GLINK_CH_STATE_OPEN) {
+      open_ch_ctx->state = GLINK_CH_STATE_LOCAL_OPEN;
+
+      /* Inform the client */
+      open_ch_ctx->notify_state(open_ch_ctx, open_ch_ctx->priv,
+          GLINK_REMOTE_DISCONNECTED);
+    } else if (open_ch_ctx->state == GLINK_CH_STATE_REMOTE_OPEN) {
+      /* Local side never opened the channel */
+      /* Free channel resources */
+      xport_ctx->channel_cleanup(open_ch_ctx);
+
+      smem_list_delete(&if_ptr->glink_core_priv->open_list, open_ch_ctx);
+
+      glink_os_free(open_ch_ctx);
+    }
+    open_ch_ctx = smem_list_next(open_ch_ctx);
+  }/* end while */
+  glink_os_cs_release(&xport_ctx->channel_q_cs);
+}
+
+void glink_ssr(const char* remote_ss)
+{
+  unsigned int remote_host;
+  glink_transport_if_type *if_ptr;
+
+  remote_host = glinki_find_remote_host(remote_ss);
+
+  /* Scan through the registered interfaces with the crashing ss
+     and let the clients know about the crash via LINK_DOWN
+     notification followed by REMOTE_DISCONNECT */
+  if_ptr = smem_list_first(&glink_registered_transports[remote_host]);
+
+  while(if_ptr != NULL) {
+    /* Invoke LINK_DOWN notification for any registered notifiers */
+    glinki_scan_notif_list_and_notify(if_ptr, GLINK_LINK_STATE_DOWN);
+
+    /* Invoke REMOTE_DISCONNECT for all channels associated with if_ptr */
+    glinki_scan_channels_and_notify_discon(if_ptr);
+
+    /* Let the xport know about ssr */
+    if_ptr->ssr(if_ptr);
+
+    if_ptr = smem_list_next(if_ptr);
+  }
+}
+
+
+/*===========================================================================
+                    EXTERNAL FUNCTION DEFINITIONS
+===========================================================================*/
+/*===========================================================================
+FUNCTION      glink_init
+
+DESCRIPTION   Initializes the GLink core library.
+
+ARGUMENTS     None
+
+RETURN VALUE  None
+
+SIDE EFFECTS  None
+===========================================================================*/
+void glink_init(void)
+{
+  uint32 i;
+
+  glink_mem_log_cs = glink_os_cs_create();
+
+  glink_core_status = GLINK_INITIALIZED;
+
+  /* Create/Initalize crtitical sections */
+  glink_transport_q_cs = glink_os_cs_create();
+  if(glink_transport_q_cs == NULL) {
+    return;
+  }
+
+  glink_os_cs_acquire(glink_transport_q_cs);
+  for(i= 0; i < sizeof(glink_registered_transports)/sizeof(smem_list_type);
+      i++)
+  {
+    smem_list_init(&glink_registered_transports[i]);
+  }
+  glink_os_cs_release(glink_transport_q_cs);
+}
+
+/*===========================================================================
+FUNCTION      glink_core_register_transport
+
+DESCRIPTION   Transport calls this API to register its interface with GLINK
+              Core
+
+ARGUMENTS   *if_ptr   Pointer to interface instance; must be unique
+                      for each edge
+
+            *cfg      Pointer to transport configuration structure.
+
+RETURN VALUE  Standard GLINK error codes.
+
+SIDE EFFECTS  None
+===========================================================================*/
+glink_err_type glink_core_register_transport
+(
+  glink_transport_if_type       *if_ptr,
+  glink_core_transport_cfg_type *cfg
+)
+{
+  unsigned int remote_host = 0;
+  glink_core_xport_ctx_type *xport_ctx;
+  /* Param validation */
+  if(if_ptr == NULL || cfg == NULL)
+  {
+    GLINK_LOG_EVENT(GLINK_EVENT_REGISTER_XPORT, NULL, "", "",
+        GLINK_STATUS_INVALID_PARAM);
+    return GLINK_STATUS_INVALID_PARAM;
+  }
+
+  if(cfg->name == NULL       ||
+     cfg->remote_ss == NULL  ||
+     cfg->version == NULL    ||
+     cfg->version_count == 0 ||
+     cfg->max_cid == 0)
+  {
+    GLINK_LOG_EVENT(GLINK_EVENT_REGISTER_XPORT, NULL, "", "",
+        GLINK_STATUS_INVALID_PARAM);
+    return GLINK_STATUS_INVALID_PARAM;
+  }
+
+
+  if(if_ptr->tx_cmd_version == NULL             ||
+     if_ptr->tx_cmd_version_ack == NULL         ||
+     if_ptr->set_version == NULL                ||
+     if_ptr->tx_cmd_ch_open == NULL             ||
+     if_ptr->tx_cmd_ch_close == NULL            ||
+     if_ptr->tx_cmd_ch_remote_open_ack == NULL  ||
+     if_ptr->tx_cmd_ch_remote_close_ack == NULL ||
+     if_ptr->tx_cmd_set_sigs  == NULL           ||
+     if_ptr->ssr  == NULL)
+  {
+    GLINK_LOG_EVENT(GLINK_EVENT_REGISTER_XPORT, NULL, cfg->name,
+        cfg->remote_ss, GLINK_STATUS_INVALID_PARAM);
+    return GLINK_STATUS_INVALID_PARAM;;
+  }
+
+
+  /* Allocate/fill out the GLink Core interface structure */
+  {
+    glink_core_if_type *core_if = glink_os_calloc(sizeof(glink_core_if_type));
+    if(core_if == NULL) {
+      GLINK_LOG_EVENT(GLINK_EVENT_REGISTER_XPORT, NULL, cfg->name,
+          cfg->remote_ss, GLINK_STATUS_OUT_OF_RESOURCES);
+      return GLINK_STATUS_OUT_OF_RESOURCES;
+    }
+    core_if->link_up = glink_link_up;
+    core_if->rx_cmd_version = glink_rx_cmd_version;
+    core_if->rx_cmd_version_ack = glink_rx_cmd_version_ack;
+    core_if->rx_cmd_ch_remote_open = glink_rx_cmd_ch_remote_open;
+    core_if->rx_cmd_ch_open_ack = glink_rx_cmd_ch_open_ack;
+    core_if->rx_cmd_ch_close_ack = glink_rx_cmd_ch_close_ack;
+    core_if->rx_cmd_ch_remote_close = glink_rx_cmd_ch_remote_close;
+    core_if->ch_state_local_trans = glink_ch_state_local_trans;
+    core_if->rx_put_pkt_ctx = glink_rx_put_pkt_ctx;
+    core_if->rx_cmd_remote_sigs = glink_rx_cmd_remote_sigs;
+    core_if->tx_resume = glink_tx_resume;
+    core_if->set_core_version = glink_set_core_version;
+
+    /* Set the glink_core_if_ptr to point to the allocated structure */
+    if_ptr->glink_core_if_ptr = core_if;
+  }
+
+  /* Allocate/fill out the GLink private context data */
+  {
+     xport_ctx = glink_os_calloc(sizeof(glink_core_xport_ctx_type));
+    if(xport_ctx == NULL) {
+      /* Free previously allocated memory */
+      glink_os_free(if_ptr->glink_core_if_ptr);
+
+      GLINK_LOG_EVENT(GLINK_EVENT_REGISTER_XPORT, NULL, cfg->name,
+          cfg->remote_ss, GLINK_STATUS_OUT_OF_RESOURCES);
+
+      return GLINK_STATUS_OUT_OF_RESOURCES;
+    }
+
+    glink_os_string_copy(xport_ctx->xport, cfg->name,
+        sizeof(xport_ctx->xport));
+    glink_os_string_copy(xport_ctx->remote_ss, cfg->remote_ss,
+        sizeof(xport_ctx->xport));
+    xport_ctx->free_lcid = 1; /* lcid 0 is reserved for invalid channel */
+    xport_ctx->version_array = cfg->version;
+    xport_ctx->version_indx = cfg->version_count - 1;
+
+    glink_os_cs_init(&xport_ctx->channel_q_cs);
+    glink_os_cs_init(&xport_ctx->liid_cs);
+
+    glink_os_cs_acquire(&xport_ctx->channel_q_cs);
+    smem_list_init(&xport_ctx->open_list);
+    glink_os_cs_release(&xport_ctx->channel_q_cs);
+
+    /* Set the glink_core_if_ptr to point to the allocated structure */
+    if_ptr->glink_core_priv = xport_ctx;
+    xport_ctx->status = GLINK_XPORT_REGISTERED;
+  }
+
+  /* Push the transport interface into appropriate queue */
+  remote_host = glinki_find_remote_host(cfg->remote_ss);
+
+  if(remote_host == GLINK_NUM_HOSTS ) {
+    /* Unknown transport name trying to register with GLink */
+    GLINK_LOG_EVENT(GLINK_EVENT_REGISTER_XPORT, NULL, xport_ctx->xport,
+           xport_ctx->remote_ss, GLINK_STATUS_INVALID_PARAM);
+
+    return GLINK_STATUS_INVALID_PARAM;
+  }
+  glink_os_cs_acquire(glink_transport_q_cs);
+  smem_list_append(&glink_registered_transports[remote_host], if_ptr);
+  glink_os_cs_release(glink_transport_q_cs);
+
+  GLINK_LOG_EVENT(GLINK_EVENT_REGISTER_XPORT, NULL, xport_ctx->xport,
+      xport_ctx->remote_ss, GLINK_STATUS_SUCCESS);
+
+  return GLINK_STATUS_SUCCESS;
+}
+
+/**
+ * Regsiters a client specified callback to be invoked when the specified
+ * transport (link) is up/down.
+ *
+ * @param[in]    link_id  Pointer to the configuration structure for the
+ *                        xport(link) to be monitored. See glink.h
+ * @param[in]    priv     Callback data returned to client when callback
+ *                        is invoked.
+ *
+ * @return       Standard GLink error codes
+ *
+ * @sideeffects  Puts the callback in a queue which gets scanned when a
+ *               transport(link) comes up OR an SSR happnes.
+ */
+glink_err_type glink_register_link_state_cb
+(
+  glink_link_id_type *link_id,
+  void*              priv
+)
+{
+  glink_link_notif_data_type* link_notif_data;
+  unsigned int remote_host;
+
+  /* Input validation */
+  ASSERT(link_id != NULL);
+
+  /* Make sure client provided us with the correct version of the input
+   * structure */
+  if(link_id->version != GLINK_LINK_ID_VER || link_id->link_notifier == NULL) {
+    return GLINK_STATUS_INVALID_PARAM;
+  }
+
+  /* Save the callback on the notification list */
+  if((link_notif_data = glink_os_malloc(sizeof(glink_link_notif_data_type)))
+       == NULL) {
+    return GLINK_STATUS_OUT_OF_RESOURCES;
+  }
+
+  /* Check for remote_ss validity */
+  if(link_id->remote_ss != NULL) {
+    remote_host = glinki_find_remote_host(link_id->remote_ss);
+
+    if(remote_host == sizeof(glink_hosts_supported)/sizeof(char *)) {
+      glink_os_free(link_notif_data);
+      return GLINK_STATUS_INVALID_PARAM;
+    }
+  }
+
+  link_notif_data->xport = link_id->xport;
+  link_notif_data->remote_ss = link_id->remote_ss;
+  link_notif_data->link_notifier = link_id->link_notifier;
+  link_notif_data->priv = priv; /* private client data */
+
+  /* Append the request to the list for link UP/DOWN notifications */
+  smem_list_append(&glink_link_notif_list, link_notif_data);
+
+  /* Scan the list of available transport to see if this link is already up */
+  glinki_scan_xports_and_notify(link_notif_data);
+
+  return GLINK_STATUS_SUCCESS;
+}
+
+/**
+ * Degsiter the link UP/DOWN notification callback associated with the
+ * provided handle.
+ *
+ * @param[in]    handle  Callback handler returned by
+ *                       glink_register_link_state_cb
+ *
+ * @return       Standard GLink error codes
+ *
+ * @sideeffects  Removes the callback in a queue which gets scanned when a
+ *               transport(link) comes up OR an SSR happnes.
+ */
+glink_err_type glink_deregister_link_state_cb
+(
+  glink_link_handle_type handle
+)
+{
+  ASSERT(handle);
+
+  smem_list_delete(&glink_link_notif_list,
+                   (glink_link_notif_data_type*)handle);
+
+  glink_os_free(handle);
+
+  return GLINK_STATUS_SUCCESS;
+}
+
+/**
+ * This function gives best available transport for give edge
+ *
+ * @param[in]    remote_host  Index into glink_registered_transports array of
+ *                            registered transports list per edge
+ *
+ * @return       pointer to glink_transport_if_type
+ *
+ * @sideeffects  NONE
+ */
+glink_transport_if_type* glink_get_best_xport
+(
+  unsigned int remote_host
+)
+{
+  glink_transport_if_type   *if_ptr    = NULL, *best_if_ptr = NULL;
+  glink_xport_priority       priority  = GLINK_MIN_PRIORITY;
+  glink_core_xport_ctx_type *xport_ctx = NULL;
+
+  best_if_ptr = if_ptr = smem_list_first(
+                          &glink_registered_transports[remote_host]);
+
+  while(if_ptr != NULL)
+  {
+    /* check if priority of current transport is higher than
+     * current highest priority (0 = highest priority)
+     */
+    xport_ctx = if_ptr->glink_core_priv;
+    if( xport_ctx->status == GLINK_XPORT_LINK_UP &&
+        if_ptr->glink_priority < priority )
+    {
+      best_if_ptr = if_ptr;
+      priority    = if_ptr->glink_priority;
+    }
+
+    if_ptr    = smem_list_next(if_ptr);
+  } /* end while() */
+
+  return best_if_ptr;
+}
+
+/**
+ * Opens a logical GLink based on the specified config params
+ *
+ * @param[in]    cfg_ptr  Pointer to the configuration structure for the
+ *                        GLink. See glink.h
+ * @param[out]   handle   GLink handle associated with the logical channel
+ *
+ * @return       Standard GLink error codes
+ *
+ * @sideeffects  Allocates channel resources and informs remote host about
+ *               channel open.
+ */
+glink_err_type glink_open
+(
+  glink_open_config_type *cfg_ptr,
+  glink_handle_type      *handle
+)
+{
+  glink_transport_if_type *if_ptr, *req_if_ptr;
+  glink_channel_ctx_type  *ch_ctx;
+  unsigned int            remote_host;
+
+  /* Param validation */
+  if(cfg_ptr == NULL)
+  {
+    GLINK_LOG_EVENT(GLINK_EVENT_CH_OPEN, NULL, "", "",
+        GLINK_STATUS_INVALID_PARAM);
+    return GLINK_STATUS_INVALID_PARAM;
+  }
+
+  if(cfg_ptr->remote_ss == NULL             ||
+     cfg_ptr->name == NULL                  ||
+     cfg_ptr->notify_state == NULL)
+  {
+    GLINK_LOG_EVENT(GLINK_EVENT_CH_OPEN, NULL, "", "",
+        GLINK_STATUS_INVALID_PARAM);
+    return GLINK_STATUS_INVALID_PARAM;
+  }
+
+  /* Evaluate the equivalent edge name->enum for future use */
+  remote_host = glinki_find_remote_host(cfg_ptr->remote_ss);
+
+  if(remote_host == GLINK_NUM_HOSTS ) {
+    /* Unknown transport name trying to register with GLink */
+    GLINK_LOG_EVENT(GLINK_EVENT_REGISTER_XPORT, cfg_ptr->name, "",
+        cfg_ptr->remote_ss, GLINK_STATUS_INVALID_PARAM);
+
+    return GLINK_STATUS_INVALID_PARAM;
+  }
+
+  /* Allocate and initialize channel info structure */
+  ch_ctx = glink_os_calloc(sizeof(glink_channel_ctx_type));
+  if(ch_ctx == NULL) {
+    GLINK_LOG_EVENT(GLINK_EVENT_CH_OPEN, cfg_ptr->name, "",
+        "", GLINK_STATUS_OUT_OF_RESOURCES);
+    return GLINK_STATUS_OUT_OF_RESOURCES;
+  }
+
+  /* Fill in the channel info structure */
+  glink_os_string_copy(ch_ctx->name, cfg_ptr->name, sizeof(ch_ctx->name));
+  ch_ctx->priv = cfg_ptr->priv;
+  ch_ctx->notify_rx = cfg_ptr->notify_rx;
+  ch_ctx->notify_rxv = cfg_ptr->notify_rxv;
+  ch_ctx->notify_tx_done = cfg_ptr->notify_tx_done;
+  ch_ctx->notify_state = cfg_ptr->notify_state;
+  ch_ctx->notify_rx_intent_req = cfg_ptr->notify_rx_intent_req;
+  ch_ctx->notify_rx_intent = cfg_ptr->notify_rx_intent;
+  ch_ctx->notify_rx_sigs = cfg_ptr->notify_rx_sigs;
+  ch_ctx->ch_open_options = cfg_ptr->options;
+  ch_ctx->notify_rx_abort = cfg_ptr->notify_rx_abort;
+  ch_ctx->notify_tx_abort = cfg_ptr->notify_tx_abort;
+
+  if (ch_ctx->notify_rx_sigs == NULL) {
+    /* set default callback */
+    ch_ctx->notify_rx_sigs = glink_default_notify_rx_sigs;
+  }
+
+  glink_os_cs_acquire(glink_transport_q_cs);
+
+  /* Check to see if requested transport is available */
+  for (if_ptr = smem_list_first(&glink_registered_transports[remote_host]);
+       if_ptr != NULL;
+       if_ptr = smem_list_next(if_ptr))
+  {
+    glink_core_xport_ctx_type *xport_ctx = if_ptr->glink_core_priv;
+    glink_channel_ctx_type    *allocated_ch_ctx;
+
+    if (xport_ctx->status == GLINK_XPORT_LINK_UP &&
+        (cfg_ptr->transport == NULL ||
+         0 == strcmp(cfg_ptr->transport, xport_ctx->xport)) &&
+        xport_ctx->verify_open_cfg(ch_ctx))
+    {
+      glink_err_type status;
+
+      if(cfg_ptr->transport == NULL)
+      {
+        /* get best available transport */
+        if_ptr = req_if_ptr = glink_get_best_xport(remote_host);
+      }
+      else
+      {
+        if(cfg_ptr->options & GLINK_OPT_INITIAL_XPORT)
+        {
+          /* xport suggested by client is optional.
+           * get best available xport */
+          req_if_ptr = glink_get_best_xport(remote_host);
+        }
+        else
+        {
+          req_if_ptr = if_ptr;
+        }
+      }
+      /* Xport match found */
+      status = glinki_add_ch_to_xport( if_ptr,
+                                       req_if_ptr,
+                                       ch_ctx,
+                                       &allocated_ch_ctx,
+                                       TRUE,
+                                       TRUE,
+                                       if_ptr->glink_priority );
+
+      if (status == GLINK_STATUS_SUCCESS) {
+        /* Set the handle and return */
+        *handle = allocated_ch_ctx;
+      }
+      else {
+        *handle = NULL;
+      }
+
+      glink_os_cs_release(glink_transport_q_cs);
+
+      GLINK_LOG_EVENT(GLINK_EVENT_CH_OPEN, ch_ctx->name, xport_ctx->xport,
+        xport_ctx->remote_ss, status);
+      return status;
+    }
+  } /* end for() */
+
+  glink_os_cs_release(glink_transport_q_cs);
+
+  /* Code gets here if we are not able to find reqeusted transport */
+  GLINK_LOG_EVENT(GLINK_EVENT_CH_OPEN, cfg_ptr->name, cfg_ptr->transport,
+      cfg_ptr->remote_ss, GLINK_STATUS_NO_TRANSPORT);
+  glink_os_free(ch_ctx);
+  return GLINK_STATUS_NO_TRANSPORT;
+}
+
+/**
+ * Closes the GLink logical channel specified by the handle.
+ *
+ * @param[in]    handle   GLink handle associated with the logical channel
+ *
+ * @return       Standard GLink error codes
+ *
+ * @sideeffects  Closes local end of the channel and informs remote host
+ */
+glink_err_type glink_close
+(
+  glink_handle_type handle
+)
+{
+  glink_err_type status;
+  glink_core_xport_ctx_type *xport_ctx = handle->if_ptr->glink_core_priv;
+  glink_ch_state_type ch_state;
+
+  if(handle == NULL) {
+    GLINK_LOG_EVENT(GLINK_EVENT_CH_CLOSE, NULL, "",
+        "", GLINK_STATUS_INVALID_PARAM);
+    return GLINK_STATUS_INVALID_PARAM;
+  }
+
+  ch_state = handle->state;
+
+  /* Check to see if channel is in open/opening state */
+  if (ch_state != GLINK_CH_STATE_OPEN &&
+      ch_state != GLINK_CH_STATE_LOCAL_OPEN &&
+      ch_state != GLINK_CH_STATE_LOCAL_OPEN_REMOTE_CLOSE &&
+      ch_state != GLINK_CH_STATE_REMOTE_OPEN)
+  {
+    GLINK_LOG_EVENT(GLINK_EVENT_CH_CLOSE, handle->name, xport_ctx->xport,
+      xport_ctx->remote_ss, ch_state);
+    return GLINK_STATUS_FAILURE;
+  }
+
+  /* Transition to closing */
+  //handle->state = GLINK_CH_STATE_CLOSING;
+
+  /* Send CLOSE cmd to the transport interface */
+  status = handle->if_ptr->tx_cmd_ch_close(handle->if_ptr, handle->lcid);
+  GLINK_LOG_EVENT(GLINK_EVENT_CH_CLOSE, handle->name, xport_ctx->xport,
+      xport_ctx->remote_ss, status);
+  return status;
+
+}
+
+/**
+ * Transmit the provided buffer over GLink.
+ *
+ * @param[in]    handle    GLink handle associated with the logical channel
+ *
+ * @param[in]   *pkt_priv  Per packet private data
+ *
+ * @param[in]   *data      Pointer to the data buffer to be transmitted
+ *
+ * @param[in]   size       Size of buffer
+ *
+ * @param[in]   req_intent Whether to block and request for remote rx intent in
+ *                         case it is not available for this pkt tx
+ *
+ * @return       Standard GLink error codes
+ *
+ * @sideeffects  Causes remote host to wake-up and process rx pkt
+ */
+glink_err_type glink_tx
+(
+  glink_handle_type handle,
+  const void        *pkt_priv,
+  const void        *data,
+  size_t            size,
+  uint32            options
+)
+{
+  return glink_txv(handle, pkt_priv, (void*)data, size,
+                   &glink_dummy_tx_vprovider, NULL, options);
+
+}
+
+/**
+ * Transmit the provided vector buffer over GLink.
+ *
+ * @param[in]    handle    GLink handle associated with the logical channel
+ *
+ * @param[in]   *pkt_priv  Per packet private data
+ *
+ * @param[in]   *iovec     Pointer to the vector buffer to be transmitted
+ *
+ * @param[in]   size       Size of buffer
+ *
+ * @param[in]   vprovider  Buffer provider for virtual space
+ *
+ * @param[in]   pprovider  Buffer provider for physical space
+ *
+ * @param[in]   req_intent Whether to block and request for remote rx intent in
+ *                         case it is not available for this pkt tx
+ *
+ * @return       Standard GLink error codes
+ *
+ * @sideeffects  Causes remote host to wake-up and process rx pkt
+ */
+glink_err_type glink_txv
+(
+  glink_handle_type        handle,
+  const void               *pkt_priv,
+  void                     *iovec,
+  size_t                   size,
+  glink_buffer_provider_fn vprovider,
+  glink_buffer_provider_fn pprovider,
+  uint32                   options
+)
+{
+  glink_err_type         status;
+  glink_core_tx_pkt_type pctx;
+  boolean                req_intent = options & GLINK_TX_REQ_INTENT;
+  glink_core_xport_ctx_type *xport_ctx = handle->if_ptr->glink_core_priv;
+
+  /* Input validation */
+  if(handle == NULL || iovec == NULL || size == 0 ||
+     (vprovider == NULL && pprovider == NULL)) {
+    GLINK_LOG_EVENT(GLINK_EVENT_CH_TX, NULL, "",
+        "", GLINK_STATUS_INVALID_PARAM);
+    return GLINK_STATUS_INVALID_PARAM;
+  }
+
+  /* Make sure channel is in OPEN state */
+  if(handle->state != GLINK_CH_STATE_OPEN )
+  {
+    GLINK_LOG_EVENT(GLINK_EVENT_CH_CLOSE, handle->name, xport_ctx->xport,
+      xport_ctx->remote_ss, GLINK_STATUS_FAILURE);
+    return GLINK_STATUS_FAILURE;
+  }
+
+  /* Protect the entire tx operation under a lock as a client may call
+     tx in different thread context */
+  glink_os_cs_acquire(&handle->tx_cs);
+
+  pctx.pkt_priv = pkt_priv;
+  pctx.size = size;
+  pctx.size_remaining = size;
+  pctx.vprovider = vprovider;
+  pctx.pprovider = pprovider;
+
+  if (vprovider == &glink_dummy_tx_vprovider)
+  {
+    pctx.data = (void*)iovec;
+    pctx.iovec = &pctx;
+  }
+  else
+  {
+    pctx.data = (void*)iovec;
+    pctx.iovec = iovec;
+  }
+
+  status = xport_ctx->use_rm_intent(handle, &pctx, req_intent);
+
+  /* Call transport API to transmit data */
+  while (pctx.size_remaining != 0 && status == GLINK_STATUS_SUCCESS)
+  {
+    status = handle->if_ptr->tx(handle->if_ptr, handle->lcid, &pctx);
+  }
+
+  GLINK_LOG_EVENT(GLINK_EVENT_CH_TX, handle->name, xport_ctx->xport,
+      xport_ctx->remote_ss, status);
+
+  glink_os_cs_release(&handle->tx_cs);
+  return status;
+}
+
+/**
+ * Queue one or more Rx intent for the logical GPIC Link channel.
+ *
+ * @param[in]    handle   GLink handle associated with the logical channel
+ *
+ * @param[in]   *pkt_priv Per packet private data
+ *
+ * @param[in]   size      Size of buffer
+ *
+ * @return       Standard GLink error codes
+ *
+ * @sideeffects  GLink XAL allocates rx buffers for receiving packets
+ */
+glink_err_type glink_queue_rx_intent
+(
+  glink_handle_type handle,
+  const void        *pkt_priv,
+  size_t            size
+)
+{
+  glink_err_type         status;
+  glink_rx_intent_type   *lc_intent;
+  glink_core_xport_ctx_type *xport_ctx = handle->if_ptr->glink_core_priv;
+  size_t tmp;
+
+  /* Input validation */
+  if(handle == NULL || size == 0) {
+    GLINK_LOG_EVENT(GLINK_EVENT_CH_Q_RX_INTENT, NULL, "",
+        "", GLINK_STATUS_INVALID_PARAM);
+    return GLINK_STATUS_INVALID_PARAM;
+  }
+
+  /* short circuit for intentless mode */
+  if(xport_ctx->xport_capabilities & GLINK_CAPABILITY_INTENTLESS) {
+    return GLINK_STATUS_FAILURE;
+  }
+
+  /* Make sure channel is in OPEN state */
+  if(handle->state != GLINK_CH_STATE_OPEN)
+  {
+    GLINK_LOG_EVENT(GLINK_EVENT_CH_Q_RX_INTENT, handle->name, xport_ctx->xport,
+      xport_ctx->remote_ss, GLINK_STATUS_FAILURE);
+    return GLINK_STATUS_FAILURE;
+  }
+
+  /* Allocate an intent structure */
+  lc_intent = glink_os_calloc(sizeof(glink_rx_intent_type));
+  if(lc_intent == NULL) {
+    GLINK_LOG_EVENT(GLINK_EVENT_CH_Q_RX_INTENT, handle->name, xport_ctx->xport,
+        xport_ctx->remote_ss, GLINK_STATUS_OUT_OF_RESOURCES);
+    return GLINK_STATUS_OUT_OF_RESOURCES;
+  }
+
+  glink_os_cs_acquire(&handle->if_ptr->glink_core_priv->liid_cs);
+
+  /* Call transport API to allocate rx intent buffer */
+  status = handle->if_ptr->allocate_rx_intent(handle->if_ptr, size, lc_intent);
+  if(status != GLINK_STATUS_SUCCESS) {
+    glink_os_free(lc_intent);
+    glink_os_cs_release(&handle->if_ptr->glink_core_priv->liid_cs);
+    GLINK_LOG_EVENT(GLINK_EVENT_CH_Q_RX_INTENT, handle->name, xport_ctx->xport,
+        xport_ctx->remote_ss, status);
+    return status;
+  }
+
+  if (handle->notify_rxv == NULL &&
+     (lc_intent->vprovider(lc_intent->iovec, 0, &tmp) == NULL || tmp < size)) {
+    /* Allocate bounce buffer for non-vectored Rx */
+    lc_intent->data = glink_os_malloc(size);
+
+    if(lc_intent->data == NULL) {
+      handle->if_ptr->deallocate_rx_intent(handle->if_ptr, lc_intent);
+      glink_os_free(lc_intent);
+      glink_os_cs_release(&handle->if_ptr->glink_core_priv->liid_cs);
+      GLINK_LOG_EVENT(GLINK_EVENT_CH_Q_RX_INTENT, handle->name,
+        xport_ctx->xport, xport_ctx->remote_ss, GLINK_STATUS_OUT_OF_RESOURCES);
+      return GLINK_STATUS_OUT_OF_RESOURCES;
+    }
+  }
+
+  /* push the intent on local queue. Do this before calling tx cmd
+     as transport may try to read data into the newly queued rx_buffer */
+  lc_intent->iid = handle->if_ptr->glink_core_priv->liid;
+  lc_intent->size = size;
+  lc_intent->pkt_priv = pkt_priv;
+  glink_os_cs_acquire(&handle->pintents->intent_q_cs);
+  smem_list_append(&handle->pintents->local_intent_q, lc_intent);
+  glink_os_cs_release(&handle->pintents->intent_q_cs);
+
+  /* Call transport API to queue rx intent */
+  /* Increment the local intent ID counter associated with this channel */
+  handle->if_ptr->glink_core_priv->liid++;
+
+  status = handle->if_ptr->tx_cmd_local_rx_intent(handle->if_ptr,
+              handle->lcid, size, lc_intent->iid);
+  if(status != GLINK_STATUS_SUCCESS) {
+    /* Failure */
+    glink_os_cs_acquire(&handle->pintents->intent_q_cs);
+    smem_list_delete(&handle->pintents->local_intent_q, lc_intent);
+    glink_os_cs_release(&handle->pintents->intent_q_cs);
+
+    handle->if_ptr->deallocate_rx_intent(handle->if_ptr, lc_intent);
+    glink_os_free(lc_intent->data);
+    glink_os_free(lc_intent);
+  }
+  glink_os_cs_release(&handle->if_ptr->glink_core_priv->liid_cs);
+
+  GLINK_LOG_EVENT(GLINK_EVENT_CH_Q_RX_INTENT, handle->name, xport_ctx->xport,
+      xport_ctx->remote_ss, status);
+  return status;
+}
+
+/**
+ * Client uses this to signal to GLink layer that it is done with the received
+ * data buffer. This API should be called to free up the receive buffer, which,
+ * in zero-copy mode is actually remote-side's transmit buffer.
+ *
+ * @param[in]    handle   GLink handle associated with the logical channel
+ *
+ * @param[in]   *ptr      Pointer to the received buffer
+ *
+ * @param[in]   reuse    Reuse intent
+ *
+ * @return       Standard GLink error codes
+ *
+ * @sideeffects  GLink XAL frees the Rx buffer
+ */
+glink_err_type glink_rx_done
+(
+  glink_handle_type handle,
+  const void        *ptr,
+  boolean           reuse
+)
+{
+  glink_rx_intent_type      *lc_intent;
+  glink_core_xport_ctx_type *xport_ctx = handle->if_ptr->glink_core_priv;
+
+  /* Input validation */
+  if(handle == NULL || ptr == NULL) {
+    GLINK_LOG_EVENT(GLINK_EVENT_CH_RX_DONE, NULL, "",
+        "", GLINK_STATUS_INVALID_PARAM);
+    return GLINK_STATUS_INVALID_PARAM;
+  }
+
+  /* short circuit for intentless mode */
+  if(xport_ctx->xport_capabilities & GLINK_CAPABILITY_INTENTLESS) {
+    return GLINK_STATUS_SUCCESS;
+  }
+
+  /* Make sure channel is in OPEN state */
+  if(handle->state != GLINK_CH_STATE_OPEN)
+  {
+    GLINK_LOG_EVENT(GLINK_EVENT_CH_RX_DONE, handle->name, xport_ctx->xport,
+      xport_ctx->remote_ss, GLINK_STATUS_FAILURE);
+    return GLINK_STATUS_FAILURE;
+  }
+
+  /* Free the intent */
+  lc_intent = smem_list_first(&handle->pintents->local_intent_client_q);
+  while(lc_intent != NULL) {
+    size_t tmp;
+
+    if(lc_intent->iovec == ptr || (handle->notify_rxv == NULL &&
+       (lc_intent->data == ptr ||
+       ptr == lc_intent->vprovider(lc_intent->iovec, 0, &tmp)))) {
+
+      uint32 iid;
+
+      /* Found intent, delete it */
+      glink_os_cs_acquire(&handle->pintents->intent_q_cs);
+      smem_list_delete(&handle->pintents->local_intent_client_q, lc_intent);
+      glink_os_cs_release(&handle->pintents->intent_q_cs);
+
+      iid = lc_intent->iid;
+
+      if (reuse)
+      {
+        lc_intent->used = 0;
+
+        glink_os_cs_acquire(&handle->pintents->intent_q_cs);
+        smem_list_append(&handle->pintents->local_intent_q, lc_intent);
+        glink_os_cs_release(&handle->pintents->intent_q_cs);
+      }
+      else
+      {
+        /* Free the intent */
+        handle->if_ptr->deallocate_rx_intent(handle->if_ptr, lc_intent);
+        if(lc_intent->data) {
+          /* Free the bounce buffer if we had allocated one */
+          glink_os_free(lc_intent->data);
+        }
+        glink_os_free(lc_intent);
+      }
+
+      /* Note that the actual buffer, lc_intent->data, was allocated by the
+      * transport and should be freed by the xport. We should not touch it */
+      /* Let the xport know we are done with the buffer */
+      handle->if_ptr->tx_cmd_local_rx_done(handle->if_ptr, handle->lcid,
+                                           iid, reuse);
+
+      GLINK_LOG_EVENT(GLINK_EVENT_CH_RX_DONE, handle->name, xport_ctx->xport,
+          xport_ctx->remote_ss, GLINK_STATUS_SUCCESS);
+      return GLINK_STATUS_SUCCESS;
+    }
+    lc_intent = smem_list_next(lc_intent);
+  }
+
+  GLINK_LOG_EVENT(GLINK_EVENT_CH_RX_DONE, handle->name, xport_ctx->xport,
+      xport_ctx->remote_ss, GLINK_STATUS_INVALID_PARAM);
+  return GLINK_STATUS_INVALID_PARAM;
+}
+
+/**
+ * Set the 32 bit control signal field. Depending on the transport, it may
+ * take appropriate actions on the set bit-mask, or transmit the entire
+ * 32-bit value to the remote host.
+ *
+ * @param[in]   handle     GLink handle associated with the logical channel
+ *
+ * @param[in]   sig_value  32 bit signal word
+ *
+ * @return       Standard GLink error codes
+ *
+ * @sideeffects  None
+ */
+glink_err_type glink_sigs_set
+(
+  glink_handle_type handle,
+  uint32            sig_value
+)
+{
+  glink_core_xport_ctx_type *xport_ctx = handle->if_ptr->glink_core_priv;
+  glink_err_type status;
+
+  /* Input validation */
+  if(handle == NULL) {
+    GLINK_LOG_EVENT(GLINK_EVENT_CH_SIG_SET, NULL, "",
+        "", GLINK_STATUS_INVALID_PARAM);
+    return GLINK_STATUS_INVALID_PARAM;
+  }
+
+  /* Make sure channel is in OPEN state */
+  if(handle->state != GLINK_CH_STATE_OPEN)
+  {
+    GLINK_LOG_EVENT(GLINK_EVENT_CH_SIG_SET, handle->name, xport_ctx->xport,
+      xport_ctx->remote_ss, GLINK_STATUS_FAILURE);
+    return GLINK_STATUS_FAILURE;
+  }
+
+  status = handle->if_ptr->tx_cmd_set_sigs(handle->if_ptr, handle->lcid,
+                                           sig_value);
+  if(GLINK_STATUS_SUCCESS == status) {
+    /* Update local copy of local control signal state */
+    handle->local_sigs = sig_value;
+  }
+
+  return status;
+}
+
+/**
+ * Get the local 32 bit control signal bit-field.
+ *
+ * @param[in]   handle      GLink handle associated with the logical channel
+ *
+ * @param[out]  *sig_value  Pointer to a 32 bit signal word to get sig value
+ *
+ * @return      Standard GLink error codes
+ *
+ * @sideeffects  None
+ */
+glink_err_type glink_sigs_local_get
+(
+  glink_handle_type handle,
+  uint32            *sig_value
+)
+{
+  /* Input validation */
+  if(handle == NULL || sig_value == NULL) {
+    GLINK_LOG_EVENT(GLINK_EVENT_CH_SIG_L_GET, NULL, "",
+        "", GLINK_STATUS_INVALID_PARAM);
+    return GLINK_STATUS_INVALID_PARAM;
+  }
+
+  *sig_value = handle->local_sigs;
+
+  return GLINK_STATUS_SUCCESS;
+}
+
+/**
+ * Get the remote 32 bit control signal bit-field.
+ *
+ * @param[in]   handle      GLink handle associated with the logical channel
+ *
+ * @param[out]  *sig_value  Pointer to a 32 bit signal word to get sig value
+ *
+ * @return      Standard GLink error codes
+ *
+ * @sideeffects  None
+ */
+glink_err_type glink_sigs_remote_get
+(
+  glink_handle_type handle,
+  uint32            *sig_value
+)
+{
+  /* Input validation */
+  if(handle == NULL || sig_value == NULL) {
+    GLINK_LOG_EVENT(GLINK_EVENT_CH_SIG_R_GET, NULL, "",
+        "", GLINK_STATUS_INVALID_PARAM);
+    return GLINK_STATUS_INVALID_PARAM;
+  }
+
+  *sig_value = handle->remote_sigs;
+
+  return GLINK_STATUS_SUCCESS;
+}
+
+/*================= RESTRICTED API ==========================*/
+
+/**
+ * This API allows the RPM client to poll the transport for any new data
+ * that might have come in. It would *usually* be used when incoming interrupts
+ * are disabled.
+ *
+ * @param[in]   handle      GLink handle associated with the logical channel
+ *
+ * @return      Standard GLink error codes
+ *
+ * @sideeffects  None
+ */
+glink_err_type glink_rpm_rx_poll
+(
+  glink_handle_type handle
+)
+{
+  ASSERT(handle);
+
+  if(handle->if_ptr->poll) {
+    return handle->if_ptr->poll(handle->if_ptr);
+  }
+  return GLINK_STATUS_FAILURE;
+}
+
+/**
+ * This API allows the RPM client to mask/unmask rx interrupts
+ *
+ * @param[in]   handle      GLink handle associated with the logical channel
+ *
+ * @param[in]   mask        Whether to mask or un-mask the incoming interrupt
+ *
+ * @param[in]   platform_struct Any platform specific into that transport may
+                                require
+ *
+ * @return      Standard GLink error codes
+ *
+ * @sideeffects  None
+ */
+glink_err_type glink_rpm_mask_rx_interrupt
+(
+  glink_handle_type handle,
+  boolean           mask,
+  void              *platform_struct
+)
+{
+  ASSERT(handle);
+
+  if(handle->if_ptr->mask_rx_irq) {
+    return handle->if_ptr->mask_rx_irq(handle->if_ptr, mask);
+  }
+  return GLINK_STATUS_FAILURE;
+}
+
+/**
+ * This API waits until link is down.
+ *
+ * @param[in]   handle      GLink handle associated with the logical channel
+ *
+ * @return      Standard GLink error codes
+ *
+ * @sideeffects  None
+ */
+glink_err_type glink_wait_link_down
+(
+  glink_handle_type handle
+)
+{
+  ASSERT(handle && handle->if_ptr && handle->if_ptr->wait_link_down);
+
+  return handle->if_ptr->wait_link_down(handle->if_ptr) ?
+         GLINK_STATUS_SUCCESS : GLINK_STATUS_FAILURE;
+}
+
+/* ============ Internal Logging API ================ */
+void glink_mem_log
+(
+  const char *func,
+  uint32 line,
+  glink_log_event_type type,
+  const char *msg,
+  const char *xport,
+  const char *remote_ss,
+  uint32 param
+)
+{
+#ifdef DEBUG_GLINK
+  dprintf(INFO, "%s:%u, event:%d, msg:%s, xport:%s, remote_ss:%s, param:%u\n", func, line, type, msg, xport, remote_ss, param);
+#endif
+}
diff --git a/platform/msm_shared/glink/glink_core_if.c b/platform/msm_shared/glink/glink_core_if.c
new file mode 100644
index 0000000..3c66369
--- /dev/null
+++ b/platform/msm_shared/glink/glink_core_if.c
@@ -0,0 +1,983 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+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 The Linux Foundation 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+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 FILES
+===========================================================================*/
+
+#include "glink_os_utils.h"
+#include "glink.h"
+#include "glink_internal.h"
+#include "glink_core_if.h"
+#include "smem_list.h"
+#include "glink_channel_migration.h"
+
+
+#define FEATURE_CH_MIGRATION_FREE
+
+void glinki_scan_notif_list_and_notify
+(
+  glink_transport_if_type *if_ptr,
+  glink_link_state_type state
+);
+
+/*===========================================================================
+                              GLOBAL DATA DECLARATIONS
+===========================================================================*/
+
+/*===========================================================================
+                     LOCAL FUNCTION DEFINITIONS
+===========================================================================*/
+/*===========================================================================
+FUNCTION      glink_process_negotiation_complete
+===========================================================================*/
+/**
+
+  This is called when negotiation is complete.
+  It will set the version and call link up callback to notify
+
+
+  @param[in]    xport_ctx    transport context
+
+  @param[in]    if_ptr       Pointer to interface instance; must be unique
+                             for each edge
+
+  @param[in]    version      negotiated version
+
+  @param[in]    features     negotiated with local side
+
+  @return        None
+  @sideeffects   None.
+  @dependencies  None.
+*/
+/*=========================================================================*/
+static void glink_process_negotiation_complete
+(
+  glink_core_xport_ctx_type *xport_ctx,
+  glink_transport_if_type   *if_ptr,
+  uint32                    version,
+  uint32                    features
+)
+{
+  /* Version/Feautre can be negotiated both in ver_req and ver_ack
+   * Only go through process once in case they are negotiated
+   * in ver_req before receiving ver_ack */
+  if( xport_ctx->status == GLINK_XPORT_LINK_UP )
+  {
+    return;
+  }
+
+  /* setup core based on transport capabilities*/
+  xport_ctx->xport_capabilities = if_ptr->set_version( if_ptr,
+                                                       version,
+                                                       features );
+  glink_core_setup(if_ptr);
+
+  /* transport is ready to open channels */
+  if_ptr->glink_core_priv->status = GLINK_XPORT_LINK_UP;
+
+  /* Scan the notification list to check is we have to let any registered
+  * clients know that link came online */
+  glinki_scan_notif_list_and_notify(if_ptr, GLINK_LINK_STATE_UP);
+}
+
+static void glink_dummy_ch_migration_notification_cb
+(
+  glink_handle_type         handle,
+  const void               *priv,
+  glink_channel_event_type event
+)
+{
+}
+
+/*===========================================================================
+                    EXTERNAL FUNCTION DEFINITIONS
+===========================================================================*/
+/*===========================================================================
+FUNCTION      glink_link_up
+
+DESCRIPTION   Indicates that transport is now ready to start negotiation
+              using the v0 configuration
+
+ARGUMENTS   *if_ptr   Pointer to interface instance; must be unique
+                      for each edge
+
+RETURN VALUE  None.
+
+SIDE EFFECTS  None
+===========================================================================*/
+void glink_link_up
+(
+  glink_transport_if_type *if_ptr
+)
+{
+  const glink_core_version_type *version_array;
+  glink_core_xport_ctx_type *xport_ctx;
+
+  ASSERT(if_ptr != NULL);
+
+  xport_ctx = if_ptr->glink_core_priv;
+
+  version_array = xport_ctx->version_array;
+
+  /* Update the transport state */
+  if_ptr->glink_core_priv->status = GLINK_XPORT_NEGOTIATING;
+
+  /* Start the negtiation */
+  if_ptr->tx_cmd_version(if_ptr, version_array->version,
+      version_array->features);
+
+  GLINK_LOG_EVENT(GLINK_EVENT_LINK_UP, NULL, xport_ctx->xport,
+      xport_ctx->remote_ss, GLINK_STATUS_SUCCESS);
+
+}
+
+/*===========================================================================
+FUNCTION      glink_rx_cmd_version
+
+DESCRIPTION   Receive transport version for remote-initiated version
+              negotiation
+
+ARGUMENTS   *if_ptr   Pointer to interface instance; must be unique
+                      for each edge
+
+            version  Remote Version
+
+            features Remote Features
+
+RETURN VALUE  None.
+
+SIDE EFFECTS  None
+===========================================================================*/
+void glink_rx_cmd_version
+(
+  glink_transport_if_type *if_ptr,
+  uint32                  version,
+  uint32                  features
+)
+{
+  const glink_core_version_type *ver;
+  uint32 negotiated_features;
+  glink_core_xport_ctx_type *xport_ctx;
+
+  ASSERT(if_ptr != NULL);
+
+  xport_ctx = if_ptr->glink_core_priv;
+
+  /* The version to use must be a subset of supported version and features
+   * on this host and remote host */
+  ver = &xport_ctx->version_array[xport_ctx->version_indx];
+  ASSERT(ver);
+
+  if (version == ver->version)
+  {
+    /* Call the transport's negotiation function */
+    negotiated_features = ver->negotiate_features(if_ptr, ver, features);
+
+    /* If negotiated features match the provided features, version nogetiation
+     * is complete */
+    if(negotiated_features == features)
+    {
+      /* send version ack before allowing to open channels */
+      if_ptr->tx_cmd_version_ack(if_ptr, version, features);
+
+      glink_process_negotiation_complete( xport_ctx, if_ptr,
+                                          version, features );
+      return;
+    }
+    else
+    {
+      if_ptr->tx_cmd_version_ack(if_ptr, version, negotiated_features);
+    }
+  }
+  else
+  {
+    /* Next time use older version */
+    ver = &xport_ctx->version_array[xport_ctx->version_indx];
+
+    /* Versions don't match, return ACK with the feature set that we support */
+    if_ptr->tx_cmd_version_ack(if_ptr, ver->version, ver->features);
+  }
+}
+
+/*===========================================================================
+FUNCTION      glink_rx_cmd_version_ack
+
+DESCRIPTION   Receive ACK to previous glink_transport_if::tx_cmd_version
+              command
+
+ARGUMENTS   *if_ptr   Pointer to interface instance; must be unique
+                      for each edge
+
+            version  Remote Version
+
+            features Remote Features
+
+RETURN VALUE  None.
+
+SIDE EFFECTS  None
+===========================================================================*/
+void glink_rx_cmd_version_ack
+(
+  glink_transport_if_type *if_ptr,
+  uint32                  version,
+  uint32                  features
+)
+{
+  const glink_core_version_type* ver;
+  uint32 negotiated_features;
+  glink_core_xport_ctx_type *xport_ctx;
+
+  ASSERT(if_ptr != NULL);
+
+  xport_ctx = if_ptr->glink_core_priv;
+
+  /* Check to see if version returned by remote end is supported by
+   * this host. Remote side would have acked only when the version/features
+   * sent by this host did not match the remote */
+
+  ver = &xport_ctx->version_array[xport_ctx->version_indx];
+  ASSERT(ver);
+
+  if (ver->version == version)
+  {
+    /* Call the transport's negotiation function */
+    negotiated_features = ver->negotiate_features(if_ptr, ver, features);
+
+    if(negotiated_features != features)
+    {
+      /* Continue negotiating */
+      if_ptr->tx_cmd_version(if_ptr, version, negotiated_features);
+    }
+    else
+    {
+      glink_process_negotiation_complete( xport_ctx, if_ptr,
+                                          version, features );
+    }
+  }
+  else
+  {
+    while (ver->version > version)
+    {
+      /* Next time use older version */
+      ASSERT(xport_ctx->version_indx > 0);
+      xport_ctx->version_indx--;
+      ver = &xport_ctx->version_array[xport_ctx->version_indx];
+    }
+
+    /* Versions don't match, return ACK with the feature set that we support */
+    if_ptr->tx_cmd_version(if_ptr, ver->version, ver->features);
+  }
+}
+
+/*===========================================================================
+FUNCTION      glink_rx_cmd_ch_remote_open
+
+DESCRIPTION   Receive remote channel open request; Calls
+              glink_transport_if:: tx_cmd_ch_remote_open_ack as a result
+
+ARGUMENTS   *if_ptr   Pointer to interface instance; must be unique
+                      for each edge
+
+            rcid     Remote Channel ID
+
+            *name    String name for logical channel
+
+            prio     xport priority requested by remote side
+
+RETURN VALUE  None.
+
+SIDE EFFECTS  None
+===========================================================================*/
+void glink_rx_cmd_ch_remote_open
+(
+  glink_transport_if_type *if_ptr,
+  uint32                  rcid,
+  const char              *name,
+  glink_xport_priority    priority
+)
+{
+  glink_channel_ctx_type *remote_ch_ctx;
+  glink_channel_ctx_type  *allocated_ch_ctx;
+  glink_core_xport_ctx_type  *xport_ctx;
+  glink_err_type status;
+  glink_xport_priority negotiated_prio;
+  boolean migration_state = TRUE;
+
+  ASSERT(if_ptr != NULL);
+  ASSERT(name != NULL);
+
+#ifndef FEATURE_CH_MIGRATION_FREE
+  glink_transport_if_type *present_if_ptr = NULL;
+  boolean channel_exist = FALSE;
+  glink_channel_ctx_type *present_ch_ctx = NULL;
+  /* search if channel with given name exists locally */
+  channel_exist = glinki_local_channel_exists(if_ptr, &present_if_ptr, name, &present_ch_ctx, TRUE);
+
+  /* start channel migration negotiation only if channel exists on local side
+   * for negotiation AND channel is willing to migrate */
+  if(channel_exist &&
+     (present_ch_ctx->ch_open_options & GLINK_OPT_INITIAL_XPORT))
+  {
+    /* channel exists on one of the xports for given remote ss */
+    current_prio =  present_ch_ctx->req_if_ptr->glink_priority;
+    negotiated_prio = glinki_negotiate_ch_migration(priority, current_prio);
+
+    /* if current channel is open in same xport as negotiated xport
+     * local side wont migrate. Set migration flag to FALSE */
+    if(negotiated_prio == present_if_ptr->glink_priority)
+    {
+      migration_state = FALSE;
+    }
+  }
+  else if(channel_exist)
+  {
+    /* channel exists but channel does not want to be moved to another xport.
+       channel is set in stone */
+    negotiated_prio = present_if_ptr->glink_priority;
+    migration_state = FALSE;
+  }
+  else
+  {
+    /* channel does not exist on local side as yet
+     * return negotiated prio as current xport prio on which
+     * remote open request is received */
+    negotiated_prio = if_ptr->glink_priority;
+    migration_state = FALSE;
+  }
+#else
+  negotiated_prio = if_ptr->glink_priority;
+    migration_state = FALSE;
+#endif
+
+  xport_ctx = if_ptr->glink_core_priv;
+
+  /* Allocate and initialize channel info structure */
+  remote_ch_ctx = glink_os_calloc(sizeof(glink_channel_ctx_type));
+  if(remote_ch_ctx == NULL) {
+    GLINK_LOG_EVENT(GLINK_EVENT_RM_CH_OPEN, name, xport_ctx->xport,
+        xport_ctx->remote_ss, GLINK_STATUS_OUT_OF_RESOURCES);
+    ASSERT(0);
+  }
+
+  /* Fill in the channel info structure */
+  glink_os_string_copy(remote_ch_ctx->name, name, sizeof(remote_ch_ctx->name));
+  remote_ch_ctx->rcid = rcid;
+
+  status = glinki_add_ch_to_xport(if_ptr, NULL, remote_ch_ctx,
+                                  &allocated_ch_ctx, FALSE,
+                                  migration_state, negotiated_prio);
+  ASSERT(status == GLINK_STATUS_SUCCESS);
+
+  GLINK_LOG_EVENT(GLINK_EVENT_RM_CH_OPEN, name, xport_ctx->xport,
+      xport_ctx->remote_ss, GLINK_STATUS_SUCCESS);
+
+#ifndef FEATURE_CH_MIGRATION_FREE
+
+  /* We are done with channel migration negotiation at this stage
+   * Tag all channels with given name on xports other than negotiated
+   * xport for deletion */
+  glinki_tag_ch_for_deletion(if_ptr, name, negotiated_prio);
+
+    if(migration_state == TRUE)
+    {
+      glink_channel_ctx_type *new_ch_ctx;
+
+    /* create a new channel context as current channel will be migrated */
+    new_ch_ctx = (glink_channel_ctx_type *)
+                   glink_os_calloc(sizeof(glink_channel_ctx_type));
+
+    /* Fill in the channel info structure */
+    new_ch_ctx->req_if_ptr =
+             glinki_get_xport_from_prio(negotiated_prio,
+                                          if_ptr->glink_core_priv->remote_ss);
+    glink_os_string_copy(new_ch_ctx->name, present_ch_ctx->name,
+                         sizeof(present_ch_ctx->name));
+    new_ch_ctx->priv = present_ch_ctx->priv;
+    new_ch_ctx->notify_rx = present_ch_ctx->notify_rx;
+    new_ch_ctx->notify_rxv = present_ch_ctx->notify_rxv;
+    new_ch_ctx->notify_tx_done = present_ch_ctx->notify_tx_done;
+    new_ch_ctx->notify_state = present_ch_ctx->notify_state;
+    new_ch_ctx->notify_rx_intent_req = present_ch_ctx->notify_rx_intent_req;
+    new_ch_ctx->notify_rx_intent = present_ch_ctx->notify_rx_intent;
+    new_ch_ctx->notify_rx_sigs = present_ch_ctx->notify_rx_sigs;
+    new_ch_ctx->ch_open_options = present_ch_ctx->ch_open_options;
+
+//      glink_os_cs_init(&new_ch_ctx->intent_q_cs);
+
+    /* close current channel */
+    present_ch_ctx->notify_state = glink_dummy_ch_migration_notification_cb;
+    if_ptr->tx_cmd_ch_close( if_ptr, present_ch_ctx->lcid );
+
+    /* add new channel context on negotiated xport */
+    glinki_add_ch_to_xport(new_ch_ctx->req_if_ptr,
+                           new_ch_ctx->req_if_ptr,
+                           new_ch_ctx,
+                           &allocated_ch_ctx,
+                           TRUE,
+                           TRUE,
+                           new_ch_ctx->req_if_ptr->glink_priority);
+  }
+#endif
+}
+
+/*===========================================================================
+FUNCTION      glink_rx_cmd_ch_open_ack
+
+DESCRIPTION   This function is invoked by the transport in response to
+              glink_transport_if:: tx_cmd_ch_open
+
+ARGUMENTS   *if_ptr   Pointer to interface instance; must be unique
+                      for each edge
+
+            lcid     Local Channel ID
+
+            prio     Negotiated xport priority from remote side
+
+RETURN VALUE  None.
+
+SIDE EFFECTS  None
+===========================================================================*/
+void glink_rx_cmd_ch_open_ack
+(
+  glink_transport_if_type *if_ptr,
+  uint32                  lcid,
+  glink_xport_priority    migrated_ch_prio
+)
+{
+  glink_channel_ctx_type *open_ch_ctx;
+  glink_core_xport_ctx_type  *xport_ctx;
+
+  ASSERT(if_ptr != NULL);
+
+  xport_ctx = if_ptr->glink_core_priv;
+
+  /* Move to closed state. Implies we clean up the channel from the
+   * open list */
+
+  /* Find channel in the open_list */
+  open_ch_ctx = smem_list_first(&if_ptr->glink_core_priv->open_list);
+  while(open_ch_ctx != NULL)
+  {
+    if(open_ch_ctx->lcid == lcid) {
+#ifndef FEATURE_CH_MIGRATION_FREE
+      glink_transport_if_type *present_if_ptr = NULL;
+      glink_channel_ctx_type  *present_ch_ctx = NULL;
+      boolean channel_exist;
+      /* find the channel in all xport list */
+      channel_exist = glinki_local_channel_exists(if_ptr,
+                                                  &present_if_ptr,
+                                                  open_ch_ctx->name,
+                                                  &present_ch_ctx,
+                                                  FALSE);
+
+      if(if_ptr->glink_priority == migrated_ch_prio && !channel_exist)
+      {
+        /* only local side has opened the channel. Remote side has not come up yet
+         * which implies negotiation did not take place on remote side */
+        /* DO NOTHING */
+      }
+      else if(if_ptr->glink_priority == migrated_ch_prio)
+      {
+        /* remote channel exists. channel migration negotiation happened
+         * on remote side and negotitated xport is same as current xport */
+        if(present_ch_ctx->ref_count == 1)
+        {
+          /* remote channel is present on different xport than negotiated one.
+           * remote side will migrate its channel to negotiated xport */
+          /* DO NOTHING */
+        }
+        else if(present_ch_ctx->ref_count == 2)
+        {
+          /* remote channel is open on same xport as current xport.
+           * change channel state to GLINK_CH_STATE_OPEN and notify client */
+          open_ch_ctx->state = GLINK_CH_STATE_OPEN;
+          open_ch_ctx->notify_state(open_ch_ctx, open_ch_ctx->priv,
+                                    GLINK_CONNECTED);
+        }
+        else
+        {
+          /* something went wrong in updating ref_count of channel */
+          ASSERT(0);
+        }
+      }
+      else
+      {
+
+        /* migrated xport priority <> current xport priority */
+        /* check if remote channel is opened on negotiated xport already */
+          if(migrated_ch_prio == present_if_ptr->glink_priority &&
+             (open_ch_ctx->ch_open_options & GLINK_OPT_INITIAL_XPORT))
+          {
+            /* remote channel is already on negotiated xport. remote channel
+             * will not migrate. Local side should migrate */
+
+            glink_channel_ctx_type *new_ch_ctx =
+              (glink_channel_ctx_type *)glink_os_calloc(
+                                       sizeof(glink_channel_ctx_type));
+
+            /* Fill in the channel info structure */
+            glink_os_string_copy(new_ch_ctx->name,
+                                 open_ch_ctx->name,
+                                 sizeof(open_ch_ctx->name));
+            new_ch_ctx->priv = open_ch_ctx->priv;
+            new_ch_ctx->notify_rx = open_ch_ctx->notify_rx;
+            new_ch_ctx->notify_rxv = open_ch_ctx->notify_rxv;
+            new_ch_ctx->notify_tx_done = open_ch_ctx->notify_tx_done;
+            new_ch_ctx->notify_state = open_ch_ctx->notify_state;
+            new_ch_ctx->notify_rx_intent_req =
+                                            open_ch_ctx->notify_rx_intent_req;
+            new_ch_ctx->notify_rx_intent = open_ch_ctx->notify_rx_intent;
+            new_ch_ctx->notify_rx_sigs = open_ch_ctx->notify_rx_sigs;
+            new_ch_ctx->ch_open_options = open_ch_ctx->ch_open_options;
+
+            present_ch_ctx->notify_state = glink_dummy_ch_migration_notification_cb;
+            if_ptr->tx_cmd_ch_close( if_ptr, present_ch_ctx->lcid );
+
+            /* migrate to negotiated xport */
+            glinki_add_ch_to_xport(present_if_ptr,
+                                   present_if_ptr,
+                                   new_ch_ctx,
+                                   NULL,
+                                   TRUE,
+                                   TRUE,
+                                   present_if_ptr->glink_priority);
+          }
+          else
+          {
+            /* Either our transport is "set in stone"  OR */
+            /* remote side will migrate to negotiated xport and will call
+             * remote open on this side which will cause channel migration
+             * negotiation and this side will ultimately migrate */
+            /* DO NOTHING */
+          }
+        }
+#else
+        if(open_ch_ctx->ref_count == 2)
+        {
+          /* remote channel is open on same xport as current xport.
+           * change channel state to GLINK_CH_STATE_OPEN and notify client */
+          open_ch_ctx->state = GLINK_CH_STATE_OPEN;
+          open_ch_ctx->notify_state(open_ch_ctx, open_ch_ctx->priv,
+                                    GLINK_CONNECTED);
+        }
+#endif
+
+      GLINK_LOG_EVENT(GLINK_EVENT_CH_OPEN_ACK, open_ch_ctx->name,
+          xport_ctx->xport, xport_ctx->remote_ss, lcid);
+      return;
+    }
+    open_ch_ctx = smem_list_next(open_ch_ctx);
+  }
+  /* We are here in case we could not find the channel in the open list. */
+  ASSERT(0);
+}
+
+/*===========================================================================
+FUNCTION      glink_rx_cmd_ch_close_ack
+
+DESCRIPTION   This function is invoked by the transport in response to
+              glink_transport_if_type:: tx_cmd_ch_close
+
+ARGUMENTS   *if_ptr   Pointer to interface instance; must be unique
+                      for each edge
+
+            lcid      Local Channel ID
+
+RETURN VALUE  None.
+
+SIDE EFFECTS  None
+===========================================================================*/
+void glink_rx_cmd_ch_close_ack
+(
+  glink_transport_if_type *if_ptr, /* Pointer to the interface instance */
+  uint32                  lcid     /* Local channel ID */
+)
+{
+  glink_channel_ctx_type *open_ch_ctx;
+  glink_core_xport_ctx_type  *xport_ctx;
+
+  ASSERT(if_ptr != NULL);
+
+  xport_ctx = if_ptr->glink_core_priv;
+
+  /* Move to closed state. Implies we clean up the channel from the
+   * open list */
+
+  /* Find channel in the open_list */
+  glink_os_cs_acquire(&xport_ctx->channel_q_cs);
+  open_ch_ctx = smem_list_first(&if_ptr->glink_core_priv->open_list);
+  while(open_ch_ctx != NULL)
+  {
+    if(open_ch_ctx->lcid == lcid) {
+      /* Found channel */
+      open_ch_ctx->ref_count--;
+      GLINK_LOG_EVENT(GLINK_EVENT_CH_CLOSE_ACK, open_ch_ctx->name,
+          xport_ctx->xport, xport_ctx->remote_ss, lcid);
+
+      /* Transition state */
+      if(open_ch_ctx->state == GLINK_CH_STATE_OPEN) {
+        /* this side initiated close procedure */
+        open_ch_ctx->state = GLINK_CH_STATE_REMOTE_OPEN_LOCAL_CLOSE;
+      } else if(open_ch_ctx->state == GLINK_CH_STATE_LOCAL_OPEN ||
+                open_ch_ctx->state == GLINK_CH_STATE_LOCAL_OPEN_REMOTE_CLOSE ||
+                open_ch_ctx->state == GLINK_CH_STATE_REMOTE_OPEN) {
+        /* Other side never opened the port, or closed from its end */
+        /* Clear everything */
+        if(open_ch_ctx->ref_count == 0)
+        {
+          xport_ctx->channel_cleanup(open_ch_ctx);
+          /* re-use channel id if it can be done */
+          if(lcid == (xport_ctx->free_lcid-1)) {
+            /* If channel being closed is the last opened channel
+               re-use the lcid of this channel for any new channels */
+            xport_ctx->free_lcid--;
+          }
+          smem_list_delete(&if_ptr->glink_core_priv->open_list, open_ch_ctx);
+
+          /* Notify the client */
+          open_ch_ctx->notify_state( open_ch_ctx, open_ch_ctx->priv,
+                                     GLINK_LOCAL_DISCONNECTED);
+          glink_os_free(open_ch_ctx);
+        }
+      } else {
+        /* Unsupported state */
+        ASSERT(0);
+      }
+
+      glink_os_cs_release(&xport_ctx->channel_q_cs);
+      return;
+    }
+    open_ch_ctx = smem_list_next(open_ch_ctx);
+  }/* end while */
+
+  /* We are here in case we could not find the channel in the open list. */
+  ASSERT(0);
+
+  glink_os_cs_release(&xport_ctx->channel_q_cs);
+}
+
+/*===========================================================================
+FUNCTION      glink_rx_cmd_ch_remote_close
+
+DESCRIPTION   Remote channel close request; will result in sending
+              glink_transport_if_type:: tx_cmd_ch_remote_close_ack
+
+ARGUMENTS   *if_ptr   Pointer to interface instance; must be unique
+                      for each edge
+
+            rcid      Remote Channel ID
+
+RETURN VALUE  None.
+
+SIDE EFFECTS  None
+===========================================================================*/
+void glink_rx_cmd_ch_remote_close
+(
+  glink_transport_if_type *if_ptr, /* Pointer to the interface instance */
+  uint32                  rcid     /* Remote channel ID */
+)
+{
+  glink_channel_ctx_type *open_ch_ctx;
+  glink_core_xport_ctx_type  *xport_ctx;
+
+  ASSERT(if_ptr != NULL);
+
+  xport_ctx = if_ptr->glink_core_priv;
+
+  /* Find channel in the open_list */
+  glink_os_cs_acquire(&xport_ctx->channel_q_cs);
+  open_ch_ctx = smem_list_first(&if_ptr->glink_core_priv->open_list);
+  while(open_ch_ctx != NULL)
+  {
+    if(open_ch_ctx->rcid == rcid) {
+        GLINK_LOG_EVENT(GLINK_EVENT_CH_REMOTE_CLOSE, open_ch_ctx->name,
+            xport_ctx->xport, xport_ctx->remote_ss, rcid);
+      /* Found channel, transition it to appropriate state based
+       * on current state */
+      open_ch_ctx->ref_count--;
+
+      if(open_ch_ctx->state == GLINK_CH_STATE_OPEN) {
+         open_ch_ctx->state = GLINK_CH_STATE_LOCAL_OPEN_REMOTE_CLOSE;
+
+        /* Inform the client */
+        open_ch_ctx->notify_state( open_ch_ctx, open_ch_ctx->priv,
+                                   GLINK_REMOTE_DISCONNECTED);
+
+        /* Send the remote close ACK back to the other side */
+        if_ptr->tx_cmd_ch_remote_close_ack(if_ptr, open_ch_ctx->rcid);
+
+        /* Free channel resources */
+        xport_ctx->channel_cleanup(open_ch_ctx);
+
+        GLINK_LOG_EVENT(GLINK_EVENT_CH_REMOTE_CLOSE, open_ch_ctx->name,
+            xport_ctx->xport, xport_ctx->remote_ss, rcid);
+        glink_os_cs_release(&xport_ctx->channel_q_cs);
+
+        return;
+      } else if (open_ch_ctx->state == GLINK_CH_STATE_REMOTE_OPEN ||
+                 open_ch_ctx->state == GLINK_CH_STATE_REMOTE_OPEN_LOCAL_CLOSE) {
+        /* Local side never opened the channel OR it opened it but closed it */
+        /* Free channel resources */
+        xport_ctx->channel_cleanup(open_ch_ctx);
+
+        /* Send the remote close ACK back to the other side */
+        if_ptr->tx_cmd_ch_remote_close_ack(if_ptr, open_ch_ctx->rcid);
+
+        if(open_ch_ctx->ref_count == 0)
+        {
+          /* re-use channel id if it can be done */
+          if (open_ch_ctx->lcid == (xport_ctx->free_lcid - 1)) {
+            /* If channel being closed is the last opened channel
+            re-use the lcid of this channel for any new channels */
+            xport_ctx->free_lcid--;
+          }
+          smem_list_delete(&if_ptr->glink_core_priv->open_list, open_ch_ctx);
+          glink_os_free(open_ch_ctx);
+        }
+
+        glink_os_cs_release(&xport_ctx->channel_q_cs);
+
+        return;
+      } else {
+        /* SHould not get this callback for a channel in any other state */
+
+        //OS_LOG_ERROR(3, "GLINK_RX_CMD_CH_REMOTE_CLOSE: received close cmd for invalid state"
+        //                "[channel ctx: 0x%x][current channel state: %d]",
+        //                open_ch_ctx, open_ch_ctx->state );
+        glink_os_cs_release(&xport_ctx->channel_q_cs);
+        if_ptr->tx_cmd_ch_remote_close_ack(if_ptr, open_ch_ctx->rcid);
+        return;
+      }
+    }
+    open_ch_ctx = smem_list_next(open_ch_ctx);
+  }/* end while */
+
+  /* We are here in case we could not find the channel in the open list
+   * or OPEN state. */
+  ASSERT(0);
+
+  glink_os_cs_release(&xport_ctx->channel_q_cs);
+}
+
+/*===========================================================================
+FUNCTION      glink_ch_state_local_trans
+
+DESCRIPTION   Process local state transition
+
+ARGUMENTS   *if_ptr   Pointer to interface instance; must be unique
+                      for each edge
+
+            rcid      Remote Channel ID
+
+RETURN VALUE  None.
+
+SIDE EFFECTS  None
+===========================================================================*/
+void glink_ch_state_local_trans
+(
+  glink_transport_if_type  *if_ptr,  /* Pointer to the interface instance */
+  uint32                   lcid,     /* Local channel ID */
+  glink_ch_state_type      new_state /* New local channel state */
+)
+{
+  glink_channel_ctx_type *open_ch_ctx;
+  glink_core_xport_ctx_type  *xport_ctx;
+
+  ASSERT(if_ptr != NULL);
+
+  xport_ctx = if_ptr->glink_core_priv;
+
+  /* Find channel in the open_list */
+  open_ch_ctx = smem_list_first(&if_ptr->glink_core_priv->open_list);
+  while(open_ch_ctx != NULL)
+  {
+    if(open_ch_ctx->lcid == lcid) {
+      /* Found channel, transition it to appropriate state */
+      open_ch_ctx->state = new_state;
+    }
+    open_ch_ctx = smem_list_next(open_ch_ctx);
+    GLINK_LOG_EVENT(GLINK_EVENT_CH_STATE_TRANS, open_ch_ctx->name,
+          xport_ctx->xport, xport_ctx->remote_ss, new_state);
+    return;
+  }/* end while */
+
+  /* We are here in case we could not find the channel in the open list
+   * or OPEN state. */
+  ASSERT(0);
+}
+
+/*===========================================================================
+FUNCTION      glink_rx_put_pkt_ctx
+
+DESCRIPTION   Transport invokes this call to receive a packet fragment (must
+              have previously received an rx_cmd_rx_data packet)
+
+ARGUMENTS   *if_ptr      Pointer to interface instance; must be unique
+                         for each edge
+
+            rcid         Remote Channel ID
+
+            *intent_ptr  Pointer to the intent fragment
+
+            complete     True if pkt is complete
+
+RETURN VALUE  None
+
+SIDE EFFECTS  None
+===========================================================================*/
+void glink_rx_put_pkt_ctx
+(
+  glink_transport_if_type *if_ptr, /* Pointer to the interface instance */
+  uint32                  rcid,    /* Remote channel ID */
+  glink_rx_intent_type    *intent_ptr, /* Fragment ptr */
+  boolean                 complete     /* True if pkt is complete */
+)
+{
+  glink_channel_ctx_type *open_ch_ctx;
+  glink_core_xport_ctx_type  *xport_ctx;
+
+  ASSERT(if_ptr != NULL && intent_ptr != NULL);
+
+  xport_ctx = if_ptr->glink_core_priv;
+
+  /* Find channel in the open_list */
+  open_ch_ctx = smem_list_first(&if_ptr->glink_core_priv->open_list);
+  while(open_ch_ctx != NULL)
+  {
+    if(open_ch_ctx->rcid == rcid) {
+      /* Found channel */
+      GLINK_LOG_EVENT(GLINK_EVENT_CH_PUT_PKT_CTX, open_ch_ctx->name,
+          xport_ctx->xport, xport_ctx->remote_ss, intent_ptr->iid);
+
+      xport_ctx->channel_receive_pkt(open_ch_ctx, intent_ptr);
+
+      return;
+    }
+    open_ch_ctx = smem_list_next(open_ch_ctx);
+  }/* end while */
+
+  /* We end up here if we don't find the channel */
+  ASSERT(0);
+}
+
+/*===========================================================================
+FUNCTION      glink_rx_cmd_remote_sigs
+
+DESCRIPTION   Transport invokes this call to inform GLink of remote side
+              changing its control signals
+
+ARGUMENTS   *if_ptr      Pointer to interface instance; must be unique
+                         for each edge
+
+            rcid         Remote Channel ID
+
+            remote_sigs  Remote signal state.
+
+RETURN VALUE  None.
+
+SIDE EFFECTS  None
+===========================================================================*/
+void glink_rx_cmd_remote_sigs
+(
+  glink_transport_if_type *if_ptr,    /* Pointer to the interface instance */
+  uint32                  rcid,       /* Remote channel ID */
+  uint32                  remote_sigs /* Remote control signals */
+)
+{
+  glink_channel_ctx_type *open_ch_ctx;
+  uint32 prev_sigs;
+
+  ASSERT(if_ptr != NULL);
+
+  /* Find channel in the open_list */
+  open_ch_ctx = smem_list_first(&if_ptr->glink_core_priv->open_list);
+  while(open_ch_ctx != NULL)
+  {
+    if(open_ch_ctx->rcid == rcid) {
+      /* Found channel, let client know of new remote signal state */
+      prev_sigs = open_ch_ctx->remote_sigs;
+      open_ch_ctx->remote_sigs = remote_sigs;
+      open_ch_ctx->notify_rx_sigs(open_ch_ctx, open_ch_ctx->priv,
+                                  prev_sigs, remote_sigs);
+      return;
+    }
+    open_ch_ctx = smem_list_next(open_ch_ctx);
+  }
+
+  /* We end up here if we don't find the channel */
+  ASSERT(0);
+}
+
+
+/*===========================================================================
+FUNCTION      glink_tx_resume
+
+DESCRIPTION   If transport was full and could not continue a transmit
+              operation, then it will call this function to notify the core
+              that it is ready to resume transmission.
+
+ARGUMENTS   *if_ptr    Pointer to interface instance; must be unique
+                       for each edge
+
+RETURN VALUE  None.
+
+SIDE EFFECTS  None
+===========================================================================*/
+void glink_tx_resume
+(
+  glink_transport_if_type *if_ptr /* Pointer to the interface instance */
+)
+{
+  /* Not sure what to do here */
+}
+
+
+/*===========================================================================
+FUNCTION      glink_set_core_version
+
+DESCRIPTION   Sets the core version used by the transport; called after
+              completing negotiation.
+
+ARGUMENTS   *if_ptr    Pointer to interface instance; must be unique
+                       for each edge
+
+             version   Negotiated transport version
+
+RETURN VALUE  None.
+
+SIDE EFFECTS  None
+===========================================================================*/
+void glink_set_core_version
+(
+  glink_transport_if_type *if_ptr, /* Pointer to the interface instance */
+  uint32                  version  /* Version */
+)
+{
+}
diff --git a/platform/msm_shared/glink/glink_core_intentless_xport.c b/platform/msm_shared/glink/glink_core_intentless_xport.c
new file mode 100644
index 0000000..289ef18
--- /dev/null
+++ b/platform/msm_shared/glink/glink_core_intentless_xport.c
@@ -0,0 +1,131 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+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 The Linux Foundation 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+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 FILES
+===========================================================================*/
+
+#include "glink.h"
+#include "glink_internal.h"
+
+/*===========================================================================
+LOCAL FUNCTION DEFINITIONS
+===========================================================================*/
+
+/*===========================================================================
+  FUNCTION      glink_core_stub_intentless
+===========================================================================*/
+/**
+
+  Stub for intentless transport functionality.
+
+  @return     GLINK_STATUS_SUCCESS.
+
+  @sideeffects  None.
+*/
+/*=========================================================================*/
+
+static glink_err_type glink_core_stub_intentless(void)
+{
+  return GLINK_STATUS_SUCCESS;
+}
+
+/*===========================================================================
+  FUNCTION      glink_verify_open_cfg_intentless
+===========================================================================*/
+/**
+
+  Verifies open config for an intentless transport
+
+  @param[in]  open_ch_ctx   Channel context.
+
+  @return     TRUE if config is good.
+
+  @sideeffects  None.
+*/
+/*=========================================================================*/
+static boolean glink_verify_open_cfg_intentless
+(
+glink_channel_ctx_type   *ch_ctx
+)
+{
+  return (ch_ctx->notify_rxv != NULL);
+}
+
+/*===========================================================================
+  FUNCTION      glink_channel_receive_pkt
+===========================================================================*/
+/**
+
+  Precesses Rx packet for the channel
+
+  @param[in]  open_ch_ctx   Channel context.
+  @param[in]  intent_ptr    Packet descriptor
+
+  @return     None.
+
+  @sideeffects  None.
+*/
+/*=========================================================================*/
+static void glink_channel_receive_pkt_intentless
+(
+  glink_channel_ctx_type *open_ch_ctx,
+  glink_rx_intent_type *intent_ptr
+)
+{
+  open_ch_ctx->notify_rxv(open_ch_ctx, open_ch_ctx->priv,
+    NULL, intent_ptr->iovec, intent_ptr->pkt_sz, 0,
+    intent_ptr->vprovider, intent_ptr->pprovider);
+}
+
+/*===========================================================================
+EXTERNAL FUNCTION DEFINITIONS
+===========================================================================*/
+
+/*===========================================================================
+  FUNCTION      glink_core_setup_intentless_xport
+===========================================================================*/
+/**
+
+  Initializes internal core functions for the intentless transport.
+
+  @param[in]  if_ptr   The Pointer to the interface instance.
+
+  @return     None.
+
+  @sideeffects  None.
+*/
+/*=========================================================================*/
+void glink_core_setup_intentless_xport(glink_transport_if_type *if_ptr)
+{
+  if_ptr->glink_core_priv->verify_open_cfg = glink_verify_open_cfg_intentless;
+  if_ptr->glink_core_priv->channel_init = (channel_init_fn)glink_core_stub_intentless;
+  if_ptr->glink_core_priv->channel_cleanup = (channel_cleanup_fn)glink_core_stub_intentless;
+  if_ptr->glink_core_priv->use_rm_intent = (use_rm_intent_fn)glink_core_stub_intentless;
+  if_ptr->glink_core_priv->channel_receive_pkt = glink_channel_receive_pkt_intentless;
+}
diff --git a/platform/msm_shared/glink/glink_os_utils_dal.c b/platform/msm_shared/glink/glink_os_utils_dal.c
new file mode 100644
index 0000000..7ad6fb7
--- /dev/null
+++ b/platform/msm_shared/glink/glink_os_utils_dal.c
@@ -0,0 +1,358 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+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 The Linux Foundation 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+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 FILES
+===========================================================================*/
+
+#include "glink_os_utils.h"
+#include <arch/defines.h>
+#include <malloc.h>
+#include <kernel/thread.h>
+#include <string.h>
+#include <kernel/event.h>
+#include <platform/irqs.h>
+#include <platform/interrupts.h>
+
+/*===========================================================================
+                           MACRO DEFINITIONS
+===========================================================================*/
+
+#define OS_LOG_BUFFER_SIZE  ( 16384 )
+
+/*===========================================================================
+                           TYPE DEFINITIONS
+===========================================================================*/
+typedef void (*glink_os_thread_fn_type)(void* param);
+
+typedef struct _glink_os_thread_info_type {
+  glink_os_thread_fn_type thread_fn;
+  void                    *param;
+}glink_os_thread_info_type;
+
+/*===========================================================================
+                    EXTERNAL FUNCTION DEFINITIONS
+===========================================================================*/
+
+/*===========================================================================
+  FUNCTION      glink_os_cs_init
+===========================================================================*/
+/**
+  Initializes a Critical Section
+
+  @param[in]  cs   pointer to critical section object allocated by caller.
+
+  @return
+  TRUE if critical section was initialized, FALSE otherwise
+*/
+/*=========================================================================*/
+boolean glink_os_cs_init( os_cs_type *cs )
+{
+  boolean return_value = TRUE;
+
+  /* Create the new critical section */
+
+  return ( return_value );
+}
+
+/*===========================================================================
+  FUNCTION  glink_os_cs_deinit
+===========================================================================*/
+/**
+  This function de-initializes a critical section.
+
+  @param[in]  cs         Pointer to the critical section to be de-initialized.
+
+  @return
+  TRUE if critical section was initialized, FALSE otherwise
+
+*/
+/*=========================================================================*/
+boolean glink_os_cs_deinit( os_cs_type *cs )
+{
+  /* Deinitialize the critical section */
+
+  return TRUE;
+}
+
+/*===========================================================================
+FUNCTION      glink_os_cs_acquire
+===========================================================================*/
+/**
+  Lock a critical section
+
+  @param[in]  cs   Pointer the the critical section
+
+  @return     None.
+*/
+/*=========================================================================*/
+void glink_os_cs_acquire( os_cs_type *cs )
+{
+  enter_critical_section();
+}
+
+/*===========================================================================
+FUNCTION      glink_os_cs_release
+===========================================================================*/
+/**
+  Unlock a critical section
+
+  @param[in]  cs   Pointer the the critical section
+
+  @return     None.
+*/
+/*=========================================================================*/
+void glink_os_cs_release( os_cs_type *cs )
+{
+  exit_critical_section();
+}
+
+/*===========================================================================
+FUNCTION      glink_os_cs_destroy
+===========================================================================*/
+/**
+  Destroys a Critical Section
+
+  @return     none.
+*/
+/*=========================================================================*/
+void glink_os_cs_destroy( os_cs_type *cs )
+{
+  /* Initialize the critical section */
+  return;
+}
+
+/*===========================================================================
+  FUNCTION  glink_os_malloc
+===========================================================================*/
+/**
+  Dynamically allocate a region of memory from the heap.  The region should be
+  freed using \c glink_os_free when no longer used.
+
+  @param[in]  size   The number of bytes to be allocated.
+
+  @return    The pointer to the region of memory that was allocated.
+             NULL if the allocation failed.
+*/
+/*=========================================================================*/
+
+void *glink_os_malloc( size_t size )
+{
+  void *pMem;
+
+  pMem = malloc(size);
+  if (pMem == NULL)
+      return NULL;
+  return pMem;
+}
+
+/*===========================================================================
+  FUNCTION  glink_os_calloc
+===========================================================================*/
+/**
+  Dynamically allocate a region of memory from the heap and initialize with
+  the zeroes.  The region should be freed using \c glink_os_free
+  when no longer used.
+
+  @param[in]  size   The number of bytes to be allocated.
+
+  @return    The pointer to the region of memory that was allocated.
+             NULL if the allocation failed.
+*/
+/*=========================================================================*/
+void *glink_os_calloc( size_t size )
+{
+  void *pMem;
+  pMem = malloc(size);
+  if( pMem == NULL )
+  {
+    return NULL;
+  }
+  else
+  {
+    memset( pMem, 0, size );
+    return pMem;
+  }
+}
+
+/*===========================================================================
+  FUNCTION  glink_os_free
+===========================================================================*/
+/**
+  Free a region of memory that was allocated by \c glink_os_malloc.
+
+  @param[in] pMem    The reference to the region of memory to be freed.
+
+  @return    NA
+*/
+/*=========================================================================*/
+void glink_os_free( void *pMem )
+{
+  free( pMem );
+}
+
+/*===========================================================================
+  FUNCTION  glink_os_string_copy
+===========================================================================*/
+/**
+  Copies the source string into the destination buffer until
+  size is reached, or until a '\0' is encountered.  If valid,
+  the destination string will always be NULL deliminated.
+
+  @param[in] dst    The destination string, contents will be updated.
+  @param[in] src    The source string
+  @param[in] size   The maximum copy size (size of dst)
+
+  @return
+  The destination string pointer, dst.
+*/
+/*==========================================================================*/
+char *glink_os_string_copy( char *dst, const char *src, uint32 size )
+{
+  ( void )strlcpy( dst, src, size );
+
+  return dst;
+}
+
+/*===========================================================================
+  FUNCTION  glink_os_string_compare
+===========================================================================*/
+/**
+  Compares two strings delimited by size or NULL character.
+
+  @param[in] s1     String 1
+  @param[in] s2     String 2
+  @param[in] size   The maximum number of characters to compare
+
+  @return
+  0 if strings are identical (up to size characters), non-zero otherwise
+*/
+/*==========================================================================*/
+long glink_os_string_compare( const char *s1, const char *s2, uint32 size )
+{
+  return strncmp( s1, s2, size );
+}
+
+/*===========================================================================
+  FUNCTION  glink_os_copy_mem
+===========================================================================*/
+/**
+  Copies the source buffer into the destination buffer.
+
+  @param[in] dst    The destination, contents will be updated.
+  @param[in] src    The source
+  @param[in] size   The maximum copy size (size of dst)
+
+  @return
+  The destination string pointer, dst.
+*/
+/*==========================================================================*/
+void glink_os_copy_mem( void *dst, const void *src, uint32 size )
+{
+  memcpy( dst, src, size );
+}
+
+/*===========================================================================
+  FUNCTION      glink_os_register_isr
+===========================================================================*/
+/**
+  Registers ISR with the interrupt controller
+
+  @param[in]  irq_in    Interrupt to register for
+  @param[in]  isr       Callback to be invoked when interrupt fires
+  @param[in]  cb_data   Data to be provided to the callback
+
+  @return     TRUE if registration was successful, FALSE otherwise.
+*/
+/*=========================================================================*/
+boolean glink_os_register_isr( uint32 irq_in, os_isr_cb_fn isr, void* cb_data )
+{
+  boolean return_value = TRUE;
+
+  /* Register the interrupt */
+  dprintf(SPEW, "Register interrupt: %u\n", irq_in);
+  register_int_handler(irq_in, (int_handler)(isr), cb_data);
+
+  return ( return_value );
+}
+
+/*===========================================================================
+  FUNCTION      glink_os_deregister_isr
+===========================================================================*/
+/**
+  De-registers ISR with the interrupt controller
+
+  @param[in]  irq_in    Interrupt to deregister for
+
+  @return     TRUE if de-registration was successful, FALSE otherwise.
+*/
+/*=========================================================================*/
+boolean glink_os_deregister_isr( uint32 irq_in )
+{
+  boolean return_value = TRUE;
+  mask_interrupt(irq_in);
+  return ( return_value );
+}
+
+/*===========================================================================
+  FUNCTION      glink_os_enable_interrupt
+===========================================================================*/
+/**
+  Enables the interrupt in the interrupt controller
+
+  @param[in]  irq_in    Interrupt to enable
+
+  @return     TRUE if operation was successful, FALSE otherwise.
+*/
+/*=========================================================================*/
+boolean glink_os_enable_interrupt( uint32 irq_in )
+{
+  boolean return_value = TRUE;
+  unmask_interrupt(irq_in);
+  return ( return_value );
+}
+
+/*===========================================================================
+  FUNCTION      glink_os_disable_interrupt
+===========================================================================*/
+/**
+  Disables the interrupt in the interrupt controller
+
+  @param[in]  irq_in    Interrupt to disable
+
+  @return     TRUE if operation was successful, FALSE otherwise.
+*/
+/*=========================================================================*/
+boolean glink_os_disable_interrupt( uint32 irq_in )
+{
+  boolean return_value = TRUE;
+  dprintf(INFO, "Disable IPC Interrupt\n");
+  mask_interrupt(irq_in);
+  return ( return_value );
+}
diff --git a/platform/msm_shared/glink/glink_rpmcore_setup.c b/platform/msm_shared/glink/glink_rpmcore_setup.c
new file mode 100644
index 0000000..a206afa
--- /dev/null
+++ b/platform/msm_shared/glink/glink_rpmcore_setup.c
@@ -0,0 +1,65 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+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 The Linux Foundation 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+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 FILES
+===========================================================================*/
+
+#include "glink.h"
+#include "glink_internal.h"
+
+
+/*===========================================================================
+EXTERNAL FUNCTION DEFINITIONS
+===========================================================================*/
+
+/*===========================================================================
+FUNCTION      glink_core_setup
+===========================================================================*/
+/**
+
+  Initializes internal core functions based on the transport capabilities.
+
+  @param[in]  if_ptr   The Pointer to the interface instance.
+
+  @return     None.
+
+  @sideeffects  None.
+*/
+/*=========================================================================*/
+void glink_core_setup(glink_transport_if_type *if_ptr)
+{
+  if (if_ptr->glink_core_priv->xport_capabilities & GLINK_CAPABILITY_INTENTLESS)
+  {
+    glink_core_setup_intentless_xport(if_ptr);
+  }
+  else
+  {
+    ASSERT(0);
+  }
+}
diff --git a/platform/msm_shared/glink/glink_vector.c b/platform/msm_shared/glink/glink_vector.c
new file mode 100644
index 0000000..31f0883
--- /dev/null
+++ b/platform/msm_shared/glink/glink_vector.c
@@ -0,0 +1,196 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+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 The Linux Foundation 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+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 FILES
+===========================================================================*/
+#include "glink.h"
+#include "glink_core_if.h"
+#include "glink_transport_if.h"
+#include "glink_vector.h"
+#include "glink_os_utils.h"
+
+/*===========================================================================
+                       LOCAL DATA DECLARATIONS
+===========================================================================*/
+
+
+/*===========================================================================
+                       PRIVATE FUNCTIONS
+===========================================================================*/
+
+/*===========================================================================
+FUNCTION      glink_dummy_tx_vprovider
+===========================================================================*/
+/**
+
+  Buffer provider for virtual space that operates on a non-vectored buffer.
+
+  @param[in]  iovec   Pointer to the dummy vector.
+  @param[in]  offset  Offset within the dummy vector.
+  @param[out] size    Size of the provied buffer.
+
+  @return     virtual address of the buffer.
+
+  @sideeffects  None.
+*/
+/*=========================================================================*/
+void* glink_dummy_tx_vprovider
+(
+  void*  iovec,
+  size_t offset,
+  size_t *size
+)
+{
+  glink_core_tx_pkt_type* pkt = (glink_core_tx_pkt_type*)iovec;
+
+  if (pkt == NULL || size == NULL || pkt->size <= offset)
+  {
+    return NULL;
+  }
+
+  *size = pkt->size - offset;
+
+  return (char*)(pkt->data) + offset;
+}
+
+/*===========================================================================
+FUNCTION      glink_iovec_vprovider
+===========================================================================*/
+/**
+
+  Buffer provider for virtual space that operates on a Glink iovec.
+
+  @param[in]  iovec   Pointer to the dummy vector.
+  @param[in]  offset  Offset within the dummy vector.
+  @param[out] size    Size of the provied buffer.
+
+  @return     virtual address of the buffer.
+
+  @sideeffects  None.
+*/
+/*=========================================================================*/
+void* glink_iovec_vprovider
+(
+  void*  iovec,
+  size_t offset,
+  size_t *size
+)
+{
+  glink_iovector_type* iovec_l = (glink_iovector_type*)iovec;
+
+  if (iovec_l == NULL || size == NULL)
+  {
+    return NULL;
+  }
+
+  if (!iovec_l->vlist)
+  {
+    // create vlist and map virtual from physical addresses
+    ASSERT(0);
+  }
+
+  if (!iovec_l->vlast || iovec_l->vlast->start_offset > offset)
+  {
+       iovec_l->vlast = iovec_l->vlist;
+  }
+
+  while (iovec_l->vlast &&
+         iovec_l->vlast->start_offset + iovec_l->vlast->size <= offset)
+  {
+    iovec_l->vlast = iovec_l->vlast->next;
+  }
+
+  if (iovec_l->vlast == NULL)
+  {
+    return NULL;
+  }
+
+  offset -= iovec_l->vlast->start_offset;
+  *size = iovec_l->vlast->size - offset;
+
+  return (char*)(iovec_l->vlast->data) + offset;
+}
+
+/*===========================================================================
+FUNCTION      glink_iovec_pprovider
+===========================================================================*/
+/**
+
+  Buffer provider for physical space that operates on a Glink iovec.
+
+  @param[in]  iovec   Pointer to the dummy vector.
+  @param[in]  offset  Offset within the dummy vector.
+  @param[out] size    Size of the provied buffer.
+
+  @return     physical address of the buffer.
+
+  @sideeffects  None.
+*/
+/*=========================================================================*/
+void* glink_iovec_pprovider
+(
+  void*  iovec,
+  size_t offset,
+  size_t *size
+)
+{
+  glink_iovector_type* iovec_l = (glink_iovector_type*)iovec;
+
+  if (iovec_l == NULL || size == NULL)
+  {
+    return NULL;
+  }
+
+  if (!iovec_l->plist)
+  {
+    // create plist and get physical addresses from virtual
+    ASSERT(0); // not implemented
+  }
+
+  if (!iovec_l->plast || iovec_l->plast->start_offset > offset)
+  {
+       iovec_l->plast = iovec_l->plist;
+  }
+
+  while (iovec_l->plast &&
+         iovec_l->plast->start_offset + iovec_l->plast->size <= offset)
+  {
+    iovec_l->plast = iovec_l->plast->next;
+  }
+
+  if (iovec_l->plast == NULL)
+  {
+    return NULL;
+  }
+
+  offset -= iovec_l->plast->start_offset;
+  *size = iovec_l->plast->size - offset;
+
+  return (char*)(iovec_l->plast->data) + offset;
+}
diff --git a/platform/msm_shared/glink/xport_rpm.c b/platform/msm_shared/glink/xport_rpm.c
new file mode 100644
index 0000000..f1b68b9
--- /dev/null
+++ b/platform/msm_shared/glink/xport_rpm.c
@@ -0,0 +1,1150 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+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 The Linux Foundation 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+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 FILES
+===========================================================================*/
+
+#include "glink.h"
+#include "glink_core_if.h"
+#include "glink_transport_if.h"
+#include "glink_os_utils.h"
+#include "glink_internal.h"
+#include "glink_vector.h"
+#include "xport_rpm_config.h"
+#include "xport_rpm.h"
+#include <reg.h>
+#include <bits.h>
+#include <platform/iomap.h>
+
+/*===========================================================================
+                           MACRO DEFINITIONS
+===========================================================================*/
+#define XPORT_RPM_NAME "RPM"
+
+#define XPORT_RPM_LOG(msg, remote_host, param) \
+          GLINK_LOG_EVENT(GLINK_EVENT_XPORT_INTERNAL, msg, XPORT_RPM_NAME, \
+            remote_host, (uint32)param)
+
+#define MSGRAM_READ32(ctx, ind) (*(volatile uint32*)&(ctx)->rx_fifo[ind])
+#define CHECK_INDEX_WRAP_AROUND(ind, size) \
+          {if ((ind) >= (size)) ind = 0;}
+
+#define ROUNDUP64(d) (((d) + 7) & (~7))
+#define ROUNDUP32(d) (((d) + 3) & (~3))
+
+/*===========================================================================
+                              GLOBAL DATA DECLARATIONS
+===========================================================================*/
+
+extern const uint32 xport_rpm_config_num;
+extern const char* xport_rpm_msg_ram;
+extern const void* xport_rpm_msg_ram_toc;
+
+xport_rpm_config_type* xport_rpm_get_config(uint32 ind);
+
+/* RPM channel descriptor */
+typedef struct _xport_rpm_ind_type
+{
+  uint32 read_ind;
+  uint32 write_ind;
+} xport_rpm_ind_type;
+
+/* RPM transport context */
+typedef struct _xport_rpm_ctx_type
+{
+  /* context structure should start from trasport interface */
+  glink_transport_if_type xport_if;
+  const xport_rpm_config_type *pcfg;
+  volatile xport_rpm_ind_type* tx_desc;
+  volatile xport_rpm_ind_type* rx_desc;
+  char* tx_fifo;
+  char* rx_fifo;
+  uint32 tx_fifo_size;
+  uint32 rx_fifo_size;
+  os_cs_type *tx_link_lock;
+  os_cs_type *rx_link_lock;
+  uint32 pkt_start_ind;
+  uint32 pkt_size;
+  boolean reset;
+  boolean irq_mask;
+} xport_rpm_ctx_type;
+
+xport_rpm_ctx_type *xport_rpm_ctx = NULL;
+glink_core_version_type xport_rpm_version;
+
+/*===========================================================================
+                    LOCAL FUNCTION DEFINITIONS
+===========================================================================*/
+
+/*===========================================================================
+FUNCTION      xport_rpm_plain_pkt_provider
+===========================================================================*/
+/**
+
+  Packet provider for virtual space that operates on MSG RAM FIFO.
+
+  @param[in]  iovec   Pointer to the vector.
+  @param[in]  offset  Offset within the vector.
+  @param[out] size    Size of the provied buffer.
+
+  @return     virtual address of the buffer.
+
+  @sideeffects  None.
+*/
+/*=========================================================================*/
+static void* xport_rpm_pkt_provider
+(
+  void*  iovec,
+  size_t offset,
+  size_t *size
+)
+{
+  xport_rpm_ctx_type* ctx_ptr = (xport_rpm_ctx_type*)iovec;
+  uint32 last;
+
+  if (ctx_ptr == NULL || size == NULL || ctx_ptr->pkt_size <= offset)
+  {
+    return NULL;
+  }
+
+  last = ctx_ptr->rx_fifo_size - ctx_ptr->pkt_start_ind;
+
+  if (offset >= last)
+  {
+    *size = ctx_ptr->pkt_size - offset;
+
+    return &ctx_ptr->rx_fifo[offset - last];
+  }
+
+  *size = ctx_ptr->pkt_size <= last ?
+          ctx_ptr->pkt_size - offset :
+          last - offset;
+
+  return &ctx_ptr->rx_fifo[offset + ctx_ptr->pkt_start_ind];
+}
+
+/*===========================================================================
+FUNCTION      xport_rpm_send_event
+===========================================================================*/
+/**
+
+  Updates shared write index and sends interrupt.
+
+  @param[in]  ctx_ptr   Pointer to transport context.
+
+  @return     None.
+
+  @sideeffects  None.
+
+  @dependencies It should be invoked within tx_link_lock protection.
+*/
+/*=========================================================================*/
+static void xport_rpm_send_event
+(
+  xport_rpm_ctx_type *ctx_ptr
+)
+{
+  /* read out the write index to initiate a bus transaction from MSG RAM */
+  volatile uint32 write_ind = ctx_ptr->tx_desc->write_ind;
+
+  XPORT_RPM_LOG("Send event write ind", ctx_ptr->pcfg->remote_ss, write_ind);
+
+  // notify rpm
+  dprintf(SPEW, "%s:%d: Notify RPM with IPC interrupt\n", __func__, __LINE__);
+  /* Set BIT 0 to notify RPM via IPC interrupt*/
+  writel(BIT(0), APCS_HLOS_IPC_INTERRUPT_0);
+}
+
+/*===========================================================================
+FUNCTION      xport_rpm_write_msgram
+===========================================================================*/
+/**
+
+  Copies data from local buffer into Tx FIFO located at MSG RAM
+
+  @param[in]  ctx_ptr   Pointer to transport context.
+  @param[in]  write_ind Index to start wrting from.
+  @param[in]  buffer    Buffer to copy from.
+  @param[in]  size      Size of the data in the buffer.
+
+  @return     New write index.
+
+  @sideeffects  None.
+
+  @dependencies It should be invoked within tx_link_lock protection.
+*/
+/*=========================================================================*/
+static uint32 xport_rpm_write_msgram
+(
+  xport_rpm_ctx_type *ctx_ptr,
+  uint32 write_ind,
+  uint32 *buffer,
+  uint32 size
+)
+{
+  uint32 remaining = ctx_ptr->tx_fifo_size - write_ind;
+  uint32 *buffer_end;
+  volatile uint32* write_ptr = (volatile uint32*)&ctx_ptr->tx_fifo[write_ind];
+
+  if (remaining <= size)
+  {
+    buffer_end = (uint32*)((char*)buffer + remaining);
+
+    /* write in 32bit increments due to MSG RAM access requirement */
+    while (buffer < buffer_end)
+    {
+      *write_ptr++ = *buffer++;
+    }
+
+    size -= remaining;
+    write_ptr = (volatile uint32*)&ctx_ptr->tx_fifo[0];
+  }
+
+  buffer_end = (uint32*)((char*)buffer + size);
+
+  /* write in 32bit increments due to MSG RAM access requirement */
+  while (buffer < buffer_end)
+  {
+    *write_ptr++ = *buffer++;
+  }
+
+  return (char*)write_ptr - &ctx_ptr->tx_fifo[0];
+}
+
+/*===========================================================================
+FUNCTION      xport_rpm_send_cmd
+===========================================================================*/
+/**
+
+  Helper to send a single command.
+
+  @param[in]  ctx_ptr           Pointer to transport context.
+  @param[in]  cmd               buffer containing the command
+  @param[in]  cmd_size          Size of command buffer.
+  @param[in]  data              buffer containing the data
+  @param[in]  data_size         Size of data buffer.
+
+  @return     None.
+
+  @dependencies None.
+*/
+/*=========================================================================*/
+static glink_err_type xport_rpm_send_cmd
+(
+  xport_rpm_ctx_type  *ctx_ptr,
+  uint32              *cmd,
+  uint32               cmd_size,
+  uint32              *data,
+  uint32               data_size
+)
+{
+  uint32 total_size = cmd_size + data_size;
+  uint32 reserve_size = ROUNDUP64(total_size);
+  uint32 write_ind, read_ind, avail_size;
+
+  glink_os_cs_acquire(ctx_ptr->tx_link_lock);
+
+  write_ind = ctx_ptr->tx_desc->write_ind;
+  read_ind = ctx_ptr->tx_desc->read_ind;
+  avail_size = write_ind < read_ind ? read_ind - write_ind :
+               ctx_ptr->tx_fifo_size - write_ind + read_ind;
+
+  if (reserve_size + sizeof(uint64_t) > avail_size)
+  {
+    glink_os_cs_release(ctx_ptr->tx_link_lock);
+    return GLINK_STATUS_OUT_OF_RESOURCES;
+  }
+
+  XPORT_RPM_LOG("send cmd", ctx_ptr->pcfg->remote_ss, cmd[0]);
+
+  write_ind
+    = xport_rpm_write_msgram( ctx_ptr, write_ind,
+                              cmd, ROUNDUP32( cmd_size ) );
+
+  if (data != NULL)
+  {
+    write_ind
+      = xport_rpm_write_msgram( ctx_ptr, write_ind,
+                                data, ROUNDUP32( data_size ) );
+  }
+
+  /* add alignment bytes to Tx FIFO */
+  write_ind += (reserve_size - total_size) & (~3);
+
+  if (write_ind >= ctx_ptr->tx_fifo_size)
+  {
+    write_ind -= ctx_ptr->tx_fifo_size;
+  }
+
+  ctx_ptr->tx_desc->write_ind = write_ind;
+
+  xport_rpm_send_event(ctx_ptr);
+
+  glink_os_cs_release(ctx_ptr->tx_link_lock);
+
+  return GLINK_STATUS_SUCCESS;
+}
+
+/*===========================================================================
+                    EXTERNAL FUNCTION DEFINITIONS
+===========================================================================*/
+
+/*===========================================================================
+FUNCTION      xport_rpm_tx_cmd_version
+===========================================================================*/
+/**
+
+  Transmit a version command for local negotiation -
+  expected response is to be delivered via glink_rx_cmd_version_ack().
+
+  @param[in]  if_ptr    Pointer to transport interface instance.
+  @param[in]  version   Version to be sent.
+  @param[in]  feature   Features to be sent.
+
+  @return     None.
+
+  @sideeffects  None.
+*/
+/*=========================================================================*/
+void xport_rpm_tx_cmd_version
+(
+  glink_transport_if_type *if_ptr,
+  uint32 version,
+  uint32 features
+)
+{
+  xport_rpm_ctx_type *ctx_ptr = (xport_rpm_ctx_type *)if_ptr;
+  uint32 cmd[2];
+
+  cmd[0] = XPORT_RPM_SET_CMD_ID(XPORT_RPM_CMD_VERSION_REQ);
+  cmd[0] |= XPORT_RPM_SET_VERSION(version);
+  cmd[1] = features;
+
+  if(xport_rpm_send_cmd(ctx_ptr, &cmd[0], sizeof(cmd), NULL, 0) != GLINK_STATUS_SUCCESS)
+  {
+    dprintf(CRITICAL, "%s:%d: Send Version Failed\n", __func__, __LINE__);
+    ASSERT(0);
+  }
+}
+
+/*===========================================================================
+FUNCTION      xport_rpm_tx_cmd_version_ack
+===========================================================================*/
+/**
+
+  Transmit a version ack for remote negotiation.
+
+  @param[in]  if_ptr    Pointer to transport interface instance.
+  @param[in]  version   Version to be sent.
+  @param[in]  feature   Features to be sent.
+
+  @return     None.
+
+  @sideeffects  None.
+*/
+/*=========================================================================*/
+void xport_rpm_tx_cmd_version_ack
+(
+  glink_transport_if_type *if_ptr,
+  uint32 version,
+  uint32 features
+)
+{
+  xport_rpm_ctx_type *ctx_ptr = (xport_rpm_ctx_type *)if_ptr;
+  uint32 cmd[2];
+
+  cmd[0] = XPORT_RPM_SET_CMD_ID(XPORT_RPM_CMD_VERSION_ACK);
+  cmd[0] |= XPORT_RPM_SET_VERSION(version);
+  cmd[1] = features;
+
+  if (xport_rpm_send_cmd(ctx_ptr, &cmd[0], sizeof(cmd), NULL, 0) != GLINK_STATUS_SUCCESS)
+  {
+    dprintf(CRITICAL, "%s:%d: Send Version ACK Failed", __func__, __LINE__);
+    ASSERT(0);
+  }
+}
+
+/*===========================================================================
+FUNCTION      xport_rpm_set_version
+===========================================================================*/
+/**
+
+  Signals that negotiation is complete and the transport can now
+  do version-specific initialization.
+
+  @param[in]  if_ptr    Pointer to transport interface instance.
+  @param[in]  version   Version to be used.
+  @param[in]  feature   Features to be used.
+
+  @return     Capabilities.
+
+  @sideeffects  None.
+*/
+/*=========================================================================*/
+uint32 xport_rpm_set_version
+(
+  glink_transport_if_type *if_ptr,
+  uint32 version,
+  uint32 features
+)
+{
+  return GLINK_CAPABILITY_SIG_SUPPORT | GLINK_CAPABILITY_INTENTLESS;
+}
+
+/*===========================================================================
+FUNCTION      xport_rpm_tx_cmd_ch_open
+===========================================================================*/
+/**
+
+  Sends the open command - expected response is to be delivered
+  via glink_rx_cmd_ch_open_ack().
+
+  @param[in]  if_ptr   Pointer to transport interface instance.
+  @param[in]  lcid     Local channel ID.
+  @param[in]  name     Channel name.
+  @param[in]  prio     Requested xport priority by channel.
+
+  @return     Returns error code.
+
+  @sideeffects  None.
+*/
+/*=========================================================================*/
+glink_err_type xport_rpm_tx_cmd_ch_open
+(
+  glink_transport_if_type *if_ptr,
+  uint32 lcid,
+  const char *name,
+  glink_xport_priority prio
+)
+{
+  xport_rpm_ctx_type *ctx_ptr = (xport_rpm_ctx_type *)if_ptr;
+  uint32 cmd[2];
+
+  cmd[0] = XPORT_RPM_SET_CMD_ID(XPORT_RPM_CMD_OPEN_CHANNEL);
+  cmd[0] |= XPORT_RPM_SET_CHANNEL_ID(lcid);
+  cmd[1] =  strlen(name) + 1;
+
+  return xport_rpm_send_cmd(ctx_ptr, &cmd[0], sizeof(cmd), (void*)name, cmd[1]);
+}
+
+/*===========================================================================
+FUNCTION      xport_rpm_tx_cmd_ch_close
+===========================================================================*/
+/**
+
+  Sends the close command - expected response is to be delivered
+  via glink_rx_cmd_ch_close_ack().
+
+  @param[in]  if_ptr   Pointer to transport interface instance.
+  @param[in]  lcid     Local channel ID.
+
+  @return     Returns error code.
+
+  @sideeffects  None.
+*/
+/*=========================================================================*/
+glink_err_type xport_rpm_tx_cmd_ch_close
+(
+  glink_transport_if_type *if_ptr,
+  uint32 lcid
+)
+{
+  xport_rpm_ctx_type *ctx_ptr = (xport_rpm_ctx_type *)if_ptr;
+  uint32 cmd;
+
+  cmd = XPORT_RPM_SET_CMD_ID(XPORT_RPM_CMD_CLOSE_CHANNEL);
+  cmd |= XPORT_RPM_SET_CHANNEL_ID(lcid);
+
+  return xport_rpm_send_cmd(ctx_ptr, &cmd, sizeof(cmd), NULL, 0);
+}
+
+/*===========================================================================
+FUNCTION      xport_rpm_tx_cmd_ch_remote_open_ack
+===========================================================================*/
+/**
+
+  Sends the remote open ACK command.
+
+  @param[in]  if_ptr   Pointer to transport interface instance.
+  @param[in]  rcid     Remote channel ID.
+  @param[in]  prio     send negotiated xport priority to remote side.
+
+  @return     None.
+
+  @sideeffects  None.
+*/
+/*=========================================================================*/
+void xport_rpm_tx_cmd_ch_remote_open_ack
+(
+  glink_transport_if_type *if_ptr,
+  uint32 rcid,
+  glink_xport_priority prio
+)
+{
+  xport_rpm_ctx_type *ctx_ptr = (xport_rpm_ctx_type *)if_ptr;
+  uint32 cmd;
+
+  cmd = XPORT_RPM_SET_CMD_ID(XPORT_RPM_CMD_OPEN_CHANNEL_ACK);
+  cmd |= XPORT_RPM_SET_CHANNEL_ID(rcid);
+
+  if (xport_rpm_send_cmd(ctx_ptr, &cmd, sizeof(cmd), NULL, 0) != GLINK_STATUS_SUCCESS)
+  {
+    //ERR_FATAL("send Open Ack failed", 0, 0, 0);
+    ASSERT(0);
+  }
+}
+
+/*===========================================================================
+FUNCTION      xport_rpm_tx_cmd_ch_remote_close_ack
+===========================================================================*/
+/**
+
+  Sends the remote close ACK command.
+
+  @param[in]  if_ptr   Pointer to transport interface instance.
+  @param[in]  rcid     Remote channel ID.
+
+  @return     None.
+
+  @sideeffects  None.
+*/
+/*=========================================================================*/
+void xport_rpm_tx_cmd_ch_remote_close_ack
+(
+  glink_transport_if_type *if_ptr,
+  uint32 rcid
+)
+{
+  xport_rpm_ctx_type *ctx_ptr = (xport_rpm_ctx_type *)if_ptr;
+  uint32 cmd;
+
+  cmd = XPORT_RPM_SET_CMD_ID(XPORT_RPM_CMD_CLOSE_CHANNEL_ACK);
+  cmd |= XPORT_RPM_SET_CHANNEL_ID(rcid);
+
+  if (xport_rpm_send_cmd(ctx_ptr, &cmd, sizeof(cmd), NULL, 0) != GLINK_STATUS_SUCCESS)
+  {
+    dprintf(CRITICAL, "%s:%d: Send Clock ACK failed\n", __func__, __LINE__);
+    ASSERT(0);
+  }
+}
+
+/*===========================================================================
+FUNCTION      xport_rpm_tx
+===========================================================================*/
+/**
+
+  Send a data packet or a fragment of it.
+
+  @param[in]  if_ptr   Pointer to transport interface instance.
+  @param[in]  lcid     Local channel ID.
+  @param[in]  pctx     Packet TX context.
+
+  @return     Returns error code.
+
+  @sideeffects  None.
+*/
+/*=========================================================================*/
+glink_err_type xport_rpm_tx
+(
+  glink_transport_if_type *if_ptr,
+  uint32 lcid,
+  glink_core_tx_pkt_type *pctx
+)
+{
+  xport_rpm_ctx_type *ctx_ptr = (xport_rpm_ctx_type *)if_ptr;
+  uint32 cmd[4];
+
+  cmd[0] = XPORT_RPM_SET_CMD_ID(XPORT_RPM_CMD_TX_DATA);
+  cmd[0] |= XPORT_RPM_SET_CHANNEL_ID(lcid);
+  cmd[1] = 0;
+  cmd[2] = pctx->size;
+  cmd[3] = 0;
+
+  pctx->size_remaining = 0;
+
+  return xport_rpm_send_cmd(ctx_ptr, &cmd[0], sizeof(cmd), (void*)pctx->data, pctx->size);
+}
+
+/*===========================================================================
+FUNCTION      xport_rpm_tx_cmd_set_sigs
+===========================================================================*/
+/**
+
+  Sends the local channel signals as per the specified 32-bit mask.
+
+  @param[in]  if_ptr    Pointer to transport interface instance.
+  @param[in]  lcid      Local channel ID.
+  @param[in]  sigs      Signal mask.
+
+  @return     Returns error code.
+
+  @sideeffects  None.
+*/
+/*=========================================================================*/
+glink_err_type xport_rpm_tx_cmd_set_sigs
+(
+  glink_transport_if_type *if_ptr,
+  uint32 lcid,
+  uint32 sigs
+)
+{
+  xport_rpm_ctx_type *ctx_ptr = (xport_rpm_ctx_type *)if_ptr;
+  uint32 cmd[2];
+
+  cmd[0] = XPORT_RPM_SET_CMD_ID(XPORT_RPM_CMD_TX_SIGNALS);
+  cmd[0] |= XPORT_RPM_SET_CHANNEL_ID(lcid);
+  cmd[1] = sigs;
+
+  return xport_rpm_send_cmd(ctx_ptr, &cmd[0], sizeof(cmd), NULL, 0);
+}
+
+/*===========================================================================
+FUNCTION      xport_rpm_negotiate_features
+===========================================================================*/
+/**
+
+  Callback to verify feature set.
+
+  @param[in]  if_ptr        Pointer to transport interface.
+  @param[in]  version_ptr   Pointer to version descriptor.
+  @param[in]  features      Proposed feature set.
+
+  @return     0.
+
+  @sideeffects  None.
+
+  @dependencies None.
+*/
+/*=========================================================================*/
+uint32 xport_rpm_negotiate_features(
+  glink_transport_if_type *if_ptr,
+  const glink_core_version_type *version_ptr,
+  uint32 features)
+{
+  return 0;
+}
+
+/*===========================================================================
+FUNCTION      xport_rpm_poll
+===========================================================================*/
+/**
+
+  Poll of RPM transport.
+
+  @param[in]  ctx_ptr   Pointer to transport context.
+
+  @return     Returns error code.
+
+  @sideeffects  None.
+
+  @dependencies None.
+*/
+/*=========================================================================*/
+glink_err_type xport_rpm_poll( xport_rpm_ctx_type *ctx_ptr )
+{
+  uint32 write_ind, read_ind;
+  boolean stop_processing = FALSE;
+
+  if (ctx_ptr->reset == TRUE)
+  {
+    /* reset flag has been set after SSR, notify link up */
+    ctx_ptr->reset = FALSE;
+    ctx_ptr->xport_if.glink_core_if_ptr->link_up((glink_transport_if_type *)ctx_ptr);
+  }
+
+  glink_os_cs_acquire(ctx_ptr->rx_link_lock);
+
+  /* Process pending commands and data */
+  write_ind = ctx_ptr->rx_desc->write_ind;
+  read_ind = ctx_ptr->rx_desc->read_ind;
+
+  XPORT_RPM_LOG("RPM ISR write ind", ctx_ptr->pcfg->remote_ss, write_ind);
+  XPORT_RPM_LOG("RPM ISR read ind", ctx_ptr->pcfg->remote_ss, read_ind);
+
+  /* Ensure the index is 64-bit aligned */
+  if ((write_ind & 0x7) != 0)
+  {
+    dprintf(CRITICAL,"%s:%d: Write Index is not aligned: %u\n",__func__, __LINE__, write_ind);
+    ASSERT(0);
+  }
+
+  while (write_ind != read_ind && !stop_processing)
+  {
+    uint32 cmd = MSGRAM_READ32(ctx_ptr, read_ind);
+    uint32 cid = XPORT_RPM_GET_CHANNEL_ID(cmd); // most commands have channel ID
+    uint32 cmd_arg;
+
+    /* it can't wrap aroud here so just inceremt the index */
+    read_ind += sizeof(cmd);
+
+    XPORT_RPM_LOG("Cmd Rx", ctx_ptr->pcfg->remote_ss, cmd);
+
+    switch (XPORT_RPM_GET_CMD_ID(cmd))
+    {
+      case XPORT_RPM_CMD_VERSION_REQ:
+
+        cmd_arg = MSGRAM_READ32(ctx_ptr, read_ind);
+
+        /* no need to incerment read_ind here since it will be rounded up */
+
+        ctx_ptr->xport_if.glink_core_if_ptr->rx_cmd_version(
+          (glink_transport_if_type *)ctx_ptr,
+          XPORT_RPM_GET_VERSION(cmd), cmd_arg);
+        break;
+
+      case XPORT_RPM_CMD_VERSION_ACK:
+
+        cmd_arg = MSGRAM_READ32(ctx_ptr, read_ind);
+
+        /* no need to increment read_ind here since it will be rounded up */
+
+        ctx_ptr->xport_if.glink_core_if_ptr->rx_cmd_version_ack(
+          (glink_transport_if_type *)ctx_ptr,
+          XPORT_RPM_GET_VERSION(cmd), cmd_arg);
+        break;
+
+      case XPORT_RPM_CMD_OPEN_CHANNEL:
+        cmd_arg = MSGRAM_READ32(ctx_ptr, read_ind);
+        cmd_arg = ROUNDUP64(cmd_arg);
+
+        read_ind += sizeof(cmd_arg);
+
+        /* channel name should fit into the FIFO */
+        if (cmd_arg == 0 || cmd_arg >= ctx_ptr->rx_fifo_size)
+        {
+          dprintf(CRITICAL, "%s:%d: Invalid name length: %u", __func__, __LINE__, cmd_arg);
+          ASSERT(0);
+        }
+        else
+        {
+          char      tmpstr[ROUNDUP64(GLINK_CH_NAME_LEN)];
+          uint32  curr = 0;
+
+          while (curr < cmd_arg && curr < sizeof(tmpstr))
+          {
+            CHECK_INDEX_WRAP_AROUND(read_ind, ctx_ptr->rx_fifo_size);
+
+            *(uint32*)&tmpstr[curr] = MSGRAM_READ32(ctx_ptr, read_ind);
+            curr += sizeof(uint32);
+            read_ind += sizeof(uint32);
+          }
+
+          /* add all the unread stuff */
+          read_ind += cmd_arg - curr;
+
+          /* make sure the last character is NULL */
+          tmpstr[sizeof(tmpstr) - 1] = 0;
+
+          ctx_ptr->xport_if.glink_core_if_ptr->rx_cmd_ch_remote_open(
+            (glink_transport_if_type *)ctx_ptr, cid, tmpstr, GLINK_XPORT_RPM);
+        }
+
+        break;
+
+      case XPORT_RPM_CMD_CLOSE_CHANNEL:
+
+        ctx_ptr->xport_if.glink_core_if_ptr->rx_cmd_ch_remote_close(
+          //(glink_transport_if_type *)ctx_ptr, XPORT_RPM_GET_CHANNEL_ID(cmd));
+          (glink_transport_if_type *)ctx_ptr, cid);
+
+        /* no need to increment read_ind here since it would be rounded up */
+
+        break;
+
+      case XPORT_RPM_CMD_OPEN_CHANNEL_ACK:
+
+        /* no need to increment read_ind here since it would be rounded up */
+
+        ctx_ptr->xport_if.glink_core_if_ptr->rx_cmd_ch_open_ack(
+            (glink_transport_if_type *)ctx_ptr, cid, GLINK_XPORT_RPM);
+
+        break;
+
+      case XPORT_RPM_CMD_CLOSE_CHANNEL_ACK:
+
+        ctx_ptr->xport_if.glink_core_if_ptr->rx_cmd_ch_close_ack(
+          (glink_transport_if_type *)ctx_ptr, cid);
+
+        /* no need to increment read_ind here since it would be rounded up */
+
+        break;
+
+      case XPORT_RPM_CMD_TX_DATA:
+      {
+        glink_rx_intent_type desc;
+        memset( &desc, sizeof( glink_rx_intent_type), 0 );
+
+        read_ind += sizeof(cmd_arg);
+
+        CHECK_INDEX_WRAP_AROUND(read_ind, ctx_ptr->rx_fifo_size);
+
+        cmd_arg = MSGRAM_READ32(ctx_ptr, read_ind);
+
+        /* packet data should fit into the FIFO */
+        if (cmd_arg >= ctx_ptr->rx_fifo_size)
+        {
+          dprintf(CRITICAL, "%s:%d: Invalid packet length: %u",__func__, __LINE__, cmd_arg);
+          ASSERT(0);
+        }
+
+        read_ind += 2*sizeof(cmd_arg);
+
+        CHECK_INDEX_WRAP_AROUND(read_ind, ctx_ptr->rx_fifo_size);
+
+        ctx_ptr->pkt_start_ind = read_ind;
+        ctx_ptr->pkt_size = cmd_arg;
+
+        desc.size = cmd_arg;
+        desc.used = cmd_arg;
+        desc.pkt_sz = cmd_arg;
+        desc.iovec = ctx_ptr;
+        desc.vprovider = xport_rpm_pkt_provider;
+
+        read_ind += cmd_arg;
+
+        ctx_ptr->xport_if.glink_core_if_ptr->rx_put_pkt_ctx(
+          (glink_transport_if_type *)ctx_ptr, cid,
+          &desc, TRUE);
+
+        /* If interrupt was disabled then stop delivering messages */
+        stop_processing = ctx_ptr->irq_mask;
+
+        break;
+      }
+
+      case XPORT_RPM_CMD_TX_SIGNALS:
+
+        cmd_arg = MSGRAM_READ32(ctx_ptr, read_ind);
+
+        /* no need to incerement read_ind here since it will be rounded up */
+
+        ctx_ptr->xport_if.glink_core_if_ptr->rx_cmd_remote_sigs(
+          (glink_transport_if_type *)ctx_ptr,
+          cid, cmd_arg);
+        break;
+
+      default:
+      	dprintf(CRITICAL, "%s:%d: Invalid Command: %u\n",__func__, __LINE__, cmd);
+      	ASSERT(0);
+        break;
+    }
+
+    read_ind = ROUNDUP64(read_ind);
+
+    if (read_ind >= ctx_ptr->rx_fifo_size)
+    {
+      read_ind -= ctx_ptr->rx_fifo_size;
+    }
+
+    /* Update the shared read index */
+    ctx_ptr->rx_desc->read_ind = read_ind;
+  }
+
+  glink_os_cs_release(ctx_ptr->rx_link_lock);
+
+  return GLINK_STATUS_SUCCESS;
+}
+
+#ifdef GLINK_RPM_PROC
+/*===========================================================================
+FUNCTION      xport_rpm_isr
+===========================================================================*/
+/**
+
+  ISR of RPM transport.
+
+  @return     Returns error code.
+
+  @sideeffects  None.
+
+  @dependencies None.
+*/
+/*=========================================================================*/
+glink_err_type xport_rpm_isr( void )
+{
+  xport_rpm_ctx_type *ctx_ptr  = xport_rpm_get_context();
+
+  return xport_rpm_poll( ctx_ptr );
+}
+#else
+/*===========================================================================
+FUNCTION      xport_rpm_isr
+===========================================================================*/
+/**
+
+  ISR of RPM transport.
+
+  @param[in]  ctx_ptr   Pointer to transport context.
+
+  @return     Returns error code.
+
+  @sideeffects  None.
+
+  @dependencies None.
+*/
+/*=========================================================================*/
+glink_err_type xport_rpm_isr( xport_rpm_ctx_type *ctx_ptr )
+{
+  return xport_rpm_poll( ctx_ptr );
+}
+#endif
+
+
+/*===========================================================================
+FUNCTION      xport_rpm_ssr
+===========================================================================*/
+/**
+
+  Processes SSR event.
+
+  @param[in]  if_ptr   Pointer to transport interface instance.
+
+  @return     Returns error code.
+
+  @sideeffects  None.
+*/
+/*=========================================================================*/
+glink_err_type xport_rpm_ssr(glink_transport_if_type *if_ptr)
+{
+  xport_rpm_ctx_type *ctx_ptr = (xport_rpm_ctx_type *)if_ptr;
+
+  ctx_ptr->tx_desc->write_ind = 0;
+  ctx_ptr->rx_desc->read_ind = 0;
+  ctx_ptr->reset = TRUE;
+
+  return GLINK_STATUS_SUCCESS;
+}
+
+/*===========================================================================
+FUNCTION      xport_rpm_wait_link_down
+===========================================================================*/
+/**
+
+  Waits for read/write indicies to be set to 0 by the remote host.
+
+  @param[in]  if_ptr   Pointer to transport interface instance.
+
+  @return     TRUE if link is down, FALSE otherwise.
+
+  @sideeffects  None.
+*/
+/*=========================================================================*/
+boolean xport_rpm_wait_link_down(glink_transport_if_type *if_ptr)
+{
+  xport_rpm_ctx_type *ctx_ptr = (xport_rpm_ctx_type *)if_ptr;
+
+  return (ctx_ptr->tx_desc->write_ind == 0 &&
+          ctx_ptr->tx_desc->read_ind == 0  &&
+          ctx_ptr->rx_desc->write_ind == 0 &&
+          ctx_ptr->rx_desc->read_ind == 0);
+}
+
+
+/*===========================================================================
+FUNCTION      xport_rpm_mask_interrupt
+===========================================================================*/
+/**
+
+  Enables or disables interrupts.
+
+  @param[in]  if_ptr   Pointer to transport interface instance.
+  @param[in]  mask     TRUE=mask, FALSE=unmask
+
+  @return     Returns error code.
+
+  @sideeffects  None.
+*/
+/*=========================================================================*/
+glink_err_type xport_rpm_mask_interrupt(glink_transport_if_type *if_ptr, boolean mask)
+{
+  xport_rpm_ctx_type *ctx_ptr = (xport_rpm_ctx_type *)if_ptr;
+
+  if (ctx_ptr->irq_mask != mask)
+  {
+    if (mask)
+    {
+      glink_os_disable_interrupt(ctx_ptr->pcfg->irq_in);
+    }
+    else
+    {
+      glink_os_enable_interrupt(ctx_ptr->pcfg->irq_in);
+    }
+
+    ctx_ptr->irq_mask = mask;
+  }
+
+  return GLINK_STATUS_SUCCESS;
+}
+
+/*===========================================================================
+FUNCTION      xport_rpm_init
+===========================================================================*/
+/**
+
+  Initializes RPM transport.
+  Must be called before any other operations are done.
+
+  @param[in]  arg   The argument.
+
+  @return     Returns error code.
+
+  @sideeffects  None.
+*/
+/*=========================================================================*/
+glink_err_type xport_rpm_init(void *arg)
+{
+  uint32 ind;
+  glink_core_transport_cfg_type xport_rpm_cfg = { 0 };
+  uint32 *msg_ram_toc = (uint32*)xport_rpm_msg_ram_toc;
+  xport_rpm_toc_entry_type *entry;
+  uint32 msg_ram_toc_num;
+  char* msg_ram_toc_entry_start = (char*)&msg_ram_toc[XPORT_RPM_TOC_ENTRIES_IDX];
+  dprintf(SPEW, "%s:%d: RPM Transport INIT\n", __func__, __LINE__);
+
+  if (xport_rpm_config_num == 0)
+  {
+    return GLINK_STATUS_SUCCESS;
+  }
+
+  if (msg_ram_toc[XPORT_RPM_TOC_MAGIC_IDX] != XPORT_RPM_TOC_MAGIC)
+  {
+    dprintf(CRITICAL, "%s:%d: RPM Transport Failure: Invalid ToC cookie\n", __func__, __LINE__);
+    return GLINK_STATUS_FAILURE;
+  }
+
+  msg_ram_toc_num = msg_ram_toc[XPORT_RPM_TOC_LENGTH_IDX];
+
+  if (msg_ram_toc_num == 0)
+  {
+    dprintf(SPEW, "%s:%d RPM Transport Success\n", __func__, __LINE__);
+    return GLINK_STATUS_SUCCESS;
+  }
+
+  xport_rpm_ctx = glink_os_calloc(sizeof(*xport_rpm_ctx)*xport_rpm_config_num);
+
+  if (xport_rpm_ctx == NULL)
+  {
+    dprintf(INFO, "%s:%d RPM Transport Failed to allocate context\n", __func__, __LINE__);
+    ASSERT(0);
+  }
+
+  /* Initialize supported version and features */
+  xport_rpm_version.version = 1;
+  xport_rpm_version.features = 0;
+  xport_rpm_version.negotiate_features = &xport_rpm_negotiate_features;
+
+  /* Initialize edges */
+  dprintf(SPEW, "%s:%d: Initialize Edges\n", __func__, __LINE__);
+
+  for (ind = 0; ind < xport_rpm_config_num; ind++)
+  {
+    xport_rpm_ctx[ind].pcfg = xport_rpm_get_config(ind);
+
+    /* Find FIFOs in MSG RAM ToC */
+    for (entry = (xport_rpm_toc_entry_type*)msg_ram_toc_entry_start;
+         (char*)entry < msg_ram_toc_num*sizeof(*entry) + msg_ram_toc_entry_start &&
+           (xport_rpm_ctx[ind].tx_desc == NULL || xport_rpm_ctx[ind].rx_desc == NULL);
+         entry++)
+    {
+      if (entry->fifo_id == xport_rpm_ctx[ind].pcfg->tx_fifo_id)
+      {
+        xport_rpm_ctx[ind].tx_desc = (xport_rpm_ind_type*)&xport_rpm_msg_ram[entry->fifo_offset];
+        xport_rpm_ctx[ind].tx_desc->write_ind = 0;
+        xport_rpm_ctx[ind].tx_fifo = (char*)(xport_rpm_ctx[ind].tx_desc + 1);
+        xport_rpm_ctx[ind].tx_fifo_size = entry->fifo_size;
+      }
+      else if (entry->fifo_id == xport_rpm_ctx[ind].pcfg->rx_fifo_id)
+      {
+        xport_rpm_ctx[ind].rx_desc =(xport_rpm_ind_type*)&xport_rpm_msg_ram[entry->fifo_offset];
+        xport_rpm_ctx[ind].rx_desc->read_ind = 0;
+        xport_rpm_ctx[ind].rx_fifo = (char*)(xport_rpm_ctx[ind].rx_desc + 1);
+        xport_rpm_ctx[ind].rx_fifo_size = entry->fifo_size;
+      }
+    }
+
+    if (xport_rpm_ctx[ind].tx_desc == NULL || xport_rpm_ctx[ind].rx_desc == NULL)
+    {
+      /* FIFOs not found in MSG RAM ToC. */
+      xport_rpm_ctx[ind].pcfg = NULL;
+      continue;
+    }
+
+    /* Initialize context */
+    xport_rpm_ctx[ind].tx_link_lock = NULL;
+    xport_rpm_ctx[ind].rx_link_lock = NULL;
+
+    /* Initialize GLink transport interface */
+    xport_rpm_ctx[ind].xport_if.tx_cmd_version = &xport_rpm_tx_cmd_version;
+    xport_rpm_ctx[ind].xport_if.tx_cmd_version_ack = &xport_rpm_tx_cmd_version_ack;
+    xport_rpm_ctx[ind].xport_if.set_version = &xport_rpm_set_version;
+    xport_rpm_ctx[ind].xport_if.tx_cmd_ch_open = &xport_rpm_tx_cmd_ch_open;
+    xport_rpm_ctx[ind].xport_if.tx_cmd_ch_close = &xport_rpm_tx_cmd_ch_close;
+    xport_rpm_ctx[ind].xport_if.tx_cmd_ch_remote_open_ack = &xport_rpm_tx_cmd_ch_remote_open_ack;
+    xport_rpm_ctx[ind].xport_if.tx_cmd_ch_remote_close_ack = &xport_rpm_tx_cmd_ch_remote_close_ack;
+    xport_rpm_ctx[ind].xport_if.tx = &xport_rpm_tx;
+    xport_rpm_ctx[ind].xport_if.tx_cmd_set_sigs = &xport_rpm_tx_cmd_set_sigs;
+    xport_rpm_ctx[ind].xport_if.ssr = &xport_rpm_ssr;
+    xport_rpm_ctx[ind].xport_if.mask_rx_irq = &xport_rpm_mask_interrupt;
+    xport_rpm_ctx[ind].xport_if.poll = (poll_fn)&xport_rpm_poll;
+    xport_rpm_ctx[ind].xport_if.wait_link_down = &xport_rpm_wait_link_down;
+
+    /* TODO: glink transport priority */
+    xport_rpm_ctx[ind].xport_if.glink_priority = GLINK_XPORT_RPM;
+
+    /* Setup GLink configuration */
+    xport_rpm_cfg.name = XPORT_RPM_NAME;
+    xport_rpm_cfg.remote_ss = xport_rpm_ctx[ind].pcfg->remote_ss;
+    xport_rpm_cfg.version = &xport_rpm_version;
+    xport_rpm_cfg.version_count = 1;
+    xport_rpm_cfg.max_cid = 0xFF;
+    xport_rpm_cfg.max_iid = 0;
+    if (glink_core_register_transport(&xport_rpm_ctx[ind].xport_if, &xport_rpm_cfg) !=
+        GLINK_STATUS_SUCCESS)
+    {
+      /* Registration failed, set index to invalid. */
+      xport_rpm_ctx[ind].pcfg = NULL;
+      continue;
+    }
+
+    if ( !glink_os_register_isr( xport_rpm_ctx[ind].pcfg->irq_in,
+                                (os_isr_cb_fn)xport_rpm_isr,
+                                &xport_rpm_ctx[ind]) )
+    {
+       /* ISR registration failed, set index to invalid. */
+      xport_rpm_ctx[ind].pcfg = NULL;
+      continue;
+    }
+
+    /* send link up notification */
+    xport_rpm_ctx[ind].xport_if.glink_core_if_ptr->link_up((glink_transport_if_type *)&xport_rpm_ctx[ind].xport_if);
+  }
+
+  return GLINK_STATUS_SUCCESS;
+}
diff --git a/platform/msm_shared/glink/xport_rpm_config.c b/platform/msm_shared/glink/xport_rpm_config.c
new file mode 100644
index 0000000..1fff513
--- /dev/null
+++ b/platform/msm_shared/glink/xport_rpm_config.c
@@ -0,0 +1,92 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+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 The Linux Foundation 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 "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+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 FILES
+===========================================================================*/
+#include "xport_rpm_config.h"
+#include "smem_type.h"
+#include "glink_os_utils.h"
+#include <platform/iomap.h>
+
+/*===========================================================================
+                           MACRO DEFINITIONS
+===========================================================================*/
+
+#define XPORT_RPM_MSG_RAM_BASE        RPM_SS_MSG_RAM_START_ADDRESS_BASE_PHYS
+#define XPORT_RPM_MSG_RAM_SIZE        RPM_SS_MSG_RAM_START_ADDRESS_BASE_SIZE
+
+/** Size of Glink RPM transport ToC in MSG RAM */
+#define XPORT_RPM_MSG_TOC_SIZE        0x100
+
+/*===========================================================================
+                        DATA DECLARATIONS
+===========================================================================*/
+const xport_rpm_config_type xport_rpm_config[] =
+{
+  /* LK->Rpm */
+  {
+    "rpm",                /* Remote host name        */
+    XPORT_RPM_AP2R_ID,    /* Tx FIFO ID in RPM ToC   */
+    XPORT_RPM_R2AP_ID,    /* Rx FIFO ID in RPM ToC   */
+    {                     /* Outgoing interrupt      */
+      8, //DALIPCINT_PROC_RPM,
+      0, //DALIPCINT_GP_0
+    },
+    200                   /* Incoming interrupt      */
+  }
+};
+
+const uint32 xport_rpm_config_num = ARRAY_LENGTH(xport_rpm_config);
+const char* xport_rpm_msg_ram = (char*)XPORT_RPM_MSG_RAM_BASE;
+const uint32* xport_rpm_msg_ram_toc = (uint32*)(XPORT_RPM_MSG_RAM_BASE + XPORT_RPM_MSG_RAM_SIZE - XPORT_RPM_MSG_TOC_SIZE);
+
+/*===========================================================================
+FUNCTION      xport_rpm_get_config
+===========================================================================*/
+/**
+
+  Provides a pointer to transport config strucutre.
+
+  @param[in]  ind    Index of the config
+
+  @return     Pointer to transport config strucutre.
+
+  @sideeffects  None.
+*/
+/*=========================================================================*/
+const xport_rpm_config_type* xport_rpm_get_config(uint32 ind)
+{
+  if (ind >= xport_rpm_config_num)
+  {
+    return NULL;
+  }
+
+  return &xport_rpm_config[ind];
+}