blob: 2ba920ab8f4c919790681114dce92186bd5c085d [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>
Jacob Erlbeckec478752015-06-19 16:35:38 +020029#include <values.h>
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +020030
31/* 3GPP TS 05.02 Annex B.1 */
32
33#define MS_NA 255 /* N/A */
34#define MS_A 254 /* 1 with hopping, 0 without */
35#define MS_B 253 /* 1 with hopping, 0 without (change Rx to Tx)*/
36#define MS_C 252 /* 1 with hopping, 0 without (change Tx to Rx)*/
37
38struct gprs_ms_multislot_class {
39 uint8_t rx, tx, sum; /* Maximum Number of Slots: RX, Tx, Sum Rx+Tx */
40 uint8_t ta, tb, ra, rb; /* Minimum Number of Slots */
41 uint8_t type; /* Type of Mobile */
42};
43
44static const struct gprs_ms_multislot_class gprs_ms_multislot_class[32] = {
45/* M-S Class Rx Tx Sum Tta Ttb Tra Trb Type */
46/* N/A */ { MS_NA,MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA },
47/* 1 */ { 1, 1, 2, 3, 2, 4, 2, 1 },
48/* 2 */ { 2, 1, 3, 3, 2, 3, 1, 1 },
49/* 3 */ { 2, 2, 3, 3, 2, 3, 1, 1 },
50/* 4 */ { 3, 1, 4, 3, 1, 3, 1, 1 },
51/* 5 */ { 2, 2, 4, 3, 1, 3, 1, 1 },
52/* 6 */ { 3, 2, 4, 3, 1, 3, 1, 1 },
53/* 7 */ { 3, 3, 4, 3, 1, 3, 1, 1 },
54/* 8 */ { 4, 1, 5, 3, 1, 2, 1, 1 },
55/* 9 */ { 3, 2, 5, 3, 1, 2, 1, 1 },
56/* 10 */ { 4, 2, 5, 3, 1, 2, 1, 1 },
57/* 11 */ { 4, 3, 5, 3, 1, 2, 1, 1 },
58/* 12 */ { 4, 4, 5, 2, 1, 2, 1, 1 },
59/* 13 */ { 3, 3, MS_NA, MS_NA, MS_A, 3, MS_A, 2 },
60/* 14 */ { 4, 4, MS_NA, MS_NA, MS_A, 3, MS_A, 2 },
61/* 15 */ { 5, 5, MS_NA, MS_NA, MS_A, 3, MS_A, 2 },
62/* 16 */ { 6, 6, MS_NA, MS_NA, MS_A, 2, MS_A, 2 },
63/* 17 */ { 7, 7, MS_NA, MS_NA, MS_A, 1, 0, 2 },
64/* 18 */ { 8, 8, MS_NA, MS_NA, 0, 0, 0, 2 },
65/* 19 */ { 6, 2, MS_NA, 3, MS_B, 2, MS_C, 1 },
66/* 20 */ { 6, 3, MS_NA, 3, MS_B, 2, MS_C, 1 },
67/* 21 */ { 6, 4, MS_NA, 3, MS_B, 2, MS_C, 1 },
68/* 22 */ { 6, 4, MS_NA, 2, MS_B, 2, MS_C, 1 },
69/* 23 */ { 6, 6, MS_NA, 2, MS_B, 2, MS_C, 1 },
70/* 24 */ { 8, 2, MS_NA, 3, MS_B, 2, MS_C, 1 },
71/* 25 */ { 8, 3, MS_NA, 3, MS_B, 2, MS_C, 1 },
72/* 26 */ { 8, 4, MS_NA, 3, MS_B, 2, MS_C, 1 },
73/* 27 */ { 8, 4, MS_NA, 2, MS_B, 2, MS_C, 1 },
74/* 28 */ { 8, 6, MS_NA, 2, MS_B, 2, MS_C, 1 },
75/* 29 */ { 8, 8, MS_NA, 2, MS_B, 2, MS_C, 1 },
76/* N/A */ { MS_NA,MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA },
77/* N/A */ { MS_NA,MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA },
78};
79
Holger Hans Peter Freyther6796ed22013-10-20 16:45:10 +020080static inline int8_t find_free_usf(struct gprs_rlcmac_pdch *pdch)
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +020081{
Daniel Willmanncd44ec42014-08-07 15:04:57 +020082 struct gprs_rlcmac_ul_tbf *tbf;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +020083 uint8_t usf_map = 0;
84 uint8_t tfi, usf;
85
86 /* make map of used USF */
87 for (tfi = 0; tfi < 32; tfi++) {
Daniel Willmann17a1d5e2014-05-30 20:21:30 +020088 tbf = pdch->ul_tbf_by_tfi(tfi);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +020089 if (!tbf)
90 continue;
Daniel Willmann7e994e32014-08-07 15:49:21 +020091 usf_map |= (1 << tbf->m_usf[pdch->ts_no]);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +020092 }
93
94 /* look for USF, don't use USF=7 */
95 for (usf = 0; usf < 7; usf++) {
96 if (!(usf_map & (1 << usf)))
97 return usf;
98 }
99
100 return -1;
101}
102
Jacob Erlbeckec478752015-06-19 16:35:38 +0200103static int find_possible_pdchs(struct gprs_rlcmac_trx *trx,
104 uint8_t mask, const char *mask_reason = NULL)
Holger Hans Peter Freytherb0a00752013-09-29 08:18:17 +0200105{
Jacob Erlbeckec478752015-06-19 16:35:38 +0200106 unsigned ts;
107 int valid_ts_set = 0;
108
109 for (ts = 0; ts < ARRAY_SIZE(trx->pdch); ts++) {
Holger Hans Peter Freytherb0a00752013-09-29 08:18:17 +0200110 struct gprs_rlcmac_pdch *pdch;
111
112 pdch = &trx->pdch[ts];
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +0200113 if (!pdch->is_enabled()) {
Holger Hans Peter Freytherb0a00752013-09-29 08:18:17 +0200114 LOGP(DRLCMAC, LOGL_DEBUG, "- Skipping TS %d, because "
115 "not enabled\n", ts);
116 continue;
117 }
Jacob Erlbeckec478752015-06-19 16:35:38 +0200118
119 if (((1 << ts) & mask) == 0) {
120 if (mask_reason)
121 LOGP(DRLCMAC, LOGL_DEBUG,
122 "- Skipping TS %d, because %s\n",
123 ts, mask_reason);
124 continue;
125 }
126
127 valid_ts_set |= 1 << ts;
Holger Hans Peter Freytherb0a00752013-09-29 08:18:17 +0200128 }
129
Jacob Erlbeckec478752015-06-19 16:35:38 +0200130 return valid_ts_set;
131}
132
133static int find_least_busy_pdch(struct gprs_rlcmac_trx *trx,
134 enum gprs_rlcmac_tbf_direction dir,
135 uint8_t mask,
136 int *free_usf = 0)
137{
138 unsigned ts;
139 int min_used = INT_MAX;
140 int min_ts = -1;
141 int min_usf = -1;
142
143 for (ts = 0; ts < ARRAY_SIZE(trx->pdch); ts++) {
144 struct gprs_rlcmac_pdch *pdch = &trx->pdch[ts];
145 int num_tbfs;
146 int usf = -1; /* must be signed */
147
148 if (((1 << ts) & mask) == 0)
149 continue;
150
151 num_tbfs = pdch->num_tbfs(dir);
152 if (num_tbfs < min_used) {
153 /* We have found a candidate */
154 /* Make sure that an USF is available */
155 if (dir == GPRS_RLCMAC_UL_TBF) {
156 usf = find_free_usf(pdch);
157 if (usf < 0) {
158 LOGP(DRLCMAC, LOGL_DEBUG,
159 "- Skipping TS %d, because "
160 "no USF available\n", ts);
161 continue;
162 }
163 }
164 if (min_ts >= 0)
165 LOGP(DRLCMAC, LOGL_DEBUG,
166 "- Skipping TS %d, because "
167 "num TBFs %d > %d\n",
168 min_ts, min_used, num_tbfs);
169 min_used = num_tbfs;
170 min_ts = ts;
171 min_usf = usf;
172 } else {
173 LOGP(DRLCMAC, LOGL_DEBUG,
174 "- Skipping TS %d, because "
175 "num TBFs %d >= %d\n",
176 ts, num_tbfs, min_used);
177 }
178 }
179
180 if (min_ts < 0)
181 return -1;
182
183 if (free_usf)
184 *free_usf = min_usf;
185
186 return min_ts;
Holger Hans Peter Freytherb0a00752013-09-29 08:18:17 +0200187}
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200188
Jacob Erlbeckccc34e42015-06-29 13:45:05 +0200189static void attach_tbf_to_pdch(struct gprs_rlcmac_pdch *pdch,
190 struct gprs_rlcmac_tbf *tbf)
191{
192 if (tbf->pdch[pdch->ts_no])
193 tbf->pdch[pdch->ts_no]->detach_tbf(tbf);
194
195 tbf->pdch[pdch->ts_no] = pdch;
196 pdch->attach_tbf(tbf);
197}
198
Holger Hans Peter Freyther743bafa2013-09-29 07:50:50 +0200199static void assign_uplink_tbf_usf(
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200200 struct gprs_rlcmac_pdch *pdch,
Daniel Willmanncd44ec42014-08-07 15:04:57 +0200201 struct gprs_rlcmac_ul_tbf *tbf, int8_t usf)
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200202{
Holger Hans Peter Freyther34f6e5e2013-10-27 20:31:47 +0100203 tbf->trx->ul_tbf[tbf->tfi()] = tbf;
Daniel Willmann7e994e32014-08-07 15:49:21 +0200204 tbf->m_usf[pdch->ts_no] = usf;
Jacob Erlbeckccc34e42015-06-29 13:45:05 +0200205 attach_tbf_to_pdch(pdch, tbf);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200206}
207
Holger Hans Peter Freyther8481a052013-09-29 08:08:28 +0200208static void assign_dlink_tbf(
209 struct gprs_rlcmac_pdch *pdch,
Daniel Willmanncd44ec42014-08-07 15:04:57 +0200210 struct gprs_rlcmac_dl_tbf *tbf)
Holger Hans Peter Freyther8481a052013-09-29 08:08:28 +0200211{
Holger Hans Peter Freyther34f6e5e2013-10-27 20:31:47 +0100212 tbf->trx->dl_tbf[tbf->tfi()] = tbf;
Jacob Erlbeckccc34e42015-06-29 13:45:05 +0200213 attach_tbf_to_pdch(pdch, tbf);
Holger Hans Peter Freyther8481a052013-09-29 08:08:28 +0200214}
215
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200216
217/* Slot Allocation: Algorithm A
218 *
219 * Assign single slot for uplink and downlink
220 */
221int alloc_algorithm_a(struct gprs_rlcmac_bts *bts,
Jacob Erlbecke2e004e2015-06-18 17:16:26 +0200222 GprsMs *ms,
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200223 struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single)
224{
225 struct gprs_rlcmac_pdch *pdch;
Jacob Erlbeckec478752015-06-19 16:35:38 +0200226 int ts = -1;
227 int usf = -1;
228 int mask = 0xff;
229 const char *mask_reason = NULL;
230 struct gprs_rlcmac_tbf *ref_tbf;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200231
232 LOGP(DRLCMAC, LOGL_DEBUG, "Slot Allocation (Algorithm A) for class "
Jacob Erlbeckbefc7602015-06-02 12:33:30 +0200233 "%d\n", tbf->ms_class());
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200234
Jacob Erlbeckec478752015-06-19 16:35:38 +0200235 if ((ref_tbf = ms->tbf(tbf->direction)))
236 mask_reason = "need to reuse TS";
237 else if ((ref_tbf = ms->tbf(reverse(tbf->direction))))
238 mask_reason = ref_tbf->direction == GPRS_RLCMAC_UL_TBF ?
239 "not an uplink TBF" : "not a downlink TBF";
240
241 if (ref_tbf)
242 ts = ref_tbf->first_common_ts;
243
244 if (ts >= 0)
245 mask = 1 << ts;
246
247 mask = find_possible_pdchs(tbf->trx, mask, mask_reason);
248 if (!mask)
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200249 return -EINVAL;
250
Jacob Erlbeckec478752015-06-19 16:35:38 +0200251 ts = find_least_busy_pdch(tbf->trx, tbf->direction, mask, &usf);
252
253 if (ts < 0) {
254 LOGP(DRLCMAC, LOGL_NOTICE, "- Failed "
255 "to allocate a TS, no USF available\n");
256 return -EBUSY;
257 }
258
Holger Hans Peter Freytherb0a00752013-09-29 08:18:17 +0200259 pdch = &tbf->trx->pdch[ts];
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200260 if (tbf->direction == GPRS_RLCMAC_UL_TBF) {
Daniel Willmanncd44ec42014-08-07 15:04:57 +0200261 struct gprs_rlcmac_ul_tbf *ul_tbf = static_cast<gprs_rlcmac_ul_tbf *>(tbf);
Holger Hans Peter Freyther948a3d62013-09-30 14:10:23 +0200262
Jacob Erlbeckec478752015-06-19 16:35:38 +0200263 if (usf < 0)
264 usf = find_free_usf(pdch);
265
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200266 if (usf < 0) {
267 LOGP(DRLCMAC, LOGL_NOTICE, "- Failed "
268 "allocating TS=%d, no USF available\n", ts);
269 return -EBUSY;
270 }
Jacob Erlbeckec478752015-06-19 16:35:38 +0200271
272 LOGP(DRLCMAC, LOGL_DEBUG, "- Assign uplink TS=%d USF=%d\n",
273 ts, usf);
Daniel Willmanncd44ec42014-08-07 15:04:57 +0200274 assign_uplink_tbf_usf(pdch, ul_tbf, usf);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200275 } else {
Daniel Willmanncd44ec42014-08-07 15:04:57 +0200276 struct gprs_rlcmac_dl_tbf *dl_tbf = static_cast<gprs_rlcmac_dl_tbf *>(tbf);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200277 LOGP(DRLCMAC, LOGL_DEBUG, "- Assign downlink TS=%d\n", ts);
Daniel Willmanncd44ec42014-08-07 15:04:57 +0200278 assign_dlink_tbf(pdch, dl_tbf);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200279 }
280 /* the only one TS is the common TS */
281 tbf->first_ts = tbf->first_common_ts = ts;
282
Daniel Willmanncf1fae72014-05-30 17:58:01 +0200283 tbf->upgrade_to_multislot = 0;
284
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200285 return 0;
286}
287
Holger Hans Peter Freyther882fc9b2013-12-25 20:34:26 +0100288/*
289 * Select a window of Rx slots if available.
290 * The maximum allowed slots depend on RX or the window of available
291 * slots. This must be done for uplink TBF also, because it is the basis
292 * for calculating control slot and uplink slot(s).
293 */
294static uint8_t select_dl_slots(struct gprs_rlcmac_trx *trx,
295 const int ms_type, const int ms_max_rxslots,
296 uint8_t *out_rx_win_min, uint8_t *out_rx_win_max)
297
298{
299 uint8_t rx_window = 0;
300 int rx_window_size = 0;
301 int8_t last_tsc = -1; /* must be signed */
302 uint8_t rx_win_min = 0, rx_win_max = 0;
303
304 for (int ts_no = 0; ts_no < 8; ts_no++) {
305 struct gprs_rlcmac_pdch *pdch;
306 pdch = &trx->pdch[ts_no];
307
308 /* check if enabled */
309 if (!pdch->is_enabled()) {
310 LOGP(DRLCMAC, LOGL_DEBUG, "- Skipping TS %d, because "
311 "not enabled\n", ts_no);
312 if (ms_type == 1 && rx_window)
Andreas Eversbergb03d4272014-01-04 15:14:19 +0100313 goto inc_window;
Holger Hans Peter Freyther882fc9b2013-12-25 20:34:26 +0100314 continue;
315 }
316 /* check if TSC changes */
317 if (last_tsc < 0)
318 last_tsc = pdch->tsc;
319 else if (last_tsc != pdch->tsc) {
320 LOGP(DRLCMAC, LOGL_ERROR, "Skipping TS %d of TRX=%d, "
321 "because it has different TSC than lower TS "
322 "of TRX. In order to allow multislot, all "
323 "slots must be configured with the same "
324 "TSC!\n", ts_no, trx->trx_no);
325 if (ms_type == 1 && rx_window)
Andreas Eversbergb03d4272014-01-04 15:14:19 +0100326 goto inc_window;
Holger Hans Peter Freyther882fc9b2013-12-25 20:34:26 +0100327 continue;
328 }
329
330 if (!rx_window)
331 rx_win_min = ts_no;
332
333 rx_window |= (1 << ts_no);
334 LOGP(DRLCMAC, LOGL_DEBUG, "- Selected DL TS %d\n", ts_no);
335
336 /* range of window (required for Type 1) */
337 rx_win_max = ts_no;
338
Andreas Eversbergb03d4272014-01-04 15:14:19 +0100339inc_window:
Holger Hans Peter Freyther882fc9b2013-12-25 20:34:26 +0100340 if (++rx_window_size == ms_max_rxslots) {
341 LOGP(DRLCMAC, LOGL_DEBUG, "- Done, because slots / "
342 "window reached maximum alowed Rx size\n");
343 break;
344 }
Andreas Eversbergccde4c42014-01-04 15:17:22 +0100345 if (ms_type == 1 && rx_window_size == 5) {
346 LOGP(DRLCMAC, LOGL_DEBUG, "- Done, because slots / "
347 "window reached maximum supported Rx size of "
348 "this algorithm\n");
349 break;
350 }
Holger Hans Peter Freyther882fc9b2013-12-25 20:34:26 +0100351 }
352
353 LOGP(DRLCMAC, LOGL_DEBUG, "- Selected slots for RX: "
354 "(TS=0)\"%c%c%c%c%c%c%c%c\"(TS=7)\n",
355 ((rx_window & 0x01)) ? 'D' : '.',
356 ((rx_window & 0x02)) ? 'D' : '.',
357 ((rx_window & 0x04)) ? 'D' : '.',
358 ((rx_window & 0x08)) ? 'D' : '.',
359 ((rx_window & 0x10)) ? 'D' : '.',
360 ((rx_window & 0x20)) ? 'D' : '.',
361 ((rx_window & 0x40)) ? 'D' : '.',
362 ((rx_window & 0x80)) ? 'D' : '.');
363
364 *out_rx_win_min = rx_win_min;
365 *out_rx_win_max = rx_win_max;
366 return rx_window;
367}
368
Jacob Erlbecke2e004e2015-06-18 17:16:26 +0200369static int reduce_rx_window(const int ms_type, const GprsMs *ms,
Holger Hans Peter Freythere45c19b2013-12-25 20:53:53 +0100370 const int Tt, const int Tr,
371 int *rx_window,
372 uint8_t *rx_win_min, uint8_t *rx_win_max)
373{
Jacob Erlbecke2e004e2015-06-18 17:16:26 +0200374 gprs_rlcmac_ul_tbf *ul_tbf;
375
Holger Hans Peter Freythere45c19b2013-12-25 20:53:53 +0100376 if (ms_type != 1)
377 return 0;
Jacob Erlbecke2e004e2015-06-18 17:16:26 +0200378 if (!ms)
Holger Hans Peter Freythere45c19b2013-12-25 20:53:53 +0100379 return 0;
Jacob Erlbecke2e004e2015-06-18 17:16:26 +0200380
381 ul_tbf = ms->ul_tbf();
382
383 if (!ul_tbf)
Holger Hans Peter Freythere45c19b2013-12-25 20:53:53 +0100384 return 0;
385
386 uint8_t collide = 0, ul_usage = 0;
387
388 /* calculate mask of colliding slots */
389 for (uint8_t ts_no = 0; ts_no < 8; ts_no++) {
390 int j;
Jacob Erlbecke2e004e2015-06-18 17:16:26 +0200391 if (!ul_tbf->pdch[ts_no])
Holger Hans Peter Freythere45c19b2013-12-25 20:53:53 +0100392 continue;
393
394 ul_usage |= (1 << ts_no);
395 /* mark bits from TS-t .. TS+r */
Andreas Eversberg91670552014-05-29 11:08:58 +0200396 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 +0100397 collide |= (1 << j);
398 }
399
400 LOGP(DRLCMAC, LOGL_DEBUG, "- Not allowed slots due to existing "
401 "UL allocation: (TS=0)\"%c%c%c%c%c%c%c%c\"(TS=7) "
402 " D=downlink x=not usable\n",
403 ((ul_usage & 0x01)) ? 'D' : ((collide & 0x01))?'x':'.',
404 ((ul_usage & 0x02)) ? 'D' : ((collide & 0x02))?'x':'.',
405 ((ul_usage & 0x04)) ? 'D' : ((collide & 0x04))?'x':'.',
406 ((ul_usage & 0x08)) ? 'D' : ((collide & 0x08))?'x':'.',
407 ((ul_usage & 0x10)) ? 'D' : ((collide & 0x10))?'x':'.',
408 ((ul_usage & 0x20)) ? 'D' : ((collide & 0x20))?'x':'.',
409 ((ul_usage & 0x40)) ? 'D' : ((collide & 0x40))?'x':'.',
410 ((ul_usage & 0x80)) ? 'D' : ((collide & 0x80))?'x':'.');
411
412 /*
413 * Uplink/Downlink in GSM is shifted by three timeslots. Make
414 * sure they don't collide.
415 */
416 *rx_window &= ~(collide << 3);
417 *rx_window &= ~(collide >> 5);
418 LOGP(DRLCMAC, LOGL_DEBUG, "- Remaining slots for RX: "
419 "(TS=0)\"%c%c%c%c%c%c%c%c\"(TS=7)\n",
420 ((*rx_window & 0x01)) ? 'D' : '.',
421 ((*rx_window & 0x02)) ? 'D' : '.',
422 ((*rx_window & 0x04)) ? 'D' : '.',
423 ((*rx_window & 0x08)) ? 'D' : '.',
424 ((*rx_window & 0x10)) ? 'D' : '.',
425 ((*rx_window & 0x20)) ? 'D' : '.',
426 ((*rx_window & 0x40)) ? 'D' : '.',
427 ((*rx_window & 0x80)) ? 'D' : '.');
428
429 if (!*rx_window) {
430 LOGP(DRLCMAC, LOGL_NOTICE, "No suitable downlink slots "
431 "available with current uplink assignment\n");
432 return -EBUSY;
433 }
434
Andreas Eversberg1cd9d882014-01-04 15:42:38 +0100435 return 0;
436}
437
438/* shrink range of rx_win_min and rx_win_max */
439static void shrink_rx_window(uint8_t *rx_win_min, uint8_t *rx_win_max, int rx_window)
440{
Holger Hans Peter Freythere45c19b2013-12-25 20:53:53 +0100441 /* calculate new min/max */
442 for (uint8_t ts_no = *rx_win_min; ts_no <= *rx_win_max; ts_no++) {
Andreas Eversberg1cd9d882014-01-04 15:42:38 +0100443 if ((rx_window & (1 << ts_no)))
Holger Hans Peter Freythere45c19b2013-12-25 20:53:53 +0100444 break;
445 *rx_win_min = ts_no + 1;
Andreas Eversberg1cd9d882014-01-04 15:42:38 +0100446 LOGP(DRLCMAC, LOGL_DEBUG, "- TS is unused, so "
Holger Hans Peter Freythere45c19b2013-12-25 20:53:53 +0100447 "raising start of DL window to %d\n",
448 *rx_win_min);
449 }
450 for (uint8_t ts_no = *rx_win_max; ts_no >= *rx_win_min; ts_no--) {
Andreas Eversberg1cd9d882014-01-04 15:42:38 +0100451 if ((rx_window & (1 << ts_no)))
Holger Hans Peter Freythere45c19b2013-12-25 20:53:53 +0100452 break;
453 *rx_win_max = ts_no - 1;
Andreas Eversberg1cd9d882014-01-04 15:42:38 +0100454 LOGP(DRLCMAC, LOGL_DEBUG, "- TS is unused, so "
Holger Hans Peter Freythere45c19b2013-12-25 20:53:53 +0100455 "lowering end of DL window to %d\n",
456 *rx_win_max);
457 }
Holger Hans Peter Freythere45c19b2013-12-25 20:53:53 +0100458}
459
Holger Hans Peter Freytherdd4af802013-12-25 21:03:42 +0100460/*
461 * reduce window, to allow at least one uplink TX slot
462 * this is only required for Type 1
463 */
464static uint8_t update_rx_win_max(const int ms_type, const int Tt,
465 const int Tr, uint8_t rx_win_min, uint8_t rx_win_max)
466{
467 if (ms_type != 1)
468 return rx_win_max;
469
470 if (rx_win_max - rx_win_min + 1 + Tt + 1 + Tr > 8) {
471 rx_win_max = rx_win_min + 7 - Tt - 1 - Tr;
472 LOGP(DRLCMAC, LOGL_DEBUG, "- Reduce RX window due to time "
473 "contraints to %d slots\n", rx_win_max - rx_win_min + 1);
474 }
475
476 return rx_win_max;
477}
478
Holger Hans Peter Freyther3fd2ddf2013-12-25 21:11:20 +0100479static void tx_win_from_rx(const int ms_type,
480 uint8_t rx_win_min, uint8_t rx_win_max,
481 int Tt, int Tr,
482 uint8_t *tx_win_min, uint8_t *tx_win_max,
483 uint8_t *tx_range)
484{
485 if (ms_type == 1) {
486 /* calculate TX window (shifted by 3 timeslots)
487 * it uses the space between tx_win_max and tx_win_min */
488 *tx_win_min = (rx_win_max - 2 + Tt) & 7;
489 *tx_win_max = (rx_win_min + 4 - Tr) & 7;
490 } else {
491 /* TX and RX simultaniously */
492 *tx_win_min = rx_win_min;
493 *tx_win_max = 7;
494 }
495
496 *tx_range = (*tx_win_max - *tx_win_min + 1) & 7;
Andreas Eversberg7a16d462014-01-04 15:25:18 +0100497 /* if TX window fills complete range */
498 if (*tx_range == 0)
499 *tx_range = 8;
Holger Hans Peter Freyther3fd2ddf2013-12-25 21:11:20 +0100500 LOGP(DRLCMAC, LOGL_DEBUG, "- TX-Window is: %d..%d\n", *tx_win_min,
501 *tx_win_max);
502}
Holger Hans Peter Freythere45c19b2013-12-25 20:53:53 +0100503
Holger Hans Peter Freyther1fe69322013-12-26 09:31:31 +0100504/*
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100505 * Select a window of Tx slots if available.
506 * The maximum allowed slots depend on TX or the window of available
507 * slots.
508 */
509static int select_ul_slots(gprs_rlcmac_trx *trx,
510 const int ms_type, const int ms_max_txslots,
511 uint8_t tx_win_min, uint8_t tx_range,
Andreas Eversberg765736d2014-01-04 15:27:31 +0100512 int8_t *usf, int8_t *first_common_ts, uint8_t rx_window)
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100513{
514 int tsc = -1;
515 uint8_t tx_window = 0;
516 int i;
517 uint8_t ts_no;
518
Andreas Eversbergfe2dcc82014-01-04 15:39:54 +0100519 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 +0100520 gprs_rlcmac_pdch *pdch = &trx->pdch[ts_no];
521
522 /* check if enabled */
523 if (!pdch->is_enabled()) {
524 LOGP(DRLCMAC, LOGL_DEBUG, "- Skipping TS %d, "
525 "because not enabled\n", ts_no);
Andreas Eversbergb03d4272014-01-04 15:14:19 +0100526 if (ms_type == 1 && tx_window)
527 goto inc_window;
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100528 continue;
529 }
Andreas Eversberg765736d2014-01-04 15:27:31 +0100530 /* check if used as downlink */
531 if (!(rx_window & (1 << ts_no))) {
532 LOGP(DRLCMAC, LOGL_DEBUG, "- Skipping TS %d, "
533 "because not a downlink slot\n", ts_no);
534 if (ms_type == 1 && tx_window)
535 goto inc_window;
536 continue;
537 }
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100538 /* check if TSC changes */
539 if (tsc < 0)
540 tsc = pdch->tsc;
541 else if (tsc != pdch->tsc) {
542 LOGP(DRLCMAC, LOGL_ERROR, "Skipping TS %d of "
543 "TRX=%d, because it has different TSC "
544 "than lower TS of TRX. In order to "
545 "allow multislot, all slots must be "
546 "configured with the same TSC!\n",
547 ts_no, trx->trx_no);
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100548 if (ms_type == 1)
Andreas Eversbergb03d4272014-01-04 15:14:19 +0100549 goto inc_window;
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100550 continue;
551 }
552 /* check for free usf */
553 usf[ts_no] = find_free_usf(pdch);
554 if (usf[ts_no] < 0) {
555 LOGP(DRLCMAC, LOGL_DEBUG, "- Skipping TS %d, "
556 "because no USF available\n", ts_no);
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100557 if (ms_type == 1)
Andreas Eversbergb03d4272014-01-04 15:14:19 +0100558 goto inc_window;
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100559 continue;
560 }
561
562 if (!tx_window)
563 *first_common_ts = ts_no;
564
565 tx_window |= (1 << ts_no);
566 LOGP(DRLCMAC, LOGL_DEBUG, "- Selected UL TS %d\n", ts_no);
567
Andreas Eversbergb03d4272014-01-04 15:14:19 +0100568inc_window:
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100569 if (1 && ms_type == 1) { /* FIXME: multislot UL assignment */
570 LOGP(DRLCMAC, LOGL_DEBUG, "- Done, because "
571 "1 slot assigned\n");
572 break;
573 }
Andreas Eversberg0a940082014-01-15 13:53:43 +0100574 if (i+1 == ms_max_txslots) {
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100575 LOGP(DRLCMAC, LOGL_DEBUG, "- Done, because "
576 "slots / window reached maximum "
577 "allowed Tx size\n");
578 break;
579 }
580 }
581
582 LOGP(DRLCMAC, LOGL_DEBUG, "- Selected TX window: "
583 "(TS=0)\"%c%c%c%c%c%c%c%c\"(TS=7)\n",
584 ((tx_window & 0x01)) ? 'U' : '.',
585 ((tx_window & 0x02)) ? 'U' : '.',
586 ((tx_window & 0x04)) ? 'U' : '.',
587 ((tx_window & 0x08)) ? 'U' : '.',
588 ((tx_window & 0x10)) ? 'U' : '.',
589 ((tx_window & 0x20)) ? 'U' : '.',
590 ((tx_window & 0x40)) ? 'U' : '.',
591 ((tx_window & 0x80)) ? 'U' : '.');
592
593 if (!tx_window) {
594 LOGP(DRLCMAC, LOGL_NOTICE, "No suitable uplink slots "
595 "available\n");
596 return -EBUSY;
597 }
598
599 return tx_window;
600}
601
602/*
Holger Hans Peter Freyther1fe69322013-12-26 09:31:31 +0100603 * Assign the first common ts, which is used for control or
604 * single slot.
605 */
Andreas Eversberg765736d2014-01-04 15:27:31 +0100606static int select_first_ts(gprs_rlcmac_trx *trx, uint8_t tx_win_min,
607 uint8_t tx_range, uint8_t rx_window)
Holger Hans Peter Freyther1fe69322013-12-26 09:31:31 +0100608{
609 uint8_t ts_no;
610 int i;
Andreas Eversbergfe2dcc82014-01-04 15:39:54 +0100611 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 +0100612 gprs_rlcmac_pdch *pdch = &trx->pdch[ts_no];
613 /* check if enabled */
614 if (!pdch->is_enabled()) {
615 LOGP(DRLCMAC, LOGL_DEBUG, "- Skipping TS %d, "
616 "because not enabled\n", ts_no);
617 continue;
618 }
Andreas Eversberg765736d2014-01-04 15:27:31 +0100619 /* check if used as downlink */
620 if (!(rx_window & (1 << ts_no))) {
621 LOGP(DRLCMAC, LOGL_DEBUG, "- Skipping TS %d, "
622 "because not a downlink slot\n", ts_no);
623 continue;
624 }
Holger Hans Peter Freyther1fe69322013-12-26 09:31:31 +0100625 return ts_no;
626 }
627
628 return -1;
629}
630
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200631/* Slot Allocation: Algorithm B
632 *
633 * Assign as many downlink slots as possible.
634 * Assign one uplink slot. (With free USF)
635 *
636 */
637int alloc_algorithm_b(struct gprs_rlcmac_bts *bts,
Jacob Erlbecke2e004e2015-06-18 17:16:26 +0200638 GprsMs *ms,
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200639 struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single)
640{
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200641 const struct gprs_ms_multislot_class *ms_class;
Holger Hans Peter Freyther882fc9b2013-12-25 20:34:26 +0100642 uint8_t Tx, Sum; /* Maximum Number of Slots: RX, Tx, Sum Rx+Tx */
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200643 uint8_t Tta, Ttb, Tra, Trb, Tt, Tr; /* Minimum Number of Slots */
644 uint8_t Type; /* Type of Mobile */
Holger Hans Peter Freythere45c19b2013-12-25 20:53:53 +0100645 int rx_window;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200646 static const char *digit[10] = { "0","1","2","3","4","5","6","7","8","9" };
647 int8_t usf[8] = { -1, -1, -1, -1, -1, -1, -1, -1 }; /* must be signed */
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200648 int8_t first_common_ts = -1;
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100649 uint8_t ts;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200650 uint8_t slotcount = 0;
651
652
Jacob Erlbeckbefc7602015-06-02 12:33:30 +0200653 if (tbf->ms_class() >= 32) {
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200654 LOGP(DRLCMAC, LOGL_ERROR, "Multislot class %d out of range.\n",
Jacob Erlbeckbefc7602015-06-02 12:33:30 +0200655 tbf->ms_class());
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200656 return -EINVAL;
657 }
658
Jacob Erlbeckbefc7602015-06-02 12:33:30 +0200659 if (tbf->ms_class()) {
660 ms_class = &gprs_ms_multislot_class[tbf->ms_class()];
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200661 LOGP(DRLCMAC, LOGL_DEBUG, "Slot Allocation (Algorithm B) for "
Jacob Erlbeckbefc7602015-06-02 12:33:30 +0200662 "class %d\n", tbf->ms_class());
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200663 } else {
664 ms_class = &gprs_ms_multislot_class[12];
665 LOGP(DRLCMAC, LOGL_DEBUG, "Slot Allocation (Algorithm B) for "
666 "unknow class (assuming 12)\n");
667 }
668
669 if (ms_class->tx == MS_NA) {
670 LOGP(DRLCMAC, LOGL_NOTICE, "Multislot class %d not "
Jacob Erlbeckbefc7602015-06-02 12:33:30 +0200671 "applicable.\n", tbf->ms_class());
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200672 return -EINVAL;
673 }
674
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200675 Tx = ms_class->tx;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200676 Sum = ms_class->sum;
677 Tta = ms_class->ta;
678 Ttb = ms_class->tb;
679 Tra = ms_class->ra;
680 Trb = ms_class->rb;
681 Type = ms_class->type;
682
683 /* Tta and Ttb may depend on hopping or frequency change */
Holger Hans Peter Freytherf34f3442013-12-25 20:33:37 +0100684 if (Ttb == MS_A || Ttb == MS_B)
Holger Hans Peter Freyther11a74892013-09-29 08:13:42 +0200685 Ttb = 0;
Holger Hans Peter Freytherf34f3442013-12-25 20:33:37 +0100686 if (Trb == MS_A || Trb == MS_C)
Holger Hans Peter Freyther11a74892013-09-29 08:13:42 +0200687 Trb = 0;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200688
689 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 +0100690 " Tra=%d Trb=%d Type=%d\n", ms_class->rx, Tx,
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200691 (Sum == MS_NA) ? "N/A" : digit[Sum],
692 (Tta == MS_NA) ? "N/A" : digit[Tta], Ttb, Tra, Trb, Type);
693
694 /* select the values for time contraints */
Holger Hans Peter Freyther11a74892013-09-29 08:13:42 +0200695 /* applicable to type 1 and type 2 */
696 Tt = Ttb;
697 Tr = Trb;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200698
Holger Hans Peter Freyther882fc9b2013-12-25 20:34:26 +0100699 uint8_t rx_win_min, rx_win_max;
700 rx_window = select_dl_slots(tbf->trx, ms_class->type, ms_class->rx,
701 &rx_win_min, &rx_win_max);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200702
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200703
704 /* reduce window, if existing uplink slots collide RX window */
Jacob Erlbecke2e004e2015-06-18 17:16:26 +0200705 int rc = reduce_rx_window(ms_class->type, ms, Tt, Tr,
Holger Hans Peter Freythere45c19b2013-12-25 20:53:53 +0100706 &rx_window, &rx_win_min, &rx_win_max);
707 if (rc < 0)
708 return rc;
Andreas Eversberg1cd9d882014-01-04 15:42:38 +0100709 shrink_rx_window(&rx_win_min, &rx_win_max, rx_window);
Holger Hans Peter Freytherdd4af802013-12-25 21:03:42 +0100710 rx_win_max = update_rx_win_max(ms_class->type, Tt, Tr,
711 rx_win_min, rx_win_max);
Andreas Eversberg1cd9d882014-01-04 15:42:38 +0100712 shrink_rx_window(&rx_win_min, &rx_win_max, rx_window);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200713 LOGP(DRLCMAC, LOGL_DEBUG, "- RX-Window is: %d..%d\n", rx_win_min,
714 rx_win_max);
715
716 /* calculate TX window */
Holger Hans Peter Freyther3fd2ddf2013-12-25 21:11:20 +0100717 uint8_t tx_win_min, tx_win_max, tx_range;
718 tx_win_from_rx(ms_class->type, rx_win_min, rx_win_max, Tt, Tr,
719 &tx_win_min, &tx_win_max, &tx_range);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200720
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100721 /* select UL slots but in both cases assign first_common_ts */
722 uint8_t tx_window = 0;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200723 if (tbf->direction == GPRS_RLCMAC_UL_TBF) {
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100724 rc = select_ul_slots(tbf->trx, ms_class->type, ms_class->tx,
Andreas Eversberg765736d2014-01-04 15:27:31 +0100725 tx_win_min, tx_range, usf,
726 &first_common_ts, rx_window);
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100727 if (rc < 0)
728 return rc;
729 tx_window = rc;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200730 } else {
Andreas Eversberg765736d2014-01-04 15:27:31 +0100731 first_common_ts = select_first_ts(tbf->trx, tx_win_min,
732 tx_range, rx_window);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200733 }
Holger Hans Peter Freyther73193112013-12-26 09:49:05 +0100734 #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 +0200735
736 if (first_common_ts < 0) {
737 LOGP(DRLCMAC, LOGL_NOTICE, "No first common slots available\n");
738 return -EINVAL;
739 }
740
741 if (tbf->direction == GPRS_RLCMAC_DL_TBF) {
Daniel Willmanncd44ec42014-08-07 15:04:57 +0200742 struct gprs_rlcmac_dl_tbf *dl_tbf = static_cast<gprs_rlcmac_dl_tbf *>(tbf);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200743 /* assign downlink */
744 if (rx_window == 0) {
745 LOGP(DRLCMAC, LOGL_NOTICE, "No downlink slots "
746 "available\n");
747 return -EINVAL;
748 }
749 for (ts = 0; ts < 8; ts++) {
750 if ((rx_window & (1 << ts))) {
751 /* be sure to select a single downlink slots
752 * that can be used for uplink, if multiple
753 * slots are assigned later. */
754 if (single && first_common_ts != ts)
755 continue;
756 LOGP(DRLCMAC, LOGL_DEBUG, "- Assigning DL TS "
757 "%d\n", ts);
Daniel Willmanncd44ec42014-08-07 15:04:57 +0200758 assign_dlink_tbf(&tbf->trx->pdch[ts], dl_tbf);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200759 slotcount++;
760 if (slotcount == 1)
Daniel Willmanncd44ec42014-08-07 15:04:57 +0200761 dl_tbf->first_ts = ts;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200762 if (single)
763 break;
764 }
765 }
766 } else {
Daniel Willmanncd44ec42014-08-07 15:04:57 +0200767 struct gprs_rlcmac_ul_tbf *ul_tbf = static_cast<gprs_rlcmac_ul_tbf *>(tbf);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200768 for (ts = 0; ts < 8; ts++) {
769 if ((tx_window & (1 << ts))) {
770 LOGP(DRLCMAC, LOGL_DEBUG, "- Assigning UL TS "
771 "%d\n", ts);
Daniel Willmanncd44ec42014-08-07 15:04:57 +0200772 assign_uplink_tbf_usf(&tbf->trx->pdch[ts], ul_tbf, usf[ts]);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200773 slotcount++;
774 if (slotcount == 1)
Daniel Willmanncd44ec42014-08-07 15:04:57 +0200775 ul_tbf->first_ts = ts;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200776 if (single)
777 break;
778 }
779 }
780 }
781 if (single && slotcount) {
Daniel Willmanncf1fae72014-05-30 17:58:01 +0200782 uint8_t ts_count = 0;
783 for (ts = 0; ts < 8; ts++)
784 if ((tx_window & (1 << ts)))
785 ts_count++;
786
787 tbf->upgrade_to_multislot = (ts_count > 1);
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200788 LOGP(DRLCMAC, LOGL_INFO, "Using single slot at TS %d for %s\n",
789 tbf->first_ts,
790 (tbf->direction == GPRS_RLCMAC_DL_TBF) ? "DL" : "UL");
791 } else {
Daniel Willmanncf1fae72014-05-30 17:58:01 +0200792 tbf->upgrade_to_multislot = 0;
Holger Hans Peter Freyther02ab4a82013-09-29 07:37:40 +0200793 LOGP(DRLCMAC, LOGL_INFO, "Using %d slots for %s\n", slotcount,
794 (tbf->direction == GPRS_RLCMAC_DL_TBF) ? "DL" : "UL");
795 }
796 if (slotcount == 0)
797 return -EBUSY;
798
799 tbf->first_common_ts = first_common_ts;
800
801 return 0;
802}