Merge commit 'fdd0a700930bdd04bc8827ef88dc5039ecc5b6ce'
[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 #include <gsm.h>
29
30 #include <layer1/sync.h>
31 #include <layer1/tdma_sched.h>
32 #include <layer1/mframe_sched.h>
33
34 enum mf_sched_item_flag {
35         MF_F_SACCH,
36         //MF_F_UL_OFFS_15,      /* uplink 15 frames after downlink */
37 };
38
39 /* A multiframe operation which can be scheduled for a multiframe */
40 struct mframe_sched_item {
41         /* The TDMA scheduler item that shall be scheduled */
42         const struct tdma_sched_item *sched_set;
43         /* Which modulo shall be used on the frame number */
44         uint16_t modulo;
45         /* At which number inside the modulo shall we be scheduled */
46         uint16_t frame_nr;
47         /* bit-mask of flags */
48         uint32_t flags;
49 };
50
51 /* FIXME: properly clean this up */
52 extern const struct tdma_sched_item nb_sched_set[];
53 extern const struct tdma_sched_item nb_sched_set_ul[];
54 #define NB_QUAD_DL      nb_sched_set
55 #define NB_QUAD_FH_DL   NB_QUAD_DL
56 #define NB_QUAD_UL      nb_sched_set_ul
57 #define NB_QUAD_FH_UL   NB_QUAD_UL
58
59 /* BCCH Normal */
60 static const struct mframe_sched_item mf_bcch_norm[] = {
61         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 2 },
62         { .sched_set = NULL }
63 };
64
65 /* BCCH Extended */
66 static const struct mframe_sched_item mf_bcch_ext[] = {
67         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 6 },
68         { .sched_set = NULL }
69 };
70
71 /* Full CCCH in a pure BCCH + CCCH C0T0 */
72 static const struct mframe_sched_item mf_ccch[] = {
73         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 6 },
74         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 12 },
75         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 16 },
76         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 22 },
77         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 26 },
78         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 32 },
79         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 36 },
80         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 42 },
81         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 46 },
82         { .sched_set = NULL }
83 };
84
85 /* Full CCCH in a combined CCCH on C0T0 */
86 static const struct mframe_sched_item mf_ccch_comb[] = {
87         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 6 },
88         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 12 },
89         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 16 },
90         { .sched_set = NULL }
91 };
92
93 /* SDCCH/4 in a combined CCCH on C0T0, cannot be FH */
94 static const struct mframe_sched_item mf_sdcch4_0[] = {
95         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 22 },
96         { .sched_set = NB_QUAD_UL, .modulo = 51, .frame_nr = 22+15 },
97         { .sched_set = NB_QUAD_DL, .modulo = 2*51, .frame_nr = 42,
98           .flags = MF_F_SACCH },
99         { .sched_set = NB_QUAD_UL, .modulo = 2*51, .frame_nr = 42+15,
100           .flags = MF_F_SACCH },
101         { .sched_set = NULL }
102 };
103 static const struct mframe_sched_item mf_sdcch4_1[] = {
104         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 26 },
105         { .sched_set = NB_QUAD_UL, .modulo = 51, .frame_nr = 26+15 },
106         { .sched_set = NB_QUAD_DL, .modulo = 2*51, .frame_nr = 46,
107           .flags = MF_F_SACCH },
108         { .sched_set = NB_QUAD_UL, .modulo = 2*51, .frame_nr = 46+15,
109           .flags = MF_F_SACCH },
110         { .sched_set = NULL }
111 };
112 static const struct mframe_sched_item mf_sdcch4_2[] = {
113         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 32 },
114         { .sched_set = NB_QUAD_UL, .modulo = 51, .frame_nr = 32+15 },
115         { .sched_set = NB_QUAD_DL, .modulo = 2*51, .frame_nr = 51+42,
116           .flags = MF_F_SACCH },
117         { .sched_set = NB_QUAD_UL, .modulo = 2*51, .frame_nr = 51+42+15,
118           .flags = MF_F_SACCH },
119         { .sched_set = NULL }
120 };
121 static const struct mframe_sched_item mf_sdcch4_3[] = {
122         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 36 },
123         { .sched_set = NB_QUAD_UL, .modulo = 51, .frame_nr = 36+15 },
124         { .sched_set = NB_QUAD_DL, .modulo = 2*51, .frame_nr = 51+46,
125           .flags = MF_F_SACCH },
126         { .sched_set = NB_QUAD_UL, .modulo = 2*51, .frame_nr = 51+46+15,
127           .flags = MF_F_SACCH },
128         { .sched_set = NULL }
129 };
130
131 /* SDCCH/8, can be frequency hopping (FH) */
132 static const struct mframe_sched_item mf_sdcch8_0[] = {
133         { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 0 },
134         { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 0+15 },
135         { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 32,
136           .flags = MF_F_SACCH },
137         { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 32+15,
138           .flags = MF_F_SACCH },
139         { .sched_set = NULL }
140 };
141 static const struct mframe_sched_item mf_sdcch8_1[] = {
142         { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 4 },
143         { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 4+15 },
144         { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 36,
145           .flags = MF_F_SACCH },
146         { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 36+15,
147           .flags = MF_F_SACCH },
148         { .sched_set = NULL }
149 };
150 static const struct mframe_sched_item mf_sdcch8_2[] = {
151         { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 8 },
152         { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 8+15 },
153         { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 40,
154           .flags = MF_F_SACCH },
155         { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 40+15,
156           .flags = MF_F_SACCH },
157         { .sched_set = NULL }
158 };
159 static const struct mframe_sched_item mf_sdcch8_3[] = {
160         { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 12 },
161         { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 12+15 },
162         { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 44,
163           .flags = MF_F_SACCH },
164         { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 44+15,
165           .flags = MF_F_SACCH },
166         { .sched_set = NULL }
167 };
168 static const struct mframe_sched_item mf_sdcch8_4[] = {
169         { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 16 },
170         { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 16+15 },
171         { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 51+32,
172           .flags = MF_F_SACCH },
173         { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 51+32+15,
174           .flags = MF_F_SACCH },
175         { .sched_set = NULL }
176 };
177 static const struct mframe_sched_item mf_sdcch8_5[] = {
178         { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 20 },
179         { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 20+15 },
180         { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 51+36,
181           .flags = MF_F_SACCH },
182         { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 51+36+15,
183           .flags = MF_F_SACCH },
184         { .sched_set = NULL }
185 };
186 static const struct mframe_sched_item mf_sdcch8_6[] = {
187         { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 24 },
188         { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 24+15 },
189         { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 51+40,
190           .flags = MF_F_SACCH },
191         { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 51+40+15,
192           .flags = MF_F_SACCH },
193         { .sched_set = NULL }
194 };
195 static const struct mframe_sched_item mf_sdcch8_7[] = {
196         { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 28 },
197         { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 28+15 },
198         { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 51+44,
199           .flags = MF_F_SACCH },
200         { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 51+44+15,
201           .flags = MF_F_SACCH },
202         { .sched_set = NULL }
203 };
204
205 static const struct mframe_sched_item *sched_set_for_task[32] = {
206         [MF_TASK_BCCH_NORM] = mf_bcch_norm,
207         [MF_TASK_BCCH_EXT] = mf_bcch_ext,
208         [MF_TASK_CCCH] = mf_ccch,
209         [MF_TASK_CCCH_COMB] = mf_ccch_comb,
210
211         [MF_TASK_SDCCH4_0] = mf_sdcch4_0,
212         [MF_TASK_SDCCH4_1] = mf_sdcch4_1,
213         [MF_TASK_SDCCH4_2] = mf_sdcch4_2,
214         [MF_TASK_SDCCH4_3] = mf_sdcch4_3,
215
216         [MF_TASK_SDCCH8_0] = mf_sdcch8_0,
217         [MF_TASK_SDCCH8_1] = mf_sdcch8_1,
218         [MF_TASK_SDCCH8_2] = mf_sdcch8_2,
219         [MF_TASK_SDCCH8_3] = mf_sdcch8_3,
220         [MF_TASK_SDCCH8_4] = mf_sdcch8_4,
221         [MF_TASK_SDCCH8_5] = mf_sdcch8_5,
222         [MF_TASK_SDCCH8_6] = mf_sdcch8_6,
223         [MF_TASK_SDCCH8_7] = mf_sdcch8_7,
224 };
225
226 /* how many TDMA frame ticks should we schedule events ahead? */
227 #define SCHEDULE_AHEAD  2
228
229 /* how long do we need to tell the DSP in advance what we want to do? */
230 #define SCHEDULE_LATENCY        1
231
232 /* (test and) schedule one particular sched_item_set by means of the TDMA scheduler */
233 static void mframe_schedule_set(const struct mframe_sched_item *set)
234 {
235         const struct mframe_sched_item *si;
236
237         for (si = set; si->sched_set != NULL; si++) {
238                 unsigned int trigger = si->frame_nr % si->modulo;
239                 unsigned int current = (l1s.current_time.fn + SCHEDULE_AHEAD) % si->modulo;
240                 if (current == trigger) {
241                         /* FIXME: what to do with SACCH Flag etc? */
242                         tdma_schedule_set(SCHEDULE_AHEAD-SCHEDULE_LATENCY, si->sched_set);
243                 }
244         }
245 }
246
247 /* Schedule mframe_sched_items according to current MF TASK list */
248 void mframe_schedule(uint32_t tasks_enabled)
249 {
250         unsigned int i;
251
252         for (i = 0; i < 32; i++) {
253                 if (tasks_enabled & (1 << i))
254                         mframe_schedule_set(sched_set_for_task[i]);
255         }
256 }