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];
+}