return wlcore_set_key(wl, cmd, vif, sta, key_conf);
 }
 
+static int wl12xx_set_peer_cap(struct wl1271 *wl,
+                              struct ieee80211_sta_ht_cap *ht_cap,
+                              bool allow_ht_operation,
+                              u32 rate_set, u8 hlid)
+{
+       return wl1271_acx_set_ht_capabilities(wl, ht_cap, allow_ht_operation,
+                                             hlid);
+}
+
 static int wl12xx_setup(struct wl1271 *wl);
 
 static struct wlcore_ops wl12xx_ops = {
        .set_key                = wl12xx_set_key,
        .channel_switch         = wl12xx_cmd_channel_switch,
        .pre_pkt_send           = NULL,
+       .set_peer_cap           = wl12xx_set_peer_cap,
 };
 
 static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
 
        return ret;
 
 }
+
+/*
+ * this command is basically the same as wl1271_acx_ht_capabilities,
+ * with the addition of supported rates. they should be unified in
+ * the next fw api change
+ */
+int wl18xx_acx_set_peer_cap(struct wl1271 *wl,
+                           struct ieee80211_sta_ht_cap *ht_cap,
+                           bool allow_ht_operation,
+                           u32 rate_set, u8 hlid)
+{
+       struct wlcore_acx_peer_cap *acx;
+       int ret = 0;
+       u32 ht_capabilites = 0;
+
+       wl1271_debug(DEBUG_ACX,
+                    "acx set cap ht_supp: %d ht_cap: %d rates: 0x%x",
+                    ht_cap->ht_supported, ht_cap->cap, rate_set);
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+       if (!acx) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       if (allow_ht_operation && ht_cap->ht_supported) {
+               /* no need to translate capabilities - use the spec values */
+               ht_capabilites = ht_cap->cap;
+
+               /*
+                * this bit is not employed by the spec but only by FW to
+                * indicate peer HT support
+                */
+               ht_capabilites |= WL12XX_HT_CAP_HT_OPERATION;
+
+               /* get data from A-MPDU parameters field */
+               acx->ampdu_max_length = ht_cap->ampdu_factor;
+               acx->ampdu_min_spacing = ht_cap->ampdu_density;
+       }
+
+       acx->hlid = hlid;
+       acx->ht_capabilites = cpu_to_le32(ht_capabilites);
+       acx->supported_rates = cpu_to_le32(rate_set);
+
+       ret = wl1271_cmd_configure(wl, ACX_PEER_CAP, acx, sizeof(*acx));
+       if (ret < 0) {
+               wl1271_warning("acx ht capabilities setting failed: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(acx);
+       return ret;
+}
 
        u8 padding[2];
 };
 
+/*
+ * ACX_PEER_CAP
+ * this struct is very similar to wl1271_acx_ht_capabilities, with the
+ * addition of supported rates
+ */
+struct wlcore_acx_peer_cap {
+       struct acx_header header;
+
+       /* bitmask of capability bits supported by the peer */
+       __le32 ht_capabilites;
+
+       /* rates supported by the remote peer */
+       __le32 supported_rates;
+
+       /* Indicates to which link these capabilities apply. */
+       u8 hlid;
+
+       /*
+        * This the maximum A-MPDU length supported by the AP. The FW may not
+        * exceed this length when sending A-MPDUs
+        */
+       u8 ampdu_max_length;
+
+       /* This is the minimal spacing required when sending A-MPDUs to the AP*/
+       u8 ampdu_min_spacing;
+
+       u8 padding;
+} __packed;
+
 int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,
                                  u32 sdio_blk_size, u32 extra_mem_blks,
                                  u32 len_field_size);
 int wl18xx_acx_set_checksum_state(struct wl1271 *wl);
 int wl18xx_acx_clear_statistics(struct wl1271 *wl);
 int wl18xx_acx_peer_ht_operation_mode(struct wl1271 *wl, u8 hlid, bool wide);
+int wl18xx_acx_set_peer_cap(struct wl1271 *wl,
+                           struct ieee80211_sta_ht_cap *ht_cap,
+                           bool allow_ht_operation,
+                           u32 rate_set, u8 hlid);
 
 #endif /* __WL18XX_ACX_H__ */
 
        mutex_unlock(&wl->mutex);
 }
 
+static int wl18xx_set_peer_cap(struct wl1271 *wl,
+                              struct ieee80211_sta_ht_cap *ht_cap,
+                              bool allow_ht_operation,
+                              u32 rate_set, u8 hlid)
+{
+       return wl18xx_acx_set_peer_cap(wl, ht_cap, allow_ht_operation,
+                                      rate_set, hlid);
+}
 
 static int wl18xx_setup(struct wl1271 *wl);
 
        .channel_switch = wl18xx_cmd_channel_switch,
        .pre_pkt_send   = wl18xx_pre_pkt_send,
        .sta_rc_update  = wl18xx_sta_rc_update,
+       .set_peer_cap   = wl18xx_set_peer_cap,
 };
 
 /* HT cap appropriate for wide channels in 2Ghz */
 
        kfree(acx);
        return ret;
 }
+EXPORT_SYMBOL_GPL(wl1271_acx_set_ht_capabilities);
+
 
 int wl1271_acx_set_ht_information(struct wl1271 *wl,
                                   struct wl12xx_vif *wlvif,
 
        cmd->sta.hlid = wlvif->sta.hlid;
        cmd->sta.session = wl->session_ids[wlvif->sta.hlid];
        /*
-        * We don't have the correct remote rates in this stage, and there
-        * is no way to update them later, so use our supported rates instead.
-        * The fw will take the configured rate policies into account anyway.
+        * We don't have the correct remote rates in this stage. the rates
+        * will be reconfigured later, after authorization.
         */
-       cmd->sta.remote_rates = cpu_to_le32(supported_rates);
+       cmd->sta.remote_rates = cpu_to_le32(wlvif->rate_set);
 
        wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d "
                     "basic_rate_set: 0x%x, remote_rates: 0x%x",
 
                wl->ops->sta_rc_update(wl, wlvif, sta, changed);
 }
 
+static inline int
+wlcore_hw_set_peer_cap(struct wl1271 *wl,
+                      struct ieee80211_sta_ht_cap *ht_cap,
+                      bool allow_ht_operation,
+                      u32 rate_set, u8 hlid)
+{
+       if (wl->ops->set_peer_cap)
+               return wl->ops->set_peer_cap(wl, ht_cap, allow_ht_operation,
+                                            rate_set, hlid);
+
+       return 0;
+}
+
 #endif
 
                bool enabled =
                        bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT;
 
-               ret = wl1271_acx_set_ht_capabilities(wl,
-                                                    &sta_ht_cap,
-                                                    enabled,
-                                                    wlvif->sta.hlid);
+               ret = wlcore_hw_set_peer_cap(wl,
+                                            &sta_ht_cap,
+                                            enabled,
+                                            wlvif->rate_set,
+                                            wlvif->sta.hlid);
                if (ret < 0) {
                        wl1271_warning("Set ht cap failed %d", ret);
                        goto out;
 
        u32 (*pre_pkt_send)(struct wl1271 *wl, u32 buf_offset, u32 last_len);
        void (*sta_rc_update)(struct wl1271 *wl, struct wl12xx_vif *wlvif,
                              struct ieee80211_sta *sta, u32 changed);
+       int (*set_peer_cap)(struct wl1271 *wl,
+                           struct ieee80211_sta_ht_cap *ht_cap,
+                           bool allow_ht_operation,
+                           u32 rate_set, u8 hlid);
+
 };
 
 enum wlcore_partitions {