static bool iwl_testmode_valid_hw_addr(u32 addr) { if (iwlagn_hw_valid_rtc_data_addr(addr)) return true; if (IWLAGN_RTC_INST_LOWER_BOUND <= addr && addr < IWLAGN_RTC_INST_UPPER_BOUND) return true; return false; }
static int iwl_testmode_indirect_write(struct iwl_priv *priv, u32 addr, u32 size, unsigned char *buf) { struct iwl_trans *trans = trans(priv); u32 val, i; unsigned long flags; if (IWL_TM_ABS_PRPH_START <= addr && addr < IWL_TM_ABS_PRPH_START + PRPH_END) { /* Periphery writes can be 1-3 bytes long, or DWORDs */ if (size < 4) { memcpy(&val, buf, size); spin_lock_irqsave(&trans->reg_lock, flags); iwl_grab_nic_access(trans); iwl_write32(trans, HBUS_TARG_PRPH_WADDR, (addr & 0x0000FFFF) | ((size - 1) << 24)); iwl_write32(trans, HBUS_TARG_PRPH_WDAT, val); iwl_release_nic_access(trans); /* needed after consecutive writes w/o read */ mmiowb(); spin_unlock_irqrestore(&trans->reg_lock, flags); } else { if (size % 4) return -EINVAL; for (i = 0; i < size; i += 4) iwl_write_prph(trans, addr+i, *(u32 *)(buf+i)); } } else if (iwlagn_hw_valid_rtc_data_addr(addr) || (IWLAGN_RTC_INST_LOWER_BOUND <= addr && addr < IWLAGN_RTC_INST_UPPER_BOUND)) { _iwl_write_targ_mem_words(trans, addr, buf, size/4); } else return -EINVAL; return 0; }
int iwl_dump_nic_event_log(struct iwl_trans *trans, bool full_log, char **buf, bool display) { u32 base; /* SRAM byte address of event log header */ u32 capacity; /* event log capacity in # entries */ u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ u32 num_wraps; /* # times uCode wrapped to top of log */ u32 next_entry; /* index of next entry to be written by uCode */ u32 size; /* # entries that we'll print */ u32 logsize; int pos = 0; size_t bufsz = 0; struct iwl_priv *priv = priv(trans); base = priv->device_pointers.log_event_table; if (priv->ucode_type == IWL_UCODE_INIT) { logsize = priv->init_evtlog_size; if (!base) base = priv->init_evtlog_ptr; } else { logsize = priv->inst_evtlog_size; if (!base) base = priv->inst_evtlog_ptr; } if (!iwlagn_hw_valid_rtc_data_addr(base)) { IWL_ERR(trans, "Invalid event log pointer 0x%08X for %s uCode\n", base, (priv->ucode_type == IWL_UCODE_INIT) ? "Init" : "RT"); return -EINVAL; } /* event log header */ capacity = iwl_read_targ_mem(bus(trans), base); mode = iwl_read_targ_mem(bus(trans), base + (1 * sizeof(u32))); num_wraps = iwl_read_targ_mem(bus(trans), base + (2 * sizeof(u32))); next_entry = iwl_read_targ_mem(bus(trans), base + (3 * sizeof(u32))); if (capacity > logsize) { IWL_ERR(trans, "Log capacity %d is bogus, limit to %d " "entries\n", capacity, logsize); capacity = logsize; } if (next_entry > logsize) { IWL_ERR(trans, "Log write index %d is bogus, limit to %d\n", next_entry, logsize); next_entry = logsize; } size = num_wraps ? capacity : next_entry; /* bail out if nothing in log */ if (size == 0) { IWL_ERR(trans, "Start IWL Event Log Dump: nothing in log\n"); return pos; } #ifdef CONFIG_IWLWIFI_DEBUG if (!(iwl_get_debug_level(trans->shrd) & IWL_DL_FW_ERRORS) && !full_log) size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES) ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size; #else size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES) ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size; #endif IWL_ERR(trans, "Start IWL Event Log Dump: display last %u entries\n", size); #ifdef CONFIG_IWLWIFI_DEBUG if (display) { if (full_log) bufsz = capacity * 48; else bufsz = size * 48; *buf = kmalloc(bufsz, GFP_KERNEL); if (!*buf) return -ENOMEM; } if ((iwl_get_debug_level(trans->shrd) & IWL_DL_FW_ERRORS) || full_log) { /* * if uCode has wrapped back to top of log, * start at the oldest entry, * i.e the next one that uCode would fill. */ if (num_wraps) pos = iwl_print_event_log(trans, next_entry, capacity - next_entry, mode, pos, buf, bufsz); /* (then/else) start at top of log */ pos = iwl_print_event_log(trans, 0, next_entry, mode, pos, buf, bufsz); } else pos = iwl_print_last_event_logs(trans, capacity, num_wraps, next_entry, size, mode, pos, buf, bufsz); #else pos = iwl_print_last_event_logs(trans, capacity, num_wraps, next_entry, size, mode, pos, buf, bufsz); #endif return pos; }
static void iwl_dump_nic_error_log(struct iwl_trans *trans) { u32 base; struct iwl_error_event_table table; struct iwl_priv *priv = priv(trans); struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); base = priv->device_pointers.error_event_table; if (priv->ucode_type == IWL_UCODE_INIT) { if (!base) base = priv->init_errlog_ptr; } else { if (!base) base = priv->inst_errlog_ptr; } if (!iwlagn_hw_valid_rtc_data_addr(base)) { IWL_ERR(trans, "Not valid error log pointer 0x%08X for %s uCode\n", base, (priv->ucode_type == IWL_UCODE_INIT) ? "Init" : "RT"); return; } iwl_read_targ_mem_words(bus(priv), 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", trans->shrd->status, table.valid); } trans_pcie->isr_stats.err_code = table.error_id; trace_iwlwifi_dev_ucode_error(priv, table.error_id, table.tsf_low, table.data1, table.data2, table.line, table.blink1, table.blink2, table.ilink1, table.ilink2, table.bcon_time, table.gp1, table.gp2, table.gp3, table.ucode_ver, table.hw_ver, table.brd_ver); IWL_ERR(trans, "0x%08X | %-28s\n", table.error_id, desc_lookup(table.error_id)); IWL_ERR(trans, "0x%08X | uPc\n", table.pc); IWL_ERR(trans, "0x%08X | branchlink1\n", table.blink1); IWL_ERR(trans, "0x%08X | branchlink2\n", table.blink2); IWL_ERR(trans, "0x%08X | interruptlink1\n", table.ilink1); IWL_ERR(trans, "0x%08X | interruptlink2\n", table.ilink2); IWL_ERR(trans, "0x%08X | data1\n", table.data1); IWL_ERR(trans, "0x%08X | data2\n", table.data2); IWL_ERR(trans, "0x%08X | line\n", table.line); IWL_ERR(trans, "0x%08X | beacon time\n", table.bcon_time); IWL_ERR(trans, "0x%08X | tsf low\n", table.tsf_low); IWL_ERR(trans, "0x%08X | tsf hi\n", table.tsf_hi); IWL_ERR(trans, "0x%08X | time gp1\n", table.gp1); IWL_ERR(trans, "0x%08X | time gp2\n", table.gp2); IWL_ERR(trans, "0x%08X | time gp3\n", table.gp3); IWL_ERR(trans, "0x%08X | uCode version\n", table.ucode_ver); IWL_ERR(trans, "0x%08X | hw version\n", table.hw_ver); IWL_ERR(trans, "0x%08X | board version\n", table.brd_ver); IWL_ERR(trans, "0x%08X | hcmd\n", table.hcmd); }
int iwl_dump_nic_event_log(struct iwl_trans *trans, bool full_log, char **buf, bool display) { u32 base; /* */ u32 capacity; /* */ u32 mode; /* */ u32 num_wraps; /* */ u32 next_entry; /* */ u32 size; /* */ u32 logsize; int pos = 0; size_t bufsz = 0; base = trans->shrd->device_pointers.log_event_table; if (trans->shrd->ucode_type == IWL_UCODE_INIT) { logsize = trans->shrd->fw->init_evtlog_size; if (!base) base = trans->shrd->fw->init_evtlog_ptr; } else { logsize = trans->shrd->fw->inst_evtlog_size; if (!base) base = trans->shrd->fw->inst_evtlog_ptr; } if (!iwlagn_hw_valid_rtc_data_addr(base)) { IWL_ERR(trans, "Invalid event log pointer 0x%08X for %s uCode\n", base, (trans->shrd->ucode_type == IWL_UCODE_INIT) ? "Init" : "RT"); return -EINVAL; } /* */ capacity = iwl_read_targ_mem(trans, base); mode = iwl_read_targ_mem(trans, base + (1 * sizeof(u32))); num_wraps = iwl_read_targ_mem(trans, base + (2 * sizeof(u32))); next_entry = iwl_read_targ_mem(trans, base + (3 * sizeof(u32))); if (capacity > logsize) { IWL_ERR(trans, "Log capacity %d is bogus, limit to %d " "entries\n", capacity, logsize); capacity = logsize; } if (next_entry > logsize) { IWL_ERR(trans, "Log write index %d is bogus, limit to %d\n", next_entry, logsize); next_entry = logsize; } size = num_wraps ? capacity : next_entry; /* */ if (size == 0) { IWL_ERR(trans, "Start IWL Event Log Dump: nothing in log\n"); return pos; } #ifdef CONFIG_IWLWIFI_DEBUG if (!(iwl_have_debug_level(IWL_DL_FW_ERRORS)) && !full_log) size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES) ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size; #else size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES) ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size; #endif IWL_ERR(trans, "Start IWL Event Log Dump: display last %u entries\n", size); #ifdef CONFIG_IWLWIFI_DEBUG if (display) { if (full_log) bufsz = capacity * 48; else bufsz = size * 48; *buf = kmalloc(bufsz, GFP_KERNEL); if (!*buf) return -ENOMEM; } if (iwl_have_debug_level(IWL_DL_FW_ERRORS) || full_log) { /* */ if (num_wraps) pos = iwl_print_event_log(trans, next_entry, capacity - next_entry, mode, pos, buf, bufsz); /* */ pos = iwl_print_event_log(trans, 0, next_entry, mode, pos, buf, bufsz); } else pos = iwl_print_last_event_logs(trans, capacity, num_wraps, next_entry, size, mode, pos, buf, bufsz); #else pos = iwl_print_last_event_logs(trans, capacity, num_wraps, next_entry, size, mode, pos, buf, bufsz); #endif return pos; }