Search Linux Wireless

[RFC] ath9k: Insert wmb before linking dma descriptors

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi all,

I've been looking at how ath9k does DMA and comparing with the
recommendations in the Linux kernel documentation for the DMA API[1]. To
me it looks like we risk setting up incorrect DMA descriptors on
platforms that can reorder writes because all data in the descriptor may
not be written to memory before the descriptor is linked into the DMA
chain.

The patch below attempts to remove this risk by inserting a write memory
barrier between where we set up a descriptor and where we add it to the 
DMA chain. My hope is that this may solve some of the harder chip lockups 
on MIPS but more testing is required to determine if it has this effect.

Any thoughts?

/Björn

1. http://www.mjmwired.net/kernel/Documentation/DMA-API.txt

---
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 081192e..8e43443 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -450,6 +450,8 @@ void ath_beacon_tasklet(unsigned long data)
 				"beacon queue %u did not stop?\n", sc->beacon.beaconq);
 		}
 
+		wmb();
+
 		/* NB: cabq traffic should already be queued and primed */
 		ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bfaddr);
 		ath9k_hw_txstart(ah, sc->beacon.beaconq);
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 9c166f3..2cc0271 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -90,6 +90,8 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)
 			     common->rx_bufsize,
 			     0);
 
+	wmb();
+
 	if (sc->rx.rxlink == NULL)
 		ath9k_hw_putrxbuf(ah, bf->bf_daddr);
 	else
@@ -500,6 +502,9 @@ int ath_startrecv(struct ath_softc *sc)
 		goto start_recv;
 
 	bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list);
+
+	wmb();
+
 	ath9k_hw_putrxbuf(ah, bf->bf_daddr);
 	ath9k_hw_rxena(ah);
 
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index f7da6b2..4b8c428 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1250,6 +1250,8 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
 	ath_print(common, ATH_DBG_QUEUE,
 		  "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
 
+	wmb();
+
 	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
 		if (txq->axq_depth >= ATH_TXFIFO_DEPTH) {
 			list_splice_tail_init(head, &txq->txq_fifo_pending);

[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux