mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-31 14:04:26 -04:00 
			
		
		
		
	3.18.12 backported 61ada528dea028331e99e8ceaed87c683ad25de2 ("sched/wait:
Provide infrastructure to deal with nested blocking") from 3.19, causing
the following error on load:
[   13.588000] compat: exports duplicate symbol woken_wake_function (owned by kernel)
Fix this by guarding it with a check for 3.18.11 or earlier instead of
3.19.
Signed-off-by: Jonas Gorski <jogo@openwrt.org>
SVN-Revision: 45710
		
	
			
		
			
				
	
	
		
			97 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			97 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From: Sergey Ryazanov <ryazanov.s.a@gmail.com>
 | |
| Date: Wed, 4 Mar 2015 05:12:11 +0300
 | |
| Subject: [PATCH] ath5k: fix reset race
 | |
| 
 | |
| To prepare for reset ath5k should finish all asynchronous tasks. At
 | |
| first, it disables the interrupt generation, then it waits for the
 | |
| interrupt handler and tasklets completion, and then proceeds to the HW
 | |
| configuration update. But it does not consider that the interrupt
 | |
| handler or tasklet re-enables the interrupt generation. And we fall in a
 | |
| situation when ath5k assumes that interrupts are disabled, but it is
 | |
| not.
 | |
| 
 | |
| This can lead to different consequences, such as reception of the frame,
 | |
| when we do not expect it. Under certain circumstances, this can lead to
 | |
| the following warning:
 | |
| 
 | |
|   WARNING: at ath5k/base.c:589 ath5k_tasklet_rx+0x318/0x6ec [ath5k]()
 | |
|   invalid hw_rix: 1a
 | |
|   [..]
 | |
|   Call Trace:
 | |
|   [<802656a8>] show_stack+0x48/0x70
 | |
|   [<802dd92c>] warn_slowpath_common+0x88/0xbc
 | |
|   [<802dd98c>] warn_slowpath_fmt+0x2c/0x38
 | |
|   [<81b51be8>] ath5k_tasklet_rx+0x318/0x6ec [ath5k]
 | |
|   [<8028ac64>] tasklet_action+0x8c/0xf0
 | |
|   [<80075804>] __do_softirq+0x180/0x32c
 | |
|   [<80196ce8>] irq_exit+0x54/0x70
 | |
|   [<80041848>] ret_from_irq+0x0/0x4
 | |
|   [<80182fdc>] ioread32+0x4/0xc
 | |
|   [<81b4c42c>] ath5k_hw_set_sleep_clock+0x2ec/0x474 [ath5k]
 | |
|   [<81b4cf28>] ath5k_hw_reset+0x50/0xeb8 [ath5k]
 | |
|   [<81b50900>] ath5k_reset+0xd4/0x310 [ath5k]
 | |
|   [<81b557e8>] ath5k_config+0x4c/0x104 [ath5k]
 | |
|   [<80d01770>] ieee80211_hw_config+0x2f4/0x35c [mac80211]
 | |
|   [<80d09aa8>] ieee80211_scan_work+0x2e4/0x414 [mac80211]
 | |
|   [<8022c3f4>] process_one_work+0x28c/0x400
 | |
|   [<802df8f8>] worker_thread+0x258/0x3c0
 | |
|   [<801b5710>] kthread+0xe0/0xec
 | |
|   [<800418a8>] ret_from_kernel_thread+0x14/0x1c
 | |
| 
 | |
| Fix this issue by adding a new status flag, which forbids to re-enable
 | |
| the interrupt generation until the HW configuration is completed.
 | |
| 
 | |
| Note: previous patch, which reorders the Rx disable code helps to avoid
 | |
| the above warning, but not fixes the root cause of unexpected frame
 | |
| receiving.
 | |
| 
 | |
| CC: Jiri Slaby <jirislaby@gmail.com>
 | |
| CC: Nick Kossifidis <mickflemm@gmail.com>
 | |
| CC: Luis R. Rodriguez <mcgrof@do-not-panic.com>
 | |
| Reported-by: Christophe Prevotaux <cprevotaux@nltinc.com>
 | |
| Tested-by: Christophe Prevotaux <cprevotaux@nltinc.com>
 | |
| Tested-by: Eric Bree <ebree@nltinc.com>
 | |
| Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
 | |
| ---
 | |
| 
 | |
| --- a/drivers/net/wireless/ath/ath5k/ath5k.h
 | |
| +++ b/drivers/net/wireless/ath/ath5k/ath5k.h
 | |
| @@ -1283,6 +1283,7 @@ struct ath5k_hw {
 | |
|  #define ATH_STAT_PROMISC	1
 | |
|  #define ATH_STAT_LEDSOFT	2		/* enable LED gpio status */
 | |
|  #define ATH_STAT_STARTED	3		/* opened & irqs enabled */
 | |
| +#define ATH_STAT_RESET		4		/* hw reset */
 | |
|  
 | |
|  	unsigned int		filter_flags;	/* HW flags, AR5K_RX_FILTER_* */
 | |
|  	unsigned int		fif_filter_flags; /* Current FIF_* filter flags */
 | |
| --- a/drivers/net/wireless/ath/ath5k/base.c
 | |
| +++ b/drivers/net/wireless/ath/ath5k/base.c
 | |
| @@ -1523,6 +1523,9 @@ ath5k_set_current_imask(struct ath5k_hw
 | |
|  	enum ath5k_int imask;
 | |
|  	unsigned long flags;
 | |
|  
 | |
| +	if (test_bit(ATH_STAT_RESET, ah->status))
 | |
| +		return;
 | |
| +
 | |
|  	spin_lock_irqsave(&ah->irqlock, flags);
 | |
|  	imask = ah->imask;
 | |
|  	if (ah->rx_pending)
 | |
| @@ -2862,6 +2865,8 @@ ath5k_reset(struct ath5k_hw *ah, struct
 | |
|  
 | |
|  	ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "resetting\n");
 | |
|  
 | |
| +	__set_bit(ATH_STAT_RESET, ah->status);
 | |
| +
 | |
|  	ath5k_hw_set_imr(ah, 0);
 | |
|  	synchronize_irq(ah->irq);
 | |
|  	ath5k_stop_tasklets(ah);
 | |
| @@ -2952,6 +2957,8 @@ ath5k_reset(struct ath5k_hw *ah, struct
 | |
|  	 */
 | |
|  /*	ath5k_chan_change(ah, c); */
 | |
|  
 | |
| +	__clear_bit(ATH_STAT_RESET, ah->status);
 | |
| +
 | |
|  	ath5k_beacon_config(ah);
 | |
|  	/* intrs are enabled by ath5k_beacon_config */
 | |
|  
 |