// SPDX-License-Identifier: GPL-2.0 #include #include #include "softmac_core.h" #include "p2p.h" #include "utils.h" #define RPU_DEBUG_P2P(fmt, ...) \ do { \ if (rpu_debug & RPU_DEBUG_P2P) \ pr_debug(fmt, ##__VA_ARGS__); \ } while (0) void rpu_roc_complete_work(struct work_struct *work) { struct delayed_work *dwork = NULL; struct img_priv *priv = NULL; struct tx_config *tx = NULL; u32 roc_queue = 0; dwork = container_of(work, struct delayed_work, work); priv = container_of(dwork, struct img_priv, roc_complete_work); tx = &priv->tx; if (priv->roc_params.roc_in_progress == 0) return; mutex_lock(&priv->mutex); roc_queue = tx_queue_unmap(UMAC_ROC_AC); /* Stop the ROC queue */ ieee80211_stop_queue(priv->hw, roc_queue); /* Unlock RCU immediately as we are freeing off_chanctx in this funciton * only and because flush_vif_queues sleep */ rcu_read_lock(); rcu_read_unlock(); priv->roc_params.roc_in_progress = 0; if (priv->cancel_roc == 0) { ieee80211_remain_on_channel_expired(priv->hw); RPU_DEBUG_ROC("%s:%d ROC STOPPED..\n", __func__, __LINE__); } else { priv->cancel_hw_roc_done = 1; priv->cancel_roc = 0; RPU_DEBUG_ROC("%s:%d ROC CANCELLED..\n", __func__, __LINE__); } /* Start the ROC queue */ ieee80211_wake_queue(priv->hw, roc_queue); mutex_unlock(&priv->mutex); } int remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_channel *channel, int duration, enum ieee80211_roc_type type) { (void)vif; struct img_priv *priv = (struct img_priv *)hw->priv; unsigned int pri_chnl_num = ieee80211_frequency_to_channel(channel->center_freq); int ret = 0; mutex_lock(&priv->mutex); RPU_DEBUG_ROC("%s:%d The Params are:", __func__, __LINE__); RPU_DEBUG_ROC(" channel:%d duration:%d type: %d\n", ieee80211_frequency_to_channel(channel->center_freq), duration, type); if (priv->roc_params.roc_in_progress) { RPU_DEBUG_ROC("%s:%d Dropping roc...Busy\n", __func__, __LINE__); mutex_unlock(&priv->mutex); return -EBUSY; } /* Inform FW that ROC is started: * For pure TX we send OFFCHANNEL_TX so that driver can terminate ROC * For Tx + Rx we use NORMAL, FW will terminate ROC based on duration. */ if (duration != 10 && type == ROC_TYPE_OFFCHANNEL_TX) type = ROC_TYPE_NORMAL; CALL_RPU(rpu_prog_roc, ROC_START, pri_chnl_num, duration, type); prog_rpu_fail: mutex_unlock(&priv->mutex); return ret; } int cancel_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct img_priv *priv = (struct img_priv *)hw->priv; int ret = 0; mutex_lock(&priv->mutex); if (priv->roc_params.roc_in_progress) { priv->cancel_hw_roc_done = 0; priv->cancel_roc = 1; RPU_DEBUG_ROC("%s:%d Cancelling HW ROC....\n", __func__, __LINE__); CALL_RPU(rpu_prog_roc, ROC_STOP, 0, 0, 0); mutex_unlock(&priv->mutex); if (!wait_for_cancel_hw_roc(priv)) { RPU_DEBUG_ROC("%s:%d Cancel HW ROC....done\n", __func__, __LINE__); ret = 0; } else { RPU_DEBUG_ROC("%s:%d Cancel HW ROC..timedout\n", __func__, __LINE__); ret = -1; } } prog_rpu_fail: mutex_unlock(&priv->mutex); return ret; } void rpu_noa_event(int event, struct lmac_event_noa *noa, void *context, struct sk_buff *skb) { struct img_priv *priv = (struct img_priv *)context; struct ieee80211_vif *vif; struct umac_vif *uvif; bool transmit = false; rcu_read_lock(); vif = (struct ieee80211_vif *)rcu_dereference(priv->vifs[noa->if_index]); if (vif == NULL) { rcu_read_unlock(); return; } uvif = (struct umac_vif *)vif->drv_priv; spin_lock_bh(&uvif->noa_que_lock); if (event == FROM_TX) { if (uvif->noa_active) { if (!uvif->noa_tx_allowed || skb_peek(&uvif->noa_que)) __skb_queue_tail(&uvif->noa_que, skb); else transmit = true; } else transmit = true; } else if (event == FROM_TX_DONE) { if (uvif->noa_active && uvif->noa_tx_allowed) { skb = __skb_dequeue(&uvif->noa_que); if (skb) transmit = true; } } else { /* event = FROM_EVENT_NOA */ uvif->noa_active = noa->noa_active; if (uvif->noa_active) { RPU_DEBUG_P2P("%s: noa active = %d, ", priv->name, noa->noa_active); RPU_DEBUG_P2P("ap_present = %d\n", noa->ap_present); uvif->noa_tx_allowed = noa->ap_present; if (uvif->noa_tx_allowed) { skb = __skb_dequeue(&uvif->noa_que); if (skb) transmit = true; } } else { RPU_DEBUG_P2P("%s: noa active = %d\n", priv->name, noa->noa_active); uvif->noa_tx_allowed = 1; /* Can be done in a better way. For now, just flush the * NoA Queue */ while ((skb = __skb_dequeue(&uvif->noa_que))) dev_kfree_skb_any(skb); } } spin_unlock_bh(&uvif->noa_que_lock); rcu_read_unlock(); if (transmit) { rpu_tx_frame(skb, NULL, priv, false); } }