mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-30 21:44:27 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			238 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			238 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| --- a/drivers/net/wireless/ath/ath9k/ath9k.h
 | |
| +++ b/drivers/net/wireless/ath/ath9k/ath9k.h
 | |
| @@ -309,8 +309,8 @@ struct ath_rx {
 | |
|  	u8 rxotherant;
 | |
|  	u32 *rxlink;
 | |
|  	unsigned int rxfilter;
 | |
| -	spinlock_t rxflushlock;
 | |
|  	spinlock_t rxbuflock;
 | |
| +	spinlock_t pcu_lock;
 | |
|  	struct list_head rxbuf;
 | |
|  	struct ath_descdma rxdma;
 | |
|  	struct ath_buf *rx_bufptr;
 | |
| --- a/drivers/net/wireless/ath/ath9k/main.c
 | |
| +++ b/drivers/net/wireless/ath/ath9k/main.c
 | |
| @@ -239,6 +239,9 @@ int ath_set_channel(struct ath_softc *sc
 | |
|  	 */
 | |
|  	ath9k_hw_disable_interrupts(ah);
 | |
|  	ath_drain_all_txq(sc, false);
 | |
| +
 | |
| +	spin_lock_bh(&sc->rx.pcu_lock);
 | |
| +
 | |
|  	stopped = ath_stoprecv(sc);
 | |
|  
 | |
|  	/* XXX: do not flush receive queue here. We don't want
 | |
| @@ -266,6 +269,7 @@ int ath_set_channel(struct ath_softc *sc
 | |
|  			  "reset status %d\n",
 | |
|  			  channel->center_freq, r);
 | |
|  		spin_unlock_bh(&sc->sc_resetlock);
 | |
| +		spin_unlock_bh(&sc->rx.pcu_lock);
 | |
|  		goto ps_restore;
 | |
|  	}
 | |
|  	spin_unlock_bh(&sc->sc_resetlock);
 | |
| @@ -274,9 +278,12 @@ int ath_set_channel(struct ath_softc *sc
 | |
|  		ath_print(common, ATH_DBG_FATAL,
 | |
|  			  "Unable to restart recv logic\n");
 | |
|  		r = -EIO;
 | |
| +		spin_unlock_bh(&sc->rx.pcu_lock);
 | |
|  		goto ps_restore;
 | |
|  	}
 | |
|  
 | |
| +	spin_unlock_bh(&sc->rx.pcu_lock);
 | |
| +
 | |
|  	ath_update_txpow(sc);
 | |
|  	ath9k_hw_set_interrupts(ah, ah->imask);
 | |
|  
 | |
| @@ -610,7 +617,7 @@ void ath9k_tasklet(unsigned long data)
 | |
|  		rxmask = (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN);
 | |
|  
 | |
|  	if (status & rxmask) {
 | |
| -		spin_lock_bh(&sc->rx.rxflushlock);
 | |
| +		spin_lock_bh(&sc->rx.pcu_lock);
 | |
|  
 | |
|  		/* Check for high priority Rx first */
 | |
|  		if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
 | |
| @@ -618,7 +625,7 @@ void ath9k_tasklet(unsigned long data)
 | |
|  			ath_rx_tasklet(sc, 0, true);
 | |
|  
 | |
|  		ath_rx_tasklet(sc, 0, false);
 | |
| -		spin_unlock_bh(&sc->rx.rxflushlock);
 | |
| +		spin_unlock_bh(&sc->rx.pcu_lock);
 | |
|  	}
 | |
|  
 | |
|  	if (status & ATH9K_INT_TX) {
 | |
| @@ -876,6 +883,7 @@ void ath_radio_enable(struct ath_softc *
 | |
|  	if (!ah->curchan)
 | |
|  		ah->curchan = ath_get_curchannel(sc, sc->hw);
 | |
|  
 | |
| +	spin_lock_bh(&sc->rx.pcu_lock);
 | |
|  	spin_lock_bh(&sc->sc_resetlock);
 | |
|  	r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
 | |
|  	if (r) {
 | |
| @@ -890,8 +898,10 @@ void ath_radio_enable(struct ath_softc *
 | |
|  	if (ath_startrecv(sc) != 0) {
 | |
|  		ath_print(common, ATH_DBG_FATAL,
 | |
|  			  "Unable to restart recv logic\n");
 | |
| +		spin_unlock_bh(&sc->rx.pcu_lock);
 | |
|  		return;
 | |
|  	}
 | |
| +	spin_unlock_bh(&sc->rx.pcu_lock);
 | |
|  
 | |
|  	if (sc->sc_flags & SC_OP_BEACONS)
 | |
|  		ath_beacon_config(sc, NULL);	/* restart beacons */
 | |
| @@ -930,6 +940,9 @@ void ath_radio_disable(struct ath_softc 
 | |
|  	ath9k_hw_disable_interrupts(ah);
 | |
|  
 | |
|  	ath_drain_all_txq(sc, false);	/* clear pending tx frames */
 | |
| +
 | |
| +	spin_lock_bh(&sc->rx.pcu_lock);
 | |
| +
 | |
|  	ath_stoprecv(sc);		/* turn off frame recv */
 | |
|  	ath_flushrecv(sc);		/* flush recv queue */
 | |
|  
 | |
| @@ -947,6 +960,9 @@ void ath_radio_disable(struct ath_softc 
 | |
|  	spin_unlock_bh(&sc->sc_resetlock);
 | |
|  
 | |
|  	ath9k_hw_phy_disable(ah);
 | |
| +
 | |
| +	spin_unlock_bh(&sc->rx.pcu_lock);
 | |
| +
 | |
|  	ath9k_hw_configpcipowersave(ah, 1, 1);
 | |
|  	ath9k_ps_restore(sc);
 | |
|  	ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP);
 | |
| @@ -966,6 +982,9 @@ int ath_reset(struct ath_softc *sc, bool
 | |
|  
 | |
|  	ath9k_hw_disable_interrupts(ah);
 | |
|  	ath_drain_all_txq(sc, retry_tx);
 | |
| +
 | |
| +	spin_lock_bh(&sc->rx.pcu_lock);
 | |
| +
 | |
|  	ath_stoprecv(sc);
 | |
|  	ath_flushrecv(sc);
 | |
|  
 | |
| @@ -980,6 +999,8 @@ int ath_reset(struct ath_softc *sc, bool
 | |
|  		ath_print(common, ATH_DBG_FATAL,
 | |
|  			  "Unable to start recv logic\n");
 | |
|  
 | |
| +	spin_unlock_bh(&sc->rx.pcu_lock);
 | |
| +
 | |
|  	/*
 | |
|  	 * We may be doing a reset in response to a request
 | |
|  	 * that changes the channel so update any state that
 | |
| @@ -1142,6 +1163,7 @@ static int ath9k_start(struct ieee80211_
 | |
|  	 * be followed by initialization of the appropriate bits
 | |
|  	 * and then setup of the interrupt mask.
 | |
|  	 */
 | |
| +	spin_lock_bh(&sc->rx.pcu_lock);
 | |
|  	spin_lock_bh(&sc->sc_resetlock);
 | |
|  	r = ath9k_hw_reset(ah, init_channel, ah->caldata, false);
 | |
|  	if (r) {
 | |
| @@ -1150,6 +1172,7 @@ static int ath9k_start(struct ieee80211_
 | |
|  			  "(freq %u MHz)\n", r,
 | |
|  			  curchan->center_freq);
 | |
|  		spin_unlock_bh(&sc->sc_resetlock);
 | |
| +		spin_unlock_bh(&sc->rx.pcu_lock);
 | |
|  		goto mutex_unlock;
 | |
|  	}
 | |
|  	spin_unlock_bh(&sc->sc_resetlock);
 | |
| @@ -1171,8 +1194,10 @@ static int ath9k_start(struct ieee80211_
 | |
|  		ath_print(common, ATH_DBG_FATAL,
 | |
|  			  "Unable to start recv logic\n");
 | |
|  		r = -EIO;
 | |
| +		spin_unlock_bh(&sc->rx.pcu_lock);
 | |
|  		goto mutex_unlock;
 | |
|  	}
 | |
| +	spin_unlock_bh(&sc->rx.pcu_lock);
 | |
|  
 | |
|  	/* Setup our intr mask. */
 | |
|  	ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL |
 | |
| @@ -1371,12 +1396,14 @@ static void ath9k_stop(struct ieee80211_
 | |
|  	 * before setting the invalid flag. */
 | |
|  	ath9k_hw_disable_interrupts(ah);
 | |
|  
 | |
| +	spin_lock_bh(&sc->rx.pcu_lock);
 | |
|  	if (!(sc->sc_flags & SC_OP_INVALID)) {
 | |
|  		ath_drain_all_txq(sc, false);
 | |
|  		ath_stoprecv(sc);
 | |
|  		ath9k_hw_phy_disable(ah);
 | |
|  	} else
 | |
|  		sc->rx.rxlink = NULL;
 | |
| +	spin_unlock_bh(&sc->rx.pcu_lock);
 | |
|  
 | |
|  	/* disable HAL and put h/w to sleep */
 | |
|  	ath9k_hw_disable(ah);
 | |
| --- a/drivers/net/wireless/ath/ath9k/recv.c
 | |
| +++ b/drivers/net/wireless/ath/ath9k/recv.c
 | |
| @@ -297,19 +297,17 @@ static void ath_edma_start_recv(struct a
 | |
|  	ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_LP,
 | |
|  			      sc->rx.rx_edma[ATH9K_RX_QUEUE_LP].rx_fifo_hwsize);
 | |
|  
 | |
| -	spin_unlock_bh(&sc->rx.rxbuflock);
 | |
| -
 | |
|  	ath_opmode_init(sc);
 | |
|  
 | |
|  	ath9k_hw_startpcureceive(sc->sc_ah, (sc->sc_flags & SC_OP_OFFCHANNEL));
 | |
| +
 | |
| +	spin_unlock_bh(&sc->rx.rxbuflock);
 | |
|  }
 | |
|  
 | |
|  static void ath_edma_stop_recv(struct ath_softc *sc)
 | |
|  {
 | |
| -	spin_lock_bh(&sc->rx.rxbuflock);
 | |
|  	ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_HP);
 | |
|  	ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_LP);
 | |
| -	spin_unlock_bh(&sc->rx.rxbuflock);
 | |
|  }
 | |
|  
 | |
|  int ath_rx_init(struct ath_softc *sc, int nbufs)
 | |
| @@ -319,8 +317,8 @@ int ath_rx_init(struct ath_softc *sc, in
 | |
|  	struct ath_buf *bf;
 | |
|  	int error = 0;
 | |
|  
 | |
| -	spin_lock_init(&sc->rx.rxflushlock);
 | |
|  	sc->sc_flags &= ~SC_OP_RXFLUSH;
 | |
| +	spin_lock_init(&sc->rx.pcu_lock);
 | |
|  	spin_lock_init(&sc->rx.rxbuflock);
 | |
|  
 | |
|  	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
 | |
| @@ -506,9 +504,9 @@ int ath_startrecv(struct ath_softc *sc)
 | |
|  	ath9k_hw_rxena(ah);
 | |
|  
 | |
|  start_recv:
 | |
| -	spin_unlock_bh(&sc->rx.rxbuflock);
 | |
|  	ath_opmode_init(sc);
 | |
|  	ath9k_hw_startpcureceive(ah, (sc->sc_flags & SC_OP_OFFCHANNEL));
 | |
| +	spin_unlock_bh(&sc->rx.rxbuflock);
 | |
|  
 | |
|  	return 0;
 | |
|  }
 | |
| @@ -518,6 +516,7 @@ bool ath_stoprecv(struct ath_softc *sc)
 | |
|  	struct ath_hw *ah = sc->sc_ah;
 | |
|  	bool stopped;
 | |
|  
 | |
| +	spin_lock_bh(&sc->rx.rxbuflock);
 | |
|  	ath9k_hw_stoppcurecv(ah);
 | |
|  	ath9k_hw_setrxfilter(ah, 0);
 | |
|  	stopped = ath9k_hw_stopdmarecv(ah);
 | |
| @@ -526,19 +525,18 @@ bool ath_stoprecv(struct ath_softc *sc)
 | |
|  		ath_edma_stop_recv(sc);
 | |
|  	else
 | |
|  		sc->rx.rxlink = NULL;
 | |
| +	spin_unlock_bh(&sc->rx.rxbuflock);
 | |
|  
 | |
|  	return stopped;
 | |
|  }
 | |
|  
 | |
|  void ath_flushrecv(struct ath_softc *sc)
 | |
|  {
 | |
| -	spin_lock_bh(&sc->rx.rxflushlock);
 | |
|  	sc->sc_flags |= SC_OP_RXFLUSH;
 | |
|  	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
 | |
|  		ath_rx_tasklet(sc, 1, true);
 | |
|  	ath_rx_tasklet(sc, 1, false);
 | |
|  	sc->sc_flags &= ~SC_OP_RXFLUSH;
 | |
| -	spin_unlock_bh(&sc->rx.rxflushlock);
 | |
|  }
 | |
|  
 | |
|  static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb)
 |