summaryrefslogtreecommitdiff
path: root/drivers/uwb/rsv.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/uwb/rsv.c')
-rw-r--r--drivers/uwb/rsv.c88
1 files changed, 57 insertions, 31 deletions
diff --git a/drivers/uwb/rsv.c b/drivers/uwb/rsv.c
index bae16204..1cd84f9 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);
}