diff options
Diffstat (limited to 'drivers/uwb/rsv.c')
-rw-r--r-- | drivers/uwb/rsv.c | 88 |
1 files changed, 57 insertions, 31 deletions
diff --git a/drivers/uwb/rsv.c b/drivers/uwb/rsv.c index bae16204576..1cd84f92754 100644 --- a/drivers/uwb/rsv.c +++ b/drivers/uwb/rsv.c @@ -15,7 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <linux/version.h> #include <linux/kernel.h> #include <linux/uwb.h> @@ -82,6 +81,23 @@ static void uwb_rsv_dump(struct uwb_rsv *rsv) dev_dbg(dev, "rsv %s -> %s: %s\n", owner, target, uwb_rsv_state_str(rsv->state)); } +static void uwb_rsv_release(struct kref *kref) +{ + struct uwb_rsv *rsv = container_of(kref, struct uwb_rsv, kref); + + kfree(rsv); +} + +static void uwb_rsv_get(struct uwb_rsv *rsv) +{ + kref_get(&rsv->kref); +} + +static void uwb_rsv_put(struct uwb_rsv *rsv) +{ + kref_put(&rsv->kref, uwb_rsv_release); +} + /* * Get a free stream index for a reservation. * @@ -285,7 +301,8 @@ void uwb_rsv_set_state(struct uwb_rsv *rsv, enum uwb_rsv_state new_state) switch (new_state) { case UWB_RSV_STATE_NONE: uwb_drp_avail_release(rsv->rc, &rsv->mas); - uwb_rsv_put_stream(rsv); + if (uwb_rsv_is_owner(rsv)) + uwb_rsv_put_stream(rsv); uwb_rsv_state_update(rsv, UWB_RSV_STATE_NONE); uwb_rsv_callback(rsv); break; @@ -324,6 +341,7 @@ static struct uwb_rsv *uwb_rsv_alloc(struct uwb_rc *rc) INIT_LIST_HEAD(&rsv->rc_node); INIT_LIST_HEAD(&rsv->pal_node); + kref_init(&rsv->kref); init_timer(&rsv->timer); rsv->timer.function = uwb_rsv_timer; rsv->timer.data = (unsigned long)rsv; @@ -333,14 +351,6 @@ static struct uwb_rsv *uwb_rsv_alloc(struct uwb_rc *rc) return rsv; } -static void uwb_rsv_free(struct uwb_rsv *rsv) -{ - uwb_dev_put(rsv->owner); - if (rsv->target.type == UWB_RSV_TARGET_DEV) - uwb_dev_put(rsv->target.dev); - kfree(rsv); -} - /** * uwb_rsv_create - allocate and initialize a UWB reservation structure * @rc: the radio controller @@ -374,23 +384,23 @@ void uwb_rsv_remove(struct uwb_rsv *rsv) if (rsv->state != UWB_RSV_STATE_NONE) uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE); del_timer_sync(&rsv->timer); - list_del(&rsv->rc_node); - uwb_rsv_free(rsv); + uwb_dev_put(rsv->owner); + if (rsv->target.type == UWB_RSV_TARGET_DEV) + uwb_dev_put(rsv->target.dev); + + list_del_init(&rsv->rc_node); + uwb_rsv_put(rsv); } /** * uwb_rsv_destroy - free a UWB reservation structure * @rsv: the reservation to free * - * The reservation will be terminated if it is pending or established. + * The reservation must already be terminated. */ void uwb_rsv_destroy(struct uwb_rsv *rsv) { - struct uwb_rc *rc = rsv->rc; - - mutex_lock(&rc->rsvs_mutex); - uwb_rsv_remove(rsv); - mutex_unlock(&rc->rsvs_mutex); + uwb_rsv_put(rsv); } EXPORT_SYMBOL_GPL(uwb_rsv_destroy); @@ -422,6 +432,7 @@ int uwb_rsv_establish(struct uwb_rsv *rsv) goto out; } + uwb_rsv_get(rsv); list_add_tail(&rsv->rc_node, &rc->reservations); rsv->owner = &rc->uwb_dev; uwb_dev_get(rsv->owner); @@ -477,9 +488,14 @@ EXPORT_SYMBOL_GPL(uwb_rsv_terminate); * * Reservation requests from peers are denied unless a PAL accepts it * by calling this function. + * + * The PAL call uwb_rsv_destroy() for all accepted reservations before + * calling uwb_pal_unregister(). */ void uwb_rsv_accept(struct uwb_rsv *rsv, uwb_rsv_cb_f cb, void *pal_priv) { + uwb_rsv_get(rsv); + rsv->callback = cb; rsv->pal_priv = pal_priv; rsv->state = UWB_RSV_STATE_T_ACCEPTED; @@ -532,7 +548,6 @@ static struct uwb_rsv *uwb_rsv_new_target(struct uwb_rc *rc, rsv->target.dev = &rc->uwb_dev; rsv->type = uwb_ie_drp_type(drp_ie); rsv->stream = uwb_ie_drp_stream_index(drp_ie); - set_bit(rsv->stream, rsv->owner->streams); uwb_drp_ie_to_bm(&rsv->mas, drp_ie); /* @@ -540,14 +555,14 @@ static struct uwb_rsv *uwb_rsv_new_target(struct uwb_rc *rc, * deny the request. */ rsv->state = UWB_RSV_STATE_T_DENIED; - spin_lock(&rc->pal_lock); + mutex_lock(&rc->uwb_dev.mutex); list_for_each_entry(pal, &rc->pals, node) { if (pal->new_rsv) - pal->new_rsv(rsv); + pal->new_rsv(pal, rsv); if (rsv->state == UWB_RSV_STATE_T_ACCEPTED) break; } - spin_unlock(&rc->pal_lock); + mutex_unlock(&rc->uwb_dev.mutex); list_add_tail(&rsv->rc_node, &rc->reservations); state = rsv->state; @@ -644,6 +659,25 @@ static void uwb_rsv_timer(unsigned long arg) uwb_rsv_sched_update(rsv->rc); } +/** + * uwb_rsv_remove_all - remove all reservations + * @rc: the radio controller + * + * A DRP IE update is not done. + */ +void uwb_rsv_remove_all(struct uwb_rc *rc) +{ + struct uwb_rsv *rsv, *t; + + mutex_lock(&rc->rsvs_mutex); + list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) { + uwb_rsv_remove(rsv); + } + mutex_unlock(&rc->rsvs_mutex); + + cancel_work_sync(&rc->rsv_update_work); +} + void uwb_rsv_init(struct uwb_rc *rc) { INIT_LIST_HEAD(&rc->reservations); @@ -667,14 +701,6 @@ int uwb_rsv_setup(struct uwb_rc *rc) void uwb_rsv_cleanup(struct uwb_rc *rc) { - struct uwb_rsv *rsv, *t; - - mutex_lock(&rc->rsvs_mutex); - list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) { - uwb_rsv_remove(rsv); - } - mutex_unlock(&rc->rsvs_mutex); - - cancel_work_sync(&rc->rsv_update_work); + uwb_rsv_remove_all(rc); destroy_workqueue(rc->rsv_workq); } |