[layer1] Adding neighbour cell measurement code to layer1.
[osmocom-bb.git] / src / target / firmware / layer1 / mframe_sched.c
1 /* GSM Multiframe Scheduler Implementation (on top of TDMA sched) */
2
3 /* (C) 2010 by Harald Welte <laforge@gnumonks.org>
4  *
5  * All Rights Reserved
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (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 along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  */
22
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <string.h>
26
27 #include <debug.h>
28
29 #include <osmocom/gsm/gsm_utils.h>
30
31 #include <layer1/prim.h>
32 #include <layer1/sync.h>
33 #include <layer1/tdma_sched.h>
34 #include <layer1/mframe_sched.h>
35
36 /* A multiframe operation which can be scheduled for a multiframe */
37 struct mframe_sched_item {
38         /* The TDMA scheduler item that shall be scheduled */
39         const struct tdma_sched_item *sched_set;
40         /* Which modulo shall be used on the frame number */
41         uint16_t modulo;
42         /* At which number inside the modulo shall we be scheduled */
43         uint16_t frame_nr;
44         /* bit-mask of flags */
45         uint16_t flags;
46 };
47
48 /* FIXME: properly clean this up */
49 #define NB_QUAD_DL      nb_sched_set
50 #define NB_QUAD_FH_DL   NB_QUAD_DL
51 #define NB_QUAD_UL      nb_sched_set_ul
52 #define NB_QUAD_FH_UL   NB_QUAD_UL
53 #define NEIGH_PM        neigh_pm_sched_set
54
55 /* BCCH Normal */
56 static const struct mframe_sched_item mf_bcch_norm[] = {
57         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 2 },
58         { .sched_set = NULL }
59 };
60
61 /* BCCH Extended */
62 static const struct mframe_sched_item mf_bcch_ext[] = {
63         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 6 },
64         { .sched_set = NULL }
65 };
66
67 /* Full CCCH in a pure BCCH + CCCH C0T0 */
68 static const struct mframe_sched_item mf_ccch[] = {
69         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 6 },
70         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 12 },
71         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 16 },
72         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 22 },
73         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 26 },
74         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 32 },
75         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 36 },
76         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 42 },
77         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 46 },
78         { .sched_set = NULL }
79 };
80
81 /* Full CCCH in a combined CCCH on C0T0 */
82 static const struct mframe_sched_item mf_ccch_comb[] = {
83         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 6 },
84         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 12 },
85         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 16 },
86         { .sched_set = NULL }
87 };
88
89 /* SDCCH/4 in a combined CCCH on C0T0, cannot be FH */
90 static const struct mframe_sched_item mf_sdcch4_0[] = {
91         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 22 },
92         { .sched_set = NB_QUAD_UL, .modulo = 51, .frame_nr = 22+15 },
93         { .sched_set = NB_QUAD_DL, .modulo = 2*51, .frame_nr = 42,
94           .flags = MF_F_SACCH },
95         { .sched_set = NB_QUAD_UL, .modulo = 2*51, .frame_nr = 42+15,
96           .flags = MF_F_SACCH },
97         { .sched_set = NULL }
98 };
99 static const struct mframe_sched_item mf_sdcch4_1[] = {
100         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 26 },
101         { .sched_set = NB_QUAD_UL, .modulo = 51, .frame_nr = 26+15 },
102         { .sched_set = NB_QUAD_DL, .modulo = 2*51, .frame_nr = 46,
103           .flags = MF_F_SACCH },
104         { .sched_set = NB_QUAD_UL, .modulo = 2*51, .frame_nr = 46+15,
105           .flags = MF_F_SACCH },
106         { .sched_set = NULL }
107 };
108 static const struct mframe_sched_item mf_sdcch4_2[] = {
109         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 32 },
110         { .sched_set = NB_QUAD_UL, .modulo = 51, .frame_nr = 32+15 },
111         { .sched_set = NB_QUAD_DL, .modulo = 2*51, .frame_nr = 51+42,
112           .flags = MF_F_SACCH },
113         { .sched_set = NB_QUAD_UL, .modulo = 2*51, .frame_nr = 51+42+15,
114           .flags = MF_F_SACCH },
115         { .sched_set = NULL }
116 };
117 static const struct mframe_sched_item mf_sdcch4_3[] = {
118         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 36 },
119         { .sched_set = NB_QUAD_UL, .modulo = 51, .frame_nr = 36+15 },
120         { .sched_set = NB_QUAD_DL, .modulo = 2*51, .frame_nr = 51+46,
121           .flags = MF_F_SACCH },
122         { .sched_set = NB_QUAD_UL, .modulo = 2*51, .frame_nr = 51+46+15,
123           .flags = MF_F_SACCH },
124         { .sched_set = NULL }
125 };
126
127 /* SDCCH/8, can be frequency hopping (FH) */
128 static const struct mframe_sched_item mf_sdcch8_0[] = {
129         { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 0 },
130         { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 0+15 },
131         { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 32,
132           .flags = MF_F_SACCH },
133         { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 32+15,
134           .flags = MF_F_SACCH },
135         { .sched_set = NULL }
136 };
137 static const struct mframe_sched_item mf_sdcch8_1[] = {
138         { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 4 },
139         { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 4+15 },
140         { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 36,
141           .flags = MF_F_SACCH },
142         { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 36+15,
143           .flags = MF_F_SACCH },
144         { .sched_set = NULL }
145 };
146 static const struct mframe_sched_item mf_sdcch8_2[] = {
147         { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 8 },
148         { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 8+15 },
149         { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 40,
150           .flags = MF_F_SACCH },
151         { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 40+15,
152           .flags = MF_F_SACCH },
153         { .sched_set = NULL }
154 };
155 static const struct mframe_sched_item mf_sdcch8_3[] = {
156         { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 12 },
157         { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 12+15 },
158         { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 44,
159           .flags = MF_F_SACCH },
160         { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 44+15,
161           .flags = MF_F_SACCH },
162         { .sched_set = NULL }
163 };
164 static const struct mframe_sched_item mf_sdcch8_4[] = {
165         { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 16 },
166         { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 16+15 },
167         { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 51+32,
168           .flags = MF_F_SACCH },
169         { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 51+32+15,
170           .flags = MF_F_SACCH },
171         { .sched_set = NULL }
172 };
173 static const struct mframe_sched_item mf_sdcch8_5[] = {
174         { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 20 },
175         { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 20+15 },
176         { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 51+36,
177           .flags = MF_F_SACCH },
178         { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 51+36+15,
179           .flags = MF_F_SACCH },
180         { .sched_set = NULL }
181 };
182 static const struct mframe_sched_item mf_sdcch8_6[] = {
183         { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 24 },
184         { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 24+15 },
185         { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 51+40,
186           .flags = MF_F_SACCH },
187         { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 51+40+15,
188           .flags = MF_F_SACCH },
189         { .sched_set = NULL }
190 };
191 static const struct mframe_sched_item mf_sdcch8_7[] = {
192         { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 28 },
193         { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 28+15 },
194         { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 51+44,
195           .flags = MF_F_SACCH },
196         { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 51+44+15,
197           .flags = MF_F_SACCH },
198         { .sched_set = NULL }
199 };
200
201 /* Measurement for MF 51 */
202 static const struct mframe_sched_item mf_neigh_pm51[] = {
203         { .sched_set = NEIGH_PM   , .modulo = 51, .frame_nr = 50 },
204         { .sched_set = NULL }
205 };
206
207 /* TCH */
208 #define TCH     tch_sched_set
209 #define TCH_A   tch_a_sched_set
210 #define TCH_D   tch_d_sched_set
211
212 static const struct mframe_sched_item mf_tch_f_even[] = {
213         { .sched_set = TCH,   .modulo = 13, .frame_nr =  0 },
214         { .sched_set = TCH,   .modulo = 13, .frame_nr =  1 },
215         { .sched_set = TCH,   .modulo = 13, .frame_nr =  2 },
216         { .sched_set = TCH,   .modulo = 13, .frame_nr =  3 },
217         { .sched_set = TCH,   .modulo = 13, .frame_nr =  4 },
218         { .sched_set = TCH,   .modulo = 13, .frame_nr =  5 },
219         { .sched_set = TCH,   .modulo = 13, .frame_nr =  6 },
220         { .sched_set = TCH,   .modulo = 13, .frame_nr =  7 },
221         { .sched_set = TCH,   .modulo = 13, .frame_nr =  8 },
222         { .sched_set = TCH,   .modulo = 13, .frame_nr =  9 },
223         { .sched_set = TCH,   .modulo = 13, .frame_nr = 10 },
224         { .sched_set = TCH,   .modulo = 13, .frame_nr = 11 },
225         { .sched_set = TCH_A, .modulo = 26, .frame_nr = 12,
226           .flags = MF_F_SACCH },
227         { .sched_set = NULL }
228 };
229
230 static const struct mframe_sched_item mf_tch_f_odd[] = {
231         { .sched_set = TCH,   .modulo = 13, .frame_nr =  0 },
232         { .sched_set = TCH,   .modulo = 13, .frame_nr =  1 },
233         { .sched_set = TCH,   .modulo = 13, .frame_nr =  2 },
234         { .sched_set = TCH,   .modulo = 13, .frame_nr =  3 },
235         { .sched_set = TCH,   .modulo = 13, .frame_nr =  4 },
236         { .sched_set = TCH,   .modulo = 13, .frame_nr =  5 },
237         { .sched_set = TCH,   .modulo = 13, .frame_nr =  6 },
238         { .sched_set = TCH,   .modulo = 13, .frame_nr =  7 },
239         { .sched_set = TCH,   .modulo = 13, .frame_nr =  8 },
240         { .sched_set = TCH,   .modulo = 13, .frame_nr =  9 },
241         { .sched_set = TCH,   .modulo = 13, .frame_nr = 10 },
242         { .sched_set = TCH,   .modulo = 13, .frame_nr = 11 },
243         { .sched_set = TCH_A, .modulo = 26, .frame_nr = 25,
244           .flags = MF_F_SACCH },
245         { .sched_set = NULL }
246 };
247
248 static const struct mframe_sched_item mf_tch_h_0[] = {
249         { .sched_set = TCH,   .modulo = 13, .frame_nr =  0 },
250         { .sched_set = TCH_D, .modulo = 13, .frame_nr =  1 },
251         { .sched_set = TCH,   .modulo = 13, .frame_nr =  2 },
252         { .sched_set = TCH_D, .modulo = 13, .frame_nr =  3 },
253         { .sched_set = TCH,   .modulo = 13, .frame_nr =  4 },
254         { .sched_set = TCH_D, .modulo = 13, .frame_nr =  5 },
255         { .sched_set = TCH,   .modulo = 13, .frame_nr =  6 },
256         { .sched_set = TCH_D, .modulo = 13, .frame_nr =  7 },
257         { .sched_set = TCH,   .modulo = 13, .frame_nr =  8 },
258         { .sched_set = TCH_D, .modulo = 13, .frame_nr =  9 },
259         { .sched_set = TCH,   .modulo = 13, .frame_nr = 10 },
260         { .sched_set = TCH_D, .modulo = 13, .frame_nr = 11 },
261         { .sched_set = TCH_A, .modulo = 26, .frame_nr = 12,
262           .flags = MF_F_SACCH },
263         { .sched_set = NULL }
264 };
265
266 static const struct mframe_sched_item mf_tch_h_1[] = {
267         { .sched_set = TCH_D, .modulo = 13, .frame_nr =  0 },
268         { .sched_set = TCH,   .modulo = 13, .frame_nr =  1 },
269         { .sched_set = TCH_D, .modulo = 13, .frame_nr =  2 },
270         { .sched_set = TCH,   .modulo = 13, .frame_nr =  3 },
271         { .sched_set = TCH_D, .modulo = 13, .frame_nr =  4 },
272         { .sched_set = TCH,   .modulo = 13, .frame_nr =  5 },
273         { .sched_set = TCH_D, .modulo = 13, .frame_nr =  6 },
274         { .sched_set = TCH,   .modulo = 13, .frame_nr =  7 },
275         { .sched_set = TCH_D, .modulo = 13, .frame_nr =  8 },
276         { .sched_set = TCH,   .modulo = 13, .frame_nr =  9 },
277         { .sched_set = TCH_D, .modulo = 13, .frame_nr = 10 },
278         { .sched_set = TCH,   .modulo = 13, .frame_nr = 11 },
279         { .sched_set = TCH_A, .modulo = 26, .frame_nr = 25,
280           .flags = MF_F_SACCH },
281         { .sched_set = NULL }
282 };
283
284 /* Measurement for MF 26 */
285 static const struct mframe_sched_item mf_neigh_pm26_even[] = {
286         { .sched_set = NEIGH_PM   , .modulo = 26, .frame_nr = 25 },
287         { .sched_set = NULL }
288 };
289 static const struct mframe_sched_item mf_neigh_pm26_odd[] = {
290         { .sched_set = NEIGH_PM   , .modulo = 26, .frame_nr = 12 },
291         { .sched_set = NULL }
292 };
293
294 /* Test TX */
295 static const struct mframe_sched_item mf_tx_all_nb[] = {
296         { .sched_set = NB_QUAD_FH_UL, .modulo = 4, .frame_nr = 0 },
297         { .sched_set = NULL }
298 };
299
300 static const struct mframe_sched_item *sched_set_for_task[32] = {
301         [MF_TASK_BCCH_NORM] = mf_bcch_norm,
302         [MF_TASK_BCCH_EXT] = mf_bcch_ext,
303         [MF_TASK_CCCH] = mf_ccch,
304         [MF_TASK_CCCH_COMB] = mf_ccch_comb,
305
306         [MF_TASK_SDCCH4_0] = mf_sdcch4_0,
307         [MF_TASK_SDCCH4_1] = mf_sdcch4_1,
308         [MF_TASK_SDCCH4_2] = mf_sdcch4_2,
309         [MF_TASK_SDCCH4_3] = mf_sdcch4_3,
310
311         [MF_TASK_SDCCH8_0] = mf_sdcch8_0,
312         [MF_TASK_SDCCH8_1] = mf_sdcch8_1,
313         [MF_TASK_SDCCH8_2] = mf_sdcch8_2,
314         [MF_TASK_SDCCH8_3] = mf_sdcch8_3,
315         [MF_TASK_SDCCH8_4] = mf_sdcch8_4,
316         [MF_TASK_SDCCH8_5] = mf_sdcch8_5,
317         [MF_TASK_SDCCH8_6] = mf_sdcch8_6,
318         [MF_TASK_SDCCH8_7] = mf_sdcch8_7,
319
320         [MF_TASK_TCH_F_EVEN] = mf_tch_f_even,
321         [MF_TASK_TCH_F_ODD]  = mf_tch_f_odd,
322         [MF_TASK_TCH_H_0]    = mf_tch_h_0,
323         [MF_TASK_TCH_H_1]    = mf_tch_h_1,
324
325         [MF_TASK_NEIGH_PM51] = mf_neigh_pm51,
326         [MF_TASK_NEIGH_PM26E] = mf_neigh_pm26_even,
327         [MF_TASK_NEIGH_PM26O] = mf_neigh_pm26_odd,
328
329         [MF_TASK_UL_ALL_NB] = mf_tx_all_nb,
330 };
331
332 /* encodes a channel number according to 08.58 Chapter 9.3.1 */
333 uint8_t mframe_task2chan_nr(enum mframe_task mft, uint8_t ts)
334 {
335         uint8_t cbits;
336
337         switch (mft) {
338         case MF_TASK_BCCH_NORM:
339         case MF_TASK_BCCH_EXT:
340                 cbits = 0x10;
341                 break;
342         case MF_TASK_CCCH:
343         case MF_TASK_CCCH_COMB:
344                 cbits = 0x12;
345                 break;
346         case MF_TASK_SDCCH4_0:
347                 cbits = 0x04 + 0;
348                 break;
349         case MF_TASK_SDCCH4_1:
350                 cbits = 0x04 + 1;
351                 break;
352         case MF_TASK_SDCCH4_2:
353                 cbits = 0x04 + 2;
354                 break;
355         case MF_TASK_SDCCH4_3:
356                 cbits = 0x04 + 3;
357                 break;
358         case MF_TASK_SDCCH8_0:
359                 cbits = 0x08 + 0;
360                 break;
361         case MF_TASK_SDCCH8_1:
362                 cbits = 0x08 + 1;
363                 break;
364         case MF_TASK_SDCCH8_2:
365                 cbits = 0x08 + 2;
366                 break;
367         case MF_TASK_SDCCH8_3:
368                 cbits = 0x08 + 3;
369                 break;
370         case MF_TASK_SDCCH8_4:
371                 cbits = 0x08 + 4;
372                 break;
373         case MF_TASK_SDCCH8_5:
374                 cbits = 0x08 + 5;
375                 break;
376         case MF_TASK_SDCCH8_6:
377                 cbits = 0x08 + 6;
378                 break;
379         case MF_TASK_SDCCH8_7:
380                 cbits = 0x08 + 7;
381                 break;
382         case MF_TASK_TCH_F_EVEN:
383         case MF_TASK_TCH_F_ODD:
384                 cbits = 0x01;
385                 break;
386         case MF_TASK_TCH_H_0:
387                 cbits = 0x02 + 0;
388                 break;
389         case MF_TASK_TCH_H_1:
390                 cbits = 0x02 + 1;
391                 break;
392         case MF_TASK_UL_ALL_NB:
393                 /* ERROR: cannot express as channel number */
394                 cbits = 0;
395                 break;
396         }
397
398         return (cbits << 3) | (ts & 0x7);
399 }
400
401 /* how many TDMA frame ticks should we schedule events ahead? */
402 #define SCHEDULE_AHEAD  2
403
404 /* how long do we need to tell the DSP in advance what we want to do? */
405 #define SCHEDULE_LATENCY        1
406
407 /* (test and) schedule one particular sched_item_set by means of the TDMA scheduler */
408 static void mframe_schedule_set(enum mframe_task task_id)
409 {
410         const struct mframe_sched_item *set = sched_set_for_task[task_id];
411         const struct mframe_sched_item *si;
412
413         for (si = set; si->sched_set != NULL; si++) {
414                 unsigned int trigger = si->frame_nr % si->modulo;
415                 unsigned int current = (l1s.current_time.fn + SCHEDULE_AHEAD) % si->modulo;
416                 if (current == trigger) {
417                         uint32_t fn;
418                         int rv;
419
420                         /* Schedule the set */
421                         /* FIXME: what to do with SACCH Flag etc? */
422                         rv = tdma_schedule_set(SCHEDULE_AHEAD-SCHEDULE_LATENCY,
423                                           si->sched_set, task_id | (si->flags<<8));
424
425                         /* Compute the next safe time to queue a DSP command */
426                         fn = l1s.current_time.fn;
427                         ADD_MODULO(fn, rv - 2, GSM_MAX_FN); /* -2 = worst case last dsp command */
428                         if ((fn > l1s.mframe_sched.safe_fn) ||
429                             (l1s.mframe_sched.safe_fn >= GSM_MAX_FN))
430                                 l1s.mframe_sched.safe_fn = fn;
431                 }
432         }
433 }
434
435 /* Enable a specific task */
436 void mframe_enable(enum mframe_task task_id)
437 {
438         l1s.mframe_sched.tasks_tgt |= (1 << task_id);
439 }
440
441 /* Disable a specific task */
442 void mframe_disable(enum mframe_task task_id)
443 {
444         l1s.mframe_sched.tasks_tgt &= ~(1 << task_id);
445 }
446
447 /* Replace the current active set by the new one */
448 void mframe_set(uint32_t tasks)
449 {
450         l1s.mframe_sched.tasks_tgt = tasks;
451 }
452
453 /* Schedule mframe_sched_items according to current MF TASK list */
454 void mframe_schedule(void)
455 {
456         unsigned int i;
457         int fn_diff;
458
459         /* Try to enable/disable task to meet target bitmap */
460         fn_diff = l1s.mframe_sched.safe_fn - l1s.current_time.fn;
461         if ((fn_diff <= 0) || (fn_diff >= (GSM_MAX_FN>>1)) ||
462             (l1s.mframe_sched.safe_fn >= GSM_MAX_FN))
463                 /* If nothing is in the way, enable new tasks */
464                 l1s.mframe_sched.tasks = l1s.mframe_sched.tasks_tgt;
465         else
466                 /* Else, Disable only */
467                 l1s.mframe_sched.tasks &= l1s.mframe_sched.tasks_tgt;
468
469         /* Schedule any active pending set */
470         for (i = 0; i < 32; i++) {
471                 if (l1s.mframe_sched.tasks & (1 << i))
472                         mframe_schedule_set(i);
473         }
474 }
475
476 /* reset the scheduler, disabling all tasks */
477 void mframe_reset(void)
478 {
479         l1s.mframe_sched.tasks = 0;
480         l1s.mframe_sched.tasks_tgt = 0;
481         l1s.mframe_sched.safe_fn = -1UL;        /* Force safe */
482 }
483