aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wimax/i2400m/driver.c
diff options
context:
space:
mode:
authorInaky Perez-Gonzalez <inaky@linux.intel.com>2009-09-16 20:10:55 -0400
committerInaky Perez-Gonzalez <inaky@linux.intel.com>2009-10-19 02:56:07 -0400
commitc2315b4ea9ac9c3f8caf03c3511d86fabe4a5fcd (patch)
tree17e2d15abfd26fa83f8a9654bf581f6d40fc8c33 /drivers/net/wimax/i2400m/driver.c
parent8f90f3ee83dc54e182d6a7548727cbae4b523e6e (diff)
wimax/i2400m: clarify and fix i2400m->{ready,updown}
The i2400m driver uses two different bits to distinguish how much the driver is up. i2400m->ready is used to denote that the infrastructure to communicate with the device is up and running. i2400m->updown is used to indicate if 'ready' and the device is up and running, ready to take control and data traffic. However, all this was pretty dirty and not clear, with many open spots where race conditions were present. This commit cleans up the situation by: - documenting the usage of both bits - setting them only in specific, well controlled places (i2400m_dev_start, i2400m_dev_stop) - ensuring the i2400m workqueue can't get in the middle of the setting by flushing it when i2400m->ready is set to zero. This allows the report hook not having to check again for the bit to be set [rx.c:i2400m_report_hook_work()]. - using i2400m->updown to determine if the device is up and running instead of the wimax state in i2400m_dev_reset_handle(). - not loosing missed messages sent by the hardware before i2400m->ready is set. In rx.c, whatever the device sends can be sent to user space over the message pipes as soon as the wimax device is registered, so don't wait for i2400m->ready to be set. Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
Diffstat (limited to 'drivers/net/wimax/i2400m/driver.c')
-rw-r--r--drivers/net/wimax/i2400m/driver.c44
1 files changed, 29 insertions, 15 deletions
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index a0ae19966c0c..6280646d7d7f 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -455,6 +455,8 @@ retry:
455 result = i2400m->bus_dev_start(i2400m); 455 result = i2400m->bus_dev_start(i2400m);
456 if (result < 0) 456 if (result < 0)
457 goto error_bus_dev_start; 457 goto error_bus_dev_start;
458 i2400m->ready = 1;
459 wmb(); /* see i2400m->ready's documentation */
458 result = i2400m_firmware_check(i2400m); /* fw versions ok? */ 460 result = i2400m_firmware_check(i2400m); /* fw versions ok? */
459 if (result < 0) 461 if (result < 0)
460 goto error_fw_check; 462 goto error_fw_check;
@@ -462,7 +464,6 @@ retry:
462 result = i2400m_check_mac_addr(i2400m); 464 result = i2400m_check_mac_addr(i2400m);
463 if (result < 0) 465 if (result < 0)
464 goto error_check_mac_addr; 466 goto error_check_mac_addr;
465 i2400m->ready = 1;
466 wimax_state_change(wimax_dev, WIMAX_ST_UNINITIALIZED); 467 wimax_state_change(wimax_dev, WIMAX_ST_UNINITIALIZED);
467 result = i2400m_dev_initialize(i2400m); 468 result = i2400m_dev_initialize(i2400m);
468 if (result < 0) 469 if (result < 0)
@@ -475,6 +476,9 @@ retry:
475 476
476error_dev_initialize: 477error_dev_initialize:
477error_check_mac_addr: 478error_check_mac_addr:
479 i2400m->ready = 0;
480 wmb(); /* see i2400m->ready's documentation */
481 flush_workqueue(i2400m->work_queue);
478error_fw_check: 482error_fw_check:
479 i2400m->bus_dev_stop(i2400m); 483 i2400m->bus_dev_stop(i2400m);
480error_bus_dev_start: 484error_bus_dev_start:
@@ -498,11 +502,15 @@ error_bootstrap:
498static 502static
499int i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri bm_flags) 503int i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri bm_flags)
500{ 504{
501 int result; 505 int result = 0;
502 mutex_lock(&i2400m->init_mutex); /* Well, start the device */ 506 mutex_lock(&i2400m->init_mutex); /* Well, start the device */
503 result = __i2400m_dev_start(i2400m, bm_flags); 507 if (i2400m->updown == 0) {
504 if (result >= 0) 508 result = __i2400m_dev_start(i2400m, bm_flags);
505 i2400m->updown = 1; 509 if (result >= 0) {
510 i2400m->updown = 1;
511 wmb(); /* see i2400m->updown's documentation */
512 }
513 }
506 mutex_unlock(&i2400m->init_mutex); 514 mutex_unlock(&i2400m->init_mutex);
507 return result; 515 return result;
508} 516}
@@ -529,7 +537,14 @@ void __i2400m_dev_stop(struct i2400m *i2400m)
529 wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING); 537 wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING);
530 i2400m_net_wake_stop(i2400m); 538 i2400m_net_wake_stop(i2400m);
531 i2400m_dev_shutdown(i2400m); 539 i2400m_dev_shutdown(i2400m);
532 i2400m->ready = 0; 540 /*
541 * Make sure no report hooks are running *before* we stop the
542 * communication infrastructure with the device.
543 */
544 i2400m->ready = 0; /* nobody can queue work anymore */
545 wmb(); /* see i2400m->ready's documentation */
546 flush_workqueue(i2400m->work_queue);
547
533 i2400m->bus_dev_stop(i2400m); 548 i2400m->bus_dev_stop(i2400m);
534 destroy_workqueue(i2400m->work_queue); 549 destroy_workqueue(i2400m->work_queue);
535 i2400m_rx_release(i2400m); 550 i2400m_rx_release(i2400m);
@@ -551,6 +566,7 @@ void i2400m_dev_stop(struct i2400m *i2400m)
551 if (i2400m->updown) { 566 if (i2400m->updown) {
552 __i2400m_dev_stop(i2400m); 567 __i2400m_dev_stop(i2400m);
553 i2400m->updown = 0; 568 i2400m->updown = 0;
569 wmb(); /* see i2400m->updown's documentation */
554 } 570 }
555 mutex_unlock(&i2400m->init_mutex); 571 mutex_unlock(&i2400m->init_mutex);
556} 572}
@@ -632,7 +648,6 @@ void __i2400m_dev_reset_handle(struct work_struct *ws)
632 const char *reason; 648 const char *reason;
633 struct i2400m *i2400m = iw->i2400m; 649 struct i2400m *i2400m = iw->i2400m;
634 struct device *dev = i2400m_dev(i2400m); 650 struct device *dev = i2400m_dev(i2400m);
635 enum wimax_st wimax_state;
636 struct i2400m_reset_ctx *ctx = i2400m->reset_ctx; 651 struct i2400m_reset_ctx *ctx = i2400m->reset_ctx;
637 652
638 if (WARN_ON(iw->pl_size != sizeof(reason))) 653 if (WARN_ON(iw->pl_size != sizeof(reason)))
@@ -647,29 +662,28 @@ void __i2400m_dev_reset_handle(struct work_struct *ws)
647 /* We are still in i2400m_dev_start() [let it fail] or 662 /* We are still in i2400m_dev_start() [let it fail] or
648 * i2400m_dev_stop() [we are shutting down anyway, so 663 * i2400m_dev_stop() [we are shutting down anyway, so
649 * ignore it] or we are resetting somewhere else. */ 664 * ignore it] or we are resetting somewhere else. */
650 dev_err(dev, "device rebooted\n"); 665 dev_err(dev, "device rebooted somewhere else?\n");
651 i2400m_msg_to_dev_cancel_wait(i2400m, -EL3RST); 666 i2400m_msg_to_dev_cancel_wait(i2400m, -EL3RST);
652 complete(&i2400m->msg_completion); 667 complete(&i2400m->msg_completion);
653 goto out; 668 goto out;
654 } 669 }
655 wimax_state = wimax_state_get(&i2400m->wimax_dev); 670 if (i2400m->updown == 0) {
656 if (wimax_state < WIMAX_ST_UNINITIALIZED) { 671 dev_info(dev, "%s: device is down, doing nothing\n", reason);
657 dev_info(dev, "%s: it is down, ignoring\n", reason); 672 goto out_unlock;
658 goto out_unlock; /* ifconfig up/down wasn't called */
659 } 673 }
660 dev_err(dev, "%s: reinitializing driver\n", reason); 674 dev_err(dev, "%s: reinitializing driver\n", reason);
661 __i2400m_dev_stop(i2400m); 675 __i2400m_dev_stop(i2400m);
662 i2400m->updown = 0;
663 result = __i2400m_dev_start(i2400m, 676 result = __i2400m_dev_start(i2400m,
664 I2400M_BRI_SOFT | I2400M_BRI_MAC_REINIT); 677 I2400M_BRI_SOFT | I2400M_BRI_MAC_REINIT);
665 if (result < 0) { 678 if (result < 0) {
679 i2400m->updown = 0;
680 wmb(); /* see i2400m->updown's documentation */
666 dev_err(dev, "%s: cannot start the device: %d\n", 681 dev_err(dev, "%s: cannot start the device: %d\n",
667 reason, result); 682 reason, result);
668 result = i2400m->bus_reset(i2400m, I2400M_RT_BUS); 683 result = i2400m->bus_reset(i2400m, I2400M_RT_BUS);
669 if (result >= 0) 684 if (result >= 0)
670 result = -ENODEV; 685 result = -ENODEV;
671 } else 686 }
672 i2400m->updown = 1;
673out_unlock: 687out_unlock:
674 if (i2400m->reset_ctx) { 688 if (i2400m->reset_ctx) {
675 ctx->result = result; 689 ctx->result = result;