2 /*******************************************************************************
3 ################################################################################
4 # Copyright (c) [2017-2019] [Radisys] #
6 # Licensed under the Apache License, Version 2.0 (the "License"); #
7 # you may not use this file except in compliance with the License. #
8 # You may obtain a copy of the License at #
10 # http://www.apache.org/licenses/LICENSE-2.0 #
12 # Unless required by applicable law or agreed to in writing, software #
13 # distributed under the License is distributed on an "AS IS" BASIS, #
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
15 # See the License for the specific language governing permissions and #
16 # limitations under the License. #
17 ################################################################################
18 *******************************************************************************/
20 #include "common_def.h"
26 #include "du_app_mac_inf.h"
27 #include "mac_sch_interface.h"
29 #include "sch_utils.h"
33 * @brief intialize the SchDrxHarqCb structre
37 * Function :schInitDrxHarqCb
39 * intialize the SchDrxHarqCb structre
41 * @param[in] SchDrxHarqCb *hqCb
47 void schInitDrxHarqCb(SchDrxHarqCb *hqDrxCb)
49 memset(hqDrxCb, 0, sizeof(SchDrxHarqCb));
50 hqDrxCb->retxExpDistance = SCH_DRX_INVALID_DISTANCE;
51 hqDrxCb->retxStrtIndex = SCH_DRX_INVALID_INDEX;
52 hqDrxCb->rttIndex = SCH_DRX_INVALID_INDEX;
53 hqDrxCb->retxIndex = SCH_DRX_INVALID_INDEX;
57 * @brief intialize the SchDrxUeCb structre
61 * Function : schInitDrxUeCb
63 * intialize the SchDrxUeCb structre
65 * @param[in] SchUeCb *ueCb
71 void schInitDrxUeCb(SchUeCb *ueCb)
73 memset(&ueCb->drxUeCb, 0, sizeof(SchDrxUeCb));
74 ueCb->drxUeCb.onDurationStartIndex = SCH_DRX_INVALID_INDEX;
75 ueCb->drxUeCb.onDurationExpiryIndex = SCH_DRX_INVALID_INDEX;
76 ueCb->drxUeCb.inActvExpiryIndex = SCH_DRX_INVALID_INDEX;
77 ueCb->drxUeCb.shortCycleExpiryIndex = SCH_DRX_INVALID_INDEX;
78 ueCb->drxUeCb.onDurationStartDistance = SCH_DRX_INVALID_DISTANCE;
79 ueCb->drxUeCb.onDurationExpiryDistance = SCH_DRX_INVALID_DISTANCE;
80 ueCb->drxUeCb.inActiveTmrExpiryDistance = SCH_DRX_INVALID_DISTANCE;
81 ueCb->drxUeCb.drxDlUeActiveStatus = false;
82 ueCb->drxUeCb.drxUlUeActiveStatus = false;
85 /* will uncomment this function in next gerrit */
88 * @brief delete Dl harq drx timers and information
92 * Function : schDeleteDlHarqDrxTimer
94 * delete Dl harq drx timers and information
96 * @param[in] SchCellCb *cell, SchUeCb *ueCb
101 void schDeleteDlHarqDrxTimer(SchCellCb *cell, SchDlHqEnt *dlHqEnt)
103 uint8_t idx, numHqPrcs;
105 SchDlHqProcCb *procs;
106 CmLList *node = NULLP;
108 numHqPrcs = dlHqEnt->numHqPrcs;
109 for(idx =0; idx<numHqPrcs; idx++)
111 procs = &dlHqEnt->procs[idx];
112 tmrIdx = procs->dlDrxHarqCb.retxStrtIndex;
113 CM_LLIST_FIRST_NODE(&cell->drxCb[tmrIdx].dlRetransTmrStartList, node);
116 cmLListDelFrm(&cell->drxCb[tmrIdx].dlRetransTmrStartList, node);
117 SCH_FREE(node, sizeof(CmLList));
120 tmrIdx = procs->dlDrxHarqCb.rttIndex;
121 CM_LLIST_FIRST_NODE(&cell->drxCb[tmrIdx].dlHarqRttExpiryList, node);
124 cmLListDelFrm(&cell->drxCb[tmrIdx].dlHarqRttExpiryList, node);
125 SCH_FREE(node, sizeof(CmLList));
128 tmrIdx = procs->dlDrxHarqCb.retxIndex;
129 CM_LLIST_FIRST_NODE(&cell->drxCb[tmrIdx].dlRetransExpiryList, node);
132 cmLListDelFrm(&cell->drxCb[tmrIdx].dlRetransExpiryList, node);
133 SCH_FREE(node, sizeof(CmLList));
135 schInitDrxHarqCb(&procs->dlDrxHarqCb);
140 * @brief delete UL harq drx timers and information
144 * Function : schDeleteUlHarqDrxTimer
146 * delete Ul harq drx timers and information
148 * @param[in] SchCellCb *cell, SchUeCb *ueCb
153 void schDeleteUlHarqDrxTimer(SchCellCb *cell, SchUlHqEnt *ulHqEnt)
155 uint8_t idx, numHqPrcs;
157 CmLList *node = NULLP;
158 SchUlHqProcCb *procs;
160 numHqPrcs = ulHqEnt->numHqPrcs;
161 for(idx =0; idx<numHqPrcs; idx++)
163 procs = &ulHqEnt->procs[idx];
164 tmrIdx = procs->ulDrxHarqCb.retxStrtIndex;
165 CM_LLIST_FIRST_NODE(&cell->drxCb[tmrIdx].ulRetransTmrStartList, node);
168 cmLListDelFrm(&cell->drxCb[tmrIdx].ulRetransTmrStartList, node);
169 SCH_FREE(node, sizeof(CmLList));
172 tmrIdx = procs->ulDrxHarqCb.rttIndex;
173 CM_LLIST_FIRST_NODE(&cell->drxCb[tmrIdx].ulHarqRttExpiryList, node);
176 cmLListDelFrm(&cell->drxCb[tmrIdx].ulHarqRttExpiryList, node);
177 SCH_FREE(node, sizeof(CmLList));
180 tmrIdx = procs->ulDrxHarqCb.retxIndex;
181 CM_LLIST_FIRST_NODE(&cell->drxCb[tmrIdx].ulRetransExpiryList, node);
184 cmLListDelFrm(&cell->drxCb[tmrIdx].ulRetransExpiryList, node);
185 SCH_FREE(node, sizeof(CmLList));
187 schInitDrxHarqCb(&procs->ulDrxHarqCb);
193 * @brief delete UE drx timers and information
197 * Function : schDeleteUeDrxInfo
199 * delete UE drx timers and information
201 * @param[in] SchCellCb *cell, SchUeCb *ueCb
206 void schDeleteUeDrxInfo(SchCellCb *cell, SchUeCb *ueCb)
210 if(ueCb->ueDrxInfoPres == true)
212 drxUeCb = &ueCb->drxUeCb;
214 /* delete on duration start timer from ueCb */
215 if(drxUeCb->onDurationStartIndex != SCH_DRX_INVALID_INDEX)
217 cmLListDelFrm(&cell->drxCb[drxUeCb->onDurationStartIndex].onDurationStartList, drxUeCb->onDurationStartNodeInfo);
218 SCH_FREE(drxUeCb->onDurationStartNodeInfo, sizeof(CmLList));
221 /* delete on duration expiry timer from ueCb */
222 if(drxUeCb->onDurationExpiryIndex != SCH_DRX_INVALID_INDEX)
224 cmLListDelFrm(&cell->drxCb[drxUeCb->onDurationExpiryIndex].onDurationExpiryList, drxUeCb->onDurationExpiryNodeInfo);
225 SCH_FREE(drxUeCb->onDurationExpiryNodeInfo, sizeof(CmLList));
228 /* delete inActv Expiry Index timer from ueCb */
229 if(drxUeCb->inActvExpiryIndex != SCH_DRX_INVALID_INDEX)
231 cmLListDelFrm(&cell->drxCb[drxUeCb->inActvExpiryIndex].inActvTmrExpiryList, drxUeCb->inActvTimerExpiryNodeInfo);
232 SCH_FREE(drxUeCb->inActvTimerExpiryNodeInfo, sizeof(CmLList));
235 /* delete short cycle expiry timer from ueCb */
236 if(drxUeCb->shortCycleExpiryIndex != SCH_DRX_INVALID_INDEX)
238 cmLListDelFrm(&cell->drxCb[drxUeCb->shortCycleExpiryIndex].shortCycleExpiryList, drxUeCb->shortCycleTmrExpiryNodeInfo);
239 SCH_FREE(drxUeCb->shortCycleTmrExpiryNodeInfo, sizeof(CmLList));
241 /* TODO - will uncomment this function in next gerrit */
242 //schDeleteDlHarqDrxTimer(cell, &ueCb->dlHqEnt);
243 //schDeleteUlHarqDrxTimer(cell, &ueCb->ulHqEnt);
244 schInitDrxUeCb(ueCb);
249 * @brief fill drxUeCb structure with the help of ue cfg/recfg information
253 * Function : schFillDrxUeCb
255 * fill drxUeCb structure with the help of ue cfg/recfg information
257 * @param[in] SchDrxCfg drxCfg ->configuration received from ue cfg/recfg api
258 * SchDrxUeCb *drxUeCb -> structure that need to be fill
264 void schFillDrxUeCb(uint8_t numerology, SchDrxCfg drxCfg, SchDrxUeCb *drxUeCb)
266 if(drxCfg.drxOnDurationTimer.onDurationTimerValInMs)
268 SCH_CNVRT_MS_TO_SLOT(drxUeCb->onDurationLen, drxCfg.drxOnDurationTimer.onDurationtimerValue.milliSeconds, numerology);
272 SCH_CNVRT_MS_TO_SLOT(drxUeCb->onDurationLen, drxCfg.drxOnDurationTimer.onDurationtimerValue.subMilliSeconds, numerology);
273 drxUeCb->onDurationLen = drxUeCb->onDurationLen >> 5;
275 SCH_CNVRT_MS_TO_SLOT(drxUeCb->inActvTimerLen, drxCfg.drxInactivityTimer, numerology);
276 SCH_CNVRT_SYMBL_TO_SLOT(drxUeCb->harqRttDlTimerLen, drxCfg.drxHarqRttTimerDl);
277 SCH_CNVRT_SYMBL_TO_SLOT(drxUeCb->harqRttUlTimerLen, drxCfg.drxHarqRttTimerUl);
278 drxUeCb->retransDlTimerLen = drxCfg.drxRetransmissionTimerDl;
279 drxUeCb->retransUlTimerLen = drxCfg.drxRetransmissionTimerUl;
280 SCH_CNVRT_MS_TO_SLOT(drxUeCb->longCycleLen, drxCfg.drxLongCycleStartOffset.drxLongCycleStartOffsetChoice, numerology);
281 SCH_CNVRT_MS_TO_SLOT(drxUeCb->drxStartOffset, drxCfg.drxLongCycleStartOffset.drxLongCycleStartOffsetVal, numerology);
282 if(drxCfg.shortDrxPres)
284 drxUeCb->shortCyclePresent = true;
285 SCH_CNVRT_MS_TO_SLOT(drxUeCb->shortCycleLen, drxCfg.shortDrx.drxShortCycle, numerology);
286 drxUeCb->shortCycleTmrLen = drxUeCb->shortCycleLen*drxCfg.shortDrx.drxShortCycleTimer;
288 drxUeCb->longCycleToBeUsed = true;
289 SCH_CNVRT_MS_TO_SLOT(drxUeCb->drxSlotOffset, drxCfg.drxSlotOffset, numerology);
290 drxUeCb->drxSlotOffset = drxUeCb->drxSlotOffset>>5;
294 * @brief Add new entry into the drx timer list
298 * Function : schAddDrxTimerIntoList
300 * Add new entry into the drx timer list
302 * @param[in] CmLListCp *drxTimerList -> List in which new entery have to add
303 * void * ueInfo -> ue information which is need to the added into list
309 uint8_t schAddDrxTimerIntoList(CmLListCp *drxTimerList,void * nodeInfo, CmLList *drxNodeInfo)
311 CmLList *currentNodeInfo = NULLP;
313 SCH_ALLOC(currentNodeInfo, sizeof(CmLList));
316 DU_LOG("\nERROR --> SCH : schAddDrxTimerIntoList() : Memory allocation failed");
320 currentNodeInfo->node = (PTR)nodeInfo;
322 cmLListAdd2Tail(drxTimerList, currentNodeInfo);
323 drxNodeInfo = currentNodeInfo;
324 DU_LOG("\nINFO --> SCH : Drx node added into the list");
329 * @brief This function is used to find the next onduration start timing
333 * Function : findNextOndurationOccurance
335 * This function is used to find the next onduration start timing
337 * @param[in] SchCellCb *cell, SchDrxUeCb *ueDrxCb, SlotTimingInfo *nxtOnDur,
344 void findNextOndurationOccurance(SchCellCb *cell, SchDrxUeCb *ueDrxCb, SlotTimingInfo *nxtOnDur, uint8_t delta)
346 uint16_t tmpDistance, numOfCycles;
347 uint32_t curTime, cycleLen, nxtDist;
348 SlotTimingInfo tmpTime;
350 if (ueDrxCb->longCycleToBeUsed == true)
352 cycleLen = ueDrxCb->longCycleLen;
356 cycleLen = ueDrxCb->shortCycleLen;
359 /* Add delta to current time */
360 ADD_DELTA_TO_TIME(cell->slotInfo, tmpTime, delta, cell->numSlots);
362 /* Convert tmpTime to number of slots */
363 curTime = ((tmpTime.sfn * cell->numSlots) + tmpTime.slot);
365 /* as per 38.321, if the criterion below is satisfied, then that sfn and
366 * slot are the correct ones for the on-duration timer.
367 * if the Short DRX Cycle is used, and [(SFN × 10) + subframe number] modulo
368 * (drx-ShortCycle) = (drxStartOffset) modulo (drx-ShortCycle); or
369 * if the Long DRX Cycle is used, and [(SFN × 10) + subframe number] modulo
370 * (drx-LongCycle) = drxStartOffset */
371 if ( curTime <= ueDrxCb->drxStartOffset)
373 /* offset is the nextOnDur */
374 nxtDist = ((((ueDrxCb->drxStartOffset / cell->numSlots)) & (MAX_SFN - 1)) * cell->numSlots) + (ueDrxCb->drxStartOffset % cell->numSlots);
378 tmpDistance = curTime - ueDrxCb->drxStartOffset;
379 numOfCycles = tmpDistance / cycleLen;
381 if (0 == (tmpDistance % cycleLen))
383 /* Perfect match pick up the current time */
384 nxtDist = ((((curTime / cell->numSlots)) & (MAX_SFN - 1)) * cell->numSlots) + (curTime % cell->numSlots);
388 nxtDist = ueDrxCb->drxStartOffset + (numOfCycles + 1) * cycleLen;
392 /* If slot offset is non-zero then Add slot offset to the calculated onDur
394 if(ueDrxCb->drxSlotOffset)
396 nxtDist = nxtDist + ueDrxCb->drxSlotOffset;
398 /*If next On Duration is less than DL DELTA ahead, we will miss it and
399 * hence need to move to the On-Duration after that.*/
400 if((nxtDist - (curTime - delta)) <= SCH_DRX_MAX_DELTA)
402 nxtDist = nxtDist + cycleLen;
405 nxtOnDur->sfn = ((nxtDist / cell->numSlots) & (MAX_SFN - 1));
406 nxtOnDur->slot = (nxtDist % cell->numSlots);
410 * @brief Add entry into the on duration list and short cycle list
414 * Function : schDrxUeReCfgTimer
416 * This function is used to Add entry into the on duration list and short
419 * @param[in] SchCellCb *cell, SchUeCb *ueCb
425 void schDrxUeReCfgTimer(SchCellCb *cell, SchUeCb *ueCb)
427 uint8_t currentSlotIndx;
428 uint32_t onDurTime, onDurExpSlotTime, currentSlotTime;
430 SlotTimingInfo onDurationOccurance;
432 if(ueCb->drxUeCb.shortCyclePresent == false)
434 /* if short cycle configuration are not recived as a part of UE Recfg then if there is any entry present in short cycle timer list
435 * remove the entry from the list */
436 if(ueCb->drxUeCb.shortCycleExpiryIndex != SCH_DRX_INVALID_INDEX)
438 cmLListDelFrm(&cell->drxCb[ueCb->drxUeCb.shortCycleExpiryIndex ].shortCycleExpiryList, ueCb->drxUeCb.shortCycleTmrExpiryNodeInfo);
439 SCH_FREE(ueCb->drxUeCb.shortCycleTmrExpiryNodeInfo, sizeof(CmLList));
440 ueCb->drxUeCb.shortCycleExpiryIndex = SCH_DRX_INVALID_INDEX;
441 ueCb->drxUeCb.shortCycleDistance = SCH_DRX_INVALID_DISTANCE;
444 /* If there is any entry present in on duration start list then remove the
445 * entry from the list and recaluate the nect onduration cucurance */
446 if(ueCb->drxUeCb.onDurationStartIndex != SCH_DRX_INVALID_INDEX)
448 cmLListDelFrm(&cell->drxCb[ueCb->drxUeCb.onDurationStartIndex].onDurationStartList, ueCb->drxUeCb.onDurationStartNodeInfo);
449 SCH_FREE(ueCb->drxUeCb.onDurationStartNodeInfo, sizeof(CmLList));
450 ueCb->drxUeCb.onDurationStartIndex = SCH_DRX_INVALID_INDEX;
451 ueCb->drxUeCb.onDurationStartDistance = SCH_DRX_INVALID_DISTANCE;
454 findNextOndurationOccurance(cell, &ueCb->drxUeCb, &onDurationOccurance, 0);
455 onDurTime = onDurationOccurance.sfn*cell->numSlots+onDurationOccurance.slot;
457 /* If Onduration timer of old configuration is already running then next onduration
458 * starts once it expires*/
459 if((ueCb->drxUeCb.onDurationExpiryDistance != SCH_DRX_INVALID_DISTANCE) && (ueCb->drxUeCb.onDurationExpiryIndex != SCH_DRX_INVALID_INDEX))
461 currentSlotTime = cell->slotInfo.sfn * cell->numSlots + cell->slotInfo.slot;
462 currentSlotIndx = (currentSlotTime + PHY_DELTA_DL + SCHED_DELTA)%MAX_DRX_SIZE;
463 if(currentSlotIndx >= ueCb->drxUeCb.onDurationExpiryIndex )
465 onDurExpSlotTime = currentSlotTime + ((ueCb->drxUeCb.onDurationExpiryDistance +1) * MAX_DRX_SIZE) +\
466 (ueCb->drxUeCb.onDurationExpiryIndex - currentSlotIndx + PHY_DELTA_DL + SCHED_DELTA);
471 onDurExpSlotTime = currentSlotTime + ((ueCb->drxUeCb.onDurationExpiryDistance) * MAX_DRX_SIZE) +\
472 (ueCb->drxUeCb.onDurationExpiryIndex - currentSlotIndx + PHY_DELTA_DL + SCHED_DELTA);
474 if(onDurTime <= onDurExpSlotTime)
476 if(ueCb->drxUeCb.longCycleToBeUsed == true)
477 cycleLen = ueCb->drxUeCb.longCycleLen;
479 cycleLen = ueCb->drxUeCb.shortCycleLen;
481 onDurTime = onDurTime + ((onDurExpSlotTime - onDurTime)/cycleLen + 1) * cycleLen;
484 SCH_CALCULATE_TIMER_INDEX(onDurTime, ueCb->drxUeCb.onDurationStartIndex);
485 ueCb->drxUeCb.onDurationStartDistance = SCH_CALC_SLOT_DIFF(onDurationOccurance, cell->slotInfo, cell->numSlots)/MAX_DRX_SIZE;
486 schAddDrxTimerIntoList(&cell->drxCb[ueCb->drxUeCb.onDurationStartIndex].onDurationStartList, ueCb, ueCb->drxUeCb.onDurationStartNodeInfo);
490 * @brief Add entry into the on duration list
494 * Function : schAddUeInOndurationList
496 * This function is used to Add entry into the on duration list
498 * @param[in] SchCellCb *cell, SchDrxUeCb *ueDrxCb, SlotTimingInfo *nxtOnDur,
505 void schAddUeInOndurationList(SchCellCb *cell, SchUeCb *ueCb, uint8_t delta)
508 SlotTimingInfo onDurationOccurance;
510 if(ueCb->ueDrxInfoPres)
512 findNextOndurationOccurance(cell, &ueCb->drxUeCb, &onDurationOccurance, delta);
513 onDurTime = onDurationOccurance.sfn*cell->numSlots+onDurationOccurance.slot;
514 SCH_CALCULATE_TIMER_INDEX(onDurTime, ueCb->drxUeCb.onDurationStartIndex);
515 ueCb->drxUeCb.onDurationStartDistance = SCH_CALC_SLOT_DIFF(onDurationOccurance, cell->slotInfo, cell->numSlots)/MAX_DRX_SIZE;
516 schAddDrxTimerIntoList(&cell->drxCb[ueCb->drxUeCb.onDurationStartIndex].onDurationStartList, ueCb, ueCb->drxUeCb.onDurationStartNodeInfo);
522 /**********************************************************************
524 **********************************************************************/