uwb: per-radio controller event thread and beacon cache
authorStefano Panella <stefano.panella@csr.com>
Tue, 4 Nov 2008 15:39:08 +0000 (15:39 +0000)
committerDavid Vrabel <david.vrabel@csr.com>
Tue, 4 Nov 2008 15:55:26 +0000 (15:55 +0000)
Use an event thread per-radio controller so processing events from one
radio controller doesn't delay another.

A radio controller shouldn't have information on devices seen by a
different radio controller (they may be on different channels) so make the
beacon cache per-radio controller.

Signed-off-by: Stefano Panella <stefano.panella@csr.com>
Signed-off-by: David Vrabel <david.vrabel@csr.com>
drivers/uwb/beacon.c
drivers/uwb/driver.c
drivers/uwb/lc-rc.c
drivers/uwb/uwb-internal.h
drivers/uwb/uwbd.c
include/linux/uwb.h

index ad82398..d9f2a8a 100644 (file)
@@ -168,12 +168,6 @@ out_up:
  * FIXME: use something faster for search than a list
  */
 
-struct uwb_beca uwb_beca = {
-       .list = LIST_HEAD_INIT(uwb_beca.list),
-       .mutex = __MUTEX_INITIALIZER(uwb_beca.mutex)
-};
-
-
 void uwb_bce_kfree(struct kref *_bce)
 {
        struct uwb_beca_e *bce = container_of(_bce, struct uwb_beca_e, refcnt);
@@ -185,10 +179,11 @@ void uwb_bce_kfree(struct kref *_bce)
 
 /* Find a beacon by dev addr in the cache */
 static
-struct uwb_beca_e *__uwb_beca_find_bydev(const struct uwb_dev_addr *dev_addr)
+struct uwb_beca_e *__uwb_beca_find_bydev(struct uwb_rc *rc,
+                                        const struct uwb_dev_addr *dev_addr)
 {
        struct uwb_beca_e *bce, *next;
-       list_for_each_entry_safe(bce, next, &uwb_beca.list, node) {
+       list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) {
                d_printf(6, NULL, "looking for addr %02x:%02x in %02x:%02x\n",
                         dev_addr->data[0], dev_addr->data[1],
                         bce->dev_addr.data[0], bce->dev_addr.data[1]);
@@ -202,10 +197,11 @@ out:
 
 /* Find a beacon by dev addr in the cache */
 static
-struct uwb_beca_e *__uwb_beca_find_bymac(const struct uwb_mac_addr *mac_addr)
+struct uwb_beca_e *__uwb_beca_find_bymac(struct uwb_rc *rc, 
+                                        const struct uwb_mac_addr *mac_addr)
 {
        struct uwb_beca_e *bce, *next;
-       list_for_each_entry_safe(bce, next, &uwb_beca.list, node) {
+       list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) {
                if (!memcmp(bce->mac_addr, mac_addr->data,
                            sizeof(struct uwb_mac_addr)))
                        goto out;
@@ -229,11 +225,11 @@ struct uwb_dev *uwb_dev_get_by_devaddr(struct uwb_rc *rc,
        struct uwb_dev *found = NULL;
        struct uwb_beca_e *bce;
 
-       mutex_lock(&uwb_beca.mutex);
-       bce = __uwb_beca_find_bydev(devaddr);
+       mutex_lock(&rc->uwb_beca.mutex);
+       bce = __uwb_beca_find_bydev(rc, devaddr);
        if (bce)
                found = uwb_dev_try_get(rc, bce->uwb_dev);
-       mutex_unlock(&uwb_beca.mutex);
+       mutex_unlock(&rc->uwb_beca.mutex);
 
        return found;
 }
@@ -249,11 +245,11 @@ struct uwb_dev *uwb_dev_get_by_macaddr(struct uwb_rc *rc,
        struct uwb_dev *found = NULL;
        struct uwb_beca_e *bce;
 
-       mutex_lock(&uwb_beca.mutex);
-       bce = __uwb_beca_find_bymac(macaddr);
+       mutex_lock(&rc->uwb_beca.mutex);
+       bce = __uwb_beca_find_bymac(rc, macaddr);
        if (bce)
                found = uwb_dev_try_get(rc, bce->uwb_dev);
-       mutex_unlock(&uwb_beca.mutex);
+       mutex_unlock(&rc->uwb_beca.mutex);
 
        return found;
 }
@@ -274,7 +270,9 @@ static void uwb_beca_e_init(struct uwb_beca_e *bce)
  * @bf:         Beacon frame (part of b, really)
  * @ts_jiffies: Timestamp (in jiffies) when the beacon was received
  */
-struct uwb_beca_e *__uwb_beca_add(struct uwb_rc_evt_beacon *be,
+static
+struct uwb_beca_e *__uwb_beca_add(struct uwb_rc *rc,
+                                 struct uwb_rc_evt_beacon *be,
                                  struct uwb_beacon_frame *bf,
                                  unsigned long ts_jiffies)
 {
@@ -286,7 +284,7 @@ struct uwb_beca_e *__uwb_beca_add(struct uwb_rc_evt_beacon *be,
        uwb_beca_e_init(bce);
        bce->ts_jiffies = ts_jiffies;
        bce->uwb_dev = NULL;
-       list_add(&bce->node, &uwb_beca.list);
+       list_add(&bce->node, &rc->uwb_beca.list);
        return bce;
 }
 
@@ -295,13 +293,13 @@ struct uwb_beca_e *__uwb_beca_add(struct uwb_rc_evt_beacon *be,
  *
  * Remove associated devicest too.
  */
-void uwb_beca_purge(void)
+void uwb_beca_purge(struct uwb_rc *rc)
 {
        struct uwb_beca_e *bce, *next;
        unsigned long expires;
 
-       mutex_lock(&uwb_beca.mutex);
-       list_for_each_entry_safe(bce, next, &uwb_beca.list, node) {
+       mutex_lock(&rc->uwb_beca.mutex);
+       list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) {
                expires = bce->ts_jiffies + msecs_to_jiffies(beacon_timeout_ms);
                if (time_after(jiffies, expires)) {
                        uwbd_dev_offair(bce);
@@ -309,19 +307,20 @@ void uwb_beca_purge(void)
                        uwb_bce_put(bce);
                }
        }
-       mutex_unlock(&uwb_beca.mutex);
+       mutex_unlock(&rc->uwb_beca.mutex);
 }
 
 /* Clean up the whole beacon cache. Called on shutdown */
-void uwb_beca_release(void)
+void uwb_beca_release(struct uwb_rc *rc)
 {
        struct uwb_beca_e *bce, *next;
-       mutex_lock(&uwb_beca.mutex);
-       list_for_each_entry_safe(bce, next, &uwb_beca.list, node) {
+
+       mutex_lock(&rc->uwb_beca.mutex);
+       list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) {
                list_del(&bce->node);
                uwb_bce_put(bce);
        }
-       mutex_unlock(&uwb_beca.mutex);
+       mutex_unlock(&rc->uwb_beca.mutex);
 }
 
 static void uwb_beacon_print(struct uwb_rc *rc, struct uwb_rc_evt_beacon *be,
@@ -437,18 +436,18 @@ int uwbd_evt_handle_rc_beacon(struct uwb_event *evt)
        if (uwb_mac_addr_bcast(&bf->Device_Identifier))
                return 0;
 
-       mutex_lock(&uwb_beca.mutex);
-       bce = __uwb_beca_find_bymac(&bf->Device_Identifier);
+       mutex_lock(&rc->uwb_beca.mutex);
+       bce = __uwb_beca_find_bymac(rc, &bf->Device_Identifier);
        if (bce == NULL) {
                /* Not in there, a new device is pinging */
                uwb_beacon_print(evt->rc, be, bf);
-               bce = __uwb_beca_add(be, bf, evt->ts_jiffies);
+               bce = __uwb_beca_add(rc, be, bf, evt->ts_jiffies);
                if (bce == NULL) {
-                       mutex_unlock(&uwb_beca.mutex);
+                       mutex_unlock(&rc->uwb_beca.mutex);
                        return -ENOMEM;
                }
        }
-       mutex_unlock(&uwb_beca.mutex);
+       mutex_unlock(&rc->uwb_beca.mutex);
 
        mutex_lock(&bce->mutex);
        /* purge old beacon data */
index 521cdeb..f57c265 100644 (file)
@@ -118,7 +118,6 @@ static int __init uwb_subsys_init(void)
        result = class_register(&uwb_rc_class);
        if (result < 0)
                goto error_uwb_rc_class_register;
-       uwbd_start();
        uwb_dbg_init();
        return 0;
 
@@ -132,7 +131,6 @@ module_init(uwb_subsys_init);
 static void __exit uwb_subsys_exit(void)
 {
        uwb_dbg_exit();
-       uwbd_stop();
        class_unregister(&uwb_rc_class);
        uwb_est_destroy();
        return;
index 1129e87..38e3d57 100644 (file)
@@ -36,8 +36,6 @@
 #include <linux/etherdevice.h>
 #include <linux/usb.h>
 
-#define D_LOCAL 1
-#include <linux/uwb/debug.h>
 #include "uwb-internal.h"
 
 static int uwb_rc_index_match(struct device *dev, void *data)
@@ -83,7 +81,6 @@ static void uwb_rc_sys_release(struct device *dev)
 
        uwb_rc_neh_destroy(rc);
        uwb_rc_ie_release(rc);
-       d_printf(1, dev, "freed uwb_rc %p\n", rc);
        kfree(rc);
 }
 
@@ -100,6 +97,8 @@ void uwb_rc_init(struct uwb_rc *rc)
        rc->scan_type = UWB_SCAN_DISABLED;
        INIT_LIST_HEAD(&rc->notifs_chain.list);
        mutex_init(&rc->notifs_chain.mutex);
+       INIT_LIST_HEAD(&rc->uwb_beca.list);
+       mutex_init(&rc->uwb_beca.mutex);
        uwb_drp_avail_init(rc);
        uwb_rc_ie_init(rc);
        uwb_rsv_init(rc);
@@ -250,6 +249,12 @@ int uwb_rc_add(struct uwb_rc *rc, struct device *parent_dev, void *priv)
 
        rc->priv = priv;
 
+       init_waitqueue_head(&rc->uwbd.wq);
+       INIT_LIST_HEAD(&rc->uwbd.event_list);
+       spin_lock_init(&rc->uwbd.event_list_lock);
+
+       uwbd_start(rc);
+
        result = rc->start(rc);
        if (result < 0)
                goto error_rc_start;
@@ -284,7 +289,7 @@ error_sys_add:
 error_dev_add:
 error_rc_setup:
        rc->stop(rc);
-       uwbd_flush(rc);
+       uwbd_stop(rc);
 error_rc_start:
        return result;
 }
@@ -315,16 +320,18 @@ void uwb_rc_rm(struct uwb_rc *rc)
        uwb_rc_reset(rc);
 
        rc->stop(rc);
-       uwbd_flush(rc);
+
+       uwbd_stop(rc);
 
        uwb_dev_lock(&rc->uwb_dev);
        rc->priv = NULL;
        rc->cmd = NULL;
        uwb_dev_unlock(&rc->uwb_dev);
-       mutex_lock(&uwb_beca.mutex);
+       mutex_lock(&rc->uwb_beca.mutex);
        uwb_dev_for_each(rc, uwb_dev_offair_helper, NULL);
        __uwb_rc_sys_rm(rc);
-       mutex_unlock(&uwb_beca.mutex);
+       mutex_unlock(&rc->uwb_beca.mutex);
+       uwb_beca_release(rc);
        uwb_dev_rm(&rc->uwb_dev);
 }
 EXPORT_SYMBOL_GPL(uwb_rc_rm);
index 031e8a8..4c24496 100644 (file)
@@ -160,8 +160,8 @@ struct uwb_event {
        };
 };
 
-extern void uwbd_start(void);
-extern void uwbd_stop(void);
+extern void uwbd_start(struct uwb_rc *rc);
+extern void uwbd_stop(struct uwb_rc *rc);
 extern struct uwb_event *uwb_event_alloc(size_t, gfp_t gfp_mask);
 extern void uwbd_event_queue(struct uwb_event *);
 void uwbd_flush(struct uwb_rc *rc);
@@ -194,15 +194,6 @@ int uwbd_evt_handle_rc_dev_addr_conflict(struct uwb_event *evt);
 
 extern unsigned long beacon_timeout_ms;
 
-/** Beacon cache list */
-struct uwb_beca {
-       struct list_head list;
-       size_t entries;
-       struct mutex mutex;
-};
-
-extern struct uwb_beca uwb_beca;
-
 /**
  * Beacon cache entry
  *
@@ -229,9 +220,6 @@ struct uwb_beca_e {
 struct uwb_beacon_frame;
 extern ssize_t uwb_bce_print_IEs(struct uwb_dev *, struct uwb_beca_e *,
                                 char *, size_t);
-extern struct uwb_beca_e *__uwb_beca_add(struct uwb_rc_evt_beacon *,
-                                        struct uwb_beacon_frame *,
-                                        unsigned long);
 
 extern void uwb_bce_kfree(struct kref *_bce);
 static inline void uwb_bce_get(struct uwb_beca_e *bce)
@@ -242,8 +230,8 @@ static inline void uwb_bce_put(struct uwb_beca_e *bce)
 {
        kref_put(&bce->refcnt, uwb_bce_kfree);
 }
-extern void uwb_beca_purge(void);
-extern void uwb_beca_release(void);
+extern void uwb_beca_purge(struct uwb_rc *rc);
+extern void uwb_beca_release(struct uwb_rc *rc);
 
 struct uwb_dev *uwb_dev_get_by_devaddr(struct uwb_rc *rc,
                                       const struct uwb_dev_addr *devaddr);
index f751135..ec42ce9 100644 (file)
@@ -170,8 +170,6 @@ static const struct uwbd_event uwbd_message_handlers[] = {
        },
 };
 
-static DEFINE_MUTEX(uwbd_event_mutex);
-
 /**
  * Handle an URC event passed to the UWB Daemon
  *
@@ -235,19 +233,10 @@ static void uwbd_event_handle_message(struct uwb_event *evt)
                return;
        }
 
-       /* If this is a reset event we need to drop the
-        * uwbd_event_mutex or it deadlocks when the reset handler
-        * attempts to flush the uwbd events. */
-       if (evt->message == UWB_EVT_MSG_RESET)
-               mutex_unlock(&uwbd_event_mutex);
-
        result = uwbd_message_handlers[evt->message].handler(evt);
        if (result < 0)
                dev_err(&rc->uwb_dev.dev, "UWBD: '%s' message failed: %d\n",
                        uwbd_message_handlers[evt->message].name, result);
-
-       if (evt->message == UWB_EVT_MSG_RESET)
-               mutex_lock(&uwbd_event_mutex);
 }
 
 static void uwbd_event_handle(struct uwb_event *evt)
@@ -275,20 +264,6 @@ static void uwbd_event_handle(struct uwb_event *evt)
 
        __uwb_rc_put(rc);       /* for the __uwb_rc_get() in uwb_rc_notif_cb() */
 }
-/* The UWB Daemon */
-
-
-/** Daemon's PID: used to decide if we can queue or not */
-static int uwbd_pid;
-/** Daemon's task struct for managing the kthread */
-static struct task_struct *uwbd_task;
-/** Daemon's waitqueue for waiting for new events */
-static DECLARE_WAIT_QUEUE_HEAD(uwbd_wq);
-/** Daemon's list of events; we queue/dequeue here */
-static struct list_head uwbd_event_list = LIST_HEAD_INIT(uwbd_event_list);
-/** Daemon's list lock to protect concurent access */
-static DEFINE_SPINLOCK(uwbd_event_list_lock);
-
 
 /**
  * UWB Daemon
@@ -302,65 +277,58 @@ static DEFINE_SPINLOCK(uwbd_event_list_lock);
  * FIXME: should change so we don't have a 1HZ timer all the time, but
  *        only if there are devices.
  */
-static int uwbd(void *unused)
+static int uwbd(void *param)
 {
+       struct uwb_rc *rc = param;
        unsigned long flags;
-       struct list_head list = LIST_HEAD_INIT(list);
-       struct uwb_event *evt, *nxt;
+       struct uwb_event *evt;
        int should_stop = 0;
+
        while (1) {
                wait_event_interruptible_timeout(
-                       uwbd_wq,
-                       !list_empty(&uwbd_event_list)
+                       rc->uwbd.wq,
+                       !list_empty(&rc->uwbd.event_list)
                          || (should_stop = kthread_should_stop()),
                        HZ);
                if (should_stop)
                        break;
                try_to_freeze();
 
-               mutex_lock(&uwbd_event_mutex);
-               spin_lock_irqsave(&uwbd_event_list_lock, flags);
-               list_splice_init(&uwbd_event_list, &list);
-               spin_unlock_irqrestore(&uwbd_event_list_lock, flags);
-               list_for_each_entry_safe(evt, nxt, &list, list_node) {
+               spin_lock_irqsave(&rc->uwbd.event_list_lock, flags);
+               if (!list_empty(&rc->uwbd.event_list)) {
+                       evt = list_first_entry(&rc->uwbd.event_list, struct uwb_event, list_node);
                        list_del(&evt->list_node);
+               } else
+                       evt = NULL;
+               spin_unlock_irqrestore(&rc->uwbd.event_list_lock, flags);
+
+               if (evt) {
                        uwbd_event_handle(evt);
                        kfree(evt);
                }
-               mutex_unlock(&uwbd_event_mutex);
 
-               uwb_beca_purge();       /* Purge devices that left */
+               uwb_beca_purge(rc);     /* Purge devices that left */
        }
        return 0;
 }
 
 
 /** Start the UWB daemon */
-void uwbd_start(void)
+void uwbd_start(struct uwb_rc *rc)
 {
-       uwbd_task = kthread_run(uwbd, NULL, "uwbd");
-       if (uwbd_task == NULL)
+       rc->uwbd.task = kthread_run(uwbd, rc, "uwbd");
+       if (rc->uwbd.task == NULL)
                printk(KERN_ERR "UWB: Cannot start management daemon; "
                       "UWB won't work\n");
        else
-               uwbd_pid = uwbd_task->pid;
+               rc->uwbd.pid = rc->uwbd.task->pid;
 }
 
 /* Stop the UWB daemon and free any unprocessed events */
-void uwbd_stop(void)
+void uwbd_stop(struct uwb_rc *rc)
 {
-       unsigned long flags;
-       struct uwb_event *evt, *nxt;
-       kthread_stop(uwbd_task);
-       spin_lock_irqsave(&uwbd_event_list_lock, flags);
-       uwbd_pid = 0;
-       list_for_each_entry_safe(evt, nxt, &uwbd_event_list, list_node) {
-               if (evt->type == UWB_EVT_TYPE_NOTIF)
-                       kfree(evt->notif.rceb);
-               kfree(evt);
-       }
-       spin_unlock_irqrestore(&uwbd_event_list_lock, flags);
-       uwb_beca_release();
+       kthread_stop(rc->uwbd.task);
+       uwbd_flush(rc);
 }
 
 /*
@@ -377,18 +345,20 @@ void uwbd_stop(void)
  */
 void uwbd_event_queue(struct uwb_event *evt)
 {
+       struct uwb_rc *rc = evt->rc;
        unsigned long flags;
-       spin_lock_irqsave(&uwbd_event_list_lock, flags);
-       if (uwbd_pid != 0) {
-               list_add(&evt->list_node, &uwbd_event_list);
-               wake_up_all(&uwbd_wq);
+
+       spin_lock_irqsave(&rc->uwbd.event_list_lock, flags);
+       if (rc->uwbd.pid != 0) {
+               list_add(&evt->list_node, &rc->uwbd.event_list);
+               wake_up_all(&rc->uwbd.wq);
        } else {
                __uwb_rc_put(evt->rc);
                if (evt->type == UWB_EVT_TYPE_NOTIF)
                        kfree(evt->notif.rceb);
                kfree(evt);
        }
-       spin_unlock_irqrestore(&uwbd_event_list_lock, flags);
+       spin_unlock_irqrestore(&rc->uwbd.event_list_lock, flags);
        return;
 }
 
@@ -396,10 +366,8 @@ void uwbd_flush(struct uwb_rc *rc)
 {
        struct uwb_event *evt, *nxt;
 
-       mutex_lock(&uwbd_event_mutex);
-
-       spin_lock_irq(&uwbd_event_list_lock);
-       list_for_each_entry_safe(evt, nxt, &uwbd_event_list, list_node) {
+       spin_lock_irq(&rc->uwbd.event_list_lock);
+       list_for_each_entry_safe(evt, nxt, &rc->uwbd.event_list, list_node) {
                if (evt->rc == rc) {
                        __uwb_rc_put(rc);
                        list_del(&evt->list_node);
@@ -408,7 +376,5 @@ void uwbd_flush(struct uwb_rc *rc)
                        kfree(evt);
                }
        }
-       spin_unlock_irq(&uwbd_event_list_lock);
-
-       mutex_unlock(&uwbd_event_mutex);
+       spin_unlock_irq(&rc->uwbd.event_list_lock);
 }
index 6d93f54..881f0c5 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/device.h>
 #include <linux/mutex.h>
 #include <linux/timer.h>
+#include <linux/wait.h>
 #include <linux/workqueue.h>
 #include <linux/uwb/spec.h>
 
@@ -86,6 +87,22 @@ struct uwb_notifs_chain {
        struct mutex mutex;
 };
 
+/* Beacon cache list */
+struct uwb_beca {
+       struct list_head list;
+       size_t entries;
+       struct mutex mutex;
+};
+
+/* Event handling thread. */
+struct uwbd {
+       int pid;
+       struct task_struct *task;
+       wait_queue_head_t wq;
+       struct list_head event_list;
+       spinlock_t event_list_lock;
+};
+
 /**
  * struct uwb_mas_bm - a bitmap of all MAS in a superframe
  * @bm: a bitmap of length #UWB_NUM_MAS
@@ -342,6 +359,9 @@ struct uwb_rc {
        enum uwb_scan_type scan_type:3;
        unsigned ready:1;
        struct uwb_notifs_chain notifs_chain;
+       struct uwb_beca uwb_beca;
+
+       struct uwbd uwbd;
 
        struct uwb_drp_avail drp_avail;
        struct list_head reservations;