iwlwifi: uCode Alive notification with timeout
authorWey-Yi Guy <wey-yi.w.guy@intel.com>
Fri, 17 Jul 2009 16:30:23 +0000 (09:30 -0700)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 24 Jul 2009 19:05:25 +0000 (15:05 -0400)
Wait for REPLY_ALIVE notification from init and runtime uCode.
based on the type of REPLY_ALIVE, different status bit will be set to
wake up the queue:
STATUS_INIT_UCODE_ALIVE for init uCode
STATUS_RT_UCODE_ALIVE for runtime uCode.

If timeout, attempt to download the failing uCode image again. This can
only be done for the init ucode images of all iwlagn devices and the
runtime ucode image of the 5000 series and up. If there is a problem
with the 4965 runtime ucode coming up we restart the interface and thus
trigger a new download of the init ucode also.

Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/iwlwifi/iwl-4965.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-dev.h

index f4eb683aa2d5f1d26ce519534f686e7905988ff3..272409c806198740f8e76c9d0607020d553b8d3f 100644 (file)
@@ -146,7 +146,7 @@ static int iwl4965_load_bsm(struct iwl_priv *priv)
 
        IWL_DEBUG_INFO(priv, "Begin load bsm\n");
 
-       priv->ucode_type = UCODE_RT;
+       priv->ucode_type = UCODE_INIT;
 
        /* make sure bootstrap program is no larger than BSM's SRAM size */
        if (len > IWL49_MAX_BSM_SIZE)
@@ -256,6 +256,8 @@ static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv)
 */
 static void iwl4965_init_alive_start(struct iwl_priv *priv)
 {
+       int ret;
+
        /* Check alive response for "valid" sign from uCode */
        if (priv->card_alive_init.is_valid != UCODE_VALID_OK) {
                /* We had an error bringing up the hardware, so take it
@@ -287,6 +289,28 @@ static void iwl4965_init_alive_start(struct iwl_priv *priv)
                IWL_DEBUG_INFO(priv, "Couldn't set up uCode pointers.\n");
                goto restart;
        }
+       priv->ucode_type = UCODE_RT;
+       if (test_bit(STATUS_RT_UCODE_ALIVE, &priv->status)) {
+               IWL_WARN(priv, "Runtime uCode already alive? "
+                       "Waiting for alive anyway\n");
+               clear_bit(STATUS_RT_UCODE_ALIVE, &priv->status);
+       }
+       ret = wait_event_interruptible_timeout(
+                       priv->wait_command_queue,
+                       test_bit(STATUS_RT_UCODE_ALIVE, &priv->status),
+                       UCODE_ALIVE_TIMEOUT);
+       if (!ret) {
+               /* FIXME: if STATUS_RT_UCODE_ALIVE timeout
+                * go back to restart the download Init uCode again
+                * this might cause to trap in the restart loop
+                */
+               priv->ucode_type = UCODE_NONE;
+               if (!test_bit(STATUS_RT_UCODE_ALIVE, &priv->status)) {
+                       IWL_ERR(priv, "Runtime timeout after %dms\n",
+                               jiffies_to_msecs(UCODE_ALIVE_TIMEOUT));
+                       goto restart;
+               }
+       }
        return;
 
 restart:
index 6b874dab412032d155524cb822cda1e93b373280..f61f653a1b7240b4936f5cb2543df1165f19d457 100644 (file)
@@ -533,12 +533,16 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv,
 
        if (palive->ver_subtype == INITIALIZE_SUBTYPE) {
                IWL_DEBUG_INFO(priv, "Initialization Alive received.\n");
+               set_bit(STATUS_INIT_UCODE_ALIVE, &priv->status);
+               wake_up_interruptible(&priv->wait_command_queue);
                memcpy(&priv->card_alive_init,
                       &pkt->u.alive_frame,
                       sizeof(struct iwl_init_alive_resp));
                pwork = &priv->init_alive_start;
        } else {
                IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
+               set_bit(STATUS_RT_UCODE_ALIVE, &priv->status);
+               wake_up_interruptible(&priv->wait_command_queue);
                memcpy(&priv->card_alive, &pkt->u.alive_frame,
                       sizeof(struct iwl_alive_resp));
                pwork = &priv->alive_start;
@@ -1782,6 +1786,7 @@ static int __iwl_up(struct iwl_priv *priv)
 {
        int i;
        int ret;
+       unsigned long status;
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
                IWL_WARN(priv, "Exit pending; will not bring the NIC up\n");
@@ -1859,6 +1864,51 @@ static int __iwl_up(struct iwl_priv *priv)
                /* start card; "initialize" will load runtime ucode */
                iwl_nic_start(priv);
 
+               /* Just finish download Init or Runtime uCode image to device
+                * now we wait here for uCode send REPLY_ALIVE notification
+                * to indicate uCode is ready.
+                * 1) For Init uCode image, all iwlagn devices should wait here
+                * on STATUS_INIT_UCODE_ALIVE status bit; if timeout before
+                * receive the REPLY_ALIVE notification, go back and try to
+                * download the Init uCode image again.
+                * 2) For Runtime uCode image, all iwlagn devices except 4965
+                * wait here on STATUS_RT_UCODE_ALIVE status bit; if
+                * timeout before receive the REPLY_ALIVE notification, go back
+                * and download the Runtime uCode image again.
+                * 3) For 4965 Runtime uCode, it will not go through this path,
+                * need to wait for STATUS_RT_UCODE_ALIVE status bit in
+                * iwl4965_init_alive_start() function; if timeout, need to
+                * restart and download Init uCode image.
+                */
+               if (priv->ucode_type == UCODE_INIT)
+                       status = STATUS_INIT_UCODE_ALIVE;
+               else
+                       status = STATUS_RT_UCODE_ALIVE;
+               if (test_bit(status, &priv->status)) {
+                       IWL_WARN(priv,
+                               "%s uCode already alive? "
+                               "Waiting for alive anyway\n",
+                               (status == STATUS_INIT_UCODE_ALIVE)
+                               ? "INIT" : "Runtime");
+                       clear_bit(status, &priv->status);
+               }
+               ret = wait_event_interruptible_timeout(
+                               priv->wait_command_queue,
+                               test_bit(status, &priv->status),
+                               UCODE_ALIVE_TIMEOUT);
+               if (!ret) {
+                       if (!test_bit(status, &priv->status)) {
+                               priv->ucode_type =
+                                       (status == STATUS_INIT_UCODE_ALIVE)
+                                       ? UCODE_NONE : UCODE_INIT;
+                               IWL_ERR(priv,
+                                       "%s timeout after %dms\n",
+                                       (status == STATUS_INIT_UCODE_ALIVE)
+                                       ? "INIT" : "Runtime",
+                                       jiffies_to_msecs(UCODE_ALIVE_TIMEOUT));
+                               continue;
+                       }
+               }
                IWL_DEBUG_INFO(priv, DRV_NAME " is coming up\n");
 
                return 0;
index b82480a517824af834825417afe8349ae51db807..8655e092fca79a61f1e5cf12abe4dfa19a7d64a7 100644 (file)
@@ -1341,10 +1341,17 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv)
        u32 desc, time, count, base, data1;
        u32 blink1, blink2, ilink1, ilink2;
 
-       if (priv->ucode_type == UCODE_INIT)
-               base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
-       else
+       switch (priv->ucode_type) {
+       case UCODE_RT:
                base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
+               break;
+       case UCODE_INIT:
+               base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
+               break;
+       default:
+               IWL_ERR(priv, "uCode image not available\n");
+               return;
+       }
 
        if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
                IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base);
@@ -1396,10 +1403,17 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
 
        if (num_events == 0)
                return;
-       if (priv->ucode_type == UCODE_INIT)
-               base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
-       else
+       switch (priv->ucode_type) {
+       case UCODE_RT:
                base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+               break;
+       case UCODE_INIT:
+               base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
+               break;
+       default:
+               IWL_ERR(priv, "uCode image not available\n");
+               return;
+       }
 
        if (mode == 0)
                event_size = 2 * sizeof(u32);
@@ -1436,10 +1450,17 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv)
        u32 next_entry; /* index of next entry to be written by uCode */
        u32 size;       /* # entries that we'll print */
 
-       if (priv->ucode_type == UCODE_INIT)
-               base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
-       else
+       switch (priv->ucode_type) {
+       case UCODE_RT:
                base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+               break;
+       case UCODE_INIT:
+               base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
+               break;
+       default:
+               IWL_ERR(priv, "uCode image not available\n");
+               return;
+       }
 
        if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
                IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base);
index c844fab95abb5a2e7b944a6f9d5f98c7fe78028e..a697b843863bd9d701940f2c671649b8c8c69e73 100644 (file)
@@ -512,6 +512,8 @@ void iwlcore_free_geos(struct iwl_priv *priv);
 #define STATUS_POWER_PMI       16
 #define STATUS_FW_ERROR                17
 #define STATUS_MODE_PENDING    18
+#define STATUS_INIT_UCODE_ALIVE        19
+#define STATUS_RT_UCODE_ALIVE  20
 
 
 static inline int iwl_is_ready(struct iwl_priv *priv)
index f4afd0c3265f7122fda78942b2e6f20e1bebe635..926df3ae241651fd0a86563764a5072efcb5008d 100644 (file)
@@ -772,6 +772,8 @@ struct iwl_calib_result {
        size_t buf_len;
 };
 
+#define UCODE_ALIVE_TIMEOUT    (5 * HZ)
+
 enum ucode_type {
        UCODE_NONE = 0,
        UCODE_INIT,