diff options
author | Stefano Panella <stefano.panella@csr.com> | 2008-11-04 10:39:08 -0500 |
---|---|---|
committer | David Vrabel <david.vrabel@csr.com> | 2008-11-04 10:55:26 -0500 |
commit | fec1a5932f16c0eb1b3f5ca2e18d81d860924088 (patch) | |
tree | 48836158dbd458bb462b18f4deffa89e9db80376 /drivers/uwb/uwbd.c | |
parent | 6d5a681dfb583b2f1eefe7cd5505419ca2d4d6c8 (diff) |
uwb: per-radio controller event thread and beacon cache
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>
Diffstat (limited to 'drivers/uwb/uwbd.c')
-rw-r--r-- | drivers/uwb/uwbd.c | 98 |
1 files changed, 32 insertions, 66 deletions
diff --git a/drivers/uwb/uwbd.c b/drivers/uwb/uwbd.c index f75113571f4a..ec42ce92dbce 100644 --- a/drivers/uwb/uwbd.c +++ b/drivers/uwb/uwbd.c | |||
@@ -170,8 +170,6 @@ static const struct uwbd_event uwbd_message_handlers[] = { | |||
170 | }, | 170 | }, |
171 | }; | 171 | }; |
172 | 172 | ||
173 | static DEFINE_MUTEX(uwbd_event_mutex); | ||
174 | |||
175 | /** | 173 | /** |
176 | * Handle an URC event passed to the UWB Daemon | 174 | * Handle an URC event passed to the UWB Daemon |
177 | * | 175 | * |
@@ -235,19 +233,10 @@ static void uwbd_event_handle_message(struct uwb_event *evt) | |||
235 | return; | 233 | return; |
236 | } | 234 | } |
237 | 235 | ||
238 | /* If this is a reset event we need to drop the | ||
239 | * uwbd_event_mutex or it deadlocks when the reset handler | ||
240 | * attempts to flush the uwbd events. */ | ||
241 | if (evt->message == UWB_EVT_MSG_RESET) | ||
242 | mutex_unlock(&uwbd_event_mutex); | ||
243 | |||
244 | result = uwbd_message_handlers[evt->message].handler(evt); | 236 | result = uwbd_message_handlers[evt->message].handler(evt); |
245 | if (result < 0) | 237 | if (result < 0) |
246 | dev_err(&rc->uwb_dev.dev, "UWBD: '%s' message failed: %d\n", | 238 | dev_err(&rc->uwb_dev.dev, "UWBD: '%s' message failed: %d\n", |
247 | uwbd_message_handlers[evt->message].name, result); | 239 | uwbd_message_handlers[evt->message].name, result); |
248 | |||
249 | if (evt->message == UWB_EVT_MSG_RESET) | ||
250 | mutex_lock(&uwbd_event_mutex); | ||
251 | } | 240 | } |
252 | 241 | ||
253 | static void uwbd_event_handle(struct uwb_event *evt) | 242 | static void uwbd_event_handle(struct uwb_event *evt) |
@@ -275,20 +264,6 @@ static void uwbd_event_handle(struct uwb_event *evt) | |||
275 | 264 | ||
276 | __uwb_rc_put(rc); /* for the __uwb_rc_get() in uwb_rc_notif_cb() */ | 265 | __uwb_rc_put(rc); /* for the __uwb_rc_get() in uwb_rc_notif_cb() */ |
277 | } | 266 | } |
278 | /* The UWB Daemon */ | ||
279 | |||
280 | |||
281 | /** Daemon's PID: used to decide if we can queue or not */ | ||
282 | static int uwbd_pid; | ||
283 | /** Daemon's task struct for managing the kthread */ | ||
284 | static struct task_struct *uwbd_task; | ||
285 | /** Daemon's waitqueue for waiting for new events */ | ||
286 | static DECLARE_WAIT_QUEUE_HEAD(uwbd_wq); | ||
287 | /** Daemon's list of events; we queue/dequeue here */ | ||
288 | static struct list_head uwbd_event_list = LIST_HEAD_INIT(uwbd_event_list); | ||
289 | /** Daemon's list lock to protect concurent access */ | ||
290 | static DEFINE_SPINLOCK(uwbd_event_list_lock); | ||
291 | |||
292 | 267 | ||
293 | /** | 268 | /** |
294 | * UWB Daemon | 269 | * UWB Daemon |
@@ -302,65 +277,58 @@ static DEFINE_SPINLOCK(uwbd_event_list_lock); | |||
302 | * FIXME: should change so we don't have a 1HZ timer all the time, but | 277 | * FIXME: should change so we don't have a 1HZ timer all the time, but |
303 | * only if there are devices. | 278 | * only if there are devices. |
304 | */ | 279 | */ |
305 | static int uwbd(void *unused) | 280 | static int uwbd(void *param) |
306 | { | 281 | { |
282 | struct uwb_rc *rc = param; | ||
307 | unsigned long flags; | 283 | unsigned long flags; |
308 | struct list_head list = LIST_HEAD_INIT(list); | 284 | struct uwb_event *evt; |
309 | struct uwb_event *evt, *nxt; | ||
310 | int should_stop = 0; | 285 | int should_stop = 0; |
286 | |||
311 | while (1) { | 287 | while (1) { |
312 | wait_event_interruptible_timeout( | 288 | wait_event_interruptible_timeout( |
313 | uwbd_wq, | 289 | rc->uwbd.wq, |
314 | !list_empty(&uwbd_event_list) | 290 | !list_empty(&rc->uwbd.event_list) |
315 | || (should_stop = kthread_should_stop()), | 291 | || (should_stop = kthread_should_stop()), |
316 | HZ); | 292 | HZ); |
317 | if (should_stop) | 293 | if (should_stop) |
318 | break; | 294 | break; |
319 | try_to_freeze(); | 295 | try_to_freeze(); |
320 | 296 | ||
321 | mutex_lock(&uwbd_event_mutex); | 297 | spin_lock_irqsave(&rc->uwbd.event_list_lock, flags); |
322 | spin_lock_irqsave(&uwbd_event_list_lock, flags); | 298 | if (!list_empty(&rc->uwbd.event_list)) { |
323 | list_splice_init(&uwbd_event_list, &list); | 299 | evt = list_first_entry(&rc->uwbd.event_list, struct uwb_event, list_node); |
324 | spin_unlock_irqrestore(&uwbd_event_list_lock, flags); | ||
325 | list_for_each_entry_safe(evt, nxt, &list, list_node) { | ||
326 | list_del(&evt->list_node); | 300 | list_del(&evt->list_node); |
301 | } else | ||
302 | evt = NULL; | ||
303 | spin_unlock_irqrestore(&rc->uwbd.event_list_lock, flags); | ||
304 | |||
305 | if (evt) { | ||
327 | uwbd_event_handle(evt); | 306 | uwbd_event_handle(evt); |
328 | kfree(evt); | 307 | kfree(evt); |
329 | } | 308 | } |
330 | mutex_unlock(&uwbd_event_mutex); | ||
331 | 309 | ||
332 | uwb_beca_purge(); /* Purge devices that left */ | 310 | uwb_beca_purge(rc); /* Purge devices that left */ |
333 | } | 311 | } |
334 | return 0; | 312 | return 0; |
335 | } | 313 | } |
336 | 314 | ||
337 | 315 | ||
338 | /** Start the UWB daemon */ | 316 | /** Start the UWB daemon */ |
339 | void uwbd_start(void) | 317 | void uwbd_start(struct uwb_rc *rc) |
340 | { | 318 | { |
341 | uwbd_task = kthread_run(uwbd, NULL, "uwbd"); | 319 | rc->uwbd.task = kthread_run(uwbd, rc, "uwbd"); |
342 | if (uwbd_task == NULL) | 320 | if (rc->uwbd.task == NULL) |
343 | printk(KERN_ERR "UWB: Cannot start management daemon; " | 321 | printk(KERN_ERR "UWB: Cannot start management daemon; " |
344 | "UWB won't work\n"); | 322 | "UWB won't work\n"); |
345 | else | 323 | else |
346 | uwbd_pid = uwbd_task->pid; | 324 | rc->uwbd.pid = rc->uwbd.task->pid; |
347 | } | 325 | } |
348 | 326 | ||
349 | /* Stop the UWB daemon and free any unprocessed events */ | 327 | /* Stop the UWB daemon and free any unprocessed events */ |
350 | void uwbd_stop(void) | 328 | void uwbd_stop(struct uwb_rc *rc) |
351 | { | 329 | { |
352 | unsigned long flags; | 330 | kthread_stop(rc->uwbd.task); |
353 | struct uwb_event *evt, *nxt; | 331 | uwbd_flush(rc); |
354 | kthread_stop(uwbd_task); | ||
355 | spin_lock_irqsave(&uwbd_event_list_lock, flags); | ||
356 | uwbd_pid = 0; | ||
357 | list_for_each_entry_safe(evt, nxt, &uwbd_event_list, list_node) { | ||
358 | if (evt->type == UWB_EVT_TYPE_NOTIF) | ||
359 | kfree(evt->notif.rceb); | ||
360 | kfree(evt); | ||
361 | } | ||
362 | spin_unlock_irqrestore(&uwbd_event_list_lock, flags); | ||
363 | uwb_beca_release(); | ||
364 | } | 332 | } |
365 | 333 | ||
366 | /* | 334 | /* |
@@ -377,18 +345,20 @@ void uwbd_stop(void) | |||
377 | */ | 345 | */ |
378 | void uwbd_event_queue(struct uwb_event *evt) | 346 | void uwbd_event_queue(struct uwb_event *evt) |
379 | { | 347 | { |
348 | struct uwb_rc *rc = evt->rc; | ||
380 | unsigned long flags; | 349 | unsigned long flags; |
381 | spin_lock_irqsave(&uwbd_event_list_lock, flags); | 350 | |
382 | if (uwbd_pid != 0) { | 351 | spin_lock_irqsave(&rc->uwbd.event_list_lock, flags); |
383 | list_add(&evt->list_node, &uwbd_event_list); | 352 | if (rc->uwbd.pid != 0) { |
384 | wake_up_all(&uwbd_wq); | 353 | list_add(&evt->list_node, &rc->uwbd.event_list); |
354 | wake_up_all(&rc->uwbd.wq); | ||
385 | } else { | 355 | } else { |
386 | __uwb_rc_put(evt->rc); | 356 | __uwb_rc_put(evt->rc); |
387 | if (evt->type == UWB_EVT_TYPE_NOTIF) | 357 | if (evt->type == UWB_EVT_TYPE_NOTIF) |
388 | kfree(evt->notif.rceb); | 358 | kfree(evt->notif.rceb); |
389 | kfree(evt); | 359 | kfree(evt); |
390 | } | 360 | } |
391 | spin_unlock_irqrestore(&uwbd_event_list_lock, flags); | 361 | spin_unlock_irqrestore(&rc->uwbd.event_list_lock, flags); |
392 | return; | 362 | return; |
393 | } | 363 | } |
394 | 364 | ||
@@ -396,10 +366,8 @@ void uwbd_flush(struct uwb_rc *rc) | |||
396 | { | 366 | { |
397 | struct uwb_event *evt, *nxt; | 367 | struct uwb_event *evt, *nxt; |
398 | 368 | ||
399 | mutex_lock(&uwbd_event_mutex); | 369 | spin_lock_irq(&rc->uwbd.event_list_lock); |
400 | 370 | list_for_each_entry_safe(evt, nxt, &rc->uwbd.event_list, list_node) { | |
401 | spin_lock_irq(&uwbd_event_list_lock); | ||
402 | list_for_each_entry_safe(evt, nxt, &uwbd_event_list, list_node) { | ||
403 | if (evt->rc == rc) { | 371 | if (evt->rc == rc) { |
404 | __uwb_rc_put(rc); | 372 | __uwb_rc_put(rc); |
405 | list_del(&evt->list_node); | 373 | list_del(&evt->list_node); |
@@ -408,7 +376,5 @@ void uwbd_flush(struct uwb_rc *rc) | |||
408 | kfree(evt); | 376 | kfree(evt); |
409 | } | 377 | } |
410 | } | 378 | } |
411 | spin_unlock_irq(&uwbd_event_list_lock); | 379 | spin_unlock_irq(&rc->uwbd.event_list_lock); |
412 | |||
413 | mutex_unlock(&uwbd_event_mutex); | ||
414 | } | 380 | } |