alloc_algo: Pass a struct containing all req params

This is a first step towards isolating the allocation algorithm from
applying changes on PCU state.
In next steps the tbf pointer will be dropped and the allocation
algorithm will only result a "result" struct which then the caller can
apply to whatever TBF object it requires.

Change-Id: Ie4d9ace526ad012d97738bc55bdb5cc1472c632d
diff --git a/src/alloc_algo.cpp b/src/alloc_algo.cpp
index 047bae2..9d4db4c 100644
--- a/src/alloc_algo.cpp
+++ b/src/alloc_algo.cpp
@@ -39,12 +39,12 @@
 /* Consider a PDCH as idle if has at most this number of TBFs assigned to it */
 #define PDCH_IDLE_TBF_THRESH	1
 
-#define LOGPSL(tbf, level, fmt, args...) LOGP(DRLCMAC, level, "[%s] " fmt, \
-					      (tbf->direction == GPRS_RLCMAC_DL_TBF) ? "DL" : "UL", ## args)
+#define LOGPSL(req, level, fmt, args...) LOGP(DRLCMAC, level, "[%s] " fmt, \
+					      (req->direction == GPRS_RLCMAC_DL_TBF) ? "DL" : "UL", ## args)
 
-#define LOGPAL(tbf, kind, single, trx_n, level, fmt, args...) LOGPSL(tbf, level, \
+#define LOGPAL(req, kind, level, fmt, args...) LOGPSL(req, level, \
 								     "algo %s <%s> (suggested TRX: %d): " fmt, \
-								     kind, single ? "single" : "multi", trx_n, ## args)
+								     kind, req->single ? "single" : "multi", req->use_trx, ## args)
 
 static char *set_flag_chars(char *buf, uint8_t val, char set_char, char unset_char = 0)
 {
@@ -237,21 +237,21 @@
 	attach_tbf_to_pdch(pdch, tbf);
 }
 
-static int find_trx(const struct gprs_rlcmac_bts *bts, const GprsMs *ms, int8_t use_trx)
+static int find_trx(const struct alloc_resources_req *req)
 {
 	unsigned trx_no;
 	unsigned ts;
 
 	/* We must use the TRX currently actively used by an MS */
-	if (ms && ms_current_trx(ms))
-		return ms_current_trx(ms)->trx_no;
+	if (req->ms && ms_current_trx(req->ms))
+		return ms_current_trx(req->ms)->trx_no;
 
-	if (use_trx >= 0 && use_trx < 8)
-		return use_trx;
+	if (req->use_trx >= 0 && req->use_trx < 8)
+		return req->use_trx;
 
 	/* Find the first TRX that has a PDCH with a free UL and DL TFI */
-	for (trx_no = 0; trx_no < ARRAY_SIZE(bts->trx); trx_no += 1) {
-		const struct gprs_rlcmac_trx *trx = &bts->trx[trx_no];
+	for (trx_no = 0; trx_no < ARRAY_SIZE(req->bts->trx); trx_no += 1) {
+		const struct gprs_rlcmac_trx *trx = &req->bts->trx[trx_no];
 		for (ts = 0; ts < ARRAY_SIZE(trx->pdch); ts++) {
 			const struct gprs_rlcmac_pdch *pdch = &trx->pdch[ts];
 			if (!pdch->is_enabled())
@@ -295,31 +295,28 @@
 
 /*! Return free TFI
  *
- *  \param[in] bts Pointer to BTS struct
- *  \param[in] ms Pointer to MS object
- *  \param[in] dir DL or UL direction
- *  \param[in] use_trx which TRX to use or -1 if it should be selected based on what MS uses
+ *  \param[in] req Contains all the requested params
  *  \param[out] trx_no_ TRX number on which TFI was found
  *  \returns negative error code or 0 on success
  */
-static int tfi_find_free(const struct gprs_rlcmac_bts *bts, const GprsMs *ms,
-			 enum gprs_rlcmac_tbf_direction dir, int8_t use_trx, uint8_t *trx_no_)
+static int tfi_find_free(const struct alloc_resources_req *req, uint8_t *trx_no_)
 {
 	const struct gprs_rlcmac_trx *trx;
 	int tfi;
+	int8_t use_trx = req->use_trx;
 	uint8_t trx_no;
 
 	/* If MS is already doing stuff on a TRX, set use_trx to it: */
-	if ((trx = ms_current_trx(ms))) {
+	if ((trx = ms_current_trx(req->ms))) {
 		if (use_trx >= 0 && use_trx != trx->trx_no) {
 			LOGP(DRLCMAC, LOGL_ERROR, "- Requested incompatible TRX %d (current is %d)\n",
-			     use_trx, trx->trx_no);
+			     req->use_trx, trx->trx_no);
 			return -EINVAL;
 		}
 		use_trx = trx->trx_no;
 	}
 
-	tfi = bts_tfi_find_free(bts, dir, &trx_no, use_trx);
+	tfi = bts_tfi_find_free(req->bts, req->direction, &trx_no, use_trx);
 	if (tfi < 0)
 		return -EBUSY;
 
@@ -333,14 +330,10 @@
  *
  * Assign single slot for uplink and downlink
  *
- *  \param[in,out] bts Pointer to BTS struct
- *  \param[in,out] tbf Pointer to TBF struct
- *  \param[in] single flag indicating if we should force single-slot allocation
- *  \param[in] use_trx which TRX to use or -1 if it should be selected during allocation
+ *  \param[in] req Contains all the requested params
  *  \returns negative error code or 0 on success
  */
-int alloc_algorithm_a(struct gprs_rlcmac_bts *bts, struct gprs_rlcmac_tbf *tbf, bool single,
-		      int8_t use_trx)
+int alloc_algorithm_a(const struct alloc_resources_req *req)
 {
 	struct gprs_rlcmac_pdch *pdch;
 	int ts = -1;
@@ -350,23 +343,22 @@
 	int usf = -1;
 	uint8_t mask = 0xff;
 	const char *mask_reason = NULL;
-	struct GprsMs *ms = tbf->ms();
-	gprs_rlcmac_trx *trx = ms_current_trx(ms);
-	struct gprs_rlcmac_pdch *first_common_ts = ms_first_common_ts(ms);
+	gprs_rlcmac_trx *trx = ms_current_trx(req->ms);
+	struct gprs_rlcmac_pdch *first_common_ts = ms_first_common_ts(req->ms);
 
-	LOGPAL(tbf, "A", single, use_trx, LOGL_DEBUG, "Alloc start\n");
+	LOGPAL(req, "A", LOGL_DEBUG, "Alloc start\n");
 
-	trx_no = find_trx(bts, ms, use_trx);
+	trx_no = find_trx(req);
 	if (trx_no < 0) {
-		LOGPAL(tbf, "A", single, use_trx, LOGL_NOTICE,
+		LOGPAL(req, "A", LOGL_NOTICE,
 		       "failed to find a usable TRX (TFI exhausted)\n");
 		return trx_no;
 	}
 	if (!trx)
-		trx = &bts->trx[trx_no];
+		trx = &req->bts->trx[trx_no];
 
-	dl_slots = ms_reserved_dl_slots(ms);
-	ul_slots = ms_reserved_ul_slots(ms);
+	dl_slots = ms_reserved_dl_slots(req->ms);
+	ul_slots = ms_reserved_ul_slots(req->ms);
 
 	if (first_common_ts) {
 		mask_reason = "need to reuse TS";
@@ -380,18 +372,18 @@
 	if (!mask)
 		return -EINVAL;
 
-	ts = find_least_busy_pdch(trx, tbf->direction, mask,
+	ts = find_least_busy_pdch(trx, req->direction, mask,
 		compute_usage_for_algo_a,
 		&tfi, &usf);
 
-	if (tbf->direction == GPRS_RLCMAC_UL_TBF && usf < 0) {
-		LOGPAL(tbf, "A", single, use_trx, LOGL_NOTICE,
+	if (req->direction == GPRS_RLCMAC_UL_TBF && usf < 0) {
+		LOGPAL(req, "A", LOGL_NOTICE,
 		       "failed to allocate a TS, no USF available\n");
 		return -EBUSY;
 	}
 
 	if (ts < 0) {
-		LOGPAL(tbf, "A", single, use_trx, LOGL_NOTICE,
+		LOGPAL(req, "A", LOGL_NOTICE,
 		       "failed to allocate a TS, no TFI available\n");
 		return -EBUSY;
 	}
@@ -400,23 +392,23 @@
 
 	/* The allocation will be successful, so the system state and tbf/ms
 	 * may be modified from now on. */
-	if (tbf->direction == GPRS_RLCMAC_UL_TBF) {
-		struct gprs_rlcmac_ul_tbf *ul_tbf = tbf_as_ul_tbf(tbf);
-		LOGPSL(tbf, LOGL_DEBUG, "Assign uplink TS=%d TFI=%d USF=%d\n", ts, tfi, usf);
+	if (req->direction == GPRS_RLCMAC_UL_TBF) {
+		struct gprs_rlcmac_ul_tbf *ul_tbf = tbf_as_ul_tbf(req->tbf);
+		LOGPSL(req, LOGL_DEBUG, "Assign uplink TS=%d TFI=%d USF=%d\n", ts, tfi, usf);
 		assign_uplink_tbf_usf(pdch, ul_tbf, tfi, usf);
 	} else {
-		struct gprs_rlcmac_dl_tbf *dl_tbf = tbf_as_dl_tbf(tbf);
-		LOGPSL(tbf, LOGL_DEBUG, "Assign downlink TS=%d TFI=%d\n", ts, tfi);
+		struct gprs_rlcmac_dl_tbf *dl_tbf = tbf_as_dl_tbf(req->tbf);
+		LOGPSL(req, LOGL_DEBUG, "Assign downlink TS=%d TFI=%d\n", ts, tfi);
 		assign_dlink_tbf(pdch, dl_tbf, tfi);
 	}
 
-	tbf->trx = trx;
+	req->tbf->trx = trx;
 	/* the only one TS is the common TS */
-	ms_set_reserved_slots(ms, trx, 1 << ts, 1 << ts);
-	ms_set_first_common_ts(ms, pdch);
+	ms_set_reserved_slots(req->ms, trx, 1 << ts, 1 << ts);
+	ms_set_first_common_ts(req->ms, pdch);
 
-	tbf->upgrade_to_multislot = false;
-	bts_do_rate_ctr_inc(bts, CTR_TBF_ALLOC_ALGO_A);
+	req->tbf->upgrade_to_multislot = false;
+	bts_do_rate_ctr_inc(req->bts, CTR_TBF_ALLOC_ALGO_A);
 	return 0;
 }
 
@@ -668,19 +660,19 @@
  * number or to negative value on error
  *
  *  \param[in] trx Pointer to TRX object
- *  \param[in] tbf Pointer to TBF object
+ *  \param[in] direction Direction of the TBF to allocate
  *  \param[in] dl_slots set of DL timeslots
  *  \param[in] ul_slots set of UL timeslots
  *  \param[in] ts corresponding TS or -1 for autoselection
  *  \returns slot mask with single UL or DL timeslot number if possible
  */
-static uint8_t get_single_ts(const gprs_rlcmac_trx *trx, const gprs_rlcmac_tbf *tbf, uint8_t dl_slots, uint8_t ul_slots,
+static uint8_t get_single_ts(const gprs_rlcmac_trx *trx, enum gprs_rlcmac_tbf_direction direction, uint8_t dl_slots, uint8_t ul_slots,
 			     int ts)
 {
 	uint8_t ret = dl_slots & ul_slots; /* Make sure to consider the first common slot only */
 
 	if (ts < 0)
-		ts = find_least_busy_pdch(trx, tbf->direction, ret, compute_usage_by_num_tbfs, NULL, NULL);
+		ts = find_least_busy_pdch(trx, direction, ret, compute_usage_by_num_tbfs, NULL, NULL);
 
 	if (ts < 0)
 		return ffs(ret);
@@ -690,9 +682,8 @@
 
 /*! Find set of timeslots available for allocation
  *
+ *  \param[in] req Contains all the requested params
  *  \param[in] trx Pointer to TRX object
- *  \param[in] tbf Pointer to TBF object
- *  \param[in] single Flag to force the single TS allocation
  *  \param[in] ul_slots set of UL timeslots
  *  \param[in] dl_slots set of DL timeslots
  *  \param[in] reserved_ul_slots set of reserved UL timeslots
@@ -700,17 +691,17 @@
  *  \param[in] first_common_ts First TS common for both UL and DL or -1 if unknown
  *  \returns negative error code or selected TS on success
  */
-static int tbf_select_slot_set(const gprs_rlcmac_tbf *tbf, const gprs_rlcmac_trx *trx, bool single,
+static int tbf_select_slot_set(const struct alloc_resources_req *req, const gprs_rlcmac_trx *trx,
 			       uint8_t ul_slots, uint8_t dl_slots,
 			       uint8_t reserved_ul_slots, uint8_t reserved_dl_slots,
 			       int8_t first_common_ts)
 {
-	bool is_ul = tbf->direction == GPRS_RLCMAC_UL_TBF;
+	bool is_ul = req->direction == GPRS_RLCMAC_UL_TBF;
 	uint8_t sl = is_ul ? ul_slots : dl_slots;
 	char slot_info[9] = { 0 };
 
-	if (single)
-		sl = get_single_ts(trx, tbf, dl_slots, ul_slots, first_common_ts);
+	if (req->single)
+		sl = get_single_ts(trx, req->direction, dl_slots, ul_slots, first_common_ts);
 
 	if (!sl) {
 		LOGP(DRLCMAC, LOGL_NOTICE, "No %s slots available\n",
@@ -729,7 +720,7 @@
 
 	LOGPC(DRLCMAC, LOGL_DEBUG, "Selected %s slots: (TS=0)\"%s\"(TS=7), %s\n",
 	      is_ul ? "UL" : "DL",
-	      slot_info, single ? "single" : "multi");
+	      slot_info, req->single ? "single" : "multi");
 
 	return sl;
 }
@@ -849,14 +840,10 @@
  * Assign as many downlink slots as possible.
  * Assign one uplink slot. (With free USF)
  *
- *  \param[in,out] bts Pointer to BTS struct
- *  \param[in,out] tbf Pointer to TBF struct
- *  \param[in] single flag indicating if we should force single-slot allocation
- *  \param[in] use_trx which TRX to use or -1 if it should be selected during allocation
+ *  \param[in] req Contains all the requested params
  *  \returns negative error code or 0 on success
  */
-int alloc_algorithm_b(struct gprs_rlcmac_bts *bts, struct gprs_rlcmac_tbf *tbf, bool single,
-		      int8_t use_trx)
+int alloc_algorithm_b(const struct alloc_resources_req *req)
 {
 	uint8_t dl_slots;
 	uint8_t ul_slots;
@@ -869,30 +856,29 @@
 	int usf[8] = {-1, -1, -1, -1, -1, -1, -1, -1};
 	int rc;
 	int tfi;
-	struct GprsMs *ms = tbf->ms();
 	gprs_rlcmac_trx *trx;
-	struct gprs_rlcmac_pdch *first_common_ts = ms_first_common_ts(ms);
+	struct gprs_rlcmac_pdch *first_common_ts = ms_first_common_ts(req->ms);
 
-	LOGPAL(tbf, "B", single, use_trx, LOGL_DEBUG, "Alloc start\n");
+	LOGPAL(req, "B", LOGL_DEBUG, "Alloc start\n");
 
 	/* Step 1: Get current state from the MS object */
 
-	reserved_dl_slots = ms_reserved_dl_slots(ms);
-	reserved_ul_slots = ms_reserved_ul_slots(ms);
+	reserved_dl_slots = ms_reserved_dl_slots(req->ms);
+	reserved_ul_slots = ms_reserved_ul_slots(req->ms);
 	first_common_tn = first_common_ts ? first_common_ts->ts_no : -1;
 
 	/* Step 2a: Find usable TRX and TFI */
-	tfi = tfi_find_free(bts, ms, tbf->direction, use_trx, &trx_no);
+	tfi = tfi_find_free(req, &trx_no);
 	if (tfi < 0) {
-		LOGPAL(tbf, "B", single, use_trx, LOGL_NOTICE, "failed to allocate a TFI\n");
+		LOGPAL(req, "B", LOGL_NOTICE, "failed to allocate a TFI\n");
 		return tfi;
 	}
 
 	/* Step 2b: Reserve slots on the TRX for the MS */
-	trx = &bts->trx[trx_no];
+	trx = &req->bts->trx[trx_no];
 
 	if (!reserved_dl_slots || !reserved_ul_slots) {
-		rc = find_multi_slots(trx, ms_ms_class(ms), &reserved_ul_slots, &reserved_dl_slots);
+		rc = find_multi_slots(trx, ms_ms_class(req->ms), &reserved_ul_slots, &reserved_dl_slots);
 		if (rc < 0)
 			return rc;
 	}
@@ -900,13 +886,13 @@
 	ul_slots = reserved_ul_slots;
 
 	/* Step 3a: Derive the slot set for the current TBF */
-	rc = tbf_select_slot_set(tbf, trx, single, ul_slots, dl_slots, reserved_ul_slots, reserved_dl_slots,
+	rc = tbf_select_slot_set(req, trx, ul_slots, dl_slots, reserved_ul_slots, reserved_dl_slots,
 				 first_common_tn);
 	if (rc < 0)
 		return -EINVAL;
 
 	/* Step 3b: Derive the slot set for a given direction */
-	if (tbf->direction == GPRS_RLCMAC_DL_TBF) {
+	if (req->direction == GPRS_RLCMAC_DL_TBF) {
 		dl_slots = rc;
 		count_slots(dl_slots, reserved_dl_slots, &slotcount, &reserve_count);
 	} else {
@@ -922,23 +908,23 @@
 
 	first_ts = ffs(rc) - 1;
 	if (first_ts < 0) {
-		LOGPAL(tbf, "B", single, use_trx, LOGL_NOTICE, "first slot unavailable\n");
+		LOGPAL(req, "B", LOGL_NOTICE, "first slot unavailable\n");
 		return -EINVAL;
 	}
 
 	first_common_tn = ffs(dl_slots & ul_slots) - 1;
 	if (first_common_tn < 0) {
-		LOGPAL(tbf, "B", single, use_trx, LOGL_NOTICE, "first common slot unavailable\n");
+		LOGPAL(req, "B", LOGL_NOTICE, "first common slot unavailable\n");
 		return -EINVAL;
 	}
 	first_common_ts = &trx->pdch[first_common_tn];
 
-	if (single && slotcount) {
-		tbf->upgrade_to_multislot = (reserve_count > slotcount);
-		LOGPAL(tbf, "B", single, use_trx, LOGL_INFO, "using single slot at TS %d\n", first_ts);
+	if (req->single && slotcount) {
+		req->tbf->upgrade_to_multislot = (reserve_count > slotcount);
+		LOGPAL(req, "B", LOGL_INFO, "using single slot at TS %d\n", first_ts);
 	} else {
-		tbf->upgrade_to_multislot = false;
-		LOGPAL(tbf, "B", single, use_trx, LOGL_INFO, "using %d slots\n", slotcount);
+		req->tbf->upgrade_to_multislot = false;
+		LOGPAL(req, "B", LOGL_INFO, "using %d slots\n", slotcount);
 	}
 
 	/* The allocation will be successful, so the system state and tbf/ms
@@ -946,16 +932,16 @@
 
 	/* Step 4: Update MS and TBF and really allocate the resources */
 
-	update_ms_reserved_slots(trx, ms, reserved_ul_slots, reserved_dl_slots, ul_slots, dl_slots);
-	ms_set_first_common_ts(ms, first_common_ts);
-	tbf->trx = trx;
+	update_ms_reserved_slots(trx, req->ms, reserved_ul_slots, reserved_dl_slots, ul_slots, dl_slots);
+	ms_set_first_common_ts(req->ms, first_common_ts);
+	req->tbf->trx = trx;
 
-	if (tbf->direction == GPRS_RLCMAC_DL_TBF)
-		assign_dl_tbf_slots(tbf_as_dl_tbf(tbf), trx, dl_slots, tfi);
+	if (req->direction == GPRS_RLCMAC_DL_TBF)
+		assign_dl_tbf_slots(tbf_as_dl_tbf(req->tbf), trx, dl_slots, tfi);
 	else
-		assign_ul_tbf_slots(tbf_as_ul_tbf(tbf), trx, ul_slots, tfi, usf);
+		assign_ul_tbf_slots(tbf_as_ul_tbf(req->tbf), trx, ul_slots, tfi, usf);
 
-	bts_do_rate_ctr_inc(bts, CTR_TBF_ALLOC_ALGO_B);
+	bts_do_rate_ctr_inc(req->bts, CTR_TBF_ALLOC_ALGO_B);
 
 	return 0;
 }
@@ -968,35 +954,31 @@
  * The goal is to support as many MS and TBF as possible. On low usage, the
  * goal is to provide the highest possible bandwidth per MS.
  *
- *  \param[in,out] bts Pointer to BTS struct
- *  \param[in,out] tbf Pointer to TBF struct
- *  \param[in] single flag indicating if we should force single-slot allocation
- *  \param[in] use_trx which TRX to use or -1 if it should be selected during allocation
+ *  \param[in] req Contains all the requested params
  *  \returns negative error code or 0 on success
  */
-int alloc_algorithm_dynamic(struct gprs_rlcmac_bts *bts, struct gprs_rlcmac_tbf *tbf, bool single,
-			    int8_t use_trx)
+int alloc_algorithm_dynamic(const struct alloc_resources_req *req)
 {
 	int rc;
 
 	/* Reset load_is_high if there is at least one idle PDCH */
-	if (bts->multislot_disabled) {
-		bts->multislot_disabled = !idle_pdch_avail(bts);
-		if (!bts->multislot_disabled)
+	if (req->bts->multislot_disabled) {
+		req->bts->multislot_disabled = !idle_pdch_avail(req->bts);
+		if (!req->bts->multislot_disabled)
 			LOGP(DRLCMAC, LOGL_DEBUG, "Enabling algorithm B\n");
 	}
 
-	if (!bts->multislot_disabled) {
-		rc = alloc_algorithm_b(bts, tbf, single, use_trx);
+	if (!req->bts->multislot_disabled) {
+		rc = alloc_algorithm_b(req);
 		if (rc >= 0)
 			return rc;
 
-		if (!bts->multislot_disabled)
+		if (!req->bts->multislot_disabled)
 			LOGP(DRLCMAC, LOGL_DEBUG, "Disabling algorithm B\n");
-		bts->multislot_disabled = 1;
+		req->bts->multislot_disabled = 1;
 	}
 
-	return alloc_algorithm_a(bts, tbf, single, use_trx);
+	return alloc_algorithm_a(req);
 }
 
 int gprs_alloc_max_dl_slots_per_ms(const struct gprs_rlcmac_bts *bts, uint8_t ms_class)