diff options
Diffstat (limited to 'drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c')
| -rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 579 | 
1 files changed, 293 insertions, 286 deletions
| diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 3564686add9a..cf857f1edf8c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -533,9 +533,11 @@ struct brcmf_sdio {  	u8 *rxbuf;		/* Buffer for receiving control packets */  	uint rxblen;		/* Allocated length of rxbuf */  	u8 *rxctl;		/* Aligned pointer into rxbuf */ +	u8 *rxctl_orig;		/* pointer for freeing rxctl */  	u8 *databuf;		/* Buffer for receiving big glom packet */  	u8 *dataptr;		/* Aligned pointer into databuf */  	uint rxlen;		/* Length of valid data in buffer */ +	spinlock_t rxctl_lock;	/* protection lock for ctrl frame resources */  	u8 sdpcm_ver;	/* Bus protocol reported by dongle */ @@ -582,8 +584,6 @@ struct brcmf_sdio {  	struct list_head dpc_tsklst;  	spinlock_t dpc_tl_lock; -	struct semaphore sdsem; -  	const struct firmware *firmware;  	u32 fw_ptr; @@ -614,6 +614,12 @@ static const uint max_roundup = 512;  #define ALIGNMENT  4 +enum brcmf_sdio_frmtype { +	BRCMF_SDIO_FT_NORMAL, +	BRCMF_SDIO_FT_SUPER, +	BRCMF_SDIO_FT_SUB, +}; +  static void pkt_align(struct sk_buff *p, int len, int align)  {  	uint datalign; @@ -683,7 +689,7 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)  		brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,  				 clkreq, &err);  		if (err) { -			brcmf_dbg(ERROR, "HT Avail request error: %d\n", err); +			brcmf_err("HT Avail request error: %d\n", err);  			return -EBADE;  		} @@ -691,7 +697,7 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)  		clkctl = brcmf_sdio_regrb(bus->sdiodev,  					  SBSDIO_FUNC1_CHIPCLKCSR, &err);  		if (err) { -			brcmf_dbg(ERROR, "HT Avail read error: %d\n", err); +			brcmf_err("HT Avail read error: %d\n", err);  			return -EBADE;  		} @@ -701,7 +707,7 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)  			devctl = brcmf_sdio_regrb(bus->sdiodev,  						  SBSDIO_DEVICE_CTL, &err);  			if (err) { -				brcmf_dbg(ERROR, "Devctl error setting CA: %d\n", +				brcmf_err("Devctl error setting CA: %d\n",  					  err);  				return -EBADE;  			} @@ -735,11 +741,11 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)  				usleep_range(5000, 10000);  		}  		if (err) { -			brcmf_dbg(ERROR, "HT Avail request error: %d\n", err); +			brcmf_err("HT Avail request error: %d\n", err);  			return -EBADE;  		}  		if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { -			brcmf_dbg(ERROR, "HT Avail timeout (%d): clkctl 0x%02x\n", +			brcmf_err("HT Avail timeout (%d): clkctl 0x%02x\n",  				  PMU_MAX_TRANSITION_DLY, clkctl);  			return -EBADE;  		} @@ -751,7 +757,7 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)  #if defined(DEBUG)  		if (!bus->alp_only) {  			if (SBSDIO_ALPONLY(clkctl)) -				brcmf_dbg(ERROR, "HT Clock should be on\n"); +				brcmf_err("HT Clock should be on\n");  		}  #endif				/* defined (DEBUG) */ @@ -773,7 +779,7 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)  				 clkreq, &err);  		brcmf_dbg(INFO, "CLKCTL: turned OFF\n");  		if (err) { -			brcmf_dbg(ERROR, "Failed access turning clock off: %d\n", +			brcmf_err("Failed access turning clock off: %d\n",  				  err);  			return -EBADE;  		} @@ -830,7 +836,7 @@ static int brcmf_sdbrcm_clkctl(struct brcmf_sdio *bus, uint target, bool pendok)  		else if (bus->clkstate == CLK_AVAIL)  			brcmf_sdbrcm_htclk(bus, false, false);  		else -			brcmf_dbg(ERROR, "request for %d -> %d\n", +			brcmf_err("request for %d -> %d\n",  				  bus->clkstate, target);  		brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);  		break; @@ -874,7 +880,7 @@ static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus)  		brcmf_dbg(INFO, "Dongle reports NAK handled, expect rtx of %d\n",  			  bus->rx_seq);  		if (!bus->rxskip) -			brcmf_dbg(ERROR, "unexpected NAKHANDLED!\n"); +			brcmf_err("unexpected NAKHANDLED!\n");  		bus->rxskip = false;  		intstatus |= I_HMB_FRAME_IND; @@ -888,7 +894,7 @@ static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus)  		    (hmb_data & HMB_DATA_VERSION_MASK) >>  		    HMB_DATA_VERSION_SHIFT;  		if (bus->sdpcm_ver != SDPCM_PROT_VERSION) -			brcmf_dbg(ERROR, "Version mismatch, dongle reports %d, " +			brcmf_err("Version mismatch, dongle reports %d, "  				  "expecting %d\n",  				  bus->sdpcm_ver, SDPCM_PROT_VERSION);  		else @@ -921,7 +927,7 @@ static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus)  			 HMB_DATA_FC |  			 HMB_DATA_FWREADY |  			 HMB_DATA_FCDATA_MASK | HMB_DATA_VERSION_MASK)) -		brcmf_dbg(ERROR, "Unknown mailbox data content: 0x%02x\n", +		brcmf_err("Unknown mailbox data content: 0x%02x\n",  			  hmb_data);  	return intstatus; @@ -934,7 +940,7 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)  	u8 hi, lo;  	int err; -	brcmf_dbg(ERROR, "%sterminate frame%s\n", +	brcmf_err("%sterminate frame%s\n",  		  abort ? "abort command, " : "",  		  rtx ? ", send NAK" : ""); @@ -957,14 +963,14 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)  			break;  		if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) { -			brcmf_dbg(ERROR, "count growing: last 0x%04x now 0x%04x\n", +			brcmf_err("count growing: last 0x%04x now 0x%04x\n",  				  lastrbc, (hi << 8) + lo);  		}  		lastrbc = (hi << 8) + lo;  	}  	if (!retries) -		brcmf_dbg(ERROR, "count never zeroed: last 0x%04x\n", lastrbc); +		brcmf_err("count never zeroed: last 0x%04x\n", lastrbc);  	else  		brcmf_dbg(INFO, "flush took %d iterations\n", 0xffff - retries); @@ -1031,8 +1037,9 @@ static void brcmf_sdbrcm_free_glom(struct brcmf_sdio *bus)  	}  } -static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header, -				struct brcmf_sdio_read *rd) +static int brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header, +			       struct brcmf_sdio_read *rd, +			       enum brcmf_sdio_frmtype type)  {  	u16 len, checksum;  	u8 rx_seq, fc, tx_seq_max; @@ -1047,17 +1054,26 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,  	/* All zero means no more to read */  	if (!(len | checksum)) {  		bus->rxpending = false; -		return false; +		return -ENODATA;  	}  	if ((u16)(~(len ^ checksum))) { -		brcmf_dbg(ERROR, "HW header checksum error\n"); +		brcmf_err("HW header checksum error\n");  		bus->sdcnt.rx_badhdr++;  		brcmf_sdbrcm_rxfail(bus, false, false); -		return false; +		return -EIO;  	}  	if (len < SDPCM_HDRLEN) { -		brcmf_dbg(ERROR, "HW header length error\n"); -		return false; +		brcmf_err("HW header length error\n"); +		return -EPROTO; +	} +	if (type == BRCMF_SDIO_FT_SUPER && +	    (roundup(len, bus->blocksize) != rd->len)) { +		brcmf_err("HW superframe header length error\n"); +		return -EPROTO; +	} +	if (type == BRCMF_SDIO_FT_SUB && len > rd->len) { +		brcmf_err("HW subframe header length error\n"); +		return -EPROTO;  	}  	rd->len = len; @@ -1071,35 +1087,56 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,  	 * Byte 5: Maximum Sequence number allow for Tx  	 * Byte 6~7: Reserved  	 */ +	if (type == BRCMF_SDIO_FT_SUPER && +	    SDPCM_GLOMDESC(&header[SDPCM_FRAMETAG_LEN])) { +		brcmf_err("Glom descriptor found in superframe head\n"); +		rd->len = 0; +		return -EINVAL; +	}  	rx_seq = SDPCM_PACKET_SEQUENCE(&header[SDPCM_FRAMETAG_LEN]);  	rd->channel = SDPCM_PACKET_CHANNEL(&header[SDPCM_FRAMETAG_LEN]); -	if (len > MAX_RX_DATASZ && rd->channel != SDPCM_CONTROL_CHANNEL) { -		brcmf_dbg(ERROR, "HW header length too long\n"); +	if (len > MAX_RX_DATASZ && rd->channel != SDPCM_CONTROL_CHANNEL && +	    type != BRCMF_SDIO_FT_SUPER) { +		brcmf_err("HW header length too long\n");  		bus->sdiodev->bus_if->dstats.rx_errors++;  		bus->sdcnt.rx_toolong++;  		brcmf_sdbrcm_rxfail(bus, false, false);  		rd->len = 0; -		return false; +		return -EPROTO; +	} +	if (type == BRCMF_SDIO_FT_SUPER && rd->channel != SDPCM_GLOM_CHANNEL) { +		brcmf_err("Wrong channel for superframe\n"); +		rd->len = 0; +		return -EINVAL; +	} +	if (type == BRCMF_SDIO_FT_SUB && rd->channel != SDPCM_DATA_CHANNEL && +	    rd->channel != SDPCM_EVENT_CHANNEL) { +		brcmf_err("Wrong channel for subframe\n"); +		rd->len = 0; +		return -EINVAL;  	}  	rd->dat_offset = SDPCM_DOFFSET_VALUE(&header[SDPCM_FRAMETAG_LEN]);  	if (rd->dat_offset < SDPCM_HDRLEN || rd->dat_offset > rd->len) { -		brcmf_dbg(ERROR, "seq %d: bad data offset\n", rx_seq); +		brcmf_err("seq %d: bad data offset\n", rx_seq);  		bus->sdcnt.rx_badhdr++;  		brcmf_sdbrcm_rxfail(bus, false, false);  		rd->len = 0; -		return false; +		return -ENXIO;  	}  	if (rd->seq_num != rx_seq) { -		brcmf_dbg(ERROR, "seq %d: sequence number error, expect %d\n", +		brcmf_err("seq %d: sequence number error, expect %d\n",  			  rx_seq, rd->seq_num);  		bus->sdcnt.rx_badseq++;  		rd->seq_num = rx_seq;  	} +	/* no need to check the reset for subframe */ +	if (type == BRCMF_SDIO_FT_SUB) +		return 0;  	rd->len_nxtfrm = header[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];  	if (rd->len_nxtfrm << 4 > MAX_RX_DATASZ) {  		/* only warm for NON glom packet */  		if (rd->channel != SDPCM_GLOM_CHANNEL) -			brcmf_dbg(ERROR, "seq %d: next length error\n", rx_seq); +			brcmf_err("seq %d: next length error\n", rx_seq);  		rd->len_nxtfrm = 0;  	}  	fc = SDPCM_FCMASK_VALUE(&header[SDPCM_FRAMETAG_LEN]); @@ -1113,12 +1150,12 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,  	}  	tx_seq_max = SDPCM_WINDOW_VALUE(&header[SDPCM_FRAMETAG_LEN]);  	if ((u8)(tx_seq_max - bus->tx_seq) > 0x40) { -		brcmf_dbg(ERROR, "seq %d: max tx seq number error\n", rx_seq); +		brcmf_err("seq %d: max tx seq number error\n", rx_seq);  		tx_seq_max = bus->tx_seq + 2;  	}  	bus->tx_max = tx_seq_max; -	return true; +	return 0;  }  static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) @@ -1126,16 +1163,16 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  	u16 dlen, totlen;  	u8 *dptr, num = 0; -	u16 sublen, check; +	u16 sublen;  	struct sk_buff *pfirst, *pnext;  	int errcode; -	u8 chan, seq, doff, sfdoff; -	u8 txmax; +	u8 doff, sfdoff;  	int ifidx = 0;  	bool usechain = bus->use_rxchain; -	u16 next_len; + +	struct brcmf_sdio_read rd_new;  	/* If packets, issue read(s) and send up packet chain */  	/* Return sequence numbers consumed? */ @@ -1149,7 +1186,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  		dlen = (u16) (bus->glomd->len);  		dptr = bus->glomd->data;  		if (!dlen || (dlen & 1)) { -			brcmf_dbg(ERROR, "bad glomd len(%d), ignore descriptor\n", +			brcmf_err("bad glomd len(%d), ignore descriptor\n",  				  dlen);  			dlen = 0;  		} @@ -1161,13 +1198,13 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  			dptr += sizeof(u16);  			if ((sublen < SDPCM_HDRLEN) ||  			    ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) { -				brcmf_dbg(ERROR, "descriptor len %d bad: %d\n", +				brcmf_err("descriptor len %d bad: %d\n",  					  num, sublen);  				pnext = NULL;  				break;  			}  			if (sublen % BRCMF_SDALIGN) { -				brcmf_dbg(ERROR, "sublen %d not multiple of %d\n", +				brcmf_err("sublen %d not multiple of %d\n",  					  sublen, BRCMF_SDALIGN);  				usechain = false;  			} @@ -1184,7 +1221,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  			/* Allocate/chain packet for next subframe */  			pnext = brcmu_pkt_buf_get_skb(sublen + BRCMF_SDALIGN);  			if (pnext == NULL) { -				brcmf_dbg(ERROR, "bcm_pkt_buf_get_skb failed, num %d len %d\n", +				brcmf_err("bcm_pkt_buf_get_skb failed, num %d len %d\n",  					  num, sublen);  				break;  			} @@ -1235,6 +1272,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  		 * read directly into the chained packet, or allocate a large  		 * packet and and copy into the chain.  		 */ +		sdio_claim_host(bus->sdiodev->func[1]);  		if (usechain) {  			errcode = brcmf_sdcard_recv_chain(bus->sdiodev,  					bus->sdiodev->sbwad, @@ -1246,24 +1284,26 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  					bus->dataptr, dlen);  			sublen = (u16) brcmf_sdbrcm_glom_from_buf(bus, dlen);  			if (sublen != dlen) { -				brcmf_dbg(ERROR, "FAILED TO COPY, dlen %d sublen %d\n", +				brcmf_err("FAILED TO COPY, dlen %d sublen %d\n",  					  dlen, sublen);  				errcode = -1;  			}  			pnext = NULL;  		} else { -			brcmf_dbg(ERROR, "COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", +			brcmf_err("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n",  				  dlen);  			errcode = -1;  		} +		sdio_release_host(bus->sdiodev->func[1]);  		bus->sdcnt.f2rxdata++;  		/* On failure, kill the superframe, allow a couple retries */  		if (errcode < 0) { -			brcmf_dbg(ERROR, "glom read of %d bytes failed: %d\n", +			brcmf_err("glom read of %d bytes failed: %d\n",  				  dlen, errcode);  			bus->sdiodev->bus_if->dstats.rx_errors++; +			sdio_claim_host(bus->sdiodev->func[1]);  			if (bus->glomerr++ < 3) {  				brcmf_sdbrcm_rxfail(bus, true, true);  			} else { @@ -1272,6 +1312,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  				bus->sdcnt.rxglomfail++;  				brcmf_sdbrcm_free_glom(bus);  			} +			sdio_release_host(bus->sdiodev->func[1]);  			return 0;  		} @@ -1279,68 +1320,17 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  				   pfirst->data, min_t(int, pfirst->len, 48),  				   "SUPERFRAME:\n"); -		/* Validate the superframe header */ -		dptr = (u8 *) (pfirst->data); -		sublen = get_unaligned_le16(dptr); -		check = get_unaligned_le16(dptr + sizeof(u16)); - -		chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); -		seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]); -		next_len = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; -		if ((next_len << 4) > MAX_RX_DATASZ) { -			brcmf_dbg(INFO, "nextlen too large (%d) seq %d\n", -				  next_len, seq); -			next_len = 0; -		} -		bus->cur_read.len = next_len << 4; -		doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); -		txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); - -		errcode = 0; -		if ((u16)~(sublen ^ check)) { -			brcmf_dbg(ERROR, "(superframe): HW hdr error: len/check 0x%04x/0x%04x\n", -				  sublen, check); -			errcode = -1; -		} else if (roundup(sublen, bus->blocksize) != dlen) { -			brcmf_dbg(ERROR, "(superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n", -				  sublen, roundup(sublen, bus->blocksize), -				  dlen); -			errcode = -1; -		} else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != -			   SDPCM_GLOM_CHANNEL) { -			brcmf_dbg(ERROR, "(superframe): bad channel %d\n", -				  SDPCM_PACKET_CHANNEL( -					  &dptr[SDPCM_FRAMETAG_LEN])); -			errcode = -1; -		} else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) { -			brcmf_dbg(ERROR, "(superframe): got 2nd descriptor?\n"); -			errcode = -1; -		} else if ((doff < SDPCM_HDRLEN) || -			   (doff > (pfirst->len - SDPCM_HDRLEN))) { -			brcmf_dbg(ERROR, "(superframe): Bad data offset %d: HW %d pkt %d min %d\n", -				  doff, sublen, pfirst->len, SDPCM_HDRLEN); -			errcode = -1; -		} - -		/* Check sequence number of superframe SW header */ -		if (rxseq != seq) { -			brcmf_dbg(INFO, "(superframe) rx_seq %d, expected %d\n", -				  seq, rxseq); -			bus->sdcnt.rx_badseq++; -			rxseq = seq; -		} - -		/* Check window for sanity */ -		if ((u8) (txmax - bus->tx_seq) > 0x40) { -			brcmf_dbg(ERROR, "unlikely tx max %d with tx_seq %d\n", -				  txmax, bus->tx_seq); -			txmax = bus->tx_seq + 2; -		} -		bus->tx_max = txmax; +		rd_new.seq_num = rxseq; +		rd_new.len = dlen; +		sdio_claim_host(bus->sdiodev->func[1]); +		errcode = brcmf_sdio_hdparser(bus, pfirst->data, &rd_new, +					      BRCMF_SDIO_FT_SUPER); +		sdio_release_host(bus->sdiodev->func[1]); +		bus->cur_read.len = rd_new.len_nxtfrm << 4;  		/* Remove superframe header, remember offset */ -		skb_pull(pfirst, doff); -		sfdoff = doff; +		skb_pull(pfirst, rd_new.dat_offset); +		sfdoff = rd_new.dat_offset;  		num = 0;  		/* Validate all the subframe headers */ @@ -1349,40 +1339,22 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  			if (errcode)  				break; -			dptr = (u8 *) (pnext->data); -			dlen = (u16) (pnext->len); -			sublen = get_unaligned_le16(dptr); -			check = get_unaligned_le16(dptr + sizeof(u16)); -			chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); -			doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); +			rd_new.len = pnext->len; +			rd_new.seq_num = rxseq++; +			sdio_claim_host(bus->sdiodev->func[1]); +			errcode = brcmf_sdio_hdparser(bus, pnext->data, &rd_new, +						      BRCMF_SDIO_FT_SUB); +			sdio_release_host(bus->sdiodev->func[1]);  			brcmf_dbg_hex_dump(BRCMF_GLOM_ON(), -					   dptr, 32, "subframe:\n"); +					   pnext->data, 32, "subframe:\n"); -			if ((u16)~(sublen ^ check)) { -				brcmf_dbg(ERROR, "(subframe %d): HW hdr error: len/check 0x%04x/0x%04x\n", -					  num, sublen, check); -				errcode = -1; -			} else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) { -				brcmf_dbg(ERROR, "(subframe %d): length mismatch: len 0x%04x, expect 0x%04x\n", -					  num, sublen, dlen); -				errcode = -1; -			} else if ((chan != SDPCM_DATA_CHANNEL) && -				   (chan != SDPCM_EVENT_CHANNEL)) { -				brcmf_dbg(ERROR, "(subframe %d): bad channel %d\n", -					  num, chan); -				errcode = -1; -			} else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) { -				brcmf_dbg(ERROR, "(subframe %d): Bad data offset %d: HW %d min %d\n", -					  num, doff, sublen, SDPCM_HDRLEN); -				errcode = -1; -			} -			/* increase the subframe count */  			num++;  		}  		if (errcode) {  			/* Terminate frame on error, request  				 a couple retries */ +			sdio_claim_host(bus->sdiodev->func[1]);  			if (bus->glomerr++ < 3) {  				/* Restore superframe header space */  				skb_push(pfirst, sfdoff); @@ -1393,6 +1365,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  				bus->sdcnt.rxglomfail++;  				brcmf_sdbrcm_free_glom(bus);  			} +			sdio_release_host(bus->sdiodev->func[1]);  			bus->cur_read.len = 0;  			return 0;  		} @@ -1402,27 +1375,11 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  		skb_queue_walk_safe(&bus->glom, pfirst, pnext) {  			dptr = (u8 *) (pfirst->data);  			sublen = get_unaligned_le16(dptr); -			chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); -			seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);  			doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); -			brcmf_dbg(GLOM, "Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n", -				  num, pfirst, pfirst->data, -				  pfirst->len, sublen, chan, seq); - -			/* precondition: chan == SDPCM_DATA_CHANNEL || -					 chan == SDPCM_EVENT_CHANNEL */ - -			if (rxseq != seq) { -				brcmf_dbg(GLOM, "rx_seq %d, expected %d\n", -					  seq, rxseq); -				bus->sdcnt.rx_badseq++; -				rxseq = seq; -			} -			rxseq++; -  			brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_DATA_ON(), -					   dptr, dlen, "Rx Subframe Data:\n"); +					   dptr, pfirst->len, +					   "Rx Subframe Data:\n");  			__skb_trim(pfirst, sublen);  			skb_pull(pfirst, doff); @@ -1433,7 +1390,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  				continue;  			} else if (brcmf_proto_hdrpull(bus->sdiodev->dev,  						       &ifidx, pfirst) != 0) { -				brcmf_dbg(ERROR, "rx protocol error\n"); +				brcmf_err("rx protocol error\n");  				bus->sdiodev->bus_if->dstats.rx_errors++;  				skb_unlink(pfirst, &bus->glom);  				brcmu_pkt_buf_free_skb(pfirst); @@ -1449,11 +1406,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  					   pfirst->prev);  		}  		/* sent any remaining packets up */ -		if (bus->glom.qlen) { -			up(&bus->sdsem); +		if (bus->glom.qlen)  			brcmf_rx_frame(bus->sdiodev->dev, ifidx, &bus->glom); -			down(&bus->sdsem); -		}  		bus->sdcnt.rxglomframes++;  		bus->sdcnt.rxglompkts += bus->glom.qlen; @@ -1494,21 +1448,24 @@ static void  brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)  {  	uint rdlen, pad; - +	u8 *buf = NULL, *rbuf;  	int sdret;  	brcmf_dbg(TRACE, "Enter\n"); -	/* Set rxctl for frame (w/optional alignment) */ -	bus->rxctl = bus->rxbuf; -	bus->rxctl += BRCMF_FIRSTREAD; -	pad = ((unsigned long)bus->rxctl % BRCMF_SDALIGN); +	if (bus->rxblen) +		buf = vzalloc(bus->rxblen); +	if (!buf) { +		brcmf_err("no memory for control frame\n"); +		goto done; +	} +	rbuf = bus->rxbuf; +	pad = ((unsigned long)rbuf % BRCMF_SDALIGN);  	if (pad) -		bus->rxctl += (BRCMF_SDALIGN - pad); -	bus->rxctl -= BRCMF_FIRSTREAD; +		rbuf += (BRCMF_SDALIGN - pad);  	/* Copy the already-read portion over */ -	memcpy(bus->rxctl, hdr, BRCMF_FIRSTREAD); +	memcpy(buf, hdr, BRCMF_FIRSTREAD);  	if (len <= BRCMF_FIRSTREAD)  		goto gotpkt; @@ -1529,7 +1486,7 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)  	/* Drop if the read is too big or it exceeds our maximum */  	if ((rdlen + BRCMF_FIRSTREAD) > bus->sdiodev->bus_if->maxctl) { -		brcmf_dbg(ERROR, "%d-byte control read exceeds %d-byte buffer\n", +		brcmf_err("%d-byte control read exceeds %d-byte buffer\n",  			  rdlen, bus->sdiodev->bus_if->maxctl);  		bus->sdiodev->bus_if->dstats.rx_errors++;  		brcmf_sdbrcm_rxfail(bus, false, false); @@ -1537,7 +1494,7 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)  	}  	if ((len - doff) > bus->sdiodev->bus_if->maxctl) { -		brcmf_dbg(ERROR, "%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n", +		brcmf_err("%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",  			  len, len - doff, bus->sdiodev->bus_if->maxctl);  		bus->sdiodev->bus_if->dstats.rx_errors++;  		bus->sdcnt.rx_toolong++; @@ -1545,30 +1502,40 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)  		goto done;  	} -	/* Read remainder of frame body into the rxctl buffer */ +	/* Read remain of frame body */  	sdret = brcmf_sdcard_recv_buf(bus->sdiodev,  				bus->sdiodev->sbwad,  				SDIO_FUNC_2, -				F2SYNC, (bus->rxctl + BRCMF_FIRSTREAD), rdlen); +				F2SYNC, rbuf, rdlen);  	bus->sdcnt.f2rxdata++;  	/* Control frame failures need retransmission */  	if (sdret < 0) { -		brcmf_dbg(ERROR, "read %d control bytes failed: %d\n", +		brcmf_err("read %d control bytes failed: %d\n",  			  rdlen, sdret);  		bus->sdcnt.rxc_errors++;  		brcmf_sdbrcm_rxfail(bus, true, true);  		goto done; -	} +	} else +		memcpy(buf + BRCMF_FIRSTREAD, rbuf, rdlen);  gotpkt:  	brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_CTL_ON(), -			   bus->rxctl, len, "RxCtrl:\n"); +			   buf, len, "RxCtrl:\n");  	/* Point to valid data and indicate its length */ -	bus->rxctl += doff; +	spin_lock_bh(&bus->rxctl_lock); +	if (bus->rxctl) { +		brcmf_err("last control frame is being processed.\n"); +		spin_unlock_bh(&bus->rxctl_lock); +		vfree(buf); +		goto done; +	} +	bus->rxctl = buf + doff; +	bus->rxctl_orig = buf;  	bus->rxlen = len - doff; +	spin_unlock_bh(&bus->rxctl_lock);  done:  	/* Awake any waiters */ @@ -1623,6 +1590,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  		rd->len_left = rd->len;  		/* read header first for unknow frame length */ +		sdio_claim_host(bus->sdiodev->func[1]);  		if (!rd->len) {  			sdret = brcmf_sdcard_recv_buf(bus->sdiodev,  						      bus->sdiodev->sbwad, @@ -1631,10 +1599,11 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  						      BRCMF_FIRSTREAD);  			bus->sdcnt.f2rxhdrs++;  			if (sdret < 0) { -				brcmf_dbg(ERROR, "RXHEADER FAILED: %d\n", +				brcmf_err("RXHEADER FAILED: %d\n",  					  sdret);  				bus->sdcnt.rx_hdrfail++;  				brcmf_sdbrcm_rxfail(bus, true, true); +				sdio_release_host(bus->sdiodev->func[1]);  				continue;  			} @@ -1642,7 +1611,9 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  					   bus->rxhdr, SDPCM_HDRLEN,  					   "RxHdr:\n"); -			if (!brcmf_sdio_hdparser(bus, bus->rxhdr, rd)) { +			if (brcmf_sdio_hdparser(bus, bus->rxhdr, rd, +						BRCMF_SDIO_FT_NORMAL)) { +				sdio_release_host(bus->sdiodev->func[1]);  				if (!bus->rxpending)  					break;  				else @@ -1658,6 +1629,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  				rd->len_nxtfrm = 0;  				/* treat all packet as event if we don't know */  				rd->channel = SDPCM_EVENT_CHANNEL; +				sdio_release_host(bus->sdiodev->func[1]);  				continue;  			}  			rd->len_left = rd->len > BRCMF_FIRSTREAD ? @@ -1671,10 +1643,11 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  					    BRCMF_SDALIGN);  		if (!pkt) {  			/* Give up on data, request rtx of events */ -			brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed\n"); +			brcmf_err("brcmu_pkt_buf_get_skb failed\n");  			bus->sdiodev->bus_if->dstats.rx_dropped++;  			brcmf_sdbrcm_rxfail(bus, false,  					    RETRYCHAN(rd->channel)); +			sdio_release_host(bus->sdiodev->func[1]);  			continue;  		}  		skb_pull(pkt, head_read); @@ -1683,14 +1656,17 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  		sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad,  					      SDIO_FUNC_2, F2SYNC, pkt);  		bus->sdcnt.f2rxdata++; +		sdio_release_host(bus->sdiodev->func[1]);  		if (sdret < 0) { -			brcmf_dbg(ERROR, "read %d bytes from channel %d failed: %d\n", +			brcmf_err("read %d bytes from channel %d failed: %d\n",  				  rd->len, rd->channel, sdret);  			brcmu_pkt_buf_free_skb(pkt);  			bus->sdiodev->bus_if->dstats.rx_errors++; +			sdio_claim_host(bus->sdiodev->func[1]);  			brcmf_sdbrcm_rxfail(bus, true,  					    RETRYCHAN(rd->channel)); +			sdio_release_host(bus->sdiodev->func[1]);  			continue;  		} @@ -1701,20 +1677,24 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  		} else {  			memcpy(bus->rxhdr, pkt->data, SDPCM_HDRLEN);  			rd_new.seq_num = rd->seq_num; -			if (!brcmf_sdio_hdparser(bus, bus->rxhdr, &rd_new)) { +			sdio_claim_host(bus->sdiodev->func[1]); +			if (brcmf_sdio_hdparser(bus, bus->rxhdr, &rd_new, +						BRCMF_SDIO_FT_NORMAL)) {  				rd->len = 0;  				brcmu_pkt_buf_free_skb(pkt);  			}  			bus->sdcnt.rx_readahead_cnt++;  			if (rd->len != roundup(rd_new.len, 16)) { -				brcmf_dbg(ERROR, "frame length mismatch:read %d, should be %d\n", +				brcmf_err("frame length mismatch:read %d, should be %d\n",  					  rd->len,  					  roundup(rd_new.len, 16) >> 4);  				rd->len = 0;  				brcmf_sdbrcm_rxfail(bus, true, true); +				sdio_release_host(bus->sdiodev->func[1]);  				brcmu_pkt_buf_free_skb(pkt);  				continue;  			} +			sdio_release_host(bus->sdiodev->func[1]);  			rd->len_nxtfrm = rd_new.len_nxtfrm;  			rd->channel = rd_new.channel;  			rd->dat_offset = rd_new.dat_offset; @@ -1726,11 +1706,13 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  					   "RxHdr:\n");  			if (rd_new.channel == SDPCM_CONTROL_CHANNEL) { -				brcmf_dbg(ERROR, "readahead on control packet %d?\n", +				brcmf_err("readahead on control packet %d?\n",  					  rd_new.seq_num);  				/* Force retry w/normal header read */  				rd->len = 0; +				sdio_claim_host(bus->sdiodev->func[1]);  				brcmf_sdbrcm_rxfail(bus, false, true); +				sdio_release_host(bus->sdiodev->func[1]);  				brcmu_pkt_buf_free_skb(pkt);  				continue;  			} @@ -1751,9 +1733,11 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  				skb_pull(pkt, SDPCM_HDRLEN);  				bus->glomd = pkt;  			} else { -				brcmf_dbg(ERROR, "%s: glom superframe w/o " +				brcmf_err("%s: glom superframe w/o "  					  "descriptor!\n", __func__); +				sdio_claim_host(bus->sdiodev->func[1]);  				brcmf_sdbrcm_rxfail(bus, false, false); +				sdio_release_host(bus->sdiodev->func[1]);  			}  			/* prepare the descriptor for the next read */  			rd->len = rd->len_nxtfrm << 4; @@ -1778,16 +1762,13 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  			continue;  		} else if (brcmf_proto_hdrpull(bus->sdiodev->dev, &ifidx,  			   pkt) != 0) { -			brcmf_dbg(ERROR, "rx protocol error\n"); +			brcmf_err("rx protocol error\n");  			brcmu_pkt_buf_free_skb(pkt);  			bus->sdiodev->bus_if->dstats.rx_errors++;  			continue;  		} -		/* Unlock during rx call */ -		up(&bus->sdsem);  		brcmf_rx_packet(bus->sdiodev->dev, ifidx, pkt); -		down(&bus->sdsem);  	}  	rxcount = maxframes - rxleft; @@ -1805,15 +1786,6 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  }  static void -brcmf_sdbrcm_wait_for_event(struct brcmf_sdio *bus, bool *lockvar) -{ -	up(&bus->sdsem); -	wait_event_interruptible_timeout(bus->ctrl_wait, !*lockvar, HZ * 2); -	down(&bus->sdsem); -	return; -} - -static void  brcmf_sdbrcm_wait_event_wakeup(struct brcmf_sdio *bus)  {  	if (waitqueue_active(&bus->ctrl_wait)) @@ -1846,7 +1818,7 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,  			bus->sdiodev->bus_if->tx_realloc++;  			new = brcmu_pkt_buf_get_skb(pkt->len + BRCMF_SDALIGN);  			if (!new) { -				brcmf_dbg(ERROR, "couldn't allocate new %d-byte packet\n", +				brcmf_err("couldn't allocate new %d-byte packet\n",  					  pkt->len + BRCMF_SDALIGN);  				ret = -ENOMEM;  				goto done; @@ -1914,6 +1886,7 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,  	if (len & (ALIGNMENT - 1))  			len = roundup(len, ALIGNMENT); +	sdio_claim_host(bus->sdiodev->func[1]);  	ret = brcmf_sdcard_send_pkt(bus->sdiodev, bus->sdiodev->sbwad,  				    SDIO_FUNC_2, F2SYNC, pkt);  	bus->sdcnt.f2txdata++; @@ -1941,15 +1914,14 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,  		}  	} +	sdio_release_host(bus->sdiodev->func[1]);  	if (ret == 0)  		bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;  done:  	/* restore pkt buffer pointer before calling tx complete routine */  	skb_pull(pkt, SDPCM_HDRLEN + pad); -	up(&bus->sdsem);  	brcmf_txcomplete(bus->sdiodev->dev, pkt, ret != 0); -	down(&bus->sdsem);  	if (free_pkt)  		brcmu_pkt_buf_free_skb(pkt); @@ -1990,9 +1962,11 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)  		/* In poll mode, need to check for other events */  		if (!bus->intr && cnt) {  			/* Check device status, signal pending interrupt */ +			sdio_claim_host(bus->sdiodev->func[1]);  			ret = r_sdreg32(bus, &intstatus,  					offsetof(struct sdpcmd_regs,  						 intstatus)); +			sdio_release_host(bus->sdiodev->func[1]);  			bus->sdcnt.f2txdata++;  			if (ret != 0)  				break; @@ -2029,7 +2003,7 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)  		bus->watchdog_tsk = NULL;  	} -	down(&bus->sdsem); +	sdio_claim_host(bus->sdiodev->func[1]);  	/* Enable clock for device interrupts */  	brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); @@ -2050,7 +2024,7 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)  				 (saveclk | SBSDIO_FORCE_HT), &err);  	}  	if (err) -		brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err); +		brcmf_err("Failed to force clock for F2: err %d\n", err);  	/* Turn off the bus (F2), free any pending packets */  	brcmf_dbg(INTR, "disable SDIO interrupts\n"); @@ -2063,6 +2037,7 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)  	/* Turn off the backplane clock (only) */  	brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); +	sdio_release_host(bus->sdiodev->func[1]);  	/* Clear the data packet queues */  	brcmu_pktq_flush(&bus->txq, true, NULL, NULL); @@ -2073,14 +2048,14 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)  	brcmf_sdbrcm_free_glom(bus);  	/* Clear rx control and wake any waiters */ +	spin_lock_bh(&bus->rxctl_lock);  	bus->rxlen = 0; +	spin_unlock_bh(&bus->rxctl_lock);  	brcmf_sdbrcm_dcmd_resp_wake(bus);  	/* Reset some F2 state stuff */  	bus->rxskip = false;  	bus->tx_seq = bus->rx_seq = 0; - -	up(&bus->sdsem);  }  #ifdef CONFIG_BRCMFMAC_SDIO_OOB @@ -2164,7 +2139,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)  	brcmf_dbg(TRACE, "Enter\n"); -	down(&bus->sdsem); +	sdio_claim_host(bus->sdiodev->func[1]);  	/* If waiting for HTAVAIL, check status */  	if (bus->clkstate == CLK_PENDING) { @@ -2175,7 +2150,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)  		devctl = brcmf_sdio_regrb(bus->sdiodev,  					  SBSDIO_DEVICE_CTL, &err);  		if (err) { -			brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", err); +			brcmf_err("error reading DEVCTL: %d\n", err);  			bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;  		}  #endif				/* DEBUG */ @@ -2184,7 +2159,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)  		clkctl = brcmf_sdio_regrb(bus->sdiodev,  					  SBSDIO_FUNC1_CHIPCLKCSR, &err);  		if (err) { -			brcmf_dbg(ERROR, "error reading CSR: %d\n", +			brcmf_err("error reading CSR: %d\n",  				  err);  			bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;  		} @@ -2196,7 +2171,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)  			devctl = brcmf_sdio_regrb(bus->sdiodev,  						  SBSDIO_DEVICE_CTL, &err);  			if (err) { -				brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", +				brcmf_err("error reading DEVCTL: %d\n",  					  err);  				bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;  			} @@ -2204,7 +2179,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)  			brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,  					 devctl, &err);  			if (err) { -				brcmf_dbg(ERROR, "error writing DEVCTL: %d\n", +				brcmf_err("error writing DEVCTL: %d\n",  					  err);  				bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;  			} @@ -2218,9 +2193,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)  	/* Pending interrupt indicates new device status */  	if (atomic_read(&bus->ipend) > 0) {  		atomic_set(&bus->ipend, 0); -		sdio_claim_host(bus->sdiodev->func[1]);  		err = brcmf_sdio_intr_rstatus(bus); -		sdio_release_host(bus->sdiodev->func[1]);  	}  	/* Start with leftover status bits */ @@ -2249,19 +2222,21 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)  		intstatus |= brcmf_sdbrcm_hostmail(bus);  	} +	sdio_release_host(bus->sdiodev->func[1]); +  	/* Generally don't ask for these, can get CRC errors... */  	if (intstatus & I_WR_OOSYNC) { -		brcmf_dbg(ERROR, "Dongle reports WR_OOSYNC\n"); +		brcmf_err("Dongle reports WR_OOSYNC\n");  		intstatus &= ~I_WR_OOSYNC;  	}  	if (intstatus & I_RD_OOSYNC) { -		brcmf_dbg(ERROR, "Dongle reports RD_OOSYNC\n"); +		brcmf_err("Dongle reports RD_OOSYNC\n");  		intstatus &= ~I_RD_OOSYNC;  	}  	if (intstatus & I_SBINT) { -		brcmf_dbg(ERROR, "Dongle reports SBINT\n"); +		brcmf_err("Dongle reports SBINT\n");  		intstatus &= ~I_SBINT;  	} @@ -2295,6 +2270,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)  		(bus->clkstate == CLK_AVAIL)) {  		int i; +		sdio_claim_host(bus->sdiodev->func[1]);  		err = brcmf_sdcard_send_buf(bus->sdiodev, bus->sdiodev->sbwad,  			SDIO_FUNC_2, F2SYNC, bus->ctrl_frame_buf,  			(u32) bus->ctrl_frame_len); @@ -2328,6 +2304,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)  		} else {  			bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;  		} +		sdio_release_host(bus->sdiodev->func[1]);  		bus->ctrl_frame_stat = false;  		brcmf_sdbrcm_wait_event_wakeup(bus);  	} @@ -2342,7 +2319,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)  	}  	if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) || (err != 0)) { -		brcmf_dbg(ERROR, "failed backplane access over SDIO, halting operation\n"); +		brcmf_err("failed backplane access over SDIO, halting operation\n");  		bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;  		atomic_set(&bus->intstatus, 0);  	} else if (atomic_read(&bus->intstatus) || @@ -2357,10 +2334,10 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)  	if ((bus->clkstate != CLK_PENDING)  	    && bus->idletime == BRCMF_IDLE_IMMEDIATE) {  		bus->activity = false; +		sdio_claim_host(bus->sdiodev->func[1]);  		brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); +		sdio_release_host(bus->sdiodev->func[1]);  	} - -	up(&bus->sdsem);  }  static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt) @@ -2393,7 +2370,7 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)  		skb_pull(pkt, SDPCM_HDRLEN);  		brcmf_txcomplete(bus->sdiodev->dev, pkt, false);  		brcmu_pkt_buf_free_skb(pkt); -		brcmf_dbg(ERROR, "out of bus->txq !!!\n"); +		brcmf_err("out of bus->txq !!!\n");  		ret = -ENOSR;  	} else {  		ret = 0; @@ -2443,7 +2420,7 @@ brcmf_sdbrcm_membytes(struct brcmf_sdio *bus, bool write, u32 address, u8 *data,  	/* Set the backplane window to include the start address */  	bcmerror = brcmf_sdcard_set_sbaddr_window(bus->sdiodev, address);  	if (bcmerror) { -		brcmf_dbg(ERROR, "window change failed\n"); +		brcmf_err("window change failed\n");  		goto xfer_done;  	} @@ -2455,7 +2432,7 @@ brcmf_sdbrcm_membytes(struct brcmf_sdio *bus, bool write, u32 address, u8 *data,  		bcmerror = brcmf_sdcard_rwdata(bus->sdiodev, write,  					       sdaddr, data, dsize);  		if (bcmerror) { -			brcmf_dbg(ERROR, "membytes transfer failed\n"); +			brcmf_err("membytes transfer failed\n");  			break;  		} @@ -2467,7 +2444,7 @@ brcmf_sdbrcm_membytes(struct brcmf_sdio *bus, bool write, u32 address, u8 *data,  			bcmerror = brcmf_sdcard_set_sbaddr_window(bus->sdiodev,  								  address);  			if (bcmerror) { -				brcmf_dbg(ERROR, "window change failed\n"); +				brcmf_err("window change failed\n");  				break;  			}  			sdaddr = 0; @@ -2478,7 +2455,7 @@ brcmf_sdbrcm_membytes(struct brcmf_sdio *bus, bool write, u32 address, u8 *data,  xfer_done:  	/* Return the window to backplane enumeration space for core access */  	if (brcmf_sdcard_set_sbaddr_window(bus->sdiodev, bus->sdiodev->sbwad)) -		brcmf_dbg(ERROR, "FAILED to set window back to 0x%x\n", +		brcmf_err("FAILED to set window back to 0x%x\n",  			  bus->sdiodev->sbwad);  	sdio_release_host(bus->sdiodev->func[1]); @@ -2651,11 +2628,10 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)  	/* precondition: IS_ALIGNED((unsigned long)frame, 2) */ -	/* Need to lock here to protect txseq and SDIO tx calls */ -	down(&bus->sdsem); -  	/* Make sure backplane clock is on */ +	sdio_claim_host(bus->sdiodev->func[1]);  	brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); +	sdio_release_host(bus->sdiodev->func[1]);  	/* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */  	*(__le16 *) frame = cpu_to_le16((u16) msglen); @@ -2678,7 +2654,9 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)  		bus->ctrl_frame_buf = frame;  		bus->ctrl_frame_len = len; -		brcmf_sdbrcm_wait_for_event(bus, &bus->ctrl_frame_stat); +		wait_event_interruptible_timeout(bus->ctrl_wait, +						 !bus->ctrl_frame_stat, +						 msecs_to_jiffies(2000));  		if (!bus->ctrl_frame_stat) {  			brcmf_dbg(INFO, "ctrl_frame_stat == false\n"); @@ -2697,7 +2675,9 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)  				   frame, min_t(u16, len, 16), "TxHdr:\n");  		do { +			sdio_claim_host(bus->sdiodev->func[1]);  			ret = brcmf_tx_frame(bus, frame, len); +			sdio_release_host(bus->sdiodev->func[1]);  		} while (ret < 0 && retries++ < TXRETRIES);  	} @@ -2707,13 +2687,13 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)  		spin_unlock_irqrestore(&bus->dpc_tl_lock, flags);  		bus->activity = false; +		sdio_claim_host(bus->sdiodev->func[1]);  		brcmf_sdbrcm_clkctl(bus, CLK_NONE, true); +		sdio_release_host(bus->sdiodev->func[1]);  	} else {  		spin_unlock_irqrestore(&bus->dpc_tl_lock, flags);  	} -	up(&bus->sdsem); -  	if (ret)  		bus->sdcnt.tx_ctlerrs++;  	else @@ -2743,8 +2723,10 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus,  	 * Read last word in socram to determine  	 * address of sdpcm_shared structure  	 */ +	sdio_claim_host(bus->sdiodev->func[1]);  	rv = brcmf_sdbrcm_membytes(bus, false, shaddr,  				   (u8 *)&addr_le, 4); +	sdio_claim_host(bus->sdiodev->func[1]);  	if (rv < 0)  		return rv; @@ -2757,14 +2739,16 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus,  	 * NVRAM length at the end of memory should have been overwritten.  	 */  	if (!brcmf_sdio_valid_shared_address(addr)) { -			brcmf_dbg(ERROR, "invalid sdpcm_shared address 0x%08X\n", +			brcmf_err("invalid sdpcm_shared address 0x%08X\n",  				  addr);  			return -EINVAL;  	}  	/* Read hndrte_shared structure */ +	sdio_claim_host(bus->sdiodev->func[1]);  	rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&sh_le,  				   sizeof(struct sdpcm_shared_le)); +	sdio_release_host(bus->sdiodev->func[1]);  	if (rv < 0)  		return rv; @@ -2778,8 +2762,7 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus,  	sh->msgtrace_addr = le32_to_cpu(sh_le.msgtrace_addr);  	if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) { -		brcmf_dbg(ERROR, -			  "sdpcm_shared version mismatch: dhd %d dongle %d\n", +		brcmf_err("sdpcm_shared version mismatch: dhd %d dongle %d\n",  			  SDPCM_SHARED_VERSION,  			  sh->flags & SDPCM_SHARED_VERSION_MASK);  		return -EPROTO; @@ -2867,12 +2850,14 @@ static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh,  	if ((sh->flags & SDPCM_SHARED_TRAP) == 0)  		return 0; +	sdio_claim_host(bus->sdiodev->func[1]);  	error = brcmf_sdbrcm_membytes(bus, false, sh->trap_addr, (u8 *)&tr,  				      sizeof(struct brcmf_trap_info));  	if (error < 0)  		return error;  	nbytes = brcmf_sdio_dump_console(bus, sh, data, count); +	sdio_release_host(bus->sdiodev->func[1]);  	if (nbytes < 0)  		return nbytes; @@ -2918,6 +2903,7 @@ static int brcmf_sdio_assert_info(struct brcmf_sdio *bus,  		return 0;  	} +	sdio_claim_host(bus->sdiodev->func[1]);  	if (sh->assert_file_addr != 0) {  		error = brcmf_sdbrcm_membytes(bus, false, sh->assert_file_addr,  					      (u8 *)file, 80); @@ -2930,6 +2916,7 @@ static int brcmf_sdio_assert_info(struct brcmf_sdio *bus,  		if (error < 0)  			return error;  	} +	sdio_release_host(bus->sdiodev->func[1]);  	res = scnprintf(buf, sizeof(buf),  			"dongle assert: %s:%d: assert(%s)\n", @@ -2942,9 +2929,7 @@ static int brcmf_sdbrcm_checkdied(struct brcmf_sdio *bus)  	int error;  	struct sdpcm_shared sh; -	down(&bus->sdsem);  	error = brcmf_sdio_readshared(bus, &sh); -	up(&bus->sdsem);  	if (error < 0)  		return error; @@ -2952,10 +2937,10 @@ static int brcmf_sdbrcm_checkdied(struct brcmf_sdio *bus)  	if ((sh.flags & SDPCM_SHARED_ASSERT_BUILT) == 0)  		brcmf_dbg(INFO, "firmware not built with -assert\n");  	else if (sh.flags & SDPCM_SHARED_ASSERT) -		brcmf_dbg(ERROR, "assertion in dongle\n"); +		brcmf_err("assertion in dongle\n");  	if (sh.flags & SDPCM_SHARED_TRAP) -		brcmf_dbg(ERROR, "firmware trap in dongle\n"); +		brcmf_err("firmware trap in dongle\n");  	return 0;  } @@ -2971,7 +2956,6 @@ static int brcmf_sdbrcm_died_dump(struct brcmf_sdio *bus, char __user *data,  	if (pos != 0)  		return 0; -	down(&bus->sdsem);  	error = brcmf_sdio_readshared(bus, &sh);  	if (error < 0)  		goto done; @@ -2988,7 +2972,6 @@ static int brcmf_sdbrcm_died_dump(struct brcmf_sdio *bus, char __user *data,  	error += nbytes;  	*ppos += error;  done: -	up(&bus->sdsem);  	return error;  } @@ -3039,6 +3022,7 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)  	int timeleft;  	uint rxlen = 0;  	bool pending; +	u8 *buf;  	struct brcmf_bus *bus_if = dev_get_drvdata(dev);  	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;  	struct brcmf_sdio *bus = sdiodev->bus; @@ -3048,17 +3032,21 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)  	/* Wait until control frame is available */  	timeleft = brcmf_sdbrcm_dcmd_resp_wait(bus, &bus->rxlen, &pending); -	down(&bus->sdsem); +	spin_lock_bh(&bus->rxctl_lock);  	rxlen = bus->rxlen;  	memcpy(msg, bus->rxctl, min(msglen, rxlen)); +	bus->rxctl = NULL; +	buf = bus->rxctl_orig; +	bus->rxctl_orig = NULL;  	bus->rxlen = 0; -	up(&bus->sdsem); +	spin_unlock_bh(&bus->rxctl_lock); +	vfree(buf);  	if (rxlen) {  		brcmf_dbg(CTL, "resumed on rxctl frame, got %d expected %d\n",  			  rxlen, msglen);  	} else if (timeleft == 0) { -		brcmf_dbg(ERROR, "resumed on timeout\n"); +		brcmf_err("resumed on timeout\n");  		brcmf_sdbrcm_checkdied(bus);  	} else if (pending) {  		brcmf_dbg(CTL, "cancelled\n"); @@ -3109,14 +3097,14 @@ static int brcmf_sdbrcm_write_vars(struct brcmf_sdio *bus)  		bcmerror = brcmf_sdbrcm_membytes(bus, false, varaddr,  						 nvram_ularray, bus->varsz);  		if (bcmerror) { -			brcmf_dbg(ERROR, "error %d on reading %d nvram bytes at 0x%08x\n", +			brcmf_err("error %d on reading %d nvram bytes at 0x%08x\n",  				  bcmerror, bus->varsz, varaddr);  		}  		/* Compare the org NVRAM with the one read from RAM */  		if (memcmp(bus->vars, nvram_ularray, bus->varsz)) -			brcmf_dbg(ERROR, "Downloaded NVRAM image is corrupted\n"); +			brcmf_err("Downloaded NVRAM image is corrupted\n");  		else -			brcmf_dbg(ERROR, "Download/Upload/Compare of NVRAM ok\n"); +			brcmf_err("Download/Upload/Compare of NVRAM ok\n");  		kfree(nvram_ularray);  #endif				/* DEBUG */ @@ -3174,14 +3162,14 @@ static int brcmf_sdbrcm_download_state(struct brcmf_sdio *bus, bool enter)  		}  	} else {  		if (!ci->iscoreup(bus->sdiodev, ci, BCMA_CORE_INTERNAL_MEM)) { -			brcmf_dbg(ERROR, "SOCRAM core is down after reset?\n"); +			brcmf_err("SOCRAM core is down after reset?\n");  			bcmerror = -EBADE;  			goto fail;  		}  		bcmerror = brcmf_sdbrcm_write_vars(bus);  		if (bcmerror) { -			brcmf_dbg(ERROR, "no vars written to RAM\n"); +			brcmf_err("no vars written to RAM\n");  			bcmerror = 0;  		} @@ -3221,7 +3209,7 @@ static int brcmf_sdbrcm_download_code_file(struct brcmf_sdio *bus)  	ret = request_firmware(&bus->firmware, BRCMF_SDIO_FW_NAME,  			       &bus->sdiodev->func[2]->dev);  	if (ret) { -		brcmf_dbg(ERROR, "Fail to request firmware %d\n", ret); +		brcmf_err("Fail to request firmware %d\n", ret);  		return ret;  	}  	bus->fw_ptr = 0; @@ -3240,7 +3228,7 @@ static int brcmf_sdbrcm_download_code_file(struct brcmf_sdio *bus)  		brcmf_sdbrcm_get_image((char *)memptr, MEMBLOCK, bus))) {  		ret = brcmf_sdbrcm_membytes(bus, true, offset, memptr, len);  		if (ret) { -			brcmf_dbg(ERROR, "error %d on writing %d membytes at 0x%08x\n", +			brcmf_err("error %d on writing %d membytes at 0x%08x\n",  				  ret, MEMBLOCK, offset);  			goto err;  		} @@ -3340,7 +3328,7 @@ static int brcmf_sdbrcm_download_nvram(struct brcmf_sdio *bus)  	ret = request_firmware(&bus->firmware, BRCMF_SDIO_NV_NAME,  			       &bus->sdiodev->func[2]->dev);  	if (ret) { -		brcmf_dbg(ERROR, "Fail to request nvram %d\n", ret); +		brcmf_err("Fail to request nvram %d\n", ret);  		return ret;  	} @@ -3357,23 +3345,23 @@ static int _brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus)  	/* Keep arm in reset */  	if (brcmf_sdbrcm_download_state(bus, true)) { -		brcmf_dbg(ERROR, "error placing ARM core in reset\n"); +		brcmf_err("error placing ARM core in reset\n");  		goto err;  	}  	/* External image takes precedence if specified */  	if (brcmf_sdbrcm_download_code_file(bus)) { -		brcmf_dbg(ERROR, "dongle image file download failed\n"); +		brcmf_err("dongle image file download failed\n");  		goto err;  	}  	/* External nvram takes precedence if specified */  	if (brcmf_sdbrcm_download_nvram(bus)) -		brcmf_dbg(ERROR, "dongle nvram file download failed\n"); +		brcmf_err("dongle nvram file download failed\n");  	/* Take arm out of reset */  	if (brcmf_sdbrcm_download_state(bus, false)) { -		brcmf_dbg(ERROR, "error getting out of ARM core reset\n"); +		brcmf_err("error getting out of ARM core reset\n");  		goto err;  	} @@ -3388,13 +3376,16 @@ brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus)  {  	bool ret; -	/* Download the firmware */ +	sdio_claim_host(bus->sdiodev->func[1]); +  	brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);  	ret = _brcmf_sdbrcm_download_firmware(bus) == 0;  	brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); +	sdio_release_host(bus->sdiodev->func[1]); +  	return ret;  } @@ -3423,7 +3414,7 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)  	bus->sdcnt.tickcnt = 0;  	brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); -	down(&bus->sdsem); +	sdio_claim_host(bus->sdiodev->func[1]);  	/* Make sure backplane clock is on, needed to generate F2 interrupt */  	brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); @@ -3438,7 +3429,7 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)  				 (saveclk | SBSDIO_FORCE_HT), &err);  	}  	if (err) { -		brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err); +		brcmf_err("Failed to force clock for F2: err %d\n", err);  		goto exit;  	} @@ -3484,7 +3475,7 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)  	if (ret == 0) {  		ret = brcmf_sdio_intr_register(bus->sdiodev);  		if (ret != 0) -			brcmf_dbg(ERROR, "intr register failed:%d\n", ret); +			brcmf_err("intr register failed:%d\n", ret);  	}  	/* If we didn't come up, turn off backplane clock */ @@ -3492,7 +3483,7 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)  		brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);  exit: -	up(&bus->sdsem); +	sdio_release_host(bus->sdiodev->func[1]);  	return ret;  } @@ -3504,12 +3495,12 @@ void brcmf_sdbrcm_isr(void *arg)  	brcmf_dbg(TRACE, "Enter\n");  	if (!bus) { -		brcmf_dbg(ERROR, "bus is null pointer, exiting\n"); +		brcmf_err("bus is null pointer, exiting\n");  		return;  	}  	if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) { -		brcmf_dbg(ERROR, "bus is down. we have nothing to do\n"); +		brcmf_err("bus is down. we have nothing to do\n");  		return;  	}  	/* Count the interrupt call */ @@ -3518,13 +3509,13 @@ void brcmf_sdbrcm_isr(void *arg)  		atomic_set(&bus->ipend, 1);  	else  		if (brcmf_sdio_intr_rstatus(bus)) { -			brcmf_dbg(ERROR, "failed backplane access\n"); +			brcmf_err("failed backplane access\n");  			bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;  		}  	/* Disable additional interrupts (is this needed now)? */  	if (!bus->intr) -		brcmf_dbg(ERROR, "isr w/o interrupt configured!\n"); +		brcmf_err("isr w/o interrupt configured!\n");  	brcmf_sdbrcm_adddpctsk(bus);  	queue_work(bus->brcmf_wq, &bus->datawork); @@ -3539,8 +3530,6 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)  	brcmf_dbg(TIMER, "Enter\n"); -	down(&bus->sdsem); -  	/* Poll period: check device if appropriate. */  	if (bus->poll && (++bus->polltick >= bus->pollrate)) {  		u32 intstatus = 0; @@ -3557,9 +3546,11 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)  				u8 devpend;  				spin_unlock_irqrestore(&bus->dpc_tl_lock,  						       flags); +				sdio_claim_host(bus->sdiodev->func[1]);  				devpend = brcmf_sdio_regrb(bus->sdiodev,  							   SDIO_CCCR_INTx,  							   NULL); +				sdio_release_host(bus->sdiodev->func[1]);  				intstatus =  				    devpend & (INTR_STATUS_FUNC1 |  					       INTR_STATUS_FUNC2); @@ -3584,16 +3575,18 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)  	}  #ifdef DEBUG  	/* Poll for console output periodically */ -	if (bus_if->state == BRCMF_BUS_DATA && +	if (bus_if && bus_if->state == BRCMF_BUS_DATA &&  	    bus->console_interval != 0) {  		bus->console.count += BRCMF_WD_POLL_MS;  		if (bus->console.count >= bus->console_interval) {  			bus->console.count -= bus->console_interval; +			sdio_claim_host(bus->sdiodev->func[1]);  			/* Make sure backplane clock is on */  			brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);  			if (brcmf_sdbrcm_readconsole(bus) < 0)  				/* stop on error */  				bus->console_interval = 0; +			sdio_release_host(bus->sdiodev->func[1]);  		}  	}  #endif				/* DEBUG */ @@ -3606,13 +3599,13 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)  				bus->activity = false;  				brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);  			} else { +				sdio_claim_host(bus->sdiodev->func[1]);  				brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); +				sdio_release_host(bus->sdiodev->func[1]);  			}  		}  	} -	up(&bus->sdsem); -  	return (atomic_read(&bus->ipend) > 0);  } @@ -3707,6 +3700,8 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)  	bus->alp_only = true; +	sdio_claim_host(bus->sdiodev->func[1]); +  	pr_debug("F1 signature read @0x18000000=0x%4x\n",  		 brcmf_sdio_regrl(bus->sdiodev, SI_ENUM_BASE, NULL)); @@ -3722,18 +3717,18 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)  					  SBSDIO_FUNC1_CHIPCLKCSR, &err);  	if (err || ((clkctl & ~SBSDIO_AVBITS) != BRCMF_INIT_CLKCTL1)) { -		brcmf_dbg(ERROR, "ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n", +		brcmf_err("ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n",  			  err, BRCMF_INIT_CLKCTL1, clkctl);  		goto fail;  	}  	if (brcmf_sdio_chip_attach(bus->sdiodev, &bus->ci, regsva)) { -		brcmf_dbg(ERROR, "brcmf_sdio_chip_attach failed!\n"); +		brcmf_err("brcmf_sdio_chip_attach failed!\n");  		goto fail;  	}  	if (!brcmf_sdbrcm_chipmatch((u16) bus->ci->chip)) { -		brcmf_dbg(ERROR, "unsupported chip: 0x%04x\n", bus->ci->chip); +		brcmf_err("unsupported chip: 0x%04x\n", bus->ci->chip);  		goto fail;  	} @@ -3743,7 +3738,7 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)  	/* Get info on the SOCRAM cores... */  	bus->ramsize = bus->ci->ramsize;  	if (!(bus->ramsize)) { -		brcmf_dbg(ERROR, "failed to find SOCRAM memory!\n"); +		brcmf_err("failed to find SOCRAM memory!\n");  		goto fail;  	} @@ -3754,6 +3749,8 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)  	reg_val = brcmf_sdio_regrl(bus->sdiodev, reg_addr, NULL);  	brcmf_sdio_regwl(bus->sdiodev, reg_addr, reg_val | CC_BPRESEN, NULL); +	sdio_release_host(bus->sdiodev->func[1]); +  	brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN);  	/* Locate an appropriately-aligned portion of hdrbuf */ @@ -3769,6 +3766,7 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)  	return true;  fail: +	sdio_release_host(bus->sdiodev->func[1]);  	return false;  } @@ -3776,6 +3774,8 @@ static bool brcmf_sdbrcm_probe_init(struct brcmf_sdio *bus)  {  	brcmf_dbg(TRACE, "Enter\n"); +	sdio_claim_host(bus->sdiodev->func[1]); +  	/* Disable F2 to clear any intermediate frame state on the dongle */  	brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx,  			 SDIO_FUNC_ENABLE_1, NULL); @@ -3786,6 +3786,8 @@ static bool brcmf_sdbrcm_probe_init(struct brcmf_sdio *bus)  	/* Done with backplane-dependent accesses, can drop clock... */  	brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); +	sdio_release_host(bus->sdiodev->func[1]); +  	/* ...and initialize clock/power states */  	bus->clkstate = CLK_SDONLY;  	bus->idletime = BRCMF_IDLE_INTERVAL; @@ -3841,8 +3843,10 @@ static void brcmf_sdbrcm_release_dongle(struct brcmf_sdio *bus)  	brcmf_dbg(TRACE, "Enter\n");  	if (bus->ci) { +		sdio_claim_host(bus->sdiodev->func[1]);  		brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);  		brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); +		sdio_release_host(bus->sdiodev->func[1]);  		brcmf_sdio_chip_detach(&bus->ci);  		if (bus->vars && bus->varsz)  			kfree(bus->vars); @@ -3862,7 +3866,8 @@ static void brcmf_sdbrcm_release(struct brcmf_sdio *bus)  		brcmf_sdio_intr_unregister(bus->sdiodev);  		cancel_work_sync(&bus->datawork); -		destroy_workqueue(bus->brcmf_wq); +		if (bus->brcmf_wq) +			destroy_workqueue(bus->brcmf_wq);  		if (bus->sdiodev->bus_if->drvr) {  			brcmf_detach(bus->sdiodev->dev); @@ -3877,6 +3882,14 @@ static void brcmf_sdbrcm_release(struct brcmf_sdio *bus)  	brcmf_dbg(TRACE, "Disconnected\n");  } +static struct brcmf_bus_ops brcmf_sdio_bus_ops = { +	.stop = brcmf_sdbrcm_bus_stop, +	.init = brcmf_sdbrcm_bus_init, +	.txdata = brcmf_sdbrcm_bus_txdata, +	.txctl = brcmf_sdbrcm_bus_txctl, +	.rxctl = brcmf_sdbrcm_bus_rxctl, +}; +  void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)  {  	int ret; @@ -3904,31 +3917,29 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)  	bus->txminmax = BRCMF_TXMINMAX;  	bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1; +	INIT_WORK(&bus->datawork, brcmf_sdio_dataworker); +	bus->brcmf_wq = create_singlethread_workqueue("brcmf_wq"); +	if (bus->brcmf_wq == NULL) { +		brcmf_err("insufficient memory to create txworkqueue\n"); +		goto fail; +	} +  	/* attempt to attach to the dongle */  	if (!(brcmf_sdbrcm_probe_attach(bus, regsva))) { -		brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_attach failed\n"); +		brcmf_err("brcmf_sdbrcm_probe_attach failed\n");  		goto fail;  	} +	spin_lock_init(&bus->rxctl_lock);  	spin_lock_init(&bus->txqlock);  	init_waitqueue_head(&bus->ctrl_wait);  	init_waitqueue_head(&bus->dcmd_resp_wait); -	bus->brcmf_wq = create_singlethread_workqueue("brcmf_wq"); -	if (bus->brcmf_wq == NULL) { -		brcmf_dbg(ERROR, "insufficient memory to create txworkqueue\n"); -		goto fail; -	} -	INIT_WORK(&bus->datawork, brcmf_sdio_dataworker); -  	/* Set up the watchdog timer */  	init_timer(&bus->timer);  	bus->timer.data = (unsigned long)bus;  	bus->timer.function = brcmf_sdbrcm_watchdog; -	/* Initialize thread based operation and lock */ -	sema_init(&bus->sdsem, 1); -  	/* Initialize watchdog thread */  	init_completion(&bus->watchdog_wait);  	bus->watchdog_tsk = kthread_run(brcmf_sdbrcm_watchdog_thread, @@ -3942,26 +3953,24 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)  	spin_lock_init(&bus->dpc_tl_lock);  	/* Assign bus interface call back */ -	bus->sdiodev->bus_if->brcmf_bus_stop = brcmf_sdbrcm_bus_stop; -	bus->sdiodev->bus_if->brcmf_bus_init = brcmf_sdbrcm_bus_init; -	bus->sdiodev->bus_if->brcmf_bus_txdata = brcmf_sdbrcm_bus_txdata; -	bus->sdiodev->bus_if->brcmf_bus_txctl = brcmf_sdbrcm_bus_txctl; -	bus->sdiodev->bus_if->brcmf_bus_rxctl = brcmf_sdbrcm_bus_rxctl; +	bus->sdiodev->bus_if->dev = bus->sdiodev->dev; +	bus->sdiodev->bus_if->ops = &brcmf_sdio_bus_ops; +  	/* Attach to the brcmf/OS/network interface */  	ret = brcmf_attach(SDPCM_RESERVE, bus->sdiodev->dev);  	if (ret != 0) { -		brcmf_dbg(ERROR, "brcmf_attach failed\n"); +		brcmf_err("brcmf_attach failed\n");  		goto fail;  	}  	/* Allocate buffers */  	if (!(brcmf_sdbrcm_probe_malloc(bus))) { -		brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_malloc failed\n"); +		brcmf_err("brcmf_sdbrcm_probe_malloc failed\n");  		goto fail;  	}  	if (!(brcmf_sdbrcm_probe_init(bus))) { -		brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_init failed\n"); +		brcmf_err("brcmf_sdbrcm_probe_init failed\n");  		goto fail;  	} @@ -3991,10 +4000,8 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)  	/* if firmware path present try to download and bring up bus */  	ret = brcmf_bus_start(bus->sdiodev->dev);  	if (ret != 0) { -		if (ret == -ENOLINK) { -			brcmf_dbg(ERROR, "dongle is not responding\n"); -			goto fail; -		} +		brcmf_err("dongle is not responding\n"); +		goto fail;  	}  	return bus; |