mbox->sc_ssid,
                                                 mbox->sc_pwd_len,
                                                 mbox->sc_pwd);
+       if (vector & FW_LOGGER_INDICATION)
+               wlcore_event_fw_logger(wl);
 
        return 0;
 }
 
        SMART_CONFIG_SYNC_EVENT_ID               = BIT(22),
        SMART_CONFIG_DECODE_EVENT_ID             = BIT(23),
        TIME_SYNC_EVENT_ID                       = BIT(24),
+       FW_LOGGER_INDICATION                    = BIT(25),
 };
 
 enum wl18xx_radar_types {
 
        },
        .fwlog = {
                .mode                         = WL12XX_FWLOG_CONTINUOUS,
-               .mem_blocks                   = 2,
+               .mem_blocks                   = 0,
                .severity                     = 0,
                .timestamp                    = WL12XX_FWLOG_TIMESTAMP_DISABLED,
                .output                       = WL12XX_FWLOG_OUTPUT_DBG_PINS,
                .mem  = { .start = 0x00A00000, .size  = 0x00012000 },
                .reg  = { .start = 0x00807000, .size  = 0x00005000 },
                .mem2 = { .start = 0x00800000, .size  = 0x0000B000 },
-               .mem3 = { .start = 0x00000000, .size  = 0x00000000 },
+               .mem3 = { .start = 0x00401594, .size  = 0x00001020 },
        },
        [PART_DOWN] = {
                .mem  = { .start = 0x00000000, .size  = 0x00014000 },
                .mem  = { .start = 0x00800000, .size  = 0x000050FC },
                .reg  = { .start = 0x00B00404, .size  = 0x00001000 },
                .mem2 = { .start = 0x00C00000, .size  = 0x00000400 },
-               .mem3 = { .start = 0x00000000, .size  = 0x00000000 },
+               .mem3 = { .start = 0x00401594, .size  = 0x00001020 },
        },
        [PART_PHY_INIT] = {
                .mem  = { .start = WL18XX_PHY_INIT_MEM_ADDR,
                DFS_CHANNELS_CONFIG_COMPLETE_EVENT |
                SMART_CONFIG_SYNC_EVENT_ID |
                SMART_CONFIG_DECODE_EVENT_ID |
-               TIME_SYNC_EVENT_ID;
+               TIME_SYNC_EVENT_ID |
+               FW_LOGGER_INDICATION;
 
        wl->ap_event_mask = MAX_TX_FAILURE_EVENT_ID;
 
 
  */
 enum wl12xx_fwlogger_log_mode {
        WL12XX_FWLOG_CONTINUOUS,
-       WL12XX_FWLOG_ON_DEMAND
 };
 
 /* Include/exclude timestamps from the log messages */
 
        .llseek = dev_mem_seek,
 };
 
+static ssize_t fw_logger_read(struct file *file, char __user *user_buf,
+                             size_t count, loff_t *ppos)
+{
+       struct wl1271 *wl = file->private_data;
+
+       return wl1271_format_buffer(user_buf, count,
+                                       ppos, "%d\n",
+                                       wl->conf.fwlog.output);
+}
+
+static ssize_t fw_logger_write(struct file *file,
+                              const char __user *user_buf,
+                              size_t count, loff_t *ppos)
+{
+       struct wl1271 *wl = file->private_data;
+       unsigned long value;
+       int ret;
+
+       ret = kstrtoul_from_user(user_buf, count, 0, &value);
+       if (ret < 0) {
+               wl1271_warning("illegal value in fw_logger");
+               return -EINVAL;
+       }
+
+       if ((value > 2) || (value == 0)) {
+               wl1271_warning("fw_logger value must be 1-UART 2-SDIO");
+               return -ERANGE;
+       }
+
+       if (wl->conf.fwlog.output == 0) {
+               wl1271_warning("iligal opperation - fw logger disabled by default, please change mode via wlconf");
+               return -EINVAL;
+       }
+
+       mutex_lock(&wl->mutex);
+       ret = wl1271_ps_elp_wakeup(wl);
+       if (ret < 0) {
+               count = ret;
+               goto out;
+       }
+
+       wl->conf.fwlog.output = value;
+
+       ret = wl12xx_cmd_config_fwlog(wl);
+
+       wl1271_ps_elp_sleep(wl);
+
+out:
+       mutex_unlock(&wl->mutex);
+       return count;
+}
+
+static const struct file_operations fw_logger_ops = {
+       .open = simple_open,
+       .read = fw_logger_read,
+       .write = fw_logger_write,
+       .llseek = default_llseek,
+};
+
 static int wl1271_debugfs_add_files(struct wl1271 *wl,
                                    struct dentry *rootdir)
 {
        DEBUGFS_ADD(irq_timeout, rootdir);
        DEBUGFS_ADD(fw_stats_raw, rootdir);
        DEBUGFS_ADD(sleep_auth, rootdir);
+       DEBUGFS_ADD(fw_logger, rootdir);
 
        streaming = debugfs_create_dir("rx_streaming", rootdir);
        if (!streaming || IS_ERR(streaming))
 
 #include "ps.h"
 #include "scan.h"
 #include "wl12xx_80211.h"
+#include "hw_ops.h"
+
+#define WL18XX_LOGGER_SDIO_BUFF_MAX    (0x1020)
+#define WL18XX_DATA_RAM_BASE_ADDRESS   (0x20000000)
+#define WL18XX_LOGGER_SDIO_BUFF_ADDR   (0x40159c)
+#define WL18XX_LOGGER_BUFF_OFFSET      (sizeof(struct fw_logger_information))
+#define WL18XX_LOGGER_READ_POINT_OFFSET                (12)
+
+int wlcore_event_fw_logger(struct wl1271 *wl)
+{
+       u32 ret;
+       struct fw_logger_information fw_log;
+       u8  *buffer;
+       u32 internal_fw_addrbase = WL18XX_DATA_RAM_BASE_ADDRESS;
+       u32 addr = WL18XX_LOGGER_SDIO_BUFF_ADDR;
+       u32 end_buff_addr = WL18XX_LOGGER_SDIO_BUFF_ADDR +
+                               WL18XX_LOGGER_BUFF_OFFSET;
+       u32 available_len;
+       u32 actual_len;
+       u32 clear_addr;
+       size_t len;
+       u32 start_loc;
+
+       buffer = kzalloc(WL18XX_LOGGER_SDIO_BUFF_MAX, GFP_KERNEL);
+       if (!buffer) {
+               wl1271_error("Fail to allocate fw logger memory");
+               fw_log.actual_buff_size = cpu_to_le32(0);
+               goto out;
+       }
+
+       ret = wlcore_read(wl, addr, buffer, WL18XX_LOGGER_SDIO_BUFF_MAX,
+                         false);
+       if (ret < 0) {
+               wl1271_error("Fail to read logger buffer, error_id = %d",
+                            ret);
+               fw_log.actual_buff_size = cpu_to_le32(0);
+               goto free_out;
+       }
+
+       memcpy(&fw_log, buffer, sizeof(fw_log));
+
+       if (le32_to_cpu(fw_log.actual_buff_size) == 0)
+               goto free_out;
+
+       actual_len = le32_to_cpu(fw_log.actual_buff_size);
+       start_loc = (le32_to_cpu(fw_log.buff_read_ptr) -
+                       internal_fw_addrbase) - addr;
+       end_buff_addr += le32_to_cpu(fw_log.max_buff_size);
+       available_len = end_buff_addr -
+                       (le32_to_cpu(fw_log.buff_read_ptr) -
+                                internal_fw_addrbase);
+       actual_len = min(actual_len, available_len);
+       len = actual_len;
+
+       wl12xx_copy_fwlog(wl, &buffer[start_loc], len);
+       clear_addr = addr + start_loc + le32_to_cpu(fw_log.actual_buff_size) +
+                       internal_fw_addrbase;
+
+       len = le32_to_cpu(fw_log.actual_buff_size) - len;
+       if (len) {
+               wl12xx_copy_fwlog(wl,
+                                 &buffer[WL18XX_LOGGER_BUFF_OFFSET],
+                                 len);
+               clear_addr = addr + WL18XX_LOGGER_BUFF_OFFSET + len +
+                               internal_fw_addrbase;
+       }
+
+       /* double check that clear address and write pointer are the same */
+       if (clear_addr != le32_to_cpu(fw_log.buff_write_ptr)) {
+               wl1271_error("Calculate of clear addr Clear = %x, write = %x",
+                            clear_addr, le32_to_cpu(fw_log.buff_write_ptr));
+       }
+
+       /* indicate FW about Clear buffer */
+       ret = wlcore_write32(wl, addr + WL18XX_LOGGER_READ_POINT_OFFSET,
+                            fw_log.buff_write_ptr);
+free_out:
+       kfree(buffer);
+out:
+       return le32_to_cpu(fw_log.actual_buff_size);
+}
+EXPORT_SYMBOL_GPL(wlcore_event_fw_logger);
 
 void wlcore_event_rssi_trigger(struct wl1271 *wl, s8 *metric_arr)
 {
 
 
 #define NUM_OF_RSSI_SNR_TRIGGERS 8
 
+struct fw_logger_information {
+       __le32 max_buff_size;
+       __le32 actual_buff_size;
+       __le32 num_trace_drop;
+       __le32 buff_read_ptr;
+       __le32 buff_write_ptr;
+} __packed;
+
 struct wl1271;
 
 int wl1271_event_unmask(struct wl1271 *wl);
 void wlcore_event_inactive_sta(struct wl1271 *wl, unsigned long sta_bitmap);
 void wlcore_event_roc_complete(struct wl1271 *wl);
 void wlcore_event_rssi_trigger(struct wl1271 *wl, s8 *metric_arr);
+int  wlcore_event_fw_logger(struct wl1271 *wl);
 #endif
 
        if (ret < 0)
                goto out;
 
-       /*
-        * We don't need the size of the last partition, as it is
-        * automatically calculated based on the total memory size and
-        * the sizes of the previous partitions.
-        */
        ret = wlcore_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start);
+       if (ret < 0)
+               goto out;
+
+       ret = wlcore_raw_write32(wl, HW_PART3_SIZE_ADDR, p->mem3.size);
+       if (ret < 0)
+               goto out;
 
 out:
        return ret;
 
 #define HW_PART1_START_ADDR             (HW_PARTITION_REGISTERS_ADDR + 12)
 #define HW_PART2_SIZE_ADDR              (HW_PARTITION_REGISTERS_ADDR + 16)
 #define HW_PART2_START_ADDR             (HW_PARTITION_REGISTERS_ADDR + 20)
-#define HW_PART3_START_ADDR             (HW_PARTITION_REGISTERS_ADDR + 24)
-
+#define HW_PART3_SIZE_ADDR              (HW_PARTITION_REGISTERS_ADDR + 24)
+#define HW_PART3_START_ADDR             (HW_PARTITION_REGISTERS_ADDR + 28)
 #define HW_ACCESS_REGISTER_SIZE         4
 
 #define HW_ACCESS_PRAM_MAX_RANGE       0x3c000
 
-
 /*
  * This file is part of wlcore
  *
 
 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;
-               } else if (!strcmp(fwlog_param, "ondemand")) {
-                       wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
+                       wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_HOST;
                } else if (!strcmp(fwlog_param, "dbgpins")) {
                        wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
                        wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
 
 static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
 {
-       struct wlcore_partition_set part, old_part;
-       u32 addr;
-       u32 offset;
-       u32 end_of_log;
-       u8 *block;
-       int ret;
+       u32 end_of_log = 0;
 
-       if ((wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
-           (wl->conf.fwlog.mem_blocks == 0))
+       if (wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED)
                return;
 
        wl1271_info("Reading FW panic log");
 
-       block = kmalloc(wl->fw_mem_block_size, GFP_KERNEL);
-       if (!block)
-               return;
-
        /*
         * Make sure the chip is awake and the logger isn't active.
         * Do not send a stop fwlog command if the fw is hanged or if
         * dbgpins are used (due to some fw bug).
         */
        if (wl1271_ps_elp_wakeup(wl))
-               goto out;
+               return;
        if (!wl->watchdog_recovery &&
            wl->conf.fwlog.output != WL12XX_FWLOG_OUTPUT_DBG_PINS)
                wl12xx_cmd_stop_fwlog(wl);
 
-       /* Read the first memory block address */
-       ret = wlcore_fw_status(wl, wl->fw_status);
-       if (ret < 0)
-               goto out;
-
-       addr = wl->fw_status->log_start_addr;
-       if (!addr)
-               goto out;
-
-       if (wl->conf.fwlog.mode == WL12XX_FWLOG_CONTINUOUS) {
-               offset = sizeof(addr) + sizeof(struct wl1271_rx_descriptor);
-               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 {
-               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;
+               end_of_log = wlcore_event_fw_logger(wl);
+               if (end_of_log == 0) {
+                       msleep(100);
+                       end_of_log = wlcore_event_fw_logger(wl);
                }
-
-               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;
-
-               /*
-                * Memory blocks are linked to one another. The first 4 bytes
-                * of each memory block hold the hardware address of the next
-                * one. The last memory block points to the first one in
-                * on demand mode and is equal to 0x2000000 in continuous mode.
-                */
-               addr = le32_to_cpup((__le32 *)block);
-
-               if (!wl12xx_copy_fwlog(wl, block + offset,
-                                       wl->fw_mem_block_size - offset))
-                       break;
-       } while (addr && (addr != end_of_log));
-
-       wake_up_interruptible(&wl->fwlog_waitq);
-
-out:
-       kfree(block);
-       wlcore_set_partition(wl, &old_part);
+       } while (end_of_log != 0);
 }
 
 static void wlcore_save_freed_pkts(struct wl1271 *wl, struct wl12xx_vif *wlvif,
        wl->active_sta_count = 0;
        wl->active_link_count = 0;
        wl->fwlog_size = 0;
-       init_waitqueue_head(&wl->fwlog_waitq);
 
        /* The system link is always allocated */
        __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
        /* Unblock any fwlog readers */
        mutex_lock(&wl->mutex);
        wl->fwlog_size = -1;
-       wake_up_interruptible_all(&wl->fwlog_waitq);
        mutex_unlock(&wl->mutex);
 
        wlcore_sysfs_free(wl);
 
 module_param_named(fwlog, fwlog_param, charp, 0);
 MODULE_PARM_DESC(fwlog,
-                "FW logger options: continuous, ondemand, dbgpins or disable");
+                "FW logger options: continuous, dbgpins or disable");
 
 module_param(fwlog_mem_blocks, int, S_IRUSR | S_IWUSR);
 MODULE_PARM_DESC(fwlog_mem_blocks, "fwlog mem_blocks");
 
        if (desc->packet_class == WL12XX_RX_CLASS_LOGGER) {
                size_t len = length - sizeof(*desc);
                wl12xx_copy_fwlog(wl, data + sizeof(*desc), len);
-               wake_up_interruptible(&wl->fwlog_waitq);
                return 0;
        }
 
 
        if (ret < 0)
                return -ERESTARTSYS;
 
-       /* Let only one thread read the log at a time, blocking others */
-       while (wl->fwlog_size == 0) {
-               DEFINE_WAIT(wait);
-
-               prepare_to_wait_exclusive(&wl->fwlog_waitq,
-                                         &wait,
-                                         TASK_INTERRUPTIBLE);
-
-               if (wl->fwlog_size != 0) {
-                       finish_wait(&wl->fwlog_waitq, &wait);
-                       break;
-               }
-
-               mutex_unlock(&wl->mutex);
-
-               schedule();
-               finish_wait(&wl->fwlog_waitq, &wait);
-
-               if (signal_pending(current))
-                       return -ERESTARTSYS;
-
-               ret = mutex_lock_interruptible(&wl->mutex);
-               if (ret < 0)
-                       return -ERESTARTSYS;
-       }
-
        /* Check if the fwlog is still valid */
        if (wl->fwlog_size < 0) {
                mutex_unlock(&wl->mutex);
 
        /* FW memory block size */
        u32 fw_mem_block_size;
 
-       /* Sysfs FW log entry readers wait queue */
-       wait_queue_head_t fwlog_waitq;
-
        /* Hardware recovery work */
        struct work_struct recovery_work;
        bool watchdog_recovery;