Fix a race condition in UE where PUSCH could not be sent when UE sends PUCCH and PUSCH at the same slot
This MR fixes the race on ULSCH processing in UE where PUSCH is not sent occasionally when UE sends PUCCH and PUSCH at the same slot. When that happens, the following trace will appear
ESC[0mESC[0mESC[1;31m[PHY] Missed ULSCH detection. NDI toggled but rv 2 does not correspond to first reception
This issue is related to !1305 (merged).
BACKGROUND
The setting up of PDU in ul_config (a),
the setting up of tx_request->tx_request_body (b)
and the invocation of nr_ue_scheduled_response (c)
are done in different places. Most importantly, multiple threads will invoke the setting up of PDU in ul_config and the invocation of nr_ue_scheduled_response() at the same time.
ROOT CAUSE
The PDUs are handled and the fields in ul_config is cleared whenever the first nr_ue_scheduled_response() is invoked. That happens even if PUSCH PDU has been configured and is not ready to be handled in nr_ue_scheduled_response() as tx_request->tx_request_body is about to set up by another thread. The time sequence is
a by task1 for PUCCH <<<<< PUCCH PDU is set up
a by task2 for PUSCH <<<<< PUSCH PDU is set up
c by task1 for PUCCH <<<<< this will clear PUCCH PDU and PUSCH PDU where PUSCH PDU is not handled as b is not done yet.
b by task2 for PUSCH <<<<< tx_request->tx_request_body is set up
c by task2 for PUSCH <<<<< PUSCH PDU for task2 will not be handled as it has been cleared.
The correct way to do is:
- When a particular PDU is handled, set FAPI_NR_UL_CONFIG_TYPE_XXX to FAPI_NR_UL_CONFIG_TYPE_NONE so that it will not handled any more.
- Clear the fields in ul_config when all the config pdu are done
//Clear the fields when all the config pdu are done
if (pdu_done == ul_config->number_pdus) {
if (scheduled_response->tx_request)
scheduled_response->tx_request->number_of_pdus = 0;
ul_config->sfn = 0;
ul_config->slot = 0;
ul_config->number_pdus = 0;
LOG_D(PHY, "%d.%d clear ul_config %p\n", scheduled_response->frame, slot, ul_config);
memset(ul_config->ul_config_list, 0, sizeof(ul_config->ul_config_list));
}
- Since some PDUs might be indeed not handled in a slot. fill_ul_config will clear ul_config for a new slot.
// clear ul_config for new frame/slot
if ((ul_config->slot != slot_tx || ul_config->sfn != frame_tx) && ul_config->number_pdus != 0) {
LOG_D(MAC, "%d.%d %d.%d f clear ul %p t %d pdu %d\n", frame_tx, slot_tx, ul_config->sfn, ul_config->slot, ul_config, pdu_type, ul_config->number_pdus);
ul_config->number_pdus = 0;
memset(ul_config->ul_config_list, 0, sizeof(ul_config->ul_config_list));
}