diff --git a/src/gprs_rlcmac_sched.cpp b/src/gprs_rlcmac_sched.cpp index f6af9b71..efd8a9ef 100644 --- a/src/gprs_rlcmac_sched.cpp +++ b/src/gprs_rlcmac_sched.cpp @@ -21,40 +21,14 @@ #include #include -extern struct llist_head block_queue; - -static uint8_t rlcmac_dl_idle[23] = { - 0x47, /* control without optional header octets, no polling, USF=111 */ - 0x94, /* dummy downlink control message, paging mode 00 */ - 0x2b, /* no persistance level, 7 bits spare pattern */ - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b -}; - -int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, - uint32_t fn, uint8_t block_nr) +uint32_t sched_poll(uint8_t trx, uint8_t ts, uint32_t fn, uint8_t block_nr, + struct gprs_rlcmac_tbf **poll_tbf, + struct gprs_rlcmac_tbf **ul_ack_tbf, + struct gprs_rlcmac_tbf **dl_ass_tbf, + struct gprs_rlcmac_tbf **ul_ass_tbf) { - struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; - struct gprs_rlcmac_pdch *pdch; - struct gprs_rlcmac_tbf *tbf, *poll_tbf = NULL, *dl_ass_tbf = NULL, - *ul_ass_tbf = NULL, *ul_ack_tbf = NULL; - uint8_t usf = 0x7; - struct msgb *msg = NULL; + struct gprs_rlcmac_tbf *tbf; uint32_t poll_fn; - uint8_t i, tfi; - - if (trx >= 8 || ts >= 8) - return -EINVAL; - pdch = &bts->trx[trx].pdch[ts]; - - if (!pdch->enable) { - LOGP(DRLCMACSCHED, LOGL_ERROR, "Received RTS on disabled PDCH: " - "TRX=%d TS=%d\n", trx, ts); - return -EIO; - } - - /* store last frame number of RTS */ - pdch->last_rts_fn = fn; /* check special TBF for events */ poll_fn = fn + 4; @@ -68,13 +42,13 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, /* polling for next uplink block */ if (tbf->poll_state == GPRS_RLCMAC_POLL_SCHED && tbf->poll_fn == poll_fn) - poll_tbf = tbf; + *poll_tbf = tbf; if (tbf->ul_ack_state == GPRS_RLCMAC_UL_ACK_SEND_ACK) - ul_ack_tbf = tbf; + *ul_ack_tbf = tbf; if (tbf->dl_ass_state == GPRS_RLCMAC_DL_ASS_SEND_ASS) - dl_ass_tbf = tbf; + *dl_ass_tbf = tbf; if (tbf->ul_ass_state == GPRS_RLCMAC_UL_ASS_SEND_ASS) - ul_ass_tbf = tbf; + *ul_ass_tbf = tbf; } llist_for_each_entry(tbf, &gprs_rlcmac_dl_tbfs, list) { /* this trx, this ts */ @@ -83,51 +57,60 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, /* polling for next uplink block */ if (tbf->poll_state == GPRS_RLCMAC_POLL_SCHED && tbf->poll_fn == poll_fn) - poll_tbf = tbf; + *poll_tbf = tbf; if (tbf->dl_ass_state == GPRS_RLCMAC_DL_ASS_SEND_ASS) - dl_ass_tbf = tbf; + *dl_ass_tbf = tbf; if (tbf->ul_ass_state == GPRS_RLCMAC_UL_ASS_SEND_ASS) - ul_ass_tbf = tbf; + *ul_ass_tbf = tbf; } - /* check uplink ressource for polling */ - if (poll_tbf) { + return poll_fn; +} + +uint8_t sched_select_uplink(uint8_t trx, uint8_t ts, uint32_t fn, + uint8_t block_nr, struct gprs_rlcmac_pdch *pdch) +{ + struct gprs_rlcmac_tbf *tbf; + uint8_t usf = 0x07; + uint8_t i, tfi; + + /* select uplink ressource */ + for (i = 0, tfi = pdch->next_ul_tfi; i < 32; + i++, tfi = (tfi + 1) & 31) { + tbf = pdch->ul_tbf[tfi]; + /* no TBF for this tfi, go next */ + if (!tbf) + continue; + /* no UL ressources needed, go next */ + /* we don't need to give ressources in FINISHED state, + * because we have received all blocks and only poll + * for packet control ack. */ + if (tbf->state != GPRS_RLCMAC_FLOW) + continue; + + /* use this USF */ + usf = tbf->dir.ul.usf[ts]; LOGP(DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: TRX=%d " - "TS=%d FN=%d block_nr=%d scheduling free USF for " - "polling at FN=%d of %s TFI=%d\n", trx, ts, fn, - block_nr, poll_fn, - (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", - poll_tbf->tfi); - /* use free USF */ - /* else, we search for uplink ressource */ - } else { - /* select uplink ressource */ - for (i = 0, tfi = pdch->next_ul_tfi; i < 32; - i++, tfi = (tfi + 1) & 31) { - tbf = pdch->ul_tbf[tfi]; - /* no TBF for this tfi, go next */ - if (!tbf) - continue; - /* no UL ressources needed, go next */ - /* we don't need to give ressources in FINISHED state, - * because we have received all blocks and only poll - * for packet control ack. */ - if (tbf->state != GPRS_RLCMAC_FLOW) - continue; - - /* use this USF */ - usf = tbf->dir.ul.usf[ts]; - LOGP(DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: " - "TRX=%d TS=%d FN=%d block_nr=%d scheduling " - "USF=%d for required uplink ressource of " - "UL TBF=%d\n", trx, ts, fn, block_nr, usf, tfi); - /* next TBF to handle ressource is the next one */ - pdch->next_ul_tfi = (tfi + 1) & 31; - break; - } + "TS=%d FN=%d block_nr=%d scheduling USF=%d for " + "required uplink ressource of UL TBF=%d\n", trx, ts, fn, + block_nr, usf, tfi); + /* next TBF to handle ressource is the next one */ + pdch->next_ul_tfi = (tfi + 1) & 31; + break; } - /* Prio 1: select control message */ + return usf; +} + +struct msgb *sched_select_ctrl_msg(uint8_t trx, uint8_t ts, uint32_t fn, + uint8_t block_nr, struct gprs_rlcmac_pdch *pdch, + struct gprs_rlcmac_tbf *ul_ack_tbf, + struct gprs_rlcmac_tbf *dl_ass_tbf, + struct gprs_rlcmac_tbf *ul_ass_tbf) +{ + struct msgb *msg = NULL; + struct gprs_rlcmac_tbf *tbf = NULL; + /* schedule PACKET DOWNLINK ASSIGNMENT */ if (dl_ass_tbf) { tbf = dl_ass_tbf; @@ -143,64 +126,137 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, tbf = ul_ack_tbf; msg = gprs_rlcmac_send_uplink_ack(tbf, fn); } + /* any message */ if (msg) { LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling control " "message at RTS for %s TBF=%d (TRX=%d, TS=%d)\n", (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tbf->tfi, trx, ts); + return msg; } /* schedule PACKET PAGING REQUEST */ - if (!msg && !llist_empty(&pdch->paging_list)) { - msg = gprs_rlcmac_send_packet_paging_request(pdch); - if (msg) - LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling paging " - "request message at RTS for (TRX=%d, TS=%d)\n", - trx, ts); + if (llist_empty(&pdch->paging_list)) + return NULL; + msg = gprs_rlcmac_send_packet_paging_request(pdch); + if (msg) + LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling paging request " + "message at RTS for (TRX=%d, TS=%d)\n", trx, ts); + + return msg; +} + +struct msgb *sched_select_downlink(uint8_t trx, uint8_t ts, uint32_t fn, + uint8_t block_nr, struct gprs_rlcmac_pdch *pdch) +{ + struct msgb *msg = NULL; + struct gprs_rlcmac_tbf *tbf = NULL; + uint8_t i, tfi; + + /* select downlink ressource */ + for (i = 0, tfi = pdch->next_dl_tfi; i < 32; + i++, tfi = (tfi + 1) & 31) { + tbf = pdch->dl_tbf[tfi]; + /* no TBF for this tfi, go next */ + if (!tbf) + continue; + /* no DL TBF, go next */ + if (tbf->direction != GPRS_RLCMAC_DL_TBF) + continue; + /* no DL ressources needed, go next */ + if (tbf->state != GPRS_RLCMAC_FLOW + && tbf->state != GPRS_RLCMAC_FINISHED) + continue; + + LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling data message at " + "RTS for DL TBF=%d (TRX=%d, TS=%d)\n", tfi, trx, ts); + /* next TBF to handle ressource is the next one */ + pdch->next_dl_tfi = (tfi + 1) & 31; + /* generate DL data block */ + msg = gprs_rlcmac_send_data_block_acknowledged(tbf, fn, + ts); + break; } + return msg; +} +static uint8_t rlcmac_dl_idle[23] = { + 0x47, /* control without optional header octets, no polling, USF=111 */ + 0x94, /* dummy downlink control message, paging mode 00 */ + 0x2b, /* no persistance level, 7 bits spare pattern */ + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b +}; + +struct msgb *sched_dummy(void) +{ + struct msgb *msg; + + msg = msgb_alloc(23, "rlcmac_dl_idle"); + if (!msg) + return NULL; + memcpy(msgb_put(msg, 23), rlcmac_dl_idle, 23); + + return msg; +} + +int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn, + uint32_t fn, uint8_t block_nr) +{ + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + struct gprs_rlcmac_pdch *pdch; + struct gprs_rlcmac_tbf *poll_tbf = NULL, *dl_ass_tbf = NULL, + *ul_ass_tbf = NULL, *ul_ack_tbf = NULL; + uint8_t usf = 0x7; + struct msgb *msg = NULL; + uint32_t poll_fn; + + if (trx >= 8 || ts >= 8) + return -EINVAL; + pdch = &bts->trx[trx].pdch[ts]; + + if (!pdch->enable) { + LOGP(DRLCMACSCHED, LOGL_ERROR, "Received RTS on disabled PDCH: " + "TRX=%d TS=%d\n", trx, ts); + return -EIO; + } + + /* store last frame number of RTS */ + pdch->last_rts_fn = fn; + + poll_fn = sched_poll(trx, ts, fn, block_nr, &poll_tbf, &ul_ack_tbf, + &dl_ass_tbf, &ul_ass_tbf); + /* check uplink ressource for polling */ + if (poll_tbf) + LOGP(DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: TRX=%d " + "TS=%d FN=%d block_nr=%d scheduling free USF for " + "polling at FN=%d of %s TFI=%d\n", trx, ts, fn, + block_nr, poll_fn, + (poll_tbf->direction == GPRS_RLCMAC_UL_TBF) + ? "UL" : "DL", poll_tbf->tfi); + /* use free USF */ + /* else, we search for uplink ressource */ + else + usf = sched_select_uplink(trx, ts, fn, block_nr, pdch); + + /* Prio 1: select control message */ + msg = sched_select_ctrl_msg(trx, ts, fn, block_nr, pdch, ul_ack_tbf, + dl_ass_tbf, ul_ass_tbf); + /* Prio 2: select data message for downlink */ - if (!msg) { - /* select downlink ressource */ - for (i = 0, tfi = pdch->next_dl_tfi; i < 32; - i++, tfi = (tfi + 1) & 31) { - tbf = pdch->dl_tbf[tfi]; - /* no TBF for this tfi, go next */ - if (!tbf) - continue; - /* no DL TBF, go next */ - if (tbf->direction != GPRS_RLCMAC_DL_TBF) - continue; - /* no DL ressources needed, go next */ - if (tbf->state != GPRS_RLCMAC_FLOW - && tbf->state != GPRS_RLCMAC_FINISHED) - continue; - - LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling data " - "message at RTS for DL TBF=%d (TRX=%d, " - "TS=%d)\n", tfi, trx, ts); - /* next TBF to handle ressource is the next one */ - pdch->next_dl_tfi = (tfi + 1) & 31; - /* generate DL data block */ - msg = gprs_rlcmac_send_data_block_acknowledged(tbf, fn, - ts); - break; - } - } + if (!msg) + msg = sched_select_downlink(trx, ts, fn, block_nr, pdch); /* Prio 3: send dummy contol message */ - if (!msg) { - msg = msgb_alloc(23, "rlcmac_dl_idle"); - if (!msg) - return -ENOMEM; - memcpy(msgb_put(msg, 23), rlcmac_dl_idle, 23); - } + if (!msg) + msg = sched_dummy(); + + if (!msg) + return -ENOMEM; /* msg is now available */ /* set USF */ msg->data[0] = (msg->data[0] & 0xf8) | usf; -// printf("len=%d, date=%s\n", msg->len, osmo_hexdump(msg->data, msg->len)); - /* send PDTCH/PACCH to L1 */ pcu_l1if_tx_pdtch(msg, trx, ts, arfcn, fn, block_nr);