|
@@ -2599,6 +2599,115 @@ static void ath6kl_wmi_relinquish_implicit_pstream_credits(struct wmi *wmi)
|
|
|
spin_unlock_bh(&wmi->lock);
|
|
|
}
|
|
|
|
|
|
+static int ath6kl_set_bitrate_mask64(struct wmi *wmi, u8 if_idx,
|
|
|
+ const struct cfg80211_bitrate_mask *mask)
|
|
|
+{
|
|
|
+ struct sk_buff *skb;
|
|
|
+ int ret, mode, band;
|
|
|
+ u64 mcsrate, ratemask[IEEE80211_NUM_BANDS];
|
|
|
+ struct wmi_set_tx_select_rates64_cmd *cmd;
|
|
|
+
|
|
|
+ memset(&ratemask, 0, sizeof(ratemask));
|
|
|
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
|
|
|
+ /* copy legacy rate mask */
|
|
|
+ ratemask[band] = mask->control[band].legacy;
|
|
|
+ if (band == IEEE80211_BAND_5GHZ)
|
|
|
+ ratemask[band] =
|
|
|
+ mask->control[band].legacy << 4;
|
|
|
+
|
|
|
+ /* copy mcs rate mask */
|
|
|
+ mcsrate = mask->control[band].mcs[1];
|
|
|
+ mcsrate <<= 8;
|
|
|
+ mcsrate |= mask->control[band].mcs[0];
|
|
|
+ ratemask[band] |= mcsrate << 12;
|
|
|
+ ratemask[band] |= mcsrate << 28;
|
|
|
+ }
|
|
|
+
|
|
|
+ ath6kl_dbg(ATH6KL_DBG_WMI,
|
|
|
+ "Ratemask 64 bit: 2.4:%llx 5:%llx\n",
|
|
|
+ ratemask[0], ratemask[1]);
|
|
|
+
|
|
|
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd) * WMI_RATES_MODE_MAX);
|
|
|
+ if (!skb)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ cmd = (struct wmi_set_tx_select_rates64_cmd *) skb->data;
|
|
|
+ for (mode = 0; mode < WMI_RATES_MODE_MAX; mode++) {
|
|
|
+ /* A mode operate in 5GHZ band */
|
|
|
+ if (mode == WMI_RATES_MODE_11A ||
|
|
|
+ mode == WMI_RATES_MODE_11A_HT20 ||
|
|
|
+ mode == WMI_RATES_MODE_11A_HT40)
|
|
|
+ band = IEEE80211_BAND_5GHZ;
|
|
|
+ else
|
|
|
+ band = IEEE80211_BAND_2GHZ;
|
|
|
+ cmd->ratemask[mode] = cpu_to_le64(ratemask[band]);
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
|
|
|
+ WMI_SET_TX_SELECT_RATES_CMDID,
|
|
|
+ NO_SYNC_WMIFLAG);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int ath6kl_set_bitrate_mask32(struct wmi *wmi, u8 if_idx,
|
|
|
+ const struct cfg80211_bitrate_mask *mask)
|
|
|
+{
|
|
|
+ struct sk_buff *skb;
|
|
|
+ int ret, mode, band;
|
|
|
+ u32 mcsrate, ratemask[IEEE80211_NUM_BANDS];
|
|
|
+ struct wmi_set_tx_select_rates32_cmd *cmd;
|
|
|
+
|
|
|
+ memset(&ratemask, 0, sizeof(ratemask));
|
|
|
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
|
|
|
+ /* copy legacy rate mask */
|
|
|
+ ratemask[band] = mask->control[band].legacy;
|
|
|
+ if (band == IEEE80211_BAND_5GHZ)
|
|
|
+ ratemask[band] =
|
|
|
+ mask->control[band].legacy << 4;
|
|
|
+
|
|
|
+ /* copy mcs rate mask */
|
|
|
+ mcsrate = mask->control[band].mcs[0];
|
|
|
+ ratemask[band] |= mcsrate << 12;
|
|
|
+ ratemask[band] |= mcsrate << 20;
|
|
|
+ }
|
|
|
+
|
|
|
+ ath6kl_dbg(ATH6KL_DBG_WMI,
|
|
|
+ "Ratemask 32 bit: 2.4:%x 5:%x\n",
|
|
|
+ ratemask[0], ratemask[1]);
|
|
|
+
|
|
|
+ skb = ath6kl_wmi_get_new_buf(sizeof(*cmd) * WMI_RATES_MODE_MAX);
|
|
|
+ if (!skb)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ cmd = (struct wmi_set_tx_select_rates32_cmd *) skb->data;
|
|
|
+ for (mode = 0; mode < WMI_RATES_MODE_MAX; mode++) {
|
|
|
+ /* A mode operate in 5GHZ band */
|
|
|
+ if (mode == WMI_RATES_MODE_11A ||
|
|
|
+ mode == WMI_RATES_MODE_11A_HT20 ||
|
|
|
+ mode == WMI_RATES_MODE_11A_HT40)
|
|
|
+ band = IEEE80211_BAND_5GHZ;
|
|
|
+ else
|
|
|
+ band = IEEE80211_BAND_2GHZ;
|
|
|
+ cmd->ratemask[mode] = cpu_to_le32(ratemask[band]);
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
|
|
|
+ WMI_SET_TX_SELECT_RATES_CMDID,
|
|
|
+ NO_SYNC_WMIFLAG);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+int ath6kl_wmi_set_bitrate_mask(struct wmi *wmi, u8 if_idx,
|
|
|
+ const struct cfg80211_bitrate_mask *mask)
|
|
|
+{
|
|
|
+ struct ath6kl *ar = wmi->parent_dev;
|
|
|
+
|
|
|
+ if (ar->hw.flags & ATH6KL_HW_FLAG_64BIT_RATES)
|
|
|
+ return ath6kl_set_bitrate_mask64(wmi, if_idx, mask);
|
|
|
+ else
|
|
|
+ return ath6kl_set_bitrate_mask32(wmi, if_idx, mask);
|
|
|
+}
|
|
|
+
|
|
|
int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx,
|
|
|
enum ath6kl_host_mode host_mode)
|
|
|
{
|