diff options
author | Bartosz Markowski <bartosz.markowski@tieto.com> | 2013-09-26 11:47:12 -0400 |
---|---|---|
committer | Kalle Valo <kvalo@qca.qualcomm.com> | 2013-09-27 07:58:14 -0400 |
commit | 5e00d31a0fb74c36f3b174ff0d4914cf09016e6f (patch) | |
tree | 9557fe332e411ef341be3fb11951bb5a7c9a8baa /drivers/net/wireless/ath/ath10k/wmi.c | |
parent | b3effe61a1a3b8f20fa4b4d30c4390a6b81a6fc2 (diff) |
ath10k: bring back the WMI path for mgmt frames
This is still the only way to submit mgmt frames in case
of 10.X firmware.
This patch introduces wmi_mgmt_tx queue, because of the
fact WMI command can block. This is a problem for
ath10k_tx_htt(), since it's called from atomic context.
The skb queue and worker are introduced to move the mgmt
frame handling out of .tx callback context and not block.
Signed-off-by: Bartosz Markowski <bartosz.markowski@tieto.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath10k/wmi.c')
-rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi.c | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 97ba23e78abf..8c223671ecc4 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c | |||
@@ -410,6 +410,57 @@ static int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, | |||
410 | return ret; | 410 | return ret; |
411 | } | 411 | } |
412 | 412 | ||
413 | int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb) | ||
414 | { | ||
415 | int ret = 0; | ||
416 | struct wmi_mgmt_tx_cmd *cmd; | ||
417 | struct ieee80211_hdr *hdr; | ||
418 | struct sk_buff *wmi_skb; | ||
419 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
420 | int len; | ||
421 | u16 fc; | ||
422 | |||
423 | hdr = (struct ieee80211_hdr *)skb->data; | ||
424 | fc = le16_to_cpu(hdr->frame_control); | ||
425 | |||
426 | if (WARN_ON_ONCE(!ieee80211_is_mgmt(hdr->frame_control))) | ||
427 | return -EINVAL; | ||
428 | |||
429 | len = sizeof(cmd->hdr) + skb->len; | ||
430 | len = round_up(len, 4); | ||
431 | |||
432 | wmi_skb = ath10k_wmi_alloc_skb(len); | ||
433 | if (!wmi_skb) | ||
434 | return -ENOMEM; | ||
435 | |||
436 | cmd = (struct wmi_mgmt_tx_cmd *)wmi_skb->data; | ||
437 | |||
438 | cmd->hdr.vdev_id = __cpu_to_le32(ATH10K_SKB_CB(skb)->vdev_id); | ||
439 | cmd->hdr.tx_rate = 0; | ||
440 | cmd->hdr.tx_power = 0; | ||
441 | cmd->hdr.buf_len = __cpu_to_le32((u32)(skb->len)); | ||
442 | |||
443 | memcpy(cmd->hdr.peer_macaddr.addr, ieee80211_get_DA(hdr), ETH_ALEN); | ||
444 | memcpy(cmd->buf, skb->data, skb->len); | ||
445 | |||
446 | ath10k_dbg(ATH10K_DBG_WMI, "wmi mgmt tx skb %p len %d ftype %02x stype %02x\n", | ||
447 | wmi_skb, wmi_skb->len, fc & IEEE80211_FCTL_FTYPE, | ||
448 | fc & IEEE80211_FCTL_STYPE); | ||
449 | |||
450 | /* Send the management frame buffer to the target */ | ||
451 | ret = ath10k_wmi_cmd_send(ar, wmi_skb, ar->wmi.cmd->mgmt_tx_cmdid); | ||
452 | if (ret) { | ||
453 | dev_kfree_skb_any(skb); | ||
454 | return ret; | ||
455 | } | ||
456 | |||
457 | /* TODO: report tx status to mac80211 - temporary just ACK */ | ||
458 | info->flags |= IEEE80211_TX_STAT_ACK; | ||
459 | ieee80211_tx_status_irqsafe(ar->hw, skb); | ||
460 | |||
461 | return ret; | ||
462 | } | ||
463 | |||
413 | static int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb) | 464 | static int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb) |
414 | { | 465 | { |
415 | struct wmi_scan_event *event = (struct wmi_scan_event *)skb->data; | 466 | struct wmi_scan_event *event = (struct wmi_scan_event *)skb->data; |