Adding single block allocation

It is mandatory to support it because MS may request a single block.
In this case the network must assign a single block.

It is possible to force single block allocation for all uplink requests
on RACH. (VTY option)
This commit is contained in:
Andreas Eversberg 2012-08-07 16:00:56 +02:00
parent cbcd124588
commit 07e97cf8a5
6 changed files with 344 additions and 90 deletions

View File

@ -879,6 +879,67 @@ void tbf_timer_stop(struct gprs_rlcmac_tbf *tbf)
}
}
/* starting time for assigning single slot
* This offset must be a multiple of 13. */
#define AGCH_START_OFFSET 52
LLIST_HEAD(gprs_rlcmac_sbas);
int sba_alloc(uint8_t *_trx, uint8_t *_ts, uint32_t *_fn, uint8_t ta)
{
struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
struct gprs_rlcmac_pdch *pdch;
struct gprs_rlcmac_sba *sba;
uint8_t trx, ts;
uint32_t fn;
sba = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_sba);
if (!sba)
return -ENOMEM;
for (trx = 0; trx < 8; trx++) {
for (ts = 0; ts < 8; ts++) {
pdch = &bts->trx[trx].pdch[ts];
if (!pdch->enable)
continue;
break;
}
if (ts < 8)
break;
}
if (trx == 8) {
LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH available.\n");
return -EINVAL;
}
fn = (pdch->last_rts_fn + AGCH_START_OFFSET) % 2715648;
sba->trx = trx;
sba->ts = ts;
sba->fn = fn;
sba->ta = ta;
llist_add(&sba->list, &gprs_rlcmac_sbas);
*_trx = trx;
*_ts = ts;
*_fn = fn;
return 0;
}
struct gprs_rlcmac_sba *sba_find(uint8_t trx, uint8_t ts, uint32_t fn)
{
struct gprs_rlcmac_sba *sba;
llist_for_each_entry(sba, &gprs_rlcmac_sbas, list) {
if (sba->trx == trx && sba->ts == ts && sba->fn == fn)
return sba;
}
return NULL;
}
#if 0
static void tbf_gsm_timer_cb(void *_tbf)
{
@ -1129,9 +1190,9 @@ struct msgb *gprs_rlcmac_send_packet_paging_request(
// GSM 04.08 9.1.18 Immediate assignment
int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra,
uint32_t fn, uint8_t ta, uint16_t arfcn, uint8_t ts, uint8_t tsc,
uint32_t ref_fn, uint8_t ta, uint16_t arfcn, uint8_t ts, uint8_t tsc,
uint8_t tfi, uint8_t usf, uint32_t tlli,
uint8_t polling, uint32_t poll_fn)
uint8_t polling, uint32_t fn, uint8_t single_block)
{
unsigned wp = 0;
uint8_t plen;
@ -1157,9 +1218,9 @@ int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra,
//10.5.2.30 Request Reference
bitvec_write_field(dest, wp,ra,8); // RA
bitvec_write_field(dest, wp,(fn / (26 * 51)) % 32,5); // T1'
bitvec_write_field(dest, wp,fn % 51,6); // T3
bitvec_write_field(dest, wp,fn % 26,5); // T2
bitvec_write_field(dest, wp,(ref_fn / (26 * 51)) % 32,5); // T1'
bitvec_write_field(dest, wp,ref_fn % 51,6); // T3
bitvec_write_field(dest, wp,ref_fn % 26,5); // T2
// 10.5.2.40 Timing Advance
bitvec_write_field(dest, wp,0x0,2); // spare
@ -1193,9 +1254,9 @@ int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra,
bitvec_write_field(dest, wp,0x0,4); // TIMING_ADVANCE_INDEX
if (polling) {
bitvec_write_field(dest, wp,0x1,1); // TBF Starting TIME present
bitvec_write_field(dest, wp,(poll_fn / (26 * 51)) % 32,5); // T1'
bitvec_write_field(dest, wp,poll_fn % 51,6); // T3
bitvec_write_field(dest, wp,poll_fn % 26,5); // T2
bitvec_write_field(dest, wp,(fn / (26 * 51)) % 32,5); // T1'
bitvec_write_field(dest, wp,fn % 51,6); // T3
bitvec_write_field(dest, wp,fn % 26,5); // T2
} else {
bitvec_write_field(dest, wp,0x0,1); // TBF Starting TIME present
}
@ -1209,20 +1270,32 @@ int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra,
// GMS 04.08 10.5.2.37b 10.5.2.16
bitvec_write_field(dest, wp, 3, 2); // "HH"
bitvec_write_field(dest, wp, 0, 2); // "0" Packet Uplink Assignment
bitvec_write_field(dest, wp, 1, 1); // Block Allocation : Not Single Block Allocation
bitvec_write_field(dest, wp, tfi, 5); // TFI_ASSIGNMENT Temporary Flow Identity
bitvec_write_field(dest, wp, 0, 1); // POLLING
bitvec_write_field(dest, wp, 0, 1); // ALLOCATION_TYPE: dynamic
bitvec_write_field(dest, wp, usf, 3); // USF
bitvec_write_field(dest, wp, 0, 1); // USF_GRANULARITY
bitvec_write_field(dest, wp, 0 , 1); // "0" power control: Not Present
bitvec_write_field(dest, wp, bts->initial_cs-1, 2); // CHANNEL_CODING_COMMAND
bitvec_write_field(dest, wp, 1, 1); // TLLI_BLOCK_CHANNEL_CODING
bitvec_write_field(dest, wp, 1 , 1); // "1" Alpha : Present
bitvec_write_field(dest, wp, 0, 4); // Alpha
bitvec_write_field(dest, wp, 0, 5); // Gamma
bitvec_write_field(dest, wp, 0, 1); // TIMING_ADVANCE_INDEX_FLAG
bitvec_write_field(dest, wp, 0, 1); // TBF_STARTING_TIME_FLAG
if (single_block) {
bitvec_write_field(dest, wp, 0, 1); // Block Allocation : Single Block Allocation
bitvec_write_field(dest, wp, 1, 1); // "1" Alpha : Present
bitvec_write_field(dest, wp, 0, 4); // Alpha
bitvec_write_field(dest, wp, 0, 5); // Gamma
bitvec_write_field(dest, wp, 0, 1); // TIMING_ADVANCE_INDEX_FLAG
bitvec_write_field(dest, wp, 1, 1); // TBF_STARTING_TIME_FLAG
bitvec_write_field(dest, wp,(fn / (26 * 51)) % 32,5); // T1'
bitvec_write_field(dest, wp,fn % 51,6); // T3
bitvec_write_field(dest, wp,fn % 26,5); // T2
} else {
bitvec_write_field(dest, wp, 1, 1); // Block Allocation : Not Single Block Allocation
bitvec_write_field(dest, wp, tfi, 5); // TFI_ASSIGNMENT Temporary Flow Identity
bitvec_write_field(dest, wp, 0, 1); // POLLING
bitvec_write_field(dest, wp, 0, 1); // ALLOCATION_TYPE: dynamic
bitvec_write_field(dest, wp, usf, 3); // USF
bitvec_write_field(dest, wp, 0, 1); // USF_GRANULARITY
bitvec_write_field(dest, wp, 0, 1); // "0" power control: Not Present
bitvec_write_field(dest, wp, bts->initial_cs-1, 2); // CHANNEL_CODING_COMMAND
bitvec_write_field(dest, wp, 1, 1); // TLLI_BLOCK_CHANNEL_CODING
bitvec_write_field(dest, wp, 1, 1); // "1" Alpha : Present
bitvec_write_field(dest, wp, 0, 4); // Alpha
bitvec_write_field(dest, wp, 0, 5); // Gamma
bitvec_write_field(dest, wp, 0, 1); // TIMING_ADVANCE_INDEX_FLAG
bitvec_write_field(dest, wp, 0, 1); // TBF_STARTING_TIME_FLAG
}
}
return plen;

View File

@ -79,6 +79,7 @@ struct gprs_rlcmac_bts {
int (*alloc_algorithm)(struct gprs_rlcmac_tbf *old_tbf,
struct gprs_rlcmac_tbf *tbf, uint32_t cust);
uint32_t alloc_algorithm_curst; /* options to customize algorithm */
uint8_t force_two_phase;
};
extern struct gprs_rlcmac_bts *gprs_rlcmac_bts;
@ -219,6 +220,7 @@ struct gprs_rlcmac_tbf {
extern struct llist_head gprs_rlcmac_ul_tbfs; /* list of uplink TBFs */
extern struct llist_head gprs_rlcmac_dl_tbfs; /* list of downlink TBFs */
extern struct llist_head gprs_rlcmac_sbas; /* list of single block allocs */
/*
* paging entry
@ -229,6 +231,21 @@ struct gprs_rlcmac_paging {
uint8_t identity_lv[9];
};
/*
* single block allocation entry
*/
struct gprs_rlcmac_sba {
struct llist_head list;
uint8_t trx;
uint8_t ts;
uint32_t fn;
uint8_t ta;
};
int sba_alloc(uint8_t *_trx, uint8_t *_ts, uint32_t *_fn, uint8_t ta);
struct gprs_rlcmac_sba *sba_find(uint8_t trx, uint8_t ts, uint32_t fn);
int tfi_alloc(enum gprs_rlcmac_tbf_direction dir, uint8_t *_trx, uint8_t *_ts,
int8_t use_trx, int8_t first_ts);
@ -270,9 +287,9 @@ int gprs_rlcmac_rcv_block(uint8_t trx, uint8_t ts, uint8_t *data, uint8_t len,
uint32_t fn);
int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra,
uint32_t fn, uint8_t ta, uint16_t arfcn, uint8_t ts, uint8_t tsc,
uint32_t ref_fn, uint8_t ta, uint16_t arfcn, uint8_t ts, uint8_t tsc,
uint8_t tfi, uint8_t usf, uint32_t tlli, uint8_t polling,
uint32_t poll_fn);
uint32_t fn, uint8_t single_block);
void write_packet_uplink_assignment(bitvec * dest, uint8_t old_tfi,
uint8_t old_downlink, uint32_t tlli, uint8_t use_tlli,

View File

@ -185,11 +185,61 @@ int gprs_rlcmac_poll_timeout(struct gprs_rlcmac_tbf *tbf)
return 0;
}
static uint8_t get_ms_class_by_capability(MS_Radio_Access_capability_t *cap)
{
int i;
for (i = 0; i < cap->Count_MS_RA_capability_value; i++) {
if (!cap->MS_RA_capability_value[i].u.Content.Exist_Multislot_capability)
continue;
if (!cap->MS_RA_capability_value[i].u.Content.Multislot_capability.Exist_GPRS_multislot_class)
continue;
return cap->MS_RA_capability_value[i].u.Content.Multislot_capability.GPRS_multislot_class;
}
return 0;
}
static struct gprs_rlcmac_tbf *alloc_ul_tbf(int8_t use_trx, int8_t first_ts,
uint8_t ms_class, uint32_t tlli, uint8_t ta,
struct gprs_rlcmac_tbf *dl_tbf)
{
struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
uint8_t trx, ts;
struct gprs_rlcmac_tbf *tbf;
uint8_t tfi;
/* create new TBF, use sme TRX as DL TBF */
tfi = tfi_alloc(GPRS_RLCMAC_UL_TBF, &trx, &ts, use_trx, first_ts);
if (tfi < 0) {
LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
/* FIXME: send reject */
return NULL;
}
/* use multislot class of downlink TBF */
tbf = tbf_alloc(dl_tbf, GPRS_RLCMAC_UL_TBF, tfi, trx, ts, ms_class, 0);
if (!tbf) {
LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
/* FIXME: send reject */
return NULL;
}
tbf->tlli = tlli;
tbf->tlli_valid = 1; /* no contention resolution */
tbf->dir.ul.contention_resolution_done = 1;
tbf->ta = ta; /* use current TA */
tbf_new_state(tbf, GPRS_RLCMAC_ASSIGN);
tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_PACCH);
tbf_timer_start(tbf, 3169, bts->t3169, 0);
return tbf;
}
/* Received Uplink RLC control block. */
int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts,
uint32_t fn)
{
struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
int8_t tfi = 0; /* must be signed */
uint32_t tlli = 0;
struct gprs_rlcmac_tbf *tbf;
@ -318,34 +368,10 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts,
}
/* check for channel request */
if (ul_control_block->u.Packet_Downlink_Ack_Nack.Exist_Channel_Request_Description) {
uint8_t trx, ts;
struct gprs_rlcmac_tbf *ul_tbf;
LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF in ack "
"message, so we provide one:\n");
uplink_request:
/* create new TBF, use sme TRX as DL TBF */
tfi = tfi_alloc(GPRS_RLCMAC_UL_TBF, &trx, &ts, tbf->trx, tbf->first_ts);
if (tfi < 0) {
LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
/* FIXME: send reject */
break;
}
/* use multislot class of downlink TBF */
ul_tbf = tbf_alloc(tbf, GPRS_RLCMAC_UL_TBF, tfi, trx,
ts, tbf->ms_class, 0);
if (!ul_tbf) {
LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
/* FIXME: send reject */
break;
}
ul_tbf->tlli = tbf->tlli;
ul_tbf->tlli_valid = 1; /* no contention resolution */
ul_tbf->dir.ul.contention_resolution_done = 1;
ul_tbf->ta = tbf->ta; /* use current TA */
tbf_new_state(ul_tbf, GPRS_RLCMAC_ASSIGN);
ul_tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_PACCH);
tbf_timer_start(ul_tbf, 3169, bts->t3169, 0);
alloc_ul_tbf(tbf->trx, tbf->first_ts, tbf->ms_class, tbf->tlli, tbf->ta, tbf);
/* schedule uplink assignment */
tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS;
}
@ -355,7 +381,23 @@ uplink_request:
tlli = ul_control_block->u.Packet_Resource_Request.ID.u.TLLI;
tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_UL_TBF);
if (!tbf) {
LOGP(DRLCMAC, LOGL_NOTICE, "PACKET RESSOURCE REQ unknown uplink TLLI=0x%08x\n", tlli);
uint8_t ms_class = 0;
LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF "
"in packet ressource request of single "
"block, so we provide one:\n");
if (ul_control_block->u.Packet_Resource_Request.Exist_MS_Radio_Access_capability)
ms_class = get_ms_class_by_capability(&ul_control_block->u.Packet_Resource_Request.MS_Radio_Access_capability);
if (!ms_class)
LOGP(DRLCMAC, LOGL_NOTICE, "MS does not give us a class.\n");
tbf = alloc_ul_tbf(trx, ts, ms_class, tlli, 0, NULL);
#warning FIXME TA!!!
if (!tbf)
break;
/* set control ts to current MS's TS, until assignment complete */
LOGP(DRLCMAC, LOGL_DEBUG, "Change control TS to %d until assinment is complete.\n", ts);
tbf->control_ts = ts;
/* schedule uplink assignment */
tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS;
break;
}
tfi = tbf->tfi;
@ -658,11 +700,18 @@ struct msgb *gprs_rlcmac_send_uplink_ack(struct gprs_rlcmac_tbf *tbf,
int final = (tbf->state == GPRS_RLCMAC_FINISHED);
struct msgb *msg;
if (final && tbf->poll_state != GPRS_RLCMAC_POLL_NONE) {
LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already "
"sheduled for TBF=%d, so we must wait for final uplink "
"ack...\n", tbf->tfi);
if (final) {
if (tbf->poll_state != GPRS_RLCMAC_POLL_NONE) {
LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already "
"sheduled for TBF=%d, so we must wait for "
"final uplink ack...\n", tbf->tfi);
return NULL;
}
if (sba_find(tbf->trx, tbf->control_ts, (fn + 13) % 2715648)) {
LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already "
"scheduled for single block allocation...\n");
return NULL;
}
}
msg = msgb_alloc(23, "rlcmac_ul_ack");
@ -907,6 +956,11 @@ struct msgb *gprs_rlcmac_send_packet_uplink_assignment(
"assignment...\n", tbf->tfi);
return NULL;
}
if (sba_find(tbf->trx, tbf->control_ts, (fn + 13) % 2715648)) {
LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already scheduled for "
"single block allocation...\n");
return NULL;
}
#endif
/* on down TBF we get the uplink TBF to be assigned. */
@ -935,8 +989,8 @@ struct msgb *gprs_rlcmac_send_packet_uplink_assignment(
bitvec_unhex(ass_vec,
"2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
write_packet_uplink_assignment(ass_vec, tbf->tfi,
(tbf->direction == GPRS_RLCMAC_DL_TBF), 0, 0, new_tbf,
POLLING_ASSIGNMENT_UL);
(tbf->direction == GPRS_RLCMAC_DL_TBF), tbf->tlli,
tbf->tlli_valid, new_tbf, POLLING_ASSIGNMENT_UL);
bitvec_pack(ass_vec, msgb_put(msg, 23));
RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t);
LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++\n");
@ -965,37 +1019,73 @@ int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta)
struct gprs_rlcmac_tbf *tbf;
uint8_t trx, ts;
int8_t tfi; /* must be signed */
uint8_t sb = 0;
uint32_t sb_fn = 0;
int rc;
uint8_t plen;
LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF on RACH, so we provide "
"one:\n");
// Create new TBF
tfi = tfi_alloc(GPRS_RLCMAC_UL_TBF, &trx, &ts, -1, -1);
if (tfi < 0) {
LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
/* FIXME: send reject */
return -EBUSY;
}
/* set class to 0, since we don't know the multislot class yet */
tbf = tbf_alloc(NULL, GPRS_RLCMAC_UL_TBF, tfi, trx, ts, 0, 1);
if (!tbf) {
LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
/* FIXME: send reject */
return -EBUSY;
if ((ra & 0xf8) == 0x70) {
LOGP(DRLCMAC, LOGL_DEBUG, "MS requests single block "
"allocation\n");
sb = 1;
} else if (bts->force_two_phase) {
LOGP(DRLCMAC, LOGL_DEBUG, "MS requests single phase access, "
"but we force two phase access\n");
sb = 1;
}
if (qta < 0)
qta = 0;
if (qta > 252)
qta = 252;
tbf->ta = qta >> 2;
tbf_new_state(tbf, GPRS_RLCMAC_FLOW);
tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_CCCH);
tbf_timer_start(tbf, 3169, bts->t3169, 0);
LOGP(DRLCMAC, LOGL_DEBUG, "TBF: [UPLINK] START TFI: %u\n", tbf->tfi);
LOGP(DRLCMAC, LOGL_DEBUG, "RX: [PCU <- BTS] TFI: %u RACH qbit-ta=%d ra=%d, Fn=%d (%d,%d,%d)\n", tbf->tfi, qta, ra, Fn, (Fn / (26 * 51)) % 32, Fn % 51, Fn % 26);
LOGP(DRLCMAC, LOGL_INFO, "TX: START TFI: %u Immediate Assignment Uplink (AGCH)\n", tbf->tfi);
if (sb) {
rc = sba_alloc(&trx, &ts, &sb_fn, qta >> 2);
if (rc < 0)
return rc;
LOGP(DRLCMAC, LOGL_DEBUG, "RX: [PCU <- BTS] RACH qbit-ta=%d "
"ra=0x%02x, Fn=%d (%d,%d,%d)\n", qta, ra, Fn,
(Fn / (26 * 51)) % 32, Fn % 51, Fn % 26);
LOGP(DRLCMAC, LOGL_INFO, "TX: Immediate Assignment Uplink "
"(AGCH)\n");
} else {
// Create new TBF
tfi = tfi_alloc(GPRS_RLCMAC_UL_TBF, &trx, &ts, -1, -1);
if (tfi < 0) {
LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
/* FIXME: send reject */
return -EBUSY;
}
/* set class to 0, since we don't know the multislot class yet */
tbf = tbf_alloc(NULL, GPRS_RLCMAC_UL_TBF, tfi, trx, ts, 0, 1);
if (!tbf) {
LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
/* FIXME: send reject */
return -EBUSY;
}
tbf->ta = qta >> 2;
tbf_new_state(tbf, GPRS_RLCMAC_FLOW);
tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_CCCH);
tbf_timer_start(tbf, 3169, bts->t3169, 0);
LOGP(DRLCMAC, LOGL_DEBUG, "TBF: [UPLINK] START TFI: %u\n",
tbf->tfi);
LOGP(DRLCMAC, LOGL_DEBUG, "RX: [PCU <- BTS] TFI: %u RACH "
"qbit-ta=%d ra=0x%02x, Fn=%d (%d,%d,%d)\n", tbf->tfi,
qta, ra, Fn, (Fn / (26 * 51)) % 32, Fn % 51, Fn % 26);
LOGP(DRLCMAC, LOGL_INFO, "TX: START TFI: %u Immediate "
"Assignment Uplink (AGCH)\n", tbf->tfi);
}
bitvec *immediate_assignment = bitvec_alloc(22) /* without plen */;
bitvec_unhex(immediate_assignment, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
int plen = write_immediate_assignment(immediate_assignment, 0, ra, Fn, tbf->ta, tbf->arfcn, tbf->first_ts, tbf->tsc, tbf->tfi, tbf->dir.ul.usf[tbf->first_ts], 0, 0, 0);
bitvec_unhex(immediate_assignment,
"2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
if (sb)
plen = write_immediate_assignment(immediate_assignment, 0, ra,
Fn, qta >> 2, bts->trx[trx].arfcn, ts,
bts->trx[trx].pdch[ts].tsc, 0, 0, 0, 0, sb_fn, 1);
else
plen = write_immediate_assignment(immediate_assignment, 0, ra,
Fn, tbf->ta, tbf->arfcn, tbf->first_ts, tbf->tsc,
tbf->tfi, tbf->dir.ul.usf[tbf->first_ts], 0, 0, 0, 0);
pcu_l1if_tx_agch(immediate_assignment, plen);
bitvec_free(immediate_assignment);
@ -1355,6 +1445,10 @@ tx_block:
LOGP(DRLCMAC, LOGL_DEBUG, "Polling cannot be "
"sheduled in this TS %d, waiting for "
"TS %d\n", ts, tbf->control_ts);
else if (sba_find(tbf->trx, ts, (fn + 13) % 2715648))
LOGP(DRLCMAC, LOGL_DEBUG, "Polling cannot be "
"sheduled, because single block alllocation "
"already exists\n");
else {
LOGP(DRLCMAC, LOGL_DEBUG, "Polling sheduled in this "
"TS %d\n", ts);
@ -1534,6 +1628,11 @@ struct msgb *gprs_rlcmac_send_packet_downlink_assignment(
"assignment...\n", tbf->tfi);
return NULL;
}
if (sba_find(tbf->trx, tbf->control_ts, (fn + 13) % 2715648)) {
LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already "
"scheduled for single block allocation...\n");
return NULL;
}
}
/* on uplink TBF we get the downlink TBF to be assigned. */
@ -1604,7 +1703,7 @@ static void gprs_rlcmac_downlink_assignment(gprs_rlcmac_tbf *tbf, uint8_t poll,
bitvec_unhex(immediate_assignment, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
/* use request reference that has maximum distance to current time,
* so the assignment will not conflict with possible RACH requests. */
int plen = write_immediate_assignment(immediate_assignment, 1, 125, (tbf->pdch[tbf->first_ts]->last_rts_fn + 21216) % 2715648, tbf->ta, tbf->arfcn, tbf->first_ts, tbf->tsc, tbf->tfi, 0, tbf->tlli, poll, tbf->poll_fn);
int plen = write_immediate_assignment(immediate_assignment, 1, 125, (tbf->pdch[tbf->first_ts]->last_rts_fn + 21216) % 2715648, tbf->ta, tbf->arfcn, tbf->first_ts, tbf->tsc, tbf->tfi, 0, tbf->tlli, poll, tbf->poll_fn, 0);
pcu_l1if_tx_pch(immediate_assignment, plen, imsi);
bitvec_free(immediate_assignment);
}

View File

@ -67,6 +67,26 @@ uint32_t sched_poll(uint8_t trx, uint8_t ts, uint32_t fn, uint8_t block_nr,
return poll_fn;
}
uint32_t sched_sba(uint8_t trx, uint8_t ts, uint32_t fn, uint8_t block_nr)
{
uint32_t sba_fn;
struct gprs_rlcmac_sba *sba;
/* check special TBF for events */
sba_fn = fn + 4;
if ((block_nr % 3) == 2)
sba_fn ++;
sba_fn = sba_fn % 2715648;
sba = sba_find(trx, ts, sba_fn);
if (sba) {
llist_del(&sba->list);
talloc_free(sba);
return sba_fn;
}
return 0xffffffff;
}
uint8_t sched_select_uplink(uint8_t trx, uint8_t ts, uint32_t fn,
uint8_t block_nr, struct gprs_rlcmac_pdch *pdch)
{
@ -135,14 +155,15 @@ struct msgb *sched_select_ctrl_msg(uint8_t trx, uint8_t ts, uint32_t fn,
return msg;
}
/* schedule PACKET PAGING REQUEST */
if (llist_empty(&pdch->paging_list))
return NULL;
msg = gprs_rlcmac_send_packet_paging_request(pdch);
if (msg)
if (!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);
return msg;
}
return msg;
return NULL;
}
struct msgb *sched_select_downlink(uint8_t trx, uint8_t ts, uint32_t fn,
@ -208,7 +229,7 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn,
*ul_ass_tbf = NULL, *ul_ack_tbf = NULL;
uint8_t usf = 0x7;
struct msgb *msg = NULL;
uint32_t poll_fn;
uint32_t poll_fn, sba_fn;
if (trx >= 8 || ts >= 8)
return -EINVAL;
@ -234,6 +255,13 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn,
(poll_tbf->direction == GPRS_RLCMAC_UL_TBF)
? "UL" : "DL", poll_tbf->tfi);
/* use free USF */
/* else. check for sba */
else if ((sba_fn = sched_sba(trx, ts, fn, block_nr) != 0xffffffff))
LOGP(DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: TRX=%d "
"TS=%d FN=%d block_nr=%d scheduling free USF for "
"single block allocation at FN=%d\n", trx, ts, fn,
block_nr, sba_fn);
/* use free USF */
/* else, we search for uplink ressource */
else
usf = sched_select_uplink(trx, ts, fn, block_nr, pdch);

View File

@ -247,11 +247,12 @@ static int pcu_rx_rach_ind(struct gsm_pcu_if_rach_ind *rach_ind)
return rc;
}
int flush_pdch(struct gprs_rlcmac_pdch *pdch)
int flush_pdch(struct gprs_rlcmac_pdch *pdch, uint8_t trx, uint8_t ts)
{
uint8_t tfi;
struct gprs_rlcmac_tbf *tbf;
struct gprs_rlcmac_paging *pag;
struct gprs_rlcmac_sba *sba, *sba2;
/* kick all TBF on slot */
for (tfi = 0; tfi < 32; tfi++) {
@ -266,6 +267,13 @@ int flush_pdch(struct gprs_rlcmac_pdch *pdch)
while ((pag = gprs_rlcmac_dequeue_paging(pdch)))
talloc_free(pag);
llist_for_each_entry_safe(sba, sba2, &gprs_rlcmac_sbas, list) {
if (sba->trx == trx && sba->ts == ts) {
llist_del(&sba->list);
talloc_free(sba);
}
}
return 0;
}
@ -294,7 +302,8 @@ bssgp_failed:
bts->trx[trx].arfcn = info_ind->trx[trx].arfcn;
for (ts = 0; ts < 8; ts++) {
if (bts->trx[trx].pdch[ts].enable)
flush_pdch(&bts->trx[trx].pdch[ts]);
flush_pdch(&bts->trx[trx].pdch[ts],
trx, ts);
}
}
gprs_bssgp_destroy();
@ -399,7 +408,7 @@ bssgp_failed:
if (pdch->enable) {
pcu_tx_act_req(trx, ts, 0);
pdch->enable = 0;
flush_pdch(pdch);
flush_pdch(pdch, trx, ts);
}
}
}

View File

@ -90,6 +90,8 @@ static int config_write_pcu(struct vty *vty)
vty_out(vty, " alloc-algorithm a%s", VTY_NEWLINE);
if (bts->alloc_algorithm == alloc_algorithm_b)
vty_out(vty, " alloc-algorithm b%s", VTY_NEWLINE);
if (bts->force_two_phase)
vty_out(vty, " two-phase-access%s", VTY_NEWLINE);
}
@ -193,6 +195,30 @@ DEFUN(cfg_pcu_alloc,
return CMD_SUCCESS;
}
DEFUN(cfg_pcu_two_phase,
cfg_pcu_two_phase_cmd,
"two-phase-access",
"Force two phase access when MS requests single phase access\n")
{
struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
bts->force_two_phase = 1;
return CMD_SUCCESS;
}
DEFUN(cfg_pcu_no_two_phase,
cfg_pcu_no_two_phase_cmd,
"no two-phase-access",
NO_STR "Only use two phase access when requested my MS\n")
{
struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
bts->force_two_phase = 0;
return CMD_SUCCESS;
}
static const char pcu_copyright[] =
"Copyright (C) 2012 by ...\r\n"
"License GNU GPL version 2 or later\r\n"
@ -222,6 +248,8 @@ int pcu_vty_init(const struct log_info *cat)
install_element(PCU_NODE, &cfg_pcu_queue_lifetime_inf_cmd);
install_element(PCU_NODE, &cfg_pcu_no_queue_lifetime_cmd);
install_element(PCU_NODE, &cfg_pcu_alloc_cmd);
install_element(PCU_NODE, &cfg_pcu_two_phase_cmd);
install_element(PCU_NODE, &cfg_pcu_no_two_phase_cmd);
install_element(PCU_NODE, &ournode_end_cmd);
return 0;