FreeCalypso > hg > fc-tourmaline
view src/cs/services/etm/etm_task.c @ 220:0ed36de51973
ABB semaphore protection overhaul
The ABB semaphone protection logic that came with TCS211 from TI
was broken in several ways:
* Some semaphore-protected functions were called from Application_Initialize()
context. NU_Obtain_Semaphore() called with NU_SUSPEND fails with
NU_INVALID_SUSPEND in this context, but the return value wasn't checked,
and NU_Release_Semaphore() would be called unconditionally at the end.
The latter call would increment the semaphore count past 1, making the
semaphore no longer binary and thus no longer effective for resource
protection. The fix is to check the return value from NU_Obtain_Semaphore()
and skip the NU_Release_Semaphore() call if the semaphore wasn't properly
obtained.
* Some SPI hardware manipulation was being done before entering the semaphore-
protected critical section. The fix is to reorder the code: first obtain
the semaphore, then do everything else.
* In the corner case of L1/DSP recovery, l1_abb_power_on() would call some
non-semaphore-protected ABB & SPI init functions. The fix is to skip those
calls in the case of recovery.
* A few additional corner cases existed, all of which are fixed by making
ABB semaphore protection 100% consistent for all ABB functions and code paths.
There is still one remaining problem of priority inversion: suppose a low-
priority task calls an ABB function, and some medium-priority task just happens
to preempt right in the middle of that semaphore-protected ABB operation. Then
the high-priority SPI task is locked out for a non-deterministic time until
that medium-priority task finishes its work and goes back to sleep. This
priority inversion problem remains outstanding for now.
| author | Mychaela Falconia <falcon@freecalypso.org> |
|---|---|
| date | Mon, 26 Apr 2021 20:55:25 +0000 |
| parents | 4e78acac3d88 |
| children |
line wrap: on
line source
/******************************************************************************** * Enhanced TestMode (ETM) * @file etm.c * * @author Kim T. Peteren (ktp@ti.com) * @version 0.1 * * * History: * * Date Modification * ------------------------------------ * 16/06/2003 Creation * 03/03/2004 Upadted regarding the ATP + minor ETM DB handling updates * 28/07/2004 Fixed ETM database issue * * (C) Copyright 2003 by Texas Instruments Incorporated, All Rights Reserved *********************************************************************************/ #include "etm/etm.h" #include "etm/etm_api.h" #include "etm/etm_messages_i.h" #include "etm/etm_trace.h" #include "etm/etm_env.h" #include "audio/audio_api.h" #include "rv/rv_general.h" #include "rvf/rvf_api.h" #include "rvt/rvt_gen.h" #include "rvf/rvf_target.h" #include "rv/rv_defined_swe.h" #include <string.h> #ifdef RVM_LCC_SWE #include "lcc/lcc_api.h" #include "lcc/lcc_cfg_i.h" #include "lcc/lcc.h" #include "lcc/lcc_env.h" #include "lcc/lcc_trace.h" #endif // Version of the ETM TASK moved to etm_version.h //const uint16 etm_task_revision = (1<<12) | (0x1); /****************************************************************************** * Globals *****************************************************************************/ #define ETM_DB_MAX 16 // Limited of registered SWEntities into ETM DB #define ETM_DB_NO_USE 0xFFFFFFFF // typedef struct { char swe_name[ETM_NAME_MAX_LEN]; int mid; int task_id; T_RVF_ADDR_ID addr_id; // Unique mailbox (ID) of the SWE which will //receive the message ETM_CALLBACK_FUNC rx_callback_func; } T_ETM_USER_DB; static T_ETM_USER_DB etm_user_db[ETM_DB_MAX]; static int etm_db_counter = 0; /****************************************************************************** * Prototypes *****************************************************************************/ extern T_ETM_ENV_CTRL_BLK *etm_env_ctrl_blk; #ifdef RVM_LCC_SWE extern T_PWR_CTRL_BLOCK *pwr_ctrl; #endif int etm_database_manager(T_RV_HDR *msg_p); int etm_forward_packet(int mid, T_RV_HDR *msg); void etm_error_packet_send(int mid, int error); void etm_receive(unsigned char *inbuf, unsigned short size); int etm_ffs_pkt_receive(uint8 *data, int size); extern int etm_at_atp_message(void *msg); #ifdef RVM_LCC_SWE extern int etm_pwr_ul(void *msg); extern int etm_pwr_dl(T_ETM_PKT *pkt, uint8 *buf, int insize); #endif /****************************************************************************** * Main Testmode Task Loop *****************************************************************************/ T_RV_RET etm_task(void) { extern int etm_core_init(void); extern int etm_audio_init(void); #ifdef RVM_LCC_SWE extern int etm_pwr_init(void); #endif T_RV_HDR *msg = NULL; T_ETM_PKT *pkt = NULL; UINT32 start_time = 0; UINT32 end_time = 0; UINT16 recv_event, i; int status = RV_OK, buf_size; /* Entity registration to ETM */ /* This should be in the individual SWE init. function*/ status = etm_core_init(); status = etm_audio_init(); #ifdef RVM_LCC_SWE status = etm_pwr_init(); #endif while (1) { recv_event = rvf_wait(0xffff,0); /* Wait (infinite) for all events. */ start_time = rvf_get_tick_count(); tr_etm(TgTrEtmLow,"ETM: _task: Time Waiting (%d) tick", start_time - end_time); tr_etm(TgTrEtmLow,"ETM: _task: Time Start(%d)", start_time); tr_etm(TgTrEtmLow,"ETM: _task: Got message passing to bit filter (0x%x)", recv_event); if (!(recv_event & RVF_TASK_MBOX_0_EVT_MASK)) continue; /* Read the message in the ETM mailbox */ if ((msg = rvf_read_mbox(ETM_MAILBOX)) == NULL) continue; tr_etm(TgTrEtmLow,"ETM: _task: msg_id(0x%x)", msg->msg_id); switch (msg->msg_id) { /* Entity registration request or unregistration */ case ETM_REGISTER_REQ: case ETM_UNREGISTER: status = etm_database_manager(msg); break; /* ETM packet received */ case ETM_DATA_FWR: if ((status = etm_forward_packet(((T_ETM_DATA_FWR *) msg)->mid, msg)) != ETM_OK) etm_error_packet_send(((T_ETM_DATA_FWR *) msg)->mid, status); break; /* TM3 packet received */ case ETM_TM3_DATA_FWR: if ((status = etm_forward_packet(ETM_TM3, msg)) != ETM_OK) etm_error_packet_send(ETM_TM3, status); break; default: tr_etm(TgTrEtmLow,"ETM: _task: msg_id '0x%x' NOT supported", msg->msg_id); } if (status != ETM_OK) { tr_etm(TgTrFatal,"ETM: _task: mid(0x%x) ERROR(%d)", ((T_ETM_DATA_FWR *) msg)->mid, status); etm_free(msg); // Free the message } end_time = rvf_get_tick_count(); tr_etm(TgTrEtmLow,"ETM: _task: Time End (%d)", end_time); tr_etm(TgTrEtmLow,"ETM: _task: Time Total (%d) tick", end_time - start_time); } return RV_OK; } void etm_error_packet_send(int mid, int error) { T_ETM_PKT *pkt; tr_etm(TgTrFatal,"ETM: _error_packet_send: Module(0x%x) ERROR(%d)", mid, error); if (error == ETM_NOMEM) { rvf_dump_mem(); } if ((pkt = (T_ETM_PKT *) etm_malloc(sizeof(T_ETM_PKT))) == NULL) { rvf_dump_mem(); return; } // Init. of return packet pkt->mid = mid; pkt->status = -error; pkt->size = 0; pkt->index = 0; etm_pkt_send(pkt); etm_free(pkt); // Free return packet } /* Forwarding of DATA to the SWE can either be done by message/primitive or callback */ int etm_forward_packet(int mid, T_RV_HDR* msg) { ETM_CALLBACK_FUNC rx_callback_func = NULL; int i, cid, status = ETM_OK; T_ETM_DATA_READY* message_p; T_RVF_ADDR_ID swe_addr_id = 0; // Search for supported MID in the table for (i = 0; etm_user_db[i].mid != TABLE_END; i++) { tr_etm(TgTrEtmLow,"ETM: _forward_packet: Lookup in db for mid(0x%x)", mid); if (etm_user_db[i].mid == mid) { rx_callback_func = etm_user_db[i].rx_callback_func; swe_addr_id = etm_user_db[i].addr_id; break; } } tr_etm(TgTrEtmLow,"ETM: _forward_packet: rx_callback_func(%d) swe_addr_id(%d)", *rx_callback_func, swe_addr_id); // Invoke the SWE mailbox if (swe_addr_id) { /* Allocate the memory for the message to send */ if ((message_p = (T_ETM_DATA_READY*) etm_malloc(sizeof(T_ETM_DATA_READY))) == NULL) return ETM_NOMEM; /* Fill the header of the message */ message_p->header.msg_id = ETM_DATA_READY; /* Fill the address source id */ message_p->header.src_addr_id = rvf_get_taskid(); message_p->header.dest_addr_id = etm_env_ctrl_blk->addr_id; message_p->header.callback_func = NULL; /* Fill the data in the message */ memcpy(((T_ETM_DATA_READY*) message_p)->data, ((T_ETM_DATA_FWR*) msg)->data, ((T_ETM_DATA_FWR*) msg)->size); /* Send the message to the entity */ if ((status = rvf_send_msg(swe_addr_id, message_p)) != RV_OK) { tr_etm(TgTrFatal,"ETM: _forward_packet: Failed to sent message - ERROR(%d)", status); return ETM_RV_FATAL; } etm_free(msg); // Free the message } // Invoke the SWE callback function else if (rx_callback_func) { tr_etm(TgTrEtmLow,"ETM: _forward_packet: to mid(0x%x)", mid); status = rx_callback_func (((T_ETM_DATA_FWR*) msg)->data, ((T_ETM_DATA_FWR*) msg)->size); rx_callback_func = NULL; if (status != ETM_OK) return status; etm_free(msg); // Free the message } else { return ETM_NOSYS; } return ETM_OK; } /****************************************************************************** * Get and Free buffer (Internal Functions) *****************************************************************************/ void *etm_malloc(int size) { /* Memory bank status (red, yellow, green) */ T_RVF_MB_STATUS mb_status; void *addr; mb_status = rvf_get_buf(etm_env_ctrl_blk->prim_id, size, &addr); /* The flag returned by rvf_get_buf is red, there is not enough * memory to allocate the buffer. */ if (mb_status == RVF_RED) { tr_etm(TgTrFatal, "ETM: _malloc: Error to get memory"); return NULL; } /* The flag is yellow, there will soon be not enough memory anymore. */ else if (mb_status == RVF_YELLOW) { tr_etm(TgTrFatal, "ETM: _malloc: Getting short on memory"); } tr_etm(TgTrEtmLow,"ETM: _malloc: size(%d) at addr(0x%x)", size, addr); return addr; } int etm_free(void *addr) { int status; tr_etm(TgTrEtmLow,"ETM: _free: addr(0x%x)", addr); if ((status = rvf_free_buf(addr)) != RV_OK) { tr_etm(TgTrFatal, "ETM: _free: ERROR(%d)", status); } return ETM_RV_FATAL; } /****************************************************************************** * ETM receive Functions API (Internal Functions) ******************************************************************************/ /* The input pointer buf point at a complete TM3 packet. */ int etm_tm3_data_forward(uint8 *buf, int size) { /* Type for a registration event. */ T_ETM_TM3_DATA_FWR *msg; tr_etm(TgTrEtmLow, "ETM: _tm3_data_forward: cid(0x%x) size(%d)", *buf, size); /* Allocate the memory for the message to send */ if ((msg = (T_ETM_TM3_DATA_FWR*) etm_malloc(sizeof(T_ETM_TM3_DATA_FWR))) == NULL) return ETM_NOMEM; /* Fill the message id */ msg->header.msg_id = ETM_TM3_DATA_FWR; /* Fill the address source id */ msg->header.src_addr_id = rvf_get_taskid(); msg->header.dest_addr_id = etm_env_ctrl_blk->addr_id; msg->header.callback_func = NULL; /* Fill the message parameters */ msg->size = size; msg->cid = *buf; memcpy(&msg->data, buf, size); // At this point, all the data have been parsed and copied into // the ETM primitive. Now we send the primitive to the ETM task. if (rvf_send_msg(etm_env_ctrl_blk->addr_id, msg) != RV_OK) { tr_etm(TgTrFatal, "ETM: _tm3_data_forward: FAILED"); return ETM_RV_FATAL; // msg is auto freed by rvf_send_msg() if error } return ETM_OK; } /* The input pointer buf point at payload of the TM packet, minus mid and cksum. */ int etm_data_forward(char mid, uint8 *inbuf, int size) { /* Type for a registration event. */ T_ETM_DATA_FWR *msg; tr_etm(TgTrEtmLow, "ETM: _data_forward: mid(0x%x) size(%d)", mid, size); /* Allocate the memory for the message to send */ if ((msg = (T_ETM_DATA_FWR*) etm_malloc(sizeof(T_ETM_DATA_FWR))) == NULL) return ETM_NOMEM; /* Fill the message id */ msg->header.msg_id = ETM_DATA_FWR; /* Fill the address source id */ msg->header.src_addr_id = rvf_get_taskid(); msg->header.dest_addr_id = etm_env_ctrl_blk->addr_id; msg->header.callback_func = NULL; /* Fill the message parameters */ msg->size = size; msg->mid = mid; memcpy(&msg->data, inbuf, size); // At this point, all the data have been parsed and copied into // the ETM primitive. Now we send the primitive to the ETM task. if (rvf_send_msg(etm_env_ctrl_blk->addr_id, msg) != RV_OK) { tr_etm(TgTrFatal, "ETM: _data_forward: FAILED"); return ETM_RV_FATAL; // msg is auto freed by rvf_send_msg() if error } return ETM_OK; } /* This function is registred in the RVT module as the TestMode receive function */ /* It's called every time a TestMode packet is received on the UART and the */ /* data is forwarded to the ETM Entity via a message/primitiv */ /* The function is a callback func. used by the RVT TASK -> UART RX. */ void etm_receive(uint8 *inbuf, unsigned short size) { int error = ETM_NOSYS, i, index; char mid; unsigned char cksum; T_ETM_PKT *pkt; tr_etm(TgTrEtmLow, "ETM: _receive: inbuf size(%d)", size); // Copy data payload size (size minus MID/CID byte and checksum byte) mid = *inbuf++; cksum = mid; for (i = 0; i < size - 1; i++) { cksum ^= inbuf[i]; } if (cksum != 0) { error = ETM_PACKET; goto ETM_RECEIVE_END; } // Check it's a TM3 packet if ((0x20 <= mid && mid < 0x27) || (0x30 <= mid && mid < 0x3A) || (0x40 <= mid && mid < 0x49) || (0x50 <= mid && mid < 0x57)) { // Forward complete TM3 packet error = etm_tm3_data_forward(--inbuf, size); } else { /* Controlling of receptor for regisration */ for (index=0; index < etm_db_counter; index++) { if (etm_user_db[index].mid == mid) { // Forward ETM packet without <mid> and <cksum>, -2 in size error = etm_data_forward(mid, inbuf, size - 2); break; } else if ((index == etm_db_counter) && (etm_user_db[index].mid != mid)) { tr_etm(TgTrFatal, "ETM: _receive: mid(0x%x) not supported", mid); } } } ETM_RECEIVE_END: /* Fill in Error status in ETM packet and send */ if (error) { if (error == ETM_NOMEM) { rvf_dump_mem(); return; } if ((pkt = (T_ETM_PKT *) etm_malloc(sizeof(T_ETM_PKT))) == NULL) return; pkt->size = 0; pkt->mid = mid; pkt->status = -error; etm_pkt_send(pkt); etm_free(pkt); // Free return Packet } } /****************************************************************************** * Registration manager Functions API (Internal function) ******************************************************************************/ int etm_database_add(T_ETM_REGISTER_REQ *msg_p, int index) { memcpy(etm_user_db[index].swe_name, msg_p->name, strlen(msg_p->name)); etm_user_db[index].mid = msg_p->mid; etm_user_db[index].task_id = msg_p->task_id; etm_user_db[index].addr_id = msg_p->addr_id; etm_user_db[index].rx_callback_func = msg_p->rx_callback_func; etm_user_db[index+1].mid = TABLE_END; return ETM_OK; } int etm_database_manager(T_RV_HDR *msg_p) { int index, mid, status; if (msg_p->msg_id == ETM_REGISTER_REQ) { mid = ((T_ETM_REGISTER_REQ *) msg_p)->mid; tr_etm(TgTrEtmLow,"ETM: _database_manager: _REGISTER_REQ reguest is received from (%s)", ((T_ETM_REGISTER_REQ *) msg_p)->name); /* Lookup in the ETM DB array */ for (index=0; index < ETM_DB_MAX; index++) { /* Use unregistrered space */ if ((etm_user_db[index].mid == ETM_DB_NO_USE) && (etm_user_db[index].addr_id == 0) && (etm_user_db[index].rx_callback_func == NULL)) { status = etm_database_add((T_ETM_REGISTER_REQ*) msg_p, index); etm_db_counter++; etm_free(msg_p); // Free Message return ETM_OK; } /* Reject double registration */ else if ((etm_user_db[index].mid == mid) && ((etm_user_db[index].addr_id != 0) || (etm_user_db[index].rx_callback_func != NULL))) { tr_etm(TgTrFatal,"ETM: _database_manager: The Module(0x%x) is registrered", mid); etm_free(msg_p); // Free Message return ETM_OK; } } /* Add the entity to the etm database */ if (etm_db_counter < ETM_DB_MAX) { status = etm_database_add((T_ETM_REGISTER_REQ*) msg_p, etm_db_counter); etm_db_counter++; etm_free(msg_p); // Free Message return ETM_OK; } etm_free(msg_p); // Free Message return ETM_DB_LIMIT; } if (msg_p->msg_id == ETM_UNREGISTER) { mid = ((T_ETM_UNREGISTER *) msg_p)->mid; tr_etm(TgTrEtmLow,"ETM: _database_manager: _UNREGISTER reguest is received from (%s)", ((T_ETM_REGISTER_REQ *) msg_p)->name); /* Lookup in the array, if the SWE is stocked then clean it*/ for (index=0; index < ETM_DB_MAX; index++) { if (etm_user_db[index].mid == mid) { etm_user_db[index].mid = ETM_DB_NO_USE; etm_user_db[index].addr_id = 0; etm_user_db[index].rx_callback_func = NULL; etm_db_counter--; etm_free(msg_p); // Free Message return ETM_OK; } } etm_free(msg_p); // Free Message return ETM_INVAL; } etm_free(msg_p); // Free Message return ETM_OK; }
