aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wimax/i2400m/driver.c68
-rw-r--r--drivers/net/wimax/i2400m/i2400m.h34
2 files changed, 86 insertions, 16 deletions
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index 3a6c8ddb5353..1674dba43f83 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -436,7 +436,8 @@ int i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri bm_flags)
436 result = __i2400m_dev_start(i2400m, bm_flags); 436 result = __i2400m_dev_start(i2400m, bm_flags);
437 if (result >= 0) { 437 if (result >= 0) {
438 i2400m->updown = 1; 438 i2400m->updown = 1;
439 wmb(); /* see i2400m->updown's documentation */ 439 i2400m->alive = 1;
440 wmb();/* see i2400m->updown and i2400m->alive's doc */
440 } 441 }
441 } 442 }
442 mutex_unlock(&i2400m->init_mutex); 443 mutex_unlock(&i2400m->init_mutex);
@@ -497,7 +498,8 @@ void i2400m_dev_stop(struct i2400m *i2400m)
497 if (i2400m->updown) { 498 if (i2400m->updown) {
498 __i2400m_dev_stop(i2400m); 499 __i2400m_dev_stop(i2400m);
499 i2400m->updown = 0; 500 i2400m->updown = 0;
500 wmb(); /* see i2400m->updown's documentation */ 501 i2400m->alive = 0;
502 wmb(); /* see i2400m->updown and i2400m->alive's doc */
501 } 503 }
502 mutex_unlock(&i2400m->init_mutex); 504 mutex_unlock(&i2400m->init_mutex);
503} 505}
@@ -669,6 +671,9 @@ void __i2400m_dev_reset_handle(struct work_struct *ws)
669 671
670 d_fnstart(3, dev, "(ws %p i2400m %p reason %s)\n", ws, i2400m, reason); 672 d_fnstart(3, dev, "(ws %p i2400m %p reason %s)\n", ws, i2400m, reason);
671 673
674 i2400m->boot_mode = 1;
675 wmb(); /* Make sure i2400m_msg_to_dev() sees boot_mode */
676
672 result = 0; 677 result = 0;
673 if (mutex_trylock(&i2400m->init_mutex) == 0) { 678 if (mutex_trylock(&i2400m->init_mutex) == 0) {
674 /* We are still in i2400m_dev_start() [let it fail] or 679 /* We are still in i2400m_dev_start() [let it fail] or
@@ -679,32 +684,62 @@ void __i2400m_dev_reset_handle(struct work_struct *ws)
679 complete(&i2400m->msg_completion); 684 complete(&i2400m->msg_completion);
680 goto out; 685 goto out;
681 } 686 }
682 if (i2400m->updown == 0) { 687
683 dev_info(dev, "%s: device is down, doing nothing\n", reason);
684 goto out_unlock;
685 }
686 dev_err(dev, "%s: reinitializing driver\n", reason); 688 dev_err(dev, "%s: reinitializing driver\n", reason);
687 __i2400m_dev_stop(i2400m); 689 rmb();
688 result = __i2400m_dev_start(i2400m, 690 if (i2400m->updown) {
689 I2400M_BRI_SOFT | I2400M_BRI_MAC_REINIT); 691 __i2400m_dev_stop(i2400m);
690 if (result < 0) {
691 i2400m->updown = 0; 692 i2400m->updown = 0;
692 wmb(); /* see i2400m->updown's documentation */ 693 wmb(); /* see i2400m->updown's documentation */
693 dev_err(dev, "%s: cannot start the device: %d\n",
694 reason, result);
695 result = -EUCLEAN;
696 } 694 }
697out_unlock: 695
696 if (i2400m->alive) {
697 result = __i2400m_dev_start(i2400m,
698 I2400M_BRI_SOFT | I2400M_BRI_MAC_REINIT);
699 if (result < 0) {
700 dev_err(dev, "%s: cannot start the device: %d\n",
701 reason, result);
702 result = -EUCLEAN;
703 if (atomic_read(&i2400m->bus_reset_retries)
704 >= I2400M_BUS_RESET_RETRIES) {
705 result = -ENODEV;
706 dev_err(dev, "tried too many times to "
707 "reset the device, giving up\n");
708 }
709 }
710 }
711
698 if (i2400m->reset_ctx) { 712 if (i2400m->reset_ctx) {
699 ctx->result = result; 713 ctx->result = result;
700 complete(&ctx->completion); 714 complete(&ctx->completion);
701 } 715 }
702 mutex_unlock(&i2400m->init_mutex); 716 mutex_unlock(&i2400m->init_mutex);
703 if (result == -EUCLEAN) { 717 if (result == -EUCLEAN) {
718 /*
719 * We come here because the reset during operational mode
720 * wasn't successully done and need to proceed to a bus
721 * reset. For the dev_reset_handle() to be able to handle
722 * the reset event later properly, we restore boot_mode back
723 * to the state before previous reset. ie: just like we are
724 * issuing the bus reset for the first time
725 */
726 i2400m->boot_mode = 0;
727 wmb();
728
729 atomic_inc(&i2400m->bus_reset_retries);
704 /* ops, need to clean up [w/ init_mutex not held] */ 730 /* ops, need to clean up [w/ init_mutex not held] */
705 result = i2400m_reset(i2400m, I2400M_RT_BUS); 731 result = i2400m_reset(i2400m, I2400M_RT_BUS);
706 if (result >= 0) 732 if (result >= 0)
707 result = -ENODEV; 733 result = -ENODEV;
734 } else {
735 rmb();
736 if (i2400m->alive) {
737 /* great, we expect the device state up and
738 * dev_start() actually brings the device state up */
739 i2400m->updown = 1;
740 wmb();
741 atomic_set(&i2400m->bus_reset_retries, 0);
742 }
708 } 743 }
709out: 744out:
710 i2400m_put(i2400m); 745 i2400m_put(i2400m);
@@ -729,8 +764,6 @@ out:
729 */ 764 */
730int i2400m_dev_reset_handle(struct i2400m *i2400m, const char *reason) 765int i2400m_dev_reset_handle(struct i2400m *i2400m, const char *reason)
731{ 766{
732 i2400m->boot_mode = 1;
733 wmb(); /* Make sure i2400m_msg_to_dev() sees boot_mode */
734 return i2400m_schedule_work(i2400m, __i2400m_dev_reset_handle, 767 return i2400m_schedule_work(i2400m, __i2400m_dev_reset_handle,
735 GFP_ATOMIC, &reason, sizeof(reason)); 768 GFP_ATOMIC, &reason, sizeof(reason));
736} 769}
@@ -803,6 +836,9 @@ void i2400m_init(struct i2400m *i2400m)
803 836
804 mutex_init(&i2400m->init_mutex); 837 mutex_init(&i2400m->init_mutex);
805 /* wake_tx_ws is initialized in i2400m_tx_setup() */ 838 /* wake_tx_ws is initialized in i2400m_tx_setup() */
839 atomic_set(&i2400m->bus_reset_retries, 0);
840
841 i2400m->alive = 0;
806} 842}
807EXPORT_SYMBOL_GPL(i2400m_init); 843EXPORT_SYMBOL_GPL(i2400m_init);
808 844
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h
index da218b98e27f..ad8e6a3be1e3 100644
--- a/drivers/net/wimax/i2400m/i2400m.h
+++ b/drivers/net/wimax/i2400m/i2400m.h
@@ -177,6 +177,11 @@ enum {
177 I2400M_BM_ACK_BUF_SIZE = 256, 177 I2400M_BM_ACK_BUF_SIZE = 256,
178}; 178};
179 179
180enum {
181 /* Maximum number of bus reset can be retried */
182 I2400M_BUS_RESET_RETRIES = 3,
183};
184
180/** 185/**
181 * struct i2400m_poke_table - Hardware poke table for the Intel 2400m 186 * struct i2400m_poke_table - Hardware poke table for the Intel 2400m
182 * 187 *
@@ -517,6 +522,29 @@ struct i2400m_barker_db;
517 * same. 522 * same.
518 * 523 *
519 * @pm_notifier: used to register for PM events 524 * @pm_notifier: used to register for PM events
525 *
526 * @bus_reset_retries: counter for the number of bus resets attempted for
527 * this boot. It's not for tracking the number of bus resets during
528 * the whole driver life cycle (from insmod to rmmod) but for the
529 * number of dev_start() executed until dev_start() returns a success
530 * (ie: a good boot means a dev_stop() followed by a successful
531 * dev_start()). dev_reset_handler() increments this counter whenever
532 * it is triggering a bus reset. It checks this counter to decide if a
533 * subsequent bus reset should be retried. dev_reset_handler() retries
534 * the bus reset until dev_start() succeeds or the counter reaches
535 * I2400M_BUS_RESET_RETRIES. The counter is cleared to 0 in
536 * dev_reset_handle() when dev_start() returns a success,
537 * ie: a successul boot is completed.
538 *
539 * @alive: flag to denote if the device *should* be alive. This flag is
540 * everything like @updown (see doc for @updown) except reflecting
541 * the device state *we expect* rather than the actual state as denoted
542 * by @updown. It is set 1 whenever @updown is set 1 in dev_start().
543 * Then the device is expected to be alive all the time
544 * (i2400m->alive remains 1) until the driver is removed. Therefore
545 * all the device reboot events detected can be still handled properly
546 * by either dev_reset_handle() or .pre_reset/.post_reset as long as
547 * the driver presents. It is set 0 along with @updown in dev_stop().
520 */ 548 */
521struct i2400m { 549struct i2400m {
522 struct wimax_dev wimax_dev; /* FIRST! See doc */ 550 struct wimax_dev wimax_dev; /* FIRST! See doc */
@@ -591,6 +619,12 @@ struct i2400m {
591 struct i2400m_barker_db *barker; 619 struct i2400m_barker_db *barker;
592 620
593 struct notifier_block pm_notifier; 621 struct notifier_block pm_notifier;
622
623 /* counting bus reset retries in this boot */
624 atomic_t bus_reset_retries;
625
626 /* if the device is expected to be alive */
627 unsigned alive;
594}; 628};
595 629
596 630