FreeCalypso > hg > fc-magnetite
view src/aci2/aci_dti_mng/dti_conn_mng.c @ 639:026c98f757a6
tpudrv12.h & targets/gtm900.h: our current support is for MGC2GSMT version only
As it turns out, there exist two different Huawei-made hw platforms both
bearing the marketing name GTM900-B: one is MG01GSMT, the other is MGC2GSMT.
The two are NOT fw-compatible: aside from flash chip differences which
should be handled by autodetection, the two hw platforms are already known
to have different RFFEs with different control signals, and there may be
other differences not yet known. Our current gtm900 build target is for
MGC2GSMT only; we do not yet have a specimen of MG01GSMT on hand, hence
no support for that version will be possible until and unless someone
provides one.
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Thu, 30 Jan 2020 18:19:01 +0000 |
parents | 93999a60b835 |
children |
line wrap: on
line source
/* +----------------------------------------------------------------------------- | Project : ... | Modul : dti_conn_mng.c +----------------------------------------------------------------------------- | Copyright 2002 Texas Instruments Berlin, AG | All rights reserved. | | This file is confidential and a trade secret of Texas | Instruments Berlin, AG | The receipt of or possession of this file does not convey | any rights to reproduce or disclose its contents or to | manufacture, use, or sell anything it may describe, in | whole, or in part, without the specific written consent of | Texas Instruments Berlin, AG. +----------------------------------------------------------------------------- | Purpose : Implementation of DTI Connection Manager +----------------------------------------------------------------------------- */ #ifndef DTI_CONN_MNG_C #define DTI_CONN_MNG_C #endif /*===== INCLUDES ===================================================*/ #include "aci_all.h" #include "pconst.cdg" #include "mconst.cdg" #include "cnf_aci.h" #include "mon_aci.h" #include "pei.h" #include "aci_cmh.h" #include "ati_cmd.h" #include "aci_io.h" #include "aci_cmh.h" #include "aci_lst.h" #include "aci_mem.h" #include "dti.h" #include "dti_conn_mng.h" #include "dti_cntrl_mng.h" LOCAL ULONG used_dti_channels = 0; LOCAL T_ACI_LIST *dti_channel_list = NULL; /* list_begin */ LOCAL T_DTI_CONN_PARAMS glob_params; /********************** LOCAL FUNCTIONS *****************************/ LOCAL UBYTE dti_conn_get_new_dti_id (void) { ULONG tst_id; UBYTE i; TRACE_FUNCTION("dti_conn_get_new_dti_id()"); /* create a new DTI ID */ for (i = 0; i <= MAX_DTI_CONN_CHANNELS; i++) { tst_id = (0x01 << i) & used_dti_channels; if (!tst_id) { break; } } if (tst_id) { TRACE_EVENT("No DTI ID available"); return (DTI_DTI_ID_NOTPRESENT); } used_dti_channels |= (0x01 << i); TRACE_EVENT_P1("DTI ID %d created", i); return (i); } LOCAL void dti_conn_remove_dti_id (UBYTE dti_id) { ULONG tst_id; TRACE_FUNCTION("dti_conn_remove_id()"); if (dti_id >= MAX_DTI_CONN_CHANNELS) return; tst_id = 0x01 << (dti_id); used_dti_channels &= ~tst_id; TRACE_EVENT_P1("DTI ID %d removed", dti_id); } LOCAL BOOL dti_conn_error_cb(UBYTE dti_id, T_DTI_CONN_STATE result_type) { /* theorically should not be called... Yet helpfull for testing */ TRACE_FUNCTION("dti_conn_error_cb()"); TRACE_EVENT("ERROR: DTI connection callback has not been initialized !"); return FALSE; } LOCAL void dti_conn_reset_conn_parms( T_DTI_CONN_CHANNEL *dti_channel ) { UBYTE i,j; TRACE_FUNCTION("dti_conn_reset_conn_parms()"); dti_channel->erase_channel = FALSE; dti_channel->num_of_conns = 0; dti_channel->conn_cb = dti_conn_error_cb; dti_channel->state = DTI_CONN_STATE_DISCONNECTED; for (i=0; i<MAX_DTI_CONN_TUPLES; i++) { dti_channel->tuple_list[i].state = DTI_CONN_STATE_DISCONNECTED; for (j=0; j<NUM_OF_PEERS; j++) { dti_channel->tuple_list[i].peers[j].state = DTI_CONN_STATE_DISCONNECTED; dti_channel->tuple_list[i].peers[j].ent_id = DTI_ENTITY_INVALID; } } } LOCAL BOOL DTItest_dti_id( UBYTE dti_id, void *elem) { T_DTI_CONN_CHANNEL *dti_channel = (T_DTI_CONN_CHANNEL *)elem; if (dti_channel EQ NULL) return FALSE; if (dti_channel -> dti_id EQ dti_id ) return TRUE; else return FALSE; } LOCAL T_DTI_CONN_TUPLE *dti_conn_find_dti_tuple( T_DTI_CONN_CHANNEL *dti_channel, UBYTE tuple_no) { return &(dti_channel->tuple_list[tuple_no]); } LOCAL T_DTI_CONN_CHANNEL *dti_conn_find_dti_conn( UBYTE dti_id ) { T_DTI_CONN_CHANNEL *dti_channel; TRACE_FUNCTION("dti_conn_find_dti_conn()"); /*find channel in list */ dti_channel = find_element (dti_channel_list, dti_id, DTItest_dti_id); return dti_channel; } LOCAL BOOL dti_conn_connect( T_DTI_CONN_CHANNEL* dti_channel, T_DTI_ENTITY_ID* entity_list, UBYTE num_entities, T_DTI_CONN_MODE mode ) { ULONG link_id; UBYTE tuple_no; UBYTE i; TRACE_FUNCTION("dti_conn_connect()"); dti_channel->state = DTI_CONN_STATE_CONNECTING; if (dti_channel->conn_cb) { dti_channel->conn_cb(dti_channel->dti_id, DTI_CONN_STATE_CONNECTING); } else { TRACE_EVENT("conn_cb is NULL"); } if (mode EQ APPEND) { tuple_no = dti_channel->num_of_conns; } else /* SPLIT */ { tuple_no = 0; dti_channel->num_of_conns = 0; } for (i=0; i<num_entities-1; i++) { dti_channel->tuple_list[tuple_no].peers[0].ent_id = entity_list[i]; dti_channel->tuple_list[tuple_no].peers[1].ent_id = entity_list[i+1]; if ( (dti_channel->tuple_list[tuple_no].state NEQ DTI_CONN_STATE_DISCONNECTING) AND (dti_channel->tuple_list[tuple_no].state NEQ DTI_CONN_STATE_CONNECTING) ) { dti_channel->tuple_list[tuple_no].state = DTI_CONN_STATE_CONNECTING; dti_channel->tuple_list[tuple_no].tuple_no = tuple_no; dti_channel->state = DTI_CONN_STATE_CONNECTING; link_id = dti_conn_compose_link_id(0, 0, dti_channel->dti_id, tuple_no); dti_channel->tuple_list[tuple_no].peers[0].state = DTI_CONN_STATE_CONNECTING; dti_channel->tuple_list[tuple_no].peers[1].state = DTI_CONN_STATE_CONNECTING; /* connect a tuple */ glob_params.mng_ent_cb(link_id, entity_list[i], entity_list[i+1], DTI_CONNECT); glob_params.mng_ent_cb(link_id, entity_list[i+1], entity_list[i], DTI_CONNECT); } tuple_no++; } dti_channel->num_of_conns = tuple_no; return TRUE; } LOCAL BOOL dti_conn_disconnect( T_DTI_CONN_CHANNEL* dti_channel ) { ULONG link_id; UBYTE i; TRACE_FUNCTION("dti_conn_disconnect()"); dti_channel->state = DTI_CONN_STATE_DISCONNECTING; if (dti_channel->conn_cb) { dti_channel->conn_cb(dti_channel->dti_id, DTI_CONN_STATE_DISCONNECTING); } else { TRACE_EVENT("conn_cb is NULL"); } for (i=0; i < dti_channel->num_of_conns; i++) { /* set tuple state only if it is not already DISCONNECTED */ if (dti_channel->tuple_list[i].state NEQ DTI_CONN_STATE_DISCONNECTED) { dti_channel->tuple_list[i].state = DTI_CONN_STATE_DISCONNECTING; } link_id = dti_conn_compose_link_id(0, 0, dti_channel->dti_id, i); /* disconnect only a connected entity */ if (dti_channel->tuple_list[i].peers[0].state EQ DTI_CONN_STATE_CONNECTED OR dti_channel->tuple_list[i].peers[0].state EQ DTI_CONN_STATE_CONNECTING ) { dti_channel->tuple_list[i].peers[0].state = DTI_CONN_STATE_DISCONNECTING; glob_params.mng_ent_cb(link_id, dti_channel->tuple_list[i].peers[0].ent_id, dti_channel->tuple_list[i].peers[1].ent_id, DTI_DISCONNECT); } /* disconnect only a connected entity */ if (dti_channel->tuple_list[i].peers[1].state EQ DTI_CONN_STATE_CONNECTED OR dti_channel->tuple_list[i].peers[1].state EQ DTI_CONN_STATE_CONNECTING ) { dti_channel->tuple_list[i].peers[1].state = DTI_CONN_STATE_DISCONNECTING; glob_params.mng_ent_cb(link_id, dti_channel->tuple_list[i].peers[1].ent_id, dti_channel->tuple_list[i].peers[0].ent_id, DTI_DISCONNECT); } } return TRUE; } /********************** GLOBAL FUNCTIONS *****************************/ GLOBAL T_DTI_CONN_LINK_ID dti_conn_compose_link_id(UBYTE dummy, UBYTE assoc, UBYTE dti_id, UBYTE tuple_no) { T_DTI_CONN_LINK_ID link_id = 0; link_id += dummy; link_id <<= 8; link_id += assoc; link_id <<= 8; link_id += dti_id; link_id <<= 8; link_id += tuple_no; return link_id; } /* +--------------------------------------------------------------------+ | PROJECT : MODULE : DTI_CONN | | STATE : code ROUTINE : dti_conn_init | +--------------------------------------------------------------------+ PURPOSE : initialise the DTI Connection Manager */ GLOBAL void dti_conn_init( T_DTI_CONN_MNG_ENT_CB* mng_ent_cb ) { TRACE_FUNCTION("dti_conn_init()"); dti_channel_list = new_list (); glob_params.conn_cb = NULL; glob_params.mng_ent_cb = mng_ent_cb; glob_params.num_entities = 0; } /* +--------------------------------------------------------------------+ | PROJECT : MODULE : DTI_CONN | | STATE : code ROUTINE : dti_conn_new | +--------------------------------------------------------------------+ PURPOSE : register new DTI channel */ GLOBAL UBYTE dti_conn_new(UBYTE dti_id ) { T_DTI_CONN_CHANNEL *dti_channel; TRACE_FUNCTION("dti_conn_new()"); if (dti_id EQ DTI_DTI_ID_NOTPRESENT) { dti_id = dti_conn_get_new_dti_id (); } if (dti_id EQ DTI_DTI_ID_NOTPRESENT) { return (DTI_DTI_ID_NOTPRESENT); } /* search for an existing entry with correspondant dti_id */ dti_channel = dti_conn_find_dti_conn (dti_id); if( dti_channel ) { return (DTI_DTI_ID_NOTPRESENT); /* couldn't create a new entry */ } ACI_MALLOC(dti_channel, sizeof(T_DTI_CONN_CHANNEL)); dti_conn_reset_conn_parms (dti_channel); dti_channel->dti_id = dti_id; insert_list(dti_channel_list, dti_channel); return (dti_channel->dti_id); } /* +---------------------------------------------------------------------+ | PROJECT : MODULE : DTI_CONN | | STATE : code ROUTINE : dti_conn_erase_entry | +---------------------------------------------------------------------+ PURPOSE : /* erase entry from DTI channel list */ GLOBAL void dti_conn_erase_entry(UBYTE dti_id) { T_DTI_CONN_CHANNEL *dti_channel; TRACE_FUNCTION("dti_conn_erase_entry"); /* find element to be erased */ dti_channel = remove_element (dti_channel_list, dti_id, DTItest_dti_id); if( dti_channel NEQ NULL ) /* entry not erased yet */ ACI_MFREE (dti_channel); dti_conn_remove_dti_id(dti_id); } /* +-----------------------------------------------------------------------+ | PROJECT : MODULE : DTI_CONN | | STATE : code ROUTINE : dti_conn_is_dti_channel_connected | +-----------------------------------------------------------------------+ PURPOSE : returns TRUE if end-to-end DTI connection is connected and the given entity is in this connection */ GLOBAL BOOL dti_conn_is_dti_channel_connected( T_DTI_ENTITY_ID ent_id, UBYTE dti_id ) { UBYTE count = 0; UBYTE i; UBYTE entity_found = FALSE; T_DTI_CONN_CHANNEL *dti_channel = dti_conn_find_dti_conn( dti_id ); TRACE_FUNCTION("dti_conn_is_dti_channel_connected()"); if (dti_channel EQ NULL) { TRACE_EVENT_P1("dti_channel for dti_id %d not found", dti_id); return FALSE; } for (i=0; i<dti_channel->num_of_conns; i++) { if ((dti_channel->tuple_list[i].peers[0].ent_id EQ ent_id) OR (dti_channel->tuple_list[i].peers[1].ent_id EQ ent_id)) { entity_found = TRUE; break; } } if (entity_found EQ FALSE) return FALSE; if (dti_channel->state EQ DTI_CONN_STATE_CONNECTED) { return TRUE; } else { for (i=0; i<dti_channel->num_of_conns; i++) { if (dti_channel->tuple_list[i].state EQ DTI_CONN_STATE_CONNECTED) { count++; } } if (count EQ dti_channel->num_of_conns) { return TRUE; } } return FALSE; } /* +--------------------------------------------------------------------------+ | PROJECT : MODULE : DTI_CONN | | STATE : code ROUTINE : dti_conn_is_dti_channel_disconnected | +--------------------------------------------------------------------------+ PURPOSE : returns TRUE if end-to-end DTI connection is disconnected */ GLOBAL BOOL dti_conn_is_dti_channel_disconnected( UBYTE dti_id ) { UBYTE count = 0; UBYTE i; T_DTI_CONN_CHANNEL *dti_channel = dti_conn_find_dti_conn( dti_id ); TRACE_FUNCTION("dti_conn_is_dti_channel_disconnected()"); if (dti_channel EQ NULL) { return TRUE; } if (dti_channel->state EQ DTI_CONN_STATE_DISCONNECTED) { return TRUE; } else { for (i=0; i<dti_channel->num_of_conns; i++) { if (dti_channel->tuple_list[i].state EQ DTI_CONN_STATE_DISCONNECTED) { count++; } } if (count EQ dti_channel->num_of_conns) { return TRUE; } } return FALSE; } /* +---------------------------------------------------------------------+ | PROJECT : MODULE : DTI_CONN | | STATE : code ROUTINE : dti_conn_est_dpath | +---------------------------------------------------------------------+ PURPOSE : establishes data path. */ GLOBAL BOOL dti_conn_est_dpath( UBYTE dti_id, T_DTI_ENTITY_ID* entity_list, UBYTE num_entities, T_DTI_CONN_MODE mode, T_DTI_CONN_CB* cb) { T_DTI_CONN_CHANNEL *dti_channel; TRACE_FUNCTION("dti_conn_est_dpath()"); /*find channel in list */ dti_channel = dti_conn_find_dti_conn (dti_id); if (dti_channel EQ NULL) { TRACE_EVENT_P1("[ERR] dti_conn_est_dpath: dti_channel dti_id=%x not found", dti_id); /* DTI ID not found */ return FALSE; } if ( entity_list[0] EQ DTI_ENTITY_INVALID OR entity_list[1] EQ DTI_ENTITY_INVALID) { /* improper entity list */ TRACE_EVENT("[ERR] improper entity list "); return FALSE; } /* if 'SPLIT' then the whole DTI channel must be disconnected before a * new connection is established */ if ((mode EQ SPLIT) AND (dti_channel->state NEQ DTI_CONN_STATE_DISCONNECTED)) { dti_conn_disconnect (dti_channel); /* save new entity list to entity list buffer */ memcpy(glob_params.entity_list_buf, entity_list, sizeof(T_DTI_ENTITY_ID)*num_entities); glob_params.num_entities = num_entities; glob_params.conn_cb = cb; } else { dti_channel->conn_cb = cb; dti_conn_connect (dti_channel, entity_list, num_entities, mode); } return TRUE; } /* +---------------------------------------------------------------------+ | PROJECT : MODULE : DTI_CONN | | STATE : code ROUTINE : dti_conn_close_dpath | +---------------------------------------------------------------------+ PURPOSE : closes a DTI connection */ GLOBAL BOOL dti_conn_close_dpath( UBYTE dti_id ) { T_DTI_CONN_CHANNEL *dti_channel; UBYTE i=0; TRACE_FUNCTION("dti_conn_close_dpath()"); dti_channel = dti_conn_find_dti_conn( dti_id ); if (dti_channel EQ NULL) { TRACE_EVENT_P1("[ERR] dti_conn_close_dpath: dti_channel dti_id=%x not found", dti_id); return FALSE; } if (dti_channel->state NEQ DTI_CONN_STATE_DISCONNECTED) { dti_channel->state = DTI_CONN_STATE_DISCONNECTING; dti_conn_disconnect (dti_channel); } else { TRACE_EVENT("[ERR] dti_conn_close_dpath: try to close dpath which was DISCONNECTED"); return FALSE; } return TRUE; } /* +-----------------------------------------------------------------------+ | PROJECT : MODULE : DTI_CONN | | STATE : code ROUTINE : dti_conn_entity_connected | +-----------------------------------------------------------------------+ PURPOSE : response after a DTI connect request. This function is called to inform the DTI Connection Manager that a connection is established. */ GLOBAL void dti_conn_entity_connected( T_DTI_CONN_LINK_ID link_id, T_DTI_ENTITY_ID ent_id, T_DTI_CONN_RESULT result ) { T_DTI_CONN_CHANNEL *dti_channel; T_DTI_CONN_TUPLE *tuple; UBYTE i; UBYTE dti_id = EXTRACT_DTI_ID(link_id); BOOL both_entities_connected = FALSE; UBYTE count = 0; TRACE_FUNCTION("dti_conn_entity_connected()"); dti_channel = dti_conn_find_dti_conn( dti_id ); if (dti_channel EQ NULL) { TRACE_EVENT_P1("[ERR] dti_conn_entity_connected: dti_channel link_id=%x not found", link_id); return; } if (result EQ DTI_ERROR) { /* mark entity as disconnected */ dti_conn_entity_disconnected( link_id, ent_id ); /* close the whole DTI channel */ dti_conn_close_dpath( dti_id ); return; } if (dti_channel->state EQ DTI_CONN_STATE_CONNECTED) { TRACE_EVENT_P1("dti channel with dti_id=%x already connected", dti_id); return; } tuple = dti_conn_find_dti_tuple( dti_channel, EXTRACT_TUPLE_NO(link_id ) ); for (i=0; i<NUM_OF_PEERS; i++) { if (tuple->peers[i].state EQ DTI_CONN_STATE_CONNECTED) { count++; } if (tuple->peers[i].ent_id EQ ent_id) { if (tuple->peers[i].state EQ DTI_CONN_STATE_CONNECTING) { tuple->peers[i].state = DTI_CONN_STATE_CONNECTED; count++; } } if (count EQ NUM_OF_PEERS) { both_entities_connected = TRUE; } } /* if both entities are CONNECTED */ if (both_entities_connected) { tuple->state = DTI_CONN_STATE_CONNECTED; /* if all other tuples CONNECTED */ if (dti_conn_is_dti_channel_connected(ent_id, dti_id)) { dti_channel->state = DTI_CONN_STATE_CONNECTED; TRACE_EVENT_P1("DTI ID %d connected", dti_id); /* call connect_cb here */ if (dti_channel->conn_cb) { dti_channel->conn_cb(dti_id, DTI_CONN_STATE_CONNECTED); } else { TRACE_EVENT("conn_cb is NULL"); } } } } /* +-----------------------------------------------------------------------+ | PROJECT : MODULE : DTI_CONN | | STATE : code ROUTINE : dti_conn_entity_disconnected | +-----------------------------------------------------------------------+ PURPOSE : response after a DTI connect request. This function is called to inform the DTI Connection Manager that a connection is closed. */ GLOBAL void dti_conn_entity_disconnected( T_DTI_CONN_LINK_ID link_id, T_DTI_ENTITY_ID ent_id ) { T_DTI_CONN_CHANNEL *dti_channel; T_DTI_CONN_TUPLE *tuple; UBYTE i; UBYTE dti_id = EXTRACT_DTI_ID(link_id); UBYTE count = 0; TRACE_FUNCTION("dti_conn_entity_disconnected()"); dti_channel = dti_conn_find_dti_conn( dti_id ); if (dti_channel EQ NULL) { TRACE_EVENT_P1("[ERR] dti_conn_entity_disconnected: dti_channel link_id=%x not found", link_id); return; } if (dti_channel->state EQ DTI_CONN_STATE_DISCONNECTED) { TRACE_EVENT_P1("dti channel with dti_id=%x already diconnected", dti_id); return; } tuple = dti_conn_find_dti_tuple( dti_channel, EXTRACT_TUPLE_NO(link_id) ); for (i=0; i<NUM_OF_PEERS; i++) { if (tuple->peers[i].state EQ DTI_CONN_STATE_DISCONNECTED) { count++; } /* find disconnected entity */ if (tuple->peers[i].ent_id EQ ent_id) { tuple->peers[i].state = DTI_CONN_STATE_DISCONNECTED; tuple->peers[i].ent_id = DTI_ENTITY_INVALID; count++; tuple->state = DTI_CONN_STATE_DISCONNECTING; if (dti_channel->state EQ DTI_CONN_STATE_CONNECTED) { /* set DTI channel state */ dti_channel->state = DTI_CONN_STATE_DISCONNECTING; } } } /* if both entities are DISCONNECTED */ if (count EQ NUM_OF_PEERS) { /* set tuple state */ tuple->state = DTI_CONN_STATE_DISCONNECTED; /* if all other tuples DISCONNECTED */ if (dti_conn_is_dti_channel_disconnected(dti_id)) { dti_channel->state = DTI_CONN_STATE_DISCONNECTED; TRACE_EVENT_P1("DTI ID %d disconnected", dti_id); /* reset number of conns */ dti_channel->num_of_conns = 0; /* call disconnect_cb here */ if (dti_channel->conn_cb) { dti_channel->conn_cb(dti_id, DTI_CONN_STATE_DISCONNECTED); } else { TRACE_EVENT("conn_cb is NULL"); } if (glob_params.num_entities NEQ 0) { dti_channel->conn_cb = glob_params.conn_cb; dti_conn_connect( dti_channel, glob_params.entity_list_buf, glob_params.num_entities, SPLIT ); glob_params.num_entities = 0; } else { if (dti_channel->erase_channel EQ TRUE) { /* erase entry in DTI Conn Mng */ dti_conn_erase_entry(dti_id); } } } } } /* +-----------------------------------------------------------------------+ | PROJECT : MODULE : DTI_CONN | | STATE : code ROUTINE : dti_conn_close_all_connections| +-----------------------------------------------------------------------+ PURPOSE : This function is called to close all established DTI connections. */ GLOBAL void dti_conn_close_all_connections() { T_DTI_CONN_CHANNEL *dti_channel; TRACE_FUNCTION("dti_conn_close_all_connections()"); while(TRUE) { dti_channel = get_next_element (dti_channel_list, dti_channel); if (dti_channel EQ NULL) { return; } if (dti_channel->state EQ DTI_CONN_STATE_CONNECTED) { dti_conn_close_dpath(dti_channel->dti_id); dti_channel->erase_channel = TRUE; } else { dti_conn_erase_entry(dti_channel->dti_id); } } }