/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2006 Sandia National Laboratories. All rights * reserved. * Copyright (c) 2007 The Regents of the University of California. * All rights reserved. * Copyright (c) 2013-2014 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2015 Intel, Inc. All rights reserved * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "opal_config.h" #include #include #include #include #include #include "opal/prefetch.h" #include "opal/types.h" #include "btl_usnic.h" #include "btl_usnic_ack.h" #include "btl_usnic_endpoint.h" #include "btl_usnic_frag.h" #include "btl_usnic_module.h" #include "btl_usnic_proc.h" #include "btl_usnic_send.h" #include "btl_usnic_util.h" /* * Construct/destruct an endpoint structure. */ static void endpoint_construct(mca_btl_base_endpoint_t *endpoint) { int i; endpoint->endpoint_module = NULL; endpoint->endpoint_proc = NULL; endpoint->endpoint_proc_index = -1; endpoint->endpoint_exiting = false; endpoint->endpoint_connectivity_checked = false; endpoint->endpoint_on_all_endpoints = false; for (i = 0; i < USNIC_NUM_CHANNELS; ++i) { endpoint->endpoint_remote_modex.ports[i] = 0; endpoint->endpoint_remote_addrs[i] = FI_ADDR_NOTAVAIL; } endpoint->endpoint_send_credits = 8; /* list of fragments queued to be sent */ OBJ_CONSTRUCT(&endpoint->endpoint_frag_send_queue, opal_list_t); endpoint->endpoint_next_frag_id = 1; endpoint->endpoint_acktime = 0; /* endpoint starts not-ready-to-send */ endpoint->endpoint_ready_to_send = 0; endpoint->endpoint_ack_needed = false; /* clear sent/received sequence number array */ memset(endpoint->endpoint_sent_segs, 0, sizeof(endpoint->endpoint_sent_segs)); memset(endpoint->endpoint_rcvd_segs, 0, sizeof(endpoint->endpoint_rcvd_segs)); /* * Make a new OPAL hotel for this module * "hotel" is a construct used for triggering segment retransmission * due to timeout */ OBJ_CONSTRUCT(&endpoint->endpoint_hotel, opal_hotel_t); opal_hotel_init(&endpoint->endpoint_hotel, WINDOW_SIZE, opal_sync_event_base, mca_btl_usnic_component.retrans_timeout, 0, opal_btl_usnic_ack_timeout); /* Setup this endpoint's list links */ OBJ_CONSTRUCT(&(endpoint->endpoint_ack_li), opal_list_item_t); OBJ_CONSTRUCT(&(endpoint->endpoint_endpoint_li), opal_list_item_t); endpoint->endpoint_ack_needed = false; /* fragment reassembly info */ endpoint->endpoint_rx_frag_info = calloc(sizeof(struct opal_btl_usnic_rx_frag_info_t), MAX_ACTIVE_FRAGS); assert(NULL != endpoint->endpoint_rx_frag_info); if (OPAL_UNLIKELY(endpoint->endpoint_rx_frag_info == NULL)) { BTL_ERROR(("calloc returned NULL -- this should not happen!")); opal_btl_usnic_exit(endpoint->endpoint_module); /* Does not return */ } } static void endpoint_destruct(mca_btl_base_endpoint_t *endpoint) { opal_btl_usnic_proc_t *proc; if (endpoint->endpoint_ack_needed) { opal_btl_usnic_remove_from_endpoints_needing_ack(endpoint); } OBJ_DESTRUCT(&(endpoint->endpoint_ack_li)); /* Remove the endpoint from the all_endpoints list */ opal_btl_usnic_module_t *module = endpoint->endpoint_module; opal_mutex_lock(&module->all_endpoints_lock); if (endpoint->endpoint_on_all_endpoints) { opal_list_remove_item(&module->all_endpoints, &endpoint->endpoint_endpoint_li); endpoint->endpoint_on_all_endpoints = false; } opal_mutex_unlock(&module->all_endpoints_lock); OBJ_DESTRUCT(&(endpoint->endpoint_endpoint_li)); if (endpoint->endpoint_hotel.rooms != NULL) { OBJ_DESTRUCT(&(endpoint->endpoint_hotel)); } OBJ_DESTRUCT(&endpoint->endpoint_frag_send_queue); /* release owning proc */ proc = endpoint->endpoint_proc; if (NULL != proc) { proc->proc_endpoints[endpoint->endpoint_proc_index] = NULL; OBJ_RELEASE(proc); } free(endpoint->endpoint_rx_frag_info); } OBJ_CLASS_INSTANCE(opal_btl_usnic_endpoint_t, opal_list_item_t, endpoint_construct, endpoint_destruct); /* * Forcibly drain all pending output on an endpoint, without waiting for * actual completion. */ void opal_btl_usnic_flush_endpoint(opal_btl_usnic_endpoint_t *endpoint) { opal_btl_usnic_send_frag_t *frag; /* First, free all pending fragments */ while (!opal_list_is_empty(&endpoint->endpoint_frag_send_queue)) { frag = (opal_btl_usnic_send_frag_t *) opal_list_remove_first( &endpoint->endpoint_frag_send_queue); /* _cond still needs to check ownership, but make sure the * fragment is marked as done. */ frag->sf_ack_bytes_left = 0; frag->sf_seg_post_cnt = 0; opal_btl_usnic_send_frag_return_cond(endpoint->endpoint_module, frag); } /* Now, ACK everything that is pending */ opal_btl_usnic_handle_ack(endpoint, endpoint->endpoint_next_seq_to_send - 1); }