1 // SPDX-License-Identifier: GPL-2.0-only
3 * UWB reservation management.
5 * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
7 #include <linux/kernel.h>
8 #include <linux/slab.h>
11 #include "uwb-internal.h"
13 static void uwb_rsv_fill_column_alloc(struct uwb_rsv_alloc_info
*ai
)
15 int col
, mas
, safe_mas
, unsafe_mas
;
16 unsigned char *bm
= ai
->bm
;
17 struct uwb_rsv_col_info
*ci
= ai
->ci
;
20 for (col
= ci
->csi
.start_col
; col
< UWB_NUM_ZONES
; col
+= ci
->csi
.interval
) {
22 safe_mas
= ci
->csi
.safe_mas_per_col
;
23 unsafe_mas
= ci
->csi
.unsafe_mas_per_col
;
25 for (mas
= 0; mas
< UWB_MAS_PER_ZONE
; mas
++ ) {
26 if (bm
[col
* UWB_MAS_PER_ZONE
+ mas
] == 0) {
31 } else if (unsafe_mas
> 0) {
33 c
= UWB_RSV_MAS_UNSAFE
;
37 bm
[col
* UWB_MAS_PER_ZONE
+ mas
] = c
;
43 static void uwb_rsv_fill_row_alloc(struct uwb_rsv_alloc_info
*ai
)
46 unsigned char *bm
= ai
->bm
;
47 struct uwb_rsv_row_info
*ri
= &ai
->ri
;
52 for (mas
= UWB_MAS_PER_ZONE
- 1; mas
>= 0; mas
--) {
53 if (ri
->avail
[mas
] == 1) {
55 if (rows
> ri
->used_rows
) {
57 } else if (rows
> 7) {
58 c
= UWB_RSV_MAS_UNSAFE
;
61 for (col
= 0; col
< UWB_NUM_ZONES
; col
++) {
62 if (bm
[col
* UWB_NUM_ZONES
+ mas
] != UWB_RSV_MAS_NOT_AVAIL
) {
63 bm
[col
* UWB_NUM_ZONES
+ mas
] = c
;
64 if(c
== UWB_RSV_MAS_SAFE
)
65 ai
->safe_allocated_mases
++;
67 ai
->unsafe_allocated_mases
++;
73 ai
->total_allocated_mases
= ai
->safe_allocated_mases
+ ai
->unsafe_allocated_mases
;
77 * Find the best column set for a given availability, interval, num safe mas and
80 * The different sets are tried in order as shown below, depending on the interval.
117 * set 1 -> { 2 6 10 14 }
119 * set 1 -> { 1 5 9 13 }
120 * set 2 -> { 3 7 11 15 }
124 * set 1 -> { 1 3 5 7 9 11 13 15 }
126 static int uwb_rsv_find_best_column_set(struct uwb_rsv_alloc_info
*ai
, int interval
,
127 int num_safe_mas
, int num_unsafe_mas
)
129 struct uwb_rsv_col_info
*ci
= ai
->ci
;
130 struct uwb_rsv_col_set_info
*csi
= &ci
->csi
;
131 struct uwb_rsv_col_set_info tmp_csi
;
132 int deep
, set
, col
, start_col_deep
, col_start_set
;
133 int start_col
, max_mas_in_set
, lowest_max_mas_in_deep
;
135 int found
= UWB_RSV_ALLOC_NOT_FOUND
;
137 tmp_csi
.start_col
= 0;
138 start_col_deep
= interval
;
139 n_mas
= num_unsafe_mas
+ num_safe_mas
;
141 for (deep
= 0; ((interval
>> deep
) & 0x1) == 0; deep
++) {
144 lowest_max_mas_in_deep
= UWB_MAS_PER_ZONE
;
146 for (set
= 1; set
<= (1 << deep
); set
++) {
148 start_col
= start_col_deep
+ col_start_set
;
149 for (col
= start_col
; col
< UWB_NUM_ZONES
; col
+= interval
) {
151 if (ci
[col
].max_avail_safe
>= num_safe_mas
&&
152 ci
[col
].max_avail_unsafe
>= n_mas
) {
153 if (ci
[col
].highest_mas
[n_mas
] > max_mas_in_set
)
154 max_mas_in_set
= ci
[col
].highest_mas
[n_mas
];
160 if ((lowest_max_mas_in_deep
> max_mas_in_set
) && max_mas_in_set
) {
161 lowest_max_mas_in_deep
= max_mas_in_set
;
163 tmp_csi
.start_col
= start_col
;
165 col_start_set
+= (interval
>> deep
);
168 if (lowest_max_mas_in_deep
< 8) {
169 csi
->start_col
= tmp_csi
.start_col
;
170 found
= UWB_RSV_ALLOC_FOUND
;
172 } else if ((lowest_max_mas_in_deep
> 8) &&
173 (lowest_max_mas_in_deep
!= UWB_MAS_PER_ZONE
) &&
174 (found
== UWB_RSV_ALLOC_NOT_FOUND
)) {
175 csi
->start_col
= tmp_csi
.start_col
;
176 found
= UWB_RSV_ALLOC_FOUND
;
180 if (found
== UWB_RSV_ALLOC_FOUND
) {
181 csi
->interval
= interval
;
182 csi
->safe_mas_per_col
= num_safe_mas
;
183 csi
->unsafe_mas_per_col
= num_unsafe_mas
;
185 ai
->safe_allocated_mases
= (UWB_NUM_ZONES
/ interval
) * num_safe_mas
;
186 ai
->unsafe_allocated_mases
= (UWB_NUM_ZONES
/ interval
) * num_unsafe_mas
;
187 ai
->total_allocated_mases
= ai
->safe_allocated_mases
+ ai
->unsafe_allocated_mases
;
188 ai
->interval
= interval
;
193 static void get_row_descriptors(struct uwb_rsv_alloc_info
*ai
)
195 unsigned char *bm
= ai
->bm
;
196 struct uwb_rsv_row_info
*ri
= &ai
->ri
;
200 for (mas
= 0; mas
< UWB_MAS_PER_ZONE
; mas
++) {
202 for (col
= 1; col
< UWB_NUM_ZONES
; col
++) {
203 if (bm
[col
* UWB_NUM_ZONES
+ mas
] == UWB_RSV_MAS_NOT_AVAIL
) {
212 static void uwb_rsv_fill_column_info(unsigned char *bm
, int column
, struct uwb_rsv_col_info
*rci
)
215 int block_count
= 0, start_block
= 0;
216 int previous_avail
= 0;
218 int safe_mas_in_row
[UWB_MAS_PER_ZONE
] = {
219 8, 7, 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1,
222 rci
->max_avail_safe
= 0;
224 for (mas
= 0; mas
< UWB_MAS_PER_ZONE
; mas
++) {
225 if (!bm
[column
* UWB_NUM_ZONES
+ mas
]) {
227 rci
->max_avail_unsafe
= available
;
229 rci
->highest_mas
[available
] = mas
;
231 if (previous_avail
) {
233 if ((block_count
> safe_mas_in_row
[start_block
]) &&
234 (!rci
->max_avail_safe
))
235 rci
->max_avail_safe
= available
- 1;
245 if (!rci
->max_avail_safe
)
246 rci
->max_avail_safe
= rci
->max_avail_unsafe
;
249 static void get_column_descriptors(struct uwb_rsv_alloc_info
*ai
)
251 unsigned char *bm
= ai
->bm
;
252 struct uwb_rsv_col_info
*ci
= ai
->ci
;
255 for (col
= 1; col
< UWB_NUM_ZONES
; col
++) {
256 uwb_rsv_fill_column_info(bm
, col
, &ci
[col
]);
260 static int uwb_rsv_find_best_row_alloc(struct uwb_rsv_alloc_info
*ai
)
263 int max_rows
= ai
->max_mas
/ UWB_USABLE_MAS_PER_ROW
;
264 int min_rows
= ai
->min_mas
/ UWB_USABLE_MAS_PER_ROW
;
265 if (ai
->min_mas
% UWB_USABLE_MAS_PER_ROW
)
267 for (n_rows
= max_rows
; n_rows
>= min_rows
; n_rows
--) {
268 if (n_rows
<= ai
->ri
.free_rows
) {
269 ai
->ri
.used_rows
= n_rows
;
270 ai
->interval
= 1; /* row reservation */
271 uwb_rsv_fill_row_alloc(ai
);
272 return UWB_RSV_ALLOC_FOUND
;
275 return UWB_RSV_ALLOC_NOT_FOUND
;
278 static int uwb_rsv_find_best_col_alloc(struct uwb_rsv_alloc_info
*ai
, int interval
)
280 int n_safe
, n_unsafe
, n_mas
;
281 int n_column
= UWB_NUM_ZONES
/ interval
;
282 int max_per_zone
= ai
->max_mas
/ n_column
;
283 int min_per_zone
= ai
->min_mas
/ n_column
;
285 if (ai
->min_mas
% n_column
)
288 if (min_per_zone
> UWB_MAS_PER_ZONE
) {
289 return UWB_RSV_ALLOC_NOT_FOUND
;
292 if (max_per_zone
> UWB_MAS_PER_ZONE
) {
293 max_per_zone
= UWB_MAS_PER_ZONE
;
296 for (n_mas
= max_per_zone
; n_mas
>= min_per_zone
; n_mas
--) {
297 if (uwb_rsv_find_best_column_set(ai
, interval
, 0, n_mas
) == UWB_RSV_ALLOC_NOT_FOUND
)
299 for (n_safe
= n_mas
; n_safe
>= 0; n_safe
--) {
300 n_unsafe
= n_mas
- n_safe
;
301 if (uwb_rsv_find_best_column_set(ai
, interval
, n_safe
, n_unsafe
) == UWB_RSV_ALLOC_FOUND
) {
302 uwb_rsv_fill_column_alloc(ai
);
303 return UWB_RSV_ALLOC_FOUND
;
307 return UWB_RSV_ALLOC_NOT_FOUND
;
310 int uwb_rsv_find_best_allocation(struct uwb_rsv
*rsv
, struct uwb_mas_bm
*available
,
311 struct uwb_mas_bm
*result
)
313 struct uwb_rsv_alloc_info
*ai
;
317 ai
= kzalloc(sizeof(struct uwb_rsv_alloc_info
), GFP_KERNEL
);
319 return UWB_RSV_ALLOC_NOT_FOUND
;
320 ai
->min_mas
= rsv
->min_mas
;
321 ai
->max_mas
= rsv
->max_mas
;
322 ai
->max_interval
= rsv
->max_interval
;
325 /* fill the not available vector from the available bm */
326 for_each_clear_bit(bit_index
, available
->bm
, UWB_NUM_MAS
)
327 ai
->bm
[bit_index
] = UWB_RSV_MAS_NOT_AVAIL
;
329 if (ai
->max_interval
== 1) {
330 get_row_descriptors(ai
);
331 if (uwb_rsv_find_best_row_alloc(ai
) == UWB_RSV_ALLOC_FOUND
)
334 goto alloc_not_found
;
337 get_column_descriptors(ai
);
339 for (interval
= 16; interval
>= 2; interval
>>=1) {
340 if (interval
> ai
->max_interval
)
342 if (uwb_rsv_find_best_col_alloc(ai
, interval
) == UWB_RSV_ALLOC_FOUND
)
346 /* try row reservation if no column is found */
347 get_row_descriptors(ai
);
348 if (uwb_rsv_find_best_row_alloc(ai
) == UWB_RSV_ALLOC_FOUND
)
351 goto alloc_not_found
;
354 bitmap_zero(result
->bm
, UWB_NUM_MAS
);
355 bitmap_zero(result
->unsafe_bm
, UWB_NUM_MAS
);
356 /* fill the safe and unsafe bitmaps */
357 for (bit_index
= 0; bit_index
< UWB_NUM_MAS
; bit_index
++) {
358 if (ai
->bm
[bit_index
] == UWB_RSV_MAS_SAFE
)
359 set_bit(bit_index
, result
->bm
);
360 else if (ai
->bm
[bit_index
] == UWB_RSV_MAS_UNSAFE
)
361 set_bit(bit_index
, result
->unsafe_bm
);
363 bitmap_or(result
->bm
, result
->bm
, result
->unsafe_bm
, UWB_NUM_MAS
);
365 result
->safe
= ai
->safe_allocated_mases
;
366 result
->unsafe
= ai
->unsafe_allocated_mases
;
369 return UWB_RSV_ALLOC_FOUND
;
373 return UWB_RSV_ALLOC_NOT_FOUND
;