|
@@ -44,6 +44,7 @@
|
|
|
#define WL1271_BOOT_RETRIES 3
|
|
|
|
|
|
static char *fwlog_param;
|
|
|
+static int fwlog_mem_blocks = -1;
|
|
|
static int bug_on_recovery = -1;
|
|
|
static int no_recovery = -1;
|
|
|
|
|
@@ -291,6 +292,18 @@ static void wlcore_adjust_conf(struct wl1271 *wl)
|
|
|
{
|
|
|
/* Adjust settings according to optional module parameters */
|
|
|
|
|
|
+ /* Firmware Logger params */
|
|
|
+ if (fwlog_mem_blocks != -1) {
|
|
|
+ if (fwlog_mem_blocks >= CONF_FWLOG_MIN_MEM_BLOCKS &&
|
|
|
+ fwlog_mem_blocks <= CONF_FWLOG_MAX_MEM_BLOCKS) {
|
|
|
+ wl->conf.fwlog.mem_blocks = fwlog_mem_blocks;
|
|
|
+ } else {
|
|
|
+ wl1271_error(
|
|
|
+ "Illegal fwlog_mem_blocks=%d using default %d",
|
|
|
+ fwlog_mem_blocks, wl->conf.fwlog.mem_blocks);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
if (fwlog_param) {
|
|
|
if (!strcmp(fwlog_param, "continuous")) {
|
|
|
wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
|
|
@@ -780,6 +793,7 @@ void wl12xx_queue_recovery_work(struct wl1271 *wl)
|
|
|
if (wl->state == WLCORE_STATE_ON) {
|
|
|
wl->state = WLCORE_STATE_RESTARTING;
|
|
|
set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
|
|
|
+ wl1271_ps_elp_wakeup(wl);
|
|
|
wlcore_disable_interrupts_nosync(wl);
|
|
|
ieee80211_queue_work(wl->hw, &wl->recovery_work);
|
|
|
}
|
|
@@ -787,19 +801,10 @@ void wl12xx_queue_recovery_work(struct wl1271 *wl)
|
|
|
|
|
|
size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
|
|
|
{
|
|
|
- size_t len = 0;
|
|
|
-
|
|
|
- /* The FW log is a length-value list, find where the log end */
|
|
|
- while (len < maxlen) {
|
|
|
- if (memblock[len] == 0)
|
|
|
- break;
|
|
|
- if (len + memblock[len] + 1 > maxlen)
|
|
|
- break;
|
|
|
- len += memblock[len] + 1;
|
|
|
- }
|
|
|
+ size_t len;
|
|
|
|
|
|
/* Make sure we have enough room */
|
|
|
- len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
|
|
|
+ len = min(maxlen, (size_t)(PAGE_SIZE - wl->fwlog_size));
|
|
|
|
|
|
/* Fill the FW log file, consumed by the sysfs fwlog entry */
|
|
|
memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
|
|
@@ -808,10 +813,9 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
|
|
|
return len;
|
|
|
}
|
|
|
|
|
|
-#define WLCORE_FW_LOG_END 0x2000000
|
|
|
-
|
|
|
static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
|
|
|
{
|
|
|
+ struct wlcore_partition_set part, old_part;
|
|
|
u32 addr;
|
|
|
u32 offset;
|
|
|
u32 end_of_log;
|
|
@@ -824,7 +828,7 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
|
|
|
|
|
|
wl1271_info("Reading FW panic log");
|
|
|
|
|
|
- block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
|
|
|
+ block = kmalloc(wl->fw_mem_block_size, GFP_KERNEL);
|
|
|
if (!block)
|
|
|
return;
|
|
|
|
|
@@ -850,17 +854,31 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
|
|
|
|
|
|
if (wl->conf.fwlog.mode == WL12XX_FWLOG_CONTINUOUS) {
|
|
|
offset = sizeof(addr) + sizeof(struct wl1271_rx_descriptor);
|
|
|
- end_of_log = WLCORE_FW_LOG_END;
|
|
|
+ end_of_log = wl->fwlog_end;
|
|
|
} else {
|
|
|
offset = sizeof(addr);
|
|
|
end_of_log = addr;
|
|
|
}
|
|
|
|
|
|
+ old_part = wl->curr_part;
|
|
|
+ memset(&part, 0, sizeof(part));
|
|
|
+
|
|
|
/* Traverse the memory blocks linked list */
|
|
|
do {
|
|
|
- memset(block, 0, WL12XX_HW_BLOCK_SIZE);
|
|
|
- ret = wlcore_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
|
|
|
- false);
|
|
|
+ part.mem.start = wlcore_hw_convert_hwaddr(wl, addr);
|
|
|
+ part.mem.size = PAGE_SIZE;
|
|
|
+
|
|
|
+ ret = wlcore_set_partition(wl, &part);
|
|
|
+ if (ret < 0) {
|
|
|
+ wl1271_error("%s: set_partition start=0x%X size=%d",
|
|
|
+ __func__, part.mem.start, part.mem.size);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ memset(block, 0, wl->fw_mem_block_size);
|
|
|
+ ret = wlcore_read_hwaddr(wl, addr, block,
|
|
|
+ wl->fw_mem_block_size, false);
|
|
|
+
|
|
|
if (ret < 0)
|
|
|
goto out;
|
|
|
|
|
@@ -871,8 +889,9 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
|
|
|
* on demand mode and is equal to 0x2000000 in continuous mode.
|
|
|
*/
|
|
|
addr = le32_to_cpup((__le32 *)block);
|
|
|
+
|
|
|
if (!wl12xx_copy_fwlog(wl, block + offset,
|
|
|
- WL12XX_HW_BLOCK_SIZE - offset))
|
|
|
+ wl->fw_mem_block_size - offset))
|
|
|
break;
|
|
|
} while (addr && (addr != end_of_log));
|
|
|
|
|
@@ -880,6 +899,7 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
|
|
|
|
|
|
out:
|
|
|
kfree(block);
|
|
|
+ wlcore_set_partition(wl, &old_part);
|
|
|
}
|
|
|
|
|
|
static void wlcore_print_recovery(struct wl1271 *wl)
|
|
@@ -924,7 +944,8 @@ static void wl1271_recovery_work(struct work_struct *work)
|
|
|
goto out_unlock;
|
|
|
|
|
|
if (!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags)) {
|
|
|
- wl12xx_read_fwlog_panic(wl);
|
|
|
+ if (wl->conf.fwlog.output == WL12XX_FWLOG_OUTPUT_HOST)
|
|
|
+ wl12xx_read_fwlog_panic(wl);
|
|
|
wlcore_print_recovery(wl);
|
|
|
}
|
|
|
|
|
@@ -1928,8 +1949,10 @@ static void wlcore_op_stop_locked(struct wl1271 *wl)
|
|
|
|
|
|
/*
|
|
|
* FW channels must be re-calibrated after recovery,
|
|
|
- * clear the last Reg-Domain channel configuration.
|
|
|
+ * save current Reg-Domain channel configuration and clear it.
|
|
|
*/
|
|
|
+ memcpy(wl->reg_ch_conf_pending, wl->reg_ch_conf_last,
|
|
|
+ sizeof(wl->reg_ch_conf_pending));
|
|
|
memset(wl->reg_ch_conf_last, 0, sizeof(wl->reg_ch_conf_last));
|
|
|
}
|
|
|
|
|
@@ -2623,6 +2646,12 @@ deinit:
|
|
|
!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags))
|
|
|
goto unlock;
|
|
|
|
|
|
+ if (wl->ap_count == 0 && is_ap) {
|
|
|
+ /* mask ap events */
|
|
|
+ wl->event_mask &= ~wl->ap_event_mask;
|
|
|
+ wl1271_event_unmask(wl);
|
|
|
+ }
|
|
|
+
|
|
|
if (wl->ap_count == 0 && is_ap && wl->sta_count) {
|
|
|
u8 sta_auth = wl->conf.conn.sta_sleep_auth;
|
|
|
/* Configure for power according to debugfs */
|
|
@@ -6152,6 +6181,9 @@ module_param_named(fwlog, fwlog_param, charp, 0);
|
|
|
MODULE_PARM_DESC(fwlog,
|
|
|
"FW logger options: continuous, ondemand, dbgpins or disable");
|
|
|
|
|
|
+module_param(fwlog_mem_blocks, int, S_IRUSR | S_IWUSR);
|
|
|
+MODULE_PARM_DESC(fwlog_mem_blocks, "fwlog mem_blocks");
|
|
|
+
|
|
|
module_param(bug_on_recovery, int, S_IRUSR | S_IWUSR);
|
|
|
MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
|
|
|
|