/*=========================================================================*/ glink_err_type xport_rpm_ssr(glink_transport_if_type *if_ptr) { xport_rpm_ctx_type *ctx_ptr = (xport_rpm_ctx_type *)if_ptr; glink_os_cs_acquire(ctx_ptr->tx_link_lock); glink_os_cs_acquire(ctx_ptr->rx_link_lock); 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; ctx_ptr->reset = TRUE; glink_os_cs_release(ctx_ptr->rx_link_lock); glink_os_cs_release(ctx_ptr->tx_link_lock); return GLINK_STATUS_SUCCESS; }
/*=========================================================================== 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); }
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); }
/** * 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; }
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; }
/*=========================================================================== 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/*=========================================================================*/ glink_err_type xport_rpm_isr( 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 increment 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 temp_string[ROUNDUP64(GLINK_CH_NAME_LEN)] = {0}; uint32 num_copied_chars = 0; uint32 *string_ptr; string_ptr = ( uint32 * )&temp_string[0]; while( ( num_copied_chars < cmd_arg ) && ( num_copied_chars < sizeof( temp_string ) ) ) { CHECK_INDEX_WRAP_AROUND( read_ind, ctx_ptr->rx_fifo_size ); *( string_ptr++ ) = MSGRAM_READ32( ctx_ptr, read_ind ); num_copied_chars += sizeof( uint32 ); read_ind += sizeof( uint32 ); } /* add all the unread stuff */ read_ind += cmd_arg - num_copied_chars; /* make sure the last character is NULL */ temp_string[ sizeof( temp_string ) - 1 ] = 0; ctx_ptr->xport_if.glink_core_if_ptr->rx_cmd_ch_remote_open( (glink_transport_if_type *)ctx_ptr, cid, temp_string, GLINK_XPORT_RPM); } break; case XPORT_RPM_CMD_CLOSE_CHANNEL: /* no need to increment read_ind here since it will be rounded up */ ctx_ptr->xport_if.glink_core_if_ptr->rx_cmd_ch_remote_close( (glink_transport_if_type *)ctx_ptr, cid); break; case XPORT_RPM_CMD_OPEN_CHANNEL_ACK: /* no need to increment read_ind here since it will 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: /* no need to increment read_ind here since it will be rounded up */ ctx_ptr->xport_if.glink_core_if_ptr->rx_cmd_ch_close_ack( (glink_transport_if_type *)ctx_ptr, cid); 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 increment 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; } /* Update read index only if transport has not been reset */ if( !ctx_ptr->reset ) { 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; } else { stop_processing = TRUE; } } glink_os_cs_release(ctx_ptr->rx_link_lock); return GLINK_STATUS_SUCCESS; }
/*=========================================================================*/ 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); /* Transport is in reset */ if( ctx_ptr->reset ) { glink_os_cs_release(ctx_ptr->tx_link_lock); return GLINK_STATUS_SUCCESS; } 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) > 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; }