result = __i2400m_dev_start(i2400m, bm_flags);
                if (result >= 0) {
                        i2400m->updown = 1;
-                       wmb();  /* see i2400m->updown's documentation */
+                       i2400m->alive = 1;
+                       wmb();/* see i2400m->updown and i2400m->alive's doc */
                }
        }
        mutex_unlock(&i2400m->init_mutex);
        if (i2400m->updown) {
                __i2400m_dev_stop(i2400m);
                i2400m->updown = 0;
-               wmb();  /* see i2400m->updown's documentation  */
+               i2400m->alive = 0;
+               wmb();  /* see i2400m->updown and i2400m->alive's doc */
        }
        mutex_unlock(&i2400m->init_mutex);
 }
 
        d_fnstart(3, dev, "(ws %p i2400m %p reason %s)\n", ws, i2400m, reason);
 
+       i2400m->boot_mode = 1;
+       wmb();          /* Make sure i2400m_msg_to_dev() sees boot_mode */
+
        result = 0;
        if (mutex_trylock(&i2400m->init_mutex) == 0) {
                /* We are still in i2400m_dev_start() [let it fail] or
                complete(&i2400m->msg_completion);
                goto out;
        }
-       if (i2400m->updown == 0)  {
-               dev_info(dev, "%s: device is down, doing nothing\n", reason);
-               goto out_unlock;
-       }
+
        dev_err(dev, "%s: reinitializing driver\n", reason);
-       __i2400m_dev_stop(i2400m);
-       result = __i2400m_dev_start(i2400m,
-                                   I2400M_BRI_SOFT | I2400M_BRI_MAC_REINIT);
-       if (result < 0) {
+       rmb();
+       if (i2400m->updown) {
+               __i2400m_dev_stop(i2400m);
                i2400m->updown = 0;
                wmb();          /* see i2400m->updown's documentation  */
-               dev_err(dev, "%s: cannot start the device: %d\n",
-                       reason, result);
-               result = -EUCLEAN;
        }
-out_unlock:
+
+       if (i2400m->alive) {
+               result = __i2400m_dev_start(i2400m,
+                                   I2400M_BRI_SOFT | I2400M_BRI_MAC_REINIT);
+               if (result < 0) {
+                       dev_err(dev, "%s: cannot start the device: %d\n",
+                               reason, result);
+                       result = -EUCLEAN;
+                       if (atomic_read(&i2400m->bus_reset_retries)
+                                       >= I2400M_BUS_RESET_RETRIES) {
+                               result = -ENODEV;
+                               dev_err(dev, "tried too many times to "
+                                       "reset the device, giving up\n");
+                       }
+               }
+       }
+
        if (i2400m->reset_ctx) {
                ctx->result = result;
                complete(&ctx->completion);
        }
        mutex_unlock(&i2400m->init_mutex);
        if (result == -EUCLEAN) {
+               /*
+                * We come here because the reset during operational mode
+                * wasn't successully done and need to proceed to a bus
+                * reset. For the dev_reset_handle() to be able to handle
+                * the reset event later properly, we restore boot_mode back
+                * to the state before previous reset. ie: just like we are
+                * issuing the bus reset for the first time
+                */
+               i2400m->boot_mode = 0;
+               wmb();
+
+               atomic_inc(&i2400m->bus_reset_retries);
                /* ops, need to clean up [w/ init_mutex not held] */
                result = i2400m_reset(i2400m, I2400M_RT_BUS);
                if (result >= 0)
                        result = -ENODEV;
+       } else {
+               rmb();
+               if (i2400m->alive) {
+                       /* great, we expect the device state up and
+                        * dev_start() actually brings the device state up */
+                       i2400m->updown = 1;
+                       wmb();
+                       atomic_set(&i2400m->bus_reset_retries, 0);
+               }
        }
 out:
        i2400m_put(i2400m);
  */
 int i2400m_dev_reset_handle(struct i2400m *i2400m, const char *reason)
 {
-       i2400m->boot_mode = 1;
-       wmb();          /* Make sure i2400m_msg_to_dev() sees boot_mode */
        return i2400m_schedule_work(i2400m, __i2400m_dev_reset_handle,
                                    GFP_ATOMIC, &reason, sizeof(reason));
 }
 
        mutex_init(&i2400m->init_mutex);
        /* wake_tx_ws is initialized in i2400m_tx_setup() */
+       atomic_set(&i2400m->bus_reset_retries, 0);
+
+       i2400m->alive = 0;
 }
 EXPORT_SYMBOL_GPL(i2400m_init);
 
 
        I2400M_BM_ACK_BUF_SIZE = 256,
 };
 
+enum {
+       /* Maximum number of bus reset can be retried */
+       I2400M_BUS_RESET_RETRIES = 3,
+};
+
 /**
  * struct i2400m_poke_table - Hardware poke table for the Intel 2400m
  *
  *     same.
  *
  * @pm_notifier: used to register for PM events
+ *
+ * @bus_reset_retries: counter for the number of bus resets attempted for
+ *     this boot. It's not for tracking the number of bus resets during
+ *     the whole driver life cycle (from insmod to rmmod) but for the
+ *     number of dev_start() executed until dev_start() returns a success
+ *     (ie: a good boot means a dev_stop() followed by a successful
+ *     dev_start()). dev_reset_handler() increments this counter whenever
+ *     it is triggering a bus reset. It checks this counter to decide if a
+ *     subsequent bus reset should be retried. dev_reset_handler() retries
+ *     the bus reset until dev_start() succeeds or the counter reaches
+ *     I2400M_BUS_RESET_RETRIES. The counter is cleared to 0 in
+ *     dev_reset_handle() when dev_start() returns a success,
+ *     ie: a successul boot is completed.
+ *
+ * @alive: flag to denote if the device *should* be alive. This flag is
+ *     everything like @updown (see doc for @updown) except reflecting
+ *     the device state *we expect* rather than the actual state as denoted
+ *     by @updown. It is set 1 whenever @updown is set 1 in dev_start().
+ *     Then the device is expected to be alive all the time
+ *     (i2400m->alive remains 1) until the driver is removed. Therefore
+ *     all the device reboot events detected can be still handled properly
+ *     by either dev_reset_handle() or .pre_reset/.post_reset as long as
+ *     the driver presents. It is set 0 along with @updown in dev_stop().
  */
 struct i2400m {
        struct wimax_dev wimax_dev;     /* FIRST! See doc */
        struct i2400m_barker_db *barker;
 
        struct notifier_block pm_notifier;
+
+       /* counting bus reset retries in this boot */
+       atomic_t bus_reset_retries;
+
+       /* if the device is expected to be alive */
+       unsigned alive;
 };