blob: 29749b8e9a2366322a690ed027552b0a08ce8baa [file] [log] [blame]
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +02001/* gprs_rlcmac.cpp
2 *
3 * Copyright (C) 2012 Ivan Klyuchnikov
4 * Copyright (C) 2012 Andreas Eversberg <jolly@eversberg.eu>
5 * Copyright (C) 2013 by Holger Hans Peter Freyther
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21
22#include <gprs_rlcmac.h>
23#include <gprs_debug.h>
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +020024#include <bts.h>
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +020025#include <tbf.h>
Jacob Erlbecke2e004e2015-06-18 17:16:26 +020026#include <gprs_ms.h>
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +020027
28#include <errno.h>
29
30/* 3GPP TS 05.02 Annex B.1 */
31
32#define MS_NA 255 /* N/A */
33#define MS_A 254 /* 1 with hopping, 0 without */
34#define MS_B 253 /* 1 with hopping, 0 without (change Rx to Tx)*/
35#define MS_C 252 /* 1 with hopping, 0 without (change Tx to Rx)*/
36
37struct gprs_ms_multislot_class {
38 uint8_t rx, tx, sum; /* Maximum Number of Slots: RX, Tx, Sum Rx+Tx */
39 uint8_t ta, tb, ra, rb; /* Minimum Number of Slots */
40 uint8_t type; /* Type of Mobile */
41};
42
43static const struct gprs_ms_multislot_class gprs_ms_multislot_class[32] = {
44/* M-S Class Rx Tx Sum Tta Ttb Tra Trb Type */
45/* N/A */ { MS_NA,MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA },
46/* 1 */ { 1, 1, 2, 3, 2, 4, 2, 1 },
47/* 2 */ { 2, 1, 3, 3, 2, 3, 1, 1 },
48/* 3 */ { 2, 2, 3, 3, 2, 3, 1, 1 },
49/* 4 */ { 3, 1, 4, 3, 1, 3, 1, 1 },
50/* 5 */ { 2, 2, 4, 3, 1, 3, 1, 1 },
51/* 6 */ { 3, 2, 4, 3, 1, 3, 1, 1 },
52/* 7 */ { 3, 3, 4, 3, 1, 3, 1, 1 },
53/* 8 */ { 4, 1, 5, 3, 1, 2, 1, 1 },
54/* 9 */ { 3, 2, 5, 3, 1, 2, 1, 1 },
55/* 10 */ { 4, 2, 5, 3, 1, 2, 1, 1 },
56/* 11 */ { 4, 3, 5, 3, 1, 2, 1, 1 },
57/* 12 */ { 4, 4, 5, 2, 1, 2, 1, 1 },
58/* 13 */ { 3, 3, MS_NA, MS_NA, MS_A, 3, MS_A, 2 },
59/* 14 */ { 4, 4, MS_NA, MS_NA, MS_A, 3, MS_A, 2 },
60/* 15 */ { 5, 5, MS_NA, MS_NA, MS_A, 3, MS_A, 2 },
61/* 16 */ { 6, 6, MS_NA, MS_NA, MS_A, 2, MS_A, 2 },
62/* 17 */ { 7, 7, MS_NA, MS_NA, MS_A, 1, 0, 2 },
63/* 18 */ { 8, 8, MS_NA, MS_NA, 0, 0, 0, 2 },
64/* 19 */ { 6, 2, MS_NA, 3, MS_B, 2, MS_C, 1 },
65/* 20 */ { 6, 3, MS_NA, 3, MS_B, 2, MS_C, 1 },
66/* 21 */ { 6, 4, MS_NA, 3, MS_B, 2, MS_C, 1 },
67/* 22 */ { 6, 4, MS_NA, 2, MS_B, 2, MS_C, 1 },
68/* 23 */ { 6, 6, MS_NA, 2, MS_B, 2, MS_C, 1 },
69/* 24 */ { 8, 2, MS_NA, 3, MS_B, 2, MS_C, 1 },
70/* 25 */ { 8, 3, MS_NA, 3, MS_B, 2, MS_C, 1 },
71/* 26 */ { 8, 4, MS_NA, 3, MS_B, 2, MS_C, 1 },
72/* 27 */ { 8, 4, MS_NA, 2, MS_B, 2, MS_C, 1 },
73/* 28 */ { 8, 6, MS_NA, 2, MS_B, 2, MS_C, 1 },
74/* 29 */ { 8, 8, MS_NA, 2, MS_B, 2, MS_C, 1 },
75/* N/A */ { MS_NA,MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA },
76/* N/A */ { MS_NA,MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA },
77};
78
Holger Hans Peter Freyther6796ed22013-10-20 16:45:10 +020079static inline int8_t find_free_usf(struct gprs_rlcmac_pdch *pdch)
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +020080{
Daniel Willmanncd44ec42014-08-07 15:04:57 +020081 struct gprs_rlcmac_ul_tbf *tbf;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +020082 uint8_t usf_map = 0;
83 uint8_t tfi, usf;
84
85 /* make map of used USF */
86 for (tfi = 0; tfi < 32; tfi++) {
Daniel Willmann17a1d5e2014-05-30 20:21:30 +020087 tbf = pdch->ul_tbf_by_tfi(tfi);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +020088 if (!tbf)
89 continue;
Daniel Willmann7e994e32014-08-07 15:49:21 +020090 usf_map |= (1 << tbf->m_usf[pdch->ts_no]);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +020091 }
92
93 /* look for USF, don't use USF=7 */
94 for (usf = 0; usf < 7; usf++) {
95 if (!(usf_map & (1 << usf)))
96 return usf;
97 }
98
99 return -1;
100}
101
Holger Hans Peter Freytherb0a00752013-09-29 08:18:17 +0200102static int find_enabled_pdch(struct gprs_rlcmac_trx *trx, const uint8_t start_ts)
103{
104 int ts;
105 for (ts = start_ts; ts < 8; ts++) {
106 struct gprs_rlcmac_pdch *pdch;
107
108 pdch = &trx->pdch[ts];
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +0200109 if (!pdch->is_enabled()) {
Holger Hans Peter Freytherb0a00752013-09-29 08:18:17 +0200110 LOGP(DRLCMAC, LOGL_DEBUG, "- Skipping TS %d, because "
111 "not enabled\n", ts);
112 continue;
113 }
114 return ts;
115 }
116
117 return 8;
118}
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200119
Jacob Erlbeckccc34e42015-06-29 13:45:05 +0200120static void attach_tbf_to_pdch(struct gprs_rlcmac_pdch *pdch,
121 struct gprs_rlcmac_tbf *tbf)
122{
123 if (tbf->pdch[pdch->ts_no])
124 tbf->pdch[pdch->ts_no]->detach_tbf(tbf);
125
126 tbf->pdch[pdch->ts_no] = pdch;
127 pdch->attach_tbf(tbf);
128}
129
Holger Hans Peter Freyther743bafa2013-09-29 07:50:50 +0200130static void assign_uplink_tbf_usf(
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200131 struct gprs_rlcmac_pdch *pdch,
Daniel Willmanncd44ec42014-08-07 15:04:57 +0200132 struct gprs_rlcmac_ul_tbf *tbf, int8_t usf)
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200133{
Holger Hans Peter Freyther34f6e5e2013-10-27 20:31:47 +0100134 tbf->trx->ul_tbf[tbf->tfi()] = tbf;
Daniel Willmann7e994e32014-08-07 15:49:21 +0200135 tbf->m_usf[pdch->ts_no] = usf;
Jacob Erlbeckccc34e42015-06-29 13:45:05 +0200136 attach_tbf_to_pdch(pdch, tbf);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200137}
138
Holger Hans Peter Freyther8481a052013-09-29 08:08:28 +0200139static void assign_dlink_tbf(
140 struct gprs_rlcmac_pdch *pdch,
Daniel Willmanncd44ec42014-08-07 15:04:57 +0200141 struct gprs_rlcmac_dl_tbf *tbf)
Holger Hans Peter Freyther8481a052013-09-29 08:08:28 +0200142{
Holger Hans Peter Freyther34f6e5e2013-10-27 20:31:47 +0100143 tbf->trx->dl_tbf[tbf->tfi()] = tbf;
Jacob Erlbeckccc34e42015-06-29 13:45:05 +0200144 attach_tbf_to_pdch(pdch, tbf);
Holger Hans Peter Freyther8481a052013-09-29 08:08:28 +0200145}
146
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200147
148/* Slot Allocation: Algorithm A
149 *
150 * Assign single slot for uplink and downlink
151 */
152int alloc_algorithm_a(struct gprs_rlcmac_bts *bts,
Jacob Erlbecke2e004e2015-06-18 17:16:26 +0200153 GprsMs *ms,
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200154 struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single)
155{
156 struct gprs_rlcmac_pdch *pdch;
157 uint8_t ts;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200158
159 LOGP(DRLCMAC, LOGL_DEBUG, "Slot Allocation (Algorithm A) for class "
Jacob Erlbeckbefc7602015-06-02 12:33:30 +0200160 "%d\n", tbf->ms_class());
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200161
Holger Hans Peter Freytherb0a00752013-09-29 08:18:17 +0200162 ts = find_enabled_pdch(tbf->trx, 0);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200163 if (ts == 8)
164 return -EINVAL;
165
Holger Hans Peter Freytherb0a00752013-09-29 08:18:17 +0200166 pdch = &tbf->trx->pdch[ts];
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200167 if (tbf->direction == GPRS_RLCMAC_UL_TBF) {
Holger Hans Peter Freyther948a3d62013-09-30 14:10:23 +0200168 int8_t usf; /* must be signed */
Daniel Willmanncd44ec42014-08-07 15:04:57 +0200169 struct gprs_rlcmac_ul_tbf *ul_tbf = static_cast<gprs_rlcmac_ul_tbf *>(tbf);
Holger Hans Peter Freyther948a3d62013-09-30 14:10:23 +0200170
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200171 /* if USF available */
Holger Hans Peter Freyther6796ed22013-10-20 16:45:10 +0200172 usf = find_free_usf(pdch);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200173 if (usf < 0) {
174 LOGP(DRLCMAC, LOGL_NOTICE, "- Failed "
175 "allocating TS=%d, no USF available\n", ts);
176 return -EBUSY;
177 }
178 LOGP(DRLCMAC, LOGL_DEBUG, "- Assign uplink "
179 "TS=%d USF=%d\n", ts, usf);
Daniel Willmanncd44ec42014-08-07 15:04:57 +0200180 assign_uplink_tbf_usf(pdch, ul_tbf, usf);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200181 } else {
Daniel Willmanncd44ec42014-08-07 15:04:57 +0200182 struct gprs_rlcmac_dl_tbf *dl_tbf = static_cast<gprs_rlcmac_dl_tbf *>(tbf);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200183 LOGP(DRLCMAC, LOGL_DEBUG, "- Assign downlink TS=%d\n", ts);
Daniel Willmanncd44ec42014-08-07 15:04:57 +0200184 assign_dlink_tbf(pdch, dl_tbf);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200185 }
186 /* the only one TS is the common TS */
187 tbf->first_ts = tbf->first_common_ts = ts;
188
Daniel Willmanncf1fae72014-05-30 17:58:01 +0200189 tbf->upgrade_to_multislot = 0;
190
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200191 return 0;
192}
193
Holger Hans Peter Freyther882fc9b2013-12-25 20:34:26 +0100194/*
195 * Select a window of Rx slots if available.
196 * The maximum allowed slots depend on RX or the window of available
197 * slots. This must be done for uplink TBF also, because it is the basis
198 * for calculating control slot and uplink slot(s).
199 */
200static uint8_t select_dl_slots(struct gprs_rlcmac_trx *trx,
201 const int ms_type, const int ms_max_rxslots,
202 uint8_t *out_rx_win_min, uint8_t *out_rx_win_max)
203
204{
205 uint8_t rx_window = 0;
206 int rx_window_size = 0;
207 int8_t last_tsc = -1; /* must be signed */
208 uint8_t rx_win_min = 0, rx_win_max = 0;
209
210 for (int ts_no = 0; ts_no < 8; ts_no++) {
211 struct gprs_rlcmac_pdch *pdch;
212 pdch = &trx->pdch[ts_no];
213
214 /* check if enabled */
215 if (!pdch->is_enabled()) {
216 LOGP(DRLCMAC, LOGL_DEBUG, "- Skipping TS %d, because "
217 "not enabled\n", ts_no);
218 if (ms_type == 1 && rx_window)
Andreas Eversbergb03d4272014-01-04 15:14:19 +0100219 goto inc_window;
Holger Hans Peter Freyther882fc9b2013-12-25 20:34:26 +0100220 continue;
221 }
222 /* check if TSC changes */
223 if (last_tsc < 0)
224 last_tsc = pdch->tsc;
225 else if (last_tsc != pdch->tsc) {
226 LOGP(DRLCMAC, LOGL_ERROR, "Skipping TS %d of TRX=%d, "
227 "because it has different TSC than lower TS "
228 "of TRX. In order to allow multislot, all "
229 "slots must be configured with the same "
230 "TSC!\n", ts_no, trx->trx_no);
231 if (ms_type == 1 && rx_window)
Andreas Eversbergb03d4272014-01-04 15:14:19 +0100232 goto inc_window;
Holger Hans Peter Freyther882fc9b2013-12-25 20:34:26 +0100233 continue;
234 }
235
236 if (!rx_window)
237 rx_win_min = ts_no;
238
239 rx_window |= (1 << ts_no);
240 LOGP(DRLCMAC, LOGL_DEBUG, "- Selected DL TS %d\n", ts_no);
241
242 /* range of window (required for Type 1) */
243 rx_win_max = ts_no;
244
Andreas Eversbergb03d4272014-01-04 15:14:19 +0100245inc_window:
Holger Hans Peter Freyther882fc9b2013-12-25 20:34:26 +0100246 if (++rx_window_size == ms_max_rxslots) {
247 LOGP(DRLCMAC, LOGL_DEBUG, "- Done, because slots / "
248 "window reached maximum alowed Rx size\n");
249 break;
250 }
Andreas Eversbergccde4c42014-01-04 15:17:22 +0100251 if (ms_type == 1 && rx_window_size == 5) {
252 LOGP(DRLCMAC, LOGL_DEBUG, "- Done, because slots / "
253 "window reached maximum supported Rx size of "
254 "this algorithm\n");
255 break;
256 }
Holger Hans Peter Freyther882fc9b2013-12-25 20:34:26 +0100257 }
258
259 LOGP(DRLCMAC, LOGL_DEBUG, "- Selected slots for RX: "
260 "(TS=0)\"%c%c%c%c%c%c%c%c\"(TS=7)\n",
261 ((rx_window & 0x01)) ? 'D' : '.',
262 ((rx_window & 0x02)) ? 'D' : '.',
263 ((rx_window & 0x04)) ? 'D' : '.',
264 ((rx_window & 0x08)) ? 'D' : '.',
265 ((rx_window & 0x10)) ? 'D' : '.',
266 ((rx_window & 0x20)) ? 'D' : '.',
267 ((rx_window & 0x40)) ? 'D' : '.',
268 ((rx_window & 0x80)) ? 'D' : '.');
269
270 *out_rx_win_min = rx_win_min;
271 *out_rx_win_max = rx_win_max;
272 return rx_window;
273}
274
Jacob Erlbecke2e004e2015-06-18 17:16:26 +0200275static int reduce_rx_window(const int ms_type, const GprsMs *ms,
Holger Hans Peter Freythere45c19b2013-12-25 20:53:53 +0100276 const int Tt, const int Tr,
277 int *rx_window,
278 uint8_t *rx_win_min, uint8_t *rx_win_max)
279{
Jacob Erlbecke2e004e2015-06-18 17:16:26 +0200280 gprs_rlcmac_ul_tbf *ul_tbf;
281
Holger Hans Peter Freythere45c19b2013-12-25 20:53:53 +0100282 if (ms_type != 1)
283 return 0;
Jacob Erlbecke2e004e2015-06-18 17:16:26 +0200284 if (!ms)
Holger Hans Peter Freythere45c19b2013-12-25 20:53:53 +0100285 return 0;
Jacob Erlbecke2e004e2015-06-18 17:16:26 +0200286
287 ul_tbf = ms->ul_tbf();
288
289 if (!ul_tbf)
Holger Hans Peter Freythere45c19b2013-12-25 20:53:53 +0100290 return 0;
291
292 uint8_t collide = 0, ul_usage = 0;
293
294 /* calculate mask of colliding slots */
295 for (uint8_t ts_no = 0; ts_no < 8; ts_no++) {
296 int j;
Jacob Erlbecke2e004e2015-06-18 17:16:26 +0200297 if (!ul_tbf->pdch[ts_no])
Holger Hans Peter Freythere45c19b2013-12-25 20:53:53 +0100298 continue;
299
300 ul_usage |= (1 << ts_no);
301 /* mark bits from TS-t .. TS+r */
Andreas Eversberg91670552014-05-29 11:08:58 +0200302 for (j = (ts_no - Tt) & 7; j != ((ts_no + Tr + 1) & 7); j = (j + 1) & 7)
Holger Hans Peter Freythere45c19b2013-12-25 20:53:53 +0100303 collide |= (1 << j);
304 }
305
306 LOGP(DRLCMAC, LOGL_DEBUG, "- Not allowed slots due to existing "
307 "UL allocation: (TS=0)\"%c%c%c%c%c%c%c%c\"(TS=7) "
308 " D=downlink x=not usable\n",
309 ((ul_usage & 0x01)) ? 'D' : ((collide & 0x01))?'x':'.',
310 ((ul_usage & 0x02)) ? 'D' : ((collide & 0x02))?'x':'.',
311 ((ul_usage & 0x04)) ? 'D' : ((collide & 0x04))?'x':'.',
312 ((ul_usage & 0x08)) ? 'D' : ((collide & 0x08))?'x':'.',
313 ((ul_usage & 0x10)) ? 'D' : ((collide & 0x10))?'x':'.',
314 ((ul_usage & 0x20)) ? 'D' : ((collide & 0x20))?'x':'.',
315 ((ul_usage & 0x40)) ? 'D' : ((collide & 0x40))?'x':'.',
316 ((ul_usage & 0x80)) ? 'D' : ((collide & 0x80))?'x':'.');
317
318 /*
319 * Uplink/Downlink in GSM is shifted by three timeslots. Make
320 * sure they don't collide.
321 */
322 *rx_window &= ~(collide << 3);
323 *rx_window &= ~(collide >> 5);
324 LOGP(DRLCMAC, LOGL_DEBUG, "- Remaining slots for RX: "
325 "(TS=0)\"%c%c%c%c%c%c%c%c\"(TS=7)\n",
326 ((*rx_window & 0x01)) ? 'D' : '.',
327 ((*rx_window & 0x02)) ? 'D' : '.',
328 ((*rx_window & 0x04)) ? 'D' : '.',
329 ((*rx_window & 0x08)) ? 'D' : '.',
330 ((*rx_window & 0x10)) ? 'D' : '.',
331 ((*rx_window & 0x20)) ? 'D' : '.',
332 ((*rx_window & 0x40)) ? 'D' : '.',
333 ((*rx_window & 0x80)) ? 'D' : '.');
334
335 if (!*rx_window) {
336 LOGP(DRLCMAC, LOGL_NOTICE, "No suitable downlink slots "
337 "available with current uplink assignment\n");
338 return -EBUSY;
339 }
340
Andreas Eversberg1cd9d882014-01-04 15:42:38 +0100341 return 0;
342}
343
344/* shrink range of rx_win_min and rx_win_max */
345static void shrink_rx_window(uint8_t *rx_win_min, uint8_t *rx_win_max, int rx_window)
346{
Holger Hans Peter Freythere45c19b2013-12-25 20:53:53 +0100347 /* calculate new min/max */
348 for (uint8_t ts_no = *rx_win_min; ts_no <= *rx_win_max; ts_no++) {
Andreas Eversberg1cd9d882014-01-04 15:42:38 +0100349 if ((rx_window & (1 << ts_no)))
Holger Hans Peter Freythere45c19b2013-12-25 20:53:53 +0100350 break;
351 *rx_win_min = ts_no + 1;
Andreas Eversberg1cd9d882014-01-04 15:42:38 +0100352 LOGP(DRLCMAC, LOGL_DEBUG, "- TS is unused, so "
Holger Hans Peter Freythere45c19b2013-12-25 20:53:53 +0100353 "raising start of DL window to %d\n",
354 *rx_win_min);
355 }
356 for (uint8_t ts_no = *rx_win_max; ts_no >= *rx_win_min; ts_no--) {
Andreas Eversberg1cd9d882014-01-04 15:42:38 +0100357 if ((rx_window & (1 << ts_no)))
Holger Hans Peter Freythere45c19b2013-12-25 20:53:53 +0100358 break;
359 *rx_win_max = ts_no - 1;
Andreas Eversberg1cd9d882014-01-04 15:42:38 +0100360 LOGP(DRLCMAC, LOGL_DEBUG, "- TS is unused, so "
Holger Hans Peter Freythere45c19b2013-12-25 20:53:53 +0100361 "lowering end of DL window to %d\n",
362 *rx_win_max);
363 }
Holger Hans Peter Freythere45c19b2013-12-25 20:53:53 +0100364}
365
Holger Hans Peter Freytherdd4af802013-12-25 21:03:42 +0100366/*
367 * reduce window, to allow at least one uplink TX slot
368 * this is only required for Type 1
369 */
370static uint8_t update_rx_win_max(const int ms_type, const int Tt,
371 const int Tr, uint8_t rx_win_min, uint8_t rx_win_max)
372{
373 if (ms_type != 1)
374 return rx_win_max;
375
376 if (rx_win_max - rx_win_min + 1 + Tt + 1 + Tr > 8) {
377 rx_win_max = rx_win_min + 7 - Tt - 1 - Tr;
378 LOGP(DRLCMAC, LOGL_DEBUG, "- Reduce RX window due to time "
379 "contraints to %d slots\n", rx_win_max - rx_win_min + 1);
380 }
381
382 return rx_win_max;
383}
384
Holger Hans Peter Freyther3fd2ddf2013-12-25 21:11:20 +0100385static void tx_win_from_rx(const int ms_type,
386 uint8_t rx_win_min, uint8_t rx_win_max,
387 int Tt, int Tr,
388 uint8_t *tx_win_min, uint8_t *tx_win_max,
389 uint8_t *tx_range)
390{
391 if (ms_type == 1) {
392 /* calculate TX window (shifted by 3 timeslots)
393 * it uses the space between tx_win_max and tx_win_min */
394 *tx_win_min = (rx_win_max - 2 + Tt) & 7;
395 *tx_win_max = (rx_win_min + 4 - Tr) & 7;
396 } else {
397 /* TX and RX simultaniously */
398 *tx_win_min = rx_win_min;
399 *tx_win_max = 7;
400 }
401
402 *tx_range = (*tx_win_max - *tx_win_min + 1) & 7;
Andreas Eversberg7a16d462014-01-04 15:25:18 +0100403 /* if TX window fills complete range */
404 if (*tx_range == 0)
405 *tx_range = 8;
Holger Hans Peter Freyther3fd2ddf2013-12-25 21:11:20 +0100406 LOGP(DRLCMAC, LOGL_DEBUG, "- TX-Window is: %d..%d\n", *tx_win_min,
407 *tx_win_max);
408}
Holger Hans Peter Freythere45c19b2013-12-25 20:53:53 +0100409
Holger Hans Peter Freyther1fe69322013-12-26 09:31:31 +0100410/*
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100411 * Select a window of Tx slots if available.
412 * The maximum allowed slots depend on TX or the window of available
413 * slots.
414 */
415static int select_ul_slots(gprs_rlcmac_trx *trx,
416 const int ms_type, const int ms_max_txslots,
417 uint8_t tx_win_min, uint8_t tx_range,
Andreas Eversberg765736d2014-01-04 15:27:31 +0100418 int8_t *usf, int8_t *first_common_ts, uint8_t rx_window)
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100419{
420 int tsc = -1;
421 uint8_t tx_window = 0;
422 int i;
423 uint8_t ts_no;
424
Andreas Eversbergfe2dcc82014-01-04 15:39:54 +0100425 for (ts_no = tx_win_min, i = 0; i < tx_range; ts_no = (ts_no + 1) & 7, i++) {
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100426 gprs_rlcmac_pdch *pdch = &trx->pdch[ts_no];
427
428 /* check if enabled */
429 if (!pdch->is_enabled()) {
430 LOGP(DRLCMAC, LOGL_DEBUG, "- Skipping TS %d, "
431 "because not enabled\n", ts_no);
Andreas Eversbergb03d4272014-01-04 15:14:19 +0100432 if (ms_type == 1 && tx_window)
433 goto inc_window;
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100434 continue;
435 }
Andreas Eversberg765736d2014-01-04 15:27:31 +0100436 /* check if used as downlink */
437 if (!(rx_window & (1 << ts_no))) {
438 LOGP(DRLCMAC, LOGL_DEBUG, "- Skipping TS %d, "
439 "because not a downlink slot\n", ts_no);
440 if (ms_type == 1 && tx_window)
441 goto inc_window;
442 continue;
443 }
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100444 /* check if TSC changes */
445 if (tsc < 0)
446 tsc = pdch->tsc;
447 else if (tsc != pdch->tsc) {
448 LOGP(DRLCMAC, LOGL_ERROR, "Skipping TS %d of "
449 "TRX=%d, because it has different TSC "
450 "than lower TS of TRX. In order to "
451 "allow multislot, all slots must be "
452 "configured with the same TSC!\n",
453 ts_no, trx->trx_no);
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100454 if (ms_type == 1)
Andreas Eversbergb03d4272014-01-04 15:14:19 +0100455 goto inc_window;
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100456 continue;
457 }
458 /* check for free usf */
459 usf[ts_no] = find_free_usf(pdch);
460 if (usf[ts_no] < 0) {
461 LOGP(DRLCMAC, LOGL_DEBUG, "- Skipping TS %d, "
462 "because no USF available\n", ts_no);
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100463 if (ms_type == 1)
Andreas Eversbergb03d4272014-01-04 15:14:19 +0100464 goto inc_window;
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100465 continue;
466 }
467
468 if (!tx_window)
469 *first_common_ts = ts_no;
470
471 tx_window |= (1 << ts_no);
472 LOGP(DRLCMAC, LOGL_DEBUG, "- Selected UL TS %d\n", ts_no);
473
Andreas Eversbergb03d4272014-01-04 15:14:19 +0100474inc_window:
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100475 if (1 && ms_type == 1) { /* FIXME: multislot UL assignment */
476 LOGP(DRLCMAC, LOGL_DEBUG, "- Done, because "
477 "1 slot assigned\n");
478 break;
479 }
Andreas Eversberg0a940082014-01-15 13:53:43 +0100480 if (i+1 == ms_max_txslots) {
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100481 LOGP(DRLCMAC, LOGL_DEBUG, "- Done, because "
482 "slots / window reached maximum "
483 "allowed Tx size\n");
484 break;
485 }
486 }
487
488 LOGP(DRLCMAC, LOGL_DEBUG, "- Selected TX window: "
489 "(TS=0)\"%c%c%c%c%c%c%c%c\"(TS=7)\n",
490 ((tx_window & 0x01)) ? 'U' : '.',
491 ((tx_window & 0x02)) ? 'U' : '.',
492 ((tx_window & 0x04)) ? 'U' : '.',
493 ((tx_window & 0x08)) ? 'U' : '.',
494 ((tx_window & 0x10)) ? 'U' : '.',
495 ((tx_window & 0x20)) ? 'U' : '.',
496 ((tx_window & 0x40)) ? 'U' : '.',
497 ((tx_window & 0x80)) ? 'U' : '.');
498
499 if (!tx_window) {
500 LOGP(DRLCMAC, LOGL_NOTICE, "No suitable uplink slots "
501 "available\n");
502 return -EBUSY;
503 }
504
505 return tx_window;
506}
507
508/*
Holger Hans Peter Freyther1fe69322013-12-26 09:31:31 +0100509 * Assign the first common ts, which is used for control or
510 * single slot.
511 */
Andreas Eversberg765736d2014-01-04 15:27:31 +0100512static int select_first_ts(gprs_rlcmac_trx *trx, uint8_t tx_win_min,
513 uint8_t tx_range, uint8_t rx_window)
Holger Hans Peter Freyther1fe69322013-12-26 09:31:31 +0100514{
515 uint8_t ts_no;
516 int i;
Andreas Eversbergfe2dcc82014-01-04 15:39:54 +0100517 for (ts_no = tx_win_min, i = 0; i < tx_range; ts_no = (ts_no + 1) & 7, i++) {
Holger Hans Peter Freyther1fe69322013-12-26 09:31:31 +0100518 gprs_rlcmac_pdch *pdch = &trx->pdch[ts_no];
519 /* check if enabled */
520 if (!pdch->is_enabled()) {
521 LOGP(DRLCMAC, LOGL_DEBUG, "- Skipping TS %d, "
522 "because not enabled\n", ts_no);
523 continue;
524 }
Andreas Eversberg765736d2014-01-04 15:27:31 +0100525 /* check if used as downlink */
526 if (!(rx_window & (1 << ts_no))) {
527 LOGP(DRLCMAC, LOGL_DEBUG, "- Skipping TS %d, "
528 "because not a downlink slot\n", ts_no);
529 continue;
530 }
Holger Hans Peter Freyther1fe69322013-12-26 09:31:31 +0100531 return ts_no;
532 }
533
534 return -1;
535}
536
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200537/* Slot Allocation: Algorithm B
538 *
539 * Assign as many downlink slots as possible.
540 * Assign one uplink slot. (With free USF)
541 *
542 */
543int alloc_algorithm_b(struct gprs_rlcmac_bts *bts,
Jacob Erlbecke2e004e2015-06-18 17:16:26 +0200544 GprsMs *ms,
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200545 struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single)
546{
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200547 const struct gprs_ms_multislot_class *ms_class;
Holger Hans Peter Freyther882fc9b2013-12-25 20:34:26 +0100548 uint8_t Tx, Sum; /* Maximum Number of Slots: RX, Tx, Sum Rx+Tx */
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200549 uint8_t Tta, Ttb, Tra, Trb, Tt, Tr; /* Minimum Number of Slots */
550 uint8_t Type; /* Type of Mobile */
Holger Hans Peter Freythere45c19b2013-12-25 20:53:53 +0100551 int rx_window;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200552 static const char *digit[10] = { "0","1","2","3","4","5","6","7","8","9" };
553 int8_t usf[8] = { -1, -1, -1, -1, -1, -1, -1, -1 }; /* must be signed */
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200554 int8_t first_common_ts = -1;
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100555 uint8_t ts;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200556 uint8_t slotcount = 0;
557
558
Jacob Erlbeckbefc7602015-06-02 12:33:30 +0200559 if (tbf->ms_class() >= 32) {
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200560 LOGP(DRLCMAC, LOGL_ERROR, "Multislot class %d out of range.\n",
Jacob Erlbeckbefc7602015-06-02 12:33:30 +0200561 tbf->ms_class());
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200562 return -EINVAL;
563 }
564
Jacob Erlbeckbefc7602015-06-02 12:33:30 +0200565 if (tbf->ms_class()) {
566 ms_class = &gprs_ms_multislot_class[tbf->ms_class()];
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200567 LOGP(DRLCMAC, LOGL_DEBUG, "Slot Allocation (Algorithm B) for "
Jacob Erlbeckbefc7602015-06-02 12:33:30 +0200568 "class %d\n", tbf->ms_class());
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200569 } else {
570 ms_class = &gprs_ms_multislot_class[12];
571 LOGP(DRLCMAC, LOGL_DEBUG, "Slot Allocation (Algorithm B) for "
572 "unknow class (assuming 12)\n");
573 }
574
575 if (ms_class->tx == MS_NA) {
576 LOGP(DRLCMAC, LOGL_NOTICE, "Multislot class %d not "
Jacob Erlbeckbefc7602015-06-02 12:33:30 +0200577 "applicable.\n", tbf->ms_class());
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200578 return -EINVAL;
579 }
580
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200581 Tx = ms_class->tx;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200582 Sum = ms_class->sum;
583 Tta = ms_class->ta;
584 Ttb = ms_class->tb;
585 Tra = ms_class->ra;
586 Trb = ms_class->rb;
587 Type = ms_class->type;
588
589 /* Tta and Ttb may depend on hopping or frequency change */
Holger Hans Peter Freytherf34f3442013-12-25 20:33:37 +0100590 if (Ttb == MS_A || Ttb == MS_B)
Holger Hans Peter Freyther11a74892013-09-29 08:13:42 +0200591 Ttb = 0;
Holger Hans Peter Freytherf34f3442013-12-25 20:33:37 +0100592 if (Trb == MS_A || Trb == MS_C)
Holger Hans Peter Freyther11a74892013-09-29 08:13:42 +0200593 Trb = 0;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200594
595 LOGP(DRLCMAC, LOGL_DEBUG, "- Rx=%d Tx=%d Sum Rx+Tx=%s Tta=%s Ttb=%d "
Holger Hans Peter Freyther882fc9b2013-12-25 20:34:26 +0100596 " Tra=%d Trb=%d Type=%d\n", ms_class->rx, Tx,
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200597 (Sum == MS_NA) ? "N/A" : digit[Sum],
598 (Tta == MS_NA) ? "N/A" : digit[Tta], Ttb, Tra, Trb, Type);
599
600 /* select the values for time contraints */
Holger Hans Peter Freyther11a74892013-09-29 08:13:42 +0200601 /* applicable to type 1 and type 2 */
602 Tt = Ttb;
603 Tr = Trb;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200604
Holger Hans Peter Freyther882fc9b2013-12-25 20:34:26 +0100605 uint8_t rx_win_min, rx_win_max;
606 rx_window = select_dl_slots(tbf->trx, ms_class->type, ms_class->rx,
607 &rx_win_min, &rx_win_max);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200608
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200609
610 /* reduce window, if existing uplink slots collide RX window */
Jacob Erlbecke2e004e2015-06-18 17:16:26 +0200611 int rc = reduce_rx_window(ms_class->type, ms, Tt, Tr,
Holger Hans Peter Freythere45c19b2013-12-25 20:53:53 +0100612 &rx_window, &rx_win_min, &rx_win_max);
613 if (rc < 0)
614 return rc;
Andreas Eversberg1cd9d882014-01-04 15:42:38 +0100615 shrink_rx_window(&rx_win_min, &rx_win_max, rx_window);
Holger Hans Peter Freytherdd4af802013-12-25 21:03:42 +0100616 rx_win_max = update_rx_win_max(ms_class->type, Tt, Tr,
617 rx_win_min, rx_win_max);
Andreas Eversberg1cd9d882014-01-04 15:42:38 +0100618 shrink_rx_window(&rx_win_min, &rx_win_max, rx_window);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200619 LOGP(DRLCMAC, LOGL_DEBUG, "- RX-Window is: %d..%d\n", rx_win_min,
620 rx_win_max);
621
622 /* calculate TX window */
Holger Hans Peter Freyther3fd2ddf2013-12-25 21:11:20 +0100623 uint8_t tx_win_min, tx_win_max, tx_range;
624 tx_win_from_rx(ms_class->type, rx_win_min, rx_win_max, Tt, Tr,
625 &tx_win_min, &tx_win_max, &tx_range);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200626
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100627 /* select UL slots but in both cases assign first_common_ts */
628 uint8_t tx_window = 0;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200629 if (tbf->direction == GPRS_RLCMAC_UL_TBF) {
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100630 rc = select_ul_slots(tbf->trx, ms_class->type, ms_class->tx,
Andreas Eversberg765736d2014-01-04 15:27:31 +0100631 tx_win_min, tx_range, usf,
632 &first_common_ts, rx_window);
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100633 if (rc < 0)
634 return rc;
635 tx_window = rc;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200636 } else {
Andreas Eversberg765736d2014-01-04 15:27:31 +0100637 first_common_ts = select_first_ts(tbf->trx, tx_win_min,
638 tx_range, rx_window);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200639 }
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100640 #warning "first_common_ts might be different if there was no free USF for the new uplink assignment"
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200641
642 if (first_common_ts < 0) {
643 LOGP(DRLCMAC, LOGL_NOTICE, "No first common slots available\n");
644 return -EINVAL;
645 }
646
647 if (tbf->direction == GPRS_RLCMAC_DL_TBF) {
Daniel Willmanncd44ec42014-08-07 15:04:57 +0200648 struct gprs_rlcmac_dl_tbf *dl_tbf = static_cast<gprs_rlcmac_dl_tbf *>(tbf);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200649 /* assign downlink */
650 if (rx_window == 0) {
651 LOGP(DRLCMAC, LOGL_NOTICE, "No downlink slots "
652 "available\n");
653 return -EINVAL;
654 }
655 for (ts = 0; ts < 8; ts++) {
656 if ((rx_window & (1 << ts))) {
657 /* be sure to select a single downlink slots
658 * that can be used for uplink, if multiple
659 * slots are assigned later. */
660 if (single && first_common_ts != ts)
661 continue;
662 LOGP(DRLCMAC, LOGL_DEBUG, "- Assigning DL TS "
663 "%d\n", ts);
Daniel Willmanncd44ec42014-08-07 15:04:57 +0200664 assign_dlink_tbf(&tbf->trx->pdch[ts], dl_tbf);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200665 slotcount++;
666 if (slotcount == 1)
Daniel Willmanncd44ec42014-08-07 15:04:57 +0200667 dl_tbf->first_ts = ts;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200668 if (single)
669 break;
670 }
671 }
672 } else {
Daniel Willmanncd44ec42014-08-07 15:04:57 +0200673 struct gprs_rlcmac_ul_tbf *ul_tbf = static_cast<gprs_rlcmac_ul_tbf *>(tbf);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200674 for (ts = 0; ts < 8; ts++) {
675 if ((tx_window & (1 << ts))) {
676 LOGP(DRLCMAC, LOGL_DEBUG, "- Assigning UL TS "
677 "%d\n", ts);
Daniel Willmanncd44ec42014-08-07 15:04:57 +0200678 assign_uplink_tbf_usf(&tbf->trx->pdch[ts], ul_tbf, usf[ts]);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200679 slotcount++;
680 if (slotcount == 1)
Daniel Willmanncd44ec42014-08-07 15:04:57 +0200681 ul_tbf->first_ts = ts;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200682 if (single)
683 break;
684 }
685 }
686 }
687 if (single && slotcount) {
Daniel Willmanncf1fae72014-05-30 17:58:01 +0200688 uint8_t ts_count = 0;
689 for (ts = 0; ts < 8; ts++)
690 if ((tx_window & (1 << ts)))
691 ts_count++;
692
693 tbf->upgrade_to_multislot = (ts_count > 1);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200694 LOGP(DRLCMAC, LOGL_INFO, "Using single slot at TS %d for %s\n",
695 tbf->first_ts,
696 (tbf->direction == GPRS_RLCMAC_DL_TBF) ? "DL" : "UL");
697 } else {
Daniel Willmanncf1fae72014-05-30 17:58:01 +0200698 tbf->upgrade_to_multislot = 0;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200699 LOGP(DRLCMAC, LOGL_INFO, "Using %d slots for %s\n", slotcount,
700 (tbf->direction == GPRS_RLCMAC_DL_TBF) ? "DL" : "UL");
701 }
702 if (slotcount == 0)
703 return -EBUSY;
704
705 tbf->first_common_ts = first_common_ts;
706
707 return 0;
708}