diff options
Diffstat (limited to 'drivers/net/wireless/brcm80211')
56 files changed, 6385 insertions, 5692 deletions
diff --git a/drivers/net/wireless/brcm80211/Kconfig b/drivers/net/wireless/brcm80211/Kconfig index b00a7e92225..fcfed6b99a6 100644 --- a/drivers/net/wireless/brcm80211/Kconfig +++ b/drivers/net/wireless/brcm80211/Kconfig @@ -4,11 +4,12 @@ config BRCMUTIL  config BRCMSMAC  	tristate "Broadcom IEEE802.11n PCIe SoftMAC WLAN driver"  	depends on MAC80211 -	depends on BCMA +	depends on BCMA_POSSIBLE +	select BCMA +	select NEW_LEDS if BCMA_DRIVER_GPIO +	select LEDS_CLASS if BCMA_DRIVER_GPIO  	select BRCMUTIL  	select FW_LOADER -	select CRC_CCITT -	select CRC8  	select CORDIC  	---help---  	  This module adds support for PCIe wireless adapters based on Broadcom diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile index 8e9b1221b32..98e67c18f27 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile +++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile @@ -24,19 +24,20 @@ ccflags-y += -D__CHECK_ENDIAN__  obj-$(CONFIG_BRCMFMAC) += brcmfmac.o  brcmfmac-objs += \  		wl_cfg80211.o \ +		chip.o \  		fwil.o \  		fweh.o \  		fwsignal.o \  		p2p.o \ -		dhd_cdc.o \ +		proto.o \ +		bcdc.o \  		dhd_common.o \  		dhd_linux.o \ +		firmware.o \  		btcoex.o  brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \  		dhd_sdio.o \ -		bcmsdh.o \ -		bcmsdh_sdmmc.o \ -		sdio_chip.o +		bcmsdh.o  brcmfmac-$(CONFIG_BRCMFMAC_USB) += \  		usb.o  brcmfmac-$(CONFIG_BRCMDBG) += \ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c new file mode 100644 index 00000000000..c229210d50b --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c @@ -0,0 +1,375 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/******************************************************************************* + * Communicates with the dongle by using dcmd codes. + * For certain dcmd codes, the dongle interprets string data from the host. + ******************************************************************************/ + +#include <linux/types.h> +#include <linux/netdevice.h> + +#include <brcmu_utils.h> +#include <brcmu_wifi.h> + +#include "dhd.h" +#include "dhd_bus.h" +#include "fwsignal.h" +#include "dhd_dbg.h" +#include "tracepoint.h" +#include "proto.h" +#include "bcdc.h" + +struct brcmf_proto_bcdc_dcmd { +	__le32 cmd;	/* dongle command value */ +	__le32 len;	/* lower 16: output buflen; +			 * upper 16: input buflen (excludes header) */ +	__le32 flags;	/* flag defns given below */ +	__le32 status;	/* status code returned from the device */ +}; + +/* BCDC flag definitions */ +#define BCDC_DCMD_ERROR		0x01		/* 1=cmd failed */ +#define BCDC_DCMD_SET		0x02		/* 0=get, 1=set cmd */ +#define BCDC_DCMD_IF_MASK	0xF000		/* I/F index */ +#define BCDC_DCMD_IF_SHIFT	12 +#define BCDC_DCMD_ID_MASK	0xFFFF0000	/* id an cmd pairing */ +#define BCDC_DCMD_ID_SHIFT	16		/* ID Mask shift bits */ +#define BCDC_DCMD_ID(flags)	\ +	(((flags) & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT) + +/* + * BCDC header - Broadcom specific extension of CDC. + * Used on data packets to convey priority across USB. + */ +#define	BCDC_HEADER_LEN		4 +#define BCDC_PROTO_VER		2	/* Protocol version */ +#define BCDC_FLAG_VER_MASK	0xf0	/* Protocol version mask */ +#define BCDC_FLAG_VER_SHIFT	4	/* Protocol version shift */ +#define BCDC_FLAG_SUM_GOOD	0x04	/* Good RX checksums */ +#define BCDC_FLAG_SUM_NEEDED	0x08	/* Dongle needs to do TX checksums */ +#define BCDC_PRIORITY_MASK	0x7 +#define BCDC_FLAG2_IF_MASK	0x0f	/* packet rx interface in APSTA */ +#define BCDC_FLAG2_IF_SHIFT	0 + +#define BCDC_GET_IF_IDX(hdr) \ +	((int)((((hdr)->flags2) & BCDC_FLAG2_IF_MASK) >> BCDC_FLAG2_IF_SHIFT)) +#define BCDC_SET_IF_IDX(hdr, idx) \ +	((hdr)->flags2 = (((hdr)->flags2 & ~BCDC_FLAG2_IF_MASK) | \ +	((idx) << BCDC_FLAG2_IF_SHIFT))) + +/** + * struct brcmf_proto_bcdc_header - BCDC header format + * + * @flags: flags contain protocol and checksum info. + * @priority: 802.1d priority and USB flow control info (bit 4:7). + * @flags2: additional flags containing dongle interface index. + * @data_offset: start of packet data. header is following by firmware signals. + */ +struct brcmf_proto_bcdc_header { +	u8 flags; +	u8 priority; +	u8 flags2; +	u8 data_offset; +}; + +/* + * maximum length of firmware signal data between + * the BCDC header and packet data in the tx path. + */ +#define BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES	12 + +#define RETRIES 2 /* # of retries to retrieve matching dcmd response */ +#define BUS_HEADER_LEN	(16+64)		/* Must be atleast SDPCM_RESERVE +					 * (amount of header tha might be added) +					 * plus any space that might be needed +					 * for bus alignment padding. +					 */ +struct brcmf_bcdc { +	u16 reqid; +	u8 bus_header[BUS_HEADER_LEN]; +	struct brcmf_proto_bcdc_dcmd msg; +	unsigned char buf[BRCMF_DCMD_MAXLEN]; +}; + + +static int +brcmf_proto_bcdc_msg(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf, +		     uint len, bool set) +{ +	struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd; +	struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg; +	u32 flags; + +	brcmf_dbg(BCDC, "Enter\n"); + +	memset(msg, 0, sizeof(struct brcmf_proto_bcdc_dcmd)); + +	msg->cmd = cpu_to_le32(cmd); +	msg->len = cpu_to_le32(len); +	flags = (++bcdc->reqid << BCDC_DCMD_ID_SHIFT); +	if (set) +		flags |= BCDC_DCMD_SET; +	flags = (flags & ~BCDC_DCMD_IF_MASK) | +		(ifidx << BCDC_DCMD_IF_SHIFT); +	msg->flags = cpu_to_le32(flags); + +	if (buf) +		memcpy(bcdc->buf, buf, len); + +	len += sizeof(*msg); +	if (len > BRCMF_TX_IOCTL_MAX_MSG_SIZE) +		len = BRCMF_TX_IOCTL_MAX_MSG_SIZE; + +	/* Send request */ +	return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&bcdc->msg, len); +} + +static int brcmf_proto_bcdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len) +{ +	int ret; +	struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd; + +	brcmf_dbg(BCDC, "Enter\n"); +	len += sizeof(struct brcmf_proto_bcdc_dcmd); +	do { +		ret = brcmf_bus_rxctl(drvr->bus_if, (unsigned char *)&bcdc->msg, +				      len); +		if (ret < 0) +			break; +	} while (BCDC_DCMD_ID(le32_to_cpu(bcdc->msg.flags)) != id); + +	return ret; +} + +static int +brcmf_proto_bcdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, +			    void *buf, uint len) +{ +	struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd; +	struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg; +	void *info; +	int ret = 0, retries = 0; +	u32 id, flags; + +	brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len); + +	ret = brcmf_proto_bcdc_msg(drvr, ifidx, cmd, buf, len, false); +	if (ret < 0) { +		brcmf_err("brcmf_proto_bcdc_msg failed w/status %d\n", +			  ret); +		goto done; +	} + +retry: +	/* wait for interrupt and get first fragment */ +	ret = brcmf_proto_bcdc_cmplt(drvr, bcdc->reqid, len); +	if (ret < 0) +		goto done; + +	flags = le32_to_cpu(msg->flags); +	id = (flags & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT; + +	if ((id < bcdc->reqid) && (++retries < RETRIES)) +		goto retry; +	if (id != bcdc->reqid) { +		brcmf_err("%s: unexpected request id %d (expected %d)\n", +			  brcmf_ifname(drvr, ifidx), id, bcdc->reqid); +		ret = -EINVAL; +		goto done; +	} + +	/* Check info buffer */ +	info = (void *)&msg[1]; + +	/* Copy info buffer */ +	if (buf) { +		if (ret < (int)len) +			len = ret; +		memcpy(buf, info, len); +	} + +	/* Check the ERROR flag */ +	if (flags & BCDC_DCMD_ERROR) +		ret = le32_to_cpu(msg->status); + +done: +	return ret; +} + +static int +brcmf_proto_bcdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, +			  void *buf, uint len) +{ +	struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd; +	struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg; +	int ret = 0; +	u32 flags, id; + +	brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len); + +	ret = brcmf_proto_bcdc_msg(drvr, ifidx, cmd, buf, len, true); +	if (ret < 0) +		goto done; + +	ret = brcmf_proto_bcdc_cmplt(drvr, bcdc->reqid, len); +	if (ret < 0) +		goto done; + +	flags = le32_to_cpu(msg->flags); +	id = (flags & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT; + +	if (id != bcdc->reqid) { +		brcmf_err("%s: unexpected request id %d (expected %d)\n", +			  brcmf_ifname(drvr, ifidx), id, bcdc->reqid); +		ret = -EINVAL; +		goto done; +	} + +	/* Check the ERROR flag */ +	if (flags & BCDC_DCMD_ERROR) +		ret = le32_to_cpu(msg->status); + +done: +	return ret; +} + +static void +brcmf_proto_bcdc_hdrpush(struct brcmf_pub *drvr, int ifidx, u8 offset, +			 struct sk_buff *pktbuf) +{ +	struct brcmf_proto_bcdc_header *h; + +	brcmf_dbg(BCDC, "Enter\n"); + +	/* Push BDC header used to convey priority for buses that don't */ +	skb_push(pktbuf, BCDC_HEADER_LEN); + +	h = (struct brcmf_proto_bcdc_header *)(pktbuf->data); + +	h->flags = (BCDC_PROTO_VER << BCDC_FLAG_VER_SHIFT); +	if (pktbuf->ip_summed == CHECKSUM_PARTIAL) +		h->flags |= BCDC_FLAG_SUM_NEEDED; + +	h->priority = (pktbuf->priority & BCDC_PRIORITY_MASK); +	h->flags2 = 0; +	h->data_offset = offset; +	BCDC_SET_IF_IDX(h, ifidx); +	trace_brcmf_bcdchdr(pktbuf->data); +} + +static int +brcmf_proto_bcdc_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx, +			 struct sk_buff *pktbuf) +{ +	struct brcmf_proto_bcdc_header *h; + +	brcmf_dbg(BCDC, "Enter\n"); + +	/* Pop BCDC header used to convey priority for buses that don't */ +	if (pktbuf->len <= BCDC_HEADER_LEN) { +		brcmf_dbg(INFO, "rx data too short (%d <= %d)\n", +			  pktbuf->len, BCDC_HEADER_LEN); +		return -EBADE; +	} + +	trace_brcmf_bcdchdr(pktbuf->data); +	h = (struct brcmf_proto_bcdc_header *)(pktbuf->data); + +	*ifidx = BCDC_GET_IF_IDX(h); +	if (*ifidx >= BRCMF_MAX_IFS) { +		brcmf_err("rx data ifnum out of range (%d)\n", *ifidx); +		return -EBADE; +	} +	/* The ifidx is the idx to map to matching netdev/ifp. When receiving +	 * events this is easy because it contains the bssidx which maps +	 * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd. +	 * bssidx 1 is used for p2p0 and no data can be received or +	 * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0 +	 */ +	if (*ifidx) +		(*ifidx)++; + +	if (((h->flags & BCDC_FLAG_VER_MASK) >> BCDC_FLAG_VER_SHIFT) != +	    BCDC_PROTO_VER) { +		brcmf_err("%s: non-BCDC packet received, flags 0x%x\n", +			  brcmf_ifname(drvr, *ifidx), h->flags); +		return -EBADE; +	} + +	if (h->flags & BCDC_FLAG_SUM_GOOD) { +		brcmf_dbg(BCDC, "%s: BDC rcv, good checksum, flags 0x%x\n", +			  brcmf_ifname(drvr, *ifidx), h->flags); +		pktbuf->ip_summed = CHECKSUM_UNNECESSARY; +	} + +	pktbuf->priority = h->priority & BCDC_PRIORITY_MASK; + +	skb_pull(pktbuf, BCDC_HEADER_LEN); +	if (do_fws) +		brcmf_fws_hdrpull(drvr, *ifidx, h->data_offset << 2, pktbuf); +	else +		skb_pull(pktbuf, h->data_offset << 2); + +	if (pktbuf->len == 0) +		return -ENODATA; +	return 0; +} + +static int +brcmf_proto_bcdc_txdata(struct brcmf_pub *drvr, int ifidx, u8 offset, +			struct sk_buff *pktbuf) +{ +	brcmf_proto_bcdc_hdrpush(drvr, ifidx, offset, pktbuf); +	return brcmf_bus_txdata(drvr->bus_if, pktbuf); +} + + +int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr) +{ +	struct brcmf_bcdc *bcdc; + +	bcdc = kzalloc(sizeof(*bcdc), GFP_ATOMIC); +	if (!bcdc) +		goto fail; + +	/* ensure that the msg buf directly follows the cdc msg struct */ +	if ((unsigned long)(&bcdc->msg + 1) != (unsigned long)bcdc->buf) { +		brcmf_err("struct brcmf_proto_bcdc is not correctly defined\n"); +		goto fail; +	} + +	drvr->proto->hdrpull = brcmf_proto_bcdc_hdrpull; +	drvr->proto->query_dcmd = brcmf_proto_bcdc_query_dcmd; +	drvr->proto->set_dcmd = brcmf_proto_bcdc_set_dcmd; +	drvr->proto->txdata = brcmf_proto_bcdc_txdata; +	drvr->proto->pd = bcdc; + +	drvr->hdrlen += BCDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES; +	drvr->bus_if->maxctl = BRCMF_DCMD_MAXLEN + +			sizeof(struct brcmf_proto_bcdc_dcmd); +	return 0; + +fail: +	kfree(bcdc); +	return -ENOMEM; +} + +void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr) +{ +	kfree(drvr->proto->pd); +	drvr->proto->pd = NULL; +} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.h b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.h new file mode 100644 index 00000000000..17e8c039ff3 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2013 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef BRCMFMAC_BCDC_H +#define BRCMFMAC_BCDC_H + + +int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr); +void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr); + + +#endif /* BRCMFMAC_BCDC_H */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index e13b1a65c65..a16e644e7c0 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -17,17 +17,23 @@  #include <linux/types.h>  #include <linux/netdevice.h> -#include <linux/export.h>  #include <linux/pci.h>  #include <linux/pci_ids.h>  #include <linux/sched.h>  #include <linux/completion.h>  #include <linux/scatterlist.h>  #include <linux/mmc/sdio.h> +#include <linux/mmc/core.h>  #include <linux/mmc/sdio_func.h> +#include <linux/mmc/sdio_ids.h>  #include <linux/mmc/card.h>  #include <linux/mmc/host.h> +#include <linux/platform_device.h>  #include <linux/platform_data/brcmfmac-sdio.h> +#include <linux/suspend.h> +#include <linux/errno.h> +#include <linux/module.h> +#include <net/cfg80211.h>  #include <defs.h>  #include <brcm_hw_ids.h> @@ -40,8 +46,21 @@  #define SDIOH_API_ACCESS_RETRY_LIMIT	2 +#define DMA_ALIGN_MASK	0x03 -static irqreturn_t brcmf_sdio_oob_irqhandler(int irq, void *dev_id) +#define SDIO_FUNC1_BLOCKSIZE		64 +#define SDIO_FUNC2_BLOCKSIZE		512 +/* Maximum milliseconds to wait for F2 to come up */ +#define SDIO_WAIT_F2RDY	3000 + +#define BRCMF_DEFAULT_TXGLOM_SIZE	32  /* max tx frames in glom chain */ +#define BRCMF_DEFAULT_RXGLOM_SIZE	32  /* max rx frames in glom chain */ + +static int brcmf_sdiod_txglomsz = BRCMF_DEFAULT_TXGLOM_SIZE; +module_param_named(txglomsz, brcmf_sdiod_txglomsz, int, 0); +MODULE_PARM_DESC(txglomsz, "maximum tx packet chain size [SDIO]"); + +static irqreturn_t brcmf_sdiod_oob_irqhandler(int irq, void *dev_id)  {  	struct brcmf_bus *bus_if = dev_get_drvdata(dev_id);  	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; @@ -56,27 +75,46 @@ static irqreturn_t brcmf_sdio_oob_irqhandler(int irq, void *dev_id)  		sdiodev->irq_en = false;  	} -	brcmf_sdbrcm_isr(sdiodev->bus); +	brcmf_sdio_isr(sdiodev->bus);  	return IRQ_HANDLED;  } -static void brcmf_sdio_ib_irqhandler(struct sdio_func *func) +static void brcmf_sdiod_ib_irqhandler(struct sdio_func *func)  {  	struct brcmf_bus *bus_if = dev_get_drvdata(&func->dev);  	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;  	brcmf_dbg(INTR, "IB intr triggered\n"); -	brcmf_sdbrcm_isr(sdiodev->bus); +	brcmf_sdio_isr(sdiodev->bus);  }  /* dummy handler for SDIO function 2 interrupt */ -static void brcmf_sdio_dummy_irqhandler(struct sdio_func *func) +static void brcmf_sdiod_dummy_irqhandler(struct sdio_func *func) +{ +} + +static bool brcmf_sdiod_pm_resume_error(struct brcmf_sdio_dev *sdiodev) +{ +	bool is_err = false; +#ifdef CONFIG_PM_SLEEP +	is_err = atomic_read(&sdiodev->suspend); +#endif +	return is_err; +} + +static void brcmf_sdiod_pm_resume_wait(struct brcmf_sdio_dev *sdiodev, +				       wait_queue_head_t *wq)  { +#ifdef CONFIG_PM_SLEEP +	int retry = 0; +	while (atomic_read(&sdiodev->suspend) && retry++ != 30) +		wait_event_timeout(*wq, false, HZ/100); +#endif  } -int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev) +int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)  {  	int ret = 0;  	u8 data; @@ -86,7 +124,7 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)  		brcmf_dbg(SDIO, "Enter, register OOB IRQ %d\n",  			  sdiodev->pdata->oob_irq_nr);  		ret = request_irq(sdiodev->pdata->oob_irq_nr, -				  brcmf_sdio_oob_irqhandler, +				  brcmf_sdiod_oob_irqhandler,  				  sdiodev->pdata->oob_irq_flags,  				  "brcmf_oob_intr",  				  &sdiodev->func[1]->dev); @@ -110,36 +148,36 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)  		sdio_claim_host(sdiodev->func[1]);  		/* must configure SDIO_CCCR_IENx to enable irq */ -		data = brcmf_sdio_regrb(sdiodev, SDIO_CCCR_IENx, &ret); +		data = brcmf_sdiod_regrb(sdiodev, SDIO_CCCR_IENx, &ret);  		data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1; -		brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, data, &ret); +		brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_IENx, data, &ret);  		/* redirect, configure and enable io for interrupt signal */  		data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE;  		if (sdiodev->pdata->oob_irq_flags & IRQF_TRIGGER_HIGH)  			data |= SDIO_SEPINT_ACT_HI; -		brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret); +		brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret);  		sdio_release_host(sdiodev->func[1]);  	} else {  		brcmf_dbg(SDIO, "Entering\n");  		sdio_claim_host(sdiodev->func[1]); -		sdio_claim_irq(sdiodev->func[1], brcmf_sdio_ib_irqhandler); -		sdio_claim_irq(sdiodev->func[2], brcmf_sdio_dummy_irqhandler); +		sdio_claim_irq(sdiodev->func[1], brcmf_sdiod_ib_irqhandler); +		sdio_claim_irq(sdiodev->func[2], brcmf_sdiod_dummy_irqhandler);  		sdio_release_host(sdiodev->func[1]);  	}  	return 0;  } -int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev) +int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev)  {  	brcmf_dbg(SDIO, "Entering\n");  	if ((sdiodev->pdata) && (sdiodev->pdata->oob_irq_supported)) {  		sdio_claim_host(sdiodev->func[1]); -		brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL); -		brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL); +		brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL); +		brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL);  		sdio_release_host(sdiodev->func[1]);  		if (sdiodev->oob_irq_requested) { @@ -162,29 +200,151 @@ int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)  	return 0;  } +static inline int brcmf_sdiod_f0_writeb(struct sdio_func *func, +					uint regaddr, u8 byte) +{ +	int err_ret; + +	/* +	 * Can only directly write to some F0 registers. +	 * Handle CCCR_IENx and CCCR_ABORT command +	 * as a special case. +	 */ +	if ((regaddr == SDIO_CCCR_ABORT) || +	    (regaddr == SDIO_CCCR_IENx)) +		sdio_writeb(func, byte, regaddr, &err_ret); +	else +		sdio_f0_writeb(func, byte, regaddr, &err_ret); + +	return err_ret; +} + +static int brcmf_sdiod_request_data(struct brcmf_sdio_dev *sdiodev, u8 fn, +				    u32 addr, u8 regsz, void *data, bool write) +{ +	struct sdio_func *func; +	int ret; + +	brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n", +		  write, fn, addr, regsz); + +	brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_word_wait); +	if (brcmf_sdiod_pm_resume_error(sdiodev)) +		return -EIO; + +	/* only allow byte access on F0 */ +	if (WARN_ON(regsz > 1 && !fn)) +		return -EINVAL; +	func = sdiodev->func[fn]; + +	switch (regsz) { +	case sizeof(u8): +		if (write) { +			if (fn) +				sdio_writeb(func, *(u8 *)data, addr, &ret); +			else +				ret = brcmf_sdiod_f0_writeb(func, addr, +							    *(u8 *)data); +		} else { +			if (fn) +				*(u8 *)data = sdio_readb(func, addr, &ret); +			else +				*(u8 *)data = sdio_f0_readb(func, addr, &ret); +		} +		break; +	case sizeof(u16): +		if (write) +			sdio_writew(func, *(u16 *)data, addr, &ret); +		else +			*(u16 *)data = sdio_readw(func, addr, &ret); +		break; +	case sizeof(u32): +		if (write) +			sdio_writel(func, *(u32 *)data, addr, &ret); +		else +			*(u32 *)data = sdio_readl(func, addr, &ret); +		break; +	default: +		brcmf_err("invalid size: %d\n", regsz); +		break; +	} + +	if (ret) +		brcmf_dbg(SDIO, "failed to %s data F%d@0x%05x, err: %d\n", +			  write ? "write" : "read", fn, addr, ret); + +	return ret; +} + +static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr, +				   u8 regsz, void *data, bool write) +{ +	u8 func; +	s32 retry = 0; +	int ret; + +	if (sdiodev->bus_if->state == BRCMF_BUS_NOMEDIUM) +		return -ENOMEDIUM; + +	/* +	 * figure out how to read the register based on address range +	 * 0x00 ~ 0x7FF: function 0 CCCR and FBR +	 * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers +	 * The rest: function 1 silicon backplane core registers +	 */ +	if ((addr & ~REG_F0_REG_MASK) == 0) +		func = SDIO_FUNC_0; +	else +		func = SDIO_FUNC_1; + +	do { +		if (!write) +			memset(data, 0, regsz); +		/* for retry wait for 1 ms till bus get settled down */ +		if (retry) +			usleep_range(1000, 2000); +		ret = brcmf_sdiod_request_data(sdiodev, func, addr, regsz, +					       data, write); +	} while (ret != 0 && ret != -ENOMEDIUM && +		 retry++ < SDIOH_API_ACCESS_RETRY_LIMIT); + +	if (ret == -ENOMEDIUM) +		brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_NOMEDIUM); +	else if (ret != 0) { +		/* +		 * SleepCSR register access can fail when +		 * waking up the device so reduce this noise +		 * in the logs. +		 */ +		if (addr != SBSDIO_FUNC1_SLEEPCSR) +			brcmf_err("failed to %s data F%d@0x%05x, err: %d\n", +				  write ? "write" : "read", func, addr, ret); +		else +			brcmf_dbg(SDIO, "failed to %s data F%d@0x%05x, err: %d\n", +				  write ? "write" : "read", func, addr, ret); +	} +	return ret; +} +  static int -brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address) +brcmf_sdiod_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)  {  	int err = 0, i;  	u8 addr[3]; -	s32 retry; + +	if (sdiodev->bus_if->state == BRCMF_BUS_NOMEDIUM) +		return -ENOMEDIUM;  	addr[0] = (address >> 8) & SBSDIO_SBADDRLOW_MASK;  	addr[1] = (address >> 16) & SBSDIO_SBADDRMID_MASK;  	addr[2] = (address >> 24) & SBSDIO_SBADDRHIGH_MASK;  	for (i = 0; i < 3; i++) { -		retry = 0; -		do { -			if (retry) -				usleep_range(1000, 2000); -			err = brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, -					SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW + i, -					&addr[i]); -		} while (err != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT); - +		err = brcmf_sdiod_regrw_helper(sdiodev, +					       SBSDIO_FUNC1_SBADDRLOW + i, +					       sizeof(u8), &addr[i], true);  		if (err) { -			brcmf_err("failed at addr:0x%0x\n", +			brcmf_err("failed at addr: 0x%0x\n",  				  SBSDIO_FUNC1_SBADDRLOW + i);  			break;  		} @@ -194,13 +354,13 @@ brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)  }  static int -brcmf_sdio_addrprep(struct brcmf_sdio_dev *sdiodev, uint width, u32 *addr) +brcmf_sdiod_addrprep(struct brcmf_sdio_dev *sdiodev, uint width, u32 *addr)  {  	uint bar0 = *addr & ~SBSDIO_SB_OFT_ADDR_MASK;  	int err = 0;  	if (bar0 != sdiodev->sbwad) { -		err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0); +		err = brcmf_sdiod_set_sbaddr_window(sdiodev, bar0);  		if (err)  			return err; @@ -215,59 +375,14 @@ brcmf_sdio_addrprep(struct brcmf_sdio_dev *sdiodev, uint width, u32 *addr)  	return 0;  } -int -brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr, -			void *data, bool write) -{ -	u8 func_num, reg_size; -	s32 retry = 0; -	int ret; - -	/* -	 * figure out how to read the register based on address range -	 * 0x00 ~ 0x7FF: function 0 CCCR and FBR -	 * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers -	 * The rest: function 1 silicon backplane core registers -	 */ -	if ((addr & ~REG_F0_REG_MASK) == 0) { -		func_num = SDIO_FUNC_0; -		reg_size = 1; -	} else if ((addr & ~REG_F1_MISC_MASK) == 0) { -		func_num = SDIO_FUNC_1; -		reg_size = 1; -	} else { -		func_num = SDIO_FUNC_1; -		reg_size = 4; - -		brcmf_sdio_addrprep(sdiodev, reg_size, &addr); -	} - -	do { -		if (!write) -			memset(data, 0, reg_size); -		if (retry)	/* wait for 1 ms till bus get settled down */ -			usleep_range(1000, 2000); -		if (reg_size == 1) -			ret = brcmf_sdioh_request_byte(sdiodev, write, -						       func_num, addr, data); -		else -			ret = brcmf_sdioh_request_word(sdiodev, write, -						       func_num, addr, data, 4); -	} while (ret != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT); - -	if (ret != 0) -		brcmf_err("failed with %d\n", ret); - -	return ret; -} - -u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret) +u8 brcmf_sdiod_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)  {  	u8 data;  	int retval;  	brcmf_dbg(SDIO, "addr:0x%08x\n", addr); -	retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false); +	retval = brcmf_sdiod_regrw_helper(sdiodev, addr, sizeof(data), &data, +					  false);  	brcmf_dbg(SDIO, "data:0x%02x\n", data);  	if (ret) @@ -276,47 +391,86 @@ u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)  	return data;  } -u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret) +u32 brcmf_sdiod_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)  {  	u32 data;  	int retval;  	brcmf_dbg(SDIO, "addr:0x%08x\n", addr); -	retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false); +	retval = brcmf_sdiod_addrprep(sdiodev, sizeof(data), &addr); +	if (retval) +		goto done; +	retval = brcmf_sdiod_regrw_helper(sdiodev, addr, sizeof(data), &data, +					  false);  	brcmf_dbg(SDIO, "data:0x%08x\n", data); +done:  	if (ret)  		*ret = retval;  	return data;  } -void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr, +void brcmf_sdiod_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr,  		      u8 data, int *ret)  {  	int retval;  	brcmf_dbg(SDIO, "addr:0x%08x, data:0x%02x\n", addr, data); -	retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true); - +	retval = brcmf_sdiod_regrw_helper(sdiodev, addr, sizeof(data), &data, +					  true);  	if (ret)  		*ret = retval;  } -void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr, +void brcmf_sdiod_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr,  		      u32 data, int *ret)  {  	int retval;  	brcmf_dbg(SDIO, "addr:0x%08x, data:0x%08x\n", addr, data); -	retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true); +	retval = brcmf_sdiod_addrprep(sdiodev, sizeof(data), &addr); +	if (retval) +		goto done; +	retval = brcmf_sdiod_regrw_helper(sdiodev, addr, sizeof(data), &data, +					  true); +done:  	if (ret)  		*ret = retval;  } +static int brcmf_sdiod_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn, +			     bool write, u32 addr, struct sk_buff *pkt) +{ +	unsigned int req_sz; +	int err; + +	brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait); +	if (brcmf_sdiod_pm_resume_error(sdiodev)) +		return -EIO; + +	/* Single skb use the standard mmc interface */ +	req_sz = pkt->len + 3; +	req_sz &= (uint)~3; + +	if (write) +		err = sdio_memcpy_toio(sdiodev->func[fn], addr, +				       ((u8 *)(pkt->data)), req_sz); +	else if (fn == 1) +		err = sdio_memcpy_fromio(sdiodev->func[fn], ((u8 *)(pkt->data)), +					 addr, req_sz); +	else +		/* function 2 read is FIFO operation */ +		err = sdio_readsb(sdiodev->func[fn], ((u8 *)(pkt->data)), addr, +				  req_sz); +	if (err == -ENOMEDIUM) +		brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_NOMEDIUM); +	return err; +} +  /** - * brcmf_sdio_buffrw - SDIO interface function for block data access + * brcmf_sdiod_sglist_rw - SDIO interface function for block data access   * @sdiodev: brcmfmac sdio device   * @fn: SDIO function number   * @write: direction flag @@ -327,51 +481,29 @@ void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr,   * stack for block data access. It assumes that the skb passed down by the   * caller has already been padded and aligned.   */ -static int brcmf_sdio_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn, -			     bool write, u32 addr, struct sk_buff_head *pktlist) +static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn, +				 bool write, u32 addr, +				 struct sk_buff_head *pktlist)  {  	unsigned int req_sz, func_blk_sz, sg_cnt, sg_data_sz, pkt_offset; -	unsigned int max_blks, max_req_sz, orig_offset, dst_offset; -	unsigned short max_seg_sz, seg_sz; +	unsigned int max_req_sz, orig_offset, dst_offset; +	unsigned short max_seg_cnt, seg_sz;  	unsigned char *pkt_data, *orig_data, *dst_data;  	struct sk_buff *pkt_next = NULL, *local_pkt_next;  	struct sk_buff_head local_list, *target_list;  	struct mmc_request mmc_req;  	struct mmc_command mmc_cmd;  	struct mmc_data mmc_dat; -	struct sg_table st;  	struct scatterlist *sgl; -	struct mmc_host *host;  	int ret = 0;  	if (!pktlist->qlen)  		return -EINVAL; -	brcmf_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait); -	if (brcmf_pm_resume_error(sdiodev)) +	brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait); +	if (brcmf_sdiod_pm_resume_error(sdiodev))  		return -EIO; -	/* Single skb use the standard mmc interface */ -	if (pktlist->qlen == 1) { -		pkt_next = pktlist->next; -		req_sz = pkt_next->len + 3; -		req_sz &= (uint)~3; - -		if (write) -			return sdio_memcpy_toio(sdiodev->func[fn], addr, -						((u8 *)(pkt_next->data)), -						req_sz); -		else if (fn == 1) -			return sdio_memcpy_fromio(sdiodev->func[fn], -						  ((u8 *)(pkt_next->data)), -						  addr, req_sz); -		else -			/* function 2 read is FIFO operation */ -			return sdio_readsb(sdiodev->func[fn], -					   ((u8 *)(pkt_next->data)), addr, -					   req_sz); -	} -  	target_list = pktlist;  	/* for host with broken sg support, prepare a page aligned list */  	__skb_queue_head_init(&local_list); @@ -398,38 +530,41 @@ static int brcmf_sdio_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn,  		target_list = &local_list;  	} -	host = sdiodev->func[fn]->card->host;  	func_blk_sz = sdiodev->func[fn]->cur_blksize; -	/* Blocks per command is limited by host count, host transfer -	 * size and the maximum for IO_RW_EXTENDED of 511 blocks. -	 */ -	max_blks = min_t(unsigned int, host->max_blk_count, 511u); -	max_req_sz = min_t(unsigned int, host->max_req_size, -			   max_blks * func_blk_sz); -	max_seg_sz = min_t(unsigned short, host->max_segs, SG_MAX_SINGLE_ALLOC); -	max_seg_sz = min_t(unsigned short, max_seg_sz, target_list->qlen); +	max_req_sz = sdiodev->max_request_size; +	max_seg_cnt = min_t(unsigned short, sdiodev->max_segment_count, +			    target_list->qlen);  	seg_sz = target_list->qlen;  	pkt_offset = 0;  	pkt_next = target_list->next; -	if (sg_alloc_table(&st, max_seg_sz, GFP_KERNEL)) { -		ret = -ENOMEM; -		goto exit; -	} +	memset(&mmc_req, 0, sizeof(struct mmc_request)); +	memset(&mmc_cmd, 0, sizeof(struct mmc_command)); +	memset(&mmc_dat, 0, sizeof(struct mmc_data)); + +	mmc_dat.sg = sdiodev->sgtable.sgl; +	mmc_dat.blksz = func_blk_sz; +	mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; +	mmc_cmd.opcode = SD_IO_RW_EXTENDED; +	mmc_cmd.arg = write ? 1<<31 : 0;	/* write flag  */ +	mmc_cmd.arg |= (fn & 0x7) << 28;	/* SDIO func num */ +	mmc_cmd.arg |= 1<<27;			/* block mode */ +	/* for function 1 the addr will be incremented */ +	mmc_cmd.arg |= (fn == 1) ? 1<<26 : 0; +	mmc_cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; +	mmc_req.cmd = &mmc_cmd; +	mmc_req.data = &mmc_dat;  	while (seg_sz) {  		req_sz = 0;  		sg_cnt = 0; -		memset(&mmc_req, 0, sizeof(struct mmc_request)); -		memset(&mmc_cmd, 0, sizeof(struct mmc_command)); -		memset(&mmc_dat, 0, sizeof(struct mmc_data)); -		sgl = st.sgl; +		sgl = sdiodev->sgtable.sgl;  		/* prep sg table */  		while (pkt_next != (struct sk_buff *)target_list) {  			pkt_data = pkt_next->data + pkt_offset;  			sg_data_sz = pkt_next->len - pkt_offset; -			if (sg_data_sz > host->max_seg_size) -				sg_data_sz = host->max_seg_size; +			if (sg_data_sz > sdiodev->max_segment_size) +				sg_data_sz = sdiodev->max_segment_size;  			if (sg_data_sz > max_req_sz - req_sz)  				sg_data_sz = max_req_sz - req_sz; @@ -444,7 +579,7 @@ static int brcmf_sdio_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn,  				pkt_next = pkt_next->next;  			} -			if (req_sz >= max_req_sz || sg_cnt >= max_seg_sz) +			if (req_sz >= max_req_sz || sg_cnt >= max_seg_cnt)  				break;  		}  		seg_sz -= sg_cnt; @@ -455,30 +590,24 @@ static int brcmf_sdio_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn,  			ret = -ENOTBLK;  			goto exit;  		} -		mmc_dat.sg = st.sgl; +  		mmc_dat.sg_len = sg_cnt; -		mmc_dat.blksz = func_blk_sz;  		mmc_dat.blocks = req_sz / func_blk_sz; -		mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; -		mmc_cmd.opcode = SD_IO_RW_EXTENDED; -		mmc_cmd.arg = write ? 1<<31 : 0;	/* write flag  */ -		mmc_cmd.arg |= (fn & 0x7) << 28;	/* SDIO func num */ -		mmc_cmd.arg |= 1<<27;			/* block mode */ -		/* incrementing addr for function 1 */ -		mmc_cmd.arg |= (fn == 1) ? 1<<26 : 0;  		mmc_cmd.arg |= (addr & 0x1FFFF) << 9;	/* address */  		mmc_cmd.arg |= mmc_dat.blocks & 0x1FF;	/* block count */ -		mmc_cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; -		mmc_req.cmd = &mmc_cmd; -		mmc_req.data = &mmc_dat; +		/* incrementing addr for function 1 */  		if (fn == 1)  			addr += req_sz;  		mmc_set_data_timeout(&mmc_dat, sdiodev->func[fn]->card); -		mmc_wait_for_req(host, &mmc_req); +		mmc_wait_for_req(sdiodev->func[fn]->card->host, &mmc_req);  		ret = mmc_cmd.error ? mmc_cmd.error : mmc_dat.error; -		if (ret != 0) { +		if (ret == -ENOMEDIUM) { +			brcmf_bus_change_state(sdiodev->bus_if, +					       BRCMF_BUS_NOMEDIUM); +			break; +		} else if (ret != 0) {  			brcmf_err("CMD53 sg block %s failed %d\n",  				  write ? "write" : "read", ret);  			ret = -EIO; @@ -511,16 +640,14 @@ static int brcmf_sdio_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn,  	}  exit: -	sg_free_table(&st); +	sg_init_table(sdiodev->sgtable.sgl, sdiodev->sgtable.orig_nents);  	while ((pkt_next = __skb_dequeue(&local_list)) != NULL)  		brcmu_pkt_buf_free_skb(pkt_next);  	return ret;  } -int -brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, -		      uint flags, u8 *buf, uint nbytes) +int brcmf_sdiod_recv_buf(struct brcmf_sdio_dev *sdiodev, u8 *buf, uint nbytes)  {  	struct sk_buff *mypkt;  	int err; @@ -532,7 +659,7 @@ brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,  		return -EIO;  	} -	err = brcmf_sdcard_recv_pkt(sdiodev, addr, fn, flags, mypkt); +	err = brcmf_sdiod_recv_pkt(sdiodev, mypkt);  	if (!err)  		memcpy(buf, mypkt->data, nbytes); @@ -540,59 +667,66 @@ brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,  	return err;  } -int -brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, -		      uint flags, struct sk_buff *pkt) +int brcmf_sdiod_recv_pkt(struct brcmf_sdio_dev *sdiodev, struct sk_buff *pkt)  { -	uint width; +	u32 addr = sdiodev->sbwad;  	int err = 0; -	struct sk_buff_head pkt_list; -	brcmf_dbg(SDIO, "fun = %d, addr = 0x%x, size = %d\n", -		  fn, addr, pkt->len); +	brcmf_dbg(SDIO, "addr = 0x%x, size = %d\n", addr, pkt->len); -	width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; -	err = brcmf_sdio_addrprep(sdiodev, width, &addr); +	err = brcmf_sdiod_addrprep(sdiodev, 4, &addr);  	if (err)  		goto done; -	skb_queue_head_init(&pkt_list); -	skb_queue_tail(&pkt_list, pkt); -	err = brcmf_sdio_buffrw(sdiodev, fn, false, addr, &pkt_list); -	skb_dequeue_tail(&pkt_list); +	err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, false, addr, pkt);  done:  	return err;  } -int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, -			    uint flags, struct sk_buff_head *pktq) +int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev, +			   struct sk_buff_head *pktq, uint totlen)  { -	uint incr_fix; -	uint width; +	struct sk_buff *glom_skb; +	struct sk_buff *skb; +	u32 addr = sdiodev->sbwad;  	int err = 0; -	brcmf_dbg(SDIO, "fun = %d, addr = 0x%x, size = %d\n", -		  fn, addr, pktq->qlen); +	brcmf_dbg(SDIO, "addr = 0x%x, size = %d\n", +		  addr, pktq->qlen); -	width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; -	err = brcmf_sdio_addrprep(sdiodev, width, &addr); +	err = brcmf_sdiod_addrprep(sdiodev, 4, &addr);  	if (err)  		goto done; -	incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC; -	err = brcmf_sdio_buffrw(sdiodev, fn, false, addr, pktq); +	if (pktq->qlen == 1) +		err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, false, addr, +					 pktq->next); +	else if (!sdiodev->sg_support) { +		glom_skb = brcmu_pkt_buf_get_skb(totlen); +		if (!glom_skb) +			return -ENOMEM; +		err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, false, addr, +					 glom_skb); +		if (err) +			goto done; + +		skb_queue_walk(pktq, skb) { +			memcpy(skb->data, glom_skb->data, skb->len); +			skb_pull(glom_skb, skb->len); +		} +	} else +		err = brcmf_sdiod_sglist_rw(sdiodev, SDIO_FUNC_2, false, addr, +					    pktq);  done:  	return err;  } -int -brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, -		      uint flags, u8 *buf, uint nbytes) +int brcmf_sdiod_send_buf(struct brcmf_sdio_dev *sdiodev, u8 *buf, uint nbytes)  {  	struct sk_buff *mypkt; -	struct sk_buff_head pktq; +	u32 addr = sdiodev->sbwad;  	int err;  	mypkt = brcmu_pkt_buf_get_skb(nbytes); @@ -603,43 +737,53 @@ brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,  	}  	memcpy(mypkt->data, buf, nbytes); -	__skb_queue_head_init(&pktq); -	__skb_queue_tail(&pktq, mypkt); -	err = brcmf_sdcard_send_pkt(sdiodev, addr, fn, flags, &pktq); -	__skb_dequeue_tail(&pktq); + +	err = brcmf_sdiod_addrprep(sdiodev, 4, &addr); + +	if (!err) +		err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, true, addr, +					 mypkt);  	brcmu_pkt_buf_free_skb(mypkt);  	return err;  } -int -brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, -		      uint flags, struct sk_buff_head *pktq) +int brcmf_sdiod_send_pkt(struct brcmf_sdio_dev *sdiodev, +			 struct sk_buff_head *pktq)  { -	uint width; -	int err = 0; +	struct sk_buff *skb; +	u32 addr = sdiodev->sbwad; +	int err; -	brcmf_dbg(SDIO, "fun = %d, addr = 0x%x, size = %d\n", -		  fn, addr, pktq->qlen); +	brcmf_dbg(SDIO, "addr = 0x%x, size = %d\n", addr, pktq->qlen); -	width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; -	brcmf_sdio_addrprep(sdiodev, width, &addr); +	err = brcmf_sdiod_addrprep(sdiodev, 4, &addr); +	if (err) +		return err; -	err = brcmf_sdio_buffrw(sdiodev, fn, true, addr, pktq); +	if (pktq->qlen == 1 || !sdiodev->sg_support) +		skb_queue_walk(pktq, skb) { +			err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, true, +						 addr, skb); +			if (err) +				break; +		} +	else +		err = brcmf_sdiod_sglist_rw(sdiodev, SDIO_FUNC_2, true, addr, +					    pktq);  	return err;  }  int -brcmf_sdio_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address, -		 u8 *data, uint size) +brcmf_sdiod_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address, +		  u8 *data, uint size)  {  	int bcmerror = 0;  	struct sk_buff *pkt;  	u32 sdaddr;  	uint dsize; -	struct sk_buff_head pkt_list;  	dsize = min_t(uint, SBSDIO_SB_OFT_ADDR_LIMIT, size);  	pkt = dev_alloc_skb(dsize); @@ -648,7 +792,6 @@ brcmf_sdio_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,  		return -EIO;  	}  	pkt->priority = 0; -	skb_queue_head_init(&pkt_list);  	/* Determine initial transfer parameters */  	sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK; @@ -662,7 +805,7 @@ brcmf_sdio_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,  	/* Do the transfer(s) */  	while (size) {  		/* Set the backplane window to include the start address */ -		bcmerror = brcmf_sdcard_set_sbaddr_window(sdiodev, address); +		bcmerror = brcmf_sdiod_set_sbaddr_window(sdiodev, address);  		if (bcmerror)  			break; @@ -676,17 +819,15 @@ brcmf_sdio_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,  		skb_put(pkt, dsize);  		if (write)  			memcpy(pkt->data, data, dsize); -		skb_queue_tail(&pkt_list, pkt); -		bcmerror = brcmf_sdio_buffrw(sdiodev, SDIO_FUNC_1, write, -					     sdaddr, &pkt_list); -		skb_dequeue_tail(&pkt_list); +		bcmerror = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_1, write, +					      sdaddr, pkt);  		if (bcmerror) {  			brcmf_err("membytes transfer failed\n");  			break;  		}  		if (!write)  			memcpy(data, pkt->data, dsize); -		skb_trim(pkt, dsize); +		skb_trim(pkt, 0);  		/* Adjust for next transfer (if any) */  		size -= dsize; @@ -701,7 +842,7 @@ brcmf_sdio_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,  	dev_kfree_skb(pkt);  	/* Return the window to backplane enumeration space for core access */ -	if (brcmf_sdcard_set_sbaddr_window(sdiodev, sdiodev->sbwad)) +	if (brcmf_sdiod_set_sbaddr_window(sdiodev, sdiodev->sbwad))  		brcmf_err("FAILED to set window back to 0x%x\n",  			  sdiodev->sbwad); @@ -710,67 +851,368 @@ brcmf_sdio_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,  	return bcmerror;  } -int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn) +int brcmf_sdiod_abort(struct brcmf_sdio_dev *sdiodev, uint fn)  {  	char t_func = (char)fn;  	brcmf_dbg(SDIO, "Enter\n");  	/* issue abort cmd52 command through F0 */ -	brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, SDIO_FUNC_0, -				 SDIO_CCCR_ABORT, &t_func); +	brcmf_sdiod_request_data(sdiodev, SDIO_FUNC_0, SDIO_CCCR_ABORT, +				 sizeof(t_func), &t_func, true);  	brcmf_dbg(SDIO, "Exit\n");  	return 0;  } -int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) +static void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev) +{ +	uint nents; +	int err; + +	if (!sdiodev->sg_support) +		return; + +	nents = max_t(uint, BRCMF_DEFAULT_RXGLOM_SIZE, brcmf_sdiod_txglomsz); +	nents += (nents >> 4) + 1; + +	WARN_ON(nents > sdiodev->max_segment_count); + +	brcmf_dbg(TRACE, "nents=%d\n", nents); +	err = sg_alloc_table(&sdiodev->sgtable, nents, GFP_KERNEL); +	if (err < 0) { +		brcmf_err("allocation failed: disable scatter-gather"); +		sdiodev->sg_support = false; +	} + +	sdiodev->txglomsz = brcmf_sdiod_txglomsz; +} + +static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev)  { -	u32 regs = 0; +	if (sdiodev->bus) { +		brcmf_sdio_remove(sdiodev->bus); +		sdiodev->bus = NULL; +	} + +	/* Disable Function 2 */ +	sdio_claim_host(sdiodev->func[2]); +	sdio_disable_func(sdiodev->func[2]); +	sdio_release_host(sdiodev->func[2]); + +	/* Disable Function 1 */ +	sdio_claim_host(sdiodev->func[1]); +	sdio_disable_func(sdiodev->func[1]); +	sdio_release_host(sdiodev->func[1]); + +	sg_free_table(&sdiodev->sgtable); +	sdiodev->sbwad = 0; + +	return 0; +} + +static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev) +{ +	struct sdio_func *func; +	struct mmc_host *host; +	uint max_blocks;  	int ret = 0; -	ret = brcmf_sdioh_attach(sdiodev); -	if (ret) +	sdiodev->num_funcs = 2; + +	sdio_claim_host(sdiodev->func[1]); + +	ret = sdio_set_block_size(sdiodev->func[1], SDIO_FUNC1_BLOCKSIZE); +	if (ret) { +		brcmf_err("Failed to set F1 blocksize\n"); +		sdio_release_host(sdiodev->func[1]); +		goto out; +	} +	ret = sdio_set_block_size(sdiodev->func[2], SDIO_FUNC2_BLOCKSIZE); +	if (ret) { +		brcmf_err("Failed to set F2 blocksize\n"); +		sdio_release_host(sdiodev->func[1]); +		goto out; +	} + +	/* increase F2 timeout */ +	sdiodev->func[2]->enable_timeout = SDIO_WAIT_F2RDY; + +	/* Enable Function 1 */ +	ret = sdio_enable_func(sdiodev->func[1]); +	sdio_release_host(sdiodev->func[1]); +	if (ret) { +		brcmf_err("Failed to enable F1: err=%d\n", ret);  		goto out; +	} -	regs = SI_ENUM_BASE; +	/* +	 * determine host related variables after brcmf_sdiod_probe() +	 * as func->cur_blksize is properly set and F2 init has been +	 * completed successfully. +	 */ +	func = sdiodev->func[2]; +	host = func->card->host; +	sdiodev->sg_support = host->max_segs > 1; +	max_blocks = min_t(uint, host->max_blk_count, 511u); +	sdiodev->max_request_size = min_t(uint, host->max_req_size, +					  max_blocks * func->cur_blksize); +	sdiodev->max_segment_count = min_t(uint, host->max_segs, +					   SG_MAX_SINGLE_ALLOC); +	sdiodev->max_segment_size = host->max_seg_size; + +	/* allocate scatter-gather table. sg support +	 * will be disabled upon allocation failure. +	 */ +	brcmf_sdiod_sgtable_alloc(sdiodev);  	/* try to attach to the target device */ -	sdiodev->bus = brcmf_sdbrcm_probe(regs, sdiodev); +	sdiodev->bus = brcmf_sdio_probe(sdiodev);  	if (!sdiodev->bus) { -		brcmf_err("device attach failed\n");  		ret = -ENODEV;  		goto out;  	}  out:  	if (ret) -		brcmf_sdio_remove(sdiodev); +		brcmf_sdiod_remove(sdiodev);  	return ret;  } -EXPORT_SYMBOL(brcmf_sdio_probe); -int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev) +/* devices we support, null terminated */ +static const struct sdio_device_id brcmf_sdmmc_ids[] = { +	{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43143)}, +	{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43241)}, +	{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329)}, +	{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330)}, +	{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334)}, +	{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43362)}, +	{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, +		     SDIO_DEVICE_ID_BROADCOM_4335_4339)}, +	{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4354)}, +	{ /* end: all zeroes */ }, +}; +MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids); + +static struct brcmfmac_sdio_platform_data *brcmfmac_sdio_pdata; + + +static int brcmf_ops_sdio_probe(struct sdio_func *func, +				const struct sdio_device_id *id)  { -	sdiodev->bus_if->state = BRCMF_BUS_DOWN; +	int err; +	struct brcmf_sdio_dev *sdiodev; +	struct brcmf_bus *bus_if; -	if (sdiodev->bus) { -		brcmf_sdbrcm_disconnect(sdiodev->bus); -		sdiodev->bus = NULL; +	brcmf_dbg(SDIO, "Enter\n"); +	brcmf_dbg(SDIO, "Class=%x\n", func->class); +	brcmf_dbg(SDIO, "sdio vendor ID: 0x%04x\n", func->vendor); +	brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device); +	brcmf_dbg(SDIO, "Function#: %d\n", func->num); + +	/* Consume func num 1 but dont do anything with it. */ +	if (func->num == 1) +		return 0; + +	/* Ignore anything but func 2 */ +	if (func->num != 2) +		return -ENODEV; + +	bus_if = kzalloc(sizeof(struct brcmf_bus), GFP_KERNEL); +	if (!bus_if) +		return -ENOMEM; +	sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL); +	if (!sdiodev) { +		kfree(bus_if); +		return -ENOMEM;  	} -	brcmf_sdioh_detach(sdiodev); +	/* store refs to functions used. mmc_card does +	 * not hold the F0 function pointer. +	 */ +	sdiodev->func[0] = kmemdup(func, sizeof(*func), GFP_KERNEL); +	sdiodev->func[0]->num = 0; +	sdiodev->func[1] = func->card->sdio_func[0]; +	sdiodev->func[2] = func; + +	sdiodev->bus_if = bus_if; +	bus_if->bus_priv.sdio = sdiodev; +	bus_if->proto_type = BRCMF_PROTO_BCDC; +	dev_set_drvdata(&func->dev, bus_if); +	dev_set_drvdata(&sdiodev->func[1]->dev, bus_if); +	sdiodev->dev = &sdiodev->func[1]->dev; +	sdiodev->pdata = brcmfmac_sdio_pdata; + +	atomic_set(&sdiodev->suspend, false); +	init_waitqueue_head(&sdiodev->request_word_wait); +	init_waitqueue_head(&sdiodev->request_buffer_wait); + +	brcmf_dbg(SDIO, "F2 found, calling brcmf_sdiod_probe...\n"); +	err = brcmf_sdiod_probe(sdiodev); +	if (err) { +		brcmf_err("F2 error, probe failed %d...\n", err); +		goto fail; +	} -	sdiodev->sbwad = 0; +	brcmf_dbg(SDIO, "F2 init completed...\n"); +	return 0; + +fail: +	dev_set_drvdata(&func->dev, NULL); +	dev_set_drvdata(&sdiodev->func[1]->dev, NULL); +	kfree(sdiodev->func[0]); +	kfree(sdiodev); +	kfree(bus_if); +	return err; +} + +static void brcmf_ops_sdio_remove(struct sdio_func *func) +{ +	struct brcmf_bus *bus_if; +	struct brcmf_sdio_dev *sdiodev; + +	brcmf_dbg(SDIO, "Enter\n"); +	brcmf_dbg(SDIO, "sdio vendor ID: 0x%04x\n", func->vendor); +	brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device); +	brcmf_dbg(SDIO, "Function: %d\n", func->num); +	if (func->num != 1 && func->num != 2) +		return; + +	bus_if = dev_get_drvdata(&func->dev); +	if (bus_if) { +		sdiodev = bus_if->bus_priv.sdio; +		brcmf_sdiod_remove(sdiodev); + +		dev_set_drvdata(&sdiodev->func[1]->dev, NULL); +		dev_set_drvdata(&sdiodev->func[2]->dev, NULL); + +		kfree(bus_if); +		kfree(sdiodev->func[0]); +		kfree(sdiodev); +	} + +	brcmf_dbg(SDIO, "Exit\n"); +} + +#ifdef CONFIG_PM_SLEEP +static int brcmf_ops_sdio_suspend(struct device *dev) +{ +	mmc_pm_flag_t sdio_flags; +	struct brcmf_bus *bus_if = dev_get_drvdata(dev); +	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; +	int ret = 0; + +	brcmf_dbg(SDIO, "Enter\n"); + +	sdio_flags = sdio_get_host_pm_caps(sdiodev->func[1]); +	if (!(sdio_flags & MMC_PM_KEEP_POWER)) { +		brcmf_err("Host can't keep power while suspended\n"); +		return -EINVAL; +	} + +	atomic_set(&sdiodev->suspend, true); + +	ret = sdio_set_host_pm_flags(sdiodev->func[1], MMC_PM_KEEP_POWER); +	if (ret) { +		brcmf_err("Failed to set pm_flags\n"); +		atomic_set(&sdiodev->suspend, false); +		return ret; +	} + +	brcmf_sdio_wd_timer(sdiodev->bus, 0); + +	return ret; +} + +static int brcmf_ops_sdio_resume(struct device *dev) +{ +	struct brcmf_bus *bus_if = dev_get_drvdata(dev); +	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; + +	brcmf_dbg(SDIO, "Enter\n"); +	brcmf_sdio_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS); +	atomic_set(&sdiodev->suspend, false);  	return 0;  } -EXPORT_SYMBOL(brcmf_sdio_remove); -void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev, bool enable) +static const struct dev_pm_ops brcmf_sdio_pm_ops = { +	.suspend	= brcmf_ops_sdio_suspend, +	.resume		= brcmf_ops_sdio_resume, +}; +#endif	/* CONFIG_PM_SLEEP */ + +static struct sdio_driver brcmf_sdmmc_driver = { +	.probe = brcmf_ops_sdio_probe, +	.remove = brcmf_ops_sdio_remove, +	.name = BRCMFMAC_SDIO_PDATA_NAME, +	.id_table = brcmf_sdmmc_ids, +	.drv = { +		.owner = THIS_MODULE, +#ifdef CONFIG_PM_SLEEP +		.pm = &brcmf_sdio_pm_ops, +#endif	/* CONFIG_PM_SLEEP */ +	}, +}; + +static int __init brcmf_sdio_pd_probe(struct platform_device *pdev)  { -	if (enable) -		brcmf_sdbrcm_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS); +	brcmf_dbg(SDIO, "Enter\n"); + +	brcmfmac_sdio_pdata = dev_get_platdata(&pdev->dev); + +	if (brcmfmac_sdio_pdata->power_on) +		brcmfmac_sdio_pdata->power_on(); + +	return 0; +} + +static int brcmf_sdio_pd_remove(struct platform_device *pdev) +{ +	brcmf_dbg(SDIO, "Enter\n"); + +	if (brcmfmac_sdio_pdata->power_off) +		brcmfmac_sdio_pdata->power_off(); + +	sdio_unregister_driver(&brcmf_sdmmc_driver); + +	return 0; +} + +static struct platform_driver brcmf_sdio_pd = { +	.remove		= brcmf_sdio_pd_remove, +	.driver		= { +		.name	= BRCMFMAC_SDIO_PDATA_NAME, +		.owner	= THIS_MODULE, +	} +}; + +void brcmf_sdio_register(void) +{ +	int ret; + +	ret = sdio_register_driver(&brcmf_sdmmc_driver); +	if (ret) +		brcmf_err("sdio_register_driver failed: %d\n", ret); +} + +void brcmf_sdio_exit(void) +{ +	brcmf_dbg(SDIO, "Enter\n"); + +	if (brcmfmac_sdio_pdata) +		platform_driver_unregister(&brcmf_sdio_pd);  	else -		brcmf_sdbrcm_wd_timer(sdiodev->bus, 0); +		sdio_unregister_driver(&brcmf_sdmmc_driver); +} + +void __init brcmf_sdio_init(void) +{ +	int ret; + +	brcmf_dbg(SDIO, "Enter\n"); + +	ret = platform_driver_probe(&brcmf_sdio_pd, brcmf_sdio_pd_probe); +	if (ret == -ENODEV) +		brcmf_dbg(SDIO, "No platform data available.\n");  } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c deleted file mode 100644 index c3462b75bd0..00000000000 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c +++ /dev/null @@ -1,525 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <linux/types.h> -#include <linux/netdevice.h> -#include <linux/mmc/sdio.h> -#include <linux/mmc/core.h> -#include <linux/mmc/sdio_func.h> -#include <linux/mmc/sdio_ids.h> -#include <linux/mmc/card.h> -#include <linux/suspend.h> -#include <linux/errno.h> -#include <linux/sched.h>	/* request_irq() */ -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/platform_data/brcmfmac-sdio.h> -#include <net/cfg80211.h> - -#include <defs.h> -#include <brcm_hw_ids.h> -#include <brcmu_utils.h> -#include <brcmu_wifi.h> -#include "sdio_host.h" -#include "dhd_dbg.h" -#include "dhd_bus.h" - -#define SDIO_VENDOR_ID_BROADCOM		0x02d0 - -#define DMA_ALIGN_MASK	0x03 - -#define SDIO_DEVICE_ID_BROADCOM_43143	43143 -#define SDIO_DEVICE_ID_BROADCOM_43241	0x4324 -#define SDIO_DEVICE_ID_BROADCOM_4329	0x4329 -#define SDIO_DEVICE_ID_BROADCOM_4330	0x4330 -#define SDIO_DEVICE_ID_BROADCOM_4334	0x4334 -#define SDIO_DEVICE_ID_BROADCOM_4335	0x4335 - -#define SDIO_FUNC1_BLOCKSIZE		64 -#define SDIO_FUNC2_BLOCKSIZE		512 - -/* devices we support, null terminated */ -static const struct sdio_device_id brcmf_sdmmc_ids[] = { -	{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43143)}, -	{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43241)}, -	{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329)}, -	{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330)}, -	{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334)}, -	{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4335)}, -	{ /* end: all zeroes */ }, -}; -MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids); - -static struct brcmfmac_sdio_platform_data *brcmfmac_sdio_pdata; - - -bool -brcmf_pm_resume_error(struct brcmf_sdio_dev *sdiodev) -{ -	bool is_err = false; -#ifdef CONFIG_PM_SLEEP -	is_err = atomic_read(&sdiodev->suspend); -#endif -	return is_err; -} - -void -brcmf_pm_resume_wait(struct brcmf_sdio_dev *sdiodev, wait_queue_head_t *wq) -{ -#ifdef CONFIG_PM_SLEEP -	int retry = 0; -	while (atomic_read(&sdiodev->suspend) && retry++ != 30) -		wait_event_timeout(*wq, false, HZ/100); -#endif -} - -static inline int brcmf_sdioh_f0_write_byte(struct brcmf_sdio_dev *sdiodev, -					    uint regaddr, u8 *byte) -{ -	struct sdio_func *sdfunc = sdiodev->func[0]; -	int err_ret; - -	/* -	 * Can only directly write to some F0 registers. -	 * Handle F2 enable/disable and Abort command -	 * as a special case. -	 */ -	if (regaddr == SDIO_CCCR_IOEx) { -		sdfunc = sdiodev->func[2]; -		if (sdfunc) { -			if (*byte & SDIO_FUNC_ENABLE_2) { -				/* Enable Function 2 */ -				err_ret = sdio_enable_func(sdfunc); -				if (err_ret) -					brcmf_err("enable F2 failed:%d\n", -						  err_ret); -			} else { -				/* Disable Function 2 */ -				err_ret = sdio_disable_func(sdfunc); -				if (err_ret) -					brcmf_err("Disable F2 failed:%d\n", -						  err_ret); -			} -		} -	} else if ((regaddr == SDIO_CCCR_ABORT) || -		   (regaddr == SDIO_CCCR_IENx)) { -		sdfunc = kmemdup(sdiodev->func[0], sizeof(struct sdio_func), -				 GFP_KERNEL); -		if (!sdfunc) -			return -ENOMEM; -		sdfunc->num = 0; -		sdio_writeb(sdfunc, *byte, regaddr, &err_ret); -		kfree(sdfunc); -	} else if (regaddr < 0xF0) { -		brcmf_err("F0 Wr:0x%02x: write disallowed\n", regaddr); -		err_ret = -EPERM; -	} else { -		sdio_f0_writeb(sdfunc, *byte, regaddr, &err_ret); -	} - -	return err_ret; -} - -int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw, uint func, -			     uint regaddr, u8 *byte) -{ -	int err_ret; - -	brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x\n", rw, func, regaddr); - -	brcmf_pm_resume_wait(sdiodev, &sdiodev->request_byte_wait); -	if (brcmf_pm_resume_error(sdiodev)) -		return -EIO; - -	if (rw && func == 0) { -		/* handle F0 separately */ -		err_ret = brcmf_sdioh_f0_write_byte(sdiodev, regaddr, byte); -	} else { -		if (rw) /* CMD52 Write */ -			sdio_writeb(sdiodev->func[func], *byte, regaddr, -				    &err_ret); -		else if (func == 0) { -			*byte = sdio_f0_readb(sdiodev->func[func], regaddr, -					      &err_ret); -		} else { -			*byte = sdio_readb(sdiodev->func[func], regaddr, -					   &err_ret); -		} -	} - -	if (err_ret) -		brcmf_err("Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n", -			  rw ? "write" : "read", func, regaddr, *byte, err_ret); - -	return err_ret; -} - -int brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev, -			     uint rw, uint func, uint addr, u32 *word, -			     uint nbytes) -{ -	int err_ret = -EIO; - -	if (func == 0) { -		brcmf_err("Only CMD52 allowed to F0\n"); -		return -EINVAL; -	} - -	brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n", -		  rw, func, addr, nbytes); - -	brcmf_pm_resume_wait(sdiodev, &sdiodev->request_word_wait); -	if (brcmf_pm_resume_error(sdiodev)) -		return -EIO; - -	if (rw) {		/* CMD52 Write */ -		if (nbytes == 4) -			sdio_writel(sdiodev->func[func], *word, addr, -				    &err_ret); -		else if (nbytes == 2) -			sdio_writew(sdiodev->func[func], (*word & 0xFFFF), -				    addr, &err_ret); -		else -			brcmf_err("Invalid nbytes: %d\n", nbytes); -	} else {		/* CMD52 Read */ -		if (nbytes == 4) -			*word = sdio_readl(sdiodev->func[func], addr, &err_ret); -		else if (nbytes == 2) -			*word = sdio_readw(sdiodev->func[func], addr, -					   &err_ret) & 0xFFFF; -		else -			brcmf_err("Invalid nbytes: %d\n", nbytes); -	} - -	if (err_ret) -		brcmf_err("Failed to %s word, Err: 0x%08x\n", -			  rw ? "write" : "read", err_ret); - -	return err_ret; -} - -static int brcmf_sdioh_get_cisaddr(struct brcmf_sdio_dev *sdiodev, u32 regaddr) -{ -	/* read 24 bits and return valid 17 bit addr */ -	int i, ret; -	u32 scratch, regdata; -	__le32 scratch_le; -	u8 *ptr = (u8 *)&scratch_le; - -	for (i = 0; i < 3; i++) { -		regdata = brcmf_sdio_regrl(sdiodev, regaddr, &ret); -		if (ret != 0) -			brcmf_err("Can't read!\n"); - -		*ptr++ = (u8) regdata; -		regaddr++; -	} - -	/* Only the lower 17-bits are valid */ -	scratch = le32_to_cpu(scratch_le); -	scratch &= 0x0001FFFF; -	return scratch; -} - -static int brcmf_sdioh_enablefuncs(struct brcmf_sdio_dev *sdiodev) -{ -	int err_ret; -	u32 fbraddr; -	u8 func; - -	brcmf_dbg(SDIO, "\n"); - -	/* Get the Card's common CIS address */ -	sdiodev->func_cis_ptr[0] = brcmf_sdioh_get_cisaddr(sdiodev, -							   SDIO_CCCR_CIS); -	brcmf_dbg(SDIO, "Card's Common CIS Ptr = 0x%x\n", -		  sdiodev->func_cis_ptr[0]); - -	/* Get the Card's function CIS (for each function) */ -	for (fbraddr = SDIO_FBR_BASE(1), func = 1; -	     func <= sdiodev->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) { -		sdiodev->func_cis_ptr[func] = -		    brcmf_sdioh_get_cisaddr(sdiodev, SDIO_FBR_CIS + fbraddr); -		brcmf_dbg(SDIO, "Function %d CIS Ptr = 0x%x\n", -			  func, sdiodev->func_cis_ptr[func]); -	} - -	/* Enable Function 1 */ -	err_ret = sdio_enable_func(sdiodev->func[1]); -	if (err_ret) -		brcmf_err("Failed to enable F1 Err: 0x%08x\n", err_ret); - -	return false; -} - -/* - *	Public entry points & extern's - */ -int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev) -{ -	int err_ret = 0; - -	brcmf_dbg(SDIO, "\n"); - -	sdiodev->num_funcs = 2; - -	sdio_claim_host(sdiodev->func[1]); - -	err_ret = sdio_set_block_size(sdiodev->func[1], SDIO_FUNC1_BLOCKSIZE); -	if (err_ret) { -		brcmf_err("Failed to set F1 blocksize\n"); -		goto out; -	} - -	err_ret = sdio_set_block_size(sdiodev->func[2], SDIO_FUNC2_BLOCKSIZE); -	if (err_ret) { -		brcmf_err("Failed to set F2 blocksize\n"); -		goto out; -	} - -	brcmf_sdioh_enablefuncs(sdiodev); - -out: -	sdio_release_host(sdiodev->func[1]); -	brcmf_dbg(SDIO, "Done\n"); -	return err_ret; -} - -void brcmf_sdioh_detach(struct brcmf_sdio_dev *sdiodev) -{ -	brcmf_dbg(SDIO, "\n"); - -	/* Disable Function 2 */ -	sdio_claim_host(sdiodev->func[2]); -	sdio_disable_func(sdiodev->func[2]); -	sdio_release_host(sdiodev->func[2]); - -	/* Disable Function 1 */ -	sdio_claim_host(sdiodev->func[1]); -	sdio_disable_func(sdiodev->func[1]); -	sdio_release_host(sdiodev->func[1]); - -} - -static int brcmf_ops_sdio_probe(struct sdio_func *func, -				const struct sdio_device_id *id) -{ -	int err; -	struct brcmf_sdio_dev *sdiodev; -	struct brcmf_bus *bus_if; - -	brcmf_dbg(SDIO, "Enter\n"); -	brcmf_dbg(SDIO, "Class=%x\n", func->class); -	brcmf_dbg(SDIO, "sdio vendor ID: 0x%04x\n", func->vendor); -	brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device); -	brcmf_dbg(SDIO, "Function#: %d\n", func->num); - -	/* Consume func num 1 but dont do anything with it. */ -	if (func->num == 1) -		return 0; - -	/* Ignore anything but func 2 */ -	if (func->num != 2) -		return -ENODEV; - -	bus_if = kzalloc(sizeof(struct brcmf_bus), GFP_KERNEL); -	if (!bus_if) -		return -ENOMEM; -	sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL); -	if (!sdiodev) { -		kfree(bus_if); -		return -ENOMEM; -	} - -	sdiodev->func[0] = func->card->sdio_func[0]; -	sdiodev->func[1] = func->card->sdio_func[0]; -	sdiodev->func[2] = func; - -	sdiodev->bus_if = bus_if; -	bus_if->bus_priv.sdio = sdiodev; -	dev_set_drvdata(&func->dev, bus_if); -	dev_set_drvdata(&sdiodev->func[1]->dev, bus_if); -	sdiodev->dev = &sdiodev->func[1]->dev; -	sdiodev->pdata = brcmfmac_sdio_pdata; - -	atomic_set(&sdiodev->suspend, false); -	init_waitqueue_head(&sdiodev->request_byte_wait); -	init_waitqueue_head(&sdiodev->request_word_wait); -	init_waitqueue_head(&sdiodev->request_buffer_wait); - -	brcmf_dbg(SDIO, "F2 found, calling brcmf_sdio_probe...\n"); -	err = brcmf_sdio_probe(sdiodev); -	if (err) { -		brcmf_err("F2 error, probe failed %d...\n", err); -		goto fail; -	} -	brcmf_dbg(SDIO, "F2 init completed...\n"); -	return 0; - -fail: -	dev_set_drvdata(&func->dev, NULL); -	dev_set_drvdata(&sdiodev->func[1]->dev, NULL); -	kfree(sdiodev); -	kfree(bus_if); -	return err; -} - -static void brcmf_ops_sdio_remove(struct sdio_func *func) -{ -	struct brcmf_bus *bus_if; -	struct brcmf_sdio_dev *sdiodev; - -	brcmf_dbg(SDIO, "Enter\n"); -	brcmf_dbg(SDIO, "sdio vendor ID: 0x%04x\n", func->vendor); -	brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device); -	brcmf_dbg(SDIO, "Function: %d\n", func->num); - -	if (func->num != 1 && func->num != 2) -		return; - -	bus_if = dev_get_drvdata(&func->dev); -	if (bus_if) { -		sdiodev = bus_if->bus_priv.sdio; -		brcmf_sdio_remove(sdiodev); - -		dev_set_drvdata(&sdiodev->func[1]->dev, NULL); -		dev_set_drvdata(&sdiodev->func[2]->dev, NULL); - -		kfree(bus_if); -		kfree(sdiodev); -	} - -	brcmf_dbg(SDIO, "Exit\n"); -} - -#ifdef CONFIG_PM_SLEEP -static int brcmf_sdio_suspend(struct device *dev) -{ -	mmc_pm_flag_t sdio_flags; -	struct brcmf_bus *bus_if = dev_get_drvdata(dev); -	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; -	int ret = 0; - -	brcmf_dbg(SDIO, "\n"); - -	atomic_set(&sdiodev->suspend, true); - -	sdio_flags = sdio_get_host_pm_caps(sdiodev->func[1]); -	if (!(sdio_flags & MMC_PM_KEEP_POWER)) { -		brcmf_err("Host can't keep power while suspended\n"); -		return -EINVAL; -	} - -	ret = sdio_set_host_pm_flags(sdiodev->func[1], MMC_PM_KEEP_POWER); -	if (ret) { -		brcmf_err("Failed to set pm_flags\n"); -		return ret; -	} - -	brcmf_sdio_wdtmr_enable(sdiodev, false); - -	return ret; -} - -static int brcmf_sdio_resume(struct device *dev) -{ -	struct brcmf_bus *bus_if = dev_get_drvdata(dev); -	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; - -	brcmf_sdio_wdtmr_enable(sdiodev, true); -	atomic_set(&sdiodev->suspend, false); -	return 0; -} - -static const struct dev_pm_ops brcmf_sdio_pm_ops = { -	.suspend	= brcmf_sdio_suspend, -	.resume		= brcmf_sdio_resume, -}; -#endif	/* CONFIG_PM_SLEEP */ - -static struct sdio_driver brcmf_sdmmc_driver = { -	.probe = brcmf_ops_sdio_probe, -	.remove = brcmf_ops_sdio_remove, -	.name = BRCMFMAC_SDIO_PDATA_NAME, -	.id_table = brcmf_sdmmc_ids, -#ifdef CONFIG_PM_SLEEP -	.drv = { -		.pm = &brcmf_sdio_pm_ops, -	}, -#endif	/* CONFIG_PM_SLEEP */ -}; - -static int brcmf_sdio_pd_probe(struct platform_device *pdev) -{ -	brcmf_dbg(SDIO, "Enter\n"); - -	brcmfmac_sdio_pdata = pdev->dev.platform_data; - -	if (brcmfmac_sdio_pdata->power_on) -		brcmfmac_sdio_pdata->power_on(); - -	return 0; -} - -static int brcmf_sdio_pd_remove(struct platform_device *pdev) -{ -	brcmf_dbg(SDIO, "Enter\n"); - -	if (brcmfmac_sdio_pdata->power_off) -		brcmfmac_sdio_pdata->power_off(); - -	sdio_unregister_driver(&brcmf_sdmmc_driver); - -	return 0; -} - -static struct platform_driver brcmf_sdio_pd = { -	.remove		= brcmf_sdio_pd_remove, -	.driver		= { -		.name	= BRCMFMAC_SDIO_PDATA_NAME, -		.owner	= THIS_MODULE, -	} -}; - -void brcmf_sdio_register(void) -{ -	int ret; - -	ret = sdio_register_driver(&brcmf_sdmmc_driver); -	if (ret) -		brcmf_err("sdio_register_driver failed: %d\n", ret); -} - -void brcmf_sdio_exit(void) -{ -	brcmf_dbg(SDIO, "Enter\n"); - -	if (brcmfmac_sdio_pdata) -		platform_driver_unregister(&brcmf_sdio_pd); -	else -		sdio_unregister_driver(&brcmf_sdmmc_driver); -} - -void __init brcmf_sdio_init(void) -{ -	int ret; - -	brcmf_dbg(SDIO, "Enter\n"); - -	ret = platform_driver_probe(&brcmf_sdio_pd, brcmf_sdio_pd_probe); -	if (ret == -ENODEV) -		brcmf_dbg(SDIO, "No platform data available.\n"); -} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/brcm80211/brcmfmac/chip.c new file mode 100644 index 00000000000..c7c9f15c0fe --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c @@ -0,0 +1,1035 @@ +/* + * Copyright (c) 2014 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/list.h> +#include <linux/ssb/ssb_regs.h> +#include <linux/bcma/bcma.h> +#include <linux/bcma/bcma_regs.h> + +#include <defs.h> +#include <soc.h> +#include <brcm_hw_ids.h> +#include <brcmu_utils.h> +#include <chipcommon.h> +#include "dhd_dbg.h" +#include "chip.h" + +/* SOC Interconnect types (aka chip types) */ +#define SOCI_SB		0 +#define SOCI_AI		1 + +/* PL-368 DMP definitions */ +#define DMP_DESC_TYPE_MSK	0x0000000F +#define  DMP_DESC_EMPTY		0x00000000 +#define  DMP_DESC_VALID		0x00000001 +#define  DMP_DESC_COMPONENT	0x00000001 +#define  DMP_DESC_MASTER_PORT	0x00000003 +#define  DMP_DESC_ADDRESS	0x00000005 +#define  DMP_DESC_ADDRSIZE_GT32	0x00000008 +#define  DMP_DESC_EOT		0x0000000F + +#define DMP_COMP_DESIGNER	0xFFF00000 +#define DMP_COMP_DESIGNER_S	20 +#define DMP_COMP_PARTNUM	0x000FFF00 +#define DMP_COMP_PARTNUM_S	8 +#define DMP_COMP_CLASS		0x000000F0 +#define DMP_COMP_CLASS_S	4 +#define DMP_COMP_REVISION	0xFF000000 +#define DMP_COMP_REVISION_S	24 +#define DMP_COMP_NUM_SWRAP	0x00F80000 +#define DMP_COMP_NUM_SWRAP_S	19 +#define DMP_COMP_NUM_MWRAP	0x0007C000 +#define DMP_COMP_NUM_MWRAP_S	14 +#define DMP_COMP_NUM_SPORT	0x00003E00 +#define DMP_COMP_NUM_SPORT_S	9 +#define DMP_COMP_NUM_MPORT	0x000001F0 +#define DMP_COMP_NUM_MPORT_S	4 + +#define DMP_MASTER_PORT_UID	0x0000FF00 +#define DMP_MASTER_PORT_UID_S	8 +#define DMP_MASTER_PORT_NUM	0x000000F0 +#define DMP_MASTER_PORT_NUM_S	4 + +#define DMP_SLAVE_ADDR_BASE	0xFFFFF000 +#define DMP_SLAVE_ADDR_BASE_S	12 +#define DMP_SLAVE_PORT_NUM	0x00000F00 +#define DMP_SLAVE_PORT_NUM_S	8 +#define DMP_SLAVE_TYPE		0x000000C0 +#define DMP_SLAVE_TYPE_S	6 +#define  DMP_SLAVE_TYPE_SLAVE	0 +#define  DMP_SLAVE_TYPE_BRIDGE	1 +#define  DMP_SLAVE_TYPE_SWRAP	2 +#define  DMP_SLAVE_TYPE_MWRAP	3 +#define DMP_SLAVE_SIZE_TYPE	0x00000030 +#define DMP_SLAVE_SIZE_TYPE_S	4 +#define  DMP_SLAVE_SIZE_4K	0 +#define  DMP_SLAVE_SIZE_8K	1 +#define  DMP_SLAVE_SIZE_16K	2 +#define  DMP_SLAVE_SIZE_DESC	3 + +/* EROM CompIdentB */ +#define CIB_REV_MASK		0xff000000 +#define CIB_REV_SHIFT		24 + +/* ARM CR4 core specific control flag bits */ +#define ARMCR4_BCMA_IOCTL_CPUHALT	0x0020 + +/* D11 core specific control flag bits */ +#define D11_BCMA_IOCTL_PHYCLOCKEN	0x0004 +#define D11_BCMA_IOCTL_PHYRESET		0x0008 + +/* chip core base & ramsize */ +/* bcm4329 */ +/* SDIO device core, ID 0x829 */ +#define BCM4329_CORE_BUS_BASE		0x18011000 +/* internal memory core, ID 0x80e */ +#define BCM4329_CORE_SOCRAM_BASE	0x18003000 +/* ARM Cortex M3 core, ID 0x82a */ +#define BCM4329_CORE_ARM_BASE		0x18002000 +#define BCM4329_RAMSIZE			0x48000 + +/* bcm43143 */ +/* SDIO device core */ +#define BCM43143_CORE_BUS_BASE		0x18002000 +/* internal memory core */ +#define BCM43143_CORE_SOCRAM_BASE	0x18004000 +/* ARM Cortex M3 core, ID 0x82a */ +#define BCM43143_CORE_ARM_BASE		0x18003000 +#define BCM43143_RAMSIZE		0x70000 + +#define CORE_SB(base, field) \ +		(base + SBCONFIGOFF + offsetof(struct sbconfig, field)) +#define	SBCOREREV(sbidh) \ +	((((sbidh) & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT) | \ +	  ((sbidh) & SSB_IDHIGH_RCLO)) + +struct sbconfig { +	u32 PAD[2]; +	u32 sbipsflag;	/* initiator port ocp slave flag */ +	u32 PAD[3]; +	u32 sbtpsflag;	/* target port ocp slave flag */ +	u32 PAD[11]; +	u32 sbtmerrloga;	/* (sonics >= 2.3) */ +	u32 PAD; +	u32 sbtmerrlog;	/* (sonics >= 2.3) */ +	u32 PAD[3]; +	u32 sbadmatch3;	/* address match3 */ +	u32 PAD; +	u32 sbadmatch2;	/* address match2 */ +	u32 PAD; +	u32 sbadmatch1;	/* address match1 */ +	u32 PAD[7]; +	u32 sbimstate;	/* initiator agent state */ +	u32 sbintvec;	/* interrupt mask */ +	u32 sbtmstatelow;	/* target state */ +	u32 sbtmstatehigh;	/* target state */ +	u32 sbbwa0;		/* bandwidth allocation table0 */ +	u32 PAD; +	u32 sbimconfiglow;	/* initiator configuration */ +	u32 sbimconfighigh;	/* initiator configuration */ +	u32 sbadmatch0;	/* address match0 */ +	u32 PAD; +	u32 sbtmconfiglow;	/* target configuration */ +	u32 sbtmconfighigh;	/* target configuration */ +	u32 sbbconfig;	/* broadcast configuration */ +	u32 PAD; +	u32 sbbstate;	/* broadcast state */ +	u32 PAD[3]; +	u32 sbactcnfg;	/* activate configuration */ +	u32 PAD[3]; +	u32 sbflagst;	/* current sbflags */ +	u32 PAD[3]; +	u32 sbidlow;		/* identification */ +	u32 sbidhigh;	/* identification */ +}; + +struct brcmf_core_priv { +	struct brcmf_core pub; +	u32 wrapbase; +	struct list_head list; +	struct brcmf_chip_priv *chip; +}; + +/* ARM CR4 core specific control flag bits */ +#define ARMCR4_BCMA_IOCTL_CPUHALT	0x0020 + +/* D11 core specific control flag bits */ +#define D11_BCMA_IOCTL_PHYCLOCKEN	0x0004 +#define D11_BCMA_IOCTL_PHYRESET		0x0008 + +struct brcmf_chip_priv { +	struct brcmf_chip pub; +	const struct brcmf_buscore_ops *ops; +	void *ctx; +	/* assured first core is chipcommon, second core is buscore */ +	struct list_head cores; +	u16 num_cores; + +	bool (*iscoreup)(struct brcmf_core_priv *core); +	void (*coredisable)(struct brcmf_core_priv *core, u32 prereset, +			    u32 reset); +	void (*resetcore)(struct brcmf_core_priv *core, u32 prereset, u32 reset, +			  u32 postreset); +}; + +static void brcmf_chip_sb_corerev(struct brcmf_chip_priv *ci, +				  struct brcmf_core *core) +{ +	u32 regdata; + +	regdata = ci->ops->read32(ci->ctx, CORE_SB(core->base, sbidhigh)); +	core->rev = SBCOREREV(regdata); +} + +static bool brcmf_chip_sb_iscoreup(struct brcmf_core_priv *core) +{ +	struct brcmf_chip_priv *ci; +	u32 regdata; +	u32 address; + +	ci = core->chip; +	address = CORE_SB(core->pub.base, sbtmstatelow); +	regdata = ci->ops->read32(ci->ctx, address); +	regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT | +		    SSB_IMSTATE_REJECT | SSB_TMSLOW_CLOCK); +	return SSB_TMSLOW_CLOCK == regdata; +} + +static bool brcmf_chip_ai_iscoreup(struct brcmf_core_priv *core) +{ +	struct brcmf_chip_priv *ci; +	u32 regdata; +	bool ret; + +	ci = core->chip; +	regdata = ci->ops->read32(ci->ctx, core->wrapbase + BCMA_IOCTL); +	ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK; + +	regdata = ci->ops->read32(ci->ctx, core->wrapbase + BCMA_RESET_CTL); +	ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0); + +	return ret; +} + +static void brcmf_chip_sb_coredisable(struct brcmf_core_priv *core, +				      u32 prereset, u32 reset) +{ +	struct brcmf_chip_priv *ci; +	u32 val, base; + +	ci = core->chip; +	base = core->pub.base; +	val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow)); +	if (val & SSB_TMSLOW_RESET) +		return; + +	val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow)); +	if ((val & SSB_TMSLOW_CLOCK) != 0) { +		/* +		 * set target reject and spin until busy is clear +		 * (preserve core-specific bits) +		 */ +		val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow)); +		ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow), +					 val | SSB_TMSLOW_REJECT); + +		val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow)); +		udelay(1); +		SPINWAIT((ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatehigh)) +			  & SSB_TMSHIGH_BUSY), 100000); + +		val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatehigh)); +		if (val & SSB_TMSHIGH_BUSY) +			brcmf_err("core state still busy\n"); + +		val = ci->ops->read32(ci->ctx, CORE_SB(base, sbidlow)); +		if (val & SSB_IDLOW_INITIATOR) { +			val = ci->ops->read32(ci->ctx, +					      CORE_SB(base, sbimstate)); +			val |= SSB_IMSTATE_REJECT; +			ci->ops->write32(ci->ctx, +					 CORE_SB(base, sbimstate), val); +			val = ci->ops->read32(ci->ctx, +					      CORE_SB(base, sbimstate)); +			udelay(1); +			SPINWAIT((ci->ops->read32(ci->ctx, +						  CORE_SB(base, sbimstate)) & +				  SSB_IMSTATE_BUSY), 100000); +		} + +		/* set reset and reject while enabling the clocks */ +		val = SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | +		      SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET; +		ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow), val); +		val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow)); +		udelay(10); + +		/* clear the initiator reject bit */ +		val = ci->ops->read32(ci->ctx, CORE_SB(base, sbidlow)); +		if (val & SSB_IDLOW_INITIATOR) { +			val = ci->ops->read32(ci->ctx, +					      CORE_SB(base, sbimstate)); +			val &= ~SSB_IMSTATE_REJECT; +			ci->ops->write32(ci->ctx, +					 CORE_SB(base, sbimstate), val); +		} +	} + +	/* leave reset and reject asserted */ +	ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow), +			 (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET)); +	udelay(1); +} + +static void brcmf_chip_ai_coredisable(struct brcmf_core_priv *core, +				      u32 prereset, u32 reset) +{ +	struct brcmf_chip_priv *ci; +	u32 regdata; + +	ci = core->chip; + +	/* if core is already in reset, skip reset */ +	regdata = ci->ops->read32(ci->ctx, core->wrapbase + BCMA_RESET_CTL); +	if ((regdata & BCMA_RESET_CTL_RESET) != 0) +		goto in_reset_configure; + +	/* configure reset */ +	ci->ops->write32(ci->ctx, core->wrapbase + BCMA_IOCTL, +			 prereset | BCMA_IOCTL_FGC | BCMA_IOCTL_CLK); +	ci->ops->read32(ci->ctx, core->wrapbase + BCMA_IOCTL); + +	/* put in reset */ +	ci->ops->write32(ci->ctx, core->wrapbase + BCMA_RESET_CTL, +			 BCMA_RESET_CTL_RESET); +	usleep_range(10, 20); + +	/* wait till reset is 1 */ +	SPINWAIT(ci->ops->read32(ci->ctx, core->wrapbase + BCMA_RESET_CTL) != +		 BCMA_RESET_CTL_RESET, 300); + +in_reset_configure: +	/* in-reset configure */ +	ci->ops->write32(ci->ctx, core->wrapbase + BCMA_IOCTL, +			 reset | BCMA_IOCTL_FGC | BCMA_IOCTL_CLK); +	ci->ops->read32(ci->ctx, core->wrapbase + BCMA_IOCTL); +} + +static void brcmf_chip_sb_resetcore(struct brcmf_core_priv *core, u32 prereset, +				    u32 reset, u32 postreset) +{ +	struct brcmf_chip_priv *ci; +	u32 regdata; +	u32 base; + +	ci = core->chip; +	base = core->pub.base; +	/* +	 * Must do the disable sequence first to work for +	 * arbitrary current core state. +	 */ +	brcmf_chip_sb_coredisable(core, 0, 0); + +	/* +	 * Now do the initialization sequence. +	 * set reset while enabling the clock and +	 * forcing them on throughout the core +	 */ +	ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow), +			 SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | +			 SSB_TMSLOW_RESET); +	regdata = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow)); +	udelay(1); + +	/* clear any serror */ +	regdata = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatehigh)); +	if (regdata & SSB_TMSHIGH_SERR) +		ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatehigh), 0); + +	regdata = ci->ops->read32(ci->ctx, CORE_SB(base, sbimstate)); +	if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO)) { +		regdata &= ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO); +		ci->ops->write32(ci->ctx, CORE_SB(base, sbimstate), regdata); +	} + +	/* clear reset and allow it to propagate throughout the core */ +	ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow), +			 SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK); +	regdata = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow)); +	udelay(1); + +	/* leave clock enabled */ +	ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow), +			 SSB_TMSLOW_CLOCK); +	regdata = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow)); +	udelay(1); +} + +static void brcmf_chip_ai_resetcore(struct brcmf_core_priv *core, u32 prereset, +				    u32 reset, u32 postreset) +{ +	struct brcmf_chip_priv *ci; +	int count; + +	ci = core->chip; + +	/* must disable first to work for arbitrary current core state */ +	brcmf_chip_ai_coredisable(core, prereset, reset); + +	count = 0; +	while (ci->ops->read32(ci->ctx, core->wrapbase + BCMA_RESET_CTL) & +	       BCMA_RESET_CTL_RESET) { +		ci->ops->write32(ci->ctx, core->wrapbase + BCMA_RESET_CTL, 0); +		count++; +		if (count > 50) +			break; +		usleep_range(40, 60); +	} + +	ci->ops->write32(ci->ctx, core->wrapbase + BCMA_IOCTL, +			 postreset | BCMA_IOCTL_CLK); +	ci->ops->read32(ci->ctx, core->wrapbase + BCMA_IOCTL); +} + +static char *brcmf_chip_name(uint chipid, char *buf, uint len) +{ +	const char *fmt; + +	fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x"; +	snprintf(buf, len, fmt, chipid); +	return buf; +} + +static struct brcmf_core *brcmf_chip_add_core(struct brcmf_chip_priv *ci, +					      u16 coreid, u32 base, +					      u32 wrapbase) +{ +	struct brcmf_core_priv *core; + +	core = kzalloc(sizeof(*core), GFP_KERNEL); +	if (!core) +		return ERR_PTR(-ENOMEM); + +	core->pub.id = coreid; +	core->pub.base = base; +	core->chip = ci; +	core->wrapbase = wrapbase; + +	list_add_tail(&core->list, &ci->cores); +	return &core->pub; +} + +#ifdef DEBUG +/* safety check for chipinfo */ +static int brcmf_chip_cores_check(struct brcmf_chip_priv *ci) +{ +	struct brcmf_core_priv *core; +	bool need_socram = false; +	bool has_socram = false; +	int idx = 1; + +	list_for_each_entry(core, &ci->cores, list) { +		brcmf_dbg(INFO, " [%-2d] core 0x%x:%-2d base 0x%08x wrap 0x%08x\n", +			  idx++, core->pub.id, core->pub.rev, core->pub.base, +			  core->wrapbase); + +		switch (core->pub.id) { +		case BCMA_CORE_ARM_CM3: +			need_socram = true; +			break; +		case BCMA_CORE_INTERNAL_MEM: +			has_socram = true; +			break; +		case BCMA_CORE_ARM_CR4: +			if (ci->pub.rambase == 0) { +				brcmf_err("RAM base not provided with ARM CR4 core\n"); +				return -ENOMEM; +			} +			break; +		default: +			break; +		} +	} + +	/* check RAM core presence for ARM CM3 core */ +	if (need_socram && !has_socram) { +		brcmf_err("RAM core not provided with ARM CM3 core\n"); +		return -ENODEV; +	} +	return 0; +} +#else	/* DEBUG */ +static inline int brcmf_chip_cores_check(struct brcmf_chip_priv *ci) +{ +	return 0; +} +#endif + +static void brcmf_chip_get_raminfo(struct brcmf_chip_priv *ci) +{ +	switch (ci->pub.chip) { +	case BCM4329_CHIP_ID: +		ci->pub.ramsize = BCM4329_RAMSIZE; +		break; +	case BCM43143_CHIP_ID: +		ci->pub.ramsize = BCM43143_RAMSIZE; +		break; +	case BCM43241_CHIP_ID: +		ci->pub.ramsize = 0x90000; +		break; +	case BCM4330_CHIP_ID: +		ci->pub.ramsize = 0x48000; +		break; +	case BCM4334_CHIP_ID: +		ci->pub.ramsize = 0x80000; +		break; +	case BCM4335_CHIP_ID: +		ci->pub.ramsize = 0xc0000; +		ci->pub.rambase = 0x180000; +		break; +	case BCM43362_CHIP_ID: +		ci->pub.ramsize = 0x3c000; +		break; +	case BCM4339_CHIP_ID: +	case BCM4354_CHIP_ID: +		ci->pub.ramsize = 0xc0000; +		ci->pub.rambase = 0x180000; +		break; +	default: +		brcmf_err("unknown chip: %s\n", ci->pub.name); +		break; +	} +} + +static u32 brcmf_chip_dmp_get_desc(struct brcmf_chip_priv *ci, u32 *eromaddr, +				   u8 *type) +{ +	u32 val; + +	/* read next descriptor */ +	val = ci->ops->read32(ci->ctx, *eromaddr); +	*eromaddr += 4; + +	if (!type) +		return val; + +	/* determine descriptor type */ +	*type = (val & DMP_DESC_TYPE_MSK); +	if ((*type & ~DMP_DESC_ADDRSIZE_GT32) == DMP_DESC_ADDRESS) +		*type = DMP_DESC_ADDRESS; + +	return val; +} + +static int brcmf_chip_dmp_get_regaddr(struct brcmf_chip_priv *ci, u32 *eromaddr, +				      u32 *regbase, u32 *wrapbase) +{ +	u8 desc; +	u32 val; +	u8 mpnum = 0; +	u8 stype, sztype, wraptype; + +	*regbase = 0; +	*wrapbase = 0; + +	val = brcmf_chip_dmp_get_desc(ci, eromaddr, &desc); +	if (desc == DMP_DESC_MASTER_PORT) { +		mpnum = (val & DMP_MASTER_PORT_NUM) >> DMP_MASTER_PORT_NUM_S; +		wraptype = DMP_SLAVE_TYPE_MWRAP; +	} else if (desc == DMP_DESC_ADDRESS) { +		/* revert erom address */ +		*eromaddr -= 4; +		wraptype = DMP_SLAVE_TYPE_SWRAP; +	} else { +		*eromaddr -= 4; +		return -EILSEQ; +	} + +	do { +		/* locate address descriptor */ +		do { +			val = brcmf_chip_dmp_get_desc(ci, eromaddr, &desc); +			/* unexpected table end */ +			if (desc == DMP_DESC_EOT) { +				*eromaddr -= 4; +				return -EFAULT; +			} +		} while (desc != DMP_DESC_ADDRESS); + +		/* skip upper 32-bit address descriptor */ +		if (val & DMP_DESC_ADDRSIZE_GT32) +			brcmf_chip_dmp_get_desc(ci, eromaddr, NULL); + +		sztype = (val & DMP_SLAVE_SIZE_TYPE) >> DMP_SLAVE_SIZE_TYPE_S; + +		/* next size descriptor can be skipped */ +		if (sztype == DMP_SLAVE_SIZE_DESC) { +			val = brcmf_chip_dmp_get_desc(ci, eromaddr, NULL); +			/* skip upper size descriptor if present */ +			if (val & DMP_DESC_ADDRSIZE_GT32) +				brcmf_chip_dmp_get_desc(ci, eromaddr, NULL); +		} + +		/* only look for 4K register regions */ +		if (sztype != DMP_SLAVE_SIZE_4K) +			continue; + +		stype = (val & DMP_SLAVE_TYPE) >> DMP_SLAVE_TYPE_S; + +		/* only regular slave and wrapper */ +		if (*regbase == 0 && stype == DMP_SLAVE_TYPE_SLAVE) +			*regbase = val & DMP_SLAVE_ADDR_BASE; +		if (*wrapbase == 0 && stype == wraptype) +			*wrapbase = val & DMP_SLAVE_ADDR_BASE; +	} while (*regbase == 0 || *wrapbase == 0); + +	return 0; +} + +static +int brcmf_chip_dmp_erom_scan(struct brcmf_chip_priv *ci) +{ +	struct brcmf_core *core; +	u32 eromaddr; +	u8 desc_type = 0; +	u32 val; +	u16 id; +	u8 nmp, nsp, nmw, nsw, rev; +	u32 base, wrap; +	int err; + +	eromaddr = ci->ops->read32(ci->ctx, CORE_CC_REG(SI_ENUM_BASE, eromptr)); + +	while (desc_type != DMP_DESC_EOT) { +		val = brcmf_chip_dmp_get_desc(ci, &eromaddr, &desc_type); +		if (!(val & DMP_DESC_VALID)) +			continue; + +		if (desc_type == DMP_DESC_EMPTY) +			continue; + +		/* need a component descriptor */ +		if (desc_type != DMP_DESC_COMPONENT) +			continue; + +		id = (val & DMP_COMP_PARTNUM) >> DMP_COMP_PARTNUM_S; + +		/* next descriptor must be component as well */ +		val = brcmf_chip_dmp_get_desc(ci, &eromaddr, &desc_type); +		if (WARN_ON((val & DMP_DESC_TYPE_MSK) != DMP_DESC_COMPONENT)) +			return -EFAULT; + +		/* only look at cores with master port(s) */ +		nmp = (val & DMP_COMP_NUM_MPORT) >> DMP_COMP_NUM_MPORT_S; +		nsp = (val & DMP_COMP_NUM_SPORT) >> DMP_COMP_NUM_SPORT_S; +		nmw = (val & DMP_COMP_NUM_MWRAP) >> DMP_COMP_NUM_MWRAP_S; +		nsw = (val & DMP_COMP_NUM_SWRAP) >> DMP_COMP_NUM_SWRAP_S; +		rev = (val & DMP_COMP_REVISION) >> DMP_COMP_REVISION_S; + +		/* need core with ports */ +		if (nmw + nsw == 0) +			continue; + +		/* try to obtain register address info */ +		err = brcmf_chip_dmp_get_regaddr(ci, &eromaddr, &base, &wrap); +		if (err) +			continue; + +		/* finally a core to be added */ +		core = brcmf_chip_add_core(ci, id, base, wrap); +		if (IS_ERR(core)) +			return PTR_ERR(core); + +		core->rev = rev; +	} + +	return 0; +} + +static int brcmf_chip_recognition(struct brcmf_chip_priv *ci) +{ +	struct brcmf_core *core; +	u32 regdata; +	u32 socitype; + +	/* Get CC core rev +	 * Chipid is assume to be at offset 0 from SI_ENUM_BASE +	 * For different chiptypes or old sdio hosts w/o chipcommon, +	 * other ways of recognition should be added here. +	 */ +	regdata = ci->ops->read32(ci->ctx, CORE_CC_REG(SI_ENUM_BASE, chipid)); +	ci->pub.chip = regdata & CID_ID_MASK; +	ci->pub.chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT; +	socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT; + +	brcmf_chip_name(ci->pub.chip, ci->pub.name, sizeof(ci->pub.name)); +	brcmf_dbg(INFO, "found %s chip: BCM%s, rev=%d\n", +		  socitype == SOCI_SB ? "SB" : "AXI", ci->pub.name, +		  ci->pub.chiprev); + +	if (socitype == SOCI_SB) { +		if (ci->pub.chip != BCM4329_CHIP_ID) { +			brcmf_err("SB chip is not supported\n"); +			return -ENODEV; +		} +		ci->iscoreup = brcmf_chip_sb_iscoreup; +		ci->coredisable = brcmf_chip_sb_coredisable; +		ci->resetcore = brcmf_chip_sb_resetcore; + +		core = brcmf_chip_add_core(ci, BCMA_CORE_CHIPCOMMON, +					   SI_ENUM_BASE, 0); +		brcmf_chip_sb_corerev(ci, core); +		core = brcmf_chip_add_core(ci, BCMA_CORE_SDIO_DEV, +					   BCM4329_CORE_BUS_BASE, 0); +		brcmf_chip_sb_corerev(ci, core); +		core = brcmf_chip_add_core(ci, BCMA_CORE_INTERNAL_MEM, +					   BCM4329_CORE_SOCRAM_BASE, 0); +		brcmf_chip_sb_corerev(ci, core); +		core = brcmf_chip_add_core(ci, BCMA_CORE_ARM_CM3, +					   BCM4329_CORE_ARM_BASE, 0); +		brcmf_chip_sb_corerev(ci, core); + +		core = brcmf_chip_add_core(ci, BCMA_CORE_80211, 0x18001000, 0); +		brcmf_chip_sb_corerev(ci, core); +	} else if (socitype == SOCI_AI) { +		ci->iscoreup = brcmf_chip_ai_iscoreup; +		ci->coredisable = brcmf_chip_ai_coredisable; +		ci->resetcore = brcmf_chip_ai_resetcore; + +		brcmf_chip_dmp_erom_scan(ci); +	} else { +		brcmf_err("chip backplane type %u is not supported\n", +			  socitype); +		return -ENODEV; +	} + +	brcmf_chip_get_raminfo(ci); + +	return brcmf_chip_cores_check(ci); +} + +static void brcmf_chip_disable_arm(struct brcmf_chip_priv *chip, u16 id) +{ +	struct brcmf_core *core; +	struct brcmf_core_priv *cr4; +	u32 val; + + +	core = brcmf_chip_get_core(&chip->pub, id); +	if (!core) +		return; + +	switch (id) { +	case BCMA_CORE_ARM_CM3: +		brcmf_chip_coredisable(core, 0, 0); +		break; +	case BCMA_CORE_ARM_CR4: +		cr4 = container_of(core, struct brcmf_core_priv, pub); + +		/* clear all IOCTL bits except HALT bit */ +		val = chip->ops->read32(chip->ctx, cr4->wrapbase + BCMA_IOCTL); +		val &= ARMCR4_BCMA_IOCTL_CPUHALT; +		brcmf_chip_resetcore(core, val, ARMCR4_BCMA_IOCTL_CPUHALT, +				     ARMCR4_BCMA_IOCTL_CPUHALT); +		break; +	default: +		brcmf_err("unknown id: %u\n", id); +		break; +	} +} + +static int brcmf_chip_setup(struct brcmf_chip_priv *chip) +{ +	struct brcmf_chip *pub; +	struct brcmf_core_priv *cc; +	u32 base; +	u32 val; +	int ret = 0; + +	pub = &chip->pub; +	cc = list_first_entry(&chip->cores, struct brcmf_core_priv, list); +	base = cc->pub.base; + +	/* get chipcommon capabilites */ +	pub->cc_caps = chip->ops->read32(chip->ctx, +					 CORE_CC_REG(base, capabilities)); + +	/* get pmu caps & rev */ +	if (pub->cc_caps & CC_CAP_PMU) { +		val = chip->ops->read32(chip->ctx, +					CORE_CC_REG(base, pmucapabilities)); +		pub->pmurev = val & PCAP_REV_MASK; +		pub->pmucaps = val; +	} + +	brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, pmucaps=0x%x\n", +		  cc->pub.rev, pub->pmurev, pub->pmucaps); + +	/* execute bus core specific setup */ +	if (chip->ops->setup) +		ret = chip->ops->setup(chip->ctx, pub); + +	/* +	 * Make sure any on-chip ARM is off (in case strapping is wrong), +	 * or downloaded code was already running. +	 */ +	brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CM3); +	brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CR4); +	return ret; +} + +struct brcmf_chip *brcmf_chip_attach(void *ctx, +				     const struct brcmf_buscore_ops *ops) +{ +	struct brcmf_chip_priv *chip; +	int err = 0; + +	if (WARN_ON(!ops->read32)) +		err = -EINVAL; +	if (WARN_ON(!ops->write32)) +		err = -EINVAL; +	if (WARN_ON(!ops->prepare)) +		err = -EINVAL; +	if (WARN_ON(!ops->exit_dl)) +		err = -EINVAL; +	if (err < 0) +		return ERR_PTR(-EINVAL); + +	chip = kzalloc(sizeof(*chip), GFP_KERNEL); +	if (!chip) +		return ERR_PTR(-ENOMEM); + +	INIT_LIST_HEAD(&chip->cores); +	chip->num_cores = 0; +	chip->ops = ops; +	chip->ctx = ctx; + +	err = ops->prepare(ctx); +	if (err < 0) +		goto fail; + +	err = brcmf_chip_recognition(chip); +	if (err < 0) +		goto fail; + +	err = brcmf_chip_setup(chip); +	if (err < 0) +		goto fail; + +	return &chip->pub; + +fail: +	brcmf_chip_detach(&chip->pub); +	return ERR_PTR(err); +} + +void brcmf_chip_detach(struct brcmf_chip *pub) +{ +	struct brcmf_chip_priv *chip; +	struct brcmf_core_priv *core; +	struct brcmf_core_priv *tmp; + +	chip = container_of(pub, struct brcmf_chip_priv, pub); +	list_for_each_entry_safe(core, tmp, &chip->cores, list) { +		list_del(&core->list); +		kfree(core); +	} +	kfree(chip); +} + +struct brcmf_core *brcmf_chip_get_core(struct brcmf_chip *pub, u16 coreid) +{ +	struct brcmf_chip_priv *chip; +	struct brcmf_core_priv *core; + +	chip = container_of(pub, struct brcmf_chip_priv, pub); +	list_for_each_entry(core, &chip->cores, list) +		if (core->pub.id == coreid) +			return &core->pub; + +	return NULL; +} + +struct brcmf_core *brcmf_chip_get_chipcommon(struct brcmf_chip *pub) +{ +	struct brcmf_chip_priv *chip; +	struct brcmf_core_priv *cc; + +	chip = container_of(pub, struct brcmf_chip_priv, pub); +	cc = list_first_entry(&chip->cores, struct brcmf_core_priv, list); +	if (WARN_ON(!cc || cc->pub.id != BCMA_CORE_CHIPCOMMON)) +		return brcmf_chip_get_core(pub, BCMA_CORE_CHIPCOMMON); +	return &cc->pub; +} + +bool brcmf_chip_iscoreup(struct brcmf_core *pub) +{ +	struct brcmf_core_priv *core; + +	core = container_of(pub, struct brcmf_core_priv, pub); +	return core->chip->iscoreup(core); +} + +void brcmf_chip_coredisable(struct brcmf_core *pub, u32 prereset, u32 reset) +{ +	struct brcmf_core_priv *core; + +	core = container_of(pub, struct brcmf_core_priv, pub); +	core->chip->coredisable(core, prereset, reset); +} + +void brcmf_chip_resetcore(struct brcmf_core *pub, u32 prereset, u32 reset, +			  u32 postreset) +{ +	struct brcmf_core_priv *core; + +	core = container_of(pub, struct brcmf_core_priv, pub); +	core->chip->resetcore(core, prereset, reset, postreset); +} + +static void +brcmf_chip_cm3_enterdl(struct brcmf_chip_priv *chip) +{ +	struct brcmf_core *core; + +	brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CM3); +	core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_80211); +	brcmf_chip_resetcore(core, D11_BCMA_IOCTL_PHYRESET | +				   D11_BCMA_IOCTL_PHYCLOCKEN, +			     D11_BCMA_IOCTL_PHYCLOCKEN, +			     D11_BCMA_IOCTL_PHYCLOCKEN); +	core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_INTERNAL_MEM); +	brcmf_chip_resetcore(core, 0, 0, 0); +} + +static bool brcmf_chip_cm3_exitdl(struct brcmf_chip_priv *chip) +{ +	struct brcmf_core *core; + +	core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_INTERNAL_MEM); +	if (!brcmf_chip_iscoreup(core)) { +		brcmf_err("SOCRAM core is down after reset?\n"); +		return false; +	} + +	chip->ops->exit_dl(chip->ctx, &chip->pub, 0); + +	core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_ARM_CM3); +	brcmf_chip_resetcore(core, 0, 0, 0); + +	return true; +} + +static inline void +brcmf_chip_cr4_enterdl(struct brcmf_chip_priv *chip) +{ +	struct brcmf_core *core; + +	brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CR4); + +	core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_80211); +	brcmf_chip_resetcore(core, D11_BCMA_IOCTL_PHYRESET | +				   D11_BCMA_IOCTL_PHYCLOCKEN, +			     D11_BCMA_IOCTL_PHYCLOCKEN, +			     D11_BCMA_IOCTL_PHYCLOCKEN); +} + +static bool brcmf_chip_cr4_exitdl(struct brcmf_chip_priv *chip, u32 rstvec) +{ +	struct brcmf_core *core; + +	chip->ops->exit_dl(chip->ctx, &chip->pub, rstvec); + +	/* restore ARM */ +	core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_ARM_CR4); +	brcmf_chip_resetcore(core, ARMCR4_BCMA_IOCTL_CPUHALT, 0, 0); + +	return true; +} + +void brcmf_chip_enter_download(struct brcmf_chip *pub) +{ +	struct brcmf_chip_priv *chip; +	struct brcmf_core *arm; + +	brcmf_dbg(TRACE, "Enter\n"); + +	chip = container_of(pub, struct brcmf_chip_priv, pub); +	arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CR4); +	if (arm) { +		brcmf_chip_cr4_enterdl(chip); +		return; +	} + +	brcmf_chip_cm3_enterdl(chip); +} + +bool brcmf_chip_exit_download(struct brcmf_chip *pub, u32 rstvec) +{ +	struct brcmf_chip_priv *chip; +	struct brcmf_core *arm; + +	brcmf_dbg(TRACE, "Enter\n"); + +	chip = container_of(pub, struct brcmf_chip_priv, pub); +	arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CR4); +	if (arm) +		return brcmf_chip_cr4_exitdl(chip, rstvec); + +	return brcmf_chip_cm3_exitdl(chip); +} + +bool brcmf_chip_sr_capable(struct brcmf_chip *pub) +{ +	u32 base, addr, reg, pmu_cc3_mask = ~0; +	struct brcmf_chip_priv *chip; + +	brcmf_dbg(TRACE, "Enter\n"); + +	/* old chips with PMU version less than 17 don't support save restore */ +	if (pub->pmurev < 17) +		return false; + +	base = brcmf_chip_get_chipcommon(pub)->base; +	chip = container_of(pub, struct brcmf_chip_priv, pub); + +	switch (pub->chip) { +	case BCM4354_CHIP_ID: +		/* explicitly check SR engine enable bit */ +		pmu_cc3_mask = BIT(2); +		/* fall-through */ +	case BCM43241_CHIP_ID: +	case BCM4335_CHIP_ID: +	case BCM4339_CHIP_ID: +		/* read PMU chipcontrol register 3 */ +		addr = CORE_CC_REG(base, chipcontrol_addr); +		chip->ops->write32(chip->ctx, addr, 3); +		addr = CORE_CC_REG(base, chipcontrol_data); +		reg = chip->ops->read32(chip->ctx, addr); +		return (reg & pmu_cc3_mask) != 0; +	default: +		addr = CORE_CC_REG(base, pmucapabilities_ext); +		reg = chip->ops->read32(chip->ctx, addr); +		if ((reg & PCAPEXT_SR_SUPPORTED_MASK) == 0) +			return false; + +		addr = CORE_CC_REG(base, retention_ctl); +		reg = chip->ops->read32(chip->ctx, addr); +		return (reg & (PMU_RCTL_MACPHY_DISABLE_MASK | +			       PMU_RCTL_LOGIC_DISABLE_MASK)) == 0; +	} +} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/chip.h b/drivers/net/wireless/brcm80211/brcmfmac/chip.h new file mode 100644 index 00000000000..c32908da90c --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2014 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef BRCMF_CHIP_H +#define BRCMF_CHIP_H + +#include <linux/types.h> + +#define CORE_CC_REG(base, field) \ +		(base + offsetof(struct chipcregs, field)) + +/** + * struct brcmf_chip - chip level information. + * + * @chip: chip identifier. + * @chiprev: chip revision. + * @cc_caps: chipcommon core capabilities. + * @pmucaps: PMU capabilities. + * @pmurev: PMU revision. + * @rambase: RAM base address (only applicable for ARM CR4 chips). + * @ramsize: amount of RAM on chip. + * @name: string representation of the chip identifier. + */ +struct brcmf_chip { +	u32 chip; +	u32 chiprev; +	u32 cc_caps; +	u32 pmucaps; +	u32 pmurev; +	u32 rambase; +	u32 ramsize; +	char name[8]; +}; + +/** + * struct brcmf_core - core related information. + * + * @id: core identifier. + * @rev: core revision. + * @base: base address of core register space. + */ +struct brcmf_core { +	u16 id; +	u16 rev; +	u32 base; +}; + +/** + * struct brcmf_buscore_ops - buscore specific callbacks. + * + * @read32: read 32-bit value over bus. + * @write32: write 32-bit value over bus. + * @prepare: prepare bus for core configuration. + * @setup: bus-specific core setup. + * @exit_dl: exit download state. + *	The callback should use the provided @rstvec when non-zero. + */ +struct brcmf_buscore_ops { +	u32 (*read32)(void *ctx, u32 addr); +	void (*write32)(void *ctx, u32 addr, u32 value); +	int (*prepare)(void *ctx); +	int (*setup)(void *ctx, struct brcmf_chip *chip); +	void (*exit_dl)(void *ctx, struct brcmf_chip *chip, u32 rstvec); +}; + +struct brcmf_chip *brcmf_chip_attach(void *ctx, +				     const struct brcmf_buscore_ops *ops); +void brcmf_chip_detach(struct brcmf_chip *chip); +struct brcmf_core *brcmf_chip_get_core(struct brcmf_chip *chip, u16 coreid); +struct brcmf_core *brcmf_chip_get_chipcommon(struct brcmf_chip *chip); +bool brcmf_chip_iscoreup(struct brcmf_core *core); +void brcmf_chip_coredisable(struct brcmf_core *core, u32 prereset, u32 reset); +void brcmf_chip_resetcore(struct brcmf_core *core, u32 prereset, u32 reset, +			  u32 postreset); +void brcmf_chip_enter_download(struct brcmf_chip *ci); +bool brcmf_chip_exit_download(struct brcmf_chip *ci, u32 rstvec); +bool brcmf_chip_sr_capable(struct brcmf_chip *pub); + +#endif /* BRCMF_AXIDMP_H */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index 2eb9e642c9b..16f9ab2568a 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h @@ -21,483 +21,33 @@  #ifndef _BRCMF_H_  #define _BRCMF_H_ -#define BRCMF_VERSION_STR		"4.218.248.5" -  #include "fweh.h" -/******************************************************************************* - * IO codes that are interpreted by dongle firmware - ******************************************************************************/ -#define BRCMF_C_GET_VERSION			1 -#define BRCMF_C_UP				2 -#define BRCMF_C_DOWN				3 -#define BRCMF_C_SET_PROMISC			10 -#define BRCMF_C_GET_RATE			12 -#define BRCMF_C_GET_INFRA			19 -#define BRCMF_C_SET_INFRA			20 -#define BRCMF_C_GET_AUTH			21 -#define BRCMF_C_SET_AUTH			22 -#define BRCMF_C_GET_BSSID			23 -#define BRCMF_C_GET_SSID			25 -#define BRCMF_C_SET_SSID			26 -#define BRCMF_C_TERMINATED			28 -#define BRCMF_C_GET_CHANNEL			29 -#define BRCMF_C_SET_CHANNEL			30 -#define BRCMF_C_GET_SRL				31 -#define BRCMF_C_SET_SRL				32 -#define BRCMF_C_GET_LRL				33 -#define BRCMF_C_SET_LRL				34 -#define BRCMF_C_GET_RADIO			37 -#define BRCMF_C_SET_RADIO			38 -#define BRCMF_C_GET_PHYTYPE			39 -#define BRCMF_C_SET_KEY				45 -#define BRCMF_C_SET_PASSIVE_SCAN		49 -#define BRCMF_C_SCAN				50 -#define BRCMF_C_SCAN_RESULTS			51 -#define BRCMF_C_DISASSOC			52 -#define BRCMF_C_REASSOC				53 -#define BRCMF_C_SET_ROAM_TRIGGER		55 -#define BRCMF_C_SET_ROAM_DELTA			57 -#define BRCMF_C_GET_BCNPRD			75 -#define BRCMF_C_SET_BCNPRD			76 -#define BRCMF_C_GET_DTIMPRD			77 -#define BRCMF_C_SET_DTIMPRD			78 -#define BRCMF_C_SET_COUNTRY			84 -#define BRCMF_C_GET_PM				85 -#define BRCMF_C_SET_PM				86 -#define BRCMF_C_GET_CURR_RATESET		114 -#define BRCMF_C_GET_AP				117 -#define BRCMF_C_SET_AP				118 -#define BRCMF_C_GET_RSSI			127 -#define BRCMF_C_GET_WSEC			133 -#define BRCMF_C_SET_WSEC			134 -#define BRCMF_C_GET_PHY_NOISE			135 -#define BRCMF_C_GET_BSS_INFO			136 -#define BRCMF_C_GET_BANDLIST			140 -#define BRCMF_C_SET_SCB_TIMEOUT			158 -#define BRCMF_C_GET_PHYLIST			180 -#define BRCMF_C_SET_SCAN_CHANNEL_TIME		185 -#define BRCMF_C_SET_SCAN_UNASSOC_TIME		187 -#define BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON	201 -#define BRCMF_C_GET_VALID_CHANNELS		217 -#define BRCMF_C_GET_KEY_PRIMARY			235 -#define BRCMF_C_SET_KEY_PRIMARY			236 -#define BRCMF_C_SET_SCAN_PASSIVE_TIME		258 -#define BRCMF_C_GET_VAR				262 -#define BRCMF_C_SET_VAR				263 - -/* phy types (returned by WLC_GET_PHYTPE) */ -#define	WLC_PHY_TYPE_A		0 -#define	WLC_PHY_TYPE_B		1 -#define	WLC_PHY_TYPE_G		2 -#define	WLC_PHY_TYPE_N		4 -#define	WLC_PHY_TYPE_LP		5 -#define	WLC_PHY_TYPE_SSN	6 -#define	WLC_PHY_TYPE_HT		7 -#define	WLC_PHY_TYPE_LCN	8 -#define	WLC_PHY_TYPE_NULL	0xf - -#define BRCMF_EVENTING_MASK_LEN	16 -  #define TOE_TX_CSUM_OL		0x00000001  #define TOE_RX_CSUM_OL		0x00000002 -#define	BRCMF_BSS_INFO_VERSION	109 /* curr ver of brcmf_bss_info_le struct */ - -/* size of brcmf_scan_params not including variable length array */ -#define BRCMF_SCAN_PARAMS_FIXED_SIZE 64 - -/* masks for channel and ssid count */ -#define BRCMF_SCAN_PARAMS_COUNT_MASK 0x0000ffff -#define BRCMF_SCAN_PARAMS_NSSID_SHIFT 16 - -/* primary (ie tx) key */ -#define BRCMF_PRIMARY_KEY	(1 << 1) -  /* For supporting multiple interfaces */  #define BRCMF_MAX_IFS	16 -#define DOT11_BSSTYPE_ANY			2  #define DOT11_MAX_DEFAULT_KEYS	4 -#define BRCMF_ESCAN_REQ_VERSION 1 - -#define WLC_BSS_RSSI_ON_CHANNEL		0x0002 - -#define BRCMF_MAXRATES_IN_SET		16	/* max # of rates in rateset */ -#define BRCMF_STA_ASSOC			0x10		/* Associated */ - -#define BRCMF_E_STATUS_SUCCESS			0 -#define BRCMF_E_STATUS_FAIL			1 -#define BRCMF_E_STATUS_TIMEOUT			2 -#define BRCMF_E_STATUS_NO_NETWORKS		3 -#define BRCMF_E_STATUS_ABORT			4 -#define BRCMF_E_STATUS_NO_ACK			5 -#define BRCMF_E_STATUS_UNSOLICITED		6 -#define BRCMF_E_STATUS_ATTEMPT			7 -#define BRCMF_E_STATUS_PARTIAL			8 -#define BRCMF_E_STATUS_NEWSCAN			9 -#define BRCMF_E_STATUS_NEWASSOC			10 -#define BRCMF_E_STATUS_11HQUIET			11 -#define BRCMF_E_STATUS_SUPPRESS			12 -#define BRCMF_E_STATUS_NOCHANS			13 -#define BRCMF_E_STATUS_CS_ABORT			15 -#define BRCMF_E_STATUS_ERROR			16 - -#define BRCMF_E_REASON_INITIAL_ASSOC		0 -#define BRCMF_E_REASON_LOW_RSSI			1 -#define BRCMF_E_REASON_DEAUTH			2 -#define BRCMF_E_REASON_DISASSOC			3 -#define BRCMF_E_REASON_BCNS_LOST		4 -#define BRCMF_E_REASON_MINTXRATE		9 -#define BRCMF_E_REASON_TXFAIL			10 - -#define BRCMF_E_REASON_LINK_BSSCFG_DIS		4 -#define BRCMF_E_REASON_FAST_ROAM_FAILED		5 -#define BRCMF_E_REASON_DIRECTED_ROAM		6 -#define BRCMF_E_REASON_TSPEC_REJECTED		7 -#define BRCMF_E_REASON_BETTER_AP		8 - -#define BRCMF_E_PRUNE_ENCR_MISMATCH		1 -#define BRCMF_E_PRUNE_BCAST_BSSID		2 -#define BRCMF_E_PRUNE_MAC_DENY			3 -#define BRCMF_E_PRUNE_MAC_NA			4 -#define BRCMF_E_PRUNE_REG_PASSV			5 -#define BRCMF_E_PRUNE_SPCT_MGMT			6 -#define BRCMF_E_PRUNE_RADAR			7 -#define BRCMF_E_RSN_MISMATCH			8 -#define BRCMF_E_PRUNE_NO_COMMON_RATES		9 -#define BRCMF_E_PRUNE_BASIC_RATES		10 -#define BRCMF_E_PRUNE_CIPHER_NA			12 -#define BRCMF_E_PRUNE_KNOWN_STA			13 -#define BRCMF_E_PRUNE_WDS_PEER			15 -#define BRCMF_E_PRUNE_QBSS_LOAD			16 -#define BRCMF_E_PRUNE_HOME_AP			17 - -#define BRCMF_E_SUP_OTHER			0 -#define BRCMF_E_SUP_DECRYPT_KEY_DATA		1 -#define BRCMF_E_SUP_BAD_UCAST_WEP128		2 -#define BRCMF_E_SUP_BAD_UCAST_WEP40		3 -#define BRCMF_E_SUP_UNSUP_KEY_LEN		4 -#define BRCMF_E_SUP_PW_KEY_CIPHER		5 -#define BRCMF_E_SUP_MSG3_TOO_MANY_IE		6 -#define BRCMF_E_SUP_MSG3_IE_MISMATCH		7 -#define BRCMF_E_SUP_NO_INSTALL_FLAG		8 -#define BRCMF_E_SUP_MSG3_NO_GTK			9 -#define BRCMF_E_SUP_GRP_KEY_CIPHER		10 -#define BRCMF_E_SUP_GRP_MSG1_NO_GTK		11 -#define BRCMF_E_SUP_GTK_DECRYPT_FAIL		12 -#define BRCMF_E_SUP_SEND_FAIL			13 -#define BRCMF_E_SUP_DEAUTH			14 - -#define BRCMF_E_IF_ADD				1 -#define BRCMF_E_IF_DEL				2 -#define BRCMF_E_IF_CHANGE			3 - -#define BRCMF_E_IF_FLAG_NOIF			1 - -#define BRCMF_E_IF_ROLE_STA			0 -#define BRCMF_E_IF_ROLE_AP			1 -#define BRCMF_E_IF_ROLE_WDS			2 - -#define BRCMF_E_LINK_BCN_LOSS			1 -#define BRCMF_E_LINK_DISASSOC			2 -#define BRCMF_E_LINK_ASSOC_REC			3 -#define BRCMF_E_LINK_BSSCFG_DIS			4 -  /* Small, medium and maximum buffer size for dcmd   */  #define BRCMF_DCMD_SMLEN	256  #define BRCMF_DCMD_MEDLEN	1536  #define BRCMF_DCMD_MAXLEN	8192 -#define BRCMF_AMPDU_RX_REORDER_MAXFLOWS		256 - -/* Pattern matching filter. Specifies an offset within received packets to - * start matching, the pattern to match, the size of the pattern, and a bitmask - * that indicates which bits within the pattern should be matched. - */ -struct brcmf_pkt_filter_pattern_le { -	/* -	 * Offset within received packet to start pattern matching. -	 * Offset '0' is the first byte of the ethernet header. -	 */ -	__le32 offset; -	/* Size of the pattern.  Bitmask must be the same size.*/ -	__le32 size_bytes; -	/* -	 * Variable length mask and pattern data. mask starts at offset 0. -	 * Pattern immediately follows mask. -	 */ -	u8 mask_and_pattern[1]; -}; - -/* IOVAR "pkt_filter_add" parameter. Used to install packet filters. */ -struct brcmf_pkt_filter_le { -	__le32 id;		/* Unique filter id, specified by app. */ -	__le32 type;		/* Filter type (WL_PKT_FILTER_TYPE_xxx). */ -	__le32 negate_match;	/* Negate the result of filter matches */ -	union {			/* Filter definitions */ -		struct brcmf_pkt_filter_pattern_le pattern; /* Filter pattern */ -	} u; -}; - -/* IOVAR "pkt_filter_enable" parameter. */ -struct brcmf_pkt_filter_enable_le { -	__le32 id;		/* Unique filter id */ -	__le32 enable;		/* Enable/disable bool */ -}; - -/* BSS info structure - * Applications MUST CHECK ie_offset field and length field to access IEs and - * next bss_info structure in a vector (in struct brcmf_scan_results) - */ -struct brcmf_bss_info_le { -	__le32 version;		/* version field */ -	__le32 length;		/* byte length of data in this record, -				 * starting at version and including IEs -				 */ -	u8 BSSID[ETH_ALEN]; -	__le16 beacon_period;	/* units are Kusec */ -	__le16 capability;	/* Capability information */ -	u8 SSID_len; -	u8 SSID[32]; -	struct { -		__le32 count;   /* # rates in this set */ -		u8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ -	} rateset;		/* supported rates */ -	__le16 chanspec;	/* chanspec for bss */ -	__le16 atim_window;	/* units are Kusec */ -	u8 dtim_period;	/* DTIM period */ -	__le16 RSSI;		/* receive signal strength (in dBm) */ -	s8 phy_noise;		/* noise (in dBm) */ - -	u8 n_cap;		/* BSS is 802.11N Capable */ -	/* 802.11N BSS Capabilities (based on HT_CAP_*): */ -	__le32 nbss_cap; -	u8 ctl_ch;		/* 802.11N BSS control channel number */ -	__le32 reserved32[1];	/* Reserved for expansion of BSS properties */ -	u8 flags;		/* flags */ -	u8 reserved[3];	/* Reserved for expansion of BSS properties */ -	u8 basic_mcs[MCSSET_LEN];	/* 802.11N BSS required MCS set */ - -	__le16 ie_offset;	/* offset at which IEs start, from beginning */ -	__le32 ie_length;	/* byte length of Information Elements */ -	__le16 SNR;		/* average SNR of during frame reception */ -	/* Add new fields here */ -	/* variable length Information Elements */ -}; - -struct brcm_rateset_le { -	/* # rates in this set */ -	__le32 count; -	/* rates in 500kbps units w/hi bit set if basic */ -	u8 rates[BRCMF_MAXRATES_IN_SET]; -}; - -struct brcmf_ssid { -	u32 SSID_len; -	unsigned char SSID[32]; -}; - -struct brcmf_ssid_le { -	__le32 SSID_len; -	unsigned char SSID[32]; -}; - -struct brcmf_scan_params_le { -	struct brcmf_ssid_le ssid_le;	/* default: {0, ""} */ -	u8 bssid[ETH_ALEN];	/* default: bcast */ -	s8 bss_type;		/* default: any, -				 * DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT -				 */ -	u8 scan_type;	/* flags, 0 use default */ -	__le32 nprobes;	  /* -1 use default, number of probes per channel */ -	__le32 active_time;	/* -1 use default, dwell time per channel for -				 * active scanning -				 */ -	__le32 passive_time;	/* -1 use default, dwell time per channel -				 * for passive scanning -				 */ -	__le32 home_time;	/* -1 use default, dwell time for the -				 * home channel between channel scans -				 */ -	__le32 channel_num;	/* count of channels and ssids that follow -				 * -				 * low half is count of channels in -				 * channel_list, 0 means default (use all -				 * available channels) -				 * -				 * high half is entries in struct brcmf_ssid -				 * array that follows channel_list, aligned for -				 * s32 (4 bytes) meaning an odd channel count -				 * implies a 2-byte pad between end of -				 * channel_list and first ssid -				 * -				 * if ssid count is zero, single ssid in the -				 * fixed parameter portion is assumed, otherwise -				 * ssid in the fixed portion is ignored -				 */ -	__le16 channel_list[1];	/* list of chanspecs */ -}; - -struct brcmf_scan_results { -	u32 buflen; -	u32 version; -	u32 count; -	struct brcmf_bss_info_le bss_info_le[]; -}; - -struct brcmf_escan_params_le { -	__le32 version; -	__le16 action; -	__le16 sync_id; -	struct brcmf_scan_params_le params_le; -}; - -struct brcmf_escan_result_le { -	__le32 buflen; -	__le32 version; -	__le16 sync_id; -	__le16 bss_count; -	struct brcmf_bss_info_le bss_info_le; -}; - -#define WL_ESCAN_RESULTS_FIXED_SIZE (sizeof(struct brcmf_escan_result_le) - \ -	sizeof(struct brcmf_bss_info_le)) - -/* used for association with a specific BSSID and chanspec list */ -struct brcmf_assoc_params_le { -	/* 00:00:00:00:00:00: broadcast scan */ -	u8 bssid[ETH_ALEN]; -	/* 0: all available channels, otherwise count of chanspecs in -	 * chanspec_list */ -	__le32 chanspec_num; -	/* list of chanspecs */ -	__le16 chanspec_list[1]; -}; - -/* used for join with or without a specific bssid and channel list */ -struct brcmf_join_params { -	struct brcmf_ssid_le ssid_le; -	struct brcmf_assoc_params_le params_le; -}; - -/* scan params for extended join */ -struct brcmf_join_scan_params_le { -	u8 scan_type;		/* 0 use default, active or passive scan */ -	__le32 nprobes;		/* -1 use default, nr of probes per channel */ -	__le32 active_time;	/* -1 use default, dwell time per channel for -				 * active scanning -				 */ -	__le32 passive_time;	/* -1 use default, dwell time per channel -				 * for passive scanning -				 */ -	__le32 home_time;	/* -1 use default, dwell time for the home -				 * channel between channel scans -				 */ -}; - -/* extended join params */ -struct brcmf_ext_join_params_le { -	struct brcmf_ssid_le ssid_le;	/* {0, ""}: wildcard scan */ -	struct brcmf_join_scan_params_le scan_le; -	struct brcmf_assoc_params_le assoc_le; -}; - -struct brcmf_wsec_key { -	u32 index;		/* key index */ -	u32 len;		/* key length */ -	u8 data[WLAN_MAX_KEY_LEN];	/* key data */ -	u32 pad_1[18]; -	u32 algo;	/* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */ -	u32 flags;	/* misc flags */ -	u32 pad_2[3]; -	u32 iv_initialized;	/* has IV been initialized already? */ -	u32 pad_3; -	/* Rx IV */ -	struct { -		u32 hi;	/* upper 32 bits of IV */ -		u16 lo;	/* lower 16 bits of IV */ -	} rxiv; -	u32 pad_4[2]; -	u8 ea[ETH_ALEN];	/* per station */ -}; - -/* - * dongle requires same struct as above but with fields in little endian order +/* IOCTL from host to device are limited in lenght. A device can only handle + * ethernet frame size. This limitation is to be applied by protocol layer.   */ -struct brcmf_wsec_key_le { -	__le32 index;		/* key index */ -	__le32 len;		/* key length */ -	u8 data[WLAN_MAX_KEY_LEN];	/* key data */ -	__le32 pad_1[18]; -	__le32 algo;	/* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */ -	__le32 flags;	/* misc flags */ -	__le32 pad_2[3]; -	__le32 iv_initialized;	/* has IV been initialized already? */ -	__le32 pad_3; -	/* Rx IV */ -	struct { -		__le32 hi;	/* upper 32 bits of IV */ -		__le16 lo;	/* lower 16 bits of IV */ -	} rxiv; -	__le32 pad_4[2]; -	u8 ea[ETH_ALEN];	/* per station */ -}; - -/* Used to get specific STA parameters */ -struct brcmf_scb_val_le { -	__le32 val; -	u8 ea[ETH_ALEN]; -}; - -/* channel encoding */ -struct brcmf_channel_info_le { -	__le32 hw_channel; -	__le32 target_channel; -	__le32 scan_channel; -}; - -struct brcmf_sta_info_le { -	__le16	ver;		/* version of this struct */ -	__le16	len;		/* length in bytes of this structure */ -	__le16	cap;		/* sta's advertised capabilities */ -	__le32	flags;		/* flags defined below */ -	__le32	idle;		/* time since data pkt rx'd from sta */ -	u8	ea[ETH_ALEN];		/* Station address */ -	__le32	count;			/* # rates in this set */ -	u8	rates[BRCMF_MAXRATES_IN_SET];	/* rates in 500kbps units */ -						/* w/hi bit set if basic */ -	__le32	in;		/* seconds elapsed since associated */ -	__le32	listen_interval_inms; /* Min Listen interval in ms for STA */ -	__le32	tx_pkts;	/* # of packets transmitted */ -	__le32	tx_failures;	/* # of packets failed */ -	__le32	rx_ucast_pkts;	/* # of unicast packets received */ -	__le32	rx_mcast_pkts;	/* # of multicast packets received */ -	__le32	tx_rate;	/* Rate of last successful tx frame */ -	__le32	rx_rate;	/* Rate of last successful rx frame */ -	__le32	rx_decrypt_succeeds;	/* # of packet decrypted successfully */ -	__le32	rx_decrypt_failures;	/* # of packet decrypted failed */ -}; +#define BRCMF_TX_IOCTL_MAX_MSG_SIZE	(ETH_FRAME_LEN+ETH_FCS_LEN) -struct brcmf_chanspec_list { -	__le32	count;		/* # of entries */ -	__le32	element[1];	/* variable length uint32 list */ -}; +#define BRCMF_AMPDU_RX_REORDER_MAXFLOWS		256 -/* - * WLC_E_PROBRESP_MSG - * WLC_E_P2P_PROBREQ_MSG - * WLC_E_ACTION_FRAME_RX +/* Length of firmware version string stored for + * ethtool driver info which uses 32 bytes as well.   */ -struct brcmf_rx_mgmt_data { -	__be16	version; -	__be16	chanspec; -	__be32	rssi; -	__be32	mactime; -	__be32	rate; -}; +#define BRCMF_DRIVER_FIRMWARE_VERSION_LEN	32  /* Bus independent dongle command */  struct brcmf_dcmd { @@ -537,7 +87,7 @@ struct brcmf_fws_info; /* firmware signalling info */  struct brcmf_pub {  	/* Linkage ponters */  	struct brcmf_bus *bus_if; -	struct brcmf_proto *prot; +	struct brcmf_proto *proto;  	struct brcmf_cfg80211_info *config;  	/* Internal brcmf items */ @@ -546,7 +96,7 @@ struct brcmf_pub {  	u8 wme_dp;		/* wme discard priority */  	/* Dongle media info */ -	unsigned long drv_version;	/* Version of dongle-resident driver */ +	char fwver[BRCMF_DRIVER_FIRMWARE_VERSION_LEN];  	u8 mac[ETH_ALEN];		/* MAC address obtained from dongle */  	/* Multicast data packets sent to dongle */ @@ -568,14 +118,6 @@ struct brcmf_pub {  #endif  }; -struct brcmf_if_event { -	u8 ifidx; -	u8 action; -	u8 flags; -	u8 bssidx; -	u8 role; -}; -  /* forward declarations */  struct brcmf_cfg80211_vif;  struct brcmf_fws_mac_descriptor; @@ -632,29 +174,22 @@ struct brcmf_skb_reorder_data {  	u8 *reorder;  }; -extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev); +int brcmf_netdev_wait_pend8021x(struct net_device *ndev);  /* Return pointer to interface name */ -extern char *brcmf_ifname(struct brcmf_pub *drvr, int idx); - -/* Query dongle */ -extern int brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, -				       uint cmd, void *buf, uint len); -extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, -				    void *buf, uint len); +char *brcmf_ifname(struct brcmf_pub *drvr, int idx); -/* Remove any protocol-specific data header. */ -extern int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx, -			       struct sk_buff *rxp); - -extern int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked); -extern struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, -				     s32 ifidx, char *name, u8 *mac_addr); -extern void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx); +int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked); +struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx, +			      char *name, u8 *mac_addr); +void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx);  void brcmf_txflowblock_if(struct brcmf_if *ifp,  			  enum brcmf_netif_stop_reason reason, bool state); -extern u32 brcmf_get_chip_info(struct brcmf_if *ifp); -extern void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, -			     bool success); +u32 brcmf_get_chip_info(struct brcmf_if *ifp); +void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, u8 ifidx, +		      bool success); + +/* Sets dongle media info (drv_version, mac address). */ +int brcmf_c_preinit_dcmds(struct brcmf_if *ifp);  #endif				/* _BRCMF_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h index 74156f84180..7735328fff2 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h @@ -17,13 +17,23 @@  #ifndef _BRCMF_BUS_H_  #define _BRCMF_BUS_H_ +#include "dhd_dbg.h" +  /* The level of bus communication with the dongle */  enum brcmf_bus_state { +	BRCMF_BUS_UNKNOWN,	/* Not determined yet */ +	BRCMF_BUS_NOMEDIUM,	/* No medium access to dongle */  	BRCMF_BUS_DOWN,		/* Not ready for frame transfers */  	BRCMF_BUS_LOAD,		/* Download access only (CPU reset) */  	BRCMF_BUS_DATA		/* Ready for frame transfers */  }; +/* The level of bus communication with the dongle */ +enum brcmf_bus_protocol_type { +	BRCMF_PROTO_BCDC, +	BRCMF_PROTO_MSGBUF +}; +  struct brcmf_bus_dcmd {  	char *name;  	char *param; @@ -34,6 +44,7 @@ struct brcmf_bus_dcmd {  /**   * struct brcmf_bus_ops - bus callback operations.   * + * @preinit: execute bus/device specific dongle init commands (optional).   * @init: prepare for communication with dongle.   * @stop: clear pending frames, disable data flow.   * @txdata: send a data frame to the dongle. When the data @@ -51,7 +62,7 @@ struct brcmf_bus_dcmd {   * indicated otherwise these callbacks are mandatory.   */  struct brcmf_bus_ops { -	int (*init)(struct device *dev); +	int (*preinit)(struct device *dev);  	void (*stop)(struct device *dev);  	int (*txdata)(struct device *dev, struct sk_buff *skb);  	int (*txctl)(struct device *dev, unsigned char *msg, uint len); @@ -63,6 +74,7 @@ struct brcmf_bus_ops {   * struct brcmf_bus - interface structure between common and bus layer   *   * @bus_priv: pointer to private bus device. + * @proto_type: protocol type, bcdc or msgbuf   * @dev: device pointer of bus device.   * @drvr: public driver information.   * @state: operational state of the bus interface. @@ -78,6 +90,7 @@ struct brcmf_bus {  		struct brcmf_sdio_dev *sdio;  		struct brcmf_usbdev *usb;  	} bus_priv; +	enum brcmf_bus_protocol_type proto_type;  	struct device *dev;  	struct brcmf_pub *drvr;  	enum brcmf_bus_state state; @@ -85,7 +98,7 @@ struct brcmf_bus {  	unsigned long tx_realloc;  	u32 chip;  	u32 chiprev; -	struct list_head dcmd_list; +	bool always_use_fws_queue;  	struct brcmf_bus_ops *ops;  }; @@ -93,9 +106,11 @@ struct brcmf_bus {  /*   * callback wrappers   */ -static inline int brcmf_bus_init(struct brcmf_bus *bus) +static inline int brcmf_bus_preinit(struct brcmf_bus *bus)  { -	return bus->ops->init(bus->dev); +	if (!bus->ops->preinit) +		return 0; +	return bus->ops->preinit(bus->dev);  }  static inline void brcmf_bus_stop(struct brcmf_bus *bus) @@ -128,39 +143,58 @@ struct pktq *brcmf_bus_gettxq(struct brcmf_bus *bus)  	return bus->ops->gettxq(bus->dev);  } + +static inline bool brcmf_bus_ready(struct brcmf_bus *bus) +{ +	return bus->state == BRCMF_BUS_LOAD || bus->state == BRCMF_BUS_DATA; +} + +static inline void brcmf_bus_change_state(struct brcmf_bus *bus, +					  enum brcmf_bus_state new_state) +{ +	/* NOMEDIUM is permanent */ +	if (bus->state == BRCMF_BUS_NOMEDIUM) +		return; + +	brcmf_dbg(TRACE, "%d -> %d\n", bus->state, new_state); +	bus->state = new_state; +} +  /*   * interface functions from common layer   */ -extern bool brcmf_c_prec_enq(struct device *dev, struct pktq *q, -			 struct sk_buff *pkt, int prec); +bool brcmf_c_prec_enq(struct device *dev, struct pktq *q, struct sk_buff *pkt, +		      int prec);  /* Receive frame for delivery to OS.  Callee disposes of rxp. */ -extern void brcmf_rx_frames(struct device *dev, struct sk_buff_head *rxlist); +void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp);  /* Indication from bus module regarding presence/insertion of dongle. */ -extern int brcmf_attach(uint bus_hdrlen, struct device *dev); +int brcmf_attach(struct device *dev);  /* Indication from bus module regarding removal/absence of dongle */ -extern void brcmf_detach(struct device *dev); +void brcmf_detach(struct device *dev);  /* Indication from bus module that dongle should be reset */ -extern void brcmf_dev_reset(struct device *dev); +void brcmf_dev_reset(struct device *dev);  /* Indication from bus module to change flow-control state */ -extern void brcmf_txflowblock(struct device *dev, bool state); +void brcmf_txflowblock(struct device *dev, bool state);  /* Notify the bus has transferred the tx packet to firmware */ -extern void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, -			     bool success); +void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success); -extern int brcmf_bus_start(struct device *dev); +int brcmf_bus_start(struct device *dev); +s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data, +				u32 len); +void brcmf_bus_add_txhdrlen(struct device *dev, uint len);  #ifdef CONFIG_BRCMFMAC_SDIO -extern void brcmf_sdio_exit(void); -extern void brcmf_sdio_init(void); -extern void brcmf_sdio_register(void); +void brcmf_sdio_exit(void); +void brcmf_sdio_init(void); +void brcmf_sdio_register(void);  #endif  #ifdef CONFIG_BRCMFMAC_USB -extern void brcmf_usb_exit(void); -extern void brcmf_usb_register(void); +void brcmf_usb_exit(void); +void brcmf_usb_register(void);  #endif  #endif				/* _BRCMF_BUS_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c deleted file mode 100644 index dd85401063c..00000000000 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c +++ /dev/null @@ -1,392 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/******************************************************************************* - * Communicates with the dongle by using dcmd codes. - * For certain dcmd codes, the dongle interprets string data from the host. - ******************************************************************************/ - -#include <linux/types.h> -#include <linux/netdevice.h> - -#include <brcmu_utils.h> -#include <brcmu_wifi.h> - -#include "dhd.h" -#include "dhd_proto.h" -#include "dhd_bus.h" -#include "fwsignal.h" -#include "dhd_dbg.h" -#include "tracepoint.h" - -struct brcmf_proto_cdc_dcmd { -	__le32 cmd;	/* dongle command value */ -	__le32 len;	/* lower 16: output buflen; -			 * upper 16: input buflen (excludes header) */ -	__le32 flags;	/* flag defns given below */ -	__le32 status;	/* status code returned from the device */ -}; - -/* Max valid buffer size that can be sent to the dongle */ -#define CDC_MAX_MSG_SIZE	(ETH_FRAME_LEN+ETH_FCS_LEN) - -/* CDC flag definitions */ -#define CDC_DCMD_ERROR		0x01	/* 1=cmd failed */ -#define CDC_DCMD_SET		0x02	/* 0=get, 1=set cmd */ -#define CDC_DCMD_IF_MASK	0xF000		/* I/F index */ -#define CDC_DCMD_IF_SHIFT	12 -#define CDC_DCMD_ID_MASK	0xFFFF0000	/* id an cmd pairing */ -#define CDC_DCMD_ID_SHIFT	16		/* ID Mask shift bits */ -#define CDC_DCMD_ID(flags)	\ -	(((flags) & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT) - -/* - * BDC header - Broadcom specific extension of CDC. - * Used on data packets to convey priority across USB. - */ -#define	BDC_HEADER_LEN		4 -#define BDC_PROTO_VER		2	/* Protocol version */ -#define BDC_FLAG_VER_MASK	0xf0	/* Protocol version mask */ -#define BDC_FLAG_VER_SHIFT	4	/* Protocol version shift */ -#define BDC_FLAG_SUM_GOOD	0x04	/* Good RX checksums */ -#define BDC_FLAG_SUM_NEEDED	0x08	/* Dongle needs to do TX checksums */ -#define BDC_PRIORITY_MASK	0x7 -#define BDC_FLAG2_IF_MASK	0x0f	/* packet rx interface in APSTA */ -#define BDC_FLAG2_IF_SHIFT	0 - -#define BDC_GET_IF_IDX(hdr) \ -	((int)((((hdr)->flags2) & BDC_FLAG2_IF_MASK) >> BDC_FLAG2_IF_SHIFT)) -#define BDC_SET_IF_IDX(hdr, idx) \ -	((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_IF_MASK) | \ -	((idx) << BDC_FLAG2_IF_SHIFT))) - -/** - * struct brcmf_proto_bdc_header - BDC header format - * - * @flags: flags contain protocol and checksum info. - * @priority: 802.1d priority and USB flow control info (bit 4:7). - * @flags2: additional flags containing dongle interface index. - * @data_offset: start of packet data. header is following by firmware signals. - */ -struct brcmf_proto_bdc_header { -	u8 flags; -	u8 priority; -	u8 flags2; -	u8 data_offset; -}; - -/* - * maximum length of firmware signal data between - * the BDC header and packet data in the tx path. - */ -#define BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES	12 - -#define RETRIES 2 /* # of retries to retrieve matching dcmd response */ -#define BUS_HEADER_LEN	(16+64)		/* Must be atleast SDPCM_RESERVE -					 * (amount of header tha might be added) -					 * plus any space that might be needed -					 * for bus alignment padding. -					 */ -#define ROUND_UP_MARGIN	2048	/* Biggest bus block size possible for -				 * round off at the end of buffer -				 * Currently is SDIO -				 */ - -struct brcmf_proto { -	u16 reqid; -	u8 bus_header[BUS_HEADER_LEN]; -	struct brcmf_proto_cdc_dcmd msg; -	unsigned char buf[BRCMF_DCMD_MAXLEN + ROUND_UP_MARGIN]; -}; - -static int brcmf_proto_cdc_msg(struct brcmf_pub *drvr) -{ -	struct brcmf_proto *prot = drvr->prot; -	int len = le32_to_cpu(prot->msg.len) + -			sizeof(struct brcmf_proto_cdc_dcmd); - -	brcmf_dbg(CDC, "Enter\n"); - -	/* NOTE : cdc->msg.len holds the desired length of the buffer to be -	 *        returned. Only up to CDC_MAX_MSG_SIZE of this buffer area -	 *        is actually sent to the dongle -	 */ -	if (len > CDC_MAX_MSG_SIZE) -		len = CDC_MAX_MSG_SIZE; - -	/* Send request */ -	return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&prot->msg, len); -} - -static int brcmf_proto_cdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len) -{ -	int ret; -	struct brcmf_proto *prot = drvr->prot; - -	brcmf_dbg(CDC, "Enter\n"); -	len += sizeof(struct brcmf_proto_cdc_dcmd); -	do { -		ret = brcmf_bus_rxctl(drvr->bus_if, (unsigned char *)&prot->msg, -				      len); -		if (ret < 0) -			break; -	} while (CDC_DCMD_ID(le32_to_cpu(prot->msg.flags)) != id); - -	return ret; -} - -int -brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, -			       void *buf, uint len) -{ -	struct brcmf_proto *prot = drvr->prot; -	struct brcmf_proto_cdc_dcmd *msg = &prot->msg; -	void *info; -	int ret = 0, retries = 0; -	u32 id, flags; - -	brcmf_dbg(CDC, "Enter, cmd %d len %d\n", cmd, len); - -	memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd)); - -	msg->cmd = cpu_to_le32(cmd); -	msg->len = cpu_to_le32(len); -	flags = (++prot->reqid << CDC_DCMD_ID_SHIFT); -	flags = (flags & ~CDC_DCMD_IF_MASK) | -		(ifidx << CDC_DCMD_IF_SHIFT); -	msg->flags = cpu_to_le32(flags); - -	if (buf) -		memcpy(prot->buf, buf, len); - -	ret = brcmf_proto_cdc_msg(drvr); -	if (ret < 0) { -		brcmf_err("brcmf_proto_cdc_msg failed w/status %d\n", -			  ret); -		goto done; -	} - -retry: -	/* wait for interrupt and get first fragment */ -	ret = brcmf_proto_cdc_cmplt(drvr, prot->reqid, len); -	if (ret < 0) -		goto done; - -	flags = le32_to_cpu(msg->flags); -	id = (flags & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT; - -	if ((id < prot->reqid) && (++retries < RETRIES)) -		goto retry; -	if (id != prot->reqid) { -		brcmf_err("%s: unexpected request id %d (expected %d)\n", -			  brcmf_ifname(drvr, ifidx), id, prot->reqid); -		ret = -EINVAL; -		goto done; -	} - -	/* Check info buffer */ -	info = (void *)&msg[1]; - -	/* Copy info buffer */ -	if (buf) { -		if (ret < (int)len) -			len = ret; -		memcpy(buf, info, len); -	} - -	/* Check the ERROR flag */ -	if (flags & CDC_DCMD_ERROR) -		ret = le32_to_cpu(msg->status); - -done: -	return ret; -} - -int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, -				 void *buf, uint len) -{ -	struct brcmf_proto *prot = drvr->prot; -	struct brcmf_proto_cdc_dcmd *msg = &prot->msg; -	int ret = 0; -	u32 flags, id; - -	brcmf_dbg(CDC, "Enter, cmd %d len %d\n", cmd, len); - -	memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd)); - -	msg->cmd = cpu_to_le32(cmd); -	msg->len = cpu_to_le32(len); -	flags = (++prot->reqid << CDC_DCMD_ID_SHIFT) | CDC_DCMD_SET; -	flags = (flags & ~CDC_DCMD_IF_MASK) | -		(ifidx << CDC_DCMD_IF_SHIFT); -	msg->flags = cpu_to_le32(flags); - -	if (buf) -		memcpy(prot->buf, buf, len); - -	ret = brcmf_proto_cdc_msg(drvr); -	if (ret < 0) -		goto done; - -	ret = brcmf_proto_cdc_cmplt(drvr, prot->reqid, len); -	if (ret < 0) -		goto done; - -	flags = le32_to_cpu(msg->flags); -	id = (flags & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT; - -	if (id != prot->reqid) { -		brcmf_err("%s: unexpected request id %d (expected %d)\n", -			  brcmf_ifname(drvr, ifidx), id, prot->reqid); -		ret = -EINVAL; -		goto done; -	} - -	/* Check the ERROR flag */ -	if (flags & CDC_DCMD_ERROR) -		ret = le32_to_cpu(msg->status); - -done: -	return ret; -} - -static bool pkt_sum_needed(struct sk_buff *skb) -{ -	return skb->ip_summed == CHECKSUM_PARTIAL; -} - -static void pkt_set_sum_good(struct sk_buff *skb, bool x) -{ -	skb->ip_summed = (x ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE); -} - -void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx, u8 offset, -			 struct sk_buff *pktbuf) -{ -	struct brcmf_proto_bdc_header *h; - -	brcmf_dbg(CDC, "Enter\n"); - -	/* Push BDC header used to convey priority for buses that don't */ -	skb_push(pktbuf, BDC_HEADER_LEN); - -	h = (struct brcmf_proto_bdc_header *)(pktbuf->data); - -	h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); -	if (pkt_sum_needed(pktbuf)) -		h->flags |= BDC_FLAG_SUM_NEEDED; - -	h->priority = (pktbuf->priority & BDC_PRIORITY_MASK); -	h->flags2 = 0; -	h->data_offset = offset; -	BDC_SET_IF_IDX(h, ifidx); -	trace_brcmf_bdchdr(pktbuf->data); -} - -int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx, -			struct sk_buff *pktbuf) -{ -	struct brcmf_proto_bdc_header *h; - -	brcmf_dbg(CDC, "Enter\n"); - -	/* Pop BDC header used to convey priority for buses that don't */ - -	if (pktbuf->len <= BDC_HEADER_LEN) { -		brcmf_dbg(INFO, "rx data too short (%d <= %d)\n", -			  pktbuf->len, BDC_HEADER_LEN); -		return -EBADE; -	} - -	trace_brcmf_bdchdr(pktbuf->data); -	h = (struct brcmf_proto_bdc_header *)(pktbuf->data); - -	*ifidx = BDC_GET_IF_IDX(h); -	if (*ifidx >= BRCMF_MAX_IFS) { -		brcmf_err("rx data ifnum out of range (%d)\n", *ifidx); -		return -EBADE; -	} -	/* The ifidx is the idx to map to matching netdev/ifp. When receiving -	 * events this is easy because it contains the bssidx which maps -	 * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd. -	 * bssidx 1 is used for p2p0 and no data can be received or -	 * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0 -	 */ -	if (*ifidx) -		(*ifidx)++; - -	if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != -	    BDC_PROTO_VER) { -		brcmf_err("%s: non-BDC packet received, flags 0x%x\n", -			  brcmf_ifname(drvr, *ifidx), h->flags); -		return -EBADE; -	} - -	if (h->flags & BDC_FLAG_SUM_GOOD) { -		brcmf_dbg(CDC, "%s: BDC rcv, good checksum, flags 0x%x\n", -			  brcmf_ifname(drvr, *ifidx), h->flags); -		pkt_set_sum_good(pktbuf, true); -	} - -	pktbuf->priority = h->priority & BDC_PRIORITY_MASK; - -	skb_pull(pktbuf, BDC_HEADER_LEN); -	if (do_fws) -		brcmf_fws_hdrpull(drvr, *ifidx, h->data_offset << 2, pktbuf); -	else -		skb_pull(pktbuf, h->data_offset << 2); - -	if (pktbuf->len == 0) -		return -ENODATA; -	return 0; -} - -int brcmf_proto_attach(struct brcmf_pub *drvr) -{ -	struct brcmf_proto *cdc; - -	cdc = kzalloc(sizeof(struct brcmf_proto), GFP_ATOMIC); -	if (!cdc) -		goto fail; - -	/* ensure that the msg buf directly follows the cdc msg struct */ -	if ((unsigned long)(&cdc->msg + 1) != (unsigned long)cdc->buf) { -		brcmf_err("struct brcmf_proto is not correctly defined\n"); -		goto fail; -	} - -	drvr->prot = cdc; -	drvr->hdrlen += BDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES; -	drvr->bus_if->maxctl = BRCMF_DCMD_MAXLEN + -			sizeof(struct brcmf_proto_cdc_dcmd) + ROUND_UP_MARGIN; -	return 0; - -fail: -	kfree(cdc); -	return -ENOMEM; -} - -/* ~NOTE~ What if another thread is waiting on the semaphore?  Holding it? */ -void brcmf_proto_detach(struct brcmf_pub *drvr) -{ -	kfree(drvr->prot); -	drvr->prot = NULL; -} - -void brcmf_proto_stop(struct brcmf_pub *drvr) -{ -	/* Nothing to do for CDC */ -} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c index 9431af2465f..ed3e32ce8c2 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c @@ -21,9 +21,9 @@  #include <brcmu_utils.h>  #include "dhd.h"  #include "dhd_bus.h" -#include "dhd_proto.h"  #include "dhd_dbg.h"  #include "fwil.h" +#include "fwil_types.h"  #include "tracepoint.h"  #define PKTFILTER_BUF_SIZE		128 @@ -32,14 +32,8 @@  #define BRCMF_DEFAULT_SCAN_UNASSOC_TIME	40  #define BRCMF_DEFAULT_PACKET_FILTER	"100 0 0 0 0x01 0x00" -#ifdef DEBUG -static const char brcmf_version[] = -	"Dongle Host Driver, version " BRCMF_VERSION_STR "\nCompiled on " -	__DATE__ " at " __TIME__; -#else -static const char brcmf_version[] = -	"Dongle Host Driver, version " BRCMF_VERSION_STR; -#endif +/* boost value for RSSI_DELTA in preferred join selection */ +#define BRCMF_JOIN_PREF_RSSI_BOOST	8  bool brcmf_c_prec_enq(struct device *dev, struct pktq *q, @@ -255,10 +249,9 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)  {  	s8 eventmask[BRCMF_EVENTING_MASK_LEN];  	u8 buf[BRCMF_DCMD_SMLEN]; +	struct brcmf_join_pref_params join_pref_params[2];  	char *ptr;  	s32 err; -	struct brcmf_bus_dcmd *cmdlst; -	struct list_head *cur, *q;  	/* retreive mac address */  	err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr, @@ -281,9 +274,14 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)  	}  	ptr = (char *)buf;  	strsep(&ptr, "\n"); +  	/* Print fw version info */  	brcmf_err("Firmware version = %s\n", buf); +	/* locate firmware version number for ethtool */ +	ptr = strrchr(buf, ' ') + 1; +	strlcpy(ifp->drvr->fwver, ptr, sizeof(ifp->drvr->fwver)); +  	/*  	 * Setup timeout if Beacons are lost and roam is off to report  	 * link down @@ -304,6 +302,20 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)  		goto done;  	} +	/* Setup join_pref to select target by RSSI(with boost on 5GHz) */ +	join_pref_params[0].type = BRCMF_JOIN_PREF_RSSI_DELTA; +	join_pref_params[0].len = 2; +	join_pref_params[0].rssi_gain = BRCMF_JOIN_PREF_RSSI_BOOST; +	join_pref_params[0].band = WLC_BAND_5G; +	join_pref_params[1].type = BRCMF_JOIN_PREF_RSSI; +	join_pref_params[1].len = 2; +	join_pref_params[1].rssi_gain = 0; +	join_pref_params[1].band = 0; +	err = brcmf_fil_iovar_data_set(ifp, "join_pref", join_pref_params, +				       sizeof(join_pref_params)); +	if (err) +		brcmf_err("Set join_pref error (%d)\n", err); +  	/* Setup event_msgs, enable E_IF */  	err = brcmf_fil_iovar_data_get(ifp, "event_msgs", eventmask,  				       BRCMF_EVENTING_MASK_LEN); @@ -342,17 +354,8 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)  	brcmf_c_pktfilter_offload_enable(ifp, BRCMF_DEFAULT_PACKET_FILTER,  					 0, true); -	/* set bus specific command if there is any */ -	list_for_each_safe(cur, q, &ifp->drvr->bus_if->dcmd_list) { -		cmdlst = list_entry(cur, struct brcmf_bus_dcmd, list); -		if (cmdlst->name && cmdlst->param && cmdlst->param_len) { -			brcmf_fil_iovar_data_set(ifp, cmdlst->name, -						 cmdlst->param, -						 cmdlst->param_len); -		} -		list_del(cur); -		kfree(cmdlst); -	} +	/* do bus specific preinit here */ +	err = brcmf_bus_preinit(ifp->drvr->bus_if);  done:  	return err;  } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c index 0f9e9057e7d..03fe8aca4d3 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c @@ -22,7 +22,6 @@  #include "dhd.h"  #include "dhd_bus.h"  #include "dhd_dbg.h" -#include "tracepoint.h"  static struct dentry *root_folder; @@ -42,6 +41,40 @@ void brcmf_debugfs_exit(void)  	root_folder = NULL;  } +static +ssize_t brcmf_debugfs_chipinfo_read(struct file *f, char __user *data, +				   size_t count, loff_t *ppos) +{ +	struct brcmf_pub *drvr = f->private_data; +	struct brcmf_bus *bus = drvr->bus_if; +	char buf[40]; +	int res; + +	/* only allow read from start */ +	if (*ppos > 0) +		return 0; + +	res = scnprintf(buf, sizeof(buf), "chip: %x(%u) rev %u\n", +			bus->chip, bus->chip, bus->chiprev); +	return simple_read_from_buffer(data, count, ppos, buf, res); +} + +static const struct file_operations brcmf_debugfs_chipinfo_ops = { +	.owner = THIS_MODULE, +	.open = simple_open, +	.read = brcmf_debugfs_chipinfo_read +}; + +static int brcmf_debugfs_create_chipinfo(struct brcmf_pub *drvr) +{ +	struct dentry *dentry =  drvr->dbgfs_dir; + +	if (!IS_ERR_OR_NULL(dentry)) +		debugfs_create_file("chipinfo", S_IRUGO, dentry, drvr, +				    &brcmf_debugfs_chipinfo_ops); +	return 0; +} +  int brcmf_debugfs_attach(struct brcmf_pub *drvr)  {  	struct device *dev = drvr->bus_if->dev; @@ -50,6 +83,7 @@ int brcmf_debugfs_attach(struct brcmf_pub *drvr)  		return -ENODEV;  	drvr->dbgfs_dir = debugfs_create_dir(dev_name(dev), root_folder); +	brcmf_debugfs_create_chipinfo(drvr);  	return PTR_ERR_OR_ZERO(drvr->dbgfs_dir);  } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h index 0af1f5dc583..ef52ed7abc6 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h @@ -33,7 +33,7 @@  #define BRCMF_USB_VAL	0x00002000  #define BRCMF_SCAN_VAL	0x00004000  #define BRCMF_CONN_VAL	0x00008000 -#define BRCMF_CDC_VAL	0x00010000 +#define BRCMF_BCDC_VAL	0x00010000  #define BRCMF_SDIO_VAL	0x00020000  /* set default print format */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index 40e7f854e10..09dd8c13d84 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -24,13 +24,13 @@  #include "dhd.h"  #include "dhd_bus.h" -#include "dhd_proto.h"  #include "dhd_dbg.h"  #include "fwil_types.h"  #include "p2p.h"  #include "wl_cfg80211.h"  #include "fwil.h"  #include "fwsignal.h" +#include "proto.h"  MODULE_AUTHOR("Broadcom Corporation");  MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver."); @@ -190,7 +190,7 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,  	int ret;  	struct brcmf_if *ifp = netdev_priv(ndev);  	struct brcmf_pub *drvr = ifp->drvr; -	struct ethhdr *eh; +	struct ethhdr *eh = (struct ethhdr *)(skb->data);  	brcmf_dbg(DATA, "Enter, idx=%d\n", ifp->bssidx); @@ -236,6 +236,9 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,  		goto done;  	} +	if (eh->h_proto == htons(ETH_P_PAE)) +		atomic_inc(&ifp->pend_8021x_cnt); +  	ret = brcmf_fws_process_skb(ifp, skb);  done: @@ -509,9 +512,8 @@ netif_rx:  	}  } -void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list) +void brcmf_rx_frame(struct device *dev, struct sk_buff *skb)  { -	struct sk_buff *skb, *pnext;  	struct brcmf_if *ifp;  	struct brcmf_bus *bus_if = dev_get_drvdata(dev);  	struct brcmf_pub *drvr = bus_if->drvr; @@ -519,56 +521,46 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)  	u8 ifidx;  	int ret; -	brcmf_dbg(DATA, "Enter: %s: count=%u\n", dev_name(dev), -		  skb_queue_len(skb_list)); - -	skb_queue_walk_safe(skb_list, skb, pnext) { -		skb_unlink(skb, skb_list); +	brcmf_dbg(DATA, "Enter: %s: rxp=%p\n", dev_name(dev), skb); -		/* process and remove protocol-specific header */ -		ret = brcmf_proto_hdrpull(drvr, true, &ifidx, skb); -		ifp = drvr->iflist[ifidx]; - -		if (ret || !ifp || !ifp->ndev) { -			if ((ret != -ENODATA) && ifp) -				ifp->stats.rx_errors++; -			brcmu_pkt_buf_free_skb(skb); -			continue; -		} +	/* process and remove protocol-specific header */ +	ret = brcmf_proto_hdrpull(drvr, true, &ifidx, skb); +	ifp = drvr->iflist[ifidx]; -		rd = (struct brcmf_skb_reorder_data *)skb->cb; -		if (rd->reorder) -			brcmf_rxreorder_process_info(ifp, rd->reorder, skb); -		else -			brcmf_netif_rx(ifp, skb); +	if (ret || !ifp || !ifp->ndev) { +		if ((ret != -ENODATA) && ifp) +			ifp->stats.rx_errors++; +		brcmu_pkt_buf_free_skb(skb); +		return;  	} + +	rd = (struct brcmf_skb_reorder_data *)skb->cb; +	if (rd->reorder) +		brcmf_rxreorder_process_info(ifp, rd->reorder, skb); +	else +		brcmf_netif_rx(ifp, skb);  } -void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, +void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp, u8 ifidx,  		      bool success)  {  	struct brcmf_if *ifp;  	struct ethhdr *eh; -	u8 ifidx;  	u16 type; -	int res; - -	res = brcmf_proto_hdrpull(drvr, false, &ifidx, txp);  	ifp = drvr->iflist[ifidx];  	if (!ifp)  		goto done; -	if (res == 0) { -		eh = (struct ethhdr *)(txp->data); -		type = ntohs(eh->h_proto); +	eh = (struct ethhdr *)(txp->data); +	type = ntohs(eh->h_proto); -		if (type == ETH_P_PAE) { -			atomic_dec(&ifp->pend_8021x_cnt); -			if (waitqueue_active(&ifp->pend_8021x_wait)) -				wake_up(&ifp->pend_8021x_wait); -		} +	if (type == ETH_P_PAE) { +		atomic_dec(&ifp->pend_8021x_cnt); +		if (waitqueue_active(&ifp->pend_8021x_wait)) +			wake_up(&ifp->pend_8021x_wait);  	} +  	if (!success)  		ifp->stats.tx_errors++;  done: @@ -579,13 +571,17 @@ void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)  {  	struct brcmf_bus *bus_if = dev_get_drvdata(dev);  	struct brcmf_pub *drvr = bus_if->drvr; +	u8 ifidx;  	/* await txstatus signal for firmware if active */  	if (brcmf_fws_fc_active(drvr->fws)) {  		if (!success)  			brcmf_fws_bustxfail(drvr->fws, txp);  	} else { -		brcmf_txfinalize(drvr, txp, success); +		if (brcmf_proto_hdrpull(drvr, false, &ifidx, txp)) +			brcmu_pkt_buf_free_skb(txp); +		else +			brcmf_txfinalize(drvr, txp, ifidx, success);  	}  } @@ -598,28 +594,6 @@ static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)  	return &ifp->stats;  } -/* - * Set current toe component enables in toe_ol iovar, - * and set toe global enable iovar - */ -static int brcmf_toe_set(struct brcmf_if *ifp, u32 toe_ol) -{ -	s32 err; - -	err = brcmf_fil_iovar_int_set(ifp, "toe_ol", toe_ol); -	if (err < 0) { -		brcmf_err("Setting toe_ol failed, %d\n", err); -		return err; -	} - -	err = brcmf_fil_iovar_int_set(ifp, "toe", (toe_ol != 0)); -	if (err < 0) -		brcmf_err("Setting toe failed, %d\n", err); - -	return err; - -} -  static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,  				    struct ethtool_drvinfo *info)  { @@ -627,8 +601,8 @@ static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,  	struct brcmf_pub *drvr = ifp->drvr;  	strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); -	snprintf(info->version, sizeof(info->version), "%lu", -		 drvr->drv_version); +	snprintf(info->version, sizeof(info->version), "n/a"); +	strlcpy(info->fw_version, drvr->fwver, sizeof(info->fw_version));  	strlcpy(info->bus_info, dev_name(drvr->bus_if->dev),  		sizeof(info->bus_info));  } @@ -637,124 +611,6 @@ static const struct ethtool_ops brcmf_ethtool_ops = {  	.get_drvinfo = brcmf_ethtool_get_drvinfo,  }; -static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr) -{ -	struct brcmf_pub *drvr = ifp->drvr; -	struct ethtool_drvinfo info; -	char drvname[sizeof(info.driver)]; -	u32 cmd; -	struct ethtool_value edata; -	u32 toe_cmpnt, csum_dir; -	int ret; - -	brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); - -	/* all ethtool calls start with a cmd word */ -	if (copy_from_user(&cmd, uaddr, sizeof(u32))) -		return -EFAULT; - -	switch (cmd) { -	case ETHTOOL_GDRVINFO: -		/* Copy out any request driver name */ -		if (copy_from_user(&info, uaddr, sizeof(info))) -			return -EFAULT; -		strncpy(drvname, info.driver, sizeof(info.driver)); -		drvname[sizeof(info.driver) - 1] = '\0'; - -		/* clear struct for return */ -		memset(&info, 0, sizeof(info)); -		info.cmd = cmd; - -		/* if requested, identify ourselves */ -		if (strcmp(drvname, "?dhd") == 0) { -			sprintf(info.driver, "dhd"); -			strcpy(info.version, BRCMF_VERSION_STR); -		} -		/* report dongle driver type */ -		else -			sprintf(info.driver, "wl"); - -		sprintf(info.version, "%lu", drvr->drv_version); -		if (copy_to_user(uaddr, &info, sizeof(info))) -			return -EFAULT; -		brcmf_dbg(TRACE, "given %*s, returning %s\n", -			  (int)sizeof(drvname), drvname, info.driver); -		break; - -		/* Get toe offload components from dongle */ -	case ETHTOOL_GRXCSUM: -	case ETHTOOL_GTXCSUM: -		ret = brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_cmpnt); -		if (ret < 0) -			return ret; - -		csum_dir = -		    (cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; - -		edata.cmd = cmd; -		edata.data = (toe_cmpnt & csum_dir) ? 1 : 0; - -		if (copy_to_user(uaddr, &edata, sizeof(edata))) -			return -EFAULT; -		break; - -		/* Set toe offload components in dongle */ -	case ETHTOOL_SRXCSUM: -	case ETHTOOL_STXCSUM: -		if (copy_from_user(&edata, uaddr, sizeof(edata))) -			return -EFAULT; - -		/* Read the current settings, update and write back */ -		ret = brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_cmpnt); -		if (ret < 0) -			return ret; - -		csum_dir = -		    (cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; - -		if (edata.data != 0) -			toe_cmpnt |= csum_dir; -		else -			toe_cmpnt &= ~csum_dir; - -		ret = brcmf_toe_set(ifp, toe_cmpnt); -		if (ret < 0) -			return ret; - -		/* If setting TX checksum mode, tell Linux the new mode */ -		if (cmd == ETHTOOL_STXCSUM) { -			if (edata.data) -				ifp->ndev->features |= NETIF_F_IP_CSUM; -			else -				ifp->ndev->features &= ~NETIF_F_IP_CSUM; -		} - -		break; - -	default: -		return -EOPNOTSUPP; -	} - -	return 0; -} - -static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr, -				    int cmd) -{ -	struct brcmf_if *ifp = netdev_priv(ndev); -	struct brcmf_pub *drvr = ifp->drvr; - -	brcmf_dbg(TRACE, "Enter, idx=%d, cmd=0x%04x\n", ifp->bssidx, cmd); - -	if (!drvr->iflist[ifp->bssidx]) -		return -1; - -	if (cmd == SIOCETHTOOL) -		return brcmf_ethtool(ifp, ifr->ifr_data); - -	return -EOPNOTSUPP; -} -  static int brcmf_netdev_stop(struct net_device *ndev)  {  	struct brcmf_if *ifp = netdev_priv(ndev); @@ -775,7 +631,6 @@ static int brcmf_netdev_open(struct net_device *ndev)  	struct brcmf_pub *drvr = ifp->drvr;  	struct brcmf_bus *bus_if = drvr->bus_if;  	u32 toe_ol; -	s32 ret = 0;  	brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); @@ -794,21 +649,20 @@ static int brcmf_netdev_open(struct net_device *ndev)  	else  		ndev->features &= ~NETIF_F_IP_CSUM; -	/* Allow transmit calls */ -	netif_start_queue(ndev);  	if (brcmf_cfg80211_up(ndev)) {  		brcmf_err("failed to bring up cfg80211\n"); -		return -1; +		return -EIO;  	} -	return ret; +	/* Allow transmit calls */ +	netif_start_queue(ndev); +	return 0;  }  static const struct net_device_ops brcmf_netdev_ops_pri = {  	.ndo_open = brcmf_netdev_open,  	.ndo_stop = brcmf_netdev_stop,  	.ndo_get_stats = brcmf_netdev_get_stats, -	.ndo_do_ioctl = brcmf_netdev_ioctl_entry,  	.ndo_start_xmit = brcmf_netdev_start_xmit,  	.ndo_set_mac_address = brcmf_netdev_set_mac_address,  	.ndo_set_rx_mode = brcmf_netdev_set_multicast_list @@ -850,7 +704,7 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked)  	brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name); -	ndev->destructor = free_netdev; +	ndev->destructor = brcmf_cfg80211_free_netdev;  	return 0;  fail: @@ -874,13 +728,6 @@ static int brcmf_net_p2p_stop(struct net_device *ndev)  	return brcmf_cfg80211_down(ndev);  } -static int brcmf_net_p2p_do_ioctl(struct net_device *ndev, -				  struct ifreq *ifr, int cmd) -{ -	brcmf_dbg(TRACE, "Enter\n"); -	return 0; -} -  static netdev_tx_t brcmf_net_p2p_start_xmit(struct sk_buff *skb,  					    struct net_device *ndev)  { @@ -893,7 +740,6 @@ static netdev_tx_t brcmf_net_p2p_start_xmit(struct sk_buff *skb,  static const struct net_device_ops brcmf_netdev_ops_p2p = {  	.ndo_open = brcmf_net_p2p_open,  	.ndo_stop = brcmf_net_p2p_stop, -	.ndo_do_ioctl = brcmf_net_p2p_do_ioctl,  	.ndo_start_xmit = brcmf_net_p2p_start_xmit  }; @@ -1015,14 +861,12 @@ void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx)  		}  		/* unregister will take care of freeing it */  		unregister_netdev(ifp->ndev); -		if (bssidx == 0) -			brcmf_cfg80211_detach(drvr->config);  	} else {  		kfree(ifp);  	}  } -int brcmf_attach(uint bus_hdrlen, struct device *dev) +int brcmf_attach(struct device *dev)  {  	struct brcmf_pub *drvr = NULL;  	int ret = 0; @@ -1037,7 +881,7 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev)  	mutex_init(&drvr->proto_block);  	/* Link to bus module */ -	drvr->hdrlen = bus_hdrlen; +	drvr->hdrlen = 0;  	drvr->bus_if = dev_get_drvdata(dev);  	drvr->bus_if->drvr = drvr; @@ -1054,8 +898,6 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev)  	/* attach firmware event handler */  	brcmf_fweh_attach(drvr); -	INIT_LIST_HEAD(&drvr->bus_if->dcmd_list); -  	return ret;  fail: @@ -1074,13 +916,6 @@ int brcmf_bus_start(struct device *dev)  	brcmf_dbg(TRACE, "\n"); -	/* Bring up the bus */ -	ret = brcmf_bus_init(bus_if); -	if (ret != 0) { -		brcmf_err("brcmf_sdbrcm_bus_init failed %d\n", ret); -		return ret; -	} -  	/* add primary networking interface */  	ifp = brcmf_add_if(drvr, 0, 0, "wlan%d", NULL);  	if (IS_ERR(ifp)) @@ -1094,7 +929,7 @@ int brcmf_bus_start(struct device *dev)  		p2p_ifp = NULL;  	/* signal bus ready */ -	bus_if->state = BRCMF_BUS_DATA; +	brcmf_bus_change_state(bus_if, BRCMF_BUS_DATA);  	/* Bus is ready, do any initialization */  	ret = brcmf_c_preinit_dcmds(ifp); @@ -1121,8 +956,7 @@ int brcmf_bus_start(struct device *dev)  fail:  	if (ret < 0) {  		brcmf_err("failed: %d\n", ret); -		if (drvr->config) -			brcmf_cfg80211_detach(drvr->config); +		brcmf_cfg80211_detach(drvr->config);  		if (drvr->fws) {  			brcmf_fws_del_interface(ifp);  			brcmf_fws_deinit(drvr); @@ -1144,14 +978,21 @@ fail:  	return 0;  } +void brcmf_bus_add_txhdrlen(struct device *dev, uint len) +{ +	struct brcmf_bus *bus_if = dev_get_drvdata(dev); +	struct brcmf_pub *drvr = bus_if->drvr; + +	if (drvr) { +		drvr->hdrlen += len; +	} +} +  static void brcmf_bus_detach(struct brcmf_pub *drvr)  {  	brcmf_dbg(TRACE, "Enter\n");  	if (drvr) { -		/* Stop the protocol module */ -		brcmf_proto_stop(drvr); -  		/* Stop the bus module */  		brcmf_bus_stop(drvr->bus_if);  	} @@ -1183,6 +1024,8 @@ void brcmf_detach(struct device *dev)  	/* stop firmware event handling */  	brcmf_fweh_detach(drvr); +	brcmf_bus_change_state(bus_if, BRCMF_BUS_DOWN); +  	/* make sure primary interface removed last */  	for (i = BRCMF_MAX_IFS-1; i > -1; i--)  		if (drvr->iflist[i]) { @@ -1190,18 +1033,27 @@ void brcmf_detach(struct device *dev)  			brcmf_del_if(drvr, i);  		} -	brcmf_bus_detach(drvr); - -	if (drvr->prot) -		brcmf_proto_detach(drvr); +	brcmf_cfg80211_detach(drvr->config);  	brcmf_fws_deinit(drvr); +	brcmf_bus_detach(drvr); + +	brcmf_proto_detach(drvr); +  	brcmf_debugfs_detach(drvr);  	bus_if->drvr = NULL;  	kfree(drvr);  } +s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data, u32 len) +{ +	struct brcmf_bus *bus_if = dev_get_drvdata(dev); +	struct brcmf_if *ifp = bus_if->drvr->iflist[0]; + +	return brcmf_fil_iovar_data_set(ifp, name, data, len); +} +  static int brcmf_get_pend_8021x_cnt(struct brcmf_if *ifp)  {  	return atomic_read(&ifp->pend_8021x_cnt); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h deleted file mode 100644 index ef917988374..00000000000 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _BRCMF_PROTO_H_ -#define _BRCMF_PROTO_H_ - -/* - * Exported from the brcmf protocol module (brcmf_cdc) - */ - -/* Linkage, sets prot link and updates hdrlen in pub */ -extern int brcmf_proto_attach(struct brcmf_pub *drvr); - -/* Unlink, frees allocated protocol memory (including brcmf_proto) */ -extern void brcmf_proto_detach(struct brcmf_pub *drvr); - -/* Stop protocol: sync w/dongle state. */ -extern void brcmf_proto_stop(struct brcmf_pub *drvr); - -/* Add any protocol-specific data header. - * Caller must reserve prot_hdrlen prepend space. - */ -extern void brcmf_proto_hdrpush(struct brcmf_pub *, int ifidx, u8 offset, -				struct sk_buff *txp); - -/* Sets dongle media info (drv_version, mac address). */ -extern int brcmf_c_preinit_dcmds(struct brcmf_if *ifp); - -#endif				/* _BRCMF_PROTO_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 1aa75d5951b..8fa0dbbbda7 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -23,6 +23,7 @@  #include <linux/interrupt.h>  #include <linux/sched.h>  #include <linux/mmc/sdio.h> +#include <linux/mmc/sdio_ids.h>  #include <linux/mmc/sdio_func.h>  #include <linux/mmc/card.h>  #include <linux/semaphore.h> @@ -32,6 +33,7 @@  #include <linux/debugfs.h>  #include <linux/vmalloc.h>  #include <linux/platform_data/brcmfmac-sdio.h> +#include <linux/moduleparam.h>  #include <asm/unaligned.h>  #include <defs.h>  #include <brcmu_wifi.h> @@ -39,7 +41,8 @@  #include <brcm_hw_ids.h>  #include <soc.h>  #include "sdio_host.h" -#include "sdio_chip.h" +#include "chip.h" +#include "firmware.h"  #define DCMD_RESP_TIMEOUT  2000	/* In milli second */ @@ -152,6 +155,34 @@ struct rte_console {  /* manfid tuple length, include tuple, link bytes */  #define SBSDIO_CIS_MANFID_TUPLE_LEN	6 +#define CORE_BUS_REG(base, field) \ +		(base + offsetof(struct sdpcmd_regs, field)) + +/* SDIO function 1 register CHIPCLKCSR */ +/* Force ALP request to backplane */ +#define SBSDIO_FORCE_ALP		0x01 +/* Force HT request to backplane */ +#define SBSDIO_FORCE_HT			0x02 +/* Force ILP request to backplane */ +#define SBSDIO_FORCE_ILP		0x04 +/* Make ALP ready (power up xtal) */ +#define SBSDIO_ALP_AVAIL_REQ		0x08 +/* Make HT ready (power up PLL) */ +#define SBSDIO_HT_AVAIL_REQ		0x10 +/* Squelch clock requests from HW */ +#define SBSDIO_FORCE_HW_CLKREQ_OFF	0x20 +/* Status: ALP is ready */ +#define SBSDIO_ALP_AVAIL		0x40 +/* Status: HT is ready */ +#define SBSDIO_HT_AVAIL			0x80 +#define SBSDIO_CSR_MASK			0x1F +#define SBSDIO_AVBITS		(SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL) +#define SBSDIO_ALPAV(regval)	((regval) & SBSDIO_AVBITS) +#define SBSDIO_HTAV(regval)	(((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS) +#define SBSDIO_ALPONLY(regval)	(SBSDIO_ALPAV(regval) && !SBSDIO_HTAV(regval)) +#define SBSDIO_CLKAV(regval, alponly) \ +	(SBSDIO_ALPAV(regval) && (alponly ? 1 : SBSDIO_HTAV(regval))) +  /* intstatus */  #define I_SMB_SW0	(1 << 0)	/* To SB Mail S/W interrupt 0 */  #define I_SMB_SW1	(1 << 1)	/* To SB Mail S/W interrupt 1 */ @@ -257,9 +288,6 @@ struct rte_console {  #define MAX_HDR_READ	(1 << 6)  #define MAX_RX_DATASZ	2048 -/* Maximum milliseconds to wait for F2 to come up */ -#define BRCMF_WAIT_F2RDY	3000 -  /* Bump up limit on waiting for HT to account for first startup;   * if the image is doing a CRC calculation before programming the PMU   * for HT availability, it could take a couple hundred ms more, so @@ -275,12 +303,6 @@ struct rte_console {  /* Flags for SDH calls */  #define F2SYNC	(SDIO_REQ_4BYTE | SDIO_REQ_FIXED) -#define BRCMF_SDIO_FW_NAME	"brcm/brcmfmac-sdio.bin" -#define BRCMF_SDIO_NV_NAME	"brcm/brcmfmac-sdio.txt" -MODULE_FIRMWARE(BRCMF_SDIO_FW_NAME); -MODULE_FIRMWARE(BRCMF_SDIO_NV_NAME); - -#define BRCMF_IDLE_IMMEDIATE	(-1)	/* Enter idle immediately */  #define BRCMF_IDLE_ACTIVE	0	/* Do not request any SD clock change  					 * when idle  					 */ @@ -365,15 +387,15 @@ struct brcmf_sdio_hdrinfo {  	u16 len_left;  	u16 len_nxtfrm;  	u8 dat_offset; +	bool lastfrm; +	u16 tail_pad;  };  /* misc chip info needed by some of the routines */  /* Private data for SDIO bus interaction */  struct brcmf_sdio {  	struct brcmf_sdio_dev *sdiodev;	/* sdio device handler */ -	struct chip_info *ci;	/* Chip info struct */ -	char *vars;		/* Variables (from CIS and/or other) */ -	uint varsz;		/* Size of variables buffer */ +	struct brcmf_chip *ci;	/* Chip info struct */  	u32 ramsize;		/* Size of RAM in SOCRAM (bytes) */ @@ -389,7 +411,7 @@ struct brcmf_sdio {  	u8 tx_seq;		/* Transmit sequence number (next) */  	u8 tx_max;		/* Maximum transmit sequence allowed */ -	u8 hdrbuf[MAX_HDR_READ + BRCMF_SDALIGN]; +	u8 *hdrbuf;		/* buffer for handling rx frame */  	u8 *rxhdr;		/* Header of current rx frame (in hdrbuf) */  	u8 rx_seq;		/* Receive sequence number (expected) */  	struct brcmf_sdio_hdrinfo cur_read; @@ -437,10 +459,11 @@ struct brcmf_sdio {  	bool alp_only;		/* Don't use HT clock (ALP only) */  	u8 *ctrl_frame_buf; -	u32 ctrl_frame_len; +	u16 ctrl_frame_len;  	bool ctrl_frame_stat; -	spinlock_t txqlock; +	spinlock_t txq_lock;		/* protect bus->txq */ +	struct semaphore tx_seq_lock;	/* protect bus->tx_seq */  	wait_queue_head_t ctrl_wait;  	wait_queue_head_t dcmd_resp_wait; @@ -454,15 +477,15 @@ struct brcmf_sdio {  	struct work_struct datawork;  	atomic_t dpc_tskcnt; -	const struct firmware *firmware; -	u32 fw_ptr; -  	bool txoff;		/* Transmit flow-controlled */  	struct brcmf_sdio_count sdcnt;  	bool sr_enabled; /* SaveRestore enabled */  	bool sleeping; /* SDIO bus sleeping */  	u8 tx_hdrlen;		/* sdio bus header length for tx packet */ +	bool txglom;		/* host tx glomming enable flag */ +	u16 head_align;		/* buffer pointer alignment */ +	u16 sgentry_align;	/* scatter-gather buffer alignment */  };  /* clkstate */ @@ -493,6 +516,146 @@ enum brcmf_sdio_frmtype {  	BRCMF_SDIO_FT_SUB,  }; +#define SDIOD_DRVSTR_KEY(chip, pmu)     (((chip) << 16) | (pmu)) + +/* SDIO Pad drive strength to select value mappings */ +struct sdiod_drive_str { +	u8 strength;	/* Pad Drive Strength in mA */ +	u8 sel;		/* Chip-specific select value */ +}; + +/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8V) */ +static const struct sdiod_drive_str sdiod_drvstr_tab1_1v8[] = { +	{32, 0x6}, +	{26, 0x7}, +	{22, 0x4}, +	{16, 0x5}, +	{12, 0x2}, +	{8, 0x3}, +	{4, 0x0}, +	{0, 0x1} +}; + +/* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */ +static const struct sdiod_drive_str sdiod_drive_strength_tab5_1v8[] = { +	{6, 0x7}, +	{5, 0x6}, +	{4, 0x5}, +	{3, 0x4}, +	{2, 0x2}, +	{1, 0x1}, +	{0, 0x0} +}; + +/* SDIO Drive Strength to sel value table for PMU Rev 17 (1.8v) */ +static const struct sdiod_drive_str sdiod_drvstr_tab6_1v8[] = { +	{3, 0x3}, +	{2, 0x2}, +	{1, 0x1}, +	{0, 0x0} }; + +/* SDIO Drive Strength to sel value table for 43143 PMU Rev 17 (3.3V) */ +static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = { +	{16, 0x7}, +	{12, 0x5}, +	{8,  0x3}, +	{4,  0x1} +}; + +#define BCM43143_FIRMWARE_NAME		"brcm/brcmfmac43143-sdio.bin" +#define BCM43143_NVRAM_NAME		"brcm/brcmfmac43143-sdio.txt" +#define BCM43241B0_FIRMWARE_NAME	"brcm/brcmfmac43241b0-sdio.bin" +#define BCM43241B0_NVRAM_NAME		"brcm/brcmfmac43241b0-sdio.txt" +#define BCM43241B4_FIRMWARE_NAME	"brcm/brcmfmac43241b4-sdio.bin" +#define BCM43241B4_NVRAM_NAME		"brcm/brcmfmac43241b4-sdio.txt" +#define BCM4329_FIRMWARE_NAME		"brcm/brcmfmac4329-sdio.bin" +#define BCM4329_NVRAM_NAME		"brcm/brcmfmac4329-sdio.txt" +#define BCM4330_FIRMWARE_NAME		"brcm/brcmfmac4330-sdio.bin" +#define BCM4330_NVRAM_NAME		"brcm/brcmfmac4330-sdio.txt" +#define BCM4334_FIRMWARE_NAME		"brcm/brcmfmac4334-sdio.bin" +#define BCM4334_NVRAM_NAME		"brcm/brcmfmac4334-sdio.txt" +#define BCM4335_FIRMWARE_NAME		"brcm/brcmfmac4335-sdio.bin" +#define BCM4335_NVRAM_NAME		"brcm/brcmfmac4335-sdio.txt" +#define BCM43362_FIRMWARE_NAME		"brcm/brcmfmac43362-sdio.bin" +#define BCM43362_NVRAM_NAME		"brcm/brcmfmac43362-sdio.txt" +#define BCM4339_FIRMWARE_NAME		"brcm/brcmfmac4339-sdio.bin" +#define BCM4339_NVRAM_NAME		"brcm/brcmfmac4339-sdio.txt" +#define BCM4354_FIRMWARE_NAME		"brcm/brcmfmac4354-sdio.bin" +#define BCM4354_NVRAM_NAME		"brcm/brcmfmac4354-sdio.txt" + +MODULE_FIRMWARE(BCM43143_FIRMWARE_NAME); +MODULE_FIRMWARE(BCM43143_NVRAM_NAME); +MODULE_FIRMWARE(BCM43241B0_FIRMWARE_NAME); +MODULE_FIRMWARE(BCM43241B0_NVRAM_NAME); +MODULE_FIRMWARE(BCM43241B4_FIRMWARE_NAME); +MODULE_FIRMWARE(BCM43241B4_NVRAM_NAME); +MODULE_FIRMWARE(BCM4329_FIRMWARE_NAME); +MODULE_FIRMWARE(BCM4329_NVRAM_NAME); +MODULE_FIRMWARE(BCM4330_FIRMWARE_NAME); +MODULE_FIRMWARE(BCM4330_NVRAM_NAME); +MODULE_FIRMWARE(BCM4334_FIRMWARE_NAME); +MODULE_FIRMWARE(BCM4334_NVRAM_NAME); +MODULE_FIRMWARE(BCM4335_FIRMWARE_NAME); +MODULE_FIRMWARE(BCM4335_NVRAM_NAME); +MODULE_FIRMWARE(BCM43362_FIRMWARE_NAME); +MODULE_FIRMWARE(BCM43362_NVRAM_NAME); +MODULE_FIRMWARE(BCM4339_FIRMWARE_NAME); +MODULE_FIRMWARE(BCM4339_NVRAM_NAME); +MODULE_FIRMWARE(BCM4354_FIRMWARE_NAME); +MODULE_FIRMWARE(BCM4354_NVRAM_NAME); + +struct brcmf_firmware_names { +	u32 chipid; +	u32 revmsk; +	const char *bin; +	const char *nv; +}; + +enum brcmf_firmware_type { +	BRCMF_FIRMWARE_BIN, +	BRCMF_FIRMWARE_NVRAM +}; + +#define BRCMF_FIRMWARE_NVRAM(name) \ +	name ## _FIRMWARE_NAME, name ## _NVRAM_NAME + +static const struct brcmf_firmware_names brcmf_fwname_data[] = { +	{ BCM43143_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM43143) }, +	{ BCM43241_CHIP_ID, 0x0000001F, BRCMF_FIRMWARE_NVRAM(BCM43241B0) }, +	{ BCM43241_CHIP_ID, 0xFFFFFFE0, BRCMF_FIRMWARE_NVRAM(BCM43241B4) }, +	{ BCM4329_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4329) }, +	{ BCM4330_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4330) }, +	{ BCM4334_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4334) }, +	{ BCM4335_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4335) }, +	{ BCM43362_CHIP_ID, 0xFFFFFFFE, BRCMF_FIRMWARE_NVRAM(BCM43362) }, +	{ BCM4339_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4339) }, +	{ BCM4354_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4354) } +}; + +static const char *brcmf_sdio_get_fwname(struct brcmf_chip *ci, +					 enum brcmf_firmware_type type) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(brcmf_fwname_data); i++) { +		if (brcmf_fwname_data[i].chipid == ci->chip && +		    brcmf_fwname_data[i].revmsk & BIT(ci->chiprev)) { +			switch (type) { +			case BRCMF_FIRMWARE_BIN: +				return brcmf_fwname_data[i].bin; +			case BRCMF_FIRMWARE_NVRAM: +				return brcmf_fwname_data[i].nv; +			default: +				brcmf_err("invalid firmware type (%d)\n", type); +				return NULL; +			} +		} +	} +	brcmf_err("Unknown chipid %d [%d]\n", +		  ci->chip, ci->chiprev); +	return NULL; +} +  static void pkt_align(struct sk_buff *p, int len, int align)  {  	uint datalign; @@ -514,48 +677,41 @@ static bool data_ok(struct brcmf_sdio *bus)   * Reads a register in the SDIO hardware block. This block occupies a series of   * adresses on the 32 bit backplane bus.   */ -static int -r_sdreg32(struct brcmf_sdio *bus, u32 *regvar, u32 offset) +static int r_sdreg32(struct brcmf_sdio *bus, u32 *regvar, u32 offset)  { -	u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV); +	struct brcmf_core *core;  	int ret; -	*regvar = brcmf_sdio_regrl(bus->sdiodev, -				   bus->ci->c_inf[idx].base + offset, &ret); +	core = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV); +	*regvar = brcmf_sdiod_regrl(bus->sdiodev, core->base + offset, &ret);  	return ret;  } -static int -w_sdreg32(struct brcmf_sdio *bus, u32 regval, u32 reg_offset) +static int w_sdreg32(struct brcmf_sdio *bus, u32 regval, u32 reg_offset)  { -	u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV); +	struct brcmf_core *core;  	int ret; -	brcmf_sdio_regwl(bus->sdiodev, -			 bus->ci->c_inf[idx].base + reg_offset, -			 regval, &ret); +	core = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV); +	brcmf_sdiod_regwl(bus->sdiodev, core->base + reg_offset, regval, &ret);  	return ret;  }  static int -brcmf_sdbrcm_kso_control(struct brcmf_sdio *bus, bool on) +brcmf_sdio_kso_control(struct brcmf_sdio *bus, bool on)  {  	u8 wr_val = 0, rd_val, cmp_val, bmask;  	int err = 0;  	int try_cnt = 0; -	brcmf_dbg(TRACE, "Enter\n"); +	brcmf_dbg(TRACE, "Enter: on=%d\n", on);  	wr_val = (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);  	/* 1st KSO write goes to AOS wake up core if device is asleep  */ -	brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR, -			 wr_val, &err); -	if (err) { -		brcmf_err("SDIO_AOS KSO write error: %d\n", err); -		return err; -	} +	brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR, +			  wr_val, &err);  	if (on) {  		/* device WAKEUP through KSO: @@ -581,26 +737,30 @@ brcmf_sdbrcm_kso_control(struct brcmf_sdio *bus, bool on)  		 * just one write attempt may fail,  		 * read it back until it matches written value  		 */ -		rd_val = brcmf_sdio_regrb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR, -					  &err); +		rd_val = brcmf_sdiod_regrb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR, +					   &err);  		if (((rd_val & bmask) == cmp_val) && !err)  			break; -		brcmf_dbg(SDIO, "KSO wr/rd retry:%d (max: %d) ERR:%x\n", -			  try_cnt, MAX_KSO_ATTEMPTS, err); +  		udelay(KSO_WAIT_US); -		brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR, -				 wr_val, &err); +		brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR, +				  wr_val, &err);  	} while (try_cnt++ < MAX_KSO_ATTEMPTS); +	if (try_cnt > 2) +		brcmf_dbg(SDIO, "try_cnt=%d rd_val=0x%x err=%d\n", try_cnt, +			  rd_val, err); + +	if (try_cnt > MAX_KSO_ATTEMPTS) +		brcmf_err("max tries: rd_val=0x%x err=%d\n", rd_val, err); +  	return err;  } -#define PKT_AVAILABLE()		(intstatus & I_HMB_FRAME_IND) -  #define HOSTINTMASK		(I_HMB_SW_MASK | I_CHIPACTIVE)  /* Turn backplane clock on or off */ -static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok) +static int brcmf_sdio_htclk(struct brcmf_sdio *bus, bool on, bool pendok)  {  	int err;  	u8 clkctl, clkreq, devctl; @@ -620,16 +780,16 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)  		clkreq =  		    bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ; -		brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, -				 clkreq, &err); +		brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, +				  clkreq, &err);  		if (err) {  			brcmf_err("HT Avail request error: %d\n", err);  			return -EBADE;  		}  		/* Check current status */ -		clkctl = brcmf_sdio_regrb(bus->sdiodev, -					  SBSDIO_FUNC1_CHIPCLKCSR, &err); +		clkctl = brcmf_sdiod_regrb(bus->sdiodev, +					   SBSDIO_FUNC1_CHIPCLKCSR, &err);  		if (err) {  			brcmf_err("HT Avail read error: %d\n", err);  			return -EBADE; @@ -638,8 +798,8 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)  		/* Go to pending and await interrupt if appropriate */  		if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {  			/* Allow only clock-available interrupt */ -			devctl = brcmf_sdio_regrb(bus->sdiodev, -						  SBSDIO_DEVICE_CTL, &err); +			devctl = brcmf_sdiod_regrb(bus->sdiodev, +						   SBSDIO_DEVICE_CTL, &err);  			if (err) {  				brcmf_err("Devctl error setting CA: %d\n",  					  err); @@ -647,28 +807,28 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)  			}  			devctl |= SBSDIO_DEVCTL_CA_INT_ONLY; -			brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL, -					 devctl, &err); +			brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL, +					  devctl, &err);  			brcmf_dbg(SDIO, "CLKCTL: set PENDING\n");  			bus->clkstate = CLK_PENDING;  			return 0;  		} else if (bus->clkstate == CLK_PENDING) {  			/* Cancel CA-only interrupt filter */ -			devctl = brcmf_sdio_regrb(bus->sdiodev, -						  SBSDIO_DEVICE_CTL, &err); +			devctl = brcmf_sdiod_regrb(bus->sdiodev, +						   SBSDIO_DEVICE_CTL, &err);  			devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; -			brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL, -					 devctl, &err); +			brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL, +					  devctl, &err);  		}  		/* Otherwise, wait here (polling) for HT Avail */  		timeout = jiffies +  			  msecs_to_jiffies(PMU_MAX_TRANSITION_DLY/1000);  		while (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { -			clkctl = brcmf_sdio_regrb(bus->sdiodev, -						  SBSDIO_FUNC1_CHIPCLKCSR, -						  &err); +			clkctl = brcmf_sdiod_regrb(bus->sdiodev, +						   SBSDIO_FUNC1_CHIPCLKCSR, +						   &err);  			if (time_after(jiffies, timeout))  				break;  			else @@ -695,22 +855,21 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)  		}  #endif				/* defined (DEBUG) */ -		bus->activity = true;  	} else {  		clkreq = 0;  		if (bus->clkstate == CLK_PENDING) {  			/* Cancel CA-only interrupt filter */ -			devctl = brcmf_sdio_regrb(bus->sdiodev, -						  SBSDIO_DEVICE_CTL, &err); +			devctl = brcmf_sdiod_regrb(bus->sdiodev, +						   SBSDIO_DEVICE_CTL, &err);  			devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; -			brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL, -					 devctl, &err); +			brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL, +					  devctl, &err);  		}  		bus->clkstate = CLK_SDONLY; -		brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, -				 clkreq, &err); +		brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, +				  clkreq, &err);  		brcmf_dbg(SDIO, "CLKCTL: turned OFF\n");  		if (err) {  			brcmf_err("Failed access turning clock off: %d\n", @@ -722,7 +881,7 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)  }  /* Change idle/active SD state */ -static int brcmf_sdbrcm_sdclk(struct brcmf_sdio *bus, bool on) +static int brcmf_sdio_sdclk(struct brcmf_sdio *bus, bool on)  {  	brcmf_dbg(SDIO, "Enter\n"); @@ -735,7 +894,7 @@ static int brcmf_sdbrcm_sdclk(struct brcmf_sdio *bus, bool on)  }  /* Transition SD and backplane clock readiness */ -static int brcmf_sdbrcm_clkctl(struct brcmf_sdio *bus, uint target, bool pendok) +static int brcmf_sdio_clkctl(struct brcmf_sdio *bus, uint target, bool pendok)  {  #ifdef DEBUG  	uint oldstate = bus->clkstate; @@ -746,7 +905,7 @@ static int brcmf_sdbrcm_clkctl(struct brcmf_sdio *bus, uint target, bool pendok)  	/* Early exit if we're already there */  	if (bus->clkstate == target) {  		if (target == CLK_AVAIL) { -			brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); +			brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS);  			bus->activity = true;  		}  		return 0; @@ -756,32 +915,32 @@ static int brcmf_sdbrcm_clkctl(struct brcmf_sdio *bus, uint target, bool pendok)  	case CLK_AVAIL:  		/* Make sure SD clock is available */  		if (bus->clkstate == CLK_NONE) -			brcmf_sdbrcm_sdclk(bus, true); +			brcmf_sdio_sdclk(bus, true);  		/* Now request HT Avail on the backplane */ -		brcmf_sdbrcm_htclk(bus, true, pendok); -		brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); +		brcmf_sdio_htclk(bus, true, pendok); +		brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS);  		bus->activity = true;  		break;  	case CLK_SDONLY:  		/* Remove HT request, or bring up SD clock */  		if (bus->clkstate == CLK_NONE) -			brcmf_sdbrcm_sdclk(bus, true); +			brcmf_sdio_sdclk(bus, true);  		else if (bus->clkstate == CLK_AVAIL) -			brcmf_sdbrcm_htclk(bus, false, false); +			brcmf_sdio_htclk(bus, false, false);  		else  			brcmf_err("request for %d -> %d\n",  				  bus->clkstate, target); -		brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); +		brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS);  		break;  	case CLK_NONE:  		/* Make sure to remove HT request */  		if (bus->clkstate == CLK_AVAIL) -			brcmf_sdbrcm_htclk(bus, false, false); +			brcmf_sdio_htclk(bus, false, false);  		/* Now remove the SD clock */ -		brcmf_sdbrcm_sdclk(bus, false); -		brcmf_sdbrcm_wd_timer(bus, 0); +		brcmf_sdio_sdclk(bus, false); +		brcmf_sdio_wd_timer(bus, 0);  		break;  	}  #ifdef DEBUG @@ -792,11 +951,12 @@ static int brcmf_sdbrcm_clkctl(struct brcmf_sdio *bus, uint target, bool pendok)  }  static int -brcmf_sdbrcm_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok) +brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok)  {  	int err = 0; -	brcmf_dbg(TRACE, "Enter\n"); -	brcmf_dbg(SDIO, "request %s currently %s\n", +	u8 clkcsr; + +	brcmf_dbg(SDIO, "Enter: request %s currently %s\n",  		  (sleep ? "SLEEP" : "WAKE"),  		  (bus->sleeping ? "SLEEP" : "WAKE")); @@ -813,15 +973,27 @@ brcmf_sdbrcm_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok)  			    atomic_read(&bus->ipend) > 0 ||  			    (!atomic_read(&bus->fcstate) &&  			    brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && -			    data_ok(bus))) -				 return -EBUSY; -			err = brcmf_sdbrcm_kso_control(bus, false); +			    data_ok(bus))) { +				 err = -EBUSY; +				 goto done; +			} + +			clkcsr = brcmf_sdiod_regrb(bus->sdiodev, +						   SBSDIO_FUNC1_CHIPCLKCSR, +						   &err); +			if ((clkcsr & SBSDIO_CSR_MASK) == 0) { +				brcmf_dbg(SDIO, "no clock, set ALP\n"); +				brcmf_sdiod_regwb(bus->sdiodev, +						  SBSDIO_FUNC1_CHIPCLKCSR, +						  SBSDIO_ALP_AVAIL_REQ, &err); +			} +			err = brcmf_sdio_kso_control(bus, false);  			/* disable watchdog */  			if (!err) -				brcmf_sdbrcm_wd_timer(bus, 0); +				brcmf_sdio_wd_timer(bus, 0);  		} else {  			bus->idlecount = 0; -			err = brcmf_sdbrcm_kso_control(bus, true); +			err = brcmf_sdio_kso_control(bus, true);  		}  		if (!err) {  			/* Change state */ @@ -831,7 +1003,7 @@ brcmf_sdbrcm_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok)  		} else {  			brcmf_err("error while changing bus sleep state %d\n",  				  err); -			return err; +			goto done;  		}  	} @@ -839,16 +1011,97 @@ end:  	/* control clocks */  	if (sleep) {  		if (!bus->sr_enabled) -			brcmf_sdbrcm_clkctl(bus, CLK_NONE, pendok); +			brcmf_sdio_clkctl(bus, CLK_NONE, pendok);  	} else { -		brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, pendok); +		brcmf_sdio_clkctl(bus, CLK_AVAIL, pendok);  	} - +done: +	brcmf_dbg(SDIO, "Exit: err=%d\n", err);  	return err;  } -static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus) +#ifdef DEBUG +static inline bool brcmf_sdio_valid_shared_address(u32 addr) +{ +	return !(addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)); +} + +static int brcmf_sdio_readshared(struct brcmf_sdio *bus, +				 struct sdpcm_shared *sh) +{ +	u32 addr; +	int rv; +	u32 shaddr = 0; +	struct sdpcm_shared_le sh_le; +	__le32 addr_le; + +	shaddr = bus->ci->rambase + bus->ramsize - 4; + +	/* +	 * Read last word in socram to determine +	 * address of sdpcm_shared structure +	 */ +	sdio_claim_host(bus->sdiodev->func[1]); +	brcmf_sdio_bus_sleep(bus, false, false); +	rv = brcmf_sdiod_ramrw(bus->sdiodev, false, shaddr, (u8 *)&addr_le, 4); +	sdio_release_host(bus->sdiodev->func[1]); +	if (rv < 0) +		return rv; + +	addr = le32_to_cpu(addr_le); + +	brcmf_dbg(SDIO, "sdpcm_shared address 0x%08X\n", addr); + +	/* +	 * Check if addr is valid. +	 * NVRAM length at the end of memory should have been overwritten. +	 */ +	if (!brcmf_sdio_valid_shared_address(addr)) { +			brcmf_err("invalid sdpcm_shared address 0x%08X\n", +				  addr); +			return -EINVAL; +	} + +	/* Read hndrte_shared structure */ +	rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr, (u8 *)&sh_le, +			       sizeof(struct sdpcm_shared_le)); +	if (rv < 0) +		return rv; + +	/* Endianness */ +	sh->flags = le32_to_cpu(sh_le.flags); +	sh->trap_addr = le32_to_cpu(sh_le.trap_addr); +	sh->assert_exp_addr = le32_to_cpu(sh_le.assert_exp_addr); +	sh->assert_file_addr = le32_to_cpu(sh_le.assert_file_addr); +	sh->assert_line = le32_to_cpu(sh_le.assert_line); +	sh->console_addr = le32_to_cpu(sh_le.console_addr); +	sh->msgtrace_addr = le32_to_cpu(sh_le.msgtrace_addr); + +	if ((sh->flags & SDPCM_SHARED_VERSION_MASK) > SDPCM_SHARED_VERSION) { +		brcmf_err("sdpcm shared version unsupported: dhd %d dongle %d\n", +			  SDPCM_SHARED_VERSION, +			  sh->flags & SDPCM_SHARED_VERSION_MASK); +		return -EPROTO; +	} + +	return 0; +} + +static void brcmf_sdio_get_console_addr(struct brcmf_sdio *bus) +{ +	struct sdpcm_shared sh; + +	if (brcmf_sdio_readshared(bus, &sh) == 0) +		bus->console_addr = sh.console_addr; +} +#else +static void brcmf_sdio_get_console_addr(struct brcmf_sdio *bus) +{ +} +#endif /* DEBUG */ + +static u32 brcmf_sdio_hostmail(struct brcmf_sdio *bus)  {  	u32 intstatus = 0;  	u32 hmb_data; @@ -891,6 +1144,12 @@ static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus)  		else  			brcmf_dbg(SDIO, "Dongle ready, protocol version %d\n",  				  bus->sdpcm_ver); + +		/* +		 * Retrieve console state address now that firmware should have +		 * updated it. +		 */ +		brcmf_sdio_get_console_addr(bus);  	}  	/* @@ -924,7 +1183,7 @@ static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus)  	return intstatus;  } -static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx) +static void brcmf_sdio_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)  {  	uint retries = 0;  	u16 lastrbc; @@ -936,18 +1195,18 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)  		  rtx ? ", send NAK" : "");  	if (abort) -		brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); +		brcmf_sdiod_abort(bus->sdiodev, SDIO_FUNC_2); -	brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL, -			 SFC_RF_TERM, &err); +	brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL, +			  SFC_RF_TERM, &err);  	bus->sdcnt.f1regdata++;  	/* Wait until the packet has been flushed (device/FIFO stable) */  	for (lastrbc = retries = 0xffff; retries > 0; retries--) { -		hi = brcmf_sdio_regrb(bus->sdiodev, -				      SBSDIO_FUNC1_RFRAMEBCHI, &err); -		lo = brcmf_sdio_regrb(bus->sdiodev, -				      SBSDIO_FUNC1_RFRAMEBCLO, &err); +		hi = brcmf_sdiod_regrb(bus->sdiodev, +				       SBSDIO_FUNC1_RFRAMEBCHI, &err); +		lo = brcmf_sdiod_regrb(bus->sdiodev, +				       SBSDIO_FUNC1_RFRAMEBCLO, &err);  		bus->sdcnt.f1regdata += 2;  		if ((hi == 0) && (lo == 0)) @@ -977,14 +1236,32 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)  	/* Clear partial in any case */  	bus->cur_read.len = 0; +} -	/* If we can't reach the device, signal failure */ -	if (err) -		bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; +static void brcmf_sdio_txfail(struct brcmf_sdio *bus) +{ +	struct brcmf_sdio_dev *sdiodev = bus->sdiodev; +	u8 i, hi, lo; + +	/* On failure, abort the command and terminate the frame */ +	brcmf_err("sdio error, abort command and terminate frame\n"); +	bus->sdcnt.tx_sderrs++; + +	brcmf_sdiod_abort(sdiodev, SDIO_FUNC_2); +	brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM, NULL); +	bus->sdcnt.f1regdata++; + +	for (i = 0; i < 3; i++) { +		hi = brcmf_sdiod_regrb(sdiodev, SBSDIO_FUNC1_WFRAMEBCHI, NULL); +		lo = brcmf_sdiod_regrb(sdiodev, SBSDIO_FUNC1_WFRAMEBCLO, NULL); +		bus->sdcnt.f1regdata += 2; +		if ((hi == 0) && (lo == 0)) +			break; +	}  }  /* return total length of buffer chain */ -static uint brcmf_sdbrcm_glom_len(struct brcmf_sdio *bus) +static uint brcmf_sdio_glom_len(struct brcmf_sdio *bus)  {  	struct sk_buff *p;  	uint total; @@ -995,7 +1272,7 @@ static uint brcmf_sdbrcm_glom_len(struct brcmf_sdio *bus)  	return total;  } -static void brcmf_sdbrcm_free_glom(struct brcmf_sdio *bus) +static void brcmf_sdio_free_glom(struct brcmf_sdio *bus)  {  	struct sk_buff *cur, *next; @@ -1011,10 +1288,18 @@ static void brcmf_sdbrcm_free_glom(struct brcmf_sdio *bus)   * host and WiFi dongle which contains information needed for SDIO core and   * firmware   * - * It consists of 2 parts: hw header and software header + * It consists of 3 parts: hardware header, hardware extension header and + * software header   * hardware header (frame tag) - 4 bytes   * Byte 0~1: Frame length   * Byte 2~3: Checksum, bit-wise inverse of frame length + * hardware extension header - 8 bytes + * Tx glom mode only, N/A for Rx or normal Tx + * Byte 0~1: Packet length excluding hw frame tag + * Byte 2: Reserved + * Byte 3: Frame flags, bit 0: last frame indication + * Byte 4~5: Reserved + * Byte 6~7: Tail padding length   * software header - 8 bytes   * Byte 0: Rx/Tx sequence number   * Byte 1: 4 MSB Channel number, 4 LSB arbitrary flag @@ -1025,6 +1310,7 @@ static void brcmf_sdbrcm_free_glom(struct brcmf_sdio *bus)   * Byte 6~7: Reserved   */  #define SDPCM_HWHDR_LEN			4 +#define SDPCM_HWEXT_LEN			8  #define SDPCM_SWHDR_LEN			8  #define SDPCM_HDRLEN			(SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN)  /* software header */ @@ -1061,6 +1347,8 @@ static int brcmf_sdio_hdparse(struct brcmf_sdio *bus, u8 *header,  	u8 rx_seq, fc, tx_seq_max;  	u32 swheader; +	trace_brcmf_sdpcm_hdr(SDPCM_RX, header); +  	/* hw header */  	len = get_unaligned_le16(header);  	checksum = get_unaligned_le16(header + sizeof(u16)); @@ -1072,7 +1360,7 @@ static int brcmf_sdio_hdparse(struct brcmf_sdio *bus, u8 *header,  	if ((u16)(~(len ^ checksum))) {  		brcmf_err("HW header checksum error\n");  		bus->sdcnt.rx_badhdr++; -		brcmf_sdbrcm_rxfail(bus, false, false); +		brcmf_sdio_rxfail(bus, false, false);  		return -EIO;  	}  	if (len < SDPCM_HDRLEN) { @@ -1104,7 +1392,7 @@ static int brcmf_sdio_hdparse(struct brcmf_sdio *bus, u8 *header,  	    type != BRCMF_SDIO_FT_SUPER) {  		brcmf_err("HW header length too long\n");  		bus->sdcnt.rx_toolong++; -		brcmf_sdbrcm_rxfail(bus, false, false); +		brcmf_sdio_rxfail(bus, false, false);  		rd->len = 0;  		return -EPROTO;  	} @@ -1123,7 +1411,7 @@ static int brcmf_sdio_hdparse(struct brcmf_sdio *bus, u8 *header,  	if (rd->dat_offset < SDPCM_HDRLEN || rd->dat_offset > rd->len) {  		brcmf_err("seq %d: bad data offset\n", rx_seq);  		bus->sdcnt.rx_badhdr++; -		brcmf_sdbrcm_rxfail(bus, false, false); +		brcmf_sdio_rxfail(bus, false, false);  		rd->len = 0;  		return -ENXIO;  	} @@ -1172,24 +1460,34 @@ static inline void brcmf_sdio_update_hwhdr(u8 *header, u16 frm_length)  static void brcmf_sdio_hdpack(struct brcmf_sdio *bus, u8 *header,  			      struct brcmf_sdio_hdrinfo *hd_info)  { -	u32 sw_header; +	u32 hdrval; +	u8 hdr_offset;  	brcmf_sdio_update_hwhdr(header, hd_info->len); - -	sw_header = bus->tx_seq; -	sw_header |= (hd_info->channel << SDPCM_CHANNEL_SHIFT) & -		     SDPCM_CHANNEL_MASK; -	sw_header |= (hd_info->dat_offset << SDPCM_DOFFSET_SHIFT) & -		     SDPCM_DOFFSET_MASK; -	*(((__le32 *)header) + 1) = cpu_to_le32(sw_header); -	*(((__le32 *)header) + 2) = 0; +	hdr_offset = SDPCM_HWHDR_LEN; + +	if (bus->txglom) { +		hdrval = (hd_info->len - hdr_offset) | (hd_info->lastfrm << 24); +		*((__le32 *)(header + hdr_offset)) = cpu_to_le32(hdrval); +		hdrval = (u16)hd_info->tail_pad << 16; +		*(((__le32 *)(header + hdr_offset)) + 1) = cpu_to_le32(hdrval); +		hdr_offset += SDPCM_HWEXT_LEN; +	} + +	hdrval = hd_info->seq_num; +	hdrval |= (hd_info->channel << SDPCM_CHANNEL_SHIFT) & +		  SDPCM_CHANNEL_MASK; +	hdrval |= (hd_info->dat_offset << SDPCM_DOFFSET_SHIFT) & +		  SDPCM_DOFFSET_MASK; +	*((__le32 *)(header + hdr_offset)) = cpu_to_le32(hdrval); +	*(((__le32 *)(header + hdr_offset)) + 1) = 0; +	trace_brcmf_sdpcm_hdr(SDPCM_TX + !!(bus->txglom), header);  } -static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) +static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq)  {  	u16 dlen, totlen;  	u8 *dptr, num = 0; -	u32 align = 0;  	u16 sublen;  	struct sk_buff *pfirst, *pnext; @@ -1204,11 +1502,6 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  	brcmf_dbg(SDIO, "start: glomd %p glom %p\n",  		  bus->glomd, skb_peek(&bus->glom)); -	if (bus->sdiodev->pdata) -		align = bus->sdiodev->pdata->sd_sgentry_align; -	if (align < 4) -		align = 4; -  	/* If there's a descriptor, generate the packet chain */  	if (bus->glomd) {  		pfirst = pnext = NULL; @@ -1232,9 +1525,9 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  				pnext = NULL;  				break;  			} -			if (sublen % align) { +			if (sublen % bus->sgentry_align) {  				brcmf_err("sublen %d not multiple of %d\n", -					  sublen, align); +					  sublen, bus->sgentry_align);  			}  			totlen += sublen; @@ -1247,7 +1540,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 + align); +			pnext = brcmu_pkt_buf_get_skb(sublen + bus->sgentry_align);  			if (pnext == NULL) {  				brcmf_err("bcm_pkt_buf_get_skb failed, num %d len %d\n",  					  num, sublen); @@ -1256,7 +1549,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  			skb_queue_tail(&bus->glom, pnext);  			/* Adhere to start alignment requirements */ -			pkt_align(pnext, sublen, align); +			pkt_align(pnext, sublen, bus->sgentry_align);  		}  		/* If all allocations succeeded, save packet chain @@ -1271,7 +1564,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  			}  			pfirst = pnext = NULL;  		} else { -			brcmf_sdbrcm_free_glom(bus); +			brcmf_sdio_free_glom(bus);  			num = 0;  		} @@ -1294,16 +1587,15 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  		}  		pfirst = skb_peek(&bus->glom); -		dlen = (u16) brcmf_sdbrcm_glom_len(bus); +		dlen = (u16) brcmf_sdio_glom_len(bus);  		/* Do an SDIO read for the superframe.  Configurable iovar to  		 * read directly into the chained packet, or allocate a large  		 * packet and and copy into the chain.  		 */  		sdio_claim_host(bus->sdiodev->func[1]); -		errcode = brcmf_sdcard_recv_chain(bus->sdiodev, -				bus->sdiodev->sbwad, -				SDIO_FUNC_2, F2SYNC, &bus->glom); +		errcode = brcmf_sdiod_recv_chain(bus->sdiodev, +						 &bus->glom, dlen);  		sdio_release_host(bus->sdiodev->func[1]);  		bus->sdcnt.f2rxdata++; @@ -1314,12 +1606,12 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  			sdio_claim_host(bus->sdiodev->func[1]);  			if (bus->glomerr++ < 3) { -				brcmf_sdbrcm_rxfail(bus, true, true); +				brcmf_sdio_rxfail(bus, true, true);  			} else {  				bus->glomerr = 0; -				brcmf_sdbrcm_rxfail(bus, true, false); +				brcmf_sdio_rxfail(bus, true, false);  				bus->sdcnt.rxglomfail++; -				brcmf_sdbrcm_free_glom(bus); +				brcmf_sdio_free_glom(bus);  			}  			sdio_release_host(bus->sdiodev->func[1]);  			return 0; @@ -1367,12 +1659,12 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  			if (bus->glomerr++ < 3) {  				/* Restore superframe header space */  				skb_push(pfirst, sfdoff); -				brcmf_sdbrcm_rxfail(bus, true, true); +				brcmf_sdio_rxfail(bus, true, true);  			} else {  				bus->glomerr = 0; -				brcmf_sdbrcm_rxfail(bus, true, false); +				brcmf_sdio_rxfail(bus, true, false);  				bus->sdcnt.rxglomfail++; -				brcmf_sdbrcm_free_glom(bus); +				brcmf_sdio_free_glom(bus);  			}  			sdio_release_host(bus->sdiodev->func[1]);  			bus->cur_read.len = 0; @@ -1406,19 +1698,18 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)  					   bus->glom.qlen, pfirst, pfirst->data,  					   pfirst->len, pfirst->next,  					   pfirst->prev); +			skb_unlink(pfirst, &bus->glom); +			brcmf_rx_frame(bus->sdiodev->dev, pfirst); +			bus->sdcnt.rxglompkts++;  		} -		/* sent any remaining packets up */ -		if (bus->glom.qlen) -			brcmf_rx_frames(bus->sdiodev->dev, &bus->glom);  		bus->sdcnt.rxglomframes++; -		bus->sdcnt.rxglompkts += bus->glom.qlen;  	}  	return num;  } -static int brcmf_sdbrcm_dcmd_resp_wait(struct brcmf_sdio *bus, uint *condition, -					bool *pending) +static int brcmf_sdio_dcmd_resp_wait(struct brcmf_sdio *bus, uint *condition, +				     bool *pending)  {  	DECLARE_WAITQUEUE(wait, current);  	int timeout = msecs_to_jiffies(DCMD_RESP_TIMEOUT); @@ -1439,7 +1730,7 @@ static int brcmf_sdbrcm_dcmd_resp_wait(struct brcmf_sdio *bus, uint *condition,  	return timeout;  } -static int brcmf_sdbrcm_dcmd_resp_wake(struct brcmf_sdio *bus) +static int brcmf_sdio_dcmd_resp_wake(struct brcmf_sdio *bus)  {  	if (waitqueue_active(&bus->dcmd_resp_wait))  		wake_up_interruptible(&bus->dcmd_resp_wait); @@ -1447,7 +1738,7 @@ static int brcmf_sdbrcm_dcmd_resp_wake(struct brcmf_sdio *bus)  	return 0;  }  static void -brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff) +brcmf_sdio_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)  {  	uint rdlen, pad;  	u8 *buf = NULL, *rbuf; @@ -1461,9 +1752,9 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)  		goto done;  	rbuf = bus->rxbuf; -	pad = ((unsigned long)rbuf % BRCMF_SDALIGN); +	pad = ((unsigned long)rbuf % bus->head_align);  	if (pad) -		rbuf += (BRCMF_SDALIGN - pad); +		rbuf += (bus->head_align - pad);  	/* Copy the already-read portion over */  	memcpy(buf, hdr, BRCMF_FIRSTREAD); @@ -1477,19 +1768,15 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)  		if ((pad <= bus->roundup) && (pad < bus->blocksize) &&  		    ((len + pad) < bus->sdiodev->bus_if->maxctl))  			rdlen += pad; -	} else if (rdlen % BRCMF_SDALIGN) { -		rdlen += BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN); +	} else if (rdlen % bus->head_align) { +		rdlen += bus->head_align - (rdlen % bus->head_align);  	} -	/* Satisfy length-alignment requirements */ -	if (rdlen & (ALIGNMENT - 1)) -		rdlen = roundup(rdlen, ALIGNMENT); -  	/* Drop if the read is too big or it exceeds our maximum */  	if ((rdlen + BRCMF_FIRSTREAD) > bus->sdiodev->bus_if->maxctl) {  		brcmf_err("%d-byte control read exceeds %d-byte buffer\n",  			  rdlen, bus->sdiodev->bus_if->maxctl); -		brcmf_sdbrcm_rxfail(bus, false, false); +		brcmf_sdio_rxfail(bus, false, false);  		goto done;  	} @@ -1497,15 +1784,12 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)  		brcmf_err("%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",  			  len, len - doff, bus->sdiodev->bus_if->maxctl);  		bus->sdcnt.rx_toolong++; -		brcmf_sdbrcm_rxfail(bus, false, false); +		brcmf_sdio_rxfail(bus, false, false);  		goto done;  	}  	/* Read remain of frame body */ -	sdret = brcmf_sdcard_recv_buf(bus->sdiodev, -				bus->sdiodev->sbwad, -				SDIO_FUNC_2, -				F2SYNC, rbuf, rdlen); +	sdret = brcmf_sdiod_recv_buf(bus->sdiodev, rbuf, rdlen);  	bus->sdcnt.f2rxdata++;  	/* Control frame failures need retransmission */ @@ -1513,7 +1797,7 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)  		brcmf_err("read %d control bytes failed: %d\n",  			  rdlen, sdret);  		bus->sdcnt.rxc_errors++; -		brcmf_sdbrcm_rxfail(bus, true, true); +		brcmf_sdio_rxfail(bus, true, true);  		goto done;  	} else  		memcpy(buf + BRCMF_FIRSTREAD, rbuf, rdlen); @@ -1538,26 +1822,25 @@ gotpkt:  done:  	/* Awake any waiters */ -	brcmf_sdbrcm_dcmd_resp_wake(bus); +	brcmf_sdio_dcmd_resp_wake(bus);  }  /* Pad read to blocksize for efficiency */ -static void brcmf_pad(struct brcmf_sdio *bus, u16 *pad, u16 *rdlen) +static void brcmf_sdio_pad(struct brcmf_sdio *bus, u16 *pad, u16 *rdlen)  {  	if (bus->roundup && bus->blocksize && *rdlen > bus->blocksize) {  		*pad = bus->blocksize - (*rdlen % bus->blocksize);  		if (*pad <= bus->roundup && *pad < bus->blocksize &&  		    *rdlen + *pad + BRCMF_FIRSTREAD < MAX_RX_DATASZ)  			*rdlen += *pad; -	} else if (*rdlen % BRCMF_SDALIGN) { -		*rdlen += BRCMF_SDALIGN - (*rdlen % BRCMF_SDALIGN); +	} else if (*rdlen % bus->head_align) { +		*rdlen += bus->head_align - (*rdlen % bus->head_align);  	}  }  static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  {  	struct sk_buff *pkt;		/* Packet for event or data frames */ -	struct sk_buff_head pktlist;	/* needed for bus interface */  	u16 pad;		/* Number of pad bytes to read */  	uint rxleft = 0;	/* Remaining number of frames allowed */  	int ret;		/* Return code from calls */ @@ -1571,8 +1854,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  	bus->rxpending = true;  	for (rd->seq_num = bus->rx_seq, rxleft = maxframes; -	     !bus->rxskip && rxleft && -	     bus->sdiodev->bus_if->state != BRCMF_BUS_DOWN; +	     !bus->rxskip && rxleft && brcmf_bus_ready(bus->sdiodev->bus_if);  	     rd->seq_num++, rxleft--) {  		/* Handle glomming separately */ @@ -1580,7 +1862,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  			u8 cnt;  			brcmf_dbg(GLOM, "calling rxglom: glomd %p, glom %p\n",  				  bus->glomd, skb_peek(&bus->glom)); -			cnt = brcmf_sdbrcm_rxglom(bus, rd->seq_num); +			cnt = brcmf_sdio_rxglom(bus, rd->seq_num);  			brcmf_dbg(GLOM, "rxglom returned %d\n", cnt);  			rd->seq_num += cnt - 1;  			rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1; @@ -1591,17 +1873,14 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  		/* read header first for unknow frame length */  		sdio_claim_host(bus->sdiodev->func[1]);  		if (!rd->len) { -			ret = brcmf_sdcard_recv_buf(bus->sdiodev, -						      bus->sdiodev->sbwad, -						      SDIO_FUNC_2, F2SYNC, -						      bus->rxhdr, -						      BRCMF_FIRSTREAD); +			ret = brcmf_sdiod_recv_buf(bus->sdiodev, +						   bus->rxhdr, BRCMF_FIRSTREAD);  			bus->sdcnt.f2rxhdrs++;  			if (ret < 0) {  				brcmf_err("RXHEADER FAILED: %d\n",  					  ret);  				bus->sdcnt.rx_hdrfail++; -				brcmf_sdbrcm_rxfail(bus, true, true); +				brcmf_sdio_rxfail(bus, true, true);  				sdio_release_host(bus->sdiodev->func[1]);  				continue;  			} @@ -1620,9 +1899,9 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  			}  			if (rd->channel == SDPCM_CONTROL_CHANNEL) { -				brcmf_sdbrcm_read_control(bus, bus->rxhdr, -							  rd->len, -							  rd->dat_offset); +				brcmf_sdio_read_control(bus, bus->rxhdr, +							rd->len, +							rd->dat_offset);  				/* prepare the descriptor for the next read */  				rd->len = rd->len_nxtfrm << 4;  				rd->len_nxtfrm = 0; @@ -1636,23 +1915,22 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  			head_read = BRCMF_FIRSTREAD;  		} -		brcmf_pad(bus, &pad, &rd->len_left); +		brcmf_sdio_pad(bus, &pad, &rd->len_left);  		pkt = brcmu_pkt_buf_get_skb(rd->len_left + head_read + -					    BRCMF_SDALIGN); +					    bus->head_align);  		if (!pkt) {  			/* Give up on data, request rtx of events */  			brcmf_err("brcmu_pkt_buf_get_skb failed\n"); -			brcmf_sdbrcm_rxfail(bus, false, +			brcmf_sdio_rxfail(bus, false,  					    RETRYCHAN(rd->channel));  			sdio_release_host(bus->sdiodev->func[1]);  			continue;  		}  		skb_pull(pkt, head_read); -		pkt_align(pkt, rd->len_left, BRCMF_SDALIGN); +		pkt_align(pkt, rd->len_left, bus->head_align); -		ret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad, -					      SDIO_FUNC_2, F2SYNC, pkt); +		ret = brcmf_sdiod_recv_pkt(bus->sdiodev, pkt);  		bus->sdcnt.f2rxdata++;  		sdio_release_host(bus->sdiodev->func[1]); @@ -1661,7 +1939,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  				  rd->len, rd->channel, ret);  			brcmu_pkt_buf_free_skb(pkt);  			sdio_claim_host(bus->sdiodev->func[1]); -			brcmf_sdbrcm_rxfail(bus, true, +			brcmf_sdio_rxfail(bus, true,  					    RETRYCHAN(rd->channel));  			sdio_release_host(bus->sdiodev->func[1]);  			continue; @@ -1686,7 +1964,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  					  rd->len,  					  roundup(rd_new.len, 16) >> 4);  				rd->len = 0; -				brcmf_sdbrcm_rxfail(bus, true, true); +				brcmf_sdio_rxfail(bus, true, true);  				sdio_release_host(bus->sdiodev->func[1]);  				brcmu_pkt_buf_free_skb(pkt);  				continue; @@ -1708,7 +1986,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  				/* Force retry w/normal header read */  				rd->len = 0;  				sdio_claim_host(bus->sdiodev->func[1]); -				brcmf_sdbrcm_rxfail(bus, false, true); +				brcmf_sdio_rxfail(bus, false, true);  				sdio_release_host(bus->sdiodev->func[1]);  				brcmu_pkt_buf_free_skb(pkt);  				continue; @@ -1733,7 +2011,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  				brcmf_err("%s: glom superframe w/o "  					  "descriptor!\n", __func__);  				sdio_claim_host(bus->sdiodev->func[1]); -				brcmf_sdbrcm_rxfail(bus, false, false); +				brcmf_sdio_rxfail(bus, false, false);  				sdio_release_host(bus->sdiodev->func[1]);  			}  			/* prepare the descriptor for the next read */ @@ -1759,9 +2037,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  			continue;  		} -		skb_queue_head_init(&pktlist); -		skb_queue_tail(&pktlist, pkt); -		brcmf_rx_frames(bus->sdiodev->dev, &pktlist); +		brcmf_rx_frame(bus->sdiodev->dev, pkt);  	}  	rxcount = maxframes - rxleft; @@ -1779,17 +2055,101 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)  }  static void -brcmf_sdbrcm_wait_event_wakeup(struct brcmf_sdio *bus) +brcmf_sdio_wait_event_wakeup(struct brcmf_sdio *bus)  {  	if (waitqueue_active(&bus->ctrl_wait))  		wake_up_interruptible(&bus->ctrl_wait);  	return;  } +static int brcmf_sdio_txpkt_hdalign(struct brcmf_sdio *bus, struct sk_buff *pkt) +{ +	u16 head_pad; +	u8 *dat_buf; + +	dat_buf = (u8 *)(pkt->data); + +	/* Check head padding */ +	head_pad = ((unsigned long)dat_buf % bus->head_align); +	if (head_pad) { +		if (skb_headroom(pkt) < head_pad) { +			bus->sdiodev->bus_if->tx_realloc++; +			head_pad = 0; +			if (skb_cow(pkt, head_pad)) +				return -ENOMEM; +		} +		skb_push(pkt, head_pad); +		dat_buf = (u8 *)(pkt->data); +		memset(dat_buf, 0, head_pad + bus->tx_hdrlen); +	} +	return head_pad; +} + +/** + * struct brcmf_skbuff_cb reserves first two bytes in sk_buff::cb for + * bus layer usage. + */  /* flag marking a dummy skb added for DMA alignment requirement */ -#define DUMMY_SKB_FLAG		0x10000 +#define ALIGN_SKB_FLAG		0x8000  /* bit mask of data length chopped from the previous packet */ -#define DUMMY_SKB_CHOP_LEN_MASK	0xffff +#define ALIGN_SKB_CHOP_LEN_MASK	0x7fff + +static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio *bus, +				    struct sk_buff_head *pktq, +				    struct sk_buff *pkt, u16 total_len) +{ +	struct brcmf_sdio_dev *sdiodev; +	struct sk_buff *pkt_pad; +	u16 tail_pad, tail_chop, chain_pad; +	unsigned int blksize; +	bool lastfrm; +	int ntail, ret; + +	sdiodev = bus->sdiodev; +	blksize = sdiodev->func[SDIO_FUNC_2]->cur_blksize; +	/* sg entry alignment should be a divisor of block size */ +	WARN_ON(blksize % bus->sgentry_align); + +	/* Check tail padding */ +	lastfrm = skb_queue_is_last(pktq, pkt); +	tail_pad = 0; +	tail_chop = pkt->len % bus->sgentry_align; +	if (tail_chop) +		tail_pad = bus->sgentry_align - tail_chop; +	chain_pad = (total_len + tail_pad) % blksize; +	if (lastfrm && chain_pad) +		tail_pad += blksize - chain_pad; +	if (skb_tailroom(pkt) < tail_pad && pkt->len > blksize) { +		pkt_pad = brcmu_pkt_buf_get_skb(tail_pad + tail_chop + +						bus->head_align); +		if (pkt_pad == NULL) +			return -ENOMEM; +		ret = brcmf_sdio_txpkt_hdalign(bus, pkt_pad); +		if (unlikely(ret < 0)) { +			kfree_skb(pkt_pad); +			return ret; +		} +		memcpy(pkt_pad->data, +		       pkt->data + pkt->len - tail_chop, +		       tail_chop); +		*(u16 *)(pkt_pad->cb) = ALIGN_SKB_FLAG + tail_chop; +		skb_trim(pkt, pkt->len - tail_chop); +		skb_trim(pkt_pad, tail_pad + tail_chop); +		__skb_queue_after(pktq, pkt, pkt_pad); +	} else { +		ntail = pkt->data_len + tail_pad - +			(pkt->end - pkt->tail); +		if (skb_cloned(pkt) || ntail > 0) +			if (pskb_expand_head(pkt, 0, ntail, GFP_ATOMIC)) +				return -ENOMEM; +		if (skb_linearize(pkt)) +			return -ENOMEM; +		__skb_put(pkt, tail_pad); +	} + +	return tail_pad; +} +  /**   * brcmf_sdio_txpkt_prep - packet preparation for transmit   * @bus: brcmf_sdio structure pointer @@ -1806,86 +2166,66 @@ static int  brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq,  		      uint chan)  { -	u16 head_pad, tail_pad, tail_chop, head_align, sg_align; -	int ntail; -	struct sk_buff *pkt_next, *pkt_new; -	u8 *dat_buf; -	unsigned blksize = bus->sdiodev->func[SDIO_FUNC_2]->cur_blksize; +	u16 head_pad, total_len; +	struct sk_buff *pkt_next; +	u8 txseq; +	int ret;  	struct brcmf_sdio_hdrinfo hd_info = {0}; -	/* SDIO ADMA requires at least 32 bit alignment */ -	head_align = 4; -	sg_align = 4; -	if (bus->sdiodev->pdata) { -		head_align = bus->sdiodev->pdata->sd_head_align > 4 ? -			     bus->sdiodev->pdata->sd_head_align : 4; -		sg_align = bus->sdiodev->pdata->sd_sgentry_align > 4 ? -			   bus->sdiodev->pdata->sd_sgentry_align : 4; -	} -	/* sg entry alignment should be a divisor of block size */ -	WARN_ON(blksize % sg_align); - -	pkt_next = pktq->next; -	dat_buf = (u8 *)(pkt_next->data); +	txseq = bus->tx_seq; +	total_len = 0; +	skb_queue_walk(pktq, pkt_next) { +		/* alignment packet inserted in previous +		 * loop cycle can be skipped as it is +		 * already properly aligned and does not +		 * need an sdpcm header. +		 */ +		if (*(u16 *)(pkt_next->cb) & ALIGN_SKB_FLAG) +			continue; -	/* Check head padding */ -	head_pad = ((unsigned long)dat_buf % head_align); -	if (head_pad) { -		if (skb_headroom(pkt_next) < head_pad) { -			bus->sdiodev->bus_if->tx_realloc++; -			head_pad = 0; -			if (skb_cow(pkt_next, head_pad)) -				return -ENOMEM; +		/* align packet data pointer */ +		ret = brcmf_sdio_txpkt_hdalign(bus, pkt_next); +		if (ret < 0) +			return ret; +		head_pad = (u16)ret; +		if (head_pad) +			memset(pkt_next->data + bus->tx_hdrlen, 0, head_pad); + +		total_len += pkt_next->len; + +		hd_info.len = pkt_next->len; +		hd_info.lastfrm = skb_queue_is_last(pktq, pkt_next); +		if (bus->txglom && pktq->qlen > 1) { +			ret = brcmf_sdio_txpkt_prep_sg(bus, pktq, +						       pkt_next, total_len); +			if (ret < 0) +				return ret; +			hd_info.tail_pad = (u16)ret; +			total_len += (u16)ret;  		} -		skb_push(pkt_next, head_pad); -		dat_buf = (u8 *)(pkt_next->data); -		memset(dat_buf, 0, head_pad + bus->tx_hdrlen); -	} - -	/* Check tail padding */ -	pkt_new = NULL; -	tail_chop = pkt_next->len % sg_align; -	tail_pad = sg_align - tail_chop; -	tail_pad += blksize - (pkt_next->len + tail_pad) % blksize; -	if (skb_tailroom(pkt_next) < tail_pad && pkt_next->len > blksize) { -		pkt_new = brcmu_pkt_buf_get_skb(tail_pad + tail_chop); -		if (pkt_new == NULL) -			return -ENOMEM; -		memcpy(pkt_new->data, -		       pkt_next->data + pkt_next->len - tail_chop, -		       tail_chop); -		*(u32 *)(pkt_new->cb) = DUMMY_SKB_FLAG + tail_chop; -		skb_trim(pkt_next, pkt_next->len - tail_chop); -		__skb_queue_after(pktq, pkt_next, pkt_new); -	} else { -		ntail = pkt_next->data_len + tail_pad - -			(pkt_next->end - pkt_next->tail); -		if (skb_cloned(pkt_next) || ntail > 0) -			if (pskb_expand_head(pkt_next, 0, ntail, GFP_ATOMIC)) -				return -ENOMEM; -		if (skb_linearize(pkt_next)) -			return -ENOMEM; -		dat_buf = (u8 *)(pkt_next->data); -		__skb_put(pkt_next, tail_pad); -	} - -	/* Now prep the header */ -	if (pkt_new) -		hd_info.len = pkt_next->len + tail_chop; -	else -		hd_info.len = pkt_next->len - tail_pad; -	hd_info.channel = chan; -	hd_info.dat_offset = head_pad + bus->tx_hdrlen; -	brcmf_sdio_hdpack(bus, dat_buf, &hd_info); - -	if (BRCMF_BYTES_ON() && -	    ((BRCMF_CTL_ON() && chan == SDPCM_CONTROL_CHANNEL) || -	     (BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL))) -		brcmf_dbg_hex_dump(true, pkt_next, hd_info.len, "Tx Frame:\n"); -	else if (BRCMF_HDRS_ON()) -		brcmf_dbg_hex_dump(true, pkt_next, head_pad + bus->tx_hdrlen, -				   "Tx Header:\n"); +		hd_info.channel = chan; +		hd_info.dat_offset = head_pad + bus->tx_hdrlen; +		hd_info.seq_num = txseq++; + +		/* Now fill the header */ +		brcmf_sdio_hdpack(bus, pkt_next->data, &hd_info); + +		if (BRCMF_BYTES_ON() && +		    ((BRCMF_CTL_ON() && chan == SDPCM_CONTROL_CHANNEL) || +		     (BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL))) +			brcmf_dbg_hex_dump(true, pkt_next->data, hd_info.len, +					   "Tx Frame:\n"); +		else if (BRCMF_HDRS_ON()) +			brcmf_dbg_hex_dump(true, pkt_next->data, +					   head_pad + bus->tx_hdrlen, +					   "Tx Header:\n"); +	} +	/* Hardware length tag of the first packet should be total +	 * length of the chain (including padding) +	 */ +	if (bus->txglom) +		brcmf_sdio_update_hwhdr(pktq->next->data, total_len);  	return 0;  } @@ -1903,113 +2243,113 @@ brcmf_sdio_txpkt_postp(struct brcmf_sdio *bus, struct sk_buff_head *pktq)  {  	u8 *hdr;  	u32 dat_offset; -	u32 dummy_flags, chop_len; +	u16 tail_pad; +	u16 dummy_flags, chop_len;  	struct sk_buff *pkt_next, *tmp, *pkt_prev;  	skb_queue_walk_safe(pktq, pkt_next, tmp) { -		dummy_flags = *(u32 *)(pkt_next->cb); -		if (dummy_flags & DUMMY_SKB_FLAG) { -			chop_len = dummy_flags & DUMMY_SKB_CHOP_LEN_MASK; +		dummy_flags = *(u16 *)(pkt_next->cb); +		if (dummy_flags & ALIGN_SKB_FLAG) { +			chop_len = dummy_flags & ALIGN_SKB_CHOP_LEN_MASK;  			if (chop_len) {  				pkt_prev = pkt_next->prev; -				memcpy(pkt_prev->data + pkt_prev->len, -				       pkt_next->data, chop_len);  				skb_put(pkt_prev, chop_len);  			}  			__skb_unlink(pkt_next, pktq);  			brcmu_pkt_buf_free_skb(pkt_next);  		} else { -			hdr = pkt_next->data + SDPCM_HWHDR_LEN; +			hdr = pkt_next->data + bus->tx_hdrlen - SDPCM_SWHDR_LEN;  			dat_offset = le32_to_cpu(*(__le32 *)hdr);  			dat_offset = (dat_offset & SDPCM_DOFFSET_MASK) >>  				     SDPCM_DOFFSET_SHIFT;  			skb_pull(pkt_next, dat_offset); +			if (bus->txglom) { +				tail_pad = le16_to_cpu(*(__le16 *)(hdr - 2)); +				skb_trim(pkt_next, pkt_next->len - tail_pad); +			}  		}  	}  }  /* Writes a HW/SW header into the packet and sends it. */  /* Assumes: (a) header space already there, (b) caller holds lock */ -static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt, -			      uint chan) +static int brcmf_sdio_txpkt(struct brcmf_sdio *bus, struct sk_buff_head *pktq, +			    uint chan)  {  	int ret; -	int i; -	struct sk_buff_head localq; +	struct sk_buff *pkt_next, *tmp;  	brcmf_dbg(TRACE, "Enter\n"); -	__skb_queue_head_init(&localq); -	__skb_queue_tail(&localq, pkt); -	ret = brcmf_sdio_txpkt_prep(bus, &localq, chan); +	ret = brcmf_sdio_txpkt_prep(bus, pktq, chan);  	if (ret)  		goto done;  	sdio_claim_host(bus->sdiodev->func[1]); -	ret = brcmf_sdcard_send_pkt(bus->sdiodev, bus->sdiodev->sbwad, -				    SDIO_FUNC_2, F2SYNC, &localq); +	ret = brcmf_sdiod_send_pkt(bus->sdiodev, pktq);  	bus->sdcnt.f2txdata++; -	if (ret < 0) { -		/* On failure, abort the command and terminate the frame */ -		brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n", -			  ret); -		bus->sdcnt.tx_sderrs++; +	if (ret < 0) +		brcmf_sdio_txfail(bus); -		brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); -		brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL, -				 SFC_WF_TERM, NULL); -		bus->sdcnt.f1regdata++; - -		for (i = 0; i < 3; i++) { -			u8 hi, lo; -			hi = brcmf_sdio_regrb(bus->sdiodev, -					      SBSDIO_FUNC1_WFRAMEBCHI, NULL); -			lo = brcmf_sdio_regrb(bus->sdiodev, -					      SBSDIO_FUNC1_WFRAMEBCLO, NULL); -			bus->sdcnt.f1regdata += 2; -			if ((hi == 0) && (lo == 0)) -				break; -		} - -	}  	sdio_release_host(bus->sdiodev->func[1]); -	if (ret == 0) -		bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP;  done: -	brcmf_sdio_txpkt_postp(bus, &localq); -	__skb_dequeue_tail(&localq); -	brcmf_txcomplete(bus->sdiodev->dev, pkt, ret == 0); +	brcmf_sdio_txpkt_postp(bus, pktq); +	if (ret == 0) +		bus->tx_seq = (bus->tx_seq + pktq->qlen) % SDPCM_SEQ_WRAP; +	skb_queue_walk_safe(pktq, pkt_next, tmp) { +		__skb_unlink(pkt_next, pktq); +		brcmf_txcomplete(bus->sdiodev->dev, pkt_next, ret == 0); +	}  	return ret;  } -static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes) +static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes)  {  	struct sk_buff *pkt; +	struct sk_buff_head pktq;  	u32 intstatus = 0; -	int ret = 0, prec_out; +	int ret = 0, prec_out, i;  	uint cnt = 0; -	u8 tx_prec_map; +	u8 tx_prec_map, pkt_num;  	brcmf_dbg(TRACE, "Enter\n");  	tx_prec_map = ~bus->flowcontrol;  	/* Send frames until the limit or some other event */ -	for (cnt = 0; (cnt < maxframes) && data_ok(bus); cnt++) { -		spin_lock_bh(&bus->txqlock); -		pkt = brcmu_pktq_mdeq(&bus->txq, tx_prec_map, &prec_out); -		if (pkt == NULL) { -			spin_unlock_bh(&bus->txqlock); +	for (cnt = 0; (cnt < maxframes) && data_ok(bus);) { +		pkt_num = 1; +		if (down_interruptible(&bus->tx_seq_lock)) +			return cnt; +		if (bus->txglom) +			pkt_num = min_t(u8, bus->tx_max - bus->tx_seq, +					bus->sdiodev->txglomsz); +		pkt_num = min_t(u32, pkt_num, +				brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol)); +		__skb_queue_head_init(&pktq); +		spin_lock_bh(&bus->txq_lock); +		for (i = 0; i < pkt_num; i++) { +			pkt = brcmu_pktq_mdeq(&bus->txq, tx_prec_map, +					      &prec_out); +			if (pkt == NULL) +				break; +			__skb_queue_tail(&pktq, pkt); +		} +		spin_unlock_bh(&bus->txq_lock); +		if (i == 0) { +			up(&bus->tx_seq_lock);  			break;  		} -		spin_unlock_bh(&bus->txqlock); -		ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL); +		ret = brcmf_sdio_txpkt(bus, &pktq, SDPCM_DATA_CHANNEL); +		up(&bus->tx_seq_lock); + +		cnt += i;  		/* In poll mode, need to check for other events */ -		if (!bus->intr && cnt) { +		if (!bus->intr) {  			/* Check device status, signal pending interrupt */  			sdio_claim_host(bus->sdiodev->func[1]);  			ret = r_sdreg32(bus, &intstatus, @@ -2034,7 +2374,69 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)  	return cnt;  } -static void brcmf_sdbrcm_bus_stop(struct device *dev) +static int brcmf_sdio_tx_ctrlframe(struct brcmf_sdio *bus, u8 *frame, u16 len) +{ +	u8 doff; +	u16 pad; +	uint retries = 0; +	struct brcmf_sdio_hdrinfo hd_info = {0}; +	int ret; + +	brcmf_dbg(TRACE, "Enter\n"); + +	/* Back the pointer to make room for bus header */ +	frame -= bus->tx_hdrlen; +	len += bus->tx_hdrlen; + +	/* Add alignment padding (optional for ctl frames) */ +	doff = ((unsigned long)frame % bus->head_align); +	if (doff) { +		frame -= doff; +		len += doff; +		memset(frame + bus->tx_hdrlen, 0, doff); +	} + +	/* Round send length to next SDIO block */ +	pad = 0; +	if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { +		pad = bus->blocksize - (len % bus->blocksize); +		if ((pad > bus->roundup) || (pad >= bus->blocksize)) +			pad = 0; +	} else if (len % bus->head_align) { +		pad = bus->head_align - (len % bus->head_align); +	} +	len += pad; + +	hd_info.len = len - pad; +	hd_info.channel = SDPCM_CONTROL_CHANNEL; +	hd_info.dat_offset = doff + bus->tx_hdrlen; +	hd_info.seq_num = bus->tx_seq; +	hd_info.lastfrm = true; +	hd_info.tail_pad = pad; +	brcmf_sdio_hdpack(bus, frame, &hd_info); + +	if (bus->txglom) +		brcmf_sdio_update_hwhdr(frame, len); + +	brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_CTL_ON(), +			   frame, len, "Tx Frame:\n"); +	brcmf_dbg_hex_dump(!(BRCMF_BYTES_ON() && BRCMF_CTL_ON()) && +			   BRCMF_HDRS_ON(), +			   frame, min_t(u16, len, 16), "TxHdr:\n"); + +	do { +		ret = brcmf_sdiod_send_buf(bus->sdiodev, frame, len); + +		if (ret < 0) +			brcmf_sdio_txfail(bus); +		else +			bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP; +	} while (ret < 0 && retries++ < TXRETRIES); + +	return ret; +} + +static void brcmf_sdio_bus_stop(struct device *dev)  {  	u32 local_hostintmask;  	u8 saveclk; @@ -2051,62 +2453,57 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)  		bus->watchdog_tsk = NULL;  	} -	sdio_claim_host(bus->sdiodev->func[1]); - -	/* Enable clock for device interrupts */ -	brcmf_sdbrcm_bus_sleep(bus, false, false); +	if (bus_if->state == BRCMF_BUS_DOWN) { +		sdio_claim_host(sdiodev->func[1]); + +		/* Enable clock for device interrupts */ +		brcmf_sdio_bus_sleep(bus, false, false); + +		/* Disable and clear interrupts at the chip level also */ +		w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask)); +		local_hostintmask = bus->hostintmask; +		bus->hostintmask = 0; + +		/* Force backplane clocks to assure F2 interrupt propagates */ +		saveclk = brcmf_sdiod_regrb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, +					    &err); +		if (!err) +			brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, +					  (saveclk | SBSDIO_FORCE_HT), &err); +		if (err) +			brcmf_err("Failed to force clock for F2: err %d\n", +				  err); -	/* Disable and clear interrupts at the chip level also */ -	w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask)); -	local_hostintmask = bus->hostintmask; -	bus->hostintmask = 0; +		/* Turn off the bus (F2), free any pending packets */ +		brcmf_dbg(INTR, "disable SDIO interrupts\n"); +		sdio_disable_func(sdiodev->func[SDIO_FUNC_2]); -	/* Change our idea of bus state */ -	bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; +		/* Clear any pending interrupts now that F2 is disabled */ +		w_sdreg32(bus, local_hostintmask, +			  offsetof(struct sdpcmd_regs, intstatus)); -	/* Force clocks on backplane to be sure F2 interrupt propagates */ -	saveclk = brcmf_sdio_regrb(bus->sdiodev, -				   SBSDIO_FUNC1_CHIPCLKCSR, &err); -	if (!err) { -		brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, -				 (saveclk | SBSDIO_FORCE_HT), &err); +		sdio_release_host(sdiodev->func[1]);  	} -	if (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"); -	brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx, SDIO_FUNC_ENABLE_1, -			 NULL); - -	/* Clear any pending interrupts now that F2 is disabled */ -	w_sdreg32(bus, local_hostintmask, -		  offsetof(struct sdpcmd_regs, intstatus)); - -	/* 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);  	/* Clear any held glomming stuff */  	if (bus->glomd)  		brcmu_pkt_buf_free_skb(bus->glomd); -	brcmf_sdbrcm_free_glom(bus); +	brcmf_sdio_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); +	brcmf_sdio_dcmd_resp_wake(bus);  	/* Reset some F2 state stuff */  	bus->rxskip = false;  	bus->tx_seq = bus->rx_seq = 0;  } -static inline void brcmf_sdbrcm_clrintr(struct brcmf_sdio *bus) +static inline void brcmf_sdio_clrintr(struct brcmf_sdio *bus)  {  	unsigned long flags; @@ -2120,49 +2517,50 @@ static inline void brcmf_sdbrcm_clrintr(struct brcmf_sdio *bus)  	}  } +static void atomic_orr(int val, atomic_t *v) +{ +	int old_val; + +	old_val = atomic_read(v); +	while (atomic_cmpxchg(v, old_val, val | old_val) != old_val) +		old_val = atomic_read(v); +} +  static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)  { -	u8 idx; +	struct brcmf_core *buscore;  	u32 addr;  	unsigned long val; -	int n, ret; +	int ret; -	idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV); -	addr = bus->ci->c_inf[idx].base + -	       offsetof(struct sdpcmd_regs, intstatus); +	buscore = brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV); +	addr = buscore->base + offsetof(struct sdpcmd_regs, intstatus); -	ret = brcmf_sdio_regrw_helper(bus->sdiodev, addr, &val, false); +	val = brcmf_sdiod_regrl(bus->sdiodev, addr, &ret);  	bus->sdcnt.f1regdata++;  	if (ret != 0) -		val = 0; +		return ret;  	val &= bus->hostintmask;  	atomic_set(&bus->fcstate, !!(val & I_HMB_FC_STATE));  	/* Clear interrupts */  	if (val) { -		ret = brcmf_sdio_regrw_helper(bus->sdiodev, addr, &val, true); +		brcmf_sdiod_regwl(bus->sdiodev, addr, val, &ret);  		bus->sdcnt.f1regdata++; -	} - -	if (ret) { -		atomic_set(&bus->intstatus, 0); -	} else if (val) { -		for_each_set_bit(n, &val, 32) -			set_bit(n, (unsigned long *)&bus->intstatus.counter); +		atomic_orr(val, &bus->intstatus);  	}  	return ret;  } -static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) +static void brcmf_sdio_dpc(struct brcmf_sdio *bus)  {  	u32 newstatus = 0;  	unsigned long intstatus; -	uint rxlimit = bus->rxbound;	/* Rx frames to read before resched */  	uint txlimit = bus->txbound;	/* Tx frames to send before resched */ -	uint framecnt = 0;	/* Temporary counter of tx/rx frames */ -	int err = 0, n; +	uint framecnt;			/* Temporary counter of tx/rx frames */ +	int err = 0;  	brcmf_dbg(TRACE, "Enter\n"); @@ -2174,48 +2572,29 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)  #ifdef DEBUG  		/* Check for inconsistent device control */ -		devctl = brcmf_sdio_regrb(bus->sdiodev, -					  SBSDIO_DEVICE_CTL, &err); -		if (err) { -			brcmf_err("error reading DEVCTL: %d\n", err); -			bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; -		} +		devctl = brcmf_sdiod_regrb(bus->sdiodev, +					   SBSDIO_DEVICE_CTL, &err);  #endif				/* DEBUG */  		/* Read CSR, if clock on switch to AVAIL, else ignore */ -		clkctl = brcmf_sdio_regrb(bus->sdiodev, -					  SBSDIO_FUNC1_CHIPCLKCSR, &err); -		if (err) { -			brcmf_err("error reading CSR: %d\n", -				  err); -			bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; -		} +		clkctl = brcmf_sdiod_regrb(bus->sdiodev, +					   SBSDIO_FUNC1_CHIPCLKCSR, &err);  		brcmf_dbg(SDIO, "DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n",  			  devctl, clkctl);  		if (SBSDIO_HTAV(clkctl)) { -			devctl = brcmf_sdio_regrb(bus->sdiodev, -						  SBSDIO_DEVICE_CTL, &err); -			if (err) { -				brcmf_err("error reading DEVCTL: %d\n", -					  err); -				bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; -			} +			devctl = brcmf_sdiod_regrb(bus->sdiodev, +						   SBSDIO_DEVICE_CTL, &err);  			devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; -			brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL, -					 devctl, &err); -			if (err) { -				brcmf_err("error writing DEVCTL: %d\n", -					  err); -				bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; -			} +			brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL, +					  devctl, &err);  			bus->clkstate = CLK_AVAIL;  		}  	}  	/* Make sure backplane clock is on */ -	brcmf_sdbrcm_bus_sleep(bus, false, true); +	brcmf_sdio_bus_sleep(bus, false, true);  	/* Pending interrupt indicates new device status */  	if (atomic_read(&bus->ipend) > 0) { @@ -2246,7 +2625,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)  	/* Handle host mailbox indication */  	if (intstatus & I_HMB_HOST_INT) {  		intstatus &= ~I_HMB_HOST_INT; -		intstatus |= brcmf_sdbrcm_hostmail(bus); +		intstatus |= brcmf_sdio_hostmail(bus);  	}  	sdio_release_host(bus->sdiodev->func[1]); @@ -2278,97 +2657,53 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)  		intstatus &= ~I_HMB_FRAME_IND;  	/* On frame indication, read available frames */ -	if (PKT_AVAILABLE() && bus->clkstate == CLK_AVAIL) { -		framecnt = brcmf_sdio_readframes(bus, rxlimit); +	if ((intstatus & I_HMB_FRAME_IND) && (bus->clkstate == CLK_AVAIL)) { +		brcmf_sdio_readframes(bus, bus->rxbound);  		if (!bus->rxpending)  			intstatus &= ~I_HMB_FRAME_IND; -		rxlimit -= min(framecnt, rxlimit);  	}  	/* Keep still-pending events for next scheduling */ -	if (intstatus) { -		for_each_set_bit(n, &intstatus, 32) -			set_bit(n, (unsigned long *)&bus->intstatus.counter); -	} - -	brcmf_sdbrcm_clrintr(bus); - -	if (data_ok(bus) && bus->ctrl_frame_stat && -		(bus->clkstate == CLK_AVAIL)) { -		int i; +	if (intstatus) +		atomic_orr(intstatus, &bus->intstatus); -		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); +	brcmf_sdio_clrintr(bus); -		if (err < 0) { -			/* On failure, abort the command and -				terminate the frame */ -			brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n", -				  err); -			bus->sdcnt.tx_sderrs++; - -			brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); - -			brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL, -					 SFC_WF_TERM, &err); -			bus->sdcnt.f1regdata++; - -			for (i = 0; i < 3; i++) { -				u8 hi, lo; -				hi = brcmf_sdio_regrb(bus->sdiodev, -						      SBSDIO_FUNC1_WFRAMEBCHI, -						      &err); -				lo = brcmf_sdio_regrb(bus->sdiodev, -						      SBSDIO_FUNC1_WFRAMEBCLO, -						      &err); -				bus->sdcnt.f1regdata += 2; -				if ((hi == 0) && (lo == 0)) -					break; -			} +	if (bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL) && +	    (down_interruptible(&bus->tx_seq_lock) == 0)) { +		if (data_ok(bus)) { +			sdio_claim_host(bus->sdiodev->func[1]); +			err = brcmf_sdio_tx_ctrlframe(bus,  bus->ctrl_frame_buf, +						      bus->ctrl_frame_len); +			sdio_release_host(bus->sdiodev->func[1]); -		} else { -			bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP; +			bus->ctrl_frame_stat = false; +			brcmf_sdio_wait_event_wakeup(bus);  		} -		sdio_release_host(bus->sdiodev->func[1]); -		bus->ctrl_frame_stat = false; -		brcmf_sdbrcm_wait_event_wakeup(bus); +		up(&bus->tx_seq_lock);  	}  	/* Send queued frames (limit 1 if rx may still be pending) */ -	else if ((bus->clkstate == CLK_AVAIL) && !atomic_read(&bus->fcstate) && -		 brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit -		 && data_ok(bus)) { +	if ((bus->clkstate == CLK_AVAIL) && !atomic_read(&bus->fcstate) && +	    brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && +	    data_ok(bus)) {  		framecnt = bus->rxpending ? min(txlimit, bus->txminmax) :  					    txlimit; -		framecnt = brcmf_sdbrcm_sendfromq(bus, framecnt); -		txlimit -= framecnt; +		brcmf_sdio_sendfromq(bus, framecnt);  	} -	if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) || (err != 0)) { +	if (!brcmf_bus_ready(bus->sdiodev->bus_if) || (err != 0)) {  		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) ||  		   atomic_read(&bus->ipend) > 0 ||  		   (!atomic_read(&bus->fcstate) &&  		    brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && -		    data_ok(bus)) || PKT_AVAILABLE()) { +		    data_ok(bus))) {  		atomic_inc(&bus->dpc_tskcnt);  	} - -	/* If we're done for now, turn off clock request. */ -	if ((bus->clkstate != CLK_PENDING) -	    && bus->idletime == BRCMF_IDLE_IMMEDIATE) { -		bus->activity = false; -		brcmf_dbg(SDIO, "idle state\n"); -		sdio_claim_host(bus->sdiodev->func[1]); -		brcmf_sdbrcm_bus_sleep(bus, true, false); -		sdio_release_host(bus->sdiodev->func[1]); -	}  } -static struct pktq *brcmf_sdbrcm_bus_gettxq(struct device *dev) +static struct pktq *brcmf_sdio_bus_gettxq(struct device *dev)  {  	struct brcmf_bus *bus_if = dev_get_drvdata(dev);  	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; @@ -2377,18 +2712,15 @@ static struct pktq *brcmf_sdbrcm_bus_gettxq(struct device *dev)  	return &bus->txq;  } -static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt) +static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt)  {  	int ret = -EBADE; -	uint datalen, prec; +	uint prec;  	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; -	ulong flags; - -	brcmf_dbg(TRACE, "Enter\n"); -	datalen = pkt->len; +	brcmf_dbg(TRACE, "Enter: pkt: data %p len %d\n", pkt->data, pkt->len);  	/* Add space for the header */  	skb_push(pkt, bus->tx_hdrlen); @@ -2402,7 +2734,9 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)  	bus->sdcnt.fcqueued++;  	/* Priority based enq */ -	spin_lock_irqsave(&bus->txqlock, flags); +	spin_lock_bh(&bus->txq_lock); +	/* reset bus_flags in packet cb */ +	*(u16 *)(pkt->cb) = 0;  	if (!brcmf_c_prec_enq(bus->sdiodev->dev, &bus->txq, pkt, prec)) {  		skb_pull(pkt, bus->tx_hdrlen);  		brcmf_err("out of bus->txq !!!\n"); @@ -2415,7 +2749,7 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)  		bus->txoff = true;  		brcmf_txflowblock(bus->sdiodev->dev, true);  	} -	spin_unlock_irqrestore(&bus->txqlock, flags); +	spin_unlock_bh(&bus->txq_lock);  #ifdef DEBUG  	if (pktq_plen(&bus->txq, prec) > qcount[prec]) @@ -2433,7 +2767,7 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)  #ifdef DEBUG  #define CONSOLE_LINE_MAX	192 -static int brcmf_sdbrcm_readconsole(struct brcmf_sdio *bus) +static int brcmf_sdio_readconsole(struct brcmf_sdio *bus)  {  	struct brcmf_console *c = &bus->console;  	u8 line[CONSOLE_LINE_MAX], ch; @@ -2446,8 +2780,8 @@ static int brcmf_sdbrcm_readconsole(struct brcmf_sdio *bus)  	/* Read console log struct */  	addr = bus->console_addr + offsetof(struct rte_console, log_le); -	rv = brcmf_sdio_ramrw(bus->sdiodev, false, addr, (u8 *)&c->log_le, -			      sizeof(c->log_le)); +	rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr, (u8 *)&c->log_le, +			       sizeof(c->log_le));  	if (rv < 0)  		return rv; @@ -2472,7 +2806,7 @@ static int brcmf_sdbrcm_readconsole(struct brcmf_sdio *bus)  	/* Read the console buffer */  	addr = le32_to_cpu(c->log_le.buf); -	rv = brcmf_sdio_ramrw(bus->sdiodev, false, addr, c->buf, c->bufsize); +	rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr, c->buf, c->bufsize);  	if (rv < 0)  		return rv; @@ -2510,107 +2844,27 @@ break2:  }  #endif				/* DEBUG */ -static int brcmf_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len) -{ -	int i; -	int ret; - -	bus->ctrl_frame_stat = false; -	ret = brcmf_sdcard_send_buf(bus->sdiodev, bus->sdiodev->sbwad, -				    SDIO_FUNC_2, F2SYNC, frame, len); - -	if (ret < 0) { -		/* On failure, abort the command and terminate the frame */ -		brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n", -			  ret); -		bus->sdcnt.tx_sderrs++; - -		brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); - -		brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL, -				 SFC_WF_TERM, NULL); -		bus->sdcnt.f1regdata++; - -		for (i = 0; i < 3; i++) { -			u8 hi, lo; -			hi = brcmf_sdio_regrb(bus->sdiodev, -					      SBSDIO_FUNC1_WFRAMEBCHI, NULL); -			lo = brcmf_sdio_regrb(bus->sdiodev, -					      SBSDIO_FUNC1_WFRAMEBCLO, NULL); -			bus->sdcnt.f1regdata += 2; -			if (hi == 0 && lo == 0) -				break; -		} -		return ret; -	} - -	bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQ_WRAP; - -	return ret; -} -  static int -brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) +brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)  { -	u8 *frame; -	u16 len; -	uint retries = 0; -	u8 doff = 0; -	int ret = -1;  	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; -	struct brcmf_sdio_hdrinfo hd_info = {0}; +	int ret = -1;  	brcmf_dbg(TRACE, "Enter\n"); -	/* Back the pointer to make a room for bus header */ -	frame = msg - bus->tx_hdrlen; -	len = (msglen += bus->tx_hdrlen); - -	/* Add alignment padding (optional for ctl frames) */ -	doff = ((unsigned long)frame % BRCMF_SDALIGN); -	if (doff) { -		frame -= doff; -		len += doff; -		msglen += doff; -		memset(frame, 0, doff + bus->tx_hdrlen); -	} -	/* precondition: doff < BRCMF_SDALIGN */ -	doff += bus->tx_hdrlen; - -	/* Round send length to next SDIO block */ -	if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { -		u16 pad = bus->blocksize - (len % bus->blocksize); -		if ((pad <= bus->roundup) && (pad < bus->blocksize)) -			len += pad; -	} else if (len % BRCMF_SDALIGN) { -		len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN); -	} - -	/* Satisfy length-alignment requirements */ -	if (len & (ALIGNMENT - 1)) -		len = roundup(len, ALIGNMENT); - -	/* precondition: IS_ALIGNED((unsigned long)frame, 2) */ - -	/* Make sure backplane clock is on */ -	sdio_claim_host(bus->sdiodev->func[1]); -	brcmf_sdbrcm_bus_sleep(bus, false, false); -	sdio_release_host(bus->sdiodev->func[1]); - -	hd_info.len = (u16)msglen; -	hd_info.channel = SDPCM_CONTROL_CHANNEL; -	hd_info.dat_offset = doff; -	brcmf_sdio_hdpack(bus, frame, &hd_info); +	if (down_interruptible(&bus->tx_seq_lock)) +		return -EINTR;  	if (!data_ok(bus)) {  		brcmf_dbg(INFO, "No bus credit bus->tx_max %d, bus->tx_seq %d\n",  			  bus->tx_max, bus->tx_seq); -		bus->ctrl_frame_stat = true; +		up(&bus->tx_seq_lock);  		/* Send from dpc */ -		bus->ctrl_frame_buf = frame; -		bus->ctrl_frame_len = len; +		bus->ctrl_frame_buf = msg; +		bus->ctrl_frame_len = msglen; +		bus->ctrl_frame_stat = true;  		wait_event_interruptible_timeout(bus->ctrl_wait,  						 !bus->ctrl_frame_stat, @@ -2621,31 +2875,18 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)  			ret = 0;  		} else {  			brcmf_dbg(SDIO, "ctrl_frame_stat == true\n"); +			bus->ctrl_frame_stat = false; +			if (down_interruptible(&bus->tx_seq_lock)) +				return -EINTR;  			ret = -1;  		}  	} -  	if (ret == -1) { -		brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_CTL_ON(), -				   frame, len, "Tx Frame:\n"); -		brcmf_dbg_hex_dump(!(BRCMF_BYTES_ON() && BRCMF_CTL_ON()) && -				   BRCMF_HDRS_ON(), -				   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); -	} - -	if ((bus->idletime == BRCMF_IDLE_IMMEDIATE) && -	    atomic_read(&bus->dpc_tskcnt) == 0) { -		bus->activity = false;  		sdio_claim_host(bus->sdiodev->func[1]); -		brcmf_dbg(INFO, "idle\n"); -		brcmf_sdbrcm_clkctl(bus, CLK_NONE, true); +		brcmf_sdio_bus_sleep(bus, false, false); +		ret = brcmf_sdio_tx_ctrlframe(bus, msg, msglen);  		sdio_release_host(bus->sdiodev->func[1]); +		up(&bus->tx_seq_lock);  	}  	if (ret) @@ -2657,72 +2898,6 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)  }  #ifdef DEBUG -static inline bool brcmf_sdio_valid_shared_address(u32 addr) -{ -	return !(addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)); -} - -static int brcmf_sdio_readshared(struct brcmf_sdio *bus, -				 struct sdpcm_shared *sh) -{ -	u32 addr; -	int rv; -	u32 shaddr = 0; -	struct sdpcm_shared_le sh_le; -	__le32 addr_le; - -	shaddr = bus->ci->rambase + bus->ramsize - 4; - -	/* -	 * Read last word in socram to determine -	 * address of sdpcm_shared structure -	 */ -	sdio_claim_host(bus->sdiodev->func[1]); -	brcmf_sdbrcm_bus_sleep(bus, false, false); -	rv = brcmf_sdio_ramrw(bus->sdiodev, false, shaddr, (u8 *)&addr_le, 4); -	sdio_release_host(bus->sdiodev->func[1]); -	if (rv < 0) -		return rv; - -	addr = le32_to_cpu(addr_le); - -	brcmf_dbg(SDIO, "sdpcm_shared address 0x%08X\n", addr); - -	/* -	 * Check if addr is valid. -	 * NVRAM length at the end of memory should have been overwritten. -	 */ -	if (!brcmf_sdio_valid_shared_address(addr)) { -			brcmf_err("invalid sdpcm_shared address 0x%08X\n", -				  addr); -			return -EINVAL; -	} - -	/* Read hndrte_shared structure */ -	rv = brcmf_sdio_ramrw(bus->sdiodev, false, addr, (u8 *)&sh_le, -			      sizeof(struct sdpcm_shared_le)); -	if (rv < 0) -		return rv; - -	/* Endianness */ -	sh->flags = le32_to_cpu(sh_le.flags); -	sh->trap_addr = le32_to_cpu(sh_le.trap_addr); -	sh->assert_exp_addr = le32_to_cpu(sh_le.assert_exp_addr); -	sh->assert_file_addr = le32_to_cpu(sh_le.assert_file_addr); -	sh->assert_line = le32_to_cpu(sh_le.assert_line); -	sh->console_addr = le32_to_cpu(sh_le.console_addr); -	sh->msgtrace_addr = le32_to_cpu(sh_le.msgtrace_addr); - -	if ((sh->flags & SDPCM_SHARED_VERSION_MASK) > SDPCM_SHARED_VERSION) { -		brcmf_err("sdpcm shared version unsupported: dhd %d dongle %d\n", -			  SDPCM_SHARED_VERSION, -			  sh->flags & SDPCM_SHARED_VERSION_MASK); -		return -EPROTO; -	} - -	return 0; -} -  static int brcmf_sdio_dump_console(struct brcmf_sdio *bus,  				   struct sdpcm_shared *sh, char __user *data,  				   size_t count) @@ -2736,22 +2911,22 @@ static int brcmf_sdio_dump_console(struct brcmf_sdio *bus,  	/* obtain console information from device memory */  	addr = sh->console_addr + offsetof(struct rte_console, log_le); -	rv = brcmf_sdio_ramrw(bus->sdiodev, false, addr, -			      (u8 *)&sh_val, sizeof(u32)); +	rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr, +			       (u8 *)&sh_val, sizeof(u32));  	if (rv < 0)  		return rv;  	console_ptr = le32_to_cpu(sh_val);  	addr = sh->console_addr + offsetof(struct rte_console, log_le.buf_size); -	rv = brcmf_sdio_ramrw(bus->sdiodev, false, addr, -			      (u8 *)&sh_val, sizeof(u32)); +	rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr, +			       (u8 *)&sh_val, sizeof(u32));  	if (rv < 0)  		return rv;  	console_size = le32_to_cpu(sh_val);  	addr = sh->console_addr + offsetof(struct rte_console, log_le.idx); -	rv = brcmf_sdio_ramrw(bus->sdiodev, false, addr, -			      (u8 *)&sh_val, sizeof(u32)); +	rv = brcmf_sdiod_ramrw(bus->sdiodev, false, addr, +			       (u8 *)&sh_val, sizeof(u32));  	if (rv < 0)  		return rv;  	console_index = le32_to_cpu(sh_val); @@ -2765,8 +2940,8 @@ static int brcmf_sdio_dump_console(struct brcmf_sdio *bus,  	/* obtain the console data from device */  	conbuf[console_size] = '\0'; -	rv = brcmf_sdio_ramrw(bus->sdiodev, false, console_ptr, (u8 *)conbuf, -			      console_size); +	rv = brcmf_sdiod_ramrw(bus->sdiodev, false, console_ptr, (u8 *)conbuf, +			       console_size);  	if (rv < 0)  		goto done; @@ -2803,8 +2978,8 @@ static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh,  		return 0;  	} -	error = brcmf_sdio_ramrw(bus->sdiodev, false, sh->trap_addr, (u8 *)&tr, -				 sizeof(struct brcmf_trap_info)); +	error = brcmf_sdiod_ramrw(bus->sdiodev, false, sh->trap_addr, (u8 *)&tr, +				  sizeof(struct brcmf_trap_info));  	if (error < 0)  		return error; @@ -2847,14 +3022,14 @@ static int brcmf_sdio_assert_info(struct brcmf_sdio *bus,  	sdio_claim_host(bus->sdiodev->func[1]);  	if (sh->assert_file_addr != 0) { -		error = brcmf_sdio_ramrw(bus->sdiodev, false, -					 sh->assert_file_addr, (u8 *)file, 80); +		error = brcmf_sdiod_ramrw(bus->sdiodev, false, +					  sh->assert_file_addr, (u8 *)file, 80);  		if (error < 0)  			return error;  	}  	if (sh->assert_exp_addr != 0) { -		error = brcmf_sdio_ramrw(bus->sdiodev, false, -					 sh->assert_exp_addr, (u8 *)expr, 80); +		error = brcmf_sdiod_ramrw(bus->sdiodev, false, +					  sh->assert_exp_addr, (u8 *)expr, 80);  		if (error < 0)  			return error;  	} @@ -2866,7 +3041,7 @@ static int brcmf_sdio_assert_info(struct brcmf_sdio *bus,  	return simple_read_from_buffer(data, count, &pos, buf, res);  } -static int brcmf_sdbrcm_checkdied(struct brcmf_sdio *bus) +static int brcmf_sdio_checkdied(struct brcmf_sdio *bus)  {  	int error;  	struct sdpcm_shared sh; @@ -2887,8 +3062,8 @@ static int brcmf_sdbrcm_checkdied(struct brcmf_sdio *bus)  	return 0;  } -static int brcmf_sdbrcm_died_dump(struct brcmf_sdio *bus, char __user *data, -				  size_t count, loff_t *ppos) +static int brcmf_sdio_died_dump(struct brcmf_sdio *bus, char __user *data, +				size_t count, loff_t *ppos)  {  	int error = 0;  	struct sdpcm_shared sh; @@ -2929,7 +3104,7 @@ static ssize_t brcmf_sdio_forensic_read(struct file *f, char __user *data,  	struct brcmf_sdio *bus = f->private_data;  	int res; -	res = brcmf_sdbrcm_died_dump(bus, data, count, ppos); +	res = brcmf_sdio_died_dump(bus, data, count, ppos);  	if (res > 0)  		*ppos += res;  	return (ssize_t)res; @@ -2952,9 +3127,11 @@ static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus)  	debugfs_create_file("forensics", S_IRUGO, dentry, bus,  			    &brcmf_sdio_forensic_ops);  	brcmf_debugfs_create_sdio_count(drvr, &bus->sdcnt); +	debugfs_create_u32("console_interval", 0644, dentry, +			   &bus->console_interval);  }  #else -static int brcmf_sdbrcm_checkdied(struct brcmf_sdio *bus) +static int brcmf_sdio_checkdied(struct brcmf_sdio *bus)  {  	return 0;  } @@ -2965,7 +3142,7 @@ static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus)  #endif /* DEBUG */  static int -brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen) +brcmf_sdio_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)  {  	int timeleft;  	uint rxlen = 0; @@ -2978,7 +3155,7 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)  	brcmf_dbg(TRACE, "Enter\n");  	/* Wait until control frame is available */ -	timeleft = brcmf_sdbrcm_dcmd_resp_wait(bus, &bus->rxlen, &pending); +	timeleft = brcmf_sdio_dcmd_resp_wait(bus, &bus->rxlen, &pending);  	spin_lock_bh(&bus->rxctl_lock);  	rxlen = bus->rxlen; @@ -2995,13 +3172,13 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)  			  rxlen, msglen);  	} else if (timeleft == 0) {  		brcmf_err("resumed on timeout\n"); -		brcmf_sdbrcm_checkdied(bus); +		brcmf_sdio_checkdied(bus);  	} else if (pending) {  		brcmf_dbg(CTL, "cancelled\n");  		return -ERESTARTSYS;  	} else {  		brcmf_dbg(CTL, "resumed for unknown reason?\n"); -		brcmf_sdbrcm_checkdied(bus); +		brcmf_sdio_checkdied(bus);  	}  	if (rxlen) @@ -3012,272 +3189,177 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)  	return rxlen ? (int)rxlen : -ETIMEDOUT;  } -static bool brcmf_sdbrcm_download_state(struct brcmf_sdio *bus, bool enter) -{ -	struct chip_info *ci = bus->ci; - -	/* To enter download state, disable ARM and reset SOCRAM. -	 * To exit download state, simply reset ARM (default is RAM boot). -	 */ -	if (enter) { -		bus->alp_only = true; - -		brcmf_sdio_chip_enter_download(bus->sdiodev, ci); -	} else { -		if (!brcmf_sdio_chip_exit_download(bus->sdiodev, ci, bus->vars, -						   bus->varsz)) -			return false; - -		/* Allow HT Clock now that the ARM is running. */ -		bus->alp_only = false; - -		bus->sdiodev->bus_if->state = BRCMF_BUS_LOAD; -	} - -	return true; -} - -static int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_sdio *bus) -{ -	if (bus->firmware->size < bus->fw_ptr + len) -		len = bus->firmware->size - bus->fw_ptr; - -	memcpy(buf, &bus->firmware->data[bus->fw_ptr], len); -	bus->fw_ptr += len; -	return len; -} - -static int brcmf_sdbrcm_download_code_file(struct brcmf_sdio *bus) +#ifdef DEBUG +static bool +brcmf_sdio_verifymemory(struct brcmf_sdio_dev *sdiodev, u32 ram_addr, +			u8 *ram_data, uint ram_sz)  { +	char *ram_cmp; +	int err; +	bool ret = true; +	int address;  	int offset; -	uint len; -	u8 *memblock = NULL, *memptr; -	int ret; -	u8 idx; - -	brcmf_dbg(INFO, "Enter\n"); - -	ret = request_firmware(&bus->firmware, BRCMF_SDIO_FW_NAME, -			       &bus->sdiodev->func[2]->dev); -	if (ret) { -		brcmf_err("Fail to request firmware %d\n", ret); -		return ret; -	} -	bus->fw_ptr = 0; - -	memptr = memblock = kmalloc(MEMBLOCK + BRCMF_SDALIGN, GFP_ATOMIC); -	if (memblock == NULL) { -		ret = -ENOMEM; -		goto err; -	} -	if ((u32)(unsigned long)memblock % BRCMF_SDALIGN) -		memptr += (BRCMF_SDALIGN - -			   ((u32)(unsigned long)memblock % BRCMF_SDALIGN)); - -	offset = bus->ci->rambase; - -	/* Download image */ -	len = brcmf_sdbrcm_get_image((char *)memptr, MEMBLOCK, bus); -	idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_ARM_CR4); -	if (BRCMF_MAX_CORENUM != idx) -		memcpy(&bus->ci->rst_vec, memptr, sizeof(bus->ci->rst_vec)); -	while (len) { -		ret = brcmf_sdio_ramrw(bus->sdiodev, true, offset, memptr, len); -		if (ret) { -			brcmf_err("error %d on writing %d membytes at 0x%08x\n", -				  ret, MEMBLOCK, offset); -			goto err; +	int len; + +	/* read back and verify */ +	brcmf_dbg(INFO, "Compare RAM dl & ul at 0x%08x; size=%d\n", ram_addr, +		  ram_sz); +	ram_cmp = kmalloc(MEMBLOCK, GFP_KERNEL); +	/* do not proceed while no memory but  */ +	if (!ram_cmp) +		return true; + +	address = ram_addr; +	offset = 0; +	while (offset < ram_sz) { +		len = ((offset + MEMBLOCK) < ram_sz) ? MEMBLOCK : +		      ram_sz - offset; +		err = brcmf_sdiod_ramrw(sdiodev, false, address, ram_cmp, len); +		if (err) { +			brcmf_err("error %d on reading %d membytes at 0x%08x\n", +				  err, len, address); +			ret = false; +			break; +		} else if (memcmp(ram_cmp, &ram_data[offset], len)) { +			brcmf_err("Downloaded RAM image is corrupted, block offset is %d, len is %d\n", +				  offset, len); +			ret = false; +			break;  		} - -		offset += MEMBLOCK; -		len = brcmf_sdbrcm_get_image((char *)memptr, MEMBLOCK, bus); +		offset += len; +		address += len;  	} -err: -	kfree(memblock); - -	release_firmware(bus->firmware); -	bus->fw_ptr = 0; +	kfree(ram_cmp);  	return ret;  } +#else	/* DEBUG */ +static bool +brcmf_sdio_verifymemory(struct brcmf_sdio_dev *sdiodev, u32 ram_addr, +			u8 *ram_data, uint ram_sz) +{ +	return true; +} +#endif	/* DEBUG */ -/* - * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file - * and ending in a NUL. - * Removes carriage returns, empty lines, comment lines, and converts - * newlines to NULs. - * Shortens buffer as needed and pads with NULs.  End of buffer is marked - * by two NULs. -*/ - -static int brcmf_process_nvram_vars(struct brcmf_sdio *bus) -{ -	char *varbuf; -	char *dp; -	bool findNewline; -	int column; -	int ret = 0; -	uint buf_len, n, len; - -	len = bus->firmware->size; -	varbuf = vmalloc(len); -	if (!varbuf) -		return -ENOMEM; - -	memcpy(varbuf, bus->firmware->data, len); -	dp = varbuf; +static int brcmf_sdio_download_code_file(struct brcmf_sdio *bus, +					 const struct firmware *fw) +{ +	int err; -	findNewline = false; -	column = 0; +	brcmf_dbg(TRACE, "Enter\n"); -	for (n = 0; n < len; n++) { -		if (varbuf[n] == 0) -			break; -		if (varbuf[n] == '\r') -			continue; -		if (findNewline && varbuf[n] != '\n') -			continue; -		findNewline = false; -		if (varbuf[n] == '#') { -			findNewline = true; -			continue; -		} -		if (varbuf[n] == '\n') { -			if (column == 0) -				continue; -			*dp++ = 0; -			column = 0; -			continue; -		} -		*dp++ = varbuf[n]; -		column++; -	} -	buf_len = dp - varbuf; -	while (dp < varbuf + n) -		*dp++ = 0; - -	kfree(bus->vars); -	/* roundup needed for download to device */ -	bus->varsz = roundup(buf_len + 1, 4); -	bus->vars = kmalloc(bus->varsz, GFP_KERNEL); -	if (bus->vars == NULL) { -		bus->varsz = 0; -		ret = -ENOMEM; -		goto err; -	} +	err = brcmf_sdiod_ramrw(bus->sdiodev, true, bus->ci->rambase, +				(u8 *)fw->data, fw->size); +	if (err) +		brcmf_err("error %d on writing %d membytes at 0x%08x\n", +			  err, (int)fw->size, bus->ci->rambase); +	else if (!brcmf_sdio_verifymemory(bus->sdiodev, bus->ci->rambase, +					  (u8 *)fw->data, fw->size)) +		err = -EIO; -	/* copy the processed variables and add null termination */ -	memcpy(bus->vars, varbuf, buf_len); -	bus->vars[buf_len] = 0; -err: -	vfree(varbuf); -	return ret; +	return err;  } -static int brcmf_sdbrcm_download_nvram(struct brcmf_sdio *bus) +static int brcmf_sdio_download_nvram(struct brcmf_sdio *bus, +				     void *vars, u32 varsz)  { -	int ret; - -	ret = request_firmware(&bus->firmware, BRCMF_SDIO_NV_NAME, -			       &bus->sdiodev->func[2]->dev); -	if (ret) { -		brcmf_err("Fail to request nvram %d\n", ret); -		return ret; -	} +	int address; +	int err; -	ret = brcmf_process_nvram_vars(bus); +	brcmf_dbg(TRACE, "Enter\n"); -	release_firmware(bus->firmware); +	address = bus->ci->ramsize - varsz + bus->ci->rambase; +	err = brcmf_sdiod_ramrw(bus->sdiodev, true, address, vars, varsz); +	if (err) +		brcmf_err("error %d on writing %d nvram bytes at 0x%08x\n", +			  err, varsz, address); +	else if (!brcmf_sdio_verifymemory(bus->sdiodev, address, vars, varsz)) +		err = -EIO; -	return ret; +	return err;  } -static int _brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus) +static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus, +					const struct firmware *fw, +					void *nvram, u32 nvlen)  { -	int bcmerror = -1; +	int bcmerror = -EFAULT; +	u32 rstvec; + +	sdio_claim_host(bus->sdiodev->func[1]); +	brcmf_sdio_clkctl(bus, CLK_AVAIL, false);  	/* Keep arm in reset */ -	if (!brcmf_sdbrcm_download_state(bus, true)) { -		brcmf_err("error placing ARM core in reset\n"); -		goto err; -	} +	brcmf_chip_enter_download(bus->ci); + +	rstvec = get_unaligned_le32(fw->data); +	brcmf_dbg(SDIO, "firmware rstvec: %x\n", rstvec); -	if (brcmf_sdbrcm_download_code_file(bus)) { +	bcmerror = brcmf_sdio_download_code_file(bus, fw); +	release_firmware(fw); +	if (bcmerror) {  		brcmf_err("dongle image file download failed\n"); +		brcmf_fw_nvram_free(nvram);  		goto err;  	} -	if (brcmf_sdbrcm_download_nvram(bus)) { +	bcmerror = brcmf_sdio_download_nvram(bus, nvram, nvlen); +	brcmf_fw_nvram_free(nvram); +	if (bcmerror) {  		brcmf_err("dongle nvram file download failed\n");  		goto err;  	}  	/* Take arm out of reset */ -	if (!brcmf_sdbrcm_download_state(bus, false)) { +	if (!brcmf_chip_exit_download(bus->ci, rstvec)) {  		brcmf_err("error getting out of ARM core reset\n");  		goto err;  	} +	/* Allow HT Clock now that the ARM is running. */ +	brcmf_bus_change_state(bus->sdiodev->bus_if, BRCMF_BUS_LOAD);  	bcmerror = 0;  err: +	brcmf_sdio_clkctl(bus, CLK_SDONLY, false); +	sdio_release_host(bus->sdiodev->func[1]);  	return bcmerror;  } -static bool brcmf_sdbrcm_sr_capable(struct brcmf_sdio *bus) -{ -	u32 addr, reg; - -	brcmf_dbg(TRACE, "Enter\n"); - -	/* old chips with PMU version less than 17 don't support save restore */ -	if (bus->ci->pmurev < 17) -		return false; - -	/* read PMU chipcontrol register 3*/ -	addr = CORE_CC_REG(bus->ci->c_inf[0].base, chipcontrol_addr); -	brcmf_sdio_regwl(bus->sdiodev, addr, 3, NULL); -	addr = CORE_CC_REG(bus->ci->c_inf[0].base, chipcontrol_data); -	reg = brcmf_sdio_regrl(bus->sdiodev, addr, NULL); - -	return (bool)reg; -} - -static void brcmf_sdbrcm_sr_init(struct brcmf_sdio *bus) +static void brcmf_sdio_sr_init(struct brcmf_sdio *bus)  {  	int err = 0;  	u8 val;  	brcmf_dbg(TRACE, "Enter\n"); -	val = brcmf_sdio_regrb(bus->sdiodev, SBSDIO_FUNC1_WAKEUPCTRL, -			       &err); +	val = brcmf_sdiod_regrb(bus->sdiodev, SBSDIO_FUNC1_WAKEUPCTRL, &err);  	if (err) {  		brcmf_err("error reading SBSDIO_FUNC1_WAKEUPCTRL\n");  		return;  	}  	val |= 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT; -	brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_WAKEUPCTRL, -			 val, &err); +	brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_WAKEUPCTRL, val, &err);  	if (err) {  		brcmf_err("error writing SBSDIO_FUNC1_WAKEUPCTRL\n");  		return;  	}  	/* Add CMD14 Support */ -	brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_BRCM_CARDCAP, -			 (SDIO_CCCR_BRCM_CARDCAP_CMD14_SUPPORT | -			  SDIO_CCCR_BRCM_CARDCAP_CMD14_EXT), -			 &err); +	brcmf_sdiod_regwb(bus->sdiodev, SDIO_CCCR_BRCM_CARDCAP, +			  (SDIO_CCCR_BRCM_CARDCAP_CMD14_SUPPORT | +			   SDIO_CCCR_BRCM_CARDCAP_CMD14_EXT), +			  &err);  	if (err) {  		brcmf_err("error writing SDIO_CCCR_BRCM_CARDCAP\n");  		return;  	} -	brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, -			 SBSDIO_FORCE_HT, &err); +	brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, +			  SBSDIO_FORCE_HT, &err);  	if (err) {  		brcmf_err("error writing SBSDIO_FUNC1_CHIPCLKCSR\n");  		return; @@ -3289,7 +3371,7 @@ static void brcmf_sdbrcm_sr_init(struct brcmf_sdio *bus)  }  /* enable KSO bit */ -static int brcmf_sdbrcm_kso_init(struct brcmf_sdio *bus) +static int brcmf_sdio_kso_init(struct brcmf_sdio *bus)  {  	u8 val;  	int err = 0; @@ -3297,11 +3379,10 @@ static int brcmf_sdbrcm_kso_init(struct brcmf_sdio *bus)  	brcmf_dbg(TRACE, "Enter\n");  	/* KSO bit added in SDIO core rev 12 */ -	if (bus->ci->c_inf[1].rev < 12) +	if (brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV)->rev < 12)  		return 0; -	val = brcmf_sdio_regrb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR, -			       &err); +	val = brcmf_sdiod_regrb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR, &err);  	if (err) {  		brcmf_err("error reading SBSDIO_FUNC1_SLEEPCSR\n");  		return err; @@ -3310,8 +3391,8 @@ static int brcmf_sdbrcm_kso_init(struct brcmf_sdio *bus)  	if (!(val & SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) {  		val |= (SBSDIO_FUNC1_SLEEPCSR_KSO_EN <<  			SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT); -		brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR, -				 val, &err); +		brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR, +				  val, &err);  		if (err) {  			brcmf_err("error writing SBSDIO_FUNC1_SLEEPCSR\n");  			return err; @@ -3322,132 +3403,61 @@ static int brcmf_sdbrcm_kso_init(struct brcmf_sdio *bus)  } -static bool -brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus) -{ -	bool ret; - -	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; -} - -static int brcmf_sdbrcm_bus_init(struct device *dev) +static int brcmf_sdio_bus_preinit(struct device *dev)  {  	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; -	unsigned long timeout; -	u8 ready, enable; -	int err, ret = 0; -	u8 saveclk; - -	brcmf_dbg(TRACE, "Enter\n"); - -	/* try to download image and nvram to the dongle */ -	if (bus_if->state == BRCMF_BUS_DOWN) { -		if (!(brcmf_sdbrcm_download_firmware(bus))) -			return -1; -	} - -	if (!bus->sdiodev->bus_if->drvr) -		return 0; - -	/* Start the watchdog timer */ -	bus->sdcnt.tickcnt = 0; -	brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); - -	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); -	if (bus->clkstate != CLK_AVAIL) -		goto exit; - -	/* Force clocks on backplane to be sure F2 interrupt propagates */ -	saveclk = brcmf_sdio_regrb(bus->sdiodev, -				   SBSDIO_FUNC1_CHIPCLKCSR, &err); -	if (!err) { -		brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, -				 (saveclk | SBSDIO_FORCE_HT), &err); -	} -	if (err) { -		brcmf_err("Failed to force clock for F2: err %d\n", err); -		goto exit; -	} - -	/* Enable function 2 (frame transfers) */ -	w_sdreg32(bus, SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT, -		  offsetof(struct sdpcmd_regs, tosbmailboxdata)); -	enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2); - -	brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx, enable, NULL); - -	timeout = jiffies + msecs_to_jiffies(BRCMF_WAIT_F2RDY); -	ready = 0; -	while (enable != ready) { -		ready = brcmf_sdio_regrb(bus->sdiodev, -					 SDIO_CCCR_IORx, NULL); -		if (time_after(jiffies, timeout)) -			break; -		else if (time_after(jiffies, timeout - BRCMF_WAIT_F2RDY + 50)) -			/* prevent busy waiting if it takes too long */ -			msleep_interruptible(20); -	} - -	brcmf_dbg(INFO, "enable 0x%02x, ready 0x%02x\n", enable, ready); - -	/* If F2 successfully enabled, set core and enable interrupts */ -	if (ready == enable) { -		/* Set up the interrupt mask and enable interrupts */ -		bus->hostintmask = HOSTINTMASK; -		w_sdreg32(bus, bus->hostintmask, -			  offsetof(struct sdpcmd_regs, hostintmask)); +	uint pad_size; +	u32 value; +	int err; -		brcmf_sdio_regwb(bus->sdiodev, SBSDIO_WATERMARK, 8, &err); +	/* the commands below use the terms tx and rx from +	 * a device perspective, ie. bus:txglom affects the +	 * bus transfers from device to host. +	 */ +	if (brcmf_chip_get_core(bus->ci, BCMA_CORE_SDIO_DEV)->rev < 12) { +		/* for sdio core rev < 12, disable txgloming */ +		value = 0; +		err = brcmf_iovar_data_set(dev, "bus:txglom", &value, +					   sizeof(u32));  	} else { -		/* Disable F2 again */ -		enable = SDIO_FUNC_ENABLE_1; -		brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx, enable, NULL); -		ret = -ENODEV; +		/* otherwise, set txglomalign */ +		value = 4; +		if (sdiodev->pdata) +			value = sdiodev->pdata->sd_sgentry_align; +		/* SDIO ADMA requires at least 32 bit alignment */ +		value = max_t(u32, value, 4); +		err = brcmf_iovar_data_set(dev, "bus:txglomalign", &value, +					   sizeof(u32));  	} -	if (brcmf_sdbrcm_sr_capable(bus)) { -		brcmf_sdbrcm_sr_init(bus); -	} else { -		/* Restore previous clock setting */ -		brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, -				 saveclk, &err); -	} +	if (err < 0) +		goto done; -	if (ret == 0) { -		ret = brcmf_sdio_intr_register(bus->sdiodev); -		if (ret != 0) -			brcmf_err("intr register failed:%d\n", ret); +	bus->tx_hdrlen = SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN; +	if (sdiodev->sg_support) { +		bus->txglom = false; +		value = 1; +		pad_size = bus->sdiodev->func[2]->cur_blksize << 1; +		err = brcmf_iovar_data_set(bus->sdiodev->dev, "bus:rxglom", +					   &value, sizeof(u32)); +		if (err < 0) { +			/* bus:rxglom is allowed to fail */ +			err = 0; +		} else { +			bus->txglom = true; +			bus->tx_hdrlen += SDPCM_HWEXT_LEN; +		}  	} +	brcmf_bus_add_txhdrlen(bus->sdiodev->dev, bus->tx_hdrlen); -	/* If we didn't come up, turn off backplane clock */ -	if (bus_if->state != BRCMF_BUS_DATA) -		brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); - -exit: -	sdio_release_host(bus->sdiodev->func[1]); - -	return ret; +done: +	return err;  } -void brcmf_sdbrcm_isr(void *arg) +void brcmf_sdio_isr(struct brcmf_sdio *bus)  { -	struct brcmf_sdio *bus = (struct brcmf_sdio *) arg; -  	brcmf_dbg(TRACE, "Enter\n");  	if (!bus) { @@ -3455,7 +3465,7 @@ void brcmf_sdbrcm_isr(void *arg)  		return;  	} -	if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) { +	if (!brcmf_bus_ready(bus->sdiodev->bus_if)) {  		brcmf_err("bus is down. we have nothing to do\n");  		return;  	} @@ -3466,7 +3476,6 @@ void brcmf_sdbrcm_isr(void *arg)  	else  		if (brcmf_sdio_intr_rstatus(bus)) {  			brcmf_err("failed backplane access\n"); -			bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;  		}  	/* Disable additional interrupts (is this needed now)? */ @@ -3477,7 +3486,7 @@ void brcmf_sdbrcm_isr(void *arg)  	queue_work(bus->brcmf_wq, &bus->datawork);  } -static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus) +static bool brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus)  {  #ifdef DEBUG  	struct brcmf_bus *bus_if = dev_get_drvdata(bus->sdiodev->dev); @@ -3501,9 +3510,9 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)  				u8 devpend;  				sdio_claim_host(bus->sdiodev->func[1]); -				devpend = brcmf_sdio_regrb(bus->sdiodev, -							   SDIO_CCCR_INTx, -							   NULL); +				devpend = brcmf_sdiod_regrb(bus->sdiodev, +							    SDIO_CCCR_INTx, +							    NULL);  				sdio_release_host(bus->sdiodev->func[1]);  				intstatus =  				    devpend & (INTR_STATUS_FUNC1 | @@ -3533,8 +3542,8 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)  			bus->console.count -= bus->console_interval;  			sdio_claim_host(bus->sdiodev->func[1]);  			/* Make sure backplane clock is on */ -			brcmf_sdbrcm_bus_sleep(bus, false, false); -			if (brcmf_sdbrcm_readconsole(bus) < 0) +			brcmf_sdio_bus_sleep(bus, false, false); +			if (brcmf_sdio_readconsole(bus) < 0)  				/* stop on error */  				bus->console_interval = 0;  			sdio_release_host(bus->sdiodev->func[1]); @@ -3548,11 +3557,11 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)  			bus->idlecount = 0;  			if (bus->activity) {  				bus->activity = false; -				brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); +				brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS);  			} else {  				brcmf_dbg(SDIO, "idle\n");  				sdio_claim_host(bus->sdiodev->func[1]); -				brcmf_sdbrcm_bus_sleep(bus, true, false); +				brcmf_sdio_bus_sleep(bus, true, false);  				sdio_release_host(bus->sdiodev->func[1]);  			}  		} @@ -3567,38 +3576,177 @@ static void brcmf_sdio_dataworker(struct work_struct *work)  					      datawork);  	while (atomic_read(&bus->dpc_tskcnt)) { -		brcmf_sdbrcm_dpc(bus); -		atomic_dec(&bus->dpc_tskcnt); +		atomic_set(&bus->dpc_tskcnt, 0); +		brcmf_sdio_dpc(bus);  	}  } -static void brcmf_sdbrcm_release_malloc(struct brcmf_sdio *bus) +static void +brcmf_sdio_drivestrengthinit(struct brcmf_sdio_dev *sdiodev, +			     struct brcmf_chip *ci, u32 drivestrength)  { -	brcmf_dbg(TRACE, "Enter\n"); +	const struct sdiod_drive_str *str_tab = NULL; +	u32 str_mask; +	u32 str_shift; +	u32 base; +	u32 i; +	u32 drivestrength_sel = 0; +	u32 cc_data_temp; +	u32 addr; -	kfree(bus->rxbuf); -	bus->rxctl = bus->rxbuf = NULL; -	bus->rxlen = 0; +	if (!(ci->cc_caps & CC_CAP_PMU)) +		return; + +	switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) { +	case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12): +		str_tab = sdiod_drvstr_tab1_1v8; +		str_mask = 0x00003800; +		str_shift = 11; +		break; +	case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17): +		str_tab = sdiod_drvstr_tab6_1v8; +		str_mask = 0x00001800; +		str_shift = 11; +		break; +	case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17): +		/* note: 43143 does not support tristate */ +		i = ARRAY_SIZE(sdiod_drvstr_tab2_3v3) - 1; +		if (drivestrength >= sdiod_drvstr_tab2_3v3[i].strength) { +			str_tab = sdiod_drvstr_tab2_3v3; +			str_mask = 0x00000007; +			str_shift = 0; +		} else +			brcmf_err("Invalid SDIO Drive strength for chip %s, strength=%d\n", +				  ci->name, drivestrength); +		break; +	case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13): +		str_tab = sdiod_drive_strength_tab5_1v8; +		str_mask = 0x00003800; +		str_shift = 11; +		break; +	default: +		brcmf_err("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n", +			  ci->name, ci->chiprev, ci->pmurev); +		break; +	} + +	if (str_tab != NULL) { +		for (i = 0; str_tab[i].strength != 0; i++) { +			if (drivestrength >= str_tab[i].strength) { +				drivestrength_sel = str_tab[i].sel; +				break; +			} +		} +		base = brcmf_chip_get_chipcommon(ci)->base; +		addr = CORE_CC_REG(base, chipcontrol_addr); +		brcmf_sdiod_regwl(sdiodev, addr, 1, NULL); +		cc_data_temp = brcmf_sdiod_regrl(sdiodev, addr, NULL); +		cc_data_temp &= ~str_mask; +		drivestrength_sel <<= str_shift; +		cc_data_temp |= drivestrength_sel; +		brcmf_sdiod_regwl(sdiodev, addr, cc_data_temp, NULL); + +		brcmf_dbg(INFO, "SDIO: %d mA (req=%d mA) drive strength selected, set to 0x%08x\n", +			  str_tab[i].strength, drivestrength, cc_data_temp); +	}  } -static bool brcmf_sdbrcm_probe_malloc(struct brcmf_sdio *bus) +static int brcmf_sdio_buscoreprep(void *ctx)  { -	brcmf_dbg(TRACE, "Enter\n"); +	struct brcmf_sdio_dev *sdiodev = ctx; +	int err = 0; +	u8 clkval, clkset; -	if (bus->sdiodev->bus_if->maxctl) { -		bus->rxblen = -		    roundup((bus->sdiodev->bus_if->maxctl + SDPCM_HDRLEN), -			    ALIGNMENT) + BRCMF_SDALIGN; -		bus->rxbuf = kmalloc(bus->rxblen, GFP_ATOMIC); -		if (!(bus->rxbuf)) -			return false; +	/* Try forcing SDIO core to do ALPAvail request only */ +	clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ; +	brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); +	if (err) { +		brcmf_err("error writing for HT off\n"); +		return err;  	} -	return true; +	/* If register supported, wait for ALPAvail and then force ALP */ +	/* This may take up to 15 milliseconds */ +	clkval = brcmf_sdiod_regrb(sdiodev, +				   SBSDIO_FUNC1_CHIPCLKCSR, NULL); + +	if ((clkval & ~SBSDIO_AVBITS) != clkset) { +		brcmf_err("ChipClkCSR access: wrote 0x%02x read 0x%02x\n", +			  clkset, clkval); +		return -EACCES; +	} + +	SPINWAIT(((clkval = brcmf_sdiod_regrb(sdiodev, +					      SBSDIO_FUNC1_CHIPCLKCSR, NULL)), +			!SBSDIO_ALPAV(clkval)), +			PMU_MAX_TRANSITION_DLY); +	if (!SBSDIO_ALPAV(clkval)) { +		brcmf_err("timeout on ALPAV wait, clkval 0x%02x\n", +			  clkval); +		return -EBUSY; +	} + +	clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP; +	brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); +	udelay(65); + +	/* Also, disable the extra SDIO pull-ups */ +	brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL); + +	return 0; +} + +static void brcmf_sdio_buscore_exitdl(void *ctx, struct brcmf_chip *chip, +				      u32 rstvec) +{ +	struct brcmf_sdio_dev *sdiodev = ctx; +	struct brcmf_core *core; +	u32 reg_addr; + +	/* clear all interrupts */ +	core = brcmf_chip_get_core(chip, BCMA_CORE_SDIO_DEV); +	reg_addr = core->base + offsetof(struct sdpcmd_regs, intstatus); +	brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL); + +	if (rstvec) +		/* Write reset vector to address 0 */ +		brcmf_sdiod_ramrw(sdiodev, true, 0, (void *)&rstvec, +				  sizeof(rstvec)); +} + +static u32 brcmf_sdio_buscore_read32(void *ctx, u32 addr) +{ +	struct brcmf_sdio_dev *sdiodev = ctx; +	u32 val, rev; + +	val = brcmf_sdiod_regrl(sdiodev, addr, NULL); +	if (sdiodev->func[0]->device == SDIO_DEVICE_ID_BROADCOM_4335_4339 && +	    addr == CORE_CC_REG(SI_ENUM_BASE, chipid)) { +		rev = (val & CID_REV_MASK) >> CID_REV_SHIFT; +		if (rev >= 2) { +			val &= ~CID_ID_MASK; +			val |= BCM4339_CHIP_ID; +		} +	} +	return val;  } +static void brcmf_sdio_buscore_write32(void *ctx, u32 addr, u32 val) +{ +	struct brcmf_sdio_dev *sdiodev = ctx; + +	brcmf_sdiod_regwl(sdiodev, addr, val, NULL); +} + +static const struct brcmf_buscore_ops brcmf_sdio_buscore_ops = { +	.prepare = brcmf_sdio_buscoreprep, +	.exit_dl = brcmf_sdio_buscore_exitdl, +	.read32 = brcmf_sdio_buscore_read32, +	.write32 = brcmf_sdio_buscore_write32, +}; +  static bool -brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva) +brcmf_sdio_probe_attach(struct brcmf_sdio *bus)  {  	u8 clkctl = 0;  	int err = 0; @@ -3606,23 +3754,21 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)  	u32 reg_val;  	u32 drivestrength; -	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)); +		 brcmf_sdiod_regrl(bus->sdiodev, SI_ENUM_BASE, NULL));  	/* -	 * Force PLL off until brcmf_sdio_chip_attach() +	 * Force PLL off until brcmf_chip_attach()  	 * programs PLL control regs  	 */ -	brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, -			 BRCMF_INIT_CLKCTL1, &err); +	brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, +			  BRCMF_INIT_CLKCTL1, &err);  	if (!err) -		clkctl = brcmf_sdio_regrb(bus->sdiodev, -					  SBSDIO_FUNC1_CHIPCLKCSR, &err); +		clkctl = brcmf_sdiod_regrb(bus->sdiodev, +					   SBSDIO_FUNC1_CHIPCLKCSR, &err);  	if (err || ((clkctl & ~SBSDIO_AVBITS) != BRCMF_INIT_CLKCTL1)) {  		brcmf_err("ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n", @@ -3630,12 +3776,19 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)  		goto fail;  	} -	if (brcmf_sdio_chip_attach(bus->sdiodev, &bus->ci, regsva)) { -		brcmf_err("brcmf_sdio_chip_attach failed!\n"); +	/* SDIO register access works so moving +	 * state from UNKNOWN to DOWN. +	 */ +	brcmf_bus_change_state(bus->sdiodev->bus_if, BRCMF_BUS_DOWN); + +	bus->ci = brcmf_chip_attach(bus->sdiodev, &brcmf_sdio_buscore_ops); +	if (IS_ERR(bus->ci)) { +		brcmf_err("brcmf_chip_attach failed!\n"); +		bus->ci = NULL;  		goto fail;  	} -	if (brcmf_sdbrcm_kso_init(bus)) { +	if (brcmf_sdio_kso_init(bus)) {  		brcmf_err("error enabling KSO\n");  		goto fail;  	} @@ -3644,7 +3797,7 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)  		drivestrength = bus->sdiodev->pdata->drive_strength;  	else  		drivestrength = DEFAULT_SDIO_DRIVE_STRENGTH; -	brcmf_sdio_chip_drivestrengthinit(bus->sdiodev, bus->ci, drivestrength); +	brcmf_sdio_drivestrengthinit(bus->sdiodev, bus->ci, drivestrength);  	/* Get info on the SOCRAM cores... */  	bus->ramsize = bus->ci->ramsize; @@ -3654,44 +3807,42 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)  	}  	/* Set card control so an SDIO card reset does a WLAN backplane reset */ -	reg_val = brcmf_sdio_regrb(bus->sdiodev, -				   SDIO_CCCR_BRCM_CARDCTRL, &err); +	reg_val = brcmf_sdiod_regrb(bus->sdiodev, +				    SDIO_CCCR_BRCM_CARDCTRL, &err);  	if (err)  		goto fail;  	reg_val |= SDIO_CCCR_BRCM_CARDCTRL_WLANRESET; -	brcmf_sdio_regwb(bus->sdiodev, -			 SDIO_CCCR_BRCM_CARDCTRL, reg_val, &err); +	brcmf_sdiod_regwb(bus->sdiodev, +			  SDIO_CCCR_BRCM_CARDCTRL, reg_val, &err);  	if (err)  		goto fail;  	/* set PMUControl so a backplane reset does PMU state reload */ -	reg_addr = CORE_CC_REG(bus->ci->c_inf[0].base, +	reg_addr = CORE_CC_REG(brcmf_chip_get_chipcommon(bus->ci)->base,  			       pmucontrol); -	reg_val = brcmf_sdio_regrl(bus->sdiodev, -				   reg_addr, -				   &err); +	reg_val = brcmf_sdiod_regrl(bus->sdiodev, reg_addr, &err);  	if (err)  		goto fail;  	reg_val |= (BCMA_CC_PMU_CTL_RES_RELOAD << BCMA_CC_PMU_CTL_RES_SHIFT); -	brcmf_sdio_regwl(bus->sdiodev, -			 reg_addr, -			 reg_val, -			 &err); +	brcmf_sdiod_regwl(bus->sdiodev, reg_addr, reg_val, &err);  	if (err)  		goto fail; -  	sdio_release_host(bus->sdiodev->func[1]);  	brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN); +	/* allocate header buffer */ +	bus->hdrbuf = kzalloc(MAX_HDR_READ + bus->head_align, GFP_KERNEL); +	if (!bus->hdrbuf) +		return false;  	/* Locate an appropriately-aligned portion of hdrbuf */  	bus->rxhdr = (u8 *) roundup((unsigned long)&bus->hdrbuf[0], -				    BRCMF_SDALIGN); +				    bus->head_align);  	/* Set the poll and/or interrupt flags */  	bus->intr = true; @@ -3706,42 +3857,8 @@ fail:  	return false;  } -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); - -	bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; -	bus->rxflow = false; - -	/* 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; -	bus->idleclock = BRCMF_IDLE_ACTIVE; - -	/* Query the F2 block size, set roundup accordingly */ -	bus->blocksize = bus->sdiodev->func[2]->cur_blksize; -	bus->roundup = min(max_roundup, bus->blocksize); - -	/* SR state */ -	bus->sleeping = false; -	bus->sr_enabled = false; - -	return true; -} -  static int -brcmf_sdbrcm_watchdog_thread(void *data) +brcmf_sdio_watchdog_thread(void *data)  {  	struct brcmf_sdio *bus = (struct brcmf_sdio *)data; @@ -3751,9 +3868,10 @@ brcmf_sdbrcm_watchdog_thread(void *data)  		if (kthread_should_stop())  			break;  		if (!wait_for_completion_interruptible(&bus->watchdog_wait)) { -			brcmf_sdbrcm_bus_watchdog(bus); +			brcmf_sdio_bus_watchdog(bus);  			/* Count the tick for reference */  			bus->sdcnt.tickcnt++; +			reinit_completion(&bus->watchdog_wait);  		} else  			break;  	} @@ -3761,7 +3879,7 @@ brcmf_sdbrcm_watchdog_thread(void *data)  }  static void -brcmf_sdbrcm_watchdog(unsigned long data) +brcmf_sdio_watchdog(unsigned long data)  {  	struct brcmf_sdio *bus = (struct brcmf_sdio *)data; @@ -3774,73 +3892,124 @@ brcmf_sdbrcm_watchdog(unsigned long data)  	}  } -static void brcmf_sdbrcm_release_dongle(struct brcmf_sdio *bus) +static struct brcmf_bus_ops brcmf_sdio_bus_ops = { +	.stop = brcmf_sdio_bus_stop, +	.preinit = brcmf_sdio_bus_preinit, +	.txdata = brcmf_sdio_bus_txdata, +	.txctl = brcmf_sdio_bus_txctl, +	.rxctl = brcmf_sdio_bus_rxctl, +	.gettxq = brcmf_sdio_bus_gettxq, +}; + +static void brcmf_sdio_firmware_callback(struct device *dev, +					 const struct firmware *code, +					 void *nvram, u32 nvram_len)  { -	brcmf_dbg(TRACE, "Enter\n"); +	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; +	int err = 0; +	u8 saveclk; -	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); -		bus->vars = NULL; +	brcmf_dbg(TRACE, "Enter: dev=%s\n", dev_name(dev)); + +	/* try to download image and nvram to the dongle */ +	if (bus_if->state == BRCMF_BUS_DOWN) { +		bus->alp_only = true; +		err = brcmf_sdio_download_firmware(bus, code, nvram, nvram_len); +		if (err) +			goto fail; +		bus->alp_only = false;  	} -	brcmf_dbg(TRACE, "Disconnected\n"); -} +	if (!bus_if->drvr) +		return; -/* Detach and free everything */ -static void brcmf_sdbrcm_release(struct brcmf_sdio *bus) -{ -	brcmf_dbg(TRACE, "Enter\n"); +	/* Start the watchdog timer */ +	bus->sdcnt.tickcnt = 0; +	brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS); -	if (bus) { -		/* De-register interrupt handler */ -		brcmf_sdio_intr_unregister(bus->sdiodev); +	sdio_claim_host(sdiodev->func[1]); -		cancel_work_sync(&bus->datawork); -		if (bus->brcmf_wq) -			destroy_workqueue(bus->brcmf_wq); +	/* Make sure backplane clock is on, needed to generate F2 interrupt */ +	brcmf_sdio_clkctl(bus, CLK_AVAIL, false); +	if (bus->clkstate != CLK_AVAIL) +		goto release; -		if (bus->sdiodev->bus_if->drvr) { -			brcmf_detach(bus->sdiodev->dev); -			brcmf_sdbrcm_release_dongle(bus); -		} +	/* Force clocks on backplane to be sure F2 interrupt propagates */ +	saveclk = brcmf_sdiod_regrb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, &err); +	if (!err) { +		brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, +				  (saveclk | SBSDIO_FORCE_HT), &err); +	} +	if (err) { +		brcmf_err("Failed to force clock for F2: err %d\n", err); +		goto release; +	} -		brcmf_sdbrcm_release_malloc(bus); +	/* Enable function 2 (frame transfers) */ +	w_sdreg32(bus, SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT, +		  offsetof(struct sdpcmd_regs, tosbmailboxdata)); +	err = sdio_enable_func(sdiodev->func[SDIO_FUNC_2]); -		kfree(bus); + +	brcmf_dbg(INFO, "enable F2: err=%d\n", err); + +	/* If F2 successfully enabled, set core and enable interrupts */ +	if (!err) { +		/* Set up the interrupt mask and enable interrupts */ +		bus->hostintmask = HOSTINTMASK; +		w_sdreg32(bus, bus->hostintmask, +			  offsetof(struct sdpcmd_regs, hostintmask)); + +		brcmf_sdiod_regwb(sdiodev, SBSDIO_WATERMARK, 8, &err); +	} else { +		/* Disable F2 again */ +		sdio_disable_func(sdiodev->func[SDIO_FUNC_2]); +		goto release;  	} -	brcmf_dbg(TRACE, "Disconnected\n"); -} +	if (brcmf_chip_sr_capable(bus->ci)) { +		brcmf_sdio_sr_init(bus); +	} else { +		/* Restore previous clock setting */ +		brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, +				  saveclk, &err); +	} -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, -	.gettxq = brcmf_sdbrcm_bus_gettxq, -}; +	if (err == 0) { +		err = brcmf_sdiod_intr_register(sdiodev); +		if (err != 0) +			brcmf_err("intr register failed:%d\n", err); +	} + +	/* If we didn't come up, turn off backplane clock */ +	if (err != 0) +		brcmf_sdio_clkctl(bus, CLK_NONE, false); + +	sdio_release_host(sdiodev->func[1]); + +	err = brcmf_bus_start(dev); +	if (err != 0) { +		brcmf_err("dongle is not responding\n"); +		goto fail; +	} +	return; + +release: +	sdio_release_host(sdiodev->func[1]); +fail: +	brcmf_dbg(TRACE, "failed: dev=%s, err=%d\n", dev_name(dev), err); +	device_release_driver(dev); +} -void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) +struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)  {  	int ret;  	struct brcmf_sdio *bus; -	struct brcmf_bus_dcmd *dlst; -	u32 dngl_txglom; -	u32 txglomalign = 0; -	u8 idx;  	brcmf_dbg(TRACE, "Enter\n"); -	/* We make an assumption about address window mappings: -	 * regsva == SI_ENUM_BASE*/ -  	/* Allocate private bus interface state */  	bus = kzalloc(sizeof(struct brcmf_sdio), GFP_ATOMIC);  	if (!bus) @@ -3854,6 +4023,18 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)  	bus->txminmax = BRCMF_TXMINMAX;  	bus->tx_seq = SDPCM_SEQ_WRAP - 1; +	/* platform specific configuration: +	 *   alignments must be at least 4 bytes for ADMA +         */ +	bus->head_align = ALIGNMENT; +	bus->sgentry_align = ALIGNMENT; +	if (sdiodev->pdata) { +		if (sdiodev->pdata->sd_head_align > ALIGNMENT) +			bus->head_align = sdiodev->pdata->sd_head_align; +		if (sdiodev->pdata->sd_sgentry_align > ALIGNMENT) +			bus->sgentry_align = sdiodev->pdata->sd_sgentry_align; +	} +  	INIT_WORK(&bus->datawork, brcmf_sdio_dataworker);  	bus->brcmf_wq = create_singlethread_workqueue("brcmf_wq");  	if (bus->brcmf_wq == NULL) { @@ -3862,24 +4043,25 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)  	}  	/* attempt to attach to the dongle */ -	if (!(brcmf_sdbrcm_probe_attach(bus, regsva))) { -		brcmf_err("brcmf_sdbrcm_probe_attach failed\n"); +	if (!(brcmf_sdio_probe_attach(bus))) { +		brcmf_err("brcmf_sdio_probe_attach failed\n");  		goto fail;  	}  	spin_lock_init(&bus->rxctl_lock); -	spin_lock_init(&bus->txqlock); +	spin_lock_init(&bus->txq_lock); +	sema_init(&bus->tx_seq_lock, 1);  	init_waitqueue_head(&bus->ctrl_wait);  	init_waitqueue_head(&bus->dcmd_resp_wait);  	/* Set up the watchdog timer */  	init_timer(&bus->timer);  	bus->timer.data = (unsigned long)bus; -	bus->timer.function = brcmf_sdbrcm_watchdog; +	bus->timer.function = brcmf_sdio_watchdog;  	/* Initialize watchdog thread */  	init_completion(&bus->watchdog_wait); -	bus->watchdog_tsk = kthread_run(brcmf_sdbrcm_watchdog_thread, +	bus->watchdog_tsk = kthread_run(brcmf_sdio_watchdog_thread,  					bus, "brcmf_watchdog");  	if (IS_ERR(bus->watchdog_tsk)) {  		pr_warn("brcmf_watchdog thread failed to start\n"); @@ -3898,78 +4080,112 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)  	bus->tx_hdrlen = SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN;  	/* Attach to the common layer, reserve hdr space */ -	ret = brcmf_attach(bus->tx_hdrlen, bus->sdiodev->dev); +	ret = brcmf_attach(bus->sdiodev->dev);  	if (ret != 0) {  		brcmf_err("brcmf_attach failed\n");  		goto fail;  	} +	/* Query the F2 block size, set roundup accordingly */ +	bus->blocksize = bus->sdiodev->func[2]->cur_blksize; +	bus->roundup = min(max_roundup, bus->blocksize); +  	/* Allocate buffers */ -	if (!(brcmf_sdbrcm_probe_malloc(bus))) { -		brcmf_err("brcmf_sdbrcm_probe_malloc failed\n"); -		goto fail; +	if (bus->sdiodev->bus_if->maxctl) { +		bus->sdiodev->bus_if->maxctl += bus->roundup; +		bus->rxblen = +		    roundup((bus->sdiodev->bus_if->maxctl + SDPCM_HDRLEN), +			    ALIGNMENT) + bus->head_align; +		bus->rxbuf = kmalloc(bus->rxblen, GFP_ATOMIC); +		if (!(bus->rxbuf)) { +			brcmf_err("rxbuf allocation failed\n"); +			goto fail; +		}  	} -	if (!(brcmf_sdbrcm_probe_init(bus))) { -		brcmf_err("brcmf_sdbrcm_probe_init failed\n"); -		goto fail; -	} +	sdio_claim_host(bus->sdiodev->func[1]); + +	/* Disable F2 to clear any intermediate frame state on the dongle */ +	sdio_disable_func(bus->sdiodev->func[SDIO_FUNC_2]); + +	bus->rxflow = false; + +	/* Done with backplane-dependent accesses, can drop clock... */ +	brcmf_sdiod_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; +	bus->idleclock = BRCMF_IDLE_ACTIVE; + +	/* SR state */ +	bus->sleeping = false; +	bus->sr_enabled = false;  	brcmf_sdio_debugfs_create(bus);  	brcmf_dbg(INFO, "completed!!\n"); -	/* sdio bus core specific dcmd */ -	idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV); -	dlst = kzalloc(sizeof(struct brcmf_bus_dcmd), GFP_KERNEL); -	if (dlst) { -		if (bus->ci->c_inf[idx].rev < 12) { -			/* for sdio core rev < 12, disable txgloming */ -			dngl_txglom = 0; -			dlst->name = "bus:txglom"; -			dlst->param = (char *)&dngl_txglom; -			dlst->param_len = sizeof(u32); -		} else { -			/* otherwise, set txglomalign */ -			if (sdiodev->pdata) -				txglomalign = sdiodev->pdata->sd_sgentry_align; -			/* SDIO ADMA requires at least 32 bit alignment */ -			if (txglomalign < 4) -				txglomalign = 4; -			dlst->name = "bus:txglomalign"; -			dlst->param = (char *)&txglomalign; -			dlst->param_len = sizeof(u32); -		} -		list_add(&dlst->list, &bus->sdiodev->bus_if->dcmd_list); -	} - -	/* if firmware path present try to download and bring up bus */ -	ret = brcmf_bus_start(bus->sdiodev->dev); +	ret = brcmf_fw_get_firmwares(sdiodev->dev, BRCMF_FW_REQUEST_NVRAM, +				     brcmf_sdio_get_fwname(bus->ci, +							   BRCMF_FIRMWARE_BIN), +				     brcmf_sdio_get_fwname(bus->ci, +							   BRCMF_FIRMWARE_NVRAM), +				     brcmf_sdio_firmware_callback);  	if (ret != 0) { -		brcmf_err("dongle is not responding\n"); +		brcmf_err("async firmware request failed: %d\n", ret);  		goto fail;  	}  	return bus;  fail: -	brcmf_sdbrcm_release(bus); +	brcmf_sdio_remove(bus);  	return NULL;  } -void brcmf_sdbrcm_disconnect(void *ptr) +/* Detach and free everything */ +void brcmf_sdio_remove(struct brcmf_sdio *bus)  { -	struct brcmf_sdio *bus = (struct brcmf_sdio *)ptr; -  	brcmf_dbg(TRACE, "Enter\n"); -	if (bus) -		brcmf_sdbrcm_release(bus); +	if (bus) { +		/* De-register interrupt handler */ +		brcmf_sdiod_intr_unregister(bus->sdiodev); + +		brcmf_detach(bus->sdiodev->dev); + +		cancel_work_sync(&bus->datawork); +		if (bus->brcmf_wq) +			destroy_workqueue(bus->brcmf_wq); + +		if (bus->ci) { +			if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) { +				sdio_claim_host(bus->sdiodev->func[1]); +				brcmf_sdio_clkctl(bus, CLK_AVAIL, false); +				/* Leave the device in state where it is +				 * 'quiet'. This is done by putting it in +				 * download_state which essentially resets +				 * all necessary cores. +				 */ +				msleep(20); +				brcmf_chip_enter_download(bus->ci); +				brcmf_sdio_clkctl(bus, CLK_NONE, false); +				sdio_release_host(bus->sdiodev->func[1]); +			} +			brcmf_chip_detach(bus->ci); +		} + +		kfree(bus->rxbuf); +		kfree(bus->hdrbuf); +		kfree(bus); +	}  	brcmf_dbg(TRACE, "Disconnected\n");  } -void -brcmf_sdbrcm_wd_timer(struct brcmf_sdio *bus, uint wdtick) +void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, uint wdtick)  {  	/* Totally stop the timer */  	if (!wdtick && bus->wd_timer_valid) { @@ -3980,7 +4196,7 @@ brcmf_sdbrcm_wd_timer(struct brcmf_sdio *bus, uint wdtick)  	}  	/* don't start the wd until fw is loaded */ -	if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) +	if (bus->sdiodev->bus_if->state != BRCMF_BUS_DATA)  		return;  	if (wdtick) { diff --git a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c new file mode 100644 index 00000000000..7b7d237c1dd --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2013 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/device.h> +#include <linux/firmware.h> + +#include "dhd_dbg.h" +#include "firmware.h" + +enum nvram_parser_state { +	IDLE, +	KEY, +	VALUE, +	COMMENT, +	END +}; + +/** + * struct nvram_parser - internal info for parser. + * + * @state: current parser state. + * @fwnv: input buffer being parsed. + * @nvram: output buffer with parse result. + * @nvram_len: lenght of parse result. + * @line: current line. + * @column: current column in line. + * @pos: byte offset in input buffer. + * @entry: start position of key,value entry. + */ +struct nvram_parser { +	enum nvram_parser_state state; +	const struct firmware *fwnv; +	u8 *nvram; +	u32 nvram_len; +	u32 line; +	u32 column; +	u32 pos; +	u32 entry; +}; + +static bool is_nvram_char(char c) +{ +	/* comment marker excluded */ +	if (c == '#') +		return false; + +	/* key and value may have any other readable character */ +	return (c > 0x20 && c < 0x7f); +} + +static bool is_whitespace(char c) +{ +	return (c == ' ' || c == '\r' || c == '\n' || c == '\t'); +} + +static enum nvram_parser_state brcmf_nvram_handle_idle(struct nvram_parser *nvp) +{ +	char c; + +	c = nvp->fwnv->data[nvp->pos]; +	if (c == '\n') +		return COMMENT; +	if (is_whitespace(c)) +		goto proceed; +	if (c == '#') +		return COMMENT; +	if (is_nvram_char(c)) { +		nvp->entry = nvp->pos; +		return KEY; +	} +	brcmf_dbg(INFO, "warning: ln=%d:col=%d: ignoring invalid character\n", +		  nvp->line, nvp->column); +proceed: +	nvp->column++; +	nvp->pos++; +	return IDLE; +} + +static enum nvram_parser_state brcmf_nvram_handle_key(struct nvram_parser *nvp) +{ +	enum nvram_parser_state st = nvp->state; +	char c; + +	c = nvp->fwnv->data[nvp->pos]; +	if (c == '=') { +		st = VALUE; +	} else if (!is_nvram_char(c)) { +		brcmf_dbg(INFO, "warning: ln=%d:col=%d: '=' expected, skip invalid key entry\n", +			  nvp->line, nvp->column); +		return COMMENT; +	} + +	nvp->column++; +	nvp->pos++; +	return st; +} + +static enum nvram_parser_state +brcmf_nvram_handle_value(struct nvram_parser *nvp) +{ +	char c; +	char *skv; +	char *ekv; +	u32 cplen; + +	c = nvp->fwnv->data[nvp->pos]; +	if (!is_nvram_char(c)) { +		/* key,value pair complete */ +		ekv = (u8 *)&nvp->fwnv->data[nvp->pos]; +		skv = (u8 *)&nvp->fwnv->data[nvp->entry]; +		cplen = ekv - skv; +		/* copy to output buffer */ +		memcpy(&nvp->nvram[nvp->nvram_len], skv, cplen); +		nvp->nvram_len += cplen; +		nvp->nvram[nvp->nvram_len] = '\0'; +		nvp->nvram_len++; +		return IDLE; +	} +	nvp->pos++; +	nvp->column++; +	return VALUE; +} + +static enum nvram_parser_state +brcmf_nvram_handle_comment(struct nvram_parser *nvp) +{ +	char *eol, *sol; + +	sol = (char *)&nvp->fwnv->data[nvp->pos]; +	eol = strchr(sol, '\n'); +	if (eol == NULL) +		return END; + +	/* eat all moving to next line */ +	nvp->line++; +	nvp->column = 1; +	nvp->pos += (eol - sol) + 1; +	return IDLE; +} + +static enum nvram_parser_state brcmf_nvram_handle_end(struct nvram_parser *nvp) +{ +	/* final state */ +	return END; +} + +static enum nvram_parser_state +(*nv_parser_states[])(struct nvram_parser *nvp) = { +	brcmf_nvram_handle_idle, +	brcmf_nvram_handle_key, +	brcmf_nvram_handle_value, +	brcmf_nvram_handle_comment, +	brcmf_nvram_handle_end +}; + +static int brcmf_init_nvram_parser(struct nvram_parser *nvp, +				   const struct firmware *nv) +{ +	memset(nvp, 0, sizeof(*nvp)); +	nvp->fwnv = nv; +	/* Alloc for extra 0 byte + roundup by 4 + length field */ +	nvp->nvram = kzalloc(nv->size + 1 + 3 + sizeof(u32), GFP_KERNEL); +	if (!nvp->nvram) +		return -ENOMEM; + +	nvp->line = 1; +	nvp->column = 1; +	return 0; +} + +/* brcmf_nvram_strip :Takes a buffer of "<var>=<value>\n" lines read from a fil + * and ending in a NUL. Removes carriage returns, empty lines, comment lines, + * and converts newlines to NULs. Shortens buffer as needed and pads with NULs. + * End of buffer is completed with token identifying length of buffer. + */ +static void *brcmf_fw_nvram_strip(const struct firmware *nv, u32 *new_length) +{ +	struct nvram_parser nvp; +	u32 pad; +	u32 token; +	__le32 token_le; + +	if (brcmf_init_nvram_parser(&nvp, nv) < 0) +		return NULL; + +	while (nvp.pos < nv->size) { +		nvp.state = nv_parser_states[nvp.state](&nvp); +		if (nvp.state == END) +			break; +	} +	pad = nvp.nvram_len; +	*new_length = roundup(nvp.nvram_len + 1, 4); +	while (pad != *new_length) { +		nvp.nvram[pad] = 0; +		pad++; +	} + +	token = *new_length / 4; +	token = (~token << 16) | (token & 0x0000FFFF); +	token_le = cpu_to_le32(token); + +	memcpy(&nvp.nvram[*new_length], &token_le, sizeof(token_le)); +	*new_length += sizeof(token_le); + +	return nvp.nvram; +} + +void brcmf_fw_nvram_free(void *nvram) +{ +	kfree(nvram); +} + +struct brcmf_fw { +	struct device *dev; +	u16 flags; +	const struct firmware *code; +	const char *nvram_name; +	void (*done)(struct device *dev, const struct firmware *fw, +		     void *nvram_image, u32 nvram_len); +}; + +static void brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx) +{ +	struct brcmf_fw *fwctx = ctx; +	u32 nvram_length = 0; +	void *nvram = NULL; + +	brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev)); +	if (!fw && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL)) +		goto fail; + +	if (fw) { +		nvram = brcmf_fw_nvram_strip(fw, &nvram_length); +		release_firmware(fw); +		if (!nvram && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL)) +			goto fail; +	} + +	fwctx->done(fwctx->dev, fwctx->code, nvram, nvram_length); +	kfree(fwctx); +	return; + +fail: +	brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev)); +	if (fwctx->code) +		release_firmware(fwctx->code); +	device_release_driver(fwctx->dev); +	kfree(fwctx); +} + +static void brcmf_fw_request_code_done(const struct firmware *fw, void *ctx) +{ +	struct brcmf_fw *fwctx = ctx; +	int ret; + +	brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev)); +	if (!fw) +		goto fail; + +	/* only requested code so done here */ +	if (!(fwctx->flags & BRCMF_FW_REQUEST_NVRAM)) { +		fwctx->done(fwctx->dev, fw, NULL, 0); +		kfree(fwctx); +		return; +	} +	fwctx->code = fw; +	ret = request_firmware_nowait(THIS_MODULE, true, fwctx->nvram_name, +				      fwctx->dev, GFP_KERNEL, fwctx, +				      brcmf_fw_request_nvram_done); + +	if (!ret) +		return; + +	/* when nvram is optional call .done() callback here */ +	if (fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL) { +		fwctx->done(fwctx->dev, fw, NULL, 0); +		kfree(fwctx); +		return; +	} + +	/* failed nvram request */ +	release_firmware(fw); +fail: +	brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev)); +	device_release_driver(fwctx->dev); +	kfree(fwctx); +} + +int brcmf_fw_get_firmwares(struct device *dev, u16 flags, +			   const char *code, const char *nvram, +			   void (*fw_cb)(struct device *dev, +					 const struct firmware *fw, +					 void *nvram_image, u32 nvram_len)) +{ +	struct brcmf_fw *fwctx; + +	brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(dev)); +	if (!fw_cb || !code) +		return -EINVAL; + +	if ((flags & BRCMF_FW_REQUEST_NVRAM) && !nvram) +		return -EINVAL; + +	fwctx = kzalloc(sizeof(*fwctx), GFP_KERNEL); +	if (!fwctx) +		return -ENOMEM; + +	fwctx->dev = dev; +	fwctx->flags = flags; +	fwctx->done = fw_cb; +	if (flags & BRCMF_FW_REQUEST_NVRAM) +		fwctx->nvram_name = nvram; + +	return request_firmware_nowait(THIS_MODULE, true, code, dev, +				       GFP_KERNEL, fwctx, +				       brcmf_fw_request_code_done); +} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/firmware.h b/drivers/net/wireless/brcm80211/brcmfmac/firmware.h new file mode 100644 index 00000000000..6431bfd7aff --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef BRCMFMAC_FIRMWARE_H +#define BRCMFMAC_FIRMWARE_H + +#define BRCMF_FW_REQUEST		0x000F +#define  BRCMF_FW_REQUEST_NVRAM		0x0001 +#define BRCMF_FW_REQ_FLAGS		0x00F0 +#define  BRCMF_FW_REQ_NV_OPTIONAL	0x0010 + +void brcmf_fw_nvram_free(void *nvram); +/* + * Request firmware(s) asynchronously. When the asynchronous request + * fails it will not use the callback, but call device_release_driver() + * instead which will call the driver .remove() callback. + */ +int brcmf_fw_get_firmwares(struct device *dev, u16 flags, +			   const char *code, const char *nvram, +			   void (*fw_cb)(struct device *dev, +					 const struct firmware *fw, +					 void *nvram_image, u32 nvram_len)); + +#endif /* BRCMFMAC_FIRMWARE_H */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h index e679214b3c9..51b53a73d07 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h @@ -102,7 +102,8 @@ struct brcmf_event;  	BRCMF_ENUM_DEF(DCS_REQUEST, 73) \  	BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) \  	BRCMF_ENUM_DEF(ACTION_FRAME_RX, 75) \ -	BRCMF_ENUM_DEF(BCMC_CREDIT_SUPPORT, 127) +	BRCMF_ENUM_DEF(BCMC_CREDIT_SUPPORT, 127) \ +	BRCMF_ENUM_DEF(PSTA_PRIMARY_INTF_IND, 128)  #define BRCMF_ENUM_DEF(id, val) \  	BRCMF_E_##id = (val), @@ -114,11 +115,59 @@ enum brcmf_fweh_event_code {  };  #undef BRCMF_ENUM_DEF +#define BRCMF_EVENTING_MASK_LEN		DIV_ROUND_UP(BRCMF_E_LAST, 8) +  /* flags field values in struct brcmf_event_msg */  #define BRCMF_EVENT_MSG_LINK		0x01  #define BRCMF_EVENT_MSG_FLUSHTXQ	0x02  #define BRCMF_EVENT_MSG_GROUP		0x04 +/* status field values in struct brcmf_event_msg */ +#define BRCMF_E_STATUS_SUCCESS			0 +#define BRCMF_E_STATUS_FAIL			1 +#define BRCMF_E_STATUS_TIMEOUT			2 +#define BRCMF_E_STATUS_NO_NETWORKS		3 +#define BRCMF_E_STATUS_ABORT			4 +#define BRCMF_E_STATUS_NO_ACK			5 +#define BRCMF_E_STATUS_UNSOLICITED		6 +#define BRCMF_E_STATUS_ATTEMPT			7 +#define BRCMF_E_STATUS_PARTIAL			8 +#define BRCMF_E_STATUS_NEWSCAN			9 +#define BRCMF_E_STATUS_NEWASSOC			10 +#define BRCMF_E_STATUS_11HQUIET			11 +#define BRCMF_E_STATUS_SUPPRESS			12 +#define BRCMF_E_STATUS_NOCHANS			13 +#define BRCMF_E_STATUS_CS_ABORT			15 +#define BRCMF_E_STATUS_ERROR			16 + +/* reason field values in struct brcmf_event_msg */ +#define BRCMF_E_REASON_INITIAL_ASSOC		0 +#define BRCMF_E_REASON_LOW_RSSI			1 +#define BRCMF_E_REASON_DEAUTH			2 +#define BRCMF_E_REASON_DISASSOC			3 +#define BRCMF_E_REASON_BCNS_LOST		4 +#define BRCMF_E_REASON_MINTXRATE		9 +#define BRCMF_E_REASON_TXFAIL			10 + +#define BRCMF_E_REASON_LINK_BSSCFG_DIS		4 +#define BRCMF_E_REASON_FAST_ROAM_FAILED		5 +#define BRCMF_E_REASON_DIRECTED_ROAM		6 +#define BRCMF_E_REASON_TSPEC_REJECTED		7 +#define BRCMF_E_REASON_BETTER_AP		8 + +/* action field values for brcmf_ifevent */ +#define BRCMF_E_IF_ADD				1 +#define BRCMF_E_IF_DEL				2 +#define BRCMF_E_IF_CHANGE			3 + +/* flag field values for brcmf_ifevent */ +#define BRCMF_E_IF_FLAG_NOIF			1 + +/* role field values for brcmf_ifevent */ +#define BRCMF_E_IF_ROLE_STA			0 +#define BRCMF_E_IF_ROLE_AP			1 +#define BRCMF_E_IF_ROLE_WDS			2 +  /**   * definitions for event packet validation.   */ @@ -157,6 +206,14 @@ struct brcmf_event_msg {  	u8 bsscfgidx;  }; +struct brcmf_if_event { +	u8 ifidx; +	u8 action; +	u8 flags; +	u8 bssidx; +	u8 role; +}; +  typedef int (*brcmf_fweh_handler_t)(struct brcmf_if *ifp,  				    const struct brcmf_event_msg *evtmsg,  				    void *data); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c index 04f395930d8..59a5af5bf99 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c @@ -27,6 +27,7 @@  #include "dhd_dbg.h"  #include "tracepoint.h"  #include "fwil.h" +#include "proto.h"  #define MAX_HEX_DUMP_LEN	64 @@ -46,11 +47,9 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)  	if (data != NULL)  		len = min_t(uint, len, BRCMF_DCMD_MAXLEN);  	if (set) -		err = brcmf_proto_cdc_set_dcmd(drvr, ifp->ifidx, cmd, data, -					       len); +		err = brcmf_proto_set_dcmd(drvr, ifp->ifidx, cmd, data, len);  	else -		err = brcmf_proto_cdc_query_dcmd(drvr, ifp->ifidx, cmd, data, -						 len); +		err = brcmf_proto_query_dcmd(drvr, ifp->ifidx, cmd, data, len);  	if (err >= 0)  		err = 0; @@ -69,7 +68,7 @@ brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len)  	brcmf_dbg(FIL, "cmd=%d, len=%d\n", cmd, len);  	brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, -			   min_t(uint, len, MAX_HEX_DUMP_LEN), "data"); +			   min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");  	err = brcmf_fil_cmd_data(ifp, cmd, data, len, true);  	mutex_unlock(&ifp->drvr->proto_block); @@ -87,7 +86,7 @@ brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len)  	brcmf_dbg(FIL, "cmd=%d, len=%d\n", cmd, len);  	brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, -			   min_t(uint, len, MAX_HEX_DUMP_LEN), "data"); +			   min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");  	mutex_unlock(&ifp->drvr->proto_block); @@ -125,7 +124,8 @@ brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data)  }  static u32 -brcmf_create_iovar(char *name, char *data, u32 datalen, char *buf, u32 buflen) +brcmf_create_iovar(char *name, const char *data, u32 datalen, +		   char *buf, u32 buflen)  {  	u32 len; @@ -145,7 +145,7 @@ brcmf_create_iovar(char *name, char *data, u32 datalen, char *buf, u32 buflen)  s32 -brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, void *data, +brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, const void *data,  			 u32 len)  {  	struct brcmf_pub *drvr = ifp->drvr; @@ -156,7 +156,7 @@ brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, void *data,  	brcmf_dbg(FIL, "name=%s, len=%d\n", name, len);  	brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, -			   min_t(uint, len, MAX_HEX_DUMP_LEN), "data"); +			   min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");  	buflen = brcmf_create_iovar(name, data, len, drvr->proto_buf,  				    sizeof(drvr->proto_buf)); @@ -196,7 +196,7 @@ brcmf_fil_iovar_data_get(struct brcmf_if *ifp, char *name, void *data,  	brcmf_dbg(FIL, "name=%s, len=%d\n", name, len);  	brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, -			   min_t(uint, len, MAX_HEX_DUMP_LEN), "data"); +			   min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");  	mutex_unlock(&drvr->proto_block);  	return err; @@ -279,7 +279,7 @@ brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, char *name,  	brcmf_dbg(FIL, "bssidx=%d, name=%s, len=%d\n", ifp->bssidx, name, len);  	brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, -			   min_t(uint, len, MAX_HEX_DUMP_LEN), "data"); +			   min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");  	buflen = brcmf_create_bsscfg(ifp->bssidx, name, data, len,  				     drvr->proto_buf, sizeof(drvr->proto_buf)); @@ -318,7 +318,7 @@ brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, char *name,  	}  	brcmf_dbg(FIL, "bssidx=%d, name=%s, len=%d\n", ifp->bssidx, name, len);  	brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, -			   min_t(uint, len, MAX_HEX_DUMP_LEN), "data"); +			   min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");  	mutex_unlock(&drvr->proto_block);  	return err; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil.h index 16eb8202fb1..a30be683f4a 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.h @@ -17,12 +17,73 @@  #ifndef _fwil_h_  #define _fwil_h_ +/******************************************************************************* + * Dongle command codes that are interpreted by firmware + ******************************************************************************/ +#define BRCMF_C_GET_VERSION			1 +#define BRCMF_C_UP				2 +#define BRCMF_C_DOWN				3 +#define BRCMF_C_SET_PROMISC			10 +#define BRCMF_C_GET_RATE			12 +#define BRCMF_C_GET_INFRA			19 +#define BRCMF_C_SET_INFRA			20 +#define BRCMF_C_GET_AUTH			21 +#define BRCMF_C_SET_AUTH			22 +#define BRCMF_C_GET_BSSID			23 +#define BRCMF_C_GET_SSID			25 +#define BRCMF_C_SET_SSID			26 +#define BRCMF_C_TERMINATED			28 +#define BRCMF_C_GET_CHANNEL			29 +#define BRCMF_C_SET_CHANNEL			30 +#define BRCMF_C_GET_SRL				31 +#define BRCMF_C_SET_SRL				32 +#define BRCMF_C_GET_LRL				33 +#define BRCMF_C_SET_LRL				34 +#define BRCMF_C_GET_RADIO			37 +#define BRCMF_C_SET_RADIO			38 +#define BRCMF_C_GET_PHYTYPE			39 +#define BRCMF_C_SET_KEY				45 +#define BRCMF_C_SET_PASSIVE_SCAN		49 +#define BRCMF_C_SCAN				50 +#define BRCMF_C_SCAN_RESULTS			51 +#define BRCMF_C_DISASSOC			52 +#define BRCMF_C_REASSOC				53 +#define BRCMF_C_SET_ROAM_TRIGGER		55 +#define BRCMF_C_SET_ROAM_DELTA			57 +#define BRCMF_C_GET_BCNPRD			75 +#define BRCMF_C_SET_BCNPRD			76 +#define BRCMF_C_GET_DTIMPRD			77 +#define BRCMF_C_SET_DTIMPRD			78 +#define BRCMF_C_SET_COUNTRY			84 +#define BRCMF_C_GET_PM				85 +#define BRCMF_C_SET_PM				86 +#define BRCMF_C_GET_CURR_RATESET		114 +#define BRCMF_C_GET_AP				117 +#define BRCMF_C_SET_AP				118 +#define BRCMF_C_GET_RSSI			127 +#define BRCMF_C_GET_WSEC			133 +#define BRCMF_C_SET_WSEC			134 +#define BRCMF_C_GET_PHY_NOISE			135 +#define BRCMF_C_GET_BSS_INFO			136 +#define BRCMF_C_GET_BANDLIST			140 +#define BRCMF_C_SET_SCB_TIMEOUT			158 +#define BRCMF_C_GET_PHYLIST			180 +#define BRCMF_C_SET_SCAN_CHANNEL_TIME		185 +#define BRCMF_C_SET_SCAN_UNASSOC_TIME		187 +#define BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON	201 +#define BRCMF_C_GET_VALID_CHANNELS		217 +#define BRCMF_C_GET_KEY_PRIMARY			235 +#define BRCMF_C_SET_KEY_PRIMARY			236 +#define BRCMF_C_SET_SCAN_PASSIVE_TIME		258 +#define BRCMF_C_GET_VAR				262 +#define BRCMF_C_SET_VAR				263 +  s32 brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len);  s32 brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len);  s32 brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data);  s32 brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data); -s32 brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, void *data, +s32 brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, const void *data,  			     u32 len);  s32 brcmf_fil_iovar_data_get(struct brcmf_if *ifp, char *name, void *data,  			     u32 len); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h index ecabb04f33c..2bc68a2137f 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h @@ -29,6 +29,37 @@  #define BRCMF_ARP_OL_HOST_AUTO_REPLY	0x00000004  #define BRCMF_ARP_OL_PEER_AUTO_REPLY	0x00000008 +#define	BRCMF_BSS_INFO_VERSION	109 /* curr ver of brcmf_bss_info_le struct */ +#define BRCMF_BSS_RSSI_ON_CHANNEL	0x0002 + +#define BRCMF_STA_ASSOC			0x10		/* Associated */ + +/* size of brcmf_scan_params not including variable length array */ +#define BRCMF_SCAN_PARAMS_FIXED_SIZE	64 + +/* masks for channel and ssid count */ +#define BRCMF_SCAN_PARAMS_COUNT_MASK	0x0000ffff +#define BRCMF_SCAN_PARAMS_NSSID_SHIFT	16 + +/* primary (ie tx) key */ +#define BRCMF_PRIMARY_KEY		(1 << 1) +#define DOT11_BSSTYPE_ANY		2 +#define BRCMF_ESCAN_REQ_VERSION		1 + +#define BRCMF_MAXRATES_IN_SET		16	/* max # of rates in rateset */ + +/* OBSS Coex Auto/On/Off */ +#define BRCMF_OBSS_COEX_AUTO		(-1) +#define BRCMF_OBSS_COEX_OFF		0 +#define BRCMF_OBSS_COEX_ON		1 + +/* join preference types for join_pref iovar */ +enum brcmf_join_pref_types { +	BRCMF_JOIN_PREF_RSSI = 1, +	BRCMF_JOIN_PREF_WPA, +	BRCMF_JOIN_PREF_BAND, +	BRCMF_JOIN_PREF_RSSI_DELTA, +};  enum brcmf_fil_p2p_if_types {  	BRCMF_FIL_P2P_IF_CLIENT, @@ -69,6 +100,11 @@ struct brcmf_fil_bss_enable_le {  	__le32 enable;  }; +struct brcmf_fil_bwcap_le { +	__le32 band; +	__le32 bw_cap; +}; +  /**   * struct tdls_iovar - common structure for tdls iovars.   * @@ -90,4 +126,306 @@ enum brcmf_tdls_manual_ep_ops {  	BRCMF_TDLS_MANUAL_EP_DISCOVERY = 6  }; +/* Pattern matching filter. Specifies an offset within received packets to + * start matching, the pattern to match, the size of the pattern, and a bitmask + * that indicates which bits within the pattern should be matched. + */ +struct brcmf_pkt_filter_pattern_le { +	/* +	 * Offset within received packet to start pattern matching. +	 * Offset '0' is the first byte of the ethernet header. +	 */ +	__le32 offset; +	/* Size of the pattern.  Bitmask must be the same size.*/ +	__le32 size_bytes; +	/* +	 * Variable length mask and pattern data. mask starts at offset 0. +	 * Pattern immediately follows mask. +	 */ +	u8 mask_and_pattern[1]; +}; + +/* IOVAR "pkt_filter_add" parameter. Used to install packet filters. */ +struct brcmf_pkt_filter_le { +	__le32 id;		/* Unique filter id, specified by app. */ +	__le32 type;		/* Filter type (WL_PKT_FILTER_TYPE_xxx). */ +	__le32 negate_match;	/* Negate the result of filter matches */ +	union {			/* Filter definitions */ +		struct brcmf_pkt_filter_pattern_le pattern; /* Filter pattern */ +	} u; +}; + +/* IOVAR "pkt_filter_enable" parameter. */ +struct brcmf_pkt_filter_enable_le { +	__le32 id;		/* Unique filter id */ +	__le32 enable;		/* Enable/disable bool */ +}; + +/* BSS info structure + * Applications MUST CHECK ie_offset field and length field to access IEs and + * next bss_info structure in a vector (in struct brcmf_scan_results) + */ +struct brcmf_bss_info_le { +	__le32 version;		/* version field */ +	__le32 length;		/* byte length of data in this record, +				 * starting at version and including IEs +				 */ +	u8 BSSID[ETH_ALEN]; +	__le16 beacon_period;	/* units are Kusec */ +	__le16 capability;	/* Capability information */ +	u8 SSID_len; +	u8 SSID[32]; +	struct { +		__le32 count;   /* # rates in this set */ +		u8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ +	} rateset;		/* supported rates */ +	__le16 chanspec;	/* chanspec for bss */ +	__le16 atim_window;	/* units are Kusec */ +	u8 dtim_period;	/* DTIM period */ +	__le16 RSSI;		/* receive signal strength (in dBm) */ +	s8 phy_noise;		/* noise (in dBm) */ + +	u8 n_cap;		/* BSS is 802.11N Capable */ +	/* 802.11N BSS Capabilities (based on HT_CAP_*): */ +	__le32 nbss_cap; +	u8 ctl_ch;		/* 802.11N BSS control channel number */ +	__le32 reserved32[1];	/* Reserved for expansion of BSS properties */ +	u8 flags;		/* flags */ +	u8 reserved[3];	/* Reserved for expansion of BSS properties */ +	u8 basic_mcs[MCSSET_LEN];	/* 802.11N BSS required MCS set */ + +	__le16 ie_offset;	/* offset at which IEs start, from beginning */ +	__le32 ie_length;	/* byte length of Information Elements */ +	__le16 SNR;		/* average SNR of during frame reception */ +	/* Add new fields here */ +	/* variable length Information Elements */ +}; + +struct brcm_rateset_le { +	/* # rates in this set */ +	__le32 count; +	/* rates in 500kbps units w/hi bit set if basic */ +	u8 rates[BRCMF_MAXRATES_IN_SET]; +}; + +struct brcmf_ssid { +	u32 SSID_len; +	unsigned char SSID[32]; +}; + +struct brcmf_ssid_le { +	__le32 SSID_len; +	unsigned char SSID[32]; +}; + +struct brcmf_scan_params_le { +	struct brcmf_ssid_le ssid_le;	/* default: {0, ""} */ +	u8 bssid[ETH_ALEN];	/* default: bcast */ +	s8 bss_type;		/* default: any, +				 * DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT +				 */ +	u8 scan_type;	/* flags, 0 use default */ +	__le32 nprobes;	  /* -1 use default, number of probes per channel */ +	__le32 active_time;	/* -1 use default, dwell time per channel for +				 * active scanning +				 */ +	__le32 passive_time;	/* -1 use default, dwell time per channel +				 * for passive scanning +				 */ +	__le32 home_time;	/* -1 use default, dwell time for the +				 * home channel between channel scans +				 */ +	__le32 channel_num;	/* count of channels and ssids that follow +				 * +				 * low half is count of channels in +				 * channel_list, 0 means default (use all +				 * available channels) +				 * +				 * high half is entries in struct brcmf_ssid +				 * array that follows channel_list, aligned for +				 * s32 (4 bytes) meaning an odd channel count +				 * implies a 2-byte pad between end of +				 * channel_list and first ssid +				 * +				 * if ssid count is zero, single ssid in the +				 * fixed parameter portion is assumed, otherwise +				 * ssid in the fixed portion is ignored +				 */ +	__le16 channel_list[1];	/* list of chanspecs */ +}; + +struct brcmf_scan_results { +	u32 buflen; +	u32 version; +	u32 count; +	struct brcmf_bss_info_le bss_info_le[]; +}; + +struct brcmf_escan_params_le { +	__le32 version; +	__le16 action; +	__le16 sync_id; +	struct brcmf_scan_params_le params_le; +}; + +struct brcmf_escan_result_le { +	__le32 buflen; +	__le32 version; +	__le16 sync_id; +	__le16 bss_count; +	struct brcmf_bss_info_le bss_info_le; +}; + +#define WL_ESCAN_RESULTS_FIXED_SIZE (sizeof(struct brcmf_escan_result_le) - \ +	sizeof(struct brcmf_bss_info_le)) + +/* used for association with a specific BSSID and chanspec list */ +struct brcmf_assoc_params_le { +	/* 00:00:00:00:00:00: broadcast scan */ +	u8 bssid[ETH_ALEN]; +	/* 0: all available channels, otherwise count of chanspecs in +	 * chanspec_list */ +	__le32 chanspec_num; +	/* list of chanspecs */ +	__le16 chanspec_list[1]; +}; + +/** + * struct join_pref params - parameters for preferred join selection. + * + * @type: preference type (see enum brcmf_join_pref_types). + * @len: length of bytes following (currently always 2). + * @rssi_gain: signal gain for selection (only when @type is RSSI_DELTA). + * @band: band to which selection preference applies. + *	This is used if @type is BAND or RSSI_DELTA. + */ +struct brcmf_join_pref_params { +	u8 type; +	u8 len; +	u8 rssi_gain; +	u8 band; +}; + +/* used for join with or without a specific bssid and channel list */ +struct brcmf_join_params { +	struct brcmf_ssid_le ssid_le; +	struct brcmf_assoc_params_le params_le; +}; + +/* scan params for extended join */ +struct brcmf_join_scan_params_le { +	u8 scan_type;		/* 0 use default, active or passive scan */ +	__le32 nprobes;		/* -1 use default, nr of probes per channel */ +	__le32 active_time;	/* -1 use default, dwell time per channel for +				 * active scanning +				 */ +	__le32 passive_time;	/* -1 use default, dwell time per channel +				 * for passive scanning +				 */ +	__le32 home_time;	/* -1 use default, dwell time for the home +				 * channel between channel scans +				 */ +}; + +/* extended join params */ +struct brcmf_ext_join_params_le { +	struct brcmf_ssid_le ssid_le;	/* {0, ""}: wildcard scan */ +	struct brcmf_join_scan_params_le scan_le; +	struct brcmf_assoc_params_le assoc_le; +}; + +struct brcmf_wsec_key { +	u32 index;		/* key index */ +	u32 len;		/* key length */ +	u8 data[WLAN_MAX_KEY_LEN];	/* key data */ +	u32 pad_1[18]; +	u32 algo;	/* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */ +	u32 flags;	/* misc flags */ +	u32 pad_2[3]; +	u32 iv_initialized;	/* has IV been initialized already? */ +	u32 pad_3; +	/* Rx IV */ +	struct { +		u32 hi;	/* upper 32 bits of IV */ +		u16 lo;	/* lower 16 bits of IV */ +	} rxiv; +	u32 pad_4[2]; +	u8 ea[ETH_ALEN];	/* per station */ +}; + +/* + * dongle requires same struct as above but with fields in little endian order + */ +struct brcmf_wsec_key_le { +	__le32 index;		/* key index */ +	__le32 len;		/* key length */ +	u8 data[WLAN_MAX_KEY_LEN];	/* key data */ +	__le32 pad_1[18]; +	__le32 algo;	/* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */ +	__le32 flags;	/* misc flags */ +	__le32 pad_2[3]; +	__le32 iv_initialized;	/* has IV been initialized already? */ +	__le32 pad_3; +	/* Rx IV */ +	struct { +		__le32 hi;	/* upper 32 bits of IV */ +		__le16 lo;	/* lower 16 bits of IV */ +	} rxiv; +	__le32 pad_4[2]; +	u8 ea[ETH_ALEN];	/* per station */ +}; + +/* Used to get specific STA parameters */ +struct brcmf_scb_val_le { +	__le32 val; +	u8 ea[ETH_ALEN]; +}; + +/* channel encoding */ +struct brcmf_channel_info_le { +	__le32 hw_channel; +	__le32 target_channel; +	__le32 scan_channel; +}; + +struct brcmf_sta_info_le { +	__le16	ver;		/* version of this struct */ +	__le16	len;		/* length in bytes of this structure */ +	__le16	cap;		/* sta's advertised capabilities */ +	__le32	flags;		/* flags defined below */ +	__le32	idle;		/* time since data pkt rx'd from sta */ +	u8	ea[ETH_ALEN];		/* Station address */ +	__le32	count;			/* # rates in this set */ +	u8	rates[BRCMF_MAXRATES_IN_SET];	/* rates in 500kbps units */ +						/* w/hi bit set if basic */ +	__le32	in;		/* seconds elapsed since associated */ +	__le32	listen_interval_inms; /* Min Listen interval in ms for STA */ +	__le32	tx_pkts;	/* # of packets transmitted */ +	__le32	tx_failures;	/* # of packets failed */ +	__le32	rx_ucast_pkts;	/* # of unicast packets received */ +	__le32	rx_mcast_pkts;	/* # of multicast packets received */ +	__le32	tx_rate;	/* Rate of last successful tx frame */ +	__le32	rx_rate;	/* Rate of last successful rx frame */ +	__le32	rx_decrypt_succeeds;	/* # of packet decrypted successfully */ +	__le32	rx_decrypt_failures;	/* # of packet decrypted failed */ +}; + +struct brcmf_chanspec_list { +	__le32	count;		/* # of entries */ +	__le32	element[1];	/* variable length uint32 list */ +}; + +/* + * WLC_E_PROBRESP_MSG + * WLC_E_P2P_PROBREQ_MSG + * WLC_E_ACTION_FRAME_RX + */ +struct brcmf_rx_mgmt_data { +	__be16	version; +	__be16	chanspec; +	__be32	rssi; +	__be32	mactime; +	__be32	rate; +}; +  #endif /* FWIL_TYPES_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c index 82f9140f3d3..699908de314 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c @@ -27,7 +27,6 @@  #include <brcmu_utils.h>  #include <brcmu_wifi.h>  #include "dhd.h" -#include "dhd_proto.h"  #include "dhd_dbg.h"  #include "dhd_bus.h"  #include "fwil.h" @@ -36,6 +35,7 @@  #include "fwsignal.h"  #include "p2p.h"  #include "wl_cfg80211.h" +#include "proto.h"  /**   * DOC: Firmware Signalling @@ -105,6 +105,7 @@ static struct {  };  #undef BRCMF_FWS_TLV_DEF +  static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)  {  	int i; @@ -123,6 +124,12 @@ static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)  #endif /* DEBUG */  /* + * The PKTTAG tlv has additional bytes when firmware-signalling + * mode has REUSESEQ flag set. + */ +#define BRCMF_FWS_TYPE_SEQ_LEN				2 + +/*   * flags used to enable tlv signalling from firmware.   */  #define BRCMF_FWS_FLAGS_RSSI_SIGNALS			0x0001 @@ -147,8 +154,15 @@ static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)  #define BRCMF_FWS_HTOD_FLAG_PKTFROMHOST			0x01  #define BRCMF_FWS_HTOD_FLAG_PKT_REQUESTED		0x02 -#define BRCMF_FWS_RET_OK_NOSCHEDULE	0 -#define BRCMF_FWS_RET_OK_SCHEDULE	1 +#define BRCMF_FWS_RET_OK_NOSCHEDULE			0 +#define BRCMF_FWS_RET_OK_SCHEDULE			1 + +#define BRCMF_FWS_MODE_REUSESEQ_SHIFT			3	/* seq reuse */ +#define BRCMF_FWS_MODE_SET_REUSESEQ(x, val)	((x) = \ +		((x) & ~(1 << BRCMF_FWS_MODE_REUSESEQ_SHIFT)) | \ +		(((val) & 1) << BRCMF_FWS_MODE_REUSESEQ_SHIFT)) +#define BRCMF_FWS_MODE_GET_REUSESEQ(x)	\ +		(((x) >> BRCMF_FWS_MODE_REUSESEQ_SHIFT) & 1)  /**   * enum brcmf_fws_skb_state - indicates processing state of skb. @@ -168,8 +182,10 @@ enum brcmf_fws_skb_state {  /**   * struct brcmf_skbuff_cb - control buffer associated with skbuff.   * + * @bus_flags: 2 bytes reserved for bus specific parameters   * @if_flags: holds interface index and packet related flags.   * @htod: host to device packet identifier (used in PKTTAG tlv). + * @htod_seq: this 16-bit is original seq number for every suppress packet.   * @state: transmit state of the packet.   * @mac: descriptor related to destination for this packet.   * @@ -177,8 +193,10 @@ enum brcmf_fws_skb_state {   * provides 48 bytes of storage so this structure should not exceed that.   */  struct brcmf_skbuff_cb { +	u16 bus_flags;  	u16 if_flags;  	u32 htod; +	u16 htod_seq;  	enum brcmf_fws_skb_state state;  	struct brcmf_fws_mac_descriptor *mac;  }; @@ -255,6 +273,22 @@ struct brcmf_skbuff_cb {  			BRCMF_SKB_HTOD_TAG_ ## field ## _MASK, \  			BRCMF_SKB_HTOD_TAG_ ## field ## _SHIFT) +#define BRCMF_SKB_HTOD_SEQ_FROMFW_MASK			0x2000 +#define BRCMF_SKB_HTOD_SEQ_FROMFW_SHIFT			13 +#define BRCMF_SKB_HTOD_SEQ_FROMDRV_MASK			0x1000 +#define BRCMF_SKB_HTOD_SEQ_FROMDRV_SHIFT		12 +#define BRCMF_SKB_HTOD_SEQ_NR_MASK			0x0fff +#define BRCMF_SKB_HTOD_SEQ_NR_SHIFT			0 + +#define brcmf_skb_htod_seq_set_field(skb, field, value) \ +	brcmu_maskset16(&(brcmf_skbcb(skb)->htod_seq), \ +			BRCMF_SKB_HTOD_SEQ_ ## field ## _MASK, \ +			BRCMF_SKB_HTOD_SEQ_ ## field ## _SHIFT, (value)) +#define brcmf_skb_htod_seq_get_field(skb, field) \ +	brcmu_maskget16(brcmf_skbcb(skb)->htod_seq, \ +			BRCMF_SKB_HTOD_SEQ_ ## field ## _MASK, \ +			BRCMF_SKB_HTOD_SEQ_ ## field ## _SHIFT) +  #define BRCMF_FWS_TXSTAT_GENERATION_MASK	0x80000000  #define BRCMF_FWS_TXSTAT_GENERATION_SHIFT	31  #define BRCMF_FWS_TXSTAT_FLAGS_MASK		0x78000000 @@ -263,8 +297,8 @@ struct brcmf_skbuff_cb {  #define BRCMF_FWS_TXSTAT_FIFO_SHIFT		24  #define BRCMF_FWS_TXSTAT_HSLOT_MASK		0x00FFFF00  #define BRCMF_FWS_TXSTAT_HSLOT_SHIFT		8 -#define BRCMF_FWS_TXSTAT_PKTID_MASK		0x00FFFFFF -#define BRCMF_FWS_TXSTAT_PKTID_SHIFT		0 +#define BRCMF_FWS_TXSTAT_FREERUN_MASK		0x000000FF +#define BRCMF_FWS_TXSTAT_FREERUN_SHIFT		0  #define brcmf_txstatus_get_field(txs, field) \  	brcmu_maskget32(txs, BRCMF_FWS_TXSTAT_ ## field ## _MASK, \ @@ -441,6 +475,8 @@ struct brcmf_fws_info {  	unsigned long borrow_defer_timestamp;  	bool bus_flow_blocked;  	bool creditmap_received; +	u8 mode; +	bool avoid_queueing;  };  /* @@ -803,20 +839,23 @@ static void brcmf_fws_cleanup(struct brcmf_fws_info *fws, int ifidx)  	brcmf_fws_hanger_cleanup(fws, matchfn, ifidx);  } -static int brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb) +static u8 brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb)  {  	struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;  	u8 *wlh;  	u16 data_offset = 0;  	u8 fillers;  	__le32 pkttag = cpu_to_le32(brcmf_skbcb(skb)->htod); +	__le16 pktseq = cpu_to_le16(brcmf_skbcb(skb)->htod_seq); -	brcmf_dbg(TRACE, "enter: %s, idx=%d pkttag=0x%08X, hslot=%d\n", +	brcmf_dbg(TRACE, "enter: %s, idx=%d hslot=%d htod %X seq %X\n",  		  entry->name, brcmf_skb_if_flags_get_field(skb, INDEX), -		  le32_to_cpu(pkttag), (le32_to_cpu(pkttag) >> 8) & 0xffff); +		  (le32_to_cpu(pkttag) >> 8) & 0xffff, +		  brcmf_skbcb(skb)->htod, brcmf_skbcb(skb)->htod_seq);  	if (entry->send_tim_signal)  		data_offset += 2 + BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN; - +	if (BRCMF_FWS_MODE_GET_REUSESEQ(fws->mode)) +		data_offset += BRCMF_FWS_TYPE_SEQ_LEN;  	/* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */  	data_offset += 2 + BRCMF_FWS_TYPE_PKTTAG_LEN;  	fillers = round_up(data_offset, 4) - data_offset; @@ -828,7 +867,12 @@ static int brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb)  	wlh[0] = BRCMF_FWS_TYPE_PKTTAG;  	wlh[1] = BRCMF_FWS_TYPE_PKTTAG_LEN;  	memcpy(&wlh[2], &pkttag, sizeof(pkttag)); -	wlh += BRCMF_FWS_TYPE_PKTTAG_LEN + 2; +	if (BRCMF_FWS_MODE_GET_REUSESEQ(fws->mode)) { +		wlh[1] += BRCMF_FWS_TYPE_SEQ_LEN; +		memcpy(&wlh[2 + BRCMF_FWS_TYPE_PKTTAG_LEN], &pktseq, +		       sizeof(pktseq)); +	} +	wlh += wlh[1] + 2;  	if (entry->send_tim_signal) {  		entry->send_tim_signal = 0; @@ -844,9 +888,7 @@ static int brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb)  	if (fillers)  		memset(wlh, BRCMF_FWS_TYPE_FILLER, fillers); -	brcmf_proto_hdrpush(fws->drvr, brcmf_skb_if_flags_get_field(skb, INDEX), -			    data_offset >> 2, skb); -	return 0; +	return (u8)(data_offset >> 2);  }  static bool brcmf_fws_tim_update(struct brcmf_fws_info *fws, @@ -854,10 +896,11 @@ static bool brcmf_fws_tim_update(struct brcmf_fws_info *fws,  				 int fifo, bool send_immediately)  {  	struct sk_buff *skb; -	struct brcmf_bus *bus;  	struct brcmf_skbuff_cb *skcb;  	s32 err;  	u32 len; +	u8 data_offset; +	int ifidx;  	/* check delayedQ and suppressQ in one call using bitmap */  	if (brcmu_pktq_mlen(&entry->psq, 3 << (fifo * 2)) == 0) @@ -873,6 +916,7 @@ static bool brcmf_fws_tim_update(struct brcmf_fws_info *fws,  		/* create a dummy packet and sent that. The traffic          */  		/* bitmap info will automatically be attached to that packet */  		len = BRCMF_FWS_TYPE_PKTTAG_LEN + 2 + +		      BRCMF_FWS_TYPE_SEQ_LEN +  		      BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN + 2 +  		      4 + fws->drvr->hdrlen;  		skb = brcmu_pkt_buf_get_skb(len); @@ -882,13 +926,13 @@ static bool brcmf_fws_tim_update(struct brcmf_fws_info *fws,  		skcb = brcmf_skbcb(skb);  		skcb->mac = entry;  		skcb->state = BRCMF_FWS_SKBSTATE_TIM; -		bus = fws->drvr->bus_if; -		err = brcmf_fws_hdrpush(fws, skb); -		if (err == 0) { -			brcmf_fws_unlock(fws); -			err = brcmf_bus_txdata(bus, skb); -			brcmf_fws_lock(fws); -		} +		skcb->htod = 0; +		skcb->htod_seq = 0; +		data_offset = brcmf_fws_hdrpush(fws, skb); +		ifidx = brcmf_skb_if_flags_get_field(skb, INDEX); +		brcmf_fws_unlock(fws); +		err = brcmf_proto_txdata(fws->drvr, ifidx, data_offset, skb); +		brcmf_fws_lock(fws);  		if (err)  			brcmu_pkt_buf_free_skb(skb);  		return true; @@ -1170,8 +1214,13 @@ static int brcmf_fws_enq(struct brcmf_fws_info *fws,  {  	int prec = 2 * fifo;  	u32 *qfull_stat = &fws->stats.delayq_full_error; -  	struct brcmf_fws_mac_descriptor *entry; +	struct pktq *pq; +	struct sk_buff_head *queue; +	struct sk_buff *p_head; +	struct sk_buff *p_tail; +	u32 fr_new; +	u32 fr_compare;  	entry = brcmf_skbcb(p)->mac;  	if (entry == NULL) { @@ -1183,9 +1232,55 @@ static int brcmf_fws_enq(struct brcmf_fws_info *fws,  	if (state == BRCMF_FWS_SKBSTATE_SUPPRESSED) {  		prec += 1;  		qfull_stat = &fws->stats.supprq_full_error; -	} -	if (brcmu_pktq_penq(&entry->psq, prec, p) == NULL) { +		/* Fix out of order delivery of frames. Dont assume frame    */ +		/* can be inserted at the end, but look for correct position */ +		pq = &entry->psq; +		if (pktq_full(pq) || pktq_pfull(pq, prec)) { +			*qfull_stat += 1; +			return -ENFILE; +		} +		queue = &pq->q[prec].skblist; + +		p_head = skb_peek(queue); +		p_tail = skb_peek_tail(queue); +		fr_new = brcmf_skb_htod_tag_get_field(p, FREERUN); + +		while (p_head != p_tail) { +			fr_compare = brcmf_skb_htod_tag_get_field(p_tail, +								  FREERUN); +			/* be sure to handle wrap of 256 */ +			if (((fr_new > fr_compare) && +			     ((fr_new - fr_compare) < 128)) || +			    ((fr_new < fr_compare) && +			     ((fr_compare - fr_new) > 128))) +				break; +			p_tail = skb_queue_prev(queue, p_tail); +		} +		/* Position found. Determine what to do */ +		if (p_tail == NULL) { +			/* empty list */ +			__skb_queue_tail(queue, p); +		} else { +			fr_compare = brcmf_skb_htod_tag_get_field(p_tail, +								  FREERUN); +			if (((fr_new > fr_compare) && +			     ((fr_new - fr_compare) < 128)) || +			    ((fr_new < fr_compare) && +			     ((fr_compare - fr_new) > 128))) { +				/* After tail */ +				__skb_queue_after(queue, p_tail, p); +			} else { +				/* Before tail */ +				__skb_insert(p, p_tail->prev, p_tail, queue); +			} +		} + +		/* Complete the counters and statistics */ +		pq->len++; +		if (pq->hi_prec < prec) +			pq->hi_prec = (u8) prec; +	} else if (brcmu_pktq_penq(&entry->psq, prec, p) == NULL) {  		*qfull_stat += 1;  		return -ENFILE;  	} @@ -1275,12 +1370,12 @@ done:  }  static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo, -					 struct sk_buff *skb, u32 genbit) +					 struct sk_buff *skb, u8 ifidx, +					 u32 genbit, u16 seq)  {  	struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;  	u32 hslot;  	int ret; -	u8 ifidx;  	hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT); @@ -1294,19 +1389,21 @@ static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo,  	entry->generation = genbit; -	ret = brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb); -	if (ret == 0) -		ret = brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_SUPPRESSED, fifo, -				    skb); +	brcmf_skb_htod_tag_set_field(skb, GENERATION, genbit); +	brcmf_skbcb(skb)->htod_seq = seq; +	if (brcmf_skb_htod_seq_get_field(skb, FROMFW)) { +		brcmf_skb_htod_seq_set_field(skb, FROMDRV, 1); +		brcmf_skb_htod_seq_set_field(skb, FROMFW, 0); +	} else { +		brcmf_skb_htod_seq_set_field(skb, FROMDRV, 0); +	} +	ret = brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_SUPPRESSED, fifo, skb); +  	if (ret != 0) { -		/* suppress q is full or hdrpull failed, drop this packet */ -		brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb, -					true); +		/* suppress q is full drop this packet */ +		brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb, true);  	} else { -		/* -		 * Mark suppressed to avoid a double free during -		 * wlfc cleanup -		 */ +		/* Mark suppressed to avoid a double free during wlfc cleanup */  		brcmf_fws_hanger_mark_suppressed(&fws->hanger, hslot);  	} @@ -1315,7 +1412,7 @@ static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo,  static int  brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot, -			   u32 genbit) +		      u32 genbit, u16 seq)  {  	u32 fifo;  	int ret; @@ -1323,6 +1420,7 @@ brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,  	struct sk_buff *skb;  	struct brcmf_skbuff_cb *skcb;  	struct brcmf_fws_mac_descriptor *entry = NULL; +	u8 ifidx;  	brcmf_dbg(DATA, "flags %d\n", flags); @@ -1358,8 +1456,8 @@ brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,  	if (entry->suppressed && entry->suppr_transit_count)  		entry->suppr_transit_count--; -	brcmf_dbg(DATA, "%s flags %X htod %X\n", entry->name, skcb->if_flags, -		  skcb->htod); +	brcmf_dbg(DATA, "%s flags %d htod %X seq %X\n", entry->name, flags, +		  skcb->htod, seq);  	/* pick up the implicit credit from this packet */  	fifo = brcmf_skb_htod_tag_get_field(skb, FIFO); @@ -1371,11 +1469,15 @@ brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,  	}  	brcmf_fws_macdesc_return_req_credit(skb); +	if (brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb)) { +		brcmu_pkt_buf_free_skb(skb); +		return -EINVAL; +	}  	if (!remove_from_hanger) -		ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, genbit); - +		ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, ifidx, +						    genbit, seq);  	if (remove_from_hanger || ret) -		brcmf_txfinalize(fws->drvr, skb, true); +		brcmf_txfinalize(fws->drvr, skb, ifidx, true);  	return 0;  } @@ -1404,10 +1506,12 @@ static int brcmf_fws_fifocreditback_indicate(struct brcmf_fws_info *fws,  static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data)  {  	__le32 status_le; +	__le16 seq_le;  	u32 status;  	u32 hslot;  	u32 genbit;  	u8 flags; +	u16 seq;  	fws->stats.txs_indicate++;  	memcpy(&status_le, data, sizeof(status_le)); @@ -1415,9 +1519,16 @@ static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data)  	flags = brcmf_txstatus_get_field(status, FLAGS);  	hslot = brcmf_txstatus_get_field(status, HSLOT);  	genbit = brcmf_txstatus_get_field(status, GENERATION); +	if (BRCMF_FWS_MODE_GET_REUSESEQ(fws->mode)) { +		memcpy(&seq_le, &data[BRCMF_FWS_TYPE_PKTTAG_LEN], +		       sizeof(seq_le)); +		seq = le16_to_cpu(seq_le); +	} else { +		seq = 0; +	}  	brcmf_fws_lock(fws); -	brcmf_fws_txs_process(fws, flags, hslot, genbit); +	brcmf_fws_txs_process(fws, flags, hslot, genbit, seq);  	brcmf_fws_unlock(fws);  	return BRCMF_FWS_RET_OK_NOSCHEDULE;  } @@ -1601,15 +1712,15 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,  	return 0;  } -static void brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo, +static u8 brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,  				   struct sk_buff *p)  {  	struct brcmf_skbuff_cb *skcb = brcmf_skbcb(p);  	struct brcmf_fws_mac_descriptor *entry = skcb->mac;  	u8 flags; -	brcmf_skb_if_flags_set_field(p, TRANSMIT, 1); -	brcmf_skb_htod_tag_set_field(p, GENERATION, entry->generation); +	if (skcb->state != BRCMF_FWS_SKBSTATE_SUPPRESSED) +		brcmf_skb_htod_tag_set_field(p, GENERATION, entry->generation);  	flags = BRCMF_FWS_HTOD_FLAG_PKTFROMHOST;  	if (brcmf_skb_if_flags_get_field(p, REQUESTED)) {  		/* @@ -1619,7 +1730,7 @@ static void brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,  		flags |= BRCMF_FWS_HTOD_FLAG_PKT_REQUESTED;  	}  	brcmf_skb_htod_tag_set_field(p, FLAGS, flags); -	brcmf_fws_hdrpush(fws, p); +	return brcmf_fws_hdrpush(fws, p);  }  static void brcmf_fws_rollback_toq(struct brcmf_fws_info *fws, @@ -1650,7 +1761,7 @@ static void brcmf_fws_rollback_toq(struct brcmf_fws_info *fws,  		fws->stats.rollback_failed++;  		hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);  		brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED, -				      hslot, 0); +				      hslot, 0, 0);  	} else {  		fws->stats.rollback_success++;  		brcmf_fws_return_credits(fws, fifo, 1); @@ -1687,20 +1798,21 @@ static int brcmf_fws_commit_skb(struct brcmf_fws_info *fws, int fifo,  {  	struct brcmf_skbuff_cb *skcb = brcmf_skbcb(skb);  	struct brcmf_fws_mac_descriptor *entry; -	struct brcmf_bus *bus = fws->drvr->bus_if;  	int rc;  	u8 ifidx; +	u8 data_offset;  	entry = skcb->mac;  	if (IS_ERR(entry))  		return PTR_ERR(entry); -	brcmf_fws_precommit_skb(fws, fifo, skb); +	data_offset = brcmf_fws_precommit_skb(fws, fifo, skb);  	entry->transit_count++;  	if (entry->suppressed)  		entry->suppr_transit_count++; +	ifidx = brcmf_skb_if_flags_get_field(skb, INDEX);  	brcmf_fws_unlock(fws); -	rc = brcmf_bus_txdata(bus, skb); +	rc = brcmf_proto_txdata(fws->drvr, ifidx, data_offset, skb);  	brcmf_fws_lock(fws);  	brcmf_dbg(DATA, "%s flags %X htod %X bus_tx %d\n", entry->name,  		  skcb->if_flags, skcb->htod, rc); @@ -1730,6 +1842,8 @@ static int brcmf_fws_assign_htod(struct brcmf_fws_info *fws, struct sk_buff *p,  	struct brcmf_skbuff_cb *skcb = brcmf_skbcb(p);  	int rc, hslot; +	skcb->htod = 0; +	skcb->htod_seq = 0;  	hslot = brcmf_fws_hanger_get_free_slot(&fws->hanger);  	brcmf_skb_htod_tag_set_field(p, HSLOT, hslot);  	brcmf_skb_htod_tag_set_field(p, FREERUN, skcb->mac->seq[fifo]); @@ -1750,16 +1864,21 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)  	struct ethhdr *eh = (struct ethhdr *)(skb->data);  	int fifo = BRCMF_FWS_FIFO_BCMC;  	bool multicast = is_multicast_ether_addr(eh->h_dest); -	bool pae = eh->h_proto == htons(ETH_P_PAE); +	int rc = 0;  	brcmf_dbg(DATA, "tx proto=0x%X\n", ntohs(eh->h_proto));  	/* determine the priority */  	if (!skb->priority) -		skb->priority = cfg80211_classify8021d(skb); +		skb->priority = cfg80211_classify8021d(skb, NULL);  	drvr->tx_multicast += !!multicast; -	if (pae) -		atomic_inc(&ifp->pend_8021x_cnt); + +	if (fws->avoid_queueing) { +		rc = brcmf_proto_txdata(drvr, ifp->ifidx, 0, skb); +		if (rc < 0) +			brcmf_txfinalize(drvr, skb, ifp->ifidx, false); +		return rc; +	}  	/* set control buffer information */  	skcb->if_flags = 0; @@ -1781,15 +1900,12 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)  		brcmf_fws_schedule_deq(fws);  	} else {  		brcmf_err("drop skb: no hanger slot\n"); -		if (pae) { -			atomic_dec(&ifp->pend_8021x_cnt); -			if (waitqueue_active(&ifp->pend_8021x_wait)) -				wake_up(&ifp->pend_8021x_wait); -		} -		brcmu_pkt_buf_free_skb(skb); +		brcmf_txfinalize(drvr, skb, ifp->ifidx, false); +		rc = -ENOMEM;  	}  	brcmf_fws_unlock(fws); -	return 0; + +	return rc;  }  void brcmf_fws_reset_interface(struct brcmf_if *ifp) @@ -1859,13 +1975,13 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker)  							&skb, true);  				ifidx = brcmf_skb_if_flags_get_field(skb,  								     INDEX); -				brcmf_proto_hdrpush(drvr, ifidx, 0, skb); -				/* Use bus module to send data frame */ +				/* Use proto layer to send data frame */  				brcmf_fws_unlock(fws); -				ret = brcmf_bus_txdata(drvr->bus_if, skb); +				ret = brcmf_proto_txdata(drvr, ifidx, 0, skb);  				brcmf_fws_lock(fws);  				if (ret < 0) -					brcmf_txfinalize(drvr, skb, false); +					brcmf_txfinalize(drvr, skb, ifidx, +							 false);  				if (fws->bus_flow_blocked)  					break;  			} @@ -1906,6 +2022,7 @@ int brcmf_fws_init(struct brcmf_pub *drvr)  	struct brcmf_fws_info *fws;  	u32 tlv = BRCMF_FWS_FLAGS_RSSI_SIGNALS;  	int rc; +	u32 mode;  	drvr->fws = kzalloc(sizeof(*(drvr->fws)), GFP_KERNEL);  	if (!drvr->fws) { @@ -1921,6 +2038,13 @@ int brcmf_fws_init(struct brcmf_pub *drvr)  	fws->drvr = drvr;  	fws->fcmode = fcmode; +	if ((drvr->bus_if->always_use_fws_queue == false) && +	    (fcmode == BRCMF_FWS_FCMODE_NONE)) { +		fws->avoid_queueing = true; +		brcmf_dbg(INFO, "FWS queueing will be avoided\n"); +		return 0; +	} +  	fws->fws_wq = create_singlethread_workqueue("brcmf_fws_wq");  	if (fws->fws_wq == NULL) {  		brcmf_err("workqueue creation failed\n"); @@ -1964,6 +2088,18 @@ int brcmf_fws_init(struct brcmf_pub *drvr)  	if (brcmf_fil_iovar_int_set(drvr->iflist[0], "ampdu_hostreorder", 1))  		brcmf_dbg(INFO, "enabling AMPDU host-reorder failed\n"); +	/* Enable seq number reuse, if supported */ +	if (brcmf_fil_iovar_int_get(drvr->iflist[0], "wlfc_mode", &mode) == 0) { +		if (BRCMF_FWS_MODE_GET_REUSESEQ(mode)) { +			mode = 0; +			BRCMF_FWS_MODE_SET_REUSESEQ(mode, 1); +			if (brcmf_fil_iovar_int_set(drvr->iflist[0], +						    "wlfc_mode", mode) == 0) { +				BRCMF_FWS_MODE_SET_REUSESEQ(fws->mode, 1); +			} +		} +	} +  	brcmf_fws_hanger_init(&fws->hanger);  	brcmf_fws_macdesc_init(&fws->desc.other, NULL, 0);  	brcmf_fws_macdesc_set_name(fws, &fws->desc.other); @@ -2020,7 +2156,7 @@ void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb)  	}  	brcmf_fws_lock(fws);  	hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT); -	brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED, hslot, 0); +	brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED, hslot, 0, 0);  	brcmf_fws_unlock(fws);  } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c index d7a97453290..f3445ac627e 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c @@ -797,7 +797,8 @@ static s32 brcmf_p2p_run_escan(struct brcmf_cfg80211_info *cfg,  			/* SOCIAL CHANNELS 1, 6, 11 */  			search_state = WL_P2P_DISC_ST_SEARCH;  			brcmf_dbg(INFO, "P2P SEARCH PHASE START\n"); -		} else if (dev != NULL && vif->mode == WL_MODE_AP) { +		} else if (dev != NULL && +			   vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) {  			/* If you are already a GO, then do SEARCH only */  			brcmf_dbg(INFO, "Already a GO. Do SEARCH Only\n");  			search_state = WL_P2P_DISC_ST_SEARCH; @@ -812,7 +813,7 @@ static s32 brcmf_p2p_run_escan(struct brcmf_cfg80211_info *cfg,  			struct ieee80211_channel *chan = request->channels[i];  			if (chan->flags & (IEEE80211_CHAN_RADAR | -					   IEEE80211_CHAN_PASSIVE_SCAN)) +					   IEEE80211_CHAN_NO_IR))  				continue;  			chanspecs[i] = channel_to_chanspec(&p2p->cfg->d11inf, @@ -823,6 +824,7 @@ static s32 brcmf_p2p_run_escan(struct brcmf_cfg80211_info *cfg,  		}  		err = brcmf_p2p_escan(p2p, num_nodfs, chanspecs, search_state,  				      action, P2PAPI_BSSCFG_DEVICE); +		kfree(chanspecs);  	}  exit:  	if (err) @@ -1148,7 +1150,7 @@ static s32 brcmf_p2p_af_searching_channel(struct brcmf_p2p_info *p2p)  	pri_vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif; -	INIT_COMPLETION(afx_hdl->act_frm_scan); +	reinit_completion(&afx_hdl->act_frm_scan);  	set_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status);  	afx_hdl->is_active = true;  	afx_hdl->peer_chan = P2P_INVALID_CHANNEL; @@ -1242,7 +1244,7 @@ bool brcmf_p2p_scan_finding_common_channel(struct brcmf_cfg80211_info *cfg,  					    IEEE80211_P2P_ATTR_DEVICE_ID,  					    p2p_dev_addr, sizeof(p2p_dev_addr));  	if ((err >= 0) && -	    (!memcmp(p2p_dev_addr, afx_hdl->tx_dst_addr, ETH_ALEN))) { +	    (ether_addr_equal(p2p_dev_addr, afx_hdl->tx_dst_addr))) {  		if (!bi->ctl_ch) {  			ch.chspec = le16_to_cpu(bi->chanspec);  			cfg->d11inf.decchspec(&ch); @@ -1379,8 +1381,7 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp,  		    (brcmf_p2p_gon_req_collision(p2p, (u8 *)e->addr))) {  			if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL,  				     &p2p->status) && -			    (memcmp(afx_hdl->tx_dst_addr, e->addr, -				    ETH_ALEN) == 0)) { +			    (ether_addr_equal(afx_hdl->tx_dst_addr, e->addr))) {  				afx_hdl->peer_chan = ch.chnum;  				brcmf_dbg(INFO, "GON request: Peer found, channel=%d\n",  					  afx_hdl->peer_chan); @@ -1501,7 +1502,7 @@ static s32 brcmf_p2p_tx_action_frame(struct brcmf_p2p_info *p2p,  	brcmf_dbg(TRACE, "Enter\n"); -	INIT_COMPLETION(p2p->send_af_done); +	reinit_completion(&p2p->send_af_done);  	clear_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status);  	clear_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status); @@ -1864,7 +1865,7 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,  	cfg->d11inf.decchspec(&ch);  	if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status) && -	    (memcmp(afx_hdl->tx_dst_addr, e->addr, ETH_ALEN) == 0)) { +	    (ether_addr_equal(afx_hdl->tx_dst_addr, e->addr))) {  		afx_hdl->peer_chan = ch.chnum;  		brcmf_dbg(INFO, "PROBE REQUEST: Peer found, channel=%d\n",  			  afx_hdl->peer_chan); @@ -1955,21 +1956,21 @@ s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg)  		err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1);  		if (err < 0) {  			brcmf_err("set p2p_disc error\n"); -			brcmf_free_vif(cfg, p2p_vif); +			brcmf_free_vif(p2p_vif);  			goto exit;  		}  		/* obtain bsscfg index for P2P discovery */  		err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bssidx);  		if (err < 0) {  			brcmf_err("retrieving discover bsscfg index failed\n"); -			brcmf_free_vif(cfg, p2p_vif); +			brcmf_free_vif(p2p_vif);  			goto exit;  		}  		/* Verify that firmware uses same bssidx as driver !! */  		if (p2p_ifp->bssidx != bssidx) {  			brcmf_err("Incorrect bssidx=%d, compared to p2p_ifp->bssidx=%d\n",  				  bssidx, p2p_ifp->bssidx); -			brcmf_free_vif(cfg, p2p_vif); +			brcmf_free_vif(p2p_vif);  			goto exit;  		} @@ -1997,7 +1998,7 @@ void brcmf_p2p_detach(struct brcmf_p2p_info *p2p)  		brcmf_p2p_cancel_remain_on_channel(vif->ifp);  		brcmf_p2p_deinit_discovery(p2p);  		/* remove discovery interface */ -		brcmf_free_vif(p2p->cfg, vif); +		brcmf_free_vif(vif);  		p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;  	}  	/* just set it all to zero */ @@ -2222,7 +2223,7 @@ static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p,  	return &p2p_vif->wdev;  fail: -	brcmf_free_vif(p2p->cfg, p2p_vif); +	brcmf_free_vif(p2p_vif);  	return ERR_PTR(err);  } @@ -2231,31 +2232,12 @@ fail:   *   * @vif: virtual interface object to delete.   */ -static void brcmf_p2p_delete_p2pdev(struct brcmf_cfg80211_info *cfg, +static void brcmf_p2p_delete_p2pdev(struct brcmf_p2p_info *p2p,  				    struct brcmf_cfg80211_vif *vif)  {  	cfg80211_unregister_wdev(&vif->wdev); -	cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL; -	brcmf_free_vif(cfg, vif); -} - -/** - * brcmf_p2p_free_p2p_if() - free up net device related data. - * - * @ndev: net device that needs to be freed. - */ -static void brcmf_p2p_free_p2p_if(struct net_device *ndev) -{ -	struct brcmf_cfg80211_info *cfg; -	struct brcmf_cfg80211_vif *vif; -	struct brcmf_if *ifp; - -	ifp = netdev_priv(ndev); -	cfg = ifp->drvr->config; -	vif = ifp->vif; - -	brcmf_free_vif(cfg, vif); -	free_netdev(ifp->ndev); +	p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL; +	brcmf_free_vif(vif);  }  /** @@ -2275,7 +2257,6 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,  	struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));  	struct brcmf_cfg80211_vif *vif;  	enum brcmf_fil_p2p_if_types iftype; -	enum wl_mode mode;  	int err;  	if (brcmf_cfg80211_vif_event_armed(cfg)) @@ -2286,11 +2267,9 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,  	switch (type) {  	case NL80211_IFTYPE_P2P_CLIENT:  		iftype = BRCMF_FIL_P2P_IF_CLIENT; -		mode = WL_MODE_BSS;  		break;  	case NL80211_IFTYPE_P2P_GO:  		iftype = BRCMF_FIL_P2P_IF_GO; -		mode = WL_MODE_AP;  		break;  	case NL80211_IFTYPE_P2P_DEVICE:  		return brcmf_p2p_create_p2pdev(&cfg->p2p, wiphy, @@ -2335,8 +2314,6 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,  		brcmf_err("Registering netdevice failed\n");  		goto fail;  	} -	/* override destructor */ -	ifp->ndev->destructor = brcmf_p2p_free_p2p_if;  	cfg->p2p.bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = vif;  	/* Disable firmware roaming for P2P interface  */ @@ -2349,7 +2326,7 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,  	return &ifp->vif->wdev;  fail: -	brcmf_free_vif(cfg, vif); +	brcmf_free_vif(vif);  	return ERR_PTR(err);  } @@ -2358,8 +2335,6 @@ fail:   *   * @wiphy: wiphy device of interface.   * @wdev: wireless device of interface. - * - * TODO: not yet supported.   */  int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)  { @@ -2385,7 +2360,7 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)  		break;  	case NL80211_IFTYPE_P2P_DEVICE: -		brcmf_p2p_delete_p2pdev(cfg, vif); +		brcmf_p2p_delete_p2pdev(p2p, vif);  		return 0;  	default:  		return -ENOTSUPP; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/proto.c b/drivers/net/wireless/brcm80211/brcmfmac/proto.c new file mode 100644 index 00000000000..b6b46418494 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/proto.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2013 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + + #include <linux/types.h> +#include <linux/slab.h> +#include <linux/netdevice.h> + +#include <brcmu_wifi.h> +#include "dhd.h" +#include "dhd_dbg.h" +#include "proto.h" +#include "bcdc.h" + + +int brcmf_proto_attach(struct brcmf_pub *drvr) +{ +	struct brcmf_proto *proto; + +	proto = kzalloc(sizeof(*proto), GFP_ATOMIC); +	if (!proto) +		goto fail; + +	drvr->proto = proto; +	/* BCDC protocol is only protocol supported for the moment */ +	if (brcmf_proto_bcdc_attach(drvr)) +		goto fail; + +	if ((proto->txdata == NULL) || (proto->hdrpull == NULL) || +	    (proto->query_dcmd == NULL) || (proto->set_dcmd == NULL)) { +		brcmf_err("Not all proto handlers have been installed\n"); +		goto fail; +	} +	return 0; + +fail: +	kfree(proto); +	drvr->proto = NULL; +	return -ENOMEM; +} + +void brcmf_proto_detach(struct brcmf_pub *drvr) +{ +	if (drvr->proto) { +		brcmf_proto_bcdc_detach(drvr); +		kfree(drvr->proto); +		drvr->proto = NULL; +	} +} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/proto.h b/drivers/net/wireless/brcm80211/brcmfmac/proto.h new file mode 100644 index 00000000000..482fb0ba4a3 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/proto.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2013 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef BRCMFMAC_PROTO_H +#define BRCMFMAC_PROTO_H + +struct brcmf_proto { +	int (*hdrpull)(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx, +		       struct sk_buff *skb); +	int (*query_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd, +			  void *buf, uint len); +	int (*set_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf, +			uint len); +	int (*txdata)(struct brcmf_pub *drvr, int ifidx, u8 offset, +		      struct sk_buff *skb); +	void *pd; +}; + + +int brcmf_proto_attach(struct brcmf_pub *drvr); +void brcmf_proto_detach(struct brcmf_pub *drvr); + +static inline int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws, +				      u8 *ifidx, struct sk_buff *skb) +{ +	return drvr->proto->hdrpull(drvr, do_fws, ifidx, skb); +} +static inline int brcmf_proto_query_dcmd(struct brcmf_pub *drvr, int ifidx, +					 uint cmd, void *buf, uint len) +{ +	return drvr->proto->query_dcmd(drvr, ifidx, cmd, buf, len); +} +static inline int brcmf_proto_set_dcmd(struct brcmf_pub *drvr, int ifidx, +				       uint cmd, void *buf, uint len) +{ +	return drvr->proto->set_dcmd(drvr, ifidx, cmd, buf, len); +} +static inline int brcmf_proto_txdata(struct brcmf_pub *drvr, int ifidx, +				       u8 offset, struct sk_buff *skb) +{ +	return drvr->proto->txdata(drvr, ifidx, offset, skb); +} + + +#endif /* BRCMFMAC_PROTO_H */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c deleted file mode 100644 index ca72177388b..00000000000 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c +++ /dev/null @@ -1,955 +0,0 @@ -/* - * Copyright (c) 2011 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -/* ***** SDIO interface chip backplane handle functions ***** */ - -#include <linux/types.h> -#include <linux/netdevice.h> -#include <linux/mmc/card.h> -#include <linux/ssb/ssb_regs.h> -#include <linux/bcma/bcma.h> - -#include <chipcommon.h> -#include <brcm_hw_ids.h> -#include <brcmu_wifi.h> -#include <brcmu_utils.h> -#include <soc.h> -#include "dhd_dbg.h" -#include "sdio_host.h" -#include "sdio_chip.h" - -/* chip core base & ramsize */ -/* bcm4329 */ -/* SDIO device core, ID 0x829 */ -#define BCM4329_CORE_BUS_BASE		0x18011000 -/* internal memory core, ID 0x80e */ -#define BCM4329_CORE_SOCRAM_BASE	0x18003000 -/* ARM Cortex M3 core, ID 0x82a */ -#define BCM4329_CORE_ARM_BASE		0x18002000 -#define BCM4329_RAMSIZE			0x48000 - -/* bcm43143 */ -/* SDIO device core */ -#define BCM43143_CORE_BUS_BASE		0x18002000 -/* internal memory core */ -#define BCM43143_CORE_SOCRAM_BASE	0x18004000 -/* ARM Cortex M3 core, ID 0x82a */ -#define BCM43143_CORE_ARM_BASE		0x18003000 -#define BCM43143_RAMSIZE		0x70000 - -#define	SBCOREREV(sbidh) \ -	((((sbidh) & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT) | \ -	  ((sbidh) & SSB_IDHIGH_RCLO)) - -/* SOC Interconnect types (aka chip types) */ -#define SOCI_SB		0 -#define SOCI_AI		1 - -/* EROM CompIdentB */ -#define CIB_REV_MASK		0xff000000 -#define CIB_REV_SHIFT		24 - -/* ARM CR4 core specific control flag bits */ -#define ARMCR4_BCMA_IOCTL_CPUHALT	0x0020 - -#define SDIOD_DRVSTR_KEY(chip, pmu)     (((chip) << 16) | (pmu)) -/* SDIO Pad drive strength to select value mappings */ -struct sdiod_drive_str { -	u8 strength;	/* Pad Drive Strength in mA */ -	u8 sel;		/* Chip-specific select value */ -}; -/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8V) */ -static const struct sdiod_drive_str sdiod_drvstr_tab1_1v8[] = { -	{32, 0x6}, -	{26, 0x7}, -	{22, 0x4}, -	{16, 0x5}, -	{12, 0x2}, -	{8, 0x3}, -	{4, 0x0}, -	{0, 0x1} -}; - -/* SDIO Drive Strength to sel value table for 43143 PMU Rev 17 (3.3V) */ -static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = { -	{16, 0x7}, -	{12, 0x5}, -	{8,  0x3}, -	{4,  0x1} -}; - -u8 -brcmf_sdio_chip_getinfidx(struct chip_info *ci, u16 coreid) -{ -	u8 idx; - -	for (idx = 0; idx < BRCMF_MAX_CORENUM; idx++) -		if (coreid == ci->c_inf[idx].id) -			return idx; - -	return BRCMF_MAX_CORENUM; -} - -static u32 -brcmf_sdio_sb_corerev(struct brcmf_sdio_dev *sdiodev, -		      struct chip_info *ci, u16 coreid) -{ -	u32 regdata; -	u8 idx; - -	idx = brcmf_sdio_chip_getinfidx(ci, coreid); - -	regdata = brcmf_sdio_regrl(sdiodev, -				   CORE_SB(ci->c_inf[idx].base, sbidhigh), -				   NULL); -	return SBCOREREV(regdata); -} - -static u32 -brcmf_sdio_ai_corerev(struct brcmf_sdio_dev *sdiodev, -		      struct chip_info *ci, u16 coreid) -{ -	u8 idx; - -	idx = brcmf_sdio_chip_getinfidx(ci, coreid); - -	return (ci->c_inf[idx].cib & CIB_REV_MASK) >> CIB_REV_SHIFT; -} - -static bool -brcmf_sdio_sb_iscoreup(struct brcmf_sdio_dev *sdiodev, -		       struct chip_info *ci, u16 coreid) -{ -	u32 regdata; -	u8 idx; - -	idx = brcmf_sdio_chip_getinfidx(ci, coreid); - -	regdata = brcmf_sdio_regrl(sdiodev, -				   CORE_SB(ci->c_inf[idx].base, sbtmstatelow), -				   NULL); -	regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT | -		    SSB_IMSTATE_REJECT | SSB_TMSLOW_CLOCK); -	return (SSB_TMSLOW_CLOCK == regdata); -} - -static bool -brcmf_sdio_ai_iscoreup(struct brcmf_sdio_dev *sdiodev, -		       struct chip_info *ci, u16 coreid) -{ -	u32 regdata; -	u8 idx; -	bool ret; - -	idx = brcmf_sdio_chip_getinfidx(ci, coreid); - -	regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL, -				   NULL); -	ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK; - -	regdata = brcmf_sdio_regrl(sdiodev, -				   ci->c_inf[idx].wrapbase+BCMA_RESET_CTL, -				   NULL); -	ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0); - -	return ret; -} - -static void -brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev, -			  struct chip_info *ci, u16 coreid, u32 core_bits) -{ -	u32 regdata, base; -	u8 idx; - -	idx = brcmf_sdio_chip_getinfidx(ci, coreid); -	base = ci->c_inf[idx].base; - -	regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL); -	if (regdata & SSB_TMSLOW_RESET) -		return; - -	regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL); -	if ((regdata & SSB_TMSLOW_CLOCK) != 0) { -		/* -		 * set target reject and spin until busy is clear -		 * (preserve core-specific bits) -		 */ -		regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow), -					   NULL); -		brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbtmstatelow), -				 regdata | SSB_TMSLOW_REJECT, NULL); - -		regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow), -					   NULL); -		udelay(1); -		SPINWAIT((brcmf_sdio_regrl(sdiodev, -					   CORE_SB(base, sbtmstatehigh), -					   NULL) & -			SSB_TMSHIGH_BUSY), 100000); - -		regdata = brcmf_sdio_regrl(sdiodev, -					   CORE_SB(base, sbtmstatehigh), -					   NULL); -		if (regdata & SSB_TMSHIGH_BUSY) -			brcmf_err("core state still busy\n"); - -		regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbidlow), -					   NULL); -		if (regdata & SSB_IDLOW_INITIATOR) { -			regdata = brcmf_sdio_regrl(sdiodev, -						   CORE_SB(base, sbimstate), -						   NULL); -			regdata |= SSB_IMSTATE_REJECT; -			brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbimstate), -					 regdata, NULL); -			regdata = brcmf_sdio_regrl(sdiodev, -						   CORE_SB(base, sbimstate), -						   NULL); -			udelay(1); -			SPINWAIT((brcmf_sdio_regrl(sdiodev, -						   CORE_SB(base, sbimstate), -						   NULL) & -				SSB_IMSTATE_BUSY), 100000); -		} - -		/* set reset and reject while enabling the clocks */ -		regdata = SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | -			  SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET; -		brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbtmstatelow), -				 regdata, NULL); -		regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow), -					   NULL); -		udelay(10); - -		/* clear the initiator reject bit */ -		regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbidlow), -					   NULL); -		if (regdata & SSB_IDLOW_INITIATOR) { -			regdata = brcmf_sdio_regrl(sdiodev, -						   CORE_SB(base, sbimstate), -						   NULL); -			regdata &= ~SSB_IMSTATE_REJECT; -			brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbimstate), -					 regdata, NULL); -		} -	} - -	/* leave reset and reject asserted */ -	brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbtmstatelow), -			 (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET), NULL); -	udelay(1); -} - -static void -brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev, -			  struct chip_info *ci, u16 coreid, u32 core_bits) -{ -	u8 idx; -	u32 regdata; - -	idx = brcmf_sdio_chip_getinfidx(ci, coreid); - -	/* if core is already in reset, just return */ -	regdata = brcmf_sdio_regrl(sdiodev, -				   ci->c_inf[idx].wrapbase+BCMA_RESET_CTL, -				   NULL); -	if ((regdata & BCMA_RESET_CTL_RESET) != 0) -		return; - -	/* ensure no pending backplane operation -	 * 300uc should be sufficient for backplane ops to be finish -	 * extra 10ms is taken into account for firmware load stage -	 * after 10300us carry on disabling the core anyway -	 */ -	SPINWAIT(brcmf_sdio_regrl(sdiodev, -				  ci->c_inf[idx].wrapbase+BCMA_RESET_ST, -				  NULL), 10300); -	regdata = brcmf_sdio_regrl(sdiodev, -				   ci->c_inf[idx].wrapbase+BCMA_RESET_ST, -				   NULL); -	if (regdata) -		brcmf_err("disabling core 0x%x with reset status %x\n", -			  coreid, regdata); - -	brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL, -			 BCMA_RESET_CTL_RESET, NULL); -	udelay(1); - -	brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL, -			 core_bits, NULL); -	regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL, -				   NULL); -	usleep_range(10, 20); - -} - -static void -brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev, -			struct chip_info *ci, u16 coreid, u32 core_bits) -{ -	u32 regdata; -	u8 idx; - -	idx = brcmf_sdio_chip_getinfidx(ci, coreid); - -	/* -	 * Must do the disable sequence first to work for -	 * arbitrary current core state. -	 */ -	brcmf_sdio_sb_coredisable(sdiodev, ci, coreid, 0); - -	/* -	 * Now do the initialization sequence. -	 * set reset while enabling the clock and -	 * forcing them on throughout the core -	 */ -	brcmf_sdio_regwl(sdiodev, -			 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), -			 SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET, -			 NULL); -	regdata = brcmf_sdio_regrl(sdiodev, -				   CORE_SB(ci->c_inf[idx].base, sbtmstatelow), -				   NULL); -	udelay(1); - -	/* clear any serror */ -	regdata = brcmf_sdio_regrl(sdiodev, -				   CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), -				   NULL); -	if (regdata & SSB_TMSHIGH_SERR) -		brcmf_sdio_regwl(sdiodev, -				 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), -				 0, NULL); - -	regdata = brcmf_sdio_regrl(sdiodev, -				   CORE_SB(ci->c_inf[idx].base, sbimstate), -				   NULL); -	if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO)) -		brcmf_sdio_regwl(sdiodev, -				 CORE_SB(ci->c_inf[idx].base, sbimstate), -				 regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO), -				 NULL); - -	/* clear reset and allow it to propagate throughout the core */ -	brcmf_sdio_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow), -			 SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK, NULL); -	regdata = brcmf_sdio_regrl(sdiodev, -				   CORE_SB(ci->c_inf[idx].base, sbtmstatelow), -				   NULL); -	udelay(1); - -	/* leave clock enabled */ -	brcmf_sdio_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow), -			 SSB_TMSLOW_CLOCK, NULL); -	regdata = brcmf_sdio_regrl(sdiodev, -				   CORE_SB(ci->c_inf[idx].base, sbtmstatelow), -				   NULL); -	udelay(1); -} - -static void -brcmf_sdio_ai_resetcore(struct brcmf_sdio_dev *sdiodev, -			struct chip_info *ci, u16 coreid, u32 core_bits) -{ -	u8 idx; -	u32 regdata; - -	idx = brcmf_sdio_chip_getinfidx(ci, coreid); - -	/* must disable first to work for arbitrary current core state */ -	brcmf_sdio_ai_coredisable(sdiodev, ci, coreid, core_bits); - -	/* now do initialization sequence */ -	brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL, -			 core_bits | BCMA_IOCTL_FGC | BCMA_IOCTL_CLK, NULL); -	regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL, -				   NULL); -	brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL, -			 0, NULL); -	regdata = brcmf_sdio_regrl(sdiodev, -				   ci->c_inf[idx].wrapbase+BCMA_RESET_CTL, -				   NULL); -	udelay(1); - -	brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL, -			 core_bits | BCMA_IOCTL_CLK, NULL); -	regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL, -				   NULL); -	udelay(1); -} - -#ifdef DEBUG -/* safety check for chipinfo */ -static int brcmf_sdio_chip_cichk(struct chip_info *ci) -{ -	u8 core_idx; - -	/* check RAM core presence for ARM CM3 core */ -	core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3); -	if (BRCMF_MAX_CORENUM != core_idx) { -		core_idx = brcmf_sdio_chip_getinfidx(ci, -						     BCMA_CORE_INTERNAL_MEM); -		if (BRCMF_MAX_CORENUM == core_idx) { -			brcmf_err("RAM core not provided with ARM CM3 core\n"); -			return -ENODEV; -		} -	} - -	/* check RAM base for ARM CR4 core */ -	core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CR4); -	if (BRCMF_MAX_CORENUM != core_idx) { -		if (ci->rambase == 0) { -			brcmf_err("RAM base not provided with ARM CR4 core\n"); -			return -ENOMEM; -		} -	} - -	return 0; -} -#else	/* DEBUG */ -static inline int brcmf_sdio_chip_cichk(struct chip_info *ci) -{ -	return 0; -} -#endif - -static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev, -				       struct chip_info *ci, u32 regs) -{ -	u32 regdata; -	int ret; - -	/* Get CC core rev -	 * Chipid is assume to be at offset 0 from regs arg -	 * For different chiptypes or old sdio hosts w/o chipcommon, -	 * other ways of recognition should be added here. -	 */ -	ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON; -	ci->c_inf[0].base = regs; -	regdata = brcmf_sdio_regrl(sdiodev, -				   CORE_CC_REG(ci->c_inf[0].base, chipid), -				   NULL); -	ci->chip = regdata & CID_ID_MASK; -	ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT; -	ci->socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT; - -	brcmf_dbg(INFO, "chipid=0x%x chiprev=%d\n", ci->chip, ci->chiprev); - -	/* Address of cores for new chips should be added here */ -	switch (ci->chip) { -	case BCM43143_CHIP_ID: -		ci->c_inf[0].wrapbase = ci->c_inf[0].base + 0x00100000; -		ci->c_inf[0].cib = 0x2b000000; -		ci->c_inf[1].id = BCMA_CORE_SDIO_DEV; -		ci->c_inf[1].base = BCM43143_CORE_BUS_BASE; -		ci->c_inf[1].wrapbase = ci->c_inf[1].base + 0x00100000; -		ci->c_inf[1].cib = 0x18000000; -		ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM; -		ci->c_inf[2].base = BCM43143_CORE_SOCRAM_BASE; -		ci->c_inf[2].wrapbase = ci->c_inf[2].base + 0x00100000; -		ci->c_inf[2].cib = 0x14000000; -		ci->c_inf[3].id = BCMA_CORE_ARM_CM3; -		ci->c_inf[3].base = BCM43143_CORE_ARM_BASE; -		ci->c_inf[3].wrapbase = ci->c_inf[3].base + 0x00100000; -		ci->c_inf[3].cib = 0x07000000; -		ci->ramsize = BCM43143_RAMSIZE; -		break; -	case BCM43241_CHIP_ID: -		ci->c_inf[0].wrapbase = 0x18100000; -		ci->c_inf[0].cib = 0x2a084411; -		ci->c_inf[1].id = BCMA_CORE_SDIO_DEV; -		ci->c_inf[1].base = 0x18002000; -		ci->c_inf[1].wrapbase = 0x18102000; -		ci->c_inf[1].cib = 0x0e004211; -		ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM; -		ci->c_inf[2].base = 0x18004000; -		ci->c_inf[2].wrapbase = 0x18104000; -		ci->c_inf[2].cib = 0x14080401; -		ci->c_inf[3].id = BCMA_CORE_ARM_CM3; -		ci->c_inf[3].base = 0x18003000; -		ci->c_inf[3].wrapbase = 0x18103000; -		ci->c_inf[3].cib = 0x07004211; -		ci->ramsize = 0x90000; -		break; -	case BCM4329_CHIP_ID: -		ci->c_inf[1].id = BCMA_CORE_SDIO_DEV; -		ci->c_inf[1].base = BCM4329_CORE_BUS_BASE; -		ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM; -		ci->c_inf[2].base = BCM4329_CORE_SOCRAM_BASE; -		ci->c_inf[3].id = BCMA_CORE_ARM_CM3; -		ci->c_inf[3].base = BCM4329_CORE_ARM_BASE; -		ci->ramsize = BCM4329_RAMSIZE; -		break; -	case BCM4330_CHIP_ID: -		ci->c_inf[0].wrapbase = 0x18100000; -		ci->c_inf[0].cib = 0x27004211; -		ci->c_inf[1].id = BCMA_CORE_SDIO_DEV; -		ci->c_inf[1].base = 0x18002000; -		ci->c_inf[1].wrapbase = 0x18102000; -		ci->c_inf[1].cib = 0x07004211; -		ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM; -		ci->c_inf[2].base = 0x18004000; -		ci->c_inf[2].wrapbase = 0x18104000; -		ci->c_inf[2].cib = 0x0d080401; -		ci->c_inf[3].id = BCMA_CORE_ARM_CM3; -		ci->c_inf[3].base = 0x18003000; -		ci->c_inf[3].wrapbase = 0x18103000; -		ci->c_inf[3].cib = 0x03004211; -		ci->ramsize = 0x48000; -		break; -	case BCM4334_CHIP_ID: -		ci->c_inf[0].wrapbase = 0x18100000; -		ci->c_inf[0].cib = 0x29004211; -		ci->c_inf[1].id = BCMA_CORE_SDIO_DEV; -		ci->c_inf[1].base = 0x18002000; -		ci->c_inf[1].wrapbase = 0x18102000; -		ci->c_inf[1].cib = 0x0d004211; -		ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM; -		ci->c_inf[2].base = 0x18004000; -		ci->c_inf[2].wrapbase = 0x18104000; -		ci->c_inf[2].cib = 0x13080401; -		ci->c_inf[3].id = BCMA_CORE_ARM_CM3; -		ci->c_inf[3].base = 0x18003000; -		ci->c_inf[3].wrapbase = 0x18103000; -		ci->c_inf[3].cib = 0x07004211; -		ci->ramsize = 0x80000; -		break; -	case BCM4335_CHIP_ID: -		ci->c_inf[0].wrapbase = 0x18100000; -		ci->c_inf[0].cib = 0x2b084411; -		ci->c_inf[1].id = BCMA_CORE_SDIO_DEV; -		ci->c_inf[1].base = 0x18005000; -		ci->c_inf[1].wrapbase = 0x18105000; -		ci->c_inf[1].cib = 0x0f004211; -		ci->c_inf[2].id = BCMA_CORE_ARM_CR4; -		ci->c_inf[2].base = 0x18002000; -		ci->c_inf[2].wrapbase = 0x18102000; -		ci->c_inf[2].cib = 0x01084411; -		ci->ramsize = 0xc0000; -		ci->rambase = 0x180000; -		break; -	default: -		brcmf_err("chipid 0x%x is not supported\n", ci->chip); -		return -ENODEV; -	} - -	ret = brcmf_sdio_chip_cichk(ci); -	if (ret) -		return ret; - -	switch (ci->socitype) { -	case SOCI_SB: -		ci->iscoreup = brcmf_sdio_sb_iscoreup; -		ci->corerev = brcmf_sdio_sb_corerev; -		ci->coredisable = brcmf_sdio_sb_coredisable; -		ci->resetcore = brcmf_sdio_sb_resetcore; -		break; -	case SOCI_AI: -		ci->iscoreup = brcmf_sdio_ai_iscoreup; -		ci->corerev = brcmf_sdio_ai_corerev; -		ci->coredisable = brcmf_sdio_ai_coredisable; -		ci->resetcore = brcmf_sdio_ai_resetcore; -		break; -	default: -		brcmf_err("socitype %u not supported\n", ci->socitype); -		return -ENODEV; -	} - -	return 0; -} - -static int -brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev) -{ -	int err = 0; -	u8 clkval, clkset; - -	/* Try forcing SDIO core to do ALPAvail request only */ -	clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ; -	brcmf_sdio_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); -	if (err) { -		brcmf_err("error writing for HT off\n"); -		return err; -	} - -	/* If register supported, wait for ALPAvail and then force ALP */ -	/* This may take up to 15 milliseconds */ -	clkval = brcmf_sdio_regrb(sdiodev, -				  SBSDIO_FUNC1_CHIPCLKCSR, NULL); - -	if ((clkval & ~SBSDIO_AVBITS) != clkset) { -		brcmf_err("ChipClkCSR access: wrote 0x%02x read 0x%02x\n", -			  clkset, clkval); -		return -EACCES; -	} - -	SPINWAIT(((clkval = brcmf_sdio_regrb(sdiodev, -					     SBSDIO_FUNC1_CHIPCLKCSR, NULL)), -			!SBSDIO_ALPAV(clkval)), -			PMU_MAX_TRANSITION_DLY); -	if (!SBSDIO_ALPAV(clkval)) { -		brcmf_err("timeout on ALPAV wait, clkval 0x%02x\n", -			  clkval); -		return -EBUSY; -	} - -	clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP; -	brcmf_sdio_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); -	udelay(65); - -	/* Also, disable the extra SDIO pull-ups */ -	brcmf_sdio_regwb(sdiodev, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL); - -	return 0; -} - -static void -brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev, -			     struct chip_info *ci) -{ -	u32 base = ci->c_inf[0].base; - -	/* get chipcommon rev */ -	ci->c_inf[0].rev = ci->corerev(sdiodev, ci, ci->c_inf[0].id); - -	/* get chipcommon capabilites */ -	ci->c_inf[0].caps = brcmf_sdio_regrl(sdiodev, -					     CORE_CC_REG(base, capabilities), -					     NULL); - -	/* get pmu caps & rev */ -	if (ci->c_inf[0].caps & CC_CAP_PMU) { -		ci->pmucaps = -			brcmf_sdio_regrl(sdiodev, -					 CORE_CC_REG(base, pmucapabilities), -					 NULL); -		ci->pmurev = ci->pmucaps & PCAP_REV_MASK; -	} - -	ci->c_inf[1].rev = ci->corerev(sdiodev, ci, ci->c_inf[1].id); - -	brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n", -		  ci->c_inf[0].rev, ci->pmurev, -		  ci->c_inf[1].rev, ci->c_inf[1].id); - -	/* -	 * Make sure any on-chip ARM is off (in case strapping is wrong), -	 * or downloaded code was already running. -	 */ -	ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3, 0); -} - -int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev, -			   struct chip_info **ci_ptr, u32 regs) -{ -	int ret; -	struct chip_info *ci; - -	brcmf_dbg(TRACE, "Enter\n"); - -	/* alloc chip_info_t */ -	ci = kzalloc(sizeof(struct chip_info), GFP_ATOMIC); -	if (!ci) -		return -ENOMEM; - -	ret = brcmf_sdio_chip_buscoreprep(sdiodev); -	if (ret != 0) -		goto err; - -	ret = brcmf_sdio_chip_recognition(sdiodev, ci, regs); -	if (ret != 0) -		goto err; - -	brcmf_sdio_chip_buscoresetup(sdiodev, ci); - -	brcmf_sdio_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopullup), -			 0, NULL); -	brcmf_sdio_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopulldown), -			 0, NULL); - -	*ci_ptr = ci; -	return 0; - -err: -	kfree(ci); -	return ret; -} - -void -brcmf_sdio_chip_detach(struct chip_info **ci_ptr) -{ -	brcmf_dbg(TRACE, "Enter\n"); - -	kfree(*ci_ptr); -	*ci_ptr = NULL; -} - -static char *brcmf_sdio_chip_name(uint chipid, char *buf, uint len) -{ -	const char *fmt; - -	fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x"; -	snprintf(buf, len, fmt, chipid); -	return buf; -} - -void -brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev, -				  struct chip_info *ci, u32 drivestrength) -{ -	const struct sdiod_drive_str *str_tab = NULL; -	u32 str_mask; -	u32 str_shift; -	char chn[8]; -	u32 base = ci->c_inf[0].base; -	u32 i; -	u32 drivestrength_sel = 0; -	u32 cc_data_temp; -	u32 addr; - -	if (!(ci->c_inf[0].caps & CC_CAP_PMU)) -		return; - -	switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) { -	case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12): -		str_tab = sdiod_drvstr_tab1_1v8; -		str_mask = 0x00003800; -		str_shift = 11; -		break; -	case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17): -		/* note: 43143 does not support tristate */ -		i = ARRAY_SIZE(sdiod_drvstr_tab2_3v3) - 1; -		if (drivestrength >= sdiod_drvstr_tab2_3v3[i].strength) { -			str_tab = sdiod_drvstr_tab2_3v3; -			str_mask = 0x00000007; -			str_shift = 0; -		} else -			brcmf_err("Invalid SDIO Drive strength for chip %s, strength=%d\n", -				  brcmf_sdio_chip_name(ci->chip, chn, 8), -				  drivestrength); -		break; -	default: -		brcmf_err("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n", -			  brcmf_sdio_chip_name(ci->chip, chn, 8), -			  ci->chiprev, ci->pmurev); -		break; -	} - -	if (str_tab != NULL) { -		for (i = 0; str_tab[i].strength != 0; i++) { -			if (drivestrength >= str_tab[i].strength) { -				drivestrength_sel = str_tab[i].sel; -				break; -			} -		} -		addr = CORE_CC_REG(base, chipcontrol_addr); -		brcmf_sdio_regwl(sdiodev, addr, 1, NULL); -		cc_data_temp = brcmf_sdio_regrl(sdiodev, addr, NULL); -		cc_data_temp &= ~str_mask; -		drivestrength_sel <<= str_shift; -		cc_data_temp |= drivestrength_sel; -		brcmf_sdio_regwl(sdiodev, addr, cc_data_temp, NULL); - -		brcmf_dbg(INFO, "SDIO: %d mA (req=%d mA) drive strength selected, set to 0x%08x\n", -			  str_tab[i].strength, drivestrength, cc_data_temp); -	} -} - -#ifdef DEBUG -static bool -brcmf_sdio_chip_verifynvram(struct brcmf_sdio_dev *sdiodev, u32 nvram_addr, -			    char *nvram_dat, uint nvram_sz) -{ -	char *nvram_ularray; -	int err; -	bool ret = true; - -	/* read back and verify */ -	brcmf_dbg(INFO, "Compare NVRAM dl & ul; size=%d\n", nvram_sz); -	nvram_ularray = kmalloc(nvram_sz, GFP_KERNEL); -	/* do not proceed while no memory but  */ -	if (!nvram_ularray) -		return true; - -	/* Upload image to verify downloaded contents. */ -	memset(nvram_ularray, 0xaa, nvram_sz); - -	/* Read the vars list to temp buffer for comparison */ -	err = brcmf_sdio_ramrw(sdiodev, false, nvram_addr, nvram_ularray, -			       nvram_sz); -	if (err) { -		brcmf_err("error %d on reading %d nvram bytes at 0x%08x\n", -			  err, nvram_sz, nvram_addr); -	} else if (memcmp(nvram_dat, nvram_ularray, nvram_sz)) { -		brcmf_err("Downloaded NVRAM image is corrupted\n"); -		ret = false; -	} -	kfree(nvram_ularray); - -	return ret; -} -#else	/* DEBUG */ -static inline bool -brcmf_sdio_chip_verifynvram(struct brcmf_sdio_dev *sdiodev, u32 nvram_addr, -			    char *nvram_dat, uint nvram_sz) -{ -	return true; -} -#endif	/* DEBUG */ - -static bool brcmf_sdio_chip_writenvram(struct brcmf_sdio_dev *sdiodev, -				       struct chip_info *ci, -				       char *nvram_dat, uint nvram_sz) -{ -	int err; -	u32 nvram_addr; -	u32 token; -	__le32 token_le; - -	nvram_addr = (ci->ramsize - 4) - nvram_sz + ci->rambase; - -	/* Write the vars list */ -	err = brcmf_sdio_ramrw(sdiodev, true, nvram_addr, nvram_dat, nvram_sz); -	if (err) { -		brcmf_err("error %d on writing %d nvram bytes at 0x%08x\n", -			  err, nvram_sz, nvram_addr); -		return false; -	} - -	if (!brcmf_sdio_chip_verifynvram(sdiodev, nvram_addr, -					 nvram_dat, nvram_sz)) -		return false; - -	/* generate token: -	 * nvram size, converted to words, in lower 16-bits, checksum -	 * in upper 16-bits. -	 */ -	token = nvram_sz / 4; -	token = (~token << 16) | (token & 0x0000FFFF); -	token_le = cpu_to_le32(token); - -	brcmf_dbg(INFO, "RAM size: %d\n", ci->ramsize); -	brcmf_dbg(INFO, "nvram is placed at %d, size %d, token=0x%08x\n", -		  nvram_addr, nvram_sz, token); - -	/* Write the length token to the last word */ -	if (brcmf_sdio_ramrw(sdiodev, true, (ci->ramsize - 4 + ci->rambase), -			     (u8 *)&token_le, 4)) -		return false; - -	return true; -} - -static void -brcmf_sdio_chip_cm3_enterdl(struct brcmf_sdio_dev *sdiodev, -			    struct chip_info *ci) -{ -	u32 zeros = 0; - -	ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3, 0); -	ci->resetcore(sdiodev, ci, BCMA_CORE_INTERNAL_MEM, 0); - -	/* clear length token */ -	brcmf_sdio_ramrw(sdiodev, true, ci->ramsize - 4, (u8 *)&zeros, 4); -} - -static bool -brcmf_sdio_chip_cm3_exitdl(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci, -			   char *nvram_dat, uint nvram_sz) -{ -	u8 core_idx; -	u32 reg_addr; - -	if (!ci->iscoreup(sdiodev, ci, BCMA_CORE_INTERNAL_MEM)) { -		brcmf_err("SOCRAM core is down after reset?\n"); -		return false; -	} - -	if (!brcmf_sdio_chip_writenvram(sdiodev, ci, nvram_dat, nvram_sz)) -		return false; - -	/* clear all interrupts */ -	core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_SDIO_DEV); -	reg_addr = ci->c_inf[core_idx].base; -	reg_addr += offsetof(struct sdpcmd_regs, intstatus); -	brcmf_sdio_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL); - -	ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CM3, 0); - -	return true; -} - -static inline void -brcmf_sdio_chip_cr4_enterdl(struct brcmf_sdio_dev *sdiodev, -			    struct chip_info *ci) -{ -	ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CR4, -		      ARMCR4_BCMA_IOCTL_CPUHALT); -} - -static bool -brcmf_sdio_chip_cr4_exitdl(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci, -			   char *nvram_dat, uint nvram_sz) -{ -	u8 core_idx; -	u32 reg_addr; - -	if (!brcmf_sdio_chip_writenvram(sdiodev, ci, nvram_dat, nvram_sz)) -		return false; - -	/* clear all interrupts */ -	core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_SDIO_DEV); -	reg_addr = ci->c_inf[core_idx].base; -	reg_addr += offsetof(struct sdpcmd_regs, intstatus); -	brcmf_sdio_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL); - -	/* Write reset vector to address 0 */ -	brcmf_sdio_ramrw(sdiodev, true, 0, (void *)&ci->rst_vec, -			 sizeof(ci->rst_vec)); - -	/* restore ARM */ -	ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CR4, 0); - -	return true; -} - -void brcmf_sdio_chip_enter_download(struct brcmf_sdio_dev *sdiodev, -				    struct chip_info *ci) -{ -	u8 arm_core_idx; - -	arm_core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3); -	if (BRCMF_MAX_CORENUM != arm_core_idx) { -		brcmf_sdio_chip_cm3_enterdl(sdiodev, ci); -		return; -	} - -	brcmf_sdio_chip_cr4_enterdl(sdiodev, ci); -} - -bool brcmf_sdio_chip_exit_download(struct brcmf_sdio_dev *sdiodev, -				   struct chip_info *ci, char *nvram_dat, -				   uint nvram_sz) -{ -	u8 arm_core_idx; - -	arm_core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3); -	if (BRCMF_MAX_CORENUM != arm_core_idx) -		return brcmf_sdio_chip_cm3_exitdl(sdiodev, ci, nvram_dat, -						  nvram_sz); - -	return brcmf_sdio_chip_cr4_exitdl(sdiodev, ci, nvram_dat, nvram_sz); -} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h deleted file mode 100644 index 83c041f1bf4..00000000000 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright (c) 2011 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _BRCMFMAC_SDIO_CHIP_H_ -#define _BRCMFMAC_SDIO_CHIP_H_ - -/* - * Core reg address translation. - * Both macro's returns a 32 bits byte address on the backplane bus. - */ -#define CORE_CC_REG(base, field) \ -		(base + offsetof(struct chipcregs, field)) -#define CORE_BUS_REG(base, field) \ -		(base + offsetof(struct sdpcmd_regs, field)) -#define CORE_SB(base, field) \ -		(base + SBCONFIGOFF + offsetof(struct sbconfig, field)) - -/* SDIO function 1 register CHIPCLKCSR */ -/* Force ALP request to backplane */ -#define SBSDIO_FORCE_ALP		0x01 -/* Force HT request to backplane */ -#define SBSDIO_FORCE_HT			0x02 -/* Force ILP request to backplane */ -#define SBSDIO_FORCE_ILP		0x04 -/* Make ALP ready (power up xtal) */ -#define SBSDIO_ALP_AVAIL_REQ		0x08 -/* Make HT ready (power up PLL) */ -#define SBSDIO_HT_AVAIL_REQ		0x10 -/* Squelch clock requests from HW */ -#define SBSDIO_FORCE_HW_CLKREQ_OFF	0x20 -/* Status: ALP is ready */ -#define SBSDIO_ALP_AVAIL		0x40 -/* Status: HT is ready */ -#define SBSDIO_HT_AVAIL			0x80 -#define SBSDIO_AVBITS		(SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL) -#define SBSDIO_ALPAV(regval)	((regval) & SBSDIO_AVBITS) -#define SBSDIO_HTAV(regval)	(((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS) -#define SBSDIO_ALPONLY(regval)	(SBSDIO_ALPAV(regval) && !SBSDIO_HTAV(regval)) -#define SBSDIO_CLKAV(regval, alponly) \ -	(SBSDIO_ALPAV(regval) && (alponly ? 1 : SBSDIO_HTAV(regval))) - -#define BRCMF_MAX_CORENUM	6 - -struct chip_core_info { -	u16 id; -	u16 rev; -	u32 base; -	u32 wrapbase; -	u32 caps; -	u32 cib; -}; - -struct chip_info { -	u32 chip; -	u32 chiprev; -	u32 socitype; -	/* core info */ -	/* always put chipcommon core at 0, bus core at 1 */ -	struct chip_core_info c_inf[BRCMF_MAX_CORENUM]; -	u32 pmurev; -	u32 pmucaps; -	u32 ramsize; -	u32 rambase; -	u32 rst_vec;	/* reset vertor for ARM CR4 core */ - -	bool (*iscoreup)(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci, -			 u16 coreid); -	u32 (*corerev)(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci, -			 u16 coreid); -	void (*coredisable)(struct brcmf_sdio_dev *sdiodev, -			struct chip_info *ci, u16 coreid, u32 core_bits); -	void (*resetcore)(struct brcmf_sdio_dev *sdiodev, -			struct chip_info *ci, u16 coreid, u32 core_bits); -}; - -struct sbconfig { -	u32 PAD[2]; -	u32 sbipsflag;	/* initiator port ocp slave flag */ -	u32 PAD[3]; -	u32 sbtpsflag;	/* target port ocp slave flag */ -	u32 PAD[11]; -	u32 sbtmerrloga;	/* (sonics >= 2.3) */ -	u32 PAD; -	u32 sbtmerrlog;	/* (sonics >= 2.3) */ -	u32 PAD[3]; -	u32 sbadmatch3;	/* address match3 */ -	u32 PAD; -	u32 sbadmatch2;	/* address match2 */ -	u32 PAD; -	u32 sbadmatch1;	/* address match1 */ -	u32 PAD[7]; -	u32 sbimstate;	/* initiator agent state */ -	u32 sbintvec;	/* interrupt mask */ -	u32 sbtmstatelow;	/* target state */ -	u32 sbtmstatehigh;	/* target state */ -	u32 sbbwa0;		/* bandwidth allocation table0 */ -	u32 PAD; -	u32 sbimconfiglow;	/* initiator configuration */ -	u32 sbimconfighigh;	/* initiator configuration */ -	u32 sbadmatch0;	/* address match0 */ -	u32 PAD; -	u32 sbtmconfiglow;	/* target configuration */ -	u32 sbtmconfighigh;	/* target configuration */ -	u32 sbbconfig;	/* broadcast configuration */ -	u32 PAD; -	u32 sbbstate;	/* broadcast state */ -	u32 PAD[3]; -	u32 sbactcnfg;	/* activate configuration */ -	u32 PAD[3]; -	u32 sbflagst;	/* current sbflags */ -	u32 PAD[3]; -	u32 sbidlow;		/* identification */ -	u32 sbidhigh;	/* identification */ -}; - -/* sdio core registers */ -struct sdpcmd_regs { -	u32 corecontrol;		/* 0x00, rev8 */ -	u32 corestatus;			/* rev8 */ -	u32 PAD[1]; -	u32 biststatus;			/* rev8 */ - -	/* PCMCIA access */ -	u16 pcmciamesportaladdr;	/* 0x010, rev8 */ -	u16 PAD[1]; -	u16 pcmciamesportalmask;	/* rev8 */ -	u16 PAD[1]; -	u16 pcmciawrframebc;		/* rev8 */ -	u16 PAD[1]; -	u16 pcmciaunderflowtimer;	/* rev8 */ -	u16 PAD[1]; - -	/* interrupt */ -	u32 intstatus;			/* 0x020, rev8 */ -	u32 hostintmask;		/* rev8 */ -	u32 intmask;			/* rev8 */ -	u32 sbintstatus;		/* rev8 */ -	u32 sbintmask;			/* rev8 */ -	u32 funcintmask;		/* rev4 */ -	u32 PAD[2]; -	u32 tosbmailbox;		/* 0x040, rev8 */ -	u32 tohostmailbox;		/* rev8 */ -	u32 tosbmailboxdata;		/* rev8 */ -	u32 tohostmailboxdata;		/* rev8 */ - -	/* synchronized access to registers in SDIO clock domain */ -	u32 sdioaccess;			/* 0x050, rev8 */ -	u32 PAD[3]; - -	/* PCMCIA frame control */ -	u8 pcmciaframectrl;		/* 0x060, rev8 */ -	u8 PAD[3]; -	u8 pcmciawatermark;		/* rev8 */ -	u8 PAD[155]; - -	/* interrupt batching control */ -	u32 intrcvlazy;			/* 0x100, rev8 */ -	u32 PAD[3]; - -	/* counters */ -	u32 cmd52rd;			/* 0x110, rev8 */ -	u32 cmd52wr;			/* rev8 */ -	u32 cmd53rd;			/* rev8 */ -	u32 cmd53wr;			/* rev8 */ -	u32 abort;			/* rev8 */ -	u32 datacrcerror;		/* rev8 */ -	u32 rdoutofsync;		/* rev8 */ -	u32 wroutofsync;		/* rev8 */ -	u32 writebusy;			/* rev8 */ -	u32 readwait;			/* rev8 */ -	u32 readterm;			/* rev8 */ -	u32 writeterm;			/* rev8 */ -	u32 PAD[40]; -	u32 clockctlstatus;		/* rev8 */ -	u32 PAD[7]; - -	u32 PAD[128];			/* DMA engines */ - -	/* SDIO/PCMCIA CIS region */ -	char cis[512];			/* 0x400-0x5ff, rev6 */ - -	/* PCMCIA function control registers */ -	char pcmciafcr[256];		/* 0x600-6ff, rev6 */ -	u16 PAD[55]; - -	/* PCMCIA backplane access */ -	u16 backplanecsr;		/* 0x76E, rev6 */ -	u16 backplaneaddr0;		/* rev6 */ -	u16 backplaneaddr1;		/* rev6 */ -	u16 backplaneaddr2;		/* rev6 */ -	u16 backplaneaddr3;		/* rev6 */ -	u16 backplanedata0;		/* rev6 */ -	u16 backplanedata1;		/* rev6 */ -	u16 backplanedata2;		/* rev6 */ -	u16 backplanedata3;		/* rev6 */ -	u16 PAD[31]; - -	/* sprom "size" & "blank" info */ -	u16 spromstatus;		/* 0x7BE, rev2 */ -	u32 PAD[464]; - -	u16 PAD[0x80]; -}; - -extern int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev, -				  struct chip_info **ci_ptr, u32 regs); -extern void brcmf_sdio_chip_detach(struct chip_info **ci_ptr); -extern void brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev, -					      struct chip_info *ci, -					      u32 drivestrength); -extern u8 brcmf_sdio_chip_getinfidx(struct chip_info *ci, u16 coreid); -extern void brcmf_sdio_chip_enter_download(struct brcmf_sdio_dev *sdiodev, -					   struct chip_info *ci); -extern bool brcmf_sdio_chip_exit_download(struct brcmf_sdio_dev *sdiodev, -					  struct chip_info *ci, char *nvram_dat, -					  uint nvram_sz); - -#endif		/* _BRCMFMAC_SDIO_CHIP_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h index 2b5407f002e..3deab7959a0 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h @@ -164,11 +164,9 @@ struct brcmf_sdio;  struct brcmf_sdio_dev {  	struct sdio_func *func[SDIO_MAX_FUNCS];  	u8 num_funcs;			/* Supported funcs on client */ -	u32 func_cis_ptr[SDIOD_MAX_IOFUNCS];  	u32 sbwad;			/* Save backplane window address */ -	void *bus; +	struct brcmf_sdio *bus;  	atomic_t suspend;		/* suspend flag */ -	wait_queue_head_t request_byte_wait;  	wait_queue_head_t request_word_wait;  	wait_queue_head_t request_buffer_wait;  	struct device *dev; @@ -178,25 +176,117 @@ struct brcmf_sdio_dev {  	bool irq_en;			/* irq enable flags */  	spinlock_t irq_en_lock;  	bool irq_wake;			/* irq wake enable flags */ +	bool sg_support; +	uint max_request_size; +	ushort max_segment_count; +	uint max_segment_size; +	uint txglomsz; +	struct sg_table sgtable; +}; + +/* sdio core registers */ +struct sdpcmd_regs { +	u32 corecontrol;		/* 0x00, rev8 */ +	u32 corestatus;			/* rev8 */ +	u32 PAD[1]; +	u32 biststatus;			/* rev8 */ + +	/* PCMCIA access */ +	u16 pcmciamesportaladdr;	/* 0x010, rev8 */ +	u16 PAD[1]; +	u16 pcmciamesportalmask;	/* rev8 */ +	u16 PAD[1]; +	u16 pcmciawrframebc;		/* rev8 */ +	u16 PAD[1]; +	u16 pcmciaunderflowtimer;	/* rev8 */ +	u16 PAD[1]; + +	/* interrupt */ +	u32 intstatus;			/* 0x020, rev8 */ +	u32 hostintmask;		/* rev8 */ +	u32 intmask;			/* rev8 */ +	u32 sbintstatus;		/* rev8 */ +	u32 sbintmask;			/* rev8 */ +	u32 funcintmask;		/* rev4 */ +	u32 PAD[2]; +	u32 tosbmailbox;		/* 0x040, rev8 */ +	u32 tohostmailbox;		/* rev8 */ +	u32 tosbmailboxdata;		/* rev8 */ +	u32 tohostmailboxdata;		/* rev8 */ + +	/* synchronized access to registers in SDIO clock domain */ +	u32 sdioaccess;			/* 0x050, rev8 */ +	u32 PAD[3]; + +	/* PCMCIA frame control */ +	u8 pcmciaframectrl;		/* 0x060, rev8 */ +	u8 PAD[3]; +	u8 pcmciawatermark;		/* rev8 */ +	u8 PAD[155]; + +	/* interrupt batching control */ +	u32 intrcvlazy;			/* 0x100, rev8 */ +	u32 PAD[3]; + +	/* counters */ +	u32 cmd52rd;			/* 0x110, rev8 */ +	u32 cmd52wr;			/* rev8 */ +	u32 cmd53rd;			/* rev8 */ +	u32 cmd53wr;			/* rev8 */ +	u32 abort;			/* rev8 */ +	u32 datacrcerror;		/* rev8 */ +	u32 rdoutofsync;		/* rev8 */ +	u32 wroutofsync;		/* rev8 */ +	u32 writebusy;			/* rev8 */ +	u32 readwait;			/* rev8 */ +	u32 readterm;			/* rev8 */ +	u32 writeterm;			/* rev8 */ +	u32 PAD[40]; +	u32 clockctlstatus;		/* rev8 */ +	u32 PAD[7]; + +	u32 PAD[128];			/* DMA engines */ + +	/* SDIO/PCMCIA CIS region */ +	char cis[512];			/* 0x400-0x5ff, rev6 */ + +	/* PCMCIA function control registers */ +	char pcmciafcr[256];		/* 0x600-6ff, rev6 */ +	u16 PAD[55]; + +	/* PCMCIA backplane access */ +	u16 backplanecsr;		/* 0x76E, rev6 */ +	u16 backplaneaddr0;		/* rev6 */ +	u16 backplaneaddr1;		/* rev6 */ +	u16 backplaneaddr2;		/* rev6 */ +	u16 backplaneaddr3;		/* rev6 */ +	u16 backplanedata0;		/* rev6 */ +	u16 backplanedata1;		/* rev6 */ +	u16 backplanedata2;		/* rev6 */ +	u16 backplanedata3;		/* rev6 */ +	u16 PAD[31]; + +	/* sprom "size" & "blank" info */ +	u16 spromstatus;		/* 0x7BE, rev2 */ +	u32 PAD[464]; + +	u16 PAD[0x80];  };  /* Register/deregister interrupt handler. */ -extern int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev); -extern int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev); +int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev); +int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev);  /* sdio device register access interface */ -extern u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret); -extern u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret); -extern void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr, -			     u8 data, int *ret); -extern void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr, -			     u32 data, int *ret); -extern int brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr, -				   void *data, bool write); +u8 brcmf_sdiod_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret); +u32 brcmf_sdiod_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret); +void brcmf_sdiod_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr, u8 data, +		       int *ret); +void brcmf_sdiod_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr, u32 data, +		       int *ret);  /* Buffer transfer to/from device (client) core via cmd53.   *   fn:       function number - *   addr:     backplane address (i.e. >= regsva from attach)   *   flags:    backplane width, address increment, sync/async   *   buf:      pointer to memory data buffer   *   nbytes:   number of bytes to transfer to/from buf @@ -206,22 +296,14 @@ extern int brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,   * Returns 0 or error code.   * NOTE: Async operation is not currently supported.   */ -extern int -brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, -		      uint flags, struct sk_buff_head *pktq); -extern int -brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, -		      uint flags, u8 *buf, uint nbytes); - -extern int -brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, -		      uint flags, struct sk_buff *pkt); -extern int -brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, -		      uint flags, u8 *buf, uint nbytes); -extern int -brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, -			uint flags, struct sk_buff_head *pktq); +int brcmf_sdiod_send_pkt(struct brcmf_sdio_dev *sdiodev, +			 struct sk_buff_head *pktq); +int brcmf_sdiod_send_buf(struct brcmf_sdio_dev *sdiodev, u8 *buf, uint nbytes); + +int brcmf_sdiod_recv_pkt(struct brcmf_sdio_dev *sdiodev, struct sk_buff *pkt); +int brcmf_sdiod_recv_buf(struct brcmf_sdio_dev *sdiodev, u8 *buf, uint nbytes); +int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev, +			   struct sk_buff_head *pktq, uint totlen);  /* Flags bits */ @@ -237,46 +319,16 @@ brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,   *   nbytes:   number of bytes to transfer to/from buf   * Returns 0 or error code.   */ -extern int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw, -			       u32 addr, u8 *buf, uint nbytes); -extern int brcmf_sdio_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, -			    u32 address, u8 *data, uint size); +int brcmf_sdiod_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address, +		      u8 *data, uint size);  /* Issue an abort to the specified function */ -extern int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn); - -/* platform specific/high level functions */ -extern int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev); -extern int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev); - -/* attach, return handler on success, NULL if failed. - *  The handler shall be provided by all subsequent calls. No local cache - *  cfghdl points to the starting address of pci device mapped memory - */ -extern int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev); -extern void brcmf_sdioh_detach(struct brcmf_sdio_dev *sdiodev); - -/* read or write one byte using cmd52 */ -extern int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw, -				    uint fnc, uint addr, u8 *byte); - -/* read or write 2/4 bytes using cmd53 */ -extern int -brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev, -			 uint rw, uint fnc, uint addr, -			 u32 *word, uint nbyte); - -/* Watchdog timer interface for pm ops */ -extern void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev, -				    bool enable); +int brcmf_sdiod_abort(struct brcmf_sdio_dev *sdiodev, uint fn); -extern void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev); -extern void brcmf_sdbrcm_disconnect(void *ptr); -extern void brcmf_sdbrcm_isr(void *arg); +struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev); +void brcmf_sdio_remove(struct brcmf_sdio *bus); +void brcmf_sdio_isr(struct brcmf_sdio *bus); -extern void brcmf_sdbrcm_wd_timer(struct brcmf_sdio *bus, uint wdtick); +void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, uint wdtick); -extern void brcmf_pm_resume_wait(struct brcmf_sdio_dev *sdiodev, -				 wait_queue_head_t *wq); -extern bool brcmf_pm_resume_error(struct brcmf_sdio_dev *sdiodev);  #endif				/* _BRCM_SDH_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.h b/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.h index bc291711289..4d7d51f9571 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.h @@ -78,16 +78,18 @@ TRACE_EVENT(brcmf_hexdump,  	TP_ARGS(data, len),  	TP_STRUCT__entry(  		__field(unsigned long, len) +		__field(unsigned long, addr)  		__dynamic_array(u8, hdata, len)  	),  	TP_fast_assign(  		__entry->len = len; +		__entry->addr = (unsigned long)data;  		memcpy(__get_dynamic_array(hdata), data, len);  	), -	TP_printk("hexdump [length=%lu]", __entry->len) +	TP_printk("hexdump [addr=%lx, length=%lu]", __entry->addr, __entry->len)  ); -TRACE_EVENT(brcmf_bdchdr, +TRACE_EVENT(brcmf_bcdchdr,  	TP_PROTO(void *data),  	TP_ARGS(data),  	TP_STRUCT__entry( @@ -105,7 +107,35 @@ TRACE_EVENT(brcmf_bdchdr,  		memcpy(__get_dynamic_array(signal),  		       (u8 *)data + 4, __entry->siglen);  	), -	TP_printk("bdc: prio=%d siglen=%d", __entry->prio, __entry->siglen) +	TP_printk("bcdc: prio=%d siglen=%d", __entry->prio, __entry->siglen) +); + +#ifndef SDPCM_RX +#define SDPCM_RX	0 +#endif +#ifndef SDPCM_TX +#define SDPCM_TX	1 +#endif +#ifndef SDPCM_GLOM +#define SDPCM_GLOM	2 +#endif + +TRACE_EVENT(brcmf_sdpcm_hdr, +	TP_PROTO(u8 dir, void *data), +	TP_ARGS(dir, data), +	TP_STRUCT__entry( +		__field(u8, dir) +		__field(u16, len) +		__dynamic_array(u8, hdr, dir == SDPCM_GLOM ? 20 : 12) +	), +	TP_fast_assign( +		memcpy(__get_dynamic_array(hdr), data, dir == SDPCM_GLOM ? 20 : 12); +		__entry->len = *(u8 *)data | (*((u8 *)data + 1) << 8); +		__entry->dir = dir; +	), +	TP_printk("sdpcm: %s len %u, seq %d", +		  __entry->dir == SDPCM_RX ? "RX" : "TX", +		  __entry->len, ((u8 *)__get_dynamic_array(hdr))[4])  );  #ifdef CONFIG_BRCM_TRACING diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c index f4aea47e073..d06fcb05adf 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c @@ -25,6 +25,7 @@  #include <dhd_bus.h>  #include <dhd_dbg.h> +#include "firmware.h"  #include "usb_rdl.h"  #include "usb.h" @@ -61,12 +62,6 @@ struct brcmf_usb_image {  	u8 *image;  	int image_len;  }; -static struct list_head fw_image_list; - -struct intr_transfer_buf { -	u32 notification; -	u32 reserved; -};  struct brcmf_usbdev_info {  	struct brcmf_usbdev bus_pub; /* MUST BE FIRST */ @@ -75,7 +70,7 @@ struct brcmf_usbdev_info {  	struct list_head rx_postq;  	struct list_head tx_freeq;  	struct list_head tx_postq; -	uint rx_pipe, tx_pipe, intr_pipe, rx_pipe2; +	uint rx_pipe, tx_pipe, rx_pipe2;  	int rx_low_watermark;  	int tx_low_watermark; @@ -87,7 +82,7 @@ struct brcmf_usbdev_info {  	struct brcmf_usbreq *tx_reqs;  	struct brcmf_usbreq *rx_reqs; -	u8 *image;	/* buffer for combine fw and nvram */ +	const u8 *image;	/* buffer for combine fw and nvram */  	int image_len;  	struct usb_device *usbdev; @@ -104,10 +99,6 @@ struct brcmf_usbdev_info {  	ulong ctl_op;  	struct urb *bulk_urb; /* used for FW download */ -	struct urb *intr_urb; /* URB for interrupt endpoint */ -	int intr_size;          /* Size of interrupt message */ -	int interval;           /* Interrupt polling interval */ -	struct intr_transfer_buf intr; /* Data buffer for interrupt endpoint */  };  static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo, @@ -435,7 +426,6 @@ static void brcmf_usb_rx_complete(struct urb *urb)  	struct brcmf_usbreq  *req = (struct brcmf_usbreq *)urb->context;  	struct brcmf_usbdev_info *devinfo = req->devinfo;  	struct sk_buff *skb; -	struct sk_buff_head skbq;  	brcmf_dbg(USB, "Enter, urb->status=%d\n", urb->status);  	brcmf_usb_del_fromq(devinfo, req); @@ -450,10 +440,8 @@ static void brcmf_usb_rx_complete(struct urb *urb)  	}  	if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) { -		skb_queue_head_init(&skbq); -		skb_queue_tail(&skbq, skb);  		skb_put(skb, urb->actual_length); -		brcmf_rx_frames(devinfo->dev, &skbq); +		brcmf_rx_frame(devinfo->dev, skb);  		brcmf_usb_rx_refill(devinfo, req);  	} else {  		brcmu_pkt_buf_free_skb(skb); @@ -525,48 +513,15 @@ brcmf_usb_state_change(struct brcmf_usbdev_info *devinfo, int state)  	/* update state of upper layer */  	if (state == BRCMFMAC_USB_STATE_DOWN) {  		brcmf_dbg(USB, "DBUS is down\n"); -		bcmf_bus->state = BRCMF_BUS_DOWN; +		brcmf_bus_change_state(bcmf_bus, BRCMF_BUS_DOWN);  	} else if (state == BRCMFMAC_USB_STATE_UP) {  		brcmf_dbg(USB, "DBUS is up\n"); -		bcmf_bus->state = BRCMF_BUS_DATA; +		brcmf_bus_change_state(bcmf_bus, BRCMF_BUS_DATA);  	} else {  		brcmf_dbg(USB, "DBUS current state=%d\n", state);  	}  } -static void -brcmf_usb_intr_complete(struct urb *urb) -{ -	struct brcmf_usbdev_info *devinfo = -			(struct brcmf_usbdev_info *)urb->context; -	int err; - -	brcmf_dbg(USB, "Enter, urb->status=%d\n", urb->status); - -	if (devinfo == NULL) -		return; - -	if (unlikely(urb->status)) { -		if (urb->status == -ENOENT || -		    urb->status == -ESHUTDOWN || -		    urb->status == -ENODEV) { -			brcmf_usb_state_change(devinfo, -					       BRCMFMAC_USB_STATE_DOWN); -		} -	} - -	if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_DOWN) { -		brcmf_err("intr cb when DBUS down, ignoring\n"); -		return; -	} - -	if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) { -		err = usb_submit_urb(devinfo->intr_urb, GFP_ATOMIC); -		if (err) -			brcmf_err("usb_submit_urb, err=%d\n", err); -	} -} -  static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)  {  	struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); @@ -622,7 +577,6 @@ static int brcmf_usb_up(struct device *dev)  {  	struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);  	u16 ifnum; -	int ret;  	brcmf_dbg(USB, "Enter\n");  	if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) @@ -631,23 +585,6 @@ static int brcmf_usb_up(struct device *dev)  	/* Success, indicate devinfo is fully up */  	brcmf_usb_state_change(devinfo, BRCMFMAC_USB_STATE_UP); -	if (devinfo->intr_urb) { -		usb_fill_int_urb(devinfo->intr_urb, devinfo->usbdev, -			devinfo->intr_pipe, -			&devinfo->intr, -			devinfo->intr_size, -			(usb_complete_t)brcmf_usb_intr_complete, -			devinfo, -			devinfo->interval); - -		ret = usb_submit_urb(devinfo->intr_urb, GFP_ATOMIC); -		if (ret) { -			brcmf_err("USB_SUBMIT_URB failed with status %d\n", -				  ret); -			return -EINVAL; -		} -	} -  	if (devinfo->ctl_urb) {  		devinfo->ctl_in_pipe = usb_rcvctrlpipe(devinfo->usbdev, 0);  		devinfo->ctl_out_pipe = usb_sndctrlpipe(devinfo->usbdev, 0); @@ -684,8 +621,6 @@ static void brcmf_usb_down(struct device *dev)  		return;  	brcmf_usb_state_change(devinfo, BRCMFMAC_USB_STATE_DOWN); -	if (devinfo->intr_urb) -		usb_kill_urb(devinfo->intr_urb);  	if (devinfo->ctl_urb)  		usb_kill_urb(devinfo->ctl_urb); @@ -1024,7 +959,7 @@ brcmf_usb_fw_download(struct brcmf_usbdev_info *devinfo)  	}  	err = brcmf_usb_dlstart(devinfo, -		devinfo->image, devinfo->image_len); +		(u8 *)devinfo->image, devinfo->image_len);  	if (err == 0)  		err = brcmf_usb_dlrun(devinfo);  	return err; @@ -1039,7 +974,6 @@ static void brcmf_usb_detach(struct brcmf_usbdev_info *devinfo)  	brcmf_usb_free_q(&devinfo->rx_freeq, false);  	brcmf_usb_free_q(&devinfo->tx_freeq, false); -	usb_free_urb(devinfo->intr_urb);  	usb_free_urb(devinfo->ctl_urb);  	usb_free_urb(devinfo->bulk_urb); @@ -1083,68 +1017,20 @@ static int check_file(const u8 *headers)  	return -1;  } -static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo) +static const char *brcmf_usb_get_fwname(struct brcmf_usbdev_info *devinfo)  { -	s8 *fwname; -	const struct firmware *fw; -	struct brcmf_usb_image *fw_image; -	int err; - -	brcmf_dbg(USB, "Enter\n");  	switch (devinfo->bus_pub.devid) {  	case 43143: -		fwname = BRCMF_USB_43143_FW_NAME; -		break; +		return BRCMF_USB_43143_FW_NAME;  	case 43235:  	case 43236:  	case 43238: -		fwname = BRCMF_USB_43236_FW_NAME; -		break; +		return BRCMF_USB_43236_FW_NAME;  	case 43242: -		fwname = BRCMF_USB_43242_FW_NAME; -		break; +		return BRCMF_USB_43242_FW_NAME;  	default: -		return -EINVAL; -		break; -	} -	brcmf_dbg(USB, "Loading FW %s\n", fwname); -	list_for_each_entry(fw_image, &fw_image_list, list) { -		if (fw_image->fwname == fwname) { -			devinfo->image = fw_image->image; -			devinfo->image_len = fw_image->image_len; -			return 0; -		} -	} -	/* fw image not yet loaded. Load it now and add to list */ -	err = request_firmware(&fw, fwname, devinfo->dev); -	if (!fw) { -		brcmf_err("fail to request firmware %s\n", fwname); -		return err; -	} -	if (check_file(fw->data) < 0) { -		brcmf_err("invalid firmware %s\n", fwname); -		return -EINVAL; +		return NULL;  	} - -	fw_image = kzalloc(sizeof(*fw_image), GFP_ATOMIC); -	if (!fw_image) -		return -ENOMEM; -	INIT_LIST_HEAD(&fw_image->list); -	list_add_tail(&fw_image->list, &fw_image_list); -	fw_image->fwname = fwname; -	fw_image->image = vmalloc(fw->size); -	if (!fw_image->image) -		return -ENOMEM; - -	memcpy(fw_image->image, fw->data, fw->size); -	fw_image->image_len = fw->size; - -	release_firmware(fw); - -	devinfo->image = fw_image->image; -	devinfo->image_len = fw_image->image_len; - -	return 0;  } @@ -1189,11 +1075,6 @@ struct brcmf_usbdev *brcmf_usb_attach(struct brcmf_usbdev_info *devinfo,  		goto error;  	devinfo->tx_freecount = ntxq; -	devinfo->intr_urb = usb_alloc_urb(0, GFP_ATOMIC); -	if (!devinfo->intr_urb) { -		brcmf_err("usb_alloc_urb (intr) failed\n"); -		goto error; -	}  	devinfo->ctl_urb = usb_alloc_urb(0, GFP_ATOMIC);  	if (!devinfo->ctl_urb) {  		brcmf_err("usb_alloc_urb (ctl) failed\n"); @@ -1205,16 +1086,6 @@ struct brcmf_usbdev *brcmf_usb_attach(struct brcmf_usbdev_info *devinfo,  		goto error;  	} -	if (!brcmf_usb_dlneeded(devinfo)) -		return &devinfo->bus_pub; - -	brcmf_dbg(USB, "Start fw downloading\n"); -	if (brcmf_usb_get_fw(devinfo)) -		goto error; - -	if (brcmf_usb_fw_download(devinfo)) -		goto error; -  	return &devinfo->bus_pub;  error: @@ -1225,18 +1096,77 @@ error:  static struct brcmf_bus_ops brcmf_usb_bus_ops = {  	.txdata = brcmf_usb_tx, -	.init = brcmf_usb_up,  	.stop = brcmf_usb_down,  	.txctl = brcmf_usb_tx_ctlpkt,  	.rxctl = brcmf_usb_rx_ctlpkt,  }; +static int brcmf_usb_bus_setup(struct brcmf_usbdev_info *devinfo) +{ +	int ret; + +	/* Attach to the common driver interface */ +	ret = brcmf_attach(devinfo->dev); +	if (ret) { +		brcmf_err("brcmf_attach failed\n"); +		return ret; +	} + +	ret = brcmf_usb_up(devinfo->dev); +	if (ret) +		goto fail; + +	ret = brcmf_bus_start(devinfo->dev); +	if (ret) +		goto fail; + +	return 0; +fail: +	brcmf_detach(devinfo->dev); +	return ret; +} + +static void brcmf_usb_probe_phase2(struct device *dev, +				   const struct firmware *fw, +				   void *nvram, u32 nvlen) +{ +	struct brcmf_bus *bus = dev_get_drvdata(dev); +	struct brcmf_usbdev_info *devinfo; +	int ret; + +	brcmf_dbg(USB, "Start fw downloading\n"); +	ret = check_file(fw->data); +	if (ret < 0) { +		brcmf_err("invalid firmware\n"); +		release_firmware(fw); +		goto error; +	} + +	devinfo = bus->bus_priv.usb->devinfo; +	devinfo->image = fw->data; +	devinfo->image_len = fw->size; + +	ret = brcmf_usb_fw_download(devinfo); +	release_firmware(fw); +	if (ret) +		goto error; + +	ret = brcmf_usb_bus_setup(devinfo); +	if (ret) +		goto error; + +	return; +error: +	brcmf_dbg(TRACE, "failed: dev=%s, err=%d\n", dev_name(dev), ret); +	device_release_driver(dev); +} +  static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)  {  	struct brcmf_bus *bus = NULL;  	struct brcmf_usbdev *bus_pub = NULL; -	int ret;  	struct device *dev = devinfo->dev; +	int ret;  	brcmf_dbg(USB, "Enter\n");  	bus_pub = brcmf_usb_attach(devinfo, BRCMF_USB_NRXQ, BRCMF_USB_NTXQ); @@ -1254,24 +1184,22 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)  	bus->bus_priv.usb = bus_pub;  	dev_set_drvdata(dev, bus);  	bus->ops = &brcmf_usb_bus_ops; -	bus->chip = bus_pub->devid; -	bus->chiprev = bus_pub->chiprev; - -	/* Attach to the common driver interface */ -	ret = brcmf_attach(0, dev); -	if (ret) { -		brcmf_err("brcmf_attach failed\n"); -		goto fail; -	} +	bus->proto_type = BRCMF_PROTO_BCDC; +	bus->always_use_fws_queue = true; -	ret = brcmf_bus_start(dev); -	if (ret) { -		brcmf_err("dongle is not responding\n"); -		brcmf_detach(dev); -		goto fail; +	if (!brcmf_usb_dlneeded(devinfo)) { +		ret = brcmf_usb_bus_setup(devinfo); +		if (ret) +			goto fail;  	} +	bus->chip = bus_pub->devid; +	bus->chiprev = bus_pub->chiprev; +	/* request firmware here */ +	brcmf_fw_get_firmwares(dev, 0, brcmf_usb_get_fwname(devinfo), NULL, +			       brcmf_usb_probe_phase2);  	return 0; +  fail:  	/* Release resources in reverse order */  	kfree(bus); @@ -1359,9 +1287,6 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)  		goto fail;  	} -	endpoint_num = endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; -	devinfo->intr_pipe = usb_rcvintpipe(usb, endpoint_num); -  	devinfo->rx_pipe = 0;  	devinfo->rx_pipe2 = 0;  	devinfo->tx_pipe = 0; @@ -1393,16 +1318,9 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)  		}  	} -	/* Allocate interrupt URB and data buffer */ -	/* RNDIS says 8-byte intr, our old drivers used 4-byte */ -	if (IFEPDESC(usb, CONTROL_IF, 0).wMaxPacketSize == cpu_to_le16(16)) -		devinfo->intr_size = 8; -	else -		devinfo->intr_size = 4; - -	devinfo->interval = IFEPDESC(usb, CONTROL_IF, 0).bInterval; - -	if (usb->speed == USB_SPEED_HIGH) +	if (usb->speed == USB_SPEED_SUPER) +		brcmf_dbg(USB, "Broadcom super speed USB wireless device detected\n"); +	else if (usb->speed == USB_SPEED_HIGH)  		brcmf_dbg(USB, "Broadcom high speed USB wireless device detected\n");  	else  		brcmf_dbg(USB, "Broadcom full speed USB wireless device detected\n"); @@ -1457,23 +1375,18 @@ static int brcmf_usb_resume(struct usb_interface *intf)  	struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);  	brcmf_dbg(USB, "Enter\n"); -	if (!brcmf_attach(0, devinfo->dev)) -		return brcmf_bus_start(&usb->dev); - -	return 0; +	return brcmf_usb_bus_setup(devinfo);  }  static int brcmf_usb_reset_resume(struct usb_interface *intf)  {  	struct usb_device *usb = interface_to_usbdev(intf);  	struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev); -  	brcmf_dbg(USB, "Enter\n"); -	if (!brcmf_usb_fw_download(devinfo)) -		return brcmf_usb_resume(intf); - -	return -EIO; +	return brcmf_fw_get_firmwares(&usb->dev, 0, +				      brcmf_usb_get_fwname(devinfo), NULL, +				      brcmf_usb_probe_phase2);  }  #define BRCMF_USB_VENDOR_ID_BROADCOM	0x0a5c @@ -1508,16 +1421,6 @@ static struct usb_driver brcmf_usbdrvr = {  	.disable_hub_initiated_lpm = 1,  }; -static void brcmf_release_fw(struct list_head *q) -{ -	struct brcmf_usb_image *fw_image, *next; - -	list_for_each_entry_safe(fw_image, next, q, list) { -		vfree(fw_image->image); -		list_del_init(&fw_image->list); -	} -} -  static int brcmf_usb_reset_device(struct device *dev, void *notused)  {  	/* device past is the usb interface so we @@ -1536,12 +1439,10 @@ void brcmf_usb_exit(void)  	ret = driver_for_each_device(drv, NULL, NULL,  				     brcmf_usb_reset_device);  	usb_deregister(&brcmf_usbdrvr); -	brcmf_release_fw(&fw_image_list);  }  void brcmf_usb_register(void)  {  	brcmf_dbg(USB, "Enter\n"); -	INIT_LIST_HEAD(&fw_image_list);  	usb_register(&brcmf_usbdrvr);  } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 571f013cebb..d8fa276e368 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -18,6 +18,7 @@  #include <linux/kernel.h>  #include <linux/etherdevice.h> +#include <linux/module.h>  #include <net/cfg80211.h>  #include <net/netlink.h> @@ -190,6 +191,7 @@ static struct ieee80211_supported_band __wl_band_2ghz = {  	.n_channels = ARRAY_SIZE(__wl_2ghz_channels),  	.bitrates = wl_g_rates,  	.n_bitrates = wl_g_rates_size, +	.ht_cap = {IEEE80211_HT_CAP_SUP_WIDTH_20_40, true},  };  static struct ieee80211_supported_band __wl_band_5ghz_a = { @@ -202,9 +204,9 @@ static struct ieee80211_supported_band __wl_band_5ghz_a = {  /* This is to override regulatory domains defined in cfg80211 module (reg.c)   * By default world regulatory domain defined in reg.c puts the flags - * NL80211_RRF_PASSIVE_SCAN and NL80211_RRF_NO_IBSS for 5GHz channels (for - * 36..48 and 149..165). With respect to these flags, wpa_supplicant doesn't - * start p2p operations on 5GHz channels. All the changes in world regulatory + * NL80211_RRF_NO_IR for 5GHz channels (for * 36..48 and 149..165). + * With respect to these flags, wpa_supplicant doesn't * start p2p + * operations on 5GHz channels. All the changes in world regulatory   * domain are to be done here.   */  static const struct ieee80211_regdomain brcmf_regdom = { @@ -219,9 +221,9 @@ static const struct ieee80211_regdomain brcmf_regdom = {  		 */  		REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),  		/* IEEE 802.11a, channel 36..64 */ -		REG_RULE(5150-10, 5350+10, 40, 6, 20, 0), +		REG_RULE(5150-10, 5350+10, 80, 6, 20, 0),  		/* IEEE 802.11a, channel 100..165 */ -		REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), } +		REG_RULE(5470-10, 5850+10, 80, 6, 20, 0), }  };  static const u32 __wl_cipher_suites[] = { @@ -251,6 +253,10 @@ struct parsed_vndr_ies {  	struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];  }; +static int brcmf_roamoff; +module_param_named(roamoff, brcmf_roamoff, int, S_IRUSR); +MODULE_PARM_DESC(roamoff, "do not use internal roaming engine"); +  /* Quarter dBm units to mW   * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153   * Table is offset so the last entry is largest mW value that fits in @@ -335,6 +341,60 @@ static u8 brcmf_mw_to_qdbm(u16 mw)  	return qdbm;  } +static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf, +			       struct cfg80211_chan_def *ch) +{ +	struct brcmu_chan ch_inf; +	s32 primary_offset; + +	brcmf_dbg(TRACE, "chandef: control %d center %d width %d\n", +		  ch->chan->center_freq, ch->center_freq1, ch->width); +	ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq1); +	primary_offset = ch->center_freq1 - ch->chan->center_freq; +	switch (ch->width) { +	case NL80211_CHAN_WIDTH_20: +		ch_inf.bw = BRCMU_CHAN_BW_20; +		WARN_ON(primary_offset != 0); +		break; +	case NL80211_CHAN_WIDTH_40: +		ch_inf.bw = BRCMU_CHAN_BW_40; +		if (primary_offset < 0) +			ch_inf.sb = BRCMU_CHAN_SB_U; +		else +			ch_inf.sb = BRCMU_CHAN_SB_L; +		break; +	case NL80211_CHAN_WIDTH_80: +		ch_inf.bw = BRCMU_CHAN_BW_80; +		if (primary_offset < 0) { +			if (primary_offset < -CH_10MHZ_APART) +				ch_inf.sb = BRCMU_CHAN_SB_UU; +			else +				ch_inf.sb = BRCMU_CHAN_SB_UL; +		} else { +			if (primary_offset > CH_10MHZ_APART) +				ch_inf.sb = BRCMU_CHAN_SB_LL; +			else +				ch_inf.sb = BRCMU_CHAN_SB_LU; +		} +		break; +	default: +		WARN_ON_ONCE(1); +	} +	switch (ch->chan->band) { +	case IEEE80211_BAND_2GHZ: +		ch_inf.band = BRCMU_CHAN_BAND_2G; +		break; +	case IEEE80211_BAND_5GHZ: +		ch_inf.band = BRCMU_CHAN_BAND_5G; +		break; +	default: +		WARN_ON_ONCE(1); +	} +	d11inf->encchspec(&ch_inf); + +	return ch_inf.chspec; +} +  u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,  			struct ieee80211_channel *ch)  { @@ -351,13 +411,11 @@ u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,   * triples, returning a pointer to the substring whose first element   * matches tag   */ -struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key) +const struct brcmf_tlv * +brcmf_parse_tlvs(const void *buf, int buflen, uint key)  { -	struct brcmf_tlv *elt; -	int totlen; - -	elt = (struct brcmf_tlv *)buf; -	totlen = buflen; +	const struct brcmf_tlv *elt = buf; +	int totlen = buflen;  	/* find tagged parameter */  	while (totlen >= TLV_HDR_LEN) { @@ -378,8 +436,8 @@ struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key)   * not update the tlvs buffer pointer/length.   */  static bool -brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, -		 u8 *oui, u32 oui_len, u8 type) +brcmf_tlv_has_ie(const u8 *ie, const u8 **tlvs, u32 *tlvs_len, +		 const u8 *oui, u32 oui_len, u8 type)  {  	/* If the contents match the OUI and the type */  	if (ie[TLV_LEN_OFF] >= oui_len + 1 && @@ -401,12 +459,12 @@ brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len,  }  static struct brcmf_vs_tlv * -brcmf_find_wpaie(u8 *parse, u32 len) +brcmf_find_wpaie(const u8 *parse, u32 len)  { -	struct brcmf_tlv *ie; +	const struct brcmf_tlv *ie;  	while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) { -		if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len, +		if (brcmf_tlv_has_ie((const u8 *)ie, &parse, &len,  				     WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE))  			return (struct brcmf_vs_tlv *)ie;  	} @@ -414,9 +472,9 @@ brcmf_find_wpaie(u8 *parse, u32 len)  }  static struct brcmf_vs_tlv * -brcmf_find_wpsie(u8 *parse, u32 len) +brcmf_find_wpsie(const u8 *parse, u32 len)  { -	struct brcmf_tlv *ie; +	const struct brcmf_tlv *ie;  	while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) {  		if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len, @@ -491,6 +549,19 @@ brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable)  	return err;  } +static bool brcmf_is_apmode(struct brcmf_cfg80211_vif *vif) +{ +	enum nl80211_iftype iftype; + +	iftype = vif->wdev.iftype; +	return iftype == NL80211_IFTYPE_AP || iftype == NL80211_IFTYPE_P2P_GO; +} + +static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif) +{ +	return vif->wdev.iftype == NL80211_IFTYPE_ADHOC; +} +  static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,  						     const char *name,  						     enum nl80211_iftype type, @@ -569,6 +640,9 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,  		if (err)  			brcmf_err("Scan abort  failed\n");  	} + +	brcmf_set_mpc(ifp, 1); +  	/*  	 * e-scan can be initiated by scheduled scan  	 * which takes precedence. @@ -578,12 +652,10 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,  		cfg->sched_escan = false;  		if (!aborted)  			cfg80211_sched_scan_results(cfg_to_wiphy(cfg)); -		brcmf_set_mpc(ifp, 1);  	} else if (scan_request) {  		brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",  			  aborted ? "Aborted" : "Done");  		cfg80211_scan_done(scan_request, aborted); -		brcmf_set_mpc(ifp, 1);  	}  	if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))  		brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n"); @@ -651,7 +723,6 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,  			  type);  		return -EOPNOTSUPP;  	case NL80211_IFTYPE_ADHOC: -		vif->mode = WL_MODE_IBSS;  		infra = 0;  		break;  	case NL80211_IFTYPE_STATION: @@ -667,12 +738,10 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,  			 */  			return 0;  		} -		vif->mode = WL_MODE_BSS;  		infra = 1;  		break;  	case NL80211_IFTYPE_AP:  	case NL80211_IFTYPE_P2P_GO: -		vif->mode = WL_MODE_AP;  		ap = 1;  		break;  	default: @@ -696,7 +765,7 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,  			err = -EAGAIN;  			goto done;  		} -		brcmf_dbg(INFO, "IF Type = %s\n", (vif->mode == WL_MODE_IBSS) ? +		brcmf_dbg(INFO, "IF Type = %s\n", brcmf_is_ibssmode(vif) ?  			  "Adhoc" : "Infra");  	}  	ndev->ieee80211_ptr->iftype = type; @@ -1095,10 +1164,10 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)  					     BRCMF_C_DISASSOC, NULL, 0);  		if (err) {  			brcmf_err("WLC_DISASSOC failed (%d)\n", err); -			cfg80211_disconnected(vif->wdev.netdev, 0, -					      NULL, 0, GFP_KERNEL);  		}  		clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state); +		cfg80211_disconnected(vif->wdev.netdev, 0, NULL, 0, GFP_KERNEL); +  	}  	clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);  	clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status); @@ -1222,8 +1291,8 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,  				params->chandef.chan->center_freq);  		if (params->channel_fixed) {  			/* adding chanspec */ -			chanspec = channel_to_chanspec(&cfg->d11inf, -						       params->chandef.chan); +			chanspec = chandef_to_chanspec(&cfg->d11inf, +						       ¶ms->chandef);  			join_params.params_le.chanspec_list[0] =  				cpu_to_le16(chanspec);  			join_params.params_le.chanspec_num = cpu_to_le32(1); @@ -1340,13 +1409,14 @@ static s32 brcmf_set_auth_type(struct net_device *ndev,  }  static s32 -brcmf_set_set_cipher(struct net_device *ndev, -		     struct cfg80211_connect_params *sme) +brcmf_set_wsec_mode(struct net_device *ndev, +		     struct cfg80211_connect_params *sme, bool mfp)  {  	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);  	struct brcmf_cfg80211_security *sec;  	s32 pval = 0;  	s32 gval = 0; +	s32 wsec;  	s32 err = 0;  	if (sme->crypto.n_ciphers_pairwise) { @@ -1398,7 +1468,12 @@ brcmf_set_set_cipher(struct net_device *ndev,  	if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval &&  	    sme->privacy)  		pval = AES_ENABLED; -	err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", pval | gval); + +	if (mfp) +		wsec = pval | gval | MFP_CAPABLE; +	else +		wsec = pval | gval; +	err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", wsec);  	if (err) {  		brcmf_err("error (%d)\n", err);  		return err; @@ -1562,13 +1637,12 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,  	struct ieee80211_channel *chan = sme->channel;  	struct brcmf_join_params join_params;  	size_t join_params_size; -	struct brcmf_tlv *rsn_ie; -	struct brcmf_vs_tlv *wpa_ie; -	void *ie; +	const struct brcmf_tlv *rsn_ie; +	const struct brcmf_vs_tlv *wpa_ie; +	const void *ie;  	u32 ie_len;  	struct brcmf_ext_join_params_le *ext_join_params;  	u16 chanspec; -  	s32 err = 0;  	brcmf_dbg(TRACE, "Enter\n"); @@ -1591,7 +1665,8 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,  			ie_len = wpa_ie->len + TLV_HDR_LEN;  		} else {  			/* find the RSN_IE */ -			rsn_ie = brcmf_parse_tlvs((u8 *)sme->ie, sme->ie_len, +			rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie, +						  sme->ie_len,  						  WLAN_EID_RSN);  			if (rsn_ie) {  				ie = rsn_ie; @@ -1636,7 +1711,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,  		goto done;  	} -	err = brcmf_set_set_cipher(ndev, sme); +	err = brcmf_set_wsec_mode(ndev, sme, sme->mfp == NL80211_MFP_REQUIRED);  	if (err) {  		brcmf_err("wl_set_set_cipher failed (%d)\n", err);  		goto done; @@ -1678,22 +1753,9 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,  	ext_join_params->ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len);  	memcpy(&ext_join_params->ssid_le.SSID, sme->ssid,  	       profile->ssid.SSID_len); -	/*increase dwell time to receive probe response or detect Beacon -	 * from target AP at a noisy air only during connect command -	 */ -	ext_join_params->scan_le.active_time = -		cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS); -	ext_join_params->scan_le.passive_time = -		cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS); +  	/* Set up join scan parameters */  	ext_join_params->scan_le.scan_type = -1; -	/* to sync with presence period of VSDB GO. -	 * Send probe request more frequently. Probe request will be stopped -	 * when it gets probe response from target AP/GO. -	 */ -	ext_join_params->scan_le.nprobes = -		cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS / -			    BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS);  	ext_join_params->scan_le.home_time = cpu_to_le32(-1);  	if (sme->bssid) @@ -1706,6 +1768,25 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,  		ext_join_params->assoc_le.chanspec_list[0] =  			cpu_to_le16(chanspec); +		/* Increase dwell time to receive probe response or detect +		 * beacon from target AP at a noisy air only during connect +		 * command. +		 */ +		ext_join_params->scan_le.active_time = +			cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS); +		ext_join_params->scan_le.passive_time = +			cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS); +		/* To sync with presence period of VSDB GO send probe request +		 * more frequently. Probe request will be stopped when it gets +		 * probe response from target AP/GO. +		 */ +		ext_join_params->scan_le.nprobes = +			cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS / +				    BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS); +	} else { +		ext_join_params->scan_le.active_time = cpu_to_le32(-1); +		ext_join_params->scan_le.passive_time = cpu_to_le32(-1); +		ext_join_params->scan_le.nprobes = cpu_to_le32(-1);  	}  	err  = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params, @@ -1758,6 +1839,7 @@ brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,  		return -EIO;  	clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state); +	cfg80211_disconnected(ndev, reason_code, NULL, 0, GFP_KERNEL);  	memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);  	scbval.val = cpu_to_le32(reason_code); @@ -1912,7 +1994,7 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,  		brcmf_dbg(CONN, "Setting the key index %d\n", key.index);  		memcpy(key.data, params->key, key.len); -		if ((ifp->vif->mode != WL_MODE_AP) && +		if (!brcmf_is_apmode(ifp->vif) &&  		    (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {  			brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");  			memcpy(keybuf, &key.data[24], sizeof(keybuf)); @@ -1980,7 +2062,9 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,  	if (!check_vif_up(ifp->vif))  		return -EIO; -	if (mac_addr) { +	if (mac_addr && +		(params->cipher != WLAN_CIPHER_SUITE_WEP40) && +		(params->cipher != WLAN_CIPHER_SUITE_WEP104)) {  		brcmf_dbg(TRACE, "Exit");  		return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);  	} @@ -2009,7 +2093,7 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,  		brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");  		break;  	case WLAN_CIPHER_SUITE_TKIP: -		if (ifp->vif->mode != WL_MODE_AP) { +		if (!brcmf_is_apmode(ifp->vif)) {  			brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");  			memcpy(keybuf, &key.data[24], sizeof(keybuf));  			memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); @@ -2153,7 +2237,7 @@ brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,  static s32  brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, -			   u8 *mac, struct station_info *sinfo) +			   const u8 *mac, struct station_info *sinfo)  {  	struct brcmf_if *ifp = netdev_priv(ndev);  	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; @@ -2163,12 +2247,14 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,  	s32 err = 0;  	u8 *bssid = profile->bssid;  	struct brcmf_sta_info_le sta_info_le; +	u32 beacon_period; +	u32 dtim_period;  	brcmf_dbg(TRACE, "Enter, MAC %pM\n", mac);  	if (!check_vif_up(ifp->vif))  		return -EIO; -	if (ifp->vif->mode == WL_MODE_AP) { +	if (brcmf_is_apmode(ifp->vif)) {  		memcpy(&sta_info_le, mac, ETH_ALEN);  		err = brcmf_fil_iovar_data_get(ifp, "sta_info",  					       &sta_info_le, @@ -2185,7 +2271,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,  		}  		brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n",  			  sinfo->inactive_time, sinfo->connected_time); -	} else if (ifp->vif->mode == WL_MODE_BSS) { +	} else if (ifp->vif->wdev.iftype == NL80211_IFTYPE_STATION) {  		if (memcmp(mac, bssid, ETH_ALEN)) {  			brcmf_err("Wrong Mac address cfg_mac-%pM wl_bssid-%pM\n",  				  mac, bssid); @@ -2217,6 +2303,30 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,  				sinfo->signal = rssi;  				brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);  			} +			err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_BCNPRD, +						    &beacon_period); +			if (err) { +				brcmf_err("Could not get beacon period (%d)\n", +					  err); +				goto done; +			} else { +				sinfo->bss_param.beacon_interval = +					beacon_period; +				brcmf_dbg(CONN, "Beacon peroid %d\n", +					  beacon_period); +			} +			err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_DTIMPRD, +						    &dtim_period); +			if (err) { +				brcmf_err("Could not get DTIM period (%d)\n", +					  err); +				goto done; +			} else { +				sinfo->bss_param.dtim_period = dtim_period; +				brcmf_dbg(CONN, "DTIM peroid %d\n", +					  dtim_period); +			} +			sinfo->filled |= STATION_INFO_BSS_PARAM;  		}  	} else  		err = -EPERM; @@ -2443,18 +2553,13 @@ CleanUp:  	return err;  } -static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif) -{ -	return vif->mode == WL_MODE_IBSS; -} -  static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg,  				 struct brcmf_if *ifp)  {  	struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev);  	struct brcmf_bss_info_le *bi;  	struct brcmf_ssid *ssid; -	struct brcmf_tlv *tim; +	const struct brcmf_tlv *tim;  	u16 beacon_interval;  	u8 dtim_period;  	size_t ie_len; @@ -2556,8 +2661,8 @@ brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,  		ch_bss.band == ch_bss_info_le.band &&  		bss_info_le->SSID_len == bss->SSID_len &&  		!memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) { -		if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) == -			(bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL)) { +		if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == +			(bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL)) {  			s16 bss_rssi = le16_to_cpu(bss->RSSI);  			s16 bss_info_rssi = le16_to_cpu(bss_info_le->RSSI); @@ -2566,13 +2671,13 @@ brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,  			*/  			if (bss_info_rssi > bss_rssi)  				bss->RSSI = bss_info_le->RSSI; -		} else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) && -			(bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) { +		} else if ((bss->flags & BRCMF_BSS_RSSI_ON_CHANNEL) && +			(bss_info_le->flags & BRCMF_BSS_RSSI_ON_CHANNEL) == 0) {  			/* preserve the on-channel rssi measurement  			* if the new measurement is off channel  			*/  			bss->RSSI = bss_info_le->RSSI; -			bss->flags |= WLC_BSS_RSSI_ON_CHANNEL; +			bss->flags |= BRCMF_BSS_RSSI_ON_CHANNEL;  		}  		return 1;  	} @@ -2988,6 +3093,7 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp,  		}  		set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); +		cfg->escan_info.run = brcmf_run_escan;  		err = brcmf_do_escan(cfg, wiphy, ifp, request);  		if (err) {  			clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); @@ -3073,7 +3179,7 @@ brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,  	}  	if (!request->n_ssids || !request->n_match_sets) { -		brcmf_err("Invalid sched scan req!! n_ssids:%d\n", +		brcmf_dbg(SCAN, "Invalid sched scan req!! n_ssids:%d\n",  			  request->n_ssids);  		return -EINVAL;  	} @@ -3218,8 +3324,9 @@ static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)  }  static s32 -brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie, -		     bool is_rsn_ie) +brcmf_configure_wpaie(struct net_device *ndev, +		      const struct brcmf_vs_tlv *wpa_ie, +		      bool is_rsn_ie)  {  	struct brcmf_if *ifp = netdev_priv(ndev);  	u32 auth = 0; /* d11 open authentication */ @@ -3682,42 +3789,26 @@ brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,  }  static s32 -brcmf_cfg80211_set_channel(struct brcmf_cfg80211_info *cfg, -			   struct brcmf_if *ifp, -			   struct ieee80211_channel *channel) -{ -	u16 chanspec; -	s32 err; - -	brcmf_dbg(TRACE, "band=%d, center_freq=%d\n", channel->band, -		  channel->center_freq); - -	chanspec = channel_to_chanspec(&cfg->d11inf, channel); -	err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec); - -	return err; -} - -static s32  brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,  			struct cfg80211_ap_settings *settings)  {  	s32 ie_offset;  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);  	struct brcmf_if *ifp = netdev_priv(ndev); -	struct brcmf_tlv *ssid_ie; +	const struct brcmf_tlv *ssid_ie;  	struct brcmf_ssid_le ssid_le;  	s32 err = -EPERM; -	struct brcmf_tlv *rsn_ie; -	struct brcmf_vs_tlv *wpa_ie; +	const struct brcmf_tlv *rsn_ie; +	const struct brcmf_vs_tlv *wpa_ie;  	struct brcmf_join_params join_params;  	enum nl80211_iftype dev_role;  	struct brcmf_fil_bss_enable_le bss_enable; +	u16 chanspec; -	brcmf_dbg(TRACE, "channel_type=%d, beacon_interval=%d, dtim_period=%d,\n", -		  cfg80211_get_chandef_type(&settings->chandef), -		  settings->beacon_interval, -		  settings->dtim_period); +	brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n", +		  settings->chandef.chan->hw_value, +		  settings->chandef.center_freq1, settings->chandef.width, +		  settings->beacon_interval, settings->dtim_period);  	brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",  		  settings->ssid, settings->ssid_len, settings->auth_type,  		  settings->inactivity_timeout); @@ -3774,9 +3865,10 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,  	brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon); -	err = brcmf_cfg80211_set_channel(cfg, ifp, settings->chandef.chan); +	chanspec = chandef_to_chanspec(&cfg->d11inf, &settings->chandef); +	err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);  	if (err < 0) { -		brcmf_err("Set Channel failed, %d\n", err); +		brcmf_err("Set Channel failed: chspec=%d, %d\n", chanspec, err);  		goto exit;  	} @@ -3923,7 +4015,7 @@ brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,  static int  brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, -			   u8 *mac) +			   const u8 *mac)  {  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);  	struct brcmf_scb_val_le scbval; @@ -3973,11 +4065,12 @@ brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,  static int  brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, -		       struct ieee80211_channel *chan, bool offchan, -		       unsigned int wait, const u8 *buf, size_t len, -		       bool no_cck, bool dont_wait_for_ack, u64 *cookie) +		       struct cfg80211_mgmt_tx_params *params, u64 *cookie)  {  	struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); +	struct ieee80211_channel *chan = params->chan; +	const u8 *buf = params->buf; +	size_t len = params->len;  	const struct ieee80211_mgmt *mgmt;  	struct brcmf_cfg80211_vif *vif;  	s32 err = 0; @@ -4150,7 +4243,7 @@ static int brcmf_convert_nl80211_tdls_oper(enum nl80211_tdls_operation oper)  }  static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy, -				    struct net_device *ndev, u8 *peer, +				    struct net_device *ndev, const u8 *peer,  				    enum nl80211_tdls_operation oper)  {  	struct brcmf_if *ifp; @@ -4217,32 +4310,6 @@ static struct cfg80211_ops wl_cfg80211_ops = {  	CFG80211_TESTMODE_CMD(brcmf_cfg80211_testmode)  }; -static s32 brcmf_nl80211_iftype_to_mode(enum nl80211_iftype type) -{ -	switch (type) { -	case NL80211_IFTYPE_AP_VLAN: -	case NL80211_IFTYPE_WDS: -	case NL80211_IFTYPE_MONITOR: -	case NL80211_IFTYPE_MESH_POINT: -		return -ENOTSUPP; -	case NL80211_IFTYPE_ADHOC: -		return WL_MODE_IBSS; -	case NL80211_IFTYPE_STATION: -	case NL80211_IFTYPE_P2P_CLIENT: -		return WL_MODE_BSS; -	case NL80211_IFTYPE_AP: -	case NL80211_IFTYPE_P2P_GO: -		return WL_MODE_AP; -	case NL80211_IFTYPE_P2P_DEVICE: -		return WL_MODE_P2P; -	case NL80211_IFTYPE_UNSPECIFIED: -	default: -		break; -	} - -	return -EINVAL; -} -  static void brcmf_wiphy_pno_params(struct wiphy *wiphy)  {  	/* scheduled scan settings */ @@ -4337,11 +4404,13 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev)  			WIPHY_FLAG_OFFCHAN_TX |  			WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |  			WIPHY_FLAG_SUPPORTS_TDLS; +	if (!brcmf_roamoff) +		wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;  	wiphy->mgmt_stypes = brcmf_txrx_stypes;  	wiphy->max_remain_on_channel_duration = 5000;  	brcmf_wiphy_pno_params(wiphy);  	brcmf_dbg(INFO, "Registering custom regulatory\n"); -	wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; +	wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;  	wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);  	err = wiphy_register(wiphy);  	if (err < 0) { @@ -4358,9 +4427,6 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,  {  	struct brcmf_cfg80211_vif *vif; -	if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT) -		return ERR_PTR(-ENOSPC); -  	brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",  		  sizeof(*vif));  	vif = kzalloc(sizeof(*vif), GFP_KERNEL); @@ -4370,28 +4436,31 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,  	vif->wdev.wiphy = cfg->wiphy;  	vif->wdev.iftype = type; -	vif->mode = brcmf_nl80211_iftype_to_mode(type);  	vif->pm_block = pm_block;  	vif->roam_off = -1;  	brcmf_init_prof(&vif->profile);  	list_add_tail(&vif->list, &cfg->vif_list); -	cfg->vif_cnt++;  	return vif;  } -void brcmf_free_vif(struct brcmf_cfg80211_info *cfg, -		    struct brcmf_cfg80211_vif *vif) +void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)  {  	list_del(&vif->list); -	cfg->vif_cnt--; -  	kfree(vif); -	if (!cfg->vif_cnt) { -		wiphy_unregister(cfg->wiphy); -		wiphy_free(cfg->wiphy); -	} +} + +void brcmf_cfg80211_free_netdev(struct net_device *ndev) +{ +	struct brcmf_cfg80211_vif *vif; +	struct brcmf_if *ifp; + +	ifp = netdev_priv(ndev); +	vif = ifp->vif; + +	brcmf_free_vif(vif); +	free_netdev(ndev);  }  static bool brcmf_is_linkup(const struct brcmf_event_msg *e) @@ -4412,7 +4481,9 @@ static bool brcmf_is_linkdown(const struct brcmf_event_msg *e)  	u32 event = e->event_code;  	u16 flags = e->flags; -	if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) { +	if ((event == BRCMF_E_DEAUTH) || (event == BRCMF_E_DEAUTH_IND) || +	    (event == BRCMF_E_DISASSOC_IND) || +	    ((event == BRCMF_E_LINK) && (!(flags & BRCMF_EVENT_MSG_LINK)))) {  		brcmf_dbg(CONN, "Processing link down\n");  		return true;  	} @@ -4654,16 +4725,18 @@ brcmf_notify_connect_status(struct brcmf_if *ifp,  	struct brcmf_cfg80211_info *cfg = ifp->drvr->config;  	struct net_device *ndev = ifp->ndev;  	struct brcmf_cfg80211_profile *profile = &ifp->vif->profile; +	struct ieee80211_channel *chan;  	s32 err = 0; -	if (ifp->vif->mode == WL_MODE_AP) { +	if (brcmf_is_apmode(ifp->vif)) {  		err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);  	} else if (brcmf_is_linkup(e)) {  		brcmf_dbg(CONN, "Linkup\n");  		if (brcmf_is_ibssmode(ifp->vif)) { +			chan = ieee80211_get_channel(cfg->wiphy, cfg->channel);  			memcpy(profile->bssid, e->addr, ETH_ALEN);  			wl_inform_ibss(cfg, ndev, e->addr); -			cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL); +			cfg80211_ibss_joined(ndev, e->addr, chan, GFP_KERNEL);  			clear_bit(BRCMF_VIF_STATUS_CONNECTING,  				  &ifp->vif->sme_state);  			set_bit(BRCMF_VIF_STATUS_CONNECTED, @@ -4674,10 +4747,6 @@ brcmf_notify_connect_status(struct brcmf_if *ifp,  		brcmf_dbg(CONN, "Linkdown\n");  		if (!brcmf_is_ibssmode(ifp->vif)) {  			brcmf_bss_connect_done(cfg, ndev, e, false); -			if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTED, -					       &ifp->vif->sme_state)) -				cfg80211_disconnected(ndev, 0, NULL, 0, -						      GFP_KERNEL);  		}  		brcmf_link_down(ifp->vif);  		brcmf_init_prof(ndev_to_prof(ndev)); @@ -4871,11 +4940,8 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)  	cfg->scan_request = NULL;  	cfg->pwr_save = true; -	cfg->roam_on = true;	/* roam on & off switch. -				 we enable roam per default */ -	cfg->active_scan = true;	/* we do active scan for -				 specific scan per default */ -	cfg->dongle_up = false;	/* dongle is not up yet */ +	cfg->active_scan = true;	/* we do active scan per default */ +	cfg->dongle_up = false;		/* dongle is not up yet */  	err = brcmf_init_priv_mem(cfg);  	if (err)  		return err; @@ -4900,6 +4966,30 @@ static void init_vif_event(struct brcmf_cfg80211_vif_event *event)  	mutex_init(&event->vif_event_lock);  } +static int brcmf_enable_bw40_2g(struct brcmf_if *ifp) +{ +	struct brcmf_fil_bwcap_le band_bwcap; +	u32 val; +	int err; + +	/* verify support for bw_cap command */ +	val = WLC_BAND_5G; +	err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &val); + +	if (!err) { +		/* only set 2G bandwidth using bw_cap command */ +		band_bwcap.band = cpu_to_le32(WLC_BAND_2G); +		band_bwcap.bw_cap = cpu_to_le32(WLC_BW_CAP_40MHZ); +		err = brcmf_fil_iovar_data_set(ifp, "bw_cap", &band_bwcap, +					       sizeof(band_bwcap)); +	} else { +		brcmf_dbg(INFO, "fallback to mimo_bw_cap\n"); +		val = WLC_N_BW_40ALL; +		err = brcmf_fil_iovar_int_set(ifp, "mimo_bw_cap", val); +	} +	return err; +} +  struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,  						  struct device *busdev)  { @@ -4957,6 +5047,17 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,  		goto cfg80211_p2p_attach_out;  	} +	/* If cfg80211 didn't disable 40MHz HT CAP in wiphy_register(), +	 * setup 40MHz in 2GHz band and enable OBSS scanning. +	 */ +	if (wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap.cap & +	    IEEE80211_HT_CAP_SUP_WIDTH_20_40) { +		err = brcmf_enable_bw40_2g(ifp); +		if (!err) +			err = brcmf_fil_iovar_int_set(ifp, "obss_coex", +						      BRCMF_OBSS_COEX_AUTO); +	} +  	err = brcmf_fil_iovar_int_set(ifp, "tdls_enable", 1);  	if (err) {  		brcmf_dbg(INFO, "TDLS not enabled (%d)\n", err); @@ -4978,24 +5079,24 @@ cfg80211_p2p_attach_out:  	wl_deinit_priv(cfg);  cfg80211_attach_out: -	brcmf_free_vif(cfg, vif); +	brcmf_free_vif(vif);  	return NULL;  }  void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)  { -	struct brcmf_cfg80211_vif *vif; -	struct brcmf_cfg80211_vif *tmp; +	if (!cfg) +		return; -	wl_deinit_priv(cfg); +	WARN_ON(!list_empty(&cfg->vif_list)); +	wiphy_unregister(cfg->wiphy);  	brcmf_btcoex_detach(cfg); -	list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) { -		brcmf_free_vif(cfg, vif); -	} +	wl_deinit_priv(cfg); +	wiphy_free(cfg->wiphy);  }  static s32 -brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout) +brcmf_dongle_roam(struct brcmf_if *ifp, u32 bcn_timeout)  {  	s32 err = 0;  	__le32 roamtrigger[2]; @@ -5005,7 +5106,7 @@ brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)  	 * Setup timeout if Beacons are lost and roam is  	 * off to report link down  	 */ -	if (roamvar) { +	if (brcmf_roamoff) {  		err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout", bcn_timeout);  		if (err) {  			brcmf_err("bcn_timeout error (%d)\n", err); @@ -5017,8 +5118,9 @@ brcmf_dongle_roam(struct brcmf_if *ifp, u32 roamvar, u32 bcn_timeout)  	 * Enable/Disable built-in roaming to allow supplicant  	 * to take care of roaming  	 */ -	brcmf_dbg(INFO, "Internal Roaming = %s\n", roamvar ? "Off" : "On"); -	err = brcmf_fil_iovar_int_set(ifp, "roam_off", roamvar); +	brcmf_dbg(INFO, "Internal Roaming = %s\n", +		  brcmf_roamoff ? "Off" : "On"); +	err = brcmf_fil_iovar_int_set(ifp, "roam_off", !!(brcmf_roamoff));  	if (err) {  		brcmf_err("roam_off error (%d)\n", err);  		goto dongle_rom_out; @@ -5086,7 +5188,8 @@ dongle_scantime_out:  } -static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap) +static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, +				   u32 bw_cap[])  {  	struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));  	struct ieee80211_channel *band_chan_arr; @@ -5099,7 +5202,6 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap)  	enum ieee80211_band band;  	u32 channel;  	u32 *n_cnt; -	bool ht40_allowed;  	u32 index;  	u32 ht40_flag;  	bool update; @@ -5132,18 +5234,20 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap)  			array_size = ARRAY_SIZE(__wl_2ghz_channels);  			n_cnt = &__wl_band_2ghz.n_channels;  			band = IEEE80211_BAND_2GHZ; -			ht40_allowed = (bw_cap == WLC_N_BW_40ALL);  		} else if (ch.band == BRCMU_CHAN_BAND_5G) {  			band_chan_arr = __wl_5ghz_a_channels;  			array_size = ARRAY_SIZE(__wl_5ghz_a_channels);  			n_cnt = &__wl_band_5ghz_a.n_channels;  			band = IEEE80211_BAND_5GHZ; -			ht40_allowed = !(bw_cap == WLC_N_BW_20ALL);  		} else { -			brcmf_err("Invalid channel Sepc. 0x%x.\n", ch.chspec); +			brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);  			continue;  		} -		if (!ht40_allowed && ch.bw == BRCMU_CHAN_BW_40) +		if (!(bw_cap[band] & WLC_BW_40MHZ_BIT) && +		    ch.bw == BRCMU_CHAN_BW_40) +			continue; +		if (!(bw_cap[band] & WLC_BW_80MHZ_BIT) && +		    ch.bw == BRCMU_CHAN_BW_80)  			continue;  		update = false;  		for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) { @@ -5161,10 +5265,13 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap)  				ieee80211_channel_to_frequency(ch.chnum, band);  			band_chan_arr[index].hw_value = ch.chnum; -			if (ch.bw == BRCMU_CHAN_BW_40 && ht40_allowed) { -				/* assuming the order is HT20, HT40 Upper, -				 * HT40 lower from chanspecs -				 */ +			/* assuming the chanspecs order is HT20, +			 * HT40 upper, HT40 lower, and VHT80. +			 */ +			if (ch.bw == BRCMU_CHAN_BW_80) { +				band_chan_arr[index].flags &= +					~IEEE80211_CHAN_NO_80MHZ; +			} else if (ch.bw == BRCMU_CHAN_BW_40) {  				ht40_flag = band_chan_arr[index].flags &  					    IEEE80211_CHAN_NO_HT40;  				if (ch.sb == BRCMU_CHAN_SB_U) { @@ -5185,8 +5292,13 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap)  						    IEEE80211_CHAN_NO_HT40MINUS;  				}  			} else { +				/* disable other bandwidths for now as mentioned +				 * order assure they are enabled for subsequent +				 * chanspecs. +				 */  				band_chan_arr[index].flags = -							IEEE80211_CHAN_NO_HT40; +						IEEE80211_CHAN_NO_HT40 | +						IEEE80211_CHAN_NO_80MHZ;  				ch.bw = BRCMU_CHAN_BW_20;  				cfg->d11inf.encchspec(&ch);  				channel = ch.chspec; @@ -5197,10 +5309,10 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap)  					if (channel & WL_CHAN_RADAR)  						band_chan_arr[index].flags |=  							(IEEE80211_CHAN_RADAR | -							IEEE80211_CHAN_NO_IBSS); +							IEEE80211_CHAN_NO_IR);  					if (channel & WL_CHAN_PASSIVE)  						band_chan_arr[index].flags |= -						    IEEE80211_CHAN_PASSIVE_SCAN; +						    IEEE80211_CHAN_NO_IR;  				}  			}  			if (!update) @@ -5212,6 +5324,95 @@ exit:  	return err;  } +static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[]) +{ +	u32 band, mimo_bwcap; +	int err; + +	band = WLC_BAND_2G; +	err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band); +	if (!err) { +		bw_cap[IEEE80211_BAND_2GHZ] = band; +		band = WLC_BAND_5G; +		err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band); +		if (!err) { +			bw_cap[IEEE80211_BAND_5GHZ] = band; +			return; +		} +		WARN_ON(1); +		return; +	} +	brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n"); +	mimo_bwcap = 0; +	err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap); +	if (err) +		/* assume 20MHz if firmware does not give a clue */ +		mimo_bwcap = WLC_N_BW_20ALL; + +	switch (mimo_bwcap) { +	case WLC_N_BW_40ALL: +		bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT; +		/* fall-thru */ +	case WLC_N_BW_20IN2G_40IN5G: +		bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT; +		/* fall-thru */ +	case WLC_N_BW_20ALL: +		bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT; +		bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT; +		break; +	default: +		brcmf_err("invalid mimo_bw_cap value\n"); +	} +} + +static void brcmf_update_ht_cap(struct ieee80211_supported_band *band, +				u32 bw_cap[2], u32 nchain) +{ +	band->ht_cap.ht_supported = true; +	if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) { +		band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; +		band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; +	} +	band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20; +	band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40; +	band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; +	band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16; +	memset(band->ht_cap.mcs.rx_mask, 0xff, nchain); +	band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; +} + +static __le16 brcmf_get_mcs_map(u32 nchain, enum ieee80211_vht_mcs_support supp) +{ +	u16 mcs_map; +	int i; + +	for (i = 0, mcs_map = 0xFFFF; i < nchain; i++) +		mcs_map = (mcs_map << 2) | supp; + +	return cpu_to_le16(mcs_map); +} + +static void brcmf_update_vht_cap(struct ieee80211_supported_band *band, +				 u32 bw_cap[2], u32 nchain) +{ +	__le16 mcs_map; + +	/* not allowed in 2.4G band */ +	if (band->band == IEEE80211_BAND_2GHZ) +		return; + +	band->vht_cap.vht_supported = true; +	/* 80MHz is mandatory */ +	band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80; +	if (bw_cap[band->band] & WLC_BW_160MHZ_BIT) { +		band->vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; +		band->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160; +	} +	/* all support 256-QAM */ +	mcs_map = brcmf_get_mcs_map(nchain, IEEE80211_VHT_MCS_SUPPORT_0_9); +	band->vht_cap.vht_mcs.rx_mcs_map = mcs_map; +	band->vht_cap.vht_mcs.tx_mcs_map = mcs_map; +}  static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)  { @@ -5219,14 +5420,17 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)  	struct wiphy *wiphy;  	s32 phy_list;  	u32 band_list[3]; -	u32 nmode; -	u32 bw_cap = 0; +	u32 nmode = 0; +	u32 vhtmode = 0; +	u32 bw_cap[2] = { 0, 0 }; +	u32 rxchain; +	u32 nchain;  	s8 phy;  	s32 err;  	u32 nband;  	s32 i; -	struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS]; -	s32 index; +	struct ieee80211_supported_band *bands[2] = { NULL, NULL }; +	struct ieee80211_supported_band *band;  	err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_PHYLIST,  				     &phy_list, sizeof(phy_list)); @@ -5248,15 +5452,26 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)  	brcmf_dbg(INFO, "BRCMF_C_GET_BANDLIST reported: 0x%08x 0x%08x 0x%08x phy\n",  		  band_list[0], band_list[1], band_list[2]); +	(void)brcmf_fil_iovar_int_get(ifp, "vhtmode", &vhtmode);  	err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);  	if (err) {  		brcmf_err("nmode error (%d)\n", err);  	} else { -		err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &bw_cap); -		if (err) -			brcmf_err("mimo_bw_cap error (%d)\n", err); +		brcmf_get_bwcap(ifp, bw_cap); +	} +	brcmf_dbg(INFO, "nmode=%d, vhtmode=%d, bw_cap=(%d, %d)\n", +		  nmode, vhtmode, bw_cap[IEEE80211_BAND_2GHZ], +		  bw_cap[IEEE80211_BAND_5GHZ]); + +	err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain); +	if (err) { +		brcmf_err("rxchain error (%d)\n", err); +		nchain = 1; +	} else { +		for (nchain = 0; rxchain; nchain++) +			rxchain = rxchain & (rxchain - 1);  	} -	brcmf_dbg(INFO, "nmode=%d, mimo_bw_cap=%d\n", nmode, bw_cap); +	brcmf_dbg(INFO, "nchain=%d\n", nchain);  	err = brcmf_construct_reginfo(cfg, bw_cap);  	if (err) { @@ -5265,40 +5480,23 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)  	}  	nband = band_list[0]; -	memset(bands, 0, sizeof(bands));  	for (i = 1; i <= nband && i < ARRAY_SIZE(band_list); i++) { -		index = -1; +		band = NULL;  		if ((band_list[i] == WLC_BAND_5G) && -		    (__wl_band_5ghz_a.n_channels > 0)) { -			index = IEEE80211_BAND_5GHZ; -			bands[index] = &__wl_band_5ghz_a; -			if ((bw_cap == WLC_N_BW_40ALL) || -			    (bw_cap == WLC_N_BW_20IN2G_40IN5G)) -				bands[index]->ht_cap.cap |= -							IEEE80211_HT_CAP_SGI_40; -		} else if ((band_list[i] == WLC_BAND_2G) && -			   (__wl_band_2ghz.n_channels > 0)) { -			index = IEEE80211_BAND_2GHZ; -			bands[index] = &__wl_band_2ghz; -			if (bw_cap == WLC_N_BW_40ALL) -				bands[index]->ht_cap.cap |= -							IEEE80211_HT_CAP_SGI_40; -		} +		    (__wl_band_5ghz_a.n_channels > 0)) +			band = &__wl_band_5ghz_a; +		else if ((band_list[i] == WLC_BAND_2G) && +			 (__wl_band_2ghz.n_channels > 0)) +			band = &__wl_band_2ghz; +		else +			continue; -		if ((index >= 0) && nmode) { -			bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20; -			bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40; -			bands[index]->ht_cap.ht_supported = true; -			bands[index]->ht_cap.ampdu_factor = -						IEEE80211_HT_MAX_AMPDU_64K; -			bands[index]->ht_cap.ampdu_density = -						IEEE80211_HT_MPDU_DENSITY_16; -			/* An HT shall support all EQM rates for one spatial -			 * stream -			 */ -			bands[index]->ht_cap.mcs.rx_mask[0] = 0xff; -		} +		if (nmode) +			brcmf_update_ht_cap(band, bw_cap, nchain); +		if (vhtmode) +			brcmf_update_vht_cap(band, bw_cap, nchain); +		bands[band->band] = band;  	}  	wiphy = cfg_to_wiphy(cfg); @@ -5343,7 +5541,7 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)  	brcmf_dbg(INFO, "power save set to %s\n",  		  (power_mode ? "enabled" : "disabled")); -	err = brcmf_dongle_roam(ifp, (cfg->roam_on ? 0 : 1), WL_BEACON_TIMEOUT); +	err = brcmf_dongle_roam(ifp, WL_BEACON_TIMEOUT);  	if (err)  		goto default_conf_out;  	err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype, diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h index d9bdaf9a72d..283c525a44f 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h @@ -89,21 +89,6 @@ enum brcmf_scan_status {  	BRCMF_SCAN_STATUS_SUPPRESS,  }; -/** - * enum wl_mode - driver mode of virtual interface. - * - * @WL_MODE_BSS: connects to BSS. - * @WL_MODE_IBSS: operate as ad-hoc. - * @WL_MODE_AP: operate as access-point. - * @WL_MODE_P2P: provide P2P discovery. - */ -enum wl_mode { -	WL_MODE_BSS, -	WL_MODE_IBSS, -	WL_MODE_AP, -	WL_MODE_P2P -}; -  /* dongle configuration */  struct brcmf_cfg80211_conf {  	u32 frag_threshold; @@ -193,7 +178,6 @@ struct vif_saved_ie {   * @ifp: lower layer interface pointer   * @wdev: wireless device.   * @profile: profile information. - * @mode: operating mode.   * @roam_off: roaming state.   * @sme_state: SME state using enum brcmf_vif_status bits.   * @pm_block: power-management blocked. @@ -204,7 +188,6 @@ struct brcmf_cfg80211_vif {  	struct brcmf_if *ifp;  	struct wireless_dev wdev;  	struct brcmf_cfg80211_profile profile; -	s32 mode;  	s32 roam_off;  	unsigned long sme_state;  	bool pm_block; @@ -402,7 +385,6 @@ struct brcmf_cfg80211_info {  	bool ibss_starter;  	bool pwr_save;  	bool dongle_up; -	bool roam_on;  	bool scan_tried;  	u8 *dcmd_buf;  	u8 *extra_buf; @@ -412,7 +394,6 @@ struct brcmf_cfg80211_info {  	struct work_struct escan_timeout_work;  	u8 *escan_ioctl_buf;  	struct list_head vif_list; -	u8 vif_cnt;  	struct brcmf_cfg80211_vif_event vif_event;  	struct completion vif_disabled;  	struct brcmu_d11inf d11inf; @@ -487,13 +468,13 @@ enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp);  struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,  					   enum nl80211_iftype type,  					   bool pm_block); -void brcmf_free_vif(struct brcmf_cfg80211_info *cfg, -	            struct brcmf_cfg80211_vif *vif); +void brcmf_free_vif(struct brcmf_cfg80211_vif *vif);  s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,  			  const u8 *vndr_ie_buf, u32 vndr_ie_len);  s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif); -struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key); +const struct brcmf_tlv * +brcmf_parse_tlvs(const void *buf, int buflen, uint key);  u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,  			struct ieee80211_channel *ch);  u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state); @@ -507,5 +488,6 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,  				bool fw_abort);  void brcmf_set_mpc(struct brcmf_if *ndev, int mpc);  void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg); +void brcmf_cfg80211_free_netdev(struct net_device *ndev);  #endif				/* _wl_cfg80211_h_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h index a8a267b5b87..2d08c155c23 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h @@ -172,19 +172,19 @@ struct si_info {  /* AMBA Interconnect exported externs */ -extern u32 ai_core_cflags(struct bcma_device *core, u32 mask, u32 val); +u32 ai_core_cflags(struct bcma_device *core, u32 mask, u32 val);  /* === exported functions === */ -extern struct si_pub *ai_attach(struct bcma_bus *pbus); -extern void ai_detach(struct si_pub *sih); -extern uint ai_cc_reg(struct si_pub *sih, uint regoff, u32 mask, u32 val); -extern void ai_clkctl_init(struct si_pub *sih); -extern u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih); -extern bool ai_clkctl_cc(struct si_pub *sih, enum bcma_clkmode mode); -extern bool ai_deviceremoved(struct si_pub *sih); +struct si_pub *ai_attach(struct bcma_bus *pbus); +void ai_detach(struct si_pub *sih); +uint ai_cc_reg(struct si_pub *sih, uint regoff, u32 mask, u32 val); +void ai_clkctl_init(struct si_pub *sih); +u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih); +bool ai_clkctl_cc(struct si_pub *sih, enum bcma_clkmode mode); +bool ai_deviceremoved(struct si_pub *sih);  /* Enable Ex-PA for 4313 */ -extern void ai_epa_4313war(struct si_pub *sih); +void ai_epa_4313war(struct si_pub *sih);  static inline u32 ai_get_cccaps(struct si_pub *sih)  { diff --git a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.h b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.h index 73d01e58610..03bdcf29bd5 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.h @@ -37,17 +37,17 @@ struct brcms_ampdu_session {  	u16 dma_len;  }; -extern void brcms_c_ampdu_reset_session(struct brcms_ampdu_session *session, -					struct brcms_c_info *wlc); -extern int brcms_c_ampdu_add_frame(struct brcms_ampdu_session *session, -				   struct sk_buff *p); -extern void brcms_c_ampdu_finalize(struct brcms_ampdu_session *session); +void brcms_c_ampdu_reset_session(struct brcms_ampdu_session *session, +				 struct brcms_c_info *wlc); +int brcms_c_ampdu_add_frame(struct brcms_ampdu_session *session, +			    struct sk_buff *p); +void brcms_c_ampdu_finalize(struct brcms_ampdu_session *session); -extern struct ampdu_info *brcms_c_ampdu_attach(struct brcms_c_info *wlc); -extern void brcms_c_ampdu_detach(struct ampdu_info *ampdu); -extern void brcms_c_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb, -				 struct sk_buff *p, struct tx_status *txs); -extern void brcms_c_ampdu_macaddr_upd(struct brcms_c_info *wlc); -extern void brcms_c_ampdu_shm_upd(struct ampdu_info *ampdu); +struct ampdu_info *brcms_c_ampdu_attach(struct brcms_c_info *wlc); +void brcms_c_ampdu_detach(struct ampdu_info *ampdu); +void brcms_c_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb, +			      struct sk_buff *p, struct tx_status *txs); +void brcms_c_ampdu_macaddr_upd(struct brcms_c_info *wlc); +void brcms_c_ampdu_shm_upd(struct ampdu_info *ampdu);  #endif				/* _BRCM_AMPDU_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/antsel.h b/drivers/net/wireless/brcm80211/brcmsmac/antsel.h index 97ea3881a8e..a3d487ab196 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/antsel.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/antsel.h @@ -17,13 +17,11 @@  #ifndef _BRCM_ANTSEL_H_  #define _BRCM_ANTSEL_H_ -extern struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc); -extern void brcms_c_antsel_detach(struct antsel_info *asi); -extern void brcms_c_antsel_init(struct antsel_info *asi); -extern void brcms_c_antsel_antcfg_get(struct antsel_info *asi, bool usedef, -				  bool sel, -				  u8 id, u8 fbid, u8 *antcfg, -				  u8 *fbantcfg); -extern u8 brcms_c_antsel_antsel2id(struct antsel_info *asi, u16 antsel); +struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc); +void brcms_c_antsel_detach(struct antsel_info *asi); +void brcms_c_antsel_init(struct antsel_info *asi); +void brcms_c_antsel_antcfg_get(struct antsel_info *asi, bool usedef, bool sel, +			       u8 id, u8 fbid, u8 *antcfg, u8 *fbantcfg); +u8 brcms_c_antsel_antsel2id(struct antsel_info *asi, u16 antsel);  #endif /* _BRCM_ANTSEL_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/brcm80211/brcmsmac/channel.c index cc87926f505..635ae034c7e 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c @@ -59,23 +59,18 @@  #define BRCM_2GHZ_2412_2462	REG_RULE(2412-10, 2462+10, 40, 0, 19, 0)  #define BRCM_2GHZ_2467_2472	REG_RULE(2467-10, 2472+10, 20, 0, 19, \ -					 NL80211_RRF_PASSIVE_SCAN | \ -					 NL80211_RRF_NO_IBSS) +					 NL80211_RRF_NO_IR)  #define BRCM_5GHZ_5180_5240	REG_RULE(5180-10, 5240+10, 40, 0, 21, \ -					 NL80211_RRF_PASSIVE_SCAN | \ -					 NL80211_RRF_NO_IBSS) +					 NL80211_RRF_NO_IR)  #define BRCM_5GHZ_5260_5320	REG_RULE(5260-10, 5320+10, 40, 0, 21, \ -					 NL80211_RRF_PASSIVE_SCAN | \  					 NL80211_RRF_DFS | \ -					 NL80211_RRF_NO_IBSS) +					 NL80211_RRF_NO_IR)  #define BRCM_5GHZ_5500_5700	REG_RULE(5500-10, 5700+10, 40, 0, 21, \ -					 NL80211_RRF_PASSIVE_SCAN | \  					 NL80211_RRF_DFS | \ -					 NL80211_RRF_NO_IBSS) +					 NL80211_RRF_NO_IR)  #define BRCM_5GHZ_5745_5825	REG_RULE(5745-10, 5825+10, 40, 0, 21, \ -					 NL80211_RRF_PASSIVE_SCAN | \ -					 NL80211_RRF_NO_IBSS) +					 NL80211_RRF_NO_IR)  static const struct ieee80211_regdomain brcms_regdom_x2 = {  	.n_reg_rules = 6, @@ -395,7 +390,7 @@ brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec,  		brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false);  	brcms_b_set_chanspec(wlc->hw, chanspec, -			      !!(ch->flags & IEEE80211_CHAN_PASSIVE_SCAN), +			      !!(ch->flags & IEEE80211_CHAN_NO_IR),  			      &txpwr);  } @@ -657,8 +652,8 @@ static void brcms_reg_apply_radar_flags(struct wiphy *wiphy)  		 */  		if (!(ch->flags & IEEE80211_CHAN_DISABLED))  			ch->flags |= IEEE80211_CHAN_RADAR | -				     IEEE80211_CHAN_NO_IBSS | -				     IEEE80211_CHAN_PASSIVE_SCAN; +				     IEEE80211_CHAN_NO_IR | +				     IEEE80211_CHAN_NO_IR;  	}  } @@ -684,18 +679,15 @@ brcms_reg_apply_beaconing_flags(struct wiphy *wiphy,  				continue;  			if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { -				rule = freq_reg_info(wiphy, ch->center_freq); +				rule = freq_reg_info(wiphy, +						     MHZ_TO_KHZ(ch->center_freq));  				if (IS_ERR(rule))  					continue; -				if (!(rule->flags & NL80211_RRF_NO_IBSS)) -					ch->flags &= ~IEEE80211_CHAN_NO_IBSS; -				if (!(rule->flags & NL80211_RRF_PASSIVE_SCAN)) -					ch->flags &= -						~IEEE80211_CHAN_PASSIVE_SCAN; +				if (!(rule->flags & NL80211_RRF_NO_IR)) +					ch->flags &= ~IEEE80211_CHAN_NO_IR;  			} else if (ch->beacon_found) { -				ch->flags &= ~(IEEE80211_CHAN_NO_IBSS | -					       IEEE80211_CHAN_PASSIVE_SCAN); +				ch->flags &= ~IEEE80211_CHAN_NO_IR;  			}  		}  	} @@ -775,8 +767,8 @@ void brcms_c_regd_init(struct brcms_c_info *wlc)  	}  	wlc->wiphy->reg_notifier = brcms_reg_notifier; -	wlc->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | -			     WIPHY_FLAG_STRICT_REGULATORY; +	wlc->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | +					REGULATORY_STRICT_REG;  	wiphy_apply_custom_regulatory(wlc->wiphy, regd->regdomain);  	brcms_reg_apply_beaconing_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER);  } diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.h b/drivers/net/wireless/brcm80211/brcmsmac/channel.h index 006483a0abe..39dd3a5b297 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/channel.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.h @@ -32,20 +32,16 @@  #define BRCMS_DFS_EU (BRCMS_DFS_TPC | BRCMS_RADAR_TYPE_EU) /* Flag for DFS EU */ -extern struct brcms_cm_info * -brcms_c_channel_mgr_attach(struct brcms_c_info *wlc); +struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc); -extern void brcms_c_channel_mgr_detach(struct brcms_cm_info *wlc_cm); +void brcms_c_channel_mgr_detach(struct brcms_cm_info *wlc_cm); -extern bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm, -				      u16 chspec); +bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm, u16 chspec); -extern void brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, -				   u16 chanspec, -				   struct txpwr_limits *txpwr); -extern void brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, -				     u16 chanspec, -				     u8 local_constraint_qdbm); -extern void brcms_c_regd_init(struct brcms_c_info *wlc); +void brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec, +				struct txpwr_limits *txpwr); +void brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec, +				  u8 local_constraint_qdbm); +void brcms_c_regd_init(struct brcms_c_info *wlc);  #endif				/* _WLC_CHANNEL_H */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index edc5d105ff9..43c71bfaa47 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -125,13 +125,13 @@ static struct ieee80211_channel brcms_2ghz_chantable[] = {  	CHAN2GHZ(10, 2457, IEEE80211_CHAN_NO_HT40PLUS),  	CHAN2GHZ(11, 2462, IEEE80211_CHAN_NO_HT40PLUS),  	CHAN2GHZ(12, 2467, -		 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS | +		 IEEE80211_CHAN_NO_IR |  		 IEEE80211_CHAN_NO_HT40PLUS),  	CHAN2GHZ(13, 2472, -		 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS | +		 IEEE80211_CHAN_NO_IR |  		 IEEE80211_CHAN_NO_HT40PLUS),  	CHAN2GHZ(14, 2484, -		 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS | +		 IEEE80211_CHAN_NO_IR |  		 IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS |  		 IEEE80211_CHAN_NO_OFDM)  }; @@ -144,51 +144,51 @@ static struct ieee80211_channel brcms_5ghz_nphy_chantable[] = {  	CHAN5GHZ(48, IEEE80211_CHAN_NO_HT40PLUS),  	/* UNII-2 */  	CHAN5GHZ(52, -		 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | -		 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), +		 IEEE80211_CHAN_RADAR | +		 IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),  	CHAN5GHZ(56, -		 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | -		 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), +		 IEEE80211_CHAN_RADAR | +		 IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),  	CHAN5GHZ(60, -		 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | -		 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), +		 IEEE80211_CHAN_RADAR | +		 IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),  	CHAN5GHZ(64, -		 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | -		 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), +		 IEEE80211_CHAN_RADAR | +		 IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),  	/* MID */  	CHAN5GHZ(100, -		 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | -		 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), +		 IEEE80211_CHAN_RADAR | +		 IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),  	CHAN5GHZ(104, -		 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | -		 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), +		 IEEE80211_CHAN_RADAR | +		 IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),  	CHAN5GHZ(108, -		 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | -		 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), +		 IEEE80211_CHAN_RADAR | +		 IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),  	CHAN5GHZ(112, -		 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | -		 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), +		 IEEE80211_CHAN_RADAR | +		 IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),  	CHAN5GHZ(116, -		 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | -		 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), +		 IEEE80211_CHAN_RADAR | +		 IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),  	CHAN5GHZ(120, -		 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | -		 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), +		 IEEE80211_CHAN_RADAR | +		 IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),  	CHAN5GHZ(124, -		 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | -		 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), +		 IEEE80211_CHAN_RADAR | +		 IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),  	CHAN5GHZ(128, -		 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | -		 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), +		 IEEE80211_CHAN_RADAR | +		 IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),  	CHAN5GHZ(132, -		 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | -		 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), +		 IEEE80211_CHAN_RADAR | +		 IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS),  	CHAN5GHZ(136, -		 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | -		 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), +		 IEEE80211_CHAN_RADAR | +		 IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS),  	CHAN5GHZ(140, -		 IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | -		 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS | +		 IEEE80211_CHAN_RADAR | +		 IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS |  		 IEEE80211_CHAN_NO_HT40MINUS),  	/* UNII-3 */  	CHAN5GHZ(149, IEEE80211_CHAN_NO_HT40MINUS), @@ -426,6 +426,12 @@ static int brcms_ops_start(struct ieee80211_hw *hw)  	bool blocked;  	int err; +	if (!wl->ucode.bcm43xx_bomminor) { +		err = brcms_request_fw(wl, wl->wlc->hw->d11core); +		if (err) +			return -ENOENT; +	} +  	ieee80211_wake_queues(hw);  	spin_lock_bh(&wl->lock);  	blocked = brcms_rfkill_set_hw_state(wl); @@ -433,14 +439,6 @@ static int brcms_ops_start(struct ieee80211_hw *hw)  	if (!blocked)  		wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy); -	if (!wl->ucode.bcm43xx_bomminor) { -		err = brcms_request_fw(wl, wl->wlc->hw->d11core); -		if (err) { -			brcms_remove(wl->wlc->hw->d11core); -			return -ENOENT; -		} -	} -  	spin_lock_bh(&wl->lock);  	/* avoid acknowledging frames before a non-monitor device is added */  	wl->mute_tx = true; @@ -899,7 +897,8 @@ static bool brcms_tx_flush_completed(struct brcms_info *wl)  	return result;  } -static void brcms_ops_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +static void brcms_ops_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +			    u32 queues, bool drop)  {  	struct brcms_info *wl = hw->priv;  	int ret; @@ -1071,7 +1070,6 @@ static int ieee_hw_init(struct ieee80211_hw *hw)  	hw->max_rates = 2;	/* Primary rate and 1 fallback rate */  	/* channel change time is dependent on chip and band  */ -	hw->channel_change_time = 7 * 1000;  	hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |  				     BIT(NL80211_IFTYPE_AP) |  				     BIT(NL80211_IFTYPE_ADHOC); @@ -1095,12 +1093,6 @@ static int ieee_hw_init(struct ieee80211_hw *hw)   * Attach to the WL device identified by vendor and device parameters.   * regs is a host accessible memory address pointing to WL device registers.   * - * brcms_attach is not defined as static because in the case where no bus - * is defined, wl_attach will never be called, and thus, gcc will issue - * a warning that this function is defined but not used if we declare - * it as static. - * - *   * is called in brcms_bcma_probe() context, therefore no locking required.   */  static struct brcms_info *brcms_attach(struct bcma_device *pdev) diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h index 4090032e81a..198053dfc31 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h @@ -88,26 +88,26 @@ struct brcms_info {  };  /* misc callbacks */ -extern void brcms_init(struct brcms_info *wl); -extern uint brcms_reset(struct brcms_info *wl); -extern void brcms_intrson(struct brcms_info *wl); -extern u32 brcms_intrsoff(struct brcms_info *wl); -extern void brcms_intrsrestore(struct brcms_info *wl, u32 macintmask); -extern int brcms_up(struct brcms_info *wl); -extern void brcms_down(struct brcms_info *wl); -extern void brcms_txflowcontrol(struct brcms_info *wl, struct brcms_if *wlif, -				bool state, int prio); -extern bool brcms_rfkill_set_hw_state(struct brcms_info *wl); +void brcms_init(struct brcms_info *wl); +uint brcms_reset(struct brcms_info *wl); +void brcms_intrson(struct brcms_info *wl); +u32 brcms_intrsoff(struct brcms_info *wl); +void brcms_intrsrestore(struct brcms_info *wl, u32 macintmask); +int brcms_up(struct brcms_info *wl); +void brcms_down(struct brcms_info *wl); +void brcms_txflowcontrol(struct brcms_info *wl, struct brcms_if *wlif, +			 bool state, int prio); +bool brcms_rfkill_set_hw_state(struct brcms_info *wl);  /* timer functions */ -extern struct brcms_timer *brcms_init_timer(struct brcms_info *wl, -				      void (*fn) (void *arg), void *arg, -				      const char *name); -extern void brcms_free_timer(struct brcms_timer *timer); -extern void brcms_add_timer(struct brcms_timer *timer, uint ms, int periodic); -extern bool brcms_del_timer(struct brcms_timer *timer); -extern void brcms_dpc(unsigned long data); -extern void brcms_timer(struct brcms_timer *t); -extern void brcms_fatal_error(struct brcms_info *wl); +struct brcms_timer *brcms_init_timer(struct brcms_info *wl, +				     void (*fn) (void *arg), void *arg, +				     const char *name); +void brcms_free_timer(struct brcms_timer *timer); +void brcms_add_timer(struct brcms_timer *timer, uint ms, int periodic); +bool brcms_del_timer(struct brcms_timer *timer); +void brcms_dpc(unsigned long data); +void brcms_timer(struct brcms_timer *t); +void brcms_fatal_error(struct brcms_info *wl);  #endif				/* _BRCM_MAC80211_IF_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c index 4608e0eb149..af8ba64ace3 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c @@ -1906,14 +1906,14 @@ static void brcms_c_get_macaddr(struct brcms_hardware *wlc_hw, u8 etheraddr[ETH_  	/* If macaddr exists, use it (Sromrev4, CIS, ...). */  	if (!is_zero_ether_addr(sprom->il0mac)) { -		memcpy(etheraddr, sprom->il0mac, 6); +		memcpy(etheraddr, sprom->il0mac, ETH_ALEN);  		return;  	}  	if (wlc_hw->_nbands > 1) -		memcpy(etheraddr, sprom->et1mac, 6); +		memcpy(etheraddr, sprom->et1mac, ETH_ALEN);  	else -		memcpy(etheraddr, sprom->il0mac, 6); +		memcpy(etheraddr, sprom->il0mac, ETH_ALEN);  }  /* power both the pll and external oscillator on/off */ @@ -4870,14 +4870,11 @@ static void brcms_c_detach_module(struct brcms_c_info *wlc)  /*   * low level detach   */ -static int brcms_b_detach(struct brcms_c_info *wlc) +static void brcms_b_detach(struct brcms_c_info *wlc)  {  	uint i;  	struct brcms_hw_band *band;  	struct brcms_hardware *wlc_hw = wlc->hw; -	int callbacks; - -	callbacks = 0;  	brcms_b_detach_dmapio(wlc_hw); @@ -4900,9 +4897,6 @@ static int brcms_b_detach(struct brcms_c_info *wlc)  		ai_detach(wlc_hw->sih);  		wlc_hw->sih = NULL;  	} - -	return callbacks; -  }  /* @@ -4917,14 +4911,15 @@ static int brcms_b_detach(struct brcms_c_info *wlc)   */  uint brcms_c_detach(struct brcms_c_info *wlc)  { -	uint callbacks = 0; +	uint callbacks;  	if (wlc == NULL)  		return 0; -	callbacks += brcms_b_detach(wlc); +	brcms_b_detach(wlc);  	/* delete software timers */ +	callbacks = 0;  	if (!brcms_c_radio_monitor_stop(wlc))  		callbacks++; @@ -5695,7 +5690,7 @@ static bool brcms_c_chipmatch_pci(struct bcma_device *core)  		return true;  	if ((device == BCM43224_D11N_ID) || (device == BCM43225_D11N2G_ID))  		return true; -	if (device == BCM4313_D11N2G_ID) +	if (device == BCM4313_D11N2G_ID || device == BCM4313_CHIP_ID)  		return true;  	if ((device == BCM43236_D11N_ID) || (device == BCM43236_D11N2G_ID))  		return true; @@ -7108,7 +7103,6 @@ prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh,  		     struct sk_buff *p,  		     struct ieee80211_rx_status *rx_status)  { -	int preamble;  	int channel;  	u32 rspec;  	unsigned char *plcp; @@ -7191,7 +7185,6 @@ prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh,  			rx_status->rate_idx -= BRCMS_LEGACY_5G_RATE_OFFSET;  		/* Determine short preamble and rate_idx */ -		preamble = 0;  		if (is_cck_rate(rspec)) {  			if (rxh->PhyRxStatus_0 & PRXS0_SHORTH)  				rx_status->flag |= RX_FLAG_SHORTPRE; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.h b/drivers/net/wireless/brcm80211/brcmsmac/main.h index b5d7a38b53f..c4d135cff04 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.h @@ -616,66 +616,54 @@ struct brcms_bss_cfg {  	struct brcms_bss_info *current_bss;  }; -extern int brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo, -			   struct sk_buff *p); -extern int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo, -		   uint *blocks); - -extern int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config); -extern void brcms_c_mac_promisc(struct brcms_c_info *wlc, uint filter_flags); -extern u16 brcms_c_calc_lsig_len(struct brcms_c_info *wlc, u32 ratespec, -				uint mac_len); -extern u32 brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc, -					     u32 rspec, -					     bool use_rspec, u16 mimo_ctlchbw); -extern u16 brcms_c_compute_rtscts_dur(struct brcms_c_info *wlc, bool cts_only, -				      u32 rts_rate, -				      u32 frame_rate, -				      u8 rts_preamble_type, -				      u8 frame_preamble_type, uint frame_len, -				      bool ba); -extern void brcms_c_inval_dma_pkts(struct brcms_hardware *hw, -			       struct ieee80211_sta *sta, -			       void (*dma_callback_fn)); -extern void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend); -extern int brcms_c_set_nmode(struct brcms_c_info *wlc); -extern void brcms_c_beacon_phytxctl_txant_upd(struct brcms_c_info *wlc, -					  u32 bcn_rate); -extern void brcms_b_antsel_type_set(struct brcms_hardware *wlc_hw, -				     u8 antsel_type); -extern void brcms_b_set_chanspec(struct brcms_hardware *wlc_hw, -				  u16 chanspec, -				  bool mute, struct txpwr_limits *txpwr); -extern void brcms_b_write_shm(struct brcms_hardware *wlc_hw, uint offset, -			      u16 v); -extern u16 brcms_b_read_shm(struct brcms_hardware *wlc_hw, uint offset); -extern void brcms_b_mhf(struct brcms_hardware *wlc_hw, u8 idx, u16 mask, -			u16 val, int bands); -extern void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags); -extern void brcms_b_mctrl(struct brcms_hardware *wlc_hw, u32 mask, u32 val); -extern void brcms_b_phy_reset(struct brcms_hardware *wlc_hw); -extern void brcms_b_bw_set(struct brcms_hardware *wlc_hw, u16 bw); -extern void brcms_b_core_phypll_reset(struct brcms_hardware *wlc_hw); -extern void brcms_c_ucode_wake_override_set(struct brcms_hardware *wlc_hw, -					u32 override_bit); -extern void brcms_c_ucode_wake_override_clear(struct brcms_hardware *wlc_hw, -					  u32 override_bit); -extern void brcms_b_write_template_ram(struct brcms_hardware *wlc_hw, -				       int offset, int len, void *buf); -extern u16 brcms_b_rate_shm_offset(struct brcms_hardware *wlc_hw, u8 rate); -extern void brcms_b_copyto_objmem(struct brcms_hardware *wlc_hw, -				   uint offset, const void *buf, int len, -				   u32 sel); -extern void brcms_b_copyfrom_objmem(struct brcms_hardware *wlc_hw, uint offset, -				     void *buf, int len, u32 sel); -extern void brcms_b_switch_macfreq(struct brcms_hardware *wlc_hw, u8 spurmode); -extern u16 brcms_b_get_txant(struct brcms_hardware *wlc_hw); -extern void brcms_b_phyclk_fgc(struct brcms_hardware *wlc_hw, bool clk); -extern void brcms_b_macphyclk_set(struct brcms_hardware *wlc_hw, bool clk); -extern void brcms_b_core_phypll_ctl(struct brcms_hardware *wlc_hw, bool on); -extern void brcms_b_txant_set(struct brcms_hardware *wlc_hw, u16 phytxant); -extern void brcms_b_band_stf_ss_set(struct brcms_hardware *wlc_hw, -				    u8 stf_mode); -extern void brcms_c_init_scb(struct scb *scb); +int brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo, struct sk_buff *p); +int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo, +			   uint *blocks); + +int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config); +void brcms_c_mac_promisc(struct brcms_c_info *wlc, uint filter_flags); +u16 brcms_c_calc_lsig_len(struct brcms_c_info *wlc, u32 ratespec, uint mac_len); +u32 brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc, u32 rspec, +			       bool use_rspec, u16 mimo_ctlchbw); +u16 brcms_c_compute_rtscts_dur(struct brcms_c_info *wlc, bool cts_only, +			       u32 rts_rate, u32 frame_rate, +			       u8 rts_preamble_type, u8 frame_preamble_type, +			       uint frame_len, bool ba); +void brcms_c_inval_dma_pkts(struct brcms_hardware *hw, +			    struct ieee80211_sta *sta, void (*dma_callback_fn)); +void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend); +int brcms_c_set_nmode(struct brcms_c_info *wlc); +void brcms_c_beacon_phytxctl_txant_upd(struct brcms_c_info *wlc, u32 bcn_rate); +void brcms_b_antsel_type_set(struct brcms_hardware *wlc_hw, u8 antsel_type); +void brcms_b_set_chanspec(struct brcms_hardware *wlc_hw, u16 chanspec, +			  bool mute, struct txpwr_limits *txpwr); +void brcms_b_write_shm(struct brcms_hardware *wlc_hw, uint offset, u16 v); +u16 brcms_b_read_shm(struct brcms_hardware *wlc_hw, uint offset); +void brcms_b_mhf(struct brcms_hardware *wlc_hw, u8 idx, u16 mask, u16 val, +		 int bands); +void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags); +void brcms_b_mctrl(struct brcms_hardware *wlc_hw, u32 mask, u32 val); +void brcms_b_phy_reset(struct brcms_hardware *wlc_hw); +void brcms_b_bw_set(struct brcms_hardware *wlc_hw, u16 bw); +void brcms_b_core_phypll_reset(struct brcms_hardware *wlc_hw); +void brcms_c_ucode_wake_override_set(struct brcms_hardware *wlc_hw, +				     u32 override_bit); +void brcms_c_ucode_wake_override_clear(struct brcms_hardware *wlc_hw, +				       u32 override_bit); +void brcms_b_write_template_ram(struct brcms_hardware *wlc_hw, int offset, +				int len, void *buf); +u16 brcms_b_rate_shm_offset(struct brcms_hardware *wlc_hw, u8 rate); +void brcms_b_copyto_objmem(struct brcms_hardware *wlc_hw, uint offset, +			   const void *buf, int len, u32 sel); +void brcms_b_copyfrom_objmem(struct brcms_hardware *wlc_hw, uint offset, +			     void *buf, int len, u32 sel); +void brcms_b_switch_macfreq(struct brcms_hardware *wlc_hw, u8 spurmode); +u16 brcms_b_get_txant(struct brcms_hardware *wlc_hw); +void brcms_b_phyclk_fgc(struct brcms_hardware *wlc_hw, bool clk); +void brcms_b_macphyclk_set(struct brcms_hardware *wlc_hw, bool clk); +void brcms_b_core_phypll_ctl(struct brcms_hardware *wlc_hw, bool on); +void brcms_b_txant_set(struct brcms_hardware *wlc_hw, u16 phytxant); +void brcms_b_band_stf_ss_set(struct brcms_hardware *wlc_hw, u8 stf_mode); +void brcms_c_init_scb(struct scb *scb);  #endif				/* _BRCM_MAIN_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_hal.h b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_hal.h index e34a71e7d24..4d3734f48d9 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_hal.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_hal.h @@ -179,121 +179,106 @@ struct shared_phy_params {  }; -extern struct shared_phy *wlc_phy_shared_attach(struct shared_phy_params *shp); -extern struct brcms_phy_pub *wlc_phy_attach(struct shared_phy *sh, -					    struct bcma_device *d11core, -					    int bandtype, struct wiphy *wiphy); -extern void wlc_phy_detach(struct brcms_phy_pub *ppi); - -extern bool wlc_phy_get_phyversion(struct brcms_phy_pub *pih, u16 *phytype, -				   u16 *phyrev, u16 *radioid, -				   u16 *radiover); -extern bool wlc_phy_get_encore(struct brcms_phy_pub *pih); -extern u32 wlc_phy_get_coreflags(struct brcms_phy_pub *pih); - -extern void wlc_phy_hw_clk_state_upd(struct brcms_phy_pub *ppi, bool newstate); -extern void wlc_phy_hw_state_upd(struct brcms_phy_pub *ppi, bool newstate); -extern void wlc_phy_init(struct brcms_phy_pub *ppi, u16 chanspec); -extern void wlc_phy_watchdog(struct brcms_phy_pub *ppi); -extern int wlc_phy_down(struct brcms_phy_pub *ppi); -extern u32 wlc_phy_clk_bwbits(struct brcms_phy_pub *pih); -extern void wlc_phy_cal_init(struct brcms_phy_pub *ppi); -extern void wlc_phy_antsel_init(struct brcms_phy_pub *ppi, bool lut_init); - -extern void wlc_phy_chanspec_set(struct brcms_phy_pub *ppi, -				 u16 chanspec); -extern u16 wlc_phy_chanspec_get(struct brcms_phy_pub *ppi); -extern void wlc_phy_chanspec_radio_set(struct brcms_phy_pub *ppi, -				       u16 newch); -extern u16 wlc_phy_bw_state_get(struct brcms_phy_pub *ppi); -extern void wlc_phy_bw_state_set(struct brcms_phy_pub *ppi, u16 bw); - -extern int wlc_phy_rssi_compute(struct brcms_phy_pub *pih, -				struct d11rxhdr *rxh); -extern void wlc_phy_por_inform(struct brcms_phy_pub *ppi); -extern void wlc_phy_noise_sample_intr(struct brcms_phy_pub *ppi); -extern bool wlc_phy_bist_check_phy(struct brcms_phy_pub *ppi); - -extern void wlc_phy_set_deaf(struct brcms_phy_pub *ppi, bool user_flag); - -extern void wlc_phy_switch_radio(struct brcms_phy_pub *ppi, bool on); -extern void wlc_phy_anacore(struct brcms_phy_pub *ppi, bool on); - - -extern void wlc_phy_BSSinit(struct brcms_phy_pub *ppi, bool bonlyap, int rssi); - -extern void wlc_phy_chanspec_ch14_widefilter_set(struct brcms_phy_pub *ppi, -						 bool wide_filter); -extern void wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band, -					  struct brcms_chanvec *channels); -extern u16 wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi, -					 uint band); - -extern void wlc_phy_txpower_sromlimit(struct brcms_phy_pub *ppi, uint chan, -				      u8 *_min_, u8 *_max_, int rate); -extern void wlc_phy_txpower_sromlimit_max_get(struct brcms_phy_pub *ppi, -					      uint chan, u8 *_max_, u8 *_min_); -extern void wlc_phy_txpower_boardlimit_band(struct brcms_phy_pub *ppi, -					    uint band, s32 *, s32 *, u32 *); -extern void wlc_phy_txpower_limit_set(struct brcms_phy_pub *ppi, -				      struct txpwr_limits *, -				      u16 chanspec); -extern int wlc_phy_txpower_get(struct brcms_phy_pub *ppi, uint *qdbm, -			       bool *override); -extern int wlc_phy_txpower_set(struct brcms_phy_pub *ppi, uint qdbm, -			       bool override); -extern void wlc_phy_txpower_target_set(struct brcms_phy_pub *ppi, -				       struct txpwr_limits *); -extern bool wlc_phy_txpower_hw_ctrl_get(struct brcms_phy_pub *ppi); -extern void wlc_phy_txpower_hw_ctrl_set(struct brcms_phy_pub *ppi, -					bool hwpwrctrl); -extern u8 wlc_phy_txpower_get_target_min(struct brcms_phy_pub *ppi); -extern u8 wlc_phy_txpower_get_target_max(struct brcms_phy_pub *ppi); -extern bool wlc_phy_txpower_ipa_ison(struct brcms_phy_pub *pih); - -extern void wlc_phy_stf_chain_init(struct brcms_phy_pub *pih, u8 txchain, -				   u8 rxchain); -extern void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain, -				  u8 rxchain); -extern void wlc_phy_stf_chain_get(struct brcms_phy_pub *pih, u8 *txchain, -				  u8 *rxchain); -extern u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih); -extern s8 wlc_phy_stf_ssmode_get(struct brcms_phy_pub *pih, -				 u16 chanspec); -extern void wlc_phy_ldpc_override_set(struct brcms_phy_pub *ppi, bool val); - -extern void wlc_phy_cal_perical(struct brcms_phy_pub *ppi, u8 reason); -extern void wlc_phy_noise_sample_request_external(struct brcms_phy_pub *ppi); -extern void wlc_phy_edcrs_lock(struct brcms_phy_pub *pih, bool lock); -extern void wlc_phy_cal_papd_recal(struct brcms_phy_pub *ppi); - -extern void wlc_phy_ant_rxdiv_set(struct brcms_phy_pub *ppi, u8 val); -extern void wlc_phy_clear_tssi(struct brcms_phy_pub *ppi); -extern void wlc_phy_hold_upd(struct brcms_phy_pub *ppi, u32 id, bool val); -extern void wlc_phy_mute_upd(struct brcms_phy_pub *ppi, bool val, u32 flags); - -extern void wlc_phy_antsel_type_set(struct brcms_phy_pub *ppi, u8 antsel_type); - -extern void wlc_phy_txpower_get_current(struct brcms_phy_pub *ppi, -					struct tx_power *power, uint channel); - -extern void wlc_phy_initcal_enable(struct brcms_phy_pub *pih, bool initcal); -extern bool wlc_phy_test_ison(struct brcms_phy_pub *ppi); -extern void wlc_phy_txpwr_percent_set(struct brcms_phy_pub *ppi, -				      u8 txpwr_percent); -extern void wlc_phy_ofdm_rateset_war(struct brcms_phy_pub *pih, bool war); -extern void wlc_phy_bf_preempt_enable(struct brcms_phy_pub *pih, -				      bool bf_preempt); -extern void wlc_phy_machwcap_set(struct brcms_phy_pub *ppi, u32 machwcap); - -extern void wlc_phy_runbist_config(struct brcms_phy_pub *ppi, bool start_end); - -extern void wlc_phy_freqtrack_start(struct brcms_phy_pub *ppi); -extern void wlc_phy_freqtrack_end(struct brcms_phy_pub *ppi); - -extern const u8 *wlc_phy_get_ofdm_rate_lookup(void); - -extern s8 wlc_phy_get_tx_power_offset_by_mcs(struct brcms_phy_pub *ppi, -					     u8 mcs_offset); -extern s8 wlc_phy_get_tx_power_offset(struct brcms_phy_pub *ppi, u8 tbl_offset); +struct shared_phy *wlc_phy_shared_attach(struct shared_phy_params *shp); +struct brcms_phy_pub *wlc_phy_attach(struct shared_phy *sh, +				     struct bcma_device *d11core, int bandtype, +				     struct wiphy *wiphy); +void wlc_phy_detach(struct brcms_phy_pub *ppi); + +bool wlc_phy_get_phyversion(struct brcms_phy_pub *pih, u16 *phytype, +			    u16 *phyrev, u16 *radioid, u16 *radiover); +bool wlc_phy_get_encore(struct brcms_phy_pub *pih); +u32 wlc_phy_get_coreflags(struct brcms_phy_pub *pih); + +void wlc_phy_hw_clk_state_upd(struct brcms_phy_pub *ppi, bool newstate); +void wlc_phy_hw_state_upd(struct brcms_phy_pub *ppi, bool newstate); +void wlc_phy_init(struct brcms_phy_pub *ppi, u16 chanspec); +void wlc_phy_watchdog(struct brcms_phy_pub *ppi); +int wlc_phy_down(struct brcms_phy_pub *ppi); +u32 wlc_phy_clk_bwbits(struct brcms_phy_pub *pih); +void wlc_phy_cal_init(struct brcms_phy_pub *ppi); +void wlc_phy_antsel_init(struct brcms_phy_pub *ppi, bool lut_init); + +void wlc_phy_chanspec_set(struct brcms_phy_pub *ppi, u16 chanspec); +u16 wlc_phy_chanspec_get(struct brcms_phy_pub *ppi); +void wlc_phy_chanspec_radio_set(struct brcms_phy_pub *ppi, u16 newch); +u16 wlc_phy_bw_state_get(struct brcms_phy_pub *ppi); +void wlc_phy_bw_state_set(struct brcms_phy_pub *ppi, u16 bw); + +int wlc_phy_rssi_compute(struct brcms_phy_pub *pih, struct d11rxhdr *rxh); +void wlc_phy_por_inform(struct brcms_phy_pub *ppi); +void wlc_phy_noise_sample_intr(struct brcms_phy_pub *ppi); +bool wlc_phy_bist_check_phy(struct brcms_phy_pub *ppi); + +void wlc_phy_set_deaf(struct brcms_phy_pub *ppi, bool user_flag); + +void wlc_phy_switch_radio(struct brcms_phy_pub *ppi, bool on); +void wlc_phy_anacore(struct brcms_phy_pub *ppi, bool on); + + +void wlc_phy_BSSinit(struct brcms_phy_pub *ppi, bool bonlyap, int rssi); + +void wlc_phy_chanspec_ch14_widefilter_set(struct brcms_phy_pub *ppi, +					  bool wide_filter); +void wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band, +				   struct brcms_chanvec *channels); +u16 wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi, uint band); + +void wlc_phy_txpower_sromlimit(struct brcms_phy_pub *ppi, uint chan, u8 *_min_, +			       u8 *_max_, int rate); +void wlc_phy_txpower_sromlimit_max_get(struct brcms_phy_pub *ppi, uint chan, +				       u8 *_max_, u8 *_min_); +void wlc_phy_txpower_boardlimit_band(struct brcms_phy_pub *ppi, uint band, +				     s32 *, s32 *, u32 *); +void wlc_phy_txpower_limit_set(struct brcms_phy_pub *ppi, struct txpwr_limits *, +			       u16 chanspec); +int wlc_phy_txpower_get(struct brcms_phy_pub *ppi, uint *qdbm, bool *override); +int wlc_phy_txpower_set(struct brcms_phy_pub *ppi, uint qdbm, bool override); +void wlc_phy_txpower_target_set(struct brcms_phy_pub *ppi, +				struct txpwr_limits *); +bool wlc_phy_txpower_hw_ctrl_get(struct brcms_phy_pub *ppi); +void wlc_phy_txpower_hw_ctrl_set(struct brcms_phy_pub *ppi, bool hwpwrctrl); +u8 wlc_phy_txpower_get_target_min(struct brcms_phy_pub *ppi); +u8 wlc_phy_txpower_get_target_max(struct brcms_phy_pub *ppi); +bool wlc_phy_txpower_ipa_ison(struct brcms_phy_pub *pih); + +void wlc_phy_stf_chain_init(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain); +void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain); +void wlc_phy_stf_chain_get(struct brcms_phy_pub *pih, u8 *txchain, u8 *rxchain); +u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih); +s8 wlc_phy_stf_ssmode_get(struct brcms_phy_pub *pih, u16 chanspec); +void wlc_phy_ldpc_override_set(struct brcms_phy_pub *ppi, bool val); + +void wlc_phy_cal_perical(struct brcms_phy_pub *ppi, u8 reason); +void wlc_phy_noise_sample_request_external(struct brcms_phy_pub *ppi); +void wlc_phy_edcrs_lock(struct brcms_phy_pub *pih, bool lock); +void wlc_phy_cal_papd_recal(struct brcms_phy_pub *ppi); + +void wlc_phy_ant_rxdiv_set(struct brcms_phy_pub *ppi, u8 val); +void wlc_phy_clear_tssi(struct brcms_phy_pub *ppi); +void wlc_phy_hold_upd(struct brcms_phy_pub *ppi, u32 id, bool val); +void wlc_phy_mute_upd(struct brcms_phy_pub *ppi, bool val, u32 flags); + +void wlc_phy_antsel_type_set(struct brcms_phy_pub *ppi, u8 antsel_type); + +void wlc_phy_txpower_get_current(struct brcms_phy_pub *ppi, +				 struct tx_power *power, uint channel); + +void wlc_phy_initcal_enable(struct brcms_phy_pub *pih, bool initcal); +bool wlc_phy_test_ison(struct brcms_phy_pub *ppi); +void wlc_phy_txpwr_percent_set(struct brcms_phy_pub *ppi, u8 txpwr_percent); +void wlc_phy_ofdm_rateset_war(struct brcms_phy_pub *pih, bool war); +void wlc_phy_bf_preempt_enable(struct brcms_phy_pub *pih, bool bf_preempt); +void wlc_phy_machwcap_set(struct brcms_phy_pub *ppi, u32 machwcap); + +void wlc_phy_runbist_config(struct brcms_phy_pub *ppi, bool start_end); + +void wlc_phy_freqtrack_start(struct brcms_phy_pub *ppi); +void wlc_phy_freqtrack_end(struct brcms_phy_pub *ppi); + +const u8 *wlc_phy_get_ofdm_rate_lookup(void); + +s8 wlc_phy_get_tx_power_offset_by_mcs(struct brcms_phy_pub *ppi, +				      u8 mcs_offset); +s8 wlc_phy_get_tx_power_offset(struct brcms_phy_pub *ppi, u8 tbl_offset);  #endif                          /* _BRCM_PHY_HAL_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h index 1dc767c3165..4960f7d2680 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h @@ -910,113 +910,103 @@ struct lcnphy_radio_regs {  	u8 do_init_g;  }; -extern u16 read_phy_reg(struct brcms_phy *pi, u16 addr); -extern void write_phy_reg(struct brcms_phy *pi, u16 addr, u16 val); -extern void and_phy_reg(struct brcms_phy *pi, u16 addr, u16 val); -extern void or_phy_reg(struct brcms_phy *pi, u16 addr, u16 val); -extern void mod_phy_reg(struct brcms_phy *pi, u16 addr, u16 mask, u16 val); - -extern u16 read_radio_reg(struct brcms_phy *pi, u16 addr); -extern void or_radio_reg(struct brcms_phy *pi, u16 addr, u16 val); -extern void and_radio_reg(struct brcms_phy *pi, u16 addr, u16 val); -extern void mod_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask, -			  u16 val); -extern void xor_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask); - -extern void write_radio_reg(struct brcms_phy *pi, u16 addr, u16 val); - -extern void wlc_phyreg_enter(struct brcms_phy_pub *pih); -extern void wlc_phyreg_exit(struct brcms_phy_pub *pih); -extern void wlc_radioreg_enter(struct brcms_phy_pub *pih); -extern void wlc_radioreg_exit(struct brcms_phy_pub *pih); - -extern void wlc_phy_read_table(struct brcms_phy *pi, -			       const struct phytbl_info *ptbl_info, -			       u16 tblAddr, u16 tblDataHi, -			       u16 tblDatalo); -extern void wlc_phy_write_table(struct brcms_phy *pi, -				const struct phytbl_info *ptbl_info, -				u16 tblAddr, u16 tblDataHi, u16 tblDatalo); -extern void wlc_phy_table_addr(struct brcms_phy *pi, uint tbl_id, -			       uint tbl_offset, u16 tblAddr, u16 tblDataHi, -			       u16 tblDataLo); -extern void wlc_phy_table_data_write(struct brcms_phy *pi, uint width, u32 val); - -extern void write_phy_channel_reg(struct brcms_phy *pi, uint val); -extern void wlc_phy_txpower_update_shm(struct brcms_phy *pi); - -extern u8 wlc_phy_nbits(s32 value); -extern void wlc_phy_compute_dB(u32 *cmplx_pwr, s8 *p_dB, u8 core); - -extern uint wlc_phy_init_radio_regs_allbands(struct brcms_phy *pi, -					     struct radio_20xx_regs *radioregs); -extern uint wlc_phy_init_radio_regs(struct brcms_phy *pi, -				    const struct radio_regs *radioregs, -				    u16 core_offset); - -extern void wlc_phy_txpower_ipa_upd(struct brcms_phy *pi); - -extern void wlc_phy_do_dummy_tx(struct brcms_phy *pi, bool ofdm, bool pa_on); -extern void wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, -					s32 *eps_imag); - -extern void wlc_phy_cal_perical_mphase_reset(struct brcms_phy *pi); -extern void wlc_phy_cal_perical_mphase_restart(struct brcms_phy *pi); - -extern bool wlc_phy_attach_nphy(struct brcms_phy *pi); -extern bool wlc_phy_attach_lcnphy(struct brcms_phy *pi); - -extern void wlc_phy_detach_lcnphy(struct brcms_phy *pi); - -extern void wlc_phy_init_nphy(struct brcms_phy *pi); -extern void wlc_phy_init_lcnphy(struct brcms_phy *pi); - -extern void wlc_phy_cal_init_nphy(struct brcms_phy *pi); -extern void wlc_phy_cal_init_lcnphy(struct brcms_phy *pi); - -extern void wlc_phy_chanspec_set_nphy(struct brcms_phy *pi, -				      u16 chanspec); -extern void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, -					u16 chanspec); -extern void wlc_phy_chanspec_set_fixup_lcnphy(struct brcms_phy *pi, -					      u16 chanspec); -extern int wlc_phy_channel2freq(uint channel); -extern int wlc_phy_chanspec_freq2bandrange_lpssn(uint); -extern int wlc_phy_chanspec_bandrange_get(struct brcms_phy *, u16 chanspec); - -extern void wlc_lcnphy_set_tx_pwr_ctrl(struct brcms_phy *pi, u16 mode); -extern s8 wlc_lcnphy_get_current_tx_pwr_idx(struct brcms_phy *pi); - -extern void wlc_phy_txpower_recalc_target_nphy(struct brcms_phy *pi); -extern void wlc_lcnphy_txpower_recalc_target(struct brcms_phy *pi); -extern void wlc_phy_txpower_recalc_target_lcnphy(struct brcms_phy *pi); - -extern void wlc_lcnphy_set_tx_pwr_by_index(struct brcms_phy *pi, int index); -extern void wlc_lcnphy_tx_pu(struct brcms_phy *pi, bool bEnable); -extern void wlc_lcnphy_stop_tx_tone(struct brcms_phy *pi); -extern void wlc_lcnphy_start_tx_tone(struct brcms_phy *pi, s32 f_kHz, -				     u16 max_val, bool iqcalmode); - -extern void wlc_phy_txpower_sromlimit_get_nphy(struct brcms_phy *pi, uint chan, -					       u8 *max_pwr, u8 rate_id); -extern void wlc_phy_ofdm_to_mcs_powers_nphy(u8 *power, u8 rate_mcs_start, -					    u8 rate_mcs_end, -					    u8 rate_ofdm_start); -extern void wlc_phy_mcs_to_ofdm_powers_nphy(u8 *power, -					    u8 rate_ofdm_start, -					    u8 rate_ofdm_end, -					    u8 rate_mcs_start); - -extern u16 wlc_lcnphy_tempsense(struct brcms_phy *pi, bool mode); -extern s16 wlc_lcnphy_tempsense_new(struct brcms_phy *pi, bool mode); -extern s8 wlc_lcnphy_tempsense_degree(struct brcms_phy *pi, bool mode); -extern s8 wlc_lcnphy_vbatsense(struct brcms_phy *pi, bool mode); -extern void wlc_phy_carrier_suppress_lcnphy(struct brcms_phy *pi); -extern void wlc_lcnphy_crsuprs(struct brcms_phy *pi, int channel); -extern void wlc_lcnphy_epa_switch(struct brcms_phy *pi, bool mode); -extern void wlc_2064_vco_cal(struct brcms_phy *pi); - -extern void wlc_phy_txpower_recalc_target(struct brcms_phy *pi); +u16 read_phy_reg(struct brcms_phy *pi, u16 addr); +void write_phy_reg(struct brcms_phy *pi, u16 addr, u16 val); +void and_phy_reg(struct brcms_phy *pi, u16 addr, u16 val); +void or_phy_reg(struct brcms_phy *pi, u16 addr, u16 val); +void mod_phy_reg(struct brcms_phy *pi, u16 addr, u16 mask, u16 val); + +u16 read_radio_reg(struct brcms_phy *pi, u16 addr); +void or_radio_reg(struct brcms_phy *pi, u16 addr, u16 val); +void and_radio_reg(struct brcms_phy *pi, u16 addr, u16 val); +void mod_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask, u16 val); +void xor_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask); + +void write_radio_reg(struct brcms_phy *pi, u16 addr, u16 val); + +void wlc_phyreg_enter(struct brcms_phy_pub *pih); +void wlc_phyreg_exit(struct brcms_phy_pub *pih); +void wlc_radioreg_enter(struct brcms_phy_pub *pih); +void wlc_radioreg_exit(struct brcms_phy_pub *pih); + +void wlc_phy_read_table(struct brcms_phy *pi, +			const struct phytbl_info *ptbl_info, +			u16 tblAddr, u16 tblDataHi, u16 tblDatalo); +void wlc_phy_write_table(struct brcms_phy *pi, +			 const struct phytbl_info *ptbl_info, +			 u16 tblAddr, u16 tblDataHi, u16 tblDatalo); +void wlc_phy_table_addr(struct brcms_phy *pi, uint tbl_id, uint tbl_offset, +			u16 tblAddr, u16 tblDataHi, u16 tblDataLo); +void wlc_phy_table_data_write(struct brcms_phy *pi, uint width, u32 val); + +void write_phy_channel_reg(struct brcms_phy *pi, uint val); +void wlc_phy_txpower_update_shm(struct brcms_phy *pi); + +u8 wlc_phy_nbits(s32 value); +void wlc_phy_compute_dB(u32 *cmplx_pwr, s8 *p_dB, u8 core); + +uint wlc_phy_init_radio_regs_allbands(struct brcms_phy *pi, +				      struct radio_20xx_regs *radioregs); +uint wlc_phy_init_radio_regs(struct brcms_phy *pi, +			     const struct radio_regs *radioregs, +			     u16 core_offset); + +void wlc_phy_txpower_ipa_upd(struct brcms_phy *pi); + +void wlc_phy_do_dummy_tx(struct brcms_phy *pi, bool ofdm, bool pa_on); +void wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, s32 *eps_imag); + +void wlc_phy_cal_perical_mphase_reset(struct brcms_phy *pi); +void wlc_phy_cal_perical_mphase_restart(struct brcms_phy *pi); + +bool wlc_phy_attach_nphy(struct brcms_phy *pi); +bool wlc_phy_attach_lcnphy(struct brcms_phy *pi); + +void wlc_phy_detach_lcnphy(struct brcms_phy *pi); + +void wlc_phy_init_nphy(struct brcms_phy *pi); +void wlc_phy_init_lcnphy(struct brcms_phy *pi); + +void wlc_phy_cal_init_nphy(struct brcms_phy *pi); +void wlc_phy_cal_init_lcnphy(struct brcms_phy *pi); + +void wlc_phy_chanspec_set_nphy(struct brcms_phy *pi, u16 chanspec); +void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, u16 chanspec); +void wlc_phy_chanspec_set_fixup_lcnphy(struct brcms_phy *pi, u16 chanspec); +int wlc_phy_channel2freq(uint channel); +int wlc_phy_chanspec_freq2bandrange_lpssn(uint); +int wlc_phy_chanspec_bandrange_get(struct brcms_phy *, u16 chanspec); + +void wlc_lcnphy_set_tx_pwr_ctrl(struct brcms_phy *pi, u16 mode); +s8 wlc_lcnphy_get_current_tx_pwr_idx(struct brcms_phy *pi); + +void wlc_phy_txpower_recalc_target_nphy(struct brcms_phy *pi); +void wlc_lcnphy_txpower_recalc_target(struct brcms_phy *pi); +void wlc_phy_txpower_recalc_target_lcnphy(struct brcms_phy *pi); + +void wlc_lcnphy_set_tx_pwr_by_index(struct brcms_phy *pi, int index); +void wlc_lcnphy_tx_pu(struct brcms_phy *pi, bool bEnable); +void wlc_lcnphy_stop_tx_tone(struct brcms_phy *pi); +void wlc_lcnphy_start_tx_tone(struct brcms_phy *pi, s32 f_kHz, u16 max_val, +			      bool iqcalmode); + +void wlc_phy_txpower_sromlimit_get_nphy(struct brcms_phy *pi, uint chan, +					u8 *max_pwr, u8 rate_id); +void wlc_phy_ofdm_to_mcs_powers_nphy(u8 *power, u8 rate_mcs_start, +				     u8 rate_mcs_end, u8 rate_ofdm_start); +void wlc_phy_mcs_to_ofdm_powers_nphy(u8 *power, u8 rate_ofdm_start, +				     u8 rate_ofdm_end, u8 rate_mcs_start); + +u16 wlc_lcnphy_tempsense(struct brcms_phy *pi, bool mode); +s16 wlc_lcnphy_tempsense_new(struct brcms_phy *pi, bool mode); +s8 wlc_lcnphy_tempsense_degree(struct brcms_phy *pi, bool mode); +s8 wlc_lcnphy_vbatsense(struct brcms_phy *pi, bool mode); +void wlc_phy_carrier_suppress_lcnphy(struct brcms_phy *pi); +void wlc_lcnphy_crsuprs(struct brcms_phy *pi, int channel); +void wlc_lcnphy_epa_switch(struct brcms_phy *pi, bool mode); +void wlc_2064_vco_cal(struct brcms_phy *pi); + +void wlc_phy_txpower_recalc_target(struct brcms_phy *pi);  #define LCNPHY_TBL_ID_PAPDCOMPDELTATBL	0x18  #define LCNPHY_TX_POWER_TABLE_SIZE	128 @@ -1030,26 +1020,24 @@ extern void wlc_phy_txpower_recalc_target(struct brcms_phy *pi);  #define LCNPHY_TX_PWR_CTRL_TEMPBASED	0xE001 -extern void wlc_lcnphy_write_table(struct brcms_phy *pi, -				   const struct phytbl_info *pti); -extern void wlc_lcnphy_read_table(struct brcms_phy *pi, -				  struct phytbl_info *pti); -extern void wlc_lcnphy_set_tx_iqcc(struct brcms_phy *pi, u16 a, u16 b); -extern void wlc_lcnphy_set_tx_locc(struct brcms_phy *pi, u16 didq); -extern void wlc_lcnphy_get_tx_iqcc(struct brcms_phy *pi, u16 *a, u16 *b); -extern u16 wlc_lcnphy_get_tx_locc(struct brcms_phy *pi); -extern void wlc_lcnphy_get_radio_loft(struct brcms_phy *pi, u8 *ei0, -				      u8 *eq0, u8 *fi0, u8 *fq0); -extern void wlc_lcnphy_calib_modes(struct brcms_phy *pi, uint mode); -extern void wlc_lcnphy_deaf_mode(struct brcms_phy *pi, bool mode); -extern bool wlc_phy_tpc_isenabled_lcnphy(struct brcms_phy *pi); -extern void wlc_lcnphy_tx_pwr_update_npt(struct brcms_phy *pi); -extern s32 wlc_lcnphy_tssi2dbm(s32 tssi, s32 a1, s32 b0, s32 b1); -extern void wlc_lcnphy_get_tssi(struct brcms_phy *pi, s8 *ofdm_pwr, -				s8 *cck_pwr); -extern void wlc_lcnphy_tx_power_adjustment(struct brcms_phy_pub *ppi); - -extern s32 wlc_lcnphy_rx_signal_power(struct brcms_phy *pi, s32 gain_index); +void wlc_lcnphy_write_table(struct brcms_phy *pi, +			    const struct phytbl_info *pti); +void wlc_lcnphy_read_table(struct brcms_phy *pi, struct phytbl_info *pti); +void wlc_lcnphy_set_tx_iqcc(struct brcms_phy *pi, u16 a, u16 b); +void wlc_lcnphy_set_tx_locc(struct brcms_phy *pi, u16 didq); +void wlc_lcnphy_get_tx_iqcc(struct brcms_phy *pi, u16 *a, u16 *b); +u16 wlc_lcnphy_get_tx_locc(struct brcms_phy *pi); +void wlc_lcnphy_get_radio_loft(struct brcms_phy *pi, u8 *ei0, u8 *eq0, u8 *fi0, +			       u8 *fq0); +void wlc_lcnphy_calib_modes(struct brcms_phy *pi, uint mode); +void wlc_lcnphy_deaf_mode(struct brcms_phy *pi, bool mode); +bool wlc_phy_tpc_isenabled_lcnphy(struct brcms_phy *pi); +void wlc_lcnphy_tx_pwr_update_npt(struct brcms_phy *pi); +s32 wlc_lcnphy_tssi2dbm(s32 tssi, s32 a1, s32 b0, s32 b1); +void wlc_lcnphy_get_tssi(struct brcms_phy *pi, s8 *ofdm_pwr, s8 *cck_pwr); +void wlc_lcnphy_tx_power_adjustment(struct brcms_phy_pub *ppi); + +s32 wlc_lcnphy_rx_signal_power(struct brcms_phy *pi, s32 gain_index);  #define NPHY_MAX_HPVGA1_INDEX		10  #define NPHY_DEF_HPVGA1_INDEXLIMIT	7 @@ -1060,9 +1048,8 @@ struct phy_iq_est {  	u32 q_pwr;  }; -extern void wlc_phy_stay_in_carriersearch_nphy(struct brcms_phy *pi, -					       bool enable); -extern void wlc_nphy_deaf_mode(struct brcms_phy *pi, bool mode); +void wlc_phy_stay_in_carriersearch_nphy(struct brcms_phy *pi, bool enable); +void wlc_nphy_deaf_mode(struct brcms_phy *pi, bool mode);  #define wlc_phy_write_table_nphy(pi, pti) \  	wlc_phy_write_table(pi, pti, 0x72, 0x74, 0x73) @@ -1076,10 +1063,10 @@ extern void wlc_nphy_deaf_mode(struct brcms_phy *pi, bool mode);  #define wlc_nphy_table_data_write(pi, w, v) \  	wlc_phy_table_data_write((pi), (w), (v)) -extern void wlc_phy_table_read_nphy(struct brcms_phy *pi, u32, u32 l, u32 o, -				    u32 w, void *d); -extern void wlc_phy_table_write_nphy(struct brcms_phy *pi, u32, u32, u32, -				     u32, const void *); +void wlc_phy_table_read_nphy(struct brcms_phy *pi, u32, u32 l, u32 o, u32 w, +			     void *d); +void wlc_phy_table_write_nphy(struct brcms_phy *pi, u32, u32, u32, u32, +			      const void *);  #define	PHY_IPA(pi) \  	((pi->ipa2g_on && CHSPEC_IS2G(pi->radio_chanspec)) || \ @@ -1089,73 +1076,67 @@ extern void wlc_phy_table_write_nphy(struct brcms_phy *pi, u32, u32, u32,  	if (NREV_LT((pi)->pubpi.phy_rev, 3)) \  		(void)bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) -extern void wlc_phy_cal_perical_nphy_run(struct brcms_phy *pi, u8 caltype); -extern void wlc_phy_aci_reset_nphy(struct brcms_phy *pi); -extern void wlc_phy_pa_override_nphy(struct brcms_phy *pi, bool en); - -extern u8 wlc_phy_get_chan_freq_range_nphy(struct brcms_phy *pi, uint chan); -extern void wlc_phy_switch_radio_nphy(struct brcms_phy *pi, bool on); - -extern void wlc_phy_stf_chain_upd_nphy(struct brcms_phy *pi); - -extern void wlc_phy_force_rfseq_nphy(struct brcms_phy *pi, u8 cmd); -extern s16 wlc_phy_tempsense_nphy(struct brcms_phy *pi); - -extern u16 wlc_phy_classifier_nphy(struct brcms_phy *pi, u16 mask, u16 val); - -extern void wlc_phy_rx_iq_est_nphy(struct brcms_phy *pi, struct phy_iq_est *est, -				   u16 num_samps, u8 wait_time, -				   u8 wait_for_crs); - -extern void wlc_phy_rx_iq_coeffs_nphy(struct brcms_phy *pi, u8 write, -				      struct nphy_iq_comp *comp); -extern void wlc_phy_aci_and_noise_reduction_nphy(struct brcms_phy *pi); - -extern void wlc_phy_rxcore_setstate_nphy(struct brcms_phy_pub *pih, -					 u8 rxcore_bitmask); -extern u8 wlc_phy_rxcore_getstate_nphy(struct brcms_phy_pub *pih); - -extern void wlc_phy_txpwrctrl_enable_nphy(struct brcms_phy *pi, u8 ctrl_type); -extern void wlc_phy_txpwr_fixpower_nphy(struct brcms_phy *pi); -extern void wlc_phy_txpwr_apply_nphy(struct brcms_phy *pi); -extern void wlc_phy_txpwr_papd_cal_nphy(struct brcms_phy *pi); -extern u16 wlc_phy_txpwr_idx_get_nphy(struct brcms_phy *pi); - -extern struct nphy_txgains wlc_phy_get_tx_gain_nphy(struct brcms_phy *pi); -extern int wlc_phy_cal_txiqlo_nphy(struct brcms_phy *pi, -				   struct nphy_txgains target_gain, -				   bool full, bool m); -extern int wlc_phy_cal_rxiq_nphy(struct brcms_phy *pi, -				 struct nphy_txgains target_gain, -				 u8 type, bool d); -extern void wlc_phy_txpwr_index_nphy(struct brcms_phy *pi, u8 core_mask, -				     s8 txpwrindex, bool res); -extern void wlc_phy_rssisel_nphy(struct brcms_phy *pi, u8 core, u8 rssi_type); -extern int wlc_phy_poll_rssi_nphy(struct brcms_phy *pi, u8 rssi_type, -				  s32 *rssi_buf, u8 nsamps); -extern void wlc_phy_rssi_cal_nphy(struct brcms_phy *pi); -extern int wlc_phy_aci_scan_nphy(struct brcms_phy *pi); -extern void wlc_phy_cal_txgainctrl_nphy(struct brcms_phy *pi, -					s32 dBm_targetpower, bool debug); -extern int wlc_phy_tx_tone_nphy(struct brcms_phy *pi, u32 f_kHz, u16 max_val, -				u8 mode, u8, bool); -extern void wlc_phy_stopplayback_nphy(struct brcms_phy *pi); -extern void wlc_phy_est_tonepwr_nphy(struct brcms_phy *pi, s32 *qdBm_pwrbuf, -				     u8 num_samps); -extern void wlc_phy_radio205x_vcocal_nphy(struct brcms_phy *pi); - -extern int wlc_phy_rssi_compute_nphy(struct brcms_phy *pi, -				     struct d11rxhdr *rxh); +void wlc_phy_cal_perical_nphy_run(struct brcms_phy *pi, u8 caltype); +void wlc_phy_aci_reset_nphy(struct brcms_phy *pi); +void wlc_phy_pa_override_nphy(struct brcms_phy *pi, bool en); + +u8 wlc_phy_get_chan_freq_range_nphy(struct brcms_phy *pi, uint chan); +void wlc_phy_switch_radio_nphy(struct brcms_phy *pi, bool on); + +void wlc_phy_stf_chain_upd_nphy(struct brcms_phy *pi); + +void wlc_phy_force_rfseq_nphy(struct brcms_phy *pi, u8 cmd); +s16 wlc_phy_tempsense_nphy(struct brcms_phy *pi); + +u16 wlc_phy_classifier_nphy(struct brcms_phy *pi, u16 mask, u16 val); + +void wlc_phy_rx_iq_est_nphy(struct brcms_phy *pi, struct phy_iq_est *est, +			    u16 num_samps, u8 wait_time, u8 wait_for_crs); + +void wlc_phy_rx_iq_coeffs_nphy(struct brcms_phy *pi, u8 write, +			       struct nphy_iq_comp *comp); +void wlc_phy_aci_and_noise_reduction_nphy(struct brcms_phy *pi); + +void wlc_phy_rxcore_setstate_nphy(struct brcms_phy_pub *pih, u8 rxcore_bitmask); +u8 wlc_phy_rxcore_getstate_nphy(struct brcms_phy_pub *pih); + +void wlc_phy_txpwrctrl_enable_nphy(struct brcms_phy *pi, u8 ctrl_type); +void wlc_phy_txpwr_fixpower_nphy(struct brcms_phy *pi); +void wlc_phy_txpwr_apply_nphy(struct brcms_phy *pi); +void wlc_phy_txpwr_papd_cal_nphy(struct brcms_phy *pi); +u16 wlc_phy_txpwr_idx_get_nphy(struct brcms_phy *pi); + +struct nphy_txgains wlc_phy_get_tx_gain_nphy(struct brcms_phy *pi); +int wlc_phy_cal_txiqlo_nphy(struct brcms_phy *pi, +			    struct nphy_txgains target_gain, bool full, bool m); +int wlc_phy_cal_rxiq_nphy(struct brcms_phy *pi, struct nphy_txgains target_gain, +			  u8 type, bool d); +void wlc_phy_txpwr_index_nphy(struct brcms_phy *pi, u8 core_mask, +			      s8 txpwrindex, bool res); +void wlc_phy_rssisel_nphy(struct brcms_phy *pi, u8 core, u8 rssi_type); +int wlc_phy_poll_rssi_nphy(struct brcms_phy *pi, u8 rssi_type, +			   s32 *rssi_buf, u8 nsamps); +void wlc_phy_rssi_cal_nphy(struct brcms_phy *pi); +int wlc_phy_aci_scan_nphy(struct brcms_phy *pi); +void wlc_phy_cal_txgainctrl_nphy(struct brcms_phy *pi, s32 dBm_targetpower, +				 bool debug); +int wlc_phy_tx_tone_nphy(struct brcms_phy *pi, u32 f_kHz, u16 max_val, u8 mode, +			 u8, bool); +void wlc_phy_stopplayback_nphy(struct brcms_phy *pi); +void wlc_phy_est_tonepwr_nphy(struct brcms_phy *pi, s32 *qdBm_pwrbuf, +			      u8 num_samps); +void wlc_phy_radio205x_vcocal_nphy(struct brcms_phy *pi); + +int wlc_phy_rssi_compute_nphy(struct brcms_phy *pi, struct d11rxhdr *rxh);  #define NPHY_TESTPATTERN_BPHY_EVM   0  #define NPHY_TESTPATTERN_BPHY_RFCS  1 -extern void wlc_phy_nphy_tkip_rifs_war(struct brcms_phy *pi, u8 rifs); +void wlc_phy_nphy_tkip_rifs_war(struct brcms_phy *pi, u8 rifs);  void wlc_phy_get_pwrdet_offsets(struct brcms_phy *pi, s8 *cckoffset,  				s8 *ofdmoffset); -extern s8 wlc_phy_upd_rssi_offset(struct brcms_phy *pi, s8 rssi, -				  u16 chanspec); +s8 wlc_phy_upd_rssi_offset(struct brcms_phy *pi, s8 rssi, u16 chanspec); -extern bool wlc_phy_n_txpower_ipa_ison(struct brcms_phy *pih); +bool wlc_phy_n_txpower_ipa_ison(struct brcms_phy *pih);  #endif				/* _BRCM_PHY_INT_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.h b/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.h index 2c5b66b7597..dd8774717ad 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.h @@ -124,56 +124,49 @@  struct brcms_phy; -extern struct phy_shim_info *wlc_phy_shim_attach(struct brcms_hardware *wlc_hw, -						 struct brcms_info *wl, -						 struct brcms_c_info *wlc); -extern void wlc_phy_shim_detach(struct phy_shim_info *physhim); +struct phy_shim_info *wlc_phy_shim_attach(struct brcms_hardware *wlc_hw, +					  struct brcms_info *wl, +					  struct brcms_c_info *wlc); +void wlc_phy_shim_detach(struct phy_shim_info *physhim);  /* PHY to WL utility functions */ -extern struct wlapi_timer *wlapi_init_timer(struct phy_shim_info *physhim, -					    void (*fn) (struct brcms_phy *pi), -					    void *arg, const char *name); -extern void wlapi_free_timer(struct wlapi_timer *t); -extern void wlapi_add_timer(struct wlapi_timer *t, uint ms, int periodic); -extern bool wlapi_del_timer(struct wlapi_timer *t); -extern void wlapi_intrson(struct phy_shim_info *physhim); -extern u32 wlapi_intrsoff(struct phy_shim_info *physhim); -extern void wlapi_intrsrestore(struct phy_shim_info *physhim, -			       u32 macintmask); - -extern void wlapi_bmac_write_shm(struct phy_shim_info *physhim, uint offset, -				 u16 v); -extern u16 wlapi_bmac_read_shm(struct phy_shim_info *physhim, uint offset); -extern void wlapi_bmac_mhf(struct phy_shim_info *physhim, u8 idx, -			   u16 mask, u16 val, int bands); -extern void wlapi_bmac_corereset(struct phy_shim_info *physhim, u32 flags); -extern void wlapi_suspend_mac_and_wait(struct phy_shim_info *physhim); -extern void wlapi_switch_macfreq(struct phy_shim_info *physhim, u8 spurmode); -extern void wlapi_enable_mac(struct phy_shim_info *physhim); -extern void wlapi_bmac_mctrl(struct phy_shim_info *physhim, u32 mask, -			     u32 val); -extern void wlapi_bmac_phy_reset(struct phy_shim_info *physhim); -extern void wlapi_bmac_bw_set(struct phy_shim_info *physhim, u16 bw); -extern void wlapi_bmac_phyclk_fgc(struct phy_shim_info *physhim, bool clk); -extern void wlapi_bmac_macphyclk_set(struct phy_shim_info *physhim, bool clk); -extern void wlapi_bmac_core_phypll_ctl(struct phy_shim_info *physhim, bool on); -extern void wlapi_bmac_core_phypll_reset(struct phy_shim_info *physhim); -extern void wlapi_bmac_ucode_wake_override_phyreg_set(struct phy_shim_info * -						      physhim); -extern void wlapi_bmac_ucode_wake_override_phyreg_clear(struct phy_shim_info * -							physhim); -extern void wlapi_bmac_write_template_ram(struct phy_shim_info *physhim, int o, -					  int len, void *buf); -extern u16 wlapi_bmac_rate_shm_offset(struct phy_shim_info *physhim, -					 u8 rate); -extern void wlapi_ucode_sample_init(struct phy_shim_info *physhim); -extern void wlapi_copyfrom_objmem(struct phy_shim_info *physhim, uint, -				  void *buf, int, u32 sel); -extern void wlapi_copyto_objmem(struct phy_shim_info *physhim, uint, -				const void *buf, int, u32); - -extern void wlapi_high_update_phy_mode(struct phy_shim_info *physhim, -				       u32 phy_mode); -extern u16 wlapi_bmac_get_txant(struct phy_shim_info *physhim); +struct wlapi_timer *wlapi_init_timer(struct phy_shim_info *physhim, +				     void (*fn)(struct brcms_phy *pi), +				     void *arg, const char *name); +void wlapi_free_timer(struct wlapi_timer *t); +void wlapi_add_timer(struct wlapi_timer *t, uint ms, int periodic); +bool wlapi_del_timer(struct wlapi_timer *t); +void wlapi_intrson(struct phy_shim_info *physhim); +u32 wlapi_intrsoff(struct phy_shim_info *physhim); +void wlapi_intrsrestore(struct phy_shim_info *physhim, u32 macintmask); + +void wlapi_bmac_write_shm(struct phy_shim_info *physhim, uint offset, u16 v); +u16 wlapi_bmac_read_shm(struct phy_shim_info *physhim, uint offset); +void wlapi_bmac_mhf(struct phy_shim_info *physhim, u8 idx, u16 mask, u16 val, +		    int bands); +void wlapi_bmac_corereset(struct phy_shim_info *physhim, u32 flags); +void wlapi_suspend_mac_and_wait(struct phy_shim_info *physhim); +void wlapi_switch_macfreq(struct phy_shim_info *physhim, u8 spurmode); +void wlapi_enable_mac(struct phy_shim_info *physhim); +void wlapi_bmac_mctrl(struct phy_shim_info *physhim, u32 mask, u32 val); +void wlapi_bmac_phy_reset(struct phy_shim_info *physhim); +void wlapi_bmac_bw_set(struct phy_shim_info *physhim, u16 bw); +void wlapi_bmac_phyclk_fgc(struct phy_shim_info *physhim, bool clk); +void wlapi_bmac_macphyclk_set(struct phy_shim_info *physhim, bool clk); +void wlapi_bmac_core_phypll_ctl(struct phy_shim_info *physhim, bool on); +void wlapi_bmac_core_phypll_reset(struct phy_shim_info *physhim); +void wlapi_bmac_ucode_wake_override_phyreg_set(struct phy_shim_info *physhim); +void wlapi_bmac_ucode_wake_override_phyreg_clear(struct phy_shim_info *physhim); +void wlapi_bmac_write_template_ram(struct phy_shim_info *physhim, int o, +				   int len, void *buf); +u16 wlapi_bmac_rate_shm_offset(struct phy_shim_info *physhim, u8 rate); +void wlapi_ucode_sample_init(struct phy_shim_info *physhim); +void wlapi_copyfrom_objmem(struct phy_shim_info *physhim, uint, void *buf, +			   int, u32 sel); +void wlapi_copyto_objmem(struct phy_shim_info *physhim, uint, const void *buf, +			 int, u32); + +void wlapi_high_update_phy_mode(struct phy_shim_info *physhim, u32 phy_mode); +u16 wlapi_bmac_get_txant(struct phy_shim_info *physhim);  #endif				/* _BRCM_PHY_SHIM_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pmu.h b/drivers/net/wireless/brcm80211/brcmsmac/pmu.h index 20e2012d5a3..a014bbc4f93 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/pmu.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/pmu.h @@ -20,7 +20,7 @@  #include "types.h" -extern u16 si_pmu_fast_pwrup_delay(struct si_pub *sih); -extern u32 si_pmu_measure_alpclk(struct si_pub *sih); +u16 si_pmu_fast_pwrup_delay(struct si_pub *sih); +u32 si_pmu_measure_alpclk(struct si_pub *sih);  #endif /* _BRCM_PMU_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pub.h b/drivers/net/wireless/brcm80211/brcmsmac/pub.h index d36ea5e1cc4..4da38cb4f31 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/pub.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/pub.h @@ -266,83 +266,76 @@ struct brcms_antselcfg {  };  /* common functions for every port */ -extern struct brcms_c_info * -brcms_c_attach(struct brcms_info *wl, struct bcma_device *core, uint unit, -	       bool piomode, uint *perr); -extern uint brcms_c_detach(struct brcms_c_info *wlc); -extern int brcms_c_up(struct brcms_c_info *wlc); -extern uint brcms_c_down(struct brcms_c_info *wlc); - -extern bool brcms_c_chipmatch(struct bcma_device *core); -extern void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx); -extern void brcms_c_reset(struct brcms_c_info *wlc); - -extern void brcms_c_intrson(struct brcms_c_info *wlc); -extern u32 brcms_c_intrsoff(struct brcms_c_info *wlc); -extern void brcms_c_intrsrestore(struct brcms_c_info *wlc, u32 macintmask); -extern bool brcms_c_intrsupd(struct brcms_c_info *wlc); -extern bool brcms_c_isr(struct brcms_c_info *wlc); -extern bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded); -extern bool brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc, -				     struct sk_buff *sdu, -				     struct ieee80211_hw *hw); -extern bool brcms_c_aggregatable(struct brcms_c_info *wlc, u8 tid); -extern void brcms_c_protection_upd(struct brcms_c_info *wlc, uint idx, -				   int val); -extern int brcms_c_get_header_len(void); -extern void brcms_c_set_addrmatch(struct brcms_c_info *wlc, -				  int match_reg_offset, -				  const u8 *addr); -extern void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci, -			      const struct ieee80211_tx_queue_params *arg, -			      bool suspend); -extern struct brcms_pub *brcms_c_pub(struct brcms_c_info *wlc); -extern void brcms_c_ampdu_flush(struct brcms_c_info *wlc, -			    struct ieee80211_sta *sta, u16 tid); -extern void brcms_c_ampdu_tx_operational(struct brcms_c_info *wlc, u8 tid, -					 u8 ba_wsize, uint max_rx_ampdu_bytes); -extern int brcms_c_module_register(struct brcms_pub *pub, -				   const char *name, struct brcms_info *hdl, -				   int (*down_fn)(void *handle)); -extern int brcms_c_module_unregister(struct brcms_pub *pub, const char *name, -				     struct brcms_info *hdl); -extern void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc); -extern void brcms_c_enable_mac(struct brcms_c_info *wlc); -extern void brcms_c_associate_upd(struct brcms_c_info *wlc, bool state); -extern void brcms_c_scan_start(struct brcms_c_info *wlc); -extern void brcms_c_scan_stop(struct brcms_c_info *wlc); -extern int brcms_c_get_curband(struct brcms_c_info *wlc); -extern int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel); -extern int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl); -extern void brcms_c_get_current_rateset(struct brcms_c_info *wlc, +struct brcms_c_info *brcms_c_attach(struct brcms_info *wl, +				    struct bcma_device *core, uint unit, +				    bool piomode, uint *perr); +uint brcms_c_detach(struct brcms_c_info *wlc); +int brcms_c_up(struct brcms_c_info *wlc); +uint brcms_c_down(struct brcms_c_info *wlc); + +bool brcms_c_chipmatch(struct bcma_device *core); +void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx); +void brcms_c_reset(struct brcms_c_info *wlc); + +void brcms_c_intrson(struct brcms_c_info *wlc); +u32 brcms_c_intrsoff(struct brcms_c_info *wlc); +void brcms_c_intrsrestore(struct brcms_c_info *wlc, u32 macintmask); +bool brcms_c_intrsupd(struct brcms_c_info *wlc); +bool brcms_c_isr(struct brcms_c_info *wlc); +bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded); +bool brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc, struct sk_buff *sdu, +			      struct ieee80211_hw *hw); +bool brcms_c_aggregatable(struct brcms_c_info *wlc, u8 tid); +void brcms_c_protection_upd(struct brcms_c_info *wlc, uint idx, int val); +int brcms_c_get_header_len(void); +void brcms_c_set_addrmatch(struct brcms_c_info *wlc, int match_reg_offset, +			   const u8 *addr); +void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci, +			   const struct ieee80211_tx_queue_params *arg, +			   bool suspend); +struct brcms_pub *brcms_c_pub(struct brcms_c_info *wlc); +void brcms_c_ampdu_flush(struct brcms_c_info *wlc, struct ieee80211_sta *sta, +			 u16 tid); +void brcms_c_ampdu_tx_operational(struct brcms_c_info *wlc, u8 tid, +				  u8 ba_wsize, uint max_rx_ampdu_bytes); +int brcms_c_module_register(struct brcms_pub *pub, const char *name, +			    struct brcms_info *hdl, +			    int (*down_fn)(void *handle)); +int brcms_c_module_unregister(struct brcms_pub *pub, const char *name, +			      struct brcms_info *hdl); +void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc); +void brcms_c_enable_mac(struct brcms_c_info *wlc); +void brcms_c_associate_upd(struct brcms_c_info *wlc, bool state); +void brcms_c_scan_start(struct brcms_c_info *wlc); +void brcms_c_scan_stop(struct brcms_c_info *wlc); +int brcms_c_get_curband(struct brcms_c_info *wlc); +int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel); +int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl); +void brcms_c_get_current_rateset(struct brcms_c_info *wlc,  				 struct brcm_rateset *currs); -extern int brcms_c_set_rateset(struct brcms_c_info *wlc, -					struct brcm_rateset *rs); -extern int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period); -extern u16 brcms_c_get_phy_type(struct brcms_c_info *wlc, int phyidx); -extern void brcms_c_set_shortslot_override(struct brcms_c_info *wlc, +int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs); +int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period); +u16 brcms_c_get_phy_type(struct brcms_c_info *wlc, int phyidx); +void brcms_c_set_shortslot_override(struct brcms_c_info *wlc,  				    s8 sslot_override); -extern void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc, -					u8 interval); -extern u64 brcms_c_tsf_get(struct brcms_c_info *wlc); -extern void brcms_c_tsf_set(struct brcms_c_info *wlc, u64 tsf); -extern int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr); -extern int brcms_c_get_tx_power(struct brcms_c_info *wlc); -extern bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc); -extern void brcms_c_mute(struct brcms_c_info *wlc, bool on); -extern bool brcms_c_tx_flush_completed(struct brcms_c_info *wlc); -extern void brcms_c_start_station(struct brcms_c_info *wlc, u8 *addr); -extern void brcms_c_start_ap(struct brcms_c_info *wlc, u8 *addr, -			     const u8 *bssid, u8 *ssid, size_t ssid_len); -extern void brcms_c_start_adhoc(struct brcms_c_info *wlc, u8 *addr); -extern void brcms_c_update_beacon(struct brcms_c_info *wlc); -extern void brcms_c_set_new_beacon(struct brcms_c_info *wlc, -				   struct sk_buff *beacon, u16 tim_offset, -				   u16 dtim_period); -extern void brcms_c_set_new_probe_resp(struct brcms_c_info *wlc, -				       struct sk_buff *probe_resp); -extern void brcms_c_enable_probe_resp(struct brcms_c_info *wlc, bool enable); -extern void brcms_c_set_ssid(struct brcms_c_info *wlc, u8 *ssid, -			     size_t ssid_len); +void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc, u8 interval); +u64 brcms_c_tsf_get(struct brcms_c_info *wlc); +void brcms_c_tsf_set(struct brcms_c_info *wlc, u64 tsf); +int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr); +int brcms_c_get_tx_power(struct brcms_c_info *wlc); +bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc); +void brcms_c_mute(struct brcms_c_info *wlc, bool on); +bool brcms_c_tx_flush_completed(struct brcms_c_info *wlc); +void brcms_c_start_station(struct brcms_c_info *wlc, u8 *addr); +void brcms_c_start_ap(struct brcms_c_info *wlc, u8 *addr, const u8 *bssid, +		      u8 *ssid, size_t ssid_len); +void brcms_c_start_adhoc(struct brcms_c_info *wlc, u8 *addr); +void brcms_c_update_beacon(struct brcms_c_info *wlc); +void brcms_c_set_new_beacon(struct brcms_c_info *wlc, struct sk_buff *beacon, +			    u16 tim_offset, u16 dtim_period); +void brcms_c_set_new_probe_resp(struct brcms_c_info *wlc, +				struct sk_buff *probe_resp); +void brcms_c_enable_probe_resp(struct brcms_c_info *wlc, bool enable); +void brcms_c_set_ssid(struct brcms_c_info *wlc, u8 *ssid, size_t ssid_len);  #endif				/* _BRCM_PUB_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/rate.h b/drivers/net/wireless/brcm80211/brcmsmac/rate.h index 980d578825c..5bb88b78ed6 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/rate.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/rate.h @@ -216,34 +216,30 @@ static inline u8 cck_phy2mac_rate(u8 signal)  /* sanitize, and sort a rateset with the basic bit(s) preserved, validate   * rateset */ -extern bool -brcms_c_rate_hwrs_filter_sort_validate(struct brcms_c_rateset *rs, -				       const struct brcms_c_rateset *hw_rs, -				       bool check_brate, u8 txstreams); +bool brcms_c_rate_hwrs_filter_sort_validate(struct brcms_c_rateset *rs, +					    const struct brcms_c_rateset *hw_rs, +					    bool check_brate, u8 txstreams);  /* copy rateset src to dst as-is (no masking or sorting) */ -extern void brcms_c_rateset_copy(const struct brcms_c_rateset *src, -			     struct brcms_c_rateset *dst); +void brcms_c_rateset_copy(const struct brcms_c_rateset *src, +			  struct brcms_c_rateset *dst);  /* would be nice to have these documented ... */ -extern u32 brcms_c_compute_rspec(struct d11rxhdr *rxh, u8 *plcp); - -extern void brcms_c_rateset_filter(struct brcms_c_rateset *src, -	struct brcms_c_rateset *dst, bool basic_only, u8 rates, uint xmask, -	bool mcsallow); - -extern void -brcms_c_rateset_default(struct brcms_c_rateset *rs_tgt, -			const struct brcms_c_rateset *rs_hw, uint phy_type, -			int bandtype, bool cck_only, uint rate_mask, -			bool mcsallow, u8 bw, u8 txstreams); - -extern s16 brcms_c_rate_legacy_phyctl(uint rate); - -extern void brcms_c_rateset_mcs_upd(struct brcms_c_rateset *rs, u8 txstreams); -extern void brcms_c_rateset_mcs_clear(struct brcms_c_rateset *rateset); -extern void brcms_c_rateset_mcs_build(struct brcms_c_rateset *rateset, -				      u8 txstreams); -extern void brcms_c_rateset_bw_mcs_filter(struct brcms_c_rateset *rateset, -					  u8 bw); +u32 brcms_c_compute_rspec(struct d11rxhdr *rxh, u8 *plcp); + +void brcms_c_rateset_filter(struct brcms_c_rateset *src, +			    struct brcms_c_rateset *dst, bool basic_only, +			    u8 rates, uint xmask, bool mcsallow); + +void brcms_c_rateset_default(struct brcms_c_rateset *rs_tgt, +			     const struct brcms_c_rateset *rs_hw, uint phy_type, +			     int bandtype, bool cck_only, uint rate_mask, +			     bool mcsallow, u8 bw, u8 txstreams); + +s16 brcms_c_rate_legacy_phyctl(uint rate); + +void brcms_c_rateset_mcs_upd(struct brcms_c_rateset *rs, u8 txstreams); +void brcms_c_rateset_mcs_clear(struct brcms_c_rateset *rateset); +void brcms_c_rateset_mcs_build(struct brcms_c_rateset *rateset, u8 txstreams); +void brcms_c_rateset_bw_mcs_filter(struct brcms_c_rateset *rateset, u8 bw);  #endif				/* _BRCM_RATE_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/stf.h b/drivers/net/wireless/brcm80211/brcmsmac/stf.h index 19f6580f69b..ba9493009a3 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/stf.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/stf.h @@ -19,24 +19,19 @@  #include "types.h" -extern int brcms_c_stf_attach(struct brcms_c_info *wlc); -extern void brcms_c_stf_detach(struct brcms_c_info *wlc); +int brcms_c_stf_attach(struct brcms_c_info *wlc); +void brcms_c_stf_detach(struct brcms_c_info *wlc); -extern void brcms_c_tempsense_upd(struct brcms_c_info *wlc); -extern void brcms_c_stf_ss_algo_channel_get(struct brcms_c_info *wlc, -					u16 *ss_algo_channel, -					u16 chanspec); -extern int brcms_c_stf_ss_update(struct brcms_c_info *wlc, -			     struct brcms_band *band); -extern void brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc); -extern int brcms_c_stf_txchain_set(struct brcms_c_info *wlc, s32 int_val, -			       bool force); -extern bool brcms_c_stf_stbc_rx_set(struct brcms_c_info *wlc, s32 int_val); -extern void brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc); -extern void brcms_c_stf_phy_chain_calc(struct brcms_c_info *wlc); -extern u16 brcms_c_stf_phytxchain_sel(struct brcms_c_info *wlc, -				      u32 rspec); -extern u16 brcms_c_stf_d11hdrs_phyctl_txant(struct brcms_c_info *wlc, -					u32 rspec); +void brcms_c_tempsense_upd(struct brcms_c_info *wlc); +void brcms_c_stf_ss_algo_channel_get(struct brcms_c_info *wlc, +				     u16 *ss_algo_channel, u16 chanspec); +int brcms_c_stf_ss_update(struct brcms_c_info *wlc, struct brcms_band *band); +void brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc); +int brcms_c_stf_txchain_set(struct brcms_c_info *wlc, s32 int_val, bool force); +bool brcms_c_stf_stbc_rx_set(struct brcms_c_info *wlc, s32 int_val); +void brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc); +void brcms_c_stf_phy_chain_calc(struct brcms_c_info *wlc); +u16 brcms_c_stf_phytxchain_sel(struct brcms_c_info *wlc, u32 rspec); +u16 brcms_c_stf_d11hdrs_phyctl_txant(struct brcms_c_info *wlc, u32 rspec);  #endif				/* _BRCM_STF_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/ucode_loader.h b/drivers/net/wireless/brcm80211/brcmsmac/ucode_loader.h index 18750a814b4..c87dd89bcb7 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/ucode_loader.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/ucode_loader.h @@ -43,16 +43,14 @@ struct brcms_ucode {  	u32 *bcm43xx_bomminor;  }; -extern int -brcms_ucode_data_init(struct brcms_info *wl, struct brcms_ucode *ucode); +int brcms_ucode_data_init(struct brcms_info *wl, struct brcms_ucode *ucode); -extern void brcms_ucode_data_free(struct brcms_ucode *ucode); +void brcms_ucode_data_free(struct brcms_ucode *ucode); -extern int brcms_ucode_init_buf(struct brcms_info *wl, void **pbuf, -				unsigned int idx); -extern int brcms_ucode_init_uint(struct brcms_info *wl, size_t *n_bytes, -				 unsigned int idx); -extern void brcms_ucode_free_buf(void *); -extern int  brcms_check_firmwares(struct brcms_info *wl); +int brcms_ucode_init_buf(struct brcms_info *wl, void **pbuf, unsigned int idx); +int brcms_ucode_init_uint(struct brcms_info *wl, size_t *n_bytes, +			  unsigned int idx); +void brcms_ucode_free_buf(void *); +int  brcms_check_firmwares(struct brcms_info *wl);  #endif	/* _BRCM_UCODE_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmutil/d11.c b/drivers/net/wireless/brcm80211/brcmutil/d11.c index 30e54e2c6c9..2b2522bdd8e 100644 --- a/drivers/net/wireless/brcm80211/brcmutil/d11.c +++ b/drivers/net/wireless/brcm80211/brcmutil/d11.c @@ -21,19 +21,46 @@  #include <brcmu_wifi.h>  #include <brcmu_d11.h> -static void brcmu_d11n_encchspec(struct brcmu_chan *ch) +static u16 d11n_sb(enum brcmu_chan_sb sb)  { -	ch->chspec = ch->chnum & BRCMU_CHSPEC_CH_MASK; +	switch (sb) { +	case BRCMU_CHAN_SB_NONE: +		return BRCMU_CHSPEC_D11N_SB_N; +	case BRCMU_CHAN_SB_L: +		return BRCMU_CHSPEC_D11N_SB_L; +	case BRCMU_CHAN_SB_U: +		return BRCMU_CHSPEC_D11N_SB_U; +	default: +		WARN_ON(1); +	} +	return 0; +} -	switch (ch->bw) { +static u16 d11n_bw(enum brcmu_chan_bw bw) +{ +	switch (bw) {  	case BRCMU_CHAN_BW_20: -		ch->chspec |= BRCMU_CHSPEC_D11N_BW_20 | BRCMU_CHSPEC_D11N_SB_N; -		break; +		return BRCMU_CHSPEC_D11N_BW_20;  	case BRCMU_CHAN_BW_40: +		return BRCMU_CHSPEC_D11N_BW_40;  	default: -		WARN_ON_ONCE(1); -		break; +		WARN_ON(1);  	} +	return 0; +} + +static void brcmu_d11n_encchspec(struct brcmu_chan *ch) +{ +	if (ch->bw == BRCMU_CHAN_BW_20) +		ch->sb = BRCMU_CHAN_SB_NONE; + +	ch->chspec = 0; +	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_CH_MASK, +			BRCMU_CHSPEC_CH_SHIFT, ch->chnum); +	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11N_SB_MASK, +			0, d11n_sb(ch->sb)); +	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11N_BW_MASK, +			0, d11n_bw(ch->bw));  	if (ch->chnum <= CH_MAX_2G_CHANNEL)  		ch->chspec |= BRCMU_CHSPEC_D11N_BND_2G; @@ -41,23 +68,34 @@ static void brcmu_d11n_encchspec(struct brcmu_chan *ch)  		ch->chspec |= BRCMU_CHSPEC_D11N_BND_5G;  } -static void brcmu_d11ac_encchspec(struct brcmu_chan *ch) +static u16 d11ac_bw(enum brcmu_chan_bw bw)  { -	ch->chspec = ch->chnum & BRCMU_CHSPEC_CH_MASK; - -	switch (ch->bw) { +	switch (bw) {  	case BRCMU_CHAN_BW_20: -		ch->chspec |= BRCMU_CHSPEC_D11AC_BW_20; -		break; +		return BRCMU_CHSPEC_D11AC_BW_20;  	case BRCMU_CHAN_BW_40: +		return BRCMU_CHSPEC_D11AC_BW_40;  	case BRCMU_CHAN_BW_80: -	case BRCMU_CHAN_BW_80P80: -	case BRCMU_CHAN_BW_160: +		return BRCMU_CHSPEC_D11AC_BW_80;  	default: -		WARN_ON_ONCE(1); -		break; +		WARN_ON(1);  	} +	return 0; +} +static void brcmu_d11ac_encchspec(struct brcmu_chan *ch) +{ +	if (ch->bw == BRCMU_CHAN_BW_20 || ch->sb == BRCMU_CHAN_SB_NONE) +		ch->sb = BRCMU_CHAN_SB_L; + +	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_CH_MASK, +			BRCMU_CHSPEC_CH_SHIFT, ch->chnum); +	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK, +			BRCMU_CHSPEC_D11AC_SB_SHIFT, ch->sb); +	brcmu_maskset16(&ch->chspec, BRCMU_CHSPEC_D11AC_BW_MASK, +			0, d11ac_bw(ch->bw)); + +	ch->chspec &= ~BRCMU_CHSPEC_D11AC_BND_MASK;  	if (ch->chnum <= CH_MAX_2G_CHANNEL)  		ch->chspec |= BRCMU_CHSPEC_D11AC_BND_2G;  	else @@ -73,6 +111,7 @@ static void brcmu_d11n_decchspec(struct brcmu_chan *ch)  	switch (ch->chspec & BRCMU_CHSPEC_D11N_BW_MASK) {  	case BRCMU_CHSPEC_D11N_BW_20:  		ch->bw = BRCMU_CHAN_BW_20; +		ch->sb = BRCMU_CHAN_SB_NONE;  		break;  	case BRCMU_CHSPEC_D11N_BW_40:  		ch->bw = BRCMU_CHAN_BW_40; @@ -112,6 +151,7 @@ static void brcmu_d11ac_decchspec(struct brcmu_chan *ch)  	switch (ch->chspec & BRCMU_CHSPEC_D11AC_BW_MASK) {  	case BRCMU_CHSPEC_D11AC_BW_20:  		ch->bw = BRCMU_CHAN_BW_20; +		ch->sb = BRCMU_CHAN_SB_NONE;  		break;  	case BRCMU_CHSPEC_D11AC_BW_40:  		ch->bw = BRCMU_CHAN_BW_40; @@ -128,6 +168,25 @@ static void brcmu_d11ac_decchspec(struct brcmu_chan *ch)  		break;  	case BRCMU_CHSPEC_D11AC_BW_80:  		ch->bw = BRCMU_CHAN_BW_80; +		ch->sb = brcmu_maskget16(ch->chspec, BRCMU_CHSPEC_D11AC_SB_MASK, +					 BRCMU_CHSPEC_D11AC_SB_SHIFT); +		switch (ch->sb) { +		case BRCMU_CHAN_SB_LL: +			ch->chnum -= CH_30MHZ_APART; +			break; +		case BRCMU_CHAN_SB_LU: +			ch->chnum -= CH_10MHZ_APART; +			break; +		case BRCMU_CHAN_SB_UL: +			ch->chnum += CH_10MHZ_APART; +			break; +		case BRCMU_CHAN_SB_UU: +			ch->chnum += CH_30MHZ_APART; +			break; +		default: +			WARN_ON_ONCE(1); +			break; +		}  		break;  	case BRCMU_CHSPEC_D11AC_BW_8080:  	case BRCMU_CHSPEC_D11AC_BW_160: diff --git a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h index c1fe245bb07..d816270db3b 100644 --- a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h +++ b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h @@ -41,5 +41,8 @@  #define BCM4331_CHIP_ID		0x4331  #define BCM4334_CHIP_ID		0x4334  #define BCM4335_CHIP_ID		0x4335 +#define BCM43362_CHIP_ID	43362 +#define BCM4339_CHIP_ID		0x4339 +#define BCM4354_CHIP_ID		0x4354  #endif				/* _BRCM_HW_IDS_H_ */ diff --git a/drivers/net/wireless/brcm80211/include/brcmu_d11.h b/drivers/net/wireless/brcm80211/include/brcmu_d11.h index 92623f02b1c..f9745ea8b3e 100644 --- a/drivers/net/wireless/brcm80211/include/brcmu_d11.h +++ b/drivers/net/wireless/brcm80211/include/brcmu_d11.h @@ -108,13 +108,7 @@ enum brcmu_chan_bw {  };  enum brcmu_chan_sb { -	BRCMU_CHAN_SB_NONE = 0, -	BRCMU_CHAN_SB_L, -	BRCMU_CHAN_SB_U, -	BRCMU_CHAN_SB_LL, -	BRCMU_CHAN_SB_LU, -	BRCMU_CHAN_SB_UL, -	BRCMU_CHAN_SB_UU, +	BRCMU_CHAN_SB_NONE = -1,  	BRCMU_CHAN_SB_LLL,  	BRCMU_CHAN_SB_LLU,  	BRCMU_CHAN_SB_LUL, @@ -123,6 +117,12 @@ enum brcmu_chan_sb {  	BRCMU_CHAN_SB_ULU,  	BRCMU_CHAN_SB_UUL,  	BRCMU_CHAN_SB_UUU, +	BRCMU_CHAN_SB_L = BRCMU_CHAN_SB_LLL, +	BRCMU_CHAN_SB_U = BRCMU_CHAN_SB_LLU, +	BRCMU_CHAN_SB_LL = BRCMU_CHAN_SB_LLL, +	BRCMU_CHAN_SB_LU = BRCMU_CHAN_SB_LLU, +	BRCMU_CHAN_SB_UL = BRCMU_CHAN_SB_LUL, +	BRCMU_CHAN_SB_UU = BRCMU_CHAN_SB_LUU,  };  struct brcmu_chan { @@ -140,6 +140,6 @@ struct brcmu_d11inf {  	void (*decchspec)(struct brcmu_chan *ch);  }; -extern void brcmu_d11_attach(struct brcmu_d11inf *d11inf); +void brcmu_d11_attach(struct brcmu_d11inf *d11inf);  #endif	/* _BRCMU_CHANNELS_H_ */ diff --git a/drivers/net/wireless/brcm80211/include/brcmu_utils.h b/drivers/net/wireless/brcm80211/include/brcmu_utils.h index 898cacb8d01..8ba445b3fd7 100644 --- a/drivers/net/wireless/brcm80211/include/brcmu_utils.h +++ b/drivers/net/wireless/brcm80211/include/brcmu_utils.h @@ -114,31 +114,29 @@ static inline struct sk_buff *pktq_ppeek_tail(struct pktq *pq, int prec)  	return skb_peek_tail(&pq->q[prec].skblist);  } -extern struct sk_buff *brcmu_pktq_penq(struct pktq *pq, int prec, -				 struct sk_buff *p); -extern struct sk_buff *brcmu_pktq_penq_head(struct pktq *pq, int prec, -				      struct sk_buff *p); -extern struct sk_buff *brcmu_pktq_pdeq(struct pktq *pq, int prec); -extern struct sk_buff *brcmu_pktq_pdeq_tail(struct pktq *pq, int prec); -extern struct sk_buff *brcmu_pktq_pdeq_match(struct pktq *pq, int prec, -					     bool (*match_fn)(struct sk_buff *p, -							      void *arg), -					     void *arg); +struct sk_buff *brcmu_pktq_penq(struct pktq *pq, int prec, struct sk_buff *p); +struct sk_buff *brcmu_pktq_penq_head(struct pktq *pq, int prec, +				     struct sk_buff *p); +struct sk_buff *brcmu_pktq_pdeq(struct pktq *pq, int prec); +struct sk_buff *brcmu_pktq_pdeq_tail(struct pktq *pq, int prec); +struct sk_buff *brcmu_pktq_pdeq_match(struct pktq *pq, int prec, +				      bool (*match_fn)(struct sk_buff *p, +						       void *arg), +				      void *arg);  /* packet primitives */ -extern struct sk_buff *brcmu_pkt_buf_get_skb(uint len); -extern void brcmu_pkt_buf_free_skb(struct sk_buff *skb); +struct sk_buff *brcmu_pkt_buf_get_skb(uint len); +void brcmu_pkt_buf_free_skb(struct sk_buff *skb);  /* Empty the queue at particular precedence level */  /* callback function fn(pkt, arg) returns true if pkt belongs to if */ -extern void brcmu_pktq_pflush(struct pktq *pq, int prec, -	bool dir, bool (*fn)(struct sk_buff *, void *), void *arg); +void brcmu_pktq_pflush(struct pktq *pq, int prec, bool dir, +		       bool (*fn)(struct sk_buff *, void *), void *arg);  /* operations on a set of precedences in packet queue */ -extern int brcmu_pktq_mlen(struct pktq *pq, uint prec_bmp); -extern struct sk_buff *brcmu_pktq_mdeq(struct pktq *pq, uint prec_bmp, -	int *prec_out); +int brcmu_pktq_mlen(struct pktq *pq, uint prec_bmp); +struct sk_buff *brcmu_pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out);  /* operations on packet queue as a whole */ @@ -167,11 +165,11 @@ static inline bool pktq_empty(struct pktq *pq)  	return pq->len == 0;  } -extern void brcmu_pktq_init(struct pktq *pq, int num_prec, int max_len); +void brcmu_pktq_init(struct pktq *pq, int num_prec, int max_len);  /* prec_out may be NULL if caller is not interested in return value */ -extern struct sk_buff *brcmu_pktq_peek_tail(struct pktq *pq, int *prec_out); -extern void brcmu_pktq_flush(struct pktq *pq, bool dir, -		bool (*fn)(struct sk_buff *, void *), void *arg); +struct sk_buff *brcmu_pktq_peek_tail(struct pktq *pq, int *prec_out); +void brcmu_pktq_flush(struct pktq *pq, bool dir, +		      bool (*fn)(struct sk_buff *, void *), void *arg);  /* externs */  /* ip address */ @@ -204,13 +202,13 @@ static inline u16 brcmu_maskget16(u16 var, u16 mask, u8 shift)  /* externs */  /* format/print */  #ifdef DEBUG -extern void brcmu_prpkt(const char *msg, struct sk_buff *p0); +void brcmu_prpkt(const char *msg, struct sk_buff *p0);  #else  #define brcmu_prpkt(a, b)  #endif				/* DEBUG */  #ifdef DEBUG -extern __printf(3, 4) +__printf(3, 4)  void brcmu_dbg_hex_dump(const void *data, size_t size, const char *fmt, ...);  #else  __printf(3, 4) diff --git a/drivers/net/wireless/brcm80211/include/brcmu_wifi.h b/drivers/net/wireless/brcm80211/include/brcmu_wifi.h index 0505cc065e0..76b5d3a8629 100644 --- a/drivers/net/wireless/brcm80211/include/brcmu_wifi.h +++ b/drivers/net/wireless/brcm80211/include/brcmu_wifi.h @@ -29,6 +29,7 @@  #define CH_UPPER_SB			0x01  #define CH_LOWER_SB			0x02  #define CH_EWA_VALID			0x04 +#define CH_30MHZ_APART			6  #define CH_20MHZ_APART			4  #define CH_10MHZ_APART			2  #define CH_5MHZ_APART			1 /* 2G band channels are 5 Mhz apart */ @@ -82,6 +83,20 @@  #define WLC_N_BW_40ALL			1  #define WLC_N_BW_20IN2G_40IN5G		2 +#define WLC_BW_20MHZ_BIT		BIT(0) +#define WLC_BW_40MHZ_BIT		BIT(1) +#define WLC_BW_80MHZ_BIT		BIT(2) +#define WLC_BW_160MHZ_BIT		BIT(3) + +/* Bandwidth capabilities */ +#define WLC_BW_CAP_20MHZ		(WLC_BW_20MHZ_BIT) +#define WLC_BW_CAP_40MHZ		(WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) +#define WLC_BW_CAP_80MHZ		(WLC_BW_80MHZ_BIT|WLC_BW_40MHZ_BIT| \ +					 WLC_BW_20MHZ_BIT) +#define WLC_BW_CAP_160MHZ		(WLC_BW_160MHZ_BIT|WLC_BW_80MHZ_BIT| \ +					 WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) +#define WLC_BW_CAP_UNRESTRICTED		0xFF +  /* band types */  #define	WLC_BAND_AUTO			0	/* auto-select */  #define	WLC_BAND_5G			1	/* 5 Ghz */ @@ -203,6 +218,9 @@ static inline bool ac_bitmap_tst(u8 bitmap, int prec)  #define WSEC_SWFLAG		0x0008  /* to go into transition mode without setting wep */  #define SES_OW_ENABLED		0x0040 +/* MFP */ +#define MFP_CAPABLE		0x0200 +#define MFP_REQUIRED		0x0400  /* WPA authentication mode bitvec */  #define WPA_AUTH_DISABLED	0x0000	/* Legacy (i.e., non-WPA) */  | 
