}
int rtw89_core_tx_kick_off_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *skb,
- int qsel, unsigned int timeout)
+ struct rtw89_tx_wait_info *wait, int qsel,
+ unsigned int timeout)
{
- struct rtw89_tx_skb_data *skb_data = RTW89_TX_SKB_CB(skb);
- struct rtw89_tx_wait_info *wait;
unsigned long time_left;
int ret = 0;
lockdep_assert_wiphy(rtwdev->hw->wiphy);
- wait = kzalloc(sizeof(*wait), GFP_KERNEL);
- if (!wait) {
- rtw89_core_tx_kick_off(rtwdev, qsel);
- return 0;
- }
-
- init_completion(&wait->completion);
- wait->skb = skb;
- rcu_assign_pointer(skb_data->wait, wait);
-
rtw89_core_tx_kick_off(rtwdev, qsel);
time_left = wait_for_completion_timeout(&wait->completion,
msecs_to_jiffies(timeout));
}
int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta, struct sk_buff *skb, int *qsel)
+ struct ieee80211_sta *sta, struct sk_buff *skb, int *qsel,
+ struct rtw89_tx_wait_info *wait)
{
struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
struct rtw89_vif *rtwvif = vif_to_rtwvif(vif);
+ struct rtw89_tx_skb_data *skb_data = RTW89_TX_SKB_CB(skb);
struct rtw89_core_tx_request tx_req = {0};
struct rtw89_sta_link *rtwsta_link = NULL;
struct rtw89_vif_link *rtwvif_link;
rtw89_core_tx_update_desc_info(rtwdev, &tx_req);
rtw89_core_tx_wake(rtwdev, &tx_req);
+ rcu_assign_pointer(skb_data->wait, wait);
+
ret = rtw89_hci_tx_write(rtwdev, &tx_req);
if (ret) {
rtw89_err(rtwdev, "failed to transmit skb to HCI\n");
goto out;
}
rtw89_core_txq_check_agg(rtwdev, rtwtxq, skb);
- ret = rtw89_core_tx_write(rtwdev, vif, sta, skb, NULL);
+ ret = rtw89_core_tx_write(rtwdev, vif, sta, skb, NULL, NULL);
if (ret) {
rtw89_err(rtwdev, "failed to push txq: %d\n", ret);
ieee80211_free_txskb(rtwdev->hw, skb);
skb_queue_walk_safe(&rtwsta->roc_queue, skb, tmp) {
skb_unlink(skb, &rtwsta->roc_queue);
- ret = rtw89_core_tx_write(rtwdev, vif, sta, skb, &qsel);
+ ret = rtw89_core_tx_write(rtwdev, vif, sta, skb, &qsel, NULL);
if (ret) {
rtw89_warn(rtwdev, "pending tx failed with %d\n", ret);
dev_kfree_skb_any(skb);
struct rtw89_vif_link *rtwvif_link, bool qos, bool ps)
{
struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link);
+ struct rtw89_tx_wait_info *wait;
struct ieee80211_sta *sta;
struct ieee80211_hdr *hdr;
struct sk_buff *skb;
if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc)
return 0;
+ wait = kzalloc(sizeof(*wait), GFP_KERNEL);
+ if (!wait)
+ return -ENOMEM;
+
+ init_completion(&wait->completion);
+
rcu_read_lock();
sta = ieee80211_find_sta(vif, vif->cfg.ap_addr);
if (!sta) {
goto out;
}
+ wait->skb = skb;
+
hdr = (struct ieee80211_hdr *)skb->data;
if (ps)
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
- ret = rtw89_core_tx_write(rtwdev, vif, sta, skb, &qsel);
+ ret = rtw89_core_tx_write(rtwdev, vif, sta, skb, &qsel, wait);
if (ret) {
rtw89_warn(rtwdev, "nullfunc transmit failed: %d\n", ret);
dev_kfree_skb_any(skb);
rcu_read_unlock();
- return rtw89_core_tx_kick_off_and_wait(rtwdev, skb, qsel,
+ return rtw89_core_tx_kick_off_and_wait(rtwdev, skb, wait, qsel,
RTW89_ROC_TX_TIMEOUT);
out:
rcu_read_unlock();
+ kfree(wait);
return ret;
}
}
int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta, struct sk_buff *skb, int *qsel);
+ struct ieee80211_sta *sta, struct sk_buff *skb, int *qsel,
+ struct rtw89_tx_wait_info *wait);
int rtw89_h2c_tx(struct rtw89_dev *rtwdev,
struct sk_buff *skb, bool fwdl);
void rtw89_core_tx_kick_off(struct rtw89_dev *rtwdev, u8 qsel);
int rtw89_core_tx_kick_off_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *skb,
- int qsel, unsigned int timeout);
+ struct rtw89_tx_wait_info *wait, int qsel,
+ unsigned int timeout);
void rtw89_core_fill_txdesc(struct rtw89_dev *rtwdev,
struct rtw89_tx_desc_info *desc_info,
void *txdesc);