ath10k: prevent HTC from being used after stopping
It was possible to submit new HTC commands after/while HTC stopped. This led to memory corruption in some rare cases. Signed-off-by: Michal Kazior <michal.kazior@tieto.com> Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
This commit is contained in:
parent
278c4a85e6
commit
08fe9b40d0
|
@ -254,10 +254,14 @@ int ath10k_htc_send(struct ath10k_htc *htc,
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
skb_push(skb, sizeof(struct ath10k_htc_hdr));
|
|
||||||
|
|
||||||
spin_lock_bh(&htc->tx_lock);
|
spin_lock_bh(&htc->tx_lock);
|
||||||
|
if (htc->stopped) {
|
||||||
|
spin_unlock_bh(&htc->tx_lock);
|
||||||
|
return -ESHUTDOWN;
|
||||||
|
}
|
||||||
|
|
||||||
__skb_queue_tail(&ep->tx_queue, skb);
|
__skb_queue_tail(&ep->tx_queue, skb);
|
||||||
|
skb_push(skb, sizeof(struct ath10k_htc_hdr));
|
||||||
spin_unlock_bh(&htc->tx_lock);
|
spin_unlock_bh(&htc->tx_lock);
|
||||||
|
|
||||||
queue_work(htc->ar->workqueue, &ep->send_work);
|
queue_work(htc->ar->workqueue, &ep->send_work);
|
||||||
|
@ -270,23 +274,17 @@ static int ath10k_htc_tx_completion_handler(struct ath10k *ar,
|
||||||
{
|
{
|
||||||
struct ath10k_htc *htc = &ar->htc;
|
struct ath10k_htc *htc = &ar->htc;
|
||||||
struct ath10k_htc_ep *ep = &htc->endpoint[eid];
|
struct ath10k_htc_ep *ep = &htc->endpoint[eid];
|
||||||
bool stopping;
|
|
||||||
|
|
||||||
ath10k_htc_notify_tx_completion(ep, skb);
|
ath10k_htc_notify_tx_completion(ep, skb);
|
||||||
/* the skb now belongs to the completion handler */
|
/* the skb now belongs to the completion handler */
|
||||||
|
|
||||||
|
/* note: when using TX credit flow, the re-checking of queues happens
|
||||||
|
* when credits flow back from the target. in the non-TX credit case,
|
||||||
|
* we recheck after the packet completes */
|
||||||
spin_lock_bh(&htc->tx_lock);
|
spin_lock_bh(&htc->tx_lock);
|
||||||
stopping = htc->stopping;
|
if (!ep->tx_credit_flow_enabled && !htc->stopped)
|
||||||
spin_unlock_bh(&htc->tx_lock);
|
|
||||||
|
|
||||||
if (!ep->tx_credit_flow_enabled && !stopping)
|
|
||||||
/*
|
|
||||||
* note: when using TX credit flow, the re-checking of
|
|
||||||
* queues happens when credits flow back from the target.
|
|
||||||
* in the non-TX credit case, we recheck after the packet
|
|
||||||
* completes
|
|
||||||
*/
|
|
||||||
queue_work(ar->workqueue, &ep->send_work);
|
queue_work(ar->workqueue, &ep->send_work);
|
||||||
|
spin_unlock_bh(&htc->tx_lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -951,7 +949,7 @@ void ath10k_htc_stop(struct ath10k_htc *htc)
|
||||||
struct ath10k_htc_ep *ep;
|
struct ath10k_htc_ep *ep;
|
||||||
|
|
||||||
spin_lock_bh(&htc->tx_lock);
|
spin_lock_bh(&htc->tx_lock);
|
||||||
htc->stopping = true;
|
htc->stopped = true;
|
||||||
spin_unlock_bh(&htc->tx_lock);
|
spin_unlock_bh(&htc->tx_lock);
|
||||||
|
|
||||||
for (i = ATH10K_HTC_EP_0; i < ATH10K_HTC_EP_COUNT; i++) {
|
for (i = ATH10K_HTC_EP_0; i < ATH10K_HTC_EP_COUNT; i++) {
|
||||||
|
@ -972,6 +970,7 @@ int ath10k_htc_init(struct ath10k *ar)
|
||||||
|
|
||||||
spin_lock_init(&htc->tx_lock);
|
spin_lock_init(&htc->tx_lock);
|
||||||
|
|
||||||
|
htc->stopped = false;
|
||||||
ath10k_htc_reset_endpoint_states(htc);
|
ath10k_htc_reset_endpoint_states(htc);
|
||||||
|
|
||||||
/* setup HIF layer callbacks */
|
/* setup HIF layer callbacks */
|
||||||
|
|
|
@ -335,7 +335,7 @@ struct ath10k_htc {
|
||||||
struct ath10k *ar;
|
struct ath10k *ar;
|
||||||
struct ath10k_htc_ep endpoint[ATH10K_HTC_EP_COUNT];
|
struct ath10k_htc_ep endpoint[ATH10K_HTC_EP_COUNT];
|
||||||
|
|
||||||
/* protects endpoint and stopping fields */
|
/* protects endpoint and stopped fields */
|
||||||
spinlock_t tx_lock;
|
spinlock_t tx_lock;
|
||||||
|
|
||||||
struct ath10k_htc_ops htc_ops;
|
struct ath10k_htc_ops htc_ops;
|
||||||
|
@ -349,7 +349,7 @@ struct ath10k_htc {
|
||||||
struct ath10k_htc_svc_tx_credits service_tx_alloc[ATH10K_HTC_EP_COUNT];
|
struct ath10k_htc_svc_tx_credits service_tx_alloc[ATH10K_HTC_EP_COUNT];
|
||||||
int target_credit_size;
|
int target_credit_size;
|
||||||
|
|
||||||
bool stopping;
|
bool stopped;
|
||||||
};
|
};
|
||||||
|
|
||||||
int ath10k_htc_init(struct ath10k *ar);
|
int ath10k_htc_init(struct ath10k *ar);
|
||||||
|
|
Loading…
Reference in New Issue