blob: 7be9654df2ceca10f939c54e8de473c3ad1ebd86 [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"
Max1187a772018-01-26 13:31:42 +010034#include <osmocom/core/linuxlist.h>
35#include <osmocom/core/logging.h>
36#include <osmocom/core/utils.h>
Max842d7812017-11-01 18:11:24 +010037}
38
Jacob Erlbeck77da3552015-07-16 18:33:46 +020039/* Consider a PDCH as idle if has at most this number of TBFs assigned to it */
40#define PDCH_IDLE_TBF_THRESH 1
41
Jacob Erlbeckea65c722015-06-22 16:14:23 +020042static char *set_flag_chars(char *buf, uint8_t val, char set_char, char unset_char = 0)
43{
44 int i;
45
46 for (i = 0; i < 8; i += 1, val = val >> 1) {
47 if (val & 1)
48 buf[i] = set_char;
49 else if (unset_char)
50 buf[i] = unset_char;
51 }
52
53 return buf;
54}
55
56static bool test_and_set_bit(uint32_t *bits, size_t elem)
57{
58 bool was_set = bits[elem/32] & (1 << (elem % 32));
59 bits[elem/32] |= (1 << (elem % 32));
60
61 return was_set;
62}
63
Maxa76a7d02018-01-26 11:09:16 +010064static inline int8_t find_free_usf(const struct gprs_rlcmac_pdch *pdch)
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +020065{
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +020066 uint8_t usf_map = 0;
Jacob Erlbeck20b7ba72015-06-30 14:34:24 +020067 uint8_t usf;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +020068
Jacob Erlbeck20b7ba72015-06-30 14:34:24 +020069 usf_map = pdch->assigned_usf();
70 if (usf_map == (1 << 7) - 1)
71 return -1;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +020072
73 /* look for USF, don't use USF=7 */
74 for (usf = 0; usf < 7; usf++) {
75 if (!(usf_map & (1 << usf)))
76 return usf;
77 }
78
79 return -1;
80}
81
Maxa76a7d02018-01-26 11:09:16 +010082static inline int8_t find_free_tfi(const struct gprs_rlcmac_pdch *pdch, enum gprs_rlcmac_tbf_direction dir)
Jacob Erlbecke0853cd2015-07-10 12:25:25 +020083{
Maxa76a7d02018-01-26 11:09:16 +010084 uint32_t tfi_map = pdch->assigned_tfi(dir);
Jacob Erlbecke0853cd2015-07-10 12:25:25 +020085 int8_t tfi;
86
Maxd000d802017-09-20 17:55:28 +020087 if (tfi_map == NO_FREE_TFI)
Jacob Erlbecke0853cd2015-07-10 12:25:25 +020088 return -1;
89
90 /* look for USF, don't use USF=7 */
91 for (tfi = 0; tfi < 32; tfi++) {
92 if (!(tfi_map & (1 << tfi)))
93 return tfi;
94 }
95
96 return -1;
97}
98
Maxa76a7d02018-01-26 11:09:16 +010099static int find_possible_pdchs(const struct gprs_rlcmac_trx *trx, size_t max_slots, uint8_t mask,
100 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++) {
Maxa76a7d02018-01-26 11:09:16 +0100107 const struct gprs_rlcmac_pdch *pdch;
Holger Hans Peter Freytherb0a00752013-09-29 08:18:17 +0200108
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
Maxa76a7d02018-01-26 11:09:16 +0100145static int compute_usage_by_num_tbfs(const struct gprs_rlcmac_pdch *pdch, enum gprs_rlcmac_tbf_direction dir)
Jacob Erlbeckc135b872015-07-09 13:44:18 +0200146{
147 return pdch->num_tbfs(dir);
148}
149
Maxa76a7d02018-01-26 11:09:16 +0100150static int compute_usage_by_reservation(const struct gprs_rlcmac_pdch *pdch, enum gprs_rlcmac_tbf_direction)
Jacob Erlbeckc135b872015-07-09 13:44:18 +0200151{
152 return
153 pdch->num_reserved(GPRS_RLCMAC_DL_TBF) +
154 pdch->num_reserved(GPRS_RLCMAC_UL_TBF);
155}
156
Maxa76a7d02018-01-26 11:09:16 +0100157static int compute_usage_for_algo_a(const struct gprs_rlcmac_pdch *pdch, enum gprs_rlcmac_tbf_direction dir)
Jacob Erlbeck7af53e62015-07-16 15:04:07 +0200158{
159 int usage =
160 pdch->num_tbfs(GPRS_RLCMAC_DL_TBF) +
161 pdch->num_tbfs(GPRS_RLCMAC_UL_TBF) +
162 compute_usage_by_reservation(pdch, dir);
163
Maxd000d802017-09-20 17:55:28 +0200164 if (pdch->assigned_tfi(reverse(dir)) == NO_FREE_TFI)
Jacob Erlbeck7af53e62015-07-16 15:04:07 +0200165 /* No TFI in the opposite direction, avoid it */
166 usage += 32;
167
168 return usage;
169
170}
171
Maxa76a7d02018-01-26 11:09:16 +0100172/*! Return the TS which corresponds to least busy PDCH
173 *
174 * \param[in] trx Pointer to TRX object
175 * \param[in] dir TBF direction
176 * \param[in] mask set of available timeslots
177 * \param[in] fn Function pointer to function which computes number of associated TBFs
178 * \param[out] free_tfi Free TFI
179 * \param[out] free_usf Free USF
180 * \returns TS number or -1 if unable to find
181 */
182static int find_least_busy_pdch(const struct gprs_rlcmac_trx *trx, enum gprs_rlcmac_tbf_direction dir, uint8_t mask,
183 int (*fn)(const struct gprs_rlcmac_pdch *, enum gprs_rlcmac_tbf_direction dir),
184 int *free_tfi = 0, int *free_usf = 0)
Jacob Erlbeckec478752015-06-19 16:35:38 +0200185{
186 unsigned ts;
187 int min_used = INT_MAX;
188 int min_ts = -1;
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200189 int min_tfi = -1;
Jacob Erlbeckec478752015-06-19 16:35:38 +0200190 int min_usf = -1;
191
192 for (ts = 0; ts < ARRAY_SIZE(trx->pdch); ts++) {
Maxa76a7d02018-01-26 11:09:16 +0100193 const struct gprs_rlcmac_pdch *pdch = &trx->pdch[ts];
Jacob Erlbeckec478752015-06-19 16:35:38 +0200194 int num_tbfs;
195 int usf = -1; /* must be signed */
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200196 int tfi = -1;
Jacob Erlbeckec478752015-06-19 16:35:38 +0200197
198 if (((1 << ts) & mask) == 0)
199 continue;
200
Jacob Erlbeckc135b872015-07-09 13:44:18 +0200201 num_tbfs = fn(pdch, dir);
Jacob Erlbeckefe62a72015-07-02 15:48:25 +0200202
203 if (num_tbfs < min_used) {
204 /* We have found a candidate */
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200205 /* Make sure that a TFI is available */
206 if (free_tfi) {
207 tfi = find_free_tfi(pdch, dir);
208 if (tfi < 0) {
209 LOGP(DRLCMAC, LOGL_DEBUG,
210 "- Skipping TS %d, because "
211 "no TFI available\n", ts);
212 continue;
213 }
214 }
Jacob Erlbeckefe62a72015-07-02 15:48:25 +0200215 /* Make sure that an USF is available */
216 if (dir == GPRS_RLCMAC_UL_TBF) {
217 usf = find_free_usf(pdch);
218 if (usf < 0) {
219 LOGP(DRLCMAC, LOGL_DEBUG,
220 "- Skipping TS %d, because "
221 "no USF available\n", ts);
222 continue;
223 }
224 }
225 if (min_ts >= 0)
226 LOGP(DRLCMAC, LOGL_DEBUG,
227 "- Skipping TS %d, because "
228 "num TBFs %d > %d\n",
229 min_ts, min_used, num_tbfs);
230 min_used = num_tbfs;
231 min_ts = ts;
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200232 min_tfi = tfi;
Jacob Erlbeckefe62a72015-07-02 15:48:25 +0200233 min_usf = usf;
234 } else {
235 LOGP(DRLCMAC, LOGL_DEBUG,
236 "- Skipping TS %d, because "
237 "num TBFs %d >= %d\n",
238 ts, num_tbfs, min_used);
239 }
240 }
241
242 if (min_ts < 0)
243 return -1;
244
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200245 if (free_tfi)
246 *free_tfi = min_tfi;
Jacob Erlbeckefe62a72015-07-02 15:48:25 +0200247 if (free_usf)
248 *free_usf = min_usf;
249
250 return min_ts;
251}
252
Jacob Erlbeckccc34e42015-06-29 13:45:05 +0200253static void attach_tbf_to_pdch(struct gprs_rlcmac_pdch *pdch,
254 struct gprs_rlcmac_tbf *tbf)
255{
256 if (tbf->pdch[pdch->ts_no])
257 tbf->pdch[pdch->ts_no]->detach_tbf(tbf);
258
259 tbf->pdch[pdch->ts_no] = pdch;
260 pdch->attach_tbf(tbf);
261}
262
Maxa76a7d02018-01-26 11:09:16 +0100263static void assign_uplink_tbf_usf(struct gprs_rlcmac_pdch *pdch, struct gprs_rlcmac_ul_tbf *tbf, uint8_t tfi, int8_t usf)
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200264{
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200265 tbf->m_tfi = tfi;
Daniel Willmann7e994e32014-08-07 15:49:21 +0200266 tbf->m_usf[pdch->ts_no] = usf;
Jacob Erlbeckccc34e42015-06-29 13:45:05 +0200267 attach_tbf_to_pdch(pdch, tbf);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200268}
269
Maxa76a7d02018-01-26 11:09:16 +0100270static void assign_dlink_tbf(struct gprs_rlcmac_pdch *pdch, struct gprs_rlcmac_dl_tbf *tbf, uint8_t tfi)
Holger Hans Peter Freyther8481a052013-09-29 08:08:28 +0200271{
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200272 tbf->m_tfi = tfi;
Jacob Erlbeckccc34e42015-06-29 13:45:05 +0200273 attach_tbf_to_pdch(pdch, tbf);
Holger Hans Peter Freyther8481a052013-09-29 08:08:28 +0200274}
275
Maxa76a7d02018-01-26 11:09:16 +0100276static int find_trx(const struct gprs_rlcmac_bts *bts_data, const GprsMs *ms, int8_t use_trx)
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200277{
278 unsigned trx_no;
279 unsigned ts;
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200280
281 /* We must use the TRX currently actively used by an MS */
282 if (ms && ms->current_trx())
283 return ms->current_trx()->trx_no;
284
285 if (use_trx >= 0 && use_trx < 8)
286 return use_trx;
287
288 /* Find the first TRX that has a PDCH with a free UL and DL TFI */
289 for (trx_no = 0; trx_no < ARRAY_SIZE(bts_data->trx); trx_no += 1) {
Maxa76a7d02018-01-26 11:09:16 +0100290 const struct gprs_rlcmac_trx *trx = &bts_data->trx[trx_no];
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200291 for (ts = 0; ts < ARRAY_SIZE(trx->pdch); ts++) {
Maxa76a7d02018-01-26 11:09:16 +0100292 const struct gprs_rlcmac_pdch *pdch = &trx->pdch[ts];
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200293 if (!pdch->is_enabled())
294 continue;
295
Maxd000d802017-09-20 17:55:28 +0200296 if (pdch->assigned_tfi(GPRS_RLCMAC_UL_TBF) == NO_FREE_TFI)
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200297 continue;
298
Maxd000d802017-09-20 17:55:28 +0200299 if (pdch->assigned_tfi(GPRS_RLCMAC_DL_TBF) == NO_FREE_TFI)
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200300 continue;
301
302 return trx_no;
303 }
304 }
305
306 return -EBUSY;
307}
308
Maxa76a7d02018-01-26 11:09:16 +0100309static bool idle_pdch_avail(const struct gprs_rlcmac_bts *bts_data)
Jacob Erlbeck77da3552015-07-16 18:33:46 +0200310{
311 unsigned trx_no;
312 unsigned ts;
Jacob Erlbeck77da3552015-07-16 18:33:46 +0200313
314 /* Find the first PDCH with an unused DL TS */
315 for (trx_no = 0; trx_no < ARRAY_SIZE(bts_data->trx); trx_no += 1) {
Maxa76a7d02018-01-26 11:09:16 +0100316 const struct gprs_rlcmac_trx *trx = &bts_data->trx[trx_no];
Jacob Erlbeck77da3552015-07-16 18:33:46 +0200317 for (ts = 0; ts < ARRAY_SIZE(trx->pdch); ts++) {
Maxa76a7d02018-01-26 11:09:16 +0100318 const struct gprs_rlcmac_pdch *pdch = &trx->pdch[ts];
Jacob Erlbeck77da3552015-07-16 18:33:46 +0200319 if (!pdch->is_enabled())
320 continue;
321
322 if (pdch->num_tbfs(GPRS_RLCMAC_DL_TBF) > PDCH_IDLE_TBF_THRESH)
323 continue;
324
Maxa76a7d02018-01-26 11:09:16 +0100325 return true;
Jacob Erlbeck77da3552015-07-16 18:33:46 +0200326 }
327 }
328
Maxa76a7d02018-01-26 11:09:16 +0100329 return false;
Jacob Erlbeck77da3552015-07-16 18:33:46 +0200330}
331
Maxa76a7d02018-01-26 11:09:16 +0100332/*! Return free TFI
333 *
334 * \param[in] bts Pointer to BTS struct
Max7e4921d2017-09-28 16:41:24 +0200335 * \param[in] trx Optional pointer to TRX struct
Maxa76a7d02018-01-26 11:09:16 +0100336 * \param[in] ms Pointer to MS object
337 * \param[in] dir DL or UL direction
338 * \param[in] use_trx which TRX to use or -1 if it should be selected based on what MS uses
339 * \param[out] trx_no_ TRX number on which TFI was found
340 * \returns negative error code or 0 on success
341 */
342static int tfi_find_free(const BTS *bts, const gprs_rlcmac_trx *trx, const GprsMs *ms,
343 enum gprs_rlcmac_tbf_direction dir, int8_t use_trx, uint8_t *trx_no_)
Jacob Erlbeck5879c642015-07-10 10:41:36 +0200344{
345 int tfi;
346 uint8_t trx_no;
347
Max7e4921d2017-09-28 16:41:24 +0200348 if (trx) {
349 if (use_trx >= 0 && use_trx != trx->trx_no) {
350 LOGP(DRLCMAC, LOGL_ERROR, "- Requested incompatible TRX %d (current is %d)\n",
351 use_trx, trx->trx_no);
352 return -EINVAL;
353 }
354 use_trx = trx->trx_no;
355 }
356
Jacob Erlbeck5879c642015-07-10 10:41:36 +0200357 if (use_trx == -1 && ms->current_trx())
358 use_trx = ms->current_trx()->trx_no;
359
360 tfi = bts->tfi_find_free(dir, &trx_no, use_trx);
361 if (tfi < 0)
362 return -EBUSY;
363
364 if (trx_no_)
365 *trx_no_ = trx_no;
366
367 return tfi;
368}
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200369
Maxe9fe0e32017-09-28 15:56:05 +0200370/*! Slot Allocation: Algorithm A
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200371 *
372 * Assign single slot for uplink and downlink
Maxe9fe0e32017-09-28 15:56:05 +0200373 *
374 * \param[in,out] bts Pointer to BTS struct
375 * \param[in,out] ms_ Pointer to MS object
376 * \param[in,out] tbf_ Pointer to TBF struct
377 * \param[in] single flag indicating if we should force single-slot allocation
378 * \param[in] use_trx which TRX to use or -1 if it should be selected during allocation
379 * \returns negative error code or 0 on success
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200380 */
Maxe9fe0e32017-09-28 15:56:05 +0200381int alloc_algorithm_a(struct gprs_rlcmac_bts *bts, GprsMs *ms_, struct gprs_rlcmac_tbf *tbf_, bool single,
382 int8_t use_trx)
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200383{
384 struct gprs_rlcmac_pdch *pdch;
Jacob Erlbeckec478752015-06-19 16:35:38 +0200385 int ts = -1;
Jacob Erlbeck5cd496d2015-06-30 10:24:37 +0200386 uint8_t ul_slots, dl_slots;
Jacob Erlbeck5879c642015-07-10 10:41:36 +0200387 int trx_no;
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200388 int tfi = -1;
Jacob Erlbeckec478752015-06-19 16:35:38 +0200389 int usf = -1;
390 int mask = 0xff;
391 const char *mask_reason = NULL;
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200392 const GprsMs *ms = ms_;
393 const gprs_rlcmac_tbf *tbf = tbf_;
394 gprs_rlcmac_trx *trx = ms->current_trx();
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200395
396 LOGP(DRLCMAC, LOGL_DEBUG, "Slot Allocation (Algorithm A) for class "
Jacob Erlbeckbefc7602015-06-02 12:33:30 +0200397 "%d\n", tbf->ms_class());
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200398
Maxa76a7d02018-01-26 11:09:16 +0100399 trx_no = find_trx(bts, ms, use_trx);
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200400 if (trx_no < 0) {
401 LOGP(DRLCMAC, LOGL_NOTICE,
402 "- Failed to find a usable TRX (TFI exhausted)\n");
403 return trx_no;
Jacob Erlbeck5879c642015-07-10 10:41:36 +0200404 }
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200405 if (!trx)
406 trx = &bts->trx[trx_no];
Jacob Erlbeck5879c642015-07-10 10:41:36 +0200407
Jacob Erlbeck5cd496d2015-06-30 10:24:37 +0200408 dl_slots = ms->reserved_dl_slots();
409 ul_slots = ms->reserved_ul_slots();
410
411 ts = ms->first_common_ts();
412
413 if (ts >= 0) {
Jacob Erlbeckec478752015-06-19 16:35:38 +0200414 mask_reason = "need to reuse TS";
Jacob Erlbeckec478752015-06-19 16:35:38 +0200415 mask = 1 << ts;
Jacob Erlbeck5cd496d2015-06-30 10:24:37 +0200416 } else if (dl_slots || ul_slots) {
417 mask_reason = "need to use a reserved common TS";
418 mask = dl_slots & ul_slots;
419 }
Jacob Erlbeckec478752015-06-19 16:35:38 +0200420
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200421 mask = find_possible_pdchs(trx, 1, mask, mask_reason);
Jacob Erlbeckec478752015-06-19 16:35:38 +0200422 if (!mask)
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200423 return -EINVAL;
424
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200425 ts = find_least_busy_pdch(trx, tbf->direction, mask,
Jacob Erlbeck7af53e62015-07-16 15:04:07 +0200426 compute_usage_for_algo_a,
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200427 &tfi, &usf);
Jacob Erlbeckec478752015-06-19 16:35:38 +0200428
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200429 if (tbf->direction == GPRS_RLCMAC_UL_TBF && usf < 0) {
Jacob Erlbeckec478752015-06-19 16:35:38 +0200430 LOGP(DRLCMAC, LOGL_NOTICE, "- Failed "
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200431 "to allocate a TS, no USF available\n");
Jacob Erlbeckec478752015-06-19 16:35:38 +0200432 return -EBUSY;
433 }
434
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200435 if (ts < 0) {
436 LOGP(DRLCMAC, LOGL_NOTICE, "- Failed "
437 "to allocate a TS, no TFI available\n");
438 return -EBUSY;
439 }
440
441 pdch = &trx->pdch[ts];
442
443 /* The allocation will be successful, so the system state and tbf_/ms_
444 * may be modified from now on. */
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200445 if (tbf->direction == GPRS_RLCMAC_UL_TBF) {
Jacob Erlbeckaa9daa12015-12-28 18:49:12 +0100446 struct gprs_rlcmac_ul_tbf *ul_tbf = as_ul_tbf(tbf_);
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200447 LOGP(DRLCMAC, LOGL_DEBUG, "- Assign uplink TS=%d TFI=%d USF=%d\n",
448 ts, tfi, usf);
449 assign_uplink_tbf_usf(pdch, ul_tbf, tfi, usf);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200450 } else {
Jacob Erlbeckaa9daa12015-12-28 18:49:12 +0100451 struct gprs_rlcmac_dl_tbf *dl_tbf = as_dl_tbf(tbf_);
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200452 LOGP(DRLCMAC, LOGL_DEBUG, "- Assign downlink TS=%d TFI=%d\n",
453 ts, tfi);
454 assign_dlink_tbf(pdch, dl_tbf, tfi);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200455 }
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200456
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200457 tbf_->trx = trx;
458 /* the only one TS is the common TS */
459 tbf_->first_ts = tbf_->first_common_ts = ts;
460 ms_->set_reserved_slots(trx, 1 << ts, 1 << ts);
461
462 tbf_->upgrade_to_multislot = 0;
Jacob Erlbeck5979fe92015-07-14 14:02:41 +0200463 bts->bts->tbf_alloc_algo_a();
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200464 return 0;
465}
466
Maxa76a7d02018-01-26 11:09:16 +0100467/*! Find set of slots available for allocation while taking MS class into account
468 *
469 * \param[in] trx Pointer to TRX object
470 * \param[in] mslot_class The multislot class
471 * \param[in,out] ul_slots set of UL timeslots
472 * \param[in,out] dl_slots set of DL timeslots
473 * \returns negative error code or 0 on success
474 */
Max46fbfce2017-11-01 19:22:25 +0100475int 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 +0200476{
Maxf633b8d2018-01-31 15:28:53 +0100477 uint8_t Tx = mslot_class_get_tx(mslot_class), /* Max number of Tx slots */
478 Sum = mslot_class_get_sum(mslot_class); /* Max number of Tx + Rx slots */
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200479 int rx_window, tx_window, pdch_slots;
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200480 char slot_info[9] = {0};
Maxf633b8d2018-01-31 15:28:53 +0100481 int max_capacity = -1;
482 uint8_t max_ul_slots = 0, max_dl_slots = 0;
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200483 unsigned max_slots;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200484
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200485 unsigned ul_ts, dl_ts;
486 unsigned num_tx;
Jacob Erlbeck5e46a202015-07-09 11:48:23 +0200487 unsigned mask_sel;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200488
Max842d7812017-11-01 18:11:24 +0100489 if (mslot_class)
490 LOGP(DRLCMAC, LOGL_DEBUG, "Slot Allocation (Algorithm B) for class %d\n",
491 mslot_class);
492
Max842d7812017-11-01 18:11:24 +0100493 if (Tx == MS_NA) {
494 LOGP(DRLCMAC, LOGL_NOTICE, "Multislot class %d not applicable.\n",
495 mslot_class);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200496 return -EINVAL;
497 }
498
Max842d7812017-11-01 18:11:24 +0100499 max_slots = OSMO_MAX(mslot_class_get_rx(mslot_class), Tx);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200500
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200501 if (*dl_slots == 0)
502 *dl_slots = 0xff;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200503
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200504 if (*ul_slots == 0)
505 *ul_slots = 0xff;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200506
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200507 pdch_slots = find_possible_pdchs(trx, max_slots, 0xff);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200508
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200509 *dl_slots &= pdch_slots;
510 *ul_slots &= pdch_slots;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200511
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200512 LOGP(DRLCMAC, LOGL_DEBUG, "- Possible DL/UL slots: (TS=0)\"%s\"(TS=7)\n",
513 set_flag_chars(set_flag_chars(set_flag_chars(slot_info,
514 *dl_slots, 'D', '.'),
515 *ul_slots, 'U'),
516 *ul_slots & *dl_slots, 'C'));
517
518 /* Check for each UL (TX) slot */
519
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200520 /* Iterate through possible numbers of TX slots */
Max842d7812017-11-01 18:11:24 +0100521 for (num_tx = 1; num_tx <= mslot_class_get_tx(mslot_class); num_tx += 1) {
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200522 uint16_t tx_valid_win = (1 << num_tx) - 1;
Maxf633b8d2018-01-31 15:28:53 +0100523 uint8_t rx_mask[MASK_TR + 1];
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200524
Maxf633b8d2018-01-31 15:28:53 +0100525 mslot_fill_rx_mask(mslot_class, num_tx, rx_mask);
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200526
527 /* Rotate group of TX slots: UUU-----, -UUU----, ..., UU-----U */
528 for (ul_ts = 0; ul_ts < 8; ul_ts += 1, tx_valid_win <<= 1) {
529 unsigned tx_slot_count;
530 int max_rx;
531 uint16_t rx_valid_win;
532 uint32_t checked_rx[256/32] = {0};
533
534 /* Wrap valid window */
535 tx_valid_win = (tx_valid_win | tx_valid_win >> 8) & 0xff;
536
537 tx_window = tx_valid_win;
538
539 /* Filter out unavailable slots */
540 tx_window &= *ul_slots;
541
Jacob Erlbecke21b79c2015-07-16 11:48:43 +0200542 /* Skip if the the first TS (ul_ts) is not in the set */
543 if ((tx_window & (1 << ul_ts)) == 0)
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200544 continue;
545
Jacob Erlbecke21b79c2015-07-16 11:48:43 +0200546 /* Skip if the the last TS (ul_ts+num_tx-1) is not in the set */
547 if ((tx_window & (1 << ((ul_ts+num_tx-1) % 8))) == 0)
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200548 continue;
549
Jacob Erlbeck8cba7e92016-01-19 15:48:03 +0100550 tx_slot_count = pcu_bitcount(tx_window);
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200551
Max842d7812017-11-01 18:11:24 +0100552 max_rx = OSMO_MIN(mslot_class_get_rx(mslot_class), Sum - num_tx);
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200553 rx_valid_win = (1 << max_rx) - 1;
554
555 /* Rotate group of RX slots: DDD-----, -DDD----, ..., DD-----D */
556 for (dl_ts = 0; dl_ts < 8; dl_ts += 1, rx_valid_win <<= 1) {
557 /* Wrap valid window */
558 rx_valid_win = (rx_valid_win | rx_valid_win >> 8) & 0xff;
559
560 /* Validate with both Tta/Ttb/Trb and Ttb/Tra/Trb */
Jacob Erlbeck5e46a202015-07-09 11:48:23 +0200561 for (mask_sel = MASK_TT; mask_sel <= MASK_TR; mask_sel += 1) {
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200562 unsigned common_slot_count;
563 unsigned req_common_slots;
564 unsigned rx_slot_count;
565 uint16_t rx_bad;
566 uint8_t rx_good;
567 unsigned ts;
568 int capacity;
569
570 /* Filter out bad slots */
Jacob Erlbeck5e46a202015-07-09 11:48:23 +0200571 rx_bad = (uint16_t)(0xff & ~rx_mask[mask_sel]) << ul_ts;
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200572 rx_bad = (rx_bad | (rx_bad >> 8)) & 0xff;
573 rx_good = *dl_slots & ~rx_bad;
574
575 /* TODO: CHECK this calculation -> separate function for unit
576 * testing */
577
578 rx_window = rx_good & rx_valid_win;
Jacob Erlbeck8cba7e92016-01-19 15:48:03 +0100579 rx_slot_count = pcu_bitcount(rx_window);
Jacob Erlbeckbae33a72015-07-06 14:55:13 +0200580
581#if 0
582 LOGP(DRLCMAC, LOGL_DEBUG, "n_tx=%d, n_rx=%d, mask_sel=%d, "
583 "tx=%02x, rx=%02x, mask=%02x, bad=%02x, good=%02x, "
584 "ul=%02x, dl=%02x\n",
585 tx_slot_count, rx_slot_count, mask_sel,
586 tx_window, rx_window, rx_mask[mask_sel], rx_bad, rx_good,
587 *ul_slots, *dl_slots);
588#endif
589
590 /* Check compliance with TS 45.002, table 6.4.2.2.1 */
591 /* Whether to skip this round doesn not only depend on the bit
592 * sets but also on mask_sel. Therefore this check must be done
593 * before doing the test_and_set_bit shortcut. */
Maxf633b8d2018-01-31 15:28:53 +0100594 if (mslot_class_get_type(mslot_class) == 1) {
Jacob Erlbeckbae33a72015-07-06 14:55:13 +0200595 unsigned slot_sum = rx_slot_count + tx_slot_count;
596 /* Assume down+up/dynamic.
597 * TODO: For ext-dynamic, down only, up only add more
598 * cases.
599 */
600 if (slot_sum <= 6 && tx_slot_count < 3) {
601 if (mask_sel != MASK_TR)
602 /* Skip Tta */
603 continue;
604 } else if (slot_sum > 6 && tx_slot_count < 3) {
605 if (mask_sel != MASK_TT)
606 /* Skip Tra */
607 continue;
608 } else {
609 /* No supported row in table 6.4.2.2.1. */
610#ifdef ENABLE_TS_ALLOC_DEBUG
611 LOGP(DRLCMAC, LOGL_DEBUG,
612 "- Skipping DL/UL slots: (TS=0)\"%s\"(TS=7), "
613 "combination not supported\n",
614 set_flag_chars(set_flag_chars(set_flag_chars(
615 slot_info,
616 rx_bad, 'x', '.'),
617 rx_window, 'D'),
618 tx_window, 'U'));
619#endif
620 continue;
621 }
622 }
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200623
624 /* Avoid repeated RX combination check */
625 if (test_and_set_bit(checked_rx, rx_window))
626 continue;
627
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200628 if (!rx_good) {
Jacob Erlbeck1653f832015-06-30 14:48:13 +0200629#ifdef ENABLE_TS_ALLOC_DEBUG
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200630 LOGP(DRLCMAC, LOGL_DEBUG,
631 "- Skipping DL/UL slots: (TS=0)\"%s\"(TS=7), "
632 "no DL slots available\n",
633 set_flag_chars(set_flag_chars(slot_info,
634 rx_bad, 'x', '.'),
635 tx_window, 'U'));
Jacob Erlbeck1653f832015-06-30 14:48:13 +0200636#endif
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200637 continue;
638 }
639
640 if (!rx_window)
641 continue;
642
643 /* Check number of common slots according to TS 54.002, 6.4.2.2 */
Jacob Erlbeck8cba7e92016-01-19 15:48:03 +0100644 common_slot_count = pcu_bitcount(tx_window & rx_window);
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200645 req_common_slots = OSMO_MIN(tx_slot_count, rx_slot_count);
Maxf633b8d2018-01-31 15:28:53 +0100646 if (mslot_class_get_type(mslot_class) == 1)
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200647 req_common_slots = OSMO_MIN(req_common_slots, 2);
648
649 if (req_common_slots != common_slot_count) {
Jacob Erlbeck1653f832015-06-30 14:48:13 +0200650#ifdef ENABLE_TS_ALLOC_DEBUG
651 LOGP(DRLCMAC, LOGL_DEBUG,
652 "- Skipping DL/UL slots: (TS=0)\"%s\"(TS=7), "
653 "invalid number of common TS: %d (expected %d)\n",
654 set_flag_chars(set_flag_chars(set_flag_chars(
655 slot_info,
656 rx_bad, 'x', '.'),
657 rx_window, 'D'),
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200658 tx_window, 'U'),
Jacob Erlbeck1653f832015-06-30 14:48:13 +0200659 common_slot_count,
660 req_common_slots);
661#endif
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200662 continue;
663 }
664
665 /* Compute capacity */
666 capacity = 0;
667
668 for (ts = 0; ts < ARRAY_SIZE(trx->pdch); ts++) {
669 int c;
Maxa76a7d02018-01-26 11:09:16 +0100670 const struct gprs_rlcmac_pdch *pdch = &trx->pdch[ts];
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200671 if (rx_window & (1 << ts)) {
672 c = 32 - pdch->num_reserved(GPRS_RLCMAC_DL_TBF);
Jacob Erlbeck9ae28232015-07-01 12:27:30 +0200673 c = OSMO_MAX(c, 1);
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200674 capacity += c;
675 }
Jacob Erlbecked46afd2015-07-01 12:19:40 +0200676 /* Only consider common slots for UL */
677 if (tx_window & rx_window & (1 << ts)) {
Jacob Erlbeck16c6ecc2015-06-30 13:40:18 +0200678 if (find_free_usf(pdch) >= 0) {
679 c = 32 - pdch->num_reserved(GPRS_RLCMAC_UL_TBF);
680 c = OSMO_MAX(c, 1);
681 capacity += c;
682 }
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200683 }
684 }
685
Jacob Erlbeck1653f832015-06-30 14:48:13 +0200686#ifdef ENABLE_TS_ALLOC_DEBUG
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200687 LOGP(DRLCMAC, LOGL_DEBUG,
688 "- Considering DL/UL slots: (TS=0)\"%s\"(TS=7), "
689 "capacity = %d\n",
690 set_flag_chars(set_flag_chars(set_flag_chars(set_flag_chars(
691 slot_info,
692 rx_bad, 'x', '.'),
693 rx_window, 'D'),
694 tx_window, 'U'),
695 rx_window & tx_window, 'C'),
696 capacity);
Jacob Erlbeck1653f832015-06-30 14:48:13 +0200697#endif
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200698
699 if (capacity <= max_capacity)
700 continue;
701
702 max_capacity = capacity;
703 max_ul_slots = tx_window;
704 max_dl_slots = rx_window;
705 }}}}
706
707 if (!max_ul_slots || !max_dl_slots) {
708 LOGP(DRLCMAC, LOGL_NOTICE,
709 "No valid UL/DL slot combination found\n");
710 return -EINVAL;
711 }
712
713 *ul_slots = max_ul_slots;
714 *dl_slots = max_dl_slots;
715
716 return 0;
717}
718
Maxe9fe0e32017-09-28 15:56:05 +0200719/*! Slot Allocation: Algorithm B
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200720 *
721 * Assign as many downlink slots as possible.
722 * Assign one uplink slot. (With free USF)
723 *
Maxe9fe0e32017-09-28 15:56:05 +0200724 * \param[in,out] bts Pointer to BTS struct
725 * \param[in,out] ms_ Pointer to MS object
726 * \param[in,out] tbf_ Pointer to TBF struct
727 * \param[in] single flag indicating if we should force single-slot allocation
728 * \param[in] use_trx which TRX to use or -1 if it should be selected during allocation
729 * \returns negative error code or 0 on success
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200730 */
Maxe9fe0e32017-09-28 15:56:05 +0200731int alloc_algorithm_b(struct gprs_rlcmac_bts *bts, GprsMs *ms_, struct gprs_rlcmac_tbf *tbf_, bool single,
732 int8_t 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;
Maxa76a7d02018-01-26 11:09:16 +0100740 uint8_t avail_count = 0, trx_no;
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200741 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 Erlbeck5a2b8be2015-07-14 11:35:21 +0200747 const GprsMs *ms = ms_;
748 const gprs_rlcmac_tbf *tbf = tbf_;
749 gprs_rlcmac_trx *trx;
Jacob Erlbeck5879c642015-07-10 10:41:36 +0200750
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200751 /* Step 1: Get current state from the MS object */
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200752
753 if (!ms) {
754 LOGP(DRLCMAC, LOGL_ERROR, "MS not set\n");
755 return -EINVAL;
756 }
757
Max92e9c172017-09-28 16:25:25 +0200758 dl_slots = ms->reserved_dl_slots();
759 ul_slots = ms->reserved_ul_slots();
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200760 first_common_ts = ms->first_common_ts();
761 trx = ms->current_trx();
762
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200763 /* Step 2a: Find usable TRX and TFI */
Maxa76a7d02018-01-26 11:09:16 +0100764 tfi = tfi_find_free(bts->bts, trx, ms, tbf->direction, use_trx, &trx_no);
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200765 if (tfi < 0) {
766 LOGP(DRLCMAC, LOGL_NOTICE, "- Failed to allocate a TFI\n");
767 return tfi;
768 }
769
770 /* Step 2b: Reserve slots on the TRX for the MS */
771 if (!trx)
772 trx = &bts->trx[trx_no];
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200773
774 if (!dl_slots || !ul_slots) {
Max842d7812017-11-01 18:11:24 +0100775 rc = find_multi_slots(trx, ms->ms_class(), &ul_slots, &dl_slots);
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100776 if (rc < 0)
777 return rc;
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200778 }
779
Max92e9c172017-09-28 16:25:25 +0200780 reserved_dl_slots = dl_slots;
781 reserved_ul_slots = ul_slots;
782
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200783 /* Step 3: Derive the slot set for the current TBF */
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200784 if (single) {
785 /* Make sure to consider the first common slot only */
786 ul_slots = dl_slots = dl_slots & ul_slots;
787
788 ts = first_common_ts;
789
790 if (ts < 0)
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200791 ts = find_least_busy_pdch(trx, tbf->direction,
Jacob Erlbeckc135b872015-07-09 13:44:18 +0200792 dl_slots & ul_slots, compute_usage_by_num_tbfs,
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200793 NULL, NULL);
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200794 if (ts < 0)
Jacob Erlbeck8cba7e92016-01-19 15:48:03 +0100795 ul_slots = dl_slots = pcu_lsb(dl_slots & ul_slots);
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200796 else
797 ul_slots = dl_slots = (dl_slots & ul_slots) & (1<<ts);
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200798 }
799
800 if (dl_slots == 0) {
801 LOGP(DRLCMAC, LOGL_NOTICE, "No downlink slots available\n");
802 return -EINVAL;
803 }
804
805 if (ul_slots == 0) {
806 LOGP(DRLCMAC, LOGL_NOTICE, "No uplink slots available\n");
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200807 return -EINVAL;
808 }
809
810 if (tbf->direction == GPRS_RLCMAC_DL_TBF) {
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200811 LOGP(DRLCMAC, LOGL_DEBUG,
812 "- Selected DL slots: (TS=0)\"%s\"(TS=7)%s\n",
813 set_flag_chars(set_flag_chars(slot_info,
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200814 reserved_dl_slots, 'd', '.'),
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200815 dl_slots, 'D'),
816 single ? ", single" : "");
817
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200818 /* assign downlink */
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200819 if (dl_slots == 0) {
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200820 LOGP(DRLCMAC, LOGL_NOTICE, "No downlink slots "
821 "available\n");
822 return -EINVAL;
823 }
Jacob Erlbeck8cba7e92016-01-19 15:48:03 +0100824 slotcount = pcu_bitcount(dl_slots);
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200825 first_ts = ffs(dl_slots) - 1;
Jacob Erlbeck8cba7e92016-01-19 15:48:03 +0100826 avail_count = pcu_bitcount(reserved_dl_slots);
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200827
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200828 } else {
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200829 int free_usf = -1;
Daniel Willmanncf1fae72014-05-30 17:58:01 +0200830
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200831 if (first_common_ts >= 0)
832 ul_slots = 1 << first_common_ts;
833 else
834 ul_slots = ul_slots & dl_slots;
835
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200836 ts = find_least_busy_pdch(trx, GPRS_RLCMAC_UL_TBF,
Jacob Erlbeckc135b872015-07-09 13:44:18 +0200837 ul_slots, compute_usage_by_num_tbfs,
Jacob Erlbecke0853cd2015-07-10 12:25:25 +0200838 NULL, &free_usf);
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200839
840 if (free_usf < 0) {
841 LOGP(DRLCMAC, LOGL_NOTICE, "No USF available\n");
842 return -EBUSY;
843 }
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200844 OSMO_ASSERT(ts >= 0 && ts <= 8);
845
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200846 ul_slots = 1 << ts;
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200847 usf[ts] = free_usf;
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200848
849 LOGP(DRLCMAC, LOGL_DEBUG,
850 "- Selected UL slots: (TS=0)\"%s\"(TS=7)%s\n",
851 set_flag_chars(set_flag_chars(slot_info,
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200852 reserved_ul_slots, 'u', '.'),
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200853 ul_slots, 'U'),
854 single ? ", single" : "");
855
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200856 slotcount++;
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200857 first_ts = ts;
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200858
Jacob Erlbeck5f494b82015-07-01 13:10:41 +0200859 /* We will stick to that single UL slot, unreserve the others */
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200860 reserved_ul_slots = ul_slots;
Jacob Erlbeck5f494b82015-07-01 13:10:41 +0200861
Jacob Erlbeck8cba7e92016-01-19 15:48:03 +0100862 avail_count = pcu_bitcount(reserved_ul_slots);
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200863 }
864
Jacob Erlbeckea65c722015-06-22 16:14:23 +0200865 first_common_ts = ffs(dl_slots & ul_slots) - 1;
866
867 if (first_common_ts < 0) {
868 LOGP(DRLCMAC, LOGL_NOTICE, "No first common slots available\n");
869 return -EINVAL;
870 }
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200871 if (first_ts < 0) {
872 LOGP(DRLCMAC, LOGL_NOTICE, "No first slot available\n");
873 return -EINVAL;
874 }
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200875
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200876 if (single && slotcount) {
877 tbf_->upgrade_to_multislot = (avail_count > slotcount);
878 LOGP(DRLCMAC, LOGL_INFO, "Using single slot at TS %d for %s\n",
879 first_ts,
880 (tbf->direction == GPRS_RLCMAC_DL_TBF) ? "DL" : "UL");
881 } else {
882 tbf_->upgrade_to_multislot = 0;
883 LOGP(DRLCMAC, LOGL_INFO, "Using %d slots for %s\n", slotcount,
884 (tbf->direction == GPRS_RLCMAC_DL_TBF) ? "DL" : "UL");
885 }
886
887 /* The allocation will be successful, so the system state and tbf_/ms_
888 * may be modified from now on. */
889
890 /* Step 4: Update MS and TBF and really allocate the resources */
891
892 /* The reserved slots have changed, update the MS */
893 if (reserved_ul_slots != ms->reserved_ul_slots() ||
894 reserved_dl_slots != ms->reserved_dl_slots())
895 {
896 ms_->set_reserved_slots(trx,
897 reserved_ul_slots, reserved_dl_slots);
898
899 LOGP(DRLCMAC, LOGL_DEBUG,
900 "- Reserved DL/UL slots: (TS=0)\"%s\"(TS=7)\n",
901 set_flag_chars(set_flag_chars(set_flag_chars(slot_info,
902 dl_slots, 'D', '.'),
903 ul_slots, 'U'),
904 ul_slots & dl_slots, 'C'));
905 }
906
907 tbf_->trx = trx;
908 tbf_->first_common_ts = first_common_ts;
909 tbf_->first_ts = first_ts;
910
911 if (tbf->direction == GPRS_RLCMAC_DL_TBF) {
Jacob Erlbeckaa9daa12015-12-28 18:49:12 +0100912 struct gprs_rlcmac_dl_tbf *dl_tbf = as_dl_tbf(tbf_);
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200913 for (ts = 0; ts < 8; ts++) {
914 if (!(dl_slots & (1 << ts)))
915 continue;
916
917 LOGP(DRLCMAC, LOGL_DEBUG, "- Assigning DL TS "
918 "%d\n", ts);
919 assign_dlink_tbf(&trx->pdch[ts], dl_tbf, tfi);
920 }
921 } else {
Jacob Erlbeckaa9daa12015-12-28 18:49:12 +0100922 struct gprs_rlcmac_ul_tbf *ul_tbf = as_ul_tbf(tbf_);
Jacob Erlbeck5a2b8be2015-07-14 11:35:21 +0200923
924 for (ts = 0; ts < 8; ts++) {
925 if (!(ul_slots & (1 << ts)))
926 continue;
927
928 OSMO_ASSERT(usf[ts] >= 0);
929
930 LOGP(DRLCMAC, LOGL_DEBUG, "- Assigning UL TS "
931 "%d\n", ts);
932 assign_uplink_tbf_usf(&trx->pdch[ts], ul_tbf,
933 tfi, usf[ts]);
934 }
935 }
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200936
Jacob Erlbeck5979fe92015-07-14 14:02:41 +0200937 bts->bts->tbf_alloc_algo_b();
938
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200939 return 0;
940}
Jacob Erlbeck400ec022015-07-14 13:31:48 +0200941
Maxe9fe0e32017-09-28 15:56:05 +0200942/*! Slot Allocation: Algorithm dynamic
Jacob Erlbeck400ec022015-07-14 13:31:48 +0200943 *
944 * This meta algorithm automatically selects on of the other algorithms based
945 * on the current system state.
946 *
947 * The goal is to support as many MS and TBF as possible. On low usage, the
948 * goal is to provide the highest possible bandwidth per MS.
949 *
Maxe9fe0e32017-09-28 15:56:05 +0200950 * \param[in,out] bts Pointer to BTS struct
951 * \param[in,out] ms_ Pointer to MS object
952 * \param[in,out] tbf_ Pointer to TBF struct
953 * \param[in] single flag indicating if we should force single-slot allocation
954 * \param[in] use_trx which TRX to use or -1 if it should be selected during allocation
955 * \returns negative error code or 0 on success
Jacob Erlbeck400ec022015-07-14 13:31:48 +0200956 */
Maxe9fe0e32017-09-28 15:56:05 +0200957int alloc_algorithm_dynamic(struct gprs_rlcmac_bts *bts, GprsMs *ms_, struct gprs_rlcmac_tbf *tbf_, bool single,
958 int8_t use_trx)
Jacob Erlbeck400ec022015-07-14 13:31:48 +0200959{
960 int rc;
961
Jacob Erlbeck77da3552015-07-16 18:33:46 +0200962 /* Reset load_is_high if there is at least one idle PDCH */
963 if (bts->multislot_disabled) {
Maxa76a7d02018-01-26 11:09:16 +0100964 bts->multislot_disabled = !idle_pdch_avail(bts);
Jacob Erlbeck77da3552015-07-16 18:33:46 +0200965 if (!bts->multislot_disabled)
966 LOGP(DRLCMAC, LOGL_DEBUG, "Enabling algorithm B\n");
967 }
968
969 if (!bts->multislot_disabled) {
Maxe9fe0e32017-09-28 15:56:05 +0200970 rc = alloc_algorithm_b(bts, ms_, tbf_, single, use_trx);
Jacob Erlbeck77da3552015-07-16 18:33:46 +0200971 if (rc >= 0)
972 return rc;
973
974 if (!bts->multislot_disabled)
975 LOGP(DRLCMAC, LOGL_DEBUG, "Disabling algorithm B\n");
976 bts->multislot_disabled = 1;
977 }
Jacob Erlbeck400ec022015-07-14 13:31:48 +0200978
Maxe9fe0e32017-09-28 15:56:05 +0200979 return alloc_algorithm_a(bts, ms_, tbf_, single, use_trx);
Jacob Erlbeck400ec022015-07-14 13:31:48 +0200980}
Jacob Erlbeck7f79f0d2015-07-17 11:38:49 +0200981
982int gprs_alloc_max_dl_slots_per_ms(struct gprs_rlcmac_bts *bts, uint8_t ms_class)
983{
Max842d7812017-11-01 18:11:24 +0100984 int rx = mslot_class_get_rx(ms_class);
Jacob Erlbeck7f79f0d2015-07-17 11:38:49 +0200985
986 if (rx == MS_NA)
987 rx = 4;
988
989 if (bts->alloc_algorithm == alloc_algorithm_a)
990 return 1;
991
992 if (bts->multislot_disabled)
993 return 1;
994
995 return rx;
996}