return ret;
 }
 
-int wl1271_acx_mem_cfg(struct wl1271 *wl)
+int wl1271_acx_ap_mem_cfg(struct wl1271 *wl)
 {
-       struct wl1271_acx_config_memory *mem_conf;
+       struct wl1271_acx_ap_config_memory *mem_conf;
        int ret;
 
        wl1271_debug(DEBUG_ACX, "wl1271 mem cfg");
        return ret;
 }
 
-int wl1271_acx_init_mem_config(struct wl1271 *wl)
+int wl1271_acx_sta_mem_cfg(struct wl1271 *wl)
 {
+       struct wl1271_acx_sta_config_memory *mem_conf;
        int ret;
 
-       ret = wl1271_acx_mem_cfg(wl);
-       if (ret < 0)
-               return ret;
+       wl1271_debug(DEBUG_ACX, "wl1271 mem cfg");
+
+       mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL);
+       if (!mem_conf) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       /* memory config */
+       mem_conf->num_stations = DEFAULT_NUM_STATIONS;
+       mem_conf->rx_mem_block_num = ACX_RX_MEM_BLOCKS;
+       mem_conf->tx_min_mem_block_num = ACX_TX_MIN_MEM_BLOCKS;
+       mem_conf->num_ssid_profiles = ACX_NUM_SSID_PROFILES;
+       mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS);
+       mem_conf->dyn_mem_enable = wl->conf.mem.dynamic_memory;
+       mem_conf->tx_free_req = wl->conf.mem.min_req_tx_blocks;
+       mem_conf->rx_free_req = wl->conf.mem.min_req_rx_blocks;
+       mem_conf->tx_min = wl->conf.mem.tx_min;
+
+       ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf,
+                                  sizeof(*mem_conf));
+       if (ret < 0) {
+               wl1271_warning("wl1271 mem config failed: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(mem_conf);
+       return ret;
+}
+
+int wl1271_acx_init_mem_config(struct wl1271 *wl)
+{
+       int ret;
 
        wl->target_mem_map = kzalloc(sizeof(struct wl1271_acx_mem_map),
                                     GFP_KERNEL);
 
 #define ACX_TX_DESCRIPTORS    32
 #define ACX_NUM_SSID_PROFILES 1
 
-struct wl1271_acx_config_memory {
+struct wl1271_acx_ap_config_memory {
        struct acx_header header;
 
        u8 rx_mem_block_num;
        __le32 total_tx_descriptors;
 } __packed;
 
+struct wl1271_acx_sta_config_memory {
+       struct acx_header header;
+
+       u8 rx_mem_block_num;
+       u8 tx_min_mem_block_num;
+       u8 num_stations;
+       u8 num_ssid_profiles;
+       __le32 total_tx_descriptors;
+       u8 dyn_mem_enable;
+       u8 tx_free_req;
+       u8 rx_free_req;
+       u8 tx_min;
+} __packed;
+
 struct wl1271_acx_mem_map {
        struct acx_header header;
 
        ACX_HT_BSS_OPERATION        = 0x0058,
        ACX_COEX_ACTIVITY           = 0x0059,
        ACX_SET_DCO_ITRIM_PARAMS    = 0x0061,
+       ACX_GEN_FW_CMD              = 0x0070,
+       ACX_HOST_IF_CFG_BITMAP      = 0x0071,
        ACX_MAX_TX_FAILURE          = 0x0072,
        DOT11_RX_MSDU_LIFE_TIME     = 0x1004,
        DOT11_CUR_TX_PWR            = 0x100D,
        DOT11_GROUP_ADDRESS_TBL     = 0x1014,
        ACX_PM_CONFIG               = 0x1016,
        ACX_CONFIG_PS               = 0x1017,
-
-       MAX_DOT11_IE = DOT11_GROUP_ADDRESS_TBL,
-
-       MAX_IE = 0xFFFF
+       ACX_CONFIG_HANGOVER         = 0x1018,
 };
 
 
                       u32 apsd_conf0, u32 apsd_conf1);
 int wl1271_acx_frag_threshold(struct wl1271 *wl, u16 frag_threshold);
 int wl1271_acx_tx_config_options(struct wl1271 *wl);
-int wl1271_acx_mem_cfg(struct wl1271 *wl);
+int wl1271_acx_ap_mem_cfg(struct wl1271 *wl);
+int wl1271_acx_sta_mem_cfg(struct wl1271 *wl);
 int wl1271_acx_init_mem_config(struct wl1271 *wl);
 int wl1271_acx_init_rx_interrupt(struct wl1271 *wl);
 int wl1271_acx_smart_reflex(struct wl1271 *wl);
 
        join->rx_filter_options = cpu_to_le32(wl->rx_filter);
        join->bss_type = bss_type;
        join->basic_rate_set = cpu_to_le32(wl->basic_rate_set);
+       /*
+        * for supported_rate_set, we should use wl->rate_set. however,
+        * it seems that acx_rate_policies doesn't affect full_rate, and
+        * since we want to avoid additional join, we'll use a 0xffffffff value,
+        * and let the fw find the actual supported rates
+        */
+       join->supported_rate_set = cpu_to_le32(0xffffffff);
 
        if (wl->band == IEEE80211_BAND_5GHZ)
                join->bss_type |= WL1271_JOIN_CMD_BSS_TYPE_5GHZ;
        return ret;
 }
 
-int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, u32 rates, bool send)
+int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode)
 {
        struct wl1271_cmd_ps_params *ps_params = NULL;
        int ret = 0;
        }
 
        ps_params->ps_mode = ps_mode;
-       ps_params->send_null_data = send;
-       ps_params->retries = wl->conf.conn.psm_entry_nullfunc_retries;
-       ps_params->hang_over_period = wl->conf.conn.psm_entry_hangover_period;
-       ps_params->null_data_rate = cpu_to_le32(rates);
 
        ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
                              sizeof(*ps_params), 0);
 
 int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len);
 int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len);
 int wl1271_cmd_data_path(struct wl1271 *wl, bool enable);
-int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, u32 rates, bool send);
+int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode);
 int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
                           size_t len);
 int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
                                  * For CTS-to-self (FastCTS) mechanism
                                  * for BT/WLAN coexistence (SoftGemini). */
        CMD_TEMPL_ARP_RSP,
+       CMD_TEMPL_LINK_MEASUREMENT_REPORT,
 
        /* AP-mode specific */
        CMD_TEMPL_AP_BEACON = 13,
         * ACK or CTS frames).
         */
        __le32 basic_rate_set;
+       __le32 supported_rate_set;
        u8 dtim_interval;
        /*
         * bits 0-2: This bitwise field specifies the type
        struct wl1271_cmd_header header;
 
        u8 ps_mode; /* STATION_* */
-       u8 send_null_data; /* Do we have to send NULL data packet ? */
-       u8 retries; /* Number of retires for the initial NULL data packet */
-
-        /*
-         * TUs during which the target stays awake after switching
-         * to power save mode.
-         */
-       u8 hang_over_period;
-       __le32 null_data_rate;
+       u8 padding[3];
 } __packed;
 
 /* HW encryption keys */
 
        u16 inactivity_timeout;
 };
 
+struct conf_memory_settings {
+       /* Disable/Enable dynamic memory */
+       u8 dynamic_memory;
+
+       /*
+        * Minimum required free tx memory blocks in order to assure optimum
+        * performence
+        *
+        * Range: 0-120
+        */
+       u8 min_req_tx_blocks;
+
+       /*
+        * Minimum required free rx memory blocks in order to assure optimum
+        * performence
+        *
+        * Range: 0-120
+        */
+       u8 min_req_rx_blocks;
+
+       /*
+        * Minimum number of mem blocks (free+used) guaranteed for TX
+        *
+        * Range: 0-120
+        */
+       u8 tx_min;
+};
+
 struct conf_drv_settings {
        struct conf_sg_settings sg;
        struct conf_rx_settings rx;
        struct conf_scan_settings scan;
        struct conf_rf_settings rf;
        struct conf_ht_setting ht;
+       struct conf_memory_settings mem;
 };
 
 #endif
 
                /* go to extremely low power mode */
                wl1271_ps_elp_sleep(wl);
                break;
-       case EVENT_EXIT_POWER_SAVE_FAIL:
-               wl1271_debug(DEBUG_PSM, "PSM exit failed");
-
-               if (test_bit(WL1271_FLAG_PSM, &wl->flags)) {
-                       wl->psm_entry_retry = 0;
-                       break;
-               }
-
-               /* make sure the firmware goes to active mode - the frame to
-                  be sent next will indicate to the AP, that we are active. */
-               ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
-                                        wl->basic_rate, false);
-               break;
-       case EVENT_EXIT_POWER_SAVE_SUCCESS:
        default:
                break;
        }
 
 enum {
        EVENT_ENTER_POWER_SAVE_FAIL = 0,
        EVENT_ENTER_POWER_SAVE_SUCCESS,
-       EVENT_EXIT_POWER_SAVE_FAIL,
-       EVENT_EXIT_POWER_SAVE_SUCCESS,
 };
 
 struct event_debug_report {
 
        if (ret < 0)
                return ret;
 
+       /* PS config */
+       ret = wl1271_acx_config_ps(wl);
+       if (ret < 0)
+               return ret;
+
        ret = wl1271_sta_init_templates_config(wl);
        if (ret < 0)
                return ret;
        if (ret < 0)
                return ret;
 
+       ret = wl1271_acx_sta_mem_cfg(wl);
+       if (ret < 0)
+               return ret;
+
        return 0;
 }
 
        if (ret < 0)
                return ret;
 
+       ret = wl1271_acx_ap_mem_cfg(wl);
+       if (ret < 0)
+               return ret;
+
        return 0;
 }
 
 
                .tx_ba_win_size = 64,
                .inactivity_timeout = 10000,
        },
+       .mem = {
+               .dynamic_memory               = 0,
+               .min_req_tx_blocks            = 104,
+               .min_req_rx_blocks            = 22,
+               .tx_min                       = 27,
+       }
 };
 
 static void __wl1271_op_remove_interface(struct wl1271 *wl);
 }
 
 static void wl1271_fw_status(struct wl1271 *wl,
-                            struct wl1271_fw_status *status)
+                            struct wl1271_fw_full_status *full_status)
 {
+       struct wl1271_fw_common_status *status = &full_status->common;
        struct timespec ts;
        u32 total = 0;
        int i;
 
-       wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
+       if (wl->bss_type == BSS_TYPE_AP_BSS)
+               wl1271_raw_read(wl, FW_STATUS_ADDR, status,
+                               sizeof(struct wl1271_fw_ap_status), false);
+       else
+               wl1271_raw_read(wl, FW_STATUS_ADDR, status,
+                               sizeof(struct wl1271_fw_sta_status), false);
 
        wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
                     "drv_rx_counter = %d, tx_results_counter = %d)",
                loopcount--;
 
                wl1271_fw_status(wl, wl->fw_status);
-               intr = le32_to_cpu(wl->fw_status->intr);
+               intr = le32_to_cpu(wl->fw_status->common.intr);
                if (!intr) {
                        wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
                        spin_lock_irqsave(&wl->wl_lock, flags);
                        wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
 
                        /* check for tx results */
-                       if (wl->fw_status->tx_results_counter !=
+                       if (wl->fw_status->common.tx_results_counter !=
                            (wl->tx_results_count & 0xff))
                                wl1271_tx_complete(wl);
 
                                wl1271_tx_work_locked(wl);
                        }
 
-                       wl1271_rx(wl, wl->fw_status);
+                       wl1271_rx(wl, &wl->fw_status->common);
                }
 
                if (intr & WL1271_ACX_INTR_EVENT_A) {
 
                        return ret;
                }
 
-               ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE,
-                                        rates, send);
+               ret = wl1271_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE);
                if (ret < 0)
                        return ret;
 
                if (ret < 0)
                        return ret;
 
-               ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE,
-                                        rates, send);
+               ret = wl1271_cmd_ps_mode(wl, STATION_ACTIVE_MODE);
                if (ret < 0)
                        return ret;
 
 
 #include "rx.h"
 #include "io.h"
 
-static u8 wl1271_rx_get_mem_block(struct wl1271_fw_status *status,
+static u8 wl1271_rx_get_mem_block(struct wl1271_fw_common_status *status,
                                  u32 drv_rx_counter)
 {
        return le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) &
                RX_MEM_BLOCK_MASK;
 }
 
-static u32 wl1271_rx_get_buf_size(struct wl1271_fw_status *status,
+static u32 wl1271_rx_get_buf_size(struct wl1271_fw_common_status *status,
                                 u32 drv_rx_counter)
 {
        return (le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) &
        return 0;
 }
 
-void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status)
+void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
 {
        struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map;
        u32 buf_size;
 
        u8  reserved;
 } __packed;
 
-void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status);
+void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status);
 u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
 void wl1271_set_default_filters(struct wl1271 *wl);
 
 
 
 
 
-#define WL1271_FW_NAME "wl1271-fw.bin"
+#define WL1271_FW_NAME "wl1271-fw-2.bin"
 #define WL1271_AP_FW_NAME "wl1271-fw-ap.bin"
 
 #define WL1271_NVS_NAME "wl1271-nvs.bin"
 /* Broadcast and Global links + links to stations */
 #define AP_MAX_LINKS               (AP_MAX_STATIONS + 2)
 
-/* FW status registers */
-struct wl1271_fw_status {
+/* FW status registers common for AP/STA */
+struct wl1271_fw_common_status {
        __le32 intr;
        u8  fw_rx_counter;
        u8  drv_rx_counter;
        __le32 rx_pkt_descs[NUM_RX_PKT_DESC];
        __le32 tx_released_blks[NUM_TX_QUEUES];
        __le32 fw_localtime;
+} __packed;
+
+/* FW status registers for AP */
+struct wl1271_fw_ap_status {
+       struct wl1271_fw_common_status common;
 
        /* Next fields valid only in AP FW */
 
        u8 padding_1[1];
 } __packed;
 
+/* FW status registers for STA */
+struct wl1271_fw_sta_status {
+       struct wl1271_fw_common_status common;
+
+       u8  tx_total;
+       u8  reserved1;
+       __le16 reserved2;
+} __packed;
+
+struct wl1271_fw_full_status {
+       union {
+               struct wl1271_fw_common_status common;
+               struct wl1271_fw_sta_status sta;
+               struct wl1271_fw_ap_status ap;
+       };
+} __packed;
+
+
 struct wl1271_rx_mem_pool_addr {
        u32 addr;
        u32 addr_extra;
        u32 buffer_cmd;
        u32 buffer_busyword[WL1271_BUSY_WORD_CNT];
 
-       struct wl1271_fw_status *fw_status;
+       struct wl1271_fw_full_status *fw_status;
        struct wl1271_tx_hw_res_if *tx_res_if;
 
        struct ieee80211_vif *vif;