2 * UWB reservation management.
4 * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include <linux/kernel.h>
19 #include <linux/slab.h>
20 #include <linux/uwb.h>
22 #include "uwb-internal.h"
24 static void uwb_rsv_fill_column_alloc(struct uwb_rsv_alloc_info
*ai
)
26 int col
, mas
, safe_mas
, unsafe_mas
;
27 unsigned char *bm
= ai
->bm
;
28 struct uwb_rsv_col_info
*ci
= ai
->ci
;
31 for (col
= ci
->csi
.start_col
; col
< UWB_NUM_ZONES
; col
+= ci
->csi
.interval
) {
33 safe_mas
= ci
->csi
.safe_mas_per_col
;
34 unsafe_mas
= ci
->csi
.unsafe_mas_per_col
;
36 for (mas
= 0; mas
< UWB_MAS_PER_ZONE
; mas
++ ) {
37 if (bm
[col
* UWB_MAS_PER_ZONE
+ mas
] == 0) {
42 } else if (unsafe_mas
> 0) {
44 c
= UWB_RSV_MAS_UNSAFE
;
48 bm
[col
* UWB_MAS_PER_ZONE
+ mas
] = c
;
54 static void uwb_rsv_fill_row_alloc(struct uwb_rsv_alloc_info
*ai
)
57 unsigned char *bm
= ai
->bm
;
58 struct uwb_rsv_row_info
*ri
= &ai
->ri
;
63 for (mas
= UWB_MAS_PER_ZONE
- 1; mas
>= 0; mas
--) {
64 if (ri
->avail
[mas
] == 1) {
66 if (rows
> ri
->used_rows
) {
68 } else if (rows
> 7) {
69 c
= UWB_RSV_MAS_UNSAFE
;
72 for (col
= 0; col
< UWB_NUM_ZONES
; col
++) {
73 if (bm
[col
* UWB_NUM_ZONES
+ mas
] != UWB_RSV_MAS_NOT_AVAIL
) {
74 bm
[col
* UWB_NUM_ZONES
+ mas
] = c
;
75 if(c
== UWB_RSV_MAS_SAFE
)
76 ai
->safe_allocated_mases
++;
78 ai
->unsafe_allocated_mases
++;
84 ai
->total_allocated_mases
= ai
->safe_allocated_mases
+ ai
->unsafe_allocated_mases
;
88 * Find the best column set for a given availability, interval, num safe mas and
91 * The different sets are tried in order as shown below, depending on the interval.
128 * set 1 -> { 2 6 10 14 }
130 * set 1 -> { 1 5 9 13 }
131 * set 2 -> { 3 7 11 15 }
135 * set 1 -> { 1 3 5 7 9 11 13 15 }
137 static int uwb_rsv_find_best_column_set(struct uwb_rsv_alloc_info
*ai
, int interval
,
138 int num_safe_mas
, int num_unsafe_mas
)
140 struct uwb_rsv_col_info
*ci
= ai
->ci
;
141 struct uwb_rsv_col_set_info
*csi
= &ci
->csi
;
142 struct uwb_rsv_col_set_info tmp_csi
;
143 int deep
, set
, col
, start_col_deep
, col_start_set
;
144 int start_col
, max_mas_in_set
, lowest_max_mas_in_deep
;
146 int found
= UWB_RSV_ALLOC_NOT_FOUND
;
148 tmp_csi
.start_col
= 0;
149 start_col_deep
= interval
;
150 n_mas
= num_unsafe_mas
+ num_safe_mas
;
152 for (deep
= 0; ((interval
>> deep
) & 0x1) == 0; deep
++) {
155 lowest_max_mas_in_deep
= UWB_MAS_PER_ZONE
;
157 for (set
= 1; set
<= (1 << deep
); set
++) {
159 start_col
= start_col_deep
+ col_start_set
;
160 for (col
= start_col
; col
< UWB_NUM_ZONES
; col
+= interval
) {
162 if (ci
[col
].max_avail_safe
>= num_safe_mas
&&
163 ci
[col
].max_avail_unsafe
>= n_mas
) {
164 if (ci
[col
].highest_mas
[n_mas
] > max_mas_in_set
)
165 max_mas_in_set
= ci
[col
].highest_mas
[n_mas
];
171 if ((lowest_max_mas_in_deep
> max_mas_in_set
) && max_mas_in_set
) {
172 lowest_max_mas_in_deep
= max_mas_in_set
;
174 tmp_csi
.start_col
= start_col
;
176 col_start_set
+= (interval
>> deep
);
179 if (lowest_max_mas_in_deep
< 8) {
180 csi
->start_col
= tmp_csi
.start_col
;
181 found
= UWB_RSV_ALLOC_FOUND
;
183 } else if ((lowest_max_mas_in_deep
> 8) &&
184 (lowest_max_mas_in_deep
!= UWB_MAS_PER_ZONE
) &&
185 (found
== UWB_RSV_ALLOC_NOT_FOUND
)) {
186 csi
->start_col
= tmp_csi
.start_col
;
187 found
= UWB_RSV_ALLOC_FOUND
;
191 if (found
== UWB_RSV_ALLOC_FOUND
) {
192 csi
->interval
= interval
;
193 csi
->safe_mas_per_col
= num_safe_mas
;
194 csi
->unsafe_mas_per_col
= num_unsafe_mas
;
196 ai
->safe_allocated_mases
= (UWB_NUM_ZONES
/ interval
) * num_safe_mas
;
197 ai
->unsafe_allocated_mases
= (UWB_NUM_ZONES
/ interval
) * num_unsafe_mas
;
198 ai
->total_allocated_mases
= ai
->safe_allocated_mases
+ ai
->unsafe_allocated_mases
;
199 ai
->interval
= interval
;
204 static void get_row_descriptors(struct uwb_rsv_alloc_info
*ai
)
206 unsigned char *bm
= ai
->bm
;
207 struct uwb_rsv_row_info
*ri
= &ai
->ri
;
211 for (mas
= 0; mas
< UWB_MAS_PER_ZONE
; mas
++) {
213 for (col
= 1; col
< UWB_NUM_ZONES
; col
++) {
214 if (bm
[col
* UWB_NUM_ZONES
+ mas
] == UWB_RSV_MAS_NOT_AVAIL
) {
223 static void uwb_rsv_fill_column_info(unsigned char *bm
, int column
, struct uwb_rsv_col_info
*rci
)
226 int block_count
= 0, start_block
= 0;
227 int previous_avail
= 0;
229 int safe_mas_in_row
[UWB_MAS_PER_ZONE
] = {
230 8, 7, 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1,
233 rci
->max_avail_safe
= 0;
235 for (mas
= 0; mas
< UWB_MAS_PER_ZONE
; mas
++) {
236 if (!bm
[column
* UWB_NUM_ZONES
+ mas
]) {
238 rci
->max_avail_unsafe
= available
;
240 rci
->highest_mas
[available
] = mas
;
242 if (previous_avail
) {
244 if ((block_count
> safe_mas_in_row
[start_block
]) &&
245 (!rci
->max_avail_safe
))
246 rci
->max_avail_safe
= available
- 1;
256 if (!rci
->max_avail_safe
)
257 rci
->max_avail_safe
= rci
->max_avail_unsafe
;
260 static void get_column_descriptors(struct uwb_rsv_alloc_info
*ai
)
262 unsigned char *bm
= ai
->bm
;
263 struct uwb_rsv_col_info
*ci
= ai
->ci
;
266 for (col
= 1; col
< UWB_NUM_ZONES
; col
++) {
267 uwb_rsv_fill_column_info(bm
, col
, &ci
[col
]);
271 static int uwb_rsv_find_best_row_alloc(struct uwb_rsv_alloc_info
*ai
)
274 int max_rows
= ai
->max_mas
/ UWB_USABLE_MAS_PER_ROW
;
275 int min_rows
= ai
->min_mas
/ UWB_USABLE_MAS_PER_ROW
;
276 if (ai
->min_mas
% UWB_USABLE_MAS_PER_ROW
)
278 for (n_rows
= max_rows
; n_rows
>= min_rows
; n_rows
--) {
279 if (n_rows
<= ai
->ri
.free_rows
) {
280 ai
->ri
.used_rows
= n_rows
;
281 ai
->interval
= 1; /* row reservation */
282 uwb_rsv_fill_row_alloc(ai
);
283 return UWB_RSV_ALLOC_FOUND
;
286 return UWB_RSV_ALLOC_NOT_FOUND
;
289 static int uwb_rsv_find_best_col_alloc(struct uwb_rsv_alloc_info
*ai
, int interval
)
291 int n_safe
, n_unsafe
, n_mas
;
292 int n_column
= UWB_NUM_ZONES
/ interval
;
293 int max_per_zone
= ai
->max_mas
/ n_column
;
294 int min_per_zone
= ai
->min_mas
/ n_column
;
296 if (ai
->min_mas
% n_column
)
299 if (min_per_zone
> UWB_MAS_PER_ZONE
) {
300 return UWB_RSV_ALLOC_NOT_FOUND
;
303 if (max_per_zone
> UWB_MAS_PER_ZONE
) {
304 max_per_zone
= UWB_MAS_PER_ZONE
;
307 for (n_mas
= max_per_zone
; n_mas
>= min_per_zone
; n_mas
--) {
308 if (uwb_rsv_find_best_column_set(ai
, interval
, 0, n_mas
) == UWB_RSV_ALLOC_NOT_FOUND
)
310 for (n_safe
= n_mas
; n_safe
>= 0; n_safe
--) {
311 n_unsafe
= n_mas
- n_safe
;
312 if (uwb_rsv_find_best_column_set(ai
, interval
, n_safe
, n_unsafe
) == UWB_RSV_ALLOC_FOUND
) {
313 uwb_rsv_fill_column_alloc(ai
);
314 return UWB_RSV_ALLOC_FOUND
;
318 return UWB_RSV_ALLOC_NOT_FOUND
;
321 int uwb_rsv_find_best_allocation(struct uwb_rsv
*rsv
, struct uwb_mas_bm
*available
,
322 struct uwb_mas_bm
*result
)
324 struct uwb_rsv_alloc_info
*ai
;
328 ai
= kzalloc(sizeof(struct uwb_rsv_alloc_info
), GFP_KERNEL
);
330 return UWB_RSV_ALLOC_NOT_FOUND
;
331 ai
->min_mas
= rsv
->min_mas
;
332 ai
->max_mas
= rsv
->max_mas
;
333 ai
->max_interval
= rsv
->max_interval
;
336 /* fill the not available vector from the available bm */
337 for (bit_index
= 0; bit_index
< UWB_NUM_MAS
; bit_index
++) {
338 if (!test_bit(bit_index
, available
->bm
))
339 ai
->bm
[bit_index
] = UWB_RSV_MAS_NOT_AVAIL
;
342 if (ai
->max_interval
== 1) {
343 get_row_descriptors(ai
);
344 if (uwb_rsv_find_best_row_alloc(ai
) == UWB_RSV_ALLOC_FOUND
)
347 goto alloc_not_found
;
350 get_column_descriptors(ai
);
352 for (interval
= 16; interval
>= 2; interval
>>=1) {
353 if (interval
> ai
->max_interval
)
355 if (uwb_rsv_find_best_col_alloc(ai
, interval
) == UWB_RSV_ALLOC_FOUND
)
359 /* try row reservation if no column is found */
360 get_row_descriptors(ai
);
361 if (uwb_rsv_find_best_row_alloc(ai
) == UWB_RSV_ALLOC_FOUND
)
364 goto alloc_not_found
;
367 bitmap_zero(result
->bm
, UWB_NUM_MAS
);
368 bitmap_zero(result
->unsafe_bm
, UWB_NUM_MAS
);
369 /* fill the safe and unsafe bitmaps */
370 for (bit_index
= 0; bit_index
< UWB_NUM_MAS
; bit_index
++) {
371 if (ai
->bm
[bit_index
] == UWB_RSV_MAS_SAFE
)
372 set_bit(bit_index
, result
->bm
);
373 else if (ai
->bm
[bit_index
] == UWB_RSV_MAS_UNSAFE
)
374 set_bit(bit_index
, result
->unsafe_bm
);
376 bitmap_or(result
->bm
, result
->bm
, result
->unsafe_bm
, UWB_NUM_MAS
);
378 result
->safe
= ai
->safe_allocated_mases
;
379 result
->unsafe
= ai
->unsafe_allocated_mases
;
382 return UWB_RSV_ALLOC_FOUND
;
386 return UWB_RSV_ALLOC_NOT_FOUND
;