From c505cdc689d8bfbb586263d80f9a96f730fa8f17 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Tue, 16 May 2017 12:15:51 +0530 Subject: [PATCH] qcacmn: Fix race condition in tx lookup queue during tx completion Tx lookup queue holds the reference of the packet that is successfully transmitted via CE pipe. Tx lookup queue method can be called from tx path and from tasklet simultaneously for the same endpoint. One context can get the packet reference in its local lookup Queue and the other context may not find the reference as this is not brought back from lookupQueue to TxLookupQueue. Fix this by adding a per endpoint lookup queue lock. Change-Id: I0f4872f695e9ab15c27c91e733449f03871f4262 CRs-Fixed: 2047390 --- htc/htc.c | 11 ++++++++++- htc/htc_internal.h | 23 +++++++++++++---------- htc/htc_send.c | 5 +++++ 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/htc/htc.c b/htc/htc.c index 96bf64b8d0..66874377d4 100644 --- a/htc/htc.c +++ b/htc/htc.c @@ -142,7 +142,8 @@ void htc_dump(HTC_HANDLE HTCHandle, uint8_t CmdId, bool start) static void htc_cleanup(HTC_TARGET *target) { HTC_PACKET *pPacket; - /* qdf_nbuf_t netbuf; */ + int i; + HTC_ENDPOINT *endpoint; if (target->hif_dev != NULL) { hif_detach_htc(target->hif_dev); @@ -180,6 +181,10 @@ static void htc_cleanup(HTC_TARGET *target) qdf_spinlock_destroy(&target->HTCRxLock); qdf_spinlock_destroy(&target->HTCTxLock); qdf_spinlock_destroy(&target->HTCCreditLock); + for (i = 0; i < ENDPOINT_MAX; i++) { + endpoint = &target->endpoint[i]; + qdf_spinlock_destroy(&endpoint->lookup_queue_lock); + } /* free our instance */ qdf_mem_free(target); @@ -262,6 +267,10 @@ HTC_HANDLE htc_create(void *ol_sc, struct htc_init_info *pInfo, qdf_spinlock_create(&target->HTCRxLock); qdf_spinlock_create(&target->HTCTxLock); qdf_spinlock_create(&target->HTCCreditLock); + for (i = 0; i < ENDPOINT_MAX; i++) { + pEndpoint = &target->endpoint[i]; + qdf_spinlock_create(&pEndpoint->lookup_queue_lock); + } target->is_nodrop_pkt = false; target->wmi_ep_count = 1; diff --git a/htc/htc_internal.h b/htc/htc_internal.h index 097055bb8d..04686c58a2 100644 --- a/htc/htc_internal.h +++ b/htc/htc_internal.h @@ -174,6 +174,7 @@ typedef struct _HTC_ENDPOINT { #endif bool TxCreditFlowEnabled; bool async_update; /* packets can be queued asynchronously */ + qdf_spinlock_t lookup_queue_lock; } HTC_ENDPOINT; #ifdef HTC_EP_STAT_PROFILING @@ -279,16 +280,18 @@ do { \ } while (0) #endif -#define HTC_STATE_STOPPING (1 << 0) -#define HTC_STOPPING(t) ((t)->HTCStateFlags & HTC_STATE_STOPPING) -#define LOCK_HTC(t) qdf_spin_lock_bh(&(t)->HTCLock) -#define UNLOCK_HTC(t) qdf_spin_unlock_bh(&(t)->HTCLock) -#define LOCK_HTC_RX(t) qdf_spin_lock_bh(&(t)->HTCRxLock) -#define UNLOCK_HTC_RX(t) qdf_spin_unlock_bh(&(t)->HTCRxLock) -#define LOCK_HTC_TX(t) qdf_spin_lock_bh(&(t)->HTCTxLock) -#define UNLOCK_HTC_TX(t) qdf_spin_unlock_bh(&(t)->HTCTxLock) -#define LOCK_HTC_CREDIT(t) qdf_spin_lock_bh(&(t)->HTCCreditLock) -#define UNLOCK_HTC_CREDIT(t) qdf_spin_unlock_bh(&(t)->HTCCreditLock) +#define HTC_STATE_STOPPING (1 << 0) +#define HTC_STOPPING(t) ((t)->HTCStateFlags & HTC_STATE_STOPPING) +#define LOCK_HTC(t) qdf_spin_lock_bh(&(t)->HTCLock) +#define UNLOCK_HTC(t) qdf_spin_unlock_bh(&(t)->HTCLock) +#define LOCK_HTC_RX(t) qdf_spin_lock_bh(&(t)->HTCRxLock) +#define UNLOCK_HTC_RX(t) qdf_spin_unlock_bh(&(t)->HTCRxLock) +#define LOCK_HTC_TX(t) qdf_spin_lock_bh(&(t)->HTCTxLock) +#define UNLOCK_HTC_TX(t) qdf_spin_unlock_bh(&(t)->HTCTxLock) +#define LOCK_HTC_CREDIT(t) qdf_spin_lock_bh(&(t)->HTCCreditLock) +#define UNLOCK_HTC_CREDIT(t) qdf_spin_unlock_bh(&(t)->HTCCreditLock) +#define LOCK_HTC_EP_TX_LOOKUP(t) qdf_spin_lock_bh(&(t)->lookup_queue_lock) +#define UNLOCK_HTC_EP_TX_LOOKUP(t) qdf_spin_unlock_bh(&(t)->lookup_queue_lock) #define GET_HTC_TARGET_FROM_HANDLE(hnd) ((HTC_TARGET *)(hnd)) diff --git a/htc/htc_send.c b/htc/htc_send.c index ccebf5b4d4..7503469abb 100644 --- a/htc/htc_send.c +++ b/htc/htc_send.c @@ -1901,6 +1901,8 @@ static HTC_PACKET *htc_lookup_tx_packet(HTC_TARGET *target, HTC_PACKET_QUEUE lookupQueue; INIT_HTC_PACKET_QUEUE(&lookupQueue); + LOCK_HTC_EP_TX_LOOKUP(pEndpoint); + LOCK_HTC_TX(target); /* mark that HIF has indicated the send complete for another packet */ @@ -1910,10 +1912,12 @@ static HTC_PACKET *htc_lookup_tx_packet(HTC_TARGET *target, pPacket = htc_packet_dequeue(&pEndpoint->TxLookupQueue); if (qdf_unlikely(!pPacket)) { UNLOCK_HTC_TX(target); + UNLOCK_HTC_EP_TX_LOOKUP(pEndpoint); return NULL; } if (netbuf == (qdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket)) { UNLOCK_HTC_TX(target); + UNLOCK_HTC_EP_TX_LOOKUP(pEndpoint); return pPacket; } HTC_PACKET_ENQUEUE(&lookupQueue, pPacket); @@ -1949,6 +1953,7 @@ static HTC_PACKET *htc_lookup_tx_packet(HTC_TARGET *target, HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxLookupQueue, &lookupQueue); UNLOCK_HTC_TX(target); + UNLOCK_HTC_EP_TX_LOOKUP(pEndpoint); return pFoundPacket; }