blob: 471b601a43f4bc85d46b607f43f9b092d389ea3f [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>
Jacob Erlbeck8cba7e92016-01-19 15:48:03 +010027#include <pcu_utils.h>
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +020028
29#include <errno.h>
Jacob Erlbeckec478752015-06-19 16:35:38 +020030#include <values.h>
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +020031
Max842d7812017-11-01 18:11:24 +010032extern "C" {
33#include "mslot_class.h"
34}
35
Jacob Erlbeck77da3552015-07-16 18:33:46 +020036/* Consider a PDCH as idle if has at most this number of TBFs assigned to it */
37#define PDCH_IDLE_TBF_THRESH 1
38
Jacob Erlbeckea65c722015-06-22 16:14:23 +020039static char *set_flag_chars(char *buf, uint8_t val, char set_char, char unset_char = 0)
40{
41 int i;
42
43 for (i = 0; i < 8; i += 1, val = val >> 1) {
44 if (val & 1)
45 buf[i] = set_char;
46 else if (unset_char)
47 buf[i] = unset_char;
48 }
49
50 return buf;
51}
52
53static bool test_and_set_bit(uint32_t *bits, size_t elem)
54{
55 bool was_set = bits[elem/32] & (1 << (elem % 32));
56 bits[elem/32] |= (1 << (elem % 32));
57
58 return was_set;
59}
60
Holger Hans Peter Freyther6796ed22013-10-20 16:45:10 +020061static inline int8_t find_free_usf(struct gprs_rlcmac_pdch *pdch)
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +020062{
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +020063 uint8_t usf_map = 0;
Jacob Erlbeck20b7ba72015-06-30 14:34:24 +020064 uint8_t usf;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +020065
Jacob Erlbeck20b7ba72015-06-30 14:34:24 +020066 usf_map = pdch->assigned_usf();
67 if (usf_map == (1 << 7) - 1)
68 return -1;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +020069
70 /* look for USF, don't use USF=7 */
71 for (usf = 0; usf < 7; usf++) {
72 if (!(usf_map & (1 << usf)))
73 return usf;
74 }
75
76 return -1;
77}
78
Jacob Erlbecke0853cd2015-07-10 12:25:25 +020079static inline int8_t find_free_tfi(struct gprs_rlcmac_pdch *pdch,
80 enum gprs_rlcmac_tbf_direction dir)
81{
82 uint32_t tfi_map = 0;
83 int8_t tfi;
84
85 tfi_map = pdch->assigned_tfi(dir);
86 if (tfi_map == 0xffffffffUL)
87 return -1;
88
89 /* look for USF, don't use USF=7 */
90 for (tfi = 0; tfi < 32; tfi++) {
91 if (!(tfi_map & (1 << tfi)))
92 return tfi;
93 }
94
95 return -1;
96}
97
Jacob Erlbeckec478752015-06-19 16:35:38 +020098static int find_possible_pdchs(struct gprs_rlcmac_trx *trx,
Jacob Erlbeck83426b22015-06-30 09:44:05 +020099 size_t max_slots,
Jacob Erlbeckec478752015-06-19 16:35:38 +0200100 uint8_t mask, const char *mask_reason = NULL)
Holger Hans Peter Freytherb0a00752013-09-29 08:18:17 +0200101{
Jacob Erlbeckec478752015-06-19 16:35:38 +0200102 unsigned ts;
103 int valid_ts_set = 0;
Jacob Erlbeck83426b22015-06-30 09:44:05 +0200104 int8_t last_tsc = -1; /* must be signed */
Jacob Erlbeckec478752015-06-19 16:35:38 +0200105
106 for (ts = 0; ts < ARRAY_SIZE(trx->pdch); ts++) {
Holger Hans Peter Freytherb0a00752013-09-29 08:18:17 +0200107 struct gprs_rlcmac_pdch *pdch;
108
109 pdch = &trx->pdch[ts];
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +0200110 if (!pdch->is_enabled()) {
Holger Hans Peter Freytherb0a00752013-09-29 08:18:17 +0200111 LOGP(DRLCMAC, LOGL_DEBUG, "- Skipping TS %d, because "
112 "not enabled\n", ts);
113 continue;
114 }
Jacob Erlbeckec478752015-06-19 16:35:38 +0200115
116 if (((1 << ts) & mask) == 0) {
117 if (mask_reason)
118 LOGP(DRLCMAC, LOGL_DEBUG,
119 "- Skipping TS %d, because %s\n",
120 ts, mask_reason);
121 continue;
122 }
123
Jacob Erlbeck83426b22015-06-30 09:44:05 +0200124 if (max_slots > 1) {
125 /* check if TSC changes, see TS 45.002, 6.4.2 */
126 if (last_tsc < 0)
127 last_tsc = pdch->tsc;
128 else if (last_tsc != pdch->tsc) {
129 LOGP(DRLCMAC, LOGL_ERROR,
130 "Skipping TS %d of TRX=%d, because it "
131 "has different TSC than lower TS of TRX. "
132 "In order to allow multislot, all "
133 "slots must be configured with the same "
134 "TSC!\n", ts, trx->trx_no);
135 continue;
136 }
137 }
138
Jacob Erlbeckec478752015-06-19 16:35:38 +0200139 valid_ts_set |= 1 << ts;
Holger Hans Peter Freytherb0a00752013-09-29 08:18:17 +0200140 }
141
Jacob Erlbeckec478752015-06-19 16:35:38 +0200142 return valid_ts_set;
143}
144
Jacob Erlbeckc135b872015-07-09 13:44:18 +0200145static int compute_usage_by_num_tbfs(struct gprs_rlcmac_pdch *pdch,
146 enum gprs_rlcmac_tbf_direction dir)
147{
148 return pdch->num_tbfs(dir);
149}
150
151static int compute_usage_by_reservation(struct gprs_rlcmac_pdch *pdch,
152 enum gprs_rlcmac_tbf_direction)
153{
154 return
155 pdch->num_reserved(GPRS_RLCMAC_DL_TBF) +
156 pdch->num_reserved(GPRS_RLCMAC_UL_TBF);
157}
158
Jacob Erlbeck7af53e62015-07-16 15:04:07 +0200159static int compute_usage_for_algo_a(struct gprs_rlcmac_pdch *pdch,
160 enum gprs_rlcmac_tbf_direction dir)
161{
162 int usage =
163 pdch->num_tbfs(GPRS_RLCMAC_DL_TBF) +
164 pdch->num_tbfs(GPRS_RLCMAC_UL_TBF) +
165 compute_usage_by_reservation(pdch, dir);
166
167 if (pdch->assigned_tfi(reverse(dir)) == 0xffffffff)
168 /* No TFI in the opposite direction, avoid it */
169 usage += 32;
170
171 return usage;
172
173}
174
Jacob Erlbeckec478752015-06-19 16:35:38 +0200175static int find_least_busy_pdch(struct gprs_rlcmac_trx *trx,
176 enum gprs_rlcmac_tbf_direction dir,
177 uint8_t mask,
Jacob Erlbeckc135b872015-07-09 13:44:18 +0200178 int (*fn)(struct gprs_rlcmac_pdch *, enum gprs_rlcmac_tbf_direction dir),
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200179 int *free_tfi = 0, int *free_usf = 0)
Jacob Erlbeckec478752015-06-19 16:35:38 +0200180{
181 unsigned ts;
182 int min_used = INT_MAX;
183 int min_ts = -1;
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200184 int min_tfi = -1;
Jacob Erlbeckec478752015-06-19 16:35:38 +0200185 int min_usf = -1;
186
187 for (ts = 0; ts < ARRAY_SIZE(trx->pdch); ts++) {
188 struct gprs_rlcmac_pdch *pdch = &trx->pdch[ts];
189 int num_tbfs;
190 int usf = -1; /* must be signed */
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200191 int tfi = -1;
Jacob Erlbeckec478752015-06-19 16:35:38 +0200192
193 if (((1 << ts) & mask) == 0)
194 continue;
195
Jacob Erlbeckc135b872015-07-09 13:44:18 +0200196 num_tbfs = fn(pdch, dir);
Jacob Erlbeckefe62a72015-07-02 15:48:25 +0200197
198 if (num_tbfs < min_used) {
199 /* We have found a candidate */
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200200 /* Make sure that a TFI is available */
201 if (free_tfi) {
202 tfi = find_free_tfi(pdch, dir);
203 if (tfi < 0) {
204 LOGP(DRLCMAC, LOGL_DEBUG,
205 "- Skipping TS %d, because "
206 "no TFI available\n", ts);
207 continue;
208 }
209 }
Jacob Erlbeckefe62a72015-07-02 15:48:25 +0200210 /* Make sure that an USF is available */
211 if (dir == GPRS_RLCMAC_UL_TBF) {
212 usf = find_free_usf(pdch);
213 if (usf < 0) {
214 LOGP(DRLCMAC, LOGL_DEBUG,
215 "- Skipping TS %d, because "
216 "no USF available\n", ts);
217 continue;
218 }
219 }
220 if (min_ts >= 0)
221 LOGP(DRLCMAC, LOGL_DEBUG,
222 "- Skipping TS %d, because "
223 "num TBFs %d > %d\n",
224 min_ts, min_used, num_tbfs);
225 min_used = num_tbfs;
226 min_ts = ts;
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200227 min_tfi = tfi;
Jacob Erlbeckefe62a72015-07-02 15:48:25 +0200228 min_usf = usf;
229 } else {
230 LOGP(DRLCMAC, LOGL_DEBUG,
231 "- Skipping TS %d, because "
232 "num TBFs %d >= %d\n",
233 ts, num_tbfs, min_used);
234 }
235 }
236
237 if (min_ts < 0)
238 return -1;
239
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200240 if (free_tfi)
241 *free_tfi = min_tfi;
Jacob Erlbeckefe62a72015-07-02 15:48:25 +0200242 if (free_usf)
243 *free_usf = min_usf;
244
245 return min_ts;
246}
247
Jacob Erlbeckccc34e42015-06-29 13:45:05 +0200248static void attach_tbf_to_pdch(struct gprs_rlcmac_pdch *pdch,
249 struct gprs_rlcmac_tbf *tbf)
250{
251 if (tbf->pdch[pdch->ts_no])
252 tbf->pdch[pdch->ts_no]->detach_tbf(tbf);
253
254 tbf->pdch[pdch->ts_no] = pdch;
255 pdch->attach_tbf(tbf);
256}
257
Holger Hans Peter Freyther743bafa2013-09-29 07:50:50 +0200258static void assign_uplink_tbf_usf(
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200259 struct gprs_rlcmac_pdch *pdch,
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200260 struct gprs_rlcmac_ul_tbf *tbf,
261 int tfi, int8_t usf)
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200262{
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200263 tbf->m_tfi = tfi;
Daniel Willmann7e994e32014-08-07 15:49:21 +0200264 tbf->m_usf[pdch->ts_no] = usf;
Jacob Erlbeckccc34e42015-06-29 13:45:05 +0200265 attach_tbf_to_pdch(pdch, tbf);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200266}
267
Holger Hans Peter Freyther8481a052013-09-29 08:08:28 +0200268static void assign_dlink_tbf(
269 struct gprs_rlcmac_pdch *pdch,
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200270 struct gprs_rlcmac_dl_tbf *tbf,
271 int tfi)
Holger Hans Peter Freyther8481a052013-09-29 08:08:28 +0200272{
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200273 tbf->m_tfi = tfi;
Jacob Erlbeckccc34e42015-06-29 13:45:05 +0200274 attach_tbf_to_pdch(pdch, tbf);
Holger Hans Peter Freyther8481a052013-09-29 08:08:28 +0200275}
276
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200277static int find_trx(BTS *bts, const GprsMs *ms, int use_trx)
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200278{
279 unsigned trx_no;
280 unsigned ts;
281 struct gprs_rlcmac_bts *bts_data = bts->bts_data();
282
283 /* We must use the TRX currently actively used by an MS */
284 if (ms && ms->current_trx())
285 return ms->current_trx()->trx_no;
286
287 if (use_trx >= 0 && use_trx < 8)
288 return use_trx;
289
290 /* Find the first TRX that has a PDCH with a free UL and DL TFI */
291 for (trx_no = 0; trx_no < ARRAY_SIZE(bts_data->trx); trx_no += 1) {
292 struct gprs_rlcmac_trx *trx = &bts_data->trx[trx_no];
293 for (ts = 0; ts < ARRAY_SIZE(trx->pdch); ts++) {
294 struct gprs_rlcmac_pdch *pdch = &trx->pdch[ts];
295 if (!pdch->is_enabled())
296 continue;
297
298 if (pdch->assigned_tfi(GPRS_RLCMAC_UL_TBF) == 0xffffffff)
299 continue;
300
301 if (pdch->assigned_tfi(GPRS_RLCMAC_DL_TBF) == 0xffffffff)
302 continue;
303
304 return trx_no;
305 }
306 }
307
308 return -EBUSY;
309}
310
Jacob Erlbeck77da3552015-07-16 18:33:46 +0200311static struct gprs_rlcmac_pdch * find_idle_pdch(BTS *bts)
312{
313 unsigned trx_no;
314 unsigned ts;
315 struct gprs_rlcmac_bts *bts_data = bts->bts_data();
316
317 /* Find the first PDCH with an unused DL TS */
318 for (trx_no = 0; trx_no < ARRAY_SIZE(bts_data->trx); trx_no += 1) {
319 struct gprs_rlcmac_trx *trx = &bts_data->trx[trx_no];
320 for (ts = 0; ts < ARRAY_SIZE(trx->pdch); ts++) {
321 struct gprs_rlcmac_pdch *pdch = &trx->pdch[ts];
322 if (!pdch->is_enabled())
323 continue;
324
325 if (pdch->num_tbfs(GPRS_RLCMAC_DL_TBF) > PDCH_IDLE_TBF_THRESH)
326 continue;
327
328 return pdch;
329 }
330 }
331
332 return NULL;
333}
334
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200335static int tfi_find_free(BTS *bts, const GprsMs *ms,
336 enum gprs_rlcmac_tbf_direction dir, int use_trx, int *trx_no_)
Jacob Erlbeck5879c642015-07-10 10:41:36 +0200337{
338 int tfi;
339 uint8_t trx_no;
340
341 if (use_trx == -1 && ms->current_trx())
342 use_trx = ms->current_trx()->trx_no;
343
344 tfi = bts->tfi_find_free(dir, &trx_no, use_trx);
345 if (tfi < 0)
346 return -EBUSY;
347
348 if (trx_no_)
349 *trx_no_ = trx_no;
350
351 return tfi;
352}
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200353
354/* Slot Allocation: Algorithm A
355 *
356 * Assign single slot for uplink and downlink
357 */
358int alloc_algorithm_a(struct gprs_rlcmac_bts *bts,
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200359 GprsMs *ms_,
360 struct gprs_rlcmac_tbf *tbf_, uint32_t cust, uint8_t single,
Jacob Erlbeck5879c642015-07-10 10:41:36 +0200361 int use_trx)
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200362{
363 struct gprs_rlcmac_pdch *pdch;
Jacob Erlbeckec478752015-06-19 16:35:38 +0200364 int ts = -1;
Jacob Erlbeck5cd496d2015-06-30 10:24:37 +0200365 uint8_t ul_slots, dl_slots;
Jacob Erlbeck5879c642015-07-10 10:41:36 +0200366 int trx_no;
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200367 int tfi = -1;
Jacob Erlbeckec478752015-06-19 16:35:38 +0200368 int usf = -1;
369 int mask = 0xff;
370 const char *mask_reason = NULL;
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200371 const GprsMs *ms = ms_;
372 const gprs_rlcmac_tbf *tbf = tbf_;
373 gprs_rlcmac_trx *trx = ms->current_trx();
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200374
375 LOGP(DRLCMAC, LOGL_DEBUG, "Slot Allocation (Algorithm A) for class "
Jacob Erlbeckbefc7602015-06-02 12:33:30 +0200376 "%d\n", tbf->ms_class());
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200377
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200378 trx_no = find_trx(bts->bts, ms, use_trx);
379 if (trx_no < 0) {
380 LOGP(DRLCMAC, LOGL_NOTICE,
381 "- Failed to find a usable TRX (TFI exhausted)\n");
382 return trx_no;
Jacob Erlbeck5879c642015-07-10 10:41:36 +0200383 }
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200384 if (!trx)
385 trx = &bts->trx[trx_no];
Jacob Erlbeck5879c642015-07-10 10:41:36 +0200386
Jacob Erlbeck5cd496d2015-06-30 10:24:37 +0200387 dl_slots = ms->reserved_dl_slots();
388 ul_slots = ms->reserved_ul_slots();
389
390 ts = ms->first_common_ts();
391
392 if (ts >= 0) {
Jacob Erlbeckec478752015-06-19 16:35:38 +0200393 mask_reason = "need to reuse TS";
Jacob Erlbeckec478752015-06-19 16:35:38 +0200394 mask = 1 << ts;
Jacob Erlbeck5cd496d2015-06-30 10:24:37 +0200395 } else if (dl_slots || ul_slots) {
396 mask_reason = "need to use a reserved common TS";
397 mask = dl_slots & ul_slots;
398 }
Jacob Erlbeckec478752015-06-19 16:35:38 +0200399
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200400 mask = find_possible_pdchs(trx, 1, mask, mask_reason);
Jacob Erlbeckec478752015-06-19 16:35:38 +0200401 if (!mask)
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200402 return -EINVAL;
403
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200404 ts = find_least_busy_pdch(trx, tbf->direction, mask,
Jacob Erlbeck7af53e62015-07-16 15:04:07 +0200405 compute_usage_for_algo_a,
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200406 &tfi, &usf);
Jacob Erlbeckec478752015-06-19 16:35:38 +0200407
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200408 if (tbf->direction == GPRS_RLCMAC_UL_TBF && usf < 0) {
Jacob Erlbeckec478752015-06-19 16:35:38 +0200409 LOGP(DRLCMAC, LOGL_NOTICE, "- Failed "
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200410 "to allocate a TS, no USF available\n");
Jacob Erlbeckec478752015-06-19 16:35:38 +0200411 return -EBUSY;
412 }
413
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200414 if (ts < 0) {
415 LOGP(DRLCMAC, LOGL_NOTICE, "- Failed "
416 "to allocate a TS, no TFI available\n");
417 return -EBUSY;
418 }
419
420 pdch = &trx->pdch[ts];
421
422 /* The allocation will be successful, so the system state and tbf_/ms_
423 * may be modified from now on. */
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200424 if (tbf->direction == GPRS_RLCMAC_UL_TBF) {
Jacob Erlbeckaa9daa12015-12-28 18:49:12 +0100425 struct gprs_rlcmac_ul_tbf *ul_tbf = as_ul_tbf(tbf_);
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200426 LOGP(DRLCMAC, LOGL_DEBUG, "- Assign uplink TS=%d TFI=%d USF=%d\n",
427 ts, tfi, usf);
428 assign_uplink_tbf_usf(pdch, ul_tbf, tfi, usf);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200429 } else {
Jacob Erlbeckaa9daa12015-12-28 18:49:12 +0100430 struct gprs_rlcmac_dl_tbf *dl_tbf = as_dl_tbf(tbf_);
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200431 LOGP(DRLCMAC, LOGL_DEBUG, "- Assign downlink TS=%d TFI=%d\n",
432 ts, tfi);
433 assign_dlink_tbf(pdch, dl_tbf, tfi);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200434 }
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200435
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200436 tbf_->trx = trx;
437 /* the only one TS is the common TS */
438 tbf_->first_ts = tbf_->first_common_ts = ts;
439 ms_->set_reserved_slots(trx, 1 << ts, 1 << ts);
440
441 tbf_->upgrade_to_multislot = 0;
Jacob Erlbeck5979fe92015-07-14 14:02:41 +0200442 bts->bts->tbf_alloc_algo_a();
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200443 return 0;
444}
445
Max46fbfce2017-11-01 19:22:25 +0100446int find_multi_slots(struct gprs_rlcmac_trx *trx, uint8_t mslot_class, uint8_t *ul_slots, uint8_t *dl_slots)
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200447{
Holger Hans Peter Freyther882fc9b2013-12-25 20:34:26 +0100448 uint8_t Tx, Sum; /* Maximum Number of Slots: RX, Tx, Sum Rx+Tx */
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200449 uint8_t Tta, Ttb, Tra, Trb; /* Minimum Number of Slots */
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200450 uint8_t Type; /* Type of Mobile */
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200451 int rx_window, tx_window, pdch_slots;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200452 static const char *digit[10] = { "0","1","2","3","4","5","6","7","8","9" };
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200453 char slot_info[9] = {0};
454 int max_capacity;
455 uint8_t max_ul_slots;
456 uint8_t max_dl_slots;
457 unsigned max_slots;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200458
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200459 unsigned ul_ts, dl_ts;
460 unsigned num_tx;
Jacob Erlbeck5e46a202015-07-09 11:48:23 +0200461 enum {MASK_TT, MASK_TR};
462 unsigned mask_sel;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200463
Max842d7812017-11-01 18:11:24 +0100464 if (mslot_class)
465 LOGP(DRLCMAC, LOGL_DEBUG, "Slot Allocation (Algorithm B) for class %d\n",
466 mslot_class);
467
468 Tx = mslot_class_get_tx(mslot_class);
469 Sum = mslot_class_get_sum(mslot_class);
470 Tta = mslot_class_get_ta(mslot_class);
471 Ttb = mslot_class_get_tb(mslot_class);
472 Tra = mslot_class_get_ra(mslot_class);
473 Trb = mslot_class_get_rb(mslot_class);
474 Type = mslot_class_get_type(mslot_class);
475
476 if (Tx == MS_NA) {
477 LOGP(DRLCMAC, LOGL_NOTICE, "Multislot class %d not applicable.\n",
478 mslot_class);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200479 return -EINVAL;
480 }
481
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200482 LOGP(DRLCMAC, LOGL_DEBUG, "- Rx=%d Tx=%d Sum Rx+Tx=%s Tta=%s Ttb=%d "
Max842d7812017-11-01 18:11:24 +0100483 " Tra=%d Trb=%d Type=%d\n", mslot_class_get_rx(mslot_class), Tx,
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200484 (Sum == MS_NA) ? "N/A" : digit[Sum],
485 (Tta == MS_NA) ? "N/A" : digit[Tta], Ttb, Tra, Trb, Type);
486
Max842d7812017-11-01 18:11:24 +0100487 max_slots = OSMO_MAX(mslot_class_get_rx(mslot_class), Tx);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200488
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200489 if (*dl_slots == 0)
490 *dl_slots = 0xff;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200491
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200492 if (*ul_slots == 0)
493 *ul_slots = 0xff;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200494
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200495 pdch_slots = find_possible_pdchs(trx, max_slots, 0xff);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200496
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200497 *dl_slots &= pdch_slots;
498 *ul_slots &= pdch_slots;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200499
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200500 LOGP(DRLCMAC, LOGL_DEBUG, "- Possible DL/UL slots: (TS=0)\"%s\"(TS=7)\n",
501 set_flag_chars(set_flag_chars(set_flag_chars(slot_info,
502 *dl_slots, 'D', '.'),
503 *ul_slots, 'U'),
504 *ul_slots & *dl_slots, 'C'));
505
506 /* Check for each UL (TX) slot */
507
508 max_capacity = -1;
509 max_ul_slots = 0;
510 max_dl_slots = 0;
511
512 /* Iterate through possible numbers of TX slots */
Max842d7812017-11-01 18:11:24 +0100513 for (num_tx = 1; num_tx <= mslot_class_get_tx(mslot_class); num_tx += 1) {
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200514 uint16_t tx_valid_win = (1 << num_tx) - 1;
515
Jacob Erlbeck5e46a202015-07-09 11:48:23 +0200516 uint8_t rx_mask[MASK_TR+1];
Max842d7812017-11-01 18:11:24 +0100517 if (Type == 1) {
Jacob Erlbeckdd08ac82015-07-09 12:06:56 +0200518 rx_mask[MASK_TT] = (0x100 >> OSMO_MAX(Ttb, Tta)) - 1;
519 rx_mask[MASK_TT] &= ~((1 << (Trb + num_tx)) - 1);
520 rx_mask[MASK_TR] = (0x100 >> Ttb) - 1;
521 rx_mask[MASK_TR] &=
522 ~((1 << (OSMO_MAX(Trb, Tra) + num_tx)) - 1);
523 } else {
524 /* Class type 2 MS have independant RX and TX */
525 rx_mask[MASK_TT] = 0xff;
526 rx_mask[MASK_TR] = 0xff;
527 }
528
Jacob Erlbeck5e46a202015-07-09 11:48:23 +0200529 rx_mask[MASK_TT] = (rx_mask[MASK_TT] << 3) | (rx_mask[MASK_TT] >> 5);
Jacob Erlbeck5e46a202015-07-09 11:48:23 +0200530 rx_mask[MASK_TR] = (rx_mask[MASK_TR] << 3) | (rx_mask[MASK_TR] >> 5);
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200531
532 /* Rotate group of TX slots: UUU-----, -UUU----, ..., UU-----U */
533 for (ul_ts = 0; ul_ts < 8; ul_ts += 1, tx_valid_win <<= 1) {
534 unsigned tx_slot_count;
535 int max_rx;
536 uint16_t rx_valid_win;
537 uint32_t checked_rx[256/32] = {0};
538
539 /* Wrap valid window */
540 tx_valid_win = (tx_valid_win | tx_valid_win >> 8) & 0xff;
541
542 tx_window = tx_valid_win;
543
544 /* Filter out unavailable slots */
545 tx_window &= *ul_slots;
546
Jacob Erlbecke21b79c2015-07-16 11:48:43 +0200547 /* Skip if the the first TS (ul_ts) is not in the set */
548 if ((tx_window & (1 << ul_ts)) == 0)
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200549 continue;
550
Jacob Erlbecke21b79c2015-07-16 11:48:43 +0200551 /* Skip if the the last TS (ul_ts+num_tx-1) is not in the set */
552 if ((tx_window & (1 << ((ul_ts+num_tx-1) % 8))) == 0)
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200553 continue;
554
Jacob Erlbeck8cba7e92016-01-19 15:48:03 +0100555 tx_slot_count = pcu_bitcount(tx_window);
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200556
Max842d7812017-11-01 18:11:24 +0100557 max_rx = OSMO_MIN(mslot_class_get_rx(mslot_class), Sum - num_tx);
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200558 rx_valid_win = (1 << max_rx) - 1;
559
560 /* Rotate group of RX slots: DDD-----, -DDD----, ..., DD-----D */
561 for (dl_ts = 0; dl_ts < 8; dl_ts += 1, rx_valid_win <<= 1) {
562 /* Wrap valid window */
563 rx_valid_win = (rx_valid_win | rx_valid_win >> 8) & 0xff;
564
565 /* Validate with both Tta/Ttb/Trb and Ttb/Tra/Trb */
Jacob Erlbeck5e46a202015-07-09 11:48:23 +0200566 for (mask_sel = MASK_TT; mask_sel <= MASK_TR; mask_sel += 1) {
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200567 unsigned common_slot_count;
568 unsigned req_common_slots;
569 unsigned rx_slot_count;
570 uint16_t rx_bad;
571 uint8_t rx_good;
572 unsigned ts;
573 int capacity;
574
575 /* Filter out bad slots */
Jacob Erlbeck5e46a202015-07-09 11:48:23 +0200576 rx_bad = (uint16_t)(0xff & ~rx_mask[mask_sel]) << ul_ts;
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200577 rx_bad = (rx_bad | (rx_bad >> 8)) & 0xff;
578 rx_good = *dl_slots & ~rx_bad;
579
580 /* TODO: CHECK this calculation -> separate function for unit
581 * testing */
582
583 rx_window = rx_good & rx_valid_win;
Jacob Erlbeck8cba7e92016-01-19 15:48:03 +0100584 rx_slot_count = pcu_bitcount(rx_window);
Jacob Erlbeckbae33a72015-07-06 14:55:13 +0200585
586#if 0
587 LOGP(DRLCMAC, LOGL_DEBUG, "n_tx=%d, n_rx=%d, mask_sel=%d, "
588 "tx=%02x, rx=%02x, mask=%02x, bad=%02x, good=%02x, "
589 "ul=%02x, dl=%02x\n",
590 tx_slot_count, rx_slot_count, mask_sel,
591 tx_window, rx_window, rx_mask[mask_sel], rx_bad, rx_good,
592 *ul_slots, *dl_slots);
593#endif
594
595 /* Check compliance with TS 45.002, table 6.4.2.2.1 */
596 /* Whether to skip this round doesn not only depend on the bit
597 * sets but also on mask_sel. Therefore this check must be done
598 * before doing the test_and_set_bit shortcut. */
Max842d7812017-11-01 18:11:24 +0100599 if (Type == 1) {
Jacob Erlbeckbae33a72015-07-06 14:55:13 +0200600 unsigned slot_sum = rx_slot_count + tx_slot_count;
601 /* Assume down+up/dynamic.
602 * TODO: For ext-dynamic, down only, up only add more
603 * cases.
604 */
605 if (slot_sum <= 6 && tx_slot_count < 3) {
606 if (mask_sel != MASK_TR)
607 /* Skip Tta */
608 continue;
609 } else if (slot_sum > 6 && tx_slot_count < 3) {
610 if (mask_sel != MASK_TT)
611 /* Skip Tra */
612 continue;
613 } else {
614 /* No supported row in table 6.4.2.2.1. */
615#ifdef ENABLE_TS_ALLOC_DEBUG
616 LOGP(DRLCMAC, LOGL_DEBUG,
617 "- Skipping DL/UL slots: (TS=0)\"%s\"(TS=7), "
618 "combination not supported\n",
619 set_flag_chars(set_flag_chars(set_flag_chars(
620 slot_info,
621 rx_bad, 'x', '.'),
622 rx_window, 'D'),
623 tx_window, 'U'));
624#endif
625 continue;
626 }
627 }
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200628
629 /* Avoid repeated RX combination check */
630 if (test_and_set_bit(checked_rx, rx_window))
631 continue;
632
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200633 if (!rx_good) {
Jacob Erlbeck1653f832015-06-30 14:48:13 +0200634#ifdef ENABLE_TS_ALLOC_DEBUG
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200635 LOGP(DRLCMAC, LOGL_DEBUG,
636 "- Skipping DL/UL slots: (TS=0)\"%s\"(TS=7), "
637 "no DL slots available\n",
638 set_flag_chars(set_flag_chars(slot_info,
639 rx_bad, 'x', '.'),
640 tx_window, 'U'));
Jacob Erlbeck1653f832015-06-30 14:48:13 +0200641#endif
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200642 continue;
643 }
644
645 if (!rx_window)
646 continue;
647
648 /* Check number of common slots according to TS 54.002, 6.4.2.2 */
Jacob Erlbeck8cba7e92016-01-19 15:48:03 +0100649 common_slot_count = pcu_bitcount(tx_window & rx_window);
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200650 req_common_slots = OSMO_MIN(tx_slot_count, rx_slot_count);
Max842d7812017-11-01 18:11:24 +0100651 if (Type == 1)
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200652 req_common_slots = OSMO_MIN(req_common_slots, 2);
653
654 if (req_common_slots != common_slot_count) {
Jacob Erlbeck1653f832015-06-30 14:48:13 +0200655#ifdef ENABLE_TS_ALLOC_DEBUG
656 LOGP(DRLCMAC, LOGL_DEBUG,
657 "- Skipping DL/UL slots: (TS=0)\"%s\"(TS=7), "
658 "invalid number of common TS: %d (expected %d)\n",
659 set_flag_chars(set_flag_chars(set_flag_chars(
660 slot_info,
661 rx_bad, 'x', '.'),
662 rx_window, 'D'),
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200663 tx_window, 'U'),
Jacob Erlbeck1653f832015-06-30 14:48:13 +0200664 common_slot_count,
665 req_common_slots);
666#endif
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200667 continue;
668 }
669
670 /* Compute capacity */
671 capacity = 0;
672
673 for (ts = 0; ts < ARRAY_SIZE(trx->pdch); ts++) {
674 int c;
675 struct gprs_rlcmac_pdch *pdch = &trx->pdch[ts];
676 if (rx_window & (1 << ts)) {
677 c = 32 - pdch->num_reserved(GPRS_RLCMAC_DL_TBF);
Jacob Erlbeck9ae28232015-07-01 12:27:30 +0200678 c = OSMO_MAX(c, 1);
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200679 capacity += c;
680 }
Jacob Erlbecked46afd2015-07-01 12:19:40 +0200681 /* Only consider common slots for UL */
682 if (tx_window & rx_window & (1 << ts)) {
Jacob Erlbeck16c6ecc2015-06-30 13:40:18 +0200683 if (find_free_usf(pdch) >= 0) {
684 c = 32 - pdch->num_reserved(GPRS_RLCMAC_UL_TBF);
685 c = OSMO_MAX(c, 1);
686 capacity += c;
687 }
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200688 }
689 }
690
Jacob Erlbeck1653f832015-06-30 14:48:13 +0200691#ifdef ENABLE_TS_ALLOC_DEBUG
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200692 LOGP(DRLCMAC, LOGL_DEBUG,
693 "- Considering DL/UL slots: (TS=0)\"%s\"(TS=7), "
694 "capacity = %d\n",
695 set_flag_chars(set_flag_chars(set_flag_chars(set_flag_chars(
696 slot_info,
697 rx_bad, 'x', '.'),
698 rx_window, 'D'),
699 tx_window, 'U'),
700 rx_window & tx_window, 'C'),
701 capacity);
Jacob Erlbeck1653f832015-06-30 14:48:13 +0200702#endif
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200703
704 if (capacity <= max_capacity)
705 continue;
706
707 max_capacity = capacity;
708 max_ul_slots = tx_window;
709 max_dl_slots = rx_window;
710 }}}}
711
712 if (!max_ul_slots || !max_dl_slots) {
713 LOGP(DRLCMAC, LOGL_NOTICE,
714 "No valid UL/DL slot combination found\n");
715 return -EINVAL;
716 }
717
718 *ul_slots = max_ul_slots;
719 *dl_slots = max_dl_slots;
720
721 return 0;
722}
723
724/* Slot Allocation: Algorithm B
725 *
726 * Assign as many downlink slots as possible.
727 * Assign one uplink slot. (With free USF)
728 *
729 */
730int alloc_algorithm_b(struct gprs_rlcmac_bts *bts,
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200731 GprsMs *ms_, struct gprs_rlcmac_tbf *tbf_,
732 uint32_t cust, uint8_t single, int use_trx)
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200733{
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200734 uint8_t dl_slots;
735 uint8_t ul_slots;
736 uint8_t reserved_dl_slots;
737 uint8_t reserved_ul_slots;
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200738 int8_t first_common_ts;
739 uint8_t slotcount = 0;
740 uint8_t avail_count = 0;
741 char slot_info[9] = {0};
742 int ts;
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200743 int first_ts = -1;
744 int usf[8] = {-1, -1, -1, -1, -1, -1, -1, -1};
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200745 int rc;
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200746 int tfi;
Jacob Erlbeck5879c642015-07-10 10:41:36 +0200747 int trx_no;
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200748 const GprsMs *ms = ms_;
749 const gprs_rlcmac_tbf *tbf = tbf_;
750 gprs_rlcmac_trx *trx;
Jacob Erlbeck5879c642015-07-10 10:41:36 +0200751
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200752 /* Step 1: Get current state from the MS object */
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200753
754 if (!ms) {
755 LOGP(DRLCMAC, LOGL_ERROR, "MS not set\n");
756 return -EINVAL;
757 }
758
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200759 reserved_dl_slots = dl_slots = ms->reserved_dl_slots();
760 reserved_ul_slots = ul_slots = ms->reserved_ul_slots();
761 first_common_ts = ms->first_common_ts();
762 trx = ms->current_trx();
763
764 if (trx) {
765 if (use_trx >= 0 && use_trx != trx->trx_no) {
766 LOGP(DRLCMAC, LOGL_ERROR,
767 "- Requested incompatible TRX %d (current is %d)\n",
768 use_trx, trx->trx_no);
769 return -EINVAL;
770 }
771 use_trx = trx->trx_no;
772 }
773
774 /* Step 2a: Find usable TRX and TFI */
775 tfi = tfi_find_free(bts->bts, ms, tbf->direction, use_trx, &trx_no);
776 if (tfi < 0) {
777 LOGP(DRLCMAC, LOGL_NOTICE, "- Failed to allocate a TFI\n");
778 return tfi;
779 }
780
781 /* Step 2b: Reserve slots on the TRX for the MS */
782 if (!trx)
783 trx = &bts->trx[trx_no];
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200784
785 if (!dl_slots || !ul_slots) {
Max842d7812017-11-01 18:11:24 +0100786 rc = find_multi_slots(trx, ms->ms_class(), &ul_slots, &dl_slots);
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100787 if (rc < 0)
788 return rc;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200789
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200790 reserved_dl_slots = dl_slots;
791 reserved_ul_slots = ul_slots;
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200792 }
793
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200794 /* Step 3: Derive the slot set for the current TBF */
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200795 if (single) {
796 /* Make sure to consider the first common slot only */
797 ul_slots = dl_slots = dl_slots & ul_slots;
798
799 ts = first_common_ts;
800
801 if (ts < 0)
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200802 ts = find_least_busy_pdch(trx, tbf->direction,
Jacob Erlbeckc135b872015-07-09 13:44:18 +0200803 dl_slots & ul_slots, compute_usage_by_num_tbfs,
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200804 NULL, NULL);
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200805 if (ts < 0)
Jacob Erlbeck8cba7e92016-01-19 15:48:03 +0100806 ul_slots = dl_slots = pcu_lsb(dl_slots & ul_slots);
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200807 else
808 ul_slots = dl_slots = (dl_slots & ul_slots) & (1<<ts);
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200809 }
810
811 if (dl_slots == 0) {
812 LOGP(DRLCMAC, LOGL_NOTICE, "No downlink slots available\n");
813 return -EINVAL;
814 }
815
816 if (ul_slots == 0) {
817 LOGP(DRLCMAC, LOGL_NOTICE, "No uplink slots available\n");
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200818 return -EINVAL;
819 }
820
821 if (tbf->direction == GPRS_RLCMAC_DL_TBF) {
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200822 LOGP(DRLCMAC, LOGL_DEBUG,
823 "- Selected DL slots: (TS=0)\"%s\"(TS=7)%s\n",
824 set_flag_chars(set_flag_chars(slot_info,
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200825 reserved_dl_slots, 'd', '.'),
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200826 dl_slots, 'D'),
827 single ? ", single" : "");
828
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200829 /* assign downlink */
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200830 if (dl_slots == 0) {
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200831 LOGP(DRLCMAC, LOGL_NOTICE, "No downlink slots "
832 "available\n");
833 return -EINVAL;
834 }
Jacob Erlbeck8cba7e92016-01-19 15:48:03 +0100835 slotcount = pcu_bitcount(dl_slots);
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200836 first_ts = ffs(dl_slots) - 1;
Jacob Erlbeck8cba7e92016-01-19 15:48:03 +0100837 avail_count = pcu_bitcount(reserved_dl_slots);
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200838
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200839 } else {
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200840 int free_usf = -1;
Daniel Willmanncf1fae72014-05-30 17:58:01 +0200841
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200842 if (first_common_ts >= 0)
843 ul_slots = 1 << first_common_ts;
844 else
845 ul_slots = ul_slots & dl_slots;
846
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200847 ts = find_least_busy_pdch(trx, GPRS_RLCMAC_UL_TBF,
Jacob Erlbeckc135b872015-07-09 13:44:18 +0200848 ul_slots, compute_usage_by_num_tbfs,
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200849 NULL, &free_usf);
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200850
851 if (free_usf < 0) {
852 LOGP(DRLCMAC, LOGL_NOTICE, "No USF available\n");
853 return -EBUSY;
854 }
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200855 OSMO_ASSERT(ts >= 0 && ts <= 8);
856
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200857 ul_slots = 1 << ts;
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200858 usf[ts] = free_usf;
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200859
860 LOGP(DRLCMAC, LOGL_DEBUG,
861 "- Selected UL slots: (TS=0)\"%s\"(TS=7)%s\n",
862 set_flag_chars(set_flag_chars(slot_info,
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200863 reserved_ul_slots, 'u', '.'),
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200864 ul_slots, 'U'),
865 single ? ", single" : "");
866
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200867 slotcount++;
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200868 first_ts = ts;
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200869
Jacob Erlbeck5f494b82015-07-01 13:10:41 +0200870 /* We will stick to that single UL slot, unreserve the others */
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200871 reserved_ul_slots = ul_slots;
Jacob Erlbeck5f494b82015-07-01 13:10:41 +0200872
Jacob Erlbeck8cba7e92016-01-19 15:48:03 +0100873 avail_count = pcu_bitcount(reserved_ul_slots);
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200874 }
875
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200876 first_common_ts = ffs(dl_slots & ul_slots) - 1;
877
878 if (first_common_ts < 0) {
879 LOGP(DRLCMAC, LOGL_NOTICE, "No first common slots available\n");
880 return -EINVAL;
881 }
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200882 if (first_ts < 0) {
883 LOGP(DRLCMAC, LOGL_NOTICE, "No first slot available\n");
884 return -EINVAL;
885 }
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200886
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200887 if (single && slotcount) {
888 tbf_->upgrade_to_multislot = (avail_count > slotcount);
889 LOGP(DRLCMAC, LOGL_INFO, "Using single slot at TS %d for %s\n",
890 first_ts,
891 (tbf->direction == GPRS_RLCMAC_DL_TBF) ? "DL" : "UL");
892 } else {
893 tbf_->upgrade_to_multislot = 0;
894 LOGP(DRLCMAC, LOGL_INFO, "Using %d slots for %s\n", slotcount,
895 (tbf->direction == GPRS_RLCMAC_DL_TBF) ? "DL" : "UL");
896 }
897
898 /* The allocation will be successful, so the system state and tbf_/ms_
899 * may be modified from now on. */
900
901 /* Step 4: Update MS and TBF and really allocate the resources */
902
903 /* The reserved slots have changed, update the MS */
904 if (reserved_ul_slots != ms->reserved_ul_slots() ||
905 reserved_dl_slots != ms->reserved_dl_slots())
906 {
907 ms_->set_reserved_slots(trx,
908 reserved_ul_slots, reserved_dl_slots);
909
910 LOGP(DRLCMAC, LOGL_DEBUG,
911 "- Reserved DL/UL slots: (TS=0)\"%s\"(TS=7)\n",
912 set_flag_chars(set_flag_chars(set_flag_chars(slot_info,
913 dl_slots, 'D', '.'),
914 ul_slots, 'U'),
915 ul_slots & dl_slots, 'C'));
916 }
917
918 tbf_->trx = trx;
919 tbf_->first_common_ts = first_common_ts;
920 tbf_->first_ts = first_ts;
921
922 if (tbf->direction == GPRS_RLCMAC_DL_TBF) {
Jacob Erlbeckaa9daa12015-12-28 18:49:12 +0100923 struct gprs_rlcmac_dl_tbf *dl_tbf = as_dl_tbf(tbf_);
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200924 for (ts = 0; ts < 8; ts++) {
925 if (!(dl_slots & (1 << ts)))
926 continue;
927
928 LOGP(DRLCMAC, LOGL_DEBUG, "- Assigning DL TS "
929 "%d\n", ts);
930 assign_dlink_tbf(&trx->pdch[ts], dl_tbf, tfi);
931 }
932 } else {
Jacob Erlbeckaa9daa12015-12-28 18:49:12 +0100933 struct gprs_rlcmac_ul_tbf *ul_tbf = as_ul_tbf(tbf_);
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200934
935 for (ts = 0; ts < 8; ts++) {
936 if (!(ul_slots & (1 << ts)))
937 continue;
938
939 OSMO_ASSERT(usf[ts] >= 0);
940
941 LOGP(DRLCMAC, LOGL_DEBUG, "- Assigning UL TS "
942 "%d\n", ts);
943 assign_uplink_tbf_usf(&trx->pdch[ts], ul_tbf,
944 tfi, usf[ts]);
945 }
946 }
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200947
Jacob Erlbeck5979fe92015-07-14 14:02:41 +0200948 bts->bts->tbf_alloc_algo_b();
949
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200950 return 0;
951}
Jacob Erlbeck400ec022015-07-14 13:31:48 +0200952
953/* Slot Allocation: Algorithm dynamic
954 *
955 * This meta algorithm automatically selects on of the other algorithms based
956 * on the current system state.
957 *
958 * The goal is to support as many MS and TBF as possible. On low usage, the
959 * goal is to provide the highest possible bandwidth per MS.
960 *
961 */
962int alloc_algorithm_dynamic(struct gprs_rlcmac_bts *bts,
963 GprsMs *ms_, struct gprs_rlcmac_tbf *tbf_,
964 uint32_t cust, uint8_t single, int use_trx)
965{
966 int rc;
967
Jacob Erlbeck77da3552015-07-16 18:33:46 +0200968 /* Reset load_is_high if there is at least one idle PDCH */
969 if (bts->multislot_disabled) {
970 bts->multislot_disabled = find_idle_pdch(bts->bts) == NULL;
971 if (!bts->multislot_disabled)
972 LOGP(DRLCMAC, LOGL_DEBUG, "Enabling algorithm B\n");
973 }
974
975 if (!bts->multislot_disabled) {
976 rc = alloc_algorithm_b(bts, ms_, tbf_, cust, single, use_trx);
977 if (rc >= 0)
978 return rc;
979
980 if (!bts->multislot_disabled)
981 LOGP(DRLCMAC, LOGL_DEBUG, "Disabling algorithm B\n");
982 bts->multislot_disabled = 1;
983 }
Jacob Erlbeck400ec022015-07-14 13:31:48 +0200984
985 rc = alloc_algorithm_a(bts, ms_, tbf_, cust, single, use_trx);
986 return rc;
987}
Jacob Erlbeck7f79f0d2015-07-17 11:38:49 +0200988
989int gprs_alloc_max_dl_slots_per_ms(struct gprs_rlcmac_bts *bts, uint8_t ms_class)
990{
Max842d7812017-11-01 18:11:24 +0100991 int rx = mslot_class_get_rx(ms_class);
Jacob Erlbeck7f79f0d2015-07-17 11:38:49 +0200992
993 if (rx == MS_NA)
994 rx = 4;
995
996 if (bts->alloc_algorithm == alloc_algorithm_a)
997 return 1;
998
999 if (bts->multislot_disabled)
1000 return 1;
1001
1002 return rx;
1003}