mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-31 05:54:26 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			84 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			84 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From: Hante Meuleman <meuleman@broadcom.com>
 | |
| Date: Fri, 6 Mar 2015 18:40:40 +0100
 | |
| Subject: [PATCH] brcmfmac: Fix possible race-condition.
 | |
| 
 | |
| SDIO is using a "shared" variable to handoff ctl frames to DPC
 | |
| and to see when they are done. In a timeout situation this can
 | |
| lead to erroneous situation where DPC started to handle the ctl
 | |
| frame while the timeout expired. This patch will fix this by
 | |
| adding locking around the shared variable.
 | |
| 
 | |
| Reviewed-by: Arend Van Spriel <arend@broadcom.com>
 | |
| Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
 | |
| Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
 | |
| Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com>
 | |
| Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
 | |
| Signed-off-by: Arend van Spriel <arend@broadcom.com>
 | |
| Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
 | |
| ---
 | |
| 
 | |
| --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
 | |
| +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
 | |
| @@ -2700,11 +2700,13 @@ static void brcmf_sdio_dpc(struct brcmf_
 | |
|  	if (bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL) &&
 | |
|  	    data_ok(bus)) {
 | |
|  		sdio_claim_host(bus->sdiodev->func[1]);
 | |
| -		err = brcmf_sdio_tx_ctrlframe(bus,  bus->ctrl_frame_buf,
 | |
| -					      bus->ctrl_frame_len);
 | |
| +		if (bus->ctrl_frame_stat) {
 | |
| +			err = brcmf_sdio_tx_ctrlframe(bus,  bus->ctrl_frame_buf,
 | |
| +						      bus->ctrl_frame_len);
 | |
| +			bus->ctrl_frame_err = err;
 | |
| +			bus->ctrl_frame_stat = false;
 | |
| +		}
 | |
|  		sdio_release_host(bus->sdiodev->func[1]);
 | |
| -		bus->ctrl_frame_err = err;
 | |
| -		bus->ctrl_frame_stat = false;
 | |
|  		brcmf_sdio_wait_event_wakeup(bus);
 | |
|  	}
 | |
|  	/* Send queued frames (limit 1 if rx may still be pending) */
 | |
| @@ -2720,9 +2722,13 @@ static void brcmf_sdio_dpc(struct brcmf_
 | |
|  		brcmf_err("failed backplane access over SDIO, halting operation\n");
 | |
|  		atomic_set(&bus->intstatus, 0);
 | |
|  		if (bus->ctrl_frame_stat) {
 | |
| -			bus->ctrl_frame_err = -ENODEV;
 | |
| -			bus->ctrl_frame_stat = false;
 | |
| -			brcmf_sdio_wait_event_wakeup(bus);
 | |
| +			sdio_claim_host(bus->sdiodev->func[1]);
 | |
| +			if (bus->ctrl_frame_stat) {
 | |
| +				bus->ctrl_frame_err = -ENODEV;
 | |
| +				bus->ctrl_frame_stat = false;
 | |
| +				brcmf_sdio_wait_event_wakeup(bus);
 | |
| +			}
 | |
| +			sdio_release_host(bus->sdiodev->func[1]);
 | |
|  		}
 | |
|  	} else if (atomic_read(&bus->intstatus) ||
 | |
|  		   atomic_read(&bus->ipend) > 0 ||
 | |
| @@ -2930,15 +2936,20 @@ brcmf_sdio_bus_txctl(struct device *dev,
 | |
|  	brcmf_sdio_trigger_dpc(bus);
 | |
|  	wait_event_interruptible_timeout(bus->ctrl_wait, !bus->ctrl_frame_stat,
 | |
|  					 msecs_to_jiffies(CTL_DONE_TIMEOUT));
 | |
| -
 | |
| -	if (!bus->ctrl_frame_stat) {
 | |
| +	ret = 0;
 | |
| +	if (bus->ctrl_frame_stat) {
 | |
| +		sdio_claim_host(bus->sdiodev->func[1]);
 | |
| +		if (bus->ctrl_frame_stat) {
 | |
| +			brcmf_dbg(SDIO, "ctrl_frame timeout\n");
 | |
| +			bus->ctrl_frame_stat = false;
 | |
| +			ret = -ETIMEDOUT;
 | |
| +		}
 | |
| +		sdio_release_host(bus->sdiodev->func[1]);
 | |
| +	}
 | |
| +	if (!ret) {
 | |
|  		brcmf_dbg(SDIO, "ctrl_frame complete, err=%d\n",
 | |
|  			  bus->ctrl_frame_err);
 | |
|  		ret = bus->ctrl_frame_err;
 | |
| -	} else {
 | |
| -		brcmf_dbg(SDIO, "ctrl_frame timeout\n");
 | |
| -		bus->ctrl_frame_stat = false;
 | |
| -		ret = -ETIMEDOUT;
 | |
|  	}
 | |
|  
 | |
|  	if (ret)
 |