summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/silabs/wfx/data_tx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/silabs/wfx/data_tx.c')
-rw-r--r--drivers/net/wireless/silabs/wfx/data_tx.c54
1 files changed, 46 insertions, 8 deletions
diff --git a/drivers/net/wireless/silabs/wfx/data_tx.c b/drivers/net/wireless/silabs/wfx/data_tx.c
index caa22226b0..a44a7403ce 100644
--- a/drivers/net/wireless/silabs/wfx/data_tx.c
+++ b/drivers/net/wireless/silabs/wfx/data_tx.c
@@ -208,6 +208,36 @@ static bool wfx_is_action_back(struct ieee80211_hdr *hdr)
return true;
}
+struct wfx_tx_priv *wfx_skb_tx_priv(struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *tx_info;
+
+ if (!skb)
+ return NULL;
+ tx_info = IEEE80211_SKB_CB(skb);
+ return (struct wfx_tx_priv *)tx_info->rate_driver_data;
+}
+
+struct wfx_hif_req_tx *wfx_skb_txreq(struct sk_buff *skb)
+{
+ struct wfx_hif_msg *hif = (struct wfx_hif_msg *)skb->data;
+ struct wfx_hif_req_tx *req = (struct wfx_hif_req_tx *)hif->body;
+
+ return req;
+}
+
+struct wfx_vif *wfx_skb_wvif(struct wfx_dev *wdev, struct sk_buff *skb)
+{
+ struct wfx_tx_priv *tx_priv = wfx_skb_tx_priv(skb);
+ struct wfx_hif_msg *hif = (struct wfx_hif_msg *)skb->data;
+
+ if (tx_priv->vif_id != hif->interface && hif->interface != 2) {
+ dev_err(wdev->dev, "corrupted skb");
+ return wdev_to_wvif(wdev, hif->interface);
+ }
+ return wdev_to_wvif(wdev, tx_priv->vif_id);
+}
+
static u8 wfx_tx_get_link_id(struct wfx_vif *wvif, struct ieee80211_sta *sta,
struct ieee80211_hdr *hdr)
{
@@ -321,6 +351,7 @@ static int wfx_tx_inner(struct wfx_vif *wvif, struct ieee80211_sta *sta, struct
/* Fill tx_priv */
tx_priv = (struct wfx_tx_priv *)tx_info->rate_driver_data;
tx_priv->icv_size = wfx_tx_get_icv_len(hw_key);
+ tx_priv->vif_id = wvif->id;
/* Fill hif_msg */
WARN(skb_headroom(skb) < wmsg_len, "not enough space in skb");
@@ -331,7 +362,10 @@ static int wfx_tx_inner(struct wfx_vif *wvif, struct ieee80211_sta *sta, struct
hif_msg = (struct wfx_hif_msg *)skb->data;
hif_msg->len = cpu_to_le16(skb->len);
hif_msg->id = HIF_REQ_ID_TX;
- hif_msg->interface = wvif->id;
+ if (tx_info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
+ hif_msg->interface = 2;
+ else
+ hif_msg->interface = wvif->id;
if (skb->len > le16_to_cpu(wvif->wdev->hw_caps.size_inp_ch_buf)) {
dev_warn(wvif->wdev->dev,
"requested frame size (%d) is larger than maximum supported (%d)\n",
@@ -352,9 +386,15 @@ static int wfx_tx_inner(struct wfx_vif *wvif, struct ieee80211_sta *sta, struct
req->fc_offset = offset;
/* Queue index are inverted between firmware and Linux */
req->queue_id = 3 - queue_id;
- req->peer_sta_id = wfx_tx_get_link_id(wvif, sta, hdr);
- req->retry_policy_index = wfx_tx_get_retry_policy_id(wvif, tx_info);
- req->frame_format = wfx_tx_get_frame_format(tx_info);
+ if (tx_info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {
+ req->peer_sta_id = HIF_LINK_ID_NOT_ASSOCIATED;
+ req->retry_policy_index = HIF_TX_RETRY_POLICY_INVALID;
+ req->frame_format = HIF_FRAME_FORMAT_NON_HT;
+ } else {
+ req->peer_sta_id = wfx_tx_get_link_id(wvif, sta, hdr);
+ req->retry_policy_index = wfx_tx_get_retry_policy_id(wvif, tx_info);
+ req->frame_format = wfx_tx_get_frame_format(tx_info);
+ }
if (tx_info->driver_rates[0].flags & IEEE80211_TX_RC_SHORT_GI)
req->short_gi = 1;
if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM)
@@ -470,7 +510,7 @@ void wfx_tx_confirm_cb(struct wfx_dev *wdev, const struct wfx_hif_cnf_tx *arg)
}
tx_info = IEEE80211_SKB_CB(skb);
tx_priv = wfx_skb_tx_priv(skb);
- wvif = wdev_to_wvif(wdev, ((struct wfx_hif_msg *)skb->data)->interface);
+ wvif = wfx_skb_wvif(wdev, skb);
WARN_ON(!wvif);
if (!wvif)
return;
@@ -532,7 +572,6 @@ void wfx_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, b
struct wfx_dev *wdev = hw->priv;
struct sk_buff_head dropped;
struct wfx_vif *wvif;
- struct wfx_hif_msg *hif;
struct sk_buff *skb;
skb_queue_head_init(&dropped);
@@ -548,8 +587,7 @@ void wfx_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, b
if (wdev->chip_frozen)
wfx_pending_drop(wdev, &dropped);
while ((skb = skb_dequeue(&dropped)) != NULL) {
- hif = (struct wfx_hif_msg *)skb->data;
- wvif = wdev_to_wvif(wdev, hif->interface);
+ wvif = wfx_skb_wvif(wdev, skb);
ieee80211_tx_info_clear_status(IEEE80211_SKB_CB(skb));
wfx_skb_dtor(wvif, skb);
}