wil6210: make sure DR bit is read before rest of the status message

Due to compiler optimization, it's possible that dr_bit (descriptor
ready) is read last from the status message.
Due to race condition between HW writing the status message and
driver reading it, other fields that were read earlier (before dr_bit)
could have invalid values.

Fix this by explicitly reading the dr_bit first and then using rmb
before reading the rest of the status message.

Signed-off-by: Dedy Lansky <dlansky@codeaurora.org>
Signed-off-by: Maya Erez <merez@codeaurora.org>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
This commit is contained in:
Dedy Lansky 2019-09-10 16:46:29 +03:00 committed by Kalle Valo
parent 42fe1e519e
commit f4519fd937
2 changed files with 18 additions and 18 deletions

View File

@ -221,10 +221,17 @@ static int wil_ring_alloc_skb_edma(struct wil6210_priv *wil,
}
static inline
void wil_get_next_rx_status_msg(struct wil_status_ring *sring, void *msg)
void wil_get_next_rx_status_msg(struct wil_status_ring *sring, u8 *dr_bit,
void *msg)
{
memcpy(msg, (void *)(sring->va + (sring->elem_size * sring->swhead)),
sring->elem_size);
struct wil_rx_status_compressed *_msg;
_msg = (struct wil_rx_status_compressed *)
(sring->va + (sring->elem_size * sring->swhead));
*dr_bit = WIL_GET_BITS(_msg->d0, 31, 31);
/* make sure dr_bit is read before the rest of status msg */
rmb();
memcpy(msg, (void *)_msg, sring->elem_size);
}
static inline void wil_sring_advance_swhead(struct wil_status_ring *sring)
@ -587,8 +594,7 @@ static bool wil_is_rx_idle_edma(struct wil6210_priv *wil)
if (!sring->va)
continue;
wil_get_next_rx_status_msg(sring, msg);
dr_bit = wil_rx_status_get_desc_rdy_bit(msg);
wil_get_next_rx_status_msg(sring, &dr_bit, msg);
/* Check if there are unhandled RX status messages */
if (dr_bit == sring->desc_rdy_pol)
@ -878,8 +884,7 @@ static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil,
BUILD_BUG_ON(sizeof(struct wil_rx_status_extended) > sizeof(skb->cb));
again:
wil_get_next_rx_status_msg(sring, msg);
dr_bit = wil_rx_status_get_desc_rdy_bit(msg);
wil_get_next_rx_status_msg(sring, &dr_bit, msg);
/* Completed handling all the ready status messages */
if (dr_bit != sring->desc_rdy_pol)
@ -1135,12 +1140,15 @@ static int wil_tx_desc_map_edma(union wil_tx_desc *desc,
}
static inline void
wil_get_next_tx_status_msg(struct wil_status_ring *sring,
wil_get_next_tx_status_msg(struct wil_status_ring *sring, u8 *dr_bit,
struct wil_ring_tx_status *msg)
{
struct wil_ring_tx_status *_msg = (struct wil_ring_tx_status *)
(sring->va + (sring->elem_size * sring->swhead));
*dr_bit = _msg->desc_ready >> TX_STATUS_DESC_READY_POS;
/* make sure dr_bit is read before the rest of status msg */
rmb();
*msg = *_msg;
}
@ -1169,8 +1177,7 @@ int wil_tx_sring_handler(struct wil6210_priv *wil,
int used_before_complete;
int used_new;
wil_get_next_tx_status_msg(sring, &msg);
dr_bit = msg.desc_ready >> TX_STATUS_DESC_READY_POS;
wil_get_next_tx_status_msg(sring, &dr_bit, &msg);
/* Process completion messages while DR bit has the expected polarity */
while (dr_bit == sring->desc_rdy_pol) {
@ -1293,8 +1300,7 @@ int wil_tx_sring_handler(struct wil6210_priv *wil,
wil_sring_advance_swhead(sring);
wil_get_next_tx_status_msg(sring, &msg);
dr_bit = msg.desc_ready >> TX_STATUS_DESC_READY_POS;
wil_get_next_tx_status_msg(sring, &dr_bit, &msg);
}
/* shall we wake net queues? */

View File

@ -421,12 +421,6 @@ static inline u8 wil_rx_status_get_tid(void *msg)
return val & WIL_RX_EDMA_DLPF_LU_MISS_CID_TID_MASK;
}
static inline int wil_rx_status_get_desc_rdy_bit(void *msg)
{
return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0,
31, 31);
}
static inline int wil_rx_status_get_eop(void *msg) /* EoP = End of Packet */
{
return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0,