Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7decc736 authored by Dedy Lansky's avatar Dedy Lansky
Browse files

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.

Change-Id: I8107d4ee8acafb2922ff86cd951540f97500de95
Signed-off-by: default avatarDedy Lansky <dlansky@codeaurora.org>
parent 0780e20a
Loading
Loading
Loading
Loading
+18 −12
Original line number Diff line number Diff line
@@ -223,10 +223,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)
@@ -606,8 +613,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)
@@ -916,8 +922,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)
@@ -1169,12 +1174,15 @@ int wil_tx_desc_map_edma(union wil_tx_desc *desc, dma_addr_t pa, u32 len,
}

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;
}

@@ -1203,8 +1211,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) {
@@ -1317,8 +1324,7 @@ int wil_tx_sring_handler(struct wil6210_priv *wil,
again:
		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? */
+0 −6
Original line number Diff line number Diff line
@@ -403,12 +403,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,