blob: b25f2fdc3537fe51a58a4301d318091fc3a25add [file] [log] [blame]
Pau Espin Pedroldeaa6fd2020-07-16 20:53:21 +02001/* (C) 2018-2020 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
Stefan Sperling6442e432018-02-06 14:44:54 +01002 *
3 * Author: Stefan Sperling <ssperling@sysmocom.de>
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 Affero General Public License as published by
9 * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include <strings.h>
Pau Espin Pedroldeaa6fd2020-07-16 20:53:21 +020023#include <stdint.h>
24#include <inttypes.h>
Stefan Sperling6442e432018-02-06 14:44:54 +010025#include <errno.h>
26#include <stdbool.h>
27
28#include <osmocom/bsc/debug.h>
Pau Espin Pedrol02f20562020-07-20 16:21:54 +020029#include <osmocom/bsc/acc.h>
Stefan Sperling6442e432018-02-06 14:44:54 +010030#include <osmocom/bsc/gsm_data.h>
Stefan Sperling4d3d2432018-04-12 09:18:36 +020031#include <osmocom/bsc/chan_alloc.h>
Stefan Sperling60ecdef2018-04-10 17:55:08 +020032#include <osmocom/bsc/signal.h>
Stefan Sperlingcda994e2018-04-12 09:18:36 +020033#include <osmocom/bsc/abis_nm.h>
Pau Espin Pedrol388ed582020-07-15 20:53:16 +020034#include <osmocom/bsc/bts.h>
Stefan Sperling6442e432018-02-06 14:44:54 +010035
36/*
37 * Check if an ACC has been permanently barred for a BTS,
38 * e.g. with the 'rach access-control-class' VTY command.
39 */
Stefan Sperling0ad90b32018-04-11 13:36:52 +020040static bool acc_is_permanently_barred(struct gsm_bts *bts, unsigned int acc)
Stefan Sperling6442e432018-02-06 14:44:54 +010041{
Harald Welte7f2e8512018-10-21 12:21:57 +020042 OSMO_ASSERT(acc <= 9);
Stefan Sperling6442e432018-02-06 14:44:54 +010043 if (acc == 8 || acc == 9)
Stefan Sperling0ad90b32018-04-11 13:36:52 +020044 return (bts->si_common.rach_control.t2 & (1 << (acc - 8)));
45 return (bts->si_common.rach_control.t3 & (1 << (acc)));
Stefan Sperling6442e432018-02-06 14:44:54 +010046}
47
Pau Espin Pedroldeaa6fd2020-07-16 20:53:21 +020048/*!
49 * Return bitmasks which correspond to access control classes that are currently
50 * denied access. Ramping is only concerned with those bits which control access
51 * for ACCs 0-9, and any of the other bits will always be set to zero in these masks, i.e.
52 * it is safe to OR these bitmasks with the corresponding fields in struct gsm48_rach_control.
53 * \param[in] acc_mgr Pointer to acc_mgr structure.
54 */
55static inline uint8_t acc_mgr_get_barred_t2(struct acc_mgr *acc_mgr)
Stefan Sperling6442e432018-02-06 14:44:54 +010056{
Pau Espin Pedroldeaa6fd2020-07-16 20:53:21 +020057 return ((~acc_mgr->allowed_subset_mask) >> 8) & 0x03;
58};
59static inline uint8_t acc_mgr_get_barred_t3(struct acc_mgr *acc_mgr)
60{
61 return (~acc_mgr->allowed_subset_mask) & 0xff;
Stefan Sperling6442e432018-02-06 14:44:54 +010062}
63
Pau Espin Pedroldeaa6fd2020-07-16 20:53:21 +020064static uint8_t acc_mgr_subset_len(struct acc_mgr *acc_mgr)
Stefan Sperling6442e432018-02-06 14:44:54 +010065{
Pau Espin Pedroldeaa6fd2020-07-16 20:53:21 +020066 return OSMO_MIN(acc_mgr->len_allowed_ramp, acc_mgr->len_allowed_adm);
Stefan Sperling6442e432018-02-06 14:44:54 +010067}
68
Pau Espin Pedroldeaa6fd2020-07-16 20:53:21 +020069static void acc_mgr_enable_rotation_cond(struct acc_mgr *acc_mgr)
Stefan Sperling6442e432018-02-06 14:44:54 +010070{
Pau Espin Pedroldeaa6fd2020-07-16 20:53:21 +020071 if (acc_mgr->allowed_permanent_count && acc_mgr->allowed_subset_mask_count &&
72 acc_mgr->allowed_permanent_count != acc_mgr->allowed_subset_mask_count) {
73 if (!osmo_timer_pending(&acc_mgr->rotate_timer))
74 osmo_timer_schedule(&acc_mgr->rotate_timer, acc_mgr->rotation_time_sec, 0);
75 } else {
76 /* No rotation needed, disable rotation timer */
77 if (osmo_timer_pending(&acc_mgr->rotate_timer))
78 osmo_timer_del(&acc_mgr->rotate_timer);
Stefan Sperling6442e432018-02-06 14:44:54 +010079 }
80}
81
Pau Espin Pedroldeaa6fd2020-07-16 20:53:21 +020082static void acc_mgr_gen_subset(struct acc_mgr *acc_mgr, bool update_si)
Stefan Sperling6442e432018-02-06 14:44:54 +010083{
Pau Espin Pedroldeaa6fd2020-07-16 20:53:21 +020084 uint8_t acc;
85
86 acc_mgr->allowed_subset_mask = 0; /* clean mask */
87 acc_mgr->allowed_subset_mask_count = 0;
88 acc_mgr->allowed_permanent_count = 0;
89
Stefan Sperling6442e432018-02-06 14:44:54 +010090 for (acc = 0; acc < 10; acc++) {
Pau Espin Pedroldeaa6fd2020-07-16 20:53:21 +020091 if (acc_is_permanently_barred(acc_mgr->bts, acc))
92 continue;
93 acc_mgr->allowed_permanent_count++;
94 if (acc_mgr->allowed_subset_mask_count < acc_mgr_subset_len(acc_mgr)) {
95 acc_mgr->allowed_subset_mask |= (1 << acc);
96 acc_mgr->allowed_subset_mask_count++;
97 }
98 }
99
100 acc_mgr_enable_rotation_cond(acc_mgr);
101
102 LOG_BTS(acc_mgr->bts, DRSL, LOGL_INFO,
103 "ACC: New ACC allowed subset 0x%03" PRIx16 " (active_len=%" PRIu8
104 ", ramp_len=%" PRIu8 ", adm_len=%" PRIu8 ", perm_len=%" PRIu8 ", rotation=%s)\n",
105 acc_mgr->allowed_subset_mask, acc_mgr->allowed_subset_mask_count,
106 acc_mgr->len_allowed_ramp, acc_mgr->len_allowed_adm,
107 acc_mgr->allowed_permanent_count,
108 osmo_timer_pending(&(acc_mgr)->rotate_timer) ? "on" : "off");
109
110 /* Trigger SI data update, acc_mgr_apply_acc will bew called */
111 if (update_si)
112 gsm_bts_set_system_infos(acc_mgr->bts);
113}
114
115static uint8_t get_highest_allowed_acc(uint16_t mask)
116{
117 for (int i = 9; i >= 0; i--) {
118 if (mask & (1 << i))
119 return i;
120 }
121 OSMO_ASSERT(0);
122 return 0;
123}
124
125static uint8_t get_lowest_allowed_acc(uint16_t mask)
126{
127 for (int i = 0; i < 10; i++) {
128 if (mask & (1 << i))
129 return i;
130 }
131 OSMO_ASSERT(0);
132 return 0;
133}
134
135#define LOG_ACC_CHG(acc_mgr, level, old_mask, verb_str) \
136 LOG_BTS((acc_mgr)->bts, DRSL, level, \
137 "ACC: %s ACC allowed active subset 0x%03" PRIx16 " -> 0x%03" PRIx16 \
138 " (active_len=%" PRIu8 ", ramp_len=%" PRIu8 ", adm_len=%" PRIu8 \
139 ", perm_len=%" PRIu8 ", rotation=%s)\n", \
140 verb_str, old_mask, (acc_mgr)->allowed_subset_mask, \
141 (acc_mgr)->allowed_subset_mask_count, \
142 (acc_mgr)->len_allowed_ramp, (acc_mgr)->len_allowed_adm, \
143 (acc_mgr)->allowed_permanent_count, \
144 osmo_timer_pending(&(acc_mgr)->rotate_timer) ? "on" : "off")
145
146/* Call when either adm_len or ramp_len changed (and values have been updated) */
147static void acc_mgr_subset_length_changed(struct acc_mgr *acc_mgr)
148{
149 uint16_t old_mask = acc_mgr->allowed_subset_mask;
150 uint8_t curr_len = acc_mgr->allowed_subset_mask_count;
151 uint8_t new_len = acc_mgr_subset_len(acc_mgr);
152 int8_t diff = new_len - curr_len;
153 uint8_t i;
154
155 if (curr_len == new_len)
156 return;
157
158 if (new_len == 0) {
159 acc_mgr->allowed_subset_mask = 0;
160 acc_mgr->allowed_subset_mask_count = 0;
161 acc_mgr_enable_rotation_cond(acc_mgr);
162 LOG_ACC_CHG(acc_mgr, LOGL_INFO, old_mask, "update");
163 gsm_bts_set_system_infos(acc_mgr->bts);
164 return;
165 }
166
167 if (curr_len == 0) {
168 acc_mgr_gen_subset(acc_mgr, true);
169 return;
170 }
171
172 /* Try to add new ACCs to the set starting from highest one (since we rotate rolling up) */
173 if (diff > 0) { /* curr_len < new_len */
174 uint8_t highest = get_highest_allowed_acc(acc_mgr->allowed_subset_mask);
175 /* It's fine skipping highest in the loop since it's known to be already set: */
176 for (i = (highest + 1) % 10; i != highest; i = (i + 1) % 10) {
177 if (acc_is_permanently_barred(acc_mgr->bts, i))
178 continue;
179 if (acc_mgr->allowed_subset_mask & (1 << i))
180 continue; /* already in set */
181 acc_mgr->allowed_subset_mask |= (1 << i);
182 acc_mgr->allowed_subset_mask_count++;
183 diff--;
184 if (diff == 0)
185 break;
186 }
187 } else { /* curr_len > new_len, try removing from lowest one. */
188 uint8_t lowest = get_lowest_allowed_acc(acc_mgr->allowed_subset_mask);
189 i = lowest;
190 do {
191 if ((acc_mgr->allowed_subset_mask & (1 << i))) {
192 acc_mgr->allowed_subset_mask &= ~(1 << i);
193 acc_mgr->allowed_subset_mask_count--;
194 diff++;
195 if (diff == 0)
196 break;
197 }
198 i = (i + 1) % 10;
199 } while(i != lowest);
200 }
201
202 acc_mgr_enable_rotation_cond(acc_mgr);
203 LOG_ACC_CHG(acc_mgr, LOGL_INFO, old_mask, "update");
204
205 /* if we updated the set, notify about it */
206 if (curr_len != acc_mgr->allowed_subset_mask_count)
207 gsm_bts_set_system_infos(acc_mgr->bts);
208
209}
210
211/* Eg: (2,3,4) -> first=2; last=4. (3,7,8) -> first=3, last=8; (8,9,2) -> first=8, last=2 */
212void get_subset_limits(struct acc_mgr *acc_mgr, uint8_t *first, uint8_t *last)
213{
214 uint8_t lowest = get_lowest_allowed_acc(acc_mgr->allowed_subset_mask);
215 uint8_t highest = get_highest_allowed_acc(acc_mgr->allowed_subset_mask);
216 /* check if there's unselected ACCs between lowest and highest, that
217 * means subset is wrapping around, eg: (8,9,1)
218 * Assumption: The permanent set is bigger than the current selected subset */
219 bool is_wrapped = false;
220 uint8_t i = (lowest + 1) % 10;
221 do {
222 if (!acc_is_permanently_barred(acc_mgr->bts, i) &&
223 !(acc_mgr->allowed_subset_mask & (1 << i))) {
224 is_wrapped = true;
225 break;
226 }
227 i = (i + 1 ) % 10;
228 } while (i != (highest + 1) % 10);
229
230 if (is_wrapped) {
231 *first = highest;
232 *last = lowest;
233 } else {
234 *first = lowest;
235 *last = highest;
236 }
237}
238static void do_acc_rotate_step(void *data)
239{
240 struct acc_mgr *acc_mgr = data;
241 uint8_t i;
242 uint8_t first, last;
243 uint16_t old_mask = acc_mgr->allowed_subset_mask;
244
245 /* Assumption: The size of the subset didn't change, that's handled by
246 * acc_mgr_subset_length_changed()
247 */
248
249 /* Assumption: Rotation timer has been disabled if no ACC is allowed */
250 OSMO_ASSERT(acc_mgr->allowed_subset_mask_count != 0);
251
252 /* One ACC is rotated at a time: Drop first ACC and add next from last ACC */
253 get_subset_limits(acc_mgr, &first, &last);
254
255 acc_mgr->allowed_subset_mask &= ~(1 << first);
256 i = (last + 1) % 10;
257 do {
258 if (!acc_is_permanently_barred(acc_mgr->bts, i) &&
259 !(acc_mgr->allowed_subset_mask & (1 << i))) {
260 /* found first one which can be allowed, do it and be done */
261 acc_mgr->allowed_subset_mask |= (1 << i);
262 break;
263 }
264 i = (i + 1 ) % 10;
265 } while (i != (last + 1) % 10);
266
267 osmo_timer_schedule(&acc_mgr->rotate_timer, acc_mgr->rotation_time_sec, 0);
268
269 if (old_mask != acc_mgr->allowed_subset_mask) {
270 LOG_ACC_CHG(acc_mgr, LOGL_INFO, old_mask, "rotate");
271 gsm_bts_set_system_infos(acc_mgr->bts);
Stefan Sperling6442e432018-02-06 14:44:54 +0100272 }
273}
274
Pau Espin Pedroldeaa6fd2020-07-16 20:53:21 +0200275void acc_mgr_init(struct acc_mgr *acc_mgr, struct gsm_bts *bts)
276{
277 acc_mgr->bts = bts;
278 acc_mgr->len_allowed_adm = 10; /* Allow all by default */
279 acc_mgr->len_allowed_ramp = 10;
280 acc_mgr->rotation_time_sec = ACC_MGR_QUANTUM_DEFAULT;
281 osmo_timer_setup(&acc_mgr->rotate_timer, do_acc_rotate_step, acc_mgr);
282 /* FIXME: Don't update SI yet, avoid crash due to bts->model being NULL */
283 acc_mgr_gen_subset(acc_mgr, false);
284}
285
286uint8_t acc_mgr_get_len_allowed_adm(struct acc_mgr *acc_mgr)
287{
288 return acc_mgr->len_allowed_adm;
289}
290
291uint8_t acc_mgr_get_len_allowed_ramp(struct acc_mgr *acc_mgr)
292{
293 return acc_mgr->len_allowed_ramp;
294}
295
296void acc_mgr_set_len_allowed_adm(struct acc_mgr *acc_mgr, uint8_t len_allowed_adm)
297{
298 uint8_t old_len;
299
300 OSMO_ASSERT(len_allowed_adm <= 10);
301
302 if (acc_mgr->len_allowed_adm == len_allowed_adm)
303 return;
304
305 LOG_BTS(acc_mgr->bts, DRSL, LOGL_DEBUG,
306 "ACC: administrative rotate subset size set to %" PRIu8 "\n", len_allowed_adm);
307
308 old_len = acc_mgr_subset_len(acc_mgr);
309 acc_mgr->len_allowed_adm = len_allowed_adm;
310 if (old_len != acc_mgr_subset_len(acc_mgr))
311 acc_mgr_subset_length_changed(acc_mgr);
312}
313void acc_mgr_set_len_allowed_ramp(struct acc_mgr *acc_mgr, uint8_t len_allowed_ramp)
314{
315 uint8_t old_len;
316
317 OSMO_ASSERT(len_allowed_ramp <= 10);
318
319 if (acc_mgr->len_allowed_ramp == len_allowed_ramp)
320 return;
321
322 LOG_BTS(acc_mgr->bts, DRSL, LOGL_DEBUG,
323 "ACC: ramping rotate subset size set to %" PRIu8 "\n", len_allowed_ramp);
324
325 old_len = acc_mgr_subset_len(acc_mgr);
326 acc_mgr->len_allowed_ramp = len_allowed_ramp;
327 if (old_len != acc_mgr_subset_len(acc_mgr))
328 acc_mgr_subset_length_changed(acc_mgr);
329}
330
331void acc_mgr_set_rotation_time(struct acc_mgr *acc_mgr, uint32_t rotation_time_sec)
332{
333 LOG_BTS(acc_mgr->bts, DRSL, LOGL_DEBUG,
334 "ACC: rotate subset time set to %" PRIu32 " seconds\n", rotation_time_sec);
335 acc_mgr->rotation_time_sec = rotation_time_sec;
336}
337
338void acc_mgr_perm_subset_changed(struct acc_mgr *acc_mgr, struct gsm48_rach_control *rach_control)
339{
340 /* Even if amount is the same, the allowed/barred ones may have changed,
341 * so let's retrigger generation of an entire subset rather than
342 * rotating it */
343 acc_mgr_gen_subset(acc_mgr, true);
344}
345
346/*!
347 * Potentially mark certain Access Control Classes (ACCs) as barred in accordance to ACC policy.
348 * \param[in] acc_mgr Pointer to acc_mgr structure.
349 * \param[in] rach_control RACH control parameters in which barred ACCs will be configured.
350 */
351void acc_mgr_apply_acc(struct acc_mgr *acc_mgr, struct gsm48_rach_control *rach_control)
352{
353 rach_control->t2 |= acc_mgr_get_barred_t2(acc_mgr);
354 rach_control->t3 |= acc_mgr_get_barred_t3(acc_mgr);
355}
356
357
358//////////////////////////
359// acc_ramp
360//////////////////////////
Stefan Sperling6442e432018-02-06 14:44:54 +0100361static unsigned int get_next_step_interval(struct acc_ramp *acc_ramp)
362{
363 struct gsm_bts *bts = acc_ramp->bts;
364 uint64_t load;
365
366 if (acc_ramp->step_interval_is_fixed)
367 return acc_ramp->step_interval_sec;
368
369 /* Scale the step interval to current channel load average. */
370 load = (bts->chan_load_avg << 8); /* convert to fixed-point */
371 acc_ramp->step_interval_sec = ((load * ACC_RAMP_STEP_INTERVAL_MAX) / 100) >> 8;
372 if (acc_ramp->step_interval_sec < ACC_RAMP_STEP_SIZE_MIN)
373 acc_ramp->step_interval_sec = ACC_RAMP_STEP_INTERVAL_MIN;
374 else if (acc_ramp->step_interval_sec > ACC_RAMP_STEP_INTERVAL_MAX)
375 acc_ramp->step_interval_sec = ACC_RAMP_STEP_INTERVAL_MAX;
376
Harald Welteafe987f2019-06-13 16:37:24 +0200377 LOG_BTS(bts, DRSL, LOGL_DEBUG,
378 "ACC RAMP: step interval set to %u seconds based on %u%% channel load average\n",
379 acc_ramp->step_interval_sec, bts->chan_load_avg);
Stefan Sperling6442e432018-02-06 14:44:54 +0100380 return acc_ramp->step_interval_sec;
381}
382
383static void do_acc_ramping_step(void *data)
384{
385 struct acc_ramp *acc_ramp = data;
Pau Espin Pedroldeaa6fd2020-07-16 20:53:21 +0200386 struct acc_mgr *acc_mgr = &acc_ramp->bts->acc_mgr;
387 uint8_t old_len = acc_mgr_get_len_allowed_ramp(acc_mgr);
388 uint8_t new_len = OSMO_MIN(10, old_len + acc_ramp->step_size);
Stefan Sperling6442e432018-02-06 14:44:54 +0100389
Pau Espin Pedroldeaa6fd2020-07-16 20:53:21 +0200390 acc_mgr_set_len_allowed_ramp(acc_mgr, new_len);
Stefan Sperling6442e432018-02-06 14:44:54 +0100391
392 /* If we have not allowed all ACCs yet, schedule another ramping step. */
Pau Espin Pedroldeaa6fd2020-07-16 20:53:21 +0200393 if (new_len != 10)
Stefan Sperling6442e432018-02-06 14:44:54 +0100394 osmo_timer_schedule(&acc_ramp->step_timer, get_next_step_interval(acc_ramp), 0);
395}
396
Stefan Sperling60ecdef2018-04-10 17:55:08 +0200397/* Implements osmo_signal_cbfn() -- trigger or abort ACC ramping upon changes RF lock state. */
398static int acc_ramp_nm_sig_cb(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data)
399{
400 struct nm_statechg_signal_data *nsd = signal_data;
401 struct acc_ramp *acc_ramp = handler_data;
402 struct gsm_bts_trx *trx = NULL;
Stefan Sperlingcda994e2018-04-12 09:18:36 +0200403 bool trigger_ramping = false, abort_ramping = false;
Stefan Sperling60ecdef2018-04-10 17:55:08 +0200404
Stefan Sperlingb06c7a22018-04-11 20:46:38 +0200405 /* Handled signals map to an Administrative State Change ACK, or a State Changed Event Report. */
406 if (signal != S_NM_STATECHG_ADM && signal != S_NM_STATECHG_OPER)
Stefan Sperling60ecdef2018-04-10 17:55:08 +0200407 return 0;
408
409 if (nsd->obj_class != NM_OC_RADIO_CARRIER)
410 return 0;
411
412 trx = nsd->obj;
413
Harald Welteafe987f2019-06-13 16:37:24 +0200414 LOG_TRX(trx, DRSL, LOGL_DEBUG, "ACC RAMP: administrative state %s -> %s\n",
Stefan Sperlingcda994e2018-04-12 09:18:36 +0200415 get_value_string(abis_nm_adm_state_names, nsd->old_state->administrative),
416 get_value_string(abis_nm_adm_state_names, nsd->new_state->administrative));
Harald Welteafe987f2019-06-13 16:37:24 +0200417 LOG_TRX(trx, DRSL, LOGL_DEBUG, "ACC RAMP: operational state %s -> %s\n",
Stefan Sperlingcda994e2018-04-12 09:18:36 +0200418 abis_nm_opstate_name(nsd->old_state->operational),
419 abis_nm_opstate_name(nsd->new_state->operational));
420
Stefan Sperling60ecdef2018-04-10 17:55:08 +0200421 /* We only care about state changes of the first TRX. */
422 if (trx->nr != 0)
423 return 0;
424
425 /* RSL must already be up. We cannot send RACH system information to the BTS otherwise. */
Stefan Sperlingcda994e2018-04-12 09:18:36 +0200426 if (trx->rsl_link == NULL) {
Harald Welteafe987f2019-06-13 16:37:24 +0200427 LOG_TRX(trx, DRSL, LOGL_DEBUG,
428 "ACC RAMP: ignoring state change because RSL link is down\n");
Stefan Sperling60ecdef2018-04-10 17:55:08 +0200429 return 0;
Stefan Sperling60ecdef2018-04-10 17:55:08 +0200430 }
431
Stefan Sperlingcda994e2018-04-12 09:18:36 +0200432 /* Trigger or abort ACC ramping based on the new state of this TRX. */
433 if (nsd->old_state->administrative != nsd->new_state->administrative) {
434 switch (nsd->new_state->administrative) {
435 case NM_STATE_UNLOCKED:
436 if (nsd->old_state->operational != nsd->new_state->operational) {
437 /*
438 * Administrative and operational state have both changed.
439 * Trigger ramping only if TRX 0 will be both enabled and unlocked.
440 */
441 if (nsd->new_state->operational == NM_OPSTATE_ENABLED)
442 trigger_ramping = true;
443 else
Harald Welteafe987f2019-06-13 16:37:24 +0200444 LOG_TRX(trx, DRSL, LOGL_DEBUG,
445 "ACC RAMP: ignoring state change because TRX is "
446 "transitioning into operational state '%s'\n",
447 abis_nm_opstate_name(nsd->new_state->operational));
Stefan Sperlingcda994e2018-04-12 09:18:36 +0200448 } else {
449 /*
450 * Operational state has not changed.
451 * Trigger ramping only if TRX 0 is already usable.
452 */
453 if (trx_is_usable(trx))
454 trigger_ramping = true;
455 else
Harald Welteafe987f2019-06-13 16:37:24 +0200456 LOG_TRX(trx, DRSL, LOGL_DEBUG, "ACC RAMP: ignoring state change "
457 "because TRX is not usable\n");
Stefan Sperlingcda994e2018-04-12 09:18:36 +0200458 }
459 break;
460 case NM_STATE_LOCKED:
461 case NM_STATE_SHUTDOWN:
462 abort_ramping = true;
463 break;
464 case NM_STATE_NULL:
465 default:
Harald Welteafe987f2019-06-13 16:37:24 +0200466 LOG_TRX(trx, DRSL, LOGL_ERROR, "ACC RAMP: unrecognized administrative state '0x%x' "
467 "reported for TRX 0\n", nsd->new_state->administrative);
Stefan Sperlingcda994e2018-04-12 09:18:36 +0200468 break;
469 }
470 }
471 if (nsd->old_state->operational != nsd->new_state->operational) {
472 switch (nsd->new_state->operational) {
473 case NM_OPSTATE_ENABLED:
474 if (nsd->old_state->administrative != nsd->new_state->administrative) {
475 /*
476 * Administrative and operational state have both changed.
477 * Trigger ramping only if TRX 0 will be both enabled and unlocked.
478 */
479 if (nsd->new_state->administrative == NM_STATE_UNLOCKED)
480 trigger_ramping = true;
481 else
Harald Welteafe987f2019-06-13 16:37:24 +0200482 LOG_TRX(trx, DRSL, LOGL_DEBUG, "ACC RAMP: ignoring state change "
483 "because TRX is transitioning into administrative state '%s'\n",
484 get_value_string(abis_nm_adm_state_names, nsd->new_state->administrative));
Stefan Sperlingcda994e2018-04-12 09:18:36 +0200485 } else {
486 /*
487 * Administrative state has not changed.
488 * Trigger ramping only if TRX 0 is already unlocked.
489 */
490 if (trx->mo.nm_state.administrative == NM_STATE_UNLOCKED)
491 trigger_ramping = true;
492 else
Harald Welteafe987f2019-06-13 16:37:24 +0200493 LOG_TRX(trx, DRSL, LOGL_DEBUG, "ACC RAMP: ignoring state change "
494 "because TRX is in administrative state '%s'\n",
495 get_value_string(abis_nm_adm_state_names, trx->mo.nm_state.administrative));
Stefan Sperlingcda994e2018-04-12 09:18:36 +0200496 }
497 break;
498 case NM_OPSTATE_DISABLED:
499 abort_ramping = true;
500 break;
501 case NM_OPSTATE_NULL:
502 default:
Harald Welteafe987f2019-06-13 16:37:24 +0200503 LOG_TRX(trx, DRSL, LOGL_ERROR, "ACC RAMP: unrecognized operational state '0x%x' "
504 "reported for TRX 0\n", nsd->new_state->administrative);
Stefan Sperlingcda994e2018-04-12 09:18:36 +0200505 break;
506 }
507 }
508
509 if (trigger_ramping)
510 acc_ramp_trigger(acc_ramp);
511 else if (abort_ramping)
512 acc_ramp_abort(acc_ramp);
513
Stefan Sperling60ecdef2018-04-10 17:55:08 +0200514 return 0;
515}
516
Stefan Sperling6442e432018-02-06 14:44:54 +0100517/*!
518 * Initialize an acc_ramp data structure.
519 * Storage for this structure must be provided by the caller.
520 *
Stefan Sperlingea333412018-04-10 16:36:54 +0200521 * By default, ACC ramping is disabled and all ACCs are allowed.
Stefan Sperling6442e432018-02-06 14:44:54 +0100522 *
523 * \param[in] acc_ramp Pointer to acc_ramp structure to be initialized.
Stefan Sperling6442e432018-02-06 14:44:54 +0100524 * \param[in] bts BTS which uses this ACC ramp data structure.
525 */
Stefan Sperlingea333412018-04-10 16:36:54 +0200526void acc_ramp_init(struct acc_ramp *acc_ramp, struct gsm_bts *bts)
Stefan Sperling6442e432018-02-06 14:44:54 +0100527{
528 acc_ramp->bts = bts;
Stefan Sperlingea333412018-04-10 16:36:54 +0200529 acc_ramp_set_enabled(acc_ramp, false);
Stefan Sperling6442e432018-02-06 14:44:54 +0100530 acc_ramp->step_size = ACC_RAMP_STEP_SIZE_DEFAULT;
531 acc_ramp->step_interval_sec = ACC_RAMP_STEP_INTERVAL_MIN;
532 acc_ramp->step_interval_is_fixed = false;
533 osmo_timer_setup(&acc_ramp->step_timer, do_acc_ramping_step, acc_ramp);
Stefan Sperling60ecdef2018-04-10 17:55:08 +0200534 osmo_signal_register_handler(SS_NM, acc_ramp_nm_sig_cb, acc_ramp);
Stefan Sperling6442e432018-02-06 14:44:54 +0100535}
536
537/*!
538 * Change the ramping step size which controls how many ACCs will be allowed per ramping step.
539 * Returns negative on error (step_size out of range), else zero.
540 * \param[in] acc_ramp Pointer to acc_ramp structure.
541 * \param[in] step_size The new step size value.
542 */
543int acc_ramp_set_step_size(struct acc_ramp *acc_ramp, unsigned int step_size)
544{
545 if (step_size < ACC_RAMP_STEP_SIZE_MIN || step_size > ACC_RAMP_STEP_SIZE_MAX)
546 return -ERANGE;
547
548 acc_ramp->step_size = step_size;
Harald Welteafe987f2019-06-13 16:37:24 +0200549 LOG_BTS(acc_ramp->bts, DRSL, LOGL_DEBUG, "ACC RAMP: ramping step size set to %u\n", step_size);
Stefan Sperling6442e432018-02-06 14:44:54 +0100550 return 0;
551}
552
553/*!
554 * Change the ramping step interval to a fixed value. Unless this function is called,
555 * the interval is automatically scaled to the BTS channel load average.
556 * \param[in] acc_ramp Pointer to acc_ramp structure.
557 * \param[in] step_interval The new fixed step interval in seconds.
558 */
559int acc_ramp_set_step_interval(struct acc_ramp *acc_ramp, unsigned int step_interval)
560{
561 if (step_interval < ACC_RAMP_STEP_INTERVAL_MIN || step_interval > ACC_RAMP_STEP_INTERVAL_MAX)
562 return -ERANGE;
563
564 acc_ramp->step_interval_sec = step_interval;
565 acc_ramp->step_interval_is_fixed = true;
Harald Welteafe987f2019-06-13 16:37:24 +0200566 LOG_BTS(acc_ramp->bts, DRSL, LOGL_DEBUG, "ACC RAMP: ramping step interval set to %u seconds\n",
567 step_interval);
Stefan Sperling6442e432018-02-06 14:44:54 +0100568 return 0;
569}
570
571/*!
572 * Clear a previously set fixed ramping step interval, so that the interval
573 * is again automatically scaled to the BTS channel load average.
574 * \param[in] acc_ramp Pointer to acc_ramp structure.
575 */
576void acc_ramp_set_step_interval_dynamic(struct acc_ramp *acc_ramp)
577{
578 acc_ramp->step_interval_is_fixed = false;
Harald Welteafe987f2019-06-13 16:37:24 +0200579 LOG_BTS(acc_ramp->bts, DRSL, LOGL_DEBUG, "ACC RAMP: ramping step interval set to 'dynamic'\n");
Stefan Sperling6442e432018-02-06 14:44:54 +0100580}
581
582/*!
Stefan Sperlingea333412018-04-10 16:36:54 +0200583 * Determine if ACC ramping should be started according to configuration, and
Stefan Sperling4d3d2432018-04-12 09:18:36 +0200584 * begin the ramping process if the necessary conditions are present.
Stefan Sperlingea333412018-04-10 16:36:54 +0200585 * Perform at least one ramping step to allow 'step_size' ACCs.
586 * If 'step_size' is ACC_RAMP_STEP_SIZE_MAX, or if ACC ramping is disabled,
587 * all ACCs will be allowed immediately.
Stefan Sperling6442e432018-02-06 14:44:54 +0100588 * \param[in] acc_ramp Pointer to acc_ramp structure.
589 */
Stefan Sperlingea333412018-04-10 16:36:54 +0200590void acc_ramp_trigger(struct acc_ramp *acc_ramp)
Stefan Sperling6442e432018-02-06 14:44:54 +0100591{
Stefan Sperlingea333412018-04-10 16:36:54 +0200592 /* Abort any previously running ramping process and allow all available ACCs. */
Stefan Sperling6442e432018-02-06 14:44:54 +0100593 acc_ramp_abort(acc_ramp);
594
Stefan Sperlingea333412018-04-10 16:36:54 +0200595 if (acc_ramp_is_enabled(acc_ramp)) {
Stefan Sperlingcda994e2018-04-12 09:18:36 +0200596 /* Set all available ACCs to barred and start ramping up. */
Pau Espin Pedroldeaa6fd2020-07-16 20:53:21 +0200597 acc_mgr_set_len_allowed_ramp(&acc_ramp->bts->acc_mgr, 0);
Stefan Sperlingcda994e2018-04-12 09:18:36 +0200598 do_acc_ramping_step(acc_ramp);
Stefan Sperlingea333412018-04-10 16:36:54 +0200599 }
Stefan Sperling6442e432018-02-06 14:44:54 +0100600}
601
602/*!
Stefan Sperlingea333412018-04-10 16:36:54 +0200603 * Abort the ramping process and allow all available ACCs immediately.
Stefan Sperling6442e432018-02-06 14:44:54 +0100604 * \param[in] acc_ramp Pointer to acc_ramp structure.
605 */
606void acc_ramp_abort(struct acc_ramp *acc_ramp)
607{
608 if (osmo_timer_pending(&acc_ramp->step_timer))
609 osmo_timer_del(&acc_ramp->step_timer);
Stefan Sperlingea333412018-04-10 16:36:54 +0200610
Pau Espin Pedroldeaa6fd2020-07-16 20:53:21 +0200611 acc_mgr_set_len_allowed_ramp(&acc_ramp->bts->acc_mgr, 10);
Stefan Sperling6442e432018-02-06 14:44:54 +0100612}