wlcore: add ACX_PEER_CAP command
authorEliad Peller <eliad@wizery.com>
Wed, 28 Nov 2012 09:42:31 +0000 (11:42 +0200)
committerLuciano Coelho <coelho@ti.com>
Tue, 11 Dec 2012 07:35:34 +0000 (09:35 +0200)
ACX_PEER_CAP command is just ACX_PEER_HT_CAP, but allows
configuring the peer's support rates as well.

this is needed because we start the station role when
the remote rates are not known yet.

the two commands should be unified in future fw versions,
but for now add a new set_peer_cap per-hw op, that will
use ACX_PEER_CAP for 18xx, and ACX_PEER_HT_CAP for 12xx.

Signed-off-by: Eliad Peller <eliad@wizery.com>
Signed-off-by: Arik Nemtsov <arik@wizery.com>
Signed-off-by: Luciano Coelho <coelho@ti.com>
drivers/net/wireless/ti/wl12xx/main.c
drivers/net/wireless/ti/wl18xx/acx.c
drivers/net/wireless/ti/wl18xx/acx.h
drivers/net/wireless/ti/wl18xx/main.c
drivers/net/wireless/ti/wlcore/acx.c
drivers/net/wireless/ti/wlcore/cmd.c
drivers/net/wireless/ti/wlcore/hw_ops.h
drivers/net/wireless/ti/wlcore/main.c
drivers/net/wireless/ti/wlcore/wlcore.h

index 64dffafa35fb6a19dd24944d1bc9615a7f976980..8b4827f47deb8fd941043cbe905fe47343031767 100644 (file)
@@ -1616,6 +1616,15 @@ static int wl12xx_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
        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 = {
@@ -1651,6 +1660,7 @@ 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 = {
index 801d8af5cef22a53d7bc45a5d4c76904e285f03d..a169bb5a5dbf7984c0cdb52390492e0d6a27fbb0 100644 (file)
@@ -140,3 +140,57 @@ out:
        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;
+}
index b57e3483509d28636cbd735765b96293abb391d3..0e636def1217b9c150f323fcbbc8bd5214bf0386 100644 (file)
@@ -297,11 +297,44 @@ struct wlcore_peer_ht_operation_mode {
        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__ */
index a5119d3d5e70263f0b5b19f291cd93997a762447..55fd46b9628df47362e4925cd7a515c93ac113fb 100644 (file)
@@ -1386,6 +1386,14 @@ out:
        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);
 
@@ -1423,6 +1431,7 @@ static struct wlcore_ops wl18xx_ops = {
        .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 */
index 9c32f0c840d7a9c93e08f74b4ebb9016e4f7fa64..c79654323396cb6fd73b5dff82b44f72e1148d08 100644 (file)
@@ -1340,6 +1340,8 @@ out:
        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,
index 56432c8cda00c564f25918cbdc96997f4c39fadf..1fbee0d518723bfaf3daea362211729a8d1c8194 100644 (file)
@@ -506,11 +506,10 @@ int wl12xx_cmd_role_start_sta(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",
index 0e0b6563a3ff01ef5b397a024738bef3bd65e667..4db03e14acf7e1afead38c74b35e445c0a4c5d53 100644 (file)
@@ -209,4 +209,17 @@ wlcore_hw_sta_rc_update(struct wl1271 *wl, struct wl12xx_vif *wlvif,
                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
index 486b7fa0259c95317d2cd4e8cc1bb17e3ed77b3f..fed227c88a8af0d17fc2edff26145134d4ceb185 100644 (file)
@@ -4132,10 +4132,11 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
                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;
index e8245f36a67ec52893e065ce4534148726db1866..a4441164bb4b03d38eed39fec97ca1b77b17409d 100644 (file)
@@ -106,6 +106,11 @@ struct wlcore_ops {
        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 {