iwlwifi: mvm: support alive notification api version2
authorEran Harary <eran.harary@intel.com>
Mon, 3 Feb 2014 07:29:57 +0000 (09:29 +0200)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Thu, 6 Feb 2014 19:12:26 +0000 (21:12 +0200)
Alive notification ver2 support error table information
for 2 CPUs.
This is useful to fetch the error information in case of
firmware assert.

Signed-off-by: Eran Harary <eran.harary@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
drivers/net/wireless/iwlwifi/mvm/fw-api.h
drivers/net/wireless/iwlwifi/mvm/fw.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/utils.c

index 3bf5f82..a7c88f1 100644 (file)
@@ -411,6 +411,35 @@ struct mvm_alive_resp {
        __le32 scd_base_ptr;            /* SRAM address for SCD */
 } __packed; /* ALIVE_RES_API_S_VER_1 */
 
+struct mvm_alive_resp_ver2 {
+       __le16 status;
+       __le16 flags;
+       u8 ucode_minor;
+       u8 ucode_major;
+       __le16 id;
+       u8 api_minor;
+       u8 api_major;
+       u8 ver_subtype;
+       u8 ver_type;
+       u8 mac;
+       u8 opt;
+       __le16 reserved2;
+       __le32 timestamp;
+       __le32 error_event_table_ptr;   /* SRAM address for error log */
+       __le32 log_event_table_ptr;     /* SRAM address for LMAC event log */
+       __le32 cpu_register_ptr;
+       __le32 dbgm_config_ptr;
+       __le32 alive_counter_ptr;
+       __le32 scd_base_ptr;            /* SRAM address for SCD */
+       __le32 st_fwrd_addr;            /* pointer to Store and forward */
+       __le32 st_fwrd_size;
+       u8 umac_minor;                  /* UMAC version: minor */
+       u8 umac_major;                  /* UMAC version: major */
+       __le16 umac_id;                 /* UMAC version: id */
+       __le32 error_info_addr;         /* SRAM address for UMAC error log */
+       __le32 dbg_print_buff_addr;
+} __packed; /* ALIVE_RES_API_S_VER_2 */
+
 /* Error response/notification */
 enum {
        FW_ERR_UNKNOWN_CMD = 0x0,
index 155bb20..bae75b3 100644 (file)
@@ -110,18 +110,46 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
                container_of(notif_wait, struct iwl_mvm, notif_wait);
        struct iwl_mvm_alive_data *alive_data = data;
        struct mvm_alive_resp *palive;
-
-       palive = (void *)pkt->data;
-
-       mvm->error_event_table = le32_to_cpu(palive->error_event_table_ptr);
-       mvm->log_event_table = le32_to_cpu(palive->log_event_table_ptr);
-       alive_data->scd_base_addr = le32_to_cpu(palive->scd_base_ptr);
-
-       alive_data->valid = le16_to_cpu(palive->status) == IWL_ALIVE_STATUS_OK;
-       IWL_DEBUG_FW(mvm,
-                    "Alive ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n",
-                    le16_to_cpu(palive->status), palive->ver_type,
-                    palive->ver_subtype, palive->flags);
+       struct mvm_alive_resp_ver2 *palive2;
+
+       if (iwl_rx_packet_payload_len(pkt) == sizeof(*palive)) {
+               palive = (void *)pkt->data;
+
+               mvm->support_umac_log = false;
+               mvm->error_event_table =
+                       le32_to_cpu(palive->error_event_table_ptr);
+               mvm->log_event_table = le32_to_cpu(palive->log_event_table_ptr);
+               alive_data->scd_base_addr = le32_to_cpu(palive->scd_base_ptr);
+
+               alive_data->valid = le16_to_cpu(palive->status) ==
+                                   IWL_ALIVE_STATUS_OK;
+               IWL_DEBUG_FW(mvm,
+                            "Alive VER1 ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n",
+                            le16_to_cpu(palive->status), palive->ver_type,
+                            palive->ver_subtype, palive->flags);
+       } else {
+               palive2 = (void *)pkt->data;
+
+               mvm->support_umac_log = true;
+               mvm->error_event_table =
+                       le32_to_cpu(palive2->error_event_table_ptr);
+               mvm->log_event_table =
+                       le32_to_cpu(palive2->log_event_table_ptr);
+               alive_data->scd_base_addr = le32_to_cpu(palive2->scd_base_ptr);
+               mvm->umac_error_event_table =
+                       le32_to_cpu(palive2->error_info_addr);
+
+               alive_data->valid = le16_to_cpu(palive2->status) ==
+                                   IWL_ALIVE_STATUS_OK;
+               IWL_DEBUG_FW(mvm,
+                            "Alive VER2 ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n",
+                            le16_to_cpu(palive2->status), palive2->ver_type,
+                            palive2->ver_subtype, palive2->flags);
+
+               IWL_DEBUG_FW(mvm,
+                            "UMAC version: Major - 0x%x, Minor - 0x%x\n",
+                            palive2->umac_major, palive2->umac_minor);
+       }
 
        return true;
 }
index ab6e1e9..ebea5f2 100644 (file)
@@ -457,6 +457,8 @@ struct iwl_mvm {
        bool init_ucode_complete;
        u32 error_event_table;
        u32 log_event_table;
+       u32 umac_error_event_table;
+       bool support_umac_log;
 
        u32 ampdu_ref;
 
index 68b7fac..f4598cb 100644 (file)
@@ -376,9 +376,67 @@ struct iwl_error_event_table {
        u32 flow_handler;       /* FH read/write pointers, RX credit */
 } __packed;
 
+/*
+ * UMAC error struct - relevant starting from family 8000 chip.
+ * Note: This structure is read from the device with IO accesses,
+ * and the reading already does the endian conversion. As it is
+ * read with u32-sized accesses, any members with a different size
+ * need to be ordered correctly though!
+ */
+struct iwl_umac_error_event_table {
+       u32 valid;              /* (nonzero) valid, (0) log is empty */
+       u32 error_id;           /* type of error */
+       u32 pc;                 /* program counter */
+       u32 blink1;             /* branch link */
+       u32 blink2;             /* branch link */
+       u32 ilink1;             /* interrupt link */
+       u32 ilink2;             /* interrupt link */
+       u32 data1;              /* error-specific data */
+       u32 data2;              /* error-specific data */
+       u32 line;               /* source code line of error */
+       u32 umac_ver;           /* umac version */
+} __packed;
+
 #define ERROR_START_OFFSET  (1 * sizeof(u32))
 #define ERROR_ELEM_SIZE     (7 * sizeof(u32))
 
+static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm)
+{
+       struct iwl_trans *trans = mvm->trans;
+       struct iwl_umac_error_event_table table;
+       u32 base;
+
+       base = mvm->umac_error_event_table;
+
+       if (base < 0x800000 || base >= 0x80C000) {
+               IWL_ERR(mvm,
+                       "Not valid error log pointer 0x%08X for %s uCode\n",
+                       base,
+                       (mvm->cur_ucode == IWL_UCODE_INIT)
+                                       ? "Init" : "RT");
+               return;
+       }
+
+       iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));
+
+       if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
+               IWL_ERR(trans, "Start IWL Error Log Dump:\n");
+               IWL_ERR(trans, "Status: 0x%08lX, count: %d\n",
+                       mvm->status, table.valid);
+       }
+
+       IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id,
+               desc_lookup(table.error_id));
+       IWL_ERR(mvm, "0x%08X | umac uPc\n", table.pc);
+       IWL_ERR(mvm, "0x%08X | umac branchlink1\n", table.blink1);
+       IWL_ERR(mvm, "0x%08X | umac branchlink2\n", table.blink2);
+       IWL_ERR(mvm, "0x%08X | umac interruptlink1\n", table.ilink1);
+       IWL_ERR(mvm, "0x%08X | umac interruptlink2\n", table.ilink2);
+       IWL_ERR(mvm, "0x%08X | umac data1\n", table.data1);
+       IWL_ERR(mvm, "0x%08X | umac data2\n", table.data2);
+       IWL_ERR(mvm, "0x%08X | umac version\n", table.umac_ver);
+}
+
 void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
 {
        struct iwl_trans *trans = mvm->trans;
@@ -451,6 +509,9 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
        IWL_ERR(mvm, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel);
        IWL_ERR(mvm, "0x%08X | timestamp\n", table.u_timestamp);
        IWL_ERR(mvm, "0x%08X | flow_handler\n", table.flow_handler);
+
+       if (mvm->support_umac_log)
+               iwl_mvm_dump_umac_error_log(mvm);
 }
 
 void iwl_mvm_dump_sram(struct iwl_mvm *mvm)