diff options
author | Michal Kazior <michal.kazior@tieto.com> | 2013-08-09 04:13:33 -0400 |
---|---|---|
committer | Kalle Valo <kvalo@qca.qualcomm.com> | 2013-08-15 09:04:41 -0400 |
commit | 0d9b0438b616479e4decadf2cb7d39a5f4e5360f (patch) | |
tree | f5be3bb28986d5ad255440b686dfeac8d96b5635 | |
parent | 68c8a9b22eeec0b57ba261eec5b642ec1cc5fa16 (diff) |
ath10k: add support for firmware newer than 636
The mgmt_rx event structure has been expanded.
Since the structure header is expanded the payload
(i.e. mgmt frame) is shifted by a few bytes. This
needs to be taken into account in order to support
both old and new firmware.
This introduces a fw_features to keep track of any
FW-related ABI/behaviour changes.
Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
-rw-r--r-- | drivers/net/wireless/ath/ath10k/core.h | 10 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi.c | 32 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi.h | 16 |
3 files changed, 47 insertions, 11 deletions
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index e4bba563ed42..ab05c4c1b0fa 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h | |||
@@ -270,6 +270,14 @@ enum ath10k_state { | |||
270 | ATH10K_STATE_WEDGED, | 270 | ATH10K_STATE_WEDGED, |
271 | }; | 271 | }; |
272 | 272 | ||
273 | enum ath10k_fw_features { | ||
274 | /* wmi_mgmt_rx_hdr contains extra RSSI information */ | ||
275 | ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX = 0, | ||
276 | |||
277 | /* keep last */ | ||
278 | ATH10K_FW_FEATURE_COUNT, | ||
279 | }; | ||
280 | |||
273 | struct ath10k { | 281 | struct ath10k { |
274 | struct ath_common ath_common; | 282 | struct ath_common ath_common; |
275 | struct ieee80211_hw *hw; | 283 | struct ieee80211_hw *hw; |
@@ -288,6 +296,8 @@ struct ath10k { | |||
288 | u32 vht_cap_info; | 296 | u32 vht_cap_info; |
289 | u32 num_rf_chains; | 297 | u32 num_rf_chains; |
290 | 298 | ||
299 | DECLARE_BITMAP(fw_features, ATH10K_FW_FEATURE_COUNT); | ||
300 | |||
291 | struct targetdef *targetdef; | 301 | struct targetdef *targetdef; |
292 | struct hostdef *hostdef; | 302 | struct hostdef *hostdef; |
293 | 303 | ||
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 775fedfd6832..32fd5e735beb 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c | |||
@@ -316,7 +316,9 @@ static inline u8 get_rate_idx(u32 rate, enum ieee80211_band band) | |||
316 | 316 | ||
317 | static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) | 317 | static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) |
318 | { | 318 | { |
319 | struct wmi_mgmt_rx_event *event = (struct wmi_mgmt_rx_event *)skb->data; | 319 | struct wmi_mgmt_rx_event_v1 *ev_v1; |
320 | struct wmi_mgmt_rx_event_v2 *ev_v2; | ||
321 | struct wmi_mgmt_rx_hdr_v1 *ev_hdr; | ||
320 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | 322 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
321 | struct ieee80211_hdr *hdr; | 323 | struct ieee80211_hdr *hdr; |
322 | u32 rx_status; | 324 | u32 rx_status; |
@@ -326,13 +328,24 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) | |||
326 | u32 rate; | 328 | u32 rate; |
327 | u32 buf_len; | 329 | u32 buf_len; |
328 | u16 fc; | 330 | u16 fc; |
331 | int pull_len; | ||
332 | |||
333 | if (test_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features)) { | ||
334 | ev_v2 = (struct wmi_mgmt_rx_event_v2 *)skb->data; | ||
335 | ev_hdr = &ev_v2->hdr.v1; | ||
336 | pull_len = sizeof(*ev_v2); | ||
337 | } else { | ||
338 | ev_v1 = (struct wmi_mgmt_rx_event_v1 *)skb->data; | ||
339 | ev_hdr = &ev_v1->hdr; | ||
340 | pull_len = sizeof(*ev_v1); | ||
341 | } | ||
329 | 342 | ||
330 | channel = __le32_to_cpu(event->hdr.channel); | 343 | channel = __le32_to_cpu(ev_hdr->channel); |
331 | buf_len = __le32_to_cpu(event->hdr.buf_len); | 344 | buf_len = __le32_to_cpu(ev_hdr->buf_len); |
332 | rx_status = __le32_to_cpu(event->hdr.status); | 345 | rx_status = __le32_to_cpu(ev_hdr->status); |
333 | snr = __le32_to_cpu(event->hdr.snr); | 346 | snr = __le32_to_cpu(ev_hdr->snr); |
334 | phy_mode = __le32_to_cpu(event->hdr.phy_mode); | 347 | phy_mode = __le32_to_cpu(ev_hdr->phy_mode); |
335 | rate = __le32_to_cpu(event->hdr.rate); | 348 | rate = __le32_to_cpu(ev_hdr->rate); |
336 | 349 | ||
337 | memset(status, 0, sizeof(*status)); | 350 | memset(status, 0, sizeof(*status)); |
338 | 351 | ||
@@ -359,7 +372,7 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) | |||
359 | status->signal = snr + ATH10K_DEFAULT_NOISE_FLOOR; | 372 | status->signal = snr + ATH10K_DEFAULT_NOISE_FLOOR; |
360 | status->rate_idx = get_rate_idx(rate, status->band); | 373 | status->rate_idx = get_rate_idx(rate, status->band); |
361 | 374 | ||
362 | skb_pull(skb, sizeof(event->hdr)); | 375 | skb_pull(skb, pull_len); |
363 | 376 | ||
364 | hdr = (struct ieee80211_hdr *)skb->data; | 377 | hdr = (struct ieee80211_hdr *)skb->data; |
365 | fc = le16_to_cpu(hdr->frame_control); | 378 | fc = le16_to_cpu(hdr->frame_control); |
@@ -944,6 +957,9 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar, | |||
944 | ar->phy_capability = __le32_to_cpu(ev->phy_capability); | 957 | ar->phy_capability = __le32_to_cpu(ev->phy_capability); |
945 | ar->num_rf_chains = __le32_to_cpu(ev->num_rf_chains); | 958 | ar->num_rf_chains = __le32_to_cpu(ev->num_rf_chains); |
946 | 959 | ||
960 | if (ar->fw_version_build > 636) | ||
961 | set_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features); | ||
962 | |||
947 | if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) { | 963 | if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) { |
948 | ath10k_warn("hardware advertises support for more spatial streams than it should (%d > %d)\n", | 964 | ath10k_warn("hardware advertises support for more spatial streams than it should (%d > %d)\n", |
949 | ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM); | 965 | ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM); |
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 2c5a4f8daf2e..08860c475721 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h | |||
@@ -1268,7 +1268,7 @@ struct wmi_scan_event { | |||
1268 | * good idea to pass all the fields in the RX status | 1268 | * good idea to pass all the fields in the RX status |
1269 | * descriptor up to the host. | 1269 | * descriptor up to the host. |
1270 | */ | 1270 | */ |
1271 | struct wmi_mgmt_rx_hdr { | 1271 | struct wmi_mgmt_rx_hdr_v1 { |
1272 | __le32 channel; | 1272 | __le32 channel; |
1273 | __le32 snr; | 1273 | __le32 snr; |
1274 | __le32 rate; | 1274 | __le32 rate; |
@@ -1277,8 +1277,18 @@ struct wmi_mgmt_rx_hdr { | |||
1277 | __le32 status; /* %WMI_RX_STATUS_ */ | 1277 | __le32 status; /* %WMI_RX_STATUS_ */ |
1278 | } __packed; | 1278 | } __packed; |
1279 | 1279 | ||
1280 | struct wmi_mgmt_rx_event { | 1280 | struct wmi_mgmt_rx_hdr_v2 { |
1281 | struct wmi_mgmt_rx_hdr hdr; | 1281 | struct wmi_mgmt_rx_hdr_v1 v1; |
1282 | __le32 rssi_ctl[4]; | ||
1283 | } __packed; | ||
1284 | |||
1285 | struct wmi_mgmt_rx_event_v1 { | ||
1286 | struct wmi_mgmt_rx_hdr_v1 hdr; | ||
1287 | u8 buf[0]; | ||
1288 | } __packed; | ||
1289 | |||
1290 | struct wmi_mgmt_rx_event_v2 { | ||
1291 | struct wmi_mgmt_rx_hdr_v2 hdr; | ||
1282 | u8 buf[0]; | 1292 | u8 buf[0]; |
1283 | } __packed; | 1293 | } __packed; |
1284 | 1294 | ||