Skip to contentSkip to conversation

wcn36xx: use READ_ONCE() to access desc->ctrl

PATCH In review Daniel Mack 3 participants 5 messages Apr 10, 2018 – Apr 19, 2018 Qualcomm WCN36XX wireless driver

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 wcn36xx: use READ_ONCE() to access desc->ctrl

When accessing shared memory to check for the stat of submitted descriptors, make sure to use READ_ONCE(). This will guarantee the compiler treats these memory locations as volatile and doesn't apply any caching.

While this doesn't fix any particular problem I ran into, it's best practice to do it this way.

Note that this patch also removes the superflous extra condition check in the do-while loop in reap_tx_dxes(), as the loop will break instantly anyway in that case.

---
 drivers/net/wireless/ath/wcn36xx/dxe.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)
drivers/net/wireless/ath/wcn36xx/dxe.c +3 -4
index 26e6c42f886a..c52f1c21ece9 100644
@@ -363,7 +363,7 @@ static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch)
 	spin_lock_irqsave(&ch->lock, flags);
 	ctl = ch->tail_blk_ctl;
 	do {
-		if (ctl->desc->ctrl & WCN36xx_DXE_CTRL_VLD)
+		if (READ_ONCE(ctl->desc->ctrl) & WCN36xx_DXE_CTRL_VLD)
 			break;
 		if (ctl->skb) {
 			dma_unmap_single(wcn->dev, ctl->desc->src_addr_l,
@@ -382,8 +382,7 @@ static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch)
 			ctl->skb = NULL;
 		}
 		ctl = ctl->next;
-	} while (ctl != ch->head_blk_ctl &&
-	       !(ctl->desc->ctrl & WCN36xx_DXE_CTRL_VLD));
+	} while (ctl != ch->head_blk_ctl);
 
 	ch->tail_blk_ctl = ctl;
 	spin_unlock_irqrestore(&ch->lock, flags);
@@ -525,7 +524,7 @@ static int wcn36xx_rx_handle_packets(struct wcn36xx *wcn,
 		int_mask = WCN36XX_DXE_INT_CH3_MASK;
 	}
 
-	while (!(dxe->ctrl & WCN36xx_DXE_CTRL_VLD)) {
+	while (!(READ_ONCE(dxe->ctrl) & WCN36xx_DXE_CTRL_VLD)) {
 		skb = ctl->skb;
 		dma_addr = dxe->dst_addr_l;
 		ret = wcn36xx_dxe_fill_skb(wcn->dev, ctl, GFP_ATOMIC);
Signature · 1 line
2.14.3
#1 lore raw
Quoted 4 lines · Daniel Mack

When accessing shared memory to check for the stat of submitted descriptors, make sure to use READ_ONCE(). This will guarantee the compiler treats these memory locations as volatile and doesn't apply any caching.

The structure that is tested is not shared memory. It's accessed only by the apps processor.
In this case, caching does make sense.
I'm not sure regarding READ_ONCE in that context I'll have to do some reading regarding that.
But I don't think this is right here.

Thanks,
Ramon

Quoted 48 lines

While this doesn't fix any particular problem I ran into, it's best practice to do it this way.

Note that this patch also removes the superflous extra condition check in the do-while loop in reap_tx_dxes(), as the loop will break instantly anyway in that case.

---
 drivers/net/wireless/ath/wcn36xx/dxe.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)
drivers/net/wireless/ath/wcn36xx/dxe.c +3 -5
index 26e6c42f886a..c52f1c21ece9 100644
@@ -363,7 +363,7 @@ static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch)
        spin_lock_irqsave(&ch->lock, flags);
        ctl = ch->tail_blk_ctl;
        do {
-               if (ctl->desc->ctrl & WCN36xx_DXE_CTRL_VLD)
+               if (READ_ONCE(ctl->desc->ctrl) & WCN36xx_DXE_CTRL_VLD)
                        break;
                if (ctl->skb) {
                        dma_unmap_single(wcn->dev, ctl->desc->src_addr_l,
@@ -382,8 +382,7 @@ static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch)
                        ctl->skb = NULL;
                }
                ctl = ctl->next;
-       } while (ctl != ch->head_blk_ctl &&
-              !(ctl->desc->ctrl & WCN36xx_DXE_CTRL_VLD));
+       } while (ctl != ch->head_blk_ctl);
 
        ch->tail_blk_ctl = ctl;
        spin_unlock_irqrestore(&ch->lock, flags);
@@ -525,7 +524,7 @@ static int wcn36xx_rx_handle_packets(struct wcn36xx *wcn,
                int_mask = WCN36XX_DXE_INT_CH3_MASK;
        }
 
-       while (!(dxe->ctrl & WCN36xx_DXE_CTRL_VLD)) {
+       while (!(READ_ONCE(dxe->ctrl) & WCN36xx_DXE_CTRL_VLD)) {
                skb = ctl->skb;
                dma_addr = dxe->dst_addr_l;
                ret = wcn36xx_dxe_fill_skb(wcn->dev, ctl, GFP_ATOMIC);
--

2.14.3

#2 lore raw
Quoted 8 lines · Ramon Fried
Quoted 4 lines · Daniel Mack

When accessing shared memory to check for the stat of submitted descriptors, make sure to use READ_ONCE(). This will guarantee the compiler treats these memory locations as volatile and doesn't apply any caching.

The structure that is tested is not shared memory. It's accessed only by the apps processor.

Hmm? ctl->desc is of type struct wcn36xx_dxe_desc, which is packed and shared with the firmware. The WCN36xx_DXE_CTRL_VLD bit in ctrl bitfield is set by the firmware when a frame is valid, and before asserting the RX interrupt. So the host CPU must treat it as volatile and expect it to change.

Am I reading this wrong?

Thanks,
Daniel

#3 lore raw
Quoted 10 lines · Daniel Mack
Quoted 8 lines · Ramon Fried
Quoted 4 lines · Daniel Mack

When accessing shared memory to check for the stat of submitted descriptors, make sure to use READ_ONCE(). This will guarantee the compiler treats these memory locations as volatile and doesn't apply any caching.

The structure that is tested is not shared memory. It's accessed only by the apps processor.

Quoted 8 lines

Hmm? ctl->desc is of type struct wcn36xx_dxe_desc, which is packed and shared with the firmware. The WCN36xx_DXE_CTRL_VLD bit in ctrl bitfield is set by the firmware when a frame is valid, and before asserting the RX interrupt. So the host CPU must treat it as volatile and expect it to change.

Am I reading this wrong?

No, you're right. I missed that.

Quoted 3 lines

Thanks,
Daniel

#4 lore raw
In reply to Daniel Mack
Quoted 8 lines · Daniel Mack

When accessing shared memory to check for the stat of submitted descriptors, make sure to use READ_ONCE(). This will guarantee the compiler treats these memory locations as volatile and doesn't apply any caching.

While this doesn't fix any particular problem I ran into, it's best practice to do it this way.

Quoted 6 lines

Note that this patch also removes the superflous extra condition check in the do-while loop in reap_tx_dxes(), as the loop will break instantly anyway in that case.

Patch applied to ath-next branch of ath.git, thanks.

9ff6fde86fd2 wcn36xx: use READ_ONCE() to access desc->ctrl

Signature · 3 lines
https://patchwork.kernel.org/patch/10333551/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches