uwb: reference count reservations
[deliverable/linux.git] / drivers / uwb / rsv.c
CommitLineData
8cc13a09
DV
1/*
2 * UWB reservation management.
3 *
4 * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
5 *
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.
9 *
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.
14 *
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/>.
17 */
18#include <linux/version.h>
19#include <linux/kernel.h>
20#include <linux/uwb.h>
21
22#include "uwb-internal.h"
23
24static void uwb_rsv_timer(unsigned long arg);
25
26static const char *rsv_states[] = {
27 [UWB_RSV_STATE_NONE] = "none",
28 [UWB_RSV_STATE_O_INITIATED] = "initiated",
29 [UWB_RSV_STATE_O_PENDING] = "pending",
30 [UWB_RSV_STATE_O_MODIFIED] = "modified",
31 [UWB_RSV_STATE_O_ESTABLISHED] = "established",
32 [UWB_RSV_STATE_T_ACCEPTED] = "accepted",
33 [UWB_RSV_STATE_T_DENIED] = "denied",
34 [UWB_RSV_STATE_T_PENDING] = "pending",
35};
36
37static const char *rsv_types[] = {
38 [UWB_DRP_TYPE_ALIEN_BP] = "alien-bp",
39 [UWB_DRP_TYPE_HARD] = "hard",
40 [UWB_DRP_TYPE_SOFT] = "soft",
41 [UWB_DRP_TYPE_PRIVATE] = "private",
42 [UWB_DRP_TYPE_PCA] = "pca",
43};
44
45/**
46 * uwb_rsv_state_str - return a string for a reservation state
47 * @state: the reservation state.
48 */
49const char *uwb_rsv_state_str(enum uwb_rsv_state state)
50{
51 if (state < UWB_RSV_STATE_NONE || state >= UWB_RSV_STATE_LAST)
52 return "unknown";
53 return rsv_states[state];
54}
55EXPORT_SYMBOL_GPL(uwb_rsv_state_str);
56
57/**
58 * uwb_rsv_type_str - return a string for a reservation type
59 * @type: the reservation type
60 */
61const char *uwb_rsv_type_str(enum uwb_drp_type type)
62{
63 if (type < UWB_DRP_TYPE_ALIEN_BP || type > UWB_DRP_TYPE_PCA)
64 return "invalid";
65 return rsv_types[type];
66}
67EXPORT_SYMBOL_GPL(uwb_rsv_type_str);
68
69static void uwb_rsv_dump(struct uwb_rsv *rsv)
70{
71 struct device *dev = &rsv->rc->uwb_dev.dev;
72 struct uwb_dev_addr devaddr;
73 char owner[UWB_ADDR_STRSIZE], target[UWB_ADDR_STRSIZE];
74
75 uwb_dev_addr_print(owner, sizeof(owner), &rsv->owner->dev_addr);
76 if (rsv->target.type == UWB_RSV_TARGET_DEV)
77 devaddr = rsv->target.dev->dev_addr;
78 else
79 devaddr = rsv->target.devaddr;
80 uwb_dev_addr_print(target, sizeof(target), &devaddr);
81
82 dev_dbg(dev, "rsv %s -> %s: %s\n", owner, target, uwb_rsv_state_str(rsv->state));
83}
84
cae1c114
DV
85static void uwb_rsv_release(struct kref *kref)
86{
87 struct uwb_rsv *rsv = container_of(kref, struct uwb_rsv, kref);
88
89 kfree(rsv);
90}
91
92static void uwb_rsv_get(struct uwb_rsv *rsv)
93{
94 kref_get(&rsv->kref);
95}
96
97static void uwb_rsv_put(struct uwb_rsv *rsv)
98{
99 kref_put(&rsv->kref, uwb_rsv_release);
100}
101
8cc13a09
DV
102/*
103 * Get a free stream index for a reservation.
104 *
105 * If the target is a DevAddr (e.g., a WUSB cluster reservation) then
106 * the stream is allocated from a pool of per-RC stream indexes,
107 * otherwise a unique stream index for the target is selected.
108 */
109static int uwb_rsv_get_stream(struct uwb_rsv *rsv)
110{
111 struct uwb_rc *rc = rsv->rc;
112 unsigned long *streams_bm;
113 int stream;
114
115 switch (rsv->target.type) {
116 case UWB_RSV_TARGET_DEV:
117 streams_bm = rsv->target.dev->streams;
118 break;
119 case UWB_RSV_TARGET_DEVADDR:
120 streams_bm = rc->uwb_dev.streams;
121 break;
122 default:
123 return -EINVAL;
124 }
125
126 stream = find_first_zero_bit(streams_bm, UWB_NUM_STREAMS);
127 if (stream >= UWB_NUM_STREAMS)
128 return -EBUSY;
129
130 rsv->stream = stream;
131 set_bit(stream, streams_bm);
132
133 return 0;
134}
135
136static void uwb_rsv_put_stream(struct uwb_rsv *rsv)
137{
138 struct uwb_rc *rc = rsv->rc;
139 unsigned long *streams_bm;
140
141 switch (rsv->target.type) {
142 case UWB_RSV_TARGET_DEV:
143 streams_bm = rsv->target.dev->streams;
144 break;
145 case UWB_RSV_TARGET_DEVADDR:
146 streams_bm = rc->uwb_dev.streams;
147 break;
148 default:
149 return;
150 }
151
152 clear_bit(rsv->stream, streams_bm);
153}
154
155/*
156 * Generate a MAS allocation with a single row component.
157 */
158static void uwb_rsv_gen_alloc_row(struct uwb_mas_bm *mas,
159 int first_mas, int mas_per_zone,
160 int zs, int ze)
161{
162 struct uwb_mas_bm col;
163 int z;
164
165 bitmap_zero(mas->bm, UWB_NUM_MAS);
166 bitmap_zero(col.bm, UWB_NUM_MAS);
167 bitmap_fill(col.bm, mas_per_zone);
168 bitmap_shift_left(col.bm, col.bm, first_mas + zs * UWB_MAS_PER_ZONE, UWB_NUM_MAS);
169
170 for (z = zs; z <= ze; z++) {
171 bitmap_or(mas->bm, mas->bm, col.bm, UWB_NUM_MAS);
172 bitmap_shift_left(col.bm, col.bm, UWB_MAS_PER_ZONE, UWB_NUM_MAS);
173 }
174}
175
176/*
177 * Allocate some MAS for this reservation based on current local
178 * availability, the reservation parameters (max_mas, min_mas,
179 * sparsity), and the WiMedia rules for MAS allocations.
180 *
181 * Returns -EBUSY is insufficient free MAS are available.
182 *
183 * FIXME: to simplify this, only safe reservations with a single row
184 * component in zones 1 to 15 are tried (zone 0 is skipped to avoid
185 * problems with the MAS reserved for the BP).
186 *
187 * [ECMA-368] section B.2.
188 */
189static int uwb_rsv_alloc_mas(struct uwb_rsv *rsv)
190{
191 static const int safe_mas_in_row[UWB_NUM_ZONES] = {
192 8, 7, 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1,
193 };
194 int n, r;
195 struct uwb_mas_bm mas;
196 bool found = false;
197
198 /*
199 * Search all valid safe allocations until either: too few MAS
200 * are available; or the smallest allocation with sufficient
201 * MAS is found.
202 *
203 * The top of the zones are preferred, so space for larger
204 * allocations is available in the bottom of the zone (e.g., a
205 * 15 MAS allocation should start in row 14 leaving space for
206 * a 120 MAS allocation at row 0).
207 */
208 for (n = safe_mas_in_row[0]; n >= 1; n--) {
209 int num_mas;
210
211 num_mas = n * (UWB_NUM_ZONES - 1);
212 if (num_mas < rsv->min_mas)
213 break;
214 if (found && num_mas < rsv->max_mas)
215 break;
216
217 for (r = UWB_MAS_PER_ZONE-1; r >= 0; r--) {
218 if (safe_mas_in_row[r] < n)
219 continue;
220 uwb_rsv_gen_alloc_row(&mas, r, n, 1, UWB_NUM_ZONES);
221 if (uwb_drp_avail_reserve_pending(rsv->rc, &mas) == 0) {
222 found = true;
223 break;
224 }
225 }
226 }
227
228 if (!found)
229 return -EBUSY;
230
231 bitmap_copy(rsv->mas.bm, mas.bm, UWB_NUM_MAS);
232 return 0;
233}
234
235static void uwb_rsv_stroke_timer(struct uwb_rsv *rsv)
236{
237 int sframes = UWB_MAX_LOST_BEACONS;
238
239 /*
240 * Multicast reservations can become established within 1
241 * super frame and should not be terminated if no response is
242 * received.
243 */
244 if (rsv->is_multicast) {
245 if (rsv->state == UWB_RSV_STATE_O_INITIATED)
246 sframes = 1;
247 if (rsv->state == UWB_RSV_STATE_O_ESTABLISHED)
248 sframes = 0;
249 }
250
251 rsv->expired = false;
252 if (sframes > 0) {
253 /*
254 * Add an additional 2 superframes to account for the
255 * time to send the SET DRP IE command.
256 */
257 unsigned timeout_us = (sframes + 2) * UWB_SUPERFRAME_LENGTH_US;
258 mod_timer(&rsv->timer, jiffies + usecs_to_jiffies(timeout_us));
259 } else
260 del_timer(&rsv->timer);
261}
262
263/*
264 * Update a reservations state, and schedule an update of the
265 * transmitted DRP IEs.
266 */
267static void uwb_rsv_state_update(struct uwb_rsv *rsv,
268 enum uwb_rsv_state new_state)
269{
270 rsv->state = new_state;
271 rsv->ie_valid = false;
272
273 uwb_rsv_dump(rsv);
274
275 uwb_rsv_stroke_timer(rsv);
276 uwb_rsv_sched_update(rsv->rc);
277}
278
279static void uwb_rsv_callback(struct uwb_rsv *rsv)
280{
281 if (rsv->callback)
282 rsv->callback(rsv);
283}
284
285void uwb_rsv_set_state(struct uwb_rsv *rsv, enum uwb_rsv_state new_state)
286{
287 if (rsv->state == new_state) {
288 switch (rsv->state) {
289 case UWB_RSV_STATE_O_ESTABLISHED:
290 case UWB_RSV_STATE_T_ACCEPTED:
291 case UWB_RSV_STATE_NONE:
292 uwb_rsv_stroke_timer(rsv);
293 break;
294 default:
295 /* Expecting a state transition so leave timer
296 as-is. */
297 break;
298 }
299 return;
300 }
301
302 switch (new_state) {
303 case UWB_RSV_STATE_NONE:
304 uwb_drp_avail_release(rsv->rc, &rsv->mas);
6a4b5870
DV
305 if (uwb_rsv_is_owner(rsv))
306 uwb_rsv_put_stream(rsv);
8cc13a09
DV
307 uwb_rsv_state_update(rsv, UWB_RSV_STATE_NONE);
308 uwb_rsv_callback(rsv);
309 break;
310 case UWB_RSV_STATE_O_INITIATED:
311 uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_INITIATED);
312 break;
313 case UWB_RSV_STATE_O_PENDING:
314 uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_PENDING);
315 break;
316 case UWB_RSV_STATE_O_ESTABLISHED:
317 uwb_drp_avail_reserve(rsv->rc, &rsv->mas);
318 uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_ESTABLISHED);
319 uwb_rsv_callback(rsv);
320 break;
321 case UWB_RSV_STATE_T_ACCEPTED:
322 uwb_drp_avail_reserve(rsv->rc, &rsv->mas);
323 uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_ACCEPTED);
324 uwb_rsv_callback(rsv);
325 break;
326 case UWB_RSV_STATE_T_DENIED:
327 uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_DENIED);
328 break;
329 default:
330 dev_err(&rsv->rc->uwb_dev.dev, "unhandled state: %s (%d)\n",
331 uwb_rsv_state_str(new_state), new_state);
332 }
333}
334
335static struct uwb_rsv *uwb_rsv_alloc(struct uwb_rc *rc)
336{
337 struct uwb_rsv *rsv;
338
339 rsv = kzalloc(sizeof(struct uwb_rsv), GFP_KERNEL);
340 if (!rsv)
341 return NULL;
342
343 INIT_LIST_HEAD(&rsv->rc_node);
344 INIT_LIST_HEAD(&rsv->pal_node);
cae1c114 345 kref_init(&rsv->kref);
8cc13a09
DV
346 init_timer(&rsv->timer);
347 rsv->timer.function = uwb_rsv_timer;
348 rsv->timer.data = (unsigned long)rsv;
349
350 rsv->rc = rc;
351
352 return rsv;
353}
354
8cc13a09
DV
355/**
356 * uwb_rsv_create - allocate and initialize a UWB reservation structure
357 * @rc: the radio controller
358 * @cb: callback to use when the reservation completes or terminates
359 * @pal_priv: data private to the PAL to be passed in the callback
360 *
361 * The callback is called when the state of the reservation changes from:
362 *
363 * - pending to accepted
364 * - pending to denined
365 * - accepted to terminated
366 * - pending to terminated
367 */
368struct uwb_rsv *uwb_rsv_create(struct uwb_rc *rc, uwb_rsv_cb_f cb, void *pal_priv)
369{
370 struct uwb_rsv *rsv;
371
372 rsv = uwb_rsv_alloc(rc);
373 if (!rsv)
374 return NULL;
375
376 rsv->callback = cb;
377 rsv->pal_priv = pal_priv;
378
379 return rsv;
380}
381EXPORT_SYMBOL_GPL(uwb_rsv_create);
382
383void uwb_rsv_remove(struct uwb_rsv *rsv)
384{
385 if (rsv->state != UWB_RSV_STATE_NONE)
386 uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
387 del_timer_sync(&rsv->timer);
cae1c114
DV
388 uwb_dev_put(rsv->owner);
389 if (rsv->target.type == UWB_RSV_TARGET_DEV)
390 uwb_dev_put(rsv->target.dev);
391
392 list_del_init(&rsv->rc_node);
393 uwb_rsv_put(rsv);
8cc13a09
DV
394}
395
396/**
397 * uwb_rsv_destroy - free a UWB reservation structure
398 * @rsv: the reservation to free
399 *
cae1c114 400 * The reservation must already be terminated.
8cc13a09
DV
401 */
402void uwb_rsv_destroy(struct uwb_rsv *rsv)
403{
cae1c114 404 uwb_rsv_put(rsv);
8cc13a09
DV
405}
406EXPORT_SYMBOL_GPL(uwb_rsv_destroy);
407
408/**
409 * usb_rsv_establish - start a reservation establishment
410 * @rsv: the reservation
411 *
412 * The PAL should fill in @rsv's owner, target, type, max_mas,
413 * min_mas, sparsity and is_multicast fields. If the target is a
414 * uwb_dev it must be referenced.
415 *
416 * The reservation's callback will be called when the reservation is
417 * accepted, denied or times out.
418 */
419int uwb_rsv_establish(struct uwb_rsv *rsv)
420{
421 struct uwb_rc *rc = rsv->rc;
422 int ret;
423
424 mutex_lock(&rc->rsvs_mutex);
425
426 ret = uwb_rsv_get_stream(rsv);
427 if (ret)
428 goto out;
429
430 ret = uwb_rsv_alloc_mas(rsv);
431 if (ret) {
432 uwb_rsv_put_stream(rsv);
433 goto out;
434 }
435
cae1c114 436 uwb_rsv_get(rsv);
8cc13a09
DV
437 list_add_tail(&rsv->rc_node, &rc->reservations);
438 rsv->owner = &rc->uwb_dev;
439 uwb_dev_get(rsv->owner);
440 uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_INITIATED);
441out:
442 mutex_unlock(&rc->rsvs_mutex);
443 return ret;
444}
445EXPORT_SYMBOL_GPL(uwb_rsv_establish);
446
447/**
448 * uwb_rsv_modify - modify an already established reservation
449 * @rsv: the reservation to modify
450 * @max_mas: new maximum MAS to reserve
451 * @min_mas: new minimum MAS to reserve
452 * @sparsity: new sparsity to use
453 *
454 * FIXME: implement this once there are PALs that use it.
455 */
456int uwb_rsv_modify(struct uwb_rsv *rsv, int max_mas, int min_mas, int sparsity)
457{
458 return -ENOSYS;
459}
460EXPORT_SYMBOL_GPL(uwb_rsv_modify);
461
462/**
463 * uwb_rsv_terminate - terminate an established reservation
464 * @rsv: the reservation to terminate
465 *
466 * A reservation is terminated by removing the DRP IE from the beacon,
467 * the other end will consider the reservation to be terminated when
468 * it does not see the DRP IE for at least mMaxLostBeacons.
469 *
470 * If applicable, the reference to the target uwb_dev will be released.
471 */
472void uwb_rsv_terminate(struct uwb_rsv *rsv)
473{
474 struct uwb_rc *rc = rsv->rc;
475
476 mutex_lock(&rc->rsvs_mutex);
477
478 uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
479
480 mutex_unlock(&rc->rsvs_mutex);
481}
482EXPORT_SYMBOL_GPL(uwb_rsv_terminate);
483
484/**
485 * uwb_rsv_accept - accept a new reservation from a peer
486 * @rsv: the reservation
487 * @cb: call back for reservation changes
488 * @pal_priv: data to be passed in the above call back
489 *
490 * Reservation requests from peers are denied unless a PAL accepts it
491 * by calling this function.
cae1c114
DV
492 *
493 * The PAL call uwb_rsv_destroy() for all accepted reservations before
494 * calling uwb_pal_unregister().
8cc13a09
DV
495 */
496void uwb_rsv_accept(struct uwb_rsv *rsv, uwb_rsv_cb_f cb, void *pal_priv)
497{
cae1c114
DV
498 uwb_rsv_get(rsv);
499
8cc13a09
DV
500 rsv->callback = cb;
501 rsv->pal_priv = pal_priv;
502 rsv->state = UWB_RSV_STATE_T_ACCEPTED;
503}
504EXPORT_SYMBOL_GPL(uwb_rsv_accept);
505
506/*
507 * Is a received DRP IE for this reservation?
508 */
509static bool uwb_rsv_match(struct uwb_rsv *rsv, struct uwb_dev *src,
510 struct uwb_ie_drp *drp_ie)
511{
512 struct uwb_dev_addr *rsv_src;
513 int stream;
514
515 stream = uwb_ie_drp_stream_index(drp_ie);
516
517 if (rsv->stream != stream)
518 return false;
519
520 switch (rsv->target.type) {
521 case UWB_RSV_TARGET_DEVADDR:
522 return rsv->stream == stream;
523 case UWB_RSV_TARGET_DEV:
524 if (uwb_ie_drp_owner(drp_ie))
525 rsv_src = &rsv->owner->dev_addr;
526 else
527 rsv_src = &rsv->target.dev->dev_addr;
528 return uwb_dev_addr_cmp(&src->dev_addr, rsv_src) == 0;
529 }
530 return false;
531}
532
533static struct uwb_rsv *uwb_rsv_new_target(struct uwb_rc *rc,
534 struct uwb_dev *src,
535 struct uwb_ie_drp *drp_ie)
536{
537 struct uwb_rsv *rsv;
538 struct uwb_pal *pal;
539 enum uwb_rsv_state state;
540
541 rsv = uwb_rsv_alloc(rc);
542 if (!rsv)
543 return NULL;
544
545 rsv->rc = rc;
546 rsv->owner = src;
547 uwb_dev_get(rsv->owner);
548 rsv->target.type = UWB_RSV_TARGET_DEV;
549 rsv->target.dev = &rc->uwb_dev;
550 rsv->type = uwb_ie_drp_type(drp_ie);
551 rsv->stream = uwb_ie_drp_stream_index(drp_ie);
8cc13a09
DV
552 uwb_drp_ie_to_bm(&rsv->mas, drp_ie);
553
554 /*
555 * See if any PALs are interested in this reservation. If not,
556 * deny the request.
557 */
558 rsv->state = UWB_RSV_STATE_T_DENIED;
559 spin_lock(&rc->pal_lock);
560 list_for_each_entry(pal, &rc->pals, node) {
561 if (pal->new_rsv)
562 pal->new_rsv(rsv);
563 if (rsv->state == UWB_RSV_STATE_T_ACCEPTED)
564 break;
565 }
566 spin_unlock(&rc->pal_lock);
567
568 list_add_tail(&rsv->rc_node, &rc->reservations);
569 state = rsv->state;
570 rsv->state = UWB_RSV_STATE_NONE;
571 uwb_rsv_set_state(rsv, state);
572
573 return rsv;
574}
575
576/**
577 * uwb_rsv_find - find a reservation for a received DRP IE.
578 * @rc: the radio controller
579 * @src: source of the DRP IE
580 * @drp_ie: the DRP IE
581 *
582 * If the reservation cannot be found and the DRP IE is from a peer
583 * attempting to establish a new reservation, create a new reservation
584 * and add it to the list.
585 */
586struct uwb_rsv *uwb_rsv_find(struct uwb_rc *rc, struct uwb_dev *src,
587 struct uwb_ie_drp *drp_ie)
588{
589 struct uwb_rsv *rsv;
590
591 list_for_each_entry(rsv, &rc->reservations, rc_node) {
592 if (uwb_rsv_match(rsv, src, drp_ie))
593 return rsv;
594 }
595
596 if (uwb_ie_drp_owner(drp_ie))
597 return uwb_rsv_new_target(rc, src, drp_ie);
598
599 return NULL;
600}
601
602/*
603 * Go through all the reservations and check for timeouts and (if
604 * necessary) update their DRP IEs.
605 *
606 * FIXME: look at building the SET_DRP_IE command here rather than
607 * having to rescan the list in uwb_rc_send_all_drp_ie().
608 */
609static bool uwb_rsv_update_all(struct uwb_rc *rc)
610{
611 struct uwb_rsv *rsv, *t;
612 bool ie_updated = false;
613
614 list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) {
615 if (rsv->expired)
616 uwb_drp_handle_timeout(rsv);
617 if (!rsv->ie_valid) {
618 uwb_drp_ie_update(rsv);
619 ie_updated = true;
620 }
621 }
622
623 return ie_updated;
624}
625
626void uwb_rsv_sched_update(struct uwb_rc *rc)
627{
628 queue_work(rc->rsv_workq, &rc->rsv_update_work);
629}
630
631/*
632 * Update DRP IEs and, if necessary, the DRP Availability IE and send
633 * the updated IEs to the radio controller.
634 */
635static void uwb_rsv_update_work(struct work_struct *work)
636{
637 struct uwb_rc *rc = container_of(work, struct uwb_rc, rsv_update_work);
638 bool ie_updated;
639
640 mutex_lock(&rc->rsvs_mutex);
641
642 ie_updated = uwb_rsv_update_all(rc);
643
644 if (!rc->drp_avail.ie_valid) {
645 uwb_drp_avail_ie_update(rc);
646 ie_updated = true;
647 }
648
649 if (ie_updated)
650 uwb_rc_send_all_drp_ie(rc);
651
652 mutex_unlock(&rc->rsvs_mutex);
653}
654
655static void uwb_rsv_timer(unsigned long arg)
656{
657 struct uwb_rsv *rsv = (struct uwb_rsv *)arg;
658
659 rsv->expired = true;
660 uwb_rsv_sched_update(rsv->rc);
661}
662
663void uwb_rsv_init(struct uwb_rc *rc)
664{
665 INIT_LIST_HEAD(&rc->reservations);
666 mutex_init(&rc->rsvs_mutex);
667 INIT_WORK(&rc->rsv_update_work, uwb_rsv_update_work);
668
669 bitmap_complement(rc->uwb_dev.streams, rc->uwb_dev.streams, UWB_NUM_STREAMS);
670}
671
672int uwb_rsv_setup(struct uwb_rc *rc)
673{
674 char name[16];
675
676 snprintf(name, sizeof(name), "%s_rsvd", dev_name(&rc->uwb_dev.dev));
677 rc->rsv_workq = create_singlethread_workqueue(name);
678 if (rc->rsv_workq == NULL)
679 return -ENOMEM;
680
681 return 0;
682}
683
684void uwb_rsv_cleanup(struct uwb_rc *rc)
685{
686 struct uwb_rsv *rsv, *t;
687
688 mutex_lock(&rc->rsvs_mutex);
689 list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) {
690 uwb_rsv_remove(rsv);
691 }
692 mutex_unlock(&rc->rsvs_mutex);
693
694 cancel_work_sync(&rc->rsv_update_work);
695 destroy_workqueue(rc->rsv_workq);
696}
This page took 0.053668 seconds and 5 git commands to generate.