Commit f4519fd9 authored by Dedy Lansky's avatar Dedy Lansky Committed by Kalle Valo

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: default avatarDedy Lansky <dlansky@codeaurora.org>
Signed-off-by: default avatarMaya Erez <merez@codeaurora.org>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 42fe1e51
...@@ -221,10 +221,17 @@ static int wil_ring_alloc_skb_edma(struct wil6210_priv *wil, ...@@ -221,10 +221,17 @@ static int wil_ring_alloc_skb_edma(struct wil6210_priv *wil,
} }
static inline 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)), struct wil_rx_status_compressed *_msg;
sring->elem_size);
_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) 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) ...@@ -587,8 +594,7 @@ static bool wil_is_rx_idle_edma(struct wil6210_priv *wil)
if (!sring->va) if (!sring->va)
continue; continue;
wil_get_next_rx_status_msg(sring, msg); wil_get_next_rx_status_msg(sring, &dr_bit, msg);
dr_bit = wil_rx_status_get_desc_rdy_bit(msg);
/* Check if there are unhandled RX status messages */ /* Check if there are unhandled RX status messages */
if (dr_bit == sring->desc_rdy_pol) if (dr_bit == sring->desc_rdy_pol)
...@@ -878,8 +884,7 @@ static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil, ...@@ -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)); BUILD_BUG_ON(sizeof(struct wil_rx_status_extended) > sizeof(skb->cb));
again: again:
wil_get_next_rx_status_msg(sring, msg); wil_get_next_rx_status_msg(sring, &dr_bit, msg);
dr_bit = wil_rx_status_get_desc_rdy_bit(msg);
/* Completed handling all the ready status messages */ /* Completed handling all the ready status messages */
if (dr_bit != sring->desc_rdy_pol) if (dr_bit != sring->desc_rdy_pol)
...@@ -1135,12 +1140,15 @@ static int wil_tx_desc_map_edma(union wil_tx_desc *desc, ...@@ -1135,12 +1140,15 @@ static int wil_tx_desc_map_edma(union wil_tx_desc *desc,
} }
static inline void 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 *_msg = (struct wil_ring_tx_status *) struct wil_ring_tx_status *_msg = (struct wil_ring_tx_status *)
(sring->va + (sring->elem_size * sring->swhead)); (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; *msg = *_msg;
} }
...@@ -1169,8 +1177,7 @@ int wil_tx_sring_handler(struct wil6210_priv *wil, ...@@ -1169,8 +1177,7 @@ int wil_tx_sring_handler(struct wil6210_priv *wil,
int used_before_complete; int used_before_complete;
int used_new; int used_new;
wil_get_next_tx_status_msg(sring, &msg); wil_get_next_tx_status_msg(sring, &dr_bit, &msg);
dr_bit = msg.desc_ready >> TX_STATUS_DESC_READY_POS;
/* Process completion messages while DR bit has the expected polarity */ /* Process completion messages while DR bit has the expected polarity */
while (dr_bit == sring->desc_rdy_pol) { while (dr_bit == sring->desc_rdy_pol) {
...@@ -1293,8 +1300,7 @@ int wil_tx_sring_handler(struct wil6210_priv *wil, ...@@ -1293,8 +1300,7 @@ int wil_tx_sring_handler(struct wil6210_priv *wil,
wil_sring_advance_swhead(sring); wil_sring_advance_swhead(sring);
wil_get_next_tx_status_msg(sring, &msg); wil_get_next_tx_status_msg(sring, &dr_bit, &msg);
dr_bit = msg.desc_ready >> TX_STATUS_DESC_READY_POS;
} }
/* shall we wake net queues? */ /* shall we wake net queues? */
......
...@@ -421,12 +421,6 @@ static inline u8 wil_rx_status_get_tid(void *msg) ...@@ -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; 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 */ 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, return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment